]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge git://git.linux-nfs.org/pub/linux/nfs-2.6
authorLinus Torvalds <torvalds@g5.osdl.org>
Sun, 25 Jun 2006 17:54:14 +0000 (10:54 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Sun, 25 Jun 2006 17:54:14 +0000 (10:54 -0700)
* git://git.linux-nfs.org/pub/linux/nfs-2.6: (51 commits)
  nfs: remove nfs_put_link()
  nfs-build-fix-99
  git-nfs-build-fixes
  Merge branch 'odirect'
  NFS: alloc nfs_read/write_data as direct I/O is scheduled
  NFS: Eliminate nfs_get_user_pages()
  NFS: refactor nfs_direct_free_user_pages
  NFS: remove user_addr, user_count, and pos from nfs_direct_req
  NFS: "open code" the NFS direct write rescheduler
  NFS: Separate functions for counting outstanding NFS direct I/Os
  NLM: Fix reclaim races
  NLM: sem to mutex conversion
  locks.c: add the fl_owner to nlm_compare_locks
  NFS: Display the chosen RPCSEC_GSS security flavour in /proc/mounts
  NFS: Split fs/nfs/inode.c
  NFS: Fix typo in nfs_do_clone_mount()
  NFS: Fix compile errors introduced by referrals patches
  NFSv4: Ensure that referral mounts bind to a reserved port
  NFSv4: A root pathname is sent as a zero component4
  NFSv4: Follow a referral
  ...

658 files changed:
CREDITS
Documentation/DocBook/kernel-api.tmpl
Documentation/RCU/checklist.txt
Documentation/RCU/whatisRCU.txt
Documentation/devices.txt
Documentation/filesystems/fuse.txt
Documentation/filesystems/ramfs-rootfs-initramfs.txt
Documentation/kdump/kdump.txt
Documentation/memory-barriers.txt
Documentation/rtc.txt
Documentation/sysrq.txt
Documentation/video4linux/CARDLIST.bttv
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CARDLIST.tuner
Documentation/video4linux/CQcam.txt
Documentation/video4linux/Zoran
Documentation/video4linux/bttv/CONTRIBUTORS
Documentation/video4linux/cx2341x/fw-calling.txt [new file with mode: 0644]
Documentation/video4linux/cx2341x/fw-decoder-api.txt [new file with mode: 0644]
Documentation/video4linux/cx2341x/fw-dma.txt [new file with mode: 0644]
Documentation/video4linux/cx2341x/fw-encoder-api.txt [new file with mode: 0644]
Documentation/video4linux/cx2341x/fw-memory.txt [new file with mode: 0644]
Documentation/video4linux/cx2341x/fw-osd-api.txt [new file with mode: 0644]
Documentation/video4linux/cx2341x/fw-upload.txt [new file with mode: 0644]
Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt [new file with mode: 0644]
Documentation/video4linux/et61x251.txt
Documentation/video4linux/ibmcam.txt
Documentation/video4linux/ov511.txt
Documentation/video4linux/sn9c102.txt
Documentation/video4linux/v4lgrab.c [new file with mode: 0644]
Documentation/video4linux/w9968cf.txt
Documentation/video4linux/zc0301.txt
arch/arm/kernel/bios32.c
arch/arm/mach-ixp4xx/nas100d-power.c
arch/arm/mach-ixp4xx/nslu2-power.c
arch/cris/arch-v32/drivers/pci/bios.c
arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
arch/i386/kernel/crash.c
arch/i386/kernel/doublefault.c
arch/i386/kernel/setup.c
arch/i386/kernel/smpboot.c
arch/i386/lib/usercopy.c
arch/i386/mach-default/setup.c
arch/i386/mach-visws/setup.c
arch/i386/mach-voyager/setup.c
arch/i386/pci/i386.c
arch/ia64/kernel/topology.c
arch/ia64/pci/pci.c
arch/m68k/amiga/amiga_ksyms.c
arch/m68k/amiga/amiints.c
arch/m68k/amiga/cia.c
arch/m68k/amiga/config.c
arch/m68k/apollo/Makefile
arch/m68k/apollo/config.c
arch/m68k/apollo/dn_ints.c
arch/m68k/atari/ataints.c
arch/m68k/atari/config.c
arch/m68k/bvme6000/Makefile
arch/m68k/bvme6000/bvmeints.c [deleted file]
arch/m68k/bvme6000/config.c
arch/m68k/hp300/Makefile
arch/m68k/hp300/config.c
arch/m68k/hp300/ints.c [deleted file]
arch/m68k/hp300/ints.h [deleted file]
arch/m68k/hp300/time.c
arch/m68k/kernel/Makefile
arch/m68k/kernel/dma.c [new file with mode: 0644]
arch/m68k/kernel/entry.S
arch/m68k/kernel/ints.c
arch/m68k/kernel/m68k_ksyms.c
arch/m68k/kernel/setup.c
arch/m68k/kernel/traps.c
arch/m68k/mac/baboon.c
arch/m68k/mac/config.c
arch/m68k/mac/iop.c
arch/m68k/mac/macints.c
arch/m68k/mac/oss.c
arch/m68k/mac/psc.c
arch/m68k/mac/via.c
arch/m68k/mm/kmap.c
arch/m68k/mvme147/147ints.c [deleted file]
arch/m68k/mvme147/Makefile
arch/m68k/mvme147/config.c
arch/m68k/mvme16x/16xints.c [deleted file]
arch/m68k/mvme16x/Makefile
arch/m68k/mvme16x/config.c
arch/m68k/q40/config.c
arch/m68k/q40/q40ints.c
arch/m68k/sun3/config.c
arch/m68k/sun3/sun3ints.c
arch/m68k/sun3x/config.c
arch/mips/kernel/irixsig.c
arch/mips/kernel/sysirix.c
arch/powerpc/kernel/pci_32.c
arch/powerpc/kernel/pci_64.c
arch/powerpc/kernel/proc_ppc64.c
arch/powerpc/kernel/traps.c
arch/powerpc/platforms/cell/cbe_regs.c
arch/powerpc/platforms/cell/interrupt.c
arch/powerpc/platforms/powermac/backlight.c
arch/powerpc/xmon/xmon.c
arch/ppc/kernel/pci.c
arch/s390/kernel/setup.c
arch/um/drivers/mconsole_kern.c
arch/um/include/sysdep-x86_64/syscalls.h
arch/x86_64/kernel/setup.c
arch/xtensa/kernel/pci.c
drivers/block/amiflop.c
drivers/block/cciss.c
drivers/block/cciss.h
drivers/block/cpqarray.c
drivers/block/loop.c
drivers/block/nbd.c
drivers/cdrom/mcdx.c
drivers/char/Kconfig
drivers/char/applicom.c
drivers/char/cyclades.c
drivers/char/esp.c
drivers/char/ip2/ip2main.c
drivers/char/isicom.c
drivers/char/keyboard.c
drivers/char/mmtimer.c
drivers/char/mxser.c
drivers/char/n_r3964.c
drivers/char/pcmcia/synclink_cs.c
drivers/char/rocket.c
drivers/char/specialix.c
drivers/char/synclink_gt.c
drivers/char/synclinkmp.c
drivers/firmware/Kconfig
drivers/firmware/dmi_scan.c
drivers/ide/ide-cd.c
drivers/ide/ide-floppy.c
drivers/ide/ide-io.c
drivers/ide/ide-tape.c
drivers/ieee1394/Kconfig
drivers/ieee1394/nodemgr.c
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/h3600_ts_input.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/ledtrig-heartbeat.c [new file with mode: 0644]
drivers/macintosh/Kconfig
drivers/macintosh/Makefile
drivers/macintosh/adbhid.c
drivers/macintosh/via-pmu-backlight.c [new file with mode: 0644]
drivers/macintosh/via-pmu.c
drivers/media/Kconfig
drivers/media/common/Makefile
drivers/media/common/ir-functions.c
drivers/media/common/ir-keymaps.c
drivers/media/common/saa7146_fops.c
drivers/media/common/saa7146_hlp.c
drivers/media/common/saa7146_video.c
drivers/media/common/saa7146_vv_ksyms.c [deleted file]
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
drivers/media/dvb/b2c2/flexcop-pci.c
drivers/media/dvb/b2c2/flexcop-usb.c
drivers/media/dvb/b2c2/flexcop.c
drivers/media/dvb/bt8xx/bt878.c
drivers/media/dvb/bt8xx/dst.c
drivers/media/dvb/bt8xx/dst_ca.c
drivers/media/dvb/bt8xx/dst_common.h
drivers/media/dvb/bt8xx/dvb-bt8xx.c
drivers/media/dvb/bt8xx/dvb-bt8xx.h
drivers/media/dvb/cinergyT2/Kconfig
drivers/media/dvb/cinergyT2/cinergyT2.c
drivers/media/dvb/dvb-core/Makefile
drivers/media/dvb/dvb-core/dmxdev.c
drivers/media/dvb/dvb-core/dvb_ca_en50221.c
drivers/media/dvb/dvb-core/dvb_demux.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-core/dvb_math.c [new file with mode: 0644]
drivers/media/dvb/dvb-core/dvb_math.h [new file with mode: 0644]
drivers/media/dvb/dvb-core/dvb_net.c
drivers/media/dvb/dvb-core/dvbdev.c
drivers/media/dvb/dvb-core/dvbdev.h
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/Makefile
drivers/media/dvb/dvb-usb/cxusb.c
drivers/media/dvb/dvb-usb/dibusb-common.c
drivers/media/dvb/dvb-usb/dibusb-mb.c
drivers/media/dvb/dvb-usb/digitv.c
drivers/media/dvb/dvb-usb/dtt200u-fe.c
drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dvb-usb.h
drivers/media/dvb/dvb-usb/gp8psk-fe.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/gp8psk.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/gp8psk.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/umt-010.c
drivers/media/dvb/dvb-usb/vp702x-fe.c
drivers/media/dvb/dvb-usb/vp7045-fe.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/bcm3510.c
drivers/media/dvb/frontends/bsbe1.h
drivers/media/dvb/frontends/bsru6.h
drivers/media/dvb/frontends/cx22700.c
drivers/media/dvb/frontends/cx22700.h
drivers/media/dvb/frontends/cx22702.c
drivers/media/dvb/frontends/cx22702.h
drivers/media/dvb/frontends/cx24110.c
drivers/media/dvb/frontends/cx24110.h
drivers/media/dvb/frontends/cx24123.c
drivers/media/dvb/frontends/cx24123.h
drivers/media/dvb/frontends/dib3000-common.h
drivers/media/dvb/frontends/dib3000.h
drivers/media/dvb/frontends/dib3000mb.c
drivers/media/dvb/frontends/dib3000mc.c
drivers/media/dvb/frontends/dvb-pll.c
drivers/media/dvb/frontends/dvb-pll.h
drivers/media/dvb/frontends/dvb_dummy_fe.c
drivers/media/dvb/frontends/isl6421.c [new file with mode: 0644]
drivers/media/dvb/frontends/isl6421.h [new file with mode: 0644]
drivers/media/dvb/frontends/l64781.c
drivers/media/dvb/frontends/l64781.h
drivers/media/dvb/frontends/lg_h06xf.h [new file with mode: 0644]
drivers/media/dvb/frontends/lgdt330x.c
drivers/media/dvb/frontends/lgdt330x.h
drivers/media/dvb/frontends/lnbp21.c [new file with mode: 0644]
drivers/media/dvb/frontends/lnbp21.h
drivers/media/dvb/frontends/mt312.c
drivers/media/dvb/frontends/mt312.h
drivers/media/dvb/frontends/mt352.c
drivers/media/dvb/frontends/mt352.h
drivers/media/dvb/frontends/nxt200x.c
drivers/media/dvb/frontends/nxt200x.h
drivers/media/dvb/frontends/nxt6000.c
drivers/media/dvb/frontends/nxt6000.h
drivers/media/dvb/frontends/or51132.c
drivers/media/dvb/frontends/or51132.h
drivers/media/dvb/frontends/or51211.c
drivers/media/dvb/frontends/s5h1420.c
drivers/media/dvb/frontends/s5h1420.h
drivers/media/dvb/frontends/sp8870.c
drivers/media/dvb/frontends/sp8870.h
drivers/media/dvb/frontends/sp887x.c
drivers/media/dvb/frontends/sp887x.h
drivers/media/dvb/frontends/stv0297.c
drivers/media/dvb/frontends/stv0297.h
drivers/media/dvb/frontends/stv0299.c
drivers/media/dvb/frontends/stv0299.h
drivers/media/dvb/frontends/tda10021.c
drivers/media/dvb/frontends/tda10021.h
drivers/media/dvb/frontends/tda1004x.c
drivers/media/dvb/frontends/tda1004x.h
drivers/media/dvb/frontends/tda8083.c
drivers/media/dvb/frontends/tda8083.h
drivers/media/dvb/frontends/ves1820.c
drivers/media/dvb/frontends/ves1820.h
drivers/media/dvb/frontends/ves1x93.c
drivers/media/dvb/frontends/ves1x93.h
drivers/media/dvb/frontends/zl10353.c
drivers/media/dvb/frontends/zl10353.h
drivers/media/dvb/pluto2/pluto2.c
drivers/media/dvb/ttpci/Kconfig
drivers/media/dvb/ttpci/Makefile
drivers/media/dvb/ttpci/av7110.c
drivers/media/dvb/ttpci/budget-av.c
drivers/media/dvb/ttpci/budget-ci.c
drivers/media/dvb/ttpci/budget-core.c
drivers/media/dvb/ttpci/budget-patch.c
drivers/media/dvb/ttpci/budget.c
drivers/media/dvb/ttusb-budget/Kconfig
drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
drivers/media/dvb/ttusb-dec/ttusb_dec.c
drivers/media/dvb/ttusb-dec/ttusbdecfe.c
drivers/media/radio/Kconfig
drivers/media/radio/Makefile
drivers/media/radio/miropcm20-radio.c
drivers/media/radio/miropcm20-rds-core.c
drivers/media/radio/miropcm20-rds.c
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-aztech.c
drivers/media/radio/radio-cadet.c
drivers/media/radio/radio-gemtek-pci.c
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-maestro.c
drivers/media/radio/radio-maxiradio.c
drivers/media/radio/radio-rtrack2.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-terratec.c
drivers/media/radio/radio-trust.c
drivers/media/radio/radio-typhoon.c
drivers/media/radio/radio-zoltrix.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/arv.c
drivers/media/video/bt866.c [new file with mode: 0644]
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-gpio.c
drivers/media/video/bt8xx/bttv-input.c
drivers/media/video/bt8xx/bttv.h
drivers/media/video/bt8xx/bttvp.h
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_v4l.c
drivers/media/video/cpia_pp.c
drivers/media/video/cpia_usb.c
drivers/media/video/cx2341x.c [new file with mode: 0644]
drivers/media/video/cx25840/cx25840-audio.c
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/cx25840/cx25840-core.h
drivers/media/video/cx25840/cx25840-vbi.c
drivers/media/video/cx88/Kconfig
drivers/media/video/cx88/cx88-alsa.c
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-i2c.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88-tvaudio.c
drivers/media/video/cx88/cx88-vbi.c
drivers/media/video/cx88/cx88.h
drivers/media/video/dsbr100.c
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/em28xx/em28xx-input.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/et61x251/et61x251_core.c
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ks0127.c [new file with mode: 0644]
drivers/media/video/ks0127.h [new file with mode: 0644]
drivers/media/video/meye.c
drivers/media/video/msp3400-driver.c
drivers/media/video/msp3400-kthreads.c
drivers/media/video/ov511.c
drivers/media/video/ov511.h
drivers/media/video/planb.c
drivers/media/video/pms.c
drivers/media/video/pwc/Kconfig
drivers/media/video/pwc/Makefile
drivers/media/video/pwc/pwc-ctrl.c
drivers/media/video/pwc/pwc-dec1.c [new file with mode: 0644]
drivers/media/video/pwc/pwc-dec1.h [new file with mode: 0644]
drivers/media/video/pwc/pwc-dec23.c [new file with mode: 0644]
drivers/media/video/pwc/pwc-dec23.h [new file with mode: 0644]
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc-kiara.c
drivers/media/video/pwc/pwc-kiara.h
drivers/media/video/pwc/pwc-misc.c
drivers/media/video/pwc/pwc-timon.c
drivers/media/video/pwc/pwc-timon.h
drivers/media/video/pwc/pwc-uncompress.c
drivers/media/video/pwc/pwc-uncompress.h
drivers/media/video/pwc/pwc-v4l.c [new file with mode: 0644]
drivers/media/video/pwc/pwc.h
drivers/media/video/saa5246a.c
drivers/media/video/saa5249.c
drivers/media/video/saa7110.c
drivers/media/video/saa7115.c
drivers/media/video/saa7127.c
drivers/media/video/saa7134/saa6752hs.c
drivers/media/video/saa7134/saa7134-alsa.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/se401.h
drivers/media/video/sn9c102/sn9c102_core.c
drivers/media/video/stradis.c
drivers/media/video/stv680.c
drivers/media/video/tda9875.c
drivers/media/video/tda9887.c
drivers/media/video/tea5767.c
drivers/media/video/tlv320aic23b.c [new file with mode: 0644]
drivers/media/video/tuner-3036.c
drivers/media/video/tuner-core.c
drivers/media/video/tuner-simple.c
drivers/media/video/tuner-types.c
drivers/media/video/tveeprom.c
drivers/media/video/tvmixer.c
drivers/media/video/tvp5150.c
drivers/media/video/usbvideo/Kconfig
drivers/media/video/usbvideo/Makefile
drivers/media/video/usbvideo/quickcam_messenger.c [new file with mode: 0644]
drivers/media/video/usbvideo/quickcam_messenger.h [new file with mode: 0644]
drivers/media/video/usbvideo/usbvideo.h
drivers/media/video/v4l1-compat.c
drivers/media/video/v4l2-common.c
drivers/media/video/video-buf-dvb.c
drivers/media/video/videodev.c
drivers/media/video/vino.c
drivers/media/video/vivi.c
drivers/media/video/vpx3220.c
drivers/media/video/w9966.c
drivers/media/video/zc0301/Kconfig
drivers/media/video/zc0301/Makefile
drivers/media/video/zc0301/zc0301_core.c
drivers/media/video/zc0301/zc0301_pas202bcb.c
drivers/media/video/zc0301/zc0301_pb0330.c [new file with mode: 0644]
drivers/media/video/zc0301/zc0301_sensor.h
drivers/media/video/zoran.h
drivers/media/video/zoran_card.c
drivers/media/video/zoran_device.c
drivers/media/video/zoran_driver.c
drivers/media/video/zoran_procfs.c
drivers/net/irda/irda-usb.c
drivers/net/sun3lance.c
drivers/net/wan/sdla.c
drivers/oprofile/buffer_sync.c
drivers/oprofile/event_buffer.c
drivers/oprofile/event_buffer.h
drivers/oprofile/oprof.c
drivers/parport/Kconfig
drivers/parport/Makefile
drivers/parport/daisy.c
drivers/parport/parport_ax88796.c [new file with mode: 0644]
drivers/parport/share.c
drivers/pnp/card.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/class.c
drivers/rtc/interface.c
drivers/rtc/rtc-at91.c [new file with mode: 0644]
drivers/rtc/rtc-dev.c
drivers/rtc/rtc-ds1307.c [new file with mode: 0644]
drivers/rtc/rtc-ds1553.c [new file with mode: 0644]
drivers/rtc/rtc-ds1742.c [new file with mode: 0644]
drivers/rtc/rtc-lib.c
drivers/rtc/rtc-max6902.c [new file with mode: 0644]
drivers/rtc/rtc-pcf8583.c [new file with mode: 0644]
drivers/rtc/rtc-pl031.c [new file with mode: 0644]
drivers/rtc/rtc-sa1100.c
drivers/rtc/rtc-v3020.c [new file with mode: 0644]
drivers/rtc/rtc-vr41xx.c
drivers/s390/char/sclp_quiesce.c
drivers/sbus/char/flash.c
drivers/sbus/char/vfc_dev.c
drivers/scsi/advansys.c
drivers/scsi/mac_esp.c
drivers/scsi/mac_scsi.c
drivers/scsi/megaraid/megaraid_mbox.c
drivers/scsi/sun3x_esp.c
drivers/scsi/wd7000.c
drivers/video/Kconfig
drivers/video/aty/Makefile
drivers/video/aty/aty128fb.c
drivers/video/aty/atyfb.h
drivers/video/aty/atyfb_base.c
drivers/video/aty/radeon_backlight.c [new file with mode: 0644]
drivers/video/aty/radeon_base.c
drivers/video/aty/radeonfb.h
drivers/video/chipsfb.c
drivers/video/fbsysfs.c
drivers/video/igafb.c
drivers/video/matrox/matroxfb_base.c
drivers/video/nvidia/Makefile
drivers/video/nvidia/nv_backlight.c [new file with mode: 0644]
drivers/video/nvidia/nv_proto.h
drivers/video/nvidia/nvidia.c
drivers/video/riva/fbdev.c
drivers/video/tridentfb.c
fs/9p/vfs_inode.c
fs/Kconfig
fs/affs/super.c
fs/autofs4/expire.c
fs/compat_ioctl.c
fs/dcache.c
fs/eventpoll.c
fs/ext2/Makefile
fs/ext2/balloc.c
fs/ext2/bitmap.c [deleted file]
fs/ext2/dir.c
fs/ext2/fsync.c
fs/ext2/ialloc.c
fs/ext2/super.c
fs/ext3/balloc.c
fs/ext3/ialloc.c
fs/ext3/inode.c
fs/ext3/ioctl.c
fs/ext3/namei.c
fs/ext3/resize.c
fs/ext3/super.c
fs/ext3/xattr.c
fs/freevxfs/vxfs.h
fs/freevxfs/vxfs_fshead.c
fs/fuse/Makefile
fs/fuse/control.c [new file with mode: 0644]
fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/jbd/recovery.c
fs/namei.c
fs/ntfs/file.c
fs/open.c
fs/openpromfs/inode.c
fs/select.c
fs/smbfs/smbiod.c
fs/ufs/balloc.c
fs/ufs/cylinder.c
fs/ufs/dir.c
fs/ufs/file.c
fs/ufs/ialloc.c
fs/ufs/inode.c
fs/ufs/namei.c
fs/ufs/super.c
fs/ufs/truncate.c
fs/ufs/util.c
fs/ufs/util.h
include/asm-alpha/floppy.h
include/asm-arm/floppy.h
include/asm-arm26/floppy.h
include/asm-generic/bug.h
include/asm-generic/percpu.h
include/asm-i386/floppy.h
include/asm-i386/mach-default/setup_arch.h [moved from include/asm-i386/mach-default/setup_arch_pre.h with 100% similarity]
include/asm-i386/mach-default/setup_arch_post.h [deleted file]
include/asm-i386/mach-visws/setup_arch.h [moved from include/asm-i386/mach-visws/setup_arch_pre.h with 100% similarity]
include/asm-i386/mach-visws/setup_arch_post.h [deleted file]
include/asm-i386/mach-voyager/setup_arch.h [moved from include/asm-i386/mach-voyager/setup_arch_pre.h with 97% similarity]
include/asm-i386/mach-voyager/setup_arch_post.h [deleted file]
include/asm-i386/setup.h
include/asm-i386/uaccess.h
include/asm-ia64/percpu.h
include/asm-m68k/amigaints.h
include/asm-m68k/apollohw.h
include/asm-m68k/atari_stdma.h
include/asm-m68k/atariints.h
include/asm-m68k/bvme6000hw.h
include/asm-m68k/cacheflush.h
include/asm-m68k/dma-mapping.h
include/asm-m68k/irq.h
include/asm-m68k/mac_oss.h
include/asm-m68k/machdep.h
include/asm-m68k/macintosh.h
include/asm-m68k/macints.h
include/asm-m68k/mvme147hw.h
include/asm-m68k/mvme16xhw.h
include/asm-m68k/scatterlist.h
include/asm-m68k/signal.h
include/asm-m68k/sun3ints.h
include/asm-m68k/traps.h
include/asm-m68k/uaccess.h
include/asm-mips/compat.h
include/asm-mips/mach-generic/floppy.h
include/asm-mips/mach-jazz/floppy.h
include/asm-parisc/floppy.h
include/asm-powerpc/backlight.h
include/asm-powerpc/floppy.h
include/asm-powerpc/percpu.h
include/asm-ppc/floppy.h
include/asm-s390/percpu.h
include/asm-sh/floppy.h
include/asm-sparc64/percpu.h
include/asm-x86_64/floppy.h
include/asm-x86_64/percpu.h
include/linux/acct.h
include/linux/bio.h
include/linux/console.h
include/linux/cpumask.h
include/linux/dvb/dmx.h
include/linux/eventpoll.h
include/linux/ext3_fs.h
include/linux/ext3_fs_i.h
include/linux/fb.h
include/linux/fcntl.h
include/linux/fuse.h
include/linux/hrtimer.h
include/linux/i2c-id.h
include/linux/ide.h
include/linux/kernel.h
include/linux/kthread.h
include/linux/ktime.h
include/linux/list.h
include/linux/loop.h
include/linux/migrate.h
include/linux/mm.h
include/linux/nbd.h
include/linux/parport.h
include/linux/pmu.h
include/linux/reboot.h
include/linux/resource.h
include/linux/rtc-v3020.h [new file with mode: 0644]
include/linux/rtc.h
include/linux/sched.h
include/linux/synclink.h
include/linux/sysctl.h
include/linux/ufs_fs.h
include/linux/ufs_fs_i.h
include/linux/videodev.h
include/linux/videodev2.h
include/media/cx2341x.h [new file with mode: 0644]
include/media/ir-common.h
include/media/ir-kbd-i2c.h
include/media/ovcamchip.h
include/media/pwc-ioctl.h [new file with mode: 0644]
include/media/saa7115.h
include/media/saa7146_vv.h
include/media/tuner.h
include/media/tvp5150.h [new file with mode: 0644]
include/media/v4l2-common.h
include/media/v4l2-dev.h [new file with mode: 0644]
include/media/video-buf-dvb.h
include/media/video-buf.h
include/sound/tea575x-tuner.h
init/Kconfig
kernel/acct.c
kernel/compat.c
kernel/exit.c
kernel/fork.c
kernel/hrtimer.c
kernel/kthread.c
kernel/module.c
kernel/power/Kconfig
kernel/power/disk.c
kernel/power/main.c
kernel/printk.c
kernel/sched.c
kernel/softirq.c
kernel/softlockup.c
kernel/stop_machine.c
kernel/sys.c
kernel/sysctl.c
kernel/timer.c
kernel/workqueue.c
lib/bitmap.c
lib/crc-ccitt.c
lib/crc16.c
lib/crc32.c
lib/idr.c
lib/libcrc32c.c
lib/radix-tree.c
lib/reed_solomon/reed_solomon.c
lib/vsprintf.c
mm/filemap.c
mm/filemap.h
mm/mempolicy.c
mm/migrate.c
mm/page_alloc.c
mm/pdflush.c
mm/readahead.c
mm/rmap.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/route.c
scripts/bloat-o-meter
scripts/checkstack.pl
scripts/kernel-doc
sound/oss/Kconfig
sound/oss/au1550_ac97.c
sound/oss/emu10k1/midi.c
sound/oss/msnd.c

diff --git a/CREDITS b/CREDITS
index 9bf714a1c7d97e92a634161c3538ee93e30f07d3..1d35f10ec3b2e51e984bf33e1bc4790c0c596417 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1573,12 +1573,8 @@ S: 160 00 Praha 6
 S: Czech Republic
 
 N: Niels Kristian Bech Jensen
-E: nkbj@image.dk
-W: http://www.image.dk/~nkbj
+E: nkbj1970@hotmail.com
 D: Miscellaneous kernel updates and fixes.
-S: Dr. Holsts Vej 34, lejl. 164
-S: DK-8230 Ã…byhøj
-S: Denmark
 
 N: Michael K. Johnson
 E: johnsonm@redhat.com
index 31b727ceb127b109838464b9137474c90a4355f6..3630a0d7695f91f98dfa0844370ca7af3048620a 100644 (file)
@@ -62,6 +62,8 @@
      <sect1><title>Internal Functions</title>
 !Ikernel/exit.c
 !Ikernel/signal.c
+!Iinclude/linux/kthread.h
+!Ekernel/kthread.c
      </sect1>
 
      <sect1><title>Kernel objects manipulation</title>
@@ -114,6 +116,29 @@ X!Ilib/string.c
      </sect1>
   </chapter>
 
+  <chapter id="kernel-lib">
+     <title>Basic Kernel Library Functions</title>
+
+     <para>
+       The Linux kernel provides more basic utility functions.
+     </para>
+
+     <sect1><title>Bitmap Operations</title>
+!Elib/bitmap.c
+!Ilib/bitmap.c
+     </sect1>
+
+     <sect1><title>Command-line Parsing</title>
+!Elib/cmdline.c
+     </sect1>
+
+     <sect1><title>CRC Functions</title>
+!Elib/crc16.c
+!Elib/crc32.c
+!Elib/crc-ccitt.c
+     </sect1>
+  </chapter>
+
   <chapter id="mm">
      <title>Memory Management in Linux</title>
      <sect1><title>The Slab Cache</title>
@@ -281,12 +306,13 @@ X!Ekernel/module.c
      <sect1><title>MTRR Handling</title>
 !Earch/i386/kernel/cpu/mtrr/main.c
      </sect1>
+
      <sect1><title>PCI Support Library</title>
 !Edrivers/pci/pci.c
 !Edrivers/pci/pci-driver.c
 !Edrivers/pci/remove.c
 !Edrivers/pci/pci-acpi.c
-<!-- kerneldoc does not understand to __devinit
+<!-- kerneldoc does not understand __devinit
 X!Edrivers/pci/search.c
  -->
 !Edrivers/pci/msi.c
@@ -315,6 +341,13 @@ X!Earch/i386/kernel/mca.c
      </sect1>
   </chapter>
 
+  <chapter id="firmware">
+     <title>Firmware Interfaces</title>
+     <sect1><title>DMI Interfaces</title>
+!Edrivers/firmware/dmi_scan.c
+     </sect1>
+  </chapter>
+
   <chapter id="devfs">
      <title>The Device File System</title>
 !Efs/devfs/base.c
@@ -403,7 +436,6 @@ X!Edrivers/pnp/system.c
      </sect1>
   </chapter>
 
-
   <chapter id="blkdev">
      <title>Block Devices</title>
 !Eblock/ll_rw_blk.c
@@ -414,6 +446,14 @@ X!Edrivers/pnp/system.c
 !Edrivers/char/misc.c
   </chapter>
 
+  <chapter id="parportdev">
+     <title>Parallel Port Devices</title>
+!Iinclude/linux/parport.h
+!Edrivers/parport/ieee1284.c
+!Edrivers/parport/share.c
+!Idrivers/parport/daisy.c
+  </chapter>
+
   <chapter id="viddev">
      <title>Video4Linux</title>
 !Edrivers/media/video/videodev.c
index 49e27cc19385385c25618d661566c13024a6c2fa..1d50cf0c905ef28d62d6e5eda83c6415721504a6 100644 (file)
@@ -144,9 +144,47 @@ over a rather long period of time, but improvements are always welcome!
        whether the increased speed is worth it.
 
 8.     Although synchronize_rcu() is a bit slower than is call_rcu(),
-       it usually results in simpler code.  So, unless update performance
-       is important or the updaters cannot block, synchronize_rcu()
-       should be used in preference to call_rcu().
+       it usually results in simpler code.  So, unless update
+       performance is critically important or the updaters cannot block,
+       synchronize_rcu() should be used in preference to call_rcu().
+
+       An especially important property of the synchronize_rcu()
+       primitive is that it automatically self-limits: if grace periods
+       are delayed for whatever reason, then the synchronize_rcu()
+       primitive will correspondingly delay updates.  In contrast,
+       code using call_rcu() should explicitly limit update rate in
+       cases where grace periods are delayed, as failing to do so can
+       result in excessive realtime latencies or even OOM conditions.
+
+       Ways of gaining this self-limiting property when using call_rcu()
+       include:
+
+       a.      Keeping a count of the number of data-structure elements
+               used by the RCU-protected data structure, including those
+               waiting for a grace period to elapse.  Enforce a limit
+               on this number, stalling updates as needed to allow
+               previously deferred frees to complete.
+
+               Alternatively, limit only the number awaiting deferred
+               free rather than the total number of elements.
+
+       b.      Limiting update rate.  For example, if updates occur only
+               once per hour, then no explicit rate limiting is required,
+               unless your system is already badly broken.  The dcache
+               subsystem takes this approach -- updates are guarded
+               by a global lock, limiting their rate.
+
+       c.      Trusted update -- if updates can only be done manually by
+               superuser or some other trusted user, then it might not
+               be necessary to automatically limit them.  The theory
+               here is that superuser already has lots of ways to crash
+               the machine.
+
+       d.      Use call_rcu_bh() rather than call_rcu(), in order to take
+               advantage of call_rcu_bh()'s faster grace periods.
+
+       e.      Periodically invoke synchronize_rcu(), permitting a limited
+               number of updates per grace period.
 
 9.     All RCU list-traversal primitives, which include
        list_for_each_rcu(), list_for_each_entry_rcu(),
index 6e459420ee9fba72f2bf0c1828972403cfd1882e..4f41a60e5111b1900d749018cda46182a5c000f3 100644 (file)
@@ -184,7 +184,17 @@ synchronize_rcu()
        blocking, it registers a function and argument which are invoked
        after all ongoing RCU read-side critical sections have completed.
        This callback variant is particularly useful in situations where
-       it is illegal to block.
+       it is illegal to block or where update-side performance is
+       critically important.
+
+       However, the call_rcu() API should not be used lightly, as use
+       of the synchronize_rcu() API generally results in simpler code.
+       In addition, the synchronize_rcu() API has the nice property
+       of automatically limiting update rate should grace periods
+       be delayed.  This property results in system resilience in face
+       of denial-of-service attacks.  Code using call_rcu() should limit
+       update rate in order to gain this same sort of resilience.  See
+       checklist.txt for some approaches to limiting the update rate.
 
 rcu_assign_pointer()
 
index b2f593fc76ca736a10941a5983dbbab3c8973afe..4aaf68fafebe78fe67933fffab7fe96bfb5a8bfe 100644 (file)
@@ -3,7 +3,7 @@
 
             Maintained by Torben Mathiasen <device@lanana.org>
 
-                     Last revised: 01 March 2006
+                     Last revised: 15 May 2006
 
 This list is the Linux Device List, the official registry of allocated
 device numbers and /dev directory nodes for the Linux operating
@@ -2791,6 +2791,7 @@ Your cooperation is appreciated.
                 170 = /dev/ttyNX0              Hilscher netX serial port 0
                    ...
                 185 = /dev/ttyNX15             Hilscher netX serial port 15
+                186 = /dev/ttyJ0               JTAG1 DCC protocol based serial port emulation
 
 205 char       Low-density serial ports (alternate device)
                  0 = /dev/culu0                Callout device for ttyLU0
@@ -3108,6 +3109,10 @@ Your cooperation is appreciated.
                  ...
                240 = /dev/rfdp         16th RFD FTL layer
 
+257 char       Phoenix Technologies Cryptographic Services Driver
+                 0 = /dev/ptlsec       Crypto Services Driver
+
+
 
  ****  ADDITIONAL /dev DIRECTORY ENTRIES
 
index 33f74310d161bac64f1c4d997842c5769b64759f..a584f05403a412e778cf359e84d3690d5a22d1e4 100644 (file)
@@ -18,6 +18,14 @@ Non-privileged mount (or user mount):
   user.  NOTE: this is not the same as mounts allowed with the "user"
   option in /etc/fstab, which is not discussed here.
 
+Filesystem connection:
+
+  A connection between the filesystem daemon and the kernel.  The
+  connection exists until either the daemon dies, or the filesystem is
+  umounted.  Note that detaching (or lazy umounting) the filesystem
+  does _not_ break the connection, in this case it will exist until
+  the last reference to the filesystem is released.
+
 Mount owner:
 
   The user who does the mounting.
@@ -86,16 +94,20 @@ Mount options
   The default is infinite.  Note that the size of read requests is
   limited anyway to 32 pages (which is 128kbyte on i386).
 
-Sysfs
-~~~~~
+Control filesystem
+~~~~~~~~~~~~~~~~~~
+
+There's a control filesystem for FUSE, which can be mounted by:
 
-FUSE sets up the following hierarchy in sysfs:
+  mount -t fusectl none /sys/fs/fuse/connections
 
-  /sys/fs/fuse/connections/N/
+Mounting it under the '/sys/fs/fuse/connections' directory makes it
+backwards compatible with earlier versions.
 
-where N is an increasing number allocated to each new connection.
+Under the fuse control filesystem each connection has a directory
+named by a unique number.
 
-For each connection the following attributes are defined:
+For each connection the following files exist within this directory:
 
  'waiting'
 
@@ -110,7 +122,47 @@ For each connection the following attributes are defined:
   connection.  This means that all waiting requests will be aborted an
   error returned for all aborted and new requests.
 
-Only a privileged user may read or write these attributes.
+Only the owner of the mount may read or write these files.
+
+Interrupting filesystem operations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If a process issuing a FUSE filesystem request is interrupted, the
+following will happen:
+
+  1) If the request is not yet sent to userspace AND the signal is
+     fatal (SIGKILL or unhandled fatal signal), then the request is
+     dequeued and returns immediately.
+
+  2) If the request is not yet sent to userspace AND the signal is not
+     fatal, then an 'interrupted' flag is set for the request.  When
+     the request has been successfully transfered to userspace and
+     this flag is set, an INTERRUPT request is queued.
+
+  3) If the request is already sent to userspace, then an INTERRUPT
+     request is queued.
+
+INTERRUPT requests take precedence over other requests, so the
+userspace filesystem will receive queued INTERRUPTs before any others.
+
+The userspace filesystem may ignore the INTERRUPT requests entirely,
+or may honor them by sending a reply to the _original_ request, with
+the error set to EINTR.
+
+It is also possible that there's a race between processing the
+original request and it's INTERRUPT request.  There are two possibilities:
+
+  1) The INTERRUPT request is processed before the original request is
+     processed
+
+  2) The INTERRUPT request is processed after the original request has
+     been answered
+
+If the filesystem cannot find the original request, it should wait for
+some timeout and/or a number of new requests to arrive, after which it
+should reply to the INTERRUPT request with an EAGAIN error.  In case
+1) the INTERRUPT request will be requeued.  In case 2) the INTERRUPT
+reply will be ignored.
 
 Aborting a filesystem connection
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -139,8 +191,8 @@ the filesystem.  There are several ways to do this:
   - Use forced umount (umount -f).  Works in all cases but only if
     filesystem is still attached (it hasn't been lazy unmounted)
 
-  - Abort filesystem through the sysfs interface.  Most powerful
-    method, always works.
+  - Abort filesystem through the FUSE control filesystem.  Most
+    powerful method, always works.
 
 How do non-privileged mounts work?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -304,25 +356,7 @@ Scenario 1 -  Simple deadlock
  |                                    |     for "file"]
  |                                    |    *DEADLOCK*
 
-The solution for this is to allow requests to be interrupted while
-they are in userspace:
-
- |      [interrupted by signal]       |
- |    <fuse_unlink()                  |
- |    [release semaphore]             |    [semaphore acquired]
- |  <sys_unlink()                     |
- |                                    |    >fuse_unlink()
- |                                    |      [queue req on fc->pending]
- |                                    |      [wake up fc->waitq]
- |                                    |      [sleep on req->waitq]
-
-If the filesystem daemon was single threaded, this will stop here,
-since there's no other thread to dequeue and execute the request.
-In this case the solution is to kill the FUSE daemon as well.  If
-there are multiple serving threads, you just have to kill them as
-long as any remain.
-
-Moral: a filesystem which deadlocks, can soon find itself dead.
+The solution for this is to allow the filesystem to be aborted.
 
 Scenario 2 - Tricky deadlock
 ----------------------------
@@ -355,24 +389,14 @@ but is caused by a pagefault.
  |                                    |           [lock page]
  |                                    |           * DEADLOCK *
 
-Solution is again to let the the request be interrupted (not
-elaborated further).
-
-An additional problem is that while the write buffer is being
-copied to the request, the request must not be interrupted.  This
-is because the destination address of the copy may not be valid
-after the request is interrupted.
-
-This is solved with doing the copy atomically, and allowing
-interruption while the page(s) belonging to the write buffer are
-faulted with get_user_pages().  The 'req->locked' flag indicates
-when the copy is taking place, and interruption is delayed until
-this flag is unset.
+Solution is basically the same as above.
 
-Scenario 3 - Tricky deadlock with asynchronous read
----------------------------------------------------
+An additional problem is that while the write buffer is being copied
+to the request, the request must not be interrupted/aborted.  This is
+because the destination address of the copy may not be valid after the
+request has returned.
 
-The same situation as above, except thread-1 will wait on page lock
-and hence it will be uninterruptible as well.  The solution is to
-abort the connection with forced umount (if mount is attached) or
-through the abort attribute in sysfs.
+This is solved with doing the copy atomically, and allowing abort
+while the page(s) belonging to the write buffer are faulted with
+get_user_pages().  The 'req->locked' flag indicates when the copy is
+taking place, and abort is delayed until this flag is unset.
index 60ab61e54e8ab9dc05bc191f34fb17d1be5b01c3..25981e2e51be785dca94c029f93d8040e67741ac 100644 (file)
@@ -70,11 +70,13 @@ tmpfs mounts.  See Documentation/filesystems/tmpfs.txt for more information.
 What is rootfs?
 ---------------
 
-Rootfs is a special instance of ramfs, which is always present in 2.6 systems.
-(It's used internally as the starting and stopping point for searches of the
-kernel's doubly-linked list of mount points.)
+Rootfs is a special instance of ramfs (or tmpfs, if that's enabled), which is
+always present in 2.6 systems.  You can't unmount rootfs for approximately the
+same reason you can't kill the init process; rather than having special code
+to check for and handle an empty list, it's smaller and simpler for the kernel
+to just make sure certain lists can't become empty.
 
-Most systems just mount another filesystem over it and ignore it.  The
+Most systems just mount another filesystem over rootfs and ignore it.  The
 amount of space an empty instance of ramfs takes up is tiny.
 
 What is initramfs?
@@ -92,14 +94,16 @@ out of that.
 
 All this differs from the old initrd in several ways:
 
-  - The old initrd was a separate file, while the initramfs archive is linked
-    into the linux kernel image.  (The directory linux-*/usr is devoted to
-    generating this archive during the build.)
+  - The old initrd was always a separate file, while the initramfs archive is
+    linked into the linux kernel image.  (The directory linux-*/usr is devoted
+    to generating this archive during the build.)
 
   - The old initrd file was a gzipped filesystem image (in some file format,
-    such as ext2, that had to be built into the kernel), while the new
+    such as ext2, that needed a driver built into the kernel), while the new
     initramfs archive is a gzipped cpio archive (like tar only simpler,
-    see cpio(1) and Documentation/early-userspace/buffer-format.txt).
+    see cpio(1) and Documentation/early-userspace/buffer-format.txt).  The
+    kernel's cpio extraction code is not only extremely small, it's also
+    __init data that can be discarded during the boot process.
 
   - The program run by the old initrd (which was called /initrd, not /init) did
     some setup and then returned to the kernel, while the init program from
@@ -124,13 +128,14 @@ Populating initramfs:
 
 The 2.6 kernel build process always creates a gzipped cpio format initramfs
 archive and links it into the resulting kernel binary.  By default, this
-archive is empty (consuming 134 bytes on x86).  The config option
-CONFIG_INITRAMFS_SOURCE (for some reason buried under devices->block devices
-in menuconfig, and living in usr/Kconfig) can be used to specify a source for
-the initramfs archive, which will automatically be incorporated into the
-resulting binary.  This option can point to an existing gzipped cpio archive, a
-directory containing files to be archived, or a text file specification such
-as the following example:
+archive is empty (consuming 134 bytes on x86).
+
+The config option CONFIG_INITRAMFS_SOURCE (for some reason buried under
+devices->block devices in menuconfig, and living in usr/Kconfig) can be used
+to specify a source for the initramfs archive, which will automatically be
+incorporated into the resulting binary.  This option can point to an existing
+gzipped cpio archive, a directory containing files to be archived, or a text
+file specification such as the following example:
 
   dir /dev 755 0 0
   nod /dev/console 644 0 0 c 5 1
@@ -146,23 +151,84 @@ as the following example:
 Run "usr/gen_init_cpio" (after the kernel build) to get a usage message
 documenting the above file format.
 
-One advantage of the text file is that root access is not required to
+One advantage of the configuration file is that root access is not required to
 set permissions or create device nodes in the new archive.  (Note that those
 two example "file" entries expect to find files named "init.sh" and "busybox" in
 a directory called "initramfs", under the linux-2.6.* directory.  See
 Documentation/early-userspace/README for more details.)
 
-The kernel does not depend on external cpio tools, gen_init_cpio is created
-from usr/gen_init_cpio.c which is entirely self-contained, and the kernel's
-boot-time extractor is also (obviously) self-contained.  However, if you _do_
-happen to have cpio installed, the following command line can extract the
-generated cpio image back into its component files:
+The kernel does not depend on external cpio tools.  If you specify a
+directory instead of a configuration file, the kernel's build infrastructure
+creates a configuration file from that directory (usr/Makefile calls
+scripts/gen_initramfs_list.sh), and proceeds to package up that directory
+using the config file (by feeding it to usr/gen_init_cpio, which is created
+from usr/gen_init_cpio.c).  The kernel's build-time cpio creation code is
+entirely self-contained, and the kernel's boot-time extractor is also
+(obviously) self-contained.
+
+The one thing you might need external cpio utilities installed for is creating
+or extracting your own preprepared cpio files to feed to the kernel build
+(instead of a config file or directory).
+
+The following command line can extract a cpio image (either by the above script
+or by the kernel build) back into its component files:
 
   cpio -i -d -H newc -F initramfs_data.cpio --no-absolute-filenames
 
+The following shell script can create a prebuilt cpio archive you can
+use in place of the above config file:
+
+  #!/bin/sh
+
+  # Copyright 2006 Rob Landley <rob@landley.net> and TimeSys Corporation.
+  # Licensed under GPL version 2
+
+  if [ $# -ne 2 ]
+  then
+    echo "usage: mkinitramfs directory imagename.cpio.gz"
+    exit 1
+  fi
+
+  if [ -d "$1" ]
+  then
+    echo "creating $2 from $1"
+    (cd "$1"; find . | cpio -o -H newc | gzip) > "$2"
+  else
+    echo "First argument must be a directory"
+    exit 1
+  fi
+
+Note: The cpio man page contains some bad advice that will break your initramfs
+archive if you follow it.  It says "A typical way to generate the list
+of filenames is with the find command; you should give find the -depth option
+to minimize problems with permissions on directories that are unwritable or not
+searchable."  Don't do this when creating initramfs.cpio.gz images, it won't
+work.  The Linux kernel cpio extractor won't create files in a directory that
+doesn't exist, so the directory entries must go before the files that go in
+those directories.  The above script gets them in the right order.
+
+External initramfs images:
+--------------------------
+
+If the kernel has initrd support enabled, an external cpio.gz archive can also
+be passed into a 2.6 kernel in place of an initrd.  In this case, the kernel
+will autodetect the type (initramfs, not initrd) and extract the external cpio
+archive into rootfs before trying to run /init.
+
+This has the memory efficiency advantages of initramfs (no ramdisk block
+device) but the separate packaging of initrd (which is nice if you have
+non-GPL code you'd like to run from initramfs, without conflating it with
+the GPL licensed Linux kernel binary).
+
+It can also be used to supplement the kernel's built-in initamfs image.  The
+files in the external archive will overwrite any conflicting files in
+the built-in initramfs archive.  Some distributors also prefer to customize
+a single kernel image with task-specific initramfs images, without recompiling.
+
 Contents of initramfs:
 ----------------------
 
+An initramfs archive is a complete self-contained root filesystem for Linux.
 If you don't already understand what shared libraries, devices, and paths
 you need to get a minimal root filesystem up and running, here are some
 references:
@@ -176,13 +242,36 @@ code against, along with some related utilities.  It is BSD licensed.
 
 I use uClibc (http://www.uclibc.org) and busybox (http://www.busybox.net)
 myself.  These are LGPL and GPL, respectively.  (A self-contained initramfs
-package is planned for the busybox 1.2 release.)
+package is planned for the busybox 1.3 release.)
 
 In theory you could use glibc, but that's not well suited for small embedded
 uses like this.  (A "hello world" program statically linked against glibc is
 over 400k.  With uClibc it's 7k.  Also note that glibc dlopens libnss to do
 name lookups, even when otherwise statically linked.)
 
+A good first step is to get initramfs to run a statically linked "hello world"
+program as init, and test it under an emulator like qemu (www.qemu.org) or
+User Mode Linux, like so:
+
+  cat > hello.c << EOF
+  #include <stdio.h>
+  #include <unistd.h>
+
+  int main(int argc, char *argv[])
+  {
+    printf("Hello world!\n");
+    sleep(999999999);
+  }
+  EOF
+  gcc -static hello2.c -o init
+  echo init | cpio -o -H newc | gzip > test.cpio.gz
+  # Testing external initramfs using the initrd loading mechanism.
+  qemu -kernel /boot/vmlinuz -initrd test.cpio.gz /dev/zero
+
+When debugging a normal root filesystem, it's nice to be able to boot with
+"init=/bin/sh".  The initramfs equivalent is "rdinit=/bin/sh", and it's
+just as useful.
+
 Why cpio rather than tar?
 -------------------------
 
@@ -241,7 +330,7 @@ the above threads) is:
 Future directions:
 ------------------
 
-Today (2.6.14), initramfs is always compiled in, but not always used.  The
+Today (2.6.16), initramfs is always compiled in, but not always used.  The
 kernel falls back to legacy boot code that is reached only if initramfs does
 not contain an /init program.  The fallback is legacy code, there to ensure a
 smooth transition and allowing early boot functionality to gradually move to
@@ -258,8 +347,9 @@ and so on.
 
 This kind of complexity (which inevitably includes policy) is rightly handled
 in userspace.  Both klibc and busybox/uClibc are working on simple initramfs
-packages to drop into a kernel build, and when standard solutions are ready
-and widely deployed, the kernel's legacy early boot code will become obsolete
-and a candidate for the feature removal schedule.
+packages to drop into a kernel build.
 
-But that's a while off yet.
+The klibc package has now been accepted into Andrew Morton's 2.6.17-mm tree.
+The kernel's current early boot code (partition detection, etc) will probably
+be migrated into a default initramfs, automatically created and used by the
+kernel build.
index 212cf3c21abf8849e39b5964607263e23da8e77f..08bafa8c1caa91058a2d1c1eb91128e70668781d 100644 (file)
-Documentation for kdump - the kexec-based crash dumping solution
+================================================================
+Documentation for Kdump - The kexec-based Crash Dumping Solution
 ================================================================
 
-DESIGN
-======
+This document includes overview, setup and installation, and analysis
+information.
 
-Kdump uses kexec to reboot to a second kernel whenever a dump needs to be
-taken. This second kernel is booted with very little memory. The first kernel
-reserves the section of memory that the second kernel uses. This ensures that
-on-going DMA from the first kernel does not corrupt the second kernel.
+Overview
+========
 
-All the necessary information about Core image is encoded in ELF format and
-stored in reserved area of memory before crash. Physical address of start of
-ELF header is passed to new kernel through command line parameter elfcorehdr=.
+Kdump uses kexec to quickly boot to a dump-capture kernel whenever a
+dump of the system kernel's memory needs to be taken (for example, when
+the system panics). The system kernel's memory image is preserved across
+the reboot and is accessible to the dump-capture kernel.
 
-On i386, the first 640 KB of physical memory is needed to boot, irrespective
-of where the kernel loads. Hence, this region is backed up by kexec just before
-rebooting into the new kernel.
+You can use common Linux commands, such as cp and scp, to copy the
+memory image to a dump file on the local disk, or across the network to
+a remote system.
 
-In the second kernel, "old memory" can be accessed in two ways.
+Kdump and kexec are currently supported on the x86, x86_64, and ppc64
+architectures.
 
-- The first one is through a /dev/oldmem device interface. A capture utility
-  can read the device file and write out the memory in raw format. This is raw
-  dump of memory and analysis/capture tool should be intelligent enough to
-  determine where to look for the right information. ELF headers (elfcorehdr=)
-  can become handy here.
+When the system kernel boots, it reserves a small section of memory for
+the dump-capture kernel. This ensures that ongoing Direct Memory Access
+(DMA) from the system kernel does not corrupt the dump-capture kernel.
+The kexec -p command loads the dump-capture kernel into this reserved
+memory.
 
-- The second interface is through /proc/vmcore. This exports the dump as an ELF
-  format file which can be written out using any file copy command
-  (cp, scp, etc). Further, gdb can be used to perform limited debugging on
-  the dump file. This method ensures methods ensure that there is correct
-  ordering of the dump pages (corresponding to the first 640 KB that has been
-  relocated).
+On x86 machines, the first 640 KB of physical memory is needed to boot,
+regardless of where the kernel loads. Therefore, kexec backs up this
+region just before rebooting into the dump-capture kernel.
 
-SETUP
-=====
+All of the necessary information about the system kernel's core image is
+encoded in the ELF format, and stored in a reserved area of memory
+before a crash. The physical address of the start of the ELF header is
+passed to the dump-capture kernel through the elfcorehdr= boot
+parameter.
+
+With the dump-capture kernel, you can access the memory image, or "old
+memory," in two ways:
+
+- Through a /dev/oldmem device interface. A capture utility can read the
+  device file and write out the memory in raw format. This is a raw dump
+  of memory. Analysis and capture tools must be intelligent enough to
+  determine where to look for the right information.
+
+- Through /proc/vmcore. This exports the dump as an ELF-format file that
+  you can write out using file copy commands such as cp or scp. Further,
+  you can use analysis tools such as the GNU Debugger (GDB) and the Crash
+  tool to debug the dump file. This method ensures that the dump pages are
+  correctly ordered.
+
+
+Setup and Installation
+======================
+
+Install kexec-tools and the Kdump patch
+---------------------------------------
+
+1) Login as the root user.
+
+2) Download the kexec-tools user-space package from the following URL:
+
+   http://www.xmission.com/~ebiederm/files/kexec/kexec-tools-1.101.tar.gz
+
+3) Unpack the tarball with the tar command, as follows:
+
+   tar xvpzf kexec-tools-1.101.tar.gz
+
+4) Download the latest consolidated Kdump patch from the following URL:
+
+   http://lse.sourceforge.net/kdump/
+
+   (This location is being used until all the user-space Kdump patches
+   are integrated with the kexec-tools package.)
+
+5) Change to the kexec-tools-1.101 directory, as follows:
+
+   cd kexec-tools-1.101
+
+6) Apply the consolidated patch to the kexec-tools-1.101 source tree
+   with the patch command, as follows. (Modify the path to the downloaded
+   patch as necessary.)
+
+   patch -p1 < /path-to-kdump-patch/kexec-tools-1.101-kdump.patch
+
+7) Configure the package, as follows:
+
+   ./configure
+
+8) Compile the package, as follows:
+
+   make
+
+9) Install the package, as follows:
+
+   make install
+
+
+Download and build the system and dump-capture kernels
+------------------------------------------------------
+
+Download the mainline (vanilla) kernel source code (2.6.13-rc1 or newer)
+from http://www.kernel.org. Two kernels must be built: a system kernel
+and a dump-capture kernel. Use the following steps to configure these
+kernels with the necessary kexec and Kdump features:
+
+System kernel
+-------------
+
+1) Enable "kexec system call" in "Processor type and features."
+
+   CONFIG_KEXEC=y
+
+2) Enable "sysfs file system support" in "Filesystem" -> "Pseudo
+   filesystems." This is usually enabled by default.
+
+   CONFIG_SYSFS=y
+
+   Note that "sysfs file system support" might not appear in the "Pseudo
+   filesystems" menu if "Configure standard kernel features (for small
+   systems)" is not enabled in "General Setup." In this case, check the
+   .config file itself to ensure that sysfs is turned on, as follows:
+
+   grep 'CONFIG_SYSFS' .config
+
+3) Enable "Compile the kernel with debug info" in "Kernel hacking."
+
+   CONFIG_DEBUG_INFO=Y
+
+   This causes the kernel to be built with debug symbols. The dump
+   analysis tools require a vmlinux with debug symbols in order to read
+   and analyze a dump file.
+
+4) Make and install the kernel and its modules. Update the boot loader
+   (such as grub, yaboot, or lilo) configuration files as necessary.
+
+5) Boot the system kernel with the boot parameter "crashkernel=Y@X",
+   where Y specifies how much memory to reserve for the dump-capture kernel
+   and X specifies the beginning of this reserved memory. For example,
+   "crashkernel=64M@16M" tells the system kernel to reserve 64 MB of memory
+   starting at physical address 0x01000000 for the dump-capture kernel.
+
+   On x86 and x86_64, use "crashkernel=64M@16M".
+
+   On ppc64, use "crashkernel=128M@32M".
+
+
+The dump-capture kernel
+-----------------------
 
-1) Download the upstream kexec-tools userspace package from
-   http://www.xmission.com/~ebiederm/files/kexec/kexec-tools-1.101.tar.gz.
-
-   Apply the latest consolidated kdump patch on top of kexec-tools-1.101
-   from http://lse.sourceforge.net/kdump/. This arrangment has been made
-   till all the userspace patches supporting kdump are integrated with
-   upstream kexec-tools userspace.
-
-2) Download and build the appropriate (2.6.13-rc1 onwards) vanilla kernels.
-   Two kernels need to be built in order to get this feature working.
-   Following are the steps to properly configure the two kernels specific
-   to kexec and kdump features:
-
-  A) First kernel or regular kernel:
-  ----------------------------------
-   a) Enable "kexec system call" feature (in Processor type and features).
-      CONFIG_KEXEC=y
-   b) Enable "sysfs file system support" (in Pseudo filesystems).
-      CONFIG_SYSFS=y
-   c) make
-   d) Boot into first kernel with the command line parameter "crashkernel=Y@X".
-      Use appropriate values for X and Y. Y denotes how much memory to reserve
-      for the second kernel, and X denotes at what physical address the
-      reserved memory section starts. For example: "crashkernel=64M@16M".
-
-
-  B) Second kernel or dump capture kernel:
-  ---------------------------------------
-   a) For i386 architecture enable Highmem support
-      CONFIG_HIGHMEM=y
-   b) Enable "kernel crash dumps" feature (under "Processor type and features")
-      CONFIG_CRASH_DUMP=y
-   c) Make sure a suitable value for "Physical address where the kernel is
-      loaded" (under "Processor type and features"). By default this value
-      is 0x1000000 (16MB) and it should be same as X (See option d above),
-      e.g., 16 MB or 0x1000000.
-      CONFIG_PHYSICAL_START=0x1000000
-   d) Enable "/proc/vmcore support" (Optional, under "Pseudo filesystems").
-      CONFIG_PROC_VMCORE=y
-
-3) After booting to regular kernel or first kernel, load the second kernel
-   using the following command:
-
-   kexec -p <second-kernel> --args-linux --elf32-core-headers
-   --append="root=<root-dev> init 1 irqpoll maxcpus=1"
-
-   Notes:
-   ======
-     i) <second-kernel> has to be a vmlinux image ie uncompressed elf image.
-        bzImage will not work, as of now.
-    ii) --args-linux has to be speicfied as if kexec it loading an elf image,
-        it needs to know that the arguments supplied are of linux type.
-   iii) By default ELF headers are stored in ELF64 format to support systems
-        with more than 4GB memory. Option --elf32-core-headers forces generation
-        of ELF32 headers. The reason for this option being, as of now gdb can
-        not open vmcore file with ELF64 headers on a 32 bit systems. So ELF32
-        headers can be used if one has non-PAE systems and hence memory less
-        than 4GB.
-    iv) Specify "irqpoll" as command line parameter. This reduces driver
-         initialization failures in second kernel due to shared interrupts.
-     v) <root-dev> needs to be specified in a format corresponding to the root
-        device name in the output of mount command.
-    vi) If you have built the drivers required to mount root file system as
-        modules in <second-kernel>, then, specify
-        --initrd=<initrd-for-second-kernel>.
-   vii) Specify maxcpus=1 as, if during first kernel run, if panic happens on
-        non-boot cpus, second kernel doesn't seem to be boot up all the cpus.
-        The other option is to always built the second kernel without SMP
-        support ie CONFIG_SMP=n
-
-4) After successfully loading the second kernel as above, if a panic occurs
-   system reboots into the second kernel. A module can be written to force
-   the panic or "ALT-SysRq-c" can be used initiate a crash dump for testing
-   purposes.
-
-5) Once the second kernel has booted, write out the dump file using
+1) Under "General setup," append "-kdump" to the current string in
+   "Local version."
+
+2) On x86, enable high memory support under "Processor type and
+   features":
+
+   CONFIG_HIGHMEM64G=y
+   or
+   CONFIG_HIGHMEM4G
+
+3) On x86 and x86_64, disable symmetric multi-processing support
+   under "Processor type and features":
+
+   CONFIG_SMP=n
+   (If CONFIG_SMP=y, then specify maxcpus=1 on the kernel command line
+   when loading the dump-capture kernel, see section "Load the Dump-capture
+   Kernel".)
+
+4) On ppc64, disable NUMA support and enable EMBEDDED support:
+
+   CONFIG_NUMA=n
+   CONFIG_EMBEDDED=y
+   CONFIG_EEH=N for the dump-capture kernel
+
+5) Enable "kernel crash dumps" support under "Processor type and
+   features":
+
+   CONFIG_CRASH_DUMP=y
+
+6) Use a suitable value for "Physical address where the kernel is
+   loaded" (under "Processor type and features"). This only appears when
+   "kernel crash dumps" is enabled. By default this value is 0x1000000
+   (16MB). It should be the same as X in the "crashkernel=Y@X" boot
+   parameter discussed above.
+
+   On x86 and x86_64, use "CONFIG_PHYSICAL_START=0x1000000".
+
+   On ppc64 the value is automatically set at 32MB when
+   CONFIG_CRASH_DUMP is set.
+
+6) Optionally enable "/proc/vmcore support" under "Filesystems" ->
+   "Pseudo filesystems".
+
+   CONFIG_PROC_VMCORE=y
+   (CONFIG_PROC_VMCORE is set by default when CONFIG_CRASH_DUMP is selected.)
+
+7) Make and install the kernel and its modules. DO NOT add this kernel
+   to the boot loader configuration files.
+
+
+Load the Dump-capture Kernel
+============================
+
+After booting to the system kernel, load the dump-capture kernel using
+the following command:
+
+   kexec -p <dump-capture-kernel> \
+   --initrd=<initrd-for-dump-capture-kernel> --args-linux \
+   --append="root=<root-dev> init 1 irqpoll"
+
+
+Notes on loading the dump-capture kernel:
+
+* <dump-capture-kernel> must be a vmlinux image (that is, an
+  uncompressed ELF image). bzImage does not work at this time.
+
+* By default, the ELF headers are stored in ELF64 format to support
+  systems with more than 4GB memory. The --elf32-core-headers option can
+  be used to force the generation of ELF32 headers. This is necessary
+  because GDB currently cannot open vmcore files with ELF64 headers on
+  32-bit systems. ELF32 headers can be used on non-PAE systems (that is,
+  less than 4GB of memory).
+
+* The "irqpoll" boot parameter reduces driver initialization failures
+  due to shared interrupts in the dump-capture kernel.
+
+* You must specify <root-dev> in the format corresponding to the root
+  device name in the output of mount command.
+
+* "init 1" boots the dump-capture kernel into single-user mode without
+  networking. If you want networking, use "init 3."
+
+
+Kernel Panic
+============
+
+After successfully loading the dump-capture kernel as previously
+described, the system will reboot into the dump-capture kernel if a
+system crash is triggered.  Trigger points are located in panic(),
+die(), die_nmi() and in the sysrq handler (ALT-SysRq-c).
+
+The following conditions will execute a crash trigger point:
+
+If a hard lockup is detected and "NMI watchdog" is configured, the system
+will boot into the dump-capture kernel ( die_nmi() ).
+
+If die() is called, and it happens to be a thread with pid 0 or 1, or die()
+is called inside interrupt context or die() is called and panic_on_oops is set,
+the system will boot into the dump-capture kernel.
+
+On powererpc systems when a soft-reset is generated, die() is called by all cpus and the system system will boot into the dump-capture kernel.
+
+For testing purposes, you can trigger a crash by using "ALT-SysRq-c",
+"echo c > /proc/sysrq-trigger or write a module to force the panic.
+
+Write Out the Dump File
+=======================
+
+After the dump-capture kernel is booted, write out the dump file with
+the following command:
 
    cp /proc/vmcore <dump-file>
 
-   Dump memory can also be accessed as a /dev/oldmem device for a linear/raw
-   view.  To create the device, type:
+You can also access dumped memory as a /dev/oldmem device for a linear
+and raw view. To create the device, use the following command:
 
-   mknod /dev/oldmem c 1 12
+    mknod /dev/oldmem c 1 12
 
-   Use "dd" with suitable options for count, bs and skip to access specific
-   portions of the dump.
+Use the dd command with suitable options for count, bs, and skip to
+access specific portions of the dump.
 
-   Entire memory:  dd if=/dev/oldmem of=oldmem.001
+To see the entire memory, use the following command:
 
+   dd if=/dev/oldmem of=oldmem.001
 
-ANALYSIS
+
+Analysis
 ========
-Limited analysis can be done using gdb on the dump file copied out of
-/proc/vmcore. Use vmlinux built with -g and run
 
-  gdb vmlinux <dump-file>
+Before analyzing the dump image, you should reboot into a stable kernel.
+
+You can do limited analysis using GDB on the dump file copied out of
+/proc/vmcore. Use the debug vmlinux built with -g and run the following
+command:
+
+   gdb vmlinux <dump-file>
 
-Stack trace for the task on processor 0, register display, memory display
-work fine.
+Stack trace for the task on processor 0, register display, and memory
+display work fine.
 
-Note: gdb cannot analyse core files generated in ELF64 format for i386.
+Note: GDB cannot analyze core files generated in ELF64 format for x86.
+On systems with a maximum of 4GB of memory, you can generate
+ELF32-format headers using the --elf32-core-headers kernel option on the
+dump kernel.
 
-Latest "crash" (crash-4.0-2.18) as available on Dave Anderson's site
-http://people.redhat.com/~anderson/ works well with kdump format.
+You can also use the Crash utility to analyze dump files in Kdump
+format. Crash is available on Dave Anderson's site at the following URL:
 
+   http://people.redhat.com/~anderson/
+
+
+To Do
+=====
 
-TODO
-====
-1) Provide a kernel pages filtering mechanism so that core file size is not
-   insane on systems having huge memory banks.
-2) Relocatable kernel can help in maintaining multiple kernels for crashdump
-   and same kernel as the first kernel can be used to capture the dump.
+1) Provide a kernel pages filtering mechanism, so core file size is not
+   extreme on systems with huge memory banks.
 
+2) Relocatable kernel can help in maintaining multiple kernels for
+   crash_dump, and the same kernel as the system kernel can be used to
+   capture the dump.
 
-CONTACT
+
+Contact
 =======
+
 Vivek Goyal (vgoyal@in.ibm.com)
 Maneesh Soni (maneesh@in.ibm.com)
+
+
+Trademark
+=========
+
+Linux is a trademark of Linus Torvalds in the United States, other
+countries, or both.
index 4710845dbac4fb663e35fcf0056499614a06e56b..cf0d5416a4c39271aa572188647a7d30de93806a 100644 (file)
@@ -262,9 +262,14 @@ What is required is some way of intervening to instruct the compiler and the
 CPU to restrict the order.
 
 Memory barriers are such interventions.  They impose a perceived partial
-ordering between the memory operations specified on either side of the barrier.
-They request that the sequence of memory events generated appears to other
-parts of the system as if the barrier is effective on that CPU.
+ordering over the memory operations on either side of the barrier.
+
+Such enforcement is important because the CPUs and other devices in a system
+can use a variety of tricks to improve performance - including reordering,
+deferral and combination of memory operations; speculative loads; speculative
+branch prediction and various types of caching.  Memory barriers are used to
+override or suppress these tricks, allowing the code to sanely control the
+interaction of multiple CPUs and/or devices.
 
 
 VARIETIES OF MEMORY BARRIER
@@ -282,7 +287,7 @@ Memory barriers come in four basic varieties:
      A write barrier is a partial ordering on stores only; it is not required
      to have any effect on loads.
 
-     A CPU can be viewed as as commiting a sequence of store operations to the
+     A CPU can be viewed as committing a sequence of store operations to the
      memory system as time progresses.  All stores before a write barrier will
      occur in the sequence _before_ all the stores after the write barrier.
 
@@ -413,7 +418,7 @@ There are certain things that the Linux kernel memory barriers do not guarantee:
      indirect effect will be the order in which the second CPU sees the effects
      of the first CPU's accesses occur, but see the next point:
 
- (*) There is no guarantee that the a CPU will see the correct order of effects
+ (*) There is no guarantee that a CPU will see the correct order of effects
      from a second CPU's accesses, even _if_ the second CPU uses a memory
      barrier, unless the first CPU _also_ uses a matching memory barrier (see
      the subsection on "SMP Barrier Pairing").
@@ -461,8 +466,8 @@ Whilst this may seem like a failure of coherency or causality maintenance, it
 isn't, and this behaviour can be observed on certain real CPUs (such as the DEC
 Alpha).
 
-To deal with this, a data dependency barrier must be inserted between the
-address load and the data load:
+To deal with this, a data dependency barrier or better must be inserted
+between the address load and the data load:
 
        CPU 1           CPU 2
        =============== ===============
@@ -484,7 +489,7 @@ lines.  The pointer P might be stored in an odd-numbered cache line, and the
 variable B might be stored in an even-numbered cache line.  Then, if the
 even-numbered bank of the reading CPU's cache is extremely busy while the
 odd-numbered bank is idle, one can see the new value of the pointer P (&B),
-but the old value of the variable B (1).
+but the old value of the variable B (2).
 
 
 Another example of where data dependency barriers might by required is where a
@@ -744,7 +749,7 @@ some effectively random order, despite the write barrier issued by CPU 1:
                                                :       :
 
 
-If, however, a read barrier were to be placed between the load of E and the
+If, however, a read barrier were to be placed between the load of B and the
 load of A on CPU 2:
 
        CPU 1                   CPU 2
@@ -1461,9 +1466,8 @@ instruction itself is complete.
 
 On a UP system - where this wouldn't be a problem - the smp_mb() is just a
 compiler barrier, thus making sure the compiler emits the instructions in the
-right order without actually intervening in the CPU.  Since there there's only
-one CPU, that CPU's dependency ordering logic will take care of everything
-else.
+right order without actually intervening in the CPU.  Since there's only one
+CPU, that CPU's dependency ordering logic will take care of everything else.
 
 
 ATOMIC OPERATIONS
@@ -1640,9 +1644,9 @@ functions:
 
      The PCI bus, amongst others, defines an I/O space concept - which on such
      CPUs as i386 and x86_64 cpus readily maps to the CPU's concept of I/O
-     space.  However, it may also mapped as a virtual I/O space in the CPU's
-     memory map, particularly on those CPUs that don't support alternate
-     I/O spaces.
+     space.  However, it may also be mapped as a virtual I/O space in the CPU's
+     memory map, particularly on those CPUs that don't support alternate I/O
+     spaces.
 
      Accesses to this space may be fully synchronous (as on i386), but
      intermediary bridges (such as the PCI host bridge) may not fully honour
index 95d17b3e2eee60318f370818e558583e3db34cf8..2a58f985795ad4b28ad4bc86ebcca10527e8c14e 100644 (file)
@@ -44,8 +44,10 @@ normal timer interrupt, which is 100Hz.
 Programming and/or enabling interrupt frequencies greater than 64Hz is
 only allowed by root. This is perhaps a bit conservative, but we don't want
 an evil user generating lots of IRQs on a slow 386sx-16, where it might have
-a negative impact on performance.  Note that the interrupt handler is only
-a few lines of code to minimize any possibility of this effect.
+a negative impact on performance. This 64Hz limit can be changed by writing
+a different value to /proc/sys/dev/rtc/max-user-freq. Note that the
+interrupt handler is only a few lines of code to minimize any possibility
+of this effect.
 
 Also, if the kernel time is synchronized with an external source, the 
 kernel will write the time back to the CMOS clock every 11 minutes. In 
@@ -81,6 +83,7 @@ that will be using this driver.
  */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <linux/rtc.h>
 #include <sys/ioctl.h>
 #include <sys/time.h>
index ad0bedf678b39cbddfb00d23523f4a3e02a851df..e0188a23fd5e7183768362da2ae4c5c72eebd059 100644 (file)
@@ -115,8 +115,9 @@ trojan program is running at console and which could grab your password
 when you would try to login. It will kill all programs on given console
 and thus letting you make sure that the login prompt you see is actually
 the one from init, not some trojan program.
-IMPORTANT:In its true form it is not a true SAK like the one in   :IMPORTANT
-IMPORTANT:c2 compliant systems, and it should be mistook as such. :IMPORTANT
+IMPORTANT: In its true form it is not a true SAK like the one in a :IMPORTANT
+IMPORTANT: c2 compliant system, and it should not be mistaken as   :IMPORTANT
+IMPORTANT: such.                                                   :IMPORTANT
        It seems other find it useful as (System Attention Key) which is
 useful when you want to exit a program that will not let you switch consoles.
 (For example, X or a svgalib program.)
index b72706c58a442bdb744fb34f74340b1de0337b29..4efa4645885f451e834a39908c4d8e1a26bf6faf 100644 (file)
@@ -87,7 +87,7 @@
  86 -> Osprey 101/151 w/ svid
  87 -> Osprey 200/201/250/251
  88 -> Osprey 200/250                                      [0070:ff01]
- 89 -> Osprey 210/220
+ 89 -> Osprey 210/220/230
  90 -> Osprey 500                                          [0070:ff02]
  91 -> Osprey 540                                          [0070:ff04]
  92 -> Osprey 2000                                         [0070:ff03]
 110 -> IVC-100                                             [ff00:a132]
 111 -> IVC-120G                                            [ff00:a182,ff01:a182,ff02:a182,ff03:a182,ff04:a182,ff05:a182,ff06:a182,ff07:a182,ff08:a182,ff09:a182,ff0a:a182,ff0b:a182,ff0c:a182,ff0d:a182,ff0e:a182,ff0f:a182]
 112 -> pcHDTV HD-2000 TV                                   [7063:2000]
-113 -> Twinhan DST + clones                                [11bd:0026,1822:0001,270f:fc00]
+113 -> Twinhan DST + clones                                [11bd:0026,1822:0001,270f:fc00,1822:0026]
 114 -> Winfast VC100                                       [107d:6607]
 115 -> Teppro TEV-560/InterVision IV-560
 116 -> SIMUS GVC1100                                       [aa6a:82b2]
index 3b39a91b24bd98d48189d862660e81a27ce09005..6cb63ddf6163d7768ab4dfbc99f9318dc6df08a1 100644 (file)
@@ -15,7 +15,7 @@
  14 -> KWorld/VStream XPert DVB-T                          [17de:08a6]
  15 -> DViCO FusionHDTV DVB-T1                             [18ac:db00]
  16 -> KWorld LTV883RF
- 17 -> DViCO FusionHDTV 3 Gold-Q                           [18ac:d810]
+ 17 -> DViCO FusionHDTV 3 Gold-Q                           [18ac:d810,18ac:d800]
  18 -> Hauppauge Nova-T DVB-T                              [0070:9002,0070:9001]
  19 -> Conexant DVB-T reference design                     [14f1:0187]
  20 -> Provideo PV259                                      [1540:2580]
  39 -> KWorld DVB-S 100                                    [17de:08b2]
  40 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid                [0070:9400,0070:9402]
  41 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile)  [0070:9800,0070:9802]
- 42 -> digitalnow DNTV Live! DVB-T Pro                     [1822:0025]
+ 42 -> digitalnow DNTV Live! DVB-T Pro                     [1822:0025,1822:0019]
  43 -> KWorld/VStream XPert DVB-T with cx22702             [17de:08a1]
  44 -> DViCO FusionHDTV DVB-T Dual Digital                 [18ac:db50,18ac:db54]
  45 -> KWorld HardwareMpegTV XPert                         [17de:0840]
  46 -> DViCO FusionHDTV DVB-T Hybrid                       [18ac:db40,18ac:db44]
+ 47 -> pcHDTV HD5500 HDTV                                  [7063:5500]
+ 48 -> Kworld MCE 200 Deluxe                               [17de:0841]
+ 49 -> PixelView PlayTV P7000                              [1554:4813]
+ 50 -> NPG Tech Real TV FM Top 10                          [14f1:0842]
+ 51 -> WinFast DTV2000 H                                   [107d:665e]
index bca50903233f07dc19868b2b3fd466c8b5dabfc9..9068b669f5ee5d34af6dac4ff91a834df623b2f1 100644 (file)
@@ -93,3 +93,4 @@
  92 -> AVerMedia A169 B1                        [1461:6360]
  93 -> Medion 7134 Bridge #2                    [16be:0005]
  94 -> LifeView FlyDVB-T Hybrid Cardbus         [5168:3306,5168:3502]
+ 95 -> LifeView FlyVIDEO3000 (NTSC)             [5169:0138]
index 1bcdac67dd8c140e94dd00e1f0fa856b5a75f86e..44134f04b82afc0999dd51e97c4c073a62c4a3f8 100644 (file)
@@ -62,7 +62,7 @@ tuner=60 - Thomson DTT 761X (ATSC/NTSC)
 tuner=61 - Tena TNF9533-D/IF/TNF9533-B/DF
 tuner=62 - Philips TEA5767HN FM Radio
 tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner
-tuner=64 - LG TDVS-H062F/TUA6034
+tuner=64 - LG TDVS-H06xF
 tuner=65 - Ymec TVF66T5-B/DFF
 tuner=66 - LG TALN series
 tuner=67 - Philips TD1316 Hybrid Tuner
@@ -71,3 +71,4 @@ tuner=69 - Tena TNF 5335 and similar models
 tuner=70 - Samsung TCPN 2121P30A
 tuner=71 - Xceive xc3028
 tuner=72 - Thomson FE6600
+tuner=73 - Samsung TCPG 6121P30A
index 464e4cec94cb82eca91d20d0e411bfdf61c32792..ade8651e24432f879f6e3df5700b2761a9b807bd 100644 (file)
@@ -185,207 +185,10 @@ this work is documented at the video4linux2 site listed below.
 
 9.0 --- A sample program using v4lgrabber,
 
-This program is a simple image grabber that will copy a frame from the
+v4lgrab 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
-    http://mug.sys.virginia.edu/~drf5n/extras/c-qcam.jpg
-
--------------------- 8< ---------------- 8< -----------------------------
-
-/* Simple Video4Linux image grabber. */
-/*
- *     Video4Linux Driver Test/Example Framegrabbing Program
- *
- *     Compile with:
- *             gcc -s -Wall -Wstrict-prototypes v4lgrab.c -o v4lgrab
- *      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
- *      with minor modifications (Dave Forrest, drf5n@virginia.edu).
- *
- */
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <sys/ioctl.h>
-#include <stdlib.h>
-
-#include <linux/types.h>
-#include <linux/videodev.h>
-
-#define FILE "/dev/video0"
-
-/* Stole this from tvset.c */
-
-#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);                                \
-       }                                                               \
-}
-
-int get_brightness_adj(unsigned char *image, long size, int *brightness) {
-  long i, tot = 0;
-  for (i=0;i<size*3;i++)
-    tot += image[i];
-  *brightness = (128 - tot/(size*3))/3;
-  return !((tot/(size*3)) >= 126 && (tot/(size*3)) <= 130);
-}
-
-int main(int argc, char ** argv)
-{
-  int fd = open(FILE, O_RDONLY), f;
-  struct video_capability cap;
-  struct video_window win;
-  struct video_picture vpic;
-
-  unsigned char *buffer, *src;
-  int bpp = 24, r, g, b;
-  unsigned int i, src_depth;
-
-  if (fd < 0) {
-    perror(FILE);
-    exit(1);
-  }
-
-  if (ioctl(fd, VIDIOCGCAP, &cap) < 0) {
-    perror("VIDIOGCAP");
-    fprintf(stderr, "(" FILE " not a video4linux device?)\n");
-    close(fd);
-    exit(1);
-  }
-
-  if (ioctl(fd, VIDIOCGWIN, &win) < 0) {
-    perror("VIDIOCGWIN");
-    close(fd);
-    exit(1);
-  }
-
-  if (ioctl(fd, VIDIOCGPICT, &vpic) < 0) {
-    perror("VIDIOCGPICT");
-    close(fd);
-    exit(1);
-  }
-
-  if (cap.type & VID_TYPE_MONOCHROME) {
-    vpic.depth=8;
-    vpic.palette=VIDEO_PALETTE_GREY;    /* 8bit grey */
-    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);
-       }
-      }
-    }
-  } 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;
-       }
-      }
-    }
-  }
-
-  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);
-    f = get_brightness_adj(buffer, win.width * win.height, &newbright);
-    if (f) {
-      vpic.brightness += (newbright << 8);
-      if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
-       perror("VIDIOSPICT");
-       break;
-      }
-    }
-  } while (f);
-
-  fprintf(stdout, "P6\n%d %d 255\n", win.width, win.height);
-
-  src = buffer;
-
-  for (i = 0; i < win.width * win.height; i++) {
-    READ_VIDEO_PIXEL(src, vpic.palette, src_depth, r, g, b);
-    fputc(r>>8, stdout);
-    fputc(g>>8, stdout);
-    fputc(b>>8, stdout);
-  }
-
-  close(fd);
-  return 0;
-}
--------------------- 8< ---------------- 8< -----------------------------
+format (.ppm)  To produce .jpg output, you can use it like this:
+'v4lgrab | convert - c-qcam.jpg'
 
 
 10.0 --- Other Information
index be9f21b8455589b6c697b888c1132858bce043ce..040a2c841ae96352365d0048c07744661de7b631 100644 (file)
@@ -33,6 +33,21 @@ Inputs/outputs: Composite and S-video
 Norms: PAL, SECAM (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps)
 Card number: 7
 
+AverMedia 6 Eyes AVS6EYES:
+* Zoran zr36067 PCI controller
+* Zoran zr36060 MJPEG codec
+* Samsung ks0127 TV decoder
+* Conexant bt866  TV encoder
+Drivers to use: videodev, i2c-core, i2c-algo-bit,
+               videocodec, ks0127, bt866, zr36060, zr36067
+Inputs/outputs: Six physical inputs. 1-6 are composite,
+               1-2, 3-4, 5-6 doubles as S-video,
+               1-3 triples as component.
+               One composite output.
+Norms: PAL, SECAM (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps)
+Card number: 8
+Not autodetected, card=8 is necessary.
+
 Linux Media Labs LML33:
 * Zoran zr36067 PCI controller
 * Zoran zr36060 MJPEG codec
@@ -192,6 +207,10 @@ Micronas vpx3220a TV decoder
 was introduced in 1996, is used in the DC30 and DC30+ and
 can handle: PAL B/G/H/I, PAL N, PAL M, NTSC M, NTSC 44, PAL 60, SECAM,NTSC Comb
 
+Samsung ks0127 TV decoder
+is used in the AVS6EYES card and
+can handle: NTSC-M/N/44, PAL-M/N/B/G/H/I/D/K/L and SECAM
+
 ===========================
 
 1.2 What the TV encoder can do an what not
@@ -221,6 +240,10 @@ ITT mse3000 TV encoder
 was introduced in 1991, is used in the DC10 old
 can generate: PAL , NTSC , SECAM
 
+Conexant bt866 TV encoder
+is used in AVS6EYES, and
+can generate: NTSC/PAL, PAL­M, 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.
index aef49db8847d7fd3a4c65035103275377dd19c03..8aad6dd93d6be5ea80a2a444af8308619eb6d237 100644 (file)
@@ -1,4 +1,4 @@
-Contributors to bttv: 
+Contributors to bttv:
 
 Michael Chu <mmchu@pobox.com>
   AverMedia fix and more flexible card recognition
@@ -8,8 +8,8 @@ Alan Cox <alan@redhat.com>
 
 Chris Kleitsch
   Hardware I2C
-  
-Gerd Knorr <kraxel@cs.tu-berlin.de> 
+
+Gerd Knorr <kraxel@cs.tu-berlin.de>
   Radio card (ITT sound processor)
 
 bigfoot <bigfoot@net-way.net>
@@ -18,7 +18,7 @@ Ragnar Hojland Espinosa <ragnar@macula.net>
 
 
 + many more (please mail me if you are missing in this list and would
-             like to be mentioned)
+            like to be mentioned)
 
 
 
diff --git a/Documentation/video4linux/cx2341x/fw-calling.txt b/Documentation/video4linux/cx2341x/fw-calling.txt
new file mode 100644 (file)
index 0000000..8d21181
--- /dev/null
@@ -0,0 +1,69 @@
+This page describes how to make calls to the firmware api.
+
+How to call
+===========
+
+The preferred calling convention is known as the firmware mailbox. The
+mailboxes are basically a fixed length array that serves as the call-stack.
+
+Firmware mailboxes can be located by searching the encoder and decoder memory
+for a 16 byte signature. That signature will be located on a 256-byte boundary.
+
+Signature:
+0x78, 0x56, 0x34, 0x12, 0x12, 0x78, 0x56, 0x34,
+0x34, 0x12, 0x78, 0x56, 0x56, 0x34, 0x12, 0x78
+
+The firmware implements 20 mailboxes of 20 32-bit words. The first 10 are
+reserved for API calls. The second 10 are used by the firmware for event
+notification.
+
+  Index  Name
+  -----  ----
+  0      Flags
+  1      Command
+  2      Return value
+  3      Timeout
+  4-19   Parameter/Result
+
+
+The flags are defined in the following table. The direction is from the
+perspective of the firmware.
+
+  Bit  Direction  Purpose
+  ---  ---------  -------
+  2    O          Firmware has processed the command.
+  1    I          Driver has finished setting the parameters.
+  0    I          Driver is using this mailbox.
+
+
+The command is a 32-bit enumerator. The API specifics may be found in the
+fw-*-api.txt documents.
+
+The return value is a 32-bit enumerator. Only two values are currently defined:
+0=success and -1=command undefined.
+
+There are 16 parameters/results 32-bit fields. The driver populates these fields
+with values for all the parameters required by the call. The driver overwrites
+these fields with result values returned by the call. The API specifics may be
+found in the fw-*-api.txt documents.
+
+The timeout value protects the card from a hung driver thread. If the driver
+doesn't handle the completed call within the timeout specified, the firmware
+will reset that mailbox.
+
+To make an API call, the driver iterates over each mailbox looking for the
+first one available (bit 0 has been cleared). The driver sets that bit, fills
+in the command enumerator, the timeout value and any required parameters. The
+driver then sets the parameter ready bit (bit 1). The firmware scans the
+mailboxes for pending commands, processes them, sets the result code, populates
+the result value array with that call's return values and sets the call
+complete bit (bit 2). Once bit 2 is set, the driver should retrieve the results
+and clear all the flags. If the driver does not perform this task within the
+time set in the timeout register, the firmware will reset that mailbox.
+
+Event notifications are sent from the firmware to the host. The host tells the
+firmware which events it is interested in via an API call. That call tells the
+firmware which notification mailbox to use. The firmware signals the host via
+an interrupt. Only the 16 Results fields are used, the Flags, Command, Return
+value and Timeout words are not used.
+
diff --git a/Documentation/video4linux/cx2341x/fw-decoder-api.txt b/Documentation/video4linux/cx2341x/fw-decoder-api.txt
new file mode 100644 (file)
index 0000000..9df4fb3
--- /dev/null
@@ -0,0 +1,319 @@
+Decoder firmware API description
+================================
+
+Note: this API is part of the decoder firmware, so it's cx23415 only.
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_PING_FW
+Enum   0/0x00
+Description
+       This API call does nothing. It may be used to check if the firmware
+       is responding.
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_START_PLAYBACK
+Enum   1/0x01
+Description
+       Begin or resume playback.
+Param[0]
+       0 based frame number in GOP to begin playback from.
+Param[1]
+       Specifies the number of muted audio frames to play before normal
+       audio resumes.
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_STOP_PLAYBACK
+Enum   2/0x02
+Description
+       Ends playback and clears all decoder buffers. If PTS is not zero,
+       playback stops at specified PTS.
+Param[0]
+       Display 0=last frame, 1=black
+Param[1]
+       PTS low
+Param[2]
+       PTS high
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_SET_PLAYBACK_SPEED
+Enum   3/0x03
+Description
+       Playback stream at speed other than normal. There are two modes of
+       operation:
+           Smooth: host transfers entire stream and firmware drops unused
+                   frames.
+           Coarse: host drops frames based on indexing as required to achieve
+                   desired speed.
+Param[0]
+       Bitmap:
+           0:7  0 normal
+                1 fast only "1.5 times"
+                n nX fast, 1/nX slow
+           30   Framedrop:
+                    '0' during 1.5 times play, every other B frame is dropped
+                    '1' during 1.5 times play, stream is unchanged (bitrate
+                        must not exceed 8mbps)
+           31   Speed:
+                    '0' slow
+                    '1' fast
+Param[1]
+       Direction: 0=forward, 1=reverse
+Param[2]
+       Picture mask:
+           1=I frames
+           3=I, P frames
+           7=I, P, B frames
+Param[3]
+       B frames per GOP (for reverse play only)
+Param[4]
+       Mute audio: 0=disable, 1=enable
+Param[5]
+       Display 0=frame, 1=field
+Param[6]
+       Specifies the number of muted audio frames to play before normal audio
+       resumes.
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_STEP_VIDEO
+Enum   5/0x05
+Description
+       Each call to this API steps the playback to the next unit defined below
+       in the current playback direction.
+Param[0]
+       0=frame, 1=top field, 2=bottom field
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_SET_DMA_BLOCK_SIZE
+Enum   8/0x08
+Description
+       Set DMA transfer block size. Counterpart to API 0xC9
+Param[0]
+       DMA transfer block size in bytes. A different size may be specified
+       when issuing the DMA transfer command.
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_GET_XFER_INFO
+Enum   9/0x09
+Description
+       This API call may be used to detect an end of stream condtion.
+Result[0]
+       Stream type
+Result[1]
+       Address offset
+Result[2]
+       Maximum bytes to transfer
+Result[3]
+       Buffer fullness
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_GET_DMA_STATUS
+Enum   10/0x0A
+Description
+       Status of the last DMA transfer
+Result[0]
+       Bit 1 set means transfer complete
+       Bit 2 set means DMA error
+       Bit 3 set means linked list error
+Result[1]
+       DMA type: 0=MPEG, 1=OSD, 2=YUV
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_SCHED_DMA_FROM_HOST
+Enum   11/0x0B
+Description
+       Setup DMA from host operation. Counterpart to API 0xCC
+Param[0]
+       Memory address of link list
+Param[1]
+       Total # of bytes to transfer
+Param[2]
+       DMA type (0=MPEG, 1=OSD, 2=YUV)
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_PAUSE_PLAYBACK
+Enum   13/0x0D
+Description
+       Freeze playback immediately. In this mode, when internal buffers are
+       full, no more data will be accepted and data request IRQs will be
+       masked.
+Param[0]
+       Display: 0=last frame, 1=black
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_HALT_FW
+Enum   14/0x0E
+Description
+       The firmware is halted and no further API calls are serviced until
+       the firmware is uploaded again.
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_SET_STANDARD
+Enum   16/0x10
+Description
+       Selects display standard
+Param[0]
+       0=NTSC, 1=PAL
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_GET_VERSION
+Enum   17/0x11
+Description
+       Returns decoder firmware version information
+Result[0]
+       Version bitmask:
+           Bits  0:15 build
+           Bits 16:23 minor
+           Bits 24:31 major
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_SET_STREAM_INPUT
+Enum   20/0x14
+Description
+       Select decoder stream input port
+Param[0]
+       0=memory (default), 1=streaming
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_GET_TIMING_INFO
+Enum   21/0x15
+Description
+       Returns timing information from start of playback
+Result[0]
+       Frame count by decode order
+Result[1]
+       Video PTS bits 0:31 by display order
+Result[2]
+       Video PTS bit 32 by display order
+Result[3]
+       SCR bits 0:31 by display order
+Result[4]
+       SCR bit 32 by display order
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_SET_AUDIO_MODE
+Enum   22/0x16
+Description
+       Select audio mode
+Param[0]
+       Dual mono mode action
+Param[1]
+       Stereo mode action:
+           0=Stereo, 1=Left, 2=Right, 3=Mono, 4=Swap, -1=Unchanged
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_SET_EVENT_NOTIFICATION
+Enum   23/0x17
+Description
+       Setup firmware to notify the host about a particular event.
+       Counterpart to API 0xD5
+Param[0]
+       Event: 0=Audio mode change between stereo and dual channel
+Param[1]
+       Notification 0=disabled, 1=enabled
+Param[2]
+       Interrupt bit
+Param[3]
+       Mailbox slot, -1 if no mailbox required.
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_SET_DISPLAY_BUFFERS
+Enum   24/0x18
+Description
+       Number of display buffers. To decode all frames in reverse playback you
+       must use nine buffers.
+Param[0]
+       0=six buffers, 1=nine buffers
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_EXTRACT_VBI
+Enum   25/0x19
+Description
+       Extracts VBI data
+Param[0]
+       0=extract from extension & user data, 1=extract from private packets
+Result[0]
+       VBI table location
+Result[1]
+       VBI table size
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_SET_DECODER_SOURCE
+Enum   26/0x1A
+Description
+       Selects decoder source. Ensure that the parameters passed to this
+       API match the encoder settings.
+Param[0]
+       Mode: 0=MPEG from host, 1=YUV from encoder, 2=YUV from host
+Param[1]
+       YUV picture width
+Param[2]
+       YUV picture height
+Param[3]
+       Bitmap: see Param[0] of API 0xBD
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_SET_AUDIO_OUTPUT
+Enum   27/0x1B
+Description
+       Select audio output format
+Param[0]
+       Bitmask:
+            0:1  Data size:
+                     '00' 16 bit
+                     '01' 20 bit
+                     '10' 24 bit
+            2:7  Unused
+            8:9  Mode:
+                     '00' 2 channels
+                     '01' 4 channels
+                     '10' 6 channels
+                     '11' 6 channels with one line data mode
+                          (for left justified MSB first mode, 20 bit only)
+           10:11 Unused
+           12:13 Channel format:
+                     '00' right justified MSB first mode
+                     '01' left justified MSB first mode
+                     '10' I2S mode
+           14:15 Unused
+           16:21 Right justify bit count
+           22:31 Unused
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_SET_AV_DELAY
+Enum   28/0x1C
+Description
+       Set audio/video delay in 90Khz ticks
+Param[0]
+       0=A/V in sync, negative=audio lags, positive=video lags
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_DEC_SET_PREBUFFERING
+Enum   30/0x1E
+Description
+       Decoder prebuffering, when enabled up to 128KB are buffered for
+       streams <8mpbs or 640KB for streams >8mbps
+Param[0]
+       0=off, 1=on
diff --git a/Documentation/video4linux/cx2341x/fw-dma.txt b/Documentation/video4linux/cx2341x/fw-dma.txt
new file mode 100644 (file)
index 0000000..8123e26
--- /dev/null
@@ -0,0 +1,94 @@
+This page describes the structures and procedures used by the cx2341x DMA
+engine.
+
+Introduction
+============
+
+The cx2341x PCI interface is busmaster capable. This means it has a DMA
+engine to efficiently transfer large volumes of data between the card and main
+memory without requiring help from a CPU. Like most hardware, it must operate
+on contiguous physical memory. This is difficult to come by in large quantities
+on virtual memory machines.
+
+Therefore, it also supports a technique called "scatter-gather". The card can
+transfer multiple buffers in one operation. Instead of allocating one large
+contiguous buffer, the driver can allocate several smaller buffers.
+
+In practice, I've seen the average transfer to be roughly 80K, but transfers
+above 128K were not uncommon, particularly at startup. The 128K figure is
+important, because that is the largest block that the kernel can normally
+allocate. Even still, 128K blocks are hard to come by, so the driver writer is
+urged to choose a smaller block size and learn the scatter-gather technique.
+
+Mailbox #10 is reserved for DMA transfer information.
+
+Flow
+====
+
+This section describes, in general, the order of events when handling DMA
+transfers. Detailed information follows this section.
+
+- The card raises the Encoder interrupt.
+- The driver reads the transfer type, offset and size from Mailbox #10.
+- The driver constructs the scatter-gather array from enough free dma buffers
+  to cover the size.
+- The driver schedules the DMA transfer via the ScheduleDMAtoHost API call.
+- The card raises the DMA Complete interrupt.
+- The driver checks the DMA status register for any errors.
+- The driver post-processes the newly transferred buffers.
+
+NOTE! It is possible that the Encoder and DMA Complete interrupts get raised
+simultaneously. (End of the last, start of the next, etc.)
+
+Mailbox #10
+===========
+
+The Flags, Command, Return Value and Timeout fields are ignored.
+
+Name:       Mailbox #10
+Results[0]: Type: 0: MPEG.
+Results[1]: Offset: The position relative to the card's memory space.
+Results[2]: Size: The exact number of bytes to transfer.
+
+My speculation is that since the StartCapture API has a capture type of "RAW"
+available, that the type field will have other values that correspond to YUV
+and PCM data.
+
+Scatter-Gather Array
+====================
+
+The scatter-gather array is a contiguously allocated block of memory that
+tells the card the source and destination of each data-block to transfer.
+Card "addresses" are derived from the offset supplied by Mailbox #10. Host
+addresses are the physical memory location of the target DMA buffer.
+
+Each S-G array element is a struct of three 32-bit words. The first word is
+the source address, the second is the destination address. Both take up the
+entire 32 bits. The lowest 16 bits of the third word is the transfer byte
+count. The high-bit of the third word is the "last" flag. The last-flag tells
+the card to raise the DMA_DONE interrupt. From hard personal experience, if
+you forget to set this bit, the card will still "work" but the stream will
+most likely get corrupted.
+
+The transfer count must be a multiple of 256. Therefore, the driver will need
+to track how much data in the target buffer is valid and deal with it
+accordingly.
+
+Array Element:
+
+- 32-bit Source Address
+- 32-bit Destination Address
+- 16-bit reserved (high bit is the last flag)
+- 16-bit byte count
+
+DMA Transfer Status
+===================
+
+Register 0x0004 holds the DMA Transfer Status:
+
+Bit
+4   Scatter-Gather array error
+3   DMA write error
+2   DMA read error
+1   write completed
+0   read completed
diff --git a/Documentation/video4linux/cx2341x/fw-encoder-api.txt b/Documentation/video4linux/cx2341x/fw-encoder-api.txt
new file mode 100644 (file)
index 0000000..001c686
--- /dev/null
@@ -0,0 +1,694 @@
+Encoder firmware API description
+================================
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_PING_FW
+Enum   128/0x80
+Description
+       Does nothing. Can be used to check if the firmware is responding.
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_START_CAPTURE
+Enum   129/0x81
+Description
+       Commences the capture of video, audio and/or VBI data. All encoding
+       parameters must be initialized prior to this API call. Captures frames
+       continuously or until a predefined number of frames have been captured.
+Param[0]
+       Capture stream type:
+           0=MPEG
+           1=Raw
+           2=Raw passthrough
+           3=VBI
+
+Param[1]
+       Bitmask:
+           Bit 0 when set, captures YUV
+           Bit 1 when set, captures PCM audio
+           Bit 2 when set, captures VBI (same as param[0]=3)
+           Bit 3 when set, the capture destination is the decoder
+               (same as param[0]=2)
+           Bit 4 when set, the capture destination is the host
+       Note: this parameter is only meaningful for RAW capture type.
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_STOP_CAPTURE
+Enum   130/0x82
+Description
+       Ends a capture in progress
+Param[0]
+       0=stop at end of GOP (generates IRQ)
+       1=stop immediate (no IRQ)
+Param[1]
+       Stream type to stop, see param[0] of API 0x81
+Param[2]
+       Subtype, see param[1] of API 0x81
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_AUDIO_ID
+Enum   137/0x89
+Description
+       Assigns the transport stream ID of the encoded audio stream
+Param[0]
+       Audio Stream ID
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_VIDEO_ID
+Enum   139/0x8B
+Description
+       Set video transport stream ID
+Param[0]
+       Video stream ID
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_PCR_ID
+Enum   141/0x8D
+Description
+       Assigns the transport stream ID for PCR packets
+Param[0]
+       PCR Stream ID
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_FRAME_RATE
+Enum   143/0x8F
+Description
+       Set video frames per second. Change occurs at start of new GOP.
+Param[0]
+       0=30fps
+       1=25fps
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_FRAME_SIZE
+Enum   145/0x91
+Description
+       Select video stream encoding resolution.
+Param[0]
+       Height in lines. Default 480
+Param[1]
+       Width in pixels. Default 720
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_BIT_RATE
+Enum   149/0x95
+Description
+       Assign average video stream bitrate. Note on the last three params:
+       Param[3] and [4] seem to be always 0, param [5] doesn't seem to be used.
+Param[0]
+       0=variable bitrate, 1=constant bitrate
+Param[1]
+       bitrate in bits per second
+Param[2]
+       peak bitrate in bits per second, divided by 400
+Param[3]
+       Mux bitrate in bits per second, divided by 400. May be 0 (default).
+Param[4]
+       Rate Control VBR Padding
+Param[5]
+       VBV Buffer used by encoder
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_GOP_PROPERTIES
+Enum   151/0x97
+Description
+       Setup the GOP structure
+Param[0]
+       GOP size (maximum is 34)
+Param[1]
+       Number of B frames between the I and P frame, plus 1.
+       For example: IBBPBBPBBPBB --> GOP size: 12, number of B frames: 2+1 = 3
+       Note that GOP size must be a multiple of (B-frames + 1).
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_ASPECT_RATIO
+Enum   153/0x99
+Description
+       Sets the encoding aspect ratio. Changes in the aspect ratio take effect
+       at the start of the next GOP.
+Param[0]
+       '0000' forbidden
+       '0001' 1:1 square
+       '0010' 4:3
+       '0011' 16:9
+       '0100' 2.21:1
+       '0101' reserved
+        ....
+       '1111' reserved
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_DNR_FILTER_MODE
+Enum   155/0x9B
+Description
+       Assign Dynamic Noise Reduction operating mode
+Param[0]
+       Bit0: Spatial filter, set=auto, clear=manual
+       Bit1: Temporal filter, set=auto, clear=manual
+Param[1]
+       Median filter:
+           0=Disabled
+           1=Horizontal
+           2=Vertical
+           3=Horiz/Vert
+           4=Diagonal
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_DNR_FILTER_PROPS
+Enum   157/0x9D
+Description
+       These Dynamic Noise Reduction filter values are only meaningful when
+       the respective filter is set to "manual" (See API 0x9B)
+Param[0]
+       Spatial filter: default 0, range 0:15
+Param[1]
+       Temporal filter: default 0, range 0:31
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_CORING_LEVELS
+Enum   159/0x9F
+Description
+       Assign Dynamic Noise Reduction median filter properties.
+Param[0]
+       Threshold above which the luminance median filter is enabled.
+       Default: 0, range 0:255
+Param[1]
+       Threshold below which the luminance median filter is enabled.
+       Default: 255, range 0:255
+Param[2]
+       Threshold above which the chrominance median filter is enabled.
+       Default: 0, range 0:255
+Param[3]
+       Threshold below which the chrominance median filter is enabled.
+       Default: 255, range 0:255
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_SPATIAL_FILTER_TYPE
+Enum   161/0xA1
+Description
+       Assign spatial prefilter parameters
+Param[0]
+       Luminance filter
+           0=Off
+           1=1D Horizontal
+           2=1D Vertical
+           3=2D H/V Separable (default)
+           4=2D Symmetric non-separable
+Param[1]
+       Chrominance filter
+           0=Off
+           1=1D Horizontal (default)
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_3_2_PULLDOWN
+Enum   177/0xB1
+Description
+       3:2 pulldown properties
+Param[0]
+       0=enabled
+       1=disabled
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_VBI_LINE
+Enum   183/0xB7
+Description
+       Selects VBI line number.
+Param[0]
+       Bits 0:4        line number
+       Bit  31         0=top_field, 1=bottom_field
+       Bits 0:31       all set specifies "all lines"
+Param[1]
+       VBI line information features: 0=disabled, 1=enabled
+Param[2]
+       Slicing: 0=None, 1=Closed Caption
+       Almost certainly not implemented. Set to 0.
+Param[3]
+       Luminance samples in this line.
+       Almost certainly not implemented. Set to 0.
+Param[4]
+       Chrominance samples in this line
+       Almost certainly not implemented. Set to 0.
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_STREAM_TYPE
+Enum   185/0xB9
+Description
+       Assign stream type
+       Note: Transport stream is not working in recent firmwares.
+       And in older firmwares the timestamps in the TS seem to be
+       unreliable.
+Param[0]
+        0=Program stream
+        1=Transport stream
+        2=MPEG1 stream
+        3=PES A/V stream
+        5=PES Video stream
+        7=PES Audio stream
+       10=DVD stream
+       11=VCD stream
+       12=SVCD stream
+       13=DVD_S1 stream
+       14=DVD_S2 stream
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_OUTPUT_PORT
+Enum   187/0xBB
+Description
+       Assign stream output port. Normally 0 when the data is copied through
+       the PCI bus (DMA), and 1 when the data is streamed to another chip
+       (pvrusb and cx88-blackbird).
+Param[0]
+       0=Memory (default)
+       1=Streaming
+       2=Serial
+Param[1]
+       Unknown, but leaving this to 0 seems to work best. Indications are that
+       this might have to do with USB support, although passing anything but 0
+       onl breaks things.
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_AUDIO_PROPERTIES
+Enum   189/0xBD
+Description
+       Set audio stream properties, may be called while encoding is in progress.
+       Note: all bitfields are consistent with ISO11172 documentation except
+       bits 2:3 which ISO docs define as:
+               '11' Layer I
+               '10' Layer II
+               '01' Layer III
+               '00' Undefined
+       This discrepancy may indicate a possible error in the documentation.
+       Testing indicated that only Layer II is actually working, and that
+       the minimum bitrate should be 192 kbps.
+Param[0]
+       Bitmask:
+          0:1  '00' 44.1Khz
+               '01' 48Khz
+               '10' 32Khz
+               '11' reserved
+
+          2:3  '01'=Layer I
+               '10'=Layer II
+
+          4:7  Bitrate:
+                    Index | Layer I     | Layer II
+                    ------+-------------+------------
+                   '0000' | free format | free format
+                   '0001' |  32 kbit/s  |  32 kbit/s
+                   '0010' |  64 kbit/s  |  48 kbit/s
+                   '0011' |  96 kbit/s  |  56 kbit/s
+                   '0100' | 128 kbit/s  |  64 kbit/s
+                   '0101' | 160 kbit/s  |  80 kbit/s
+                   '0110' | 192 kbit/s  |  96 kbit/s
+                   '0111' | 224 kbit/s  | 112 kbit/s
+                   '1000' | 256 kbit/s  | 128 kbit/s
+                   '1001' | 288 kbit/s  | 160 kbit/s
+                   '1010' | 320 kbit/s  | 192 kbit/s
+                   '1011' | 352 kbit/s  | 224 kbit/s
+                   '1100' | 384 kbit/s  | 256 kbit/s
+                   '1101' | 416 kbit/s  | 320 kbit/s
+                   '1110' | 448 kbit/s  | 384 kbit/s
+               Note: For Layer II, not all combinations of total bitrate
+               and mode are allowed. See ISO11172-3 3-Annex B, Table 3-B.2
+
+          8:9  '00'=Stereo
+               '01'=JointStereo
+               '10'=Dual
+               '11'=Mono
+               Note: testing seems to indicate that Mono and possibly
+               JointStereo are not working (default to stereo).
+               Dual does work, though.
+
+         10:11 Mode Extension used in joint_stereo mode.
+               In Layer I and II they indicate which subbands are in
+               intensity_stereo. All other subbands are coded in stereo.
+                   '00' subbands 4-31 in intensity_stereo, bound==4
+                   '01' subbands 8-31 in intensity_stereo, bound==8
+                   '10' subbands 12-31 in intensity_stereo, bound==12
+                   '11' subbands 16-31 in intensity_stereo, bound==16
+
+         12:13 Emphasis:
+                   '00' None
+                   '01' 50/15uS
+                   '10' reserved
+                   '11' CCITT J.17
+
+         14    CRC:
+                   '0' off
+                   '1' on
+
+         15    Copyright:
+                   '0' off
+                   '1' on
+
+         16    Generation:
+                   '0' copy
+                   '1' original
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_HALT_FW
+Enum   195/0xC3
+Description
+       The firmware is halted and no further API calls are serviced until the
+       firmware is uploaded again.
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_GET_VERSION
+Enum   196/0xC4
+Description
+       Returns the version of the encoder firmware.
+Result[0]
+       Version bitmask:
+           Bits  0:15 build
+           Bits 16:23 minor
+           Bits 24:31 major
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_GOP_CLOSURE
+Enum   197/0xC5
+Description
+       Assigns the GOP open/close property.
+Param[0]
+       0=Open
+       1=Closed
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_GET_SEQ_END
+Enum   198/0xC6
+Description
+       Obtains the sequence end code of the encoder's buffer. When a capture
+       is started a number of interrupts are still generated, the last of
+       which will have Result[0] set to 1 and Result[1] will contain the size
+       of the buffer.
+Result[0]
+       State of the transfer (1 if last buffer)
+Result[1]
+       If Result[0] is 1, this contains the size of the last buffer, undefined
+       otherwise.
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_PGM_INDEX_INFO
+Enum   199/0xC7
+Description
+       Sets the Program Index Information.
+Param[0]
+       Picture Mask:
+           0=No index capture
+           1=I frames
+           3=I,P frames
+           7=I,P,B frames
+Param[1]
+       Elements requested (up to 400)
+Result[0]
+       Offset in SDF memory of the table.
+Result[1]
+       Number of allocated elements up to a maximum of Param[1]
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_VBI_CONFIG
+Enum   200/0xC8
+Description
+       Configure VBI settings
+Param[0]
+       Bitmap:
+           0    Mode '0' Sliced, '1' Raw
+           1:3  Insertion:
+                    '000' insert in extension & user data
+                    '001' insert in private packets
+                    '010' separate stream and user data
+                    '111' separate stream and private data
+           8:15 Stream ID (normally 0xBD)
+Param[1]
+       Frames per interrupt (max 8). Only valid in raw mode.
+Param[2]
+       Total raw VBI frames. Only valid in raw mode.
+Param[3]
+       Start codes
+Param[4]
+       Stop codes
+Param[5]
+       Lines per frame
+Param[6]
+       Byte per line
+Result[0]
+       Observed frames per interrupt in raw mode only. Rage 1 to Param[1]
+Result[1]
+       Observed number of frames in raw mode. Range 1 to Param[2]
+Result[2]
+       Memory offset to start or raw VBI data
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_DMA_BLOCK_SIZE
+Enum   201/0xC9
+Description
+       Set DMA transfer block size
+Param[0]
+       DMA transfer block size in bytes or frames. When unit is bytes,
+       supported block sizes are 2^7, 2^8 and 2^9 bytes.
+Param[1]
+       Unit: 0=bytes, 1=frames
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_GET_PREV_DMA_INFO_MB_10
+Enum   202/0xCA
+Description
+       Returns information on the previous DMA transfer in conjunction with
+       bit 27 of the interrupt mask. Uses mailbox 10.
+Result[0]
+       Type of stream
+Result[1]
+       Address Offset
+Result[2]
+       Maximum size of transfer
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_GET_PREV_DMA_INFO_MB_9
+Enum   203/0xCB
+Description
+       Returns information on the previous DMA transfer in conjunction with
+       bit 27 of the interrupt mask. Uses mailbox 9.
+Result[0]
+       Status bits:
+           Bit 0 set indicates transfer complete
+           Bit 2 set indicates transfer error
+           Bit 4 set indicates linked list error
+Result[1]
+       DMA type
+Result[2]
+       Presentation Time Stamp bits 0..31
+Result[3]
+       Presentation Time Stamp bit 32
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SCHED_DMA_TO_HOST
+Enum   204/0xCC
+Description
+       Setup DMA to host operation
+Param[0]
+       Memory address of link list
+Param[1]
+       Length of link list (wtf: what units ???)
+Param[2]
+       DMA type (0=MPEG)
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_INITIALIZE_INPUT
+Enum   205/0xCD
+Description
+       Initializes the video input
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_FRAME_DROP_RATE
+Enum   208/0xD0
+Description
+       For each frame captured, skip specified number of frames.
+Param[0]
+       Number of frames to skip
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_PAUSE_ENCODER
+Enum   210/0xD2
+Description
+       During a pause condition, all frames are dropped instead of being encoded.
+Param[0]
+       0=Pause encoding
+       1=Continue encoding
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_REFRESH_INPUT
+Enum   211/0xD3
+Description
+       Refreshes the video input
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_COPYRIGHT
+Enum   212/0xD4
+Description
+       Sets stream copyright property
+Param[0]
+       0=Stream is not copyrighted
+       1=Stream is copyrighted
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_EVENT_NOTIFICATION
+Enum   213/0xD5
+Description
+       Setup firmware to notify the host about a particular event. Host must
+       unmask the interrupt bit.
+Param[0]
+       Event (0=refresh encoder input)
+Param[1]
+       Notification 0=disabled 1=enabled
+Param[2]
+       Interrupt bit
+Param[3]
+       Mailbox slot, -1 if no mailbox required.
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_NUM_VSYNC_LINES
+Enum   214/0xD6
+Description
+       Depending on the analog video decoder used, this assigns the number
+       of lines for field 1 and 2.
+Param[0]
+       Field 1 number of lines:
+           0x00EF for SAA7114
+           0x00F0 for SAA7115
+           0x0105 for Micronas
+Param[1]
+       Field 2 number of lines:
+           0x00EF for SAA7114
+           0x00F0 for SAA7115
+           0x0106 for Micronas
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_SET_PLACEHOLDER
+Enum   215/0xD7
+Description
+       Provides a mechanism of inserting custom user data in the MPEG stream.
+Param[0]
+       0=extension & user data
+       1=private packet with stream ID 0xBD
+Param[1]
+       Rate at which to insert data, in units of frames (for private packet)
+       or GOPs (for ext. & user data)
+Param[2]
+       Number of data DWORDs (below) to insert
+Param[3]
+       Custom data 0
+Param[4]
+       Custom data 1
+Param[5]
+       Custom data 2
+Param[6]
+       Custom data 3
+Param[7]
+       Custom data 4
+Param[8]
+       Custom data 5
+Param[9]
+       Custom data 6
+Param[10]
+       Custom data 7
+Param[11]
+       Custom data 8
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_MUTE_VIDEO
+Enum   217/0xD9
+Description
+       Video muting
+Param[0]
+       Bit usage:
+        0      '0'=video not muted
+               '1'=video muted, creates frames with the YUV color defined below
+        1:7    Unused
+        8:15   V chrominance information
+       16:23   U chrominance information
+       24:31   Y luminance information
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_MUTE_AUDIO
+Enum   218/0xDA
+Description
+       Audio muting
+Param[0]
+       0=audio not muted
+       1=audio muted (produces silent mpeg audio stream)
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_UNKNOWN
+Enum   219/0xDB
+Description
+       Unknown API, it's used by Hauppauge though.
+Param[0]
+       0 This is the value Hauppauge uses, Unknown what it means.
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_ENC_MISC
+Enum   220/0xDC
+Description
+       Miscellaneous actions. Not known for 100% what it does. It's really a
+       sort of ioctl call. The first parameter is a command number, the second
+       the value.
+Param[0]
+       Command number:
+        1=set initial SCR value when starting encoding.
+        2=set quality mode (apparently some test setting).
+        3=setup advanced VIM protection handling (supposedly only for the cx23416
+          for raw YUV).
+          Actually it looks like this should be 0 for saa7114/5 based card and 1
+          for cx25840 based cards.
+        4=generate artificial PTS timestamps
+        5=USB flush mode
+        6=something to do with the quantization matrix
+        7=set navigation pack insertion for DVD
+        8=enable scene change detection (seems to be a failure)
+        9=set history parameters of the video input module
+       10=set input field order of VIM
+       11=set quantization matrix
+       12=reset audio interface
+       13=set audio volume delay
+       14=set audio delay
+
+Param[1]
+       Command value.
diff --git a/Documentation/video4linux/cx2341x/fw-memory.txt b/Documentation/video4linux/cx2341x/fw-memory.txt
new file mode 100644 (file)
index 0000000..ef0aad3
--- /dev/null
@@ -0,0 +1,141 @@
+This document describes the cx2341x memory map and documents some of the register
+space.
+
+Warning! This information was figured out from searching through the memory and
+registers, this information may not be correct and is certainly not complete, and
+was not derived from anything more than searching through the memory space with
+commands like:
+
+       ivtvctl -O min=0x02000000,max=0x020000ff
+
+So take this as is, I'm always searching for more stuff, it's a large
+register space :-).
+
+Memory Map
+==========
+
+The cx2341x exposes its entire 64M memory space to the PCI host via the PCI BAR0
+(Base Address Register 0). The addresses here are offsets relative to the
+address held in BAR0.
+
+0x00000000-0x00ffffff Encoder memory space
+0x00000000-0x0003ffff Encode.rom
+      ???-???         MPEG buffer(s)
+      ???-???         Raw video capture buffer(s)
+      ???-???         Raw audio capture buffer(s)
+      ???-???         Display buffers (6 or 9)
+
+0x01000000-0x01ffffff Decoder memory space
+0x01000000-0x0103ffff Decode.rom
+      ???-???         MPEG buffers(s)
+0x0114b000-0x0115afff Audio.rom (deprecated?)
+
+0x02000000-0x0200ffff Register Space
+
+Registers
+=========
+
+The registers occupy the 64k space starting at the 0x02000000 offset from BAR0.
+All of these registers are 32 bits wide.
+
+DMA Registers 0x000-0xff:
+
+ 0x00 - Control:
+       0=reset/cancel, 1=read, 2=write, 4=stop
+ 0x04 - DMA status:
+       1=read busy, 2=write busy, 4=read error, 8=write error, 16=link list error
+ 0x08 - pci DMA pointer for read link list
+ 0x0c - pci DMA pointer for write link list
+ 0x10 - read/write DMA enable:
+       1=read enable, 2=write enable
+ 0x14 - always 0xffffffff, if set any lower instability occurs, 0x00 crashes
+ 0x18 - ??
+ 0x1c - always 0x20 or 32, smaller values slow down DMA transactions
+ 0x20 - always value of 0x780a010a
+ 0x24-0x3c - usually just random values???
+ 0x40 - Interrupt status
+ 0x44 - Write a bit here and shows up in Interrupt status 0x40
+ 0x48 - Interrupt Mask
+ 0x4C - always value of 0xfffdffff,
+       if changed to 0xffffffff DMA write interrupts break.
+ 0x50 - always 0xffffffff
+ 0x54 - always 0xffffffff (0x4c, 0x50, 0x54 seem like interrupt masks, are
+       3 processors on chip, Java ones, VPU, SPU, APU, maybe these are the
+       interrupt masks???).
+ 0x60-0x7C - random values
+ 0x80 - first write linked list reg, for Encoder Memory addr
+ 0x84 - first write linked list reg, for pci memory addr
+ 0x88 - first write linked list reg, for length of buffer in memory addr
+       (|0x80000000 or this for last link)
+ 0x8c-0xcc - rest of write linked list reg, 8 sets of 3 total, DMA goes here
+       from linked list addr in reg 0x0c, firmware must push through or
+       something.
+ 0xe0 - first (and only) read linked list reg, for pci memory addr
+ 0xe4 - first (and only) read linked list reg, for Decoder memory addr
+ 0xe8 - first (and only) read linked list reg, for length of buffer
+ 0xec-0xff - Nothing seems to be in these registers, 0xec-f4 are 0x00000000.
+
+Memory locations for Encoder Buffers 0x700-0x7ff:
+
+These registers show offsets of memory locations pertaining to each
+buffer area used for encoding, have to shift them by <<1 first.
+
+0x07F8: Encoder SDRAM refresh
+0x07FC: Encoder SDRAM pre-charge
+
+Memory locations for Decoder Buffers 0x800-0x8ff:
+
+These registers show offsets of memory locations pertaining to each
+buffer area used for decoding, have to shift them by <<1 first.
+
+0x08F8: Decoder SDRAM refresh
+0x08FC: Decoder SDRAM pre-charge
+
+Other memory locations:
+
+0x2800: Video Display Module control
+0x2D00: AO (audio output?) control
+0x2D24: Bytes Flushed
+0x7000: LSB I2C write clock bit (inverted)
+0x7004: LSB I2C write data bit (inverted)
+0x7008: LSB I2C read clock bit
+0x700c: LSB I2C read data bit
+0x9008: GPIO get input state
+0x900c: GPIO set output state
+0x9020: GPIO direction (Bit7 (GPIO 0..7) - 0:input, 1:output)
+0x9050: SPU control
+0x9054: Reset HW blocks
+0x9058: VPU control
+0xA018: Bit6: interrupt pending?
+0xA064: APU command
+
+
+Interrupt Status Register
+=========================
+
+The definition of the bits in the interrupt status register 0x0040, and the
+interrupt mask 0x0048. If a bit is cleared in the mask, then we want our ISR to
+execute.
+
+Bit
+31 Encoder Start Capture
+30 Encoder EOS
+29 Encoder VBI capture
+28 Encoder Video Input Module reset event
+27 Encoder DMA complete
+26
+25 Decoder copy protect detection event
+24 Decoder audio mode change detection event
+23
+22 Decoder data request
+21 Decoder I-Frame? done
+20 Decoder DMA complete
+19 Decoder VBI re-insertion
+18 Decoder DMA err (linked-list bad)
+
+Missing
+Encoder API call completed
+Decoder API call completed
+Encoder API post(?)
+Decoder API post(?)
+Decoder VTRACE event
diff --git a/Documentation/video4linux/cx2341x/fw-osd-api.txt b/Documentation/video4linux/cx2341x/fw-osd-api.txt
new file mode 100644 (file)
index 0000000..da98ae3
--- /dev/null
@@ -0,0 +1,342 @@
+OSD firmware API description
+============================
+
+Note: this API is part of the decoder firmware, so it's cx23415 only.
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_GET_FRAMEBUFFER
+Enum   65/0x41
+Description
+       Return base and length of contiguous OSD memory.
+Result[0]
+       OSD base address
+Result[1]
+       OSD length
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_GET_PIXEL_FORMAT
+Enum   66/0x42
+Description
+       Query OSD format
+Result[0]
+       0=8bit index, 4=AlphaRGB 8:8:8:8
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_SET_PIXEL_FORMAT
+Enum   67/0x43
+Description
+       Assign pixel format
+Param[0]
+       0=8bit index, 4=AlphaRGB 8:8:8:8
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_GET_STATE
+Enum   68/0x44
+Description
+       Query OSD state
+Result[0]
+       Bit  0   0=off, 1=on
+       Bits 1:2 alpha control
+       Bits 3:5 pixel format
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_SET_STATE
+Enum   69/0x45
+Description
+       OSD switch
+Param[0]
+       0=off, 1=on
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_GET_OSD_COORDS
+Enum   70/0x46
+Description
+       Retrieve coordinates of OSD area blended with video
+Result[0]
+       OSD buffer address
+Result[1]
+       Stride in pixels
+Result[2]
+       Lines in OSD buffer
+Result[3]
+       Horizontal offset in buffer
+Result[4]
+       Vertical offset in buffer
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_SET_OSD_COORDS
+Enum   71/0x47
+Description
+       Assign the coordinates of the OSD area to blend with video
+Param[0]
+       buffer address
+Param[1]
+       buffer stride in pixels
+Param[2]
+       lines in buffer
+Param[3]
+       horizontal offset
+Param[4]
+       vertical offset
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_GET_SCREEN_COORDS
+Enum   72/0x48
+Description
+       Retrieve OSD screen area coordinates
+Result[0]
+       top left horizontal offset
+Result[1]
+       top left vertical offset
+Result[2]
+       bottom right hotizontal offset
+Result[3]
+       bottom right vertical offset
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_SET_SCREEN_COORDS
+Enum   73/0x49
+Description
+       Assign the coordinates of the screen area to blend with video
+Param[0]
+       top left horizontal offset
+Param[1]
+       top left vertical offset
+Param[2]
+       bottom left horizontal offset
+Param[3]
+       bottom left vertical offset
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_GET_GLOBAL_ALPHA
+Enum   74/0x4A
+Description
+       Retrieve OSD global alpha
+Result[0]
+       global alpha: 0=off, 1=on
+Result[1]
+       bits 0:7 global alpha
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_SET_GLOBAL_ALPHA
+Enum   75/0x4B
+Description
+       Update global alpha
+Param[0]
+       global alpha: 0=off, 1=on
+Param[1]
+       global alpha (8 bits)
+Param[2]
+       local alpha: 0=on, 1=off
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_SET_BLEND_COORDS
+Enum   78/0x4C
+Description
+       Move start of blending area within display buffer
+Param[0]
+       horizontal offset in buffer
+Param[1]
+       vertical offset in buffer
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_GET_FLICKER_STATE
+Enum   79/0x4F
+Description
+       Retrieve flicker reduction module state
+Result[0]
+       flicker state: 0=off, 1=on
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_SET_FLICKER_STATE
+Enum   80/0x50
+Description
+       Set flicker reduction module state
+Param[0]
+       State: 0=off, 1=on
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_BLT_COPY
+Enum   82/0x52
+Description
+       BLT copy
+Param[0]
+'0000'  zero
+'0001' ~destination AND ~source
+'0010' ~destination AND  source
+'0011' ~destination
+'0100'  destination AND ~source
+'0101'                  ~source
+'0110'  destination XOR  source
+'0111' ~destination OR  ~source
+'1000' ~destination AND ~source
+'1001'  destination XNOR source
+'1010'                   source
+'1011' ~destination OR   source
+'1100'  destination
+'1101'  destination OR  ~source
+'1110'  destination OR   source
+'1111'  one
+
+Param[1]
+       Resulting alpha blending
+           '01' source_alpha
+           '10' destination_alpha
+           '11' source_alpha*destination_alpha+1
+                (zero if both source and destination alpha are zero)
+Param[2]
+       '00' output_pixel = source_pixel
+
+       '01' if source_alpha=0:
+                output_pixel = destination_pixel
+            if 256 > source_alpha > 1:
+                output_pixel = ((source_alpha + 1)*source_pixel +
+                                (255 - source_alpha)*destination_pixel)/256
+
+       '10' if destination_alpha=0:
+                output_pixel = source_pixel
+             if 255 > destination_alpha > 0:
+                output_pixel = ((255 - destination_alpha)*source_pixel +
+                                (destination_alpha + 1)*destination_pixel)/256
+
+       '11' if source_alpha=0:
+                source_temp = 0
+            if source_alpha=255:
+                source_temp = source_pixel*256
+            if 255 > source_alpha > 0:
+                source_temp = source_pixel*(source_alpha + 1)
+            if destination_alpha=0:
+                destination_temp = 0
+            if destination_alpha=255:
+                destination_temp = destination_pixel*256
+            if 255 > destination_alpha > 0:
+                destination_temp = destination_pixel*(destination_alpha + 1)
+            output_pixel = (source_temp + destination_temp)/256
+Param[3]
+       width
+Param[4]
+       height
+Param[5]
+       destination pixel mask
+Param[6]
+       destination rectangle start address
+Param[7]
+       destination stride in dwords
+Param[8]
+       source stride in dwords
+Param[9]
+       source rectangle start address
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_BLT_FILL
+Enum   83/0x53
+Description
+       BLT fill color
+Param[0]
+       Same as Param[0] on API 0x52
+Param[1]
+       Same as Param[1] on API 0x52
+Param[2]
+       Same as Param[2] on API 0x52
+Param[3]
+       width
+Param[4]
+       height
+Param[5]
+       destination pixel mask
+Param[6]
+       destination rectangle start address
+Param[7]
+       destination stride in dwords
+Param[8]
+       color fill value
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_BLT_TEXT
+Enum   84/0x54
+Description
+       BLT for 8 bit alpha text source
+Param[0]
+       Same as Param[0] on API 0x52
+Param[1]
+       Same as Param[1] on API 0x52
+Param[2]
+       Same as Param[2] on API 0x52
+Param[3]
+       width
+Param[4]
+       height
+Param[5]
+       destination pixel mask
+Param[6]
+       destination rectangle start address
+Param[7]
+       destination stride in dwords
+Param[8]
+       source stride in dwords
+Param[9]
+       source rectangle start address
+Param[10]
+       color fill value
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_SET_FRAMEBUFFER_WINDOW
+Enum   86/0x56
+Description
+       Positions the main output window on the screen. The coordinates must be
+       such that the entire window fits on the screen.
+Param[0]
+       window width
+Param[1]
+       window height
+Param[2]
+       top left window corner horizontal offset
+Param[3]
+       top left window corner vertical offset
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_SET_CHROMA_KEY
+Enum   96/0x60
+Description
+       Chroma key switch and color
+Param[0]
+       state: 0=off, 1=on
+Param[1]
+       color
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_GET_ALPHA_CONTENT_INDEX
+Enum   97/0x61
+Description
+       Retrieve alpha content index
+Result[0]
+       alpha content index, Range 0:15
+
+-------------------------------------------------------------------------------
+
+Name   CX2341X_OSD_SET_ALPHA_CONTENT_INDEX
+Enum   98/0x62
+Description
+       Assign alpha content index
+Param[0]
+       alpha content index, range 0:15
diff --git a/Documentation/video4linux/cx2341x/fw-upload.txt b/Documentation/video4linux/cx2341x/fw-upload.txt
new file mode 100644 (file)
index 0000000..60c502c
--- /dev/null
@@ -0,0 +1,49 @@
+This document describes how to upload the cx2341x firmware to the card.
+
+How to find
+===========
+
+See the web pages of the various projects that uses this chip for information
+on how to obtain the firmware.
+
+The firmware stored in a Windows driver can be detected as follows:
+
+- Each firmware image is 256k bytes.
+- The 1st 32-bit word of the Encoder image is 0x0000da7
+- The 1st 32-bit word of the Decoder image is 0x00003a7
+- The 2nd 32-bit word of both images is 0xaa55bb66
+
+How to load
+===========
+
+- Issue the FWapi command to stop the encoder if it is running. Wait for the
+  command to complete.
+- Issue the FWapi command to stop the decoder if it is running. Wait for the
+  command to complete.
+- Issue the I2C command to the digitizer to stop emitting VSYNC events.
+- Issue the FWapi command to halt the encoder's firmware.
+- Sleep for 10ms.
+- Issue the FWapi command to halt the decoder's firmware.
+- Sleep for 10ms.
+- Write 0x00000000 to register 0x2800 to stop the Video Display Module.
+- Write 0x00000005 to register 0x2D00 to stop the AO (audio output?).
+- Write 0x00000000 to register 0xA064 to ping? the APU.
+- Write 0xFFFFFFFE to register 0x9058 to stop the VPU.
+- Write 0xFFFFFFFF to register 0x9054 to reset the HW blocks.
+- Write 0x00000001 to register 0x9050 to stop the SPU.
+- Sleep for 10ms.
+- Write 0x0000001A to register 0x07FC to init the Encoder SDRAM's pre-charge.
+- Write 0x80000640 to register 0x07F8 to init the Encoder SDRAM's refresh to 1us.
+- Write 0x0000001A to register 0x08FC to init the Decoder SDRAM's pre-charge.
+- Write 0x80000640 to register 0x08F8 to init the Decoder SDRAM's refresh to 1us.
+- Sleep for 512ms. (600ms is recommended)
+- Transfer the encoder's firmware image to offset 0 in Encoder memory space.
+- Transfer the decoder's firmware image to offset 0 in Decoder memory space.
+- Use a read-modify-write operation to Clear bit 0 of register 0x9050 to
+  re-enable the SPU.
+- Sleep for 1 second.
+- Use a read-modify-write operation to Clear bits 3 and 0 of register 0x9058
+  to re-enable the VPU.
+- Sleep for 1 second.
+- Issue status API commands to both firmware images to verify.
+
diff --git a/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt b/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt
new file mode 100644 (file)
index 0000000..93fec32
--- /dev/null
@@ -0,0 +1,54 @@
+The controls for the mux are GPIO [0,1] for source, and GPIO 2 for muting.
+
+GPIO0  GPIO1
+  0        0    TV Audio
+  1        0    FM radio
+  0        1    Line-In
+  1        1    Mono tuner bypass or CD passthru (tuner specific)
+
+GPIO 16(i believe) is tied to the IR port (if present).
+
+------------------------------------------------------------------------------------
+
+>From the data sheet:
+ Register 24'h20004  PCI Interrupt Status
+  bit [18]  IR_SMP_INT Set when 32 input samples have been collected over
+  gpio[16] pin into GP_SAMPLE register.
+
+What's missing from the data sheet:
+
+Setup 4KHz sampling rate (roughly 2x oversampled; good enough for our RC5
+compat remote)
+set register 0x35C050 to  0xa80a80
+
+enable sampling
+set register 0x35C054 to 0x5
+
+Of course, enable the IRQ bit 18 in the interrupt mask register .(and
+provide for a handler)
+
+GP_SAMPLE register is at 0x35C058
+
+Bits are then right shifted into the GP_SAMPLE register at the specified
+rate; you get an interrupt when a full DWORD is recieved.
+You need to recover the actual RC5 bits out of the (oversampled) IR sensor
+bits. (Hint: look for the 0/1and 1/0 crossings of the RC5 bi-phase data)  An
+actual raw RC5 code will span 2-3 DWORDS, depending on the actual alignment.
+
+I'm pretty sure when no IR signal is present the receiver is always in a
+marking state(1); but stray light, etc can cause intermittent noise values
+as well.  Remember, this is a free running sample of the IR receiver state
+over time, so don't assume any sample starts at any particular place.
+
+http://www.atmel.com/dyn/resources/prod_documents/doc2817.pdf
+This data sheet (google search) seems to have a lovely description of the
+RC5 basics
+
+http://users.pandora.be/nenya/electronics/rc5/  and more data
+
+http://www.ee.washington.edu/circuit_archive/text/ir_decode.txt
+and even a reference to how to decode a bi-phase data stream.
+
+http://www.xs4all.nl/~sbp/knowledge/ir/rc5.htm
+still more info
+
index 29340282ab5f6becb1fe5245d2dff29db0d3cdbf..cd584f20a997df1fc9700824ad95a551a1ef16d1 100644 (file)
@@ -1,9 +1,9 @@
 
-                       ET61X[12]51 PC Camera Controllers
-                                Driver for Linux
-                       =================================
+                      ET61X[12]51 PC Camera Controllers
+                               Driver for Linux
+                      =================================
 
-                               - Documentation -
+                              - Documentation -
 
 
 Index
@@ -156,46 +156,46 @@ Name:           video_nr
 Type:           short array (min = 0, max = 64)
 Syntax:         <-1|n[,...]>
 Description:    Specify V4L2 minor mode number:
-                -1 = use next available
-                 n = use minor number n
-                You can specify up to 64 cameras this way.
-                For example:
-                video_nr=-1,2,-1 would assign minor number 2 to the second
-                registered camera and use auto for the first one and for every
-                other camera.
+               -1 = use next available
+                n = use minor number n
+               You can specify up to 64 cameras this way.
+               For example:
+               video_nr=-1,2,-1 would assign minor number 2 to the second
+               registered camera and use auto for the first one and for every
+               other camera.
 Default:        -1
 -------------------------------------------------------------------------------
 Name:           force_munmap
 Type:           bool array (min = 0, max = 64)
 Syntax:         <0|1[,...]>
 Description:    Force the application to unmap previously mapped buffer memory
-                before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
-                all the applications support this feature. This parameter is
-                specific for each detected camera.
-                0 = do not force memory unmapping
-                1 = force memory unmapping (save memory)
+               before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+               all the applications support this feature. This parameter is
+               specific for each detected camera.
+               0 = do not force memory unmapping
+               1 = force memory unmapping (save memory)
 Default:        0
 -------------------------------------------------------------------------------
 Name:           frame_timeout
 Type:           uint array (min = 0, max = 64)
 Syntax:         <n[,...]>
 Description:    Timeout for a video frame in seconds. This parameter is
-                specific for each detected camera. This parameter can be
-                changed at runtime thanks to the /sys filesystem interface.
+               specific for each detected camera. This parameter can be
+               changed at runtime thanks to the /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 Name:           debug
 Type:           ushort
 Syntax:         <n>
 Description:    Debugging information level, from 0 to 3:
-                0 = none (use carefully)
-                1 = critical errors
-                2 = significant informations
-                3 = more verbose messages
-                Level 3 is useful for testing only, when only one device
-                is used at the same time. It also shows some more informations
-                about the hardware being detected. This module parameter can be
-                changed at runtime thanks to the /sys filesystem interface.
+               0 = none (use carefully)
+               1 = critical errors
+               2 = significant informations
+               3 = more verbose messages
+               Level 3 is useful for testing only, when only one device
+               is used at the same time. It also shows some more informations
+               about the hardware being detected. This module parameter can be
+               changed at runtime thanks to the /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 
index 4a40a2e99451a54702b1d2251cc8df2c77666fc0..397a94eb77b8cba67e3ae3303e32b5440926ee3c 100644 (file)
@@ -21,7 +21,7 @@ Internal interface: Video For Linux (V4L)
 Supported controls:
 - by V4L: Contrast,  Brightness, Color, Hue
 - by driver options: frame rate, lighting conditions, video format,
-                     default picture settings, sharpness.
+                    default picture settings, sharpness.
 
 SUPPORTED CAMERAS:
 
@@ -191,66 +191,66 @@ init_model2_sat Integer         0..255 [0x34]   init_model2_sat=65
 init_model2_yb  Integer         0..255 [0xa0]   init_model2_yb=200
 
 debug           You don't need this option unless you are a developer.
-                If you are a developer then you will see in the code
-                what values do what. 0=off.
+               If you are a developer then you will see in the code
+               what values do what. 0=off.
 
 flags           This is a bit mask, and you can combine any number of
-                bits to produce what you want. Usually you don't want
-                any of extra features this option provides:
-
-                FLAGS_RETRY_VIDIOCSYNC  1  This bit allows to retry failed
-                                           VIDIOCSYNC ioctls without failing.
-                                           Will work with xawtv, will not
-                                           with xrealproducer. Default is
-                                           not set.
-                FLAGS_MONOCHROME        2  Activates monochrome (b/w) mode.
-                FLAGS_DISPLAY_HINTS     4  Shows colored pixels which have
-                                           magic meaning to developers.
-                FLAGS_OVERLAY_STATS     8  Shows tiny numbers on screen,
-                                           useful only for debugging.
-                FLAGS_FORCE_TESTPATTERN 16 Shows blue screen with numbers.
-                FLAGS_SEPARATE_FRAMES   32 Shows each frame separately, as
-                                           it was received from the camera.
-                                           Default (not set) is to mix the
-                                           preceding frame in to compensate
-                                           for occasional loss of Isoc data
-                                           on high frame rates.
-                FLAGS_CLEAN_FRAMES      64 Forces "cleanup" of each frame
-                                           prior to use; relevant only if
-                                           FLAGS_SEPARATE_FRAMES is set.
-                                           Default is not to clean frames,
-                                           this is a little faster but may
-                                           produce flicker if frame rate is
-                                           too high and Isoc data gets lost.
-                FLAGS_NO_DECODING      128 This flag turns the video stream
-                                           decoder off, and dumps the raw
-                                           Isoc data from the camera into
-                                           the reading process. Useful to
-                                           developers, but not to users.
+               bits to produce what you want. Usually you don't want
+               any of extra features this option provides:
+
+               FLAGS_RETRY_VIDIOCSYNC  1  This bit allows to retry failed
+                                          VIDIOCSYNC ioctls without failing.
+                                          Will work with xawtv, will not
+                                          with xrealproducer. Default is
+                                          not set.
+               FLAGS_MONOCHROME        2  Activates monochrome (b/w) mode.
+               FLAGS_DISPLAY_HINTS     4  Shows colored pixels which have
+                                          magic meaning to developers.
+               FLAGS_OVERLAY_STATS     8  Shows tiny numbers on screen,
+                                          useful only for debugging.
+               FLAGS_FORCE_TESTPATTERN 16 Shows blue screen with numbers.
+               FLAGS_SEPARATE_FRAMES   32 Shows each frame separately, as
+                                          it was received from the camera.
+                                          Default (not set) is to mix the
+                                          preceding frame in to compensate
+                                          for occasional loss of Isoc data
+                                          on high frame rates.
+               FLAGS_CLEAN_FRAMES      64 Forces "cleanup" of each frame
+                                          prior to use; relevant only if
+                                          FLAGS_SEPARATE_FRAMES is set.
+                                          Default is not to clean frames,
+                                          this is a little faster but may
+                                          produce flicker if frame rate is
+                                          too high and Isoc data gets lost.
+               FLAGS_NO_DECODING      128 This flag turns the video stream
+                                          decoder off, and dumps the raw
+                                          Isoc data from the camera into
+                                          the reading process. Useful to
+                                          developers, but not to users.
 
 framerate       This setting controls frame rate of the camera. This is
-                an approximate setting (in terms of "worst" ... "best")
-                because camera changes frame rate depending on amount
-                of light available. Setting 0 is slowest, 6 is fastest.
-                Beware - fast settings are very demanding and may not
-                work well with all video sizes. Be conservative.
+               an approximate setting (in terms of "worst" ... "best")
+               because camera changes frame rate depending on amount
+               of light available. Setting 0 is slowest, 6 is fastest.
+               Beware - fast settings are very demanding and may not
+               work well with all video sizes. Be conservative.
 
 hue_correction  This highly optional setting allows to adjust the
-                hue of the image in a way slightly different from
-                what usual "hue" control does. Both controls affect
-                YUV colorspace: regular "hue" control adjusts only
-                U component, and this "hue_correction" option similarly
-                adjusts only V component. However usually it is enough
-                to tweak only U or V to compensate for colored light or
-                color temperature; this option simply allows more
-                complicated correction when and if it is necessary.
+               hue of the image in a way slightly different from
+               what usual "hue" control does. Both controls affect
+               YUV colorspace: regular "hue" control adjusts only
+               U component, and this "hue_correction" option similarly
+               adjusts only V component. However usually it is enough
+               to tweak only U or V to compensate for colored light or
+               color temperature; this option simply allows more
+               complicated correction when and if it is necessary.
 
 init_brightness These settings specify _initial_ values which will be
 init_contrast   used to set up the camera. If your V4L application has
 init_color      its own controls to adjust the picture then these
 init_hue        controls will be used too. These options allow you to
-                preconfigure the camera when it gets connected, before
-                any V4L application connects to it. Good for webcams.
+               preconfigure the camera when it gets connected, before
+               any V4L application connects to it. Good for webcams.
 
 init_model2_rg  These initial settings alter color balance of the
 init_model2_rg2 camera on hardware level. All four settings may be used
@@ -258,47 +258,47 @@ init_model2_sat to tune the camera to specific lighting conditions. These
 init_model2_yb  settings only apply to Model 2 cameras.
 
 lighting        This option selects one of three hardware-defined
-                photosensitivity settings of the camera. 0=bright light,
-                1=Medium (default), 2=Low light. This setting affects
-                frame rate: the dimmer the lighting the lower the frame
-                rate (because longer exposition time is needed). The
-                Model 2 cameras allow values more than 2 for this option,
-                thus enabling extremely high sensitivity at cost of frame
-                rate, color saturation and imaging sensor noise.
+               photosensitivity settings of the camera. 0=bright light,
+               1=Medium (default), 2=Low light. This setting affects
+               frame rate: the dimmer the lighting the lower the frame
+               rate (because longer exposition time is needed). The
+               Model 2 cameras allow values more than 2 for this option,
+               thus enabling extremely high sensitivity at cost of frame
+               rate, color saturation and imaging sensor noise.
 
 sharpness       This option controls smoothing (noise reduction)
-                made by camera. Setting 0 is most smooth, setting 6
-                is most sharp. Be aware that CMOS sensor used in the
-                camera is pretty noisy, so if you choose 6 you will
-                be greeted with "snowy" image. Default is 4. Model 2
-                cameras do not support this feature.
+               made by camera. Setting 0 is most smooth, setting 6
+               is most sharp. Be aware that CMOS sensor used in the
+               camera is pretty noisy, so if you choose 6 you will
+               be greeted with "snowy" image. Default is 4. Model 2
+               cameras do not support this feature.
 
 size            This setting chooses one of several image sizes that are
-                supported by this driver. Cameras may support more, but
-                it's difficult to reverse-engineer all formats.
-                Following video sizes are supported:
-
-                size=0     128x96  (Model 1 only)
-                size=1     160x120
-                size=2     176x144
-                size=3     320x240 (Model 2 only)
-                size=4     352x240 (Model 2 only)
-                size=5     352x288
-                size=6     640x480 (Model 3 only)
-
-                The 352x288 is the native size of the Model 1 sensor
-                array, so it's the best resolution the camera can
-                yield. The best resolution of Model 2 is 176x144, and
-                larger images are produced by stretching the bitmap.
-                Model 3 has sensor with 640x480 grid, and it works too,
-                but the frame rate will be exceptionally low (1-2 FPS);
-                it may be still OK for some applications, like security.
-                Choose the image size you need. The smaller image can
-                support faster frame rate. Default is 352x288.
+               supported by this driver. Cameras may support more, but
+               it's difficult to reverse-engineer all formats.
+               Following video sizes are supported:
+
+               size=0     128x96  (Model 1 only)
+               size=1     160x120
+               size=2     176x144
+               size=3     320x240 (Model 2 only)
+               size=4     352x240 (Model 2 only)
+               size=5     352x288
+               size=6     640x480 (Model 3 only)
+
+               The 352x288 is the native size of the Model 1 sensor
+               array, so it's the best resolution the camera can
+               yield. The best resolution of Model 2 is 176x144, and
+               larger images are produced by stretching the bitmap.
+               Model 3 has sensor with 640x480 grid, and it works too,
+               but the frame rate will be exceptionally low (1-2 FPS);
+               it may be still OK for some applications, like security.
+               Choose the image size you need. The smaller image can
+               support faster frame rate. Default is 352x288.
 
 For more information and the Troubleshooting FAQ visit this URL:
 
-                http://www.linux-usb.org/ibmcam/
+               http://www.linux-usb.org/ibmcam/
 
 WHAT NEEDS TO BE DONE:
 
index 142741e3c578693c06d73cd3246ba391456271e1..79af610d4ba59175ebabcb3cb18c58dfc937d914 100644 (file)
@@ -81,7 +81,7 @@ MODULE PARAMETERS:
   TYPE: integer (Boolean)
   DEFAULT: 1
   DESC: Brightness is normally under automatic control and can't be set
-        manually by the video app. Set to 0 for manual control.
+       manually by the video app. Set to 0 for manual control.
 
   NAME: autogain
   TYPE: integer (Boolean)
@@ -97,13 +97,13 @@ MODULE PARAMETERS:
   TYPE: integer (0-6)
   DEFAULT: 3
   DESC: Sets the threshold for printing debug messages. The higher the value,
-        the more is printed. The levels are cumulative, and are as follows:
-          0=no debug messages
-          1=init/detection/unload and other significant messages
-          2=some warning messages
-          3=config/control function calls
-          4=most function calls and data parsing messages
-          5=highly repetitive mesgs
+       the more is printed. The levels are cumulative, and are as follows:
+         0=no debug messages
+         1=init/detection/unload and other significant messages
+         2=some warning messages
+         3=config/control function calls
+         4=most function calls and data parsing messages
+         5=highly repetitive mesgs
 
   NAME: snapshot
   TYPE: integer (Boolean)
@@ -116,24 +116,24 @@ MODULE PARAMETERS:
   TYPE: integer (1-4 for OV511, 1-31 for OV511+)
   DEFAULT: 1
   DESC: Number of cameras allowed to stream simultaneously on a single bus.
-        Values higher than 1 reduce the data rate of each camera, allowing two
-        or more to be used at once. If you have a complicated setup involving
-        both OV511 and OV511+ cameras, trial-and-error may be necessary for
-        finding the optimum setting.
+       Values higher than 1 reduce the data rate of each camera, allowing two
+       or more to be used at once. If you have a complicated setup involving
+       both OV511 and OV511+ cameras, trial-and-error may be necessary for
+       finding the optimum setting.
 
   NAME: compress
   TYPE: integer (Boolean)
   DEFAULT: 0
   DESC: Set this to 1 to turn on the camera's compression engine. This can
-        potentially increase the frame rate at the expense of quality, if you
-        have a fast CPU. You must load the proper compression module for your
-        camera before starting your application (ov511_decomp or ov518_decomp).
+       potentially increase the frame rate at the expense of quality, if you
+       have a fast CPU. You must load the proper compression module for your
+       camera before starting your application (ov511_decomp or ov518_decomp).
 
   NAME: testpat
   TYPE: integer (Boolean)
   DEFAULT: 0
   DESC: This configures the camera's sensor to transmit a colored test-pattern
-        instead of an image. This does not work correctly yet.
+       instead of an image. This does not work correctly yet.
 
   NAME: dumppix
   TYPE: integer (0-2)
index 142920bc011fb9120314182addc312ce57d8c0f8..1d20895b4354b99f2da591adac5027daec0253ff 100644 (file)
@@ -1,9 +1,9 @@
 
-                         SN9C10x PC Camera Controllers
-                                Driver for Linux
-                         =============================
+                        SN9C10x PC Camera Controllers
+                               Driver for Linux
+                        =============================
 
-                               - Documentation -
+                              - Documentation -
 
 
 Index
@@ -176,46 +176,46 @@ Name:           video_nr
 Type:           short array (min = 0, max = 64)
 Syntax:         <-1|n[,...]>
 Description:    Specify V4L2 minor mode number:
-                -1 = use next available
-                 n = use minor number n
-                You can specify up to 64 cameras this way.
-                For example:
-                video_nr=-1,2,-1 would assign minor number 2 to the second
-                recognized camera and use auto for the first one and for every
-                other camera.
+               -1 = use next available
+                n = use minor number n
+               You can specify up to 64 cameras this way.
+               For example:
+               video_nr=-1,2,-1 would assign minor number 2 to the second
+               recognized camera and use auto for the first one and for every
+               other camera.
 Default:        -1
 -------------------------------------------------------------------------------
 Name:           force_munmap
 Type:           bool array (min = 0, max = 64)
 Syntax:         <0|1[,...]>
 Description:    Force the application to unmap previously mapped buffer memory
-                before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
-                all the applications support this feature. This parameter is
-                specific for each detected camera.
-                0 = do not force memory unmapping
-                1 = force memory unmapping (save memory)
+               before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+               all the applications support this feature. This parameter is
+               specific for each detected camera.
+               0 = do not force memory unmapping
+               1 = force memory unmapping (save memory)
 Default:        0
 -------------------------------------------------------------------------------
 Name:           frame_timeout
 Type:           uint array (min = 0, max = 64)
 Syntax:         <n[,...]>
 Description:    Timeout for a video frame in seconds. This parameter is
-                specific for each detected camera. This parameter can be
-                changed at runtime thanks to the /sys filesystem interface.
+               specific for each detected camera. This parameter can be
+               changed at runtime thanks to the /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 Name:           debug
 Type:           ushort
 Syntax:         <n>
 Description:    Debugging information level, from 0 to 3:
-                0 = none (use carefully)
-                1 = critical errors
-                2 = significant informations
-                3 = more verbose messages
-                Level 3 is useful for testing only, when only one device
-                is used. It also shows some more informations about the
-                hardware being detected. This parameter can be changed at
-                runtime thanks to the /sys filesystem interface.
+               0 = none (use carefully)
+               1 = critical errors
+               2 = significant informations
+               3 = more verbose messages
+               Level 3 is useful for testing only, when only one device
+               is used. It also shows some more informations about the
+               hardware being detected. This parameter can be changed at
+               runtime thanks to the /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 
@@ -280,24 +280,24 @@ Byte #  Value         Description
 0x04    0xC4          Frame synchronisation pattern.
 0x05    0x96          Frame synchronisation pattern.
 0x06    0xXX          Unknown meaning. The exact value depends on the chip;
-                      possible values are 0x00, 0x01 and 0x20.
+                     possible values are 0x00, 0x01 and 0x20.
 0x07    0xXX          Variable value, whose bits are ff00uzzc, where ff is a
-                      frame counter, u is unknown, zz is a size indicator
-                      (00 = VGA, 01 = SIF, 10 = QSIF) and c stands for
-                      "compression enabled" (1 = yes, 0 = no).
+                     frame counter, u is unknown, zz is a size indicator
+                     (00 = VGA, 01 = SIF, 10 = QSIF) and c stands for
+                     "compression enabled" (1 = yes, 0 = no).
 0x08    0xXX          Brightness sum inside Auto-Exposure area (low-byte).
 0x09    0xXX          Brightness sum inside Auto-Exposure area (high-byte).
-                      For a pure white image, this number will be equal to 500
-                      times the area of the specified AE area. For images
-                      that are not pure white, the value scales down according
-                      to relative whiteness.
+                     For a pure white image, this number will be equal to 500
+                     times the area of the specified AE area. For images
+                     that are not pure white, the value scales down according
+                     to relative whiteness.
 0x0A    0xXX          Brightness sum outside Auto-Exposure area (low-byte).
 0x0B    0xXX          Brightness sum outside Auto-Exposure area (high-byte).
-                      For a pure white image, this number will be equal to 125
-                      times the area outside of the specified AE area. For
-                      images that are not pure white, the value scales down
-                      according to relative whiteness.
-                      according to relative whiteness.
+                     For a pure white image, this number will be equal to 125
+                     times the area outside of the specified AE area. For
+                     images that are not pure white, the value scales down
+                     according to relative whiteness.
+                     according to relative whiteness.
 
 The following bytes are used by the SN9C103 bridge only:
 
diff --git a/Documentation/video4linux/v4lgrab.c b/Documentation/video4linux/v4lgrab.c
new file mode 100644 (file)
index 0000000..079b628
--- /dev/null
@@ -0,0 +1,192 @@
+/* Simple Video4Linux image grabber. */
+/*
+ *     Video4Linux Driver Test/Example Framegrabbing Program
+ *
+ *     Compile with:
+ *             gcc -s -Wall -Wstrict-prototypes v4lgrab.c -o v4lgrab
+ *      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
+ *      with minor modifications (Dave Forrest, drf5n@virginia.edu).
+ *
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+
+#include <linux/types.h>
+#include <linux/videodev.h>
+
+#define FILE "/dev/video0"
+
+/* Stole this from tvset.c */
+
+#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);                                \
+       }                                                               \
+}
+
+int get_brightness_adj(unsigned char *image, long size, int *brightness) {
+  long i, tot = 0;
+  for (i=0;i<size*3;i++)
+    tot += image[i];
+  *brightness = (128 - tot/(size*3))/3;
+  return !((tot/(size*3)) >= 126 && (tot/(size*3)) <= 130);
+}
+
+int main(int argc, char ** argv)
+{
+  int fd = open(FILE, O_RDONLY), f;
+  struct video_capability cap;
+  struct video_window win;
+  struct video_picture vpic;
+
+  unsigned char *buffer, *src;
+  int bpp = 24, r, g, b;
+  unsigned int i, src_depth;
+
+  if (fd < 0) {
+    perror(FILE);
+    exit(1);
+  }
+
+  if (ioctl(fd, VIDIOCGCAP, &cap) < 0) {
+    perror("VIDIOGCAP");
+    fprintf(stderr, "(" FILE " not a video4linux device?)\n");
+    close(fd);
+    exit(1);
+  }
+
+  if (ioctl(fd, VIDIOCGWIN, &win) < 0) {
+    perror("VIDIOCGWIN");
+    close(fd);
+    exit(1);
+  }
+
+  if (ioctl(fd, VIDIOCGPICT, &vpic) < 0) {
+    perror("VIDIOCGPICT");
+    close(fd);
+    exit(1);
+  }
+
+  if (cap.type & VID_TYPE_MONOCHROME) {
+    vpic.depth=8;
+    vpic.palette=VIDEO_PALETTE_GREY;    /* 8bit grey */
+    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);
+       }
+      }
+    }
+  } 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;
+       }
+      }
+    }
+  }
+
+  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);
+    f = get_brightness_adj(buffer, win.width * win.height, &newbright);
+    if (f) {
+      vpic.brightness += (newbright << 8);
+      if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
+       perror("VIDIOSPICT");
+       break;
+      }
+    }
+  } while (f);
+
+  fprintf(stdout, "P6\n%d %d 255\n", win.width, win.height);
+
+  src = buffer;
+
+  for (i = 0; i < win.width * win.height; i++) {
+    READ_VIDEO_PIXEL(src, vpic.palette, src_depth, r, g, b);
+    fputc(r>>8, stdout);
+    fputc(g>>8, stdout);
+    fputc(b>>8, stdout);
+  }
+
+  close(fd);
+  return 0;
+}
index 3b704f2aae6dc9218df5f788b92f83818a3c1c9b..0d53ce774b01c75b26d5fb2aff1ce1e9098071de 100644 (file)
@@ -1,9 +1,9 @@
 
-                   W996[87]CF JPEG USB Dual Mode Camera Chip
-                     Driver for Linux 2.6 (basic version)
-                   =========================================
+                  W996[87]CF JPEG USB Dual Mode Camera Chip
+                    Driver for Linux 2.6 (basic version)
+                  =========================================
 
-                               - Documentation -
+                              - Documentation -
 
 
 Index
@@ -188,57 +188,57 @@ Name:            ovmod_load
 Type:            bool
 Syntax:          <0|1>
 Description:     Automatic 'ovcamchip' module loading: 0 disabled, 1 enabled.
-                 If enabled, 'insmod' searches for the required 'ovcamchip'
-                 module in the system, according to its configuration, and
-                 loads that module automatically. This action is performed as
-                 once soon as the 'w9968cf' module is loaded into memory.
+                If enabled, 'insmod' searches for the required 'ovcamchip'
+                module in the system, according to its configuration, and
+                loads that module automatically. This action is performed as
+                once soon as the 'w9968cf' module is loaded into memory.
 Default:         1
 Note:            The kernel must be compiled with the CONFIG_KMOD option
-                 enabled for the 'ovcamchip' module to be loaded and for
-                 this parameter to be present.
+                enabled for the 'ovcamchip' module to be loaded and for
+                this parameter to be present.
 -------------------------------------------------------------------------------
 Name:           simcams
 Type:           int
 Syntax:         <n>
 Description:    Number of cameras allowed to stream simultaneously.
-                n may vary from 0 to 32.
+               n may vary from 0 to 32.
 Default:        32
 -------------------------------------------------------------------------------
 Name:           video_nr
 Type:           int array (min = 0, max = 32)
 Syntax:         <-1|n[,...]>
 Description:    Specify V4L minor mode number.
-                -1 = use next available
-                 n = use minor number n
-                You can specify up to 32 cameras this way.
-                For example:
-                video_nr=-1,2,-1 would assign minor number 2 to the second
-                recognized camera and use auto for the first one and for every
-                other camera.
+               -1 = use next available
+                n = use minor number n
+               You can specify up to 32 cameras this way.
+               For example:
+               video_nr=-1,2,-1 would assign minor number 2 to the second
+               recognized camera and use auto for the first one and for every
+               other camera.
 Default:        -1
 -------------------------------------------------------------------------------
 Name:           packet_size
 Type:           int array (min = 0, max = 32)
 Syntax:         <n[,...]>
 Description:    Specify the maximum data payload size in bytes for alternate
-                settings, for each device. n is scaled between 63 and 1023.
+               settings, for each device. n is scaled between 63 and 1023.
 Default:        1023
 -------------------------------------------------------------------------------
 Name:           max_buffers
 Type:           int array (min = 0, max = 32)
 Syntax:         <n[,...]>
 Description:    For advanced users.
-                Specify the maximum number of video frame buffers to allocate
-                for each device, from 2 to 32.
+               Specify the maximum number of video frame buffers to allocate
+               for each device, from 2 to 32.
 Default:        2
 -------------------------------------------------------------------------------
 Name:           double_buffer
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Hardware double buffering: 0 disabled, 1 enabled.
-                It should be enabled if you want smooth video output: if you
-                obtain out of sync. video, disable it, or try to
-                decrease the 'clockdiv' module parameter value.
+               It should be enabled if you want smooth video output: if you
+               obtain out of sync. video, disable it, or try to
+               decrease the 'clockdiv' module parameter value.
 Default:        1 for every device.
 -------------------------------------------------------------------------------
 Name:           clamping
@@ -251,9 +251,9 @@ Name:           filter_type
 Type:           int array (min = 0, max = 32)
 Syntax:         <0|1|2[,...]>
 Description:    Video filter type.
-                0 none, 1 (1-2-1) 3-tap filter, 2 (2-3-6-3-2) 5-tap filter.
-                The filter is used to reduce noise and aliasing artifacts
-                produced by the CCD or CMOS image sensor.
+               0 none, 1 (1-2-1) 3-tap filter, 2 (2-3-6-3-2) 5-tap filter.
+               The filter is used to reduce noise and aliasing artifacts
+               produced by the CCD or CMOS image sensor.
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           largeview
@@ -266,9 +266,9 @@ Name:           upscaling
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Software scaling (for non-compressed video only):
-                0 disabled, 1 enabled.
-                Disable it if you have a slow CPU or you don't have enough
-                memory.
+               0 disabled, 1 enabled.
+               Disable it if you have a slow CPU or you don't have enough
+               memory.
 Default:        0 for every device.
 Note:           If 'w9968cf-vpp' is not present, this parameter is set to 0.
 -------------------------------------------------------------------------------
@@ -276,36 +276,36 @@ Name:           decompression
 Type:           int array (min = 0, max = 32)
 Syntax:         <0|1|2[,...]>
 Description:    Software video decompression:
-                0 = disables decompression
-                    (doesn't allow formats needing decompression).
-                1 = forces decompression
-                    (allows formats needing decompression only).
-                2 = allows any permitted formats.
-                Formats supporting (de)compressed video are YUV422P and
-                YUV420P/YUV420 in any resolutions where width and height are
-                multiples of 16.
+               0 = disables decompression
+                   (doesn't allow formats needing decompression).
+               1 = forces decompression
+                   (allows formats needing decompression only).
+               2 = allows any permitted formats.
+               Formats supporting (de)compressed video are YUV422P and
+               YUV420P/YUV420 in any resolutions where width and height are
+               multiples of 16.
 Default:        2 for every device.
 Note:           If 'w9968cf-vpp' is not present, forcing decompression is not
-                allowed; in this case this parameter is set to 2.
+               allowed; in this case this parameter is set to 2.
 -------------------------------------------------------------------------------
 Name:           force_palette
 Type:           int array (min = 0, max = 32)
 Syntax:         <0|9|10|13|15|8|7|1|6|3|4|5[,...]>
 Description:    Force picture palette.
-                In order:
-                 0 = Off - allows any of the following formats:
-                 9 = UYVY    16 bpp - Original video, compression disabled
-                10 = YUV420  12 bpp - Original video, compression enabled
-                13 = YUV422P 16 bpp - Original video, compression enabled
-                15 = YUV420P 12 bpp - Original video, compression enabled
-                 8 = YUVY    16 bpp - Software conversion from UYVY
-                 7 = YUV422  16 bpp - Software conversion from UYVY
-                 1 = GREY     8 bpp - Software conversion from UYVY
-                 6 = RGB555  16 bpp - Software conversion from UYVY
-                 3 = RGB565  16 bpp - Software conversion from UYVY
-                 4 = RGB24   24 bpp - Software conversion from UYVY
-                 5 = RGB32   32 bpp - Software conversion from UYVY
-                When not 0, this parameter will override 'decompression'.
+               In order:
+                0 = Off - allows any of the following formats:
+                9 = UYVY    16 bpp - Original video, compression disabled
+               10 = YUV420  12 bpp - Original video, compression enabled
+               13 = YUV422P 16 bpp - Original video, compression enabled
+               15 = YUV420P 12 bpp - Original video, compression enabled
+                8 = YUVY    16 bpp - Software conversion from UYVY
+                7 = YUV422  16 bpp - Software conversion from UYVY
+                1 = GREY     8 bpp - Software conversion from UYVY
+                6 = RGB555  16 bpp - Software conversion from UYVY
+                3 = RGB565  16 bpp - Software conversion from UYVY
+                4 = RGB24   24 bpp - Software conversion from UYVY
+                5 = RGB32   32 bpp - Software conversion from UYVY
+               When not 0, this parameter will override 'decompression'.
 Default:        0 for every device. Initial palette is 9 (UYVY).
 Note:           If 'w9968cf-vpp' is not present, this parameter is set to 9.
 -------------------------------------------------------------------------------
@@ -313,77 +313,77 @@ Name:           force_rgb
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Read RGB video data instead of BGR:
-                1 = use RGB component ordering.
-                0 = use BGR component ordering.
-                This parameter has effect when using RGBX palettes only.
+               1 = use RGB component ordering.
+               0 = use BGR component ordering.
+               This parameter has effect when using RGBX palettes only.
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           autobright
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Image sensor automatically changes brightness:
-                0 = no, 1 = yes
+               0 = no, 1 = yes
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           autoexp
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Image sensor automatically changes exposure:
-                0 = no, 1 = yes
+               0 = no, 1 = yes
 Default:        1 for every device.
 -------------------------------------------------------------------------------
 Name:           lightfreq
 Type:           int array (min = 0, max = 32)
 Syntax:         <50|60[,...]>
 Description:    Light frequency in Hz:
-                50 for European and Asian lighting, 60 for American lighting.
+               50 for European and Asian lighting, 60 for American lighting.
 Default:        50 for every device.
 -------------------------------------------------------------------------------
 Name:           bandingfilter
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Banding filter to reduce effects of fluorescent
-                lighting:
-                0 disabled, 1 enabled.
-                This filter tries to reduce the pattern of horizontal
-                light/dark bands caused by some (usually fluorescent) lighting.
+               lighting:
+               0 disabled, 1 enabled.
+               This filter tries to reduce the pattern of horizontal
+               light/dark bands caused by some (usually fluorescent) lighting.
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           clockdiv
 Type:           int array (min = 0, max = 32)
 Syntax:         <-1|n[,...]>
 Description:    Force pixel clock divisor to a specific value (for experts):
-                n may vary from 0 to 127.
-                -1 for automatic value.
-                See also the 'double_buffer' module parameter.
+               n may vary from 0 to 127.
+               -1 for automatic value.
+               See also the 'double_buffer' module parameter.
 Default:        -1 for every device.
 -------------------------------------------------------------------------------
 Name:           backlight
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Objects are lit from behind:
-                0 = no, 1 = yes
+               0 = no, 1 = yes
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           mirror
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Reverse image horizontally:
-                0 = no, 1 = yes
+               0 = no, 1 = yes
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           monochrome
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    The image sensor is monochrome:
-                0 = no, 1 = yes
+               0 = no, 1 = yes
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           brightness
 Type:           long array (min = 0, max = 32)
 Syntax:         <n[,...]>
 Description:    Set picture brightness (0-65535).
-                This parameter has no effect if 'autobright' is enabled.
+               This parameter has no effect if 'autobright' is enabled.
 Default:        31000 for every device.
 -------------------------------------------------------------------------------
 Name:           hue
@@ -414,23 +414,23 @@ Name:           debug
 Type:           int
 Syntax:         <n>
 Description:    Debugging information level, from 0 to 6:
-                0 = none (use carefully)
-                1 = critical errors
-                2 = significant informations
-                3 = configuration or general messages
-                4 = warnings
-                5 = called functions
-                6 = function internals
-                Level 5 and 6 are useful for testing only, when only one
-                device is used.
+               0 = none (use carefully)
+               1 = critical errors
+               2 = significant informations
+               3 = configuration or general messages
+               4 = warnings
+               5 = called functions
+               6 = function internals
+               Level 5 and 6 are useful for testing only, when only one
+               device is used.
 Default:        2
 -------------------------------------------------------------------------------
 Name:           specific_debug
 Type:           bool
 Syntax:         <0|1>
 Description:    Enable or disable specific debugging messages:
-                0 = print messages concerning every level <= 'debug' level.
-                1 = print messages concerning the level indicated by 'debug'.
+               0 = print messages concerning every level <= 'debug' level.
+               1 = print messages concerning the level indicated by 'debug'.
 Default:        0
 -------------------------------------------------------------------------------
 
index f55262c6733b6c75eba2da87405462288a53e485..f406f5e800464dcd11315459575ad5fb141a752f 100644 (file)
@@ -1,9 +1,9 @@
 
-                    ZC0301 Image Processor and Control Chip
-                                Driver for Linux
-                    =======================================
+             ZC0301 and ZC0301P Image Processor and Control Chip
+                               Driver for Linux
+             ===================================================
 
-                               - Documentation -
+                              - Documentation -
 
 
 Index
@@ -51,13 +51,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 4. Overview and features
 ========================
-This driver supports the video interface of the devices mounting the ZC0301
-Image Processor and Control Chip.
+This driver supports the video interface of the devices mounting the ZC0301 or
+ZC0301P Image Processors and Control Chips.
 
 The driver relies on the Video4Linux2 and USB core modules. It has been
 designed to run properly on SMP systems as well.
 
-The latest version of the ZC0301 driver can be found at the following URL:
+The latest version of the ZC0301[P] driver can be found at the following URL:
 http://www.linux-projects.org/
 
 Some of the features of the driver are:
@@ -117,7 +117,7 @@ supported by the USB Audio driver thanks to the ALSA API:
 
 And finally:
 
-       # USB Multimedia devices
+       # V4L USB devices
        #
        CONFIG_USB_ZC0301=m
 
@@ -146,46 +146,46 @@ Name:           video_nr
 Type:           short array (min = 0, max = 64)
 Syntax:         <-1|n[,...]>
 Description:    Specify V4L2 minor mode number:
-                -1 = use next available
-                 n = use minor number n
-                You can specify up to 64 cameras this way.
-                For example:
-                video_nr=-1,2,-1 would assign minor number 2 to the second
-                registered camera and use auto for the first one and for every
-                other camera.
+               -1 = use next available
+                n = use minor number n
+               You can specify up to 64 cameras this way.
+               For example:
+               video_nr=-1,2,-1 would assign minor number 2 to the second
+               registered camera and use auto for the first one and for every
+               other camera.
 Default:        -1
 -------------------------------------------------------------------------------
 Name:           force_munmap
 Type:           bool array (min = 0, max = 64)
 Syntax:         <0|1[,...]>
 Description:    Force the application to unmap previously mapped buffer memory
-                before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
-                all the applications support this feature. This parameter is
-                specific for each detected camera.
-                0 = do not force memory unmapping
-                1 = force memory unmapping (save memory)
+               before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+               all the applications support this feature. This parameter is
+               specific for each detected camera.
+               0 = do not force memory unmapping
+               1 = force memory unmapping (save memory)
 Default:        0
 -------------------------------------------------------------------------------
 Name:           frame_timeout
 Type:           uint array (min = 0, max = 64)
 Syntax:         <n[,...]>
 Description:    Timeout for a video frame in seconds. This parameter is
-                specific for each detected camera. This parameter can be
-                changed at runtime thanks to the /sys filesystem interface.
+               specific for each detected camera. This parameter can be
+               changed at runtime thanks to the /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 Name:           debug
 Type:           ushort
 Syntax:         <n>
 Description:    Debugging information level, from 0 to 3:
-                0 = none (use carefully)
-                1 = critical errors
-                2 = significant informations
-                3 = more verbose messages
-                Level 3 is useful for testing only, when only one device
-                is used at the same time. It also shows some more informations
-                about the hardware being detected. This module parameter can be
-                changed at runtime thanks to the /sys filesystem interface.
+               0 = none (use carefully)
+               1 = critical errors
+               2 = significant informations
+               3 = more verbose messages
+               Level 3 is useful for testing only, when only one device
+               is used at the same time. It also shows some more informations
+               about the hardware being detected. This module parameter can be
+               changed at runtime thanks to the /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 
@@ -204,11 +204,25 @@ Vendor ID  Product ID
 0x041e     0x4017
 0x041e     0x401c
 0x041e     0x401e
+0x041e     0x401f
+0x041e     0x4022
 0x041e     0x4034
 0x041e     0x4035
+0x041e     0x4036
+0x041e     0x403a
+0x0458     0x7007
+0x0458     0x700C
+0x0458     0x700f
+0x046d     0x08ae
+0x055f     0xd003
+0x055f     0xd004
 0x046d     0x08ae
 0x0ac8     0x0301
+0x0ac8     0x301b
+0x0ac8     0x303b
+0x10fd     0x0128
 0x10fd     0x8050
+0x10fd     0x804e
 
 The list above does not imply that all those devices work with this driver: up
 until now only the ones that mount the following image sensors are supported;
@@ -217,6 +231,7 @@ kernel messages will always tell you whether this is the case:
 Model       Manufacturer
 -----       ------------
 PAS202BCB   PixArt Imaging, Inc.
+PB-0330     Photobit Corporation
 
 
 9. Notes for V4L2 application developers
@@ -250,5 +265,6 @@ the fingerprint is: '88E8 F32F 7244 68BA 3958  5D40 99DA 5D2A FCE6 35A4'.
   been taken from the documentation of the ZC030x Video4Linux1 driver written
   by Andrew Birkett <andy@nobugs.org>;
 - The initialization values of the ZC0301 controller connected to the PAS202BCB
-  image sensor have been taken from the SPCA5XX driver maintained by
-  Michel Xhaard <mxhaard@magic.fr>.
+  and PB-0330 image sensors have been taken from the SPCA5XX driver maintained
+  by Michel Xhaard <mxhaard@magic.fr>;
+- Stanislav Lechev donated one camera.
index de606dfa8db934dc53d24440a8f862372baf0ba4..302fc140154797e8d2d59045a40a940cad69092a 100644 (file)
@@ -702,7 +702,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
        /*
         * Mark this as IO
         */
-       vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
        if (remap_pfn_range(vma, vma->vm_start, phys,
index 99d333d7ebdd56c0d9424a5851efe3baaa55a080..a3745ed37f9fc5c81e75bf491cc00c8d83e46835 100644 (file)
 #include <linux/module.h>
 #include <linux/reboot.h>
 #include <linux/interrupt.h>
+#include <linux/reboot.h>
 
 #include <asm/mach-types.h>
 
-extern void ctrl_alt_del(void);
-
 static irqreturn_t nas100d_reset_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
        /* Signal init to do the ctrlaltdel action, this will bypass init if
index d80c362bc539dbedbc669745cc55b8166c648e76..6d38e97142cc0df151cd8c6380b894915e2b2423 100644 (file)
 #include <linux/module.h>
 #include <linux/reboot.h>
 #include <linux/interrupt.h>
+#include <linux/reboot.h>
 
 #include <asm/mach-types.h>
 
-extern void ctrl_alt_del(void);
-
 static irqreturn_t nslu2_power_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
        /* Signal init to do the ctrlaltdel action, this will bypass init if
index 24bc149889b6d00976ea3c0115546c0c5d2a1db0..1e9d062103aec24a993c8c0e4263e4e9778df9a3 100644 (file)
@@ -27,8 +27,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
        /* Leave vm_pgoff as-is, the PCI space address is the physical
         * address on this platform.
         */
-       vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
-
        prot = pgprot_val(vma->vm_page_prot);
        vma->vm_page_prot = __pgprot(prot);
 
index 05668e3598c030e739fa03db88d47553017b57ad..5fd65325b81afd2467efb5e5602edc4e4dc3ebee 100644 (file)
@@ -371,11 +371,11 @@ static int acpi_cpufreq_early_init_acpi(void)
 
        dprintk("acpi_cpufreq_early_init\n");
 
-       for_each_cpu(i) {
+       for_each_possible_cpu(i) {
                data = kzalloc(sizeof(struct acpi_processor_performance), 
                        GFP_KERNEL);
                if (!data) {
-                       for_each_cpu(j) {
+                       for_each_possible_cpu(j) {
                                kfree(acpi_perf_data[j]);
                                acpi_perf_data[j] = NULL;
                        }
@@ -584,7 +584,7 @@ acpi_cpufreq_exit (void)
 
        cpufreq_unregister_driver(&acpi_cpufreq_driver);
 
-       for_each_cpu(i) {
+       for_each_possible_cpu(i) {
                kfree(acpi_perf_data[i]);
                acpi_perf_data[i] = NULL;
        }
index 31c3a5baaa7fd25afdff2b5454a2a8cdf3887664..f7e4356f68202f472d4a94aa0684d05244792e1a 100644 (file)
@@ -361,11 +361,11 @@ static int centrino_cpu_early_init_acpi(void)
        unsigned int    i, j;
        struct acpi_processor_performance       *data;
 
-       for_each_cpu(i) {
+       for_each_possible_cpu(i) {
                data = kzalloc(sizeof(struct acpi_processor_performance), 
                                GFP_KERNEL);
                if (!data) {
-                       for_each_cpu(j) {
+                       for_each_possible_cpu(j) {
                                kfree(acpi_perf_data[j]);
                                acpi_perf_data[j] = NULL;
                        }
@@ -805,7 +805,7 @@ static void __exit centrino_exit(void)
        cpufreq_unregister_driver(&centrino_driver);
 
 #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
-       for_each_cpu(j) {
+       for_each_possible_cpu(j) {
                kfree(acpi_perf_data[j]);
                acpi_perf_data[j] = NULL;
        }
index 2b0cfce24a619af5105e11705adb771f5298c0a1..21dc1bbb806722bf26bf5d4348d01d386b72d7ce 100644 (file)
@@ -114,7 +114,8 @@ static int crash_nmi_callback(struct pt_regs *regs, int cpu)
        atomic_dec(&waiting_for_crash_ipi);
        /* Assume hlt works */
        halt();
-       for(;;);
+       for (;;)
+               cpu_relax();
 
        return 1;
 }
index 5edb1d379add9d24bd353e2ade6c176d0a3cdca5..b4d14c2eb345299db3366b1829332d9765260e14 100644 (file)
@@ -44,7 +44,8 @@ static void doublefault_fn(void)
                }
        }
 
-       for (;;) /* nothing */;
+       for (;;)
+               cpu_relax();
 }
 
 struct tss_struct doublefault_tss __cacheline_aligned = {
index e6023970aa405c11a9b8112fe2ba7c6b8e26bd3b..6c1639836e06f1ece348c0ace29156feb6fa2ad2 100644 (file)
@@ -61,7 +61,7 @@
 #include <asm/io_apic.h>
 #include <asm/ist.h>
 #include <asm/io.h>
-#include "setup_arch_pre.h"
+#include <setup_arch.h>
 #include <bios_ebda.h>
 
 /* Forward Declaration. */
@@ -411,8 +411,8 @@ static void __init limit_regions(unsigned long long size)
        }
 }
 
-static void __init add_memory_region(unsigned long long start,
-                                  unsigned long long size, int type)
+void __init add_memory_region(unsigned long long start,
+                             unsigned long long size, int type)
 {
        int x;
 
@@ -475,7 +475,7 @@ static struct change_member *change_point[2*E820MAX] __initdata;
 static struct e820entry *overlap_list[E820MAX] __initdata;
 static struct e820entry new_bios[E820MAX] __initdata;
 
-static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
+int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
 {
        struct change_member *change_tmp;
        unsigned long current_type, last_type;
@@ -644,7 +644,7 @@ static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
  * thinkpad 560x, for example, does not cooperate with the memory
  * detection code.)
  */
-static int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
+int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
 {
        /* Only one memory region (or negative)? Ignore it */
        if (nr_map < 2)
@@ -702,12 +702,6 @@ static inline void copy_edd(void)
 }
 #endif
 
-/*
- * Do NOT EVER look at the BIOS memory size location.
- * It does not work on many machines.
- */
-#define LOWMEMSIZE()   (0x9f000)
-
 static void __init parse_cmdline_early (char ** cmdline_p)
 {
        char c = ' ', *to = command_line, *from = saved_command_line;
@@ -1424,8 +1418,6 @@ static void __init register_memory(void)
                pci_mem_start, gapstart, gapsize);
 }
 
-static char * __init machine_specific_memory_setup(void);
-
 #ifdef CONFIG_MCA
 static void set_mca_bus(int x)
 {
@@ -1708,7 +1700,6 @@ static __init int add_pcspkr(void)
 }
 device_initcall(add_pcspkr);
 
-#include "setup_arch_post.h"
 /*
  * Local Variables:
  * mode:c
index 825b2b4ca721a1c931abb2114afd0483c6c3a1ae..bd0ca5c9f05330daacdf89326db21fc4a708d17b 100644 (file)
@@ -257,7 +257,7 @@ static void __init synchronize_tsc_bp (void)
                 * all APs synchronize but they loop on '== num_cpus'
                 */
                while (atomic_read(&tsc_count_start) != num_booting_cpus()-1)
-                       mb();
+                       cpu_relax();
                atomic_set(&tsc_count_stop, 0);
                wmb();
                /*
@@ -276,7 +276,7 @@ static void __init synchronize_tsc_bp (void)
                 * Wait for all APs to leave the synchronization point:
                 */
                while (atomic_read(&tsc_count_stop) != num_booting_cpus()-1)
-                       mb();
+                       cpu_relax();
                atomic_set(&tsc_count_start, 0);
                wmb();
                atomic_inc(&tsc_count_stop);
@@ -333,19 +333,21 @@ static void __init synchronize_tsc_ap (void)
         * this gets called, so we first wait for the BP to
         * finish SMP initialization:
         */
-       while (!atomic_read(&tsc_start_flag)) mb();
+       while (!atomic_read(&tsc_start_flag))
+               cpu_relax();
 
        for (i = 0; i < NR_LOOPS; i++) {
                atomic_inc(&tsc_count_start);
                while (atomic_read(&tsc_count_start) != num_booting_cpus())
-                       mb();
+                       cpu_relax();
 
                rdtscll(tsc_values[smp_processor_id()]);
                if (i == NR_LOOPS-1)
                        write_tsc(0, 0);
 
                atomic_inc(&tsc_count_stop);
-               while (atomic_read(&tsc_count_stop) != num_booting_cpus()) mb();
+               while (atomic_read(&tsc_count_stop) != num_booting_cpus())
+                       cpu_relax();
        }
 }
 #undef NR_LOOPS
@@ -1433,7 +1435,7 @@ int __devinit __cpu_up(unsigned int cpu)
        /* Unleash the CPU! */
        cpu_set(cpu, smp_commenced_mask);
        while (!cpu_isset(cpu, cpu_online_map))
-               mb();
+               cpu_relax();
        return 0;
 }
 
index 6979297ce278642c5b4c59844d626cddd7cfdcbd..c5aa65f7c02a68d096e966286f0dfdfcc879bed9 100644 (file)
@@ -528,6 +528,97 @@ static unsigned long __copy_user_zeroing_intel_nocache(void *to,
        return size;
 }
 
+static unsigned long __copy_user_intel_nocache(void *to,
+                               const void __user *from, unsigned long size)
+{
+        int d0, d1;
+
+       __asm__ __volatile__(
+              "        .align 2,0x90\n"
+              "0:      movl 32(%4), %%eax\n"
+              "        cmpl $67, %0\n"
+              "        jbe 2f\n"
+              "1:      movl 64(%4), %%eax\n"
+              "        .align 2,0x90\n"
+              "2:      movl 0(%4), %%eax\n"
+              "21:     movl 4(%4), %%edx\n"
+              "        movnti %%eax, 0(%3)\n"
+              "        movnti %%edx, 4(%3)\n"
+              "3:      movl 8(%4), %%eax\n"
+              "31:     movl 12(%4),%%edx\n"
+              "        movnti %%eax, 8(%3)\n"
+              "        movnti %%edx, 12(%3)\n"
+              "4:      movl 16(%4), %%eax\n"
+              "41:     movl 20(%4), %%edx\n"
+              "        movnti %%eax, 16(%3)\n"
+              "        movnti %%edx, 20(%3)\n"
+              "10:     movl 24(%4), %%eax\n"
+              "51:     movl 28(%4), %%edx\n"
+              "        movnti %%eax, 24(%3)\n"
+              "        movnti %%edx, 28(%3)\n"
+              "11:     movl 32(%4), %%eax\n"
+              "61:     movl 36(%4), %%edx\n"
+              "        movnti %%eax, 32(%3)\n"
+              "        movnti %%edx, 36(%3)\n"
+              "12:     movl 40(%4), %%eax\n"
+              "71:     movl 44(%4), %%edx\n"
+              "        movnti %%eax, 40(%3)\n"
+              "        movnti %%edx, 44(%3)\n"
+              "13:     movl 48(%4), %%eax\n"
+              "81:     movl 52(%4), %%edx\n"
+              "        movnti %%eax, 48(%3)\n"
+              "        movnti %%edx, 52(%3)\n"
+              "14:     movl 56(%4), %%eax\n"
+              "91:     movl 60(%4), %%edx\n"
+              "        movnti %%eax, 56(%3)\n"
+              "        movnti %%edx, 60(%3)\n"
+              "        addl $-64, %0\n"
+              "        addl $64, %4\n"
+              "        addl $64, %3\n"
+              "        cmpl $63, %0\n"
+              "        ja  0b\n"
+              "        sfence \n"
+              "5:      movl  %0, %%eax\n"
+              "        shrl  $2, %0\n"
+              "        andl $3, %%eax\n"
+              "        cld\n"
+              "6:      rep; movsl\n"
+              "        movl %%eax,%0\n"
+              "7:      rep; movsb\n"
+              "8:\n"
+              ".section .fixup,\"ax\"\n"
+              "9:      lea 0(%%eax,%0,4),%0\n"
+              "16:     jmp 8b\n"
+              ".previous\n"
+              ".section __ex_table,\"a\"\n"
+              "        .align 4\n"
+              "        .long 0b,16b\n"
+              "        .long 1b,16b\n"
+              "        .long 2b,16b\n"
+              "        .long 21b,16b\n"
+              "        .long 3b,16b\n"
+              "        .long 31b,16b\n"
+              "        .long 4b,16b\n"
+              "        .long 41b,16b\n"
+              "        .long 10b,16b\n"
+              "        .long 51b,16b\n"
+              "        .long 11b,16b\n"
+              "        .long 61b,16b\n"
+              "        .long 12b,16b\n"
+              "        .long 71b,16b\n"
+              "        .long 13b,16b\n"
+              "        .long 81b,16b\n"
+              "        .long 14b,16b\n"
+              "        .long 91b,16b\n"
+              "        .long 6b,9b\n"
+              "        .long 7b,16b\n"
+              ".previous"
+              : "=&c"(size), "=&D" (d0), "=&S" (d1)
+              :  "1"(to), "2"(from), "0"(size)
+              : "eax", "edx", "memory");
+       return size;
+}
+
 #else
 
 /*
@@ -694,6 +785,19 @@ unsigned long __copy_from_user_ll(void *to, const void __user *from,
 }
 EXPORT_SYMBOL(__copy_from_user_ll);
 
+unsigned long __copy_from_user_ll_nozero(void *to, const void __user *from,
+                                        unsigned long n)
+{
+       BUG_ON((long)n < 0);
+       if (movsl_is_ok(to, from, n))
+               __copy_user(to, from, n);
+       else
+               n = __copy_user_intel((void __user *)to,
+                                     (const void *)from, n);
+       return n;
+}
+EXPORT_SYMBOL(__copy_from_user_ll_nozero);
+
 unsigned long __copy_from_user_ll_nocache(void *to, const void __user *from,
                                        unsigned long n)
 {
@@ -709,6 +813,21 @@ unsigned long __copy_from_user_ll_nocache(void *to, const void __user *from,
        return n;
 }
 
+unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from,
+                                       unsigned long n)
+{
+       BUG_ON((long)n < 0);
+#ifdef CONFIG_X86_INTEL_USERCOPY
+       if ( n > 64 && cpu_has_xmm2)
+                n = __copy_user_intel_nocache(to, from, n);
+       else
+               __copy_user(to, from, n);
+#else
+        __copy_user(to, from, n);
+#endif
+       return n;
+}
+
 /**
  * copy_to_user: - Copy a block of data into user space.
  * @to:   Destination address, in user space.
index b4a7455c69939dbd226ed269bb1885352e2553a9..004837c587939f89e1dc0aad2136ac26529e58ac 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/interrupt.h>
 #include <asm/acpi.h>
 #include <asm/arch_hooks.h>
+#include <asm/e820.h>
+#include <asm/setup.h>
 
 #ifdef CONFIG_HOTPLUG_CPU
 #define DEFAULT_SEND_IPI       (1)
@@ -130,3 +132,44 @@ static int __init print_ipi_mode(void)
 }
 
 late_initcall(print_ipi_mode);
+
+/**
+ * machine_specific_memory_setup - Hook for machine specific memory setup.
+ *
+ * Description:
+ *     This is included late in kernel/setup.c so that it can make
+ *     use of all of the static functions.
+ **/
+
+char * __init machine_specific_memory_setup(void)
+{
+       char *who;
+
+
+       who = "BIOS-e820";
+
+       /*
+        * Try to copy the BIOS-supplied E820-map.
+        *
+        * Otherwise fake a memory map; one section from 0k->640k,
+        * the next section from 1mb->appropriate_mem_k
+        */
+       sanitize_e820_map(E820_MAP, &E820_MAP_NR);
+       if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
+               unsigned long mem_size;
+
+               /* compare results from other methods and take the greater */
+               if (ALT_MEM_K < EXT_MEM_K) {
+                       mem_size = EXT_MEM_K;
+                       who = "BIOS-88";
+               } else {
+                       mem_size = ALT_MEM_K;
+                       who = "BIOS-e801";
+               }
+
+               e820.nr_map = 0;
+               add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+               add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
+       }
+       return who;
+}
index 07fac7e749c7406aa642528dbd292b4fb036c189..8a9e1a6f745de17f9d28e9acfaf2e3f3d205994a 100644 (file)
@@ -10,6 +10,8 @@
 #include <asm/fixmap.h>
 #include <asm/arch_hooks.h>
 #include <asm/io.h>
+#include <asm/e820.h>
+#include <asm/setup.h>
 #include "cobalt.h"
 #include "piix4.h"
 
@@ -133,3 +135,50 @@ void __init time_init_hook(void)
        /* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */
        setup_irq(0, &irq0);
 }
+
+/* Hook for machine specific memory setup. */
+
+#define MB (1024 * 1024)
+
+static unsigned long sgivwfb_mem_phys;
+static unsigned long sgivwfb_mem_size;
+
+long long mem_size __initdata = 0;
+
+char * __init machine_specific_memory_setup(void)
+{
+       long long gfx_mem_size = 8 * MB;
+
+       mem_size = ALT_MEM_K;
+
+       if (!mem_size) {
+               printk(KERN_WARNING "Bootloader didn't set memory size, upgrade it !\n");
+               mem_size = 128 * MB;
+       }
+
+       /*
+        * this hardcodes the graphics memory to 8 MB
+        * it really should be sized dynamically (or at least
+        * set as a boot param)
+        */
+       if (!sgivwfb_mem_size) {
+               printk(KERN_WARNING "Defaulting to 8 MB framebuffer size\n");
+               sgivwfb_mem_size = 8 * MB;
+       }
+
+       /*
+        * Trim to nearest MB
+        */
+       sgivwfb_mem_size &= ~((1 << 20) - 1);
+       sgivwfb_mem_phys = mem_size - gfx_mem_size;
+
+       add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+       add_memory_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM);
+       add_memory_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED);
+
+       return "PROM";
+
+       /* Remove gcc warnings */
+       (void) sanitize_e820_map(NULL, NULL);
+       (void) copy_e820_map(NULL, 0);
+}
index 7d8a3acb9441f785cd9df284577a85dafee862fa..0e225054e2229cf9543f70ede0b5794e45ddb73d 100644 (file)
@@ -7,6 +7,9 @@
 #include <linux/interrupt.h>
 #include <asm/acpi.h>
 #include <asm/arch_hooks.h>
+#include <asm/voyager.h>
+#include <asm/e820.h>
+#include <asm/setup.h>
 
 void __init pre_intr_init_hook(void)
 {
@@ -45,3 +48,74 @@ void __init time_init_hook(void)
 {
        setup_irq(0, &irq0);
 }
+
+/* Hook for machine specific memory setup. */
+
+char * __init machine_specific_memory_setup(void)
+{
+       char *who;
+
+       who = "NOT VOYAGER";
+
+       if(voyager_level == 5) {
+               __u32 addr, length;
+               int i;
+
+               who = "Voyager-SUS";
+
+               e820.nr_map = 0;
+               for(i=0; voyager_memory_detect(i, &addr, &length); i++) {
+                       add_memory_region(addr, length, E820_RAM);
+               }
+               return who;
+       } else if(voyager_level == 4) {
+               __u32 tom;
+               __u16 catbase = inb(VOYAGER_SSPB_RELOCATION_PORT)<<8;
+               /* select the DINO config space */
+               outb(VOYAGER_DINO, VOYAGER_CAT_CONFIG_PORT);
+               /* Read DINO top of memory register */
+               tom = ((inb(catbase + 0x4) & 0xf0) << 16)
+                       + ((inb(catbase + 0x5) & 0x7f) << 24);
+
+               if(inb(catbase) != VOYAGER_DINO) {
+                       printk(KERN_ERR "Voyager: Failed to get DINO for L4, setting tom to EXT_MEM_K\n");
+                       tom = (EXT_MEM_K)<<10;
+               }
+               who = "Voyager-TOM";
+               add_memory_region(0, 0x9f000, E820_RAM);
+               /* map from 1M to top of memory */
+               add_memory_region(1*1024*1024, tom - 1*1024*1024, E820_RAM);
+               /* FIXME: Should check the ASICs to see if I need to
+                * take out the 8M window.  Just do it at the moment
+                * */
+               add_memory_region(8*1024*1024, 8*1024*1024, E820_RESERVED);
+               return who;
+       }
+
+       who = "BIOS-e820";
+
+       /*
+        * Try to copy the BIOS-supplied E820-map.
+        *
+        * Otherwise fake a memory map; one section from 0k->640k,
+        * the next section from 1mb->appropriate_mem_k
+        */
+       sanitize_e820_map(E820_MAP, &E820_MAP_NR);
+       if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
+               unsigned long mem_size;
+
+               /* compare results from other methods and take the greater */
+               if (ALT_MEM_K < EXT_MEM_K) {
+                       mem_size = EXT_MEM_K;
+                       who = "BIOS-88";
+               } else {
+                       mem_size = ALT_MEM_K;
+                       who = "BIOS-e801";
+               }
+
+               e820.nr_map = 0;
+               add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+               add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
+       }
+       return who;
+}
index 7852827a599b07b5f6a5f053c617a7ac70259eaa..a151f7a99f5e8010a7f9875cede3f9aceb81ed61 100644 (file)
@@ -285,8 +285,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
        /* Leave vm_pgoff as-is, the PCI space address is the physical
         * address on this platform.
         */
-       vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
-
        prot = pgprot_val(vma->vm_page_prot);
        if (boot_cpu_data.x86 > 3)
                prot |= _PAGE_PCD | _PAGE_PWT;
index 4f3a16b37f8f840a656996d3cc7fbbbeeddaabee..879edb51d1e0e1b2c29698815127dc8b215f7067 100644 (file)
@@ -166,7 +166,7 @@ static void cache_shared_cpu_map_setup( unsigned int cpu,
 
        num_shared = (int) csi.num_shared;
        do {
-               for_each_cpu(j)
+               for_each_possible_cpu(j)
                        if (cpu_data(cpu)->socket_id == cpu_data(j)->socket_id
                                && cpu_data(j)->core_id == csi.log1_cid
                                && cpu_data(j)->thread_id == csi.log1_tid)
index 61dd8608da4f9483288f2eed009c1ebe15d93a7d..77375a55da312fd7b4ac5ddcb68933aadc381e83 100644 (file)
@@ -602,8 +602,6 @@ pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
         * Leave vm_pgoff as-is, the PCI space address is the physical
         * address on this platform.
         */
-       vma->vm_flags |= (VM_SHM | VM_RESERVED | VM_IO);
-
        if (write_combine && efi_range_is_wc(vma->vm_start,
                                             vma->vm_end - vma->vm_start))
                vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
@@ -666,7 +664,6 @@ pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma)
 
        vma->vm_pgoff += (unsigned long)addr >> PAGE_SHIFT;
        vma->vm_page_prot = prot;
-       vma->vm_flags |= (VM_SHM | VM_RESERVED | VM_IO);
 
        if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
                            size, vma->vm_page_prot))
index b7bd84c73ea7b49dd86655d80b5dd5d5487fa774..8f2e0587ae2f4981b92c997ca5beb4e0d40ae0a2 100644 (file)
@@ -23,8 +23,6 @@ EXPORT_SYMBOL(amiga_chip_avail);
 EXPORT_SYMBOL(amiga_chip_size);
 EXPORT_SYMBOL(amiga_audio_period);
 EXPORT_SYMBOL(amiga_audio_min_period);
-EXPORT_SYMBOL(amiga_do_irq);
-EXPORT_SYMBOL(amiga_do_irq_list);
 
 #ifdef CONFIG_AMIGA_PCMCIA
   EXPORT_SYMBOL(pcmcia_reset);
index b0aa61bf8700df5d532e0d64d20ff37f02834f75..f9403f4640a11bd4468f8efd8daf86c88914a82c 100644 (file)
  *           /Jes
  */
 
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/errno.h>
-#include <linux/seq_file.h>
 
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #include <asm/amipcmcia.h>
 
-extern int cia_request_irq(struct ciabase *base,int irq,
-                           irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                           unsigned long flags, const char *devname, void *dev_id);
-extern void cia_free_irq(struct ciabase *base, unsigned int irq, void *dev_id);
-extern void cia_init_IRQ(struct ciabase *base);
-extern int cia_get_irq_list(struct ciabase *base, struct seq_file *p);
-
-/* irq node variables for amiga interrupt sources */
-static irq_node_t *ami_irq_list[AMI_STD_IRQS];
-
-static unsigned short amiga_intena_vals[AMI_STD_IRQS] = {
-       [IRQ_AMIGA_VERTB]       = IF_VERTB,
-       [IRQ_AMIGA_COPPER]      = IF_COPER,
-       [IRQ_AMIGA_AUD0]        = IF_AUD0,
-       [IRQ_AMIGA_AUD1]        = IF_AUD1,
-       [IRQ_AMIGA_AUD2]        = IF_AUD2,
-       [IRQ_AMIGA_AUD3]        = IF_AUD3,
-       [IRQ_AMIGA_BLIT]        = IF_BLIT,
-       [IRQ_AMIGA_DSKSYN]      = IF_DSKSYN,
-       [IRQ_AMIGA_DSKBLK]      = IF_DSKBLK,
-       [IRQ_AMIGA_RBF]         = IF_RBF,
-       [IRQ_AMIGA_TBE]         = IF_TBE,
-       [IRQ_AMIGA_SOFT]        = IF_SOFT,
-       [IRQ_AMIGA_PORTS]       = IF_PORTS,
-       [IRQ_AMIGA_EXTER]       = IF_EXTER
-};
-static const unsigned char ami_servers[AMI_STD_IRQS] = {
-       [IRQ_AMIGA_VERTB]       = 1,
-       [IRQ_AMIGA_PORTS]       = 1,
-       [IRQ_AMIGA_EXTER]       = 1
+static void amiga_enable_irq(unsigned int irq);
+static void amiga_disable_irq(unsigned int irq);
+static irqreturn_t ami_int1(int irq, void *dev_id, struct pt_regs *fp);
+static irqreturn_t ami_int3(int irq, void *dev_id, struct pt_regs *fp);
+static irqreturn_t ami_int4(int irq, void *dev_id, struct pt_regs *fp);
+static irqreturn_t ami_int5(int irq, void *dev_id, struct pt_regs *fp);
+
+static struct irq_controller amiga_irq_controller = {
+       .name           = "amiga",
+       .lock           = SPIN_LOCK_UNLOCKED,
+       .enable         = amiga_enable_irq,
+       .disable        = amiga_disable_irq,
 };
 
-static short ami_ablecount[AMI_IRQS];
-
-static irqreturn_t ami_badint(int irq, void *dev_id, struct pt_regs *fp)
-{
-       num_spurious += 1;
-       return IRQ_NONE;
-}
-
 /*
  * void amiga_init_IRQ(void)
  *
@@ -103,23 +72,12 @@ static irqreturn_t ami_badint(int irq, void *dev_id, struct pt_regs *fp)
 
 void __init amiga_init_IRQ(void)
 {
-       int i;
+       request_irq(IRQ_AUTO_1, ami_int1, 0, "int1", NULL);
+       request_irq(IRQ_AUTO_3, ami_int3, 0, "int3", NULL);
+       request_irq(IRQ_AUTO_4, ami_int4, 0, "int4", NULL);
+       request_irq(IRQ_AUTO_5, ami_int5, 0, "int5", NULL);
 
-       /* initialize handlers */
-       for (i = 0; i < AMI_STD_IRQS; i++) {
-               if (ami_servers[i]) {
-                       ami_irq_list[i] = NULL;
-               } else {
-                       ami_irq_list[i] = new_irq_node();
-                       ami_irq_list[i]->handler = ami_badint;
-                       ami_irq_list[i]->flags   = 0;
-                       ami_irq_list[i]->dev_id  = NULL;
-                       ami_irq_list[i]->devname = NULL;
-                       ami_irq_list[i]->next    = NULL;
-               }
-       }
-       for (i = 0; i < AMI_IRQS; i++)
-               ami_ablecount[i] = 0;
+       m68k_setup_irq_controller(&amiga_irq_controller, IRQ_USER, AMI_STD_IRQS);
 
        /* turn off PCMCIA interrupts */
        if (AMIGAHW_PRESENT(PCMCIA))
@@ -134,249 +92,21 @@ void __init amiga_init_IRQ(void)
        cia_init_IRQ(&ciab_base);
 }
 
-static inline int amiga_insert_irq(irq_node_t **list, irq_node_t *node)
-{
-       unsigned long flags;
-       irq_node_t *cur;
-
-       if (!node->dev_id)
-               printk("%s: Warning: dev_id of %s is zero\n",
-                      __FUNCTION__, node->devname);
-
-       local_irq_save(flags);
-
-       cur = *list;
-
-       if (node->flags & SA_INTERRUPT) {
-               if (node->flags & SA_SHIRQ)
-                       return -EBUSY;
-               /*
-                * There should never be more than one
-                */
-               while (cur && cur->flags & SA_INTERRUPT) {
-                       list = &cur->next;
-                       cur = cur->next;
-               }
-       } else {
-               while (cur) {
-                       list = &cur->next;
-                       cur = cur->next;
-               }
-       }
-
-       node->next = cur;
-       *list = node;
-
-       local_irq_restore(flags);
-       return 0;
-}
-
-static inline void amiga_delete_irq(irq_node_t **list, void *dev_id)
-{
-       unsigned long flags;
-       irq_node_t *node;
-
-       local_irq_save(flags);
-
-       for (node = *list; node; list = &node->next, node = *list) {
-               if (node->dev_id == dev_id) {
-                       *list = node->next;
-                       /* Mark it as free. */
-                       node->handler = NULL;
-                       local_irq_restore(flags);
-                       return;
-               }
-       }
-       local_irq_restore(flags);
-       printk ("%s: tried to remove invalid irq\n", __FUNCTION__);
-}
-
-/*
- * amiga_request_irq : add an interrupt service routine for a particular
- *                     machine specific interrupt source.
- *                     If the addition was successful, it returns 0.
- */
-
-int amiga_request_irq(unsigned int irq,
-                     irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                      unsigned long flags, const char *devname, void *dev_id)
-{
-       irq_node_t *node;
-       int error = 0;
-
-       if (irq >= AMI_IRQS) {
-               printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__,
-                       irq, devname);
-               return -ENXIO;
-       }
-
-       if (irq >= IRQ_AMIGA_AUTO)
-               return cpu_request_irq(irq - IRQ_AMIGA_AUTO, handler,
-                                      flags, devname, dev_id);
-
-       if (irq >= IRQ_AMIGA_CIAB)
-               return cia_request_irq(&ciab_base, irq - IRQ_AMIGA_CIAB,
-                                      handler, flags, devname, dev_id);
-
-       if (irq >= IRQ_AMIGA_CIAA)
-               return cia_request_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA,
-                                      handler, flags, devname, dev_id);
-
-       /*
-        * IRQ_AMIGA_PORTS & IRQ_AMIGA_EXTER defaults to shared,
-        * we could add a check here for the SA_SHIRQ flag but all drivers
-        * should be aware of sharing anyway.
-        */
-       if (ami_servers[irq]) {
-               if (!(node = new_irq_node()))
-                       return -ENOMEM;
-               node->handler = handler;
-               node->flags   = flags;
-               node->dev_id  = dev_id;
-               node->devname = devname;
-               node->next    = NULL;
-               error = amiga_insert_irq(&ami_irq_list[irq], node);
-       } else {
-               ami_irq_list[irq]->handler = handler;
-               ami_irq_list[irq]->flags   = flags;
-               ami_irq_list[irq]->dev_id  = dev_id;
-               ami_irq_list[irq]->devname = devname;
-       }
-
-       /* enable the interrupt */
-       if (irq < IRQ_AMIGA_PORTS && !ami_ablecount[irq])
-               amiga_custom.intena = IF_SETCLR | amiga_intena_vals[irq];
-
-       return error;
-}
-
-void amiga_free_irq(unsigned int irq, void *dev_id)
-{
-       if (irq >= AMI_IRQS) {
-               printk ("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
-               return;
-       }
-
-       if (irq >= IRQ_AMIGA_AUTO)
-               cpu_free_irq(irq - IRQ_AMIGA_AUTO, dev_id);
-
-       if (irq >= IRQ_AMIGA_CIAB) {
-               cia_free_irq(&ciab_base, irq - IRQ_AMIGA_CIAB, dev_id);
-               return;
-       }
-
-       if (irq >= IRQ_AMIGA_CIAA) {
-               cia_free_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA, dev_id);
-               return;
-       }
-
-       if (ami_servers[irq]) {
-               amiga_delete_irq(&ami_irq_list[irq], dev_id);
-               /* if server list empty, disable the interrupt */
-               if (!ami_irq_list[irq] && irq < IRQ_AMIGA_PORTS)
-                       amiga_custom.intena = amiga_intena_vals[irq];
-       } else {
-               if (ami_irq_list[irq]->dev_id != dev_id)
-                       printk("%s: removing probably wrong IRQ %d from %s\n",
-                              __FUNCTION__, irq, ami_irq_list[irq]->devname);
-               ami_irq_list[irq]->handler = ami_badint;
-               ami_irq_list[irq]->flags   = 0;
-               ami_irq_list[irq]->dev_id  = NULL;
-               ami_irq_list[irq]->devname = NULL;
-               amiga_custom.intena = amiga_intena_vals[irq];
-       }
-}
-
 /*
  * Enable/disable a particular machine specific interrupt source.
  * Note that this may affect other interrupts in case of a shared interrupt.
  * This function should only be called for a _very_ short time to change some
  * internal data, that may not be changed by the interrupt at the same time.
- * ami_(enable|disable)_irq calls may also be nested.
  */
 
-void amiga_enable_irq(unsigned int irq)
-{
-       if (irq >= AMI_IRQS) {
-               printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
-               return;
-       }
-
-       if (--ami_ablecount[irq])
-               return;
-
-       /* No action for auto-vector interrupts */
-       if (irq >= IRQ_AMIGA_AUTO){
-               printk("%s: Trying to enable auto-vector IRQ %i\n",
-                      __FUNCTION__, irq - IRQ_AMIGA_AUTO);
-               return;
-       }
-
-       if (irq >= IRQ_AMIGA_CIAB) {
-               cia_set_irq(&ciab_base, (1 << (irq - IRQ_AMIGA_CIAB)));
-               cia_able_irq(&ciab_base, CIA_ICR_SETCLR |
-                            (1 << (irq - IRQ_AMIGA_CIAB)));
-               return;
-       }
-
-       if (irq >= IRQ_AMIGA_CIAA) {
-               cia_set_irq(&ciaa_base, (1 << (irq - IRQ_AMIGA_CIAA)));
-               cia_able_irq(&ciaa_base, CIA_ICR_SETCLR |
-                            (1 << (irq - IRQ_AMIGA_CIAA)));
-               return;
-       }
-
-       /* enable the interrupt */
-       amiga_custom.intena = IF_SETCLR | amiga_intena_vals[irq];
-}
-
-void amiga_disable_irq(unsigned int irq)
-{
-       if (irq >= AMI_IRQS) {
-               printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
-               return;
-       }
-
-       if (ami_ablecount[irq]++)
-               return;
-
-       /* No action for auto-vector interrupts */
-       if (irq >= IRQ_AMIGA_AUTO) {
-               printk("%s: Trying to disable auto-vector IRQ %i\n",
-                      __FUNCTION__, irq - IRQ_AMIGA_AUTO);
-               return;
-       }
-
-       if (irq >= IRQ_AMIGA_CIAB) {
-               cia_able_irq(&ciab_base, 1 << (irq - IRQ_AMIGA_CIAB));
-               return;
-       }
-
-       if (irq >= IRQ_AMIGA_CIAA) {
-               cia_able_irq(&ciaa_base, 1 << (irq - IRQ_AMIGA_CIAA));
-               return;
-       }
-
-       /* disable the interrupt */
-       amiga_custom.intena = amiga_intena_vals[irq];
-}
-
-inline void amiga_do_irq(int irq, struct pt_regs *fp)
+static void amiga_enable_irq(unsigned int irq)
 {
-       kstat_cpu(0).irqs[SYS_IRQS + irq]++;
-       ami_irq_list[irq]->handler(irq, ami_irq_list[irq]->dev_id, fp);
+       amiga_custom.intena = IF_SETCLR | (1 << (irq - IRQ_USER));
 }
 
-void amiga_do_irq_list(int irq, struct pt_regs *fp)
+static void amiga_disable_irq(unsigned int irq)
 {
-       irq_node_t *node;
-
-       kstat_cpu(0).irqs[SYS_IRQS + irq]++;
-
-       amiga_custom.intreq = amiga_intena_vals[irq];
-
-       for (node = ami_irq_list[irq]; node; node = node->next)
-               node->handler(irq, node->dev_id, fp);
+       amiga_custom.intena = 1 << (irq - IRQ_USER);
 }
 
 /*
@@ -390,19 +120,19 @@ static irqreturn_t ami_int1(int irq, void *dev_id, struct pt_regs *fp)
        /* if serial transmit buffer empty, interrupt */
        if (ints & IF_TBE) {
                amiga_custom.intreq = IF_TBE;
-               amiga_do_irq(IRQ_AMIGA_TBE, fp);
+               m68k_handle_int(IRQ_AMIGA_TBE, fp);
        }
 
        /* if floppy disk transfer complete, interrupt */
        if (ints & IF_DSKBLK) {
                amiga_custom.intreq = IF_DSKBLK;
-               amiga_do_irq(IRQ_AMIGA_DSKBLK, fp);
+               m68k_handle_int(IRQ_AMIGA_DSKBLK, fp);
        }
 
        /* if software interrupt set, interrupt */
        if (ints & IF_SOFT) {
                amiga_custom.intreq = IF_SOFT;
-               amiga_do_irq(IRQ_AMIGA_SOFT, fp);
+               m68k_handle_int(IRQ_AMIGA_SOFT, fp);
        }
        return IRQ_HANDLED;
 }
@@ -414,18 +144,20 @@ static irqreturn_t ami_int3(int irq, void *dev_id, struct pt_regs *fp)
        /* if a blitter interrupt */
        if (ints & IF_BLIT) {
                amiga_custom.intreq = IF_BLIT;
-               amiga_do_irq(IRQ_AMIGA_BLIT, fp);
+               m68k_handle_int(IRQ_AMIGA_BLIT, fp);
        }
 
        /* if a copper interrupt */
        if (ints & IF_COPER) {
                amiga_custom.intreq = IF_COPER;
-               amiga_do_irq(IRQ_AMIGA_COPPER, fp);
+               m68k_handle_int(IRQ_AMIGA_COPPER, fp);
        }
 
        /* if a vertical blank interrupt */
-       if (ints & IF_VERTB)
-               amiga_do_irq_list(IRQ_AMIGA_VERTB, fp);
+       if (ints & IF_VERTB) {
+               amiga_custom.intreq = IF_VERTB;
+               m68k_handle_int(IRQ_AMIGA_VERTB, fp);
+       }
        return IRQ_HANDLED;
 }
 
@@ -436,25 +168,25 @@ static irqreturn_t ami_int4(int irq, void *dev_id, struct pt_regs *fp)
        /* if audio 0 interrupt */
        if (ints & IF_AUD0) {
                amiga_custom.intreq = IF_AUD0;
-               amiga_do_irq(IRQ_AMIGA_AUD0, fp);
+               m68k_handle_int(IRQ_AMIGA_AUD0, fp);
        }
 
        /* if audio 1 interrupt */
        if (ints & IF_AUD1) {
                amiga_custom.intreq = IF_AUD1;
-               amiga_do_irq(IRQ_AMIGA_AUD1, fp);
+               m68k_handle_int(IRQ_AMIGA_AUD1, fp);
        }
 
        /* if audio 2 interrupt */
        if (ints & IF_AUD2) {
                amiga_custom.intreq = IF_AUD2;
-               amiga_do_irq(IRQ_AMIGA_AUD2, fp);
+               m68k_handle_int(IRQ_AMIGA_AUD2, fp);
        }
 
        /* if audio 3 interrupt */
        if (ints & IF_AUD3) {
                amiga_custom.intreq = IF_AUD3;
-               amiga_do_irq(IRQ_AMIGA_AUD3, fp);
+               m68k_handle_int(IRQ_AMIGA_AUD3, fp);
        }
        return IRQ_HANDLED;
 }
@@ -466,55 +198,13 @@ static irqreturn_t ami_int5(int irq, void *dev_id, struct pt_regs *fp)
        /* if serial receive buffer full interrupt */
        if (ints & IF_RBF) {
                /* acknowledge of IF_RBF must be done by the serial interrupt */
-               amiga_do_irq(IRQ_AMIGA_RBF, fp);
+               m68k_handle_int(IRQ_AMIGA_RBF, fp);
        }
 
        /* if a disk sync interrupt */
        if (ints & IF_DSKSYN) {
                amiga_custom.intreq = IF_DSKSYN;
-               amiga_do_irq(IRQ_AMIGA_DSKSYN, fp);
+               m68k_handle_int(IRQ_AMIGA_DSKSYN, fp);
        }
        return IRQ_HANDLED;
 }
-
-static irqreturn_t ami_int7(int irq, void *dev_id, struct pt_regs *fp)
-{
-       panic ("level 7 interrupt received\n");
-}
-
-irqreturn_t (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
-       [0] = ami_badint,
-       [1] = ami_int1,
-       [2] = ami_badint,
-       [3] = ami_int3,
-       [4] = ami_int4,
-       [5] = ami_int5,
-       [6] = ami_badint,
-       [7] = ami_int7
-};
-
-int show_amiga_interrupts(struct seq_file *p, void *v)
-{
-       int i;
-       irq_node_t *node;
-
-       for (i = 0; i < AMI_STD_IRQS; i++) {
-               if (!(node = ami_irq_list[i]))
-                       continue;
-               seq_printf(p, "ami  %2d: %10u ", i,
-                              kstat_cpu(0).irqs[SYS_IRQS + i]);
-               do {
-                       if (node->flags & SA_INTERRUPT)
-                               seq_puts(p, "F ");
-                       else
-                               seq_puts(p, "  ");
-                       seq_printf(p, "%s\n", node->devname);
-                       if ((node = node->next))
-                               seq_puts(p, "                    ");
-               } while (node);
-       }
-
-       cia_get_irq_list(&ciaa_base, p);
-       cia_get_irq_list(&ciab_base, p);
-       return 0;
-}
index 9476eb9440f57436365b8de4f6d70e02bb9500c0..0956e45399e5cefcc0a12a4a7bdfea0842962068 100644 (file)
@@ -29,21 +29,18 @@ struct ciabase {
        unsigned short int_mask;
        int handler_irq, cia_irq, server_irq;
        char *name;
-       irq_handler_t irq_list[CIA_IRQS];
 } ciaa_base = {
        .cia            = &ciaa,
        .int_mask       = IF_PORTS,
-       .handler_irq    = IRQ_AMIGA_AUTO_2,
+       .handler_irq    = IRQ_AMIGA_PORTS,
        .cia_irq        = IRQ_AMIGA_CIAA,
-       .server_irq     = IRQ_AMIGA_PORTS,
-       .name           = "CIAA handler"
+       .name           = "CIAA"
 }, ciab_base = {
        .cia            = &ciab,
        .int_mask       = IF_EXTER,
-       .handler_irq    = IRQ_AMIGA_AUTO_6,
+       .handler_irq    = IRQ_AMIGA_EXTER,
        .cia_irq        = IRQ_AMIGA_CIAB,
-       .server_irq     = IRQ_AMIGA_EXTER,
-       .name           = "CIAB handler"
+       .name           = "CIAB"
 };
 
 /*
@@ -66,13 +63,11 @@ unsigned char cia_set_irq(struct ciabase *base, unsigned char mask)
 
 /*
  *  Enable or disable CIA interrupts, return old interrupt mask,
- *  interrupts will only be enabled if a handler exists
  */
 
 unsigned char cia_able_irq(struct ciabase *base, unsigned char mask)
 {
-       unsigned char old, tmp;
-       int i;
+       unsigned char old;
 
        old = base->icr_mask;
        base->icr_data |= base->cia->icr;
@@ -82,99 +77,104 @@ unsigned char cia_able_irq(struct ciabase *base, unsigned char mask)
        else
                base->icr_mask &= ~mask;
        base->icr_mask &= CIA_ICR_ALL;
-       for (i = 0, tmp = 1; i < CIA_IRQS; i++, tmp <<= 1) {
-               if ((tmp & base->icr_mask) && !base->irq_list[i].handler) {
-                       base->icr_mask &= ~tmp;
-                       base->cia->icr = tmp;
-               }
-       }
        if (base->icr_data & base->icr_mask)
                amiga_custom.intreq = IF_SETCLR | base->int_mask;
        return old;
 }
 
-int cia_request_irq(struct ciabase *base, unsigned int irq,
-                    irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                    unsigned long flags, const char *devname, void *dev_id)
-{
-       unsigned char mask;
-
-       base->irq_list[irq].handler = handler;
-       base->irq_list[irq].flags   = flags;
-       base->irq_list[irq].dev_id  = dev_id;
-       base->irq_list[irq].devname = devname;
-
-       /* enable the interrupt */
-       mask = 1 << irq;
-       cia_set_irq(base, mask);
-       cia_able_irq(base, CIA_ICR_SETCLR | mask);
-       return 0;
-}
-
-void cia_free_irq(struct ciabase *base, unsigned int irq, void *dev_id)
-{
-       if (base->irq_list[irq].dev_id != dev_id)
-               printk("%s: removing probably wrong IRQ %i from %s\n",
-                      __FUNCTION__, base->cia_irq + irq,
-                      base->irq_list[irq].devname);
-
-       base->irq_list[irq].handler = NULL;
-       base->irq_list[irq].flags   = 0;
-
-       cia_able_irq(base, 1 << irq);
-}
-
 static irqreturn_t cia_handler(int irq, void *dev_id, struct pt_regs *fp)
 {
        struct ciabase *base = (struct ciabase *)dev_id;
-       int mach_irq, i;
+       int mach_irq;
        unsigned char ints;
 
        mach_irq = base->cia_irq;
-       irq = SYS_IRQS + mach_irq;
        ints = cia_set_irq(base, CIA_ICR_ALL);
        amiga_custom.intreq = base->int_mask;
-       for (i = 0; i < CIA_IRQS; i++, irq++, mach_irq++) {
-               if (ints & 1) {
-                       kstat_cpu(0).irqs[irq]++;
-                       base->irq_list[i].handler(mach_irq, base->irq_list[i].dev_id, fp);
-               }
-               ints >>= 1;
+       for (; ints; mach_irq++, ints >>= 1) {
+               if (ints & 1)
+                       m68k_handle_int(mach_irq, fp);
        }
-       amiga_do_irq_list(base->server_irq, fp);
        return IRQ_HANDLED;
 }
 
-void __init cia_init_IRQ(struct ciabase *base)
+static void cia_enable_irq(unsigned int irq)
 {
-       int i;
+       unsigned char mask;
 
-       /* init isr handlers */
-       for (i = 0; i < CIA_IRQS; i++) {
-               base->irq_list[i].handler = NULL;
-               base->irq_list[i].flags   = 0;
+       if (irq >= IRQ_AMIGA_CIAB) {
+               mask = 1 << (irq - IRQ_AMIGA_CIAB);
+               cia_set_irq(&ciab_base, mask);
+               cia_able_irq(&ciab_base, CIA_ICR_SETCLR | mask);
+       } else {
+               mask = 1 << (irq - IRQ_AMIGA_CIAA);
+               cia_set_irq(&ciaa_base, mask);
+               cia_able_irq(&ciaa_base, CIA_ICR_SETCLR | mask);
        }
+}
 
-       /* clear any pending interrupt and turn off all interrupts */
-       cia_set_irq(base, CIA_ICR_ALL);
-       cia_able_irq(base, CIA_ICR_ALL);
+static void cia_disable_irq(unsigned int irq)
+{
+       if (irq >= IRQ_AMIGA_CIAB)
+               cia_able_irq(&ciab_base, 1 << (irq - IRQ_AMIGA_CIAB));
+       else
+               cia_able_irq(&ciaa_base, 1 << (irq - IRQ_AMIGA_CIAA));
+}
 
-       /* install CIA handler */
-       request_irq(base->handler_irq, cia_handler, 0, base->name, base);
+static struct irq_controller cia_irq_controller = {
+       .name           = "cia",
+       .lock           = SPIN_LOCK_UNLOCKED,
+       .enable         = cia_enable_irq,
+       .disable        = cia_disable_irq,
+};
+
+/*
+ * Override auto irq 2 & 6 and use them as general chain
+ * for external interrupts, we link the CIA interrupt sources
+ * into this chain.
+ */
 
-       amiga_custom.intena = IF_SETCLR | base->int_mask;
+static void auto_enable_irq(unsigned int irq)
+{
+       switch (irq) {
+       case IRQ_AUTO_2:
+               amiga_custom.intena = IF_SETCLR | IF_PORTS;
+               break;
+       case IRQ_AUTO_6:
+               amiga_custom.intena = IF_SETCLR | IF_EXTER;
+               break;
+       }
 }
 
-int cia_get_irq_list(struct ciabase *base, struct seq_file *p)
+static void auto_disable_irq(unsigned int irq)
 {
-       int i, j;
-
-       j = base->cia_irq;
-       for (i = 0; i < CIA_IRQS; i++) {
-               seq_printf(p, "cia  %2d: %10d ", j + i,
-                              kstat_cpu(0).irqs[SYS_IRQS + j + i]);
-               seq_puts(p, "  ");
-               seq_printf(p, "%s\n", base->irq_list[i].devname);
+       switch (irq) {
+       case IRQ_AUTO_2:
+               amiga_custom.intena = IF_PORTS;
+               break;
+       case IRQ_AUTO_6:
+               amiga_custom.intena = IF_EXTER;
+               break;
        }
-       return 0;
+}
+
+static struct irq_controller auto_irq_controller = {
+       .name           = "auto",
+       .lock           = SPIN_LOCK_UNLOCKED,
+       .enable         = auto_enable_irq,
+       .disable        = auto_disable_irq,
+};
+
+void __init cia_init_IRQ(struct ciabase *base)
+{
+       m68k_setup_irq_controller(&cia_irq_controller, base->cia_irq, CIA_IRQS);
+
+       /* clear any pending interrupt and turn off all interrupts */
+       cia_set_irq(base, CIA_ICR_ALL);
+       cia_able_irq(base, CIA_ICR_ALL);
+
+       /* override auto int and install CIA handler */
+       m68k_setup_irq_controller(&auto_irq_controller, base->handler_irq, 1);
+       m68k_irq_startup(base->handler_irq);
+       request_irq(base->handler_irq, cia_handler, SA_SHIRQ, base->name, base);
 }
index 12e3706fe02cf17839d0910dc9d31f5b960b4c1a..b5b8a416a07a1384919b2f60ff78adfee5668117 100644 (file)
@@ -87,17 +87,8 @@ extern char m68k_debug_device[];
 static void amiga_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
 /* amiga specific irq functions */
 extern void amiga_init_IRQ (void);
-extern irqreturn_t (*amiga_default_handler[]) (int, void *, struct pt_regs *);
-extern int amiga_request_irq (unsigned int irq,
-                             irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                              unsigned long flags, const char *devname,
-                             void *dev_id);
-extern void amiga_free_irq (unsigned int irq, void *dev_id);
-extern void amiga_enable_irq (unsigned int);
-extern void amiga_disable_irq (unsigned int);
 static void amiga_get_model(char *model);
 static int amiga_get_hardware_list(char *buffer);
-extern int show_amiga_interrupts (struct seq_file *, void *);
 /* amiga specific timer functions */
 static unsigned long amiga_gettimeoffset (void);
 static int a3000_hwclk (int, struct rtc_time *);
@@ -392,14 +383,8 @@ void __init config_amiga(void)
 
   mach_sched_init      = amiga_sched_init;
   mach_init_IRQ        = amiga_init_IRQ;
-  mach_default_handler = &amiga_default_handler;
-  mach_request_irq     = amiga_request_irq;
-  mach_free_irq        = amiga_free_irq;
-  enable_irq           = amiga_enable_irq;
-  disable_irq          = amiga_disable_irq;
   mach_get_model       = amiga_get_model;
   mach_get_hardware_list = amiga_get_hardware_list;
-  mach_get_irq_list    = show_amiga_interrupts;
   mach_gettimeoffset   = amiga_gettimeoffset;
   if (AMIGAHW_PRESENT(A3000_CLK)){
     mach_hwclk         = a3000_hwclk;
index 39264f3b6ad64e27f72b0e87dba991e74f82b2dd..76a057962c38637a3f88b3d0971e8a564f274e3a 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for Linux arch/m68k/amiga source directory
 #
 
-obj-y          := config.o dn_ints.o dma.o
+obj-y          := config.o dn_ints.o
index d401962d9b251e53dcef279d5045473056d6f995..99c70978aafa8149cc425dcd1cd39f54cf23000e 100644 (file)
@@ -28,11 +28,6 @@ u_long apollo_model;
 
 extern void dn_sched_init(irqreturn_t (*handler)(int,void *,struct pt_regs *));
 extern void dn_init_IRQ(void);
-extern int dn_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
-extern void dn_free_irq(unsigned int irq, void *dev_id);
-extern void dn_enable_irq(unsigned int);
-extern void dn_disable_irq(unsigned int);
-extern int show_dn_interrupts(struct seq_file *, void *);
 extern unsigned long dn_gettimeoffset(void);
 extern int dn_dummy_hwclk(int, struct rtc_time *);
 extern int dn_dummy_set_clock_mmss(unsigned long);
@@ -40,13 +35,11 @@ extern void dn_dummy_reset(void);
 extern void dn_dummy_waitbut(void);
 extern struct fb_info *dn_fb_init(long *);
 extern void dn_dummy_debug_init(void);
-extern void dn_dummy_video_setup(char *,int *);
 extern irqreturn_t dn_process_int(int irq, struct pt_regs *fp);
 #ifdef CONFIG_HEARTBEAT
 static void dn_heartbeat(int on);
 #endif
 static irqreturn_t dn_timer_int(int irq,void *, struct pt_regs *);
-static irqreturn_t (*sched_timer_handler)(int, void *, struct pt_regs *)=NULL;
 static void dn_get_model(char *model);
 static const char *apollo_models[] = {
        [APOLLO_DN3000-APOLLO_DN3000] = "DN3000 (Otter)",
@@ -164,17 +157,10 @@ void config_apollo(void) {
 
        mach_sched_init=dn_sched_init; /* */
        mach_init_IRQ=dn_init_IRQ;
-       mach_default_handler=NULL;
-       mach_request_irq     = dn_request_irq;
-       mach_free_irq        = dn_free_irq;
-       enable_irq      = dn_enable_irq;
-       disable_irq     = dn_disable_irq;
-       mach_get_irq_list    = show_dn_interrupts;
        mach_gettimeoffset   = dn_gettimeoffset;
        mach_max_dma_address = 0xffffffff;
        mach_hwclk           = dn_dummy_hwclk; /* */
        mach_set_clock_mmss  = dn_dummy_set_clock_mmss; /* */
-       mach_process_int     = dn_process_int;
        mach_reset           = dn_dummy_reset;  /* */
 #ifdef CONFIG_HEARTBEAT
        mach_heartbeat = dn_heartbeat;
@@ -189,11 +175,13 @@ void config_apollo(void) {
 
 }
 
-irqreturn_t dn_timer_int(int irq, void *dev_id, struct pt_regs *fp) {
+irqreturn_t dn_timer_int(int irq, void *dev_id, struct pt_regs *fp)
+{
+       irqreturn_t (*timer_handler)(int, void *, struct pt_regs *) = dev_id;
 
        volatile unsigned char x;
 
-       sched_timer_handler(irq,dev_id,fp);
+       timer_handler(irq, dev_id, fp);
 
        x=*(volatile unsigned char *)(timer+3);
        x=*(volatile unsigned char *)(timer+5);
@@ -217,9 +205,7 @@ void dn_sched_init(irqreturn_t (*timer_routine)(int, void *, struct pt_regs *))
        printk("*(0x10803) %02x\n",*(volatile unsigned char *)(timer+0x3));
 #endif
 
-       sched_timer_handler=timer_routine;
-       request_irq(0,dn_timer_int,0,NULL,NULL);
-
+       request_irq(IRQ_APOLLO, dn_timer_int, 0, "time", timer_routine);
 }
 
 unsigned long dn_gettimeoffset(void) {
index a31259359a1208711a83d1828d7e5ed0b5a70a5f..9fe07803797bb9c2211decdd76e63717ad2fc258 100644 (file)
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/kernel_stat.h>
-#include <linux/timer.h>
+#include <linux/interrupt.h>
 
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
-#include <asm/page.h>
-#include <asm/machdep.h>
 #include <asm/apollohw.h>
-#include <asm/errno.h>
 
-static irq_handler_t dn_irqs[16];
-
-irqreturn_t dn_process_int(int irq, struct pt_regs *fp)
+void dn_process_int(unsigned int irq, struct pt_regs *fp)
 {
-  irqreturn_t res = IRQ_NONE;
-
-  if(dn_irqs[irq-160].handler) {
-    res = dn_irqs[irq-160].handler(irq,dn_irqs[irq-160].dev_id,fp);
-  } else {
-    printk("spurious irq %d occurred\n",irq);
-  }
-
-  *(volatile unsigned char *)(pica)=0x20;
-  *(volatile unsigned char *)(picb)=0x20;
-
-  return res;
-}
-
-void dn_init_IRQ(void) {
-
-  int i;
-
-  for(i=0;i<16;i++) {
-    dn_irqs[i].handler=NULL;
-    dn_irqs[i].flags=IRQ_FLG_STD;
-    dn_irqs[i].dev_id=NULL;
-    dn_irqs[i].devname=NULL;
-  }
-
-}
-
-int dn_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id) {
-
-  if((irq<0) || (irq>15)) {
-    printk("Trying to request invalid IRQ\n");
-    return -ENXIO;
-  }
-
-  if(!dn_irqs[irq].handler) {
-    dn_irqs[irq].handler=handler;
-    dn_irqs[irq].flags=IRQ_FLG_STD;
-    dn_irqs[irq].dev_id=dev_id;
-    dn_irqs[irq].devname=devname;
-    if(irq<8)
-      *(volatile unsigned char *)(pica+1)&=~(1<<irq);
-    else
-      *(volatile unsigned char *)(picb+1)&=~(1<<(irq-8));
-
-    return 0;
-  }
-  else {
-    printk("Trying to request already assigned irq %d\n",irq);
-    return -ENXIO;
-  }
-
-}
-
-void dn_free_irq(unsigned int irq, void *dev_id) {
-
-  if((irq<0) || (irq>15)) {
-    printk("Trying to free invalid IRQ\n");
-    return ;
-  }
-
-  if(irq<8)
-    *(volatile unsigned char *)(pica+1)|=(1<<irq);
-  else
-    *(volatile unsigned char *)(picb+1)|=(1<<(irq-8));
-
-  dn_irqs[irq].handler=NULL;
-  dn_irqs[irq].flags=IRQ_FLG_STD;
-  dn_irqs[irq].dev_id=NULL;
-  dn_irqs[irq].devname=NULL;
-
-  return ;
-
-}
-
-void dn_enable_irq(unsigned int irq) {
-
-  printk("dn enable irq\n");
-
-}
-
-void dn_disable_irq(unsigned int irq) {
-
-  printk("dn disable irq\n");
+       m68k_handle_int(irq, fp);
 
+       *(volatile unsigned char *)(pica)=0x20;
+       *(volatile unsigned char *)(picb)=0x20;
 }
 
-int show_dn_interrupts(struct seq_file *p, void *v) {
-
-  printk("dn get irq list\n");
-
-  return 0;
-
+int apollo_irq_startup(unsigned int irq)
+{
+       if (irq < 8)
+               *(volatile unsigned char *)(pica+1) &= ~(1 << irq);
+       else
+               *(volatile unsigned char *)(picb+1) &= ~(1 << (irq - 8));
+       return 0;
 }
 
-struct fb_info *dn_dummy_fb_init(long *mem_start) {
-
-  printk("fb init\n");
-
-  return NULL;
-
+void apollo_irq_shutdown(unsigned int irq)
+{
+       if (irq < 8)
+               *(volatile unsigned char *)(pica+1) |= (1 << irq);
+       else
+               *(volatile unsigned char *)(picb+1) |= (1 << (irq - 8));
 }
 
-void dn_dummy_video_setup(char *options,int *ints) {
+static struct irq_controller apollo_irq_controller = {
+       .name           = "apollo",
+       .lock           = SPIN_LOCK_UNLOCKED,
+       .startup        = apollo_irq_startup,
+       .shutdown       = apollo_irq_shutdown,
+};
 
-  printk("no video yet\n");
 
+void dn_init_IRQ(void)
+{
+       m68k_setup_user_interrupt(VEC_USER + 96, 16, dn_process_int);
+       m68k_setup_irq_controller(&apollo_irq_controller, IRQ_APOLLO, 16);
 }
index 076f4791784256a03482aa0dcda3311e34e15ae2..ece13cbf9950a1b69a966b2b99766eeeeeca2be7 100644 (file)
  * the sr copy in the frame.
  */
 
+#if 0
 
 #define        NUM_INT_SOURCES (8 + NUM_ATARI_SOURCES)
 
@@ -133,13 +134,6 @@ static struct irqhandler irq_handler[NUM_INT_SOURCES];
  */
 static struct irqparam irq_param[NUM_INT_SOURCES];
 
-/*
- * Bitmap for free interrupt vector numbers
- * (new vectors starting from 0x70 can be allocated by
- * atari_register_vme_int())
- */
-static int free_vme_vec_bitmap;
-
 /* check for valid int number (complex, sigh...) */
 #define        IS_VALID_INTNO(n)                                                                                       \
        ((n) > 0 &&                                                                                                             \
@@ -301,6 +295,14 @@ __asm__ (__ALIGN_STR "\n"
 );
        for (;;);
 }
+#endif
+
+/*
+ * Bitmap for free interrupt vector numbers
+ * (new vectors starting from 0x70 can be allocated by
+ * atari_register_vme_int())
+ */
+static int free_vme_vec_bitmap;
 
 /* GK:
  * HBL IRQ handler for Falcon. Nobody needs it :-)
@@ -313,13 +315,34 @@ __ALIGN_STR "\n\t"
        "orw    #0x200,%sp@\n\t"        /* set saved ipl to 2 */
        "rte");
 
-/* Defined in entry.S; only increments 'num_spurious' */
-asmlinkage void bad_interrupt(void);
-
-extern void atari_microwire_cmd( int cmd );
+extern void atari_microwire_cmd(int cmd);
 
 extern int atari_SCC_reset_done;
 
+static int atari_startup_irq(unsigned int irq)
+{
+       m68k_irq_startup(irq);
+       atari_turnon_irq(irq);
+       atari_enable_irq(irq);
+       return 0;
+}
+
+static void atari_shutdown_irq(unsigned int irq)
+{
+       atari_disable_irq(irq);
+       atari_turnoff_irq(irq);
+       m68k_irq_shutdown(irq);
+}
+
+static struct irq_controller atari_irq_controller = {
+       .name           = "atari",
+       .lock           = SPIN_LOCK_UNLOCKED,
+       .startup        = atari_startup_irq,
+       .shutdown       = atari_shutdown_irq,
+       .enable         = atari_enable_irq,
+       .disable        = atari_disable_irq,
+};
+
 /*
  * void atari_init_IRQ (void)
  *
@@ -333,12 +356,8 @@ extern int atari_SCC_reset_done;
 
 void __init atari_init_IRQ(void)
 {
-       int i;
-
-       /* initialize the vector table */
-       for (i = 0; i < NUM_INT_SOURCES; ++i) {
-               vectors[IRQ_SOURCE_TO_VECTOR(i)] = bad_interrupt;
-       }
+       m68k_setup_user_interrupt(VEC_USER, 192, NULL);
+       m68k_setup_irq_controller(&atari_irq_controller, 1, NUM_ATARI_SOURCES - 1);
 
        /* Initialize the MFP(s) */
 
@@ -378,8 +397,7 @@ void __init atari_init_IRQ(void)
                                                                         * enabled in VME mask
                                                                         */
                tt_scu.vme_mask = 0x60;         /* enable MFP and SCC ints */
-       }
-       else {
+       } else {
                /* If no SCU and no Hades, the HSYNC interrupt needs to be
                 * disabled this way. (Else _inthandler in kernel/sys_call.S
                 * gets overruns)
@@ -404,184 +422,6 @@ void __init atari_init_IRQ(void)
 }
 
 
-static irqreturn_t atari_call_irq_list( int irq, void *dev_id, struct pt_regs *fp )
-{
-       irq_node_t *node;
-
-       for (node = (irq_node_t *)dev_id; node; node = node->next)
-               node->handler(irq, node->dev_id, fp);
-       return IRQ_HANDLED;
-}
-
-
-/*
- * atari_request_irq : add an interrupt service routine for a particular
- *                     machine specific interrupt source.
- *                     If the addition was successful, it returns 0.
- */
-
-int atari_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                      unsigned long flags, const char *devname, void *dev_id)
-{
-       int vector;
-       unsigned long oflags = flags;
-
-       /*
-        * The following is a hack to make some PCI card drivers work,
-        * which set the SA_SHIRQ flag.
-        */
-
-       flags &= ~SA_SHIRQ;
-
-       if (flags == SA_INTERRUPT) {
-               printk ("%s: SA_INTERRUPT changed to IRQ_TYPE_SLOW for %s\n",
-                       __FUNCTION__, devname);
-               flags = IRQ_TYPE_SLOW;
-       }
-       if (flags < IRQ_TYPE_SLOW || flags > IRQ_TYPE_PRIO) {
-               printk ("%s: Bad irq type 0x%lx <0x%lx> requested from %s\n",
-                       __FUNCTION__, flags, oflags, devname);
-               return -EINVAL;
-       }
-       if (!IS_VALID_INTNO(irq)) {
-               printk ("%s: Unknown irq %d requested from %s\n",
-                       __FUNCTION__, irq, devname);
-               return -ENXIO;
-       }
-       vector = IRQ_SOURCE_TO_VECTOR(irq);
-
-       /*
-        * Check type/source combination: slow ints are (currently)
-        * only possible for MFP-interrupts.
-        */
-       if (flags == IRQ_TYPE_SLOW &&
-               (irq < STMFP_SOURCE_BASE || irq >= SCC_SOURCE_BASE)) {
-               printk ("%s: Slow irq requested for non-MFP source %d from %s\n",
-                       __FUNCTION__, irq, devname);
-               return -EINVAL;
-       }
-
-       if (vectors[vector] == bad_interrupt) {
-               /* int has no handler yet */
-               irq_handler[irq].handler = handler;
-               irq_handler[irq].dev_id  = dev_id;
-               irq_param[irq].flags   = flags;
-               irq_param[irq].devname = devname;
-               vectors[vector] =
-                       (flags == IRQ_TYPE_SLOW) ? slow_handlers[irq-STMFP_SOURCE_BASE] :
-                       (flags == IRQ_TYPE_FAST) ? atari_fast_irq_handler :
-                                                 atari_prio_irq_handler;
-               /* If MFP int, also enable and umask it */
-               atari_turnon_irq(irq);
-               atari_enable_irq(irq);
-
-               return 0;
-       }
-       else if (irq_param[irq].flags == flags) {
-               /* old handler is of same type -> handlers can be chained */
-               irq_node_t *node;
-               unsigned long flags;
-
-               local_irq_save(flags);
-
-               if (irq_handler[irq].handler != atari_call_irq_list) {
-                       /* Only one handler yet, make a node for this first one */
-                       if (!(node = new_irq_node()))
-                               return -ENOMEM;
-                       node->handler = irq_handler[irq].handler;
-                       node->dev_id  = irq_handler[irq].dev_id;
-                       node->devname = irq_param[irq].devname;
-                       node->next = NULL;
-
-                       irq_handler[irq].handler = atari_call_irq_list;
-                       irq_handler[irq].dev_id  = node;
-                       irq_param[irq].devname   = "chained";
-               }
-
-               if (!(node = new_irq_node()))
-                       return -ENOMEM;
-               node->handler = handler;
-               node->dev_id  = dev_id;
-               node->devname = devname;
-               /* new handlers are put in front of the queue */
-               node->next = irq_handler[irq].dev_id;
-               irq_handler[irq].dev_id = node;
-
-               local_irq_restore(flags);
-               return 0;
-       } else {
-               printk ("%s: Irq %d allocated by other type int (call from %s)\n",
-                       __FUNCTION__, irq, devname);
-               return -EBUSY;
-       }
-}
-
-void atari_free_irq(unsigned int irq, void *dev_id)
-{
-       unsigned long flags;
-       int vector;
-       irq_node_t **list, *node;
-
-       if (!IS_VALID_INTNO(irq)) {
-               printk("%s: Unknown irq %d\n", __FUNCTION__, irq);
-               return;
-       }
-
-       vector = IRQ_SOURCE_TO_VECTOR(irq);
-       if (vectors[vector] == bad_interrupt)
-               goto not_found;
-
-       local_irq_save(flags);
-
-       if (irq_handler[irq].handler != atari_call_irq_list) {
-               /* It's the only handler for the interrupt */
-               if (irq_handler[irq].dev_id != dev_id) {
-                       local_irq_restore(flags);
-                       goto not_found;
-               }
-               irq_handler[irq].handler = NULL;
-               irq_handler[irq].dev_id  = NULL;
-               irq_param[irq].devname   = NULL;
-               vectors[vector] = bad_interrupt;
-               /* If MFP int, also disable it */
-               atari_disable_irq(irq);
-               atari_turnoff_irq(irq);
-
-               local_irq_restore(flags);
-               return;
-       }
-
-       /* The interrupt is chained, find the irq on the list */
-       for(list = (irq_node_t **)&irq_handler[irq].dev_id; *list; list = &(*list)->next) {
-               if ((*list)->dev_id == dev_id) break;
-       }
-       if (!*list) {
-               local_irq_restore(flags);
-               goto not_found;
-       }
-
-       (*list)->handler = NULL; /* Mark it as free for reallocation */
-       *list = (*list)->next;
-
-       /* If there's now only one handler, unchain the interrupt, i.e. plug in
-        * the handler directly again and omit atari_call_irq_list */
-       node = (irq_node_t *)irq_handler[irq].dev_id;
-       if (node && !node->next) {
-               irq_handler[irq].handler = node->handler;
-               irq_handler[irq].dev_id  = node->dev_id;
-               irq_param[irq].devname   = node->devname;
-               node->handler = NULL; /* Mark it as free for reallocation */
-       }
-
-       local_irq_restore(flags);
-       return;
-
-not_found:
-       printk("%s: tried to remove invalid irq\n", __FUNCTION__);
-       return;
-}
-
-
 /*
  * atari_register_vme_int() returns the number of a free interrupt vector for
  * hardware with a programmable int vector (probably a VME board).
@@ -591,58 +431,24 @@ unsigned long atari_register_vme_int(void)
 {
        int i;
 
-       for(i = 0; i < 32; i++)
-               if((free_vme_vec_bitmap & (1 << i)) == 0)
+       for (i = 0; i < 32; i++)
+               if ((free_vme_vec_bitmap & (1 << i)) == 0)
                        break;
 
-       if(i == 16)
+       if (i == 16)
                return 0;
 
        free_vme_vec_bitmap |= 1 << i;
-       return (VME_SOURCE_BASE + i);
+       return VME_SOURCE_BASE + i;
 }
 
 
 void atari_unregister_vme_int(unsigned long irq)
 {
-       if(irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) {
+       if (irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) {
                irq -= VME_SOURCE_BASE;
                free_vme_vec_bitmap &= ~(1 << irq);
        }
 }
 
 
-int show_atari_interrupts(struct seq_file *p, void *v)
-{
-       int i;
-
-       for (i = 0; i < NUM_INT_SOURCES; ++i) {
-               if (vectors[IRQ_SOURCE_TO_VECTOR(i)] == bad_interrupt)
-                       continue;
-               if (i < STMFP_SOURCE_BASE)
-                       seq_printf(p, "auto %2d: %10u ",
-                                      i, kstat_cpu(0).irqs[i]);
-               else
-                       seq_printf(p, "vec $%02x: %10u ",
-                                      IRQ_SOURCE_TO_VECTOR(i),
-                                      kstat_cpu(0).irqs[i]);
-
-               if (irq_handler[i].handler != atari_call_irq_list) {
-                       seq_printf(p, "%s\n", irq_param[i].devname);
-               }
-               else {
-                       irq_node_t *n;
-                       for( n = (irq_node_t *)irq_handler[i].dev_id; n; n = n->next ) {
-                               seq_printf(p, "%s\n", n->devname);
-                               if (n->next)
-                                       seq_puts(p, "                    " );
-                       }
-               }
-       }
-       if (num_spurious)
-               seq_printf(p, "spurio.: %10u\n", num_spurious);
-
-       return 0;
-}
-
-
index 1012b08e552200a75dc17a39f64d201f686399fd..727289acad7e67336573d53d1c21c7fe7a105a2f 100644 (file)
@@ -57,12 +57,6 @@ static int atari_get_hardware_list(char *buffer);
 
 /* atari specific irq functions */
 extern void atari_init_IRQ (void);
-extern int atari_request_irq (unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                              unsigned long flags, const char *devname, void *dev_id);
-extern void atari_free_irq (unsigned int irq, void *dev_id);
-extern void atari_enable_irq (unsigned int);
-extern void atari_disable_irq (unsigned int);
-extern int show_atari_interrupts (struct seq_file *, void *);
 extern void atari_mksound( unsigned int count, unsigned int ticks );
 #ifdef CONFIG_HEARTBEAT
 static void atari_heartbeat( int on );
@@ -232,13 +226,8 @@ void __init config_atari(void)
 
     mach_sched_init      = atari_sched_init;
     mach_init_IRQ        = atari_init_IRQ;
-    mach_request_irq     = atari_request_irq;
-    mach_free_irq        = atari_free_irq;
-    enable_irq           = atari_enable_irq;
-    disable_irq          = atari_disable_irq;
     mach_get_model      = atari_get_model;
     mach_get_hardware_list = atari_get_hardware_list;
-    mach_get_irq_list   = show_atari_interrupts;
     mach_gettimeoffset   = atari_gettimeoffset;
     mach_reset           = atari_reset;
     mach_max_dma_address = 0xffffff;
index 2348e6ceed1e8fef69c28ec9d38776178f0d6240..d8174004fe2f36cd6e62b2ca64078d1f54b0c8f0 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for Linux arch/m68k/bvme6000 source directory
 #
 
-obj-y          := config.o bvmeints.o rtc.o
+obj-y          := config.o rtc.o
diff --git a/arch/m68k/bvme6000/bvmeints.c b/arch/m68k/bvme6000/bvmeints.c
deleted file mode 100644 (file)
index 298a8df..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * arch/m68k/bvme6000/bvmeints.c
- *
- * Copyright (C) 1997 Richard Hirst [richard@sleepie.demon.co.uk]
- *
- * based on amiints.c -- Amiga Linux interrupt handling code
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
- *
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/seq_file.h>
-
-#include <asm/ptrace.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/traps.h>
-
-static irqreturn_t bvme6000_defhand (int irq, void *dev_id, struct pt_regs *fp);
-
-/*
- * This should ideally be 4 elements only, for speed.
- */
-
-static struct {
-       irqreturn_t     (*handler)(int, void *, struct pt_regs *);
-       unsigned long   flags;
-       void            *dev_id;
-       const char      *devname;
-       unsigned        count;
-} irq_tab[256];
-
-/*
- * void bvme6000_init_IRQ (void)
- *
- * Parameters: None
- *
- * Returns:    Nothing
- *
- * This function is called during kernel startup to initialize
- * the bvme6000 IRQ handling routines.
- */
-
-void bvme6000_init_IRQ (void)
-{
-       int i;
-
-       for (i = 0; i < 256; i++) {
-               irq_tab[i].handler = bvme6000_defhand;
-               irq_tab[i].flags = IRQ_FLG_STD;
-               irq_tab[i].dev_id = NULL;
-               irq_tab[i].devname = NULL;
-               irq_tab[i].count = 0;
-       }
-}
-
-int bvme6000_request_irq(unsigned int irq,
-               irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                unsigned long flags, const char *devname, void *dev_id)
-{
-       if (irq > 255) {
-               printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
-               return -ENXIO;
-       }
-#if 0
-       /* Nothing special about auto-vectored devices for the BVME6000,
-        * but treat it specially to avoid changes elsewhere.
-        */
-
-       if (irq >= VEC_INT1 && irq <= VEC_INT7)
-               return cpu_request_irq(irq - VEC_SPUR, handler, flags,
-                                               devname, dev_id);
-#endif
-       if (!(irq_tab[irq].flags & IRQ_FLG_STD)) {
-               if (irq_tab[irq].flags & IRQ_FLG_LOCK) {
-                       printk("%s: IRQ %d from %s is not replaceable\n",
-                              __FUNCTION__, irq, irq_tab[irq].devname);
-                       return -EBUSY;
-               }
-               if (flags & IRQ_FLG_REPLACE) {
-                       printk("%s: %s can't replace IRQ %d from %s\n",
-                              __FUNCTION__, devname, irq, irq_tab[irq].devname);
-                       return -EBUSY;
-               }
-       }
-       irq_tab[irq].handler = handler;
-       irq_tab[irq].flags   = flags;
-       irq_tab[irq].dev_id  = dev_id;
-       irq_tab[irq].devname = devname;
-       return 0;
-}
-
-void bvme6000_free_irq(unsigned int irq, void *dev_id)
-{
-       if (irq > 255) {
-               printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
-               return;
-       }
-#if 0
-       if (irq >= VEC_INT1 && irq <= VEC_INT7) {
-               cpu_free_irq(irq - VEC_SPUR, dev_id);
-               return;
-       }
-#endif
-       if (irq_tab[irq].dev_id != dev_id)
-               printk("%s: Removing probably wrong IRQ %d from %s\n",
-                      __FUNCTION__, irq, irq_tab[irq].devname);
-
-       irq_tab[irq].handler = bvme6000_defhand;
-       irq_tab[irq].flags   = IRQ_FLG_STD;
-       irq_tab[irq].dev_id  = NULL;
-       irq_tab[irq].devname = NULL;
-}
-
-irqreturn_t bvme6000_process_int (unsigned long vec, struct pt_regs *fp)
-{
-       if (vec > 255) {
-               printk ("bvme6000_process_int: Illegal vector %ld", vec);
-               return IRQ_NONE;
-       } else {
-               irq_tab[vec].count++;
-               irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp);
-               return IRQ_HANDLED;
-       }
-}
-
-int show_bvme6000_interrupts(struct seq_file *p, void *v)
-{
-       int i;
-
-       for (i = 0; i < 256; i++) {
-               if (irq_tab[i].count)
-                       seq_printf(p, "Vec 0x%02x: %8d  %s\n",
-                           i, irq_tab[i].count,
-                           irq_tab[i].devname ? irq_tab[i].devname : "free");
-       }
-       return 0;
-}
-
-
-static irqreturn_t bvme6000_defhand (int irq, void *dev_id, struct pt_regs *fp)
-{
-       printk ("Unknown interrupt 0x%02x\n", irq);
-       return IRQ_NONE;
-}
-
-void bvme6000_enable_irq (unsigned int irq)
-{
-}
-
-
-void bvme6000_disable_irq (unsigned int irq)
-{
-}
-
index c90cb5fcc8efb6e82559d608ba3ed42b8e46bb5d..d1e916ae55a8003f5216bfadb258e0b1eecb5bfe 100644 (file)
 #include <asm/machdep.h>
 #include <asm/bvme6000hw.h>
 
-extern irqreturn_t bvme6000_process_int (int level, struct pt_regs *regs);
-extern void bvme6000_init_IRQ (void);
-extern void bvme6000_free_irq (unsigned int, void *);
-extern int  show_bvme6000_interrupts(struct seq_file *, void *);
-extern void bvme6000_enable_irq (unsigned int);
-extern void bvme6000_disable_irq (unsigned int);
 static void bvme6000_get_model(char *model);
 static int  bvme6000_get_hardware_list(char *buffer);
-extern int  bvme6000_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
 extern void bvme6000_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
 extern unsigned long bvme6000_gettimeoffset (void);
 extern int bvme6000_hwclk (int, struct rtc_time *);
@@ -100,6 +93,14 @@ static int bvme6000_get_hardware_list(char *buffer)
     return 0;
 }
 
+/*
+ * This function is called during kernel startup to initialize
+ * the bvme6000 IRQ handling routines.
+ */
+static void bvme6000_init_IRQ(void)
+{
+       m68k_setup_user_interrupt(VEC_USER, 192, NULL);
+}
 
 void __init config_bvme6000(void)
 {
@@ -127,12 +128,6 @@ void __init config_bvme6000(void)
     mach_hwclk           = bvme6000_hwclk;
     mach_set_clock_mmss         = bvme6000_set_clock_mmss;
     mach_reset          = bvme6000_reset;
-    mach_free_irq       = bvme6000_free_irq;
-    mach_process_int    = bvme6000_process_int;
-    mach_get_irq_list   = show_bvme6000_interrupts;
-    mach_request_irq    = bvme6000_request_irq;
-    enable_irq          = bvme6000_enable_irq;
-    disable_irq          = bvme6000_disable_irq;
     mach_get_model       = bvme6000_get_model;
     mach_get_hardware_list = bvme6000_get_hardware_list;
 
index 89b6317899e346d89048ddfd10b6820b5b209e42..288b9c67c9bf4a19f024ff892ce3f7a24d91ac63 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for Linux arch/m68k/hp300 source directory
 #
 
-obj-y          := ksyms.o config.o ints.o time.o reboot.o
+obj-y          := ksyms.o config.o time.o reboot.o
index 6d129eef370f1df8d5dab71c8127384c93ad3b16..2ef271cd818b8cc44a1aeb3ea15f0458322e5f69 100644 (file)
@@ -21,7 +21,6 @@
 #include <asm/hp300hw.h>
 #include <asm/rtc.h>
 
-#include "ints.h"
 #include "time.h"
 
 unsigned long hp300_model;
@@ -64,8 +63,6 @@ static char *hp300_models[] __initdata = {
 static char hp300_model_name[13] = "HP9000/";
 
 extern void hp300_reset(void);
-extern irqreturn_t (*hp300_default_handler[])(int, void *, struct pt_regs *);
-extern int show_hp300_interrupts(struct seq_file *, void *);
 #ifdef CONFIG_SERIAL_8250_CONSOLE
 extern int hp300_setup_serial_console(void) __init;
 #endif
@@ -245,16 +242,16 @@ static unsigned int hp300_get_ss(void)
                hp300_rtc_read(RTC_REG_SEC2);
 }
 
+static void __init hp300_init_IRQ(void)
+{
+}
+
 void __init config_hp300(void)
 {
        mach_sched_init      = hp300_sched_init;
        mach_init_IRQ        = hp300_init_IRQ;
-       mach_request_irq     = hp300_request_irq;
-       mach_free_irq        = hp300_free_irq;
        mach_get_model       = hp300_get_model;
-       mach_get_irq_list    = show_hp300_interrupts;
        mach_gettimeoffset   = hp300_gettimeoffset;
-       mach_default_handler = &hp300_default_handler;
        mach_hwclk           = hp300_hwclk;
        mach_get_ss          = hp300_get_ss;
        mach_reset           = hp300_reset;
diff --git a/arch/m68k/hp300/ints.c b/arch/m68k/hp300/ints.c
deleted file mode 100644 (file)
index 0c5bb40..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- *  linux/arch/m68k/hp300/ints.c
- *
- *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
- *
- *  This file contains the HP300-specific interrupt handling.
- *  We only use the autovector interrupts, and therefore we need to
- *  maintain lists of devices sharing each ipl.
- *  [ipl list code added by Peter Maydell <pmaydell@chiark.greenend.org.uk> 06/1998]
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <asm/machdep.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/traps.h>
-#include <asm/ptrace.h>
-#include <asm/errno.h>
-#include "ints.h"
-
-/* Each ipl has a linked list of interrupt service routines.
- * Service routines are added via hp300_request_irq() and removed
- * via hp300_free_irq(). The device driver should set IRQ_FLG_FAST
- * if it needs to be serviced early (eg FIFOless UARTs); this will
- * cause it to be added at the front of the queue rather than
- * the back.
- * Currently IRQ_FLG_SLOW and flags=0 are treated identically; if
- * we needed three levels of priority we could distinguish them
- * but this strikes me as mildly ugly...
- */
-
-/* we start with no entries in any list */
-static irq_node_t *hp300_irq_list[HP300_NUM_IRQS];
-
-static spinlock_t irqlist_lock;
-
-/* This handler receives all interrupts, dispatching them to the registered handlers */
-static irqreturn_t hp300_int_handler(int irq, void *dev_id, struct pt_regs *fp)
-{
-        irq_node_t *t;
-        /* We just give every handler on the chain an opportunity to handle
-         * the interrupt, in priority order.
-         */
-        for(t = hp300_irq_list[irq]; t; t=t->next)
-                t->handler(irq, t->dev_id, fp);
-        /* We could put in some accounting routines, checks for stray interrupts,
-         * etc, in here. Note that currently we can't tell whether or not
-         * a handler handles the interrupt, though.
-         */
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t hp300_badint(int irq, void *dev_id, struct pt_regs *fp)
-{
-       num_spurious += 1;
-       return IRQ_NONE;
-}
-
-irqreturn_t (*hp300_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
-       [0] = hp300_badint,
-       [1] = hp300_int_handler,
-       [2] = hp300_int_handler,
-       [3] = hp300_int_handler,
-       [4] = hp300_int_handler,
-       [5] = hp300_int_handler,
-       [6] = hp300_int_handler,
-       [7] = hp300_int_handler
-};
-
-/* dev_id had better be unique to each handler because it's the only way we have
- * to distinguish handlers when removing them...
- *
- * It would be pretty easy to support IRQ_FLG_LOCK (handler is not replacable)
- * and IRQ_FLG_REPLACE (handler replaces existing one with this dev_id)
- * if we wanted to. IRQ_FLG_FAST is needed for devices where interrupt latency
- * matters (eg the dreaded FIFOless UART...)
- */
-int hp300_request_irq(unsigned int irq,
-                      irqreturn_t (*handler) (int, void *, struct pt_regs *),
-                      unsigned long flags, const char *devname, void *dev_id)
-{
-        irq_node_t *t, *n = new_irq_node();
-
-        if (!n)                                   /* oops, no free nodes */
-                return -ENOMEM;
-
-       spin_lock_irqsave(&irqlist_lock, flags);
-
-        if (!hp300_irq_list[irq]) {
-                /* no list yet */
-                hp300_irq_list[irq] = n;
-                n->next = NULL;
-        } else if (flags & IRQ_FLG_FAST) {
-                /* insert at head of list */
-                n->next = hp300_irq_list[irq];
-                hp300_irq_list[irq] = n;
-        } else {
-                /* insert at end of list */
-                for(t = hp300_irq_list[irq]; t->next; t = t->next)
-                        /* do nothing */;
-                n->next = NULL;
-                t->next = n;
-        }
-
-        /* Fill in n appropriately */
-        n->handler = handler;
-        n->flags = flags;
-        n->dev_id = dev_id;
-        n->devname = devname;
-       spin_unlock_irqrestore(&irqlist_lock, flags);
-       return 0;
-}
-
-void hp300_free_irq(unsigned int irq, void *dev_id)
-{
-        irq_node_t *t;
-        unsigned long flags;
-
-        spin_lock_irqsave(&irqlist_lock, flags);
-
-        t = hp300_irq_list[irq];
-        if (!t)                                   /* no handlers at all for that IRQ */
-        {
-                printk(KERN_ERR "hp300_free_irq: attempt to remove nonexistent handler for IRQ %d\n", irq);
-                spin_unlock_irqrestore(&irqlist_lock, flags);
-               return;
-        }
-
-        if (t->dev_id == dev_id)
-        {                                         /* removing first handler on chain */
-                t->flags = IRQ_FLG_STD;           /* we probably don't really need these */
-                t->dev_id = NULL;
-                t->devname = NULL;
-                t->handler = NULL;                /* frees this irq_node_t */
-                hp300_irq_list[irq] = t->next;
-               spin_unlock_irqrestore(&irqlist_lock, flags);
-               return;
-        }
-
-        /* OK, must be removing from middle of the chain */
-
-        for (t = hp300_irq_list[irq]; t->next && t->next->dev_id != dev_id; t = t->next)
-                /* do nothing */;
-        if (!t->next)
-        {
-                printk(KERN_ERR "hp300_free_irq: attempt to remove nonexistent handler for IRQ %d\n", irq);
-               spin_unlock_irqrestore(&irqlist_lock, flags);
-               return;
-        }
-        /* remove the entry after t: */
-        t->next->flags = IRQ_FLG_STD;
-        t->next->dev_id = NULL;
-       t->next->devname = NULL;
-       t->next->handler = NULL;
-        t->next = t->next->next;
-
-       spin_unlock_irqrestore(&irqlist_lock, flags);
-}
-
-int show_hp300_interrupts(struct seq_file *p, void *v)
-{
-       return 0;
-}
-
-void __init hp300_init_IRQ(void)
-{
-       spin_lock_init(&irqlist_lock);
-}
diff --git a/arch/m68k/hp300/ints.h b/arch/m68k/hp300/ints.h
deleted file mode 100644 (file)
index 8cfabe2..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-extern void hp300_init_IRQ(void);
-extern void (*hp300_handlers[8])(int, void *, struct pt_regs *);
-extern void hp300_free_irq(unsigned int irq, void *dev_id);
-extern int hp300_request_irq(unsigned int irq,
-               irqreturn_t (*handler) (int, void *, struct pt_regs *),
-               unsigned long flags, const char *devname, void *dev_id);
-
-/* number of interrupts, includes 0 (what's that?) */
-#define HP300_NUM_IRQS 8
index 8da5b1b31e616c199349569e3028adbaab6967b4..7df05662b27795d81c6b3b0b3e49d1bb20c53652 100644 (file)
@@ -18,7 +18,6 @@
 #include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/blinken.h>
-#include "ints.h"
 
 /* Clock hardware definitions */
 
@@ -71,7 +70,7 @@ void __init hp300_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *
 
   asm volatile(" movpw %0,%1@(5)" : : "d" (INTVAL), "a" (CLOCKBASE));
 
-  cpu_request_irq(6, hp300_tick, IRQ_FLG_STD, "timer tick", vector);
+  request_irq(IRQ_AUTO_6, hp300_tick, IRQ_FLG_STD, "timer tick", vector);
 
   out_8(CLOCKBASE + CLKCR2, 0x1);              /* select CR1 */
   out_8(CLOCKBASE + CLKCR1, 0x40);             /* enable irq */
index 458925c471a1bb494c74a58efe9da146c4563e2a..dae609797dc019f02d9899851f1c1a065a97d207 100644 (file)
@@ -9,8 +9,8 @@ else
 endif
 extra-y        += vmlinux.lds
 
-obj-y          := entry.o process.o traps.o ints.o signal.o ptrace.o \
-                       sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o
+obj-y  := entry.o process.o traps.o ints.o dma.o signal.o ptrace.o \
+          sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o
 
 obj-$(CONFIG_PCI)      += bios32.o
 obj-$(CONFIG_MODULES)  += module.o
diff --git a/arch/m68k/kernel/dma.c b/arch/m68k/kernel/dma.c
new file mode 100644 (file)
index 0000000..fc449f8
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#undef DEBUG
+
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+
+#include <asm/pgalloc.h>
+#include <asm/scatterlist.h>
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+                        dma_addr_t *handle, int flag)
+{
+       struct page *page, **map;
+       pgprot_t pgprot;
+       void *addr;
+       int i, order;
+
+       pr_debug("dma_alloc_coherent: %d,%x\n", size, flag);
+
+       size = PAGE_ALIGN(size);
+       order = get_order(size);
+
+       page = alloc_pages(flag, order);
+       if (!page)
+               return NULL;
+
+       *handle = page_to_phys(page);
+       map = kmalloc(sizeof(struct page *) << order, flag & ~__GFP_DMA);
+       if (!map) {
+               __free_pages(page, order);
+               return NULL;
+       }
+       split_page(page, order);
+
+       order = 1 << order;
+       size >>= PAGE_SHIFT;
+       map[0] = page;
+       for (i = 1; i < size; i++)
+               map[i] = page + i;
+       for (; i < order; i++)
+               __free_page(page + i);
+       pgprot = __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
+       if (CPU_IS_040_OR_060)
+               pgprot_val(pgprot) |= _PAGE_GLOBAL040 | _PAGE_NOCACHE_S;
+       else
+               pgprot_val(pgprot) |= _PAGE_NOCACHE030;
+       addr = vmap(map, size, flag, pgprot);
+       kfree(map);
+
+       return addr;
+}
+EXPORT_SYMBOL(dma_alloc_coherent);
+
+void dma_free_coherent(struct device *dev, size_t size,
+                      void *addr, dma_addr_t handle)
+{
+       pr_debug("dma_free_coherent: %p, %x\n", addr, handle);
+       vfree(addr);
+}
+EXPORT_SYMBOL(dma_free_coherent);
+
+inline void dma_sync_single_for_device(struct device *dev, dma_addr_t handle, size_t size,
+                                      enum dma_data_direction dir)
+{
+       switch (dir) {
+       case DMA_TO_DEVICE:
+               cache_push(handle, size);
+               break;
+       case DMA_FROM_DEVICE:
+               cache_clear(handle, size);
+               break;
+       default:
+               if (printk_ratelimit())
+                       printk("dma_sync_single_for_device: unsupported dir %u\n", dir);
+               break;
+       }
+}
+EXPORT_SYMBOL(dma_sync_single_for_device);
+
+void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
+                           enum dma_data_direction dir)
+{
+       int i;
+
+       for (i = 0; i < nents; sg++, i++)
+               dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir);
+}
+EXPORT_SYMBOL(dma_sync_sg_for_device);
+
+dma_addr_t dma_map_single(struct device *dev, void *addr, size_t size,
+                         enum dma_data_direction dir)
+{
+       dma_addr_t handle = virt_to_bus(addr);
+
+       dma_sync_single_for_device(dev, handle, size, dir);
+       return handle;
+}
+EXPORT_SYMBOL(dma_map_single);
+
+dma_addr_t dma_map_page(struct device *dev, struct page *page,
+                       unsigned long offset, size_t size,
+                       enum dma_data_direction dir)
+{
+       dma_addr_t handle = page_to_phys(page) + offset;
+
+       dma_sync_single_for_device(dev, handle, size, dir);
+       return handle;
+}
+EXPORT_SYMBOL(dma_map_page);
+
+int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+              enum dma_data_direction dir)
+{
+       int i;
+
+       for (i = 0; i < nents; sg++, i++) {
+               sg->dma_address = page_to_phys(sg->page) + sg->offset;
+               dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir);
+       }
+       return nents;
+}
+EXPORT_SYMBOL(dma_map_sg);
index 522079f8c2bacdb4d53fed411d3296dc150bd913..449b62b30f450747f1e1ded406a880c6768d6c8a 100644 (file)
 #include <asm/asm-offsets.h>
 
 .globl system_call, buserr, trap, resume
-.globl inthandler, sys_call_table
+.globl sys_call_table
 .globl sys_fork, sys_clone, sys_vfork
 .globl ret_from_interrupt, bad_interrupt
+.globl auto_irqhandler_fixup
+.globl user_irqvec_fixup, user_irqhandler_fixup
 
 .text
 ENTRY(buserr)
@@ -191,65 +193,29 @@ do_delayed_trace:
        jbra    resume_userspace
 
 
-#if 0
-#ifdef CONFIG_AMIGA
-ami_inthandler:
-       addql   #1,irq_stat+CPUSTAT_LOCAL_IRQ_COUNT
-       SAVE_ALL_INT
-       GET_CURRENT(%d0)
-
-       bfextu  %sp@(PT_VECTOR){#4,#12},%d0
-       movel   %d0,%a0
-       addql   #1,%a0@(kstat+STAT_IRQ-VECOFF(VEC_SPUR))
-       movel   %a0@(autoirq_list-VECOFF(VEC_SPUR)),%a0
-
-| amiga vector int handler get the req mask instead of irq vector
-       lea     CUSTOMBASE,%a1
-       movew   %a1@(C_INTREQR),%d0
-       andw    %a1@(C_INTENAR),%d0
-
-| prepare stack (push frame pointer, dev_id & req mask)
-       pea     %sp@
-       movel   %a0@(IRQ_DEVID),%sp@-
-       movel   %d0,%sp@-
-       pea     %pc@(ret_from_interrupt:w)
-       jbra    @(IRQ_HANDLER,%a0)@(0)
-
-ENTRY(nmi_handler)
-       rte
-#endif
-#endif
+/* This is the main interrupt handler for autovector interrupts */
 
-/*
-** This is the main interrupt handler, responsible for calling process_int()
-*/
-inthandler:
+ENTRY(auto_inthandler)
        SAVE_ALL_INT
        GET_CURRENT(%d0)
        addqb   #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
                                        |  put exception # in d0
-       bfextu %sp@(PT_VECTOR){#4,#10},%d0
+       bfextu  %sp@(PT_VECTOR){#4,#10},%d0
+       subw    #VEC_SPUR,%d0
 
        movel   %sp,%sp@-
        movel   %d0,%sp@-               |  put vector # on stack
-#if defined(MACH_Q40_ONLY) && defined(CONFIG_BLK_DEV_FD)
-       btstb   #4,0xff000000           | Q40 floppy needs very special treatment ...
-       jbeq    1f
-       btstb   #3,0xff000004
-       jbeq    1f
-       jbsr    floppy_hardint
-       jbra    3f
-1:
-#endif
-       jbsr    process_int             |  process the IRQ
-3:     addql   #8,%sp                  |  pop parameters off stack
+auto_irqhandler_fixup = . + 2
+       jsr     m68k_handle_int         |  process the IRQ
+       addql   #8,%sp                  |  pop parameters off stack
 
 ret_from_interrupt:
        subqb   #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
-       jeq     1f
-2:
-       RESTORE_ALL
-1:
+       jeq     ret_from_last_interrupt
+2:     RESTORE_ALL
+
+       ALIGN
+ret_from_last_interrupt:
        moveq   #(~ALLOWINT>>8)&0xff,%d0
        andb    %sp@(PT_SR),%d0
        jne     2b
@@ -260,12 +226,42 @@ ret_from_interrupt:
        pea     ret_from_exception
        jra     do_softirq
 
+/* Handler for user defined interrupt vectors */
+
+ENTRY(user_inthandler)
+       SAVE_ALL_INT
+       GET_CURRENT(%d0)
+       addqb   #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+                                       |  put exception # in d0
+       bfextu  %sp@(PT_VECTOR){#4,#10},%d0
+user_irqvec_fixup = . + 2
+       subw    #VEC_USER,%d0
+
+       movel   %sp,%sp@-
+       movel   %d0,%sp@-               |  put vector # on stack
+user_irqhandler_fixup = . + 2
+       jsr     m68k_handle_int         |  process the IRQ
+       addql   #8,%sp                  |  pop parameters off stack
+
+       subqb   #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+       jeq     ret_from_last_interrupt
+       RESTORE_ALL
 
 /* Handler for uninitialized and spurious interrupts */
 
-bad_interrupt:
-       addql   #1,num_spurious
-       rte
+ENTRY(bad_inthandler)
+       SAVE_ALL_INT
+       GET_CURRENT(%d0)
+       addqb   #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+
+       movel   %sp,%sp@-
+       jsr     handle_badint
+       addql   #4,%sp
+
+       subqb   #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+       jeq     ret_from_last_interrupt
+       RESTORE_ALL
+
 
 ENTRY(sys_fork)
        SAVE_SWITCH_STACK
index 4b85514792e7868917436d2f192760a2ddba1ced..5a8344b935474a645b4ebe0e7612169df9ded3c2 100644 (file)
 #include <asm/traps.h>
 #include <asm/page.h>
 #include <asm/machdep.h>
+#include <asm/cacheflush.h>
 
 #ifdef CONFIG_Q40
 #include <asm/q40ints.h>
 #endif
 
+extern u32 auto_irqhandler_fixup[];
+extern u32 user_irqhandler_fixup[];
+extern u16 user_irqvec_fixup[];
+
 /* table for system interrupt handlers */
-static irq_handler_t irq_list[SYS_IRQS];
-
-static const char *default_names[SYS_IRQS] = {
-       [0] = "spurious int",
-       [1] = "int1 handler",
-       [2] = "int2 handler",
-       [3] = "int3 handler",
-       [4] = "int4 handler",
-       [5] = "int5 handler",
-       [6] = "int6 handler",
-       [7] = "int7 handler"
+static struct irq_node *irq_list[NR_IRQS];
+static struct irq_controller *irq_controller[NR_IRQS];
+static int irq_depth[NR_IRQS];
+
+static int m68k_first_user_vec;
+
+static struct irq_controller auto_irq_controller = {
+       .name           = "auto",
+       .lock           = SPIN_LOCK_UNLOCKED,
+       .startup        = m68k_irq_startup,
+       .shutdown       = m68k_irq_shutdown,
 };
 
-/* The number of spurious interrupts */
-volatile unsigned int num_spurious;
+static struct irq_controller user_irq_controller = {
+       .name           = "user",
+       .lock           = SPIN_LOCK_UNLOCKED,
+       .startup        = m68k_irq_startup,
+       .shutdown       = m68k_irq_shutdown,
+};
 
 #define NUM_IRQ_NODES 100
 static irq_node_t nodes[NUM_IRQ_NODES];
 
-static void dummy_enable_irq(unsigned int irq);
-static void dummy_disable_irq(unsigned int irq);
-static int dummy_request_irq(unsigned int irq,
-               irqreturn_t (*handler) (int, void *, struct pt_regs *),
-               unsigned long flags, const char *devname, void *dev_id);
-static void dummy_free_irq(unsigned int irq, void *dev_id);
-
-void (*enable_irq) (unsigned int) = dummy_enable_irq;
-void (*disable_irq) (unsigned int) = dummy_disable_irq;
-
-int (*mach_request_irq) (unsigned int, irqreturn_t (*)(int, void *, struct pt_regs *),
-                      unsigned long, const char *, void *) = dummy_request_irq;
-void (*mach_free_irq) (unsigned int, void *) = dummy_free_irq;
-
-void init_irq_proc(void);
-
 /*
  * void init_IRQ(void)
  *
@@ -101,18 +94,70 @@ void __init init_IRQ(void)
                hardirq_mask_is_broken();
        }
 
-       for (i = 0; i < SYS_IRQS; i++) {
-               if (mach_default_handler)
-                       irq_list[i].handler = (*mach_default_handler)[i];
-               irq_list[i].flags   = 0;
-               irq_list[i].dev_id  = NULL;
-               irq_list[i].devname = default_names[i];
-       }
+       for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++)
+               irq_controller[i] = &auto_irq_controller;
+
+       mach_init_IRQ();
+}
+
+/**
+ * m68k_setup_auto_interrupt
+ * @handler: called from auto vector interrupts
+ *
+ * setup the handler to be called from auto vector interrupts instead of the
+ * standard m68k_handle_int(), it will be called with irq numbers in the range
+ * from IRQ_AUTO_1 - IRQ_AUTO_7.
+ */
+void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *))
+{
+       if (handler)
+               *auto_irqhandler_fixup = (u32)handler;
+       flush_icache();
+}
 
-       for (i = 0; i < NUM_IRQ_NODES; i++)
-               nodes[i].handler = NULL;
+/**
+ * m68k_setup_user_interrupt
+ * @vec: first user vector interrupt to handle
+ * @cnt: number of active user vector interrupts
+ * @handler: called from user vector interrupts
+ *
+ * setup user vector interrupts, this includes activating the specified range
+ * of interrupts, only then these interrupts can be requested (note: this is
+ * different from auto vector interrupts). An optional handler can be installed
+ * to be called instead of the default m68k_handle_int(), it will be called
+ * with irq numbers starting from IRQ_USER.
+ */
+void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt,
+                                     void (*handler)(unsigned int, struct pt_regs *))
+{
+       int i;
+
+       m68k_first_user_vec = vec;
+       for (i = 0; i < cnt; i++)
+               irq_controller[IRQ_USER + i] = &user_irq_controller;
+       *user_irqvec_fixup = vec - IRQ_USER;
+       if (handler)
+               *user_irqhandler_fixup = (u32)handler;
+       flush_icache();
+}
+
+/**
+ * m68k_setup_irq_controller
+ * @contr: irq controller which controls specified irq
+ * @irq: first irq to be managed by the controller
+ *
+ * Change the controller for the specified range of irq, which will be used to
+ * manage these irq. auto/user irq already have a default controller, which can
+ * be changed as well, but the controller probably should use m68k_irq_startup/
+ * m68k_irq_shutdown.
+ */
+void m68k_setup_irq_controller(struct irq_controller *contr, unsigned int irq,
+                              unsigned int cnt)
+{
+       int i;
 
-       mach_init_IRQ ();
+       for (i = 0; i < cnt; i++)
+               irq_controller[irq + i] = contr;
 }
 
 irq_node_t *new_irq_node(void)
@@ -120,84 +165,183 @@ irq_node_t *new_irq_node(void)
        irq_node_t *node;
        short i;
 
-       for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--)
-               if (!node->handler)
+       for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) {
+               if (!node->handler) {
+                       memset(node, 0, sizeof(*node));
                        return node;
+               }
+       }
 
        printk ("new_irq_node: out of nodes\n");
        return NULL;
 }
 
-/*
- * We will keep these functions until I have convinced Linus to move
- * the declaration of them from include/linux/sched.h to
- * include/asm/irq.h.
- */
+int setup_irq(unsigned int irq, struct irq_node *node)
+{
+       struct irq_controller *contr;
+       struct irq_node **prev;
+       unsigned long flags;
+
+       if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
+               printk("%s: Incorrect IRQ %d from %s\n",
+                      __FUNCTION__, irq, node->devname);
+               return -ENXIO;
+       }
+
+       spin_lock_irqsave(&contr->lock, flags);
+
+       prev = irq_list + irq;
+       if (*prev) {
+               /* Can't share interrupts unless both agree to */
+               if (!((*prev)->flags & node->flags & SA_SHIRQ)) {
+                       spin_unlock_irqrestore(&contr->lock, flags);
+                       return -EBUSY;
+               }
+               while (*prev)
+                       prev = &(*prev)->next;
+       }
+
+       if (!irq_list[irq]) {
+               if (contr->startup)
+                       contr->startup(irq);
+               else
+                       contr->enable(irq);
+       }
+       node->next = NULL;
+       *prev = node;
+
+       spin_unlock_irqrestore(&contr->lock, flags);
+
+       return 0;
+}
+
 int request_irq(unsigned int irq,
                irqreturn_t (*handler) (int, void *, struct pt_regs *),
                unsigned long flags, const char *devname, void *dev_id)
 {
-       return mach_request_irq(irq, handler, flags, devname, dev_id);
+       struct irq_node *node;
+       int res;
+
+       node = new_irq_node();
+       if (!node)
+               return -ENOMEM;
+
+       node->handler = handler;
+       node->flags   = flags;
+       node->dev_id  = dev_id;
+       node->devname = devname;
+
+       res = setup_irq(irq, node);
+       if (res)
+               node->handler = NULL;
+
+       return res;
 }
 
 EXPORT_SYMBOL(request_irq);
 
 void free_irq(unsigned int irq, void *dev_id)
 {
-       mach_free_irq(irq, dev_id);
+       struct irq_controller *contr;
+       struct irq_node **p, *node;
+       unsigned long flags;
+
+       if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
+               printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
+               return;
+       }
+
+       spin_lock_irqsave(&contr->lock, flags);
+
+       p = irq_list + irq;
+       while ((node = *p)) {
+               if (node->dev_id == dev_id)
+                       break;
+               p = &node->next;
+       }
+
+       if (node) {
+               *p = node->next;
+               node->handler = NULL;
+       } else
+               printk("%s: Removing probably wrong IRQ %d\n",
+                      __FUNCTION__, irq);
+
+       if (!irq_list[irq]) {
+               if (contr->shutdown)
+                       contr->shutdown(irq);
+               else
+                       contr->disable(irq);
+       }
+
+       spin_unlock_irqrestore(&contr->lock, flags);
 }
 
 EXPORT_SYMBOL(free_irq);
 
-int cpu_request_irq(unsigned int irq,
-                    irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                    unsigned long flags, const char *devname, void *dev_id)
+void enable_irq(unsigned int irq)
 {
-       if (irq < IRQ1 || irq > IRQ7) {
-               printk("%s: Incorrect IRQ %d from %s\n",
-                      __FUNCTION__, irq, devname);
-               return -ENXIO;
-       }
+       struct irq_controller *contr;
+       unsigned long flags;
 
-#if 0
-       if (!(irq_list[irq].flags & IRQ_FLG_STD)) {
-               if (irq_list[irq].flags & IRQ_FLG_LOCK) {
-                       printk("%s: IRQ %d from %s is not replaceable\n",
-                              __FUNCTION__, irq, irq_list[irq].devname);
-                       return -EBUSY;
-               }
-               if (!(flags & IRQ_FLG_REPLACE)) {
-                       printk("%s: %s can't replace IRQ %d from %s\n",
-                              __FUNCTION__, devname, irq, irq_list[irq].devname);
-                       return -EBUSY;
-               }
+       if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
+               printk("%s: Incorrect IRQ %d\n",
+                      __FUNCTION__, irq);
+               return;
        }
-#endif
 
-       irq_list[irq].handler = handler;
-       irq_list[irq].flags   = flags;
-       irq_list[irq].dev_id  = dev_id;
-       irq_list[irq].devname = devname;
-       return 0;
+       spin_lock_irqsave(&contr->lock, flags);
+       if (irq_depth[irq]) {
+               if (!--irq_depth[irq]) {
+                       if (contr->enable)
+                               contr->enable(irq);
+               }
+       } else
+               WARN_ON(1);
+       spin_unlock_irqrestore(&contr->lock, flags);
 }
 
-void cpu_free_irq(unsigned int irq, void *dev_id)
+EXPORT_SYMBOL(enable_irq);
+
+void disable_irq(unsigned int irq)
 {
-       if (irq < IRQ1 || irq > IRQ7) {
-               printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
+       struct irq_controller *contr;
+       unsigned long flags;
+
+       if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
+               printk("%s: Incorrect IRQ %d\n",
+                      __FUNCTION__, irq);
                return;
        }
 
-       if (irq_list[irq].dev_id != dev_id)
-               printk("%s: Removing probably wrong IRQ %d from %s\n",
-                      __FUNCTION__, irq, irq_list[irq].devname);
+       spin_lock_irqsave(&contr->lock, flags);
+       if (!irq_depth[irq]++) {
+               if (contr->disable)
+                       contr->disable(irq);
+       }
+       spin_unlock_irqrestore(&contr->lock, flags);
+}
 
-       irq_list[irq].handler = (*mach_default_handler)[irq];
-       irq_list[irq].flags   = 0;
-       irq_list[irq].dev_id  = NULL;
-       irq_list[irq].devname = default_names[irq];
+EXPORT_SYMBOL(disable_irq);
+
+int m68k_irq_startup(unsigned int irq)
+{
+       if (irq <= IRQ_AUTO_7)
+               vectors[VEC_SPUR + irq] = auto_inthandler;
+       else
+               vectors[m68k_first_user_vec + irq - IRQ_USER] = user_inthandler;
+       return 0;
 }
 
+void m68k_irq_shutdown(unsigned int irq)
+{
+       if (irq <= IRQ_AUTO_7)
+               vectors[VEC_SPUR + irq] = bad_inthandler;
+       else
+               vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler;
+}
+
+
 /*
  * Do we need these probe functions on the m68k?
  *
@@ -225,58 +369,50 @@ int probe_irq_off (unsigned long irqs)
 
 EXPORT_SYMBOL(probe_irq_off);
 
-static void dummy_enable_irq(unsigned int irq)
-{
-       printk("calling uninitialized enable_irq()\n");
-}
-
-static void dummy_disable_irq(unsigned int irq)
+unsigned int irq_canonicalize(unsigned int irq)
 {
-       printk("calling uninitialized disable_irq()\n");
+#ifdef CONFIG_Q40
+       if (MACH_IS_Q40 && irq == 11)
+               irq = 10;
+#endif
+       return irq;
 }
 
-static int dummy_request_irq(unsigned int irq,
-               irqreturn_t (*handler) (int, void *, struct pt_regs *),
-               unsigned long flags, const char *devname, void *dev_id)
-{
-       printk("calling uninitialized request_irq()\n");
-       return 0;
-}
+EXPORT_SYMBOL(irq_canonicalize);
 
-static void dummy_free_irq(unsigned int irq, void *dev_id)
+asmlinkage void m68k_handle_int(unsigned int irq, struct pt_regs *regs)
 {
-       printk("calling uninitialized disable_irq()\n");
+       struct irq_node *node;
+
+       kstat_cpu(0).irqs[irq]++;
+       node = irq_list[irq];
+       do {
+               node->handler(irq, node->dev_id, regs);
+               node = node->next;
+       } while (node);
 }
 
-asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
+asmlinkage void handle_badint(struct pt_regs *regs)
 {
-       if (vec >= VEC_INT1 && vec <= VEC_INT7 && !MACH_IS_BVME6000) {
-               vec -= VEC_SPUR;
-               kstat_cpu(0).irqs[vec]++;
-               irq_list[vec].handler(vec, irq_list[vec].dev_id, fp);
-       } else {
-               if (mach_process_int)
-                       mach_process_int(vec, fp);
-               else
-                       panic("Can't process interrupt vector %ld\n", vec);
-               return;
-       }
+       kstat_cpu(0).irqs[0]++;
+       printk("unexpected interrupt from %u\n", regs->vector);
 }
 
 int show_interrupts(struct seq_file *p, void *v)
 {
+       struct irq_controller *contr;
+       struct irq_node *node;
        int i = *(loff_t *) v;
 
        /* autovector interrupts */
-       if (i < SYS_IRQS) {
-               if (mach_default_handler) {
-                       seq_printf(p, "auto %2d: %10u ", i,
-                                      i ? kstat_cpu(0).irqs[i] : num_spurious);
-                       seq_puts(p, "  ");
-                       seq_printf(p, "%s\n", irq_list[i].devname);
-               }
-       } else if (i == SYS_IRQS)
-               mach_get_irq_list(p, v);
+       if (irq_list[i]) {
+               contr = irq_controller[i];
+               node = irq_list[i];
+               seq_printf(p, "%-8s %3u: %10u %s", contr->name, i, kstat_cpu(0).irqs[i], node->devname);
+               while ((node = node->next))
+                       seq_printf(p, ", %s", node->devname);
+               seq_puts(p, "\n");
+       }
        return 0;
 }
 
index 5b7952ea2bae431dde15bd7c04c48068d529e7c2..1f5e1b5aeda4e63f78c0cf3c5a285e62bbd60e5b 100644 (file)
@@ -57,8 +57,6 @@ EXPORT_SYMBOL(dump_thread);
 EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strstr);
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(kernel_thread);
 #ifdef CONFIG_VME
 EXPORT_SYMBOL(vme_brdtype);
index 750d5b3c971fe001a2d86808a30b9cd237b0eebe..214a95f9f3acfb3f566f35070a82d94120796758 100644 (file)
@@ -68,11 +68,8 @@ char m68k_debug_device[6] = "";
 void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *)) __initdata = NULL;
 /* machine dependent irq functions */
 void (*mach_init_IRQ) (void) __initdata = NULL;
-irqreturn_t (*(*mach_default_handler)[]) (int, void *, struct pt_regs *);
 void (*mach_get_model) (char *model);
 int (*mach_get_hardware_list) (char *buffer);
-int (*mach_get_irq_list) (struct seq_file *, void *);
-irqreturn_t (*mach_process_int) (int, struct pt_regs *);
 /* machine dependent timer functions */
 unsigned long (*mach_gettimeoffset) (void);
 int (*mach_hwclk) (int, struct rtc_time*);
index 837a88709902b016f1fcc4e0d3e5586ef03db947..e86de7b061cd546768cc56cbfeca467164e4222d 100644 (file)
@@ -45,7 +45,6 @@
 asmlinkage void system_call(void);
 asmlinkage void buserr(void);
 asmlinkage void trap(void);
-asmlinkage void inthandler(void);
 asmlinkage void nmihandler(void);
 #ifdef CONFIG_M68KFPU_EMU
 asmlinkage void fpu_emu(void);
@@ -53,51 +52,7 @@ asmlinkage void fpu_emu(void);
 
 e_vector vectors[256] = {
        [VEC_BUSERR]    = buserr,
-       [VEC_ADDRERR]   = trap,
-       [VEC_ILLEGAL]   = trap,
-       [VEC_ZERODIV]   = trap,
-       [VEC_CHK]       = trap,
-       [VEC_TRAP]      = trap,
-       [VEC_PRIV]      = trap,
-       [VEC_TRACE]     = trap,
-       [VEC_LINE10]    = trap,
-       [VEC_LINE11]    = trap,
-       [VEC_RESV12]    = trap,
-       [VEC_COPROC]    = trap,
-       [VEC_FORMAT]    = trap,
-       [VEC_UNINT]     = trap,
-       [VEC_RESV16]    = trap,
-       [VEC_RESV17]    = trap,
-       [VEC_RESV18]    = trap,
-       [VEC_RESV19]    = trap,
-       [VEC_RESV20]    = trap,
-       [VEC_RESV21]    = trap,
-       [VEC_RESV22]    = trap,
-       [VEC_RESV23]    = trap,
-       [VEC_SPUR]      = inthandler,
-       [VEC_INT1]      = inthandler,
-       [VEC_INT2]      = inthandler,
-       [VEC_INT3]      = inthandler,
-       [VEC_INT4]      = inthandler,
-       [VEC_INT5]      = inthandler,
-       [VEC_INT6]      = inthandler,
-       [VEC_INT7]      = inthandler,
        [VEC_SYS]       = system_call,
-       [VEC_TRAP1]     = trap,
-       [VEC_TRAP2]     = trap,
-       [VEC_TRAP3]     = trap,
-       [VEC_TRAP4]     = trap,
-       [VEC_TRAP5]     = trap,
-       [VEC_TRAP6]     = trap,
-       [VEC_TRAP7]     = trap,
-       [VEC_TRAP8]     = trap,
-       [VEC_TRAP9]     = trap,
-       [VEC_TRAP10]    = trap,
-       [VEC_TRAP11]    = trap,
-       [VEC_TRAP12]    = trap,
-       [VEC_TRAP13]    = trap,
-       [VEC_TRAP14]    = trap,
-       [VEC_TRAP15]    = trap,
 };
 
 /* nmi handler for the Amiga */
@@ -132,12 +87,15 @@ void __init trap_init (void)
 {
        int i;
 
-       for (i = 48; i < 64; i++)
+       for (i = VEC_SPUR; i <= VEC_INT7; i++)
+               vectors[i] = bad_inthandler;
+
+       for (i = 0; i < VEC_USER; i++)
                if (!vectors[i])
                        vectors[i] = trap;
 
-       for (i = 64; i < 256; i++)
-               vectors[i] = inthandler;
+       for (i = VEC_USER; i < 256; i++)
+               vectors[i] = bad_inthandler;
 
 #ifdef CONFIG_M68KFPU_EMU
        if (FPU_IS_EMU)
@@ -927,66 +885,88 @@ void show_trace(unsigned long *stack)
 void show_registers(struct pt_regs *regs)
 {
        struct frame *fp = (struct frame *)regs;
+       mm_segment_t old_fs = get_fs();
+       u16 c, *cp;
        unsigned long addr;
        int i;
 
+       print_modules();
+       printk("PC: [<%08lx>]",regs->pc);
+       print_symbol(" %s", regs->pc);
+       printk("\nSR: %04x  SP: %p  a2: %08lx\n",
+              regs->sr, regs, regs->a2);
+       printk("d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
+              regs->d0, regs->d1, regs->d2, regs->d3);
+       printk("d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
+              regs->d4, regs->d5, regs->a0, regs->a1);
+
+       printk("Process %s (pid: %d, task=%p)\n",
+               current->comm, current->pid, current);
        addr = (unsigned long)&fp->un;
-       printk("Frame format=%X ", fp->ptregs.format);
-       switch (fp->ptregs.format) {
+       printk("Frame format=%X ", regs->format);
+       switch (regs->format) {
        case 0x2:
-           printk("instr addr=%08lx\n", fp->un.fmt2.iaddr);
-           addr += sizeof(fp->un.fmt2);
-           break;
+               printk("instr addr=%08lx\n", fp->un.fmt2.iaddr);
+               addr += sizeof(fp->un.fmt2);
+               break;
        case 0x3:
-           printk("eff addr=%08lx\n", fp->un.fmt3.effaddr);
-           addr += sizeof(fp->un.fmt3);
-           break;
+               printk("eff addr=%08lx\n", fp->un.fmt3.effaddr);
+               addr += sizeof(fp->un.fmt3);
+               break;
        case 0x4:
-           printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n"
-                   : "eff addr=%08lx pc=%08lx\n"),
-                  fp->un.fmt4.effaddr, fp->un.fmt4.pc);
-           addr += sizeof(fp->un.fmt4);
-           break;
+               printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n"
+                       : "eff addr=%08lx pc=%08lx\n"),
+                       fp->un.fmt4.effaddr, fp->un.fmt4.pc);
+               addr += sizeof(fp->un.fmt4);
+               break;
        case 0x7:
-           printk("eff addr=%08lx ssw=%04x faddr=%08lx\n",
-                  fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr);
-           printk("wb 1 stat/addr/data: %04x %08lx %08lx\n",
-                  fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0);
-           printk("wb 2 stat/addr/data: %04x %08lx %08lx\n",
-                  fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d);
-           printk("wb 3 stat/addr/data: %04x %08lx %08lx\n",
-                  fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d);
-           printk("push data: %08lx %08lx %08lx %08lx\n",
-                  fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2,
-                  fp->un.fmt7.pd3);
-           addr += sizeof(fp->un.fmt7);
-           break;
+               printk("eff addr=%08lx ssw=%04x faddr=%08lx\n",
+                       fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr);
+               printk("wb 1 stat/addr/data: %04x %08lx %08lx\n",
+                       fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0);
+               printk("wb 2 stat/addr/data: %04x %08lx %08lx\n",
+                       fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d);
+               printk("wb 3 stat/addr/data: %04x %08lx %08lx\n",
+                       fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d);
+               printk("push data: %08lx %08lx %08lx %08lx\n",
+                       fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2,
+                       fp->un.fmt7.pd3);
+               addr += sizeof(fp->un.fmt7);
+               break;
        case 0x9:
-           printk("instr addr=%08lx\n", fp->un.fmt9.iaddr);
-           addr += sizeof(fp->un.fmt9);
-           break;
+               printk("instr addr=%08lx\n", fp->un.fmt9.iaddr);
+               addr += sizeof(fp->un.fmt9);
+               break;
        case 0xa:
-           printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
-                  fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb,
-                  fp->un.fmta.daddr, fp->un.fmta.dobuf);
-           addr += sizeof(fp->un.fmta);
-           break;
+               printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
+                       fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb,
+                       fp->un.fmta.daddr, fp->un.fmta.dobuf);
+               addr += sizeof(fp->un.fmta);
+               break;
        case 0xb:
-           printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
-                  fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb,
-                  fp->un.fmtb.daddr, fp->un.fmtb.dobuf);
-           printk("baddr=%08lx dibuf=%08lx ver=%x\n",
-                  fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver);
-           addr += sizeof(fp->un.fmtb);
-           break;
+               printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
+                       fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb,
+                       fp->un.fmtb.daddr, fp->un.fmtb.dobuf);
+               printk("baddr=%08lx dibuf=%08lx ver=%x\n",
+                       fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver);
+               addr += sizeof(fp->un.fmtb);
+               break;
        default:
-           printk("\n");
+               printk("\n");
        }
        show_stack(NULL, (unsigned long *)addr);
 
-       printk("Code: ");
-       for (i = 0; i < 10; i++)
-               printk("%04x ", 0xffff & ((short *) fp->ptregs.pc)[i]);
+       printk("Code:");
+       set_fs(KERNEL_DS);
+       cp = (u16 *)regs->pc;
+       for (i = -8; i < 16; i++) {
+               if (get_user(c, cp + i) && i >= 0) {
+                       printk(" Bad PC value.");
+                       break;
+               }
+               printk(i ? " %04x" : " <%04x>", c);
+       }
+       set_fs(old_fs);
        printk ("\n");
 }
 
@@ -1190,19 +1170,7 @@ void die_if_kernel (char *str, struct pt_regs *fp, int nr)
 
        console_verbose();
        printk("%s: %08x\n",str,nr);
-       print_modules();
-       printk("PC: [<%08lx>]",fp->pc);
-       print_symbol(" %s\n", fp->pc);
-       printk("\nSR: %04x  SP: %p  a2: %08lx\n",
-              fp->sr, fp, fp->a2);
-       printk("d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
-              fp->d0, fp->d1, fp->d2, fp->d3);
-       printk("d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
-              fp->d4, fp->d5, fp->a0, fp->a1);
-
-       printk("Process %s (pid: %d, stackpage=%08lx)\n",
-               current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
-       show_stack(NULL, (unsigned long *)fp);
+       show_registers(fp);
        do_exit(SIGSEGV);
 }
 
index b19b7dd9bd21b0874a5ff4f2f34de172d21a5af6..6eaa881793d1064566b5dbdc65cba3a5c824aaec 100644 (file)
@@ -81,7 +81,7 @@ irqreturn_t baboon_irq(int irq, void *dev_id, struct pt_regs *regs)
        for (i = 0, irq_bit = 1 ; i < 3 ; i++, irq_bit <<= 1) {
                if (events & irq_bit/* & baboon_active*/) {
                        baboon_active &= ~irq_bit;
-                       mac_do_irq_list(IRQ_BABOON_0 + i, regs);
+                       m68k_handle_int(IRQ_BABOON_0 + i, regs);
                        baboon_active |= irq_bit;
                        baboon->mb_ifr &= ~irq_bit;
                }
index 19dce75711b1d73f2984859852d1313fb9f8b461..5a9990e436bb00899ea2b8b61ed17b50753057fb 100644 (file)
@@ -94,20 +94,6 @@ static void mac_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *))
        via_init_clock(vector);
 }
 
-extern irqreturn_t mac_default_handler(int, void *, struct pt_regs *);
-
-irqreturn_t (*mac_handlers[8])(int, void *, struct pt_regs *)=
-{
-       mac_default_handler,
-       mac_default_handler,
-       mac_default_handler,
-       mac_default_handler,
-       mac_default_handler,
-       mac_default_handler,
-       mac_default_handler,
-       mac_default_handler
-};
-
 /*
  * Parse a Macintosh-specific record in the bootinfo
  */
@@ -183,13 +169,7 @@ void __init config_mac(void)
 
        mach_sched_init      = mac_sched_init;
        mach_init_IRQ        = mac_init_IRQ;
-       mach_request_irq     = mac_request_irq;
-       mach_free_irq        = mac_free_irq;
-       enable_irq           = mac_enable_irq;
-       disable_irq          = mac_disable_irq;
        mach_get_model   = mac_get_model;
-       mach_default_handler = &mac_handlers;
-       mach_get_irq_list    = show_mac_interrupts;
        mach_gettimeoffset   = mac_gettimeoffset;
 #warning move to adb/via init
 #if 0
index 9179a37984074593dd01ddb1583814b69dcd628c..4c8ece7e64a36a4808ff4838a89eacb67572c229 100644 (file)
@@ -317,7 +317,7 @@ void __init iop_register_interrupts(void)
 {
        if (iop_ism_present) {
                if (oss_present) {
-                       cpu_request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq,
+                       request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq,
                                        IRQ_FLG_LOCK, "ISM IOP",
                                        (void *) IOP_NUM_ISM);
                        oss_irq_enable(IRQ_MAC_ADB);
index 7a1600bd195d630f82b75463131fe8fd30640a0a..694b14bb0de1e7796fa28da75033c62a7d8531ac 100644 (file)
 #define DEBUG_SPURIOUS
 #define SHUTUP_SONIC
 
-/*
- * The mac_irq_list array is an array of linked lists of irq_node_t nodes.
- * Each node contains one handler to be called whenever the interrupt
- * occurs, with fast handlers listed before slow handlers.
- */
-
-irq_node_t *mac_irq_list[NUM_MAC_SOURCES];
-
 /* SCC interrupt mask */
 
 static int scc_mask;
@@ -209,8 +201,8 @@ extern int  baboon_irq_pending(int);
  * SCC interrupt routines
  */
 
-static void scc_irq_enable(int);
-static void scc_irq_disable(int);
+static void scc_irq_enable(unsigned int);
+static void scc_irq_disable(unsigned int);
 
 /*
  * console_loglevel determines NMI handler function
@@ -221,21 +213,25 @@ irqreturn_t mac_debug_handler(int, void *, struct pt_regs *);
 
 /* #define DEBUG_MACINTS */
 
+static void mac_enable_irq(unsigned int irq);
+static void mac_disable_irq(unsigned int irq);
+
+static struct irq_controller mac_irq_controller = {
+       .name           = "mac",
+       .lock           = SPIN_LOCK_UNLOCKED,
+       .enable         = mac_enable_irq,
+       .disable        = mac_disable_irq,
+};
+
 void mac_init_IRQ(void)
 {
-        int i;
-
 #ifdef DEBUG_MACINTS
        printk("mac_init_IRQ(): Setting things up...\n");
 #endif
-       /* Initialize the IRQ handler lists. Initially each list is empty, */
-
-       for (i = 0; i < NUM_MAC_SOURCES; i++) {
-               mac_irq_list[i] = NULL;
-       }
-
        scc_mask = 0;
 
+       m68k_setup_irq_controller(&mac_irq_controller, IRQ_USER,
+                                 NUM_MAC_SOURCES - IRQ_USER);
        /* Make sure the SONIC interrupt is cleared or things get ugly */
 #ifdef SHUTUP_SONIC
        printk("Killing onboard sonic... ");
@@ -252,119 +248,22 @@ void mac_init_IRQ(void)
         * at levels 1-7. Most of the work is done elsewhere.
         */
 
-       if (oss_present) {
+       if (oss_present)
                oss_register_interrupts();
-       } else {
+       else
                via_register_interrupts();
-       }
-       if (psc_present) psc_register_interrupts();
-       if (baboon_present) baboon_register_interrupts();
+       if (psc_present)
+               psc_register_interrupts();
+       if (baboon_present)
+               baboon_register_interrupts();
        iop_register_interrupts();
-       cpu_request_irq(7, mac_nmi_handler, IRQ_FLG_LOCK, "NMI",
+       request_irq(IRQ_AUTO_7, mac_nmi_handler, 0, "NMI",
                        mac_nmi_handler);
 #ifdef DEBUG_MACINTS
        printk("mac_init_IRQ(): Done!\n");
 #endif
 }
 
-/*
- * Routines to work with irq_node_t's on linked lists lifted from
- * the Amiga code written by Roman Zippel.
- */
-
-static inline void mac_insert_irq(irq_node_t **list, irq_node_t *node)
-{
-       unsigned long flags;
-       irq_node_t *cur;
-
-       if (!node->dev_id)
-               printk("%s: Warning: dev_id of %s is zero\n",
-                      __FUNCTION__, node->devname);
-
-       local_irq_save(flags);
-
-       cur = *list;
-
-       if (node->flags & IRQ_FLG_FAST) {
-               node->flags &= ~IRQ_FLG_SLOW;
-               while (cur && cur->flags & IRQ_FLG_FAST) {
-                       list = &cur->next;
-                       cur = cur->next;
-               }
-       } else if (node->flags & IRQ_FLG_SLOW) {
-               while (cur) {
-                       list = &cur->next;
-                       cur = cur->next;
-               }
-       } else {
-               while (cur && !(cur->flags & IRQ_FLG_SLOW)) {
-                       list = &cur->next;
-                       cur = cur->next;
-               }
-       }
-
-       node->next = cur;
-       *list = node;
-
-       local_irq_restore(flags);
-}
-
-static inline void mac_delete_irq(irq_node_t **list, void *dev_id)
-{
-       unsigned long flags;
-       irq_node_t *node;
-
-       local_irq_save(flags);
-
-       for (node = *list; node; list = &node->next, node = *list) {
-               if (node->dev_id == dev_id) {
-                       *list = node->next;
-                       /* Mark it as free. */
-                       node->handler = NULL;
-                       local_irq_restore(flags);
-                       return;
-               }
-       }
-       local_irq_restore(flags);
-       printk ("%s: tried to remove invalid irq\n", __FUNCTION__);
-}
-
-/*
- * Call all the handlers for a given interrupt. Fast handlers are called
- * first followed by slow handlers.
- *
- * This code taken from the original Amiga code written by Roman Zippel.
- */
-
-void mac_do_irq_list(int irq, struct pt_regs *fp)
-{
-       irq_node_t *node, *slow_nodes;
-       unsigned long flags;
-
-       kstat_cpu(0).irqs[irq]++;
-
-#ifdef DEBUG_SPURIOUS
-       if (!mac_irq_list[irq] && (console_loglevel > 7)) {
-               printk("mac_do_irq_list: spurious interrupt %d!\n", irq);
-               return;
-       }
-#endif
-
-       /* serve first fast and normal handlers */
-       for (node = mac_irq_list[irq];
-            node && (!(node->flags & IRQ_FLG_SLOW));
-            node = node->next)
-               node->handler(irq, node->dev_id, fp);
-       if (!node) return;
-       local_save_flags(flags);
-       local_irq_restore((flags & ~0x0700) | (fp->sr & 0x0700));
-       /* if slow handlers exists, serve them now */
-       slow_nodes = node;
-       for (; node; node = node->next) {
-               node->handler(irq, node->dev_id, fp);
-       }
-}
-
 /*
  *  mac_enable_irq - enable an interrupt source
  * mac_disable_irq - disable an interrupt source
@@ -374,276 +273,124 @@ void mac_do_irq_list(int irq, struct pt_regs *fp)
  * These routines are just dispatchers to the VIA/OSS/PSC routines.
  */
 
-void mac_enable_irq (unsigned int irq)
+static void mac_enable_irq(unsigned int irq)
 {
-       int irq_src     = IRQ_SRC(irq);
+       int irq_src = IRQ_SRC(irq);
 
        switch(irq_src) {
-               case 1: via_irq_enable(irq);
-                       break;
-               case 2:
-               case 7: if (oss_present) {
-                               oss_irq_enable(irq);
-                       } else {
-                               via_irq_enable(irq);
-                       }
-                       break;
-               case 3:
-               case 4:
-               case 5:
-               case 6: if (psc_present) {
-                               psc_irq_enable(irq);
-                       } else if (oss_present) {
-                               oss_irq_enable(irq);
-                       } else if (irq_src == 4) {
-                               scc_irq_enable(irq);
-                       }
-                       break;
-               case 8: if (baboon_present) {
-                               baboon_irq_enable(irq);
-                       }
-                       break;
+       case 1:
+               via_irq_enable(irq);
+               break;
+       case 2:
+       case 7:
+               if (oss_present)
+                       oss_irq_enable(irq);
+               else
+                       via_irq_enable(irq);
+               break;
+       case 3:
+       case 4:
+       case 5:
+       case 6:
+               if (psc_present)
+                       psc_irq_enable(irq);
+               else if (oss_present)
+                       oss_irq_enable(irq);
+               else if (irq_src == 4)
+                       scc_irq_enable(irq);
+               break;
+       case 8:
+               if (baboon_present)
+                       baboon_irq_enable(irq);
+               break;
        }
 }
 
-void mac_disable_irq (unsigned int irq)
+static void mac_disable_irq(unsigned int irq)
 {
-       int irq_src     = IRQ_SRC(irq);
+       int irq_src = IRQ_SRC(irq);
 
        switch(irq_src) {
-               case 1: via_irq_disable(irq);
-                       break;
-               case 2:
-               case 7: if (oss_present) {
-                               oss_irq_disable(irq);
-                       } else {
-                               via_irq_disable(irq);
-                       }
-                       break;
-               case 3:
-               case 4:
-               case 5:
-               case 6: if (psc_present) {
-                               psc_irq_disable(irq);
-                       } else if (oss_present) {
-                               oss_irq_disable(irq);
-                       } else if (irq_src == 4) {
-                               scc_irq_disable(irq);
-                       }
-                       break;
-               case 8: if (baboon_present) {
-                               baboon_irq_disable(irq);
-                       }
-                       break;
+       case 1:
+               via_irq_disable(irq);
+               break;
+       case 2:
+       case 7:
+               if (oss_present)
+                       oss_irq_disable(irq);
+               else
+                       via_irq_disable(irq);
+               break;
+       case 3:
+       case 4:
+       case 5:
+       case 6:
+               if (psc_present)
+                       psc_irq_disable(irq);
+               else if (oss_present)
+                       oss_irq_disable(irq);
+               else if (irq_src == 4)
+                       scc_irq_disable(irq);
+               break;
+       case 8:
+               if (baboon_present)
+                       baboon_irq_disable(irq);
+               break;
        }
 }
 
-void mac_clear_irq( unsigned int irq )
+void mac_clear_irq(unsigned int irq)
 {
        switch(IRQ_SRC(irq)) {
-               case 1: via_irq_clear(irq);
-                       break;
-               case 2:
-               case 7: if (oss_present) {
-                               oss_irq_clear(irq);
-                       } else {
-                               via_irq_clear(irq);
-                       }
-                       break;
-               case 3:
-               case 4:
-               case 5:
-               case 6: if (psc_present) {
-                               psc_irq_clear(irq);
-                       } else if (oss_present) {
-                               oss_irq_clear(irq);
-                       }
-                       break;
-               case 8: if (baboon_present) {
-                               baboon_irq_clear(irq);
-                       }
-                       break;
+       case 1:
+               via_irq_clear(irq);
+               break;
+       case 2:
+       case 7:
+               if (oss_present)
+                       oss_irq_clear(irq);
+               else
+                       via_irq_clear(irq);
+               break;
+       case 3:
+       case 4:
+       case 5:
+       case 6:
+               if (psc_present)
+                       psc_irq_clear(irq);
+               else if (oss_present)
+                       oss_irq_clear(irq);
+               break;
+       case 8:
+               if (baboon_present)
+                       baboon_irq_clear(irq);
+               break;
        }
 }
 
-int mac_irq_pending( unsigned int irq )
+int mac_irq_pending(unsigned int irq)
 {
        switch(IRQ_SRC(irq)) {
-               case 1: return via_irq_pending(irq);
-               case 2:
-               case 7: if (oss_present) {
-                               return oss_irq_pending(irq);
-                       } else {
-                               return via_irq_pending(irq);
-                       }
-               case 3:
-               case 4:
-               case 5:
-               case 6: if (psc_present) {
-                               return psc_irq_pending(irq);
-                       } else if (oss_present) {
-                               return oss_irq_pending(irq);
-                       }
-       }
-       return 0;
-}
-
-/*
- * Add an interrupt service routine to an interrupt source.
- * Returns 0 on success.
- *
- * FIXME: You can register interrupts on nonexistent source (ie PSC4 on a
- *        non-PSC machine). We should return -EINVAL in those cases.
- */
-
-int mac_request_irq(unsigned int irq,
-                   irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                   unsigned long flags, const char *devname, void *dev_id)
-{
-       irq_node_t *node;
-
-#ifdef DEBUG_MACINTS
-       printk ("%s: irq %d requested for %s\n", __FUNCTION__, irq, devname);
-#endif
-
-       if (irq < VIA1_SOURCE_BASE) {
-               return cpu_request_irq(irq, handler, flags, devname, dev_id);
+       case 1:
+               return via_irq_pending(irq);
+       case 2:
+       case 7:
+               if (oss_present)
+                       return oss_irq_pending(irq);
+               else
+                       return via_irq_pending(irq);
+       case 3:
+       case 4:
+       case 5:
+       case 6:
+               if (psc_present)
+                       return psc_irq_pending(irq);
+               else if (oss_present)
+                       return oss_irq_pending(irq);
        }
-
-       if (irq >= NUM_MAC_SOURCES) {
-               printk ("%s: unknown irq %d requested by %s\n",
-                       __FUNCTION__, irq, devname);
-       }
-
-       /* Get a node and stick it onto the right list */
-
-       if (!(node = new_irq_node())) return -ENOMEM;
-
-       node->handler   = handler;
-       node->flags     = flags;
-       node->dev_id    = dev_id;
-       node->devname   = devname;
-       node->next      = NULL;
-       mac_insert_irq(&mac_irq_list[irq], node);
-
-       /* Now enable the IRQ source */
-
-       mac_enable_irq(irq);
-
        return 0;
 }
 
-/*
- * Removes an interrupt service routine from an interrupt source.
- */
-
-void mac_free_irq(unsigned int irq, void *dev_id)
-{
-#ifdef DEBUG_MACINTS
-       printk ("%s: irq %d freed by %p\n", __FUNCTION__, irq, dev_id);
-#endif
-
-       if (irq < VIA1_SOURCE_BASE) {
-               cpu_free_irq(irq, dev_id);
-               return;
-       }
-
-       if (irq >= NUM_MAC_SOURCES) {
-               printk ("%s: unknown irq %d freed\n",
-                       __FUNCTION__, irq);
-               return;
-       }
-
-       mac_delete_irq(&mac_irq_list[irq], dev_id);
-
-       /* If the list for this interrupt is */
-       /* empty then disable the source.    */
-
-       if (!mac_irq_list[irq]) {
-               mac_disable_irq(irq);
-       }
-}
-
-/*
- * Generate a pretty listing for /proc/interrupts
- *
- * By the time we're called the autovector interrupt list has already been
- * generated, so we just need to do the machspec interrupts.
- *
- * 990506 (jmt) - rewritten to handle chained machspec interrupt handlers.
- *                Also removed display of num_spurious it is already
- *               displayed for us as autovector irq 0.
- */
-
-int show_mac_interrupts(struct seq_file *p, void *v)
-{
-       int i;
-       irq_node_t *node;
-       char *base;
-
-       /* Don't do Nubus interrupts in this loop; we do them separately  */
-       /* below so that we can print slot numbers instead of IRQ numbers */
-
-       for (i = VIA1_SOURCE_BASE ; i < NUM_MAC_SOURCES ; ++i) {
-
-               /* Nonexistant interrupt or nothing registered; skip it. */
-
-               if ((node = mac_irq_list[i]) == NULL) continue;
-               if (node->flags & IRQ_FLG_STD) continue;
-
-               base = "";
-               switch(IRQ_SRC(i)) {
-                       case 1: base = "via1";
-                               break;
-                       case 2: if (oss_present) {
-                                       base = "oss";
-                               } else {
-                                       base = "via2";
-                               }
-                               break;
-                       case 3:
-                       case 4:
-                       case 5:
-                       case 6: if (psc_present) {
-                                       base = "psc";
-                               } else if (oss_present) {
-                                       base = "oss";
-                               } else {
-                                       if (IRQ_SRC(i) == 4) base = "scc";
-                               }
-                               break;
-                       case 7: base = "nbus";
-                               break;
-                       case 8: base = "bbn";
-                               break;
-               }
-               seq_printf(p, "%4s %2d: %10u ", base, i, kstat_cpu(0).irqs[i]);
-
-               do {
-                       if (node->flags & IRQ_FLG_FAST) {
-                               seq_puts(p, "F ");
-                       } else if (node->flags & IRQ_FLG_SLOW) {
-                               seq_puts(p, "S ");
-                       } else {
-                               seq_puts(p, "  ");
-                       }
-                       seq_printf(p, "%s\n", node->devname);
-                       if ((node = node->next)) {
-                               seq_puts(p, "                    ");
-                       }
-               } while(node);
-
-       }
-       return 0;
-}
-
-void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs)
-{
-#ifdef DEBUG_SPURIOUS
-       printk("Unexpected IRQ %d on device %p\n", irq, dev_id);
-#endif
-}
-
 static int num_debug[8];
 
 irqreturn_t mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs)
@@ -683,7 +430,7 @@ irqreturn_t mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
        while (nmi_hold == 1)
                udelay(1000);
 
-       if ( console_loglevel >= 8 ) {
+       if (console_loglevel >= 8) {
 #if 0
                show_state();
                printk("PC: %08lx\nSR: %04x  SP: %p\n", fp->pc, fp->sr, fp);
@@ -712,14 +459,16 @@ irqreturn_t mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
  * done in hardware (only the PSC can do that.)
  */
 
-static void scc_irq_enable(int irq) {
-       int irq_idx     = IRQ_IDX(irq);
+static void scc_irq_enable(unsigned int irq)
+{
+       int irq_idx = IRQ_IDX(irq);
 
        scc_mask |= (1 << irq_idx);
 }
 
-static void scc_irq_disable(int irq) {
-       int irq_idx     = IRQ_IDX(irq);
+static void scc_irq_disable(unsigned int irq)
+{
+       int irq_idx = IRQ_IDX(irq);
 
        scc_mask &= ~(1 << irq_idx);
 }
@@ -754,6 +503,8 @@ void mac_scc_dispatch(int irq, void *dev_id, struct pt_regs *regs)
        /* and since they're autovector interrupts they */
        /* pretty much kill the system.                 */
 
-       if (reg & 0x38) mac_do_irq_list(IRQ_SCCA, regs);
-       if (reg & 0x07) mac_do_irq_list(IRQ_SCCB, regs);
+       if (reg & 0x38)
+               m68k_handle_int(IRQ_SCCA, regs);
+       if (reg & 0x07)
+               m68k_handle_int(IRQ_SCCB, regs);
 }
index 333547692724feed80d76a01a9e673367075d6e4..63e04365191fe92ced06092ab496290a1d78bf3a 100644 (file)
@@ -67,15 +67,15 @@ void __init oss_init(void)
 
 void __init oss_register_interrupts(void)
 {
-       cpu_request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK,
+       request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK,
                        "scsi", (void *) oss);
-       cpu_request_irq(OSS_IRQLEV_IOPSCC, mac_scc_dispatch, IRQ_FLG_LOCK,
+       request_irq(OSS_IRQLEV_IOPSCC, mac_scc_dispatch, IRQ_FLG_LOCK,
                        "scc", mac_scc_dispatch);
-       cpu_request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK,
+       request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK,
                        "nubus", (void *) oss);
-       cpu_request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK,
+       request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK,
                        "sound", (void *) oss);
-       cpu_request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK,
+       request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK,
                        "via1", (void *) via1);
 }
 
@@ -113,7 +113,7 @@ irqreturn_t oss_irq(int irq, void *dev_id, struct pt_regs *regs)
                oss->irq_pending &= ~OSS_IP_SOUND;
        } else if (events & OSS_IP_SCSI) {
                oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED;
-               mac_do_irq_list(IRQ_MAC_SCSI, regs);
+               m68k_handle_int(IRQ_MAC_SCSI, regs);
                oss->irq_pending &= ~OSS_IP_SCSI;
                oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI;
        } else {
@@ -146,7 +146,7 @@ irqreturn_t oss_nubus_irq(int irq, void *dev_id, struct pt_regs *regs)
        for (i = 0, irq_bit = 1 ; i < 6 ; i++, irq_bit <<= 1) {
                if (events & irq_bit) {
                        oss->irq_level[i] = OSS_IRQLEV_DISABLED;
-                       mac_do_irq_list(NUBUS_SOURCE_BASE + i, regs);
+                       m68k_handle_int(NUBUS_SOURCE_BASE + i, regs);
                        oss->irq_pending &= ~irq_bit;
                        oss->irq_level[i] = OSS_IRQLEV_NUBUS;
                }
index e72384e43a1e8ee73f37f6437272829d6436a91c..e262180917552db70ae05f55221a1f7028ec25ea 100644 (file)
@@ -117,10 +117,10 @@ void __init psc_init(void)
 
 void __init psc_register_interrupts(void)
 {
-       cpu_request_irq(3, psc_irq, IRQ_FLG_LOCK, "psc3", (void *) 0x30);
-       cpu_request_irq(4, psc_irq, IRQ_FLG_LOCK, "psc4", (void *) 0x40);
-       cpu_request_irq(5, psc_irq, IRQ_FLG_LOCK, "psc5", (void *) 0x50);
-       cpu_request_irq(6, psc_irq, IRQ_FLG_LOCK, "psc6", (void *) 0x60);
+       request_irq(IRQ_AUTO_3, psc_irq, 0, "psc3", (void *) 0x30);
+       request_irq(IRQ_AUTO_4, psc_irq, 0, "psc4", (void *) 0x40);
+       request_irq(IRQ_AUTO_5, psc_irq, 0, "psc5", (void *) 0x50);
+       request_irq(IRQ_AUTO_6, psc_irq, 0, "psc6", (void *) 0x60);
 }
 
 /*
@@ -149,7 +149,7 @@ irqreturn_t psc_irq(int irq, void *dev_id, struct pt_regs *regs)
        for (i = 0, irq_bit = 1 ; i < 4 ; i++, irq_bit <<= 1) {
                if (events & irq_bit) {
                        psc_write_byte(pIER, irq_bit);
-                       mac_do_irq_list(base_irq + i, regs);
+                       m68k_handle_int(base_irq + i, regs);
                        psc_write_byte(pIFR, irq_bit);
                        psc_write_byte(pIER, irq_bit | 0x80);
                }
index a6e3814c866651642e7f8430c8e7dd091726b2b1..c4aa345d544e6127c27ab41953bf8b940d6aa9ac 100644 (file)
@@ -253,21 +253,21 @@ void __init via_init_clock(irqreturn_t (*func)(int, void *, struct pt_regs *))
 void __init via_register_interrupts(void)
 {
        if (via_alt_mapping) {
-               cpu_request_irq(IRQ_AUTO_1, via1_irq,
+               request_irq(IRQ_AUTO_1, via1_irq,
                                IRQ_FLG_LOCK|IRQ_FLG_FAST, "software",
                                (void *) via1);
-               cpu_request_irq(IRQ_AUTO_6, via1_irq,
+               request_irq(IRQ_AUTO_6, via1_irq,
                                IRQ_FLG_LOCK|IRQ_FLG_FAST, "via1",
                                (void *) via1);
        } else {
-               cpu_request_irq(IRQ_AUTO_1, via1_irq,
+               request_irq(IRQ_AUTO_1, via1_irq,
                                IRQ_FLG_LOCK|IRQ_FLG_FAST, "via1",
                                (void *) via1);
        }
-       cpu_request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+       request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
                        "via2", (void *) via2);
        if (!psc_present) {
-               cpu_request_irq(IRQ_AUTO_4, mac_scc_dispatch, IRQ_FLG_LOCK,
+               request_irq(IRQ_AUTO_4, mac_scc_dispatch, IRQ_FLG_LOCK,
                                "scc", mac_scc_dispatch);
        }
        request_irq(IRQ_MAC_NUBUS, via_nubus_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
@@ -424,7 +424,7 @@ irqreturn_t via1_irq(int irq, void *dev_id, struct pt_regs *regs)
        for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1)
                if (events & irq_bit) {
                        via1[vIER] = irq_bit;
-                       mac_do_irq_list(VIA1_SOURCE_BASE + i, regs);
+                       m68k_handle_int(VIA1_SOURCE_BASE + i, regs);
                        via1[vIFR] = irq_bit;
                        via1[vIER] = irq_bit | 0x80;
                }
@@ -439,7 +439,7 @@ irqreturn_t via1_irq(int irq, void *dev_id, struct pt_regs *regs)
                /* No, it won't be set. that's why we're doing this. */
                via_irq_disable(IRQ_MAC_NUBUS);
                via_irq_clear(IRQ_MAC_NUBUS);
-               mac_do_irq_list(IRQ_MAC_NUBUS, regs);
+               m68k_handle_int(IRQ_MAC_NUBUS, regs);
                via_irq_enable(IRQ_MAC_NUBUS);
        }
 #endif
@@ -459,7 +459,7 @@ irqreturn_t via2_irq(int irq, void *dev_id, struct pt_regs *regs)
                if (events & irq_bit) {
                        via2[gIER] = irq_bit;
                        via2[gIFR] = irq_bit | rbv_clear;
-                       mac_do_irq_list(VIA2_SOURCE_BASE + i, regs);
+                       m68k_handle_int(VIA2_SOURCE_BASE + i, regs);
                        via2[gIER] = irq_bit | 0x80;
                }
        return IRQ_HANDLED;
@@ -481,7 +481,7 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id, struct pt_regs *regs)
        for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) {
                if (events & irq_bit) {
                        via_irq_disable(NUBUS_SOURCE_BASE + i);
-                       mac_do_irq_list(NUBUS_SOURCE_BASE + i, regs);
+                       m68k_handle_int(NUBUS_SOURCE_BASE + i, regs);
                        via_irq_enable(NUBUS_SOURCE_BASE + i);
                }
        }
index 85ad19a0ac792ddc16e4a74be3854f3f752cd3cc..43ffab0487242140e070f267d35ea7f14dd83d59 100644 (file)
@@ -259,13 +259,15 @@ void __iounmap(void *addr, unsigned long size)
 
                if (CPU_IS_020_OR_030) {
                        int pmd_off = (virtaddr/PTRTREESIZE) & 15;
+                       int pmd_type = pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK;
 
-                       if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
+                       if (pmd_type == _PAGE_PRESENT) {
                                pmd_dir->pmd[pmd_off] = 0;
                                virtaddr += PTRTREESIZE;
                                size -= PTRTREESIZE;
                                continue;
-                       }
+                       } else if (pmd_type == 0)
+                               continue;
                }
 
                if (pmd_bad(*pmd_dir)) {
diff --git a/arch/m68k/mvme147/147ints.c b/arch/m68k/mvme147/147ints.c
deleted file mode 100644 (file)
index 69a744e..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * arch/m68k/mvme147/147ints.c
- *
- * Copyright (C) 1997 Richard Hirst [richard@sleepie.demon.co.uk]
- *
- * based on amiints.c -- Amiga Linux interrupt handling code
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
- *
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/seq_file.h>
-
-#include <asm/ptrace.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/traps.h>
-
-static irqreturn_t mvme147_defhand (int irq, void *dev_id, struct pt_regs *fp);
-
-/*
- * This should ideally be 4 elements only, for speed.
- */
-
-static struct {
-       irqreturn_t     (*handler)(int, void *, struct pt_regs *);
-       unsigned long   flags;
-       void            *dev_id;
-       const char      *devname;
-       unsigned        count;
-} irq_tab[256];
-
-/*
- * void mvme147_init_IRQ (void)
- *
- * Parameters: None
- *
- * Returns:    Nothing
- *
- * This function is called during kernel startup to initialize
- * the mvme147 IRQ handling routines.
- */
-
-void mvme147_init_IRQ (void)
-{
-       int i;
-
-       for (i = 0; i < 256; i++) {
-               irq_tab[i].handler = mvme147_defhand;
-               irq_tab[i].flags = IRQ_FLG_STD;
-               irq_tab[i].dev_id = NULL;
-               irq_tab[i].devname = NULL;
-               irq_tab[i].count = 0;
-       }
-}
-
-int mvme147_request_irq(unsigned int irq,
-               irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                unsigned long flags, const char *devname, void *dev_id)
-{
-       if (irq > 255) {
-               printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
-               return -ENXIO;
-       }
-       if (!(irq_tab[irq].flags & IRQ_FLG_STD)) {
-               if (irq_tab[irq].flags & IRQ_FLG_LOCK) {
-                       printk("%s: IRQ %d from %s is not replaceable\n",
-                              __FUNCTION__, irq, irq_tab[irq].devname);
-                       return -EBUSY;
-               }
-               if (flags & IRQ_FLG_REPLACE) {
-                       printk("%s: %s can't replace IRQ %d from %s\n",
-                              __FUNCTION__, devname, irq, irq_tab[irq].devname);
-                       return -EBUSY;
-               }
-       }
-       irq_tab[irq].handler = handler;
-       irq_tab[irq].flags   = flags;
-       irq_tab[irq].dev_id  = dev_id;
-       irq_tab[irq].devname = devname;
-       return 0;
-}
-
-void mvme147_free_irq(unsigned int irq, void *dev_id)
-{
-       if (irq > 255) {
-               printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
-               return;
-       }
-       if (irq_tab[irq].dev_id != dev_id)
-               printk("%s: Removing probably wrong IRQ %d from %s\n",
-                      __FUNCTION__, irq, irq_tab[irq].devname);
-
-       irq_tab[irq].handler = mvme147_defhand;
-       irq_tab[irq].flags   = IRQ_FLG_STD;
-       irq_tab[irq].dev_id  = NULL;
-       irq_tab[irq].devname = NULL;
-}
-
-irqreturn_t mvme147_process_int (unsigned long vec, struct pt_regs *fp)
-{
-       if (vec > 255) {
-               printk ("mvme147_process_int: Illegal vector %ld\n", vec);
-               return IRQ_NONE;
-       } else {
-               irq_tab[vec].count++;
-               irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp);
-               return IRQ_HANDLED;
-       }
-}
-
-int show_mvme147_interrupts (struct seq_file *p, void *v)
-{
-       int i;
-
-       for (i = 0; i < 256; i++) {
-               if (irq_tab[i].count)
-                       seq_printf(p, "Vec 0x%02x: %8d  %s\n",
-                           i, irq_tab[i].count,
-                           irq_tab[i].devname ? irq_tab[i].devname : "free");
-       }
-       return 0;
-}
-
-
-static irqreturn_t mvme147_defhand (int irq, void *dev_id, struct pt_regs *fp)
-{
-       printk ("Unknown interrupt 0x%02x\n", irq);
-       return IRQ_NONE;
-}
-
-void mvme147_enable_irq (unsigned int irq)
-{
-}
-
-
-void mvme147_disable_irq (unsigned int irq)
-{
-}
-
index f0153ed3efa5aa3f810dd255d10c98747d760990..a36d38dbfbbc8a68db791f60cdfffce7114cd4b9 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for Linux arch/m68k/mvme147 source directory
 #
 
-obj-y          := config.o 147ints.o
+obj-y          := config.o
index 0fcf9720c2fe6c149094b2e1cd06558bebdda2cb..0cd0e5bddceece3f4b5423839d5f50da80526f27 100644 (file)
 #include <asm/mvme147hw.h>
 
 
-extern irqreturn_t mvme147_process_int (int level, struct pt_regs *regs);
-extern void mvme147_init_IRQ (void);
-extern void mvme147_free_irq (unsigned int, void *);
-extern int  show_mvme147_interrupts (struct seq_file *, void *);
-extern void mvme147_enable_irq (unsigned int);
-extern void mvme147_disable_irq (unsigned int);
 static void mvme147_get_model(char *model);
 static int  mvme147_get_hardware_list(char *buffer);
-extern int mvme147_request_irq (unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
 extern void mvme147_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
 extern unsigned long mvme147_gettimeoffset (void);
 extern int mvme147_hwclk (int, struct rtc_time *);
@@ -91,6 +84,15 @@ static int mvme147_get_hardware_list(char *buffer)
        return 0;
 }
 
+/*
+ * This function is called during kernel startup to initialize
+ * the mvme147 IRQ handling routines.
+ */
+
+void mvme147_init_IRQ(void)
+{
+       m68k_setup_user_interrupt(VEC_USER, 192, NULL);
+}
 
 void __init config_mvme147(void)
 {
@@ -101,12 +103,6 @@ void __init config_mvme147(void)
        mach_hwclk              = mvme147_hwclk;
        mach_set_clock_mmss     = mvme147_set_clock_mmss;
        mach_reset              = mvme147_reset;
-       mach_free_irq           = mvme147_free_irq;
-       mach_process_int        = mvme147_process_int;
-       mach_get_irq_list       = show_mvme147_interrupts;
-       mach_request_irq        = mvme147_request_irq;
-       enable_irq              = mvme147_enable_irq;
-       disable_irq             = mvme147_disable_irq;
        mach_get_model          = mvme147_get_model;
        mach_get_hardware_list  = mvme147_get_hardware_list;
 
diff --git a/arch/m68k/mvme16x/16xints.c b/arch/m68k/mvme16x/16xints.c
deleted file mode 100644 (file)
index 793ef73..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * arch/m68k/mvme16x/16xints.c
- *
- * Copyright (C) 1995 Richard Hirst [richard@sleepie.demon.co.uk]
- *
- * based on amiints.c -- Amiga Linux interrupt handling code
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
- *
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/seq_file.h>
-
-#include <asm/system.h>
-#include <asm/ptrace.h>
-#include <asm/irq.h>
-
-static irqreturn_t mvme16x_defhand (int irq, void *dev_id, struct pt_regs *fp);
-
-/*
- * This should ideally be 4 elements only, for speed.
- */
-
-static struct {
-       irqreturn_t     (*handler)(int, void *, struct pt_regs *);
-       unsigned long   flags;
-       void            *dev_id;
-       const char      *devname;
-       unsigned        count;
-} irq_tab[192];
-
-/*
- * void mvme16x_init_IRQ (void)
- *
- * Parameters: None
- *
- * Returns:    Nothing
- *
- * This function is called during kernel startup to initialize
- * the mvme16x IRQ handling routines.  Should probably ensure
- * that the base vectors for the VMEChip2 and PCCChip2 are valid.
- */
-
-void mvme16x_init_IRQ (void)
-{
-       int i;
-
-       for (i = 0; i < 192; i++) {
-               irq_tab[i].handler = mvme16x_defhand;
-               irq_tab[i].flags = IRQ_FLG_STD;
-               irq_tab[i].dev_id = NULL;
-               irq_tab[i].devname = NULL;
-               irq_tab[i].count = 0;
-       }
-}
-
-int mvme16x_request_irq(unsigned int irq,
-               irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                unsigned long flags, const char *devname, void *dev_id)
-{
-       if (irq < 64 || irq > 255) {
-               printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
-               return -ENXIO;
-       }
-
-       if (!(irq_tab[irq-64].flags & IRQ_FLG_STD)) {
-               if (irq_tab[irq-64].flags & IRQ_FLG_LOCK) {
-                       printk("%s: IRQ %d from %s is not replaceable\n",
-                              __FUNCTION__, irq, irq_tab[irq-64].devname);
-                       return -EBUSY;
-               }
-               if (flags & IRQ_FLG_REPLACE) {
-                       printk("%s: %s can't replace IRQ %d from %s\n",
-                              __FUNCTION__, devname, irq, irq_tab[irq-64].devname);
-                       return -EBUSY;
-               }
-       }
-       irq_tab[irq-64].handler = handler;
-       irq_tab[irq-64].flags   = flags;
-       irq_tab[irq-64].dev_id  = dev_id;
-       irq_tab[irq-64].devname = devname;
-       return 0;
-}
-
-void mvme16x_free_irq(unsigned int irq, void *dev_id)
-{
-       if (irq < 64 || irq > 255) {
-               printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
-               return;
-       }
-
-       if (irq_tab[irq-64].dev_id != dev_id)
-               printk("%s: Removing probably wrong IRQ %d from %s\n",
-                      __FUNCTION__, irq, irq_tab[irq-64].devname);
-
-       irq_tab[irq-64].handler = mvme16x_defhand;
-       irq_tab[irq-64].flags   = IRQ_FLG_STD;
-       irq_tab[irq-64].dev_id  = NULL;
-       irq_tab[irq-64].devname = NULL;
-}
-
-irqreturn_t mvme16x_process_int (unsigned long vec, struct pt_regs *fp)
-{
-       if (vec < 64 || vec > 255) {
-               printk ("mvme16x_process_int: Illegal vector %ld", vec);
-               return IRQ_NONE;
-       } else {
-               irq_tab[vec-64].count++;
-               irq_tab[vec-64].handler(vec, irq_tab[vec-64].dev_id, fp);
-               return IRQ_HANDLED;
-       }
-}
-
-int show_mvme16x_interrupts (struct seq_file *p, void *v)
-{
-       int i;
-
-       for (i = 0; i < 192; i++) {
-               if (irq_tab[i].count)
-                       seq_printf(p, "Vec 0x%02x: %8d  %s\n",
-                           i+64, irq_tab[i].count,
-                           irq_tab[i].devname ? irq_tab[i].devname : "free");
-       }
-       return 0;
-}
-
-
-static irqreturn_t mvme16x_defhand (int irq, void *dev_id, struct pt_regs *fp)
-{
-       printk ("Unknown interrupt 0x%02x\n", irq);
-       return IRQ_NONE;
-}
-
-
-void mvme16x_enable_irq (unsigned int irq)
-{
-}
-
-
-void mvme16x_disable_irq (unsigned int irq)
-{
-}
-
-
index 5129f56b64a35cf3a07b52f10eaa7a6352c8a7af..950e82f216408d889a493ccd275fb356624acbfe 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for Linux arch/m68k/mvme16x source directory
 #
 
-obj-y          := config.o 16xints.o rtc.o mvme16x_ksyms.o
+obj-y          := config.o rtc.o mvme16x_ksyms.o
index 26ce81c1337dc0f62b1223edcbfa3adde6076f07..ce2727ed1bc05d64c37059fd67e49873aa534143 100644 (file)
@@ -40,15 +40,8 @@ extern t_bdid mvme_bdid;
 
 static MK48T08ptr_t volatile rtc = (MK48T08ptr_t)MVME_RTC_BASE;
 
-extern irqreturn_t mvme16x_process_int (int level, struct pt_regs *regs);
-extern void mvme16x_init_IRQ (void);
-extern void mvme16x_free_irq (unsigned int, void *);
-extern int show_mvme16x_interrupts (struct seq_file *, void *);
-extern void mvme16x_enable_irq (unsigned int);
-extern void mvme16x_disable_irq (unsigned int);
 static void mvme16x_get_model(char *model);
 static int  mvme16x_get_hardware_list(char *buffer);
-extern int  mvme16x_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
 extern void mvme16x_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
 extern unsigned long mvme16x_gettimeoffset (void);
 extern int mvme16x_hwclk (int, struct rtc_time *);
@@ -120,6 +113,16 @@ static int mvme16x_get_hardware_list(char *buffer)
     return (len);
 }
 
+/*
+ * This function is called during kernel startup to initialize
+ * the mvme16x IRQ handling routines.  Should probably ensure
+ * that the base vectors for the VMEChip2 and PCCChip2 are valid.
+ */
+
+static void mvme16x_init_IRQ (void)
+{
+       m68k_setup_user_interrupt(VEC_USER, 192, NULL);
+}
 
 #define pcc2chip       ((volatile u_char *)0xfff42000)
 #define PccSCCMICR     0x1d
@@ -138,12 +141,6 @@ void __init config_mvme16x(void)
     mach_hwclk           = mvme16x_hwclk;
     mach_set_clock_mmss         = mvme16x_set_clock_mmss;
     mach_reset          = mvme16x_reset;
-    mach_free_irq       = mvme16x_free_irq;
-    mach_process_int    = mvme16x_process_int;
-    mach_get_irq_list   = show_mvme16x_interrupts;
-    mach_request_irq    = mvme16x_request_irq;
-    enable_irq           = mvme16x_enable_irq;
-    disable_irq          = mvme16x_disable_irq;
     mach_get_model       = mvme16x_get_model;
     mach_get_hardware_list = mvme16x_get_hardware_list;
 
index 5e0f9b04d45e6adc0f94d2a23050831d124b365d..efa52d302d674aceaeb1d09b1a5a62671c7d4a9a 100644 (file)
 #include <asm/q40_master.h>
 
 extern irqreturn_t q40_process_int (int level, struct pt_regs *regs);
-extern irqreturn_t (*q40_default_handler[]) (int, void *, struct pt_regs *);  /* added just for debugging */
 extern void q40_init_IRQ (void);
-extern void q40_free_irq (unsigned int, void *);
-extern int  show_q40_interrupts (struct seq_file *, void *);
-extern void q40_enable_irq (unsigned int);
-extern void q40_disable_irq (unsigned int);
 static void q40_get_model(char *model);
 static int  q40_get_hardware_list(char *buffer);
-extern int  q40_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
 extern void q40_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
 
 extern unsigned long q40_gettimeoffset (void);
@@ -175,13 +169,6 @@ void __init config_q40(void)
     mach_set_clock_mmss         = q40_set_clock_mmss;
 
     mach_reset          = q40_reset;
-    mach_free_irq       = q40_free_irq;
-    mach_process_int    = q40_process_int;
-    mach_get_irq_list   = show_q40_interrupts;
-    mach_request_irq    = q40_request_irq;
-    enable_irq          = q40_enable_irq;
-    disable_irq          = q40_disable_irq;
-    mach_default_handler = &q40_default_handler;
     mach_get_model       = q40_get_model;
     mach_get_hardware_list = q40_get_hardware_list;
 
index f8ecc2664fe625c3672da88107368ee0a7b91fc0..472f41c4158b4bef12c46bac7d0e01c88d7f7cb4 100644 (file)
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/seq_file.h>
 #include <linux/interrupt.h>
-#include <linux/hardirq.h>
 
-#include <asm/rtc.h>
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/irq.h>
  *
 */
 
-extern int ints_inited;
+static void q40_irq_handler(unsigned int, struct pt_regs *fp);
+static void q40_enable_irq(unsigned int);
+static void q40_disable_irq(unsigned int);
 
+unsigned short q40_ablecount[35];
+unsigned short q40_state[35];
 
-irqreturn_t q40_irq2_handler (int, void *, struct pt_regs *fp);
-
-
-static irqreturn_t q40_defhand (int irq, void *dev_id, struct pt_regs *fp);
-static irqreturn_t default_handler(int lev, void *dev_id, struct pt_regs *regs);
-
-
-#define DEVNAME_SIZE 24
+static int q40_irq_startup(unsigned int irq)
+{
+       /* test for ISA ints not implemented by HW */
+       switch (irq) {
+       case 1: case 2: case 8: case 9:
+       case 11: case 12: case 13:
+               printk("%s: ISA IRQ %d not implemented by HW\n", __FUNCTION__, irq);
+               return -ENXIO;
+       }
+       return 0;
+}
 
-static struct q40_irq_node {
-       irqreturn_t     (*handler)(int, void *, struct pt_regs *);
-       unsigned long   flags;
-       void            *dev_id;
-  /*        struct q40_irq_node *next;*/
-        char           devname[DEVNAME_SIZE];
-       unsigned        count;
-        unsigned short  state;
-} irq_tab[Q40_IRQ_MAX+1];
+static void q40_irq_shutdown(unsigned int irq)
+{
+}
 
-short unsigned q40_ablecount[Q40_IRQ_MAX+1];
+static struct irq_controller q40_irq_controller = {
+       .name           = "q40",
+       .lock           = SPIN_LOCK_UNLOCKED,
+       .startup        = q40_irq_startup,
+       .shutdown       = q40_irq_shutdown,
+       .enable         = q40_enable_irq,
+       .disable        = q40_disable_irq,
+};
 
 /*
  * void q40_init_IRQ (void)
@@ -74,139 +77,29 @@ short unsigned q40_ablecount[Q40_IRQ_MAX+1];
  * the q40 IRQ handling routines.
  */
 
-static int disabled=0;
+static int disabled;
 
-void q40_init_IRQ (void)
+void q40_init_IRQ(void)
 {
-       int i;
-
-       disabled=0;
-       for (i = 0; i <= Q40_IRQ_MAX; i++) {
-               irq_tab[i].handler = q40_defhand;
-               irq_tab[i].flags = 0;
-               irq_tab[i].dev_id = NULL;
-               /*              irq_tab[i].next = NULL;*/
-               irq_tab[i].devname[0] = 0;
-               irq_tab[i].count = 0;
-               irq_tab[i].state =0;
-               q40_ablecount[i]=0;   /* all enabled */
-       }
+       m68k_setup_irq_controller(&q40_irq_controller, 1, Q40_IRQ_MAX);
 
        /* setup handler for ISA ints */
-       cpu_request_irq(IRQ2, q40_irq2_handler, 0, "q40 ISA and master chip",
-                       NULL);
+       m68k_setup_auto_interrupt(q40_irq_handler);
+
+       m68k_irq_startup(IRQ_AUTO_2);
+       m68k_irq_startup(IRQ_AUTO_4);
 
        /* now enable some ints.. */
-       master_outb(1,EXT_ENABLE_REG);  /* ISA IRQ 5-15 */
+       master_outb(1, EXT_ENABLE_REG);  /* ISA IRQ 5-15 */
 
        /* make sure keyboard IRQ is disabled */
-       master_outb(0,KEY_IRQ_ENABLE_REG);
+       master_outb(0, KEY_IRQ_ENABLE_REG);
 }
 
-int q40_request_irq(unsigned int irq,
-               irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                unsigned long flags, const char *devname, void *dev_id)
-{
-  /*printk("q40_request_irq %d, %s\n",irq,devname);*/
-
-       if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) {
-               printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
-               return -ENXIO;
-       }
-
-       /* test for ISA ints not implemented by HW */
-       switch (irq)
-         {
-         case 1: case 2: case 8: case 9:
-         case 12: case 13:
-           printk("%s: ISA IRQ %d from %s not implemented by HW\n", __FUNCTION__, irq, devname);
-           return -ENXIO;
-         case 11:
-           printk("warning IRQ 10 and 11 not distinguishable\n");
-           irq=10;
-         default:
-           ;
-         }
-
-       if (irq<Q40_IRQ_SAMPLE)
-         {
-           if (irq_tab[irq].dev_id != NULL)
-                 {
-                   printk("%s: IRQ %d from %s is not replaceable\n",
-                          __FUNCTION__, irq, irq_tab[irq].devname);
-                   return -EBUSY;
-                 }
-           /*printk("IRQ %d set to handler %p\n",irq,handler);*/
-           if (dev_id==NULL)
-                 {
-               printk("WARNING: dev_id == NULL in request_irq\n");
-               dev_id=(void*)1;
-             }
-           irq_tab[irq].handler = handler;
-           irq_tab[irq].flags   = flags;
-           irq_tab[irq].dev_id  = dev_id;
-           strlcpy(irq_tab[irq].devname,devname,sizeof(irq_tab[irq].devname));
-           irq_tab[irq].state = 0;
-           return 0;
-         }
-       else {
-         /* Q40_IRQ_SAMPLE :somewhat special actions required here ..*/
-         cpu_request_irq(4, handler, flags, devname, dev_id);
-         cpu_request_irq(6, handler, flags, devname, dev_id);
-         return 0;
-       }
-}
-
-void q40_free_irq(unsigned int irq, void *dev_id)
-{
-       if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) {
-               printk("%s: Incorrect IRQ %d, dev_id %x \n", __FUNCTION__, irq, (unsigned)dev_id);
-               return;
-       }
-
-       /* test for ISA ints not implemented by HW */
-       switch (irq)
-         {
-         case 1: case 2: case 8: case 9:
-         case 12: case 13:
-           printk("%s: ISA IRQ %d from %x invalid\n", __FUNCTION__, irq, (unsigned)dev_id);
-           return;
-         case 11: irq=10;
-         default:
-           ;
-         }
-
-       if (irq<Q40_IRQ_SAMPLE)
-         {
-           if (irq_tab[irq].dev_id != dev_id)
-             printk("%s: Removing probably wrong IRQ %d from %s\n",
-                    __FUNCTION__, irq, irq_tab[irq].devname);
-
-           irq_tab[irq].handler = q40_defhand;
-           irq_tab[irq].flags   = 0;
-           irq_tab[irq].dev_id  = NULL;
-           /* irq_tab[irq].devname = NULL; */
-           /* do not reset state !! */
-         }
-       else
-         { /* == Q40_IRQ_SAMPLE */
-           cpu_free_irq(4, dev_id);
-           cpu_free_irq(6, dev_id);
-         }
-}
-
-
-irqreturn_t q40_process_int (int level, struct pt_regs *fp)
-{
-  printk("unexpected interrupt vec=%x, pc=%lx, d0=%lx, d0_orig=%lx, d1=%lx, d2=%lx\n",
-          level, fp->pc, fp->d0, fp->orig_d0, fp->d1, fp->d2);
-  printk("\tIIRQ_REG = %x, EIRQ_REG = %x\n",master_inb(IIRQ_REG),master_inb(EIRQ_REG));
-  return IRQ_HANDLED;
-}
 
 /*
  * this stuff doesn't really belong here..
-*/
+ */
 
 int ql_ticks;              /* 200Hz ticks since last jiffie */
 static int sound_ticks;
@@ -215,54 +108,53 @@ static int sound_ticks;
 
 void q40_mksound(unsigned int hz, unsigned int ticks)
 {
-  /* for now ignore hz, except that hz==0 switches off sound */
-  /* simply alternate the ampl (128-SVOL)-(128+SVOL)-..-.. at 200Hz */
-  if (hz==0)
-    {
-      if (sound_ticks)
-       sound_ticks=1;
-
-      *DAC_LEFT=128;
-      *DAC_RIGHT=128;
-
-      return;
-    }
-  /* sound itself is done in q40_timer_int */
-  if (sound_ticks == 0) sound_ticks=1000; /* pretty long beep */
-  sound_ticks=ticks<<1;
+       /* for now ignore hz, except that hz==0 switches off sound */
+       /* simply alternate the ampl (128-SVOL)-(128+SVOL)-..-.. at 200Hz */
+       if (hz == 0) {
+               if (sound_ticks)
+                       sound_ticks = 1;
+
+               *DAC_LEFT = 128;
+               *DAC_RIGHT = 128;
+
+               return;
+       }
+       /* sound itself is done in q40_timer_int */
+       if (sound_ticks == 0)
+               sound_ticks = 1000; /* pretty long beep */
+       sound_ticks = ticks << 1;
 }
 
 static irqreturn_t (*q40_timer_routine)(int, void *, struct pt_regs *);
 
 static irqreturn_t q40_timer_int (int irq, void * dev, struct pt_regs * regs)
 {
-    ql_ticks = ql_ticks ? 0 : 1;
-    if (sound_ticks)
-      {
-       unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL;
-       sound_ticks--;
-       *DAC_LEFT=sval;
-       *DAC_RIGHT=sval;
-      }
-
-    if (!ql_ticks)
-       q40_timer_routine(irq, dev, regs);
-    return IRQ_HANDLED;
+       ql_ticks = ql_ticks ? 0 : 1;
+       if (sound_ticks) {
+               unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL;
+               sound_ticks--;
+               *DAC_LEFT=sval;
+               *DAC_RIGHT=sval;
+       }
+
+       if (!ql_ticks)
+               q40_timer_routine(irq, dev, regs);
+       return IRQ_HANDLED;
 }
 
 void q40_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *))
 {
-    int timer_irq;
+       int timer_irq;
 
-    q40_timer_routine = timer_routine;
-    timer_irq=Q40_IRQ_FRAME;
+       q40_timer_routine = timer_routine;
+       timer_irq = Q40_IRQ_FRAME;
 
-    if (request_irq(timer_irq, q40_timer_int, 0,
+       if (request_irq(timer_irq, q40_timer_int, 0,
                                "timer", q40_timer_int))
-       panic ("Couldn't register timer int");
+               panic("Couldn't register timer int");
 
-    master_outb(-1,FRAME_CLEAR_REG);
-    master_outb( 1,FRAME_RATE_REG);
+       master_outb(-1, FRAME_CLEAR_REG);
+       master_outb( 1, FRAME_RATE_REG);
 }
 
 
@@ -308,169 +200,132 @@ static int mext_disabled=0;  /* ext irq disabled by master chip? */
 static int aliased_irq=0;  /* how many times inside handler ?*/
 
 
-/* got level 2 interrupt, dispatch to ISA or keyboard/timer IRQs */
-irqreturn_t q40_irq2_handler (int vec, void *devname, struct pt_regs *fp)
+/* got interrupt, dispatch to ISA or keyboard/timer IRQs */
+static void q40_irq_handler(unsigned int irq, struct pt_regs *fp)
 {
-  unsigned mir, mer;
-  int irq,i;
+       unsigned mir, mer;
+       int i;
 
 //repeat:
-  mir=master_inb(IIRQ_REG);
-  if (mir&Q40_IRQ_FRAME_MASK) {
-         irq_tab[Q40_IRQ_FRAME].count++;
-         irq_tab[Q40_IRQ_FRAME].handler(Q40_IRQ_FRAME,irq_tab[Q40_IRQ_FRAME].dev_id,fp);
-         master_outb(-1,FRAME_CLEAR_REG);
-  }
-  if ((mir&Q40_IRQ_SER_MASK) || (mir&Q40_IRQ_EXT_MASK)) {
-         mer=master_inb(EIRQ_REG);
-         for (i=0; eirqs[i].mask; i++) {
-                 if (mer&(eirqs[i].mask)) {
-                         irq=eirqs[i].irq;
+       mir = master_inb(IIRQ_REG);
+#ifdef CONFIG_BLK_DEV_FD
+       if ((mir & Q40_IRQ_EXT_MASK) &&
+           (master_inb(EIRQ_REG) & Q40_IRQ6_MASK)) {
+               floppy_hardint();
+               return;
+       }
+#endif
+       switch (irq) {
+       case 4:
+       case 6:
+               m68k_handle_int(Q40_IRQ_SAMPLE, fp);
+               return;
+       }
+       if (mir & Q40_IRQ_FRAME_MASK) {
+               m68k_handle_int(Q40_IRQ_FRAME, fp);
+               master_outb(-1, FRAME_CLEAR_REG);
+       }
+       if ((mir & Q40_IRQ_SER_MASK) || (mir & Q40_IRQ_EXT_MASK)) {
+               mer = master_inb(EIRQ_REG);
+               for (i = 0; eirqs[i].mask; i++) {
+                       if (mer & eirqs[i].mask) {
+                               irq = eirqs[i].irq;
 /*
  * There is a little mess wrt which IRQ really caused this irq request. The
  * main problem is that IIRQ_REG and EIRQ_REG reflect the state when they
  * are read - which is long after the request came in. In theory IRQs should
  * not just go away but they occassionally do
  */
-                         if (irq>4 && irq<=15 && mext_disabled) {
-                                 /*aliased_irq++;*/
-                                 goto iirq;
-                         }
-                         if (irq_tab[irq].handler == q40_defhand ) {
-                                 printk("handler for IRQ %d not defined\n",irq);
-                                 continue; /* ignore uninited INTs :-( */
-                         }
-                         if ( irq_tab[irq].state & IRQ_INPROGRESS ) {
-                                 /* some handlers do local_irq_enable() for irq latency reasons, */
-                                 /* however reentering an active irq handler is not permitted */
+                               if (irq > 4 && irq <= 15 && mext_disabled) {
+                                       /*aliased_irq++;*/
+                                       goto iirq;
+                               }
+                               if (q40_state[irq] & IRQ_INPROGRESS) {
+                                       /* some handlers do local_irq_enable() for irq latency reasons, */
+                                       /* however reentering an active irq handler is not permitted */
 #ifdef IP_USE_DISABLE
-                                 /* in theory this is the better way to do it because it still */
-                                 /* lets through eg the serial irqs, unfortunately it crashes */
-                                 disable_irq(irq);
-                                 disabled=1;
+                                       /* in theory this is the better way to do it because it still */
+                                       /* lets through eg the serial irqs, unfortunately it crashes */
+                                       disable_irq(irq);
+                                       disabled = 1;
 #else
-                                 /*printk("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n",irq,disabled ? "already" : "not yet"); */
-                                 fp->sr = (((fp->sr) & (~0x700))+0x200);
-                                 disabled=1;
+                                       /*printk("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n",
+                                               irq, disabled ? "already" : "not yet"); */
+                                       fp->sr = (((fp->sr) & (~0x700))+0x200);
+                                       disabled = 1;
 #endif
-                                 goto iirq;
-                         }
-                         irq_tab[irq].count++;
-                         irq_tab[irq].state |= IRQ_INPROGRESS;
-                         irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp);
-                         irq_tab[irq].state &= ~IRQ_INPROGRESS;
-
-                         /* naively enable everything, if that fails than    */
-                         /* this function will be reentered immediately thus */
-                         /* getting another chance to disable the IRQ        */
-
-                         if ( disabled ) {
+                                       goto iirq;
+                               }
+                               q40_state[irq] |= IRQ_INPROGRESS;
+                               m68k_handle_int(irq, fp);
+                               q40_state[irq] &= ~IRQ_INPROGRESS;
+
+                               /* naively enable everything, if that fails than    */
+                               /* this function will be reentered immediately thus */
+                               /* getting another chance to disable the IRQ        */
+
+                               if (disabled) {
 #ifdef IP_USE_DISABLE
-                                 if (irq>4){
-                                         disabled=0;
-                                         enable_irq(irq);}
+                                       if (irq > 4) {
+                                               disabled = 0;
+                                               enable_irq(irq);
+                                       }
 #else
-                                 disabled=0;
-                                 /*printk("reenabling irq %d\n",irq); */
+                                       disabled = 0;
+                                       /*printk("reenabling irq %d\n", irq); */
 #endif
-                         }
+                               }
 // used to do 'goto repeat;' here, this delayed bh processing too long
-                         return IRQ_HANDLED;
-                 }
-         }
-         if (mer && ccleirq>0 && !aliased_irq)
-                 printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer),ccleirq--;
-  }
- iirq:
-  mir=master_inb(IIRQ_REG);
-  /* should test whether keyboard irq is really enabled, doing it in defhand */
-  if (mir&Q40_IRQ_KEYB_MASK) {
-         irq_tab[Q40_IRQ_KEYBOARD].count++;
-         irq_tab[Q40_IRQ_KEYBOARD].handler(Q40_IRQ_KEYBOARD,irq_tab[Q40_IRQ_KEYBOARD].dev_id,fp);
-  }
-  return IRQ_HANDLED;
-}
-
-int show_q40_interrupts (struct seq_file *p, void *v)
-{
-       int i;
-
-       for (i = 0; i <= Q40_IRQ_MAX; i++) {
-               if (irq_tab[i].count)
-                     seq_printf(p, "%sIRQ %02d: %8d  %s%s\n",
-                             (i<=15) ? "ISA-" : "    " ,
-                           i, irq_tab[i].count,
-                           irq_tab[i].devname[0] ? irq_tab[i].devname : "?",
-                           irq_tab[i].handler == q40_defhand ?
-                                       " (now unassigned)" : "");
+                               return;
+                       }
+               }
+               if (mer && ccleirq > 0 && !aliased_irq) {
+                       printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer);
+                       ccleirq--;
+               }
        }
-       return 0;
-}
-
+ iirq:
+       mir = master_inb(IIRQ_REG);
+       /* should test whether keyboard irq is really enabled, doing it in defhand */
+       if (mir & Q40_IRQ_KEYB_MASK)
+               m68k_handle_int(Q40_IRQ_KEYBOARD, fp);
 
-static irqreturn_t q40_defhand (int irq, void *dev_id, struct pt_regs *fp)
-{
-        if (irq!=Q40_IRQ_KEYBOARD)
-            printk ("Unknown q40 interrupt %d\n", irq);
-       else master_outb(-1,KEYBOARD_UNLOCK_REG);
-       return IRQ_NONE;
+       return;
 }
-static irqreturn_t default_handler(int lev, void *dev_id, struct pt_regs *regs)
-{
-       printk ("Uninitialised interrupt level %d\n", lev);
-       return IRQ_NONE;
-}
-
-irqreturn_t (*q40_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
-        [0] = default_handler,
-        [1] = default_handler,
-        [2] = default_handler,
-        [3] = default_handler,
-        [4] = default_handler,
-        [5] = default_handler,
-        [6] = default_handler,
-        [7] = default_handler
-};
-
 
-void q40_enable_irq (unsigned int irq)
+void q40_enable_irq(unsigned int irq)
 {
-  if ( irq>=5 && irq<=15 )
-  {
-    mext_disabled--;
-    if (mext_disabled>0)
-         printk("q40_enable_irq : nested disable/enable\n");
-    if (mext_disabled==0)
-    master_outb(1,EXT_ENABLE_REG);
-    }
+       if (irq >= 5 && irq <= 15) {
+               mext_disabled--;
+               if (mext_disabled > 0)
+                       printk("q40_enable_irq : nested disable/enable\n");
+               if (mext_disabled == 0)
+                       master_outb(1, EXT_ENABLE_REG);
+       }
 }
 
 
-void q40_disable_irq (unsigned int irq)
+void q40_disable_irq(unsigned int irq)
 {
-  /* disable ISA iqs : only do something if the driver has been
-   * verified to be Q40 "compatible" - right now IDE, NE2K
-   * Any driver should not attempt to sleep across disable_irq !!
-   */
-
-  if ( irq>=5 && irq<=15 ) {
-    master_outb(0,EXT_ENABLE_REG);
-    mext_disabled++;
-    if (mext_disabled>1) printk("disable_irq nesting count %d\n",mext_disabled);
-  }
+       /* disable ISA iqs : only do something if the driver has been
+        * verified to be Q40 "compatible" - right now IDE, NE2K
+        * Any driver should not attempt to sleep across disable_irq !!
+        */
+
+       if (irq >= 5 && irq <= 15) {
+               master_outb(0, EXT_ENABLE_REG);
+               mext_disabled++;
+               if (mext_disabled > 1)
+                       printk("disable_irq nesting count %d\n",mext_disabled);
+       }
 }
 
-unsigned long q40_probe_irq_on (void)
+unsigned long q40_probe_irq_on(void)
 {
-  printk("irq probing not working - reconfigure the driver to avoid this\n");
-  return -1;
+       printk("irq probing not working - reconfigure the driver to avoid this\n");
+       return -1;
 }
-int q40_probe_irq_off (unsigned long irqs)
+int q40_probe_irq_off(unsigned long irqs)
 {
-  return -1;
+       return -1;
 }
-/*
- * Local variables:
- * compile-command: "m68k-linux-gcc -D__KERNEL__ -I/home/rz/lx/linux-2.2.6/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -m68040   -c -o q40ints.o q40ints.c"
- * End:
- */
index f1ca0dfbaa67f928b55ad62ea38d217b4a0ff982..553c304aa2c5238261fdaecf7361f16ea6ca1919 100644 (file)
@@ -36,7 +36,6 @@ extern char _text, _end;
 char sun3_reserved_pmeg[SUN3_PMEGS_NUM];
 
 extern unsigned long sun3_gettimeoffset(void);
-extern int show_sun3_interrupts (struct seq_file *, void *);
 extern void sun3_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
 extern void sun3_get_model (char* model);
 extern void idprom_init (void);
@@ -147,13 +146,6 @@ void __init config_sun3(void)
 
         mach_sched_init      =  sun3_sched_init;
         mach_init_IRQ        =  sun3_init_IRQ;
-        mach_default_handler = &sun3_default_handler;
-        mach_request_irq     =  sun3_request_irq;
-        mach_free_irq        =  sun3_free_irq;
-       enable_irq           =  sun3_enable_irq;
-        disable_irq         =  sun3_disable_irq;
-       mach_process_int     =  sun3_process_int;
-        mach_get_irq_list    =  show_sun3_interrupts;
         mach_reset           =  sun3_reboot;
        mach_gettimeoffset   =  sun3_gettimeoffset;
        mach_get_model       =  sun3_get_model;
index e62a033cd49301e7fa39eba9397d3dc9c3033b7f..0912435e9e9090cee3bdf6b25a80faf06dff6df3 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/seq_file.h>
 
 extern void sun3_leds (unsigned char);
-static irqreturn_t sun3_inthandle(int irq, void *dev_id, struct pt_regs *fp);
 
 void sun3_disable_interrupts(void)
 {
@@ -40,48 +39,30 @@ int led_pattern[8] = {
 
 volatile unsigned char* sun3_intreg;
 
-void sun3_insert_irq(irq_node_t **list, irq_node_t *node)
-{
-}
-
-void sun3_delete_irq(irq_node_t **list, void *dev_id)
-{
-}
-
 void sun3_enable_irq(unsigned int irq)
 {
-       *sun3_intreg |=  (1<<irq);
+       *sun3_intreg |=  (1 << irq);
 }
 
 void sun3_disable_irq(unsigned int irq)
 {
-       *sun3_intreg &= ~(1<<irq);
-}
-
-inline void sun3_do_irq(int irq, struct pt_regs *fp)
-{
-       kstat_cpu(0).irqs[SYS_IRQS + irq]++;
-       *sun3_intreg &= ~(1<<irq);
-       *sun3_intreg |=  (1<<irq);
+       *sun3_intreg &= ~(1 << irq);
 }
 
 static irqreturn_t sun3_int7(int irq, void *dev_id, struct pt_regs *fp)
 {
-       sun3_do_irq(irq,fp);
-       if(!(kstat_cpu(0).irqs[SYS_IRQS + irq] % 2000))
-               sun3_leds(led_pattern[(kstat_cpu(0).irqs[SYS_IRQS+irq]%16000)
-                         /2000]);
+       *sun3_intreg |=  (1 << irq);
+       if (!(kstat_cpu(0).irqs[irq] % 2000))
+               sun3_leds(led_pattern[(kstat_cpu(0).irqs[irq] % 16000) / 2000]);
        return IRQ_HANDLED;
 }
 
 static irqreturn_t sun3_int5(int irq, void *dev_id, struct pt_regs *fp)
 {
-        kstat_cpu(0).irqs[SYS_IRQS + irq]++;
 #ifdef CONFIG_SUN3
        intersil_clear();
 #endif
-        *sun3_intreg &= ~(1<<irq);
-        *sun3_intreg |=  (1<<irq);
+        *sun3_intreg |=  (1 << irq);
 #ifdef CONFIG_SUN3
        intersil_clear();
 #endif
@@ -89,65 +70,8 @@ static irqreturn_t sun3_int5(int irq, void *dev_id, struct pt_regs *fp)
 #ifndef CONFIG_SMP
        update_process_times(user_mode(fp));
 #endif
-        if(!(kstat_cpu(0).irqs[SYS_IRQS + irq] % 20))
-                sun3_leds(led_pattern[(kstat_cpu(0).irqs[SYS_IRQS+irq]%160)
-                /20]);
-       return IRQ_HANDLED;
-}
-
-/* handle requested ints, excepting 5 and 7, which always do the same
-   thing */
-irqreturn_t (*sun3_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
-       [0] = sun3_inthandle,
-       [1] = sun3_inthandle,
-       [2] = sun3_inthandle,
-       [3] = sun3_inthandle,
-       [4] = sun3_inthandle,
-       [5] = sun3_int5,
-       [6] = sun3_inthandle,
-       [7] = sun3_int7
-};
-
-static const char *dev_names[SYS_IRQS] = {
-       [5] = "timer",
-       [7] = "int7 handler"
-};
-static void *dev_ids[SYS_IRQS];
-static irqreturn_t (*sun3_inthandler[SYS_IRQS])(int, void *, struct pt_regs *) = {
-       [5] = sun3_int5,
-       [7] = sun3_int7
-};
-static irqreturn_t (*sun3_vechandler[SUN3_INT_VECS])(int, void *, struct pt_regs *);
-static void *vec_ids[SUN3_INT_VECS];
-static const char *vec_names[SUN3_INT_VECS];
-static int vec_ints[SUN3_INT_VECS];
-
-
-int show_sun3_interrupts(struct seq_file *p, void *v)
-{
-       int i;
-
-       for(i = 0; i < (SUN3_INT_VECS-1); i++) {
-               if(sun3_vechandler[i] != NULL) {
-                       seq_printf(p, "vec %3d: %10u %s\n", i+64,
-                                  vec_ints[i],
-                                  (vec_names[i]) ? vec_names[i] :
-                                  "sun3_vechandler");
-               }
-       }
-
-       return 0;
-}
-
-static irqreturn_t sun3_inthandle(int irq, void *dev_id, struct pt_regs *fp)
-{
-       if(sun3_inthandler[irq] == NULL)
-               panic ("bad interrupt %d received (id %p)\n",irq, dev_id);
-
-        kstat_cpu(0).irqs[SYS_IRQS + irq]++;
-        *sun3_intreg &= ~(1<<irq);
-
-       sun3_inthandler[irq](irq, dev_ids[irq], fp);
+        if (!(kstat_cpu(0).irqs[irq] % 20))
+                sun3_leds(led_pattern[(kstat_cpu(0).irqs[irq] % 160) / 20]);
        return IRQ_HANDLED;
 }
 
@@ -157,109 +81,31 @@ static irqreturn_t sun3_vec255(int irq, void *dev_id, struct pt_regs *fp)
        return IRQ_HANDLED;
 }
 
-void sun3_init_IRQ(void)
+static void sun3_inthandle(unsigned int irq, struct pt_regs *fp)
 {
-       int i;
-
-       *sun3_intreg = 1;
-
-       for(i = 0; i < SYS_IRQS; i++)
-       {
-               if(dev_names[i])
-                       cpu_request_irq(i, sun3_default_handler[i], 0,
-                                       dev_names[i], NULL);
-       }
-
-       for(i = 0; i < 192; i++)
-               sun3_vechandler[i] = NULL;
-
-       sun3_vechandler[191] = sun3_vec255;
-}
-
-int sun3_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                      unsigned long flags, const char *devname, void *dev_id)
-{
-
-       if(irq < SYS_IRQS) {
-               if(sun3_inthandler[irq] != NULL) {
-                       printk("sun3_request_irq: request for irq %d -- already taken!\n", irq);
-                       return 1;
-               }
-
-               sun3_inthandler[irq] = handler;
-               dev_ids[irq] = dev_id;
-               dev_names[irq] = devname;
-
-               /* setting devname would be nice */
-               cpu_request_irq(irq, sun3_default_handler[irq], 0, devname,
-                               NULL);
-
-               return 0;
-       } else {
-               if((irq >= 64) && (irq <= 255)) {
-                       int vec;
-
-                       vec = irq - 64;
-                       if(sun3_vechandler[vec] != NULL) {
-                               printk("sun3_request_irq: request for vec %d -- already taken!\n", irq);
-                               return 1;
-                       }
-
-                       sun3_vechandler[vec] = handler;
-                       vec_ids[vec] = dev_id;
-                       vec_names[vec] = devname;
-                       vec_ints[vec] = 0;
-
-                       return 0;
-               }
-       }
-
-       printk("sun3_request_irq: invalid irq %d\n", irq);
-       return 1;
+        *sun3_intreg &= ~(1 << irq);
 
+       m68k_handle_int(irq, fp);
 }
 
-void sun3_free_irq(unsigned int irq, void *dev_id)
-{
-
-       if(irq < SYS_IRQS) {
-               if(sun3_inthandler[irq] == NULL)
-                       panic("sun3_free_int: attempt to free unused irq %d\n", irq);
-               if(dev_ids[irq] != dev_id)
-                       panic("sun3_free_int: incorrect dev_id for irq %d\n", irq);
-
-               sun3_inthandler[irq] = NULL;
-               return;
-       } else if((irq >= 64) && (irq <= 255)) {
-               int vec;
-
-               vec = irq - 64;
-               if(sun3_vechandler[vec] == NULL)
-                       panic("sun3_free_int: attempt to free unused vector %d\n", irq);
-               if(vec_ids[irq] != dev_id)
-                       panic("sun3_free_int: incorrect dev_id for vec %d\n", irq);
-
-               sun3_vechandler[vec] = NULL;
-               return;
-       } else {
-               panic("sun3_free_irq: invalid irq %d\n", irq);
-       }
-}
+static struct irq_controller sun3_irq_controller = {
+       .name           = "sun3",
+       .lock           = SPIN_LOCK_UNLOCKED,
+       .startup        = m68k_irq_startup,
+       .shutdown       = m68k_irq_shutdown,
+       .enable         = sun3_enable_irq,
+       .disable        = sun3_disable_irq,
+};
 
-irqreturn_t sun3_process_int(int irq, struct pt_regs *regs)
+void sun3_init_IRQ(void)
 {
+       *sun3_intreg = 1;
 
-       if((irq >= 64) && (irq <= 255)) {
-               int vec;
-
-               vec = irq - 64;
-               if(sun3_vechandler[vec] == NULL)
-                       panic ("bad interrupt vector %d received\n",irq);
+       m68k_setup_auto_interrupt(sun3_inthandle);
+       m68k_setup_irq_controller(&sun3_irq_controller, IRQ_AUTO_1, 7);
+       m68k_setup_user_interrupt(VEC_USER, 192, NULL);
 
-               vec_ints[vec]++;
-               return sun3_vechandler[vec](irq, vec_ids[vec], regs);
-       } else {
-               panic("sun3_process_int: unable to handle interrupt vector %d\n",
-                     irq);
-       }
+       request_irq(IRQ_AUTO_5, sun3_int5, 0, "int5", NULL);
+       request_irq(IRQ_AUTO_7, sun3_int7, 0, "int7", NULL);
+       request_irq(IRQ_USER+127, sun3_vec255, 0, "vec255", NULL);
 }
index 0920f5d33606d972fe349308dc76cefd93711195..52fb174088698388e486514fc6a4d3093ed1f32a 100644 (file)
@@ -52,17 +52,10 @@ void __init config_sun3x(void)
 
        sun3x_prom_init();
 
-       mach_get_irq_list        = show_sun3_interrupts;
        mach_max_dma_address = 0xffffffff; /* we can DMA anywhere, whee */
 
-       mach_default_handler = &sun3_default_handler;
        mach_sched_init      = sun3x_sched_init;
        mach_init_IRQ        = sun3_init_IRQ;
-       enable_irq           = sun3_enable_irq;
-       disable_irq          = sun3_disable_irq;
-       mach_request_irq     = sun3_request_irq;
-       mach_free_irq        = sun3_free_irq;
-       mach_process_int     = sun3_process_int;
 
        mach_gettimeoffset   = sun3x_gettimeoffset;
        mach_reset           = sun3x_reboot;
index a9bf6cc3abd183bd4a9cbd124be08851e6b0ee46..676e868d26fb15ab79b23d7c69be792276185be8 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/smp_lock.h>
 #include <linux/time.h>
 #include <linux/ptrace.h>
+#include <linux/resource.h>
 
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
@@ -540,8 +541,6 @@ out:
 #define IRIX_P_PGID   2
 #define IRIX_P_ALL    7
 
-extern int getrusage(struct task_struct *, int, struct rusage __user *);
-
 #define W_EXITED     1
 #define W_TRAPPED    2
 #define W_STOPPED    4
index 19e1ef43eb4be8d19f435008e587a344d713e668..1137dd6ea7aa914bd91c3ec10722c843ef531ebe 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/socket.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
+#include <linux/resource.h>
 
 #include <asm/ptrace.h>
 #include <asm/page.h>
@@ -235,7 +236,6 @@ asmlinkage int irix_prctl(unsigned option, ...)
 #undef DEBUG_PROCGRPS
 
 extern unsigned long irix_mapelf(int fd, struct elf_phdr __user *user_phdrp, int cnt);
-extern int getrusage(struct task_struct *p, int who, struct rusage __user *ru);
 extern char *prom_getenv(char *name);
 extern long prom_setenv(char *name, char *value);
 
index c858eb4bef17aad3fe2ba1dcf9eb6188d0a0f1f8..b5431ccf1147ae551c763b0fd360d3857c4ee00b 100644 (file)
@@ -1654,7 +1654,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                return -EINVAL;
 
        vma->vm_pgoff = offset >> PAGE_SHIFT;
-       vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
        vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
                                                  vma->vm_page_prot,
                                                  mmap_state, write_combine);
index 5ad87c426bed6de4557e9f2abea3855fbd1f3c50..247937dd8b736aab99a79df9bd6d5711bf951a4a 100644 (file)
@@ -877,7 +877,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                return -EINVAL;
 
        vma->vm_pgoff = offset >> PAGE_SHIFT;
-       vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
        vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
                                                  vma->vm_page_prot,
                                                  mmap_state, write_combine);
index 2b87f82df13516cd623e5e42f7f7e673431513c0..2ab8f2be911e055c2d38b726816f9d7fc6b0f3ef 100644 (file)
@@ -115,8 +115,6 @@ static int page_map_mmap( struct file *file, struct vm_area_struct *vma )
 {
        struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
 
-       vma->vm_flags |= VM_SHM | VM_LOCKED;
-
        if ((vma->vm_end - vma->vm_start) > dp->size)
                return -EINVAL;
 
index 91a6e04d9741fb197f4fb91ec039a1a154b2eabd..52f5659534f48042da4f68ddaad02806f70a3a0c 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/kprobes.h>
 #include <linux/kexec.h>
+#include <linux/backlight.h>
 
 #include <asm/kdebug.h>
 #include <asm/pgtable.h>
@@ -105,10 +106,18 @@ int die(const char *str, struct pt_regs *regs, long err)
        spin_lock_irq(&die_lock);
        bust_spinlocks(1);
 #ifdef CONFIG_PMAC_BACKLIGHT
-       if (machine_is(powermac)) {
-               set_backlight_enable(1);
-               set_backlight_level(BACKLIGHT_MAX);
+       mutex_lock(&pmac_backlight_mutex);
+       if (machine_is(powermac) && pmac_backlight) {
+               struct backlight_properties *props;
+
+               down(&pmac_backlight->sem);
+               props = pmac_backlight->props;
+               props->brightness = props->max_brightness;
+               props->power = FB_BLANK_UNBLANK;
+               props->update_status(pmac_backlight);
+               up(&pmac_backlight->sem);
        }
+       mutex_unlock(&pmac_backlight_mutex);
 #endif
        printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
 #ifdef CONFIG_PREEMPT
index 2dfde61c8412ff6fafe023e7f5d4f89d1148ea44..ce696c1cca75b4946eced462d48a2f9e9df0638f 100644 (file)
@@ -89,7 +89,7 @@ void __init cbe_regs_init(void)
        struct device_node *cpu;
 
        /* Build local fast map of CPUs */
-       for_each_cpu(i)
+       for_each_possible_cpu(i)
                cbe_thread_map[i].cpu_node = of_get_cpu_node(i, NULL);
 
        /* Find maps for each device tree CPU */
@@ -110,7 +110,7 @@ void __init cbe_regs_init(void)
                        return;
                }
                map->cpu_node = cpu;
-               for_each_cpu(i)
+               for_each_possible_cpu(i)
                        if (cbe_thread_map[i].cpu_node == cpu)
                                cbe_thread_map[i].regs = map;
 
index f4e2d8805c9e3299cce5815506caeb7cc1fe6fb3..1bbf822b4efcafada7f9181af9de762772f37f29 100644 (file)
@@ -180,7 +180,7 @@ static int setup_iic_hardcoded(void)
        unsigned long regs;
        struct iic *iic;
 
-       for_each_cpu(cpu) {
+       for_each_possible_cpu(cpu) {
                iic = &per_cpu(iic, cpu);
                nodeid = cpu/2;
 
index 8be2f7d071f0846806b19b797ff589393b8a1508..498b042e1837567c2326c93faa404d6ffa6a4d00 100644 (file)
  * Contains support for the backlight.
  *
  *   Copyright (C) 2000 Benjamin Herrenschmidt
+ *   Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
  *
  */
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/stddef.h>
-#include <linux/reboot.h>
-#include <linux/nvram.h>
-#include <linux/console.h>
-#include <asm/sections.h>
-#include <asm/ptrace.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
 #include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/nvram.h>
 #include <asm/backlight.h>
 
-#include <linux/adb.h>
-#include <linux/pmu.h>
+#define OLD_BACKLIGHT_MAX 15
 
-static struct backlight_controller *backlighter;
-static void* backlighter_data;
-static int backlight_autosave;
-static int backlight_level = BACKLIGHT_MAX;
-static int backlight_enabled = 1;
-static int backlight_req_level = -1;
-static int backlight_req_enable = -1;
+/* Protect the pmac_backlight variable */
+DEFINE_MUTEX(pmac_backlight_mutex);
 
-static void backlight_callback(void *);
-static DECLARE_WORK(backlight_work, backlight_callback, NULL);
+/* Main backlight storage
+ *
+ * Backlight drivers in this variable are required to have the "props"
+ * attribute set and to have an update_status function.
+ *
+ * We can only store one backlight here, but since Apple laptops have only one
+ * internal display, it doesn't matter. Other backlight drivers can be used
+ * independently.
+ *
+ * Lock ordering:
+ * pmac_backlight_mutex (global, main backlight)
+ *   pmac_backlight->sem (backlight class)
+ */
+struct backlight_device *pmac_backlight;
 
-void register_backlight_controller(struct backlight_controller *ctrler,
-                                         void *data, char *type)
+int pmac_has_backlight_type(const char *type)
 {
-       struct device_node* bk_node;
-       char *prop;
-       int valid = 0;
-
-       /* There's already a matching controller, bail out */
-       if (backlighter != NULL)
-               return;
-
-       bk_node = find_devices("backlight");
-
-#ifdef CONFIG_ADB_PMU
-       /* Special case for the old PowerBook since I can't test on it */
-       backlight_autosave = machine_is_compatible("AAPL,3400/2400")
-               || machine_is_compatible("AAPL,3500");
-       if ((backlight_autosave
-            || machine_is_compatible("AAPL,PowerBook1998")
-            || machine_is_compatible("PowerBook1,1"))
-           && !strcmp(type, "pmu"))
-               valid = 1;
-#endif
+       struct device_node* bk_node = find_devices("backlight");
+
        if (bk_node) {
-               prop = get_property(bk_node, "backlight-control", NULL);
-               if (prop && !strncmp(prop, type, strlen(type)))
-                       valid = 1;
-       }
-       if (!valid)
-               return;
-       backlighter = ctrler;
-       backlighter_data = data;
-
-       if (bk_node && !backlight_autosave)
-               prop = get_property(bk_node, "bklt", NULL);
-       else
-               prop = NULL;
-       if (prop) {
-               backlight_level = ((*prop)+1) >> 1;
-               if (backlight_level > BACKLIGHT_MAX)
-                       backlight_level = BACKLIGHT_MAX;
+               char *prop = get_property(bk_node, "backlight-control", NULL);
+               if (prop && strncmp(prop, type, strlen(type)) == 0)
+                       return 1;
        }
 
-#ifdef CONFIG_ADB_PMU
-       if (backlight_autosave) {
-               struct adb_request req;
-               pmu_request(&req, NULL, 2, 0xd9, 0);
-               while (!req.complete)
-                       pmu_poll();
-               backlight_level = req.reply[0] >> 4;
-       }
-#endif
-       acquire_console_sem();
-       if (!backlighter->set_enable(1, backlight_level, data))
-               backlight_enabled = 1;
-       release_console_sem();
-
-       printk(KERN_INFO "Registered \"%s\" backlight controller,"
-              "level: %d/15\n", type, backlight_level);
+       return 0;
 }
-EXPORT_SYMBOL(register_backlight_controller);
 
-void unregister_backlight_controller(struct backlight_controller
-                                           *ctrler, void *data)
+int pmac_backlight_curve_lookup(struct fb_info *info, int value)
 {
-       /* We keep the current backlight level (for now) */
-       if (ctrler == backlighter && data == backlighter_data)
-               backlighter = NULL;
+       int level = (FB_BACKLIGHT_LEVELS - 1);
+
+       if (info && info->bl_dev) {
+               int i, max = 0;
+
+               /* Look for biggest value */
+               for (i = 0; i < FB_BACKLIGHT_LEVELS; i++)
+                       max = max((int)info->bl_curve[i], max);
+
+               /* Look for nearest value */
+               for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) {
+                       int diff = abs(info->bl_curve[i] - value);
+                       if (diff < max) {
+                               max = diff;
+                               level = i;
+                       }
+               }
+
+       }
+
+       return level;
 }
-EXPORT_SYMBOL(unregister_backlight_controller);
 
-static int __set_backlight_enable(int enable)
+static void pmac_backlight_key(int direction)
 {
-       int rc;
-
-       if (!backlighter)
-               return -ENODEV;
-       acquire_console_sem();
-       rc = backlighter->set_enable(enable, backlight_level,
-                                    backlighter_data);
-       if (!rc)
-               backlight_enabled = enable;
-       release_console_sem();
-       return rc;
+       mutex_lock(&pmac_backlight_mutex);
+       if (pmac_backlight) {
+               struct backlight_properties *props;
+               int brightness;
+
+               down(&pmac_backlight->sem);
+               props = pmac_backlight->props;
+
+               brightness = props->brightness +
+                       ((direction?-1:1) * (props->max_brightness / 15));
+
+               if (brightness < 0)
+                       brightness = 0;
+               else if (brightness > props->max_brightness)
+                       brightness = props->max_brightness;
+
+               props->brightness = brightness;
+               props->update_status(pmac_backlight);
+
+               up(&pmac_backlight->sem);
+       }
+       mutex_unlock(&pmac_backlight_mutex);
 }
-int set_backlight_enable(int enable)
+
+void pmac_backlight_key_up()
 {
-       if (!backlighter)
-               return -ENODEV;
-       backlight_req_enable = enable;
-       schedule_work(&backlight_work);
-       return 0;
+       pmac_backlight_key(0);
 }
 
-EXPORT_SYMBOL(set_backlight_enable);
-
-int get_backlight_enable(void)
+void pmac_backlight_key_down()
 {
-       if (!backlighter)
-               return -ENODEV;
-       return backlight_enabled;
+       pmac_backlight_key(1);
 }
-EXPORT_SYMBOL(get_backlight_enable);
 
-static int __set_backlight_level(int level)
+int pmac_backlight_set_legacy_brightness(int brightness)
 {
-       int rc = 0;
-
-       if (!backlighter)
-               return -ENODEV;
-       if (level < BACKLIGHT_MIN)
-               level = BACKLIGHT_OFF;
-       if (level > BACKLIGHT_MAX)
-               level = BACKLIGHT_MAX;
-       acquire_console_sem();
-       if (backlight_enabled)
-               rc = backlighter->set_level(level, backlighter_data);
-       if (!rc)
-               backlight_level = level;
-       release_console_sem();
-       if (!rc && !backlight_autosave) {
-               level <<=1;
-               if (level & 0x10)
-                       level |= 0x01;
-               // -- todo: save to property "bklt"
+       int error = -ENXIO;
+
+       mutex_lock(&pmac_backlight_mutex);
+       if (pmac_backlight) {
+               struct backlight_properties *props;
+
+               down(&pmac_backlight->sem);
+               props = pmac_backlight->props;
+               props->brightness = brightness *
+                       props->max_brightness / OLD_BACKLIGHT_MAX;
+               props->update_status(pmac_backlight);
+               up(&pmac_backlight->sem);
+
+               error = 0;
        }
-       return rc;
+       mutex_unlock(&pmac_backlight_mutex);
+
+       return error;
 }
-int set_backlight_level(int level)
+
+int pmac_backlight_get_legacy_brightness()
 {
-       if (!backlighter)
-               return -ENODEV;
-       backlight_req_level = level;
-       schedule_work(&backlight_work);
-       return 0;
-}
+       int result = -ENXIO;
 
-EXPORT_SYMBOL(set_backlight_level);
+       mutex_lock(&pmac_backlight_mutex);
+       if (pmac_backlight) {
+               struct backlight_properties *props;
 
-int get_backlight_level(void)
-{
-       if (!backlighter)
-               return -ENODEV;
-       return backlight_level;
-}
-EXPORT_SYMBOL(get_backlight_level);
+               down(&pmac_backlight->sem);
+               props = pmac_backlight->props;
+               result = props->brightness *
+                       OLD_BACKLIGHT_MAX / props->max_brightness;
+               up(&pmac_backlight->sem);
+       }
+       mutex_unlock(&pmac_backlight_mutex);
 
-static void backlight_callback(void *dummy)
-{
-       int level, enable;
-
-       do {
-               level = backlight_req_level;
-               enable = backlight_req_enable;
-               mb();
-
-               if (level >= 0)
-                       __set_backlight_level(level);
-               if (enable >= 0)
-                       __set_backlight_enable(enable);
-       } while(cmpxchg(&backlight_req_level, level, -1) != level ||
-               cmpxchg(&backlight_req_enable, enable, -1) != enable);
+       return result;
 }
index 4735b41c113c7d7814a1ecff82451cb69d2f05b2..0741df8c41b7c3c60cf42eb2170d48e7b36b4af9 100644 (file)
@@ -26,9 +26,6 @@
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/xmon.h>
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/backlight.h>
-#endif
 #include <asm/processor.h>
 #include <asm/pgtable.h>
 #include <asm/mmu.h>
index 809673a36f7a2fb77d7759e098cab7e3d0c67085..d20accf9650dcbacc4ec88806c074d150cd10dca 100644 (file)
@@ -1032,7 +1032,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                return -EINVAL;
 
        vma->vm_pgoff = offset >> PAGE_SHIFT;
-       vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
        vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
                                                  vma->vm_page_prot,
                                                  mmap_state, write_combine);
index 0a04e4a564b2a57ed7e30ac85e856215016ab019..b282034452a4707357dadd5b75d9be0f3bd83206 100644 (file)
@@ -47,6 +47,7 @@
 #include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
+#include <asm/sections.h>
 
 /*
  * Machine setup..
@@ -65,11 +66,6 @@ volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
 unsigned long __initdata zholes_size[MAX_NR_ZONES];
 static unsigned long __initdata memory_end;
 
-/*
- * Setup options
- */
-extern int _text,_etext, _edata, _end;
-
 /*
  * This is set up by the setup-routine at boot-time
  * for S390 need to find out, what we have to setup
@@ -80,15 +76,11 @@ extern int _text,_etext, _edata, _end;
 
 static struct resource code_resource = {
        .name  = "Kernel code",
-       .start = (unsigned long) &_text,
-       .end = (unsigned long) &_etext - 1,
        .flags = IORESOURCE_BUSY | IORESOURCE_MEM,
 };
 
 static struct resource data_resource = {
        .name = "Kernel data",
-       .start = (unsigned long) &_etext,
-       .end = (unsigned long) &_edata - 1,
        .flags = IORESOURCE_BUSY | IORESOURCE_MEM,
 };
 
@@ -422,6 +414,11 @@ setup_resources(void)
        struct resource *res;
        int i;
 
+       code_resource.start = (unsigned long) &_text;
+       code_resource.end = (unsigned long) &_etext - 1;
+       data_resource.start = (unsigned long) &_etext;
+       data_resource.end = (unsigned long) &_edata - 1;
+
        for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
                res = alloc_bootmem_low(sizeof(struct resource));
                res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
index 6d7173fc55a395e3a1e1ef7f83263e1fa2711808..79149314ed04f9f11418a631dc4628a5f77e95fd 100644 (file)
@@ -300,8 +300,6 @@ void mconsole_reboot(struct mc_request *req)
        machine_restart(NULL);
 }
 
-extern void ctrl_alt_del(void);
-
 void mconsole_cad(struct mc_request *req)
 {
        mconsole_reply(req, "", 0, 0);
index e06f83e80f4a9e8aa57d5cf5ff26cd455e367d89..5e86aa047b2ba0ac8cf2cf6f10487a47a2d81d00 100644 (file)
@@ -12,8 +12,6 @@
 
 typedef long syscall_handler_t(void);
 
-extern syscall_handler_t *ia32_sys_call_table[];
-
 extern syscall_handler_t *sys_call_table[];
 
 #define EXECUTE_SYSCALL(syscall, regs) \
index b8d5116d73716615c0a1f970c340448265d6b373..fdb82658b1a14c29c1ec4280b5120d46a7369f91 100644 (file)
@@ -823,7 +823,7 @@ void __init setup_arch(char **cmdline_p)
 #endif
 #ifdef CONFIG_KEXEC
        if (crashk_res.start != crashk_res.end) {
-               reserve_bootmem(crashk_res.start,
+               reserve_bootmem_generic(crashk_res.start,
                        crashk_res.end - crashk_res.start + 1);
        }
 #endif
index de19501aa809afc4784bcfc9affba6e6b3c313a2..c6f471b9eaa0c603f356441bea6b980c2e85492e 100644 (file)
@@ -349,17 +349,6 @@ __pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma,
        return -EINVAL;
 }
 
-/*
- * Set vm_flags of VMA, as appropriate for this architecture, for a pci device
- * mapping.
- */
-static __inline__ void
-__pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma,
-                    enum pci_mmap_state mmap_state)
-{
-       vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
-}
-
 /*
  * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
  * device mapping.
@@ -399,7 +388,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
        if (ret < 0)
                return ret;
 
-       __pci_mmap_set_flags(dev, vma, mmap_state);
        __pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);
 
        ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
index 2a8af685926fe0d2c7b197c535c6c0549c8224f1..2641597c654916827f4e90661332da330b71e9ea 100644 (file)
@@ -64,6 +64,7 @@
 #include <linux/buffer_head.h>
 #include <linux/blkdev.h>
 #include <linux/elevator.h>
+#include <linux/interrupt.h>
 
 #include <asm/setup.h>
 #include <asm/uaccess.h>
index 25c3c4a5da813ed27e2ff4541e543079b842b871..39b0f53186e8a2a6532799c6ac172c4eeab7b96e 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/blkpg.h>
 #include <linux/timer.h>
 #include <linux/proc_fs.h>
-#include <linux/init.h> 
+#include <linux/init.h>
 #include <linux/hdreg.h>
 #include <linux/spinlock.h>
 #include <linux/compat.h>
@@ -64,143 +64,129 @@ MODULE_LICENSE("GPL");
 
 /* define the PCI info for the cards we can control */
 static const struct pci_device_id cciss_pci_device_id[] = {
-       { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISS,
-                       0x0E11, 0x4070, 0, 0, 0},
-       { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
-                        0x0E11, 0x4080, 0, 0, 0},
-       { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
-                        0x0E11, 0x4082, 0, 0, 0},
-       { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
-                        0x0E11, 0x4083, 0, 0, 0},
-       { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
-               0x0E11, 0x409A, 0, 0, 0},
-       { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
-               0x0E11, 0x409B, 0, 0, 0},
-       { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
-               0x0E11, 0x409C, 0, 0, 0},
-       { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
-               0x0E11, 0x409D, 0, 0, 0},
-       { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
-               0x0E11, 0x4091, 0, 0, 0},
-       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSA,
-               0x103C, 0x3225, 0, 0, 0},
-       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
-               0x103c, 0x3223, 0, 0, 0},
-       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
-               0x103c, 0x3234, 0, 0, 0},
-       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
-               0x103c, 0x3235, 0, 0, 0},
-       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
-               0x103c, 0x3211, 0, 0, 0},
-       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
-               0x103c, 0x3212, 0, 0, 0},
-       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
-               0x103c, 0x3213, 0, 0, 0},
-       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
-               0x103c, 0x3214, 0, 0, 0},
-       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
-               0x103c, 0x3215, 0, 0, 0},
+       {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISS,  0x0E11, 0x4070},
+       {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, 0x0E11, 0x4080},
+       {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, 0x0E11, 0x4082},
+       {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, 0x0E11, 0x4083},
+       {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x4091},
+       {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409A},
+       {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409B},
+       {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409C},
+       {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409D},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSA,     0x103C, 0x3225},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x3223},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x3234},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x3235},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3211},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3212},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3213},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3214},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3215},
        {0,}
 };
-MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
 
-#define NR_PRODUCTS ARRAY_SIZE(products)
+MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
 
 /*  board_id = Subsystem Device ID & Vendor ID
  *  product = Marketing Name for the board
- *  access = Address of the struct of function pointers 
+ *  access = Address of the struct of function pointers
  */
 static struct board_type products[] = {
-       { 0x40700E11, "Smart Array 5300", &SA5_access },
-       { 0x40800E11, "Smart Array 5i", &SA5B_access},
-       { 0x40820E11, "Smart Array 532", &SA5B_access},
-       { 0x40830E11, "Smart Array 5312", &SA5B_access},
-       { 0x409A0E11, "Smart Array 641", &SA5_access},
-       { 0x409B0E11, "Smart Array 642", &SA5_access},
-       { 0x409C0E11, "Smart Array 6400", &SA5_access},
-       { 0x409D0E11, "Smart Array 6400 EM", &SA5_access},
-       { 0x40910E11, "Smart Array 6i", &SA5_access},
-       { 0x3225103C, "Smart Array P600", &SA5_access},
-       { 0x3223103C, "Smart Array P800", &SA5_access},
-       { 0x3234103C, "Smart Array P400", &SA5_access},
-       { 0x3235103C, "Smart Array P400i", &SA5_access},
-       { 0x3211103C, "Smart Array E200i", &SA5_access},
-       { 0x3212103C, "Smart Array E200", &SA5_access},
-       { 0x3213103C, "Smart Array E200i", &SA5_access},
-       { 0x3214103C, "Smart Array E200i", &SA5_access},
-       { 0x3215103C, "Smart Array E200i", &SA5_access},
+       {0x40700E11, "Smart Array 5300", &SA5_access},
+       {0x40800E11, "Smart Array 5i", &SA5B_access},
+       {0x40820E11, "Smart Array 532", &SA5B_access},
+       {0x40830E11, "Smart Array 5312", &SA5B_access},
+       {0x409A0E11, "Smart Array 641", &SA5_access},
+       {0x409B0E11, "Smart Array 642", &SA5_access},
+       {0x409C0E11, "Smart Array 6400", &SA5_access},
+       {0x409D0E11, "Smart Array 6400 EM", &SA5_access},
+       {0x40910E11, "Smart Array 6i", &SA5_access},
+       {0x3225103C, "Smart Array P600", &SA5_access},
+       {0x3223103C, "Smart Array P800", &SA5_access},
+       {0x3234103C, "Smart Array P400", &SA5_access},
+       {0x3235103C, "Smart Array P400i", &SA5_access},
+       {0x3211103C, "Smart Array E200i", &SA5_access},
+       {0x3212103C, "Smart Array E200", &SA5_access},
+       {0x3213103C, "Smart Array E200i", &SA5_access},
+       {0x3214103C, "Smart Array E200i", &SA5_access},
+       {0x3215103C, "Smart Array E200i", &SA5_access},
 };
 
-/* How long to wait (in millesconds) for board to go into simple mode */
-#define MAX_CONFIG_WAIT 30000 
+/* How long to wait (in milliseconds) for board to go into simple mode */
+#define MAX_CONFIG_WAIT 30000
 #define MAX_IOCTL_CONFIG_WAIT 1000
 
 /*define how many times we will try a command because of bus resets */
 #define MAX_CMD_RETRIES 3
 
 #define READ_AHEAD      1024
-#define NR_CMDS                 384 /* #commands that can be outstanding */
+#define NR_CMDS                 384    /* #commands that can be outstanding */
 #define MAX_CTLR       32
 
 /* Originally cciss driver only supports 8 major numbers */
 #define MAX_CTLR_ORIG  8
 
-
 static ctlr_info_t *hba[MAX_CTLR];
 
 static void do_cciss_request(request_queue_t *q);
 static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs);
 static int cciss_open(struct inode *inode, struct file *filep);
 static int cciss_release(struct inode *inode, struct file *filep);
-static int cciss_ioctl(struct inode *inode, struct file *filep, 
-               unsigned int cmd, unsigned long arg);
+static int cciss_ioctl(struct inode *inode, struct file *filep,
+                      unsigned int cmd, unsigned long arg);
 static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo);
 
 static int revalidate_allvol(ctlr_info_t *host);
 static int cciss_revalidate(struct gendisk *disk);
 static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk);
-static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, int clear_all);
+static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
+                          int clear_all);
 
 static void cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
-       int withirq, unsigned int *total_size, unsigned int *block_size);
-static void cciss_geometry_inquiry(int ctlr, int logvol,
-                       int withirq, unsigned int total_size,
-                       unsigned int block_size, InquiryData_struct *inq_buff,
-                       drive_info_struct *drv);
+                               int withirq, unsigned int *total_size,
+                               unsigned int *block_size);
+static void cciss_geometry_inquiry(int ctlr, int logvol, int withirq,
+                                  unsigned int total_size,
+                                  unsigned int block_size,
+                                  InquiryData_struct *inq_buff,
+                                  drive_info_struct *drv);
 static void cciss_getgeometry(int cntl_num);
-static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *, __u32);
-static void start_io( ctlr_info_t *h);
-static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size,
-       unsigned int use_unit_num, unsigned int log_unit, __u8 page_code,
-       unsigned char *scsi3addr, int cmd_type);
-static int sendcmd_withirq(__u8        cmd, int ctlr, void *buff, size_t size,
-       unsigned int use_unit_num, unsigned int log_unit, __u8  page_code,
-       int cmd_type);
+static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *,
+                                          __u32);
+static void start_io(ctlr_info_t *h);
+static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size,
+                  unsigned int use_unit_num, unsigned int log_unit,
+                  __u8 page_code, unsigned char *scsi3addr, int cmd_type);
+static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size,
+                          unsigned int use_unit_num, unsigned int log_unit,
+                          __u8 page_code, int cmd_type);
 
 static void fail_all_cmds(unsigned long ctlr);
 
 #ifdef CONFIG_PROC_FS
-static int cciss_proc_get_info(char *buffer, char **start, off_t offset, 
-               int length, int *eof, void *data);
+static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
+                              int length, int *eof, void *data);
 static void cciss_procinit(int i);
 #else
-static void cciss_procinit(int i) {}
-#endif /* CONFIG_PROC_FS */
+static void cciss_procinit(int i)
+{
+}
+#endif                         /* CONFIG_PROC_FS */
 
 #ifdef CONFIG_COMPAT
 static long cciss_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg);
 #endif
 
-static struct block_device_operations cciss_fops  = {
-       .owner          = THIS_MODULE,
-       .open           = cciss_open, 
-       .release        = cciss_release,
-        .ioctl         = cciss_ioctl,
-        .getgeo                = cciss_getgeo,
+static struct block_device_operations cciss_fops = {
+       .owner = THIS_MODULE,
+       .open = cciss_open,
+       .release = cciss_release,
+       .ioctl = cciss_ioctl,
+       .getgeo = cciss_getgeo,
 #ifdef CONFIG_COMPAT
-       .compat_ioctl   = cciss_compat_ioctl,
+       .compat_ioctl = cciss_compat_ioctl,
 #endif
-       .revalidate_disk= cciss_revalidate,
+       .revalidate_disk = cciss_revalidate,
 };
 
 /*
@@ -208,28 +194,29 @@ static struct block_device_operations cciss_fops  = {
  */
 static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c)
 {
-        if (*Qptr == NULL) {
-                *Qptr = c;
-                c->next = c->prev = c;
-        } else {
-                c->prev = (*Qptr)->prev;
-                c->next = (*Qptr);
-                (*Qptr)->prev->next = c;
-                (*Qptr)->prev = c;
-        }
+       if (*Qptr == NULL) {
+               *Qptr = c;
+               c->next = c->prev = c;
+       } else {
+               c->prev = (*Qptr)->prev;
+               c->next = (*Qptr);
+               (*Qptr)->prev->next = c;
+               (*Qptr)->prev = c;
+       }
 }
 
-static inline CommandList_struct *removeQ(CommandList_struct **Qptr, 
-                                               CommandList_struct *c)
+static inline CommandList_struct *removeQ(CommandList_struct **Qptr,
+                                         CommandList_struct *c)
 {
-        if (c && c->next != c) {
-                if (*Qptr == c) *Qptr = c->next;
-                c->prev->next = c->next;
-                c->next->prev = c->prev;
-        } else {
-                *Qptr = NULL;
-        }
-        return c;
+       if (c && c->next != c) {
+               if (*Qptr == c)
+                       *Qptr = c->next;
+               c->prev->next = c->next;
+               c->next->prev = c->prev;
+       } else {
+               *Qptr = NULL;
+       }
+       return c;
 }
 
 #include "cciss_scsi.c"                /* For SCSI tape support */
@@ -242,23 +229,24 @@ static inline CommandList_struct *removeQ(CommandList_struct **Qptr,
 #define ENG_GIG 1000000000
 #define ENG_GIG_FACTOR (ENG_GIG/512)
 #define RAID_UNKNOWN 6
-static const char *raid_label[] = {"0","4","1(1+0)","5","5+1","ADG",
-                                          "UNKNOWN"};
+static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
+       "UNKNOWN"
+};
 
 static struct proc_dir_entry *proc_cciss;
 
-static int cciss_proc_get_info(char *buffer, char **start, off_t offset, 
-               int length, int *eof, void *data)
+static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
+                              int length, int *eof, void *data)
 {
-        off_t pos = 0;
-        off_t len = 0;
-        int size, i, ctlr;
-        ctlr_info_t *h = (ctlr_info_t*)data;
-        drive_info_struct *drv;
+       off_t pos = 0;
+       off_t len = 0;
+       int size, i, ctlr;
+       ctlr_info_t *h = (ctlr_info_t *) data;
+       drive_info_struct *drv;
        unsigned long flags;
-        sector_t vol_sz, vol_sz_frac;
+       sector_t vol_sz, vol_sz_frac;
 
-        ctlr = h->ctlr;
+       ctlr = h->ctlr;
 
        /* prevent displaying bogus info during configuration
         * or deconfiguration of a logical volume
@@ -266,35 +254,35 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
        spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
        if (h->busy_configuring) {
                spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-       return -EBUSY;
+               return -EBUSY;
        }
        h->busy_configuring = 1;
        spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
 
-        size = sprintf(buffer, "%s: HP %s Controller\n"
-               "Board ID: 0x%08lx\n"
-               "Firmware Version: %c%c%c%c\n"
-               "IRQ: %d\n"
-               "Logical drives: %d\n"
-               "Current Q depth: %d\n"
-               "Current # commands on controller: %d\n"
-               "Max Q depth since init: %d\n"
-               "Max # commands on controller since init: %d\n"
-               "Max SG entries since init: %d\n\n",
-                h->devname,
-                h->product_name,
-                (unsigned long)h->board_id,
-               h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3],
-                (unsigned int)h->intr[SIMPLE_MODE_INT],
-                h->num_luns, 
-               h->Qdepth, h->commands_outstanding,
-               h->maxQsinceinit, h->max_outstanding, h->maxSG);
-
-        pos += size; len += size;
+       size = sprintf(buffer, "%s: HP %s Controller\n"
+                      "Board ID: 0x%08lx\n"
+                      "Firmware Version: %c%c%c%c\n"
+                      "IRQ: %d\n"
+                      "Logical drives: %d\n"
+                      "Current Q depth: %d\n"
+                      "Current # commands on controller: %d\n"
+                      "Max Q depth since init: %d\n"
+                      "Max # commands on controller since init: %d\n"
+                      "Max SG entries since init: %d\n\n",
+                      h->devname,
+                      h->product_name,
+                      (unsigned long)h->board_id,
+                      h->firm_ver[0], h->firm_ver[1], h->firm_ver[2],
+                      h->firm_ver[3], (unsigned int)h->intr[SIMPLE_MODE_INT],
+                      h->num_luns, h->Qdepth, h->commands_outstanding,
+                      h->maxQsinceinit, h->max_outstanding, h->maxSG);
+
+       pos += size;
+       len += size;
        cciss_proc_tape_report(ctlr, buffer, &pos, &len);
-       for(i=0; i<=h->highest_lun; i++) {
+       for (i = 0; i <= h->highest_lun; i++) {
 
-                drv = &h->drv[i];
+               drv = &h->drv[i];
                if (drv->heads == 0)
                        continue;
 
@@ -305,25 +293,26 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
 
                if (drv->raid_level > 5)
                        drv->raid_level = RAID_UNKNOWN;
-               size = sprintf(buffer+len, "cciss/c%dd%d:"
-                               "\t%4u.%02uGB\tRAID %s\n",
-                               ctlr, i, (int)vol_sz, (int)vol_sz_frac,
-                               raid_label[drv->raid_level]);
-                pos += size; len += size;
-        }
-
-        *eof = 1;
-        *start = buffer+offset;
-        len -= offset;
-        if (len>length)
-                len = length;
+               size = sprintf(buffer + len, "cciss/c%dd%d:"
+                              "\t%4u.%02uGB\tRAID %s\n",
+                              ctlr, i, (int)vol_sz, (int)vol_sz_frac,
+                              raid_label[drv->raid_level]);
+               pos += size;
+               len += size;
+       }
+
+       *eof = 1;
+       *start = buffer + offset;
+       len -= offset;
+       if (len > length)
+               len = length;
        h->busy_configuring = 0;
-        return len;
+       return len;
 }
 
-static int 
-cciss_proc_write(struct file *file, const char __user *buffer, 
-                       unsigned long count, void *data)
+static int
+cciss_proc_write(struct file *file, const char __user *buffer,
+                unsigned long count, void *data)
 {
        unsigned char cmd[80];
        int len;
@@ -332,20 +321,23 @@ cciss_proc_write(struct file *file, const char __user *buffer,
        int rc;
 #endif
 
-       if (count > sizeof(cmd)-1) return -EINVAL;
-       if (copy_from_user(cmd, buffer, count)) return -EFAULT;
+       if (count > sizeof(cmd) - 1)
+               return -EINVAL;
+       if (copy_from_user(cmd, buffer, count))
+               return -EFAULT;
        cmd[count] = '\0';
        len = strlen(cmd);      // above 3 lines ensure safety
-       if (len && cmd[len-1] == '\n')
+       if (len && cmd[len - 1] == '\n')
                cmd[--len] = '\0';
 #      ifdef CONFIG_CISS_SCSI_TAPE
-               if (strcmp("engage scsi", cmd)==0) {
-                       rc = cciss_engage_scsi(h->ctlr);
-                       if (rc != 0) return -rc;
-                       return count;
-               }
-               /* might be nice to have "disengage" too, but it's not 
-                  safely possible. (only 1 module use count, lock issues.) */
+       if (strcmp("engage scsi", cmd) == 0) {
+               rc = cciss_engage_scsi(h->ctlr);
+               if (rc != 0)
+                       return -rc;
+               return count;
+       }
+       /* might be nice to have "disengage" too, but it's not
+          safely possible. (only 1 module use count, lock issues.) */
 #      endif
        return -EINVAL;
 }
@@ -358,116 +350,113 @@ static void __devinit cciss_procinit(int i)
 {
        struct proc_dir_entry *pde;
 
-        if (proc_cciss == NULL) {
-                proc_cciss = proc_mkdir("cciss", proc_root_driver);
-                if (!proc_cciss) 
+       if (proc_cciss == NULL) {
+               proc_cciss = proc_mkdir("cciss", proc_root_driver);
+               if (!proc_cciss)
                        return;
-        }
+       }
 
-       pde = create_proc_read_entry(hba[i]->devname, 
-               S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, 
-               proc_cciss, cciss_proc_get_info, hba[i]);
+       pde = create_proc_read_entry(hba[i]->devname,
+                                    S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH,
+                                    proc_cciss, cciss_proc_get_info, hba[i]);
        pde->write_proc = cciss_proc_write;
 }
-#endif /* CONFIG_PROC_FS */
+#endif                         /* CONFIG_PROC_FS */
 
-/* 
- * For operations that cannot sleep, a command block is allocated at init, 
+/*
+ * For operations that cannot sleep, a command block is allocated at init,
  * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track
- * which ones are free or in use.  For operations that can wait for kmalloc 
- * to possible sleep, this routine can be called with get_from_pool set to 0. 
- * cmd_free() MUST be called with a got_from_pool set to 0 if cmd_alloc was. 
- */ 
-static CommandList_struct * cmd_alloc(ctlr_info_t *h, int get_from_pool)
+ * which ones are free or in use.  For operations that can wait for kmalloc
+ * to possible sleep, this routine can be called with get_from_pool set to 0.
+ * cmd_free() MUST be called with a got_from_pool set to 0 if cmd_alloc was.
+ */
+static CommandList_struct *cmd_alloc(ctlr_info_t *h, int get_from_pool)
 {
        CommandList_struct *c;
-       int i; 
+       int i;
        u64bit temp64;
        dma_addr_t cmd_dma_handle, err_dma_handle;
 
-       if (!get_from_pool)
-       {
-               c = (CommandList_struct *) pci_alloc_consistent(
-                       h->pdev, sizeof(CommandList_struct), &cmd_dma_handle); 
-               if(c==NULL)
-                       return NULL;
+       if (!get_from_pool) {
+               c = (CommandList_struct *) pci_alloc_consistent(h->pdev,
+                       sizeof(CommandList_struct), &cmd_dma_handle);
+               if (c == NULL)
+                       return NULL;
                memset(c, 0, sizeof(CommandList_struct));
 
                c->cmdindex = -1;
 
-               c->err_info = (ErrorInfo_struct *)pci_alloc_consistent(
-                                       h->pdev, sizeof(ErrorInfo_struct), 
-                                       &err_dma_handle);
-       
-               if (c->err_info == NULL)
-               {
-                       pci_free_consistent(h->pdev, 
+               c->err_info = (ErrorInfo_struct *)
+                   pci_alloc_consistent(h->pdev, sizeof(ErrorInfo_struct),
+                           &err_dma_handle);
+
+               if (c->err_info == NULL) {
+                       pci_free_consistent(h->pdev,
                                sizeof(CommandList_struct), c, cmd_dma_handle);
                        return NULL;
                }
                memset(c->err_info, 0, sizeof(ErrorInfo_struct));
-       } else /* get it out of the controllers pool */ 
-       {
-               do {
-                       i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS);
-                        if (i == NR_CMDS)
-                                return NULL;
-                } while(test_and_set_bit(i & (BITS_PER_LONG - 1), h->cmd_pool_bits+(i/BITS_PER_LONG)) != 0);
+       } else {                /* get it out of the controllers pool */
+
+               do {
+                       i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS);
+                       if (i == NR_CMDS)
+                               return NULL;
+               } while (test_and_set_bit
+                        (i & (BITS_PER_LONG - 1),
+                         h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0);
 #ifdef CCISS_DEBUG
                printk(KERN_DEBUG "cciss: using command buffer %d\n", i);
 #endif
-                c = h->cmd_pool + i;
+               c = h->cmd_pool + i;
                memset(c, 0, sizeof(CommandList_struct));
-               cmd_dma_handle = h->cmd_pool_dhandle 
-                                       + i*sizeof(CommandList_struct);
+               cmd_dma_handle = h->cmd_pool_dhandle
+                   + i * sizeof(CommandList_struct);
                c->err_info = h->errinfo_pool + i;
                memset(c->err_info, 0, sizeof(ErrorInfo_struct));
-               err_dma_handle = h->errinfo_pool_dhandle 
-                                       + i*sizeof(ErrorInfo_struct);
-                h->nr_allocs++;
+               err_dma_handle = h->errinfo_pool_dhandle
+                   + i * sizeof(ErrorInfo_struct);
+               h->nr_allocs++;
 
                c->cmdindex = i;
-        }
+       }
 
        c->busaddr = (__u32) cmd_dma_handle;
-       temp64.val = (__u64) err_dma_handle;    
+       temp64.val = (__u64) err_dma_handle;
        c->ErrDesc.Addr.lower = temp64.val32.lower;
        c->ErrDesc.Addr.upper = temp64.val32.upper;
        c->ErrDesc.Len = sizeof(ErrorInfo_struct);
-       
-       c->ctlr = h->ctlr;
-        return c;
-
 
+       c->ctlr = h->ctlr;
+       return c;
 }
 
-/* 
- * Frees a command block that was previously allocated with cmd_alloc(). 
+/*
+ * Frees a command block that was previously allocated with cmd_alloc().
  */
 static void cmd_free(ctlr_info_t *h, CommandList_struct *c, int got_from_pool)
 {
        int i;
        u64bit temp64;
 
-       if( !got_from_pool)
-       { 
+       if (!got_from_pool) {
                temp64.val32.lower = c->ErrDesc.Addr.lower;
                temp64.val32.upper = c->ErrDesc.Addr.upper;
-               pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct), 
-                       c->err_info, (dma_addr_t) temp64.val);
-               pci_free_consistent(h->pdev, sizeof(CommandList_struct), 
-                       c, (dma_addr_t) c->busaddr);
-       } else 
-       {
+               pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct),
+                                   c->err_info, (dma_addr_t) temp64.val);
+               pci_free_consistent(h->pdev, sizeof(CommandList_struct),
+                                   c, (dma_addr_t) c->busaddr);
+       } else {
                i = c - h->cmd_pool;
-               clear_bit(i&(BITS_PER_LONG-1), h->cmd_pool_bits+(i/BITS_PER_LONG));
-                h->nr_frees++;
-        }
+               clear_bit(i & (BITS_PER_LONG - 1),
+                         h->cmd_pool_bits + (i / BITS_PER_LONG));
+               h->nr_frees++;
+       }
 }
 
 static inline ctlr_info_t *get_host(struct gendisk *disk)
 {
-       return disk->queue->queuedata; 
+       return disk->queue->queuedata;
 }
 
 static inline drive_info_struct *get_drv(struct gendisk *disk)
@@ -485,7 +474,7 @@ static int cciss_open(struct inode *inode, struct file *filep)
 
 #ifdef CCISS_DEBUG
        printk(KERN_DEBUG "cciss_open %s\n", inode->i_bdev->bd_disk->disk_name);
-#endif /* CCISS_DEBUG */ 
+#endif                         /* CCISS_DEBUG */
 
        if (host->busy_initializing || drv->busy_configuring)
                return -EBUSY;
@@ -498,10 +487,10 @@ static int cciss_open(struct inode *inode, struct file *filep)
         * for "raw controller".
         */
        if (drv->nr_blocks == 0) {
-               if (iminor(inode) != 0) {       /* not node 0? */
+               if (iminor(inode) != 0) {       /* not node 0? */
                        /* if not node 0 make sure it is a partition = 0 */
                        if (iminor(inode) & 0x0f) {
-                       return -ENXIO;
+                               return -ENXIO;
                                /* if it is, make sure we have a LUN ID */
                        } else if (drv->LunID == 0) {
                                return -ENXIO;
@@ -514,6 +503,7 @@ static int cciss_open(struct inode *inode, struct file *filep)
        host->usage_count++;
        return 0;
 }
+
 /*
  * Close.  Sync first.
  */
@@ -523,8 +513,9 @@ static int cciss_release(struct inode *inode, struct file *filep)
        drive_info_struct *drv = get_drv(inode->i_bdev->bd_disk);
 
 #ifdef CCISS_DEBUG
-       printk(KERN_DEBUG "cciss_release %s\n", inode->i_bdev->bd_disk->disk_name);
-#endif /* CCISS_DEBUG */
+       printk(KERN_DEBUG "cciss_release %s\n",
+              inode->i_bdev->bd_disk->disk_name);
+#endif                         /* CCISS_DEBUG */
 
        drv->usage_count--;
        host->usage_count--;
@@ -542,8 +533,10 @@ static int do_ioctl(struct file *f, unsigned cmd, unsigned long arg)
        return ret;
 }
 
-static int cciss_ioctl32_passthru(struct file *f, unsigned cmd, unsigned long arg);
-static int cciss_ioctl32_big_passthru(struct file *f, unsigned cmd, unsigned long arg);
+static int cciss_ioctl32_passthru(struct file *f, unsigned cmd,
+                                 unsigned long arg);
+static int cciss_ioctl32_big_passthru(struct file *f, unsigned cmd,
+                                     unsigned long arg);
 
 static long cciss_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg)
 {
@@ -575,19 +568,26 @@ static long cciss_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg)
        }
 }
 
-static int cciss_ioctl32_passthru(struct file *f, unsigned cmd, unsigned long arg)
+static int cciss_ioctl32_passthru(struct file *f, unsigned cmd,
+                                 unsigned long arg)
 {
        IOCTL32_Command_struct __user *arg32 =
-               (IOCTL32_Command_struct __user *) arg;
+           (IOCTL32_Command_struct __user *) arg;
        IOCTL_Command_struct arg64;
        IOCTL_Command_struct __user *p = compat_alloc_user_space(sizeof(arg64));
        int err;
        u32 cp;
 
        err = 0;
-       err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info));
-       err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request));
-       err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info));
+       err |=
+           copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
+                          sizeof(arg64.LUN_info));
+       err |=
+           copy_from_user(&arg64.Request, &arg32->Request,
+                          sizeof(arg64.Request));
+       err |=
+           copy_from_user(&arg64.error_info, &arg32->error_info,
+                          sizeof(arg64.error_info));
        err |= get_user(arg64.buf_size, &arg32->buf_size);
        err |= get_user(cp, &arg32->buf);
        arg64.buf = compat_ptr(cp);
@@ -596,28 +596,38 @@ static int cciss_ioctl32_passthru(struct file *f, unsigned cmd, unsigned long ar
        if (err)
                return -EFAULT;
 
-       err = do_ioctl(f, CCISS_PASSTHRU, (unsigned long) p);
+       err = do_ioctl(f, CCISS_PASSTHRU, (unsigned long)p);
        if (err)
                return err;
-       err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info));
+       err |=
+           copy_in_user(&arg32->error_info, &p->error_info,
+                        sizeof(arg32->error_info));
        if (err)
                return -EFAULT;
        return err;
 }
 
-static int cciss_ioctl32_big_passthru(struct file *file, unsigned cmd, unsigned long arg)
+static int cciss_ioctl32_big_passthru(struct file *file, unsigned cmd,
+                                     unsigned long arg)
 {
        BIG_IOCTL32_Command_struct __user *arg32 =
-               (BIG_IOCTL32_Command_struct __user *) arg;
+           (BIG_IOCTL32_Command_struct __user *) arg;
        BIG_IOCTL_Command_struct arg64;
-       BIG_IOCTL_Command_struct __user *p = compat_alloc_user_space(sizeof(arg64));
+       BIG_IOCTL_Command_struct __user *p =
+           compat_alloc_user_space(sizeof(arg64));
        int err;
        u32 cp;
 
        err = 0;
-       err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info));
-       err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request));
-       err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info));
+       err |=
+           copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
+                          sizeof(arg64.LUN_info));
+       err |=
+           copy_from_user(&arg64.Request, &arg32->Request,
+                          sizeof(arg64.Request));
+       err |=
+           copy_from_user(&arg64.error_info, &arg32->error_info,
+                          sizeof(arg64.error_info));
        err |= get_user(arg64.buf_size, &arg32->buf_size);
        err |= get_user(arg64.malloc_size, &arg32->malloc_size);
        err |= get_user(cp, &arg32->buf);
@@ -625,12 +635,14 @@ static int cciss_ioctl32_big_passthru(struct file *file, unsigned cmd, unsigned
        err |= copy_to_user(p, &arg64, sizeof(arg64));
 
        if (err)
-                return -EFAULT;
+               return -EFAULT;
 
-       err = do_ioctl(file, CCISS_BIG_PASSTHRU, (unsigned long) p);
+       err = do_ioctl(file, CCISS_BIG_PASSTHRU, (unsigned long)p);
        if (err)
                return err;
-       err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info));
+       err |=
+           copy_in_user(&arg32->error_info, &p->error_info,
+                        sizeof(arg32->error_info));
        if (err)
                return -EFAULT;
        return err;
@@ -651,10 +663,10 @@ static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 }
 
 /*
- * ioctl 
+ * ioctl
  */
-static int cciss_ioctl(struct inode *inode, struct file *filep, 
-               unsigned int cmd, unsigned long arg)
+static int cciss_ioctl(struct inode *inode, struct file *filep,
+                      unsigned int cmd, unsigned long arg)
 {
        struct block_device *bdev = inode->i_bdev;
        struct gendisk *disk = bdev->bd_disk;
@@ -665,171 +677,193 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
 
 #ifdef CCISS_DEBUG
        printk(KERN_DEBUG "cciss_ioctl: Called with cmd=%x %lx\n", cmd, arg);
-#endif /* CCISS_DEBUG */ 
-       
-       switch(cmd) {
+#endif                         /* CCISS_DEBUG */
+
+       switch (cmd) {
        case CCISS_GETPCIINFO:
-       {
-               cciss_pci_info_struct pciinfo;
-
-               if (!arg) return -EINVAL;
-               pciinfo.domain = pci_domain_nr(host->pdev->bus);
-               pciinfo.bus = host->pdev->bus->number;
-               pciinfo.dev_fn = host->pdev->devfn;
-               pciinfo.board_id = host->board_id;
-               if (copy_to_user(argp, &pciinfo,  sizeof( cciss_pci_info_struct )))
-                       return  -EFAULT;
-               return(0);
-       }       
+               {
+                       cciss_pci_info_struct pciinfo;
+
+                       if (!arg)
+                               return -EINVAL;
+                       pciinfo.domain = pci_domain_nr(host->pdev->bus);
+                       pciinfo.bus = host->pdev->bus->number;
+                       pciinfo.dev_fn = host->pdev->devfn;
+                       pciinfo.board_id = host->board_id;
+                       if (copy_to_user
+                           (argp, &pciinfo, sizeof(cciss_pci_info_struct)))
+                               return -EFAULT;
+                       return 0;
+               }
        case CCISS_GETINTINFO:
-       {
-               cciss_coalint_struct intinfo;
-               if (!arg) return -EINVAL;
-               intinfo.delay = readl(&host->cfgtable->HostWrite.CoalIntDelay);
-               intinfo.count = readl(&host->cfgtable->HostWrite.CoalIntCount);
-               if (copy_to_user(argp, &intinfo, sizeof( cciss_coalint_struct )))
-                       return -EFAULT;
-                return(0);
-        }
+               {
+                       cciss_coalint_struct intinfo;
+                       if (!arg)
+                               return -EINVAL;
+                       intinfo.delay =
+                           readl(&host->cfgtable->HostWrite.CoalIntDelay);
+                       intinfo.count =
+                           readl(&host->cfgtable->HostWrite.CoalIntCount);
+                       if (copy_to_user
+                           (argp, &intinfo, sizeof(cciss_coalint_struct)))
+                               return -EFAULT;
+                       return 0;
+               }
        case CCISS_SETINTINFO:
-        {
-                cciss_coalint_struct intinfo;
-               unsigned long flags;
-               int i;
-
-               if (!arg) return -EINVAL;       
-               if (!capable(CAP_SYS_ADMIN)) return -EPERM;
-               if (copy_from_user(&intinfo, argp, sizeof( cciss_coalint_struct)))
-                       return -EFAULT;
-               if ( (intinfo.delay == 0 ) && (intinfo.count == 0))
-
                {
-//                     printk("cciss_ioctl: delay and count cannot be 0\n");
-                       return( -EINVAL);
+                       cciss_coalint_struct intinfo;
+                       unsigned long flags;
+                       int i;
+
+                       if (!arg)
+                               return -EINVAL;
+                       if (!capable(CAP_SYS_ADMIN))
+                               return -EPERM;
+                       if (copy_from_user
+                           (&intinfo, argp, sizeof(cciss_coalint_struct)))
+                               return -EFAULT;
+                       if ((intinfo.delay == 0) && (intinfo.count == 0))
+                       {
+//                      printk("cciss_ioctl: delay and count cannot be 0\n");
+                               return -EINVAL;
+                       }
+                       spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+                       /* Update the field, and then ring the doorbell */
+                       writel(intinfo.delay,
+                              &(host->cfgtable->HostWrite.CoalIntDelay));
+                       writel(intinfo.count,
+                              &(host->cfgtable->HostWrite.CoalIntCount));
+                       writel(CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);
+
+                       for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
+                               if (!(readl(host->vaddr + SA5_DOORBELL)
+                                     & CFGTBL_ChangeReq))
+                                       break;
+                               /* delay and try again */
+                               udelay(1000);
+                       }
+                       spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+                       if (i >= MAX_IOCTL_CONFIG_WAIT)
+                               return -EAGAIN;
+                       return 0;
                }
-               spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-               /* Update the field, and then ring the doorbell */ 
-               writel( intinfo.delay, 
-                       &(host->cfgtable->HostWrite.CoalIntDelay));
-               writel( intinfo.count, 
-                        &(host->cfgtable->HostWrite.CoalIntCount));
-               writel( CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);
-
-               for(i=0;i<MAX_IOCTL_CONFIG_WAIT;i++) {
-                       if (!(readl(host->vaddr + SA5_DOORBELL) 
-                                       & CFGTBL_ChangeReq))
-                               break;
-                       /* delay and try again */
-                       udelay(1000);
-               }       
-               spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-               if (i >= MAX_IOCTL_CONFIG_WAIT)
-                       return -EAGAIN;
-                return(0);
-        }
        case CCISS_GETNODENAME:
-        {
-                NodeName_type NodeName;
-               int i; 
-
-               if (!arg) return -EINVAL;
-               for(i=0;i<16;i++)
-                       NodeName[i] = readb(&host->cfgtable->ServerName[i]);
-                if (copy_to_user(argp, NodeName, sizeof( NodeName_type)))
-                       return  -EFAULT;
-                return(0);
-        }
+               {
+                       NodeName_type NodeName;
+                       int i;
+
+                       if (!arg)
+                               return -EINVAL;
+                       for (i = 0; i < 16; i++)
+                               NodeName[i] =
+                                   readb(&host->cfgtable->ServerName[i]);
+                       if (copy_to_user(argp, NodeName, sizeof(NodeName_type)))
+                               return -EFAULT;
+                       return 0;
+               }
        case CCISS_SETNODENAME:
-       {
-               NodeName_type NodeName;
-               unsigned long flags;
-               int i;
-
-               if (!arg) return -EINVAL;
-               if (!capable(CAP_SYS_ADMIN)) return -EPERM;
-               
-               if (copy_from_user(NodeName, argp, sizeof( NodeName_type)))
-                       return -EFAULT;
-
-               spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-
-                       /* Update the field, and then ring the doorbell */ 
-               for(i=0;i<16;i++)
-                       writeb( NodeName[i], &host->cfgtable->ServerName[i]);
-                       
-               writel( CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);
-
-               for(i=0;i<MAX_IOCTL_CONFIG_WAIT;i++) {
-                       if (!(readl(host->vaddr + SA5_DOORBELL) 
-                                       & CFGTBL_ChangeReq))
-                               break;
-                       /* delay and try again */
-                       udelay(1000);
-               }       
-               spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-               if (i >= MAX_IOCTL_CONFIG_WAIT)
-                       return -EAGAIN;
-                return(0);
-        }
+               {
+                       NodeName_type NodeName;
+                       unsigned long flags;
+                       int i;
+
+                       if (!arg)
+                               return -EINVAL;
+                       if (!capable(CAP_SYS_ADMIN))
+                               return -EPERM;
+
+                       if (copy_from_user
+                           (NodeName, argp, sizeof(NodeName_type)))
+                               return -EFAULT;
+
+                       spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+
+                       /* Update the field, and then ring the doorbell */
+                       for (i = 0; i < 16; i++)
+                               writeb(NodeName[i],
+                                      &host->cfgtable->ServerName[i]);
+
+                       writel(CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);
+
+                       for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
+                               if (!(readl(host->vaddr + SA5_DOORBELL)
+                                     & CFGTBL_ChangeReq))
+                                       break;
+                               /* delay and try again */
+                               udelay(1000);
+                       }
+                       spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+                       if (i >= MAX_IOCTL_CONFIG_WAIT)
+                               return -EAGAIN;
+                       return 0;
+               }
 
        case CCISS_GETHEARTBEAT:
-        {
-                Heartbeat_type heartbeat;
-
-               if (!arg) return -EINVAL;
-                heartbeat = readl(&host->cfgtable->HeartBeat);
-                if (copy_to_user(argp, &heartbeat, sizeof( Heartbeat_type)))
-                       return -EFAULT;
-                return(0);
-        }
+               {
+                       Heartbeat_type heartbeat;
+
+                       if (!arg)
+                               return -EINVAL;
+                       heartbeat = readl(&host->cfgtable->HeartBeat);
+                       if (copy_to_user
+                           (argp, &heartbeat, sizeof(Heartbeat_type)))
+                               return -EFAULT;
+                       return 0;
+               }
        case CCISS_GETBUSTYPES:
-        {
-                BusTypes_type BusTypes;
-
-               if (!arg) return -EINVAL;
-                BusTypes = readl(&host->cfgtable->BusTypes);
-                if (copy_to_user(argp, &BusTypes, sizeof( BusTypes_type) ))
-                       return  -EFAULT;
-                return(0);
-        }
+               {
+                       BusTypes_type BusTypes;
+
+                       if (!arg)
+                               return -EINVAL;
+                       BusTypes = readl(&host->cfgtable->BusTypes);
+                       if (copy_to_user
+                           (argp, &BusTypes, sizeof(BusTypes_type)))
+                               return -EFAULT;
+                       return 0;
+               }
        case CCISS_GETFIRMVER:
-        {
-               FirmwareVer_type firmware;
+               {
+                       FirmwareVer_type firmware;
 
-               if (!arg) return -EINVAL;
-               memcpy(firmware, host->firm_ver, 4);
+                       if (!arg)
+                               return -EINVAL;
+                       memcpy(firmware, host->firm_ver, 4);
 
-                if (copy_to_user(argp, firmware, sizeof( FirmwareVer_type)))
-                       return -EFAULT;
-                return(0);
-        }
-        case CCISS_GETDRIVVER:
-        {
-               DriverVer_type DriverVer = DRIVER_VERSION;
+                       if (copy_to_user
+                           (argp, firmware, sizeof(FirmwareVer_type)))
+                               return -EFAULT;
+                       return 0;
+               }
+       case CCISS_GETDRIVVER:
+               {
+                       DriverVer_type DriverVer = DRIVER_VERSION;
 
-                if (!arg) return -EINVAL;
+                       if (!arg)
+                               return -EINVAL;
 
-                if (copy_to_user(argp, &DriverVer, sizeof( DriverVer_type) ))
-                       return -EFAULT;
-                return(0);
-        }
+                       if (copy_to_user
+                           (argp, &DriverVer, sizeof(DriverVer_type)))
+                               return -EFAULT;
+                       return 0;
+               }
 
        case CCISS_REVALIDVOLS:
                if (bdev != bdev->bd_contains || drv != host->drv)
                        return -ENXIO;
-                return revalidate_allvol(host);
-
-       case CCISS_GETLUNINFO: {
-               LogvolInfo_struct luninfo;
-               
-               luninfo.LunID = drv->LunID;
-               luninfo.num_opens = drv->usage_count;
-               luninfo.num_parts = 0;
-               if (copy_to_user(argp, &luninfo,
-                               sizeof(LogvolInfo_struct)))
-                       return -EFAULT;
-               return(0);
-       }
+               return revalidate_allvol(host);
+
+       case CCISS_GETLUNINFO:{
+                       LogvolInfo_struct luninfo;
+
+                       luninfo.LunID = drv->LunID;
+                       luninfo.num_opens = drv->usage_count;
+                       luninfo.num_parts = 0;
+                       if (copy_to_user(argp, &luninfo,
+                                        sizeof(LogvolInfo_struct)))
+                               return -EFAULT;
+                       return 0;
+               }
        case CCISS_DEREGDISK:
                return rebuild_lun_table(host, disk);
 
@@ -837,278 +871,284 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
                return rebuild_lun_table(host, NULL);
 
        case CCISS_PASSTHRU:
-       {
-               IOCTL_Command_struct iocommand;
-               CommandList_struct *c;
-               char    *buff = NULL;
-               u64bit  temp64;
-               unsigned long flags;
-               DECLARE_COMPLETION(wait);
-
-               if (!arg) return -EINVAL;
-       
-               if (!capable(CAP_SYS_RAWIO)) return -EPERM;
-
-               if (copy_from_user(&iocommand, argp, sizeof( IOCTL_Command_struct) ))
-                       return -EFAULT;
-               if((iocommand.buf_size < 1) && 
-                               (iocommand.Request.Type.Direction != XFER_NONE))
-               {       
-                       return -EINVAL;
-               } 
-#if 0 /* 'buf_size' member is 16-bits, and always smaller than kmalloc limit */
-               /* Check kmalloc limits */
-               if(iocommand.buf_size > 128000)
-                       return -EINVAL;
-#endif
-               if(iocommand.buf_size > 0)
-               {
-                       buff =  kmalloc(iocommand.buf_size, GFP_KERNEL);
-                       if( buff == NULL) 
-                               return -EFAULT;
-               }
-               if (iocommand.Request.Type.Direction == XFER_WRITE)
-               {
-                       /* Copy the data into the buffer we created */ 
-                       if (copy_from_user(buff, iocommand.buf, iocommand.buf_size))
-                       {
-                               kfree(buff);
-                               return -EFAULT;
-                       }
-               } else {
-                       memset(buff, 0, iocommand.buf_size);
-               }
-               if ((c = cmd_alloc(host , 0)) == NULL)
-               {
-                       kfree(buff);
-                       return -ENOMEM;
-               }
-                       // Fill in the command type 
-               c->cmd_type = CMD_IOCTL_PEND;
-                       // Fill in Command Header 
-               c->Header.ReplyQueue = 0;  // unused in simple mode
-               if( iocommand.buf_size > 0)     // buffer to fill 
                {
-                       c->Header.SGList = 1;
-                       c->Header.SGTotal= 1;
-               } else  // no buffers to fill  
-               {
-                       c->Header.SGList = 0;
-                       c->Header.SGTotal= 0;
-               }
-               c->Header.LUN = iocommand.LUN_info;
-               c->Header.Tag.lower = c->busaddr;  // use the kernel address the cmd block for tag
-               
-               // Fill in Request block 
-               c->Request = iocommand.Request; 
-       
-               // Fill in the scatter gather information
-               if (iocommand.buf_size > 0 ) 
-               {
-                       temp64.val = pci_map_single( host->pdev, buff,
-                                        iocommand.buf_size, 
-                                PCI_DMA_BIDIRECTIONAL);        
-                       c->SG[0].Addr.lower = temp64.val32.lower;
-                       c->SG[0].Addr.upper = temp64.val32.upper;
-                       c->SG[0].Len = iocommand.buf_size;
-                       c->SG[0].Ext = 0;  // we are not chaining
-               }
-               c->waiting = &wait;
+                       IOCTL_Command_struct iocommand;
+                       CommandList_struct *c;
+                       char *buff = NULL;
+                       u64bit temp64;
+                       unsigned long flags;
+                       DECLARE_COMPLETION(wait);
 
-               /* Put the request on the tail of the request queue */
-               spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-               addQ(&host->reqQ, c);
-               host->Qdepth++;
-               start_io(host);
-               spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+                       if (!arg)
+                               return -EINVAL;
 
-               wait_for_completion(&wait);
+                       if (!capable(CAP_SYS_RAWIO))
+                               return -EPERM;
 
-               /* unlock the buffers from DMA */
-               temp64.val32.lower = c->SG[0].Addr.lower;
-                temp64.val32.upper = c->SG[0].Addr.upper;
-                pci_unmap_single( host->pdev, (dma_addr_t) temp64.val,
-                       iocommand.buf_size, PCI_DMA_BIDIRECTIONAL);
+                       if (copy_from_user
+                           (&iocommand, argp, sizeof(IOCTL_Command_struct)))
+                               return -EFAULT;
+                       if ((iocommand.buf_size < 1) &&
+                           (iocommand.Request.Type.Direction != XFER_NONE)) {
+                               return -EINVAL;
+                       }
+#if 0                          /* 'buf_size' member is 16-bits, and always smaller than kmalloc limit */
+                       /* Check kmalloc limits */
+                       if (iocommand.buf_size > 128000)
+                               return -EINVAL;
+#endif
+                       if (iocommand.buf_size > 0) {
+                               buff = kmalloc(iocommand.buf_size, GFP_KERNEL);
+                               if (buff == NULL)
+                                       return -EFAULT;
+                       }
+                       if (iocommand.Request.Type.Direction == XFER_WRITE) {
+                               /* Copy the data into the buffer we created */
+                               if (copy_from_user
+                                   (buff, iocommand.buf, iocommand.buf_size)) {
+                                       kfree(buff);
+                                       return -EFAULT;
+                               }
+                       } else {
+                               memset(buff, 0, iocommand.buf_size);
+                       }
+                       if ((c = cmd_alloc(host, 0)) == NULL) {
+                               kfree(buff);
+                               return -ENOMEM;
+                       }
+                       // Fill in the command type
+                       c->cmd_type = CMD_IOCTL_PEND;
+                       // Fill in Command Header
+                       c->Header.ReplyQueue = 0;       // unused in simple mode
+                       if (iocommand.buf_size > 0)     // buffer to fill
+                       {
+                               c->Header.SGList = 1;
+                               c->Header.SGTotal = 1;
+                       } else  // no buffers to fill
+                       {
+                               c->Header.SGList = 0;
+                               c->Header.SGTotal = 0;
+                       }
+                       c->Header.LUN = iocommand.LUN_info;
+                       c->Header.Tag.lower = c->busaddr;       // use the kernel address the cmd block for tag
 
-               /* Copy the error information out */ 
-               iocommand.error_info = *(c->err_info);
-               if ( copy_to_user(argp, &iocommand, sizeof( IOCTL_Command_struct) ) )
-               {
-                       kfree(buff);
-                       cmd_free(host, c, 0);
-                       return( -EFAULT);       
-               }       
+                       // Fill in Request block
+                       c->Request = iocommand.Request;
 
-               if (iocommand.Request.Type.Direction == XFER_READ)
-                {
-                        /* Copy the data out of the buffer we created */
-                        if (copy_to_user(iocommand.buf, buff, iocommand.buf_size))
-                       {
-                               kfree(buff);
+                       // Fill in the scatter gather information
+                       if (iocommand.buf_size > 0) {
+                               temp64.val = pci_map_single(host->pdev, buff,
+                                       iocommand.buf_size,
+                                       PCI_DMA_BIDIRECTIONAL);
+                               c->SG[0].Addr.lower = temp64.val32.lower;
+                               c->SG[0].Addr.upper = temp64.val32.upper;
+                               c->SG[0].Len = iocommand.buf_size;
+                               c->SG[0].Ext = 0;       // we are not chaining
+                       }
+                       c->waiting = &wait;
+
+                       /* Put the request on the tail of the request queue */
+                       spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+                       addQ(&host->reqQ, c);
+                       host->Qdepth++;
+                       start_io(host);
+                       spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+
+                       wait_for_completion(&wait);
+
+                       /* unlock the buffers from DMA */
+                       temp64.val32.lower = c->SG[0].Addr.lower;
+                       temp64.val32.upper = c->SG[0].Addr.upper;
+                       pci_unmap_single(host->pdev, (dma_addr_t) temp64.val,
+                                        iocommand.buf_size,
+                                        PCI_DMA_BIDIRECTIONAL);
+
+                       /* Copy the error information out */
+                       iocommand.error_info = *(c->err_info);
+                       if (copy_to_user
+                           (argp, &iocommand, sizeof(IOCTL_Command_struct))) {
+                               kfree(buff);
                                cmd_free(host, c, 0);
                                return -EFAULT;
                        }
-                }
-                kfree(buff);
-               cmd_free(host, c, 0);
-                return(0);
-       } 
-       case CCISS_BIG_PASSTHRU: {
-               BIG_IOCTL_Command_struct *ioc;
-               CommandList_struct *c;
-               unsigned char **buff = NULL;
-               int     *buff_size = NULL;
-               u64bit  temp64;
-               unsigned long flags;
-               BYTE sg_used = 0;
-               int status = 0;
-               int i;
-               DECLARE_COMPLETION(wait);
-               __u32   left;
-               __u32   sz;
-               BYTE    __user *data_ptr;
-
-               if (!arg)
-                       return -EINVAL;
-               if (!capable(CAP_SYS_RAWIO))
-                       return -EPERM;
-               ioc = (BIG_IOCTL_Command_struct *) 
-                       kmalloc(sizeof(*ioc), GFP_KERNEL);
-               if (!ioc) {
-                       status = -ENOMEM;
-                       goto cleanup1;
-               }
-               if (copy_from_user(ioc, argp, sizeof(*ioc))) {
-                       status = -EFAULT;
-                       goto cleanup1;
+
+                       if (iocommand.Request.Type.Direction == XFER_READ) {
+                               /* Copy the data out of the buffer we created */
+                               if (copy_to_user
+                                   (iocommand.buf, buff, iocommand.buf_size)) {
+                                       kfree(buff);
+                                       cmd_free(host, c, 0);
+                                       return -EFAULT;
+                               }
+                       }
+                       kfree(buff);
+                       cmd_free(host, c, 0);
+                       return 0;
                }
-               if ((ioc->buf_size < 1) &&
-                       (ioc->Request.Type.Direction != XFER_NONE)) {
+       case CCISS_BIG_PASSTHRU:{
+                       BIG_IOCTL_Command_struct *ioc;
+                       CommandList_struct *c;
+                       unsigned char **buff = NULL;
+                       int *buff_size = NULL;
+                       u64bit temp64;
+                       unsigned long flags;
+                       BYTE sg_used = 0;
+                       int status = 0;
+                       int i;
+                       DECLARE_COMPLETION(wait);
+                       __u32 left;
+                       __u32 sz;
+                       BYTE __user *data_ptr;
+
+                       if (!arg)
+                               return -EINVAL;
+                       if (!capable(CAP_SYS_RAWIO))
+                               return -EPERM;
+                       ioc = (BIG_IOCTL_Command_struct *)
+                           kmalloc(sizeof(*ioc), GFP_KERNEL);
+                       if (!ioc) {
+                               status = -ENOMEM;
+                               goto cleanup1;
+                       }
+                       if (copy_from_user(ioc, argp, sizeof(*ioc))) {
+                               status = -EFAULT;
+                               goto cleanup1;
+                       }
+                       if ((ioc->buf_size < 1) &&
+                           (ioc->Request.Type.Direction != XFER_NONE)) {
                                status = -EINVAL;
                                goto cleanup1;
-               }
-               /* Check kmalloc limits  using all SGs */
-               if (ioc->malloc_size > MAX_KMALLOC_SIZE) {
-                       status = -EINVAL;
-                       goto cleanup1;
-               }
-               if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) {
-                       status = -EINVAL;
-                       goto cleanup1;
-               }
-               buff = kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL);
-               if (!buff) {
-                       status = -ENOMEM;
-                       goto cleanup1;
-               }
-               buff_size = (int *) kmalloc(MAXSGENTRIES * sizeof(int), 
-                                       GFP_KERNEL);
-               if (!buff_size) {
-                       status = -ENOMEM;
-                       goto cleanup1;
-               }
-               left = ioc->buf_size;
-               data_ptr = ioc->buf;
-               while (left) {
-                       sz = (left > ioc->malloc_size) ? ioc->malloc_size : left;
-                       buff_size[sg_used] = sz;
-                       buff[sg_used] = kmalloc(sz, GFP_KERNEL);
-                       if (buff[sg_used] == NULL) {
+                       }
+                       /* Check kmalloc limits  using all SGs */
+                       if (ioc->malloc_size > MAX_KMALLOC_SIZE) {
+                               status = -EINVAL;
+                               goto cleanup1;
+                       }
+                       if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) {
+                               status = -EINVAL;
+                               goto cleanup1;
+                       }
+                       buff =
+                           kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL);
+                       if (!buff) {
                                status = -ENOMEM;
                                goto cleanup1;
                        }
-                       if (ioc->Request.Type.Direction == XFER_WRITE) {
-                               if (copy_from_user(buff[sg_used], data_ptr, sz)) {
+                       buff_size = (int *)kmalloc(MAXSGENTRIES * sizeof(int),
+                                                  GFP_KERNEL);
+                       if (!buff_size) {
+                               status = -ENOMEM;
+                               goto cleanup1;
+                       }
+                       left = ioc->buf_size;
+                       data_ptr = ioc->buf;
+                       while (left) {
+                               sz = (left >
+                                     ioc->malloc_size) ? ioc->
+                                   malloc_size : left;
+                               buff_size[sg_used] = sz;
+                               buff[sg_used] = kmalloc(sz, GFP_KERNEL);
+                               if (buff[sg_used] == NULL) {
                                        status = -ENOMEM;
                                        goto cleanup1;
                                }
+                               if (ioc->Request.Type.Direction == XFER_WRITE) {
+                                       if (copy_from_user
+                                           (buff[sg_used], data_ptr, sz)) {
+                                               status = -ENOMEM;
+                                               goto cleanup1;
+                                       }
+                               } else {
+                                       memset(buff[sg_used], 0, sz);
+                               }
+                               left -= sz;
+                               data_ptr += sz;
+                               sg_used++;
+                       }
+                       if ((c = cmd_alloc(host, 0)) == NULL) {
+                               status = -ENOMEM;
+                               goto cleanup1;
+                       }
+                       c->cmd_type = CMD_IOCTL_PEND;
+                       c->Header.ReplyQueue = 0;
+
+                       if (ioc->buf_size > 0) {
+                               c->Header.SGList = sg_used;
+                               c->Header.SGTotal = sg_used;
                        } else {
-                               memset(buff[sg_used], 0, sz);
+                               c->Header.SGList = 0;
+                               c->Header.SGTotal = 0;
                        }
-                       left -= sz;
-                       data_ptr += sz;
-                       sg_used++;
-               }
-               if ((c = cmd_alloc(host , 0)) == NULL) {
-                       status = -ENOMEM;
-                       goto cleanup1;  
-               }
-               c->cmd_type = CMD_IOCTL_PEND;
-               c->Header.ReplyQueue = 0;
-               
-               if( ioc->buf_size > 0) {
-                       c->Header.SGList = sg_used;
-                       c->Header.SGTotal= sg_used;
-               } else { 
-                       c->Header.SGList = 0;
-                       c->Header.SGTotal= 0;
-               }
-               c->Header.LUN = ioc->LUN_info;
-               c->Header.Tag.lower = c->busaddr;
-               
-               c->Request = ioc->Request;
-               if (ioc->buf_size > 0 ) {
-                       int i;
-                       for(i=0; i<sg_used; i++) {
-                               temp64.val = pci_map_single( host->pdev, buff[i],
-                                       buff_size[i],
+                       c->Header.LUN = ioc->LUN_info;
+                       c->Header.Tag.lower = c->busaddr;
+
+                       c->Request = ioc->Request;
+                       if (ioc->buf_size > 0) {
+                               int i;
+                               for (i = 0; i < sg_used; i++) {
+                                       temp64.val =
+                                           pci_map_single(host->pdev, buff[i],
+                                                   buff_size[i],
+                                                   PCI_DMA_BIDIRECTIONAL);
+                                       c->SG[i].Addr.lower =
+                                           temp64.val32.lower;
+                                       c->SG[i].Addr.upper =
+                                           temp64.val32.upper;
+                                       c->SG[i].Len = buff_size[i];
+                                       c->SG[i].Ext = 0;       /* we are not chaining */
+                               }
+                       }
+                       c->waiting = &wait;
+                       /* Put the request on the tail of the request queue */
+                       spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+                       addQ(&host->reqQ, c);
+                       host->Qdepth++;
+                       start_io(host);
+                       spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+                       wait_for_completion(&wait);
+                       /* unlock the buffers from DMA */
+                       for (i = 0; i < sg_used; i++) {
+                               temp64.val32.lower = c->SG[i].Addr.lower;
+                               temp64.val32.upper = c->SG[i].Addr.upper;
+                               pci_unmap_single(host->pdev,
+                                       (dma_addr_t) temp64.val, buff_size[i],
                                        PCI_DMA_BIDIRECTIONAL);
-                               c->SG[i].Addr.lower = temp64.val32.lower;
-                               c->SG[i].Addr.upper = temp64.val32.upper;
-                               c->SG[i].Len = buff_size[i];
-                               c->SG[i].Ext = 0;  /* we are not chaining */
                        }
-               }
-               c->waiting = &wait;
-               /* Put the request on the tail of the request queue */
-               spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-               addQ(&host->reqQ, c);
-               host->Qdepth++;
-               start_io(host);
-               spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-               wait_for_completion(&wait);
-               /* unlock the buffers from DMA */
-               for(i=0; i<sg_used; i++) {
-                       temp64.val32.lower = c->SG[i].Addr.lower;
-                       temp64.val32.upper = c->SG[i].Addr.upper;
-                       pci_unmap_single( host->pdev, (dma_addr_t) temp64.val,
-                               buff_size[i], PCI_DMA_BIDIRECTIONAL);
-               }
-               /* Copy the error information out */
-               ioc->error_info = *(c->err_info);
-               if (copy_to_user(argp, ioc, sizeof(*ioc))) {
-                       cmd_free(host, c, 0);
-                       status = -EFAULT;
-                       goto cleanup1;
-               }
-               if (ioc->Request.Type.Direction == XFER_READ) {
-                       /* Copy the data out of the buffer we created */
-                       BYTE __user *ptr = ioc->buf;
-                       for(i=0; i< sg_used; i++) {
-                               if (copy_to_user(ptr, buff[i], buff_size[i])) {
-                                       cmd_free(host, c, 0);
-                                       status = -EFAULT;
-                                       goto cleanup1;
+                       /* Copy the error information out */
+                       ioc->error_info = *(c->err_info);
+                       if (copy_to_user(argp, ioc, sizeof(*ioc))) {
+                               cmd_free(host, c, 0);
+                               status = -EFAULT;
+                               goto cleanup1;
+                       }
+                       if (ioc->Request.Type.Direction == XFER_READ) {
+                               /* Copy the data out of the buffer we created */
+                               BYTE __user *ptr = ioc->buf;
+                               for (i = 0; i < sg_used; i++) {
+                                       if (copy_to_user
+                                           (ptr, buff[i], buff_size[i])) {
+                                               cmd_free(host, c, 0);
+                                               status = -EFAULT;
+                                               goto cleanup1;
+                                       }
+                                       ptr += buff_size[i];
                                }
-                               ptr += buff_size[i];
                        }
+                       cmd_free(host, c, 0);
+                       status = 0;
+                     cleanup1:
+                       if (buff) {
+                               for (i = 0; i < sg_used; i++)
+                                       kfree(buff[i]);
+                               kfree(buff);
+                       }
+                       kfree(buff_size);
+                       kfree(ioc);
+                       return status;
                }
-               cmd_free(host, c, 0);
-               status = 0;
-cleanup1:
-               if (buff) {
-                       for(i=0; i<sg_used; i++)
-                               kfree(buff[i]);
-                       kfree(buff);
-               }
-               kfree(buff_size);
-               kfree(ioc);
-               return(status);
-       }
        default:
                return -ENOTTY;
        }
-       
 }
 
 /*
@@ -1119,7 +1159,7 @@ cleanup1:
  *
  * Right now I'm using the getgeometry() function to do this, but this
  * function should probably be finer grained and allow you to revalidate one
- * particualar logical volume (instead of all of them on a particular
+ * particular logical volume (instead of all of them on a particular
  * controller).
  */
 static int revalidate_allvol(ctlr_info_t *host)
@@ -1127,17 +1167,17 @@ static int revalidate_allvol(ctlr_info_t *host)
        int ctlr = host->ctlr, i;
        unsigned long flags;
 
-        spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-        if (host->usage_count > 1) {
-                spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-                printk(KERN_WARNING "cciss: Device busy for volume"
-                        " revalidation (usage=%d)\n", host->usage_count);
-                return -EBUSY;
-        }
-        host->usage_count++;
+       spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+       if (host->usage_count > 1) {
+               spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+               printk(KERN_WARNING "cciss: Device busy for volume"
+                      " revalidation (usage=%d)\n", host->usage_count);
+               return -EBUSY;
+       }
+       host->usage_count++;
        spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
 
-       for(i=0; i< NWD; i++) {
+       for (i = 0; i < NWD; i++) {
                struct gendisk *disk = host->gendisk[i];
                if (disk) {
                        request_queue_t *q = disk->queue;
@@ -1149,22 +1189,22 @@ static int revalidate_allvol(ctlr_info_t *host)
                }
        }
 
-        /*
-         * Set the partition and block size structures for all volumes
-         * on this controller to zero.  We will reread all of this data
-         */
-        memset(host->drv,        0, sizeof(drive_info_struct)
-                                               * CISS_MAX_LUN);
-        /*
-         * Tell the array controller not to give us any interrupts while
-         * we check the new geometry.  Then turn interrupts back on when
-         * we're done.
-         */
-        host->access.set_intr_mask(host, CCISS_INTR_OFF);
-        cciss_getgeometry(ctlr);
-        host->access.set_intr_mask(host, CCISS_INTR_ON);
-
-       /* Loop through each real device */ 
+       /*
+        * Set the partition and block size structures for all volumes
+        * on this controller to zero.  We will reread all of this data
+        */
+       memset(host->drv, 0, sizeof(drive_info_struct)
+              * CISS_MAX_LUN);
+       /*
+        * Tell the array controller not to give us any interrupts while
+        * we check the new geometry.  Then turn interrupts back on when
+        * we're done.
+        */
+       host->access.set_intr_mask(host, CCISS_INTR_OFF);
+       cciss_getgeometry(ctlr);
+       host->access.set_intr_mask(host, CCISS_INTR_ON);
+
+       /* Loop through each real device */
        for (i = 0; i < NWD; i++) {
                struct gendisk *disk = host->gendisk[i];
                drive_info_struct *drv = &(host->drv[i]);
@@ -1176,8 +1216,8 @@ static int revalidate_allvol(ctlr_info_t *host)
                set_capacity(disk, drv->nr_blocks);
                add_disk(disk);
        }
-        host->usage_count--;
-        return 0;
+       host->usage_count--;
+       return 0;
 }
 
 static inline void complete_buffers(struct bio *bio, int status)
@@ -1191,7 +1231,6 @@ static inline void complete_buffers(struct bio *bio, int status)
                bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO);
                bio = xbh;
        }
-
 }
 
 static void cciss_softirq_done(struct request *rq)
@@ -1209,7 +1248,7 @@ static void cciss_softirq_done(struct request *rq)
 
        /* command did not need to be retried */
        /* unmap the DMA mapping for all the scatter gather elements */
-       for(i=0; i<cmd->Header.SGList; i++) {
+       for (i = 0; i < cmd->Header.SGList; i++) {
                temp64.val32.lower = cmd->SG[i].Addr.lower;
                temp64.val32.upper = cmd->SG[i].Addr.upper;
                pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir);
@@ -1219,11 +1258,12 @@ static void cciss_softirq_done(struct request *rq)
 
 #ifdef CCISS_DEBUG
        printk("Done with %p\n", rq);
-#endif /* CCISS_DEBUG */
+#endif                         /* CCISS_DEBUG */
 
+       add_disk_randomness(rq->rq_disk);
        spin_lock_irqsave(&h->lock, flags);
        end_that_request_last(rq, rq->errors);
-       cmd_free(h, cmd,1);
+       cmd_free(h, cmd, 1);
        spin_unlock_irqrestore(&h->lock, flags);
 }
 
@@ -1234,9 +1274,9 @@ static void cciss_softirq_done(struct request *rq)
  * will always be left registered with the kernel since it is also the
  * controller node.  Any changes to disk 0 will show up on the next
  * reboot.
-*/
+ */
 static void cciss_update_drive_info(int ctlr, int drv_index)
-  {
+{
        ctlr_info_t *h = hba[ctlr];
        struct gendisk *disk;
        ReadCapdata_struct *size_buff = NULL;
@@ -1246,13 +1286,13 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
        unsigned long flags = 0;
        int ret = 0;
 
-       /* if the disk already exists then deregister it before proceeding*/
-       if (h->drv[drv_index].raid_level != -1){
+       /* if the disk already exists then deregister it before proceeding */
+       if (h->drv[drv_index].raid_level != -1) {
                spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
                h->drv[drv_index].busy_configuring = 1;
                spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
                ret = deregister_disk(h->gendisk[drv_index],
-                       &h->drv[drv_index], 0);
+                                     &h->drv[drv_index], 0);
                h->drv[drv_index].busy_configuring = 0;
        }
 
@@ -1260,27 +1300,25 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
        if (ret)
                return;
 
-
-       /* Get information about the disk and modify the driver sturcture */
-       size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
-        if (size_buff == NULL)
+       /* Get information about the disk and modify the driver structure */
+       size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
+       if (size_buff == NULL)
                goto mem_msg;
-       inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+       inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
        if (inq_buff == NULL)
                goto mem_msg;
 
        cciss_read_capacity(ctlr, drv_index, size_buff, 1,
-               &total_size, &block_size);
+                           &total_size, &block_size);
        cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size,
-               inq_buff, &h->drv[drv_index]);
+                              inq_buff, &h->drv[drv_index]);
 
        ++h->num_luns;
        disk = h->gendisk[drv_index];
        set_capacity(disk, h->drv[drv_index].nr_blocks);
 
-
        /* if it's the controller it's already added */
-       if (drv_index){
+       if (drv_index) {
                disk->queue = blk_init_queue(do_cciss_request, &h->lock);
 
                /* Set up queue information */
@@ -1300,17 +1338,17 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
                disk->queue->queuedata = hba[ctlr];
 
                blk_queue_hardsect_size(disk->queue,
-                       hba[ctlr]->drv[drv_index].block_size);
+                                       hba[ctlr]->drv[drv_index].block_size);
 
                h->drv[drv_index].queue = disk->queue;
                add_disk(disk);
        }
 
-freeret:
+      freeret:
        kfree(size_buff);
        kfree(inq_buff);
        return;
-mem_msg:
+      mem_msg:
        printk(KERN_ERR "cciss: out of memory\n");
        goto freeret;
 }
@@ -1320,13 +1358,13 @@ mem_msg:
  * where new drives will be added.  If the index to be returned is greater
  * than the highest_lun index for the controller then highest_lun is set
  * to this new index.  If there are no available indexes then -1 is returned.
-*/
+ */
 static int cciss_find_free_drive_index(int ctlr)
 {
        int i;
 
-       for (i=0; i < CISS_MAX_LUN; i++){
-               if (hba[ctlr]->drv[i].raid_level == -1){
+       for (i = 0; i < CISS_MAX_LUN; i++) {
+               if (hba[ctlr]->drv[i].raid_level == -1) {
                        if (i > hba[ctlr]->highest_lun)
                                hba[ctlr]->highest_lun = i;
                        return i;
@@ -1336,7 +1374,7 @@ static int cciss_find_free_drive_index(int ctlr)
 }
 
 /* This function will add and remove logical drives from the Logical
- * drive array of the controller and maintain persistancy of ordering
+ * drive array of the controller and maintain persistency of ordering
  * so that mount points are preserved until the next reboot.  This allows
  * for the removal of logical drives in the middle of the drive array
  * without a re-ordering of those drives.
@@ -1344,7 +1382,7 @@ static int cciss_find_free_drive_index(int ctlr)
  * h           = The controller to perform the operations on
  * del_disk    = The disk to remove if specified.  If the value given
  *               is NULL then no disk is removed.
-*/
+ */
 static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
 {
        int ctlr = h->ctlr;
@@ -1361,12 +1399,12 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
 
        /* Set busy_configuring flag for this operation */
        spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
-       if (h->num_luns >= CISS_MAX_LUN){
+       if (h->num_luns >= CISS_MAX_LUN) {
                spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
                return -EINVAL;
        }
 
-       if (h->busy_configuring){
+       if (h->busy_configuring) {
                spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
                return -EBUSY;
        }
@@ -1376,7 +1414,7 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
         * and update the logical drive table.  If it is not NULL then
         * we will check if the disk is in use or not.
         */
-       if (del_disk != NULL){
+       if (del_disk != NULL) {
                drv = get_drv(del_disk);
                drv->busy_configuring = 1;
                spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
@@ -1394,61 +1432,67 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
                        goto mem_msg;
 
                return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff,
-                               sizeof(ReportLunData_struct), 0, 0, 0,
-                               TYPE_CMD);
-
-               if (return_code == IO_OK){
-                       listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
-                       listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
-                       listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;
-                       listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
-               } else{ /* reading number of logical volumes failed */
+                                             sizeof(ReportLunData_struct), 0,
+                                             0, 0, TYPE_CMD);
+
+               if (return_code == IO_OK) {
+                       listlength |=
+                           (0xff & (unsigned int)(ld_buff->LUNListLength[0]))
+                           << 24;
+                       listlength |=
+                           (0xff & (unsigned int)(ld_buff->LUNListLength[1]))
+                           << 16;
+                       listlength |=
+                           (0xff & (unsigned int)(ld_buff->LUNListLength[2]))
+                           << 8;
+                       listlength |=
+                           0xff & (unsigned int)(ld_buff->LUNListLength[3]);
+               } else {        /* reading number of logical volumes failed */
                        printk(KERN_WARNING "cciss: report logical volume"
-                               " command failed\n");
+                              " command failed\n");
                        listlength = 0;
                        goto freeret;
                }
 
                num_luns = listlength / 8;      /* 8 bytes per entry */
-               if (num_luns > CISS_MAX_LUN){
+               if (num_luns > CISS_MAX_LUN) {
                        num_luns = CISS_MAX_LUN;
                        printk(KERN_WARNING "cciss: more luns configured"
-                               " on controller than can be handled by"
-                               " this driver.\n");
+                              " on controller than can be handled by"
+                              " this driver.\n");
                }
 
                /* Compare controller drive array to drivers drive array.
-               * Check for updates in the drive information and any new drives
-               * on the controller.
-               */
-               for (i=0; i < num_luns; i++){
+                * Check for updates in the drive information and any new drives
+                * on the controller.
+                */
+               for (i = 0; i < num_luns; i++) {
                        int j;
 
                        drv_found = 0;
 
-                       lunid = (0xff &
-                               (unsigned int)(ld_buff->LUN[i][3])) << 24;
-                       lunid |= (0xff &
-                               (unsigned int)(ld_buff->LUN[i][2])) << 16;
-                       lunid |= (0xff &
-                               (unsigned int)(ld_buff->LUN[i][1])) << 8;
-                       lunid |= 0xff &
-                               (unsigned int)(ld_buff->LUN[i][0]);
+                       lunid = (0xff &
+                                (unsigned int)(ld_buff->LUN[i][3])) << 24;
+                       lunid |= (0xff &
+                                 (unsigned int)(ld_buff->LUN[i][2])) << 16;
+                       lunid |= (0xff &
+                                 (unsigned int)(ld_buff->LUN[i][1])) << 8;
+                       lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
 
                        /* Find if the LUN is already in the drive array
                         * of the controller.  If so then update its info
                         * if not is use.  If it does not exist then find
                         * the first free index and add it.
-                       */
-                       for (j=0; j <= h->highest_lun; j++){
-                               if (h->drv[j].LunID == lunid){
+                        */
+                       for (j = 0; j <= h->highest_lun; j++) {
+                               if (h->drv[j].LunID == lunid) {
                                        drv_index = j;
                                        drv_found = 1;
                                }
                        }
 
                        /* check if the drive was found already in the array */
-                       if (!drv_found){
+                       if (!drv_found) {
                                drv_index = cciss_find_free_drive_index(ctlr);
                                if (drv_index == -1)
                                        goto freeret;
@@ -1456,18 +1500,18 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
                        }
                        h->drv[drv_index].LunID = lunid;
                        cciss_update_drive_info(ctlr, drv_index);
-               } /* end for */
-       } /* end else */
+               }               /* end for */
+       }                       /* end else */
 
-freeret:
+      freeret:
        kfree(ld_buff);
        h->busy_configuring = 0;
        /* We return -1 here to tell the ACU that we have registered/updated
         * all of the drives that we can and to keep it from calling us
         * additional times.
-       */
+        */
        return -1;
-mem_msg:
+      mem_msg:
        printk(KERN_ERR "cciss: out of memory\n");
        goto freeret;
 }
@@ -1483,7 +1527,7 @@ mem_msg:
  * clear_all = This flag determines whether or not the disk information
  *             is going to be completely cleared out and the highest_lun
  *             reset.  Sometimes we want to clear out information about
- *             the disk in preperation for re-adding it.  In this case
+ *             the disk in preparation for re-adding it.  In this case
  *             the highest_lun should be left unchanged and the LunID
  *             should not be cleared.
 */
@@ -1496,19 +1540,17 @@ static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
                return -EPERM;
 
        /* make sure logical volume is NOT is use */
-       if(clear_all || (h->gendisk[0] == disk)) {
-       if (drv->usage_count > 1)
-                return -EBUSY;
-       }
-        else
-               if( drv->usage_count > 0 )
-                       return -EBUSY;
+       if (clear_all || (h->gendisk[0] == disk)) {
+               if (drv->usage_count > 1)
+                       return -EBUSY;
+       } else if (drv->usage_count > 0)
+               return -EBUSY;
 
        /* invalidate the devices and deregister the disk.  If it is disk
         * zero do not deregister it but just zero out it's values.  This
         * allows us to delete disk zero but keep the controller registered.
-       */
-       if (h->gendisk[0] != disk){
+        */
+       if (h->gendisk[0] != disk) {
                if (disk) {
                        request_queue_t *q = disk->queue;
                        if (disk->flags & GENHD_FL_UP)
@@ -1530,91 +1572,90 @@ static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
        drv->raid_level = -1;   /* This can be used as a flag variable to
                                 * indicate that this element of the drive
                                 * array is free.
-                               */
-
-       if (clear_all){
-       /* check to see if it was the last disk */
-       if (drv == h->drv + h->highest_lun) {
-               /* if so, find the new hightest lun */
-               int i, newhighest =-1;
-               for(i=0; i<h->highest_lun; i++) {
-                       /* if the disk has size > 0, it is available */
+                                */
+
+       if (clear_all) {
+               /* check to see if it was the last disk */
+               if (drv == h->drv + h->highest_lun) {
+                       /* if so, find the new hightest lun */
+                       int i, newhighest = -1;
+                       for (i = 0; i < h->highest_lun; i++) {
+                               /* if the disk has size > 0, it is available */
                                if (h->drv[i].heads)
-                               newhighest = i;
+                                       newhighest = i;
+                       }
+                       h->highest_lun = newhighest;
                }
-               h->highest_lun = newhighest;
-       }
 
-       drv->LunID = 0;
+               drv->LunID = 0;
        }
-       return(0);
+       return 0;
 }
 
-static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
-       size_t size,
-       unsigned int use_unit_num, /* 0: address the controller,
-                                     1: address logical volume log_unit,
-                                     2: periph device address is scsi3addr */
-       unsigned int log_unit, __u8 page_code, unsigned char *scsi3addr,
-       int cmd_type)
+static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num,     /* 0: address the controller,
+                                                                                                                          1: address logical volume log_unit,
+                                                                                                                          2: periph device address is scsi3addr */
+                   unsigned int log_unit, __u8 page_code,
+                   unsigned char *scsi3addr, int cmd_type)
 {
-       ctlr_info_t *h= hba[ctlr];
+       ctlr_info_t *h = hba[ctlr];
        u64bit buff_dma_handle;
        int status = IO_OK;
 
        c->cmd_type = CMD_IOCTL_PEND;
        c->Header.ReplyQueue = 0;
-       ifbuff != NULL) {
+       if (buff != NULL) {
                c->Header.SGList = 1;
-               c->Header.SGTotal= 1;
+               c->Header.SGTotal = 1;
        } else {
                c->Header.SGList = 0;
-                c->Header.SGTotal= 0;
+               c->Header.SGTotal = 0;
        }
        c->Header.Tag.lower = c->busaddr;
 
        c->Request.Type.Type = cmd_type;
        if (cmd_type == TYPE_CMD) {
-               switch(cmd) {
-               case  CISS_INQUIRY:
+               switch (cmd) {
+               case CISS_INQUIRY:
                        /* If the logical unit number is 0 then, this is going
-                       to controller so It's a physical command
-                       mode = 0 target = 0.  So we have nothing to write.
-                       otherwise, if use_unit_num == 1,
-                       mode = 1(volume set addressing) target = LUNID
-                       otherwise, if use_unit_num == 2,
-                       mode = 0(periph dev addr) target = scsi3addr */
+                          to controller so It's a physical command
+                          mode = 0 target = 0.  So we have nothing to write.
+                          otherwise, if use_unit_num == 1,
+                          mode = 1(volume set addressing) target = LUNID
+                          otherwise, if use_unit_num == 2,
+                          mode = 0(periph dev addr) target = scsi3addr */
                        if (use_unit_num == 1) {
-                               c->Header.LUN.LogDev.VolId=
-                                       h->drv[log_unit].LunID;
-                               c->Header.LUN.LogDev.Mode = 1;
+                               c->Header.LUN.LogDev.VolId =
+                                   h->drv[log_unit].LunID;
+                               c->Header.LUN.LogDev.Mode = 1;
                        } else if (use_unit_num == 2) {
-                               memcpy(c->Header.LUN.LunAddrBytes,scsi3addr,8);
+                               memcpy(c->Header.LUN.LunAddrBytes, scsi3addr,
+                                      8);
                                c->Header.LUN.LogDev.Mode = 0;
                        }
                        /* are we trying to read a vital product page */
-                       if(page_code != 0) {
+                       if (page_code != 0) {
                                c->Request.CDB[1] = 0x01;
                                c->Request.CDB[2] = page_code;
                        }
                        c->Request.CDBLen = 6;
-                       c->Request.Type.Attribute = ATTR_SIMPLE;  
+                       c->Request.Type.Attribute = ATTR_SIMPLE;
                        c->Request.Type.Direction = XFER_READ;
                        c->Request.Timeout = 0;
-                       c->Request.CDB[0] =  CISS_INQUIRY;
-                       c->Request.CDB[4] = size  & 0xFF;  
-               break;
+                       c->Request.CDB[0] = CISS_INQUIRY;
+                       c->Request.CDB[4] = size & 0xFF;
+                       break;
                case CISS_REPORT_LOG:
                case CISS_REPORT_PHYS:
-                        /* Talking to controller so It's a physical command
+                       /* Talking to controller so It's a physical command
                           mode = 00 target = 0.  Nothing to write.
-                        */
+                        */
                        c->Request.CDBLen = 12;
                        c->Request.Type.Attribute = ATTR_SIMPLE;
                        c->Request.Type.Direction = XFER_READ;
                        c->Request.Timeout = 0;
                        c->Request.CDB[0] = cmd;
-                       c->Request.CDB[6] = (size >> 24) & 0xFF;  //MSB
+                       c->Request.CDB[6] = (size >> 24) & 0xFF;        //MSB
                        c->Request.CDB[7] = (size >> 16) & 0xFF;
                        c->Request.CDB[8] = (size >> 8) & 0xFF;
                        c->Request.CDB[9] = size & 0xFF;
@@ -1628,7 +1669,7 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
                        c->Request.Type.Direction = XFER_READ;
                        c->Request.Timeout = 0;
                        c->Request.CDB[0] = cmd;
-               break;
+                       break;
                case CCISS_CACHE_FLUSH:
                        c->Request.CDBLen = 12;
                        c->Request.Type.Attribute = ATTR_SIMPLE;
@@ -1636,32 +1677,32 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
                        c->Request.Timeout = 0;
                        c->Request.CDB[0] = BMIC_WRITE;
                        c->Request.CDB[6] = BMIC_CACHE_FLUSH;
-               break;
+                       break;
                default:
                        printk(KERN_WARNING
-                               "cciss%d:  Unknown Command 0x%c\n", ctlr, cmd);
-                       return(IO_ERROR);
+                              "cciss%d:  Unknown Command 0x%c\n", ctlr, cmd);
+                       return IO_ERROR;
                }
        } else if (cmd_type == TYPE_MSG) {
                switch (cmd) {
-               case 0: /* ABORT message */
+               case 0: /* ABORT message */
                        c->Request.CDBLen = 12;
                        c->Request.Type.Attribute = ATTR_SIMPLE;
                        c->Request.Type.Direction = XFER_WRITE;
                        c->Request.Timeout = 0;
-                       c->Request.CDB[0] = cmd; /* abort */
-                       c->Request.CDB[1] = 0;   /* abort a command */
+                       c->Request.CDB[0] = cmd;        /* abort */
+                       c->Request.CDB[1] = 0;  /* abort a command */
                        /* buff contains the tag of the command to abort */
                        memcpy(&c->Request.CDB[4], buff, 8);
                        break;
-               case 1: /* RESET message */
+               case 1: /* RESET message */
                        c->Request.CDBLen = 12;
                        c->Request.Type.Attribute = ATTR_SIMPLE;
                        c->Request.Type.Direction = XFER_WRITE;
                        c->Request.Timeout = 0;
                        memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
-                       c->Request.CDB[0] = cmd;  /* reset */
-                       c->Request.CDB[1] = 0x04; /* reset a LUN */
+                       c->Request.CDB[0] = cmd;        /* reset */
+                       c->Request.CDB[1] = 0x04;       /* reset a LUN */
                case 3: /* No-Op message */
                        c->Request.CDBLen = 1;
                        c->Request.Type.Attribute = ATTR_SIMPLE;
@@ -1671,168 +1712,164 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
                        break;
                default:
                        printk(KERN_WARNING
-                               "cciss%d: unknown message type %d\n",
-                               ctlr, cmd);
+                              "cciss%d: unknown message type %d\n", ctlr, cmd);
                        return IO_ERROR;
                }
        } else {
                printk(KERN_WARNING
-                       "cciss%d: unknown command type %d\n", ctlr, cmd_type);
+                      "cciss%d: unknown command type %d\n", ctlr, cmd_type);
                return IO_ERROR;
        }
        /* Fill in the scatter gather information */
        if (size > 0) {
                buff_dma_handle.val = (__u64) pci_map_single(h->pdev,
-                       buff, size, PCI_DMA_BIDIRECTIONAL);
+                                                            buff, size,
+                                                            PCI_DMA_BIDIRECTIONAL);
                c->SG[0].Addr.lower = buff_dma_handle.val32.lower;
                c->SG[0].Addr.upper = buff_dma_handle.val32.upper;
                c->SG[0].Len = size;
-               c->SG[0].Ext = 0;  /* we are not chaining */
+               c->SG[0].Ext = 0;       /* we are not chaining */
        }
        return status;
 }
-static int sendcmd_withirq(__u8        cmd,
-       int     ctlr,
-       void    *buff,
-       size_t  size,
-       unsigned int use_unit_num,
-       unsigned int log_unit,
-       __u8    page_code,
-       int cmd_type)
+
+static int sendcmd_withirq(__u8 cmd,
+                          int ctlr,
+                          void *buff,
+                          size_t size,
+                          unsigned int use_unit_num,
+                          unsigned int log_unit, __u8 page_code, int cmd_type)
 {
        ctlr_info_t *h = hba[ctlr];
        CommandList_struct *c;
-       u64bit  buff_dma_handle;
+       u64bit buff_dma_handle;
        unsigned long flags;
        int return_status;
        DECLARE_COMPLETION(wait);
-       
-       if ((c = cmd_alloc(h , 0)) == NULL)
+
+       if ((c = cmd_alloc(h, 0)) == NULL)
                return -ENOMEM;
        return_status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num,
-               log_unit, page_code, NULL, cmd_type);
+                                log_unit, page_code, NULL, cmd_type);
        if (return_status != IO_OK) {
                cmd_free(h, c, 0);
                return return_status;
        }
-resend_cmd2:
+      resend_cmd2:
        c->waiting = &wait;
-       
+
        /* Put the request on the tail of the queue and send it */
        spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
        addQ(&h->reqQ, c);
        h->Qdepth++;
        start_io(h);
        spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-       
+
        wait_for_completion(&wait);
 
-       if(c->err_info->CommandStatus != 0) 
-       { /* an error has occurred */ 
-               switch(c->err_info->CommandStatus)
-               {
-                       case CMD_TARGET_STATUS:
-                               printk(KERN_WARNING "cciss: cmd %p has "
-                                       " completed with errors\n", c);
-                               if( c->err_info->ScsiStatus)
-                               {
-                                       printk(KERN_WARNING "cciss: cmd %p "
-                                       "has SCSI Status = %x\n",
-                                               c,  
-                                               c->err_info->ScsiStatus);
-                               }
+       if (c->err_info->CommandStatus != 0) {  /* an error has occurred */
+               switch (c->err_info->CommandStatus) {
+               case CMD_TARGET_STATUS:
+                       printk(KERN_WARNING "cciss: cmd %p has "
+                              " completed with errors\n", c);
+                       if (c->err_info->ScsiStatus) {
+                               printk(KERN_WARNING "cciss: cmd %p "
+                                      "has SCSI Status = %x\n",
+                                      c, c->err_info->ScsiStatus);
+                       }
 
                        break;
-                       case CMD_DATA_UNDERRUN:
-                       case CMD_DATA_OVERRUN:
+               case CMD_DATA_UNDERRUN:
+               case CMD_DATA_OVERRUN:
                        /* expected for inquire and report lun commands */
                        break;
-                       case CMD_INVALID:
-                               printk(KERN_WARNING "cciss: Cmd %p is "
-                                       "reported invalid\n", c);
-                               return_status = IO_ERROR;
+               case CMD_INVALID:
+                       printk(KERN_WARNING "cciss: Cmd %p is "
+                              "reported invalid\n", c);
+                       return_status = IO_ERROR;
                        break;
-                       case CMD_PROTOCOL_ERR:
-                                printk(KERN_WARNING "cciss: cmd %p has "
-                                       "protocol error \n", c);
-                                return_status = IO_ERROR;
-                        break;
-case CMD_HARDWARE_ERR:
-                                printk(KERN_WARNING "cciss: cmd %p had " 
-                                        " hardware error\n", c);
-                                return_status = IO_ERROR;
-                        break;
-                       case CMD_CONNECTION_LOST:
-                               printk(KERN_WARNING "cciss: cmd %p had "
-                                       "connection lost\n", c);
-                               return_status = IO_ERROR;
+               case CMD_PROTOCOL_ERR:
+                       printk(KERN_WARNING "cciss: cmd %p has "
+                              "protocol error \n", c);
+                       return_status = IO_ERROR;
                        break;
-                       case CMD_ABORTED:
-                               printk(KERN_WARNING "cciss: cmd %p was "
-                                       "aborted\n", c);
-                               return_status = IO_ERROR;
+               case CMD_HARDWARE_ERR:
+                       printk(KERN_WARNING "cciss: cmd %p had "
+                              " hardware error\n", c);
+                       return_status = IO_ERROR;
                        break;
-                       case CMD_ABORT_FAILED:
-                               printk(KERN_WARNING "cciss: cmd %p reports "
-                                       "abort failed\n", c);
-                               return_status = IO_ERROR;
+               case CMD_CONNECTION_LOST:
+                       printk(KERN_WARNING "cciss: cmd %p had "
+                              "connection lost\n", c);
+                       return_status = IO_ERROR;
                        break;
-                       case CMD_UNSOLICITED_ABORT:
-                               printk(KERN_WARNING 
-                                       "cciss%d: unsolicited abort %p\n",
-                                       ctlr, c);
-                               if (c->retry_count < MAX_CMD_RETRIES) {
-                                       printk(KERN_WARNING 
-                                               "cciss%d: retrying %p\n", 
-                                               ctlr, c);
-                                       c->retry_count++;
-                                       /* erase the old error information */
-                                       memset(c->err_info, 0,
-                                               sizeof(ErrorInfo_struct));
-                                       return_status = IO_OK;
-                                       INIT_COMPLETION(wait);
-                                       goto resend_cmd2;
-                               }
-                               return_status = IO_ERROR;
+               case CMD_ABORTED:
+                       printk(KERN_WARNING "cciss: cmd %p was "
+                              "aborted\n", c);
+                       return_status = IO_ERROR;
+                       break;
+               case CMD_ABORT_FAILED:
+                       printk(KERN_WARNING "cciss: cmd %p reports "
+                              "abort failed\n", c);
+                       return_status = IO_ERROR;
                        break;
-                       default:
-                               printk(KERN_WARNING "cciss: cmd %p returned "
-                                       "unknown status %x\n", c, 
-                                               c->err_info->CommandStatus); 
-                               return_status = IO_ERROR;
+               case CMD_UNSOLICITED_ABORT:
+                       printk(KERN_WARNING
+                              "cciss%d: unsolicited abort %p\n", ctlr, c);
+                       if (c->retry_count < MAX_CMD_RETRIES) {
+                               printk(KERN_WARNING
+                                      "cciss%d: retrying %p\n", ctlr, c);
+                               c->retry_count++;
+                               /* erase the old error information */
+                               memset(c->err_info, 0,
+                                      sizeof(ErrorInfo_struct));
+                               return_status = IO_OK;
+                               INIT_COMPLETION(wait);
+                               goto resend_cmd2;
+                       }
+                       return_status = IO_ERROR;
+                       break;
+               default:
+                       printk(KERN_WARNING "cciss: cmd %p returned "
+                              "unknown status %x\n", c,
+                              c->err_info->CommandStatus);
+                       return_status = IO_ERROR;
                }
-       }       
+       }
        /* unlock the buffers from DMA */
        buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
        buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
-       pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val,
-                       c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
+       pci_unmap_single(h->pdev, (dma_addr_t) buff_dma_handle.val,
+                        c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
        cmd_free(h, c, 0);
-        return(return_status);
-
+       return return_status;
 }
+
 static void cciss_geometry_inquiry(int ctlr, int logvol,
-                       int withirq, unsigned int total_size,
-                       unsigned int block_size, InquiryData_struct *inq_buff,
-                       drive_info_struct *drv)
+                                  int withirq, unsigned int total_size,
+                                  unsigned int block_size,
+                                  InquiryData_struct *inq_buff,
+                                  drive_info_struct *drv)
 {
        int return_code;
        memset(inq_buff, 0, sizeof(InquiryData_struct));
        if (withirq)
                return_code = sendcmd_withirq(CISS_INQUIRY, ctlr,
-                       inq_buff, sizeof(*inq_buff), 1, logvol ,0xC1, TYPE_CMD);
+                                             inq_buff, sizeof(*inq_buff), 1,
+                                             logvol, 0xC1, TYPE_CMD);
        else
                return_code = sendcmd(CISS_INQUIRY, ctlr, inq_buff,
-                       sizeof(*inq_buff), 1, logvol ,0xC1, NULL, TYPE_CMD);
+                                     sizeof(*inq_buff), 1, logvol, 0xC1, NULL,
+                                     TYPE_CMD);
        if (return_code == IO_OK) {
-               if(inq_buff->data_byte[8] == 0xFF) {
+               if (inq_buff->data_byte[8] == 0xFF) {
                        printk(KERN_WARNING
-                               "cciss: reading geometry failed, volume "
-                               "does not support reading geometry\n");
+                              "cciss: reading geometry failed, volume "
+                              "does not support reading geometry\n");
                        drv->block_size = block_size;
                        drv->nr_blocks = total_size;
                        drv->heads = 255;
-                       drv->sectors = 32; // Sectors per track
+                       drv->sectors = 32;      // Sectors per track
                        drv->cylinders = total_size / 255 / 32;
                } else {
                        unsigned int t;
@@ -1846,37 +1883,42 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
                        drv->raid_level = inq_buff->data_byte[8];
                        t = drv->heads * drv->sectors;
                        if (t > 1) {
-                               drv->cylinders = total_size/t;
+                               drv->cylinders = total_size / t;
                        }
                }
-       } else { /* Get geometry failed */
+       } else {                /* Get geometry failed */
                printk(KERN_WARNING "cciss: reading geometry failed\n");
        }
        printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d\n\n",
-               drv->heads, drv->sectors, drv->cylinders);
+              drv->heads, drv->sectors, drv->cylinders);
 }
+
 static void
 cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
-               int withirq, unsigned int *total_size, unsigned int *block_size)
+                   int withirq, unsigned int *total_size,
+                   unsigned int *block_size)
 {
        int return_code;
        memset(buf, 0, sizeof(*buf));
        if (withirq)
                return_code = sendcmd_withirq(CCISS_READ_CAPACITY,
-                       ctlr, buf, sizeof(*buf), 1, logvol, 0, TYPE_CMD);
+                                             ctlr, buf, sizeof(*buf), 1,
+                                             logvol, 0, TYPE_CMD);
        else
                return_code = sendcmd(CCISS_READ_CAPACITY,
-                       ctlr, buf, sizeof(*buf), 1, logvol, 0, NULL, TYPE_CMD);
+                                     ctlr, buf, sizeof(*buf), 1, logvol, 0,
+                                     NULL, TYPE_CMD);
        if (return_code == IO_OK) {
-               *total_size = be32_to_cpu(*((__be32 *) &buf->total_size[0]))+1;
-               *block_size = be32_to_cpu(*((__be32 *) &buf->block_size[0]));
-       } else { /* read capacity command failed */
+               *total_size =
+                   be32_to_cpu(*((__be32 *) & buf->total_size[0])) + 1;
+               *block_size = be32_to_cpu(*((__be32 *) & buf->block_size[0]));
+       } else {                /* read capacity command failed */
                printk(KERN_WARNING "cciss: read capacity failed\n");
                *total_size = 0;
                *block_size = BLOCK_SIZE;
        }
        printk(KERN_INFO "      blocks= %u block_size= %d\n",
-               *total_size, *block_size);
+              *total_size, *block_size);
        return;
 }
 
@@ -1885,38 +1927,38 @@ static int cciss_revalidate(struct gendisk *disk)
        ctlr_info_t *h = get_host(disk);
        drive_info_struct *drv = get_drv(disk);
        int logvol;
-       int FOUND=0;
+       int FOUND = 0;
        unsigned int block_size;
        unsigned int total_size;
        ReadCapdata_struct *size_buff = NULL;
        InquiryData_struct *inq_buff = NULL;
 
-       for(logvol=0; logvol < CISS_MAX_LUN; logvol++)
-       {
-               if(h->drv[logvol].LunID == drv->LunID) {
-                       FOUND=1;
+       for (logvol = 0; logvol < CISS_MAX_LUN; logvol++) {
+               if (h->drv[logvol].LunID == drv->LunID) {
+                       FOUND = 1;
                        break;
                }
        }
 
-       if (!FOUND) return 1;
+       if (!FOUND)
+               return 1;
 
-       size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
-        if (size_buff == NULL)
-        {
-                printk(KERN_WARNING "cciss: out of memory\n");
-                return 1;
-        }
-       inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
-        if (inq_buff == NULL)
-        {
-                printk(KERN_WARNING "cciss: out of memory\n");
+       size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
+       if (size_buff == NULL) {
+               printk(KERN_WARNING "cciss: out of memory\n");
+               return 1;
+       }
+       inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
+       if (inq_buff == NULL) {
+               printk(KERN_WARNING "cciss: out of memory\n");
                kfree(size_buff);
-                return 1;
-        }
+               return 1;
+       }
 
-       cciss_read_capacity(h->ctlr, logvol, size_buff, 1, &total_size, &block_size);
-       cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size, inq_buff, drv);
+       cciss_read_capacity(h->ctlr, logvol, size_buff, 1, &total_size,
+                           &block_size);
+       cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size,
+                              inq_buff, drv);
 
        blk_queue_hardsect_size(drv->queue, drv->block_size);
        set_capacity(disk, drv->nr_blocks);
@@ -1943,7 +1985,7 @@ static unsigned long pollcomplete(int ctlr)
                if (done == FIFO_EMPTY)
                        schedule_timeout_uninterruptible(1);
                else
-                       return (done);
+                       return done;
        }
        /* Invalid address to tell caller we ran out of time */
        return 1;
@@ -1952,28 +1994,28 @@ static unsigned long pollcomplete(int ctlr)
 static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete)
 {
        /* We get in here if sendcmd() is polling for completions
-          and gets some command back that it wasn't expecting -- 
-          something other than that which it just sent down.  
-          Ordinarily, that shouldn't happen, but it can happen when 
+          and gets some command back that it wasn't expecting --
+          something other than that which it just sent down.
+          Ordinarily, that shouldn't happen, but it can happen when
           the scsi tape stuff gets into error handling mode, and
-          starts using sendcmd() to try to abort commands and 
+          starts using sendcmd() to try to abort commands and
           reset tape drives.  In that case, sendcmd may pick up
           completions of commands that were sent to logical drives
-          through the block i/o system, or cciss ioctls completing, etc. 
+          through the block i/o system, or cciss ioctls completing, etc.
           In that case, we need to save those completions for later
           processing by the interrupt handler.
-       */
+        */
 
 #ifdef CONFIG_CISS_SCSI_TAPE
-       struct sendcmd_reject_list *srl = &hba[ctlr]->scsi_rejects;     
+       struct sendcmd_reject_list *srl = &hba[ctlr]->scsi_rejects;
 
        /* If it's not the scsi tape stuff doing error handling, (abort */
        /* or reset) then we don't expect anything weird. */
        if (cmd != CCISS_RESET_MSG && cmd != CCISS_ABORT_MSG) {
 #endif
-               printk( KERN_WARNING "cciss cciss%d: SendCmd "
-                     "Invalid command list address returned! (%lx)\n",
-                       ctlr, complete);
+               printk(KERN_WARNING "cciss cciss%d: SendCmd "
+                      "Invalid command list address returned! (%lx)\n",
+                      ctlr, complete);
                /* not much we can do. */
 #ifdef CONFIG_CISS_SCSI_TAPE
                return 1;
@@ -1984,7 +2026,7 @@ static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete)
        if (srl->ncompletions >= (NR_CMDS + 2)) {
                /* Uh oh.  No room to save it for later... */
                printk(KERN_WARNING "cciss%d: Sendcmd: Invalid command addr, "
-                       "reject list overflow, command lost!\n", ctlr);
+                      "reject list overflow, command lost!\n", ctlr);
                return 1;
        }
        /* Save it for later */
@@ -1995,340 +2037,327 @@ static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete)
 }
 
 /*
- * Send a command to the controller, and wait for it to complete.  
- * Only used at init time. 
+ * Send a command to the controller, and wait for it to complete.
+ * Only used at init time.
  */
-static int sendcmd(
-       __u8    cmd,
-       int     ctlr,
-       void    *buff,
-       size_t  size,
-       unsigned int use_unit_num, /* 0: address the controller,
-                                     1: address logical volume log_unit, 
-                                     2: periph device address is scsi3addr */
-       unsigned int log_unit,
-       __u8    page_code,
-       unsigned char *scsi3addr,
-       int cmd_type)
+static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num,     /* 0: address the controller,
+                                                                                                  1: address logical volume log_unit,
+                                                                                                  2: periph device address is scsi3addr */
+                  unsigned int log_unit,
+                  __u8 page_code, unsigned char *scsi3addr, int cmd_type)
 {
        CommandList_struct *c;
        int i;
        unsigned long complete;
-       ctlr_info_t *info_p= hba[ctlr];
+       ctlr_info_t *info_p = hba[ctlr];
        u64bit buff_dma_handle;
        int status, done = 0;
 
        if ((c = cmd_alloc(info_p, 1)) == NULL) {
                printk(KERN_WARNING "cciss: unable to get memory");
-               return(IO_ERROR);
+               return IO_ERROR;
        }
        status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num,
-               log_unit, page_code, scsi3addr, cmd_type);
+                         log_unit, page_code, scsi3addr, cmd_type);
        if (status != IO_OK) {
                cmd_free(info_p, c, 1);
                return status;
        }
-resend_cmd1:
+      resend_cmd1:
        /*
-         * Disable interrupt
-         */
+        * Disable interrupt
+        */
 #ifdef CCISS_DEBUG
        printk(KERN_DEBUG "cciss: turning intr off\n");
-#endif /* CCISS_DEBUG */ 
-        info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF);
-       
+#endif                         /* CCISS_DEBUG */
+       info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF);
+
        /* Make sure there is room in the command FIFO */
-        /* Actually it should be completely empty at this time */
+       /* Actually it should be completely empty at this time */
        /* unless we are in here doing error handling for the scsi */
        /* tape side of the driver. */
-        for (i = 200000; i > 0; i--) 
-       {
+       for (i = 200000; i > 0; i--) {
                /* if fifo isn't full go */
-                if (!(info_p->access.fifo_full(info_p))) 
-               {
-                       
-                        break;
-                }
-                udelay(10);
-                printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full,"
-                        " waiting!\n", ctlr);
-        }
-        /*
-         * Send the cmd
-         */
-        info_p->access.submit_command(info_p, c);
+               if (!(info_p->access.fifo_full(info_p))) {
+
+                       break;
+               }
+               udelay(10);
+               printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full,"
+                      " waiting!\n", ctlr);
+       }
+       /*
+        * Send the cmd
+        */
+       info_p->access.submit_command(info_p, c);
        done = 0;
        do {
                complete = pollcomplete(ctlr);
 
 #ifdef CCISS_DEBUG
                printk(KERN_DEBUG "cciss: command completed\n");
-#endif /* CCISS_DEBUG */
+#endif                         /* CCISS_DEBUG */
 
                if (complete == 1) {
-                       printk( KERN_WARNING
-                               "cciss cciss%d: SendCmd Timeout out, "
-                               "No command list address returned!\n",
-                               ctlr);
+                       printk(KERN_WARNING
+                              "cciss cciss%d: SendCmd Timeout out, "
+                              "No command list address returned!\n", ctlr);
                        status = IO_ERROR;
                        done = 1;
                        break;
                }
 
                /* This will need to change for direct lookup completions */
-               if ( (complete & CISS_ERROR_BIT)
-                    && (complete & ~CISS_ERROR_BIT) == c->busaddr)
-                    {
-                       /* if data overrun or underun on Report command 
-                               ignore it 
-                       */
+               if ((complete & CISS_ERROR_BIT)
+                   && (complete & ~CISS_ERROR_BIT) == c->busaddr) {
+                       /* if data overrun or underun on Report command
+                          ignore it
+                        */
                        if (((c->Request.CDB[0] == CISS_REPORT_LOG) ||
                             (c->Request.CDB[0] == CISS_REPORT_PHYS) ||
                             (c->Request.CDB[0] == CISS_INQUIRY)) &&
-                               ((c->err_info->CommandStatus == 
-                                       CMD_DATA_OVERRUN) || 
-                                (c->err_info->CommandStatus == 
-                                       CMD_DATA_UNDERRUN)
-                               ))
-                       {
+                           ((c->err_info->CommandStatus ==
+                             CMD_DATA_OVERRUN) ||
+                            (c->err_info->CommandStatus == CMD_DATA_UNDERRUN)
+                           )) {
                                complete = c->busaddr;
                        } else {
                                if (c->err_info->CommandStatus ==
-                                               CMD_UNSOLICITED_ABORT) {
+                                   CMD_UNSOLICITED_ABORT) {
                                        printk(KERN_WARNING "cciss%d: "
-                                               "unsolicited abort %p\n",
-                                               ctlr, c);
+                                              "unsolicited abort %p\n",
+                                              ctlr, c);
                                        if (c->retry_count < MAX_CMD_RETRIES) {
                                                printk(KERN_WARNING
-                                                  "cciss%d: retrying %p\n",
-                                                  ctlr, c);
+                                                      "cciss%d: retrying %p\n",
+                                                      ctlr, c);
                                                c->retry_count++;
                                                /* erase the old error */
                                                /* information */
                                                memset(c->err_info, 0,
-                                                  sizeof(ErrorInfo_struct));
+                                                      sizeof
+                                                      (ErrorInfo_struct));
                                                goto resend_cmd1;
                                        } else {
                                                printk(KERN_WARNING
-                                                  "cciss%d: retried %p too "
-                                                  "many times\n", ctlr, c);
+                                                      "cciss%d: retried %p too "
+                                                      "many times\n", ctlr, c);
                                                status = IO_ERROR;
                                                goto cleanup1;
                                        }
-                               } else if (c->err_info->CommandStatus == CMD_UNABORTABLE) {
-                                       printk(KERN_WARNING "cciss%d: command could not be aborted.\n", ctlr);
+                               } else if (c->err_info->CommandStatus ==
+                                          CMD_UNABORTABLE) {
+                                       printk(KERN_WARNING
+                                              "cciss%d: command could not be aborted.\n",
+                                              ctlr);
                                        status = IO_ERROR;
                                        goto cleanup1;
                                }
                                printk(KERN_WARNING "ciss ciss%d: sendcmd"
-                               " Error %x \n", ctlr, 
-                                       c->err_info->CommandStatus); 
+                                      " Error %x \n", ctlr,
+                                      c->err_info->CommandStatus);
                                printk(KERN_WARNING "ciss ciss%d: sendcmd"
-                               " offensive info\n"
-                               "  size %x\n   num %x   value %x\n", ctlr,
-                                 c->err_info->MoreErrInfo.Invalid_Cmd.offense_size,
-                                 c->err_info->MoreErrInfo.Invalid_Cmd.offense_num,
-                                 c->err_info->MoreErrInfo.Invalid_Cmd.offense_value);
+                                      " offensive info\n"
+                                      "  size %x\n   num %x   value %x\n",
+                                      ctlr,
+                                      c->err_info->MoreErrInfo.Invalid_Cmd.
+                                      offense_size,
+                                      c->err_info->MoreErrInfo.Invalid_Cmd.
+                                      offense_num,
+                                      c->err_info->MoreErrInfo.Invalid_Cmd.
+                                      offense_value);
                                status = IO_ERROR;
                                goto cleanup1;
                        }
                }
                /* This will need changing for direct lookup completions */
-                if (complete != c->busaddr) {
+               if (complete != c->busaddr) {
                        if (add_sendcmd_reject(cmd, ctlr, complete) != 0) {
-                               BUG(); /* we are pretty much hosed if we get here. */
+                               BUG();  /* we are pretty much hosed if we get here. */
                        }
                        continue;
-                } else
+               } else
                        done = 1;
-        } while (!done);
-               
-cleanup1:      
+       } while (!done);
+
+      cleanup1:
        /* unlock the data buffer from DMA */
        buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
        buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
        pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
-                               c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
+                        c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
 #ifdef CONFIG_CISS_SCSI_TAPE
        /* if we saved some commands for later, process them now. */
        if (info_p->scsi_rejects.ncompletions > 0)
                do_cciss_intr(0, info_p, NULL);
 #endif
        cmd_free(info_p, c, 1);
-       return (status);
-} 
+       return status;
+}
+
 /*
  * Map (physical) PCI mem into (virtual) kernel space
  */
 static void __iomem *remap_pci_mem(ulong base, ulong size)
 {
-        ulong page_base        = ((ulong) base) & PAGE_MASK;
-        ulong page_offs        = ((ulong) base) - page_base;
-        void __iomem *page_remapped = ioremap(page_base, page_offs+size);
+       ulong page_base = ((ulong) base) & PAGE_MASK;
+       ulong page_offs = ((ulong) base) - page_base;
+       void __iomem *page_remapped = ioremap(page_base, page_offs + size);
 
-        return page_remapped ? (page_remapped + page_offs) : NULL;
+       return page_remapped ? (page_remapped + page_offs) : NULL;
 }
 
-/* 
- * Takes jobs of the Q and sends them to the hardware, then puts it on 
- * the Q to wait for completion. 
- */ 
-static void start_io( ctlr_info_t *h)
+/*
+ * Takes jobs of the Q and sends them to the hardware, then puts it on
+ * the Q to wait for completion.
+ */
+static void start_io(ctlr_info_t *h)
 {
        CommandList_struct *c;
-       
-       while(( c = h->reqQ) != NULL )
-       {
+
+       while ((c = h->reqQ) != NULL) {
                /* can't do anything if fifo is full */
                if ((h->access.fifo_full(h))) {
                        printk(KERN_WARNING "cciss: fifo full\n");
                        break;
                }
 
-               /* Get the first entry from the Request Q */ 
+               /* Get the first entry from the Request Q */
                removeQ(&(h->reqQ), c);
                h->Qdepth--;
-       
-               /* Tell the controller execute command */ 
+
+               /* Tell the controller execute command */
                h->access.submit_command(h, c);
-               
-               /* Put job onto the completed Q */ 
-               addQ (&(h->cmpQ), c); 
+
+               /* Put job onto the completed Q */
+               addQ(&(h->cmpQ), c);
        }
 }
+
 /* Assumes that CCISS_LOCK(h->ctlr) is held. */
 /* Zeros out the error record and then resends the command back */
 /* to the controller */
-static inline void resend_cciss_cmd( ctlr_info_t *h, CommandList_struct *c)
+static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c)
 {
        /* erase the old error information */
        memset(c->err_info, 0, sizeof(ErrorInfo_struct));
 
        /* add it to software queue and then send it to the controller */
-       addQ(&(h->reqQ),c);
+       addQ(&(h->reqQ), c);
        h->Qdepth++;
-       if(h->Qdepth > h->maxQsinceinit)
+       if (h->Qdepth > h->maxQsinceinit)
                h->maxQsinceinit = h->Qdepth;
 
        start_io(h);
 }
 
-/* checks the status of the job and calls complete buffers to mark all 
+/* checks the status of the job and calls complete buffers to mark all
  * buffers for the completed job. Note that this function does not need
  * to hold the hba/queue lock.
- */ 
-static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd,
-               int timeout)
+ */
+static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
+                                   int timeout)
 {
        int status = 1;
        int retry_cmd = 0;
-               
+
        if (timeout)
-               status = 0; 
+               status = 0;
 
-       if(cmd->err_info->CommandStatus != 0) 
-       { /* an error has occurred */ 
-               switch(cmd->err_info->CommandStatus)
-               {
+       if (cmd->err_info->CommandStatus != 0) {        /* an error has occurred */
+               switch (cmd->err_info->CommandStatus) {
                        unsigned char sense_key;
-                       case CMD_TARGET_STATUS:
-                               status = 0;
-                       
-                               if( cmd->err_info->ScsiStatus == 0x02)
-                               {
-                                       printk(KERN_WARNING "cciss: cmd %p "
-                                               "has CHECK CONDITION "
-                                               " byte 2 = 0x%x\n", cmd,
-                                               cmd->err_info->SenseInfo[2]
-                                       );
-                                       /* check the sense key */
-                                       sense_key = 0xf & 
-                                               cmd->err_info->SenseInfo[2];
-                                       /* no status or recovered error */
-                                       if((sense_key == 0x0) ||
-                                           (sense_key == 0x1))
-                                       {
-                                                       status = 1;
-                                       }
-                               } else
-                               {
-                                       printk(KERN_WARNING "cciss: cmd %p "
-                                                "has SCSI Status 0x%x\n",
-                                               cmd, cmd->err_info->ScsiStatus);
+               case CMD_TARGET_STATUS:
+                       status = 0;
+
+                       if (cmd->err_info->ScsiStatus == 0x02) {
+                               printk(KERN_WARNING "cciss: cmd %p "
+                                      "has CHECK CONDITION "
+                                      " byte 2 = 0x%x\n", cmd,
+                                      cmd->err_info->SenseInfo[2]
+                                   );
+                               /* check the sense key */
+                               sense_key = 0xf & cmd->err_info->SenseInfo[2];
+                               /* no status or recovered error */
+                               if ((sense_key == 0x0) || (sense_key == 0x1)) {
+                                       status = 1;
                                }
+                       } else {
+                               printk(KERN_WARNING "cciss: cmd %p "
+                                      "has SCSI Status 0x%x\n",
+                                      cmd, cmd->err_info->ScsiStatus);
+                       }
                        break;
-                       case CMD_DATA_UNDERRUN:
-                               printk(KERN_WARNING "cciss: cmd %p has"
-                                       " completed with data underrun "
-                                       "reported\n", cmd);
+               case CMD_DATA_UNDERRUN:
+                       printk(KERN_WARNING "cciss: cmd %p has"
+                              " completed with data underrun "
+                              "reported\n", cmd);
                        break;
-                       case CMD_DATA_OVERRUN:
-                               printk(KERN_WARNING "cciss: cmd %p has"
-                                       " completed with data overrun "
-                                       "reported\n", cmd);
+               case CMD_DATA_OVERRUN:
+                       printk(KERN_WARNING "cciss: cmd %p has"
+                              " completed with data overrun "
+                              "reported\n", cmd);
                        break;
-                       case CMD_INVALID:
-                               printk(KERN_WARNING "cciss: cmd %p is "
-                                       "reported invalid\n", cmd);
-                               status = 0;
+               case CMD_INVALID:
+                       printk(KERN_WARNING "cciss: cmd %p is "
+                              "reported invalid\n", cmd);
+                       status = 0;
                        break;
-                       case CMD_PROTOCOL_ERR:
-                                printk(KERN_WARNING "cciss: cmd %p has "
-                                       "protocol error \n", cmd);
-                                status = 0;
-                        break;
-                       case CMD_HARDWARE_ERR:
-                                printk(KERN_WARNING "cciss: cmd %p had " 
-                                        " hardware error\n", cmd);
-                                status = 0;
-                        break;
-                       case CMD_CONNECTION_LOST:
-                               printk(KERN_WARNING "cciss: cmd %p had "
-                                       "connection lost\n", cmd);
-                               status=0;
+               case CMD_PROTOCOL_ERR:
+                       printk(KERN_WARNING "cciss: cmd %p has "
+                              "protocol error \n", cmd);
+                       status = 0;
                        break;
-                       case CMD_ABORTED:
-                               printk(KERN_WARNING "cciss: cmd %p was "
-                                       "aborted\n", cmd);
-                               status=0;
+               case CMD_HARDWARE_ERR:
+                       printk(KERN_WARNING "cciss: cmd %p had "
+                              " hardware error\n", cmd);
+                       status = 0;
                        break;
-                       case CMD_ABORT_FAILED:
-                               printk(KERN_WARNING "cciss: cmd %p reports "
-                                       "abort failed\n", cmd);
-                               status=0;
+               case CMD_CONNECTION_LOST:
+                       printk(KERN_WARNING "cciss: cmd %p had "
+                              "connection lost\n", cmd);
+                       status = 0;
                        break;
-                       case CMD_UNSOLICITED_ABORT:
-                               printk(KERN_WARNING "cciss%d: unsolicited "
-                                       "abort %p\n", h->ctlr, cmd);
-                               if (cmd->retry_count < MAX_CMD_RETRIES) {
-                                       retry_cmd=1;
-                                       printk(KERN_WARNING
-                                               "cciss%d: retrying %p\n",
-                                               h->ctlr, cmd);
-                                       cmd->retry_count++;
-                               } else
-                                       printk(KERN_WARNING
-                                               "cciss%d: %p retried too "
-                                               "many times\n", h->ctlr, cmd);
-                               status=0;
+               case CMD_ABORTED:
+                       printk(KERN_WARNING "cciss: cmd %p was "
+                              "aborted\n", cmd);
+                       status = 0;
+                       break;
+               case CMD_ABORT_FAILED:
+                       printk(KERN_WARNING "cciss: cmd %p reports "
+                              "abort failed\n", cmd);
+                       status = 0;
+                       break;
+               case CMD_UNSOLICITED_ABORT:
+                       printk(KERN_WARNING "cciss%d: unsolicited "
+                              "abort %p\n", h->ctlr, cmd);
+                       if (cmd->retry_count < MAX_CMD_RETRIES) {
+                               retry_cmd = 1;
+                               printk(KERN_WARNING
+                                      "cciss%d: retrying %p\n", h->ctlr, cmd);
+                               cmd->retry_count++;
+                       } else
+                               printk(KERN_WARNING
+                                      "cciss%d: %p retried too "
+                                      "many times\n", h->ctlr, cmd);
+                       status = 0;
                        break;
-                       case CMD_TIMEOUT:
-                               printk(KERN_WARNING "cciss: cmd %p timedout\n",
-                                       cmd);
-                               status=0;
+               case CMD_TIMEOUT:
+                       printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd);
+                       status = 0;
                        break;
-                       default:
-                               printk(KERN_WARNING "cciss: cmd %p returned "
-                                       "unknown status %x\n", cmd, 
-                                               cmd->err_info->CommandStatus); 
-                               status=0;
+               default:
+                       printk(KERN_WARNING "cciss: cmd %p returned "
+                              "unknown status %x\n", cmd,
+                              cmd->err_info->CommandStatus);
+                       status = 0;
                }
        }
        /* We need to return this command */
-       if(retry_cmd) {
-               resend_cciss_cmd(h,cmd);
+       if (retry_cmd) {
+               resend_cciss_cmd(h, cmd);
                return;
-       }       
+       }
 
        cmd->rq->completion_data = cmd;
        cmd->rq->errors = status;
@@ -2336,12 +2365,12 @@ static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd,
        blk_complete_request(cmd->rq);
 }
 
-/* 
- * Get a request and submit it to the controller. 
+/*
+ * Get a request and submit it to the controller.
  */
 static void do_cciss_request(request_queue_t *q)
 {
-       ctlr_info_t *h= q->queuedata; 
+       ctlr_info_t *h = q->queuedata;
        CommandList_struct *c;
        int start_blk, seg;
        struct request *creq;
@@ -2352,18 +2381,18 @@ static void do_cciss_request(request_queue_t *q)
 
        /* We call start_io here in case there is a command waiting on the
         * queue that has not been sent.
-       */
+        */
        if (blk_queue_plugged(q))
                goto startio;
 
-queue:
+      queue:
        creq = elv_next_request(q);
        if (!creq)
                goto startio;
 
        BUG_ON(creq->nr_phys_segments > MAXSGENTRIES);
 
-       if (( c = cmd_alloc(h, 1)) == NULL)
+       if ((c = cmd_alloc(h, 1)) == NULL)
                goto full;
 
        blkdev_dequeue_request(creq);
@@ -2372,81 +2401,82 @@ queue:
 
        c->cmd_type = CMD_RWREQ;
        c->rq = creq;
-       
-       /* fill in the request */ 
+
+       /* fill in the request */
        drv = creq->rq_disk->private_data;
-       c->Header.ReplyQueue = 0;  // unused in simple mode
+       c->Header.ReplyQueue = 0;       // unused in simple mode
        /* got command from pool, so use the command block index instead */
        /* for direct lookups. */
        /* The first 2 bits are reserved for controller error reporting. */
        c->Header.Tag.lower = (c->cmdindex << 3);
-       c->Header.Tag.lower |= 0x04; /* flag for direct lookup. */
-       c->Header.LUN.LogDev.VolId= drv->LunID;
+       c->Header.Tag.lower |= 0x04;    /* flag for direct lookup. */
+       c->Header.LUN.LogDev.VolId = drv->LunID;
        c->Header.LUN.LogDev.Mode = 1;
-       c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
-       c->Request.Type.Type =  TYPE_CMD; // It is a command. 
-       c->Request.Type.Attribute = ATTR_SIMPLE; 
-       c->Request.Type.Direction = 
-               (rq_data_dir(creq) == READ) ? XFER_READ: XFER_WRITE; 
-       c->Request.Timeout = 0; // Don't time out       
-       c->Request.CDB[0] = (rq_data_dir(creq) == READ) ? CCISS_READ : CCISS_WRITE;
+       c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
+       c->Request.Type.Type = TYPE_CMD;        // It is a command.
+       c->Request.Type.Attribute = ATTR_SIMPLE;
+       c->Request.Type.Direction =
+           (rq_data_dir(creq) == READ) ? XFER_READ : XFER_WRITE;
+       c->Request.Timeout = 0; // Don't time out
+       c->Request.CDB[0] =
+           (rq_data_dir(creq) == READ) ? CCISS_READ : CCISS_WRITE;
        start_blk = creq->sector;
 #ifdef CCISS_DEBUG
-       printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n",(int) creq->sector,
-               (int) creq->nr_sectors);        
-#endif /* CCISS_DEBUG */
+       printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n", (int)creq->sector,
+              (int)creq->nr_sectors);
+#endif                         /* CCISS_DEBUG */
 
        seg = blk_rq_map_sg(q, creq, tmp_sg);
 
-       /* get the DMA records for the setup */ 
+       /* get the DMA records for the setup */
        if (c->Request.Type.Direction == XFER_READ)
                dir = PCI_DMA_FROMDEVICE;
        else
                dir = PCI_DMA_TODEVICE;
 
-       for (i=0; i<seg; i++)
-       {
+       for (i = 0; i < seg; i++) {
                c->SG[i].Len = tmp_sg[i].length;
                temp64.val = (__u64) pci_map_page(h->pdev, tmp_sg[i].page,
-                                         tmp_sg[i].offset, tmp_sg[i].length,
-                                         dir);
+                                                 tmp_sg[i].offset,
+                                                 tmp_sg[i].length, dir);
                c->SG[i].Addr.lower = temp64.val32.lower;
-                c->SG[i].Addr.upper = temp64.val32.upper;
-                c->SG[i].Ext = 0;  // we are not chaining
+               c->SG[i].Addr.upper = temp64.val32.upper;
+               c->SG[i].Ext = 0;       // we are not chaining
        }
-       /* track how many SG entries we are using */ 
-       ifseg > h->maxSG)
-               h->maxSG = seg; 
+       /* track how many SG entries we are using */
+       if (seg > h->maxSG)
+               h->maxSG = seg;
 
 #ifdef CCISS_DEBUG
-       printk(KERN_DEBUG "cciss: Submitting %d sectors in %d segments\n", creq->nr_sectors, seg);
-#endif /* CCISS_DEBUG */
+       printk(KERN_DEBUG "cciss: Submitting %d sectors in %d segments\n",
+              creq->nr_sectors, seg);
+#endif                         /* CCISS_DEBUG */
 
        c->Header.SGList = c->Header.SGTotal = seg;
-       c->Request.CDB[1]= 0;
-       c->Request.CDB[2]= (start_blk >> 24) & 0xff;    //MSB
-       c->Request.CDB[3]= (start_blk >> 16) & 0xff;
-       c->Request.CDB[4]= (start_blk >>  8) & 0xff;
-       c->Request.CDB[5]= start_blk & 0xff;
-       c->Request.CDB[6]= 0; // (sect >> 24) & 0xff; MSB
-       c->Request.CDB[7]= (creq->nr_sectors >>  8) & 0xff; 
-       c->Request.CDB[8]= creq->nr_sectors & 0xff; 
+       c->Request.CDB[1] = 0;
+       c->Request.CDB[2] = (start_blk >> 24) & 0xff;   //MSB
+       c->Request.CDB[3] = (start_blk >> 16) & 0xff;
+       c->Request.CDB[4] = (start_blk >> 8) & 0xff;
+       c->Request.CDB[5] = start_blk & 0xff;
+       c->Request.CDB[6] = 0;  // (sect >> 24) & 0xff; MSB
+       c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff;
+       c->Request.CDB[8] = creq->nr_sectors & 0xff;
        c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
 
        spin_lock_irq(q->queue_lock);
 
-       addQ(&(h->reqQ),c);
+       addQ(&(h->reqQ), c);
        h->Qdepth++;
-       if(h->Qdepth > h->maxQsinceinit)
-               h->maxQsinceinit = h->Qdepth; 
+       if (h->Qdepth > h->maxQsinceinit)
+               h->maxQsinceinit = h->Qdepth;
 
        goto queue;
-full:
+      full:
        blk_stop_queue(q);
-startio:
+      startio:
        /* We will already have the driver lock here so not need
         * to lock it.
-       */
+        */
        start_io(h);
 }
 
@@ -2473,7 +2503,7 @@ static inline unsigned long get_next_completion(ctlr_info_t *h)
 static inline int interrupt_pending(ctlr_info_t *h)
 {
 #ifdef CONFIG_CISS_SCSI_TAPE
-       return ( h->access.intr_pending(h) 
+       return (h->access.intr_pending(h)
                || (h->scsi_rejects.ncompletions > 0));
 #else
        return h->access.intr_pending(h);
@@ -2483,11 +2513,11 @@ static inline int interrupt_pending(ctlr_info_t *h)
 static inline long interrupt_not_for_us(ctlr_info_t *h)
 {
 #ifdef CONFIG_CISS_SCSI_TAPE
-       return (((h->access.intr_pending(h) == 0) || 
-                (h->interrupts_enabled == 0)) 
-             && (h->scsi_rejects.ncompletions == 0));
+       return (((h->access.intr_pending(h) == 0) ||
+                (h->interrupts_enabled == 0))
+               && (h->scsi_rejects.ncompletions == 0));
 #else
-       return (((h->access.intr_pending(h) == 0) || 
+       return (((h->access.intr_pending(h) == 0) ||
                 (h->interrupts_enabled == 0)));
 #endif
 }
@@ -2509,12 +2539,14 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
         */
        spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
        while (interrupt_pending(h)) {
-               while((a = get_next_completion(h)) != FIFO_EMPTY) {
+               while ((a = get_next_completion(h)) != FIFO_EMPTY) {
                        a1 = a;
                        if ((a & 0x04)) {
                                a2 = (a >> 3);
                                if (a2 >= NR_CMDS) {
-                                       printk(KERN_WARNING "cciss: controller cciss%d failed, stopping.\n", h->ctlr);
+                                       printk(KERN_WARNING
+                                              "cciss: controller cciss%d failed, stopping.\n",
+                                              h->ctlr);
                                        fail_all_cmds(h->ctlr);
                                        return IRQ_HANDLED;
                                }
@@ -2523,22 +2555,24 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
                                a = c->busaddr;
 
                        } else {
-                       a &= ~3;
+                               a &= ~3;
                                if ((c = h->cmpQ) == NULL) {
-                                       printk(KERN_WARNING "cciss: Completion of %08x ignored\n", a1);
-                               continue;       
-                       } 
-                       while(c->busaddr != a) {
-                               c = c->next;
-                               if (c == h->cmpQ) 
-                                       break;
-                       }
+                                       printk(KERN_WARNING
+                                              "cciss: Completion of %08x ignored\n",
+                                              a1);
+                                       continue;
+                               }
+                               while (c->busaddr != a) {
+                                       c = c->next;
+                                       if (c == h->cmpQ)
+                                               break;
+                               }
                        }
                        /*
                         * If we've found the command, take it off the
                         * completion Q and free it
                         */
-                        if (c->busaddr == a) {
+                       if (c->busaddr == a) {
                                removeQ(&h->cmpQ, c);
                                if (c->cmd_type == CMD_RWREQ) {
                                        complete_command(h, c, 0);
@@ -2554,130 +2588,118 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
                }
        }
 
-       /* check to see if we have maxed out the number of commands that can
-        * be placed on the queue.  If so then exit.  We do this check here
-        * in case the interrupt we serviced was from an ioctl and did not
-        * free any new commands.
+       /* check to see if we have maxed out the number of commands that can
+        * be placed on the queue.  If so then exit.  We do this check here
+        * in case the interrupt we serviced was from an ioctl and did not
+        * free any new commands.
+        */
+       if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
+               goto cleanup;
+
+       /* We have room on the queue for more commands.  Now we need to queue
+        * them up.  We will also keep track of the next queue to run so
+        * that every queue gets a chance to be started first.
         */
-       if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
-               goto cleanup;
-
-       /* We have room on the queue for more commands.  Now we need to queue
-        * them up.  We will also keep track of the next queue to run so
-        * that every queue gets a chance to be started first.
-       */
-       for (j=0; j < h->highest_lun + 1; j++){
+       for (j = 0; j < h->highest_lun + 1; j++) {
                int curr_queue = (start_queue + j) % (h->highest_lun + 1);
-               /* make sure the disk has been added and the drive is real
-                * because this can be called from the middle of init_one.
-               */
-               if(!(h->drv[curr_queue].queue) ||
-                                  !(h->drv[curr_queue].heads))
-                       continue;
-               blk_start_queue(h->gendisk[curr_queue]->queue);
-
-               /* check to see if we have maxed out the number of commands
-                * that can be placed on the queue.
-               */
-               if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
-               {
-                       if (curr_queue == start_queue){
-                               h->next_to_run = (start_queue + 1) % (h->highest_lun + 1);
-                               goto cleanup;
-                       } else {
-                               h->next_to_run = curr_queue;
-                               goto cleanup;
-       }
-               } else {
+               /* make sure the disk has been added and the drive is real
+                * because this can be called from the middle of init_one.
+                */
+               if (!(h->drv[curr_queue].queue) || !(h->drv[curr_queue].heads))
+                       continue;
+               blk_start_queue(h->gendisk[curr_queue]->queue);
+
+               /* check to see if we have maxed out the number of commands
+                * that can be placed on the queue.
+                */
+               if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS) {
+                       if (curr_queue == start_queue) {
+                               h->next_to_run =
+                                   (start_queue + 1) % (h->highest_lun + 1);
+                               goto cleanup;
+                       } else {
+                               h->next_to_run = curr_queue;
+                               goto cleanup;
+                       }
+               } else {
                        curr_queue = (curr_queue + 1) % (h->highest_lun + 1);
-               }
-       }
+               }
+       }
 
-cleanup:
+      cleanup:
        spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
        return IRQ_HANDLED;
 }
-/* 
- *  We cannot read the structure directly, for portablity we must use 
+
+/*
+ *  We cannot read the structure directly, for portability we must use
  *   the io functions.
- *   This is for debug only. 
+ *   This is for debug only.
  */
 #ifdef CCISS_DEBUG
-static void print_cfg_table( CfgTable_struct *tb)
+static void print_cfg_table(CfgTable_struct *tb)
 {
        int i;
        char temp_name[17];
 
        printk("Controller Configuration information\n");
        printk("------------------------------------\n");
-       for(i=0;i<4;i++)
+       for (i = 0; i < 4; i++)
                temp_name[i] = readb(&(tb->Signature[i]));
-       temp_name[4]='\0';
-       printk("   Signature = %s\n", temp_name); 
+       temp_name[4] = '\0';
+       printk("   Signature = %s\n", temp_name);
        printk("   Spec Number = %d\n", readl(&(tb->SpecValence)));
-       printk("   Transport methods supported = 0x%x\n", 
-                               readl(&(tb-> TransportSupport)));
-       printk("   Transport methods active = 0x%x\n", 
-                               readl(&(tb->TransportActive)));
-       printk("   Requested transport Method = 0x%x\n", 
-                       readl(&(tb->HostWrite.TransportRequest)));
-       printk("   Coalese Interrupt Delay = 0x%x\n", 
-                       readl(&(tb->HostWrite.CoalIntDelay)));
-       printk("   Coalese Interrupt Count = 0x%x\n", 
-                       readl(&(tb->HostWrite.CoalIntCount)));
-       printk("   Max outstanding commands = 0x%d\n", 
-                       readl(&(tb->CmdsOutMax)));
-       printk("   Bus Types = 0x%x\n", readl(&(tb-> BusTypes)));
-       for(i=0;i<16;i++)
+       printk("   Transport methods supported = 0x%x\n",
+              readl(&(tb->TransportSupport)));
+       printk("   Transport methods active = 0x%x\n",
+              readl(&(tb->TransportActive)));
+       printk("   Requested transport Method = 0x%x\n",
+              readl(&(tb->HostWrite.TransportRequest)));
+       printk("   Coalesce Interrupt Delay = 0x%x\n",
+              readl(&(tb->HostWrite.CoalIntDelay)));
+       printk("   Coalesce Interrupt Count = 0x%x\n",
+              readl(&(tb->HostWrite.CoalIntCount)));
+       printk("   Max outstanding commands = 0x%d\n",
+              readl(&(tb->CmdsOutMax)));
+       printk("   Bus Types = 0x%x\n", readl(&(tb->BusTypes)));
+       for (i = 0; i < 16; i++)
                temp_name[i] = readb(&(tb->ServerName[i]));
        temp_name[16] = '\0';
        printk("   Server Name = %s\n", temp_name);
-       printk("   Heartbeat Counter = 0x%x\n\n\n", 
-                       readl(&(tb->HeartBeat)));
-}
-#endif /* CCISS_DEBUG */ 
-
-static void release_io_mem(ctlr_info_t *c)
-{
-       /* if IO mem was not protected do nothing */
-       if( c->io_mem_addr == 0)
-               return;
-       release_region(c->io_mem_addr, c->io_mem_length);
-       c->io_mem_addr = 0;
-       c->io_mem_length = 0;
+       printk("   Heartbeat Counter = 0x%x\n\n\n", readl(&(tb->HeartBeat)));
 }
+#endif                         /* CCISS_DEBUG */
 
-static int find_PCI_BAR_index(struct pci_dev *pdev,
-                               unsigned long pci_bar_addr)
+static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
 {
        int i, offset, mem_type, bar_type;
-       if (pci_bar_addr == PCI_BASE_ADDRESS_0) /* looking for BAR zero? */
+       if (pci_bar_addr == PCI_BASE_ADDRESS_0) /* looking for BAR zero? */
                return 0;
        offset = 0;
-       for (i=0; i<DEVICE_COUNT_RESOURCE; i++) {
-               bar_type = pci_resource_flags(pdev, i) &
-                       PCI_BASE_ADDRESS_SPACE;
+       for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+               bar_type = pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE;
                if (bar_type == PCI_BASE_ADDRESS_SPACE_IO)
                        offset += 4;
                else {
                        mem_type = pci_resource_flags(pdev, i) &
-                               PCI_BASE_ADDRESS_MEM_TYPE_MASK;
+                           PCI_BASE_ADDRESS_MEM_TYPE_MASK;
                        switch (mem_type) {
-                               case PCI_BASE_ADDRESS_MEM_TYPE_32:
-                               case PCI_BASE_ADDRESS_MEM_TYPE_1M:
-                                       offset += 4; /* 32 bit */
-                                       break;
-                               case PCI_BASE_ADDRESS_MEM_TYPE_64:
-                                       offset += 8;
-                                       break;
-                               default: /* reserved in PCI 2.2 */
-                                       printk(KERN_WARNING "Base address is invalid\n");
-                                       return -1;
+                       case PCI_BASE_ADDRESS_MEM_TYPE_32:
+                       case PCI_BASE_ADDRESS_MEM_TYPE_1M:
+                               offset += 4;    /* 32 bit */
+                               break;
+                       case PCI_BASE_ADDRESS_MEM_TYPE_64:
+                               offset += 8;
+                               break;
+                       default:        /* reserved in PCI 2.2 */
+                               printk(KERN_WARNING
+                                      "Base address is invalid\n");
+                               return -1;
                                break;
                        }
                }
-               if (offset == pci_bar_addr - PCI_BASE_ADDRESS_0)
-                       return i+1;
+               if (offset == pci_bar_addr - PCI_BASE_ADDRESS_0)
+                       return i + 1;
        }
        return -1;
 }
@@ -2686,53 +2708,54 @@ static int find_PCI_BAR_index(struct pci_dev *pdev,
  * controllers that are capable. If not, we use IO-APIC mode.
  */
 
-static void __devinit cciss_interrupt_mode(ctlr_info_t *c, struct pci_dev *pdev, __u32 board_id)
+static void __devinit cciss_interrupt_mode(ctlr_info_t *c,
+                                          struct pci_dev *pdev, __u32 board_id)
 {
 #ifdef CONFIG_PCI_MSI
-        int err;
-        struct msix_entry cciss_msix_entries[4] = {{0,0}, {0,1},
-                                                  {0,2}, {0,3}};
+       int err;
+       struct msix_entry cciss_msix_entries[4] = { {0, 0}, {0, 1},
+       {0, 2}, {0, 3}
+       };
 
        /* Some boards advertise MSI but don't really support it */
        if ((board_id == 0x40700E11) ||
-               (board_id == 0x40800E11) ||
-               (board_id == 0x40820E11) ||
-               (board_id == 0x40830E11))
+           (board_id == 0x40800E11) ||
+           (board_id == 0x40820E11) || (board_id == 0x40830E11))
                goto default_int_mode;
 
-        if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
-                err = pci_enable_msix(pdev, cciss_msix_entries, 4);
-                if (!err) {
-                        c->intr[0] = cciss_msix_entries[0].vector;
-                        c->intr[1] = cciss_msix_entries[1].vector;
-                        c->intr[2] = cciss_msix_entries[2].vector;
-                        c->intr[3] = cciss_msix_entries[3].vector;
-                        c->msix_vector = 1;
-                        return;
-                }
-                if (err > 0) {
-                        printk(KERN_WARNING "cciss: only %d MSI-X vectors "
-                                        "available\n", err);
-                } else {
-                        printk(KERN_WARNING "cciss: MSI-X init failed %d\n",
-                                               err);
-                }
-        }
-        if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) {
-                if (!pci_enable_msi(pdev)) {
-                        c->intr[SIMPLE_MODE_INT] = pdev->irq;
-                        c->msi_vector = 1;
-                        return;
-                } else {
-                        printk(KERN_WARNING "cciss: MSI init failed\n");
-                       c->intr[SIMPLE_MODE_INT] = pdev->irq;
-                        return;
-                }
-        }
-default_int_mode:
-#endif /* CONFIG_PCI_MSI */
+       if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
+               err = pci_enable_msix(pdev, cciss_msix_entries, 4);
+               if (!err) {
+                       c->intr[0] = cciss_msix_entries[0].vector;
+                       c->intr[1] = cciss_msix_entries[1].vector;
+                       c->intr[2] = cciss_msix_entries[2].vector;
+                       c->intr[3] = cciss_msix_entries[3].vector;
+                       c->msix_vector = 1;
+                       return;
+               }
+               if (err > 0) {
+                       printk(KERN_WARNING "cciss: only %d MSI-X vectors "
+                              "available\n", err);
+               } else {
+                       printk(KERN_WARNING "cciss: MSI-X init failed %d\n",
+                              err);
+               }
+       }
+       if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) {
+               if (!pci_enable_msi(pdev)) {
+                       c->intr[SIMPLE_MODE_INT] = pdev->irq;
+                       c->msi_vector = 1;
+                       return;
+               } else {
+                       printk(KERN_WARNING "cciss: MSI init failed\n");
+                       c->intr[SIMPLE_MODE_INT] = pdev->irq;
+                       return;
+               }
+       }
+      default_int_mode:
+#endif                         /* CONFIG_PCI_MSI */
        /* if we get here we're going to use the default interrupt mode */
-        c->intr[SIMPLE_MODE_INT] = pdev->irq;
+       c->intr[SIMPLE_MODE_INT] = pdev->irq;
        return;
 }
 
@@ -2743,58 +2766,40 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
        __u64 cfg_offset;
        __u32 cfg_base_addr;
        __u64 cfg_base_addr_index;
-       int i;
+       int i, err;
 
        /* check to see if controller has been disabled */
        /* BEFORE trying to enable it */
-       (void) pci_read_config_word(pdev, PCI_COMMAND,&command);
-       if(!(command & 0x02))
-       {
-               printk(KERN_WARNING "cciss: controller appears to be disabled\n");
-               return(-1);
+       (void)pci_read_config_word(pdev, PCI_COMMAND, &command);
+       if (!(command & 0x02)) {
+               printk(KERN_WARNING
+                      "cciss: controller appears to be disabled\n");
+               return -ENODEV;
        }
 
-       if (pci_enable_device(pdev))
-       {
+       err = pci_enable_device(pdev);
+       if (err) {
                printk(KERN_ERR "cciss: Unable to Enable PCI device\n");
-               return( -1);
+               return err;
+       }
+
+       err = pci_request_regions(pdev, "cciss");
+       if (err) {
+               printk(KERN_ERR "cciss: Cannot obtain PCI resources, "
+                      "aborting\n");
+               goto err_out_disable_pdev;
        }
 
        subsystem_vendor_id = pdev->subsystem_vendor;
        subsystem_device_id = pdev->subsystem_device;
        board_id = (((__u32) (subsystem_device_id << 16) & 0xffff0000) |
-                                       subsystem_vendor_id);
-
-       /* search for our IO range so we can protect it */
-       for(i=0; i<DEVICE_COUNT_RESOURCE; i++)
-       {
-               /* is this an IO range */ 
-               if( pci_resource_flags(pdev, i) & 0x01 ) {
-                       c->io_mem_addr = pci_resource_start(pdev, i);
-                       c->io_mem_length = pci_resource_end(pdev, i) -
-                               pci_resource_start(pdev, i) +1;
-#ifdef CCISS_DEBUG
-                       printk("IO value found base_addr[%d] %lx %lx\n", i,
-                               c->io_mem_addr, c->io_mem_length);
-#endif /* CCISS_DEBUG */
-                       /* register the IO range */ 
-                       if(!request_region( c->io_mem_addr,
-                                        c->io_mem_length, "cciss"))
-                       {
-                               printk(KERN_WARNING "cciss I/O memory range already in use addr=%lx length=%ld\n",
-                               c->io_mem_addr, c->io_mem_length);
-                               c->io_mem_addr= 0;
-                               c->io_mem_length = 0;
-                       } 
-                       break;
-               }
-       }
+                   subsystem_vendor_id);
 
 #ifdef CCISS_DEBUG
        printk("command = %x\n", command);
        printk("irq = %x\n", pdev->irq);
        printk("board_id = %x\n", board_id);
-#endif /* CCISS_DEBUG */ 
+#endif                         /* CCISS_DEBUG */
 
 /* If the kernel supports MSI/MSI-X we will try to enable that functionality,
  * else we use the IO-APIC interrupt assigned to us by system ROM.
@@ -2803,27 +2808,28 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
 
        /*
         * Memory base addr is first addr , the second points to the config
-         *   table
+        *   table
         */
 
-       c->paddr = pci_resource_start(pdev, 0); /* addressing mode bits already removed */
+       c->paddr = pci_resource_start(pdev, 0); /* addressing mode bits already removed */
 #ifdef CCISS_DEBUG
        printk("address 0 = %x\n", c->paddr);
-#endif /* CCISS_DEBUG */ 
+#endif                         /* CCISS_DEBUG */
        c->vaddr = remap_pci_mem(c->paddr, 200);
 
        /* Wait for the board to become ready.  (PCI hotplug needs this.)
         * We poll for up to 120 secs, once per 100ms. */
-       for (i=0; i < 1200; i++) {
+       for (i = 0; i < 1200; i++) {
                scratchpad = readl(c->vaddr + SA5_SCRATCHPAD_OFFSET);
                if (scratchpad == CCISS_FIRMWARE_READY)
                        break;
                set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(HZ / 10); /* wait 100ms */
+               schedule_timeout(HZ / 10);      /* wait 100ms */
        }
        if (scratchpad != CCISS_FIRMWARE_READY) {
                printk(KERN_WARNING "cciss: Board not ready.  Timed out.\n");
-               return -1;
+               err = -ENODEV;
+               goto err_out_free_res;
        }
 
        /* get the address index number */
@@ -2831,103 +2837,108 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
        cfg_base_addr &= (__u32) 0x0000ffff;
 #ifdef CCISS_DEBUG
        printk("cfg base address = %x\n", cfg_base_addr);
-#endif /* CCISS_DEBUG */
-       cfg_base_addr_index =
-               find_PCI_BAR_index(pdev, cfg_base_addr);
+#endif                         /* CCISS_DEBUG */
+       cfg_base_addr_index = find_PCI_BAR_index(pdev, cfg_base_addr);
 #ifdef CCISS_DEBUG
        printk("cfg base address index = %x\n", cfg_base_addr_index);
-#endif /* CCISS_DEBUG */
+#endif                         /* CCISS_DEBUG */
        if (cfg_base_addr_index == -1) {
                printk(KERN_WARNING "cciss: Cannot find cfg_base_addr_index\n");
-               release_io_mem(c);
-               return -1;
+               err = -ENODEV;
+               goto err_out_free_res;
        }
 
        cfg_offset = readl(c->vaddr + SA5_CTMEM_OFFSET);
 #ifdef CCISS_DEBUG
        printk("cfg offset = %x\n", cfg_offset);
-#endif /* CCISS_DEBUG */
-       c->cfgtable =  remap_pci_mem(pci_resource_start(pdev,
-                               cfg_base_addr_index) + cfg_offset,
-                               sizeof(CfgTable_struct));
+#endif                         /* CCISS_DEBUG */
+       c->cfgtable = remap_pci_mem(pci_resource_start(pdev,
+                                                      cfg_base_addr_index) +
+                                   cfg_offset, sizeof(CfgTable_struct));
        c->board_id = board_id;
 
 #ifdef CCISS_DEBUG
        print_cfg_table(c->cfgtable);
-#endif /* CCISS_DEBUG */
+#endif                         /* CCISS_DEBUG */
 
-       for(i=0; i<NR_PRODUCTS; i++) {
+       for (i = 0; i < ARRAY_SIZE(products); i++) {
                if (board_id == products[i].board_id) {
                        c->product_name = products[i].product_name;
                        c->access = *(products[i].access);
                        break;
                }
        }
-       if (i == NR_PRODUCTS) {
+       if (i == ARRAY_SIZE(products)) {
                printk(KERN_WARNING "cciss: Sorry, I don't know how"
-                       " to access the Smart Array controller %08lx\n", 
-                               (unsigned long)board_id);
-               return -1;
-       }
-       if (  (readb(&c->cfgtable->Signature[0]) != 'C') ||
-             (readb(&c->cfgtable->Signature[1]) != 'I') ||
-             (readb(&c->cfgtable->Signature[2]) != 'S') ||
-             (readb(&c->cfgtable->Signature[3]) != 'S') )
-       {
+                      " to access the Smart Array controller %08lx\n",
+                      (unsigned long)board_id);
+               err = -ENODEV;
+               goto err_out_free_res;
+       }
+       if ((readb(&c->cfgtable->Signature[0]) != 'C') ||
+           (readb(&c->cfgtable->Signature[1]) != 'I') ||
+           (readb(&c->cfgtable->Signature[2]) != 'S') ||
+           (readb(&c->cfgtable->Signature[3]) != 'S')) {
                printk("Does not appear to be a valid CISS config table\n");
-               return -1;
+               err = -ENODEV;
+               goto err_out_free_res;
        }
-
 #ifdef CONFIG_X86
-{
-       /* Need to enable prefetch in the SCSI core for 6400 in x86 */
-       __u32 prefetch;
-       prefetch = readl(&(c->cfgtable->SCSI_Prefetch));
-       prefetch |= 0x100;
-       writel(prefetch, &(c->cfgtable->SCSI_Prefetch));
-}
+       {
+               /* Need to enable prefetch in the SCSI core for 6400 in x86 */
+               __u32 prefetch;
+               prefetch = readl(&(c->cfgtable->SCSI_Prefetch));
+               prefetch |= 0x100;
+               writel(prefetch, &(c->cfgtable->SCSI_Prefetch));
+       }
 #endif
 
 #ifdef CCISS_DEBUG
        printk("Trying to put board into Simple mode\n");
-#endif /* CCISS_DEBUG */ 
+#endif                         /* CCISS_DEBUG */
        c->max_commands = readl(&(c->cfgtable->CmdsOutMax));
-       /* Update the field, and then ring the doorbell */ 
-       writel( CFGTBL_Trans_Simple, 
-               &(c->cfgtable->HostWrite.TransportRequest));
-       writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
+       /* Update the field, and then ring the doorbell */
+       writel(CFGTBL_Trans_Simple, &(c->cfgtable->HostWrite.TransportRequest));
+       writel(CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
 
        /* under certain very rare conditions, this can take awhile.
         * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right
         * as we enter this code.) */
-       for(i=0;i<MAX_CONFIG_WAIT;i++) {
+       for (i = 0; i < MAX_CONFIG_WAIT; i++) {
                if (!(readl(c->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
                        break;
                /* delay and try again */
                set_current_state(TASK_INTERRUPTIBLE);
                schedule_timeout(10);
-       }       
+       }
 
 #ifdef CCISS_DEBUG
-       printk(KERN_DEBUG "I counter got to %d %x\n", i, readl(c->vaddr + SA5_DOORBELL));
-#endif /* CCISS_DEBUG */
+       printk(KERN_DEBUG "I counter got to %d %x\n", i,
+              readl(c->vaddr + SA5_DOORBELL));
+#endif                         /* CCISS_DEBUG */
 #ifdef CCISS_DEBUG
-       print_cfg_table(c->cfgtable);   
-#endif /* CCISS_DEBUG */ 
+       print_cfg_table(c->cfgtable);
+#endif                         /* CCISS_DEBUG */
 
-       if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple))
-       {
+       if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) {
                printk(KERN_WARNING "cciss: unable to get board into"
-                                       " simple mode\n");
-               return -1;
+                      " simple mode\n");
+               err = -ENODEV;
+               goto err_out_free_res;
        }
        return 0;
 
+      err_out_free_res:
+       pci_release_regions(pdev);
+
+      err_out_disable_pdev:
+       pci_disable_device(pdev);
+       return err;
 }
 
-/* 
- * Gets information about the local volumes attached to the controller. 
- */ 
+/*
+ * Gets information about the local volumes attached to the controller.
+ */
 static void cciss_getgeometry(int cntl_num)
 {
        ReportLunData_struct *ld_buff;
@@ -2938,102 +2949,102 @@ static void cciss_getgeometry(int cntl_num)
        int listlength = 0;
        __u32 lunid = 0;
        int block_size;
-       int total_size; 
+       int total_size;
 
        ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
-       if (ld_buff == NULL)
-       {
+       if (ld_buff == NULL) {
+               printk(KERN_ERR "cciss: out of memory\n");
+               return;
+       }
+       size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
+       if (size_buff == NULL) {
                printk(KERN_ERR "cciss: out of memory\n");
+               kfree(ld_buff);
                return;
        }
-       size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
-        if (size_buff == NULL)
-        {
-                printk(KERN_ERR "cciss: out of memory\n");
+       inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
+       if (inq_buff == NULL) {
+               printk(KERN_ERR "cciss: out of memory\n");
                kfree(ld_buff);
-                return;
-        }
-       inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
-        if (inq_buff == NULL)
-        {
-                printk(KERN_ERR "cciss: out of memory\n");
-                kfree(ld_buff);
                kfree(size_buff);
-                return;
-        }
-       /* Get the firmware version */ 
-       return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, 
-               sizeof(InquiryData_struct), 0, 0 ,0, NULL, TYPE_CMD);
-       if (return_code == IO_OK)
-       {
+               return;
+       }
+       /* Get the firmware version */
+       return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff,
+                             sizeof(InquiryData_struct), 0, 0, 0, NULL,
+                             TYPE_CMD);
+       if (return_code == IO_OK) {
                hba[cntl_num]->firm_ver[0] = inq_buff->data_byte[32];
                hba[cntl_num]->firm_ver[1] = inq_buff->data_byte[33];
                hba[cntl_num]->firm_ver[2] = inq_buff->data_byte[34];
                hba[cntl_num]->firm_ver[3] = inq_buff->data_byte[35];
-       } else /* send command failed */
-       {
+       } else {                /* send command failed */
+
                printk(KERN_WARNING "cciss: unable to determine firmware"
-                       " version of controller\n");
+                      " version of controller\n");
        }
-       /* Get the number of logical volumes */ 
-       return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff, 
-                       sizeof(ReportLunData_struct), 0, 0, 0, NULL, TYPE_CMD);
+       /* Get the number of logical volumes */
+       return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff,
+                             sizeof(ReportLunData_struct), 0, 0, 0, NULL,
+                             TYPE_CMD);
 
-       if( return_code == IO_OK)
-       {
+       if (return_code == IO_OK) {
 #ifdef CCISS_DEBUG
                printk("LUN Data\n--------------------------\n");
-#endif /* CCISS_DEBUG */ 
-
-               listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
-               listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
-               listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;  
+#endif                         /* CCISS_DEBUG */
+
+               listlength |=
+                   (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
+               listlength |=
+                   (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
+               listlength |=
+                   (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;
                listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
-       } else /* reading number of logical volumes failed */
-       {
+       } else {                /* reading number of logical volumes failed */
+
                printk(KERN_WARNING "cciss: report logical volume"
-                       " command failed\n");
+                      " command failed\n");
                listlength = 0;
        }
-       hba[cntl_num]->num_luns = listlength / 8; // 8 bytes pre entry
-       if (hba[cntl_num]->num_luns > CISS_MAX_LUN)
-       {
-               printk(KERN_ERR "ciss:  only %d number of logical volumes supported\n",
-                       CISS_MAX_LUN);
+       hba[cntl_num]->num_luns = listlength / 8;       // 8 bytes pre entry
+       if (hba[cntl_num]->num_luns > CISS_MAX_LUN) {
+               printk(KERN_ERR
+                      "ciss:  only %d number of logical volumes supported\n",
+                      CISS_MAX_LUN);
                hba[cntl_num]->num_luns = CISS_MAX_LUN;
        }
 #ifdef CCISS_DEBUG
-       printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0],
-               ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
-               ld_buff->LUNListLength[3],  hba[cntl_num]->num_luns);
-#endif /* CCISS_DEBUG */
-
-       hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns-1;
-//     for(i=0; i<  hba[cntl_num]->num_luns; i++)
-       for(i=0; i < CISS_MAX_LUN; i++)
-       {
-               if (i < hba[cntl_num]->num_luns){
-                       lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3]))
-                                << 24;
-                       lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2]))
-                                << 16;
-                       lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1]))
-                                << 8;
-               lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
-               
-               hba[cntl_num]->drv[i].LunID = lunid;
-
+       printk(KERN_DEBUG "Length = %x %x %x %x = %d\n",
+              ld_buff->LUNListLength[0], ld_buff->LUNListLength[1],
+              ld_buff->LUNListLength[2], ld_buff->LUNListLength[3],
+              hba[cntl_num]->num_luns);
+#endif                         /* CCISS_DEBUG */
+
+       hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns - 1;
+//      for(i=0; i<  hba[cntl_num]->num_luns; i++)
+       for (i = 0; i < CISS_MAX_LUN; i++) {
+               if (i < hba[cntl_num]->num_luns) {
+                       lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3]))
+                           << 24;
+                       lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2]))
+                           << 16;
+                       lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1]))
+                           << 8;
+                       lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
+
+                       hba[cntl_num]->drv[i].LunID = lunid;
 
 #ifdef CCISS_DEBUG
-               printk(KERN_DEBUG "LUN[%d]:  %x %x %x %x = %x\n", i, 
-                       ld_buff->LUN[i][0], ld_buff->LUN[i][1],
-                       ld_buff->LUN[i][2], ld_buff->LUN[i][3],
-                       hba[cntl_num]->drv[i].LunID);
-#endif /* CCISS_DEBUG */
-               cciss_read_capacity(cntl_num, i, size_buff, 0,
-                       &total_size, &block_size);
+                       printk(KERN_DEBUG "LUN[%d]:  %x %x %x %x = %x\n", i,
+                              ld_buff->LUN[i][0], ld_buff->LUN[i][1],
+                              ld_buff->LUN[i][2], ld_buff->LUN[i][3],
+                              hba[cntl_num]->drv[i].LunID);
+#endif                         /* CCISS_DEBUG */
+                       cciss_read_capacity(cntl_num, i, size_buff, 0,
+                                           &total_size, &block_size);
                        cciss_geometry_inquiry(cntl_num, i, 0, total_size,
-                               block_size, inq_buff, &hba[cntl_num]->drv[i]);
+                                              block_size, inq_buff,
+                                              &hba[cntl_num]->drv[i]);
                } else {
                        /* initialize raid_level to indicate a free space */
                        hba[cntl_num]->drv[i].raid_level = -1;
@@ -3042,7 +3053,7 @@ static void cciss_getgeometry(int cntl_num)
        kfree(ld_buff);
        kfree(size_buff);
        kfree(inq_buff);
-}      
+}
 
 /* Function to find the first free pointer into our hba[] array */
 /* Returns -1 if no free entries are left.  */
@@ -3056,7 +3067,7 @@ static int alloc_cciss_hba(void)
                        goto out;
        }
 
-       for(i=0; i< MAX_CTLR; i++) {
+       for (i = 0; i < MAX_CTLR; i++) {
                if (!hba[i]) {
                        ctlr_info_t *p;
                        p = kzalloc(sizeof(ctlr_info_t), GFP_KERNEL);
@@ -3069,11 +3080,11 @@ static int alloc_cciss_hba(void)
                }
        }
        printk(KERN_WARNING "cciss: This driver supports a maximum"
-               " of %d controllers.\n", MAX_CTLR);
+              " of %d controllers.\n", MAX_CTLR);
        goto out;
-Enomem:
+      Enomem:
        printk(KERN_ERR "cciss: out of memory.\n");
-out:
+      out:
        while (n--)
                put_disk(disk[n]);
        return -1;
@@ -3096,20 +3107,17 @@ static void free_hba(int i)
  *  returns the number of block devices registered.
  */
 static int __devinit cciss_init_one(struct pci_dev *pdev,
-       const struct pci_device_id *ent)
+                                   const struct pci_device_id *ent)
 {
        request_queue_t *q;
        int i;
        int j;
        int rc;
+       int dac;
 
-       printk(KERN_DEBUG "cciss: Device 0x%x has been found at"
-                       " bus %d dev %d func %d\n",
-               pdev->device, pdev->bus->number, PCI_SLOT(pdev->devfn),
-                       PCI_FUNC(pdev->devfn));
        i = alloc_cciss_hba();
-       if(i < 0)
-               return (-1);
+       if (i < 0)
+               return -1;
 
        hba[i]->busy_initializing = 1;
 
@@ -3122,11 +3130,11 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
 
        /* configure PCI DMA stuff */
        if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK))
-               printk("cciss: using DAC cycles\n");
+               dac = 1;
        else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK))
-               printk("cciss: not using DAC cycles\n");
+               dac = 0;
        else {
-               printk("cciss: no suitable DMA available\n");
+               printk(KERN_ERR "cciss: no suitable DMA available\n");
                goto clean1;
        }
 
@@ -3138,60 +3146,69 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
        if (i < MAX_CTLR_ORIG)
                hba[i]->major = COMPAQ_CISS_MAJOR + i;
        rc = register_blkdev(hba[i]->major, hba[i]->devname);
-       if(rc == -EBUSY || rc == -EINVAL) {
+       if (rc == -EBUSY || rc == -EINVAL) {
                printk(KERN_ERR
-                       "cciss:  Unable to get major number %d for %s "
-                       "on hba %d\n", hba[i]->major, hba[i]->devname, i);
+                      "cciss:  Unable to get major number %d for %s "
+                      "on hba %d\n", hba[i]->major, hba[i]->devname, i);
                goto clean1;
-       }
-       else {
+       } else {
                if (i >= MAX_CTLR_ORIG)
                        hba[i]->major = rc;
        }
 
        /* make sure the board interrupts are off */
        hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
-       if( request_irq(hba[i]->intr[SIMPLE_MODE_INT], do_cciss_intr,
-               SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
-                       hba[i]->devname, hba[i])) {
+       if (request_irq(hba[i]->intr[SIMPLE_MODE_INT], do_cciss_intr,
+                       SA_INTERRUPT | SA_SHIRQ, hba[i]->devname, hba[i])) {
                printk(KERN_ERR "cciss: Unable to get irq %d for %s\n",
-                       hba[i]->intr[SIMPLE_MODE_INT], hba[i]->devname);
+                      hba[i]->intr[SIMPLE_MODE_INT], hba[i]->devname);
                goto clean2;
        }
-       hba[i]->cmd_pool_bits = kmalloc(((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long), GFP_KERNEL);
-       hba[i]->cmd_pool = (CommandList_struct *)pci_alloc_consistent(
-               hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct), 
-               &(hba[i]->cmd_pool_dhandle));
-       hba[i]->errinfo_pool = (ErrorInfo_struct *)pci_alloc_consistent(
-               hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct), 
-               &(hba[i]->errinfo_pool_dhandle));
-       if((hba[i]->cmd_pool_bits == NULL) 
-               || (hba[i]->cmd_pool == NULL)
-               || (hba[i]->errinfo_pool == NULL)) {
-                printk( KERN_ERR "cciss: out of memory");
+
+       printk(KERN_INFO "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n",
+              hba[i]->devname, pdev->device, pci_name(pdev),
+              hba[i]->intr[SIMPLE_MODE_INT], dac ? "" : " not");
+
+       hba[i]->cmd_pool_bits =
+           kmalloc(((NR_CMDS + BITS_PER_LONG -
+                     1) / BITS_PER_LONG) * sizeof(unsigned long), GFP_KERNEL);
+       hba[i]->cmd_pool = (CommandList_struct *)
+           pci_alloc_consistent(hba[i]->pdev,
+                   NR_CMDS * sizeof(CommandList_struct),
+                   &(hba[i]->cmd_pool_dhandle));
+       hba[i]->errinfo_pool = (ErrorInfo_struct *)
+           pci_alloc_consistent(hba[i]->pdev,
+                   NR_CMDS * sizeof(ErrorInfo_struct),
+                   &(hba[i]->errinfo_pool_dhandle));
+       if ((hba[i]->cmd_pool_bits == NULL)
+           || (hba[i]->cmd_pool == NULL)
+           || (hba[i]->errinfo_pool == NULL)) {
+               printk(KERN_ERR "cciss: out of memory");
                goto clean4;
        }
 #ifdef CONFIG_CISS_SCSI_TAPE
-       hba[i]->scsi_rejects.complete = 
-               kmalloc(sizeof(hba[i]->scsi_rejects.complete[0]) * 
-                       (NR_CMDS + 5), GFP_KERNEL);
+       hba[i]->scsi_rejects.complete =
+           kmalloc(sizeof(hba[i]->scsi_rejects.complete[0]) *
+                   (NR_CMDS + 5), GFP_KERNEL);
        if (hba[i]->scsi_rejects.complete == NULL) {
-                printk( KERN_ERR "cciss: out of memory");
+               printk(KERN_ERR "cciss: out of memory");
                goto clean4;
        }
 #endif
        spin_lock_init(&hba[i]->lock);
 
-       /* Initialize the pdev driver private data. 
-               have it point to hba[i].  */
+       /* Initialize the pdev driver private data.
+          have it point to hba[i].  */
        pci_set_drvdata(pdev, hba[i]);
-       /* command and error info recs zeroed out before 
-                       they are used */
-        memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long));
+       /* command and error info recs zeroed out before
+          they are used */
+       memset(hba[i]->cmd_pool_bits, 0,
+              ((NR_CMDS + BITS_PER_LONG -
+                1) / BITS_PER_LONG) * sizeof(unsigned long));
 
-#ifdef CCISS_DEBUG     
-       printk(KERN_DEBUG "Scanning for drives on controller cciss%d\n",i);
-#endif /* CCISS_DEBUG */
+#ifdef CCISS_DEBUG
+       printk(KERN_DEBUG "Scanning for drives on controller cciss%d\n", i);
+#endif                         /* CCISS_DEBUG */
 
        cciss_getgeometry(i);
 
@@ -3203,15 +3220,15 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
        cciss_procinit(i);
        hba[i]->busy_initializing = 0;
 
-       for(j=0; j < NWD; j++) { /* mfm */
+       for (j = 0; j < NWD; j++) {     /* mfm */
                drive_info_struct *drv = &(hba[i]->drv[j]);
                struct gendisk *disk = hba[i]->gendisk[j];
 
                q = blk_init_queue(do_cciss_request, &hba[i]->lock);
                if (!q) {
                        printk(KERN_ERR
-                          "cciss:  unable to allocate queue for disk %d\n",
-                          j);
+                              "cciss:  unable to allocate queue for disk %d\n",
+                              j);
                        break;
                }
                drv->queue = q;
@@ -3240,92 +3257,87 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
                disk->driverfs_dev = &pdev->dev;
                /* we must register the controller even if no disks exist */
                /* this is for the online array utilities */
-               if(!drv->heads && j)
+               if (!drv->heads && j)
                        continue;
                blk_queue_hardsect_size(q, drv->block_size);
                set_capacity(disk, drv->nr_blocks);
                add_disk(disk);
        }
 
-       return(1);
+       return 1;
 
-clean4:
+      clean4:
 #ifdef CONFIG_CISS_SCSI_TAPE
        kfree(hba[i]->scsi_rejects.complete);
 #endif
        kfree(hba[i]->cmd_pool_bits);
-       if(hba[i]->cmd_pool)
+       if (hba[i]->cmd_pool)
                pci_free_consistent(hba[i]->pdev,
-                       NR_CMDS * sizeof(CommandList_struct),
-                       hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);
-       if(hba[i]->errinfo_pool)
+                                   NR_CMDS * sizeof(CommandList_struct),
+                                   hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);
+       if (hba[i]->errinfo_pool)
                pci_free_consistent(hba[i]->pdev,
-                       NR_CMDS * sizeof( ErrorInfo_struct),
-                       hba[i]->errinfo_pool,
-                       hba[i]->errinfo_pool_dhandle);
+                                   NR_CMDS * sizeof(ErrorInfo_struct),
+                                   hba[i]->errinfo_pool,
+                                   hba[i]->errinfo_pool_dhandle);
        free_irq(hba[i]->intr[SIMPLE_MODE_INT], hba[i]);
-clean2:
+      clean2:
        unregister_blkdev(hba[i]->major, hba[i]->devname);
-clean1:
-       release_io_mem(hba[i]);
+      clean1:
        hba[i]->busy_initializing = 0;
        free_hba(i);
-       return(-1);
+       return -1;
 }
 
-static void __devexit cciss_remove_one (struct pci_dev *pdev)
+static void __devexit cciss_remove_one(struct pci_dev *pdev)
 {
        ctlr_info_t *tmp_ptr;
        int i, j;
        char flush_buf[4];
-       int return_code; 
+       int return_code;
 
-       if (pci_get_drvdata(pdev) == NULL)
-       {
-               printk( KERN_ERR "cciss: Unable to remove device \n");
+       if (pci_get_drvdata(pdev) == NULL) {
+               printk(KERN_ERR "cciss: Unable to remove device \n");
                return;
        }
        tmp_ptr = pci_get_drvdata(pdev);
        i = tmp_ptr->ctlr;
-       if (hba[i] == NULL) 
-       {
+       if (hba[i] == NULL) {
                printk(KERN_ERR "cciss: device appears to "
-                       "already be removed \n");
+                      "already be removed \n");
                return;
        }
        /* Turn board interrupts off  and send the flush cache command */
        /* sendcmd will turn off interrupt, and send the flush...
-       * To write all data in the battery backed cache to disks */
+        * To write all data in the battery backed cache to disks */
        memset(flush_buf, 0, 4);
        return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL,
-                               TYPE_CMD);
-       if(return_code != IO_OK)
-       {
-               printk(KERN_WARNING "Error Flushing cache on controller %d\n", 
-                       i);
+                             TYPE_CMD);
+       if (return_code != IO_OK) {
+               printk(KERN_WARNING "Error Flushing cache on controller %d\n",
+                      i);
        }
        free_irq(hba[i]->intr[2], hba[i]);
 
 #ifdef CONFIG_PCI_MSI
-        if (hba[i]->msix_vector)
-                pci_disable_msix(hba[i]->pdev);
-        else if (hba[i]->msi_vector)
-                pci_disable_msi(hba[i]->pdev);
-#endif /* CONFIG_PCI_MSI */
+       if (hba[i]->msix_vector)
+               pci_disable_msix(hba[i]->pdev);
+       else if (hba[i]->msi_vector)
+               pci_disable_msi(hba[i]->pdev);
+#endif                         /* CONFIG_PCI_MSI */
 
-       pci_set_drvdata(pdev, NULL);
        iounmap(hba[i]->vaddr);
-       cciss_unregister_scsi(i);  /* unhook from SCSI subsystem */
+       cciss_unregister_scsi(i);       /* unhook from SCSI subsystem */
        unregister_blkdev(hba[i]->major, hba[i]->devname);
-       remove_proc_entry(hba[i]->devname, proc_cciss); 
-       
+       remove_proc_entry(hba[i]->devname, proc_cciss);
+
        /* remove it from the disk list */
        for (j = 0; j < NWD; j++) {
                struct gendisk *disk = hba[i]->gendisk[j];
                if (disk) {
                        request_queue_t *q = disk->queue;
 
-                       if (disk->flags & GENHD_FL_UP) 
+                       if (disk->flags & GENHD_FL_UP)
                                del_gendisk(disk);
                        if (q)
                                blk_cleanup_queue(q);
@@ -3334,26 +3346,28 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev)
 
        pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct),
                            hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);
-       pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct),
-               hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle);
+       pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(ErrorInfo_struct),
+                           hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle);
        kfree(hba[i]->cmd_pool_bits);
 #ifdef CONFIG_CISS_SCSI_TAPE
        kfree(hba[i]->scsi_rejects.complete);
 #endif
-       release_io_mem(hba[i]);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
        free_hba(i);
-}      
+}
 
 static struct pci_driver cciss_pci_driver = {
-       .name =         "cciss",
-       .probe =        cciss_init_one,
-       .remove =       __devexit_p(cciss_remove_one),
-       .id_table =     cciss_pci_device_id, /* id_table */
+       .name = "cciss",
+       .probe = cciss_init_one,
+       .remove = __devexit_p(cciss_remove_one),
+       .id_table = cciss_pci_device_id,        /* id_table */
 };
 
 /*
  *  This is it.  Register the PCI driver information for the cards we control
- *  the OS will call our registered routines when it finds one of our cards. 
+ *  the OS will call our registered routines when it finds one of our cards.
  */
 static int __init cciss_init(void)
 {
@@ -3369,12 +3383,10 @@ static void __exit cciss_cleanup(void)
 
        pci_unregister_driver(&cciss_pci_driver);
        /* double check that all controller entrys have been removed */
-       for (i=0; i< MAX_CTLR; i++) 
-       {
-               if (hba[i] != NULL)
-               {
+       for (i = 0; i < MAX_CTLR; i++) {
+               if (hba[i] != NULL) {
                        printk(KERN_WARNING "cciss: had to remove"
-                                       " controller %d\n", i);
+                              " controller %d\n", i);
                        cciss_remove_one(hba[i]->pdev);
                }
        }
@@ -3389,21 +3401,21 @@ static void fail_all_cmds(unsigned long ctlr)
        unsigned long flags;
 
        printk(KERN_WARNING "cciss%d: controller not responding.\n", h->ctlr);
-       h->alive = 0;   /* the controller apparently died... */
+       h->alive = 0;           /* the controller apparently died... */
 
        spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
 
-       pci_disable_device(h->pdev); /* Make sure it is really dead. */
+       pci_disable_device(h->pdev);    /* Make sure it is really dead. */
 
        /* move everything off the request queue onto the completed queue */
-       while( (c = h->reqQ) != NULL ) {
+       while ((c = h->reqQ) != NULL) {
                removeQ(&(h->reqQ), c);
                h->Qdepth--;
-               addQ (&(h->cmpQ), c);
+               addQ(&(h->cmpQ), c);
        }
 
        /* Now, fail everything on the completed queue with a HW error */
-       while( (c = h->cmpQ) != NULL ) {
+       while ((c = h->cmpQ) != NULL) {
                removeQ(&h->cmpQ, c);
                c->err_info->CommandStatus = CMD_HARDWARE_ERR;
                if (c->cmd_type == CMD_RWREQ) {
@@ -3411,8 +3423,8 @@ static void fail_all_cmds(unsigned long ctlr)
                } else if (c->cmd_type == CMD_IOCTL_PEND)
                        complete(c->waiting);
 #ifdef CONFIG_CISS_SCSI_TAPE
-                       else if (c->cmd_type == CMD_SCSI)
-                               complete_scsi_command(c, 0, 0);
+               else if (c->cmd_type == CMD_SCSI)
+                       complete_scsi_command(c, 0, 0);
 #endif
        }
        spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
index b24fc0553ccf958c95538d22f79ad4f2682b068c..868e0d862b0d274980857ee8593a385006ae2432 100644 (file)
@@ -60,8 +60,6 @@ struct ctlr_info
        __u32   board_id;
        void __iomem *vaddr;
        unsigned long paddr;
-       unsigned long io_mem_addr;
-       unsigned long io_mem_length;
        CfgTable_struct __iomem *cfgtable;
        int     interrupts_enabled;
        int     major;
index b6ea2f0c72763c3b8df3a67c89a785f36841e2c1..5eb6fb7b5cfacfba6c84672cd38aaf631f401c85 100644 (file)
@@ -392,7 +392,7 @@ static void __devexit cpqarray_remove_one_eisa (int i)
 }
 
 /* pdev is NULL for eisa */
-static int cpqarray_register_ctlr( int i, struct pci_dev *pdev)
+static int __init cpqarray_register_ctlr( int i, struct pci_dev *pdev)
 {
        request_queue_t *q;
        int j;
@@ -410,8 +410,7 @@ static int cpqarray_register_ctlr( int i, struct pci_dev *pdev)
        }
        hba[i]->access.set_intr_mask(hba[i], 0);
        if (request_irq(hba[i]->intr, do_ida_intr,
-               SA_INTERRUPT|SA_SHIRQ|SA_SAMPLE_RANDOM,
-               hba[i]->devname, hba[i]))
+               SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i]))
        {
                printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n",
                                hba[i]->intr, hba[i]->devname);
@@ -745,7 +744,7 @@ __setup("smart2=", cpqarray_setup);
 /*
  * Find an EISA controller's signature.  Set up an hba if we find it.
  */
-static int cpqarray_eisa_detect(void)
+static int __init cpqarray_eisa_detect(void)
 {
        int i=0, j;
        __u32 board_id;
@@ -1036,6 +1035,8 @@ static inline void complete_command(cmdlist_t *cmd, int timeout)
 
        complete_buffers(cmd->rq->bio, ok);
 
+       add_disk_randomness(cmd->rq->rq_disk);
+
         DBGPX(printk("Done with %p\n", cmd->rq););
        end_that_request_last(cmd->rq, ok ? 1 : -EIO);
 }
index 3c74ea729fc79529ed766b98f3e1d2b78bb3da57..9dc294a74953f3793a71cb179f36224421d333e8 100644 (file)
@@ -74,6 +74,7 @@
 #include <linux/completion.h>
 #include <linux/highmem.h>
 #include <linux/gfp.h>
+#include <linux/kthread.h>
 
 #include <asm/uaccess.h>
 
@@ -578,8 +579,6 @@ static int loop_thread(void *data)
        struct loop_device *lo = data;
        struct bio *bio;
 
-       daemonize("loop%d", lo->lo_number);
-
        /*
         * loop can be used in an encrypted device,
         * hence, it mustn't be stopped at all
@@ -592,11 +591,6 @@ static int loop_thread(void *data)
        lo->lo_state = Lo_bound;
        lo->lo_pending = 1;
 
-       /*
-        * complete it, we are running
-        */
-       complete(&lo->lo_done);
-
        for (;;) {
                int pending;
 
@@ -629,7 +623,6 @@ static int loop_thread(void *data)
                        break;
        }
 
-       complete(&lo->lo_done);
        return 0;
 }
 
@@ -746,6 +739,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
        unsigned lo_blocksize;
        int             lo_flags = 0;
        int             error;
+       struct task_struct *tsk;
        loff_t          size;
 
        /* This is safe, since we have a reference from open(). */
@@ -839,10 +833,11 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
 
        set_blocksize(bdev, lo_blocksize);
 
-       error = kernel_thread(loop_thread, lo, CLONE_KERNEL);
-       if (error < 0)
+       tsk = kthread_run(loop_thread, lo, "loop%d", lo->lo_number);
+       if (IS_ERR(tsk)) {
+               error = PTR_ERR(tsk);
                goto out_putf;
-       wait_for_completion(&lo->lo_done);
+       }
        return 0;
 
  out_putf:
@@ -898,6 +893,9 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
        if (lo->lo_state != Lo_bound)
                return -ENXIO;
 
+       if (!lo->lo_thread)
+               return -EINVAL;
+
        if (lo->lo_refcnt > 1)  /* we needed one fd for the ioctl */
                return -EBUSY;
 
@@ -911,7 +909,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
                complete(&lo->lo_bh_done);
        spin_unlock_irq(&lo->lo_lock);
 
-       wait_for_completion(&lo->lo_done);
+       kthread_stop(lo->lo_thread);
 
        lo->lo_backing_file = NULL;
 
@@ -924,6 +922,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
        lo->lo_sizelimit = 0;
        lo->lo_encrypt_key_size = 0;
        lo->lo_flags = 0;
+       lo->lo_thread = NULL;
        memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
        memset(lo->lo_crypt_name, 0, LO_NAME_SIZE);
        memset(lo->lo_file_name, 0, LO_NAME_SIZE);
@@ -1288,7 +1287,6 @@ static int __init loop_init(void)
                if (!lo->lo_queue)
                        goto out_mem4;
                mutex_init(&lo->lo_ctl_mutex);
-               init_completion(&lo->lo_done);
                init_completion(&lo->lo_bh_done);
                lo->lo_number = i;
                spin_lock_init(&lo->lo_lock);
index 8bca4905d7f7357e31b8d66f53a79fc79379c874..7f554f2ed0797af3b39d87d4354609169203fdb0 100644 (file)
@@ -7,39 +7,9 @@
  * Copyright 1997-2000 Pavel Machek <pavel@ucw.cz>
  * Parts copyright 2001 Steven Whitehouse <steve@chygwyn.com>
  *
- * (part of code stolen from loop.c)
+ * This file is released under GPLv2 or later.
  *
- * 97-3-25 compiled 0-th version, not yet tested it 
- *   (it did not work, BTW) (later that day) HEY! it works!
- *   (bit later) hmm, not that much... 2:00am next day:
- *   yes, it works, but it gives something like 50kB/sec
- * 97-4-01 complete rewrite to make it possible for many requests at 
- *   once to be processed
- * 97-4-11 Making protocol independent of endianity etc.
- * 97-9-13 Cosmetic changes
- * 98-5-13 Attempt to make 64-bit-clean on 64-bit machines
- * 99-1-11 Attempt to make 64-bit-clean on 32-bit machines <ankry@mif.pg.gda.pl>
- * 01-2-27 Fix to store proper blockcount for kernel (calculated using
- *   BLOCK_SIZE_BITS, not device blocksize) <aga@permonline.ru>
- * 01-3-11 Make nbd work with new Linux block layer code. It now supports
- *   plugging like all the other block devices. Also added in MSG_MORE to
- *   reduce number of partial TCP segments sent. <steve@chygwyn.com>
- * 01-12-6 Fix deadlock condition by making queue locks independent of
- *   the transmit lock. <steve@chygwyn.com>
- * 02-10-11 Allow hung xmit to be aborted via SIGKILL & various fixes.
- *   <Paul.Clements@SteelEye.com> <James.Bottomley@SteelEye.com>
- * 03-06-22 Make nbd work with new linux 2.5 block layer design. This fixes
- *   memory corruption from module removal and possible memory corruption
- *   from sending/receiving disk data. <ldl@aros.net>
- * 03-06-23 Cosmetic changes. <ldl@aros.net>
- * 03-06-23 Enhance diagnostics support. <ldl@aros.net>
- * 03-06-24 Remove unneeded blksize_bits field from nbd_device struct.
- *   <ldl@aros.net>
- * 03-06-24 Cleanup PARANOIA usage & code. <ldl@aros.net>
- * 04-02-19 Remove PARANOIA, plus various cleanups (Paul Clements)
- * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall
- * why not: would need access_ok and friends, would share yet another
- *          structure with userland
+ * (part of code stolen from loop.c)
  */
 
 #include <linux/major.h>
index a0b580c22d80942dbd75536609076f219edce33b..0f6e7aab8d2cb18cc294b08919d87752fcf3444d 100644 (file)
@@ -1006,7 +1006,7 @@ static int mcdx_talk(struct s_drive_stuff *stuffp,
 
 /* MODULE STUFF ***********************************************************/
 
-int __mcdx_init(void)
+static int __init __mcdx_init(void)
 {
        int i;
        int drives = 0;
index 78d928f9d9f1abaa3c3a0b46e7deb69cd9f65a16..63f28d169b36e7123cfb753343ade43df0d854ae 100644 (file)
@@ -865,6 +865,7 @@ config SONYPI
 config TANBAC_TB0219
        tristate "TANBAC TB0219 base board support"
        depends TANBAC_TB022X
+       select GPIO_VR41XX
 
 menu "Ftape, the floppy tape device driver"
 
index a370e7a0bad5a1ce46b77684587e0b42f4f4d2b3..9275d5e52e6de63d86309c82096f19ac5776592e 100644 (file)
@@ -166,11 +166,7 @@ static int ac_register_board(unsigned long physloc, void __iomem *loc,
        return boardno + 1;
 }
 
-#ifdef MODULE
-
-#define applicom_init init_module
-
-void cleanup_module(void)
+static void __exit applicom_exit(void)
 {
        unsigned int i;
 
@@ -188,9 +184,7 @@ void cleanup_module(void)
        }
 }
 
-#endif                         /* MODULE */
-
-int __init applicom_init(void)
+static int __init applicom_init(void)
 {
        int i, numisa = 0;
        struct pci_dev *dev = NULL;
@@ -355,10 +349,9 @@ out:
        return ret;
 }
 
+module_init(applicom_init);
+module_exit(applicom_exit);
 
-#ifndef MODULE
-__initcall(applicom_init);
-#endif
 
 static ssize_t ac_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
 {
@@ -851,28 +844,3 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
        return 0;
 }
 
-#ifndef MODULE
-static int __init applicom_setup(char *str)
-{
-       int ints[4];
-
-       (void) get_options(str, 4, ints);
-
-       if (ints[0] > 2) {
-               printk(KERN_WARNING "Too many arguments to 'applicom=', expected mem,irq only.\n");
-       }
-
-       if (ints[0] < 2) {
-               printk(KERN_INFO"applicom numargs: %d\n", ints[0]);
-               return 0;
-       }
-
-       mem = ints[1];
-       irq = ints[2];
-       return 1;
-}
-
-__setup("applicom=", applicom_setup);
-
-#endif                         /* MODULE */
-
index cc7acf877dc0ff92c4b55b1d2314ac4f0461e306..122e7a72a4e178755dedce7922ff91b2f29a2f3e 100644 (file)
@@ -2833,9 +2833,8 @@ cy_write(struct tty_struct * tty, const unsigned char *buf, int count)
         return 0;
     }
         
-    if (!tty || !info->xmit_buf || !tmp_buf){
-        return 0;
-    }
+    if (!info->xmit_buf || !tmp_buf)
+       return 0;
 
     CY_LOCK(info, flags);
     while (1) {
@@ -2884,7 +2883,7 @@ cy_put_char(struct tty_struct *tty, unsigned char ch)
     if (serial_paranoia_check(info, tty->name, "cy_put_char"))
         return;
 
-    if (!tty || !info->xmit_buf)
+    if (!info->xmit_buf)
         return;
 
     CY_LOCK(info, flags);
index 09dc4b01232c018e95733b303a86ee8c2f9ed1ba..922174d527ae6325ed63562e1929f44892a9ded7 100644 (file)
@@ -1212,7 +1212,7 @@ static void rs_put_char(struct tty_struct *tty, unsigned char ch)
        if (serial_paranoia_check(info, tty->name, "rs_put_char"))
                return;
 
-       if (!tty || !info->xmit_buf)
+       if (!info->xmit_buf)
                return;
 
        spin_lock_irqsave(&info->lock, flags);
@@ -1256,7 +1256,7 @@ static int rs_write(struct tty_struct * tty,
        if (serial_paranoia_check(info, tty->name, "rs_write"))
                return 0;
 
-       if (!tty || !info->xmit_buf)
+       if (!info->xmit_buf)
                return 0;
            
        while (1) {
index 03db1cb3fa95c1ec8460b84a1a3a527c96841025..9ab33c3d359fae4279f338e826280d06bda983ed 100644 (file)
@@ -305,7 +305,7 @@ static struct class *ip2_class;
 
 // Some functions to keep track of what irq's we have
 
-static int __init
+static int
 is_valid_irq(int irq)
 {
        int *i = Valid_Irqs;
@@ -316,14 +316,14 @@ is_valid_irq(int irq)
        return (*i);
 }
 
-static void __init
+static void
 mark_requested_irq( char irq )
 {
        rirqs[iindx++] = irq;
 }
 
 #ifdef MODULE
-static int __init
+static int
 clear_requested_irq( char irq )
 {
        int i;
@@ -337,7 +337,7 @@ clear_requested_irq( char irq )
 }
 #endif
 
-static int __init
+static int
 have_requested_irq( char irq )
 {
        // array init to zeros so 0 irq will not be requested as a side effect
@@ -818,7 +818,7 @@ EXPORT_SYMBOL(ip2_loadmain);
 /* the board, the channel structures are initialized, and the board details   */
 /* are reported on the console.                                               */
 /******************************************************************************/
-static void __init
+static void
 ip2_init_board( int boardnum )
 {
        int i;
@@ -961,7 +961,7 @@ err_initialize:
 /* EISA motherboard, or no valid board ID is selected it returns 0. Otherwise */
 /* it returns the base address of the controller.                             */
 /******************************************************************************/
-static unsigned short __init
+static unsigned short
 find_eisa_board( int start_slot )
 {
        int i, j;
index e9ebabaf8cb03184e9990ea272cc91fa733f6a21..efaaa1937ab6dc2115e7d5057744213db9e3e75b 100644 (file)
@@ -1145,7 +1145,7 @@ static int isicom_write(struct tty_struct *tty,   const unsigned char *buf,
        if (isicom_paranoia_check(port, tty->name, "isicom_write"))
                return 0;
 
-       if (!tty || !port->xmit_buf)
+       if (!port->xmit_buf)
                return 0;
 
        spin_lock_irqsave(&card->card_lock, flags);
@@ -1180,7 +1180,7 @@ static void isicom_put_char(struct tty_struct *tty, unsigned char ch)
        if (isicom_paranoia_check(port, tty->name, "isicom_put_char"))
                return;
 
-       if (!tty || !port->xmit_buf)
+       if (!port->xmit_buf)
                return;
 
        spin_lock_irqsave(&card->card_lock, flags);
index 5755b7e5f1873eba30bacec7ce71c07fc49610da..edd996f6fb8788d9615dba959a829a73c692029c 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/vt_kern.h>
 #include <linux/sysrq.h>
 #include <linux/input.h>
+#include <linux/reboot.h>
 
 static void kbd_disconnect(struct input_handle *handle);
 extern void ctrl_alt_del(void);
index 1b05fa688996dc8e94e5e26c0436d5e5ea92ca52..d65b3109318a347f402f51db1d9bcf6c9107bf4f 100644 (file)
@@ -329,7 +329,6 @@ static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma)
        if (PAGE_SIZE > (1 << 16))
                return -ENOSYS;
 
-       vma->vm_flags |= (VM_IO | VM_SHM | VM_LOCKED );
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
        mmtimer_addr = __pa(RTC_COUNTER_ADDR);
index 0fb2fb9fb024b6e9a85ad241105e29b5a6e49a68..645d9d713aec84452615d641cfb73603d4eef2b5 100644 (file)
@@ -9,7 +9,7 @@
  *      This program is free software; you can redistribute it and/or modify
  *      it under the terms of the GNU General Public License as published by
  *      the Free Software Foundation; either version 2 of the License, or
-*      (at your option) any later version.
+ *      (at your option) any later version.
  *
  *      This program is distributed in the hope that it will be useful,
  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -71,8 +71,8 @@
 #define        MXSERMAJOR       174
 #define        MXSERCUMAJOR     175
 
-#define        MXSER_EVENT_TXLOW        1
-#define        MXSER_EVENT_HANGUP       2
+#define        MXSER_EVENT_TXLOW       1
+#define        MXSER_EVENT_HANGUP      2
 
 #define MXSER_BOARDS           4       /* Max. boards */
 #define MXSER_PORTS            32      /* Max. ports */
@@ -92,7 +92,8 @@
 #define UART_MCR_AFE           0x20
 #define UART_LSR_SPECIAL       0x1E
 
-#define RELEVANT_IFLAG(iflag)  (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|IXON|IXOFF))
+#define RELEVANT_IFLAG(iflag)  (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|\
+                                         IXON|IXOFF))
 
 #define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
 
@@ -152,27 +153,27 @@ static char *mxser_brdname[] = {
 };
 
 static int mxser_numports[] = {
-       8,                      // C168-ISA
-       4,                      // C104-ISA
-       4,                      // CI104J
-       8,                      // C168-PCI
-       4,                      // C104-PCI
-       2,                      // C102-ISA
-       2,                      // CI132
-       4,                      // CI134
-       2,                      // CP132
-       4,                      // CP114
-       4,                      // CT114
-       2,                      // CP102
-       4,                      // CP104U
-       8,                      // CP168U
-       2,                      // CP132U
-       4,                      // CP134U
-       4,                      // CP104JU
-       8,                      // RC7000
-       8,                      // CP118U 
-       2,                      // CP102UL 
-       2,                      // CP102U
+       8,                      /* C168-ISA */
+       4,                      /* C104-ISA */
+       4,                      /* CI104J */
+       8,                      /* C168-PCI */
+       4,                      /* C104-PCI */
+       2,                      /* C102-ISA */
+       2,                      /* CI132 */
+       4,                      /* CI134 */
+       2,                      /* CP132 */
+       4,                      /* CP114 */
+       4,                      /* CT114 */
+       2,                      /* CP102 */
+       4,                      /* CP104U */
+       8,                      /* CP168U */
+       2,                      /* CP132U */
+       4,                      /* CP134U */
+       4,                      /* CP104JU */
+       8,                      /* RC7000 */
+       8,                      /* CP118U */
+       2,                      /* CP102UL */
+       2,                      /* CP102U */
 };
 
 #define UART_TYPE_NUM  2
@@ -182,7 +183,7 @@ static const unsigned int Gmoxa_uart_id[UART_TYPE_NUM] = {
        MOXA_MUST_MU860_HWID
 };
 
-// This is only for PCI
+/* This is only for PCI */
 #define UART_INFO_NUM  3
 struct mxpciuart_info {
        int type;
@@ -231,7 +232,7 @@ MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
 typedef struct _moxa_pci_info {
        unsigned short busNum;
        unsigned short devNum;
-       struct pci_dev *pdev;   // add by Victor Yu. 06-23-2003
+       struct pci_dev *pdev;   /* add by Victor Yu. 06-23-2003 */
 } moxa_pci_info;
 
 static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 };
@@ -280,6 +281,7 @@ struct mxser_mon_ext {
        int fifo[32];
        int iftype[32];
 };
+
 struct mxser_hwconf {
        int board_type;
        int ports;
@@ -290,9 +292,9 @@ struct mxser_hwconf {
        int ioaddr[MXSER_PORTS_PER_BOARD];
        int baud_base[MXSER_PORTS_PER_BOARD];
        moxa_pci_info pciInfo;
-       int IsMoxaMustChipFlag; // add by Victor Yu. 08-30-2002
-       int MaxCanSetBaudRate[MXSER_PORTS_PER_BOARD];   // add by Victor Yu. 09-04-2002
-       int opmode_ioaddr[MXSER_PORTS_PER_BOARD];       // add by Victor Yu. 01-05-2004
+       int IsMoxaMustChipFlag; /* add by Victor Yu. 08-30-2002 */
+       int MaxCanSetBaudRate[MXSER_PORTS_PER_BOARD];   /* add by Victor Yu. 09-04-2002 */
+       int opmode_ioaddr[MXSER_PORTS_PER_BOARD];       /* add by Victor Yu. 01-05-2004 */
 };
 
 struct mxser_struct {
@@ -334,9 +336,9 @@ struct mxser_struct {
        wait_queue_head_t delta_msr_wait;
        struct async_icount icount;     /* kernel counters for the 4 input interrupts */
        int timeout;
-       int IsMoxaMustChipFlag; // add by Victor Yu. 08-30-2002
-       int MaxCanSetBaudRate;  // add by Victor Yu. 09-04-2002
-       int opmode_ioaddr;      // add by Victor Yu. 01-05-2004
+       int IsMoxaMustChipFlag; /* add by Victor Yu. 08-30-2002 */
+       int MaxCanSetBaudRate;  /* add by Victor Yu. 09-04-2002 */
+       int opmode_ioaddr;      /* add by Victor Yu. 01-05-2004 */
        unsigned char stop_rx;
        unsigned char ldisc_stop_rx;
        long realbaud;
@@ -345,7 +347,6 @@ struct mxser_struct {
        spinlock_t slock;
 };
 
-
 struct mxser_mstatus {
        tcflag_t cflag;
        int cts;
@@ -358,7 +359,7 @@ static struct mxser_mstatus GMStatus[MXSER_PORTS];
 
 static int mxserBoardCAP[MXSER_BOARDS] = {
        0, 0, 0, 0
-           /*  0x180, 0x280, 0x200, 0x320   */
+       /*  0x180, 0x280, 0x200, 0x320 */
 };
 
 static struct tty_driver *mxvar_sdriver;
@@ -386,7 +387,7 @@ static struct mxser_hwconf mxsercfg[MXSER_BOARDS];
 static void mxser_getcfg(int board, struct mxser_hwconf *hwconf);
 static int mxser_init(void);
 
-//static void   mxser_poll(unsigned long);
+/* static void   mxser_poll(unsigned long); */
 static int mxser_get_ISA_conf(int, struct mxser_hwconf *);
 static int mxser_get_PCI_conf(int, int, int, struct mxser_hwconf *);
 static void mxser_do_softint(void *);
@@ -440,18 +441,18 @@ static int CheckIsMoxaMust(int io)
        SET_MOXA_MUST_XON1_VALUE(io, 0x11);
        if ((hwid = inb(io + UART_MCR)) != 0) {
                outb(oldmcr, io + UART_MCR);
-               return (MOXA_OTHER_UART);
+               return MOXA_OTHER_UART;
        }
 
        GET_MOXA_MUST_HARDWARE_ID(io, &hwid);
        for (i = 0; i < UART_TYPE_NUM; i++) {
                if (hwid == Gmoxa_uart_id[i])
-                       return (int) hwid;
+                       return (int)hwid;
        }
        return MOXA_OTHER_UART;
 }
 
-// above is modified by Victor Yu. 08-15-2002
+/* above is modified by Victor Yu. 08-15-2002 */
 
 static struct tty_operations mxser_ops = {
        .open = mxser_open,
@@ -504,7 +505,6 @@ static void __exit mxser_module_exit(void)
        else
                printk(KERN_ERR "Couldn't unregister MOXA Smartio/Industio family serial driver\n");
 
-
        for (i = 0; i < MXSER_BOARDS; i++) {
                struct pci_dev *pdev;
 
@@ -513,7 +513,7 @@ static void __exit mxser_module_exit(void)
                else {
                        pdev = mxsercfg[i].pciInfo.pdev;
                        free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);
-                       if (pdev != NULL) {     //PCI
+                       if (pdev != NULL) {     /* PCI */
                                release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
                                release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3));
                        } else {
@@ -524,7 +524,6 @@ static void __exit mxser_module_exit(void)
        }
        if (verbose)
                printk(KERN_DEBUG "Done.\n");
-
 }
 
 static void process_txrx_fifo(struct mxser_struct *info)
@@ -558,8 +557,10 @@ static int mxser_initbrd(int board, struct mxser_hwconf *hwconf)
        n = board * MXSER_PORTS_PER_BOARD;
        info = &mxvar_table[n];
        /*if (verbose) */  {
-               printk(KERN_DEBUG "        ttyM%d - ttyM%d ", n, n + hwconf->ports - 1);
-               printk(" max. baud rate = %d bps.\n", hwconf->MaxCanSetBaudRate[0]);
+               printk(KERN_DEBUG "        ttyM%d - ttyM%d ",
+                       n, n + hwconf->ports - 1);
+               printk(" max. baud rate = %d bps.\n",
+                       hwconf->MaxCanSetBaudRate[0]);
        }
 
        for (i = 0; i < hwconf->ports; i++, n++, info++) {
@@ -568,12 +569,12 @@ static int mxser_initbrd(int board, struct mxser_hwconf *hwconf)
                info->irq = hwconf->irq;
                info->vector = hwconf->vector;
                info->vectormask = hwconf->vector_mask;
-               info->opmode_ioaddr = hwconf->opmode_ioaddr[i]; // add by Victor Yu. 01-05-2004
+               info->opmode_ioaddr = hwconf->opmode_ioaddr[i]; /* add by Victor Yu. 01-05-2004 */
                info->stop_rx = 0;
                info->ldisc_stop_rx = 0;
 
                info->IsMoxaMustChipFlag = hwconf->IsMoxaMustChipFlag;
-               //Enhance mode enabled here
+               /* Enhance mode enabled here */
                if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) {
                        ENABLE_MOXA_MUST_ENCHANCE_MODE(info->base);
                }
@@ -606,22 +607,25 @@ static int mxser_initbrd(int board, struct mxser_hwconf *hwconf)
 
        /* before set INT ISR, disable all int */
        for (i = 0; i < hwconf->ports; i++) {
-               outb(inb(hwconf->ioaddr[i] + UART_IER) & 0xf0, hwconf->ioaddr[i] + UART_IER);
+               outb(inb(hwconf->ioaddr[i] + UART_IER) & 0xf0,
+                       hwconf->ioaddr[i] + UART_IER);
        }
 
        n = board * MXSER_PORTS_PER_BOARD;
        info = &mxvar_table[n];
 
-       retval = request_irq(hwconf->irq, mxser_interrupt, IRQ_T(info), "mxser", info);
+       retval = request_irq(hwconf->irq, mxser_interrupt, IRQ_T(info),
+                               "mxser", info);
        if (retval) {
-               printk(KERN_ERR "Board %d: %s", board, mxser_brdname[hwconf->board_type - 1]);
-               printk("  Request irq fail,IRQ (%d) may be conflit with another device.\n", info->irq);
+               printk(KERN_ERR "Board %d: %s",
+                       board, mxser_brdname[hwconf->board_type - 1]);
+               printk("  Request irq failed, IRQ (%d) may conflict with"
+                       " another device.\n", info->irq);
                return retval;
        }
        return 0;
 }
 
-
 static void mxser_getcfg(int board, struct mxser_hwconf *hwconf)
 {
        mxsercfg[board] = *hwconf;
@@ -631,26 +635,27 @@ static void mxser_getcfg(int board, struct mxser_hwconf *hwconf)
 static int mxser_get_PCI_conf(int busnum, int devnum, int board_type, struct mxser_hwconf *hwconf)
 {
        int i, j;
-//      unsigned int    val;
+       /* unsigned int val; */
        unsigned int ioaddress;
        struct pci_dev *pdev = hwconf->pciInfo.pdev;
 
-       //io address
+       /* io address */
        hwconf->board_type = board_type;
        hwconf->ports = mxser_numports[board_type - 1];
        ioaddress = pci_resource_start(pdev, 2);
-       request_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2), "mxser(IO)");
+       request_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2),
+                       "mxser(IO)");
 
-       for (i = 0; i < hwconf->ports; i++) {
+       for (i = 0; i < hwconf->ports; i++)
                hwconf->ioaddr[i] = ioaddress + 8 * i;
-       }
 
-       //vector
+       /* vector */
        ioaddress = pci_resource_start(pdev, 3);
-       request_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3), "mxser(vector)");
+       request_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3),
+                       "mxser(vector)");
        hwconf->vector = ioaddress;
 
-       //irq
+       /* irq */
        hwconf->irq = hwconf->pciInfo.pdev->irq;
 
        hwconf->IsMoxaMustChipFlag = CheckIsMoxaMust(hwconf->ioaddr[0]);
@@ -663,7 +668,7 @@ static int mxser_get_PCI_conf(int busnum, int devnum, int board_type, struct mxs
                        if (Gpci_uart_info[j].type == hwconf->IsMoxaMustChipFlag) {
                                hwconf->MaxCanSetBaudRate[i] = Gpci_uart_info[j].max_baud;
 
-                               //exception....CP-102
+                               /* exception....CP-102 */
                                if (board_type == MXSER_BOARD_CP102)
                                        hwconf->MaxCanSetBaudRate[i] = 921600;
                                break;
@@ -678,15 +683,15 @@ static int mxser_get_PCI_conf(int busnum, int devnum, int board_type, struct mxs
                        else
                                hwconf->opmode_ioaddr[i] = ioaddress + 0x0c;
                }
-               outb(0, ioaddress + 4); // default set to RS232 mode
-               outb(0, ioaddress + 0x0c);      //default set to RS232 mode
+               outb(0, ioaddress + 4); /* default set to RS232 mode */
+               outb(0, ioaddress + 0x0c);      /* default set to RS232 mode */
        }
 
        for (i = 0; i < hwconf->ports; i++) {
                hwconf->vector_mask |= (1 << i);
                hwconf->baud_base[i] = 921600;
        }
-       return (0);
+       return 0;
 }
 #endif
 
@@ -707,7 +712,8 @@ static int mxser_init(void)
                mxsercfg[i].board_type = -1;
        }
 
-       printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n", MXSER_VERSION);
+       printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n",
+               MXSER_VERSION);
 
        /* Initialize the tty_driver structure */
        memset(mxvar_sdriver, 0, sizeof(struct tty_driver));
@@ -719,7 +725,7 @@ static int mxser_init(void)
        mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL;
        mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
        mxvar_sdriver->init_termios = tty_std_termios;
-       mxvar_sdriver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+       mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
        mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW;
        tty_set_operations(mxvar_sdriver, &mxser_ops);
        mxvar_sdriver->ttys = mxvar_tty;
@@ -739,23 +745,29 @@ static int mxser_init(void)
        /* Start finding ISA boards here */
        for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
                int cap;
+
                if (!(cap = mxserBoardCAP[b]))
                        continue;
 
                retval = mxser_get_ISA_conf(cap, &hwconf);
 
                if (retval != 0)
-                       printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n", mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
+                       printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n",
+                               mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
 
                if (retval <= 0) {
                        if (retval == MXSER_ERR_IRQ)
-                               printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+                               printk(KERN_ERR "Invalid interrupt number, "
+                                       "board not configured\n");
                        else if (retval == MXSER_ERR_IRQ_CONFLIT)
-                               printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+                               printk(KERN_ERR "Invalid interrupt number, "
+                                       "board not configured\n");
                        else if (retval == MXSER_ERR_VECTOR)
-                               printk(KERN_ERR "Invalid interrupt vector,board not configured\n");
+                               printk(KERN_ERR "Invalid interrupt vector, "
+                                       "board not configured\n");
                        else if (retval == MXSER_ERR_IOADDR)
-                               printk(KERN_ERR "Invalid I/O address,board not configured\n");
+                               printk(KERN_ERR "Invalid I/O address, "
+                                       "board not configured\n");
 
                        continue;
                }
@@ -765,35 +777,43 @@ static int mxser_init(void)
                hwconf.pciInfo.pdev = NULL;
 
                mxser_getcfg(m, &hwconf);
-               //init mxsercfg first, or mxsercfg data is not correct on ISR.
-               //mxser_initbrd will hook ISR.
+               /*
+                * init mxsercfg first,
+                * or mxsercfg data is not correct on ISR.
+                */
+               /* mxser_initbrd will hook ISR. */
                if (mxser_initbrd(m, &hwconf) < 0)
                        continue;
 
-
                m++;
        }
 
        /* Start finding ISA boards from module arg */
        for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
                int cap;
+
                if (!(cap = ioaddr[b]))
                        continue;
 
                retval = mxser_get_ISA_conf(cap, &hwconf);
 
                if (retval != 0)
-                       printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n", mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
+                       printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n",
+                               mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
 
                if (retval <= 0) {
                        if (retval == MXSER_ERR_IRQ)
-                               printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+                               printk(KERN_ERR "Invalid interrupt number, "
+                                       "board not configured\n");
                        else if (retval == MXSER_ERR_IRQ_CONFLIT)
-                               printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+                               printk(KERN_ERR "Invalid interrupt number, "
+                                       "board not configured\n");
                        else if (retval == MXSER_ERR_VECTOR)
-                               printk(KERN_ERR "Invalid interrupt vector,board not configured\n");
+                               printk(KERN_ERR "Invalid interrupt vector, "
+                                       "board not configured\n");
                        else if (retval == MXSER_ERR_IOADDR)
-                               printk(KERN_ERR "Invalid I/O address,board not configured\n");
+                               printk(KERN_ERR "Invalid I/O address, "
+                                       "board not configured\n");
 
                        continue;
                }
@@ -803,8 +823,11 @@ static int mxser_init(void)
                hwconf.pciInfo.pdev = NULL;
 
                mxser_getcfg(m, &hwconf);
-               //init mxsercfg first, or mxsercfg data is not correct on ISR.
-               //mxser_initbrd will hook ISR.
+               /*
+                * init mxsercfg first,
+                * or mxsercfg data is not correct on ISR.
+                */
+               /* mxser_initbrd will hook ISR. */
                if (mxser_initbrd(m, &hwconf) < 0)
                        continue;
 
@@ -817,7 +840,8 @@ static int mxser_init(void)
        index = 0;
        b = 0;
        while (b < n) {
-               pdev = pci_find_device(mxser_pcibrds[b].vendor, mxser_pcibrds[b].device, pdev);
+               pdev = pci_find_device(mxser_pcibrds[b].vendor,
+                               mxser_pcibrds[b].device, pdev);
                        if (pdev == NULL) {
                        b++;
                        continue;
@@ -825,30 +849,48 @@ static int mxser_init(void)
                hwconf.pciInfo.busNum = busnum = pdev->bus->number;
                hwconf.pciInfo.devNum = devnum = PCI_SLOT(pdev->devfn) << 3;
                hwconf.pciInfo.pdev = pdev;
-               printk(KERN_INFO "Found MOXA %s board(BusNo=%d,DevNo=%d)\n", mxser_brdname[(int) (mxser_pcibrds[b].driver_data) - 1], busnum, devnum >> 3);
+               printk(KERN_INFO "Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
+                       mxser_brdname[(int) (mxser_pcibrds[b].driver_data) - 1],
+                       busnum, devnum >> 3);
                index++;
-               if (m >= MXSER_BOARDS) {
-                       printk(KERN_ERR "Too many Smartio/Industio family boards find (maximum %d),board not configured\n", MXSER_BOARDS);
-               } else {
+               if (m >= MXSER_BOARDS)
+                       printk(KERN_ERR
+                               "Too many Smartio/Industio family boards find "
+                               "(maximum %d), board not configured\n",
+                               MXSER_BOARDS);
+               else {
                        if (pci_enable_device(pdev)) {
-                               printk(KERN_ERR "Moxa SmartI/O PCI enable fail !\n");
+                               printk(KERN_ERR "Moxa SmartI/O PCI enable "
+                                       "fail !\n");
                                continue;
                        }
-                       retval = mxser_get_PCI_conf(busnum, devnum, (int) mxser_pcibrds[b].driver_data, &hwconf);
+                       retval = mxser_get_PCI_conf(busnum, devnum,
+                                       (int)mxser_pcibrds[b].driver_data,
+                                       &hwconf);
                        if (retval < 0) {
                                if (retval == MXSER_ERR_IRQ)
-                                       printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+                                       printk(KERN_ERR
+                                               "Invalid interrupt number, "
+                                               "board not configured\n");
                                else if (retval == MXSER_ERR_IRQ_CONFLIT)
-                                       printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+                                       printk(KERN_ERR
+                                               "Invalid interrupt number, "
+                                               "board not configured\n");
                                else if (retval == MXSER_ERR_VECTOR)
-                                       printk(KERN_ERR "Invalid interrupt vector,board not configured\n");
+                                       printk(KERN_ERR
+                                               "Invalid interrupt vector, "
+                                               "board not configured\n");
                                else if (retval == MXSER_ERR_IOADDR)
-                                       printk(KERN_ERR "Invalid I/O address,board not configured\n");
+                                       printk(KERN_ERR
+                                               "Invalid I/O address, "
+                                               "board not configured\n");
                                continue;
                        }
                        mxser_getcfg(m, &hwconf);
-                       //init mxsercfg first, or mxsercfg data is not correct on ISR.
-                       //mxser_initbrd will hook ISR.
+                       /* init mxsercfg first,
+                        * or mxsercfg data is not correct on ISR.
+                        */
+                       /* mxser_initbrd will hook ISR. */
                        if (mxser_initbrd(m, &hwconf) < 0)
                                continue;
                        m++;
@@ -858,7 +900,8 @@ static int mxser_init(void)
 
        retval = tty_register_driver(mxvar_sdriver);
        if (retval) {
-               printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family driver !\n");
+               printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family"
+                               " driver !\n");
                put_tty_driver(mxvar_sdriver);
 
                for (i = 0; i < MXSER_BOARDS; i++) {
@@ -866,7 +909,7 @@ static int mxser_init(void)
                                continue;
                        else {
                                free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);
-                               //todo: release io, vector
+                               /* todo: release io, vector */
                        }
                }
                return retval;
@@ -877,7 +920,7 @@ static int mxser_init(void)
 
 static void mxser_do_softint(void *private_)
 {
-       struct mxser_struct *info = (struct mxser_struct *) private_;
+       struct mxser_struct *info = private_;
        struct tty_struct *tty;
 
        tty = info->tty;
@@ -926,7 +969,7 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
                return -ENODEV;
        info = mxvar_table + line;
        if (!info->base)
-               return (-ENODEV);
+               return -ENODEV;
 
        tty->driver_data = info;
        info->tty = tty;
@@ -935,11 +978,11 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
         */
        retval = mxser_startup(info);
        if (retval)
-               return (retval);
+               return retval;
 
        retval = mxser_block_til_ready(tty, filp, info);
        if (retval)
-               return (retval);
+               return retval;
 
        info->count++;
 
@@ -955,11 +998,12 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
        info->pgrp = process_group(current);
        clear_bit(TTY_DONT_FLIP, &tty->flags);
 
-       //status = mxser_get_msr(info->base, 0, info->port);
-       //mxser_check_modem_status(info, status);
+       /*
+       status = mxser_get_msr(info->base, 0, info->port);
+       mxser_check_modem_status(info, status);
+       */
 
-/* unmark here for very high baud rate (ex. 921600 bps) used
-*/
+/* unmark here for very high baud rate (ex. 921600 bps) used */
        tty->low_latency = 1;
        return 0;
 }
@@ -972,7 +1016,7 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
  */
 static void mxser_close(struct tty_struct *tty, struct file *filp)
 {
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+       struct mxser_struct *info = tty->driver_data;
 
        unsigned long timeout;
        unsigned long flags;
@@ -997,11 +1041,13 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
                 * one, we've got real problems, since it means the
                 * serial port won't be shutdown.
                 */
-               printk(KERN_ERR "mxser_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count);
+               printk(KERN_ERR "mxser_close: bad serial port count; "
+                       "tty->count is 1, info->count is %d\n", info->count);
                info->count = 1;
        }
        if (--info->count < 0) {
-               printk(KERN_ERR "mxser_close: bad serial port count for ttys%d: %d\n", info->port, info->count);
+               printk(KERN_ERR "mxser_close: bad serial port count for "
+                       "ttys%d: %d\n", info->port, info->count);
                info->count = 0;
        }
        if (info->count) {
@@ -1056,7 +1102,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
                
        ld = tty_ldisc_ref(tty);
        if (ld) {
-               if(ld->flush_buffer)
+               if (ld->flush_buffer)
                        ld->flush_buffer(tty);
                tty_ldisc_deref(ld);
        }
@@ -1078,31 +1124,34 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
 static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
        int c, total = 0;
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+       struct mxser_struct *info = tty->driver_data;
        unsigned long flags;
 
-       if (!tty || !info->xmit_buf)
-               return (0);
+       if (!info->xmit_buf)
+               return 0;
 
        while (1) {
-               c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head));
+               c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                         SERIAL_XMIT_SIZE - info->xmit_head));
                if (c <= 0)
                        break;
 
                memcpy(info->xmit_buf + info->xmit_head, buf, c);
                spin_lock_irqsave(&info->slock, flags);
-               info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1);
+               info->xmit_head = (info->xmit_head + c) &
+                                 (SERIAL_XMIT_SIZE - 1);
                info->xmit_cnt += c;
                spin_unlock_irqrestore(&info->slock, flags);
 
                buf += c;
                count -= c;
                total += c;
-
        }
 
        if (info->xmit_cnt && !tty->stopped && !(info->IER & UART_IER_THRI)) {
-               if (!tty->hw_stopped || (info->type == PORT_16550A) || (info->IsMoxaMustChipFlag)) {
+               if (!tty->hw_stopped ||
+                               (info->type == PORT_16550A) ||
+                               (info->IsMoxaMustChipFlag)) {
                        spin_lock_irqsave(&info->slock, flags);
                        info->IER |= UART_IER_THRI;
                        outb(info->IER, info->base + UART_IER);
@@ -1114,10 +1163,10 @@ static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int cou
 
 static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
 {
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+       struct mxser_struct *info = tty->driver_data;
        unsigned long flags;
 
-       if (!tty || !info->xmit_buf)
+       if (!info->xmit_buf)
                return;
 
        if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
@@ -1129,7 +1178,9 @@ static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
        info->xmit_cnt++;
        spin_unlock_irqrestore(&info->slock, flags);
        if (!tty->stopped && !(info->IER & UART_IER_THRI)) {
-               if (!tty->hw_stopped || (info->type == PORT_16550A) || info->IsMoxaMustChipFlag) {
+               if (!tty->hw_stopped ||
+                               (info->type == PORT_16550A) ||
+                               info->IsMoxaMustChipFlag) {
                        spin_lock_irqsave(&info->slock, flags);
                        info->IER |= UART_IER_THRI;
                        outb(info->IER, info->base + UART_IER);
@@ -1141,10 +1192,16 @@ static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
 
 static void mxser_flush_chars(struct tty_struct *tty)
 {
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+       struct mxser_struct *info = tty->driver_data;
        unsigned long flags;
 
-       if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf || (tty->hw_stopped && (info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)))
+       if (info->xmit_cnt <= 0 ||
+                       tty->stopped ||
+                       !info->xmit_buf ||
+                       (tty->hw_stopped &&
+                        (info->type != PORT_16550A) &&
+                        (!info->IsMoxaMustChipFlag)
+                       ))
                return;
 
        spin_lock_irqsave(&info->slock, flags);
@@ -1157,24 +1214,24 @@ static void mxser_flush_chars(struct tty_struct *tty)
 
 static int mxser_write_room(struct tty_struct *tty)
 {
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+       struct mxser_struct *info = tty->driver_data;
        int ret;
 
        ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
        if (ret < 0)
                ret = 0;
-       return (ret);
+       return ret;
 }
 
 static int mxser_chars_in_buffer(struct tty_struct *tty)
 {
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+       struct mxser_struct *info = tty->driver_data;
        return info->xmit_cnt;
 }
 
 static void mxser_flush_buffer(struct tty_struct *tty)
 {
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+       struct mxser_struct *info = tty->driver_data;
        char fcr;
        unsigned long flags;
 
@@ -1184,7 +1241,8 @@ static void mxser_flush_buffer(struct tty_struct *tty)
 
        /* below added by shinhay */
        fcr = inb(info->base + UART_FCR);
-       outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), info->base + UART_FCR);
+       outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+               info->base + UART_FCR);
        outb(fcr, info->base + UART_FCR);
 
        spin_unlock_irqrestore(&info->slock, flags);
@@ -1197,7 +1255,7 @@ static void mxser_flush_buffer(struct tty_struct *tty)
 
 static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+       struct mxser_struct *info = tty->driver_data;
        int retval;
        struct async_icount cprev, cnow;        /* kernel counter temps */
        struct serial_icounter_struct __user *p_cuser;
@@ -1206,9 +1264,9 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
        void __user *argp = (void __user *)arg;
 
        if (tty->index == MXSER_PORTS)
-               return (mxser_ioctl_special(cmd, argp));
+               return mxser_ioctl_special(cmd, argp);
 
-       // following add by Victor Yu. 01-05-2004
+       /* following add by Victor Yu. 01-05-2004 */
        if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) {
                int opmode, p;
                static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f };
@@ -1219,7 +1277,10 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
                if (cmd == MOXA_SET_OP_MODE) {
                        if (get_user(opmode, (int __user *) argp))
                                return -EFAULT;
-                       if (opmode != RS232_MODE && opmode != RS485_2WIRE_MODE && opmode != RS422_MODE && opmode != RS485_4WIRE_MODE)
+                       if (opmode != RS232_MODE &&
+                                       opmode != RS485_2WIRE_MODE &&
+                                       opmode != RS422_MODE &&
+                                       opmode != RS485_4WIRE_MODE)
                                return -EFAULT;
                        mask = ModeMask[p];
                        shiftbit = p * 2;
@@ -1236,36 +1297,36 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
                }
                return 0;
        }
-       // above add by Victor Yu. 01-05-2004
+       /* above add by Victor Yu. 01-05-2004 */
 
        if ((cmd != TIOCGSERIAL) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
                if (tty->flags & (1 << TTY_IO_ERROR))
-                       return (-EIO);
+                       return -EIO;
        }
        switch (cmd) {
        case TCSBRK:            /* SVID version: non-zero arg --> no break */
                retval = tty_check_change(tty);
                if (retval)
-                       return (retval);
+                       return retval;
                tty_wait_until_sent(tty, 0);
                if (!arg)
                        mxser_send_break(info, HZ / 4); /* 1/4 second */
-               return (0);
+               return 0;
        case TCSBRKP:           /* support for POSIX tcsendbreak() */
                retval = tty_check_change(tty);
                if (retval)
-                       return (retval);
+                       return retval;
                tty_wait_until_sent(tty, 0);
                mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
-               return (0);
+               return 0;
        case TIOCGSOFTCAR:
-               return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) argp);
+               return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
        case TIOCSSOFTCAR:
                if (get_user(templ, (unsigned long __user *) argp))
                        return -EFAULT;
                arg = templ;
                tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
-               return (0);
+               return 0;
        case TIOCGSERIAL:
                return mxser_get_serial_info(info, argp);
        case TIOCSSERIAL:
@@ -1278,7 +1339,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
                 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
                 * Caller should use TIOCGICOUNT to see which one it was
                 */
-       case TIOCMIWAIT:{
+       case TIOCMIWAIT: {
                        DECLARE_WAITQUEUE(wait, current);
                        int ret;
                        spin_lock_irqsave(&info->slock, flags);
@@ -1292,7 +1353,14 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
                                spin_unlock_irqrestore(&info->slock, flags);
 
                                set_current_state(TASK_INTERRUPTIBLE);
-                               if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
+                               if (((arg & TIOCM_RNG) &&
+                                               (cnow.rng != cprev.rng)) ||
+                                               ((arg & TIOCM_DSR) &&
+                                               (cnow.dsr != cprev.dsr)) ||
+                                               ((arg & TIOCM_CD) &&
+                                               (cnow.dcd != cprev.dcd)) ||
+                                               ((arg & TIOCM_CTS) &&
+                                               (cnow.cts != cprev.cts))) {
                                        ret = 0;
                                        break;
                                }
@@ -1338,21 +1406,18 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
                put_user(cnow.dsr, &p_cuser->dsr);
                put_user(cnow.rng, &p_cuser->rng);
                put_user(cnow.dcd, &p_cuser->dcd);
-
-/* */
                return 0;
        case MOXA_HighSpeedOn:
-               return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *) argp);
-
-       case MOXA_SDS_RSTICOUNTER:{
+               return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
+       case MOXA_SDS_RSTICOUNTER: {
                        info->mon_data.rxcnt = 0;
                        info->mon_data.txcnt = 0;
                        return 0;
                }
-// (above) added by James.
+/* (above) added by James. */
        case MOXA_ASPP_SETBAUD:{
                        long baud;
-                       if (get_user(baud, (long __user *) argp))
+                       if (get_user(baud, (long __user *)argp))
                                return -EFAULT;
                        mxser_set_baud(info, baud);
                        return 0;
@@ -1377,9 +1442,10 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
 
                        return 0;
                }
-       case MOXA_ASPP_MON:{
+       case MOXA_ASPP_MON: {
                        int mcr, status;
-//      info->mon_data.ser_param = tty->termios->c_cflag;
+
+                       /* info->mon_data.ser_param = tty->termios->c_cflag; */
 
                        status = mxser_get_msr(info->base, 1, info->port, info);
                        mxser_check_modem_status(info, status);
@@ -1400,25 +1466,25 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
                        else
                                info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
 
-
-                       if (copy_to_user(argp, &info->mon_data, sizeof(struct mxser_mon)))
+                       if (copy_to_user(argp, &info->mon_data,
+                                       sizeof(struct mxser_mon)))
                                return -EFAULT;
 
                        return 0;
-
                }
 
-       case MOXA_ASPP_LSTATUS:{
-                       if (copy_to_user(argp, &info->err_shadow, sizeof(unsigned char)))
+       case MOXA_ASPP_LSTATUS: {
+                       if (copy_to_user(argp, &info->err_shadow,
+                                       sizeof(unsigned char)))
                                return -EFAULT;
 
                        info->err_shadow = 0;
                        return 0;
-
                }
-       case MOXA_SET_BAUD_METHOD:{
+       case MOXA_SET_BAUD_METHOD: {
                        int method;
-                       if (get_user(method, (int __user *) argp))
+
+                       if (get_user(method, (int __user *)argp))
                                return -EFAULT;
                        mxser_set_baud_method[info->port] = method;
                        if (copy_to_user(argp, &method, sizeof(int)))
@@ -1442,7 +1508,8 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
 
        switch (cmd) {
        case MOXA_GET_CONF:
-               if (copy_to_user(argp, mxsercfg, sizeof(struct mxser_hwconf) * 4))
+               if (copy_to_user(argp, mxsercfg,
+                               sizeof(struct mxser_hwconf) * 4))
                        return -EFAULT;
                return 0;
        case MOXA_GET_MAJOR:
@@ -1461,11 +1528,11 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
                        if (mxvar_table[i].base)
                                result |= (1 << i);
                }
-               return put_user(result, (unsigned long __user *) argp);
+               return put_user(result, (unsigned long __user *)argp);
        case MOXA_GETDATACOUNT:
                if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
                        return -EFAULT;
-               return (0);
+               return 0;
        case MOXA_GETMSTATUS:
                for (i = 0; i < MXSER_PORTS; i++) {
                        GMStatus[i].ri = 0;
@@ -1498,22 +1565,26 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
                        else
                                GMStatus[i].cts = 0;
                }
-               if (copy_to_user(argp, GMStatus, sizeof(struct mxser_mstatus) * MXSER_PORTS))
+               if (copy_to_user(argp, GMStatus,
+                               sizeof(struct mxser_mstatus) * MXSER_PORTS))
                        return -EFAULT;
                return 0;
-       case MOXA_ASPP_MON_EXT:{
+       case MOXA_ASPP_MON_EXT: {
                        int status;
                        int opmode, p;
                        int shiftbit;
                        unsigned cflag, iflag;
 
                        for (i = 0; i < MXSER_PORTS; i++) {
-
                                if (!mxvar_table[i].base)
                                        continue;
 
-                               status = mxser_get_msr(mxvar_table[i].base, 0, i, &(mxvar_table[i]));
-//                      mxser_check_modem_status(&mxvar_table[i], status);
+                               status = mxser_get_msr(mxvar_table[i].base, 0,
+                                                       i, &(mxvar_table[i]));
+                               /*
+                               mxser_check_modem_status(&mxvar_table[i],
+                                                               status);
+                               */
                                if (status & UART_MSR_TERI)
                                        mxvar_table[i].icount.rng++;
                                if (status & UART_MSR_DDSR)
@@ -1578,75 +1649,76 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
        return 0;
 }
 
-
 static void mxser_stoprx(struct tty_struct *tty)
 {
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
-       //unsigned long flags;
-
+       struct mxser_struct *info = tty->driver_data;
+       /* unsigned long flags; */
 
        info->ldisc_stop_rx = 1;
        if (I_IXOFF(tty)) {
-
-               //MX_LOCK(&info->slock);
-               // following add by Victor Yu. 09-02-2002
+               /* MX_LOCK(&info->slock); */
+               /* following add by Victor Yu. 09-02-2002 */
                if (info->IsMoxaMustChipFlag) {
                        info->IER &= ~MOXA_MUST_RECV_ISR;
                        outb(info->IER, info->base + UART_IER);
                } else {
-                       // above add by Victor Yu. 09-02-2002
-
+                       /* above add by Victor Yu. 09-02-2002 */
                        info->x_char = STOP_CHAR(tty);
-                       //      outb(info->IER, 0); // mask by Victor Yu. 09-02-2002
+                       /* mask by Victor Yu. 09-02-2002 */
+                       /* outb(info->IER, 0); */
                        outb(0, info->base + UART_IER);
                        info->IER |= UART_IER_THRI;
-                       outb(info->IER, info->base + UART_IER); /* force Tx interrupt */
-               }               // add by Victor Yu. 09-02-2002
-               //MX_UNLOCK(&info->slock);
+                       /* force Tx interrupt */
+                       outb(info->IER, info->base + UART_IER);
+               }               /* add by Victor Yu. 09-02-2002 */
+               /* MX_UNLOCK(&info->slock); */
        }
 
        if (info->tty->termios->c_cflag & CRTSCTS) {
-               //MX_LOCK(&info->slock);
+               /* MX_LOCK(&info->slock); */
                info->MCR &= ~UART_MCR_RTS;
                outb(info->MCR, info->base + UART_MCR);
-               //MX_UNLOCK(&info->slock);
+               /* MX_UNLOCK(&info->slock); */
        }
 }
 
 static void mxser_startrx(struct tty_struct *tty)
 {
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
-       //unsigned long flags;
+       struct mxser_struct *info = tty->driver_data;
+       /* unsigned long flags; */
 
        info->ldisc_stop_rx = 0;
        if (I_IXOFF(tty)) {
                if (info->x_char)
                        info->x_char = 0;
                else {
-                       //MX_LOCK(&info->slock);
+                       /* MX_LOCK(&info->slock); */
 
-                       // following add by Victor Yu. 09-02-2002
+                       /* following add by Victor Yu. 09-02-2002 */
                        if (info->IsMoxaMustChipFlag) {
                                info->IER |= MOXA_MUST_RECV_ISR;
                                outb(info->IER, info->base + UART_IER);
                        } else {
-                               // above add by Victor Yu. 09-02-2002
+                               /* above add by Victor Yu. 09-02-2002 */
 
                                info->x_char = START_CHAR(tty);
-                               //          outb(info->IER, 0); // mask by Victor Yu. 09-02-2002
-                               outb(0, info->base + UART_IER); // add by Victor Yu. 09-02-2002
-                               info->IER |= UART_IER_THRI;     /* force Tx interrupt */
+                               /* mask by Victor Yu. 09-02-2002 */
+                               /* outb(info->IER, 0); */
+                               /* add by Victor Yu. 09-02-2002 */
+                               outb(0, info->base + UART_IER);
+                               /* force Tx interrupt */
+                               info->IER |= UART_IER_THRI;
                                outb(info->IER, info->base + UART_IER);
-                       }       // add by Victor Yu. 09-02-2002
-                       //MX_UNLOCK(&info->slock);
+                       }       /* add by Victor Yu. 09-02-2002 */
+                       /* MX_UNLOCK(&info->slock); */
                }
        }
 
        if (info->tty->termios->c_cflag & CRTSCTS) {
-               //MX_LOCK(&info->slock);
+               /* MX_LOCK(&info->slock); */
                info->MCR |= UART_MCR_RTS;
                outb(info->MCR, info->base + UART_MCR);
-               //MX_UNLOCK(&info->slock);
+               /* MX_UNLOCK(&info->slock); */
        }
 }
 
@@ -1656,48 +1728,53 @@ static void mxser_startrx(struct tty_struct *tty)
  */
 static void mxser_throttle(struct tty_struct *tty)
 {
-       //struct mxser_struct *info = (struct mxser_struct *)tty->driver_data;
-       //unsigned long flags;
-       //MX_LOCK(&info->slock);
+       /* struct mxser_struct *info = tty->driver_data; */
+       /* unsigned long flags; */
+
+       /* MX_LOCK(&info->slock); */
        mxser_stoprx(tty);
-       //MX_UNLOCK(&info->slock);
+       /* MX_UNLOCK(&info->slock); */
 }
 
 static void mxser_unthrottle(struct tty_struct *tty)
 {
-       //struct mxser_struct *info = (struct mxser_struct *)tty->driver_data;
-       //unsigned long flags;
-       //MX_LOCK(&info->slock);
+       /* struct mxser_struct *info = tty->driver_data; */
+       /* unsigned long flags; */
+
+       /* MX_LOCK(&info->slock); */
        mxser_startrx(tty);
-       //MX_UNLOCK(&info->slock);
+       /* MX_UNLOCK(&info->slock); */
 }
 
 static void mxser_set_termios(struct tty_struct *tty, struct termios *old_termios)
 {
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+       struct mxser_struct *info = tty->driver_data;
        unsigned long flags;
 
-       if ((tty->termios->c_cflag != old_termios->c_cflag) || (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) {
+       if ((tty->termios->c_cflag != old_termios->c_cflag) ||
+                       (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) {
 
                mxser_change_speed(info, old_termios);
 
-               if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
+               if ((old_termios->c_cflag & CRTSCTS) &&
+                               !(tty->termios->c_cflag & CRTSCTS)) {
                        tty->hw_stopped = 0;
                        mxser_start(tty);
                }
        }
 
 /* Handle sw stopped */
-       if ((old_termios->c_iflag & IXON) && !(tty->termios->c_iflag & IXON)) {
+       if ((old_termios->c_iflag & IXON) &&
+                       !(tty->termios->c_iflag & IXON)) {
                tty->stopped = 0;
 
-               // following add by Victor Yu. 09-02-2002
+               /* following add by Victor Yu. 09-02-2002 */
                if (info->IsMoxaMustChipFlag) {
                        spin_lock_irqsave(&info->slock, flags);
                        DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base);
                        spin_unlock_irqrestore(&info->slock, flags);
                }
-               // above add by Victor Yu. 09-02-2002
+               /* above add by Victor Yu. 09-02-2002 */
 
                mxser_start(tty);
        }
@@ -1711,7 +1788,7 @@ static void mxser_set_termios(struct tty_struct *tty, struct termios *old_termio
  */
 static void mxser_stop(struct tty_struct *tty)
 {
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+       struct mxser_struct *info = tty->driver_data;
        unsigned long flags;
 
        spin_lock_irqsave(&info->slock, flags);
@@ -1724,7 +1801,7 @@ static void mxser_stop(struct tty_struct *tty)
 
 static void mxser_start(struct tty_struct *tty)
 {
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+       struct mxser_struct *info = tty->driver_data;
        unsigned long flags;
 
        spin_lock_irqsave(&info->slock, flags);
@@ -1740,7 +1817,7 @@ static void mxser_start(struct tty_struct *tty)
  */
 static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
 {
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+       struct mxser_struct *info = tty->driver_data;
        unsigned long orig_jiffies, char_time;
        int lsr;
 
@@ -1777,7 +1854,8 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
        if (!timeout || timeout > 2 * info->timeout)
                timeout = 2 * info->timeout;
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-       printk(KERN_DEBUG "In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
+       printk(KERN_DEBUG "In rs_wait_until_sent(%d) check=%lu...",
+               timeout, char_time);
        printk("jiff=%lu...", jiffies);
 #endif
        while (!((lsr = inb(info->base + UART_LSR)) & UART_LSR_TEMT)) {
@@ -1803,7 +1881,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
  */
 void mxser_hangup(struct tty_struct *tty)
 {
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+       struct mxser_struct *info = tty->driver_data;
 
        mxser_flush_buffer(tty);
        mxser_shutdown(info);
@@ -1815,24 +1893,26 @@ void mxser_hangup(struct tty_struct *tty)
 }
 
 
-// added by James 03-12-2004.
+/* added by James 03-12-2004. */
 /*
  * mxser_rs_break() --- routine which turns the break handling on or off
  */
 static void mxser_rs_break(struct tty_struct *tty, int break_state)
 {
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+       struct mxser_struct *info = tty->driver_data;
        unsigned long flags;
 
        spin_lock_irqsave(&info->slock, flags);
        if (break_state == -1)
-               outb(inb(info->base + UART_LCR) | UART_LCR_SBC, info->base + UART_LCR);
+               outb(inb(info->base + UART_LCR) | UART_LCR_SBC,
+                       info->base + UART_LCR);
        else
-               outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, info->base + UART_LCR);
+               outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC,
+                       info->base + UART_LCR);
        spin_unlock_irqrestore(&info->slock, flags);
 }
 
-// (above) added by James.
+/* (above) added by James. */
 
 
 /*
@@ -1848,7 +1928,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        int handled = IRQ_NONE;
 
        port = NULL;
-       //spin_lock(&gm_lock);
+       /* spin_lock(&gm_lock); */
 
        for (i = 0; i < MXSER_BOARDS; i++) {
                if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) {
@@ -1857,29 +1937,25 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                }
        }
 
-       if (i == MXSER_BOARDS) {
+       if (i == MXSER_BOARDS)
                goto irq_stop;
-       }
-       if (port == 0) {
+       if (port == 0)
                goto irq_stop;
-       }
        max = mxser_numports[mxsercfg[i].board_type - 1];
        while (1) {
                irqbits = inb(port->vector) & port->vectormask;
-               if (irqbits == port->vectormask) {
+               if (irqbits == port->vectormask)
                        break;
-               }
 
                handled = IRQ_HANDLED;
                for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
-                       if (irqbits == port->vectormask) {
+                       if (irqbits == port->vectormask)
                                break;
-                       }
                        if (bits & irqbits)
                                continue;
                        info = port + i;
 
-                       // following add by Victor Yu. 09-13-2002
+                       /* following add by Victor Yu. 09-13-2002 */
                        iir = inb(info->base + UART_IIR);
                        if (iir & UART_IIR_NO_INT)
                                continue;
@@ -1890,9 +1966,9 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                                inb(info->base + UART_MSR);
                                continue;
                        }
-                       // above add by Victor Yu. 09-13-2002
+                       /* above add by Victor Yu. 09-13-2002 */
                        /*
-                          if ( info->tty->flip.count < TTY_FLIPBUF_SIZE/4 ){
+                          if (info->tty->flip.count < TTY_FLIPBUF_SIZE / 4) {
                           info->IER |= MOXA_MUST_RECV_ISR;
                           outb(info->IER, info->base + UART_IER);
                           }
@@ -1908,18 +1984,15 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                           status = inb(info->base + UART_LSR) & info->read_status_mask;
                         */
 
-                       // following add by Victor Yu. 09-02-2002
+                       /* following add by Victor Yu. 09-02-2002 */
                        status = inb(info->base + UART_LSR);
 
-                       if (status & UART_LSR_PE) {
+                       if (status & UART_LSR_PE)
                                info->err_shadow |= NPPI_NOTIFY_PARITY;
-                       }
-                       if (status & UART_LSR_FE) {
+                       if (status & UART_LSR_FE)
                                info->err_shadow |= NPPI_NOTIFY_FRAMING;
-                       }
-                       if (status & UART_LSR_OE) {
+                       if (status & UART_LSR_OE)
                                info->err_shadow |= NPPI_NOTIFY_HW_OVERRUN;
-                       }
                        if (status & UART_LSR_BI)
                                info->err_shadow |= NPPI_NOTIFY_BREAK;
 
@@ -1930,11 +2003,14 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                                   continue;
                                   }
                                 */
-                               if (iir == MOXA_MUST_IIR_GDA || iir == MOXA_MUST_IIR_RDA || iir == MOXA_MUST_IIR_RTO || iir == MOXA_MUST_IIR_LSR)
+                               if (iir == MOXA_MUST_IIR_GDA ||
+                                               iir == MOXA_MUST_IIR_RDA ||
+                                               iir == MOXA_MUST_IIR_RTO ||
+                                               iir == MOXA_MUST_IIR_LSR)
                                        mxser_receive_chars(info, &status);
 
                        } else {
-                               // above add by Victor Yu. 09-02-2002
+                               /* above add by Victor Yu. 09-02-2002 */
 
                                status &= info->read_status_mask;
                                if (status & UART_LSR_DR)
@@ -1944,13 +2020,13 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                        if (msr & UART_MSR_ANY_DELTA) {
                                mxser_check_modem_status(info, msr);
                        }
-                       // following add by Victor Yu. 09-13-2002
+                       /* following add by Victor Yu. 09-13-2002 */
                        if (info->IsMoxaMustChipFlag) {
                                if ((iir == 0x02) && (status & UART_LSR_THRE)) {
                                        mxser_transmit_chars(info);
                                }
                        } else {
-                               // above add by Victor Yu. 09-13-2002
+                               /* above add by Victor Yu. 09-13-2002 */
 
                                if (status & UART_LSR_THRE) {
 /* 8-2-99 by William
@@ -1966,7 +2042,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        }
 
       irq_stop:
-       //spin_unlock(&gm_lock);
+       /* spin_unlock(&gm_lock); */
        return handled;
 }
 
@@ -1984,56 +2060,58 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status)
 
        recv_room = tty->receive_room;
        if ((recv_room == 0) && (!info->ldisc_stop_rx)) {
-               //mxser_throttle(tty);
+               /* mxser_throttle(tty); */
                mxser_stoprx(tty);
-               //return;
+               /* return; */
        }
 
-       // following add by Victor Yu. 09-02-2002
+       /* following add by Victor Yu. 09-02-2002 */
        if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) {
 
                if (*status & UART_LSR_SPECIAL) {
                        goto intr_old;
                }
-               // following add by Victor Yu. 02-11-2004
-               if (info->IsMoxaMustChipFlag == MOXA_MUST_MU860_HWID && (*status & MOXA_MUST_LSR_RERR))
+               /* following add by Victor Yu. 02-11-2004 */
+               if (info->IsMoxaMustChipFlag == MOXA_MUST_MU860_HWID &&
+                               (*status & MOXA_MUST_LSR_RERR))
                        goto intr_old;
-               // above add by Victor Yu. 02-14-2004
+               /* above add by Victor Yu. 02-14-2004 */
                if (*status & MOXA_MUST_LSR_RERR)
                        goto intr_old;
 
                gdl = inb(info->base + MOXA_MUST_GDL_REGISTER);
 
-               if (info->IsMoxaMustChipFlag == MOXA_MUST_MU150_HWID)   // add by Victor Yu. 02-11-2004
+               /* add by Victor Yu. 02-11-2004 */
+               if (info->IsMoxaMustChipFlag == MOXA_MUST_MU150_HWID)
                        gdl &= MOXA_MUST_GDL_MASK;
                if (gdl >= recv_room) {
                        if (!info->ldisc_stop_rx) {
-                               //mxser_throttle(tty);
+                               /* mxser_throttle(tty); */
                                mxser_stoprx(tty);
                        }
-                       //return;
+                       /* return; */
                }
                while (gdl--) {
                        ch = inb(info->base + UART_RX);
                        tty_insert_flip_char(tty, ch, 0);
                        cnt++;
                        /*
-                          if((cnt>=HI_WATER) && (info->stop_rx==0)){
+                          if ((cnt >= HI_WATER) && (info->stop_rx == 0)) {
                           mxser_stoprx(tty);
-                          info->stop_rx=1;
+                          info->stop_rx = 1;
                           break;
                           } */
                }
                goto end_intr;
        }
-intr_old:
-       // above add by Victor Yu. 09-02-2002
+ intr_old:
+       /* above add by Victor Yu. 09-02-2002 */
 
        do {
                if (max-- < 0)
                        break;
                /*
-                  if((cnt>=HI_WATER) && (info->stop_rx==0)){
+                  if ((cnt >= HI_WATER) && (info->stop_rx == 0)) {
                   mxser_stoprx(tty);
                   info->stop_rx=1;
                   break;
@@ -2041,11 +2119,11 @@ intr_old:
                 */
 
                ch = inb(info->base + UART_RX);
-               // following add by Victor Yu. 09-02-2002
+               /* following add by Victor Yu. 09-02-2002 */
                if (info->IsMoxaMustChipFlag && (*status & UART_LSR_OE) /*&& !(*status&UART_LSR_DR) */ )
                        outb(0x23, info->base + UART_FCR);
                *status &= info->read_status_mask;
-               // above add by Victor Yu. 09-02-2002
+               /* above add by Victor Yu. 09-02-2002 */
                if (*status & info->ignore_status_mask) {
                        if (++ignored > 100)
                                break;
@@ -2080,7 +2158,7 @@ intr_old:
                        cnt++;
                        if (cnt >= recv_room) {
                                if (!info->ldisc_stop_rx) {
-                                       //mxser_throttle(tty);
+                                       /* mxser_throttle(tty); */
                                        mxser_stoprx(tty);
                                }
                                break;
@@ -2088,21 +2166,20 @@ intr_old:
 
                }
 
-               // following add by Victor Yu. 09-02-2002
+               /* following add by Victor Yu. 09-02-2002 */
                if (info->IsMoxaMustChipFlag)
                        break;
-               // above add by Victor Yu. 09-02-2002
+               /* above add by Victor Yu. 09-02-2002 */
 
                /* mask by Victor Yu. 09-02-2002
                 *status = inb(info->base + UART_LSR) & info->read_status_mask;
                 */
-               // following add by Victor Yu. 09-02-2002
+               /* following add by Victor Yu. 09-02-2002 */
                *status = inb(info->base + UART_LSR);
-               // above add by Victor Yu. 09-02-2002
+               /* above add by Victor Yu. 09-02-2002 */
        } while (*status & UART_LSR_DR);
 
-end_intr:              // add by Victor Yu. 09-02-2002
-
+end_intr:              /* add by Victor Yu. 09-02-2002 */
        mxvar_log.rxcnt[info->port] += cnt;
        info->mon_data.rxcnt += cnt;
        info->mon_data.up_rxcnt += cnt;
@@ -2137,7 +2214,10 @@ static void mxser_transmit_chars(struct mxser_struct *info)
                return;
        }
 
-       if ((info->xmit_cnt <= 0) || info->tty->stopped || (info->tty->hw_stopped && (info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag))) {
+       if ((info->xmit_cnt <= 0) || info->tty->stopped ||
+                       (info->tty->hw_stopped &&
+                       (info->type != PORT_16550A) &&
+                       (!info->IsMoxaMustChipFlag))) {
                info->IER &= ~UART_IER_THRI;
                outb(info->IER, info->base + UART_IER);
                spin_unlock_irqrestore(&info->slock, flags);
@@ -2147,17 +2227,18 @@ static void mxser_transmit_chars(struct mxser_struct *info)
        cnt = info->xmit_cnt;
        count = info->xmit_fifo_size;
        do {
-               outb(info->xmit_buf[info->xmit_tail++], info->base + UART_TX);
+               outb(info->xmit_buf[info->xmit_tail++],
+                       info->base + UART_TX);
                info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE - 1);
                if (--info->xmit_cnt <= 0)
                        break;
        } while (--count > 0);
        mxvar_log.txcnt[info->port] += (cnt - info->xmit_cnt);
 
-// added by James 03-12-2004.
+/* added by James 03-12-2004. */
        info->mon_data.txcnt += (cnt - info->xmit_cnt);
        info->mon_data.up_txcnt += (cnt - info->xmit_cnt);
-// (above) added by James.
+/* (above) added by James. */
 
 /* added by casper 1/11/2000 */
        info->icount.tx += (cnt - info->xmit_cnt);
@@ -2188,7 +2269,6 @@ static void mxser_check_modem_status(struct mxser_struct *info, int status)
        info->mon_data.modem_status = status;
        wake_up_interruptible(&info->delta_msr_wait);
 
-
        if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
                if (status & UART_MSR_DCD)
                        wake_up_interruptible(&info->open_wait);
@@ -2200,7 +2280,8 @@ static void mxser_check_modem_status(struct mxser_struct *info, int status)
                        if (status & UART_MSR_CTS) {
                                info->tty->hw_stopped = 0;
 
-                               if ((info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)) {
+                               if ((info->type != PORT_16550A) &&
+                                               (!info->IsMoxaMustChipFlag)) {
                                        info->IER |= UART_IER_THRI;
                                        outb(info->IER, info->base + UART_IER);
                                }
@@ -2209,7 +2290,8 @@ static void mxser_check_modem_status(struct mxser_struct *info, int status)
                } else {
                        if (!(status & UART_MSR_CTS)) {
                                info->tty->hw_stopped = 1;
-                               if ((info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)) {
+                               if ((info->type != PORT_16550A) &&
+                                               (!info->IsMoxaMustChipFlag)) {
                                        info->IER &= ~UART_IER_THRI;
                                        outb(info->IER, info->base + UART_IER);
                                }
@@ -2231,7 +2313,7 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, stru
         */
        if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
                info->flags |= ASYNC_NORMAL_ACTIVE;
-               return (0);
+               return 0;
        }
 
        if (tty->termios->c_cflag & CLOCAL)
@@ -2254,7 +2336,8 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, stru
        info->blocked_open++;
        while (1) {
                spin_lock_irqsave(&info->slock, flags);
-               outb(inb(info->base + UART_MCR) | UART_MCR_DTR | UART_MCR_RTS, info->base + UART_MCR);
+               outb(inb(info->base + UART_MCR) |
+                       UART_MCR_DTR | UART_MCR_RTS, info->base + UART_MCR);
                spin_unlock_irqrestore(&info->slock, flags);
                set_current_state(TASK_INTERRUPTIBLE);
                if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) {
@@ -2264,7 +2347,9 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, stru
                                retval = -ERESTARTSYS;
                        break;
                }
-               if (!(info->flags & ASYNC_CLOSING) && (do_clocal || (inb(info->base + UART_MSR) & UART_MSR_DCD)))
+               if (!(info->flags & ASYNC_CLOSING) &&
+                               (do_clocal ||
+                               (inb(info->base + UART_MSR) & UART_MSR_DCD)))
                        break;
                if (signal_pending(current)) {
                        retval = -ERESTARTSYS;
@@ -2278,27 +2363,26 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, stru
                info->count++;
        info->blocked_open--;
        if (retval)
-               return (retval);
+               return retval;
        info->flags |= ASYNC_NORMAL_ACTIVE;
-       return (0);
+       return 0;
 }
 
 static int mxser_startup(struct mxser_struct *info)
 {
-
        unsigned long page;
        unsigned long flags;
 
        page = __get_free_page(GFP_KERNEL);
        if (!page)
-               return (-ENOMEM);
+               return -ENOMEM;
 
        spin_lock_irqsave(&info->slock, flags);
 
        if (info->flags & ASYNC_INITIALIZED) {
                free_page(page);
                spin_unlock_irqrestore(&info->slock, flags);
-               return (0);
+               return 0;
        }
 
        if (!info->base || !info->type) {
@@ -2306,7 +2390,7 @@ static int mxser_startup(struct mxser_struct *info)
                        set_bit(TTY_IO_ERROR, &info->tty->flags);
                free_page(page);
                spin_unlock_irqrestore(&info->slock, flags);
-               return (0);
+               return 0;
        }
        if (info->xmit_buf)
                free_page(page);
@@ -2318,9 +2402,12 @@ static int mxser_startup(struct mxser_struct *info)
         * (they will be reenabled in mxser_change_speed())
         */
        if (info->IsMoxaMustChipFlag)
-               outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
+               outb((UART_FCR_CLEAR_RCVR |
+                       UART_FCR_CLEAR_XMIT |
+                       MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
        else
-               outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), info->base + UART_FCR);
+               outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+                       info->base + UART_FCR);
 
        /*
         * At this point there's no way the LSR could still be 0xFF;
@@ -2332,9 +2419,9 @@ static int mxser_startup(struct mxser_struct *info)
                if (capable(CAP_SYS_ADMIN)) {
                        if (info->tty)
                                set_bit(TTY_IO_ERROR, &info->tty->flags);
-                       return (0);
+                       return 0;
                } else
-                       return (-ENODEV);
+                       return -ENODEV;
        }
 
        /*
@@ -2356,12 +2443,12 @@ static int mxser_startup(struct mxser_struct *info)
         * Finally, enable interrupts
         */
        info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
-//      info->IER = UART_IER_RLSI | UART_IER_RDI;
+       /* info->IER = UART_IER_RLSI | UART_IER_RDI; */
 
-       // following add by Victor Yu. 08-30-2002
+       /* following add by Victor Yu. 08-30-2002 */
        if (info->IsMoxaMustChipFlag)
                info->IER |= MOXA_MUST_IER_EGDAI;
-       // above add by Victor Yu. 08-30-2002
+       /* above add by Victor Yu. 08-30-2002 */
        outb(info->IER, info->base + UART_IER); /* enable interrupts */
 
        /*
@@ -2383,7 +2470,7 @@ static int mxser_startup(struct mxser_struct *info)
        mxser_change_speed(info, NULL);
 
        info->flags |= ASYNC_INITIALIZED;
-       return (0);
+       return 0;
 }
 
 /*
@@ -2421,12 +2508,15 @@ static void mxser_shutdown(struct mxser_struct *info)
        outb(info->MCR, info->base + UART_MCR);
 
        /* clear Rx/Tx FIFO's */
-       // following add by Victor Yu. 08-30-2002
+       /* following add by Victor Yu. 08-30-2002 */
        if (info->IsMoxaMustChipFlag)
-               outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
+               outb((UART_FCR_CLEAR_RCVR |
+                       UART_FCR_CLEAR_XMIT |
+                       MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
        else
-               // above add by Victor Yu. 08-30-2002
-               outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), info->base + UART_FCR);
+               /* above add by Victor Yu. 08-30-2002 */
+               outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+                       info->base + UART_FCR);
 
        /* read data port to reset things */
        (void) inb(info->base + UART_RX);
@@ -2436,11 +2526,10 @@ static void mxser_shutdown(struct mxser_struct *info)
 
        info->flags &= ~ASYNC_INITIALIZED;
 
-       // following add by Victor Yu. 09-23-2002
-       if (info->IsMoxaMustChipFlag) {
+       /* following add by Victor Yu. 09-23-2002 */
+       if (info->IsMoxaMustChipFlag)
                SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->base);
-       }
-       // above add by Victor Yu. 09-23-2002
+       /* above add by Victor Yu. 09-23-2002 */
 
        spin_unlock_irqrestore(&info->slock, flags);
 }
@@ -2457,14 +2546,12 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
        long baud;
        unsigned long flags;
 
-
        if (!info->tty || !info->tty->termios)
                return ret;
        cflag = info->tty->termios->c_cflag;
        if (!(info->base))
                return ret;
 
-
 #ifndef B921600
 #define B921600 (B460800 +1)
 #endif
@@ -2559,9 +2646,8 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
                cval |= 0x04;
        if (cflag & PARENB)
                cval |= UART_LCR_PARITY;
-       if (!(cflag & PARODD)) {
+       if (!(cflag & PARODD))
                cval |= UART_LCR_EPAR;
-       }
        if (cflag & CMSPAR)
                cval |= UART_LCR_SPAR;
 
@@ -2574,13 +2660,12 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
                        fcr = 0;
        } else {
                fcr = UART_FCR_ENABLE_FIFO;
-               // following add by Victor Yu. 08-30-2002
+               /* following add by Victor Yu. 08-30-2002 */
                if (info->IsMoxaMustChipFlag) {
                        fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
                        SET_MOXA_MUST_FIFO_VALUE(info);
                } else {
-                       // above add by Victor Yu. 08-30-2002
-
+                       /* above add by Victor Yu. 08-30-2002 */
                        switch (info->rx_trigger) {
                        case 1:
                                fcr |= UART_FCR_TRIGGER_1;
@@ -2606,22 +2691,24 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
                info->IER |= UART_IER_MSI;
                if ((info->type == PORT_16550A) || (info->IsMoxaMustChipFlag)) {
                        info->MCR |= UART_MCR_AFE;
-                       //status = mxser_get_msr(info->base, 0, info->port);
-/*     save_flags(flags);
+                       /* status = mxser_get_msr(info->base, 0, info->port); */
+/*
+       save_flags(flags);
        cli();
        status = inb(baseaddr + UART_MSR);
-       restore_flags(flags);*/
-                       //mxser_check_modem_status(info, status);
+       restore_flags(flags);
+*/
+                       /* mxser_check_modem_status(info, status); */
                } else {
-                       //status = mxser_get_msr(info->base, 0, info->port);
-
-                       //MX_LOCK(&info->slock);
+                       /* status = mxser_get_msr(info->base, 0, info->port); */
+                       /* MX_LOCK(&info->slock); */
                        status = inb(info->base + UART_MSR);
-                       //MX_UNLOCK(&info->slock);
+                       /* MX_UNLOCK(&info->slock); */
                        if (info->tty->hw_stopped) {
                                if (status & UART_MSR_CTS) {
                                        info->tty->hw_stopped = 0;
-                                       if ((info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)) {
+                                       if ((info->type != PORT_16550A) &&
+                                                       (!info->IsMoxaMustChipFlag)) {
                                                info->IER |= UART_IER_THRI;
                                                outb(info->IER, info->base + UART_IER);
                                        }
@@ -2630,7 +2717,8 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
                        } else {
                                if (!(status & UART_MSR_CTS)) {
                                        info->tty->hw_stopped = 1;
-                                       if ((info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)) {
+                                       if ((info->type != PORT_16550A) &&
+                                                       (!info->IsMoxaMustChipFlag)) {
                                                info->IER &= ~UART_IER_THRI;
                                                outb(info->IER, info->base + UART_IER);
                                        }
@@ -2668,11 +2756,17 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
                 * overruns too.  (For real raw support).
                 */
                if (I_IGNPAR(info->tty)) {
-                       info->ignore_status_mask |= UART_LSR_OE | UART_LSR_PE | UART_LSR_FE;
-                       info->read_status_mask |= UART_LSR_OE | UART_LSR_PE | UART_LSR_FE;
+                       info->ignore_status_mask |=
+                                               UART_LSR_OE |
+                                               UART_LSR_PE |
+                                               UART_LSR_FE;
+                       info->read_status_mask |=
+                                               UART_LSR_OE |
+                                               UART_LSR_PE |
+                                               UART_LSR_FE;
                }
        }
-       // following add by Victor Yu. 09-02-2002
+       /* following add by Victor Yu. 09-02-2002 */
        if (info->IsMoxaMustChipFlag) {
                spin_lock_irqsave(&info->slock, flags);
                SET_MOXA_MUST_XON1_VALUE(info->base, START_CHAR(info->tty));
@@ -2698,7 +2792,7 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
                 */
                spin_unlock_irqrestore(&info->slock, flags);
        }
-       // above add by Victor Yu. 09-02-2002
+       /* above add by Victor Yu. 09-02-2002 */
 
 
        outb(fcr, info->base + UART_FCR);       /* set fcr */
@@ -2729,10 +2823,8 @@ static int mxser_set_baud(struct mxser_struct *info, long newspd)
                quot = (2 * info->baud_base / 269);
        } else if (newspd) {
                quot = info->baud_base / newspd;
-
                if (quot == 0)
                        quot = 1;
-
        } else {
                quot = 0;
        }
@@ -2765,8 +2857,6 @@ static int mxser_set_baud(struct mxser_struct *info, long newspd)
        return ret;
 }
 
-
-
 /*
  * ------------------------------------------------------------
  * friends of mxser_ioctl()
@@ -2777,7 +2867,7 @@ static int mxser_get_serial_info(struct mxser_struct *info, struct serial_struct
        struct serial_struct tmp;
 
        if (!retinfo)
-               return (-EFAULT);
+               return -EFAULT;
        memset(&tmp, 0, sizeof(tmp));
        tmp.type = info->type;
        tmp.line = info->port;
@@ -2791,7 +2881,7 @@ static int mxser_get_serial_info(struct mxser_struct *info, struct serial_struct
        tmp.hub6 = 0;
        if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
                return -EFAULT;
-       return (0);
+       return 0;
 }
 
 static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct __user *new_info)
@@ -2801,29 +2891,37 @@ static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct
        int retval = 0;
 
        if (!new_info || !info->base)
-               return (-EFAULT);
+               return -EFAULT;
        if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
                return -EFAULT;
 
-       if ((new_serial.irq != info->irq) || (new_serial.port != info->base) || (new_serial.custom_divisor != info->custom_divisor) || (new_serial.baud_base != info->baud_base))
-               return (-EPERM);
+       if ((new_serial.irq != info->irq) ||
+                       (new_serial.port != info->base) ||
+                       (new_serial.custom_divisor != info->custom_divisor) ||
+                       (new_serial.baud_base != info->baud_base))
+               return -EPERM;
 
        flags = info->flags & ASYNC_SPD_MASK;
 
        if (!capable(CAP_SYS_ADMIN)) {
-               if ((new_serial.baud_base != info->baud_base) || (new_serial.close_delay != info->close_delay) || ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK)))
-                       return (-EPERM);
-               info->flags = ((info->flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK));
+               if ((new_serial.baud_base != info->baud_base) ||
+                               (new_serial.close_delay != info->close_delay) ||
+                               ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK)))
+                       return -EPERM;
+               info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+                               (new_serial.flags & ASYNC_USR_MASK));
        } else {
                /*
                 * OK, past this point, all the error checking has been done.
                 * At this point, we start making changes.....
                 */
-               info->flags = ((info->flags & ~ASYNC_FLAGS) | (new_serial.flags & ASYNC_FLAGS));
+               info->flags = ((info->flags & ~ASYNC_FLAGS) |
+                               (new_serial.flags & ASYNC_FLAGS));
                info->close_delay = new_serial.close_delay * HZ / 100;
                info->closing_wait = new_serial.closing_wait * HZ / 100;
-               info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-               info->tty->low_latency = 0;     //(info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+               info->tty->low_latency =
+                               (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+               info->tty->low_latency = 0;     /* (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; */
        }
 
        /* added by casper, 3/17/2000, for mouse */
@@ -2831,7 +2929,6 @@ static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct
 
        process_txrx_fifo(info);
 
-       /* */
        if (info->flags & ASYNC_INITIALIZED) {
                if (flags != (info->flags & ASYNC_SPD_MASK)) {
                        mxser_change_speed(info, NULL);
@@ -2839,7 +2936,7 @@ static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct
        } else {
                retval = mxser_startup(info);
        }
-       return (retval);
+       return retval;
 }
 
 /*
@@ -2876,25 +2973,27 @@ static void mxser_send_break(struct mxser_struct *info, int duration)
                return;
        set_current_state(TASK_INTERRUPTIBLE);
        spin_lock_irqsave(&info->slock, flags);
-       outb(inb(info->base + UART_LCR) | UART_LCR_SBC, info->base + UART_LCR);
+       outb(inb(info->base + UART_LCR) | UART_LCR_SBC,
+               info->base + UART_LCR);
        spin_unlock_irqrestore(&info->slock, flags);
        schedule_timeout(duration);
        spin_lock_irqsave(&info->slock, flags);
-       outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, info->base + UART_LCR);
+       outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC,
+               info->base + UART_LCR);
        spin_unlock_irqrestore(&info->slock, flags);
 }
 
 static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
 {
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+       struct mxser_struct *info = tty->driver_data;
        unsigned char control, status;
        unsigned long flags;
 
 
        if (tty->index == MXSER_PORTS)
-               return (-ENOIOCTLCMD);
+               return -ENOIOCTLCMD;
        if (tty->flags & (1 << TTY_IO_ERROR))
-               return (-EIO);
+               return -EIO;
 
        control = info->MCR;
 
@@ -2904,12 +3003,16 @@ static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
                mxser_check_modem_status(info, status);
        spin_unlock_irqrestore(&info->slock, flags);
        return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
-           ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
+                   ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
+                   ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) |
+                   ((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
+                   ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
+                   ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
 }
 
 static int mxser_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear)
 {
-       struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+       struct mxser_struct *info = tty->driver_data;
        unsigned long flags;
 
 
@@ -2968,38 +3071,36 @@ static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf)
                hwconf->board_type = MXSER_BOARD_CI104J;
                hwconf->ports = 4;
        } else
-               return (0);
+               return 0;
 
        irq = 0;
        if (hwconf->ports == 2) {
                irq = regs[9] & 0xF000;
                irq = irq | (irq >> 4);
                if (irq != (regs[9] & 0xFF00))
-                       return (MXSER_ERR_IRQ_CONFLIT);
+                       return MXSER_ERR_IRQ_CONFLIT;
        } else if (hwconf->ports == 4) {
                irq = regs[9] & 0xF000;
                irq = irq | (irq >> 4);
                irq = irq | (irq >> 8);
                if (irq != regs[9])
-                       return (MXSER_ERR_IRQ_CONFLIT);
+                       return MXSER_ERR_IRQ_CONFLIT;
        } else if (hwconf->ports == 8) {
                irq = regs[9] & 0xF000;
                irq = irq | (irq >> 4);
                irq = irq | (irq >> 8);
                if ((irq != regs[9]) || (irq != regs[10]))
-                       return (MXSER_ERR_IRQ_CONFLIT);
+                       return MXSER_ERR_IRQ_CONFLIT;
        }
 
-       if (!irq) {
-               return (MXSER_ERR_IRQ);
-       }
-       hwconf->irq = ((int) (irq & 0xF000) >> 12);
+       if (!irq)
+               return MXSER_ERR_IRQ;
+       hwconf->irq = ((int)(irq & 0xF000) >> 12);
        for (i = 0; i < 8; i++)
                hwconf->ioaddr[i] = (int) regs[i + 1] & 0xFFF8;
-       if ((regs[12] & 0x80) == 0) {
-               return (MXSER_ERR_VECTOR);
-       }
-       hwconf->vector = (int) regs[11];        /* interrupt vector */
+       if ((regs[12] & 0x80) == 0)
+               return MXSER_ERR_VECTOR;
+       hwconf->vector = (int)regs[11]; /* interrupt vector */
        if (id == 1)
                hwconf->vector_mask = 0x00FF;
        else
@@ -3007,10 +3108,10 @@ static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf)
        for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) {
                if (regs[12] & bits) {
                        hwconf->baud_base[i] = 921600;
-                       hwconf->MaxCanSetBaudRate[i] = 921600;  // add by Victor Yu. 09-04-2002
+                       hwconf->MaxCanSetBaudRate[i] = 921600;  /* add by Victor Yu. 09-04-2002 */
                } else {
                        hwconf->baud_base[i] = 115200;
-                       hwconf->MaxCanSetBaudRate[i] = 115200;  // add by Victor Yu. 09-04-2002
+                       hwconf->MaxCanSetBaudRate[i] = 115200;  /* add by Victor Yu. 09-04-2002 */
                }
        }
        scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB);
@@ -3030,7 +3131,7 @@ static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf)
                hwconf->ports = 4;
        request_region(hwconf->ioaddr[0], 8 * hwconf->ports, "mxser(IO)");
        request_region(hwconf->vector, 1, "mxser(vector)");
-       return (hwconf->ports);
+       return hwconf->ports;
 }
 
 #define CHIP_SK        0x01    /* Serial Data Clock  in Eprom */
@@ -3053,7 +3154,7 @@ static int mxser_read_register(int port, unsigned short *regs)
 
        id = mxser_program_mode(port);
        if (id < 0)
-               return (id);
+               return id;
        for (i = 0; i < 14; i++) {
                k = (i & 0x3F) | 0x180;
                for (j = 0x100; j > 0; j >>= 1) {
@@ -3066,7 +3167,7 @@ static int mxser_read_register(int port, unsigned short *regs)
                                outb(CHIP_CS | CHIP_SK, port);  /* A? bit of read */
                        }
                }
-               (void) inb(port);
+               (void)inb(port);
                value = 0;
                for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) {
                        outb(CHIP_CS, port);
@@ -3078,28 +3179,33 @@ static int mxser_read_register(int port, unsigned short *regs)
                outb(0, port);
        }
        mxser_normal_mode(port);
-       return (id);
+       return id;
 }
 
 static int mxser_program_mode(int port)
 {
        int id, i, j, n;
-       //unsigned long flags;
+       /* unsigned long flags; */
 
        spin_lock(&gm_lock);
        outb(0, port);
        outb(0, port);
        outb(0, port);
-       (void) inb(port);
-       (void) inb(port);
+       (void)inb(port);
+       (void)inb(port);
        outb(0, port);
-       (void) inb(port);
-       //restore_flags(flags);
+       (void)inb(port);
+       /* restore_flags(flags); */
        spin_unlock(&gm_lock);
 
        id = inb(port + 1) & 0x1F;
-       if ((id != C168_ASIC_ID) && (id != C104_ASIC_ID) && (id != C102_ASIC_ID) && (id != CI132_ASIC_ID) && (id != CI134_ASIC_ID) && (id != CI104J_ASIC_ID))
-               return (-1);
+       if ((id != C168_ASIC_ID) &&
+                       (id != C104_ASIC_ID) &&
+                       (id != C102_ASIC_ID) &&
+                       (id != CI132_ASIC_ID) &&
+                       (id != CI134_ASIC_ID) &&
+                       (id != CI104J_ASIC_ID))
+               return -1;
        for (i = 0, j = 0; i < 4; i++) {
                n = inb(port + 2);
                if (n == 'M') {
@@ -3112,7 +3218,7 @@ static int mxser_program_mode(int port)
        }
        if (j != 2)
                id = -2;
-       return (id);
+       return id;
 }
 
 static void mxser_normal_mode(int port)
@@ -3130,7 +3236,7 @@ static void mxser_normal_mode(int port)
                if ((n & 0x61) == 0x60)
                        break;
                if ((n & 1) == 1)
-                       (void) inb(port);
+                       (void)inb(port);
        }
        outb(0x00, port + 4);
 }
index c48de09d68f0fd1c6b5334744305eb69a650d6d7..203dc2b661d5cc8b4bba97e79b893650c0c3773b 100644 (file)
@@ -951,7 +951,8 @@ static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
    {
 queue_the_message:
 
-      pMsg = kmalloc(sizeof(struct r3964_message), GFP_KERNEL);
+      pMsg = kmalloc(sizeof(struct r3964_message),
+                    error_code?GFP_ATOMIC:GFP_KERNEL);
       TRACE_M("add_msg - kmalloc %p",pMsg);
       if(pMsg==NULL) {
          return;
index 0c141c295fb6daa508198e76847911a2fc7b6b47..17bc8abd5df50b8e9ad1c821340f333807504586 100644 (file)
@@ -1582,7 +1582,7 @@ static void mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
        if (mgslpc_paranoia_check(info, tty->name, "mgslpc_put_char"))
                return;
 
-       if (!tty || !info->tx_buf)
+       if (!info->tx_buf)
                return;
 
        spin_lock_irqsave(&info->lock,flags);
@@ -1649,7 +1649,7 @@ static int mgslpc_write(struct tty_struct * tty,
                        __FILE__,__LINE__,info->device_name,count);
        
        if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write") ||
-           !tty || !info->tx_buf)
+               !info->tx_buf)
                goto cleanup;
 
        if (info->params.mode == MGSL_MODE_HDLC) {
index 7edc6a4dbdc43f371df3064f68930284889a66a0..0708c5164c830b7fd6d9863a3e65efac3b9e5289 100644 (file)
@@ -324,35 +324,15 @@ static void rp_do_receive(struct r_port *info,
                          CHANNEL_t * cp, unsigned int ChanStatus)
 {
        unsigned int CharNStat;
-       int ToRecv, wRecv, space = 0, count;
-       unsigned char *cbuf, *chead;
-       char *fbuf, *fhead;
-       struct tty_ldisc *ld;
-
-       ld = tty_ldisc_ref(tty);
+       int ToRecv, wRecv, space;
+       unsigned char *cbuf;
 
        ToRecv = sGetRxCnt(cp);
-       space = tty->receive_room;
-       if (space > 2 * TTY_FLIPBUF_SIZE)
-               space = 2 * TTY_FLIPBUF_SIZE;
-       count = 0;
 #ifdef ROCKET_DEBUG_INTR
-       printk(KERN_INFO "rp_do_receive(%d, %d)...", ToRecv, space);
+       printk(KERN_INFO "rp_do_receive(%d)...", ToRecv);
 #endif
-
-       /*
-        * determine how many we can actually read in.  If we can't
-        * read any in then we have a software overrun condition.
-        */
-       if (ToRecv > space)
-               ToRecv = space;
-
-       ToRecv = tty_prepare_flip_string_flags(tty, &chead, &fhead, ToRecv);
-       if (ToRecv <= 0)
-               goto done;
-
-       cbuf = chead;
-       fbuf = fhead;
+       if (ToRecv == 0)
+               return;
 
        /*
         * if status indicates there are errored characters in the
@@ -380,6 +360,8 @@ static void rp_do_receive(struct r_port *info,
                       info->read_status_mask);
 #endif
                while (ToRecv) {
+                       char flag;
+
                        CharNStat = sInW(sGetTxRxDataIO(cp));
 #ifdef ROCKET_DEBUG_RECEIVE
                        printk(KERN_INFO "%x...", CharNStat);
@@ -392,17 +374,16 @@ static void rp_do_receive(struct r_port *info,
                        }
                        CharNStat &= info->read_status_mask;
                        if (CharNStat & STMBREAKH)
-                               *fbuf++ = TTY_BREAK;
+                               flag = TTY_BREAK;
                        else if (CharNStat & STMPARITYH)
-                               *fbuf++ = TTY_PARITY;
+                               flag = TTY_PARITY;
                        else if (CharNStat & STMFRAMEH)
-                               *fbuf++ = TTY_FRAME;
+                               flag = TTY_FRAME;
                        else if (CharNStat & STMRCVROVRH)
-                               *fbuf++ = TTY_OVERRUN;
+                               flag = TTY_OVERRUN;
                        else
-                               *fbuf++ = TTY_NORMAL;
-                       *cbuf++ = CharNStat & 0xff;
-                       count++;
+                               flag = TTY_NORMAL;
+                       tty_insert_flip_char(tty, CharNStat & 0xff, flag);
                        ToRecv--;
                }
 
@@ -422,20 +403,23 @@ static void rp_do_receive(struct r_port *info,
                 * characters at time by doing repeated word IO
                 * transfer.
                 */
+               space = tty_prepare_flip_string(tty, &cbuf, ToRecv);
+               if (space < ToRecv) {
+#ifdef ROCKET_DEBUG_RECEIVE
+                       printk(KERN_INFO "rp_do_receive:insufficient space ToRecv=%d space=%d\n", ToRecv, space);
+#endif
+                       if (space <= 0)
+                               return;
+                       ToRecv = space;
+               }
                wRecv = ToRecv >> 1;
                if (wRecv)
                        sInStrW(sGetTxRxDataIO(cp), (unsigned short *) cbuf, wRecv);
                if (ToRecv & 1)
                        cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp));
-               memset(fbuf, TTY_NORMAL, ToRecv);
-               cbuf += ToRecv;
-               fbuf += ToRecv;
-               count += ToRecv;
        }
        /*  Push the data up to the tty layer */
-       ld->receive_buf(tty, chead, fhead, count);
-done:
-       tty_ldisc_deref(ld);
+       tty_flip_buffer_push(tty);
 }
 
 /*
index 5343e9fc6ab7e721dc1a578e6a6e81e044549490..1b5330299e30fa965086eae13d601a1e80e29be3 100644 (file)
@@ -1683,7 +1683,7 @@ static int sx_write(struct tty_struct * tty,
 
        bp = port_Board(port);
 
-       if (!tty || !port->xmit_buf || !tmp_buf) {
+       if (!port->xmit_buf || !tmp_buf) {
                func_exit();
                return 0;
        }
@@ -1733,7 +1733,7 @@ static void sx_put_char(struct tty_struct * tty, unsigned char ch)
                return;
        }
        dprintk (SX_DEBUG_TX, "check tty: %p %p\n", tty, port->xmit_buf);
-       if (!tty || !port->xmit_buf) {
+       if (!port->xmit_buf) {
                func_exit();
                return;
        }
index b4d1f4eea435afe1eccf7cc11788dd9184f2a7c4..4e35d41812248e7163c6bcbda1ee7f180dec1283 100644 (file)
@@ -101,6 +101,7 @@ MODULE_LICENSE("GPL");
 
 static struct pci_device_id pci_table[] = {
        {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+       {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT2_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
        {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT4_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
        {PCI_VENDOR_ID_MICROGATE, SYNCLINK_AC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
        {0,}, /* terminate list */
@@ -870,7 +871,7 @@ static int write(struct tty_struct *tty,
                goto cleanup;
        DBGINFO(("%s write count=%d\n", info->device_name, count));
 
-       if (!tty || !info->tx_buf)
+       if (!info->tx_buf)
                goto cleanup;
 
        if (count > info->max_frame_size) {
@@ -924,7 +925,7 @@ static void put_char(struct tty_struct *tty, unsigned char ch)
        if (sanity_check(info, tty->name, "put_char"))
                return;
        DBGINFO(("%s put_char(%d)\n", info->device_name, ch));
-       if (!tty || !info->tx_buf)
+       if (!info->tx_buf)
                return;
        spin_lock_irqsave(&info->lock,flags);
        if (!info->tx_active && (info->tx_count < info->max_frame_size))
@@ -2515,7 +2516,8 @@ static int set_txidle(struct slgt_info *info, int idle_mode)
        DBGINFO(("%s set_txidle(%d)\n", info->device_name, idle_mode));
        spin_lock_irqsave(&info->lock,flags);
        info->idle_mode = idle_mode;
-       tx_set_idle(info);
+       if (info->params.mode != MGSL_MODE_ASYNC)
+               tx_set_idle(info);
        spin_unlock_irqrestore(&info->lock,flags);
        return 0;
 }
@@ -3076,7 +3078,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
 
 static int alloc_tmp_rbuf(struct slgt_info *info)
 {
-       info->tmp_rbuf = kmalloc(info->max_frame_size, GFP_KERNEL);
+       info->tmp_rbuf = kmalloc(info->max_frame_size + 5, GFP_KERNEL);
        if (info->tmp_rbuf == NULL)
                return -ENOMEM;
        return 0;
@@ -3276,6 +3278,9 @@ static void add_device(struct slgt_info *info)
        case SYNCLINK_GT_DEVICE_ID:
                devstr = "GT";
                break;
+       case SYNCLINK_GT2_DEVICE_ID:
+               devstr = "GT2";
+               break;
        case SYNCLINK_GT4_DEVICE_ID:
                devstr = "GT4";
                break;
@@ -3353,7 +3358,9 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
        int i;
        int port_count = 1;
 
-       if (pdev->device == SYNCLINK_GT4_DEVICE_ID)
+       if (pdev->device == SYNCLINK_GT2_DEVICE_ID)
+               port_count = 2;
+       else if (pdev->device == SYNCLINK_GT4_DEVICE_ID)
                port_count = 4;
 
        /* allocate device instances for all ports */
@@ -3940,8 +3947,6 @@ static void async_mode(struct slgt_info *info)
 
        msc_set_vcr(info);
 
-       tx_set_idle(info);
-
        /* SCR (serial control)
         *
         * 15  1=tx req on FIFO half empty
@@ -4012,7 +4017,7 @@ static void hdlc_mode(struct slgt_info *info)
        case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break;
        }
 
-       switch (info->params.crc_type)
+       switch (info->params.crc_type & HDLC_CRC_MASK)
        {
        case HDLC_CRC_16_CCITT: val |= BIT9; break;
        case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break;
@@ -4073,7 +4078,7 @@ static void hdlc_mode(struct slgt_info *info)
        case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break;
        }
 
-       switch (info->params.crc_type)
+       switch (info->params.crc_type & HDLC_CRC_MASK)
        {
        case HDLC_CRC_16_CCITT: val |= BIT9; break;
        case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break;
@@ -4175,17 +4180,38 @@ static void hdlc_mode(struct slgt_info *info)
  */
 static void tx_set_idle(struct slgt_info *info)
 {
-       unsigned char val = 0xff;
+       unsigned char val;
+       unsigned short tcr;
 
-       switch(info->idle_mode)
-       {
-       case HDLC_TXIDLE_FLAGS:          val = 0x7e; break;
-       case HDLC_TXIDLE_ALT_ZEROS_ONES: val = 0xaa; break;
-       case HDLC_TXIDLE_ZEROS:          val = 0x00; break;
-       case HDLC_TXIDLE_ONES:           val = 0xff; break;
-       case HDLC_TXIDLE_ALT_MARK_SPACE: val = 0xaa; break;
-       case HDLC_TXIDLE_SPACE:          val = 0x00; break;
-       case HDLC_TXIDLE_MARK:           val = 0xff; break;
+       /* if preamble enabled (tcr[6] == 1) then tx idle size = 8 bits
+        * else tcr[5:4] = tx idle size: 00 = 8 bits, 01 = 16 bits
+        */
+       tcr = rd_reg16(info, TCR);
+       if (info->idle_mode & HDLC_TXIDLE_CUSTOM_16) {
+               /* disable preamble, set idle size to 16 bits */
+               tcr = (tcr & ~(BIT6 + BIT5)) | BIT4;
+               /* MSB of 16 bit idle specified in tx preamble register (TPR) */
+               wr_reg8(info, TPR, (unsigned char)((info->idle_mode >> 8) & 0xff));
+       } else if (!(tcr & BIT6)) {
+               /* preamble is disabled, set idle size to 8 bits */
+               tcr &= ~(BIT5 + BIT4);
+       }
+       wr_reg16(info, TCR, tcr);
+
+       if (info->idle_mode & (HDLC_TXIDLE_CUSTOM_8 | HDLC_TXIDLE_CUSTOM_16)) {
+               /* LSB of custom tx idle specified in tx idle register */
+               val = (unsigned char)(info->idle_mode & 0xff);
+       } else {
+               /* standard 8 bit idle patterns */
+               switch(info->idle_mode)
+               {
+               case HDLC_TXIDLE_FLAGS:          val = 0x7e; break;
+               case HDLC_TXIDLE_ALT_ZEROS_ONES:
+               case HDLC_TXIDLE_ALT_MARK_SPACE: val = 0xaa; break;
+               case HDLC_TXIDLE_ZEROS:
+               case HDLC_TXIDLE_SPACE:          val = 0x00; break;
+               default:                         val = 0xff;
+               }
        }
 
        wr_reg8(info, TIR, val);
@@ -4313,6 +4339,12 @@ static int rx_get_frame(struct slgt_info *info)
        unsigned long flags;
        struct tty_struct *tty = info->tty;
        unsigned char addr_field = 0xff;
+       unsigned int crc_size = 0;
+
+       switch (info->params.crc_type & HDLC_CRC_MASK) {
+       case HDLC_CRC_16_CCITT: crc_size = 2; break;
+       case HDLC_CRC_32_CCITT: crc_size = 4; break;
+       }
 
 check_again:
 
@@ -4357,7 +4389,7 @@ check_again:
        status = desc_status(info->rbufs[end]);
 
        /* ignore CRC bit if not using CRC (bit is undefined) */
-       if (info->params.crc_type == HDLC_CRC_NONE)
+       if ((info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_NONE)
                status &= ~BIT1;
 
        if (framesize == 0 ||
@@ -4366,34 +4398,34 @@ check_again:
                goto check_again;
        }
 
-       if (framesize < 2 || status & (BIT1+BIT0)) {
-               if (framesize < 2 || (status & BIT0))
-                       info->icount.rxshort++;
-               else
-                       info->icount.rxcrc++;
+       if (framesize < (2 + crc_size) || status & BIT0) {
+               info->icount.rxshort++;
                framesize = 0;
+       } else if (status & BIT1) {
+               info->icount.rxcrc++;
+               if (!(info->params.crc_type & HDLC_CRC_RETURN_EX))
+                       framesize = 0;
+       }
 
 #ifdef CONFIG_HDLC
-               {
-                       struct net_device_stats *stats = hdlc_stats(info->netdev);
-                       stats->rx_errors++;
-                       stats->rx_frame_errors++;
-               }
-#endif
-       } else {
-               /* adjust frame size for CRC, if any */
-               if (info->params.crc_type == HDLC_CRC_16_CCITT)
-                       framesize -= 2;
-               else if (info->params.crc_type == HDLC_CRC_32_CCITT)
-                       framesize -= 4;
+       if (framesize == 0) {
+               struct net_device_stats *stats = hdlc_stats(info->netdev);
+               stats->rx_errors++;
+               stats->rx_frame_errors++;
        }
+#endif
 
        DBGBH(("%s rx frame status=%04X size=%d\n",
                info->device_name, status, framesize));
        DBGDATA(info, info->rbufs[start].buf, min_t(int, framesize, DMABUFSIZE), "rx");
 
        if (framesize) {
-               if (framesize > info->max_frame_size)
+               if (!(info->params.crc_type & HDLC_CRC_RETURN_EX)) {
+                       framesize -= crc_size;
+                       crc_size = 0;
+               }
+
+               if (framesize > info->max_frame_size + crc_size)
                        info->icount.rxlong++;
                else {
                        /* copy dma buffer(s) to contiguous temp buffer */
@@ -4413,6 +4445,11 @@ check_again:
                                        i = 0;
                        }
 
+                       if (info->params.crc_type & HDLC_CRC_RETURN_EX) {
+                               *p = (status & BIT1) ? RX_CRC_ERROR : RX_OK;
+                               framesize++;
+                       }
+
 #ifdef CONFIG_HDLC
                        if (info->netcount)
                                hdlcdev_rx(info,info->tmp_rbuf, framesize);
@@ -4671,13 +4708,13 @@ static int loopback_test(struct slgt_info *info)
 static int adapter_test(struct slgt_info *info)
 {
        DBGINFO(("testing %s\n", info->device_name));
-       if ((info->init_error = register_test(info)) < 0) {
+       if (register_test(info) < 0) {
                printk("register test failure %s addr=%08X\n",
                        info->device_name, info->phys_reg_addr);
-       } else if ((info->init_error = irq_test(info)) < 0) {
+       } else if (irq_test(info) < 0) {
                printk("IRQ test failure %s IRQ=%d\n",
                        info->device_name, info->irq_level);
-       } else if ((info->init_error = loopback_test(info)) < 0) {
+       } else if (loopback_test(info) < 0) {
                printk("loopback test failure %s\n", info->device_name);
        }
        return info->init_error;
index 8587401311155dd5abcb9e0bde00ed6e8a3493c2..21bf15ad998020cdb985eba98fa607bf6fefc406 100644 (file)
@@ -988,7 +988,7 @@ static int write(struct tty_struct *tty,
        if (sanity_check(info, tty->name, "write"))
                goto cleanup;
 
-       if (!tty || !info->tx_buf)
+       if (!info->tx_buf)
                goto cleanup;
 
        if (info->params.mode == MGSL_MODE_HDLC) {
@@ -1067,7 +1067,7 @@ static void put_char(struct tty_struct *tty, unsigned char ch)
        if (sanity_check(info, tty->name, "put_char"))
                return;
 
-       if (!tty || !info->tx_buf)
+       if (!info->tx_buf)
                return;
 
        spin_lock_irqsave(&info->lock,flags);
index 1e371a510dd219313821af876b7992c5877e695a..731c3d5da0dc7c6bc66a33a705f9b7a2fceab90a 100644 (file)
@@ -6,8 +6,7 @@
 menu "Firmware Drivers"
 
 config EDD
-       tristate "BIOS Enhanced Disk Drive calls determine boot disk (EXPERIMENTAL)"
-       depends on EXPERIMENTAL
+       tristate "BIOS Enhanced Disk Drive calls determine boot disk"
        depends on !IA64
        help
          Say Y or M here if you want to enable BIOS Enhanced Disk Drive
index 948bd7e1445aeb5b441867670bdbdbcb3f8b3722..b9e3886d9e1618cc4b85345e81a8a2c23fb876ea 100644 (file)
@@ -255,10 +255,15 @@ void __init dmi_scan_machine(void)
 /**
  *     dmi_check_system - check system DMI data
  *     @list: array of dmi_system_id structures to match against
+ *             All non-null elements of the list must match
+ *             their slot's (field index's) data (i.e., each
+ *             list string must be a substring of the specified
+ *             DMI slot's string data) to be considered a
+ *             successful match.
  *
  *     Walk the blacklist table running matching functions until someone
  *     returns non zero or we hit the end. Callback function is called for
- *     each successfull match. Returns the number of matches.
+ *     each successful match. Returns the number of matches.
  */
 int dmi_check_system(struct dmi_system_id *list)
 {
@@ -287,7 +292,7 @@ EXPORT_SYMBOL(dmi_check_system);
 
 /**
  *     dmi_get_system_info - return DMI data value
- *     @field: data index (see enum dmi_filed)
+ *     @field: data index (see enum dmi_field)
  *
  *     Returns one DMI data value, can be used to perform
  *     complex DMI data checks.
@@ -301,13 +306,13 @@ EXPORT_SYMBOL(dmi_get_system_info);
 /**
  *     dmi_find_device - find onboard device by type/name
  *     @type: device type or %DMI_DEV_TYPE_ANY to match all device types
- *     @desc: device name string or %NULL to match all
+ *     @name: device name string or %NULL to match all
  *     @from: previous device found in search, or %NULL for new search.
  *
  *     Iterates through the list of known onboard devices. If a device is
  *     found with a matching @vendor and @device, a pointer to its device
  *     structure is returned.  Otherwise, %NULL is returned.
- *     A new search is initiated by passing %NULL to the @from argument.
+ *     A new search is initiated by passing %NULL as the @from argument.
  *     If @from is not %NULL, searches continue from next device.
  */
 struct dmi_device * dmi_find_device(int type, const char *name,
index 6de3cd3d6e8e266a4fd7cad57729c5a419d506cc..99fa42402e71ee7f373a335c928ed1218c73ffd6 100644 (file)
@@ -395,7 +395,8 @@ static int cdrom_log_sense(ide_drive_t *drive, struct request *rq,
                         * we cannot reliably check if drive can auto-close
                         */
                        if (rq->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24)
-                               log = 0;
+                               break;
+                       log = 1;
                        break;
                case UNIT_ATTENTION:
                        /*
@@ -417,6 +418,11 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
                              struct request *failed_command,
                              struct request_sense *sense)
 {
+       unsigned long sector;
+       unsigned long bio_sectors;
+       unsigned long valid;
+       struct cdrom_info *info = drive->driver_data;
+
        if (!cdrom_log_sense(drive, failed_command, sense))
                return;
 
@@ -429,6 +435,37 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
                if (sense->sense_key == 0x05 && sense->asc == 0x24)
                        return;
 
+       if (sense->error_code == 0x70) {        /* Current Error */
+               switch(sense->sense_key) {
+               case MEDIUM_ERROR:
+               case VOLUME_OVERFLOW:
+               case ILLEGAL_REQUEST:
+                       if (!sense->valid)
+                               break;
+                       if (failed_command == NULL ||
+                                       !blk_fs_request(failed_command))
+                               break;
+                       sector = (sense->information[0] << 24) |
+                                (sense->information[1] << 16) |
+                                (sense->information[2] <<  8) |
+                                (sense->information[3]);
+
+                       bio_sectors = bio_sectors(failed_command->bio);
+                       if (bio_sectors < 4)
+                               bio_sectors = 4;
+                       if (drive->queue->hardsect_size == 2048)
+                               sector <<= 2;   /* Device sector size is 2K */
+                       sector &= ~(bio_sectors -1);
+                       valid = (sector - failed_command->sector) << 9;
+
+                       if (valid < 0)
+                               valid = 0;
+                       if (sector < get_capacity(info->disk) &&
+                               drive->probed_capacity - sector < 4 * 75) {
+                               set_capacity(info->disk, sector);
+                       }
+               }
+       }
 #if VERBOSE_IDE_CD_ERRORS
        {
                int i;
@@ -609,17 +646,23 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate)
                                sense = failed->sense;
                                failed->sense_len = rq->sense_len;
                        }
-
+                       cdrom_analyze_sense_data(drive, failed, sense);
                        /*
                         * now end failed request
                         */
-                       spin_lock_irqsave(&ide_lock, flags);
-                       end_that_request_chunk(failed, 0, failed->data_len);
-                       end_that_request_last(failed, 0);
-                       spin_unlock_irqrestore(&ide_lock, flags);
-               }
-
-               cdrom_analyze_sense_data(drive, failed, sense);
+                       if (blk_fs_request(failed)) {
+                               if (ide_end_dequeued_request(drive, failed, 0,
+                                               failed->hard_nr_sectors))
+                                       BUG();
+                       } else {
+                               spin_lock_irqsave(&ide_lock, flags);
+                               end_that_request_chunk(failed, 0,
+                                                       failed->data_len);
+                               end_that_request_last(failed, 0);
+                               spin_unlock_irqrestore(&ide_lock, flags);
+                       }
+               } else
+                       cdrom_analyze_sense_data(drive, NULL, sense);
        }
 
        if (!rq->current_nr_sectors && blk_fs_request(rq))
@@ -633,6 +676,13 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate)
        ide_end_request(drive, uptodate, nsectors);
 }
 
+static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 stat)
+{
+       if (stat & 0x80)
+               return;
+       ide_dump_status(drive, msg, stat);
+}
+
 /* Returns 0 if the request should be continued.
    Returns 1 if the request was ended. */
 static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
@@ -761,16 +811,16 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                           sense_key == DATA_PROTECT) {
                        /* No point in retrying after an illegal
                           request or data protect error.*/
-                       ide_dump_status (drive, "command error", stat);
+                       ide_dump_status_no_sense (drive, "command error", stat);
                        do_end_request = 1;
                } else if (sense_key == MEDIUM_ERROR) {
                        /* No point in re-trying a zillion times on a bad 
                         * sector...  If we got here the error is not correctable */
-                       ide_dump_status (drive, "media error (bad sector)", stat);
+                       ide_dump_status_no_sense (drive, "media error (bad sector)", stat);
                        do_end_request = 1;
                } else if (sense_key == BLANK_CHECK) {
                        /* Disk appears blank ?? */
-                       ide_dump_status (drive, "media error (blank)", stat);
+                       ide_dump_status_no_sense (drive, "media error (blank)", stat);
                        do_end_request = 1;
                } else if ((err & ~ABRT_ERR) != 0) {
                        /* Go to the default handler
@@ -782,13 +832,27 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                        do_end_request = 1;
                }
 
-               if (do_end_request)
-                       cdrom_end_request(drive, 0);
-
-               /* If we got a CHECK_CONDITION status,
-                  queue a request sense command. */
-               if ((stat & ERR_STAT) != 0)
-                       cdrom_queue_request_sense(drive, NULL, NULL);
+               /* End a request through request sense analysis when we have
+                  sense data. We need this in order to perform end of media
+                  processing */
+
+               if (do_end_request) {
+                       if (stat & ERR_STAT) {
+                               unsigned long flags;
+                               spin_lock_irqsave(&ide_lock, flags);
+                               blkdev_dequeue_request(rq);
+                               HWGROUP(drive)->rq = NULL;
+                               spin_unlock_irqrestore(&ide_lock, flags);
+
+                               cdrom_queue_request_sense(drive, rq->sense, rq);
+                       } else
+                               cdrom_end_request(drive, 0);
+               } else {
+                       /* If we got a CHECK_CONDITION status,
+                          queue a request sense command. */
+                       if (stat & ERR_STAT)
+                               cdrom_queue_request_sense(drive, NULL, NULL);
+               }
        } else {
                blk_dump_rq_flags(rq, "ide-cd: bad rq");
                cdrom_end_request(drive, 0);
@@ -1491,8 +1555,7 @@ static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive)
 }
 
 
-static
-int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
+static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
 {
        struct request_sense sense;
        int retries = 10;
@@ -2220,6 +2283,9 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
                toc->capacity = 0x1fffff;
 
        set_capacity(info->disk, toc->capacity * sectors_per_frame);
+       /* Save a private copy of te TOC capacity for error handling */
+       drive->probed_capacity = toc->capacity * sectors_per_frame;
+
        blk_queue_hardsect_size(drive->queue,
                                sectors_per_frame << SECTOR_BITS);
 
@@ -2342,6 +2408,7 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
        if (!stat && (last_written > toc->capacity)) {
                toc->capacity = last_written;
                set_capacity(info->disk, toc->capacity * sectors_per_frame);
+               drive->probed_capacity = toc->capacity * sectors_per_frame;
        }
 
        /* Remember that we've read this stuff. */
@@ -2698,14 +2765,11 @@ int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr)
         * any other way to detect this...
         */
        if (sense.sense_key == NOT_READY) {
-               if (sense.asc == 0x3a) {
-                       if (sense.ascq == 1)
-                               return CDS_NO_DISC;
-                       else if (sense.ascq == 0 || sense.ascq == 2)
-                               return CDS_TRAY_OPEN;
-               }
+               if (sense.asc == 0x3a && sense.ascq == 1)
+                       return CDS_NO_DISC;
+               else
+                       return CDS_TRAY_OPEN;
        }
-
        return CDS_DRIVE_NOT_READY;
 }
 
index a1179e924962586335ab733c7c66e99f20209387..4656587aa2f70d2e1deced9716664f89162f7f91 100644 (file)
@@ -1284,7 +1284,7 @@ static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request
 
        debug_log(KERN_INFO "rq_status: %d, dev: %s, flags: %lx, errors: %d\n",
                        rq->rq_status,
-                       rq->rq_disk ? rq->rq_disk->disk_name ? "?",
+                       rq->rq_disk ? rq->rq_disk->disk_name : "?",
                        rq->flags, rq->errors);
        debug_log(KERN_INFO "sector: %ld, nr_sectors: %ld, "
                        "current_nr_sectors: %d\n", (long)rq->sector,
index 4f2f138de2cabe089e41bed95a48d57f63917c13..622a55c72f03616e9a8a613484b0574e82dfb0cb 100644 (file)
@@ -222,6 +222,63 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
        return ide_stopped;
 }
 
+/**
+ *     ide_end_dequeued_request        -       complete an IDE I/O
+ *     @drive: IDE device for the I/O
+ *     @uptodate:
+ *     @nr_sectors: number of sectors completed
+ *
+ *     Complete an I/O that is no longer on the request queue. This
+ *     typically occurs when we pull the request and issue a REQUEST_SENSE.
+ *     We must still finish the old request but we must not tamper with the
+ *     queue in the meantime.
+ *
+ *     NOTE: This path does not handle barrier, but barrier is not supported
+ *     on ide-cd anyway.
+ */
+
+int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
+                            int uptodate, int nr_sectors)
+{
+       unsigned long flags;
+       int ret = 1;
+
+       spin_lock_irqsave(&ide_lock, flags);
+
+       BUG_ON(!(rq->flags & REQ_STARTED));
+
+       /*
+        * if failfast is set on a request, override number of sectors and
+        * complete the whole request right now
+        */
+       if (blk_noretry_request(rq) && end_io_error(uptodate))
+               nr_sectors = rq->hard_nr_sectors;
+
+       if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors)
+               rq->errors = -EIO;
+
+       /*
+        * decide whether to reenable DMA -- 3 is a random magic for now,
+        * if we DMA timeout more than 3 times, just stay in PIO
+        */
+       if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+               drive->state = 0;
+               HWGROUP(drive)->hwif->ide_dma_on(drive);
+       }
+
+       if (!end_that_request_first(rq, uptodate, nr_sectors)) {
+               add_disk_randomness(rq->rq_disk);
+               if (blk_rq_tagged(rq))
+                       blk_queue_end_tag(drive->queue, rq);
+               end_that_request_last(rq, uptodate);
+               ret = 0;
+       }
+       spin_unlock_irqrestore(&ide_lock, flags);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ide_end_dequeued_request);
+
+
 /**
  *     ide_complete_pm_request - end the current Power Management request
  *     @drive: target drive
index f04791a58df0b0784e3e754cad9a0275034f0712..09f3a7dab28ade081cd5e0fe94120aaa96fc8e8d 100644 (file)
@@ -2646,21 +2646,23 @@ static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape)
        return __idetape_kmalloc_stage(tape, 0, 0);
 }
 
-static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char __user *buf, int n)
+static int idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char __user *buf, int n)
 {
        struct idetape_bh *bh = tape->bh;
        int count;
+       int ret = 0;
 
        while (n) {
 #if IDETAPE_DEBUG_BUGS
                if (bh == NULL) {
                        printk(KERN_ERR "ide-tape: bh == NULL in "
                                "idetape_copy_stage_from_user\n");
-                       return;
+                       return 1;
                }
 #endif /* IDETAPE_DEBUG_BUGS */
                count = min((unsigned int)(bh->b_size - atomic_read(&bh->b_count)), (unsigned int)n);
-               copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count);
+               if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count))
+                       ret = 1;
                n -= count;
                atomic_add(count, &bh->b_count);
                buf += count;
@@ -2671,23 +2673,26 @@ static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t
                }
        }
        tape->bh = bh;
+       return ret;
 }
 
-static void idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, idetape_stage_t *stage, int n)
+static int idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, idetape_stage_t *stage, int n)
 {
        struct idetape_bh *bh = tape->bh;
        int count;
+       int ret = 0;
 
        while (n) {
 #if IDETAPE_DEBUG_BUGS
                if (bh == NULL) {
                        printk(KERN_ERR "ide-tape: bh == NULL in "
                                "idetape_copy_stage_to_user\n");
-                       return;
+                       return 1;
                }
 #endif /* IDETAPE_DEBUG_BUGS */
                count = min(tape->b_count, n);
-               copy_to_user(buf, tape->b_data, count);
+               if  (copy_to_user(buf, tape->b_data, count))
+                       ret = 1;
                n -= count;
                tape->b_data += count;
                tape->b_count -= count;
@@ -2700,6 +2705,7 @@ static void idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf,
                        }
                }
        }
+       return ret;
 }
 
 static void idetape_init_merge_stage (idetape_tape_t *tape)
@@ -3719,6 +3725,7 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
        struct ide_tape_obj *tape = ide_tape_f(file);
        ide_drive_t *drive = tape->drive;
        ssize_t bytes_read,temp, actually_read = 0, rc;
+       ssize_t ret = 0;
 
 #if IDETAPE_DEBUG_LOG
        if (tape->debug_level >= 3)
@@ -3737,7 +3744,8 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
                return (0);
        if (tape->merge_stage_size) {
                actually_read = min((unsigned int)(tape->merge_stage_size), (unsigned int)count);
-               idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read);
+               if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read))
+                       ret = -EFAULT;
                buf += actually_read;
                tape->merge_stage_size -= actually_read;
                count -= actually_read;
@@ -3746,7 +3754,8 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
                bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
                if (bytes_read <= 0)
                        goto finish;
-               idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read);
+               if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read))
+                       ret = -EFAULT;
                buf += bytes_read;
                count -= bytes_read;
                actually_read += bytes_read;
@@ -3756,7 +3765,8 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
                if (bytes_read <= 0)
                        goto finish;
                temp = min((unsigned long)count, (unsigned long)bytes_read);
-               idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp);
+               if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp))
+                       ret = -EFAULT;
                actually_read += temp;
                tape->merge_stage_size = bytes_read-temp;
        }
@@ -3769,7 +3779,8 @@ finish:
                idetape_space_over_filemarks(drive, MTFSF, 1);
                return 0;
        }
-       return actually_read;
+
+       return (ret) ? ret : actually_read;
 }
 
 static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
@@ -3777,7 +3788,8 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
 {
        struct ide_tape_obj *tape = ide_tape_f(file);
        ide_drive_t *drive = tape->drive;
-       ssize_t retval, actually_written = 0;
+       ssize_t actually_written = 0;
+       ssize_t ret = 0;
 
        /* The drive is write protected. */
        if (tape->write_prot)
@@ -3813,7 +3825,7 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
                 *      some drives (Seagate STT3401A) will return an error.
                 */
                if (drive->dsc_overlap) {
-                       retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh);
+                       ssize_t retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh);
                        if (retval < 0) {
                                __idetape_kfree_stage(tape->merge_stage);
                                tape->merge_stage = NULL;
@@ -3834,12 +3846,14 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
                }
 #endif /* IDETAPE_DEBUG_BUGS */
                actually_written = min((unsigned int)(tape->stage_size - tape->merge_stage_size), (unsigned int)count);
-               idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written);
+               if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written))
+                               ret = -EFAULT;
                buf += actually_written;
                tape->merge_stage_size += actually_written;
                count -= actually_written;
 
                if (tape->merge_stage_size == tape->stage_size) {
+                       ssize_t retval;
                        tape->merge_stage_size = 0;
                        retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
                        if (retval <= 0)
@@ -3847,7 +3861,9 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
                }
        }
        while (count >= tape->stage_size) {
-               idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size);
+               ssize_t retval;
+               if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size))
+                       ret = -EFAULT;
                buf += tape->stage_size;
                count -= tape->stage_size;
                retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
@@ -3857,10 +3873,11 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
        }
        if (count) {
                actually_written += count;
-               idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count);
+               if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count))
+                       ret = -EFAULT;
                tape->merge_stage_size += count;
        }
-       return (actually_written);
+       return (ret) ? ret : actually_written;
 }
 
 static int idetape_write_filemark (ide_drive_t *drive)
index 79b81be67975050ab6f893aa147ae808abe45b22..186737539cf5f4fe32fac373fe982724bd5ac7ec 100644 (file)
@@ -4,7 +4,7 @@ menu "IEEE 1394 (FireWire) support"
 
 config IEEE1394
        tristate "IEEE 1394 (FireWire) support"
-       depends on (PCI || BROKEN) && (BROKEN || !FRV)
+       depends on PCI || BROKEN
        select NET
        help
          IEEE 1394 describes a high performance serial bus, which is also
index 948f1b8c42388152ff8d6f9d8445e75bcb957281..50c71e17de73701e4dbb175f4a99f527bc64dce6 100644 (file)
@@ -8,6 +8,7 @@
  * directory of the kernel sources for details.
  */
 
+#include <linux/bitmap.h>
 #include <linux/kernel.h>
 #include <linux/config.h>
 #include <linux/list.h>
@@ -334,10 +335,12 @@ static ssize_t fw_show_ne_bus_options(struct device *dev, struct device_attribut
 static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL);
 
 
+/* tlabels_free, tlabels_allocations, tlabels_mask are read non-atomically
+ * here, therefore displayed values may be occasionally wrong. */
 static ssize_t fw_show_ne_tlabels_free(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct node_entry *ne = container_of(dev, struct node_entry, device);
-       return sprintf(buf, "%d\n", atomic_read(&ne->tpool->count.count) + 1);
+       return sprintf(buf, "%d\n", 64 - bitmap_weight(ne->tpool->pool, 64));
 }
 static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL);
 
index 161afddd0f44396da88402f0af5bb2b9445f1a74..386023c594d74d758bbc592302d2383f84eef80b 100644 (file)
@@ -773,8 +773,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 
        ts->last_msg = m;
 
-       if (request_irq(spi->irq, ads7846_irq,
-                       SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING,
+       if (request_irq(spi->irq, ads7846_irq, SA_TRIGGER_FALLING,
                        spi->dev.driver->name, ts)) {
                dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
                err = -EBUSY;
index a18d56bdafd931526b7184e846aab71f58a75aac..a595d386312fee511e8adc1d3daabf017080dd31 100644 (file)
@@ -399,16 +399,14 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
        set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
 
        if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
-                       SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
-                       "h3600_action", &ts->dev)) {
+                       SA_SHIRQ | SA_INTERRUPT, "h3600_action", &ts->dev)) {
                printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
                err = -EBUSY;
                goto fail2;
        }
 
        if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
-                       SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
-                       "h3600_suspend", &ts->dev)) {
+                       SA_SHIRQ | SA_INTERRUPT, "h3600_suspend", &ts->dev)) {
                printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
                err = -EBUSY;
                goto fail3;
index f573d5af0b1f35fe4c7f35d8babbc2ba68da0e0d..96509989e9212d8e189d3967d42c007f41dfc8c2 100644 (file)
@@ -93,5 +93,14 @@ config LEDS_TRIGGER_IDE_DISK
          This allows LEDs to be controlled by IDE disk activity.
          If unsure, say Y.
 
+config LEDS_TRIGGER_HEARTBEAT
+       tristate "LED Heartbeat Trigger"
+       depends LEDS_TRIGGERS
+       help
+         This allows LEDs to be controlled by a CPU load average.
+         The flash frequency is a hyperbolic function of the 1-minute
+         load average.
+         If unsure, say Y.
+
 endmenu
 
index dcea1001faa4fc38701d190786bcf56bd2dcf3b1..88d3b6eaa6a203182b6b2db13743acfc1ad148d4 100644 (file)
@@ -16,3 +16,4 @@ obj-$(CONFIG_LEDS_AMS_DELTA)          += leds-ams-delta.o
 # LED Triggers
 obj-$(CONFIG_LEDS_TRIGGER_TIMER)       += ledtrig-timer.o
 obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK)    += ledtrig-ide-disk.o
+obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT)   += ledtrig-heartbeat.o
diff --git a/drivers/leds/ledtrig-heartbeat.c b/drivers/leds/ledtrig-heartbeat.c
new file mode 100644 (file)
index 0000000..4bf8cec
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * LED Heartbeat Trigger
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * Based on Richard Purdie's ledtrig-timer.c and some arch's
+ * CONFIG_HEARTBEAT code.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/leds.h>
+#include "leds.h"
+
+struct heartbeat_trig_data {
+       unsigned int phase;
+       unsigned int period;
+       struct timer_list timer;
+};
+
+static void led_heartbeat_function(unsigned long data)
+{
+       struct led_classdev *led_cdev = (struct led_classdev *) data;
+       struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data;
+       unsigned long brightness = LED_OFF;
+       unsigned long delay = 0;
+
+       /* acts like an actual heart beat -- ie thump-thump-pause... */
+       switch (heartbeat_data->phase) {
+       case 0:
+               /*
+                * The hyperbolic function below modifies the
+                * heartbeat period length in dependency of the
+                * current (1min) load. It goes through the points
+                * f(0)=1260, f(1)=860, f(5)=510, f(inf)->300.
+                */
+               heartbeat_data->period = 300 +
+                       (6720 << FSHIFT) / (5 * avenrun[0] + (7 << FSHIFT));
+               heartbeat_data->period =
+                       msecs_to_jiffies(heartbeat_data->period);
+               delay = msecs_to_jiffies(70);
+               heartbeat_data->phase++;
+               brightness = LED_FULL;
+               break;
+       case 1:
+               delay = heartbeat_data->period / 4 - msecs_to_jiffies(70);
+               heartbeat_data->phase++;
+               break;
+       case 2:
+               delay = msecs_to_jiffies(70);
+               heartbeat_data->phase++;
+               brightness = LED_FULL;
+               break;
+       default:
+               delay = heartbeat_data->period - heartbeat_data->period / 4 -
+                       msecs_to_jiffies(70);
+               heartbeat_data->phase = 0;
+               break;
+       }
+
+       led_set_brightness(led_cdev, brightness);
+       mod_timer(&heartbeat_data->timer, jiffies + delay);
+}
+
+static void heartbeat_trig_activate(struct led_classdev *led_cdev)
+{
+       struct heartbeat_trig_data *heartbeat_data;
+
+       heartbeat_data = kzalloc(sizeof(*heartbeat_data), GFP_KERNEL);
+       if (!heartbeat_data)
+               return;
+
+       led_cdev->trigger_data = heartbeat_data;
+       setup_timer(&heartbeat_data->timer,
+                   led_heartbeat_function, (unsigned long) led_cdev);
+       heartbeat_data->phase = 0;
+       led_heartbeat_function(heartbeat_data->timer.data);
+}
+
+static void heartbeat_trig_deactivate(struct led_classdev *led_cdev)
+{
+       struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data;
+
+       if (heartbeat_data) {
+               del_timer_sync(&heartbeat_data->timer);
+               kfree(heartbeat_data);
+       }
+}
+
+static struct led_trigger heartbeat_led_trigger = {
+       .name     = "heartbeat",
+       .activate = heartbeat_trig_activate,
+       .deactivate = heartbeat_trig_deactivate,
+};
+
+static int __init heartbeat_trig_init(void)
+{
+       return led_trigger_register(&heartbeat_led_trigger);
+}
+
+static void __exit heartbeat_trig_exit(void)
+{
+       led_trigger_unregister(&heartbeat_led_trigger);
+}
+
+module_init(heartbeat_trig_init);
+module_exit(heartbeat_trig_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("Heartbeat LED trigger");
+MODULE_LICENSE("GPL");
index ccf5df44cde448bda54e3f83b689e76b23630264..37cd6ee4586b35b6110a5d948a5dd01d1bbd6031 100644 (file)
@@ -99,17 +99,22 @@ config PMAC_MEDIABAY
          devices are not fully supported in the bay as I never had one to
          try with
 
-# made a separate option since backlight may end up beeing used
-# on non-powerbook machines (but only on PMU based ones AFAIK)
 config PMAC_BACKLIGHT
        bool "Backlight control for LCD screens"
        depends on ADB_PMU && (BROKEN || !PPC64)
        help
-         Say Y here to build in code to manage the LCD backlight on a
-         Macintosh PowerBook.  With this code, the backlight will be turned
-         on and off appropriately on power-management and lid-open/lid-closed
-         events; also, the PowerBook button device will be enabled so you can
-         change the screen brightness.
+         Say Y here to enable Macintosh specific extensions of the generic
+         backlight code. With this enabled, the brightness keys on older
+         PowerBooks will be enabled so you can change the screen brightness.
+         Newer models should use an userspace daemon like pbbuttonsd.
+
+config PMAC_BACKLIGHT_LEGACY
+       bool "Provide legacy ioctl's on /dev/pmu for the backlight"
+       depends on PMAC_BACKLIGHT && (BROKEN || !PPC64)
+       help
+         Say Y if you want to enable legacy ioctl's on /dev/pmu. This is for
+         programs which use this old interface. New and updated programs
+         should use the backlight classes in sysfs.
 
 config ADB_MACIO
        bool "Include MacIO (CHRP) ADB driver"
index 6081acdea404ab0c5ed72cc42ffae385036323de..8972e53d2dcbdce0ea51810c3392e957aa6c12d1 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_INPUT_ADBHID)    += adbhid.o
 obj-$(CONFIG_ANSLCD)           += ans-lcd.o
 
 obj-$(CONFIG_ADB_PMU)          += via-pmu.o
+obj-$(CONFIG_PMAC_BACKLIGHT)   += via-pmu-backlight.o
 obj-$(CONFIG_ADB_CUDA)         += via-cuda.o
 obj-$(CONFIG_PMAC_APM_EMU)     += apm_emu.o
 obj-$(CONFIG_PMAC_SMU)         += smu.o
index 394334ec5765cdb99ecee700b8d531a7f82b9416..c26e1236b2757bf990a37f8c01f1645aa5b2d89d 100644 (file)
@@ -503,9 +503,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
        case 0x1f: /* Powerbook button device */
          {
                int down = (data[1] == (data[1] & 0xf));
-#ifdef CONFIG_PMAC_BACKLIGHT
-               int backlight = get_backlight_level();
-#endif
+
                /*
                 * XXX: Where is the contrast control for the passive?
                 *  -- Cort
@@ -530,29 +528,17 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
 
                case 0xa:       /* brightness decrease */
 #ifdef CONFIG_PMAC_BACKLIGHT
-                       if (!disable_kernel_backlight) {
-                               if (down && backlight >= 0) {
-                                       if (backlight > BACKLIGHT_OFF)
-                                               set_backlight_level(backlight-1);
-                                       else
-                                               set_backlight_level(BACKLIGHT_OFF);
-                               }
-                       }
-#endif /* CONFIG_PMAC_BACKLIGHT */
+                       if (!disable_kernel_backlight && down)
+                               pmac_backlight_key_down();
+#endif
                        input_report_key(adbhid[id]->input, KEY_BRIGHTNESSDOWN, down);
                        break;
 
                case 0x9:       /* brightness increase */
 #ifdef CONFIG_PMAC_BACKLIGHT
-                       if (!disable_kernel_backlight) {
-                               if (down && backlight >= 0) {
-                                       if (backlight < BACKLIGHT_MAX)
-                                               set_backlight_level(backlight+1);
-                                       else 
-                                               set_backlight_level(BACKLIGHT_MAX);
-                               }
-                       }
-#endif /* CONFIG_PMAC_BACKLIGHT */
+                       if (!disable_kernel_backlight && down)
+                               pmac_backlight_key_up();
+#endif
                        input_report_key(adbhid[id]->input, KEY_BRIGHTNESSUP, down);
                        break;
 
diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c
new file mode 100644 (file)
index 0000000..b42d05f
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Backlight code for via-pmu
+ *
+ * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
+ * Copyright (C) 2001-2002 Benjamin Herrenschmidt
+ * Copyright (C) 2006      Michael Hanselmann <linux-kernel@hansmi.ch>
+ *
+ */
+
+#include <asm/ptrace.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <asm/backlight.h>
+#include <asm/prom.h>
+
+#define MAX_PMU_LEVEL 0xFF
+
+static struct device_node *vias;
+static struct backlight_properties pmu_backlight_data;
+
+static int pmu_backlight_get_level_brightness(struct fb_info *info,
+               int level)
+{
+       int pmulevel;
+
+       /* Get and convert the value */
+       mutex_lock(&info->bl_mutex);
+       pmulevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_PMU_LEVEL;
+       mutex_unlock(&info->bl_mutex);
+
+       if (pmulevel < 0)
+               pmulevel = 0;
+       else if (pmulevel > MAX_PMU_LEVEL)
+               pmulevel = MAX_PMU_LEVEL;
+
+       return pmulevel;
+}
+
+static int pmu_backlight_update_status(struct backlight_device *bd)
+{
+       struct fb_info *info = class_get_devdata(&bd->class_dev);
+       struct adb_request req;
+       int pmulevel, level = bd->props->brightness;
+
+       if (vias == NULL)
+               return -ENODEV;
+
+       if (bd->props->power != FB_BLANK_UNBLANK ||
+           bd->props->fb_blank != FB_BLANK_UNBLANK)
+               level = 0;
+
+       pmulevel = pmu_backlight_get_level_brightness(info, level);
+
+       pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel);
+       pmu_wait_complete(&req);
+
+       pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+               PMU_POW_BACKLIGHT | (level > 0 ? PMU_POW_ON : PMU_POW_OFF));
+       pmu_wait_complete(&req);
+
+       return 0;
+}
+
+static int pmu_backlight_get_brightness(struct backlight_device *bd)
+{
+       return bd->props->brightness;
+}
+
+static struct backlight_properties pmu_backlight_data = {
+       .owner          = THIS_MODULE,
+       .get_brightness = pmu_backlight_get_brightness,
+       .update_status  = pmu_backlight_update_status,
+       .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
+};
+
+void __init pmu_backlight_init(struct device_node *in_vias)
+{
+       struct backlight_device *bd;
+       struct fb_info *info;
+       char name[10];
+       int level, autosave;
+
+       vias = in_vias;
+
+       /* Special case for the old PowerBook since I can't test on it */
+       autosave =
+               machine_is_compatible("AAPL,3400/2400") ||
+               machine_is_compatible("AAPL,3500");
+
+       if (!autosave &&
+           !pmac_has_backlight_type("pmu") &&
+           !machine_is_compatible("AAPL,PowerBook1998") &&
+           !machine_is_compatible("PowerBook1,1"))
+               return;
+
+       /* Actually, this is a hack, but I don't know of a better way
+        * to get the first framebuffer device.
+        */
+       info = registered_fb[0];
+       if (!info) {
+               printk("pmubl: No framebuffer found\n");
+               goto error;
+       }
+
+       snprintf(name, sizeof(name), "pmubl%d", info->node);
+
+       bd = backlight_device_register(name, info, &pmu_backlight_data);
+       if (IS_ERR(bd)) {
+               printk("pmubl: Backlight registration failed\n");
+               goto error;
+       }
+
+       mutex_lock(&info->bl_mutex);
+       info->bl_dev = bd;
+       fb_bl_default_curve(info, 0x7F, 0x46, 0x0E);
+       mutex_unlock(&info->bl_mutex);
+
+       level = pmu_backlight_data.max_brightness;
+
+       if (autosave) {
+               /* read autosaved value if available */
+               struct adb_request req;
+               pmu_request(&req, NULL, 2, 0xd9, 0);
+               pmu_wait_complete(&req);
+
+               mutex_lock(&info->bl_mutex);
+               level = pmac_backlight_curve_lookup(info,
+                               (req.reply[0] >> 4) *
+                               pmu_backlight_data.max_brightness / 15);
+               mutex_unlock(&info->bl_mutex);
+       }
+
+       up(&bd->sem);
+       bd->props->brightness = level;
+       bd->props->power = FB_BLANK_UNBLANK;
+       bd->props->update_status(bd);
+       down(&bd->sem);
+
+       mutex_lock(&pmac_backlight_mutex);
+       if (!pmac_backlight)
+               pmac_backlight = bd;
+       mutex_unlock(&pmac_backlight_mutex);
+
+       printk("pmubl: Backlight initialized (%s)\n", name);
+
+       return;
+
+error:
+       return;
+}
index c63d4e7984be6e1884388f3c2875df6ce621a164..2a355ae5956241982680f1f1958c974645c84054 100644 (file)
@@ -144,7 +144,6 @@ static int data_index;
 static int data_len;
 static volatile int adb_int_pending;
 static volatile int disable_poll;
-static struct adb_request bright_req_1, bright_req_2;
 static struct device_node *vias;
 static int pmu_kind = PMU_UNKNOWN;
 static int pmu_fully_inited = 0;
@@ -161,7 +160,7 @@ static int drop_interrupts;
 #if defined(CONFIG_PM) && defined(CONFIG_PPC32)
 static int option_lid_wakeup = 1;
 #endif /* CONFIG_PM && CONFIG_PPC32 */
-#if (defined(CONFIG_PM)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT)
+#if (defined(CONFIG_PM)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT_LEGACY)
 static int sleep_in_progress;
 #endif
 static unsigned long async_req_locks;
@@ -208,10 +207,6 @@ static int proc_get_info(char *page, char **start, off_t off,
                          int count, int *eof, void *data);
 static int proc_get_irqstats(char *page, char **start, off_t off,
                          int count, int *eof, void *data);
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int pmu_set_backlight_level(int level, void* data);
-static int pmu_set_backlight_enable(int on, int level, void* data);
-#endif /* CONFIG_PMAC_BACKLIGHT */
 static void pmu_pass_intr(unsigned char *data, int len);
 static int proc_get_batt(char *page, char **start, off_t off,
                        int count, int *eof, void *data);
@@ -292,13 +287,6 @@ static char *pbook_type[] = {
        "Core99"
 };
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-static struct backlight_controller pmu_backlight_controller = {
-       pmu_set_backlight_enable,
-       pmu_set_backlight_level
-};
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
 int __init find_via_pmu(void)
 {
        u64 taddr;
@@ -417,8 +405,6 @@ static int __init via_pmu_start(void)
        if (vias == NULL)
                return -ENODEV;
 
-       bright_req_1.complete = 1;
-       bright_req_2.complete = 1;
        batt_req.complete = 1;
 
 #ifndef CONFIG_PPC_MERGE
@@ -483,9 +469,9 @@ static int __init via_pmu_dev_init(void)
                return -ENODEV;
 
 #ifdef CONFIG_PMAC_BACKLIGHT
-       /* Enable backlight */
-       register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");
-#endif /* CONFIG_PMAC_BACKLIGHT */
+       /* Initialize backlight */
+       pmu_backlight_init(vias);
+#endif
 
 #ifdef CONFIG_PPC32
        if (machine_is_compatible("AAPL,3400/2400") ||
@@ -1424,7 +1410,7 @@ next:
 #ifdef CONFIG_INPUT_ADBHID
                        if (!disable_kernel_backlight)
 #endif /* CONFIG_INPUT_ADBHID */
-                               set_backlight_level(data[1] >> 4);
+                               pmac_backlight_set_legacy_brightness(data[1] >> 4);
 #endif /* CONFIG_PMAC_BACKLIGHT */
        }
        /* Tick interrupt */
@@ -1674,61 +1660,6 @@ gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
        return IRQ_NONE;
 }
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int backlight_to_bright[] = {
-       0x7f, 0x46, 0x42, 0x3e, 0x3a, 0x36, 0x32, 0x2e,
-       0x2a, 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x12, 0x0e
-};
-static int
-pmu_set_backlight_enable(int on, int level, void* data)
-{
-       struct adb_request req;
-       
-       if (vias == NULL)
-               return -ENODEV;
-
-       if (on) {
-               pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
-                           backlight_to_bright[level]);
-               pmu_wait_complete(&req);
-       }
-       pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
-                   PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));
-               pmu_wait_complete(&req);
-
-       return 0;
-}
-
-static void
-pmu_bright_complete(struct adb_request *req)
-{
-       if (req == &bright_req_1)
-               clear_bit(1, &async_req_locks);
-       if (req == &bright_req_2)
-               clear_bit(2, &async_req_locks);
-}
-
-static int
-pmu_set_backlight_level(int level, void* data)
-{
-       if (vias == NULL)
-               return -ENODEV;
-
-       if (test_and_set_bit(1, &async_req_locks))
-               return -EAGAIN;
-       pmu_request(&bright_req_1, pmu_bright_complete, 2, PMU_BACKLIGHT_BRIGHT,
-               backlight_to_bright[level]);
-       if (test_and_set_bit(2, &async_req_locks))
-               return -EAGAIN;
-       pmu_request(&bright_req_2, pmu_bright_complete, 2, PMU_POWER_CTRL,
-                   PMU_POW_BACKLIGHT | (level > BACKLIGHT_OFF ?
-                                        PMU_POW_ON : PMU_POW_OFF));
-
-       return 0;
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
 void
 pmu_enable_irled(int on)
 {
@@ -2145,9 +2076,8 @@ pmac_suspend_devices(void)
                return -EBUSY;
        }
 
-       /* Wait for completion of async backlight requests */
-       while (!bright_req_1.complete || !bright_req_2.complete ||
-                       !batt_req.complete)
+       /* Wait for completion of async requests */
+       while (!batt_req.complete)
                pmu_poll();
 
        /* Giveup the lazy FPU & vec so we don't have to back them
@@ -2678,26 +2608,34 @@ pmu_ioctl(struct inode * inode, struct file *filp,
                        return put_user(1, argp);
 #endif /* CONFIG_PM && CONFIG_PPC32 */
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-       /* Backlight should have its own device or go via
-        * the fbdev
-        */
+#ifdef CONFIG_PMAC_BACKLIGHT_LEGACY
+       /* Compatibility ioctl's for backlight */
        case PMU_IOC_GET_BACKLIGHT:
+       {
+               int brightness;
+
                if (sleep_in_progress)
                        return -EBUSY;
-               error = get_backlight_level();
-               if (error < 0)
-                       return error;
-               return put_user(error, argp);
+
+               brightness = pmac_backlight_get_legacy_brightness();
+               if (brightness < 0)
+                       return brightness;
+               else
+                       return put_user(brightness, argp);
+
+       }
        case PMU_IOC_SET_BACKLIGHT:
        {
-               __u32 value;
+               int brightness;
+
                if (sleep_in_progress)
                        return -EBUSY;
-               error = get_user(value, argp);
-               if (!error)
-                       error = set_backlight_level(value);
-               break;
+
+               error = get_user(brightness, argp);
+               if (error)
+                       return error;
+
+               return pmac_backlight_set_legacy_brightness(brightness);
        }
 #ifdef CONFIG_INPUT_ADBHID
        case PMU_IOC_GRAB_BACKLIGHT: {
@@ -2713,7 +2651,7 @@ pmu_ioctl(struct inode * inode, struct file *filp,
                return 0;
        }
 #endif /* CONFIG_INPUT_ADBHID */
-#endif /* CONFIG_PMAC_BACKLIGHT */
+#endif /* CONFIG_PMAC_BACKLIGHT_LEGACY */
        case PMU_IOC_GET_MODEL:
                return put_user(pmu_kind, argp);
        case PMU_IOC_HAS_ADB:
index 344d83aae3ec3b5d6d7b4e9e41dee2f47d59e79f..583d151b7486a3d1911cba4fbe149242d2c0b98b 100644 (file)
@@ -25,7 +25,7 @@ config VIDEO_DEV
          module will be called videodev.
 
 config VIDEO_V4L1
-       boolean "Enable Video For Linux API 1 (DEPRECATED)"
+       bool "Enable Video For Linux API 1 (DEPRECATED)"
        depends on VIDEO_DEV
        select VIDEO_V4L1_COMPAT
        default y
@@ -36,7 +36,7 @@ config VIDEO_V4L1
          If you are unsure as to whether this is required, answer Y.
 
 config VIDEO_V4L1_COMPAT
-       boolean "Enable Video For Linux API 1 compatible Layer"
+       bool "Enable Video For Linux API 1 compatible Layer"
        depends on VIDEO_DEV
        default y
        ---help---
@@ -82,6 +82,9 @@ config VIDEO_IR
 config VIDEO_TVEEPROM
        tristate
 
+config VIDEO_CX2341X
+       tristate
+
 config USB_DABUSB
        tristate "DABUSB driver"
        depends on USB
index 61b89617a9671589a3d83cacc24e69a44faca9f1..8e744823064382309cbf35a20cfbb41c30842b7e 100644 (file)
@@ -1,5 +1,5 @@
 saa7146-objs    := saa7146_i2c.o saa7146_core.o
-saa7146_vv-objs := saa7146_vv_ksyms.o saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
+saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
 ir-common-objs  := ir-functions.o ir-keymaps.o
 
 obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
index 397cff8b345b2afc2b77b53d61f7d94c0658476f..8eaa88fd8b9b7ab3cde535b7ce4499b6c4fe6ffd 100644 (file)
@@ -269,4 +269,3 @@ EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
  * c-basic-offset: 8
  * End:
  */
-
index a294d5c2c73f0748fd096b8c13268cca169a02c4..ca98d94789476f7c7454dc3a034f2b752e68b990 100644 (file)
@@ -618,7 +618,7 @@ IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE] = {
 
 EXPORT_SYMBOL_GPL(ir_codes_em_terratec);
 
-IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE] = {
+IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = {
        [ 0x3a ] = KEY_0,
        [ 0x31 ] = KEY_1,
        [ 0x32 ] = KEY_2,
@@ -670,7 +670,7 @@ IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE] = {
        [ 0x27 ] = KEY_RECORD,
 };
 
-EXPORT_SYMBOL_GPL(ir_codes_em_pinnacle_usb);
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_grey);
 
 IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE] = {
        [ 0x0f ] = KEY_0,
@@ -1263,34 +1263,51 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
        [ 0x0f ] = KEY_9,
 
        [ 0x00 ] = KEY_POWER,
-       [ 0x02 ] = KEY_TUNER,           /* TV/FM */
-       [ 0x1e ] = KEY_VIDEO,
+       [ 0x1b ] = KEY_AUDIO,           /* Audio Source */
+       [ 0x02 ] = KEY_TUNER,           /* TV/FM, not on Y0400052 */
+       [ 0x1e ] = KEY_VIDEO,           /* Video Source */
+       [ 0x16 ] = KEY_INFO,            /* Display information */
        [ 0x04 ] = KEY_VOLUMEUP,
        [ 0x08 ] = KEY_VOLUMEDOWN,
        [ 0x0c ] = KEY_CHANNELUP,
        [ 0x10 ] = KEY_CHANNELDOWN,
        [ 0x03 ] = KEY_ZOOM,            /* fullscreen */
-       [ 0x1f ] = KEY_SUBTITLE,                /* closed caption/teletext */
+       [ 0x1f ] = KEY_TEXT,            /* closed caption/teletext */
        [ 0x20 ] = KEY_SLEEP,
+       [ 0x29 ] = KEY_CLEAR,           /* boss key */
        [ 0x14 ] = KEY_MUTE,
        [ 0x2b ] = KEY_RED,
        [ 0x2c ] = KEY_GREEN,
        [ 0x2d ] = KEY_YELLOW,
        [ 0x2e ] = KEY_BLUE,
-       [ 0x18 ] = KEY_KPPLUS,          /* fine tune + */
-       [ 0x19 ] = KEY_KPMINUS,         /* fine tune - */
+       [ 0x18 ] = KEY_KPPLUS,          /* fine tune + , not on Y040052 */
+       [ 0x19 ] = KEY_KPMINUS,         /* fine tune - , not on Y040052 */
+       [ 0x2a ] = KEY_MEDIA,           /* PIP (Picture in picture */
        [ 0x21 ] = KEY_DOT,
        [ 0x13 ] = KEY_ENTER,
-       [ 0x22 ] = KEY_BACK,
+       [ 0x11 ] = KEY_LAST,            /* Recall (last channel */
+       [ 0x22 ] = KEY_PREVIOUS,
        [ 0x23 ] = KEY_PLAYPAUSE,
        [ 0x24 ] = KEY_NEXT,
+       [ 0x25 ] = KEY_ARCHIVE,       /* Time Shifting */
        [ 0x26 ] = KEY_STOP,
-       [ 0x27 ] = KEY_RECORD
+       [ 0x27 ] = KEY_RECORD,
+       [ 0x28 ] = KEY_SAVE,          /* Screenshot */
+       [ 0x2f ] = KEY_MENU,
+       [ 0x30 ] = KEY_CANCEL,
+       [ 0x31 ] = KEY_CHANNEL,       /* Channel Surf */
+       [ 0x32 ] = KEY_SUBTITLE,
+       [ 0x33 ] = KEY_LANGUAGE,
+       [ 0x34 ] = KEY_REWIND,
+       [ 0x35 ] = KEY_FASTFORWARD,
+       [ 0x36 ] = KEY_TV,
+       [ 0x37 ] = KEY_RADIO,         /* FM */
+       [ 0x38 ] = KEY_DVD
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_winfast);
 
-IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
+IR_KEYTAB_TYPE ir_codes_pinnacle_color[IR_KEYTAB_SIZE] = {
        [ 0x59 ] = KEY_MUTE,
        [ 0x4a ] = KEY_POWER,
 
@@ -1348,7 +1365,7 @@ IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
        [ 0x0a ] = KEY_BACKSPACE,
 };
 
-EXPORT_SYMBOL_GPL(ir_codes_pinnacle);
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_color);
 
 /* Hauppauge: the newer, gray remotes (seems there are multiple
  * slightly different versions), shipped with cx88+ivtv cards.
@@ -1413,3 +1430,46 @@ IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = {
 
 EXPORT_SYMBOL_GPL(ir_codes_hauppauge_new);
 
+IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE] = {
+       [ 0x1d ] = KEY_SWITCHVIDEOMODE, /* switch inputs */
+       [ 0x2a ] = KEY_FRONT,
+
+       [ 0x3e ] = KEY_1,
+       [ 0x02 ] = KEY_2,
+       [ 0x06 ] = KEY_3,
+       [ 0x0a ] = KEY_4,
+       [ 0x0e ] = KEY_5,
+       [ 0x12 ] = KEY_6,
+       [ 0x16 ] = KEY_7,
+       [ 0x1a ] = KEY_8,
+       [ 0x1e ] = KEY_9,
+       [ 0x3a ] = KEY_0,
+       [ 0x22 ] = KEY_NUMLOCK,         /* -/-- */
+       [ 0x20 ] = KEY_REFRESH,
+
+       [ 0x03 ] = KEY_BRIGHTNESSDOWN,
+       [ 0x28 ] = KEY_AUDIO,
+       [ 0x3c ] = KEY_UP,
+       [ 0x3f ] = KEY_LEFT,
+       [ 0x2e ] = KEY_MUTE,
+       [ 0x3b ] = KEY_RIGHT,
+       [ 0x00 ] = KEY_DOWN,
+       [ 0x07 ] = KEY_BRIGHTNESSUP,
+       [ 0x2c ] = KEY_TEXT,
+
+       [ 0x37 ] = KEY_RECORD,
+       [ 0x17 ] = KEY_PLAY,
+       [ 0x13 ] = KEY_PAUSE,
+       [ 0x26 ] = KEY_STOP,
+       [ 0x18 ] = KEY_FASTFORWARD,
+       [ 0x14 ] = KEY_REWIND,
+       [ 0x33 ] = KEY_ZOOM,
+       [ 0x32 ] = KEY_KEYBOARD,
+       [ 0x30 ] = KEY_GOTO,            /* Pointing arrow */
+       [ 0x36 ] = KEY_MACRO,           /* Maximize/Minimize (yellow) */
+       [ 0x0b ] = KEY_RADIO,
+       [ 0x10 ] = KEY_POWER,
+
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_npgtech);
index 523ab3851c7b8ad71609a4df77104c29bbd099be..0027acc5b8e988b2a271ae79d1a90a96acbbd5d8 100644 (file)
@@ -501,6 +501,7 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(saa7146_vv_init);
 
 int saa7146_vv_release(struct saa7146_dev* dev)
 {
@@ -515,6 +516,7 @@ int saa7146_vv_release(struct saa7146_dev* dev)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(saa7146_vv_release);
 
 int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
                            char *name, int type)
@@ -553,6 +555,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
        *vid = vfd;
        return 0;
 }
+EXPORT_SYMBOL_GPL(saa7146_register_device);
 
 int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev)
 {
@@ -571,6 +574,7 @@ int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(saa7146_unregister_device);
 
 static int __init saa7146_vv_init_module(void)
 {
index 33bec8a6843b49bdc05ec9345326bad23a316a11..2092e6c33dd289674a51b3c58a2389cb3c77ad4f 100644 (file)
@@ -641,6 +641,7 @@ void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sy
        vv->current_hps_source = source;
        vv->current_hps_sync = sync;
 }
+EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);
 
 int saa7146_enable_overlay(struct saa7146_fh *fh)
 {
index e7079d1bd5371b19836788ec9064ed9c05a8d151..8393d472d3b81acced0acf7848cac92021ae85ef 100644 (file)
@@ -318,6 +318,7 @@ int saa7146_start_preview(struct saa7146_fh *fh)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(saa7146_start_preview);
 
 int saa7146_stop_preview(struct saa7146_fh *fh)
 {
@@ -352,6 +353,7 @@ int saa7146_stop_preview(struct saa7146_fh *fh)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(saa7146_stop_preview);
 
 static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
 {
diff --git a/drivers/media/common/saa7146_vv_ksyms.c b/drivers/media/common/saa7146_vv_ksyms.c
deleted file mode 100644 (file)
index 62226eb..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <linux/module.h>
-#include <media/saa7146_vv.h>
-
-EXPORT_SYMBOL_GPL(saa7146_start_preview);
-EXPORT_SYMBOL_GPL(saa7146_stop_preview);
-
-EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);
-EXPORT_SYMBOL_GPL(saa7146_register_device);
-EXPORT_SYMBOL_GPL(saa7146_unregister_device);
-
-EXPORT_SYMBOL_GPL(saa7146_vv_init);
-EXPORT_SYMBOL_GPL(saa7146_vv_release);
index 9c7f122826e0089d9931402be70ddedf18c2e436..3be87c72e37b7f6bf13053f3db75a0fd9a4229af 100644 (file)
@@ -14,6 +14,7 @@
 #include "stv0297.h"
 #include "mt312.h"
 #include "lgdt330x.h"
+#include "lg_h06xf.h"
 #include "dvb-pll.h"
 
 /* lnb control */
@@ -166,11 +167,12 @@ static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate,
        return 0;
 }
 
-static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
+static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
        u8 buf[4];
        u32 div;
        struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+       struct flexcop_device *fc = fe->dvb->priv;
 
        div = params->frequency / 125;
 
@@ -181,8 +183,11 @@ static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct i2c_adapter
 
        if (params->frequency < 1500000) buf[3] |= 0x10;
 
-       if (i2c_transfer(i2c, &msg, 1) != 1)
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) {
                return -EIO;
+       }
        return 0;
 }
 
@@ -241,7 +246,6 @@ static struct stv0299_config samsung_tbmu24112_config = {
        .volt13_op0_op1 = STV0299_VOLT13_OP1,
        .min_delay_ms = 100,
        .set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
-       .pll_set = samsung_tbmu24112_pll_set,
 };
 
 /* dvb-t mt352 */
@@ -264,11 +268,14 @@ static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
 {
        u32 div;
        unsigned char bs = 0;
 
+       if (buf_len < 5)
+               return -EINVAL;
+
        #define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
        div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
 
@@ -276,19 +283,18 @@ static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_front
        if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
        if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
 
-       pllbuf[0] = 0xc2; /* Note: non-linux standard PLL i2c address */
+       pllbuf[0] = 0x61;
        pllbuf[1] = div >> 8;
        pllbuf[2] = div & 0xff;
        pllbuf[3] = 0xcc;
        pllbuf[4] = bs;
 
-       return 0;
+       return 5;
 }
 
 static struct mt352_config samsung_tdtc9251dh0_config = {
        .demod_address = 0x0f,
        .demod_init    = samsung_tdtc9251dh0_demod_init,
-       .pll_set       = samsung_tdtc9251dh0_pll_set,
 };
 
 static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
@@ -297,56 +303,21 @@ static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct fir
        return request_firmware(fw, name, fc->dev);
 }
 
-static int lgdt3303_pll_set(struct dvb_frontend* fe,
-                           struct dvb_frontend_parameters* params)
+static int lgdt3303_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
        struct flexcop_device *fc = fe->dvb->priv;
-       u8 buf[4];
-       struct i2c_msg msg =
-               { .addr = 0x61, .flags = 0, .buf = buf, .len = 4 };
-       int err;
-
-       dvb_pll_configure(&dvb_pll_tdvs_tua6034,buf, params->frequency, 0);
-       dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
-                       __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
-       if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) {
-               printk(KERN_WARNING "lgdt3303: %s error "
-                          "(addr %02x <- %02x, err = %i)\n",
-                          __FUNCTION__, buf[0], buf[1], err);
-               if (err < 0)
-                       return err;
-               else
-                       return -EREMOTEIO;
-       }
-
-       buf[0] = 0x86 | 0x18;
-       buf[1] = 0x50;
-       msg.len = 2;
-       if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) {
-               printk(KERN_WARNING "lgdt3303: %s error "
-                          "(addr %02x <- %02x, err = %i)\n",
-                          __FUNCTION__, buf[0], buf[1], err);
-               if (err < 0)
-                       return err;
-               else
-                       return -EREMOTEIO;
-       }
-
-       return 0;
+       return lg_h06xf_pll_set(fe, &fc->i2c_adap, params);
 }
 
 static struct lgdt330x_config air2pc_atsc_hd5000_config = {
        .demod_address       = 0x59,
        .demod_chip          = LGDT3303,
        .serial_mpeg         = 0x04,
-       .pll_set             = lgdt3303_pll_set,
        .clock_polarity_flip = 1,
 };
 
 static struct nxt200x_config samsung_tbmv_config = {
        .demod_address    = 0x0a,
-       .pll_address      = 0xc2,
-       .pll_desc         = &dvb_pll_samsung_tbmv,
 };
 
 static struct bcm3510_config air2pc_atsc_first_gen_config = {
@@ -354,7 +325,7 @@ static struct bcm3510_config air2pc_atsc_first_gen_config = {
        .request_firmware = flexcop_fe_request_firmware,
 };
 
-static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
        u8 buf[4];
        u32 div;
@@ -371,6 +342,8 @@ static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct d
        if (params->frequency < 1550000)
                buf[3] |= 0x02;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
                return -EIO;
        return 0;
@@ -379,9 +352,52 @@ static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct d
 static struct mt312_config skystar23_samsung_tbdu18132_config = {
 
        .demod_address = 0x0e,
-       .pll_set = skystar23_samsung_tbdu18132_pll_set,
 };
 
+static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
+                                              struct dvb_frontend_parameters *fep)
+{
+       struct flexcop_device *fc = fe->dvb->priv;
+       u8 buf[4];
+       u16 div;
+       int ret;
+
+/*  62.5 kHz * 10 */
+#define REF_FREQ    625
+#define FREQ_OFFSET 36125
+
+       div = ((fep->frequency/1000 + FREQ_OFFSET ) * 10)  / REF_FREQ; // 4 MHz = 4000 KHz
+
+       buf[0] = (u8)( div >> 8) & 0x7f;
+       buf[1] = (u8)        div & 0xff;
+
+/* F(osc) = N * Reference Freq. (62.5 kHz)
+ * byte 2 :  0 N14 N13 N12 N11 N10 N9  N8
+ * byte 3 : N7 N6  N5  N4  N3  N2  N1  N0
+ * byte 4 : 1  *   *   AGD R3  R2  R1  R0
+ * byte 5 : C1 *   RE  RTS BS4 BS3 BS2 BS1
+ * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */
+       buf[2] = 0x95;
+
+// Range(MHz)  C1 *  RE RTS BS4 BS3 BS2 BS1  Byte 5
+//  47 - 153   0  *  0   0   0   0   0   1   0x01
+// 153 - 430   0  *  0   0   0   0   1   0   0x02
+// 430 - 822   0  *  0   0   1   0   0   0   0x08
+// 822 - 862   1  *  0   0   1   0   0   0   0x88
+
+            if (fep->frequency <= 153000000) buf[3] = 0x01;
+       else if (fep->frequency <= 430000000) buf[3] = 0x02;
+       else if (fep->frequency <= 822000000) buf[3] = 0x08;
+       else buf[3] = 0x88;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]);
+       ret = fc->i2c_request(fc,FC_WRITE,FC_I2C_PORT_TUNER,0x61,buf[0],&buf[1],3);
+       deb_tuner("tuner write returned: %d\n",ret);
+
+       return 0;
+}
 
 static u8 alps_tdee4_stv0297_inittab[] = {
        0x80, 0x01,
@@ -490,7 +506,9 @@ int flexcop_frontend_init(struct flexcop_device *fc)
 
        /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
        if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
-               ops = fc->fe->ops;
+               ops = &fc->fe->ops;
+
+               ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
 
                ops->set_voltage = flexcop_set_voltage;
 
@@ -503,16 +521,19 @@ int flexcop_frontend_init(struct flexcop_device *fc)
        /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
        if ((fc->fe = mt352_attach(&samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
                fc->dev_type          = FC_AIR_DVB;
+               fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
                info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
        } else
        /* try the air atsc 2nd generation (nxt2002) */
        if ((fc->fe = nxt200x_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
                fc->dev_type          = FC_AIR_ATSC2;
+               dvb_pll_attach(fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_samsung_tbmv);
                info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
        } else
        /* try the air atsc 3nd generation (lgdt3303) */
        if ((fc->fe = lgdt330x_attach(&air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
                fc->dev_type          = FC_AIR_ATSC3;
+               fc->fe->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
                info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
        } else
        /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
@@ -523,11 +544,14 @@ int flexcop_frontend_init(struct flexcop_device *fc)
        /* try the cable dvb (stv0297) */
        if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) {
                fc->dev_type                        = FC_CABLE;
+               fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
                info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address);
        } else
        /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
        if ((fc->fe = vp310_mt312_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
-               ops = fc->fe->ops;
+               ops = &fc->fe->ops;
+
+               ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params;
 
                ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
                ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
@@ -547,7 +571,7 @@ int flexcop_frontend_init(struct flexcop_device *fc)
        } else {
                if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
                        err("frontend registration failed!");
-                       ops = fc->fe->ops;
+                       ops = &fc->fe->ops;
                        if (ops->release != NULL)
                                ops->release(fc->fe);
                        fc->fe = NULL;
index 9bc40bdcc282e2bd1d25a79e6275aaab0e3ec780..f04041702191e7eb303f0920820f038756ee5d75 100644 (file)
@@ -242,19 +242,16 @@ static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci)
        if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[0],FC_DEFAULT_DMA1_BUFSIZE)) != 0)
                return ret;
 
-       if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0)
-               goto dma1_free;
+       if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0) {
+               flexcop_dma_free(&fc_pci->dma[0]);
+               return ret;
+       }
 
        flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1);
        flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO   | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2);
 
        fc_pci->init_state |= FC_PCI_DMA_INIT;
 
-       goto success;
-dma1_free:
-       flexcop_dma_free(&fc_pci->dma[0]);
-
-success:
        return ret;
 }
 
@@ -303,7 +300,7 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci)
        spin_lock_init(&fc_pci->irq_lock);
 
        fc_pci->init_state |= FC_PCI_INIT;
-       goto success;
+       return ret;
 
 err_pci_iounmap:
        pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
@@ -312,8 +309,6 @@ err_pci_release_regions:
        pci_release_regions(fc_pci->pdev);
 err_pci_disable_device:
        pci_disable_device(fc_pci->pdev);
-
-success:
        return ret;
 }
 
@@ -378,14 +373,14 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
        INIT_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work, fc_pci);
 
-       goto success;
+       return ret;
+
 err_fc_exit:
        flexcop_device_exit(fc);
 err_pci_exit:
        flexcop_pci_exit(fc_pci);
 err_kfree:
        flexcop_device_kfree(fc);
-success:
        return ret;
 }
 
index 06ec9fff0ec1e5f5d3293685e5f49d9c73a71421..515954f96c9a6afa11eb5e708963216590ee5bdb 100644 (file)
@@ -433,11 +433,10 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
        flexcop_wan_set_speed(fc_usb->fc_dev,FC_WAN_SPEED_8MBITS);
        flexcop_sram_ctrl(fc_usb->fc_dev,1,1,1);
 
-       ret = 0;
-       goto success;
+       return 0;
+
 urb_error:
        flexcop_usb_transfer_exit(fc_usb);
-success:
        return ret;
 }
 
@@ -515,15 +514,14 @@ static int flexcop_usb_probe(struct usb_interface *intf,
                goto err_fc_exit;
 
        info("%s successfully initialized and connected.",DRIVER_NAME);
-       ret = 0;
-       goto success;
+       return 0;
+
 err_fc_exit:
        flexcop_device_exit(fc);
 err_usb_exit:
        flexcop_usb_exit(fc_usb);
 err_kfree:
        flexcop_device_kfree(fc);
-success:
        return ret;
 }
 
index 56ba52470676821070a88050b43c35d634f3d209..29ec4183118e80f744aed424dc1d1715b1b9aeef 100644 (file)
@@ -67,7 +67,7 @@ static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
 static int flexcop_dvb_init(struct flexcop_device *fc)
 {
        int ret;
-       if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",fc->owner)) < 0) {
+       if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",fc->owner,fc->dev)) < 0) {
                err("error registering DVB adapter");
                return ret;
        }
@@ -116,7 +116,7 @@ static int flexcop_dvb_init(struct flexcop_device *fc)
        dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx);
 
        fc->init_state |= FC_STATE_DVB_INIT;
-       goto success;
+       return 0;
 
 err_connect_frontend:
        fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend);
@@ -129,9 +129,6 @@ err_dmx_dev:
 err_dmx:
        dvb_unregister_adapter(&fc->dvb_adapter);
        return ret;
-
-success:
-       return 0;
 }
 
 static void flexcop_dvb_exit(struct flexcop_device *fc)
@@ -279,11 +276,10 @@ int flexcop_device_initialize(struct flexcop_device *fc)
 
        flexcop_device_name(fc,"initialization of","complete");
 
-       ret = 0;
-       goto success;
+       return 0;
+
 error:
        flexcop_device_exit(fc);
-success:
        return ret;
 }
 EXPORT_SYMBOL(flexcop_device_initialize);
index 5500f8a0ffe2c6fa1f0013bbc8dc8ccb810f93dd..761fa6e7d76222195638ca7666e027fb72e57b54 100644 (file)
@@ -63,8 +63,6 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging, default is 0 (off).");
 int bt878_num;
 struct bt878 bt878[BT878_MAX];
 
-EXPORT_SYMBOL(bt878_debug);
-EXPORT_SYMBOL(bt878_verbose);
 EXPORT_SYMBOL(bt878_num);
 EXPORT_SYMBOL(bt878);
 
@@ -393,7 +391,9 @@ static struct cards card_list[] __devinitdata = {
        { 0x07711461, BTTV_BOARD_AVDVBT_771,                    "AVermedia AverTV DVB-T 771" },
        { 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE,               "DViCO FusionHDTV DVB-T Lite" },
        { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,       "DViCO FusionHDTV 5 Lite" },
-       { 0x20007063, BTTV_BOARD_PC_HDTV,                       "pcHDTV HD-2000 TV"},
+       { 0x20007063, BTTV_BOARD_PC_HDTV,                       "pcHDTV HD-2000 TV" },
+       { 0x00261822, BTTV_BOARD_TWINHAN_DST,                   "DNTV Live! Mini" },
+
        { 0, -1, NULL }
 };
 
@@ -417,6 +417,11 @@ static int __devinit bt878_probe(struct pci_dev *dev,
 
        printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n",
               bt878_num);
+       if (bt878_num >= BT878_MAX) {
+               printk(KERN_ERR "bt878: Too many devices inserted\n");
+               result = -ENOMEM;
+               goto fail0;
+       }
        if (pci_enable_device(dev))
                return -EIO;
 
index 1cfa5e5035d830f9ca66d1679efa149df2a065ec..d687a14ec0a7aa6b3b72d9fd322d9508cab8c2da 100644 (file)
@@ -38,6 +38,10 @@ static unsigned int dst_addons;
 module_param(dst_addons, int, 0644);
 MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)");
 
+static unsigned int dst_algo;
+module_param(dst_algo, int, 0644);
+MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)");
+
 #define HAS_LOCK               1
 #define ATTEMPT_TUNE           2
 #define HAS_POWER              4
@@ -47,20 +51,24 @@ MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)");
 #define DST_INFO               2
 #define DST_DEBUG              3
 
-#define dprintk(x, y, z, format, arg...) do {                                          \
-       if (z) {                                                                        \
-               if      ((x > DST_ERROR) && (x > y))                                    \
-                       printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ##arg);      \
-               else if ((x > DST_NOTICE) && (x > y))                                   \
-                       printk(KERN_NOTICE "%s: " format "\n", __FUNCTION__ , ##arg);   \
-               else if ((x > DST_INFO) && (x > y))                                     \
-                       printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##arg);     \
-               else if ((x > DST_DEBUG) && (x > y))                                    \
-                       printk(KERN_DEBUG "%s: " format "\n", __FUNCTION__ , ##arg);    \
-       } else {                                                                        \
-               if (x > y)                                                              \
-                       printk(format, ##arg);                                          \
-       }                                                                               \
+#define dprintk(x, y, z, format, arg...) do {                          \
+       if (z) {                                                        \
+               if      ((x > DST_ERROR) && (x > y))                    \
+                       printk(KERN_ERR "dst(%d) %s: " format "\n",     \
+                               state->bt->nr, __func__ , ##arg);       \
+               else if ((x > DST_NOTICE) && (x > y))                   \
+                       printk(KERN_NOTICE "dst(%d) %s: " format "\n",  \
+                               state->bt->nr, __func__ , ##arg);       \
+               else if ((x > DST_INFO) && (x > y))                     \
+                       printk(KERN_INFO "dst(%d) %s: " format "\n",    \
+                               state->bt->nr, __func__ , ##arg);       \
+               else if ((x > DST_DEBUG) && (x > y))                    \
+                       printk(KERN_DEBUG "dst(%d) %s: " format "\n",   \
+                               state->bt->nr,  __func__ , ##arg);      \
+       } else {                                                        \
+               if (x > y)                                              \
+                       printk(format, ##arg);                          \
+       }                                                               \
 } while(0)
 
 
@@ -110,7 +118,7 @@ int dst_gpio_inb(struct dst_state *state, u8 *result)
 
        *result = 0;
        if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) {
-               dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)\n", err);
+               dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)", err);
                return -EREMOTEIO;
        }
        *result = (u8) rd_packet.rd.value;
@@ -363,6 +371,17 @@ static int dst_set_freq(struct dst_state *state, u32 freq)
                state->tx_tuna[2] = (freq >> 16) & 0xff;
                state->tx_tuna[3] = (freq >> 8) & 0xff;
                state->tx_tuna[4] = (u8) freq;
+       } else if (state->dst_type == DST_TYPE_IS_ATSC) {
+               freq = freq / 1000;
+               if (freq < 51000 || freq > 858000)
+                       return -EINVAL;
+               state->tx_tuna[2] = (freq >> 16) & 0xff;
+               state->tx_tuna[3] = (freq >>  8) & 0xff;
+               state->tx_tuna[4] = (u8) freq;
+               state->tx_tuna[5] = 0x00;               /*      ATSC    */
+               state->tx_tuna[6] = 0x00;
+               if (state->dst_hw_cap & DST_TYPE_HAS_ANALOG)
+                       state->tx_tuna[7] = 0x00;       /*      Digital */
        } else
                return -EINVAL;
 
@@ -447,29 +466,41 @@ static int dst_set_symbolrate(struct dst_state *state, u32 srate)
        }
        dprintk(verbose, DST_INFO, 1, "set symrate %u", srate);
        srate /= 1000;
-       if (state->type_flags & DST_TYPE_HAS_SYMDIV) {
-               sval = srate;
-               sval <<= 20;
-               do_div(sval, 88000);
-               symcalc = (u32) sval;
-               dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc);
-               state->tx_tuna[5] = (u8) (symcalc >> 12);
-               state->tx_tuna[6] = (u8) (symcalc >> 4);
-               state->tx_tuna[7] = (u8) (symcalc << 4);
-       } else {
-               state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f;
-               state->tx_tuna[6] = (u8) (srate >> 8);
-               state->tx_tuna[7] = (u8) srate;
-       }
-       state->tx_tuna[8] &= ~0x20;
-       if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
-               if (srate > 8000)
-                       state->tx_tuna[8] |= 0x20;
+       if (state->dst_type == DST_TYPE_IS_SAT) {
+               if (state->type_flags & DST_TYPE_HAS_SYMDIV) {
+                       sval = srate;
+                       sval <<= 20;
+                       do_div(sval, 88000);
+                       symcalc = (u32) sval;
+                       dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc);
+                       state->tx_tuna[5] = (u8) (symcalc >> 12);
+                       state->tx_tuna[6] = (u8) (symcalc >> 4);
+                       state->tx_tuna[7] = (u8) (symcalc << 4);
+               } else {
+                       state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f;
+                       state->tx_tuna[6] = (u8) (srate >> 8);
+                       state->tx_tuna[7] = (u8) srate;
+               }
+               state->tx_tuna[8] &= ~0x20;
+               if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
+                       if (srate > 8000)
+                               state->tx_tuna[8] |= 0x20;
+               }
+       } else if (state->dst_type == DST_TYPE_IS_CABLE) {
+               dprintk(verbose, DST_DEBUG, 1, "%s", state->fw_name);
+               if (!strncmp(state->fw_name, "DCTNEW", 6)) {
+                       state->tx_tuna[5] = (u8) (srate >> 8);
+                       state->tx_tuna[6] = (u8) srate;
+                       state->tx_tuna[7] = 0x00;
+               } else if (!strncmp(state->fw_name, "DCT-CI", 6)) {
+                       state->tx_tuna[5] = 0x00;
+                       state->tx_tuna[6] = (u8) (srate >> 8);
+                       state->tx_tuna[7] = (u8) srate;
+               }
        }
        return 0;
 }
 
-
 static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation)
 {
        if (state->dst_type != DST_TYPE_IS_CABLE)
@@ -490,7 +521,10 @@ static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulatio
                state->tx_tuna[8] = 0x80;
                break;
        case QAM_256:
-               state->tx_tuna[8] = 0x00;
+               if (!strncmp(state->fw_name, "DCTNEW", 6))
+                       state->tx_tuna[8] = 0xff;
+               else if (!strncmp(state->fw_name, "DCT-CI", 6))
+                       state->tx_tuna[8] = 0x00;
                break;
        case QPSK:
        case QAM_AUTO:
@@ -523,13 +557,19 @@ u8 dst_check_sum(u8 *buf, u32 len)
 }
 EXPORT_SYMBOL(dst_check_sum);
 
-static void dst_type_flags_print(u32 type_flags)
+static void dst_type_flags_print(struct dst_state *state)
 {
+       u32 type_flags = state->type_flags;
+
        dprintk(verbose, DST_ERROR, 0, "DST type flags :");
-       if (type_flags & DST_TYPE_HAS_NEWTUNE)
-               dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_NEWTUNE);
+       if (type_flags & DST_TYPE_HAS_TS188)
+               dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_TS188);
+       if (type_flags & DST_TYPE_HAS_NEWTUNE_2)
+               dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner 2", DST_TYPE_HAS_NEWTUNE_2);
        if (type_flags & DST_TYPE_HAS_TS204)
                dprintk(verbose, DST_ERROR, 0, " 0x%x ts204", DST_TYPE_HAS_TS204);
+       if (type_flags & DST_TYPE_HAS_VLF)
+               dprintk(verbose, DST_ERROR, 0, " 0x%x VLF", DST_TYPE_HAS_VLF);
        if (type_flags & DST_TYPE_HAS_SYMDIV)
                dprintk(verbose, DST_ERROR, 0, " 0x%x symdiv", DST_TYPE_HAS_SYMDIV);
        if (type_flags & DST_TYPE_HAS_FW_1)
@@ -542,7 +582,7 @@ static void dst_type_flags_print(u32 type_flags)
 }
 
 
-static int dst_type_print(u8 type)
+static int dst_type_print(struct dst_state *state, u8 type)
 {
        char *otype;
        switch (type) {
@@ -558,6 +598,10 @@ static int dst_type_print(u8 type)
                otype = "cable";
                break;
 
+       case DST_TYPE_IS_ATSC:
+               otype = "atsc";
+               break;
+
        default:
                dprintk(verbose, DST_INFO, 1, "invalid dst type %d", type);
                return -EINVAL;
@@ -567,6 +611,127 @@ static int dst_type_print(u8 type)
        return 0;
 }
 
+struct tuner_types tuner_list[] = {
+       {
+               .tuner_type = TUNER_TYPE_L64724,
+               .tuner_name = "L 64724",
+               .board_name = "UNKNOWN",
+               .fw_name    = "UNKNOWN"
+       },
+
+       {
+               .tuner_type = TUNER_TYPE_STV0299,
+               .tuner_name = "STV 0299",
+               .board_name = "VP1020",
+               .fw_name    = "DST-MOT"
+       },
+
+       {
+               .tuner_type = TUNER_TYPE_STV0299,
+               .tuner_name = "STV 0299",
+               .board_name = "VP1020",
+               .fw_name    = "DST-03T"
+       },
+
+       {
+               .tuner_type = TUNER_TYPE_MB86A15,
+               .tuner_name = "MB 86A15",
+               .board_name = "VP1022",
+               .fw_name    = "DST-03T"
+       },
+
+       {
+               .tuner_type = TUNER_TYPE_MB86A15,
+               .tuner_name = "MB 86A15",
+               .board_name = "VP1025",
+               .fw_name    = "DST-03T"
+       },
+
+       {
+               .tuner_type = TUNER_TYPE_STV0299,
+               .tuner_name = "STV 0299",
+               .board_name = "VP1030",
+               .fw_name    = "DST-CI"
+       },
+
+       {
+               .tuner_type = TUNER_TYPE_STV0299,
+               .tuner_name = "STV 0299",
+               .board_name = "VP1030",
+               .fw_name    = "DSTMCI"
+       },
+
+       {
+               .tuner_type = TUNER_TYPE_UNKNOWN,
+               .tuner_name = "UNKNOWN",
+               .board_name = "VP2021",
+               .fw_name    = "DCTNEW"
+       },
+
+       {
+               .tuner_type = TUNER_TYPE_UNKNOWN,
+               .tuner_name = "UNKNOWN",
+               .board_name = "VP2030",
+               .fw_name    = "DCT-CI"
+       },
+
+       {
+               .tuner_type = TUNER_TYPE_UNKNOWN,
+               .tuner_name = "UNKNOWN",
+               .board_name = "VP2031",
+               .fw_name    = "DCT-CI"
+       },
+
+       {
+               .tuner_type = TUNER_TYPE_UNKNOWN,
+               .tuner_name = "UNKNOWN",
+               .board_name = "VP2040",
+               .fw_name    = "DCT-CI"
+       },
+
+       {
+               .tuner_type = TUNER_TYPE_UNKNOWN,
+               .tuner_name = "UNKNOWN",
+               .board_name = "VP3020",
+               .fw_name    = "DTTFTA"
+       },
+
+       {
+               .tuner_type = TUNER_TYPE_UNKNOWN,
+               .tuner_name = "UNKNOWN",
+               .board_name = "VP3021",
+               .fw_name    = "DTTFTA"
+       },
+
+       {
+               .tuner_type = TUNER_TYPE_TDA10046,
+               .tuner_name = "TDA10046",
+               .board_name = "VP3040",
+               .fw_name    = "DTT-CI"
+       },
+
+       {
+               .tuner_type = TUNER_TYPE_UNKNOWN,
+               .tuner_name = "UNKNOWN",
+               .board_name = "VP3051",
+               .fw_name    = "DTTNXT"
+       },
+
+       {
+               .tuner_type = TUNER_TYPE_NXT200x,
+               .tuner_name = "NXT200x",
+               .board_name = "VP3220",
+               .fw_name    = "ATSCDI"
+       },
+
+       {
+               .tuner_type = TUNER_TYPE_NXT200x,
+               .tuner_name = "NXT200x",
+               .board_name = "VP3250",
+               .fw_name    = "ATSCAD"
+       },
+};
+
 /*
        Known cards list
        Satellite
@@ -608,7 +773,8 @@ static struct dst_types dst_tlist[] = {
                .offset = 0,
                .dst_type =  DST_TYPE_IS_SAT,
                .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS,
-               .dst_feature = 0
+               .dst_feature = 0,
+               .tuner_type = 0
        },      /*      obsolete        */
 
        {
@@ -616,15 +782,17 @@ static struct dst_types dst_tlist[] = {
                .offset = 0,
                .dst_type =  DST_TYPE_IS_SAT,
                .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
-               .dst_feature = 0
+               .dst_feature = 0,
+               .tuner_type = 0
        },      /*      obsolete        */
 
        {
                .device_id = "DST-030",
                .offset =  0,
                .dst_type = DST_TYPE_IS_SAT,
-               .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
-               .dst_feature = 0
+               .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1,
+               .dst_feature = 0,
+               .tuner_type = 0
        },      /*      obsolete        */
 
        {
@@ -633,7 +801,8 @@ static struct dst_types dst_tlist[] = {
                .dst_type = DST_TYPE_IS_SAT,
                .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2,
                .dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5
-                                                        | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO
+                                                        | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO,
+               .tuner_type = TUNER_TYPE_MULTI
         },
 
        {
@@ -641,57 +810,63 @@ static struct dst_types dst_tlist[] = {
                .offset =  0,
                .dst_type = DST_TYPE_IS_SAT,
                .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
-               .dst_feature = 0
+               .dst_feature = 0,
+               .tuner_type = 0
        },      /*      obsolete        */
 
        {
                .device_id = "DST-CI",
                .offset = 1,
                .dst_type = DST_TYPE_IS_SAT,
-               .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
-               .dst_feature = DST_TYPE_HAS_CA
+               .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_1,
+               .dst_feature = DST_TYPE_HAS_CA,
+               .tuner_type = 0
        },      /*      An OEM board    */
 
        {
                .device_id = "DSTMCI",
                .offset = 1,
                .dst_type = DST_TYPE_IS_SAT,
-               .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT,
+               .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT | DST_TYPE_HAS_VLF,
                .dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4
-                                                       | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC
+                                                       | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC,
+               .tuner_type = TUNER_TYPE_MULTI
        },
 
        {
                .device_id = "DSTFCI",
                .offset = 1,
                .dst_type = DST_TYPE_IS_SAT,
-               .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
-               .dst_feature = 0
+               .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1,
+               .dst_feature = 0,
+               .tuner_type = 0
        },      /* unknown to vendor    */
 
        {
                .device_id = "DCT-CI",
                .offset = 1,
                .dst_type = DST_TYPE_IS_CABLE,
-               .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1
-                                                       | DST_TYPE_HAS_FW_2,
-               .dst_feature = DST_TYPE_HAS_CA
+               .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_VLF,
+               .dst_feature = DST_TYPE_HAS_CA,
+               .tuner_type = 0
        },
 
        {
                .device_id = "DCTNEW",
                .offset = 1,
                .dst_type = DST_TYPE_IS_CABLE,
-               .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD,
-               .dst_feature = 0
+               .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_MULTI_FE,
+               .dst_feature = 0,
+               .tuner_type = 0
        },
 
        {
                .device_id = "DTT-CI",
                .offset = 1,
                .dst_type = DST_TYPE_IS_TERR,
-               .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE,
-               .dst_feature = DST_TYPE_HAS_CA
+               .type_flags = DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_VLF,
+               .dst_feature = DST_TYPE_HAS_CA,
+               .tuner_type = 0
        },
 
        {
@@ -699,7 +874,8 @@ static struct dst_types dst_tlist[] = {
                .offset = 1,
                .dst_type = DST_TYPE_IS_TERR,
                .type_flags = DST_TYPE_HAS_FW_2,
-               .dst_feature = 0
+               .dst_feature = 0,
+               .tuner_type = 0
        },
 
        {
@@ -707,7 +883,8 @@ static struct dst_types dst_tlist[] = {
                .offset = 1,
                .dst_type = DST_TYPE_IS_TERR,
                .type_flags = DST_TYPE_HAS_FW_2,
-               .dst_feature = DST_TYPE_HAS_ANALOG
+               .dst_feature = DST_TYPE_HAS_ANALOG,
+               .tuner_type = 0
        },
 
        {
@@ -715,15 +892,17 @@ static struct dst_types dst_tlist[] = {
                .offset = 1,
                .dst_type = DST_TYPE_IS_ATSC,
                .type_flags = DST_TYPE_HAS_FW_2,
-               .dst_feature = 0
+               .dst_feature = 0,
+               .tuner_type = 0
        },
 
        {
                .device_id = "ATSCAD",
                .offset = 1,
                .dst_type = DST_TYPE_IS_ATSC,
-               .type_flags = DST_TYPE_HAS_FW_2,
-               .dst_feature = 0
+               .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD,
+               .dst_feature = DST_TYPE_HAS_MAC | DST_TYPE_HAS_ANALOG,
+               .tuner_type = 0
        },
 
        { }
@@ -768,6 +947,9 @@ static int dst_fw_ver(struct dst_state *state)
 
 static int dst_card_type(struct dst_state *state)
 {
+       int j;
+       struct tuner_types *p_tuner_list = NULL;
+
        u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
        get_type[7] = dst_check_sum(get_type, 7);
        if (dst_command(state, get_type, 8) < 0) {
@@ -775,9 +957,17 @@ static int dst_card_type(struct dst_state *state)
                return -1;
        }
        memset(&state->card_info, '\0', 8);
-       memcpy(&state->card_info, &state->rxbuffer, 8);
+       memcpy(&state->card_info, &state->rxbuffer, 7);
        dprintk(verbose, DST_ERROR, 1, "Device Model=[%s]", &state->card_info[0]);
 
+       for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) {
+               if (!strcmp(&state->card_info[0], p_tuner_list->board_name)) {
+                       state->tuner_type = p_tuner_list->tuner_type;
+                       dprintk(verbose, DST_ERROR, 1, "DST has [%s] tuner, tuner type=[%d]",
+                               p_tuner_list->tuner_name, p_tuner_list->tuner_type);
+               }
+       }
+
        return 0;
 }
 
@@ -790,12 +980,64 @@ static int dst_get_vendor(struct dst_state *state)
                return -1;
        }
        memset(&state->vendor, '\0', 8);
-       memcpy(&state->vendor, &state->rxbuffer, 8);
+       memcpy(&state->vendor, &state->rxbuffer, 7);
        dprintk(verbose, DST_ERROR, 1, "Vendor=[%s]", &state->vendor[0]);
 
        return 0;
 }
 
+static void debug_dst_buffer(struct dst_state *state)
+{
+       int i;
+
+       if (verbose > 2) {
+               printk("%s: [", __func__);
+               for (i = 0; i < 8; i++)
+                       printk(" %02x", state->rxbuffer[i]);
+               printk("]\n");
+       }
+}
+
+static int dst_check_stv0299(struct dst_state *state)
+{
+       u8 check_stv0299[] = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+       check_stv0299[7] = dst_check_sum(check_stv0299, 7);
+       if (dst_command(state, check_stv0299, 8) < 0) {
+               dprintk(verbose, DST_ERROR, 1, "Cmd=[0x04] failed");
+               return -1;
+       }
+       debug_dst_buffer(state);
+
+       if (memcmp(&check_stv0299, &state->rxbuffer, 8)) {
+               dprintk(verbose, DST_ERROR, 1, "Found a STV0299 NIM");
+               state->tuner_type = TUNER_TYPE_STV0299;
+               return 0;
+       }
+
+       return -1;
+}
+
+static int dst_check_mb86a15(struct dst_state *state)
+{
+       u8 check_mb86a15[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+       check_mb86a15[7] = dst_check_sum(check_mb86a15, 7);
+       if (dst_command(state, check_mb86a15, 8) < 0) {
+               dprintk(verbose, DST_ERROR, 1, "Cmd=[0x10], failed");
+               return -1;
+       }
+       debug_dst_buffer(state);
+
+       if (memcmp(&check_mb86a15, &state->rxbuffer, 8) < 0) {
+               dprintk(verbose, DST_ERROR, 1, "Found a MB86A15 NIM");
+               state->tuner_type = TUNER_TYPE_MB86A15;
+               return 0;
+       }
+
+       return -1;
+}
+
 static int dst_get_tuner_info(struct dst_state *state)
 {
        u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
@@ -803,60 +1045,59 @@ static int dst_get_tuner_info(struct dst_state *state)
 
        get_tuner_1[7] = dst_check_sum(get_tuner_1, 7);
        get_tuner_2[7] = dst_check_sum(get_tuner_2, 7);
+       dprintk(verbose, DST_ERROR, 1, "DST TYpe = MULTI FE");
        if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
-               if (dst_command(state, get_tuner_2, 8) < 0) {
-                       dprintk(verbose, DST_INFO, 1, "Unsupported Command");
-                       return -1;
+               if (dst_command(state, get_tuner_1, 8) < 0) {
+                       dprintk(verbose, DST_INFO, 1, "Cmd=[0x13], Unsupported");
+                       goto force;
                }
        } else {
-               if (dst_command(state, get_tuner_1, 8) < 0) {
-                       dprintk(verbose, DST_INFO, 1, "Unsupported Command");
-                       return -1;
+               if (dst_command(state, get_tuner_2, 8) < 0) {
+                       dprintk(verbose, DST_INFO, 1, "Cmd=[0xb], Unsupported");
+                       goto force;
                }
        }
        memset(&state->board_info, '\0', 8);
        memcpy(&state->board_info, &state->rxbuffer, 8);
        if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
-               if (state->board_info[1] == 0x0b) {
-                       if (state->type_flags & DST_TYPE_HAS_TS204)
-                               state->type_flags &= ~DST_TYPE_HAS_TS204;
-                       state->type_flags |= DST_TYPE_HAS_NEWTUNE;
-                       dprintk(verbose, DST_INFO, 1, "DST type has TS=188");
-               } else {
-                       if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
-                               state->type_flags &= ~DST_TYPE_HAS_NEWTUNE;
-                       state->type_flags |= DST_TYPE_HAS_TS204;
-                       dprintk(verbose, DST_INFO, 1, "DST type has TS=204");
-               }
-       } else {
-               if (state->board_info[0] == 0xbc) {
-                       if (state->type_flags & DST_TYPE_HAS_TS204)
-                               state->type_flags &= ~DST_TYPE_HAS_TS204;
-                       state->type_flags |= DST_TYPE_HAS_NEWTUNE;
-                       dprintk(verbose, DST_INFO, 1, "DST type has TS=188, Daughterboard=[%d]", state->board_info[1]);
-
-               } else if (state->board_info[0] == 0xcc) {
-                       if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
-                               state->type_flags &= ~DST_TYPE_HAS_NEWTUNE;
-                       state->type_flags |= DST_TYPE_HAS_TS204;
-                       dprintk(verbose, DST_INFO, 1, "DST type has TS=204 Daughterboard=[%d]", state->board_info[1]);
+               dprintk(verbose, DST_ERROR, 1, "DST type has TS=188");
+       }
+       if (state->board_info[0] == 0xbc) {
+               if (state->type_flags != DST_TYPE_IS_ATSC)
+                       state->type_flags |= DST_TYPE_HAS_TS188;
+               else
+                       state->type_flags |= DST_TYPE_HAS_NEWTUNE_2;
+
+               if (state->board_info[1] == 0x01) {
+                       state->dst_hw_cap |= DST_TYPE_HAS_DBOARD;
+                       dprintk(verbose, DST_ERROR, 1, "DST has Daughterboard");
                }
        }
 
        return 0;
+force:
+       if (!strncmp(state->fw_name, "DCT-CI", 6)) {
+               state->type_flags |= DST_TYPE_HAS_TS204;
+               dprintk(verbose, DST_ERROR, 1, "Forcing [%s] to TS188", state->fw_name);
+       }
+
+       return -1;
 }
 
 static int dst_get_device_id(struct dst_state *state)
 {
        u8 reply;
 
-       int i;
-       struct dst_types *p_dst_type;
+       int i, j;
+       struct dst_types *p_dst_type = NULL;
+       struct tuner_types *p_tuner_list = NULL;
+
        u8 use_dst_type = 0;
        u32 use_type_flags = 0;
 
        static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
 
+       state->tuner_type = 0;
        device_type[7] = dst_check_sum(device_type, 7);
 
        if (write_dst(state, device_type, FIXED_COMM))
@@ -888,8 +1129,34 @@ static int dst_get_device_id(struct dst_state *state)
 
                        /*      Card capabilities       */
                        state->dst_hw_cap = p_dst_type->dst_feature;
-                       dprintk(verbose, DST_ERROR, 1, "Recognise [%s]\n", p_dst_type->device_id);
-
+                       dprintk(verbose, DST_ERROR, 1, "Recognise [%s]", p_dst_type->device_id);
+                       strncpy(&state->fw_name[0], p_dst_type->device_id, 6);
+                       /*      Multiple tuners         */
+                       if (p_dst_type->tuner_type & TUNER_TYPE_MULTI) {
+                               switch (use_dst_type) {
+                               case DST_TYPE_IS_SAT:
+                                       /*      STV0299 check   */
+                                       if (dst_check_stv0299(state) < 0) {
+                                               dprintk(verbose, DST_ERROR, 1, "Unsupported");
+                                               state->tuner_type = TUNER_TYPE_MB86A15;
+                                       }
+                                       break;
+                               default:
+                                       break;
+                               }
+                               if (dst_check_mb86a15(state) < 0)
+                                       dprintk(verbose, DST_ERROR, 1, "Unsupported");
+                       /*      Single tuner            */
+                       } else {
+                               state->tuner_type = p_dst_type->tuner_type;
+                       }
+                       for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) {
+                               if (!(strncmp(p_dst_type->device_id, p_tuner_list->fw_name, 7)) &&
+                                       p_tuner_list->tuner_type == state->tuner_type) {
+                                       dprintk(verbose, DST_ERROR, 1, "[%s] has a [%s]",
+                                               p_dst_type->device_id, p_tuner_list->tuner_name);
+                               }
+                       }
                        break;
                }
        }
@@ -900,10 +1167,10 @@ static int dst_get_device_id(struct dst_state *state)
                use_dst_type = DST_TYPE_IS_SAT;
                use_type_flags = DST_TYPE_HAS_SYMDIV;
        }
-       dst_type_print(use_dst_type);
+       dst_type_print(state, use_dst_type);
        state->type_flags = use_type_flags;
        state->dst_type = use_dst_type;
-       dst_type_flags_print(state->type_flags);
+       dst_type_flags_print(state);
 
        return 0;
 }
@@ -911,15 +1178,15 @@ static int dst_get_device_id(struct dst_state *state)
 static int dst_probe(struct dst_state *state)
 {
        mutex_init(&state->dst_mutex);
-       if ((rdc_8820_reset(state)) < 0) {
-               dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
-               return -1;
-       }
-       if (dst_addons & DST_TYPE_HAS_CA)
+       if (dst_addons & DST_TYPE_HAS_CA) {
+               if ((rdc_8820_reset(state)) < 0) {
+                       dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
+                       return -1;
+               }
                msleep(4000);
-       else
+       } else {
                msleep(100);
-
+       }
        if ((dst_comm_init(state)) < 0) {
                dprintk(verbose, DST_ERROR, 1, "DST Initialization Failed.");
                return -1;
@@ -931,7 +1198,6 @@ static int dst_probe(struct dst_state *state)
        }
        if (dst_get_mac(state) < 0) {
                dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command");
-               return 0;
        }
        if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) {
                if (dst_get_tuner_info(state) < 0)
@@ -1048,6 +1314,10 @@ static int dst_get_signal(struct dst_state *state)
                        state->decode_lock = (state->rxbuffer[1]) ? 1 : 0;
                        state->decode_strength = state->rxbuffer[4] << 8;
                        state->decode_snr = state->rxbuffer[3] << 8;
+               } else if (state->dst_type == DST_TYPE_IS_ATSC) {
+                       state->decode_lock = (state->rxbuffer[6] == 0x00) ? 1 : 0;
+                       state->decode_strength = state->rxbuffer[4] << 8;
+                       state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3];
                }
                state->cur_jiff = jiffies;
        }
@@ -1078,8 +1348,9 @@ static int dst_get_tuna(struct dst_state *state)
        state->diseq_flags &= ~(HAS_LOCK);
        if (!dst_wait_dst_ready(state, NO_DELAY))
                return -EIO;
-       if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
-               /* how to get variable length reply ???? */
+       if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+               !(state->dst_type == DST_TYPE_IS_ATSC))
+
                retval = read_dst(state, state->rx_tuna, 10);
        else
                retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM);
@@ -1087,7 +1358,10 @@ static int dst_get_tuna(struct dst_state *state)
                dprintk(verbose, DST_DEBUG, 1, "read not successful");
                return retval;
        }
-       if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+       if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+               !(state->dst_type == DST_TYPE_IS_CABLE) &&
+               !(state->dst_type == DST_TYPE_IS_ATSC)) {
+
                if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
                        dprintk(verbose, DST_INFO, 1, "checksum failure ? ");
                        return -EIO;
@@ -1133,7 +1407,10 @@ static int dst_write_tuna(struct dvb_frontend *fe)
                dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed.");
                goto error;
        }
-       if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+//     if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+       if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+               (!(state->dst_type == DST_TYPE_IS_ATSC))) {
+
                state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9);
                retval = write_dst(state, &state->tx_tuna[0], 10);
        } else {
@@ -1189,9 +1466,12 @@ static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd
 
        if (state->dst_type != DST_TYPE_IS_SAT)
                return 0;
-       if (cmd->msg_len == 0 || cmd->msg_len > 4)
+       if (cmd->msg_len > 0 && cmd->msg_len < 5)
+               memcpy(&paket[3], cmd->msg, cmd->msg_len);
+       else if (cmd->msg_len == 5 && state->dst_hw_cap & DST_TYPE_HAS_DISEQC5)
+               memcpy(&paket[2], cmd->msg, cmd->msg_len);
+       else
                return -EINVAL;
-       memcpy(&paket[3], cmd->msg, cmd->msg_len);
        paket[7] = dst_check_sum(&paket[0], 7);
        dst_command(state, paket, 8);
        return 0;
@@ -1287,8 +1567,9 @@ static int dst_init(struct dvb_frontend *fe)
        static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 };
        static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
        static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
-       static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
        static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
+       static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
+       static u8 atsc_tuner[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
 
        state->inversion = INVERSION_OFF;
        state->voltage = SEC_VOLTAGE_13;
@@ -1298,11 +1579,13 @@ static int dst_init(struct dvb_frontend *fe)
        state->bandwidth = BANDWIDTH_7_MHZ;
        state->cur_jiff = jiffies;
        if (state->dst_type == DST_TYPE_IS_SAT)
-               memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204));
+               memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204));
        else if (state->dst_type == DST_TYPE_IS_TERR)
-               memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204));
+               memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204));
        else if (state->dst_type == DST_TYPE_IS_CABLE)
-               memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204));
+               memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204));
+       else if (state->dst_type == DST_TYPE_IS_ATSC)
+               memcpy(state->tx_tuna, atsc_tuner, sizeof (atsc_tuner));
 
        return 0;
 }
@@ -1341,7 +1624,36 @@ static int dst_read_snr(struct dvb_frontend *fe, u16 *snr)
        return 0;
 }
 
-static int dst_set_frontend(struct dvb_frontend* fe,
+static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+{
+       struct dst_state *state = fe->demodulator_priv;
+
+       if (p != NULL) {
+               dst_set_freq(state, p->frequency);
+               dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
+
+               if (state->dst_type == DST_TYPE_IS_SAT) {
+                       if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+                               dst_set_inversion(state, p->inversion);
+                       dst_set_fec(state, p->u.qpsk.fec_inner);
+                       dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
+                       dst_set_polarization(state);
+                       dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate);
+
+               } else if (state->dst_type == DST_TYPE_IS_TERR)
+                       dst_set_bandwidth(state, p->u.ofdm.bandwidth);
+               else if (state->dst_type == DST_TYPE_IS_CABLE) {
+                       dst_set_fec(state, p->u.qam.fec_inner);
+                       dst_set_symbolrate(state, p->u.qam.symbol_rate);
+                       dst_set_modulation(state, p->u.qam.modulation);
+               }
+               dst_write_tuna(fe);
+       }
+
+       return 0;
+}
+
+static int dst_tune_frontend(struct dvb_frontend* fe,
                            struct dvb_frontend_parameters* p,
                            unsigned int mode_flags,
                            int *delay,
@@ -1378,6 +1690,11 @@ static int dst_set_frontend(struct dvb_frontend* fe,
        return 0;
 }
 
+static int dst_get_tuning_algo(struct dvb_frontend *fe)
+{
+       return dst_algo;
+}
+
 static int dst_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
 {
        struct dst_state *state = fe->demodulator_priv;
@@ -1408,6 +1725,7 @@ static void dst_release(struct dvb_frontend *fe)
 static struct dvb_frontend_ops dst_dvbt_ops;
 static struct dvb_frontend_ops dst_dvbs_ops;
 static struct dvb_frontend_ops dst_dvbc_ops;
+static struct dvb_frontend_ops dst_atsc_ops;
 
 struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter)
 {
@@ -1417,24 +1735,25 @@ struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_ad
                return NULL;
        }
        /* determine settings based on type */
+       /* create dvb_frontend */
        switch (state->dst_type) {
        case DST_TYPE_IS_TERR:
-               memcpy(&state->ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
+               memcpy(&state->frontend.ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
                break;
        case DST_TYPE_IS_CABLE:
-               memcpy(&state->ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
+               memcpy(&state->frontend.ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
                break;
        case DST_TYPE_IS_SAT:
-               memcpy(&state->ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
+               memcpy(&state->frontend.ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
+               break;
+       case DST_TYPE_IS_ATSC:
+               memcpy(&state->frontend.ops, &dst_atsc_ops, sizeof(struct dvb_frontend_ops));
                break;
        default:
                dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist.");
                kfree(state);
                return NULL;
        }
-
-       /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
        state->frontend.demodulator_priv = state;
 
        return state;                           /*      Manu (DST is a card not a frontend)     */
@@ -1455,8 +1774,10 @@ static struct dvb_frontend_ops dst_dvbt_ops = {
 
        .release = dst_release,
        .init = dst_init,
-       .tune = dst_set_frontend,
+       .tune = dst_tune_frontend,
+       .set_frontend = dst_set_frontend,
        .get_frontend = dst_get_frontend,
+       .get_frontend_algo = dst_get_tuning_algo,
        .read_status = dst_read_status,
        .read_signal_strength = dst_read_signal_strength,
        .read_snr = dst_read_snr,
@@ -1479,8 +1800,10 @@ static struct dvb_frontend_ops dst_dvbs_ops = {
 
        .release = dst_release,
        .init = dst_init,
-       .tune = dst_set_frontend,
+       .tune = dst_tune_frontend,
+       .set_frontend = dst_set_frontend,
        .get_frontend = dst_get_frontend,
+       .get_frontend_algo = dst_get_tuning_algo,
        .read_status = dst_read_status,
        .read_signal_strength = dst_read_signal_strength,
        .read_snr = dst_read_snr,
@@ -1506,13 +1829,38 @@ static struct dvb_frontend_ops dst_dvbc_ops = {
 
        .release = dst_release,
        .init = dst_init,
-       .tune = dst_set_frontend,
+       .tune = dst_tune_frontend,
+       .set_frontend = dst_set_frontend,
+       .get_frontend = dst_get_frontend,
+       .get_frontend_algo = dst_get_tuning_algo,
+       .read_status = dst_read_status,
+       .read_signal_strength = dst_read_signal_strength,
+       .read_snr = dst_read_snr,
+};
+
+static struct dvb_frontend_ops dst_atsc_ops = {
+       .info = {
+               .name = "DST ATSC",
+               .type = FE_ATSC,
+               .frequency_stepsize = 62500,
+               .frequency_min = 510000000,
+               .frequency_max = 858000000,
+               .symbol_rate_min = 1000000,
+               .symbol_rate_max = 45000000,
+               .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+       },
+
+       .release = dst_release,
+       .init = dst_init,
+       .tune = dst_tune_frontend,
+       .set_frontend = dst_set_frontend,
        .get_frontend = dst_get_frontend,
+       .get_frontend_algo = dst_get_tuning_algo,
        .read_status = dst_read_status,
        .read_signal_strength = dst_read_signal_strength,
        .read_snr = dst_read_snr,
 };
 
-MODULE_DESCRIPTION("DST DVB-S/T/C Combo Frontend driver");
+MODULE_DESCRIPTION("DST DVB-S/T/C/ATSC Combo Frontend driver");
 MODULE_AUTHOR("Jamie Honan, Manu Abraham");
 MODULE_LICENSE("GPL");
index f6b49a801eba92ae75e9d8d68ccc58000d1ff199..fa923b9b346ea99440dceeac23e695c4c4b3a193 100644 (file)
@@ -68,6 +68,13 @@ static int ca_set_pid(void)
        return -EOPNOTSUPP;
 }
 
+static void put_command_and_length(u8 *data, int command, int length)
+{
+       data[0] = (command >> 16) & 0xff;
+       data[1] = (command >> 8) & 0xff;
+       data[2] = command & 0xff;
+       data[3] = length;
+}
 
 static void put_checksum(u8 *check_string, int length)
 {
@@ -124,15 +131,18 @@ static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string,
        u8 dst_ca_comm_err = 0;
 
        while (dst_ca_comm_err < RETRIES) {
-               dst_comm_init(state);
                dprintk(verbose, DST_CA_NOTICE, 1, " Put Command");
                if (dst_ci_command(state, data, ca_string, len, read)) {        // If error
                        dst_error_recovery(state);
                        dst_ca_comm_err++; // work required here.
+               } else {
+                       break;
                }
-               break;
        }
 
+       if(dst_ca_comm_err == RETRIES)
+               return -1;
+
        return 0;
 }
 
@@ -140,6 +150,7 @@ static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string,
 
 static int ca_get_app_info(struct dst_state *state)
 {
+       int length, str_length;
        static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff};
 
        put_checksum(&command[0], command[0]);
@@ -154,6 +165,68 @@ static int ca_get_app_info(struct dst_state *state)
                (state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[12]));
        dprintk(verbose, DST_CA_INFO, 1, " ==================================================================================================");
 
+       // Transform dst message to correct application_info message
+       length = state->messages[5];
+       str_length = length - 6;
+       if (str_length < 0) {
+               str_length = 0;
+               dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering.");
+       }
+
+       // First, the command and length fields
+       put_command_and_length(&state->messages[0], CA_APP_INFO, length);
+
+       // Copy application_type, application_manufacturer and manufacturer_code
+       memcpy(&state->messages[4], &state->messages[7], 5);
+
+       // Set string length and copy string
+       state->messages[9] = str_length;
+       memcpy(&state->messages[10], &state->messages[12], str_length);
+
+       return 0;
+}
+
+static int ca_get_ca_info(struct dst_state *state)
+{
+       int srcPtr, dstPtr, i, num_ids;
+       static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff};
+       const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7;
+
+       put_checksum(&slot_command[0], slot_command[0]);
+       if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) {
+               dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
+               return -1;
+       }
+       dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
+
+       // Print raw data
+       dprintk(verbose, DST_CA_INFO, 0, " DST data = [");
+       for (i = 0; i < state->messages[0] + 1; i++) {
+               dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]);
+       }
+       dprintk(verbose, DST_CA_INFO, 0, "]\n");
+
+       // Set the command and length of the output
+       num_ids = state->messages[in_num_ids_pos];
+       if (num_ids >= 100) {
+               num_ids = 100;
+               dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering.");
+       }
+       put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2);
+
+       dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = [");
+       srcPtr = in_system_id_pos;
+       dstPtr = out_system_id_pos;
+       for(i = 0; i < num_ids; i++) {
+               dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]);
+               // Append to output
+               state->messages[dstPtr + 0] = state->messages[srcPtr + 0];
+               state->messages[dstPtr + 1] = state->messages[srcPtr + 1];
+               srcPtr += 2;
+               dstPtr += 2;
+       }
+       dprintk(verbose, DST_CA_INFO, 0, "]\n");
+
        return 0;
 }
 
@@ -174,7 +247,7 @@ static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps,
 
        dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]);
        dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
-       for (i = 0; i < 8; i++)
+       for (i = 0; i < slot_cap[0] + 1; i++)
                dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]);
        dprintk(verbose, DST_CA_INFO, 0, "\n");
 
@@ -260,6 +333,11 @@ static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message,
                        if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
                                return -EFAULT;
                        break;
+               case CA_INFO:
+                       memcpy(p_ca_message->msg, state->messages, 128);
+                       if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
+                               return -EFAULT;
+                       break;
                }
        }
 
@@ -302,7 +380,7 @@ static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 l
                rdc_reset_state(state);
                return -1;
        }
-       dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command succes.");
+       dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success.");
 
        return 0;
 }
@@ -340,6 +418,7 @@ static int debug_string(u8 *msg, u32 length, u32 offset)
        return 0;
 }
 
+
 static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
 {
        u32 length = 0;
@@ -455,6 +534,16 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
                        }
                        dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !");
                        break;
+               case CA_INFO_ENQUIRY:
+                       dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information");
+
+                       if ((ca_get_ca_info(state)) < 0) {
+                               dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !");
+                               result = -1;
+                               goto free_mem_and_exit;
+                       }
+                       dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !");
+                       break;
                }
        }
 free_mem_and_exit:
@@ -473,18 +562,15 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
        void __user *arg = (void __user *)ioctl_arg;
        int result = 0;
 
-       if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
-               dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
-               return -ENOMEM;
-       }
-       if ((p_ca_slot_info = (struct ca_slot_info *) kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL)) == NULL) {
+       p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
+       p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
+       p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL);
+       if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) {
                dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
-               return -ENOMEM;
-       }
-       if ((p_ca_caps = (struct ca_caps *) kmalloc(sizeof (struct ca_caps), GFP_KERNEL)) == NULL) {
-               dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
-               return -ENOMEM;
+               result = -ENOMEM;
+               goto free_mem_and_exit;
        }
+
        /*      We have now only the standard ioctl's, the driver is upposed to handle internals.       */
        switch (cmd) {
        case CA_SEND_MSG:
@@ -582,7 +668,7 @@ static int dst_ca_release(struct inode *inode, struct file *file)
 
 static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
 {
-       int bytes_read = 0;
+       ssize_t bytes_read = 0;
 
        dprintk(verbose, DST_CA_DEBUG, 1, " Device read.");
 
index 51d4e043716c19f37899566ee0f3bf97539fb685..0677b047b3a78be3381046c3ef0eb88e576cf5c3 100644 (file)
@@ -42,7 +42,7 @@
 #define DST_TYPE_IS_CABLE      2
 #define DST_TYPE_IS_ATSC       3
 
-#define DST_TYPE_HAS_NEWTUNE   1
+#define DST_TYPE_HAS_TS188     1
 #define DST_TYPE_HAS_TS204     2
 #define DST_TYPE_HAS_SYMDIV    4
 #define DST_TYPE_HAS_FW_1      8
@@ -52,6 +52,9 @@
 #define DST_TYPE_HAS_OBS_REGS  128
 #define DST_TYPE_HAS_INC_COUNT 256
 #define DST_TYPE_HAS_MULTI_FE  512
+#define DST_TYPE_HAS_NEWTUNE_2 1024
+#define DST_TYPE_HAS_DBOARD    2048
+#define DST_TYPE_HAS_VLF       4096
 
 /*     Card capability list    */
 
 #define        DST_TYPE_HAS_ANALOG     64      /*      Analog inputs   */
 #define DST_TYPE_HAS_SESSION   128
 
+#define TUNER_TYPE_MULTI       1
+#define TUNER_TYPE_UNKNOWN     2
+/*     DVB-S           */
+#define TUNER_TYPE_L64724      4
+#define TUNER_TYPE_STV0299     8
+#define TUNER_TYPE_MB86A15     16
+
+/*     DVB-T           */
+#define TUNER_TYPE_TDA10046    32
+
+/*     ATSC            */
+#define TUNER_TYPE_NXT200x     64
+
+
 #define RDC_8820_PIO_0_DISABLE 0
 #define RDC_8820_PIO_0_ENABLE  1
 #define RDC_8820_INT           2
@@ -84,8 +101,6 @@ struct dst_state {
 
        struct bt878* bt;
 
-       struct dvb_frontend_ops ops;
-
        /* configuration settings */
        const struct dst_config* config;
 
@@ -121,8 +136,17 @@ struct dst_state {
        u8 card_info[8];
        u8 vendor[8];
        u8 board_info[8];
-
+       u32 tuner_type;
+       char *tuner_name;
        struct mutex dst_mutex;
+       u8 fw_name[8];
+};
+
+struct tuner_types {
+       u32 tuner_type;
+       char *tuner_name;
+       char *board_name;
+       char *fw_name;
 };
 
 struct dst_types {
@@ -131,6 +155,7 @@ struct dst_types {
        u8 dst_type;
        u32 type_flags;
        u32 dst_feature;
+       u32 tuner_type;
 };
 
 struct dst_config
index ccc7b2eb4a2d33a424e243612634928821c0e096..b715b972d2fcfbfdbd495d5a1cc2ed558c60e632 100644 (file)
@@ -147,12 +147,15 @@ static int thomson_dtt7579_demod_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
 {
        u32 div;
        unsigned char bs = 0;
        unsigned char cp = 0;
 
+       if (buf_len < 5)
+               return -EINVAL;
+
        div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
 
        if (params->frequency < 542000000)
@@ -169,22 +172,25 @@ static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_
        else
                bs = 0x08;
 
-       pllbuf[0] = 0xc0; // Note: non-linux standard PLL i2c address
+       pllbuf[0] = 0x60;
        pllbuf[1] = div >> 8;
        pllbuf[2] = div & 0xff;
        pllbuf[3] = cp;
        pllbuf[4] = bs;
 
-       return 0;
+       return 5;
 }
 
 static struct mt352_config thomson_dtt7579_config = {
        .demod_address = 0x0f,
        .demod_init = thomson_dtt7579_demod_init,
-       .pll_set = thomson_dtt7579_pll_set,
 };
 
-static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static struct zl10353_config thomson_dtt7579_zl10353_config = {
+       .demod_address = 0x0f,
+};
+
+static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
        u32 freq = params->frequency;
 
@@ -237,7 +243,7 @@ static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_paramete
        return 0;
 }
 
-static int pinnsat_pll_init(struct dvb_frontend* fe)
+static int pinnsat_tuner_init(struct dvb_frontend* fe)
 {
        struct dvb_bt8xx_card *card = fe->dvb->priv;
 
@@ -247,7 +253,7 @@ static int pinnsat_pll_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static int pinnsat_pll_sleep(struct dvb_frontend* fe)
+static int pinnsat_tuner_sleep(struct dvb_frontend* fe)
 {
        struct dvb_bt8xx_card *card = fe->dvb->priv;
 
@@ -258,12 +264,9 @@ static int pinnsat_pll_sleep(struct dvb_frontend* fe)
 
 static struct cx24110_config pctvsat_config = {
        .demod_address = 0x55,
-       .pll_init = pinnsat_pll_init,
-       .pll_set = cx24108_pll_set,
-       .pll_sleep = pinnsat_pll_sleep,
 };
 
-static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
        struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
        u8 cfg, cpump, band_select;
@@ -297,6 +300,8 @@ static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_front
        data[2] = ((div >> 10) & 0x60) | cfg;
        data[3] = (cpump << 6) | band_select;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(card->i2c_adapter, &msg, 1);
        return (div * 166666 - 36000000);
 }
@@ -310,7 +315,6 @@ static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const s
 
 static struct sp887x_config microtune_mt7202dtf_config = {
        .demod_address = 0x70,
-       .pll_set = microtune_mt7202dtf_pll_set,
        .request_firmware = microtune_mt7202dtf_request_firmware,
 };
 
@@ -337,12 +341,14 @@ static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
 {
        u32 div;
        unsigned char bs = 0;
        unsigned char cp = 0;
 
+       if (buf_len < 5) return -EINVAL;
+
        div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
 
        if (params->frequency < 150000000)
@@ -383,19 +389,18 @@ static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct
        else
                bs = 0x08;
 
-       pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address
+       pllbuf[0] = 0x61;
        pllbuf[1] = div >> 8;
        pllbuf[2] = div & 0xff;
        pllbuf[3] = cp;
        pllbuf[4] = bs;
 
-       return 0;
+       return 5;
 }
 
 static struct mt352_config advbt771_samsung_tdtc9251dh0_config = {
        .demod_address = 0x0f,
        .demod_init = advbt771_samsung_tdtc9251dh0_demod_init,
-       .pll_set = advbt771_samsung_tdtc9251dh0_pll_set,
 };
 
 static struct dst_config dst_config = {
@@ -455,7 +460,7 @@ static struct or51211_config or51211_config = {
        .sleep = or51211_sleep,
 };
 
-static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
        struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
        u8 buf[4];
@@ -478,6 +483,8 @@ static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_fronten
        else
                return -EINVAL;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(card->i2c_adapter, &msg, 1);
        return 0;
 }
@@ -485,7 +492,6 @@ static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_fronten
 static struct nxt6000_config vp3021_alps_tded4_config = {
        .demod_address = 0x0a,
        .clock_inversion = 1,
-       .pll_set = vp3021_alps_tded4_pll_set,
 };
 
 static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe)
@@ -506,14 +512,17 @@ static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static int digitv_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
 {
        u32 div;
        struct dvb_ofdm_parameters *op = &params->u.ofdm;
 
+       if (buf_len < 5)
+               return -EINVAL;
+
        div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
 
-       pllbuf[0] = 0xc2;
+       pllbuf[0] = 0x61;
        pllbuf[1] = (div >> 8) & 0x7F;
        pllbuf[2] = div & 0xFF;
        pllbuf[3] = 0x85;
@@ -530,7 +539,7 @@ static int digitv_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_fronten
        if (op->bandwidth == 8)
                pllbuf[4] |= 0x04;
 
-       return 0;
+       return 5;
 }
 
 static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt)
@@ -557,43 +566,18 @@ static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt)
 static struct mt352_config digitv_alps_tded4_config = {
        .demod_address = 0x0a,
        .demod_init = digitv_alps_tded4_demod_init,
-       .pll_set = digitv_alps_tded4_pll_set,
 };
 
-static int tdvs_tua6034_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int tdvs_tua6034_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
        struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
-       u8 buf[4];
-       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
-       int err;
-
-       dvb_pll_configure(&dvb_pll_tdvs_tua6034, buf, params->frequency, 0);
-       dprintk("%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
-               __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
-       if ((err = i2c_transfer(card->i2c_adapter, &msg, 1)) != 1) {
-               printk(KERN_WARNING "dvb-bt8xx: %s error "
-                       "(addr %02x <- %02x, err = %i)\n",
-                       __FUNCTION__, buf[0], buf[1], err);
-               if (err < 0)
-                       return err;
-               else
-                       return -EREMOTEIO;
-       }
-
-       /* Set the Auxiliary Byte. */
-       buf[2] &= ~0x20;
-       buf[2] |= 0x18;
-       buf[3] = 0x50;
-       i2c_transfer(card->i2c_adapter, &msg, 1);
-
-       return 0;
+       return lg_h06xf_pll_set(fe, card->i2c_adapter, params);
 }
 
 static struct lgdt330x_config tdvs_tua6034_config = {
        .demod_address    = 0x0e,
        .demod_chip       = LGDT3303,
        .serial_mpeg      = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
-       .pll_set          = tdvs_tua6034_pll_set,
 };
 
 static void lgdt330x_reset(struct dvb_bt8xx_card *bt)
@@ -617,17 +601,25 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
        switch(type) {
        case BTTV_BOARD_DVICO_DVBT_LITE:
                card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter);
+
+               if (card->fe == NULL)
+                       card->fe = zl10353_attach(&thomson_dtt7579_zl10353_config,
+                                                 card->i2c_adapter);
+
                if (card->fe != NULL) {
-                       card->fe->ops->info.frequency_min = 174000000;
-                       card->fe->ops->info.frequency_max = 862000000;
+                       card->fe->ops.tuner_ops.calc_regs = thomson_dtt7579_tuner_calc_regs;
+                       card->fe->ops.info.frequency_min = 174000000;
+                       card->fe->ops.info.frequency_max = 862000000;
                }
                break;
 
        case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
                lgdt330x_reset(card);
                card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter);
-               if (card->fe != NULL)
+               if (card->fe != NULL) {
+                       card->fe->ops.tuner_ops.set_params = tdvs_tua6034_tuner_set_params;
                        dprintk ("dvb_bt8xx: lgdt330x detected\n");
+               }
                break;
 
        case BTTV_BOARD_NEBULA_DIGITV:
@@ -640,6 +632,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
                digitv_alps_tded4_reset(card);
                card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter);
                if (card->fe != NULL) {
+                       card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params;
                        dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n");
                        break;
                }
@@ -648,19 +641,25 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
                digitv_alps_tded4_reset(card);
                card->fe = mt352_attach(&digitv_alps_tded4_config, card->i2c_adapter);
 
-               if (card->fe != NULL)
+               if (card->fe != NULL) {
+                       card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs;
                        dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n");
+               }
                break;
 
        case BTTV_BOARD_AVDVBT_761:
                card->fe = sp887x_attach(&microtune_mt7202dtf_config, card->i2c_adapter);
+               if (card->fe) {
+                       card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params;
+               }
                break;
 
        case BTTV_BOARD_AVDVBT_771:
                card->fe = mt352_attach(&advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
                if (card->fe != NULL) {
-                       card->fe->ops->info.frequency_min = 174000000;
-                       card->fe->ops->info.frequency_max = 862000000;
+                       card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs;
+                       card->fe->ops.info.frequency_min = 174000000;
+                       card->fe->ops.info.frequency_max = 862000000;
                }
                break;
 
@@ -687,6 +686,11 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
 
        case BTTV_BOARD_PINNACLESAT:
                card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter);
+               if (card->fe) {
+                       card->fe->ops.tuner_ops.init = pinnsat_tuner_init;
+                       card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep;
+                       card->fe->ops.tuner_ops.set_params = cx24108_tuner_set_params;
+               }
                break;
 
        case BTTV_BOARD_PC_HDTV:
@@ -703,8 +707,8 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
        else
                if (dvb_register_frontend(&card->dvb_adapter, card->fe)) {
                        printk("dvb-bt8xx: Frontend registration failed!\n");
-                       if (card->fe->ops->release)
-                               card->fe->ops->release(card->fe);
+                       if (card->fe->ops.release)
+                               card->fe->ops.release(card->fe);
                        card->fe = NULL;
                }
 }
@@ -713,7 +717,7 @@ static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
 {
        int result;
 
-       if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE)) < 0) {
+       if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE, &card->bt->dev->dev)) < 0) {
                printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result);
                return result;
        }
index 00dd9fa54c82cbeefc3a07fbce4aa5b8843b69c5..4745a9017a1993476f82e2fae5f6ef049ed5910c 100644 (file)
@@ -37,6 +37,8 @@
 #include "cx24110.h"
 #include "or51211.h"
 #include "lgdt330x.h"
+#include "lg_h06xf.h"
+#include "zl10353.h"
 
 struct dvb_bt8xx_card {
        struct mutex lock;
index 6018fcdba1e6dc6ec02fa9a61d1a742c6b2bca71..b5cdd57ec6f51e9d34c07d0bb61368fe438296ab 100644 (file)
@@ -64,7 +64,7 @@ config DVB_CINERGYT2_QUERY_INTERVAL
 config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
        bool "Register the onboard IR Remote Control Receiver as Input Device"
        depends on DVB_CINERGYT2_TUNING
-       default "yes"
+       default y
        help
          Enable this option if you want to use the onboard Infrared Remote
          Control Receiver as Linux-Input device.
index 9325d039ea652c622071b04d8c31ed7e6ff473ef..1b895360042531722a60830aca59e455a1f93913 100644 (file)
@@ -544,15 +544,19 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct
 {
        struct dvb_device *dvbdev = file->private_data;
        struct cinergyt2 *cinergyt2 = dvbdev->priv;
+       unsigned int mask = 0;
 
        if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
        poll_wait(file, &cinergyt2->poll_wq, wait);
 
+       if (cinergyt2->pending_fe_events != 0)
+               mask |= (POLLIN | POLLRDNORM | POLLPRI);
+
        mutex_unlock(&cinergyt2->sem);
 
-       return (POLLIN | POLLRDNORM | POLLPRI);
+       return mask;
 }
 
 
@@ -902,7 +906,7 @@ static int cinergyt2_probe (struct usb_interface *intf,
                return -ENOMEM;
        }
 
-       if ((err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE)) < 0) {
+       if ((err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE, &cinergyt2->udev->dev)) < 0) {
                kfree(cinergyt2);
                return err;
        }
index 7adb50c1e8ebb0c3f9ab8a5e60c9c9f7784b4328..11054657fdb507491dd4d944ace466bbc6ba7a35 100644 (file)
@@ -2,8 +2,8 @@
 # Makefile for the kernel DVB device drivers.
 #
 
-dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
-               dvb_ca_en50221.o dvb_frontend.o \
-               dvb_net.o dvb_ringbuffer.o
+dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o     \
+               dvb_ca_en50221.o dvb_frontend.o                 \
+               dvb_net.o dvb_ringbuffer.o dvb_math.o
 
 obj-$(CONFIG_DVB_CORE) += dvb-core.o
index 04578df3f24910dd25fa8bbea25b90344cb4c1ed..988499dfddf8d8d17bcffbb6522231f9d1485fd0 100644 (file)
@@ -872,9 +872,6 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
                mutex_unlock(&dmxdevfilter->mutex);
                break;
 
-       case DMX_GET_EVENT:
-               break;
-
        case DMX_GET_PES_PIDS:
                if (!dmxdev->demux->get_pes_pids) {
                        ret = -EINVAL;
index 00347a750681942db7775769de7f7f2cf8f3eea3..2a03bf53cb2960b2c23ac1c387924f9f284b8f54 100644 (file)
@@ -1060,8 +1060,18 @@ static int dvb_ca_en50221_thread(void *data)
                                break;
 
                        case DVB_CA_SLOTSTATE_VALIDATE:
-                               if (dvb_ca_en50221_parse_attributes(ca, slot)
-                                   != 0) {
+                               if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {
+                                       /* we need this extra check for annoying interfaces like the budget-av */
+                                       if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+                                           (ca->pub->poll_slot_status)) {
+                                               int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+                                               if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+                                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+                                                       dvb_ca_en50221_thread_update_delay(ca);
+                                                       break;
+                                               }
+                                       }
+
                                        printk("dvb_ca adapter %d: Invalid PC card inserted :(\n",
                                               ca->dvbdev->adapter->num);
                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
@@ -1108,6 +1118,17 @@ static int dvb_ca_en50221_thread(void *data)
 
                        case DVB_CA_SLOTSTATE_LINKINIT:
                                if (dvb_ca_en50221_link_init(ca, slot) != 0) {
+                                       /* we need this extra check for annoying interfaces like the budget-av */
+                                       if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+                                           (ca->pub->poll_slot_status)) {
+                                               int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+                                               if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+                                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+                                                       dvb_ca_en50221_thread_update_delay(ca);
+                                                       break;
+                                               }
+                                       }
+
                                        printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num);
                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
                                        dvb_ca_en50221_thread_update_delay(ca);
index 83ec5e06c48287ea538ae31920c978b0e3c83a53..fcff5eab21a3fc050d5207f9538c99d6c6ee63bd 100644 (file)
@@ -473,7 +473,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
                        goto bailout;
                }
                memcpy(&demux->tsbuf[i], buf, j);
-               if ((demux->tsbuf[0] == 0x47) | (demux->tsbuf[0] == 0xB8)) {
+               if ((demux->tsbuf[0] == 0x47) || (demux->tsbuf[0] == 0xB8)) {
                        memcpy(tmppack, demux->tsbuf, 188);
                        if (tmppack[0] == 0xB8)
                                tmppack[0] = 0x47;
@@ -484,7 +484,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
        }
 
        while (p < count) {
-               if ((buf[p] == 0x47) | (buf[p] == 0xB8)) {
+               if ((buf[p] == 0x47) || (buf[p] == 0xB8)) {
                        if (count - p >= 204) {
                                memcpy(tmppack, &buf[p], 188);
                                if (tmppack[0] == 0xB8)
index a051790161b095f674010e0e286c882f8df0b0a3..3152a54a2539ea2aef88abafe350186597961c4d 100644 (file)
@@ -56,7 +56,7 @@ MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AU
 module_param(dvb_override_tune_delay, int, 0644);
 MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
 module_param(dvb_powerdown_on_sleep, int, 0644);
-MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB volatage off on sleep (default)");
+MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)");
 
 #define dprintk if (dvb_frontend_debug) printk
 
@@ -72,6 +72,8 @@ MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB vola
 #define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST)
 #define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
 #define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)
+
+#define FE_ALGO_HW             1
 /*
  * FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling.
  * FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune.
@@ -151,8 +153,8 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
                sizeof (struct dvb_frontend_parameters));
 
        if (status & FE_HAS_LOCK)
-               if (fe->ops->get_frontend)
-                       fe->ops->get_frontend(fe, &e->parameters);
+               if (fe->ops.get_frontend)
+                       fe->ops.get_frontend(fe, &e->parameters);
 
        events->eventw = wp;
 
@@ -211,10 +213,15 @@ static void dvb_frontend_init(struct dvb_frontend *fe)
 {
        dprintk ("DVB: initialising frontend %i (%s)...\n",
                 fe->dvb->num,
-                fe->ops->info.name);
-
-       if (fe->ops->init)
-               fe->ops->init(fe);
+                fe->ops.info.name);
+
+       if (fe->ops.init)
+               fe->ops.init(fe);
+       if (fe->ops.tuner_ops.init) {
+               fe->ops.tuner_ops.init(fe);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
+       }
 }
 
 void dvb_frontend_reinitialise(struct dvb_frontend *fe)
@@ -259,7 +266,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
        u32 original_frequency = fepriv->parameters.frequency;
 
        /* are we using autoinversion? */
-       autoinversion = ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
+       autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
                         (fepriv->parameters.inversion == INVERSION_AUTO));
 
        /* setup parameters correctly */
@@ -329,8 +336,8 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
        fepriv->parameters.frequency += fepriv->lnb_drift;
        if (autoinversion)
                fepriv->parameters.inversion = fepriv->inversion;
-       if (fe->ops->set_frontend)
-               fe->ops->set_frontend(fe, &fepriv->parameters);
+       if (fe->ops.set_frontend)
+               fe->ops.set_frontend(fe, &fepriv->parameters);
 
        fepriv->parameters.frequency = original_frequency;
        fepriv->parameters.inversion = original_inversion;
@@ -354,8 +361,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
        /* in SCAN mode, we just set the frontend when asked and leave it alone */
        if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
                if (fepriv->state & FESTATE_RETUNE) {
-                       if (fe->ops->set_frontend)
-                               fe->ops->set_frontend(fe, &fepriv->parameters);
+                       if (fe->ops.set_frontend)
+                               fe->ops.set_frontend(fe, &fepriv->parameters);
                        fepriv->state = FESTATE_TUNED;
                }
                fepriv->delay = 3*HZ;
@@ -367,8 +374,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
        if (fepriv->state & FESTATE_RETUNE) {
                s = 0;
        } else {
-               if (fe->ops->read_status)
-                       fe->ops->read_status(fe, &s);
+               if (fe->ops.read_status)
+                       fe->ops.read_status(fe, &s);
                if (s != fepriv->status) {
                        dvb_frontend_add_event(fe, s);
                        fepriv->status = s;
@@ -381,7 +388,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
                fepriv->state = FESTATE_TUNED;
 
                /* if we're tuned, then we have determined the correct inversion */
-               if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
+               if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
                    (fepriv->parameters.inversion == INVERSION_AUTO)) {
                        fepriv->parameters.inversion = fepriv->inversion;
                }
@@ -405,7 +412,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
        /* don't actually do anything if we're in the LOSTLOCK state,
         * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
        if ((fepriv->state & FESTATE_LOSTLOCK) &&
-           (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
+           (fe->ops.info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
                dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
                return;
        }
@@ -540,16 +547,16 @@ static int dvb_frontend_thread(void *data)
                if (fepriv->reinitialise) {
                        dvb_frontend_init(fe);
                        if (fepriv->tone != -1) {
-                               fe->ops->set_tone(fe, fepriv->tone);
+                               fe->ops.set_tone(fe, fepriv->tone);
                        }
                        if (fepriv->voltage != -1) {
-                               fe->ops->set_voltage(fe, fepriv->voltage);
+                               fe->ops.set_voltage(fe, fepriv->voltage);
                        }
                        fepriv->reinitialise = 0;
                }
 
                /* do an iteration of the tuning loop */
-               if (fe->ops->tune) {
+               if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) {
                        /* have we been asked to retune? */
                        params = NULL;
                        if (fepriv->state & FESTATE_RETUNE) {
@@ -557,7 +564,7 @@ static int dvb_frontend_thread(void *data)
                                fepriv->state = FESTATE_TUNED;
                        }
 
-                       fe->ops->tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
+                       fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
                        if (s != fepriv->status) {
                                dvb_frontend_add_event(fe, s);
                                fepriv->status = s;
@@ -569,10 +576,15 @@ static int dvb_frontend_thread(void *data)
 
        if (dvb_shutdown_timeout) {
                if (dvb_powerdown_on_sleep)
-                       if (fe->ops->set_voltage)
-                               fe->ops->set_voltage(fe, SEC_VOLTAGE_OFF);
-               if (fe->ops->sleep)
-                       fe->ops->sleep(fe);
+                       if (fe->ops.set_voltage)
+                               fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
+               if (fe->ops.tuner_ops.sleep) {
+                       fe->ops.tuner_ops.sleep(fe);
+                       if (fe->ops.i2c_gate_ctrl)
+                               fe->ops.i2c_gate_ctrl(fe, 0);
+               }
+               if (fe->ops.sleep)
+                       fe->ops.sleep(fe);
        }
 
        fepriv->thread_pid = 0;
@@ -724,7 +736,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
        switch (cmd) {
        case FE_GET_INFO: {
                struct dvb_frontend_info* info = parg;
-               memcpy(info, &fe->ops->info, sizeof(struct dvb_frontend_info));
+               memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
 
                /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
                 * do it, it is done for it. */
@@ -744,58 +756,58 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                        break;
                }
 
-               if (fe->ops->read_status)
-                       err = fe->ops->read_status(fe, status);
+               if (fe->ops.read_status)
+                       err = fe->ops.read_status(fe, status);
                break;
        }
        case FE_READ_BER:
-               if (fe->ops->read_ber)
-                       err = fe->ops->read_ber(fe, (__u32*) parg);
+               if (fe->ops.read_ber)
+                       err = fe->ops.read_ber(fe, (__u32*) parg);
                break;
 
        case FE_READ_SIGNAL_STRENGTH:
-               if (fe->ops->read_signal_strength)
-                       err = fe->ops->read_signal_strength(fe, (__u16*) parg);
+               if (fe->ops.read_signal_strength)
+                       err = fe->ops.read_signal_strength(fe, (__u16*) parg);
                break;
 
        case FE_READ_SNR:
-               if (fe->ops->read_snr)
-                       err = fe->ops->read_snr(fe, (__u16*) parg);
+               if (fe->ops.read_snr)
+                       err = fe->ops.read_snr(fe, (__u16*) parg);
                break;
 
        case FE_READ_UNCORRECTED_BLOCKS:
-               if (fe->ops->read_ucblocks)
-                       err = fe->ops->read_ucblocks(fe, (__u32*) parg);
+               if (fe->ops.read_ucblocks)
+                       err = fe->ops.read_ucblocks(fe, (__u32*) parg);
                break;
 
 
        case FE_DISEQC_RESET_OVERLOAD:
-               if (fe->ops->diseqc_reset_overload) {
-                       err = fe->ops->diseqc_reset_overload(fe);
+               if (fe->ops.diseqc_reset_overload) {
+                       err = fe->ops.diseqc_reset_overload(fe);
                        fepriv->state = FESTATE_DISEQC;
                        fepriv->status = 0;
                }
                break;
 
        case FE_DISEQC_SEND_MASTER_CMD:
-               if (fe->ops->diseqc_send_master_cmd) {
-                       err = fe->ops->diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
+               if (fe->ops.diseqc_send_master_cmd) {
+                       err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
                        fepriv->state = FESTATE_DISEQC;
                        fepriv->status = 0;
                }
                break;
 
        case FE_DISEQC_SEND_BURST:
-               if (fe->ops->diseqc_send_burst) {
-                       err = fe->ops->diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
+               if (fe->ops.diseqc_send_burst) {
+                       err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
                        fepriv->state = FESTATE_DISEQC;
                        fepriv->status = 0;
                }
                break;
 
        case FE_SET_TONE:
-               if (fe->ops->set_tone) {
-                       err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
+               if (fe->ops.set_tone) {
+                       err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);
                        fepriv->tone = (fe_sec_tone_mode_t) parg;
                        fepriv->state = FESTATE_DISEQC;
                        fepriv->status = 0;
@@ -803,8 +815,8 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                break;
 
        case FE_SET_VOLTAGE:
-               if (fe->ops->set_voltage) {
-                       err = fe->ops->set_voltage(fe, (fe_sec_voltage_t) parg);
+               if (fe->ops.set_voltage) {
+                       err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);
                        fepriv->voltage = (fe_sec_voltage_t) parg;
                        fepriv->state = FESTATE_DISEQC;
                        fepriv->status = 0;
@@ -812,11 +824,11 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                break;
 
        case FE_DISHNETWORK_SEND_LEGACY_CMD:
-               if (fe->ops->dishnetwork_send_legacy_command) {
-                       err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned long) parg);
+               if (fe->ops.dishnetwork_send_legacy_command) {
+                       err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg);
                        fepriv->state = FESTATE_DISEQC;
                        fepriv->status = 0;
-               } else if (fe->ops->set_voltage) {
+               } else if (fe->ops.set_voltage) {
                        /*
                         * NOTE: This is a fallback condition.  Some frontends
                         * (stv0299 for instance) take longer than 8msec to
@@ -846,7 +858,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                        /* before sending a command, initialize by sending
                         * a 32ms 18V to the switch
                         */
-                       fe->ops->set_voltage(fe, SEC_VOLTAGE_18);
+                       fe->ops.set_voltage(fe, SEC_VOLTAGE_18);
                        dvb_frontend_sleep_until(&nexttime, 32000);
 
                        for (i = 0; i < 9; i++) {
@@ -854,7 +866,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                                        do_gettimeofday(&tv[i + 1]);
                                if ((cmd & 0x01) != last) {
                                        /* set voltage to (last ? 13V : 18V) */
-                                       fe->ops->set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
+                                       fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
                                        last = (last) ? 0 : 1;
                                }
                                cmd = cmd >> 1;
@@ -874,13 +886,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                break;
 
        case FE_DISEQC_RECV_SLAVE_REPLY:
-               if (fe->ops->diseqc_recv_slave_reply)
-                       err = fe->ops->diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
+               if (fe->ops.diseqc_recv_slave_reply)
+                       err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
                break;
 
        case FE_ENABLE_HIGH_LNB_VOLTAGE:
-               if (fe->ops->enable_high_lnb_voltage)
-                       err = fe->ops->enable_high_lnb_voltage(fe, (long) parg);
+               if (fe->ops.enable_high_lnb_voltage)
+                       err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);
                break;
 
        case FE_SET_FRONTEND: {
@@ -898,7 +910,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                        fepriv->parameters.inversion = INVERSION_AUTO;
                        fetunesettings.parameters.inversion = INVERSION_AUTO;
                }
-               if (fe->ops->info.type == FE_OFDM) {
+               if (fe->ops.info.type == FE_OFDM) {
                        /* without hierachical coding code_rate_LP is irrelevant,
                         * so we tolerate the otherwise invalid FEC_NONE setting */
                        if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
@@ -907,13 +919,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                }
 
                /* get frontend-specific tuning settings */
-               if (fe->ops->get_tune_settings && (fe->ops->get_tune_settings(fe, &fetunesettings) == 0)) {
+               if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {
                        fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
                        fepriv->max_drift = fetunesettings.max_drift;
                        fepriv->step_size = fetunesettings.step_size;
                } else {
                        /* default values */
-                       switch(fe->ops->info.type) {
+                       switch(fe->ops.info.type) {
                        case FE_QPSK:
                                fepriv->min_delay = HZ/20;
                                fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000;
@@ -928,11 +940,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 
                        case FE_OFDM:
                                fepriv->min_delay = HZ/20;
-                               fepriv->step_size = fe->ops->info.frequency_stepsize * 2;
-                               fepriv->max_drift = (fe->ops->info.frequency_stepsize * 2) + 1;
+                               fepriv->step_size = fe->ops.info.frequency_stepsize * 2;
+                               fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
                                break;
                        case FE_ATSC:
-                               printk("dvb-core: FE_ATSC not handled yet.\n");
+                               fepriv->min_delay = HZ/20;
+                               fepriv->step_size = 0;
+                               fepriv->max_drift = 0;
                                break;
                        }
                }
@@ -952,9 +966,9 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                break;
 
        case FE_GET_FRONTEND:
-               if (fe->ops->get_frontend) {
+               if (fe->ops.get_frontend) {
                        memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters));
-                       err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg);
+                       err = fe->ops.get_frontend(fe, (struct dvb_frontend_parameters*) parg);
                }
                break;
 
@@ -1067,7 +1081,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
 
        printk ("DVB: registering frontend %i (%s)...\n",
                fe->dvb->num,
-               fe->ops->info.name);
+               fe->ops.info.name);
 
        dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
                             fe, DVB_DEVICE_FRONTEND);
@@ -1085,10 +1099,15 @@ int dvb_unregister_frontend(struct dvb_frontend* fe)
        mutex_lock(&frontend_mutex);
        dvb_unregister_device (fepriv->dvbdev);
        dvb_frontend_stop (fe);
-       if (fe->ops->release)
-               fe->ops->release(fe);
+       if (fe->ops.tuner_ops.release) {
+               fe->ops.tuner_ops.release(fe);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
+       }
+       if (fe->ops.release)
+               fe->ops.release(fe);
        else
-               printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops->info.name);
+               printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops.info.name);
        /* fe is invalid now */
        kfree(fepriv);
        mutex_unlock(&frontend_mutex);
index 5926a3b745c9d5525caa074578030f652b634223..2887e2b862a4436d1002a5dcee6ffafb1b5aba1f 100644 (file)
@@ -49,6 +49,44 @@ struct dvb_frontend_tune_settings {
 
 struct dvb_frontend;
 
+struct dvb_tuner_info {
+       char name[128];
+
+       u32 frequency_min;
+       u32 frequency_max;
+       u32 frequency_step;
+
+       u32 bandwidth_min;
+       u32 bandwidth_max;
+       u32 bandwidth_step;
+};
+
+struct dvb_tuner_ops {
+
+       struct dvb_tuner_info info;
+
+       int (*release)(struct dvb_frontend *fe);
+       int (*init)(struct dvb_frontend *fe);
+       int (*sleep)(struct dvb_frontend *fe);
+
+       /** This is for simple PLLs - set all parameters in one go. */
+       int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
+
+       /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
+       int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len);
+
+       int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
+       int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
+
+#define TUNER_STATUS_LOCKED 1
+       int (*get_status)(struct dvb_frontend *fe, u32 *status);
+
+       /** These are provided seperately from set_params in order to facilitate silicon
+        * tuners which require sophisticated tuning loops, controlling each parameter seperately. */
+       int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
+       int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
+};
+
 struct dvb_frontend_ops {
 
        struct dvb_frontend_info info;
@@ -64,6 +102,8 @@ struct dvb_frontend_ops {
                    unsigned int mode_flags,
                    int *delay,
                    fe_status_t *status);
+       /* get frontend tuning algorithm from the module */
+       int (*get_frontend_algo)(struct dvb_frontend *fe);
 
        /* these two are only used for the swzigzag code */
        int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
@@ -86,6 +126,8 @@ struct dvb_frontend_ops {
        int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
        int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
        int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
+
+       struct dvb_tuner_ops tuner_ops;
 };
 
 #define MAX_EVENT 8
@@ -100,9 +142,10 @@ struct dvb_fe_events {
 };
 
 struct dvb_frontend {
-       struct dvb_frontend_ops* ops;
+       struct dvb_frontend_ops ops;
        struct dvb_adapter *dvb;
        void* demodulator_priv;
+       void* tuner_priv;
        void* frontend_priv;
        void* misc_priv;
 };
diff --git a/drivers/media/dvb/dvb-core/dvb_math.c b/drivers/media/dvb/dvb-core/dvb_math.c
new file mode 100644 (file)
index 0000000..beb7c93
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * dvb-math provides some complex fixed-point math
+ * operations shared between the dvb related stuff
+ *
+ * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/bug.h>
+#include "dvb_math.h"
+
+static const unsigned short logtable[256] = {
+       0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
+       0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
+       0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6,
+       0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37,
+       0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f,
+       0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41,
+       0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1,
+       0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142,
+       0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68,
+       0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355,
+       0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c,
+       0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490,
+       0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3,
+       0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507,
+       0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe,
+       0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca,
+       0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c,
+       0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7,
+       0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c,
+       0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c,
+       0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a,
+       0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065,
+       0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730,
+       0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc,
+       0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469,
+       0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9,
+       0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c,
+       0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765,
+       0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83,
+       0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387,
+       0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973,
+       0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47
+};
+
+unsigned int intlog2(u32 value)
+{
+       /**
+        *      returns: log2(value) * 2^24
+        *      wrong result if value = 0 (log2(0) is undefined)
+        */
+       unsigned int msb;
+       unsigned int logentry;
+       unsigned int significand;
+       unsigned int interpolation;
+
+       if (unlikely(value == 0)) {
+               WARN_ON(1);
+               return 0;
+       }
+
+       /* first detect the msb (count begins at 0) */
+       msb = fls(value) - 1;
+
+       /**
+        *      now we use a logtable after the following method:
+        *
+        *      log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24
+        *      where x = msb and therefore 1 <= y < 2
+        *      first y is determined by shifting the value left
+        *      so that msb is bit 31
+        *              0x00231f56 -> 0x8C7D5800
+        *      the result is y * 2^31 -> "significand"
+        *      then the highest 9 bits are used for a table lookup
+        *      the highest bit is discarded because it's always set
+        *      the highest nine bits in our example are 100011000
+        *      so we would use the entry 0x18
+        */
+       significand = value << (31 - msb);
+       logentry = (significand >> 23) & 0xff;
+
+       /**
+        *      last step we do is interpolation because of the
+        *      limitations of the log table the error is that part of
+        *      the significand which isn't used for lookup then we
+        *      compute the ratio between the error and the next table entry
+        *      and interpolate it between the log table entry used and the
+        *      next one the biggest error possible is 0x7fffff
+        *      (in our example it's 0x7D5800)
+        *      needed value for next table entry is 0x800000
+        *      so the interpolation is
+        *      (error / 0x800000) * (logtable_next - logtable_current)
+        *      in the implementation the division is moved to the end for
+        *      better accuracy there is also an overflow correction if
+        *      logtable_next is 256
+        */
+       interpolation = ((significand & 0x7fffff) *
+                       ((logtable[(logentry + 1) & 0xff] -
+                         logtable[logentry]) & 0xffff)) >> 15;
+
+       /* now we return the result */
+       return ((msb << 24) + (logtable[logentry] << 8) + interpolation);
+}
+EXPORT_SYMBOL(intlog2);
+
+unsigned int intlog10(u32 value)
+{
+       /**
+        *      returns: log10(value) * 2^24
+        *      wrong result if value = 0 (log10(0) is undefined)
+        */
+       u64 log;
+
+       if (unlikely(value == 0)) {
+               WARN_ON(1);
+               return 0;
+       }
+
+       log = intlog2(value);
+
+       /**
+        *      we use the following method:
+        *      log10(x) = log2(x) * log10(2)
+        */
+
+       return (log * 646456993) >> 31;
+}
+EXPORT_SYMBOL(intlog10);
diff --git a/drivers/media/dvb/dvb-core/dvb_math.h b/drivers/media/dvb/dvb-core/dvb_math.h
new file mode 100644 (file)
index 0000000..aecc867
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * dvb-math provides some complex fixed-point math
+ * operations shared between the dvb related stuff
+ *
+ * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __DVB_MATH_H
+#define __DVB_MATH_H
+
+#include <linux/types.h>
+
+/**
+ * computes log2 of a value; the result is shifted left by 24 bits
+ *
+ * to use rational values you can use the following method:
+ *   intlog2(value) = intlog2(value * 2^x) - x * 2^24
+ *
+ * example: intlog2(8) will give 3 << 24 = 3 * 2^24
+ * example: intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
+ * example: intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
+ *
+ * @param value The value (must be != 0)
+ * @return log2(value) * 2^24
+ */
+extern unsigned int intlog2(u32 value);
+
+/**
+ * computes log10 of a value; the result is shifted left by 24 bits
+ *
+ * to use rational values you can use the following method:
+ *   intlog10(value) = intlog10(value * 10^x) - x * 2^24
+ *
+ * example: intlog10(1000) will give 3 << 24 = 3 * 2^24
+ *   due to the implementation intlog10(1000) might be not exactly 3 * 2^24
+ *
+ * look at intlog2 for similar examples
+ *
+ * @param value The value (must be != 0)
+ * @return log10(value) * 2^24
+ */
+extern unsigned int intlog10(u32 value);
+
+#endif
index 9fd87521a1639bd3dae51dcdce48545614d41a85..8859ab74f0fe4c65c8e75b9350a2a0b138615525 100644 (file)
@@ -12,7 +12,7 @@
  *                          Hilmar Linder <hlinder@cosy.sbg.ac.at>
  *                      and Wolfram Stering <wstering@cosy.sbg.ac.at>
  *
- * ULE Decaps according to draft-ietf-ipdvb-ule-03.txt.
+ * ULE Decaps according to RFC 4326.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -42,6 +42,9 @@
  *                     Bugfixes and robustness improvements.
  *                     Filtering on dest MAC addresses, if present (D-Bit = 0)
  *                     ULE_DEBUG compile-time option.
+ * Apr 2006: cp v3:    Bugfixes and compliency with RFC 4326 (ULE) by
+ *                       Christian Praehauser <cpraehaus@cosy.sbg.ac.at>,
+ *                       Paris Lodron University of Salzburg.
  */
 
 /*
@@ -49,9 +52,6 @@
  *
  * Unloading does not work for 2.6.9 kernels: a refcount doesn't go to zero.
  *
- * TS_FEED callback is called once for every single TS cell although it is
- * registered (in dvb_net_feed_start()) for 100 TS cells (used for dvb_net_ule()).
- *
  */
 
 #include <linux/module.h>
@@ -89,6 +89,9 @@ static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
 
 #ifdef ULE_DEBUG
 
+#define MAC_ADDR_PRINTFMT "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"
+#define MAX_ADDR_PRINTFMT_ARGS(macap) (macap)[0],(macap)[1],(macap)[2],(macap)[3],(macap)[4],(macap)[5]
+
 #define isprint(c)     ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
 
 static void hexdump( const unsigned char *buf, unsigned short len )
@@ -214,6 +217,8 @@ static unsigned short dvb_net_eth_type_trans(struct sk_buff *skb,
 #define ULE_TEST       0
 #define ULE_BRIDGED    1
 
+#define ULE_OPTEXTHDR_PADDING 0
+
 static int ule_test_sndu( struct dvb_net_priv *p )
 {
        return -1;
@@ -221,14 +226,28 @@ static int ule_test_sndu( struct dvb_net_priv *p )
 
 static int ule_bridged_sndu( struct dvb_net_priv *p )
 {
-       /* BRIDGE SNDU handling sucks in draft-ietf-ipdvb-ule-03.txt.
-        * This has to be the last extension header, otherwise it won't work.
-        * Blame the authors!
+       struct ethhdr *hdr = (struct ethhdr*) p->ule_next_hdr;
+       if(ntohs(hdr->h_proto) < 1536) {
+               int framelen = p->ule_sndu_len - ((p->ule_next_hdr+sizeof(struct ethhdr)) - p->ule_skb->data);
+               /* A frame Type < 1536 for a bridged frame, introduces a LLC Length field. */
+               if(framelen != ntohs(hdr->h_proto)) {
+                       return -1;
+               }
+       }
+       /* Note:
+        * From RFC4326:
+        *  "A bridged SNDU is a Mandatory Extension Header of Type 1.
+        *   It must be the final (or only) extension header specified in the header chain of a SNDU."
+        * The 'ule_bridged' flag will cause the extension header processing loop to terminate.
         */
        p->ule_bridged = 1;
        return 0;
 }
 
+static int ule_exthdr_padding(struct dvb_net_priv *p)
+{
+       return 0;
+}
 
 /** Handle ULE extension headers.
  *  Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding.
@@ -242,7 +261,8 @@ static int handle_one_ule_extension( struct dvb_net_priv *p )
                { [0] = ule_test_sndu, [1] = ule_bridged_sndu, [2] = NULL,  };
 
        /* Table of optional extension header handlers.  The header type is the index. */
-       static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) = { NULL, };
+       static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) =
+               { [0] = ule_exthdr_padding, [1] = NULL, };
 
        int ext_len = 0;
        unsigned char hlen = (p->ule_sndu_type & 0x0700) >> 8;
@@ -253,25 +273,31 @@ static int handle_one_ule_extension( struct dvb_net_priv *p )
                /* Mandatory extension header */
                if (ule_mandatory_ext_handlers[htype]) {
                        ext_len = ule_mandatory_ext_handlers[htype]( p );
-                       p->ule_next_hdr += ext_len;
-                       if (! p->ule_bridged) {
-                               p->ule_sndu_type = ntohs( *(unsigned short *)p->ule_next_hdr );
-                               p->ule_next_hdr += 2;
-                       } else {
-                               p->ule_sndu_type = ntohs( *(unsigned short *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)) );
-                               /* This assures the extension handling loop will terminate. */
+                       if(ext_len >= 0) {
+                               p->ule_next_hdr += ext_len;
+                               if (!p->ule_bridged) {
+                                       p->ule_sndu_type = ntohs(*(unsigned short *)p->ule_next_hdr);
+                                       p->ule_next_hdr += 2;
+                               } else {
+                                       p->ule_sndu_type = ntohs(*(unsigned short *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)));
+                                       /* This assures the extension handling loop will terminate. */
+                               }
                        }
+                       // else: extension handler failed or SNDU should be discarded
                } else
                        ext_len = -1;   /* SNDU has to be discarded. */
        } else {
                /* Optional extension header.  Calculate the length. */
-               ext_len = hlen << 2;
+               ext_len = hlen << 1;
                /* Process the optional extension header according to its type. */
                if (ule_optional_ext_handlers[htype])
                        (void)ule_optional_ext_handlers[htype]( p );
                p->ule_next_hdr += ext_len;
-               p->ule_sndu_type = ntohs( *(unsigned short *)p->ule_next_hdr );
-               p->ule_next_hdr += 2;
+               p->ule_sndu_type = ntohs( *(unsigned short *)(p->ule_next_hdr-2) );
+               /*
+                * note: the length of the next header type is included in the
+                * length of THIS optional extension header
+                */
        }
 
        return ext_len;
@@ -284,8 +310,14 @@ static int handle_ule_extensions( struct dvb_net_priv *p )
        p->ule_next_hdr = p->ule_skb->data;
        do {
                l = handle_one_ule_extension( p );
-               if (l == -1) return -1; /* Stop extension header processing and discard SNDU. */
+               if (l < 0)
+                       return l;       /* Stop extension header processing and discard SNDU. */
                total_ext_len += l;
+#ifdef ULE_DEBUG
+               dprintk("handle_ule_extensions: ule_next_hdr=%p, ule_sndu_type=%i, "
+                       "l=%i, total_ext_len=%i\n", p->ule_next_hdr,
+                       (int) p->ule_sndu_type, l, total_ext_len);
+#endif
 
        } while (p->ule_sndu_type < 1536);
 
@@ -355,8 +387,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
                                if (priv->ule_skb) {
                                        dev_kfree_skb( priv->ule_skb );
                                        /* Prepare for next SNDU. */
-                                       ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
-                                       ((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;
+                                       priv->stats.rx_errors++;
+                                       priv->stats.rx_frame_errors++;
                                }
                                reset_ule(priv);
                                priv->need_pusi = 1;
@@ -396,27 +428,25 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
                        }
                }
 
-               /* Check continuity counter. */
                if (new_ts) {
+                       /* Check continuity counter. */
                        if ((ts[3] & 0x0F) == priv->tscc)
                                priv->tscc = (priv->tscc + 1) & 0x0F;
                        else {
                                /* TS discontinuity handling: */
                                printk(KERN_WARNING "%lu: TS discontinuity: got %#x, "
-                                      "exptected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc);
+                                      "expected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc);
                                /* Drop partly decoded SNDU, reset state, resync on PUSI. */
                                if (priv->ule_skb) {
                                        dev_kfree_skb( priv->ule_skb );
                                        /* Prepare for next SNDU. */
                                        // reset_ule(priv);  moved to below.
-                                       ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
-                                       ((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;
+                                       priv->stats.rx_errors++;
+                                       priv->stats.rx_frame_errors++;
                                }
                                reset_ule(priv);
                                /* skip to next PUSI. */
                                priv->need_pusi = 1;
-                               ts += TS_SZ;
-                               priv->ts_count++;
                                continue;
                        }
                        /* If we still have an incomplete payload, but PUSI is
@@ -425,7 +455,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
                         * cells (continuity counter wrap). */
                        if (ts[1] & TS_PUSI) {
                                if (! priv->need_pusi) {
-                                       if (*from_where > 181) {
+                                       if (!(*from_where < (ts_remain-1)) || *from_where != priv->ule_sndu_remain) {
                                                /* Pointer field is invalid.  Drop this TS cell and any started ULE SNDU. */
                                                printk(KERN_WARNING "%lu: Invalid pointer "
                                                       "field: %u.\n", priv->ts_count, *from_where);
@@ -438,8 +468,6 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
                                                }
                                                reset_ule(priv);
                                                priv->need_pusi = 1;
-                                               ts += TS_SZ;
-                                               priv->ts_count++;
                                                continue;
                                        }
                                        /* Skip pointer field (we're processing a
@@ -452,8 +480,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
                                if (priv->ule_sndu_remain > 183) {
                                        /* Current SNDU lacks more data than there could be available in the
                                         * current TS cell. */
-                                       ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
-                                       ((struct dvb_net_priv *) dev->priv)->stats.rx_length_errors++;
+                                       priv->stats.rx_errors++;
+                                       priv->stats.rx_length_errors++;
                                        printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but "
                                               "got PUSI (pf %d, ts_remain %d).  Flushing incomplete payload.\n",
                                               priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain);
@@ -492,9 +520,11 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
                                } else
                                        priv->ule_dbit = 0;
 
-                               if (priv->ule_sndu_len > 32763) {
+                               if (priv->ule_sndu_len < 5) {
                                        printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. "
                                               "Resyncing.\n", priv->ts_count, priv->ule_sndu_len);
+                                       priv->stats.rx_errors++;
+                                       priv->stats.rx_length_errors++;
                                        priv->ule_sndu_len = 0;
                                        priv->need_pusi = 1;
                                        new_ts = 1;
@@ -608,58 +638,103 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
                                ule_dump = 1;
 #endif
 
-                               ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
-                               ((struct dvb_net_priv *) dev->priv)->stats.rx_crc_errors++;
+                               priv->stats.rx_errors++;
+                               priv->stats.rx_crc_errors++;
                                dev_kfree_skb(priv->ule_skb);
                        } else {
                                /* CRC32 verified OK. */
+                               u8 dest_addr[ETH_ALEN];
+                               static const u8 bc_addr[ETH_ALEN] =
+                                       { [ 0 ... ETH_ALEN-1] = 0xff };
+
+                               /* CRC32 was OK. Remove it from skb. */
+                               priv->ule_skb->tail -= 4;
+                               priv->ule_skb->len -= 4;
+
+                               if (!priv->ule_dbit) {
+                                       /*
+                                        * The destination MAC address is the
+                                        * next data in the skb.  It comes
+                                        * before any extension headers.
+                                        *
+                                        * Check if the payload of this SNDU
+                                        * should be passed up the stack.
+                                        */
+                                       register int drop = 0;
+                                       if (priv->rx_mode != RX_MODE_PROMISC) {
+                                               if (priv->ule_skb->data[0] & 0x01) {
+                                                       /* multicast or broadcast */
+                                                       if (memcmp(priv->ule_skb->data, bc_addr, ETH_ALEN)) {
+                                                               /* multicast */
+                                                               if (priv->rx_mode == RX_MODE_MULTI) {
+                                                                       int i;
+                                                                       for(i = 0; i < priv->multi_num && memcmp(priv->ule_skb->data, priv->multi_macs[i], ETH_ALEN); i++)
+                                                                               ;
+                                                                       if (i == priv->multi_num)
+                                                                               drop = 1;
+                                                               } else if (priv->rx_mode != RX_MODE_ALL_MULTI)
+                                                                       drop = 1; /* no broadcast; */
+                                                               /* else: all multicast mode: accept all multicast packets */
+                                                       }
+                                                       /* else: broadcast */
+                                               }
+                                               else if (memcmp(priv->ule_skb->data, dev->dev_addr, ETH_ALEN))
+                                                       drop = 1;
+                                               /* else: destination address matches the MAC address of our receiver device */
+                                       }
+                                       /* else: promiscious mode; pass everything up the stack */
+
+                                       if (drop) {
+#ifdef ULE_DEBUG
+                                               dprintk("Dropping SNDU: MAC destination address does not match: dest addr: "MAC_ADDR_PRINTFMT", dev addr: "MAC_ADDR_PRINTFMT"\n",
+                                                       MAX_ADDR_PRINTFMT_ARGS(priv->ule_skb->data), MAX_ADDR_PRINTFMT_ARGS(dev->dev_addr));
+#endif
+                                               dev_kfree_skb(priv->ule_skb);
+                                               goto sndu_done;
+                                       }
+                                       else
+                                       {
+                                               memcpy(dest_addr,  priv->ule_skb->data, ETH_ALEN);
+                                               skb_pull(priv->ule_skb, ETH_ALEN);
+                                       }
+                               }
+
                                /* Handle ULE Extension Headers. */
                                if (priv->ule_sndu_type < 1536) {
                                        /* There is an extension header.  Handle it accordingly. */
-                                       int l = handle_ule_extensions( priv );
+                                       int l = handle_ule_extensions(priv);
                                        if (l < 0) {
                                                /* Mandatory extension header unknown or TEST SNDU.  Drop it. */
                                                // printk( KERN_WARNING "Dropping SNDU, extension headers.\n" );
-                                               dev_kfree_skb( priv->ule_skb );
+                                               dev_kfree_skb(priv->ule_skb);
                                                goto sndu_done;
                                        }
-                                       skb_pull( priv->ule_skb, l );
+                                       skb_pull(priv->ule_skb, l);
                                }
 
-                               /* CRC32 was OK. Remove it from skb. */
-                               priv->ule_skb->tail -= 4;
-                               priv->ule_skb->len -= 4;
-
-                               /* Filter on receiver's destination MAC address, if present. */
-                               if (!priv->ule_dbit) {
-                                       /* The destination MAC address is the next data in the skb. */
-                                       if (memcmp( priv->ule_skb->data, dev->dev_addr, ETH_ALEN )) {
-                                               /* MAC addresses don't match.  Drop SNDU. */
-                                               // printk( KERN_WARNING "Dropping SNDU, MAC address.\n" );
-                                               dev_kfree_skb( priv->ule_skb );
-                                               goto sndu_done;
-                                       }
-                                       if (! priv->ule_bridged) {
-                                               skb_push( priv->ule_skb, ETH_ALEN + 2 );
-                                               ethh = (struct ethhdr *)priv->ule_skb->data;
-                                               memcpy( ethh->h_dest, ethh->h_source, ETH_ALEN );
-                                               memset( ethh->h_source, 0, ETH_ALEN );
-                                               ethh->h_proto = htons( priv->ule_sndu_type );
-                                       } else {
-                                               /* Skip the Receiver destination MAC address. */
-                                               skb_pull( priv->ule_skb, ETH_ALEN );
-                                       }
-                               } else {
-                                       if (! priv->ule_bridged) {
-                                               skb_push( priv->ule_skb, ETH_HLEN );
-                                               ethh = (struct ethhdr *)priv->ule_skb->data;
-                                               memcpy( ethh->h_dest, dev->dev_addr, ETH_ALEN );
-                                               memset( ethh->h_source, 0, ETH_ALEN );
-                                               ethh->h_proto = htons( priv->ule_sndu_type );
-                                       } else {
-                                               /* skb is in correct state; nothing to do. */
+                               /*
+                                * Construct/assure correct ethernet header.
+                                * Note: in bridged mode (priv->ule_bridged !=
+                                * 0) we already have the (original) ethernet
+                                * header at the start of the payload (after
+                                * optional dest. address and any extension
+                                * headers).
+                                */
+
+                               if (!priv->ule_bridged) {
+                                       skb_push(priv->ule_skb, ETH_HLEN);
+                                       ethh = (struct ethhdr *)priv->ule_skb->data;
+                                       if (!priv->ule_dbit) {
+                                                /* dest_addr buffer is only valid if priv->ule_dbit == 0 */
+                                               memcpy(ethh->h_dest, dest_addr, ETH_ALEN);
+                                               memset(ethh->h_source, 0, ETH_ALEN);
                                        }
+                                       else /* zeroize source and dest */
+                                               memset( ethh, 0, ETH_ALEN*2 );
+
+                                       ethh->h_proto = htons(priv->ule_sndu_type);
                                }
+                               /* else:  skb is in correct state; nothing to do. */
                                priv->ule_bridged = 0;
 
                                /* Stuff into kernel's protocol stack. */
@@ -668,8 +743,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
                                 * receive the packet anyhow. */
                                /* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST)
                                        priv->ule_skb->pkt_type = PACKET_HOST; */
-                               ((struct dvb_net_priv *) dev->priv)->stats.rx_packets++;
-                               ((struct dvb_net_priv *) dev->priv)->stats.rx_bytes += priv->ule_skb->len;
+                               priv->stats.rx_packets++;
+                               priv->stats.rx_bytes += priv->ule_skb->len;
                                netif_rx(priv->ule_skb);
                        }
                        sndu_done:
@@ -944,7 +1019,7 @@ static int dvb_net_feed_start(struct net_device *dev)
                dprintk("%s: start filtering\n", __FUNCTION__);
                priv->secfeed->start_filtering(priv->secfeed);
        } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
-               struct timespec timeout = { 0, 30000000 }; // 30 msec
+               struct timespec timeout = { 0, 10000000 }; // 10 msec
 
                /* we have payloads encapsulated in TS */
                dprintk("%s: alloc tsfeed\n", __FUNCTION__);
@@ -956,10 +1031,13 @@ static int dvb_net_feed_start(struct net_device *dev)
 
                /* Set netdevice pointer for ts decaps callback. */
                priv->tsfeed->priv = (void *)dev;
-               ret = priv->tsfeed->set(priv->tsfeed, priv->pid,
-                                       TS_PACKET, DMX_TS_PES_OTHER,
+               ret = priv->tsfeed->set(priv->tsfeed,
+                                       priv->pid, /* pid */
+                                       TS_PACKET, /* type */
+                                       DMX_TS_PES_OTHER, /* pes type */
                                        32768,     /* circular buffer size */
-                                       timeout);
+                                       timeout    /* timeout */
+                                       );
 
                if (ret < 0) {
                        printk("%s: could not set ts feed\n", dev->name);
index 3852430d0260e65fc5daf8045c07bd19031933e0..134c2bbbeeb5f75e89921413850a0bffec367ed6 100644 (file)
@@ -236,7 +236,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
                        "dvb/adapter%d/%s%d", adap->num, dnames[type], id);
 
        class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
-                           NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
+                           adap->device, "dvb%d.%s%d", adap->num, dnames[type], id);
 
        dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
                adap->num, dnames[type], id, nums2minor(adap->num, type, id),
@@ -285,7 +285,7 @@ skip:
 }
 
 
-int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module)
+int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module, struct device *device)
 {
        int num;
 
@@ -306,6 +306,7 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct modu
        adap->num = num;
        adap->name = name;
        adap->module = module;
+       adap->device = device;
 
        list_add_tail (&adap->list_head, &dvb_adapter_list);
 
index 74ed5853f0fb02c1d0be40518d7426b50c2d3b44..d7a976d040d72249ab8d5558529d328802356c4e 100644 (file)
@@ -51,6 +51,8 @@ struct dvb_adapter {
        u8 proposed_mac [6];
        void* priv;
 
+       struct device *device;
+
        struct module *module;
 };
 
@@ -76,7 +78,7 @@ struct dvb_device {
 };
 
 
-extern int dvb_register_adapter (struct dvb_adapter *adap, const char *name, struct module *module);
+extern int dvb_register_adapter (struct dvb_adapter *adap, const char *name, struct module *module, struct device *device);
 extern int dvb_unregister_adapter (struct dvb_adapter *adap);
 
 extern int dvb_register_device (struct dvb_adapter *adap,
index e388fb1567d6ec6d813158bc29516e07ecd8c496..3bc6722a6443e1e29e80382114a75c46a7d21527 100644 (file)
@@ -88,6 +88,7 @@ config DVB_USB_CXUSB
        select DVB_CX22702
        select DVB_LGDT330X
        select DVB_MT352
+       select DVB_ZL10353
        help
          Say Y here to support the Conexant USB2.0 hybrid reference design.
          Currently, only DVB and ATSC modes are supported, analog mode
@@ -130,6 +131,15 @@ config DVB_USB_VP702X
 
          DVB-S USB2.0 receivers.
 
+config DVB_USB_GP8PSK
+       tristate "GENPIX 8PSK->USB module support"
+       depends on DVB_USB
+       help
+         Say Y here to support the
+           GENPIX 8psk module
+
+         DVB-S USB2.0 receivers.
+
 config DVB_USB_NOVA_T_USB2
        tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
        depends on DVB_USB
index 2dc9aad9681e36825043ce1d0dd8628139fdaa3a..9643f56c7fe9a02e3f5e88e3d01bbd4875bf852a 100644 (file)
@@ -7,6 +7,9 @@ obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o
 dvb-usb-vp702x-objs = vp702x.o vp702x-fe.o
 obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o
 
+dvb-usb-gp8psk-objs = gp8psk.o gp8psk-fe.o
+obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o
+
 dvb-usb-dtt200u-objs = dtt200u.o dtt200u-fe.o
 obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o
 
index 1f0d3e995c8d67e64419b4493b56085719820204..ae23bdde42a82505271051024dd2d0509ec994cb 100644 (file)
 
 #include "cx22702.h"
 #include "lgdt330x.h"
+#include "lg_h06xf.h"
 #include "mt352.h"
 #include "mt352_priv.h"
+#include "zl10353.h"
 
 /* debug */
 int dvb_usb_cxusb_debug;
@@ -322,32 +324,37 @@ static int cxusb_mt352_demod_init(struct dvb_frontend* fe)
        return 0;
 }
 
+static int cxusb_lgh064f_tuner_set_params(struct dvb_frontend *fe,
+                                         struct dvb_frontend_parameters *fep)
+{
+       struct dvb_usb_device *d = fe->dvb->priv;
+       return lg_h06xf_pll_set(fe, &d->i2c_adap, fep);
+}
+
 static struct cx22702_config cxusb_cx22702_config = {
        .demod_address = 0x63,
 
        .output_mode = CX22702_PARALLEL_OUTPUT,
-
-       .pll_init = dvb_usb_pll_init_i2c,
-       .pll_set  = dvb_usb_pll_set_i2c,
 };
 
 static struct lgdt330x_config cxusb_lgdt3303_config = {
        .demod_address = 0x0e,
        .demod_chip    = LGDT3303,
-       .pll_set       = dvb_usb_pll_set_i2c,
 };
 
 static struct mt352_config cxusb_dee1601_config = {
        .demod_address = 0x0f,
        .demod_init    = cxusb_dee1601_demod_init,
-       .pll_set       = dvb_usb_pll_set,
 };
 
-struct mt352_config cxusb_mt352_config = {
+static struct zl10353_config cxusb_zl10353_dee1601_config = {
+       .demod_address = 0x0f,
+};
+
+static struct mt352_config cxusb_mt352_config = {
        /* used in both lgz201 and th7579 */
        .demod_address = 0x0f,
        .demod_init    = cxusb_mt352_demod_init,
-       .pll_set       = dvb_usb_pll_set,
 };
 
 /* Callbacks for DVB USB */
@@ -357,17 +364,10 @@ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_device *d)
        d->pll_addr = 0x61;
        memcpy(d->pll_init, bpll, 4);
        d->pll_desc = &dvb_pll_fmd1216me;
-       return 0;
-}
 
-static int cxusb_lgh064f_tuner_attach(struct dvb_usb_device *d)
-{
-       u8 bpll[4] = { 0x00, 0x00, 0x18, 0x50 };
-       /* bpll[2] : unset bit 3, set bits 4&5
-          bpll[3] : 0x50 - digital, 0x20 - analog */
-       d->pll_addr = 0x61;
-       memcpy(d->pll_init, bpll, 4);
-       d->pll_desc = &dvb_pll_tdvs_tua6034;
+       d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+       d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+
        return 0;
 }
 
@@ -375,6 +375,7 @@ static int cxusb_dee1601_tuner_attach(struct dvb_usb_device *d)
 {
        d->pll_addr = 0x61;
        d->pll_desc = &dvb_pll_thomson_dtt7579;
+       d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
        return 0;
 }
 
@@ -382,6 +383,7 @@ static int cxusb_lgz201_tuner_attach(struct dvb_usb_device *d)
 {
        d->pll_addr = 0x61;
        d->pll_desc = &dvb_pll_lg_z201;
+       d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
        return 0;
 }
 
@@ -389,6 +391,13 @@ static int cxusb_dtt7579_tuner_attach(struct dvb_usb_device *d)
 {
        d->pll_addr = 0x60;
        d->pll_desc = &dvb_pll_thomson_dtt7579;
+       d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+       return 0;
+}
+
+static int cxusb_lgdt3303_tuner_attach(struct dvb_usb_device *d)
+{
+       d->fe->ops.tuner_ops.set_params = cxusb_lgh064f_tuner_set_params;
        return 0;
 }
 
@@ -439,7 +448,8 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_device *d)
 
        cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
 
-       if ((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL)
+       if (((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL) ||
+           ((d->fe = zl10353_attach(&cxusb_zl10353_dee1601_config, &d->i2c_adap)) != NULL))
                return 0;
 
        return -EIO;
@@ -555,7 +565,7 @@ static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = {
        .streaming_ctrl   = cxusb_streaming_ctrl,
        .power_ctrl       = cxusb_bluebird_power_ctrl,
        .frontend_attach  = cxusb_lgdt3303_frontend_attach,
-       .tuner_attach     = cxusb_lgh064f_tuner_attach,
+       .tuner_attach     = cxusb_lgdt3303_tuner_attach,
 
        .i2c_algo         = &cxusb_i2c_algo,
 
index 2d52b76671d35a729eea31b3bb16cf3f50b97953..abd75b4a350dab46c2d054d176edb991668f44bf 100644 (file)
@@ -173,11 +173,10 @@ int dibusb_dib3000mc_frontend_attach(struct dvb_usb_device *d)
        struct dib3000_config demod_cfg;
        struct dibusb_state *st = d->priv;
 
-       demod_cfg.pll_set = dvb_usb_pll_set_i2c;
-       demod_cfg.pll_init = dvb_usb_pll_init_i2c;
-
        for (demod_cfg.demod_address = 0x8; demod_cfg.demod_address < 0xd; demod_cfg.demod_address++)
                if ((d->fe = dib3000mc_attach(&demod_cfg,&d->i2c_adap,&st->ops)) != NULL) {
+                       d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+                       d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
                        d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
                        return 0;
                }
@@ -190,6 +189,10 @@ int dibusb_dib3000mc_tuner_attach (struct dvb_usb_device *d)
 {
        d->pll_addr = 0x60;
        d->pll_desc = &dvb_pll_env57h1xd5;
+
+       d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+       d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+
        return 0;
 }
 EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
index dd5a131958862a8bd7090dc2328c81fc499bfc1a..f4c45f386ebc693992cb7a165bb76896c1c60086 100644 (file)
@@ -20,11 +20,12 @@ static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_device *d)
        struct dibusb_state *st = d->priv;
 
        demod_cfg.demod_address = 0x8;
-       demod_cfg.pll_set = dvb_usb_pll_set_i2c;
-       demod_cfg.pll_init = dvb_usb_pll_init_i2c;
 
-       if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL)
+       if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL) {
+               d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+               d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
                return -ENODEV;
+       }
 
        d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
 
index 91136c00ce9ddf5bf3b5d1957601c05d0148decc..c14d9efb48fdb7162a809ba16b3cd5b207acebc0 100644 (file)
@@ -112,27 +112,30 @@ static int digitv_mt352_demod_init(struct dvb_frontend *fe)
 
 static struct mt352_config digitv_mt352_config = {
        .demod_init = digitv_mt352_demod_init,
-       .pll_set = dvb_usb_pll_set,
 };
 
-static int digitv_nxt6000_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
 {
        struct dvb_usb_device *d = fe->dvb->priv;
        u8 b[5];
-       dvb_usb_pll_set(fe,fep,b);
+       dvb_usb_tuner_calc_regs(fe,fep,b, 5);
        return digitv_ctrl_msg(d,USB_WRITE_TUNER,0,&b[1],4,NULL,0);
 }
 
 static struct nxt6000_config digitv_nxt6000_config = {
        .clock_inversion = 1,
-       .pll_set = digitv_nxt6000_pll_set,
 };
 
 static int digitv_frontend_attach(struct dvb_usb_device *d)
 {
-       if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL ||
-               (d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL)
+       if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL) {
+               d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
                return 0;
+       }
+       if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) {
+               d->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+               return 0;
+       }
        return -EIO;
 }
 
index cd21ddbfd05479f9be098ba01e8fe8c1011f064c..17413adec7a1fbd92199c97d0a45f2dfa37e8875 100644 (file)
@@ -18,7 +18,6 @@ struct dtt200u_fe_state {
 
        struct dvb_frontend_parameters fep;
        struct dvb_frontend frontend;
-       struct dvb_frontend_ops ops;
 };
 
 static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat)
@@ -163,16 +162,13 @@ struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d)
        deb_info("attaching frontend dtt200u\n");
 
        state->d = d;
-       memcpy(&state->ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops));
 
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
 
-       goto success;
+       return &state->frontend;
 error:
        return NULL;
-success:
-       return &state->frontend;
 }
 
 static struct dvb_frontend_ops dtt200u_fe_ops = {
index 6fa92100248b8291b7353b070dc7347bfea67d38..ec631708c39480cf7d390267b452c109d2da2088 100644 (file)
@@ -82,7 +82,7 @@ int dvb_usb_dvb_init(struct dvb_usb_device *d)
        int ret;
 
        if ((ret = dvb_register_adapter(&d->dvb_adap, d->desc->name,
-                       d->owner)) < 0) {
+                       d->owner, &d->udev->dev)) < 0) {
                deb_info("dvb_register_adapter failed: error %d", ret);
                goto err;
        }
@@ -121,16 +121,15 @@ int dvb_usb_dvb_init(struct dvb_usb_device *d)
 
        dvb_net_init(&d->dvb_adap, &d->dvb_net, &d->demux.dmx);
 
-       goto success;
+       d->state |= DVB_USB_STATE_DVB;
+       return 0;
+
 err_dmx_dev:
        dvb_dmx_release(&d->demux);
 err_dmx:
        dvb_unregister_adapter(&d->dvb_adap);
 err:
        return ret;
-success:
-       d->state |= DVB_USB_STATE_DVB;
-       return 0;
 }
 
 int dvb_usb_dvb_exit(struct dvb_usb_device *d)
@@ -184,13 +183,13 @@ int dvb_usb_fe_init(struct dvb_usb_device* d)
 
        /* re-assign sleep and wakeup functions */
        if (d->fe != NULL) {
-               d->fe_init = d->fe->ops->init;   d->fe->ops->init  = dvb_usb_fe_wakeup;
-               d->fe_sleep = d->fe->ops->sleep; d->fe->ops->sleep = dvb_usb_fe_sleep;
+               d->fe_init = d->fe->ops.init;   d->fe->ops.init  = dvb_usb_fe_wakeup;
+               d->fe_sleep = d->fe->ops.sleep; d->fe->ops.sleep = dvb_usb_fe_sleep;
 
                if (dvb_register_frontend(&d->dvb_adap, d->fe)) {
                        err("Frontend registration failed.");
-                       if (d->fe->ops->release)
-                               d->fe->ops->release(d->fe);
+                       if (d->fe->ops.release)
+                               d->fe->ops.release(d->fe);
                        d->fe = NULL;
                        return -ENODEV;
                }
index 9b254532af4dddd6e528c16c0a5770b3d8612173..6b611a72509309d4c4eefd84f513687df785ee5e 100644 (file)
@@ -46,7 +46,7 @@ int dvb_usb_i2c_exit(struct dvb_usb_device *d)
        return 0;
 }
 
-int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
+int dvb_usb_tuner_init_i2c(struct dvb_frontend *fe)
 {
        struct dvb_usb_device *d = fe->dvb->priv;
        struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = d->pll_init, .len = 4 };
@@ -63,6 +63,8 @@ int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
        deb_pll("pll-buf: %x %x %x %x\n",d->pll_init[0],d->pll_init[1],
                        d->pll_init[2],d->pll_init[3]);
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
                err("tuner i2c write failed for pll_init.");
                ret = -EREMOTEIO;
@@ -73,38 +75,42 @@ int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
                d->tuner_pass_ctrl(fe,0,d->pll_addr);
        return ret;
 }
-EXPORT_SYMBOL(dvb_usb_pll_init_i2c);
+EXPORT_SYMBOL(dvb_usb_tuner_init_i2c);
 
-int dvb_usb_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 b[5])
+int dvb_usb_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 *b, int buf_len)
 {
        struct dvb_usb_device *d = fe->dvb->priv;
 
+       if (buf_len != 5)
+               return -EINVAL;
        if (d->pll_desc == NULL)
                return 0;
 
        deb_pll("pll addr: %x, freq: %d %p\n",d->pll_addr,fep->frequency,d->pll_desc);
 
-       b[0] = d->pll_addr << 1;
+       b[0] = d->pll_addr;
        dvb_pll_configure(d->pll_desc,&b[1],fep->frequency,fep->u.ofdm.bandwidth);
 
        deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]);
 
-       return 0;
+       return 5;
 }
-EXPORT_SYMBOL(dvb_usb_pll_set);
+EXPORT_SYMBOL(dvb_usb_tuner_calc_regs);
 
-int dvb_usb_pll_set_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
 {
        struct dvb_usb_device *d = fe->dvb->priv;
        int ret = 0;
        u8 b[5];
        struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
 
-       dvb_usb_pll_set(fe,fep,b);
+       dvb_usb_tuner_calc_regs(fe,fep,b,5);
 
        if (d->tuner_pass_ctrl)
                d->tuner_pass_ctrl(fe,1,d->pll_addr);
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
                err("tuner i2c write failed for pll_set.");
                ret = -EREMOTEIO;
@@ -116,4 +122,4 @@ int dvb_usb_pll_set_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters
 
        return ret;
 }
-EXPORT_SYMBOL(dvb_usb_pll_set_i2c);
+EXPORT_SYMBOL(dvb_usb_tuner_set_params_i2c);
index cb239049b09836dc46b0f058d961c638aa1333aa..95698918bc116878da6ae4ac96f2b77661cf127d 100644 (file)
@@ -31,6 +31,7 @@
 #define USB_VID_VISIONPLUS                                     0x13d3
 #define USB_VID_TWINHAN                                                0x1822
 #define USB_VID_ULTIMA_ELECTRONIC                      0x05d8
+#define USB_VID_GENPIX                                 0x09c0
 
 /* Product IDs */
 #define USB_PID_ADSTECH_USB2_COLD                      0xa333
 #define USB_PID_KYE_DVB_T_WARM                         0x701f
 #define USB_PID_PCTV_200E                                      0x020e
 #define USB_PID_PCTV_400E                                      0x020f
-
+#define USB_PID_GENPIX_8PSK_COLD                               0x0200
+#define USB_PID_GENPIX_8PSK_WARM                               0x0201
 #endif
index fead958a57e3d0758461cec8317bef45bdb41e80..4cf9f89c51bf91c48f1faebee796d9a2839e0932 100644 (file)
@@ -330,9 +330,9 @@ extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16);
 extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
 
 /* commonly used pll init and set functions */
-extern int dvb_usb_pll_init_i2c(struct dvb_frontend *);
-extern int dvb_usb_pll_set(struct dvb_frontend *, struct dvb_frontend_parameters *, u8[]);
-extern int dvb_usb_pll_set_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
+extern int dvb_usb_tuner_init_i2c(struct dvb_frontend *);
+extern int dvb_usb_tuner_calc_regs(struct dvb_frontend *, struct dvb_frontend_parameters *, u8 *buf, int buf_len);
+extern int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
 
 /* commonly used firmware download types and function */
 struct hexline {
diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
new file mode 100644 (file)
index 0000000..6ccbdc9
--- /dev/null
@@ -0,0 +1,272 @@
+/* DVB USB compliant Linux driver for the
+ *  - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "gp8psk.h"
+
+struct gp8psk_fe_state {
+       struct dvb_frontend fe;
+
+       struct dvb_usb_device *d;
+
+       u16 snr;
+
+       unsigned long next_snr_check;
+};
+
+static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
+{
+       struct gp8psk_fe_state *st = fe->demodulator_priv;
+       u8 lock;
+
+       if (gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0, 0, &lock,1))
+               return -EINVAL;
+
+       if (lock)
+               *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
+       else
+               *status = 0;
+
+       return 0;
+}
+
+/* not supported by this Frontend */
+static int gp8psk_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
+{
+       (void) fe;
+       *ber = 0;
+       return 0;
+}
+
+/* not supported by this Frontend */
+static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+{
+       (void) fe;
+       *unc = 0;
+       return 0;
+}
+
+static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+       struct gp8psk_fe_state *st = fe->demodulator_priv;
+       u8 buf[2];
+
+       if (time_after(jiffies,st->next_snr_check)) {
+               gp8psk_usb_in_op(st->d,GET_SIGNAL_STRENGTH,0,0,buf,2);
+               *snr = (int)(buf[1]) << 8 | buf[0];
+               /* snr is reported in dBu*256 */
+               /* snr / 38.4 ~= 100% strength */
+               /* snr * 17 returns 100% strength as 65535 */
+               if (*snr <= 3855)
+                       *snr = (*snr<<4) + *snr; // snr * 17
+               else
+                       *snr = 65535;
+               st->next_snr_check = jiffies + (10*HZ)/1000;
+       } else {
+               *snr = st->snr;
+       }
+       return 0;
+}
+
+static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+{
+       return gp8psk_fe_read_snr(fe, strength);
+}
+
+static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+       tune->min_delay_ms = 800;
+       return 0;
+}
+
+static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
+                                 struct dvb_frontend_parameters *fep)
+{
+       struct gp8psk_fe_state *state = fe->demodulator_priv;
+       u8 cmd[10];
+       u32 freq = fep->frequency * 1000;
+
+       cmd[4] = freq         & 0xff;
+       cmd[5] = (freq >> 8)  & 0xff;
+       cmd[6] = (freq >> 16) & 0xff;
+       cmd[7] = (freq >> 24) & 0xff;
+
+       switch(fe->ops.info.type) {
+       case FE_QPSK:
+               cmd[0] =  fep->u.qpsk.symbol_rate        & 0xff;
+               cmd[1] = (fep->u.qpsk.symbol_rate >>  8) & 0xff;
+               cmd[2] = (fep->u.qpsk.symbol_rate >> 16) & 0xff;
+               cmd[3] = (fep->u.qpsk.symbol_rate >> 24) & 0xff;
+               cmd[8] = ADV_MOD_DVB_QPSK;
+               cmd[9] = 0x03; /*ADV_MOD_FEC_XXX*/
+               break;
+       default:
+               // other modes are unsuported right now
+               cmd[0] = 0;
+               cmd[1] = 0;
+               cmd[2] = 0;
+               cmd[3] = 0;
+               cmd[8] = 0;
+               cmd[9] = 0;
+               break;
+       }
+
+       gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10);
+
+       state->next_snr_check = jiffies;
+
+       return 0;
+}
+
+static int gp8psk_fe_get_frontend(struct dvb_frontend* fe,
+                                 struct dvb_frontend_parameters *fep)
+{
+       return 0;
+}
+
+
+static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe,
+                                   struct dvb_diseqc_master_cmd *m)
+{
+       struct gp8psk_fe_state *st = fe->demodulator_priv;
+
+       deb_fe("%s\n",__FUNCTION__);
+
+       if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0,
+                       m->msg, m->msg_len)) {
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe,
+                                   fe_sec_mini_cmd_t burst)
+{
+       struct gp8psk_fe_state *st = fe->demodulator_priv;
+       u8 cmd;
+
+       deb_fe("%s\n",__FUNCTION__);
+
+       /* These commands are certainly wrong */
+       cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01;
+
+       if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0,
+                       &cmd, 0)) {
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+       struct gp8psk_fe_state* state = fe->demodulator_priv;
+
+       if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE,
+                (tone == SEC_TONE_ON), 0, NULL, 0)) {
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+       struct gp8psk_fe_state* state = fe->demodulator_priv;
+
+       if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE,
+                        voltage == SEC_VOLTAGE_18, 0, NULL, 0)) {
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd)
+{
+       struct gp8psk_fe_state* state = fe->demodulator_priv;
+       u8 cmd = sw_cmd & 0x7f;
+
+       if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0,
+                       NULL, 0)) {
+               return -EINVAL;
+       }
+       if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80),
+                       0, NULL, 0)) {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void gp8psk_fe_release(struct dvb_frontend* fe)
+{
+       struct gp8psk_fe_state *state = fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops gp8psk_fe_ops;
+
+struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d)
+{
+       struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL);
+       if (s == NULL)
+               goto error;
+
+       s->d = d;
+       memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops));
+       s->fe.demodulator_priv = s;
+
+       goto success;
+error:
+       return NULL;
+success:
+       return &s->fe;
+}
+
+
+static struct dvb_frontend_ops gp8psk_fe_ops = {
+       .info = {
+               .name                   = "Genpix 8psk-USB DVB-S",
+               .type                   = FE_QPSK,
+               .frequency_min          = 950000,
+               .frequency_max          = 2150000,
+               .frequency_stepsize     = 100,
+               .symbol_rate_min        = 1000000,
+               .symbol_rate_max        = 45000000,
+               .symbol_rate_tolerance  = 500,  /* ppm */
+               .caps = FE_CAN_INVERSION_AUTO |
+                               FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                               FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                               FE_CAN_QPSK
+       },
+
+       .release = gp8psk_fe_release,
+
+       .init = NULL,
+       .sleep = NULL,
+
+       .set_frontend = gp8psk_fe_set_frontend,
+       .get_frontend = gp8psk_fe_get_frontend,
+       .get_tune_settings = gp8psk_fe_get_tune_settings,
+
+       .read_status = gp8psk_fe_read_status,
+       .read_ber = gp8psk_fe_read_ber,
+       .read_signal_strength = gp8psk_fe_read_signal_strength,
+       .read_snr = gp8psk_fe_read_snr,
+       .read_ucblocks = gp8psk_fe_read_unc_blocks,
+
+       .diseqc_send_master_cmd = gp8psk_fe_send_diseqc_msg,
+       .diseqc_send_burst = gp8psk_fe_send_diseqc_burst,
+       .set_tone = gp8psk_fe_set_tone,
+       .set_voltage = gp8psk_fe_set_voltage,
+       .dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd,
+};
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
new file mode 100644 (file)
index 0000000..9a98f3f
--- /dev/null
@@ -0,0 +1,256 @@
+/* DVB USB compliant Linux driver for the
+ *  - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "gp8psk.h"
+
+/* debug */
+static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw";
+int dvb_usb_gp8psk_debug;
+module_param_named(debug,dvb_usb_gp8psk_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
+
+int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
+{
+       int ret = 0,try = 0;
+
+       if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+               return ret;
+
+       while (ret >= 0 && ret != blen && try < 3) {
+               ret = usb_control_msg(d->udev,
+                       usb_rcvctrlpipe(d->udev,0),
+                       req,
+                       USB_TYPE_VENDOR | USB_DIR_IN,
+                       value,index,b,blen,
+                       2000);
+               deb_info("reading number %d (ret: %d)\n",try,ret);
+               try++;
+       }
+
+       if (ret < 0 || ret != blen) {
+               warn("usb in operation failed.");
+               ret = -EIO;
+       } else
+               ret = 0;
+
+       deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
+       debug_dump(b,blen,deb_xfer);
+
+       mutex_unlock(&d->usb_mutex);
+
+       return ret;
+}
+
+int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+                            u16 index, u8 *b, int blen)
+{
+       int ret;
+
+       deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
+       debug_dump(b,blen,deb_xfer);
+
+       if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+               return ret;
+
+       if (usb_control_msg(d->udev,
+                       usb_sndctrlpipe(d->udev,0),
+                       req,
+                       USB_TYPE_VENDOR | USB_DIR_OUT,
+                       value,index,b,blen,
+                       2000) != blen) {
+               warn("usb out operation failed.");
+               ret = -EIO;
+       } else
+               ret = 0;
+       mutex_unlock(&d->usb_mutex);
+
+       return ret;
+}
+
+static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d)
+{
+       int ret;
+       const struct firmware *fw = NULL;
+       u8 *ptr, *buf;
+       if ((ret = request_firmware(&fw, bcm4500_firmware,
+                                       &d->udev->dev)) != 0) {
+               err("did not find the bcm4500 firmware file. (%s) "
+                       "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
+                       bcm4500_firmware,ret);
+               return ret;
+       }
+
+       ret = -EINVAL;
+
+       if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0))
+               goto out_rel_fw;
+
+       info("downloaidng bcm4500 firmware from file '%s'",bcm4500_firmware);
+
+       ptr = fw->data;
+       buf = kmalloc(512, GFP_KERNEL | GFP_DMA);
+
+       while (ptr[0] != 0xff) {
+               u16 buflen = ptr[0] + 4;
+               if (ptr + buflen >= fw->data + fw->size) {
+                       err("failed to load bcm4500 firmware.");
+                       goto out_free;
+               }
+               memcpy(buf, ptr, buflen);
+               if (dvb_usb_generic_write(d, buf, buflen)) {
+                       err("failed to load bcm4500 firmware.");
+                       goto out_free;
+               }
+               ptr += buflen;
+       }
+
+       ret = 0;
+
+out_free:
+       kfree(buf);
+out_rel_fw:
+       release_firmware(fw);
+
+       return ret;
+}
+
+static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       u8 status, buf;
+       if (onoff) {
+               gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
+               if (! (status & 0x01))  /* started */
+                       if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
+                               return -EINVAL;
+
+               if (! (status & 0x02)) /* BCM4500 firmware loaded */
+                       if(gp8psk_load_bcm4500fw(d))
+                               return EINVAL;
+
+               if (! (status & 0x04)) /* LNB Power */
+                       if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0,
+                                       &buf, 1))
+                               return EINVAL;
+
+               /* Set DVB mode */
+               if(gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))
+                       return -EINVAL;
+               gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
+       } else {
+               /* Turn off LNB power */
+               if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1))
+                       return EINVAL;
+               /* Turn off 8psk power */
+               if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
+                       return -EINVAL;
+
+       }
+       return 0;
+}
+
+
+static int gp8psk_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       return gp8psk_usb_out_op(d, ARM_TRANSFER, onoff, 0 , NULL, 0);
+}
+
+static int gp8psk_frontend_attach(struct dvb_usb_device *d)
+{
+       d->fe = gp8psk_fe_attach(d);
+
+       return 0;
+}
+
+static struct dvb_usb_properties gp8psk_properties;
+
+static int gp8psk_usb_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       return dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL);
+}
+
+static struct usb_device_id gp8psk_usb_table [] = {
+           { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_COLD) },
+           { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_WARM) },
+           { 0 },
+};
+MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
+
+static struct dvb_usb_properties gp8psk_properties = {
+       .caps = 0,
+
+       .usb_ctrl = CYPRESS_FX2,
+       .firmware = "dvb-usb-gp8psk-01.fw",
+
+       .streaming_ctrl   = gp8psk_streaming_ctrl,
+       .power_ctrl       = gp8psk_power_ctrl,
+       .frontend_attach  = gp8psk_frontend_attach,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+       /* parameter for the MPEG2-data transfer */
+       .urb = {
+               .type = DVB_USB_BULK,
+               .count = 7,
+               .endpoint = 0x82,
+               .u = {
+                       .bulk = {
+                               .buffersize = 8192,
+                       }
+               }
+       },
+
+       .num_device_descs = 1,
+       .devices = {
+               { .name = "Genpix 8PSK-USB DVB-S USB2.0 receiver",
+                 .cold_ids = { &gp8psk_usb_table[0], NULL },
+                 .warm_ids = { &gp8psk_usb_table[1], NULL },
+               },
+               { 0 },
+       }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver gp8psk_usb_driver = {
+       .name           = "dvb_usb_gp8psk",
+       .probe          = gp8psk_usb_probe,
+       .disconnect = dvb_usb_device_exit,
+       .id_table       = gp8psk_usb_table,
+};
+
+/* module stuff */
+static int __init gp8psk_usb_module_init(void)
+{
+       int result;
+       if ((result = usb_register(&gp8psk_usb_driver))) {
+               err("usb_register failed. (%d)",result);
+               return result;
+       }
+
+       return 0;
+}
+
+static void __exit gp8psk_usb_module_exit(void)
+{
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&gp8psk_usb_driver);
+}
+
+module_init(gp8psk_usb_module_init);
+module_exit(gp8psk_usb_module_exit);
+
+MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>");
+MODULE_DESCRIPTION("Driver for Genpix 8psk-USB DVB-S USB2.0");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h
new file mode 100644 (file)
index 0000000..3eba706
--- /dev/null
@@ -0,0 +1,79 @@
+/* DVB USB compliant Linux driver for the
+ *  - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_GP8PSK_H_
+#define _DVB_USB_GP8PSK_H_
+
+#define DVB_USB_LOG_PREFIX "gp8psk"
+#include "dvb-usb.h"
+
+extern int dvb_usb_gp8psk_debug;
+#define deb_info(args...) dprintk(dvb_usb_gp8psk_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args)
+#define deb_rc(args...)   dprintk(dvb_usb_gp8psk_debug,0x04,args)
+#define deb_fe(args...)   dprintk(dvb_usb_gp8psk_debug,0x08,args)
+/* gp8psk commands */
+
+/* Twinhan Vendor requests */
+#define TH_COMMAND_IN                     0xC0
+#define TH_COMMAND_OUT                    0xC1
+
+/* command bytes */
+#define GET_8PSK_CONFIG                 0x80
+#define SET_8PSK_CONFIG                 0x81
+#define ARM_TRANSFER                    0x85
+#define TUNE_8PSK                       0x86
+#define GET_SIGNAL_STRENGTH             0x87
+#define LOAD_BCM4500                    0x88
+#define BOOT_8PSK                       0x89
+#define START_INTERSIL                  0x8A
+#define SET_LNB_VOLTAGE                 0x8B
+#define SET_22KHZ_TONE                  0x8C
+#define SEND_DISEQC_COMMAND             0x8D
+#define SET_DVB_MODE                    0x8E
+#define SET_DN_SWITCH                   0x8F
+#define GET_SIGNAL_LOCK                 0x90
+
+/* Satellite modulation modes */
+#define ADV_MOD_DVB_QPSK 0     /* DVB-S QPSK */
+#define ADV_MOD_TURBO_QPSK 1   /* Turbo QPSK */
+#define ADV_MOD_TURBO_8PSK 2   /* Turbo 8PSK (also used for Trellis 8PSK) */
+#define ADV_MOD_TURBO_16QAM 3  /* Turbo 16QAM (also used for Trellis 8PSK) */
+
+#define ADV_MOD_DCII_C_QPSK 4  /* Digicipher II Combo */
+#define ADV_MOD_DCII_I_QPSK 5  /* Digicipher II I-stream */
+#define ADV_MOD_DCII_Q_QPSK 6  /* Digicipher II Q-stream */
+#define ADV_MOD_DCII_C_OQPSK 7 /* Digicipher II offset QPSK */
+#define ADV_MOD_DSS_QPSK 8     /* DSS (DIRECTV) QPSK */
+#define ADV_MOD_DVB_BPSK 9     /* DVB-S BPSK */
+
+#define GET_USB_SPEED                     0x07
+ #define USB_SPEED_LOW                    0
+ #define USB_SPEED_FULL                   1
+ #define USB_SPEED_HIGH                   2
+
+#define RESET_FX2                         0x13
+
+#define FW_VERSION_READ                   0x0B
+#define VENDOR_STRING_READ                0x0C
+#define PRODUCT_STRING_READ               0x0D
+#define FW_BCD_VERSION_READ               0x14
+
+extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
+extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
+extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+                            u16 index, u8 *b, int blen);
+
+#endif
index 14f1911c79bb29061817eec9ffb209083677896c..97d74da0dad88676457b01081a6d8eaa406d0371 100644 (file)
@@ -57,7 +57,6 @@ static int umt_mt352_frontend_attach(struct dvb_usb_device *d)
        memset(&umt_config,0,sizeof(struct mt352_config));
        umt_config.demod_init = umt_mt352_demod_init;
        umt_config.demod_address = 0xf;
-       umt_config.pll_set = dvb_usb_pll_set;
 
        d->fe = mt352_attach(&umt_config, &d->i2c_adap);
 
@@ -68,6 +67,7 @@ static int umt_tuner_attach (struct dvb_usb_device *d)
 {
        d->pll_addr = 0x61;
        d->pll_desc = &dvb_pll_tua6034;
+       d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
        return 0;
 }
 
index 2a89f8c5da99cf78c8af7fde74c67dd24282d0c1..d4da494132ec7814f0d818ce3fda6d21dcc9a201 100644 (file)
@@ -287,17 +287,16 @@ struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d)
                goto error;
 
        s->d = d;
-       s->fe.ops = &vp702x_fe_ops;
+
+       memcpy(&s->fe.ops,&vp702x_fe_ops,sizeof(struct dvb_frontend_ops));
        s->fe.demodulator_priv = s;
 
        s->lnb_buf[1] = SET_LNB_POWER;
        s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */
 
-       goto success;
+       return &s->fe;
 error:
        return NULL;
-success:
-       return &s->fe;
 }
 
 
index 9999336aeeb6797aaa0a6c8be91d3fbde1aafe9d..8452eef90322be8d97e9a08c81881cc47f6cf311 100644 (file)
@@ -23,8 +23,6 @@
 
 struct vp7045_fe_state {
        struct dvb_frontend fe;
-       struct dvb_frontend_ops ops;
-
        struct dvb_usb_device *d;
 };
 
@@ -151,15 +149,12 @@ struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d)
                goto error;
 
        s->d = d;
-       memcpy(&s->ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops));
-       s->fe.ops = &s->ops;
+       memcpy(&s->fe.ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops));
        s->fe.demodulator_priv = s;
 
-       goto success;
+       return &s->fe;
 error:
        return NULL;
-success:
-       return &s->fe;
 }
 
 
index 37d5e0af1683a026722e0e47110c3e4f642bf164..0ef361f0309b59b72ebe10632bae24c4fa5ecbdf 100644 (file)
@@ -157,7 +157,7 @@ config DVB_STV0297
        help
          A DVB-C tuner module. Say Y when you want to support this frontend.
 
-comment "ATSC (North American/Korean Terresterial DTV) frontends"
+comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends"
        depends on DVB_CORE
 
 config DVB_NXT200X
@@ -216,4 +216,20 @@ config DVB_LGDT330X
          An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
          to support this frontend.
 
+
+comment "Miscellaneous devices"
+       depends on DVB_CORE
+
+config DVB_LNBP21
+       tristate "LNBP21 SEC controller"
+       depends on DVB_CORE
+       help
+         An SEC control chip.
+
+config DVB_ISL6421
+       tristate "ISL6421 SEC controller"
+       depends on DVB_CORE
+       help
+         An SEC control chip.
+
 endmenu
index d09b6071fbaf23763400135137f3fcd87b64af2c..5222245c7f592573b1708102c8d56035a06950e7 100644 (file)
@@ -31,3 +31,5 @@ obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
 obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
 obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
 obj-$(CONFIG_DVB_CX24123) += cx24123.o
+obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
+obj-$(CONFIG_DVB_ISL6421) += isl6421.o
index 1708a1d4893e4a7c9a9173d88555caef7016a171..baeb311de8931b82a12bfa00dbe3513051ec8a0b 100644 (file)
@@ -48,7 +48,6 @@
 struct bcm3510_state {
 
        struct i2c_adapter* i2c;
-       struct dvb_frontend_ops ops;
        const struct bcm3510_config* config;
        struct dvb_frontend frontend;
 
@@ -791,10 +790,9 @@ struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config,
 
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
 
        mutex_init(&state->hab_mutex);
index 78573b22ada900c824d9482691a2b359eb5aa2a7..d8f65738e5d2520e05d2f6508c317fcaadfb4e1f 100644 (file)
@@ -89,12 +89,13 @@ static int alps_bsbe1_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ra
        return 0;
 }
 
-static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
+static int alps_bsbe1_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
        int ret;
        u8 data[4];
        u32 div;
        struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+       struct i2c_adapter *i2c = fe->tuner_priv;
 
        if ((params->frequency < 950000) || (params->frequency > 2150000))
                return -EINVAL;
@@ -105,6 +106,8 @@ static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c,
        data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
        data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        ret = i2c_transfer(i2c, &msg, 1);
        return (ret != 1) ? -EIO : 0;
 }
@@ -117,7 +120,6 @@ static struct stv0299_config alps_bsbe1_config = {
        .skip_reinit = 0,
        .min_delay_ms = 100,
        .set_symbol_rate = alps_bsbe1_set_symbol_rate,
-       .pll_set = alps_bsbe1_pll_set,
 };
 
 #endif
index 2a5366ce79cc2f73797b66470365347795382507..e231cd84b3a16a49f4744b1c4b86e9962bcc11a5 100644 (file)
@@ -101,11 +101,12 @@ static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ra
        return 0;
 }
 
-static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params)
+static int alps_bsru6_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
        u8 buf[4];
        u32 div;
        struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+       struct i2c_adapter *i2c = fe->tuner_priv;
 
        if ((params->frequency < 950000) || (params->frequency > 2150000))
                return -EINVAL;
@@ -119,6 +120,8 @@ static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c,
        if (params->frequency > 1530000)
                buf[3] = 0xc0;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(i2c, &msg, 1) != 1)
                return -EIO;
        return 0;
@@ -134,7 +137,6 @@ static struct stv0299_config alps_bsru6_config = {
        .volt13_op0_op1 = STV0299_VOLT13_OP1,
        .min_delay_ms = 100,
        .set_symbol_rate = alps_bsru6_set_symbol_rate,
-       .pll_set = alps_bsru6_pll_set,
 };
 
 #endif
index 755f774f6b7d4262077def4b7a22b4f5b09efec1..3c7c09a362b2ac88bf517ae1e2499fa347f97f82 100644 (file)
@@ -34,8 +34,6 @@ struct cx22700_state {
 
        struct i2c_adapter* i2c;
 
-       struct dvb_frontend_ops ops;
-
        const struct cx22700_config* config;
 
        struct dvb_frontend frontend;
@@ -247,12 +245,6 @@ static int cx22700_init (struct dvb_frontend* fe)
 
        cx22700_writereg (state, 0x00, 0x01);
 
-       if (state->config->pll_init) {
-               cx22700_writereg (state, 0x0a, 0x00);  /* open i2c bus switch */
-               state->config->pll_init(fe);
-               cx22700_writereg (state, 0x0a, 0x01);  /* close i2c bus switch */
-       }
-
        return 0;
 }
 
@@ -333,9 +325,11 @@ static int cx22700_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
        cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/
        cx22700_writereg (state, 0x00, 0x00);
 
-       cx22700_writereg (state, 0x0a, 0x00);  /* open i2c bus switch */
-       state->config->pll_set(fe, p);
-       cx22700_writereg (state, 0x0a, 0x01);  /* close i2c bus switch */
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, p);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+       }
+
        cx22700_set_inversion (state, p->inversion);
        cx22700_set_tps (state, &p->u.ofdm);
        cx22700_writereg (state, 0x37, 0x01);  /* PAL loop filter off */
@@ -353,6 +347,17 @@ static int cx22700_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
        return cx22700_get_tps (state, &p->u.ofdm);
 }
 
+static int cx22700_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+       struct cx22700_state* state = fe->demodulator_priv;
+
+       if (enable) {
+               return cx22700_writereg(state, 0x0a, 0x00);
+       } else {
+               return cx22700_writereg(state, 0x0a, 0x01);
+       }
+}
+
 static int cx22700_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
 {
        fesettings->min_delay_ms = 150;
@@ -381,13 +386,12 @@ struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &cx22700_ops, sizeof(struct dvb_frontend_ops));
 
        /* check if the demod is there */
        if (cx22700_readreg(state, 0x07) < 0) goto error;
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &cx22700_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
@@ -413,6 +417,7 @@ static struct dvb_frontend_ops cx22700_ops = {
        .release = cx22700_release,
 
        .init = cx22700_init,
+       .i2c_gate_ctrl = cx22700_i2c_gate_ctrl,
 
        .set_frontend = cx22700_set_frontend,
        .get_frontend = cx22700_get_frontend,
index c9145b45874b3214f6424b9d0cfcc4292410876d..dcd8979c1a15e2668b5a5a8a8c276b59366edbb2 100644 (file)
@@ -29,10 +29,6 @@ struct cx22700_config
 {
        /* the demodulator's i2c address */
        u8 demod_address;
-
-       /* PLL maintenance */
-       int (*pll_init)(struct dvb_frontend* fe);
-       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
index 0fc899f81c5e9be0a16b1f263a09465fc3adeb96..4106d46c957fa2e081c637790dace69827c791c1 100644 (file)
@@ -40,8 +40,6 @@ struct cx22702_state {
 
        struct i2c_adapter* i2c;
 
-       struct dvb_frontend_ops ops;
-
        /* configuration settings */
        const struct cx22702_config* config;
 
@@ -211,22 +209,10 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
        u8 val;
        struct cx22702_state* state = fe->demodulator_priv;
 
-       /* set PLL */
-       cx22702_i2c_gate_ctrl(fe, 1);
-       if (state->config->pll_set) {
-               state->config->pll_set(fe, p);
-       } else if (state->config->pll_desc) {
-               u8 pllbuf[4];
-               struct i2c_msg msg = { .addr = state->config->pll_address,
-                                      .buf = pllbuf, .len = 4 };
-               dvb_pll_configure(state->config->pll_desc, pllbuf,
-                                 p->frequency,
-                                 p->u.ofdm.bandwidth);
-               i2c_transfer(state->i2c, &msg, 1);
-       } else {
-               BUG();
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, p);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
        }
-       cx22702_i2c_gate_ctrl(fe, 0);
 
        /* set inversion */
        cx22702_set_inversion (state, p->inversion);
@@ -358,10 +344,6 @@ static int cx22702_init (struct dvb_frontend* fe)
 
        cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02);
 
-       /* init PLL */
-       if (state->config->pll_init)
-               state->config->pll_init(fe);
-
        cx22702_i2c_gate_ctrl(fe, 0);
 
        return 0;
@@ -495,7 +477,6 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
        state->prevUCBlocks = 0;
 
        /* check if the demod is there */
@@ -503,7 +484,7 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
                goto error;
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
@@ -530,6 +511,7 @@ static struct dvb_frontend_ops cx22702_ops = {
        .release = cx22702_release,
 
        .init = cx22702_init,
+       .i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
 
        .set_frontend = cx22702_set_tps,
        .get_frontend = cx22702_get_frontend,
@@ -540,7 +522,6 @@ static struct dvb_frontend_ops cx22702_ops = {
        .read_signal_strength = cx22702_read_signal_strength,
        .read_snr = cx22702_read_snr,
        .read_ucblocks = cx22702_read_ucblocks,
-       .i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
 };
 
 module_param(debug, int, 0644);
index 5633976a58f19b9e90cf5b566510c4c481df6ead..7f2f241e5d4485985cfe0c0c23ddafd489e8add5 100644 (file)
@@ -39,13 +39,6 @@ struct cx22702_config
 #define CX22702_PARALLEL_OUTPUT 0
 #define CX22702_SERIAL_OUTPUT   1
        u8 output_mode;
-
-       /* PLL maintenance */
-       u8 pll_address;
-       struct dvb_pll_desc *pll_desc;
-
-       int (*pll_init)(struct dvb_frontend* fe);
-       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
index f3edf8b517dd274c0e0bd9cfdc2405d175c72355..ce3c7398bac9ffa74168145b9b67d4eccf519c02 100644 (file)
@@ -36,8 +36,6 @@ struct cx24110_state {
 
        struct i2c_adapter* i2c;
 
-       struct dvb_frontend_ops ops;
-
        const struct cx24110_config* config;
 
        struct dvb_frontend frontend;
@@ -250,7 +248,7 @@ static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
        static const u32 bands[]={5000000UL,15000000UL,90999000UL/2};
        int i;
 
-dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
+       dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
        if (srate>90999000UL/2)
                srate=90999000UL/2;
        if (srate<500000)
@@ -366,17 +364,6 @@ static int cx24110_initfe(struct dvb_frontend* fe)
                cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);
        };
 
-       if (state->config->pll_init) state->config->pll_init(fe);
-
-       return 0;
-}
-
-static int cx24110_sleep(struct dvb_frontend *fe)
-{
-       struct cx24110_state *state = fe->demodulator_priv;
-
-       if (state->config->pll_sleep)
-                 return state->config->pll_sleep(fe);
        return 0;
 }
 
@@ -548,7 +535,12 @@ static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
 {
        struct cx24110_state *state = fe->demodulator_priv;
 
-       state->config->pll_set(fe, p);
+
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, p);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+       }
+
        cx24110_set_inversion (state, p->inversion);
        cx24110_set_fec (state, p->u.qpsk.fec_inner);
        cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate);
@@ -612,7 +604,6 @@ struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
        state->lastber = 0;
        state->lastbler = 0;
        state->lastesn0 = 0;
@@ -622,7 +613,7 @@ struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
        if ((ret != 0x5a) && (ret != 0x69)) goto error;
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
@@ -651,7 +642,6 @@ static struct dvb_frontend_ops cx24110_ops = {
        .release = cx24110_release,
 
        .init = cx24110_initfe,
-       .sleep = cx24110_sleep,
        .set_frontend = cx24110_set_frontend,
        .get_frontend = cx24110_get_frontend,
        .read_status = cx24110_read_status,
index 609ac642b406ad748c791cfd441b825460cb9080..b354a64e0e74970f728d4b5f905a24b5abb3ff75 100644 (file)
@@ -31,11 +31,6 @@ struct cx24110_config
 {
        /* the demodulator's i2c address */
        u8 demod_address;
-
-       /* PLL maintenance */
-       int (*pll_init)(struct dvb_frontend* fe);
-       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-       int (*pll_sleep)(struct dvb_frontend* fe);
 };
 
 extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
index 691dc840dcc06ee15ad125aec428c6093413ad66..f2f795cba56aec2b18fc03b0c99f8bbe32820c5d 100644 (file)
@@ -41,14 +41,12 @@ static int debug;
 struct cx24123_state
 {
        struct i2c_adapter* i2c;
-       struct dvb_frontend_ops ops;
        const struct cx24123_config* config;
 
        struct dvb_frontend frontend;
 
        u32 lastber;
        u16 snr;
-       u8  lnbreg;
 
        /* Some PLL specifics for tuning */
        u32 VCAarg;
@@ -249,29 +247,6 @@ static int cx24123_writereg(struct cx24123_state* state, int reg, int data)
        return 0;
 }
 
-static int cx24123_writelnbreg(struct cx24123_state* state, int reg, int data)
-{
-       u8 buf[] = { reg, data };
-       /* fixme: put the intersil addr int the config */
-       struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 2 };
-       int err;
-
-       if (debug>1)
-               printk("cx24123: %s:  writeln addr=0x08, reg 0x%02x, value 0x%02x\n",
-                                               __FUNCTION__,reg, data);
-
-       if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
-               printk("%s: writelnbreg error (err == %i, reg == 0x%02x,"
-                        " data == 0x%02x)\n", __FUNCTION__, err, reg, data);
-               return -EREMOTEIO;
-       }
-
-       /* cache the write, no way to read back */
-       state->lnbreg = data;
-
-       return 0;
-}
-
 static int cx24123_readreg(struct cx24123_state* state, u8 reg)
 {
        int ret;
@@ -295,11 +270,6 @@ static int cx24123_readreg(struct cx24123_state* state, u8 reg)
        return b1[0];
 }
 
-static int cx24123_readlnbreg(struct cx24123_state* state, u8 reg)
-{
-       return state->lnbreg;
-}
-
 static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion)
 {
        u8 nom_reg = cx24123_readreg(state, 0x0e);
@@ -458,8 +428,8 @@ static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate)
        u8 pll_mult;
 
        /*  check if symbol rate is within limits */
-       if ((srate > state->ops.info.symbol_rate_max) ||
-           (srate < state->ops.info.symbol_rate_min))
+       if ((srate > state->frontend.ops.info.symbol_rate_max) ||
+           (srate < state->frontend.ops.info.symbol_rate_min))
                return -EOPNOTSUPP;;
 
        /* choose the sampling rate high enough for the required operation,
@@ -687,13 +657,6 @@ static int cx24123_initfe(struct dvb_frontend* fe)
        for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
                cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
 
-       if (state->config->pll_init)
-               state->config->pll_init(fe);
-
-       /* Configure the LNB for 14V */
-       if (state->config->use_isl6421)
-               cx24123_writelnbreg(state, 0x0, 0x2a);
-
        return 0;
 }
 
@@ -702,50 +665,18 @@ static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage
        struct cx24123_state *state = fe->demodulator_priv;
        u8 val;
 
-       switch (state->config->use_isl6421) {
-
-       case 1:
+       val = cx24123_readreg(state, 0x29) & ~0x40;
 
-               val = cx24123_readlnbreg(state, 0x0);
-
-               switch (voltage) {
-               case SEC_VOLTAGE_13:
-                       dprintk("%s:  isl6421 voltage = 13V\n",__FUNCTION__);
-                       return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */
-               case SEC_VOLTAGE_18:
-                       dprintk("%s:  isl6421 voltage = 18V\n",__FUNCTION__);
-                       return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */
-               case SEC_VOLTAGE_OFF:
-                       dprintk("%s:  isl5421 voltage off\n",__FUNCTION__);
-                       return cx24123_writelnbreg(state, 0x0, val & 0x30);
-               default:
-                       return -EINVAL;
-               };
-
-       case 0:
-
-               val = cx24123_readreg(state, 0x29);
-
-               switch (voltage) {
-               case SEC_VOLTAGE_13:
-                       dprintk("%s: setting voltage 13V\n", __FUNCTION__);
-                       if (state->config->enable_lnb_voltage)
-                               state->config->enable_lnb_voltage(fe, 1);
-                       return cx24123_writereg(state, 0x29, val | 0x80);
-               case SEC_VOLTAGE_18:
-                       dprintk("%s: setting voltage 18V\n", __FUNCTION__);
-                       if (state->config->enable_lnb_voltage)
-                               state->config->enable_lnb_voltage(fe, 1);
-                       return cx24123_writereg(state, 0x29, val & 0x7f);
-               case SEC_VOLTAGE_OFF:
-                       dprintk("%s: setting voltage off\n", __FUNCTION__);
-                       if (state->config->enable_lnb_voltage)
-                               state->config->enable_lnb_voltage(fe, 0);
-                       return 0;
-               default:
-                       return -EINVAL;
-               };
-       }
+       switch (voltage) {
+       case SEC_VOLTAGE_13:
+               dprintk("%s: setting voltage 13V\n", __FUNCTION__);
+               return cx24123_writereg(state, 0x29, val | 0x80);
+       case SEC_VOLTAGE_18:
+               dprintk("%s: setting voltage 18V\n", __FUNCTION__);
+               return cx24123_writereg(state, 0x29, val & 0x7f);
+       default:
+               return -EINVAL;
+       };
 
        return 0;
 }
@@ -766,27 +697,20 @@ static void cx24123_wait_for_diseqc(struct cx24123_state *state)
 static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
 {
        struct cx24123_state *state = fe->demodulator_priv;
-       int i, val;
+       int i, val, tone;
 
        dprintk("%s:\n",__FUNCTION__);
 
-       /* check if continuous tone has been stopped */
-       if (state->config->use_isl6421)
-               val = cx24123_readlnbreg(state, 0x00) & 0x10;
-       else
-               val = cx24123_readreg(state, 0x29) & 0x10;
-
-
-       if (val) {
-               printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
-               return -ENOTSUPP;
-       }
+       /* stop continuous tone if enabled */
+       tone = cx24123_readreg(state, 0x29);
+       if (tone & 0x10)
+               cx24123_writereg(state, 0x29, tone & ~0x50);
 
        /* wait for diseqc queue ready */
        cx24123_wait_for_diseqc(state);
 
        /* select tone mode */
-       cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xf8);
+       cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
 
        for (i = 0; i < cmd->msg_len; i++)
                cx24123_writereg(state, 0x2C + i, cmd->msg[i]);
@@ -797,36 +721,33 @@ static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma
        /* wait for diseqc message to finish sending */
        cx24123_wait_for_diseqc(state);
 
+       /* restart continuous tone if enabled */
+       if (tone & 0x10) {
+               cx24123_writereg(state, 0x29, tone & ~0x40);
+       }
+
        return 0;
 }
 
 static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
 {
        struct cx24123_state *state = fe->demodulator_priv;
-       int val;
+       int val, tone;
 
        dprintk("%s:\n", __FUNCTION__);
 
-       /* check if continuous tone has been stoped */
-       if (state->config->use_isl6421)
-               val = cx24123_readlnbreg(state, 0x00) & 0x10;
-       else
-               val = cx24123_readreg(state, 0x29) & 0x10;
-
-
-       if (val) {
-               printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
-               return -ENOTSUPP;
-       }
+       /* stop continuous tone if enabled */
+       tone = cx24123_readreg(state, 0x29);
+       if (tone & 0x10)
+               cx24123_writereg(state, 0x29, tone & ~0x50);
 
+       /* wait for diseqc queue ready */
        cx24123_wait_for_diseqc(state);
 
        /* select tone mode */
-       val = cx24123_readreg(state, 0x2a) & 0xf8;
-       cx24123_writereg(state, 0x2a, val | 0x04);
-
+       cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) | 0x4);
+       msleep(30);
        val = cx24123_readreg(state, 0x29);
-
        if (burst == SEC_MINI_A)
                cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x00));
        else if (burst == SEC_MINI_B)
@@ -835,7 +756,12 @@ static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t
                return -EINVAL;
 
        cx24123_wait_for_diseqc(state);
+       cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
 
+       /* restart continuous tone if enabled */
+       if (tone & 0x10) {
+               cx24123_writereg(state, 0x29, tone & ~0x40);
+       }
        return 0;
 }
 
@@ -976,38 +902,21 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
        struct cx24123_state *state = fe->demodulator_priv;
        u8 val;
 
-       switch (state->config->use_isl6421) {
-       case 1:
-
-               val = cx24123_readlnbreg(state, 0x0);
-
-               switch (tone) {
-               case SEC_TONE_ON:
-                       dprintk("%s:  isl6421 sec tone on\n",__FUNCTION__);
-                       return cx24123_writelnbreg(state, 0x0, val | 0x10);
-               case SEC_TONE_OFF:
-                       dprintk("%s:  isl6421 sec tone off\n",__FUNCTION__);
-                       return cx24123_writelnbreg(state, 0x0, val & 0x2f);
-               default:
-                       printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
-                       return -EINVAL;
-               }
-
-       case 0:
+       /* wait for diseqc queue ready */
+       cx24123_wait_for_diseqc(state);
 
-               val = cx24123_readreg(state, 0x29);
+       val = cx24123_readreg(state, 0x29) & ~0x40;
 
-               switch (tone) {
-               case SEC_TONE_ON:
-                       dprintk("%s: setting tone on\n", __FUNCTION__);
-                       return cx24123_writereg(state, 0x29, val | 0x10);
-               case SEC_TONE_OFF:
-                       dprintk("%s: setting tone off\n",__FUNCTION__);
-                       return cx24123_writereg(state, 0x29, val & 0xef);
-               default:
-                       printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
-                       return -EINVAL;
-               }
+       switch (tone) {
+       case SEC_TONE_ON:
+               dprintk("%s: setting tone on\n", __FUNCTION__);
+               return cx24123_writereg(state, 0x29, val | 0x10);
+       case SEC_TONE_OFF:
+               dprintk("%s: setting tone off\n",__FUNCTION__);
+               return cx24123_writereg(state, 0x29, val & 0xef);
+       default:
+               printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
+               return -EINVAL;
        }
 
        return 0;
@@ -1040,10 +949,8 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
        state->lastber = 0;
        state->snr = 0;
-       state->lnbreg = 0;
        state->VCAarg = 0;
        state->VGAarg = 0;
        state->bandselectarg = 0;
@@ -1059,7 +966,7 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
        }
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
index 0c922b5e9263e3579bf0a1a0a38b53d87366a35c..9606f825935c8341f53b760e9c91f06e4146e9a8 100644 (file)
@@ -28,21 +28,8 @@ struct cx24123_config
        /* the demodulator's i2c address */
        u8 demod_address;
 
-       /*
-          cards like Hauppauge Nova-S Plus/Nova-SE2 use an Intersil ISL6421 chip
-          for LNB control, while KWorld DVB-S 100 use the LNBDC and LNBTone bits
-          from register 0x29 of the CX24123 demodulator
-       */
-       int use_isl6421;
-
-       /* PLL maintenance */
-       int (*pll_init)(struct dvb_frontend* fe);
-       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
        /* Need to set device param for start_dma */
        int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
-
-       void (*enable_lnb_voltage)(struct dvb_frontend* fe, int on);
 };
 
 extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
index c31d6df15472ed8e2164febad752bef13192797b..be1c0d3e1389e6ae4241a38fb13228330079c367 100644 (file)
@@ -38,8 +38,6 @@
 struct dib3000_state {
        struct i2c_adapter* i2c;
 
-       struct dvb_frontend_ops ops;
-
 /* configuration settings */
        struct dib3000_config config;
 
index 2d5475b5c0636d5c86df2baf16ac60723e10abd1..ec927628d2734cac2eee5ef633e5eb55de4d680e 100644 (file)
@@ -30,10 +30,6 @@ struct dib3000_config
 {
        /* the demodulator's i2c address */
        u8 demod_address;
-
-       /* PLL maintenance and the i2c address of the PLL */
-       int (*pll_init)(struct dvb_frontend *fe);
-       int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params);
 };
 
 struct dib_fe_xfer_ops
index ae589adb1c0a47b9960bb9e5a130f47dc1619fe7..7c6dc7e30900a428b5a037b0099d096dcc871156 100644 (file)
@@ -60,8 +60,9 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
        fe_code_rate_t fe_cr = FEC_NONE;
        int search_state, seq;
 
-       if (tuner && state->config.pll_set) {
-               state->config.pll_set(fe, fep);
+       if (tuner && fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, fep);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
 
                deb_setf("bandwidth: ");
                switch (ofdm->bandwidth) {
@@ -386,9 +387,6 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
 
        wr(DIB3000MB_REG_DATA_IN_DIVERSITY, DIB3000MB_DATA_DIVERSITY_IN_OFF);
 
-       if (state->config.pll_init)
-               state->config.pll_init(fe);
-
        return 0;
 }
 
@@ -707,7 +705,6 @@ struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
        /* setup the state */
        state->i2c = i2c;
        memcpy(&state->config,config,sizeof(struct dib3000_config));
-       memcpy(&state->ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
 
        /* check for the correct demod */
        if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
@@ -717,7 +714,7 @@ struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
                goto error;
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
 
        /* set the xfer operations */
index 3b303dbb61565db54ed15b4bbab810be2c622860..6c3be2529980b2de1b12bf3c7ae680fbb247e000 100644 (file)
@@ -462,8 +462,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
        int search_state,auto_val;
        u16 val;
 
-       if (tuner && state->config.pll_set) { /* initial call from dvb */
-               state->config.pll_set(fe,fep);
+       if (tuner && fe->ops.tuner_ops.set_params) { /* initial call from dvb */
+               fe->ops.tuner_ops.set_params(fe, fep);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
 
                state->last_tuned_freq = fep->frequency;
        //      if (!scanboost) {
@@ -642,9 +643,6 @@ static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode)
 
        set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF);
 
-       if (state->config.pll_init)
-               state->config.pll_init(fe);
-
        deb_info("init end\n");
        return 0;
 }
@@ -839,7 +837,6 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
        /* setup the state */
        state->i2c = i2c;
        memcpy(&state->config,config,sizeof(struct dib3000_config));
-       memcpy(&state->ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
 
        /* check for the correct demod */
        if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
@@ -859,7 +856,7 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
        }
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
 
        /* set the xfer operations */
@@ -876,6 +873,7 @@ error:
        kfree(state);
        return NULL;
 }
+EXPORT_SYMBOL(dib3000mc_attach);
 
 static struct dvb_frontend_ops dib3000mc_ops = {
 
@@ -914,5 +912,3 @@ static struct dvb_frontend_ops dib3000mc_ops = {
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(dib3000mc_attach);
index 791706ec1da39a5b4ca528a08162ee19f9f70a00..a189683454b7da0ad84cb69cccaba873bf816da1 100644 (file)
@@ -227,10 +227,10 @@ struct dvb_pll_desc dvb_pll_tua6034 = {
 EXPORT_SYMBOL(dvb_pll_tua6034);
 
 /* Infineon TUA6034
- * used in LG TDVS H061F and LG TDVS H062F
+ * used in LG TDVS-H061F, LG TDVS-H062F and LG TDVS-H064F
  */
-struct dvb_pll_desc dvb_pll_tdvs_tua6034 = {
-       .name  = "LG/Infineon TUA6034",
+struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
+       .name  = "LG TDVS-H06xF",
        .min   =  54000000,
        .max   = 863000000,
        .count = 3,
@@ -240,7 +240,7 @@ struct dvb_pll_desc dvb_pll_tdvs_tua6034 = {
                {  999999999, 44000000, 62500, 0xce, 0x04 },
        },
 };
-EXPORT_SYMBOL(dvb_pll_tdvs_tua6034);
+EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf);
 
 /* Philips FMD1216ME
  * used in Medion Hybrid PCMCIA card and USB Box
@@ -419,6 +419,19 @@ struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
 };
 EXPORT_SYMBOL(dvb_pll_thomson_fe6600);
 
+struct dvb_pll_priv {
+       /* i2c details */
+       int pll_i2c_address;
+       struct i2c_adapter *i2c;
+
+       /* the PLL descriptor */
+       struct dvb_pll_desc *pll_desc;
+
+       /* cached frequency/bandwidth */
+       u32 frequency;
+       u32 bandwidth;
+};
+
 /* ----------------------------------------------------------- */
 /* code                                                        */
 
@@ -443,7 +456,8 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
        if (debug)
                printk("pll: %s: freq=%d bw=%d | i=%d/%d\n",
                       desc->name, freq, bandwidth, i, desc->count);
-       BUG_ON(i == desc->count);
+       if (i == desc->count)
+               return -EINVAL;
 
        div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize;
        buf[0] = div >> 8;
@@ -462,6 +476,163 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
 }
 EXPORT_SYMBOL(dvb_pll_configure);
 
+static int dvb_pll_release(struct dvb_frontend *fe)
+{
+       if (fe->tuner_priv)
+               kfree(fe->tuner_priv);
+       fe->tuner_priv = NULL;
+       return 0;
+}
+
+static int dvb_pll_sleep(struct dvb_frontend *fe)
+{
+       struct dvb_pll_priv *priv = fe->tuner_priv;
+       u8 buf[4];
+       struct i2c_msg msg =
+               { .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) };
+       int i;
+       int result;
+
+       for (i = 0; i < priv->pll_desc->count; i++) {
+               if (priv->pll_desc->entries[i].limit == 0)
+                       break;
+       }
+       if (i == priv->pll_desc->count)
+               return 0;
+
+       buf[0] = 0;
+       buf[1] = 0;
+       buf[2] = priv->pll_desc->entries[i].config;
+       buf[3] = priv->pll_desc->entries[i].cb;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+               return result;
+       }
+
+       return 0;
+}
+
+static int dvb_pll_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+       struct dvb_pll_priv *priv = fe->tuner_priv;
+       u8 buf[4];
+       struct i2c_msg msg =
+               { .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) };
+       int result;
+       u32 div;
+       int i;
+       u32 bandwidth = 0;
+
+       if (priv->i2c == NULL)
+               return -EINVAL;
+
+       // DVBT bandwidth only just now
+       if (fe->ops.info.type == FE_OFDM) {
+               bandwidth = params->u.ofdm.bandwidth;
+       }
+
+       if ((result = dvb_pll_configure(priv->pll_desc, buf, params->frequency, bandwidth)) != 0)
+               return result;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+               return result;
+       }
+
+       // calculate the frequency we set it to
+       for (i = 0; i < priv->pll_desc->count; i++) {
+               if (params->frequency > priv->pll_desc->entries[i].limit)
+                       continue;
+               break;
+       }
+       div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize;
+       priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset;
+       priv->bandwidth = bandwidth;
+
+       return 0;
+}
+
+static int dvb_pll_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8 *buf, int buf_len)
+{
+       struct dvb_pll_priv *priv = fe->tuner_priv;
+       int result;
+       u32 div;
+       int i;
+       u32 bandwidth = 0;
+
+       if (buf_len < 5)
+               return -EINVAL;
+
+       // DVBT bandwidth only just now
+       if (fe->ops.info.type == FE_OFDM) {
+               bandwidth = params->u.ofdm.bandwidth;
+       }
+
+       if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params->frequency, bandwidth)) != 0)
+               return result;
+       buf[0] = priv->pll_i2c_address;
+
+       // calculate the frequency we set it to
+       for (i = 0; i < priv->pll_desc->count; i++) {
+               if (params->frequency > priv->pll_desc->entries[i].limit)
+                       continue;
+               break;
+       }
+       div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize;
+       priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset;
+       priv->bandwidth = bandwidth;
+
+       return 5;
+}
+
+static int dvb_pll_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct dvb_pll_priv *priv = fe->tuner_priv;
+       *frequency = priv->frequency;
+       return 0;
+}
+
+static int dvb_pll_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+       struct dvb_pll_priv *priv = fe->tuner_priv;
+       *bandwidth = priv->bandwidth;
+       return 0;
+}
+
+static struct dvb_tuner_ops dvb_pll_tuner_ops = {
+       .release = dvb_pll_release,
+       .sleep = dvb_pll_sleep,
+       .set_params = dvb_pll_set_params,
+       .calc_regs = dvb_pll_calc_regs,
+       .get_frequency = dvb_pll_get_frequency,
+       .get_bandwidth = dvb_pll_get_bandwidth,
+};
+
+int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc)
+{
+       struct dvb_pll_priv *priv = NULL;
+
+       priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return -ENOMEM;
+
+       priv->pll_i2c_address = pll_addr;
+       priv->i2c = i2c;
+       priv->pll_desc = desc;
+
+       memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops));
+       strncpy(fe->ops.tuner_ops.info.name, desc->name, 128);
+       fe->ops.tuner_ops.info.frequency_min = desc->min;
+       fe->ops.tuner_ops.info.frequency_min = desc->max;
+
+       fe->tuner_priv = priv;
+       return 0;
+}
+EXPORT_SYMBOL(dvb_pll_attach);
+
 MODULE_DESCRIPTION("dvb pll library");
 MODULE_AUTHOR("Gerd Knorr");
 MODULE_LICENSE("GPL");
index 2b84617849899cb5cc96d91017638ad5670f7989..66361cd188078c6361d84d255febce35d0685aa2 100644 (file)
@@ -5,6 +5,9 @@
 #ifndef __DVB_PLL_H__
 #define __DVB_PLL_H__
 
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
 struct dvb_pll_desc {
        char *name;
        u32  min;
@@ -31,7 +34,7 @@ extern struct dvb_pll_desc dvb_pll_unknown_1;
 extern struct dvb_pll_desc dvb_pll_tua6010xs;
 extern struct dvb_pll_desc dvb_pll_env57h1xd5;
 extern struct dvb_pll_desc dvb_pll_tua6034;
-extern struct dvb_pll_desc dvb_pll_tdvs_tua6034;
+extern struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf;
 extern struct dvb_pll_desc dvb_pll_tda665x;
 extern struct dvb_pll_desc dvb_pll_fmd1216me;
 extern struct dvb_pll_desc dvb_pll_tded4;
@@ -44,7 +47,18 @@ extern struct dvb_pll_desc dvb_pll_philips_td1316;
 
 extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
 
-int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
+extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
                      u32 freq, int bandwidth);
 
+/**
+ * Attach a dvb-pll to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param pll_addr i2c address of the PLL (if used).
+ * @param i2c i2c adapter to use (set to NULL if not used).
+ * @param desc dvb_pll_desc to use.
+ * @return 0 on success, nonzero on failure.
+ */
+extern int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc);
+
 #endif
index 645946a992d94b1dda65bf33e14561238ee6329f..6271b1e7f6ab94c8abdc55a35f64d9ee692223ab 100644 (file)
@@ -30,7 +30,6 @@
 
 
 struct dvb_dummy_fe_state {
-       struct dvb_frontend_ops ops;
        struct dvb_frontend frontend;
 };
 
@@ -77,6 +76,11 @@ static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_fronten
 
 static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
+       if (fe->ops->tuner_ops->set_params) {
+               fe->ops->tuner_ops->set_params(fe, p);
+               if (fe->ops->i2c_gate_ctrl) fe->ops->i2c_gate_ctrl(fe, 0);
+       }
+
        return 0;
 }
 
@@ -116,11 +120,8 @@ struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void)
        state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
        if (state == NULL) goto error;
 
-       /* setup the state */
-       memcpy(&state->ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops));
-
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
@@ -139,11 +140,8 @@ struct dvb_frontend* dvb_dummy_fe_qpsk_attach()
        state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
        if (state == NULL) goto error;
 
-       /* setup the state */
-       memcpy(&state->ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops));
-
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
@@ -162,11 +160,8 @@ struct dvb_frontend* dvb_dummy_fe_qam_attach()
        state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
        if (state == NULL) goto error;
 
-       /* setup the state */
-       memcpy(&state->ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops));
-
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
diff --git a/drivers/media/dvb/frontends/isl6421.c b/drivers/media/dvb/frontends/isl6421.c
new file mode 100644 (file)
index 0000000..58c34db
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * isl6421.h - driver for lnb supply and control ic ISL6421
+ *
+ * Copyright (C) 2006 Andrew de Quincey
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You 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.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "isl6421.h"
+
+struct isl6421 {
+       u8                      config;
+       u8                      override_or;
+       u8                      override_and;
+       struct i2c_adapter      *i2c;
+       u8                      i2c_addr;
+       void                    (*release_chain)(struct dvb_frontend* fe);
+};
+
+static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+       struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+       struct i2c_msg msg = {  .addr = isl6421->i2c_addr, .flags = 0,
+                               .buf = &isl6421->config,
+                               .len = sizeof(isl6421->config) };
+
+       isl6421->config &= ~(ISL6421_VSEL1 | ISL6421_EN1);
+
+       switch(voltage) {
+       case SEC_VOLTAGE_OFF:
+               break;
+       case SEC_VOLTAGE_13:
+               isl6421->config |= ISL6421_EN1;
+               break;
+       case SEC_VOLTAGE_18:
+               isl6421->config |= (ISL6421_EN1 | ISL6421_VSEL1);
+               break;
+       default:
+               return -EINVAL;
+       };
+
+       isl6421->config |= isl6421->override_or;
+       isl6421->config &= isl6421->override_and;
+
+       return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+       struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+       struct i2c_msg msg = {  .addr = isl6421->i2c_addr, .flags = 0,
+                               .buf = &isl6421->config,
+                               .len = sizeof(isl6421->config) };
+
+       if (arg)
+               isl6421->config |= ISL6421_LLC1;
+       else
+               isl6421->config &= ~ISL6421_LLC1;
+
+       isl6421->config |= isl6421->override_or;
+       isl6421->config &= isl6421->override_and;
+
+       return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void isl6421_release(struct dvb_frontend *fe)
+{
+       struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+
+       /* power off */
+       isl6421_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+       /* free data & call next release routine */
+       fe->ops.release = isl6421->release_chain;
+       kfree(fe->misc_priv);
+       fe->misc_priv = NULL;
+       if (fe->ops.release)
+               fe->ops.release(fe);
+}
+
+int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+                  u8 override_set, u8 override_clear)
+{
+       struct isl6421 *isl6421 = kmalloc(sizeof(struct isl6421), GFP_KERNEL);
+       if (!isl6421)
+               return -ENOMEM;
+
+       /* default configuration */
+       isl6421->config = ISL6421_ISEL1;
+       isl6421->i2c = i2c;
+       isl6421->i2c_addr = i2c_addr;
+       fe->misc_priv = isl6421;
+
+       /* bits which should be forced to '1' */
+       isl6421->override_or = override_set;
+
+       /* bits which should be forced to '0' */
+       isl6421->override_and = ~override_clear;
+
+       /* detect if it is present or not */
+       if (isl6421_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+               kfree(isl6421);
+               fe->misc_priv = NULL;
+               return -EIO;
+       }
+
+       /* install release callback */
+       isl6421->release_chain = fe->ops.release;
+       fe->ops.release = isl6421_release;
+
+       /* override frontend ops */
+       fe->ops.set_voltage = isl6421_set_voltage;
+       fe->ops.enable_high_lnb_voltage = isl6421_enable_high_lnb_voltage;
+
+       return 0;
+}
+EXPORT_SYMBOL(isl6421_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6421");
+MODULE_AUTHOR("Andrew de Quincey & Oliver Endriss");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/isl6421.h b/drivers/media/dvb/frontends/isl6421.h
new file mode 100644 (file)
index 0000000..675f80a
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * isl6421.h - driver for lnb supply and control ic ISL6421
+ *
+ * Copyright (C) 2006 Andrew de Quincey
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You 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.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef _ISL6421_H
+#define _ISL6421_H
+
+#include <linux/dvb/frontend.h>
+
+/* system register bits */
+#define ISL6421_OLF1   0x01
+#define ISL6421_EN1    0x02
+#define ISL6421_VSEL1  0x04
+#define ISL6421_LLC1   0x08
+#define ISL6421_ENT1   0x10
+#define ISL6421_ISEL1  0x20
+#define ISL6421_DCL    0x40
+
+/* override_set and override_clear control which system register bits (above) to always set & clear */
+extern int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+                         u8 override_set, u8 override_clear);
+
+#endif
index 1c7c91224472ce6f2078aadec88222eacf46dbd2..f3bc82e44a288b2381066c61683d2be93e55039d 100644 (file)
@@ -32,7 +32,6 @@
 
 struct l64781_state {
        struct i2c_adapter* i2c;
-       struct dvb_frontend_ops ops;
        const struct l64781_config* config;
        struct dvb_frontend frontend;
 
@@ -141,7 +140,10 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa
        u8 val0x06;
        int bw = p->bandwidth - BANDWIDTH_8_MHZ;
 
-       state->config->pll_set(fe, param);
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, param);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+       }
 
        if (param->inversion != INVERSION_ON &&
            param->inversion != INVERSION_OFF)
@@ -463,8 +465,6 @@ static int l64781_init(struct dvb_frontend* fe)
        /* Everything is two's complement, soft bit and CSI_OUT too */
        l64781_writereg (state, 0x1e, 0x09);
 
-       if (state->config->pll_init) state->config->pll_init(fe);
-
        /* delay a bit after first init attempt */
        if (state->first) {
                state->first = 0;
@@ -508,7 +508,6 @@ struct dvb_frontend* l64781_attach(const struct l64781_config* config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
        state->first = 1;
 
        /**
@@ -554,7 +553,7 @@ struct dvb_frontend* l64781_attach(const struct l64781_config* config,
        }
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
index 947f65f87465441f366a21312631b243bbbe50f4..83b8bc21027404563875208b3e559d2037ef287a 100644 (file)
@@ -29,10 +29,6 @@ struct l64781_config
 {
        /* the demodulator's i2c address */
        u8 demod_address;
-
-       /* PLL maintenance */
-       int (*pll_init)(struct dvb_frontend* fe);
-       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 
diff --git a/drivers/media/dvb/frontends/lg_h06xf.h b/drivers/media/dvb/frontends/lg_h06xf.h
new file mode 100644 (file)
index 0000000..754d51d
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *  lg_h06xf.h - ATSC Tuner support for LG TDVS-H06xF
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 _LG_H06XF_H_
+#define _LG_H06XF_H_
+#include "dvb-pll.h"
+
+static int lg_h06xf_pll_set(struct dvb_frontend* fe, struct i2c_adapter* i2c_adap,
+                    struct dvb_frontend_parameters* params)
+{
+       u8 buf[4];
+       struct i2c_msg msg = { .addr = 0x61, .flags = 0,
+                              .buf = buf, .len = sizeof(buf) };
+       int err;
+
+       dvb_pll_configure(&dvb_pll_lg_tdvs_h06xf, buf, params->frequency, 0);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) {
+               printk(KERN_WARNING "lg_h06xf: %s error "
+                       "(addr %02x <- %02x, err = %i)\n",
+                       __FUNCTION__, buf[0], buf[1], err);
+               if (err < 0)
+                       return err;
+               else
+                       return -EREMOTEIO;
+       }
+
+       /* Set the Auxiliary Byte. */
+       buf[0] = buf[2];
+       buf[0] &= ~0x20;
+       buf[0] |= 0x18;
+       buf[1] = 0x50;
+       msg.len = 2;
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) {
+               printk(KERN_WARNING "lg_h06xf: %s error "
+                       "(addr %02x <- %02x, err = %i)\n",
+                       __FUNCTION__, buf[0], buf[1], err);
+               if (err < 0)
+                       return err;
+               else
+                       return -EREMOTEIO;
+       }
+
+       return 0;
+}
+#endif
index 4691ac54bc1d2a8f3202fb43cae0f504d9a8ce7e..6e8ad176e1a1468f0bbb3bf197232e850361f0d6 100644 (file)
@@ -29,6 +29,7 @@
  *   DViCO FusionHDTV 5 Lite
  *   DViCO FusionHDTV 5 USB Gold
  *   Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
+ *   pcHDTV HD5500
  *
  * TODO:
  * signal strength always returns 0.
@@ -59,7 +60,6 @@ if (debug) printk(KERN_DEBUG "lgdt330x: " args); \
 struct lgdt330x_state
 {
        struct i2c_adapter* i2c;
-       struct dvb_frontend_ops ops;
 
        /* Configuration settings */
        const struct lgdt330x_config* config;
@@ -399,8 +399,10 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
        }
 
        /* Tune to the specified frequency */
-       if (state->config->pll_set)
-               state->config->pll_set(fe, param);
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, param);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+       }
 
        /* Keep track of the new frequency */
        /* FIXME this is the wrong way to do this...           */
@@ -672,6 +674,7 @@ static int lgdt3303_read_snr(struct dvb_frontend* fe, u16* snr)
 
        if (state->current_modulation == VSB_8) {
 
+               i2c_read_demod_bytes(state, 0x6e, buf, 5);
                /* Phase Tracker Mean-Square Error Register for VSB */
                noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4];
        } else {
@@ -721,16 +724,19 @@ struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
        /* Setup the state */
        state->config = config;
        state->i2c = i2c;
+
+       /* Create dvb_frontend */
        switch (config->demod_chip) {
        case LGDT3302:
-               memcpy(&state->ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
+               memcpy(&state->frontend.ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
                break;
        case LGDT3303:
-               memcpy(&state->ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops));
+               memcpy(&state->frontend.ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops));
                break;
        default:
                goto error;
        }
+       state->frontend.demodulator_priv = state;
 
        /* Verify communication with demod chip */
        if (i2c_read_demod_bytes(state, 2, buf, 1))
@@ -739,9 +745,6 @@ struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
        state->current_frequency = -1;
        state->current_modulation = -1;
 
-       /* Create dvb_frontend */
-       state->frontend.ops = &state->ops;
-       state->frontend.demodulator_priv = state;
        return &state->frontend;
 
 error:
index 2a6529cccf1afe59a1c5204b76c30dab1dc676e3..bad903c6f0f8261111a6b1d2b7dfe3bdbabb9325 100644 (file)
@@ -43,7 +43,6 @@ struct lgdt330x_config
 
        /* PLL interface */
        int (*pll_rf_set) (struct dvb_frontend* fe, int index);
-       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 
        /* Need to set device param for start_dma */
        int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c
new file mode 100644 (file)
index 0000000..e933edc
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * lnbp21.h - driver for lnb supply and control ic lnbp21
+ *
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You 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.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "lnbp21.h"
+
+struct lnbp21 {
+       u8                      config;
+       u8                      override_or;
+       u8                      override_and;
+       struct i2c_adapter      *i2c;
+       void                    (*release_chain)(struct dvb_frontend* fe);
+};
+
+static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+       struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+       struct i2c_msg msg = {  .addr = 0x08, .flags = 0,
+                               .buf = &lnbp21->config,
+                               .len = sizeof(lnbp21->config) };
+
+       lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
+
+       switch(voltage) {
+       case SEC_VOLTAGE_OFF:
+               break;
+       case SEC_VOLTAGE_13:
+               lnbp21->config |= LNBP21_EN;
+               break;
+       case SEC_VOLTAGE_18:
+               lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
+               break;
+       default:
+               return -EINVAL;
+       };
+
+       lnbp21->config |= lnbp21->override_or;
+       lnbp21->config &= lnbp21->override_and;
+
+       return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+       struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+       struct i2c_msg msg = {  .addr = 0x08, .flags = 0,
+                               .buf = &lnbp21->config,
+                               .len = sizeof(lnbp21->config) };
+
+       if (arg)
+               lnbp21->config |= LNBP21_LLC;
+       else
+               lnbp21->config &= ~LNBP21_LLC;
+
+       lnbp21->config |= lnbp21->override_or;
+       lnbp21->config &= lnbp21->override_and;
+
+       return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void lnbp21_release(struct dvb_frontend *fe)
+{
+       struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+
+       /* LNBP power off */
+       lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+       /* free data & call next release routine */
+       fe->ops.release = lnbp21->release_chain;
+       kfree(fe->misc_priv);
+       fe->misc_priv = NULL;
+       if (fe->ops.release)
+               fe->ops.release(fe);
+}
+
+int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
+{
+       struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
+       if (!lnbp21)
+               return -ENOMEM;
+
+       /* default configuration */
+       lnbp21->config = LNBP21_ISEL;
+       lnbp21->i2c = i2c;
+       fe->misc_priv = lnbp21;
+
+       /* bits which should be forced to '1' */
+       lnbp21->override_or = override_set;
+
+       /* bits which should be forced to '0' */
+       lnbp21->override_and = ~override_clear;
+
+       /* detect if it is present or not */
+       if (lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+               kfree(lnbp21);
+               fe->misc_priv = NULL;
+               return -EIO;
+       }
+
+       /* install release callback */
+       lnbp21->release_chain = fe->ops.release;
+       fe->ops.release = lnbp21_release;
+
+       /* override frontend ops */
+       fe->ops.set_voltage = lnbp21_set_voltage;
+       fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+
+       return 0;
+}
+EXPORT_SYMBOL(lnbp21_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21");
+MODULE_AUTHOR("Oliver Endriss");
+MODULE_LICENSE("GPL");
index 0dcbe61b61b1c000f1613cabc7e97d62aadaf4b4..047a4ab68c01be0a0cc0c6579eff5f0c3ec149ad 100644 (file)
@@ -27,7 +27,7 @@
 #ifndef _LNBP21_H
 #define _LNBP21_H
 
-/* system register */
+/* system register bits */
 #define LNBP21_OLF     0x01
 #define LNBP21_OTF     0x02
 #define LNBP21_EN      0x04
 #define LNBP21_ISEL    0x40
 #define LNBP21_PCL     0x80
 
-struct lnbp21 {
-       u8                      config;
-       u8                      override_or;
-       u8                      override_and;
-       struct i2c_adapter      *i2c;
-       void                    (*release_chain)(struct dvb_frontend* fe);
-};
+#include <linux/dvb/frontend.h>
 
-static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
-       struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
-       struct i2c_msg msg = {  .addr = 0x08, .flags = 0,
-                               .buf = &lnbp21->config,
-                               .len = sizeof(lnbp21->config) };
-
-       lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
-
-       switch(voltage) {
-       case SEC_VOLTAGE_OFF:
-               break;
-       case SEC_VOLTAGE_13:
-               lnbp21->config |= LNBP21_EN;
-               break;
-       case SEC_VOLTAGE_18:
-               lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
-               break;
-       default:
-               return -EINVAL;
-       };
-
-       lnbp21->config |= lnbp21->override_or;
-       lnbp21->config &= lnbp21->override_and;
-
-       return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
-{
-       struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
-       struct i2c_msg msg = {  .addr = 0x08, .flags = 0,
-                               .buf = &lnbp21->config,
-                               .len = sizeof(lnbp21->config) };
-
-       if (arg)
-               lnbp21->config |= LNBP21_LLC;
-       else
-               lnbp21->config &= ~LNBP21_LLC;
-
-       lnbp21->config |= lnbp21->override_or;
-       lnbp21->config &= lnbp21->override_and;
-
-       return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static void lnbp21_exit(struct dvb_frontend *fe)
-{
-       struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
-
-       /* LNBP power off */
-       lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
-
-       /* free data & call next release routine */
-       fe->ops->release = lnbp21->release_chain;
-       kfree(fe->misc_priv);
-       fe->misc_priv = NULL;
-       if (fe->ops->release)
-               fe->ops->release(fe);
-}
-
-static int lnbp21_init(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
-{
-       struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
-
-       if (!lnbp21)
-               return -ENOMEM;
-
-       /* default configuration */
-       lnbp21->config = LNBP21_ISEL;
-
-       /* bits which should be forced to '1' */
-       lnbp21->override_or = override_set;
-
-       /* bits which should be forced to '0' */
-       lnbp21->override_and = ~override_clear;
-
-       /* install release callback */
-       lnbp21->release_chain = fe->ops->release;
-       fe->ops->release = lnbp21_exit;
-
-       /* override frontend ops */
-       fe->ops->set_voltage = lnbp21_set_voltage;
-       fe->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
-
-       lnbp21->i2c = i2c;
-       fe->misc_priv = lnbp21;
-
-       return lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
-}
+/* override_set and override_clear control which system register bits (above) to always set & clear */
+extern int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear);
 
 #endif
index d3aea83cf218e23fff5cc841cb1178152af885c7..1ef821825641c1f725a17807f594d404f96e49b7 100644 (file)
@@ -39,7 +39,6 @@
 
 struct mt312_state {
        struct i2c_adapter* i2c;
-       struct dvb_frontend_ops ops;
        /* configuration settings */
        const struct mt312_config* config;
        struct dvb_frontend frontend;
@@ -277,12 +276,6 @@ static int mt312_initfe(struct dvb_frontend* fe)
        if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0)
                return ret;
 
-       if (state->config->pll_init) {
-               mt312_writereg(state, GPP_CTRL, 0x40);
-               state->config->pll_init(fe);
-               mt312_writereg(state, GPP_CTRL, 0x00);
-       }
-
        return 0;
 }
 
@@ -477,16 +470,16 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
 
        dprintk("%s: Freq %d\n", __FUNCTION__, p->frequency);
 
-       if ((p->frequency < fe->ops->info.frequency_min)
-           || (p->frequency > fe->ops->info.frequency_max))
+       if ((p->frequency < fe->ops.info.frequency_min)
+           || (p->frequency > fe->ops.info.frequency_max))
                return -EINVAL;
 
        if ((p->inversion < INVERSION_OFF)
            || (p->inversion > INVERSION_ON))
                return -EINVAL;
 
-       if ((p->u.qpsk.symbol_rate < fe->ops->info.symbol_rate_min)
-           || (p->u.qpsk.symbol_rate > fe->ops->info.symbol_rate_max))
+       if ((p->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min)
+           || (p->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max))
                return -EINVAL;
 
        if ((p->u.qpsk.fec_inner < FEC_NONE)
@@ -529,9 +522,10 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
                return -EINVAL;
        }
 
-       mt312_writereg(state, GPP_CTRL, 0x40);
-       state->config->pll_set(fe, p);
-       mt312_writereg(state, GPP_CTRL, 0x00);
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, p);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+       }
 
        /* sr = (u16)(sr * 256.0 / 1000000.0) */
        sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625);
@@ -578,6 +572,17 @@ static int mt312_get_frontend(struct dvb_frontend* fe,
        return 0;
 }
 
+static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+       struct mt312_state* state = fe->demodulator_priv;
+
+       if (enable) {
+               return mt312_writereg(state, GPP_CTRL, 0x40);
+       } else {
+               return mt312_writereg(state, GPP_CTRL, 0x00);
+       }
+}
+
 static int mt312_sleep(struct dvb_frontend* fe)
 {
        struct mt312_state *state = fe->demodulator_priv;
@@ -633,6 +638,7 @@ static struct dvb_frontend_ops vp310_mt312_ops = {
 
        .init = mt312_initfe,
        .sleep = mt312_sleep,
+       .i2c_gate_ctrl = mt312_i2c_gate_ctrl,
 
        .set_frontend = mt312_set_frontend,
        .get_frontend = mt312_get_frontend,
@@ -663,19 +669,22 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
 
        /* check if the demod is there */
        if (mt312_readreg(state, ID, &state->id) < 0)
                goto error;
 
+       /* create dvb_frontend */
+       memcpy(&state->frontend.ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+
        switch (state->id) {
        case ID_VP310:
-               strcpy(state->ops.info.name, "Zarlink VP310 DVB-S");
+               strcpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S");
                state->frequency = 90;
                break;
        case ID_MT312:
-               strcpy(state->ops.info.name, "Zarlink MT312 DVB-S");
+               strcpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S");
                state->frequency = 60;
                break;
        default:
@@ -683,9 +692,6 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
                goto error;
        }
 
-       /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
-       state->frontend.demodulator_priv = state;
        return &state->frontend;
 
 error:
index 074d844f01393678e2e271273f8ba54bdcd6641f..666a1bd1c244ff0752c9b79a64d5abb08c5f7d07 100644 (file)
@@ -32,10 +32,6 @@ struct mt312_config
 {
        /* the demodulator's i2c address */
        u8 demod_address;
-
-       /* PLL maintenance */
-       int (*pll_init)(struct dvb_frontend* fe);
-       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
index aaaec909ddf830f0372bdf11d19aff43a164852c..5de7376c94ce13e9501b1cda912c17a09be738e6 100644 (file)
@@ -45,7 +45,6 @@
 struct mt352_state {
        struct i2c_adapter* i2c;
        struct dvb_frontend frontend;
-       struct dvb_frontend_ops ops;
 
        /* configuration settings */
        struct mt352_config config;
@@ -286,16 +285,25 @@ static int mt352_set_parameters(struct dvb_frontend* fe,
 
        mt352_calc_nominal_rate(state, op->bandwidth, buf+4);
        mt352_calc_input_freq(state, buf+6);
-       state->config.pll_set(fe, param, buf+8);
 
-       mt352_write(fe, buf, sizeof(buf));
        if (state->config.no_tuner) {
-               /* start decoding */
+               if (fe->ops.tuner_ops.set_params) {
+                       fe->ops.tuner_ops.set_params(fe, param);
+                       if (fe->ops.i2c_gate_ctrl)
+                               fe->ops.i2c_gate_ctrl(fe, 0);
+               }
+
+               mt352_write(fe, buf, 8);
                mt352_write(fe, fsm_go, 2);
        } else {
-               /* start tuning */
-               mt352_write(fe, tuner_go, 2);
+               if (fe->ops.tuner_ops.calc_regs) {
+                       fe->ops.tuner_ops.calc_regs(fe, param, buf+8, 5);
+                       buf[8] <<= 1;
+                       mt352_write(fe, buf, sizeof(buf));
+                       mt352_write(fe, tuner_go, 2);
+               }
        }
+
        return 0;
 }
 
@@ -541,13 +549,12 @@ struct dvb_frontend* mt352_attach(const struct mt352_config* config,
        /* setup the state */
        state->i2c = i2c;
        memcpy(&state->config,config,sizeof(struct mt352_config));
-       memcpy(&state->ops, &mt352_ops, sizeof(struct dvb_frontend_ops));
 
        /* check if the demod is there */
        if (mt352_read_register(state, CHIP_ID) != ID_MT352) goto error;
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &mt352_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
index 03040cd595bb4b50a0a9cb4d1f4835d663705b02..9e7ff4b8fe5f30156dabb28c4f46408328fe1169 100644 (file)
@@ -49,12 +49,6 @@ struct mt352_config
 
        /* Initialise the demodulator and PLL. Cannot be NULL */
        int (*demod_init)(struct dvb_frontend* fe);
-
-       /* PLL setup - fill out the supplied 5 byte buffer with your PLL settings.
-        * byte0: Set to pll i2c address (nonlinux; left shifted by 1)
-        * byte1-4: PLL configuration.
-        */
-       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf);
 };
 
 extern struct dvb_frontend* mt352_attach(const struct mt352_config* config,
index 9e35353945099f69d073c24996802fa57ab53701..55671cb5255e0aa6972560638cfff7e55552334d 100644 (file)
@@ -55,7 +55,6 @@
 struct nxt200x_state {
 
        struct i2c_adapter* i2c;
-       struct dvb_frontend_ops ops;
        const struct nxt200x_config* config;
        struct dvb_frontend frontend;
 
@@ -333,17 +332,17 @@ static int nxt200x_writetuner (struct nxt200x_state* state, u8* data)
 
        dprintk("%s\n", __FUNCTION__);
 
-       dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[0], data[1], data[2], data[3]);
+       dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[1], data[2], data[3], data[4]);
 
        /* if NXT2004, write directly to tuner. if NXT2002, write through NXT chip.
         * direct write is required for Philips TUV1236D and ALPS TDHU2 */
        switch (state->demod_chip) {
                case NXT2004:
-                       if (i2c_writebytes(state, state->config->pll_address, data, 4))
+                       if (i2c_writebytes(state, data[0], data+1, 4))
                                printk(KERN_WARNING "nxt200x: error writing to tuner\n");
                        /* wait until we have a lock */
                        while (count < 20) {
-                               i2c_readbytes(state, state->config->pll_address, &buf, 1);
+                               i2c_readbytes(state, data[0], &buf, 1);
                                if (buf & 0x40)
                                        return 0;
                                msleep(100);
@@ -361,10 +360,10 @@ static int nxt200x_writetuner (struct nxt200x_state* state, u8* data)
                        nxt200x_writebytes(state, 0x34, &buf, 1);
 
                        /* write actual tuner bytes */
-                       nxt200x_writebytes(state, 0x36, data, 4);
+                       nxt200x_writebytes(state, 0x36, data+1, 4);
 
                        /* set tuner i2c address */
-                       buf = state->config->pll_address;
+                       buf = data[0] << 1;
                        nxt200x_writebytes(state, 0x35, &buf, 1);
 
                        /* write UC Opmode to begin transfer */
@@ -534,7 +533,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
                                             struct dvb_frontend_parameters *p)
 {
        struct nxt200x_state* state = fe->demodulator_priv;
-       u8 buf[4];
+       u8 buf[5];
 
        /* stop the micro first */
        nxt200x_microcontroller_stop(state);
@@ -548,7 +547,9 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
        }
 
        /* get tuning information */
-       dvb_pll_configure(state->config->pll_desc, buf, p->frequency, 0);
+       if (fe->ops.tuner_ops.calc_regs) {
+               fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
+       }
 
        /* set additional params */
        switch (p->u.vsb.modulation) {
@@ -1159,7 +1160,6 @@ struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops));
        state->initialised = 0;
 
        /* read card id */
@@ -1198,7 +1198,7 @@ struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
        }
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
index 1d9d70bc37efc06dadcc703423154cadc6243557..34d61735845be8199d3d75e3c89614250b8f57aa 100644 (file)
@@ -38,10 +38,6 @@ struct nxt200x_config
        /* the demodulator's i2c address */
        u8 demod_address;
 
-       /* tuner information */
-       u8 pll_address;
-       struct dvb_pll_desc *pll_desc;
-
        /* used to set pll input */
        int (*set_pll_input)(u8* buf, int input);
 
index a16eeba0020d8484a8a43c44032eb754e831fdba..d313d7dcf3862c6fa67e1a0b6e0cd33a9c386277 100644 (file)
@@ -33,7 +33,6 @@
 
 struct nxt6000_state {
        struct i2c_adapter* i2c;
-       struct dvb_frontend_ops ops;
        /* configuration settings */
        const struct nxt6000_config* config;
        struct dvb_frontend frontend;
@@ -207,12 +206,6 @@ static void nxt6000_setup(struct dvb_frontend* fe)
                nxt6000_writereg(state, SUB_DIAG_MODE_SEL, 0);
 
        nxt6000_writereg(state, TS_FORMAT, 0);
-
-       if (state->config->pll_init) {
-               nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01);        /* open i2c bus switch */
-               state->config->pll_init(fe);
-               nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00);        /* close i2c bus switch */
-       }
 }
 
 static void nxt6000_dump_status(struct nxt6000_state *state)
@@ -469,9 +462,10 @@ static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
        struct nxt6000_state* state = fe->demodulator_priv;
        int result;
 
-       nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01);        /* open i2c bus switch */
-       state->config->pll_set(fe, param);
-       nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00);        /* close i2c bus switch */
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, param);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+       }
 
        if ((result = nxt6000_set_bandwidth(state, param->u.ofdm.bandwidth)) < 0)
                return result;
@@ -532,6 +526,17 @@ static int nxt6000_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_fron
        return 0;
 }
 
+static int nxt6000_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+       struct nxt6000_state* state = fe->demodulator_priv;
+
+       if (enable) {
+               return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01);
+       } else {
+               return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00);
+       }
+}
+
 static struct dvb_frontend_ops nxt6000_ops;
 
 struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
@@ -546,13 +551,12 @@ struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops));
 
        /* check if the demod is there */
        if (nxt6000_readreg(state, OFDM_MSC_REV) != NXT6000ASICDEVICE) goto error;
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
@@ -584,6 +588,7 @@ static struct dvb_frontend_ops nxt6000_ops = {
        .release = nxt6000_release,
 
        .init = nxt6000_init,
+       .i2c_gate_ctrl = nxt6000_i2c_gate_ctrl,
 
        .get_tune_settings = nxt6000_fe_get_tune_settings,
 
index b7d9bead30029bbd028019bcffd75c296659897b..117031d117082009c1fab69377059f29110f7a5a 100644 (file)
@@ -31,10 +31,6 @@ struct nxt6000_config
 
        /* should clock inversion be used? */
        u8 clock_inversion:1;
-
-       /* PLL maintenance */
-       int (*pll_init)(struct dvb_frontend* fe);
-       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
index 80e0f28127b7bd44b51cb19cc1d7df730983117f..d20ab30c1e8341d37af3600a41d97bb1ff02a7c1 100644 (file)
@@ -54,7 +54,6 @@ static int debug;
 struct or51132_state
 {
        struct i2c_adapter* i2c;
-       struct dvb_frontend_ops ops;
 
        /* Configuration settings */
        const struct or51132_config* config;
@@ -106,9 +105,8 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
 {
        struct or51132_state* state = fe->demodulator_priv;
        static u8 run_buf[] = {0x7F,0x01};
-       static u8 get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00};
-       u8 rec_buf[14];
-       u8 cmd_buf[14];
+       u8 rec_buf[8];
+       u8 cmd_buf[3];
        u32 firmwareAsize, firmwareBsize;
        int i,ret;
 
@@ -157,7 +155,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
        cmd_buf[0] = 0x10;
        cmd_buf[1] = 0x10;
        cmd_buf[2] = 0x00;
-       cmd_buf[3] = 0x00;
        msleep(20); /* 20ms */
        if ((ret = i2c_writebytes(state,state->config->demod_address,
                                 cmd_buf,3))) {
@@ -167,8 +164,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
 
        cmd_buf[0] = 0x04;
        cmd_buf[1] = 0x17;
-       cmd_buf[2] = 0x00;
-       cmd_buf[3] = 0x00;
        msleep(20); /* 20ms */
        if ((ret = i2c_writebytes(state,state->config->demod_address,
                                 cmd_buf,2))) {
@@ -178,8 +173,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
 
        cmd_buf[0] = 0x00;
        cmd_buf[1] = 0x00;
-       cmd_buf[2] = 0x00;
-       cmd_buf[3] = 0x00;
        msleep(20); /* 20ms */
        if ((ret = i2c_writebytes(state,state->config->demod_address,
                                 cmd_buf,2))) {
@@ -189,7 +182,11 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
 
        for(i=0;i<4;i++) {
                msleep(20); /* 20ms */
-               get_ver_buf[4] = i+1;
+               /* Once upon a time, this command might have had something
+                  to do with getting the firmware version, but it's
+                  not used anymore:
+                  {0x04,0x00,0x30,0x00,i+1} */
+               /* Read 8 bytes, two bytes at a time */
                if ((ret = i2c_readbytes(state,state->config->demod_address,
                                        &rec_buf[i*2],2))) {
                        printk(KERN_WARNING
@@ -208,7 +205,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
        cmd_buf[0] = 0x10;
        cmd_buf[1] = 0x00;
        cmd_buf[2] = 0x00;
-       cmd_buf[3] = 0x00;
        msleep(20); /* 20ms */
        if ((ret = i2c_writebytes(state,state->config->demod_address,
                                 cmd_buf,3))) {
@@ -243,7 +239,7 @@ static int or51132_sleep(struct dvb_frontend* fe)
 static int or51132_setmode(struct dvb_frontend* fe)
 {
        struct or51132_state* state = fe->demodulator_priv;
-       unsigned char cmd_buf[4];
+       unsigned char cmd_buf[3];
 
        dprintk("setmode %d\n",(int)state->current_modulation);
        /* set operation mode in Receiver 1 register; */
@@ -263,7 +259,6 @@ static int or51132_setmode(struct dvb_frontend* fe)
        default:
                printk("setmode:Modulation set to unsupported value\n");
        };
-       cmd_buf[3] = 0x00;
        if (i2c_writebytes(state,state->config->demod_address,
                           cmd_buf,3)) {
                printk(KERN_WARNING "or51132: set_mode error 1\n");
@@ -301,7 +296,6 @@ static int or51132_setmode(struct dvb_frontend* fe)
        default:
                printk("setmode: Modulation set to unsupported value\n");
        };
-       cmd_buf[3] = 0x00;
        msleep(20); /* 20ms */
        if (i2c_writebytes(state,state->config->demod_address,
                           cmd_buf,3)) {
@@ -313,52 +307,65 @@ static int or51132_setmode(struct dvb_frontend* fe)
        return 0;
 }
 
+/* Some modulations use the same firmware.  This classifies modulations
+   by the firmware they use. */
+#define MOD_FWCLASS_UNKNOWN    0
+#define MOD_FWCLASS_VSB                1
+#define MOD_FWCLASS_QAM                2
+static int modulation_fw_class(fe_modulation_t modulation)
+{
+       switch(modulation) {
+       case VSB_8:
+               return MOD_FWCLASS_VSB;
+       case QAM_AUTO:
+       case QAM_64:
+       case QAM_256:
+               return MOD_FWCLASS_QAM;
+       default:
+               return MOD_FWCLASS_UNKNOWN;
+       }
+}
+
 static int or51132_set_parameters(struct dvb_frontend* fe,
                                  struct dvb_frontend_parameters *param)
 {
        int ret;
-       u8 buf[4];
        struct or51132_state* state = fe->demodulator_priv;
        const struct firmware *fw;
-
-       /* Change only if we are actually changing the modulation */
-       if (state->current_modulation != param->u.vsb.modulation) {
-               switch(param->u.vsb.modulation) {
-               case VSB_8:
+       const char *fwname;
+       int clock_mode;
+
+       /* Upload new firmware only if we need a different one */
+       if (modulation_fw_class(state->current_modulation) !=
+           modulation_fw_class(param->u.vsb.modulation)) {
+               switch(modulation_fw_class(param->u.vsb.modulation)) {
+               case MOD_FWCLASS_VSB:
                        dprintk("set_parameters VSB MODE\n");
-                       printk("or51132: Waiting for firmware upload(%s)...\n",
-                              OR51132_VSB_FIRMWARE);
-                       ret = request_firmware(&fw, OR51132_VSB_FIRMWARE,
-                                              &state->i2c->dev);
-                       if (ret){
-                               printk(KERN_WARNING "or51132: No firmware up"
-                                      "loaded(timeout or file not found?)\n");
-                               return ret;
-                       }
+                       fwname = OR51132_VSB_FIRMWARE;
+
                        /* Set non-punctured clock for VSB */
-                       state->config->set_ts_params(fe, 0);
+                       clock_mode = 0;
                        break;
-               case QAM_AUTO:
-               case QAM_64:
-               case QAM_256:
+               case MOD_FWCLASS_QAM:
                        dprintk("set_parameters QAM MODE\n");
-                       printk("or51132: Waiting for firmware upload(%s)...\n",
-                              OR51132_QAM_FIRMWARE);
-                       ret = request_firmware(&fw, OR51132_QAM_FIRMWARE,
-                                              &state->i2c->dev);
-                       if (ret){
-                               printk(KERN_WARNING "or51132: No firmware up"
-                                      "loaded(timeout or file not found?)\n");
-                               return ret;
-                       }
+                       fwname = OR51132_QAM_FIRMWARE;
+
                        /* Set punctured clock for QAM */
-                       state->config->set_ts_params(fe, 1);
+                       clock_mode = 1;
                        break;
                default:
-                       printk("or51132:Modulation type(%d) UNSUPPORTED\n",
+                       printk("or51132: Modulation type(%d) UNSUPPORTED\n",
                               param->u.vsb.modulation);
                        return -1;
-               };
+               }
+               printk("or51132: Waiting for firmware upload(%s)...\n",
+                      fwname);
+               ret = request_firmware(&fw, fwname, &state->i2c->dev);
+               if (ret) {
+                       printk(KERN_WARNING "or51132: No firmware up"
+                              "loaded(timeout or file not found?)\n");
+                       return ret;
+               }
                ret = or51132_load_firmware(fe, fw);
                release_firmware(fw);
                if (ret) {
@@ -367,18 +374,18 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
                        return ret;
                }
                printk("or51132: Firmware upload complete.\n");
-
+               state->config->set_ts_params(fe, clock_mode);
+       }
+       /* Change only if we are actually changing the modulation */
+       if (state->current_modulation != param->u.vsb.modulation) {
                state->current_modulation = param->u.vsb.modulation;
                or51132_setmode(fe);
        }
 
-       dvb_pll_configure(state->config->pll_desc, buf,
-                         param->frequency, 0);
-       dprintk("set_parameters tuner bytes: 0x%02x 0x%02x "
-               "0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]);
-       if (i2c_writebytes(state, state->config->pll_address ,buf, 4))
-               printk(KERN_WARNING "or51132: set_parameters error "
-                      "writing to tuner\n");
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, param);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+       }
 
        /* Set to current mode */
        or51132_setmode(fe);
@@ -388,6 +395,44 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
        return 0;
 }
 
+static int or51132_get_parameters(struct dvb_frontend* fe,
+                                 struct dvb_frontend_parameters *param)
+{
+       struct or51132_state* state = fe->demodulator_priv;
+       u8 buf[2];
+
+       /* Receiver Status */
+       buf[0]=0x04;
+       buf[1]=0x00;
+       msleep(30); /* 30ms */
+       if (i2c_writebytes(state,state->config->demod_address,buf,2)) {
+               printk(KERN_WARNING "or51132: get_parameters write error\n");
+               return -EREMOTEIO;
+       }
+       msleep(30); /* 30ms */
+       if (i2c_readbytes(state,state->config->demod_address,buf,2)) {
+               printk(KERN_WARNING "or51132: get_parameters read error\n");
+               return -EREMOTEIO;
+       }
+       switch(buf[0]) {
+               case 0x06: param->u.vsb.modulation = VSB_8; break;
+               case 0x43: param->u.vsb.modulation = QAM_64; break;
+               case 0x45: param->u.vsb.modulation = QAM_256; break;
+               default:
+                       printk(KERN_WARNING "or51132: unknown status 0x%02x\n",
+                              buf[0]);
+                       return -EREMOTEIO;
+       }
+
+       /* FIXME: Read frequency from frontend, take AFC into account */
+       param->frequency = state->current_frequency;
+
+       /* FIXME: How to read inversion setting? Receiver 6 register? */
+       param->inversion = INVERSION_AUTO;
+
+       return 0;
+}
+
 static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
        struct or51132_state* state = fe->demodulator_priv;
@@ -572,12 +617,11 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config,
        /* Setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
        state->current_frequency = -1;
        state->current_modulation = -1;
 
        /* Create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
@@ -590,7 +634,7 @@ static struct dvb_frontend_ops or51132_ops = {
 
        .info = {
                .name                   = "Oren OR51132 VSB/QAM Frontend",
-               .type                   = FE_ATSC,
+               .type                   = FE_ATSC,
                .frequency_min          = 44000000,
                .frequency_max          = 958000000,
                .frequency_stepsize     = 166666,
@@ -606,6 +650,7 @@ static struct dvb_frontend_ops or51132_ops = {
        .sleep = or51132_sleep,
 
        .set_frontend = or51132_set_parameters,
+       .get_frontend = or51132_get_parameters,
        .get_tune_settings = or51132_get_tune_settings,
 
        .read_status = or51132_read_status,
index 622cdd18381b9e40ecc887cf2d3517d53b4fda1b..89658883abf5eb65a241b9b8f14bd024f8a9738d 100644 (file)
@@ -29,8 +29,6 @@ struct or51132_config
 {
        /* The demodulator's i2c address */
        u8 demod_address;
-       u8 pll_address;
-       struct dvb_pll_desc *pll_desc;
 
        /* Need to set device param for start_dma */
        int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
index 7c3aed1f546be2609631206639271fbd6f9b178b..26bed616fabec1c1293e10b7ade29940ee443ad5 100644 (file)
@@ -54,7 +54,6 @@ static u8 cmd_buf[] = {0x04,0x01,0x50,0x80,0x06}; // ATSC
 struct or51211_state {
 
        struct i2c_adapter* i2c;
-       struct dvb_frontend_ops ops;
 
        /* Configuration settings */
        const struct or51211_config* config;
@@ -585,12 +584,11 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config,
        /* Setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
        state->initialized = 0;
        state->current_frequency = 0;
 
        /* Create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
index d69477596921909e38ab53fda4d236f979352eb8..2c2c344c4c648a3c85c92f3c7e6f8f4a98e85594 100644 (file)
@@ -38,7 +38,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 struct s5h1420_state {
        struct i2c_adapter* i2c;
-       struct dvb_frontend_ops ops;
        const struct s5h1420_config* config;
        struct dvb_frontend frontend;
 
@@ -584,7 +583,6 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
        struct s5h1420_state* state = fe->demodulator_priv;
        int frequency_delta;
        struct dvb_frontend_tune_settings fesettings;
-       u32 tmp;
 
        /* check if we should do a fast-tune */
        memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters));
@@ -596,10 +594,17 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
            (state->fec_inner == p->u.qpsk.fec_inner) &&
            (state->symbol_rate == p->u.qpsk.symbol_rate)) {
 
-               if (state->config->pll_set) {
-                       s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
-                       state->config->pll_set(fe, p, &tmp);
+               if (fe->ops.tuner_ops.set_params) {
+                       fe->ops.tuner_ops.set_params(fe, p);
+                       if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+               }
+               if (fe->ops.tuner_ops.get_frequency) {
+                       u32 tmp;
+                       fe->ops.tuner_ops.get_frequency(fe, &tmp);
+                       if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
                        s5h1420_setfreqoffset(state, p->frequency - tmp);
+               } else {
+                       s5h1420_setfreqoffset(state, 0);
                }
                return 0;
        }
@@ -646,9 +651,9 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
        s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1);
 
        /* set tuner PLL */
-       if (state->config->pll_set) {
-               s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
-               state->config->pll_set(fe, p, &tmp);
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, p);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
                s5h1420_setfreqoffset(state, 0);
        }
 
@@ -708,6 +713,17 @@ static int s5h1420_get_tune_settings(struct dvb_frontend* fe,
        return 0;
 }
 
+static int s5h1420_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+       struct s5h1420_state* state = fe->demodulator_priv;
+
+       if (enable) {
+               return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
+       } else {
+               return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
+       }
+}
+
 static int s5h1420_init (struct dvb_frontend* fe)
 {
        struct s5h1420_state* state = fe->demodulator_priv;
@@ -717,13 +733,6 @@ static int s5h1420_init (struct dvb_frontend* fe)
        msleep(10);
        s5h1420_reset(state);
 
-       /* init PLL */
-       if (state->config->pll_init) {
-               s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
-               state->config->pll_init(fe);
-               s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
-       }
-
        return 0;
 }
 
@@ -756,7 +765,6 @@ struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
        state->postlocked = 0;
        state->fclk = 88000000;
        state->tunedfreq = 0;
@@ -769,7 +777,7 @@ struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
                goto error;
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
@@ -800,6 +808,7 @@ static struct dvb_frontend_ops s5h1420_ops = {
 
        .init = s5h1420_init,
        .sleep = s5h1420_sleep,
+       .i2c_gate_ctrl = s5h1420_i2c_gate_ctrl,
 
        .set_frontend = s5h1420_set_frontend,
        .get_frontend = s5h1420_get_frontend,
index 73296f13c324b67910b8f55672395d7e63d3351a..4e39015fa67e38c17bf519e8f6b143ff81a2fb3f 100644 (file)
@@ -32,10 +32,6 @@ struct s5h1420_config
 
        /* does the inversion require inversion? */
        u8 invert:1;
-
-       /* PLL maintenance */
-       int (*pll_init)(struct dvb_frontend* fe);
-       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout);
 };
 
 extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
index 73829e647e50ad0cccb0e2f8cf6f8b18ada520ff..44ec5b9a469580b943c3f92ca1bcbfd6163f6171 100644 (file)
@@ -44,8 +44,6 @@ struct sp8870_state {
 
        struct i2c_adapter* i2c;
 
-       struct dvb_frontend_ops ops;
-
        const struct sp8870_config* config;
 
        struct dvb_frontend frontend;
@@ -262,9 +260,10 @@ static int sp8870_set_frontend_parameters (struct dvb_frontend* fe,
        sp8870_microcontroller_stop(state);
 
        // set tuner parameters
-       sp8870_writereg(state, 0x206, 0x001);
-       state->config->pll_set(fe, p);
-       sp8870_writereg(state, 0x206, 0x000);
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, p);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+       }
 
        // sample rate correction bit [23..17]
        sp8870_writereg(state, 0x0319, 0x000A);
@@ -349,13 +348,6 @@ static int sp8870_init (struct dvb_frontend* fe)
        sp8870_writereg(state, 0x0D00, 0x010);
        sp8870_writereg(state, 0x0D01, 0x000);
 
-       /* setup PLL */
-       if (state->config->pll_init) {
-               sp8870_writereg(state, 0x206, 0x001);
-               state->config->pll_init(fe);
-               sp8870_writereg(state, 0x206, 0x000);
-       }
-
        return 0;
 }
 
@@ -541,6 +533,17 @@ static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend
        return 0;
 }
 
+static int sp8870_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+       struct sp8870_state* state = fe->demodulator_priv;
+
+       if (enable) {
+               return sp8870_writereg(state, 0x206, 0x001);
+       } else {
+               return sp8870_writereg(state, 0x206, 0x000);
+       }
+}
+
 static void sp8870_release(struct dvb_frontend* fe)
 {
        struct sp8870_state* state = fe->demodulator_priv;
@@ -561,14 +564,13 @@ struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
        state->initialised = 0;
 
        /* check if the demod is there */
        if (sp8870_readreg(state, 0x0200) < 0) goto error;
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
@@ -597,6 +599,7 @@ static struct dvb_frontend_ops sp8870_ops = {
 
        .init = sp8870_init,
        .sleep = sp8870_sleep,
+       .i2c_gate_ctrl = sp8870_i2c_gate_ctrl,
 
        .set_frontend = sp8870_set_frontend,
        .get_tune_settings = sp8870_get_tune_settings,
index f3b555dbc960d39370fbb367991ad1048eec904a..93afbb969d6b57f7b54cc104fe575fc5ce4641f4 100644 (file)
@@ -31,10 +31,6 @@ struct sp8870_config
        /* the demodulator's i2c address */
        u8 demod_address;
 
-       /* PLL maintenance */
-       int (*pll_init)(struct dvb_frontend* fe);
-       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
        /* request firmware for device */
        int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
 };
index eb8a602198ca99ad6990c783f31a305c368214b8..b0a2b02f660869f2724aedb46e45c0b3e8e08a22 100644 (file)
@@ -24,7 +24,6 @@
 
 struct sp887x_state {
        struct i2c_adapter* i2c;
-       struct dvb_frontend_ops ops;
        const struct sp887x_config* config;
        struct dvb_frontend frontend;
 
@@ -208,15 +207,6 @@ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware
        /* bit 0x010: enable data valid signal */
        sp887x_writereg(state, 0xd00, 0x010);
        sp887x_writereg(state, 0x0d1, 0x000);
-
-       /* setup the PLL */
-       if (state->config->pll_init) {
-               sp887x_writereg(state, 0x206, 0x001);
-               state->config->pll_init(fe);
-               sp887x_writereg(state, 0x206, 0x000);
-       }
-
-       printk ("done.\n");
        return 0;
 };
 
@@ -362,9 +352,16 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe,
        sp887x_microcontroller_stop(state);
 
        /* setup the PLL */
-       sp887x_writereg(state, 0x206, 0x001);
-       actual_freq = state->config->pll_set(fe, p);
-       sp887x_writereg(state, 0x206, 0x000);
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, p);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+       }
+       if (fe->ops.tuner_ops.get_frequency) {
+               fe->ops.tuner_ops.get_frequency(fe, &actual_freq);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+       } else {
+               actual_freq = p->frequency;
+       }
 
        /* read status reg in order to clear <pending irqs */
        sp887x_readreg(state, 0x200);
@@ -486,6 +483,17 @@ static int sp887x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
        return 0;
 }
 
+static int sp887x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+       struct sp887x_state* state = fe->demodulator_priv;
+
+       if (enable) {
+               return sp887x_writereg(state, 0x206, 0x001);
+       } else {
+               return sp887x_writereg(state, 0x206, 0x000);
+       }
+}
+
 static int sp887x_sleep(struct dvb_frontend* fe)
 {
        struct sp887x_state* state = fe->demodulator_priv;
@@ -555,14 +563,13 @@ struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &sp887x_ops, sizeof(struct dvb_frontend_ops));
        state->initialised = 0;
 
        /* check if the demod is there */
        if (sp887x_readreg(state, 0x0200) < 0) goto error;
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &sp887x_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
@@ -589,6 +596,7 @@ static struct dvb_frontend_ops sp887x_ops = {
 
        .init = sp887x_init,
        .sleep = sp887x_sleep,
+       .i2c_gate_ctrl = sp887x_i2c_gate_ctrl,
 
        .set_frontend = sp887x_setup_frontend_parameters,
        .get_tune_settings = sp887x_get_tune_settings,
index 6a05d8f8e8cc4d4ef642188c5d87bafa0f340df4..c44b0ebdf1e220e32dd2c10a469e106ba1401c9f 100644 (file)
@@ -13,12 +13,6 @@ struct sp887x_config
        /* the demodulator's i2c address */
        u8 demod_address;
 
-       /* PLL maintenance */
-       int (*pll_init)(struct dvb_frontend* fe);
-
-       /* this should return the actual frequency tuned to */
-       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
        /* request firmware for device */
        int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
 };
index eb15676d374f1fd4aadee45345163cd094ab56c3..1ca64249010ce54d4a3fa58946695396d22ccf74 100644 (file)
@@ -32,7 +32,6 @@
 
 struct stv0297_state {
        struct i2c_adapter *i2c;
-       struct dvb_frontend_ops ops;
        const struct stv0297_config *config;
        struct dvb_frontend frontend;
 
@@ -68,19 +67,25 @@ static int stv0297_readreg(struct stv0297_state *state, u8 reg)
        int ret;
        u8 b0[] = { reg };
        u8 b1[] = { 0 };
-       struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len =
-                                 1},
-       {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
-       };
+       struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1},
+                                {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
+                              };
 
        // this device needs a STOP between the register and data
-       if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
-               dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
-               return -1;
-       }
-       if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
-               dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
-               return -1;
+       if (state->config->stop_during_read) {
+               if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
+                       dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+                       return -1;
+               }
+               if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
+                       dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+                       return -1;
+               }
+       } else {
+               if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
+                       dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+                       return -1;
+               }
        }
 
        return b1[0];
@@ -107,13 +112,20 @@ static int stv0297_readregs(struct stv0297_state *state, u8 reg1, u8 * b, u8 len
        };
 
        // this device needs a STOP between the register and data
-       if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
-               dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
-               return -1;
-       }
-       if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
-               dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
-               return -1;
+       if (state->config->stop_during_read) {
+               if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
+                       dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+                       return -1;
+               }
+               if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
+                       dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+                       return -1;
+               }
+       } else {
+               if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
+                       dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+                       return -1;
+               }
        }
 
        return 0;
@@ -276,12 +288,14 @@ static int stv0297_set_inversion(struct stv0297_state *state, fe_spectral_invers
        return 0;
 }
 
-int stv0297_enable_plli2c(struct dvb_frontend *fe)
+static int stv0297_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
        struct stv0297_state *state = fe->demodulator_priv;
 
-       stv0297_writereg(state, 0x87, 0x78);
-       stv0297_writereg(state, 0x86, 0xc8);
+       if (enable) {
+               stv0297_writereg(state, 0x87, 0x78);
+               stv0297_writereg(state, 0x86, 0xc8);
+       }
 
        return 0;
 }
@@ -296,9 +310,6 @@ static int stv0297_init(struct dvb_frontend *fe)
                stv0297_writereg(state, state->config->inittab[i], state->config->inittab[i+1]);
        msleep(200);
 
-       if (state->config->pll_init)
-               state->config->pll_init(fe);
-
        return 0;
 }
 
@@ -389,7 +400,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
        case QAM_32:
        case QAM_64:
                delay = 100;
-               sweeprate = 1500;
+               sweeprate = 1000;
                break;
 
        case QAM_128:
@@ -421,7 +432,10 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
        }
 
        stv0297_init(fe);
-       state->config->pll_set(fe, p);
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, p);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+       }
 
        /* clear software interrupts */
        stv0297_writereg(state, 0x82, 0x0);
@@ -634,7 +648,6 @@ struct dvb_frontend *stv0297_attach(const struct stv0297_config *config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &stv0297_ops, sizeof(struct dvb_frontend_ops));
        state->base_freq = 0;
 
        /* check if the demod is there */
@@ -642,7 +655,7 @@ struct dvb_frontend *stv0297_attach(const struct stv0297_config *config,
                goto error;
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &stv0297_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
@@ -668,6 +681,7 @@ static struct dvb_frontend_ops stv0297_ops = {
 
        .init = stv0297_init,
        .sleep = stv0297_sleep,
+       .i2c_gate_ctrl = stv0297_i2c_gate_ctrl,
 
        .set_frontend = stv0297_set_frontend,
        .get_frontend = stv0297_get_frontend,
@@ -684,4 +698,3 @@ MODULE_AUTHOR("Dennis Noermann and Andrew de Quincey");
 MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(stv0297_attach);
-EXPORT_SYMBOL(stv0297_enable_plli2c);
index 9e53f019db717e284cf50fd1b4f7390f2f173fe6..1da5384fb985454b06f6aa8b027dba583853338d 100644 (file)
@@ -38,13 +38,11 @@ struct stv0297_config
        /* does the "inversion" need inverted? */
        u8 invert:1;
 
-       /* PLL maintenance */
-       int (*pll_init)(struct dvb_frontend* fe);
-       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+       /* set to 1 if the device requires an i2c STOP during reading */
+       u8 stop_during_read:1;
 };
 
 extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
                                           struct i2c_adapter* i2c);
-extern int stv0297_enable_plli2c(struct dvb_frontend* fe);
 
 #endif // STV0297_H
index 5bcd00f792e63ac7dbe255223103c91b4015865e..96648a75440dc9f7972bb27a1f113faec024d7b3 100644 (file)
@@ -56,7 +56,6 @@
 
 struct stv0299_state {
        struct i2c_adapter* i2c;
-       struct dvb_frontend_ops ops;
        const struct stv0299_config* config;
        struct dvb_frontend frontend;
 
@@ -131,13 +130,6 @@ static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len
        return ret == 2 ? 0 : ret;
 }
 
-int stv0299_enable_plli2c (struct dvb_frontend* fe)
-{
-       struct stv0299_state* state = fe->demodulator_priv;
-
-       return stv0299_writeregI(state, 0x05, 0xb5);    /*  enable i2c repeater on stv0299  */
-}
-
 static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec)
 {
        dprintk ("%s\n", __FUNCTION__);
@@ -457,12 +449,6 @@ static int stv0299_init (struct dvb_frontend* fe)
        for (i=0; !(state->config->inittab[i] == 0xff && state->config->inittab[i+1] == 0xff); i+=2)
                stv0299_writeregI(state, state->config->inittab[i], state->config->inittab[i+1]);
 
-       if (state->config->pll_init) {
-               stv0299_writeregI(state, 0x05, 0xb5);   /*  enable i2c repeater on stv0299  */
-               state->config->pll_init(fe, state->i2c);
-               stv0299_writeregI(state, 0x05, 0x35);   /*  disable i2c repeater on stv0299  */
-       }
-
        return 0;
 }
 
@@ -560,9 +546,10 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
        if (state->config->invert) invval = (~invval) & 1;
        stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval);
 
-       stv0299_writeregI(state, 0x05, 0xb5);   /*  enable i2c repeater on stv0299  */
-       state->config->pll_set(fe, state->i2c, p);
-       stv0299_writeregI(state, 0x05, 0x35);   /*  disable i2c repeater on stv0299  */
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, p);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+       }
 
        stv0299_set_FEC (state, p->u.qpsk.fec_inner);
        stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
@@ -611,6 +598,19 @@ static int stv0299_sleep(struct dvb_frontend* fe)
        return 0;
 }
 
+static int stv0299_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+       struct stv0299_state* state = fe->demodulator_priv;
+
+       if (enable) {
+               stv0299_writeregI(state, 0x05, 0xb5);
+       } else {
+               stv0299_writeregI(state, 0x05, 0x35);
+       }
+       udelay(1);
+       return 0;
+}
+
 static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
 {
        struct stv0299_state* state = fe->demodulator_priv;
@@ -647,7 +647,6 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &stv0299_ops, sizeof(struct dvb_frontend_ops));
        state->initialised = 0;
        state->tuner_frequency = 0;
        state->symbol_rate = 0;
@@ -664,7 +663,7 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
        if (id != 0xa1 && id != 0x80) goto error;
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &stv0299_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
@@ -695,6 +694,7 @@ static struct dvb_frontend_ops stv0299_ops = {
 
        .init = stv0299_init,
        .sleep = stv0299_sleep,
+       .i2c_gate_ctrl = stv0299_i2c_gate_ctrl,
 
        .set_frontend = stv0299_set_frontend,
        .get_frontend = stv0299_get_frontend,
@@ -721,9 +721,8 @@ MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
 MODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver");
 MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, "
-             "Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy");
+             "Andreas Oberritter, Andrew de Quincey, Kenneth Aafly");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(stv0299_enable_plli2c);
 EXPORT_SYMBOL(stv0299_writereg);
 EXPORT_SYMBOL(stv0299_attach);
index 32c87b4c2f1375ec78c267db07cc666130eb6642..1504828e423246faf41c4c5f09a9b864344af627 100644 (file)
@@ -87,14 +87,9 @@ struct stv0299_config
 
        /* Set the symbol rate */
        int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio);
-
-       /* PLL maintenance */
-       int (*pll_init)(struct dvb_frontend *fe, struct i2c_adapter *i2c);
-       int (*pll_set)(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params);
 };
 
 extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data);
-extern int stv0299_enable_plli2c (struct dvb_frontend* fe);
 
 extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
                                           struct i2c_adapter* i2c);
index 21255cac9793e89b07a3627a076120364cb83163..e83ff2104c9b650c2e30a52118b7e291afa581f9 100644 (file)
@@ -36,7 +36,6 @@
 
 struct tda10021_state {
        struct i2c_adapter* i2c;
-       struct dvb_frontend_ops ops;
        /* configuration settings */
        const struct tda10021_config* config;
        struct dvb_frontend frontend;
@@ -90,6 +89,14 @@ static int tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data)
        return (ret != 1) ? -EREMOTEIO : 0;
 }
 
+int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data)
+{
+       struct tda10021_state* state = fe->demodulator_priv;
+
+       return tda10021_writereg(state, reg, data);
+}
+EXPORT_SYMBOL(tda10021_write_byte);
+
 static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
 {
        u8 b0 [] = { reg };
@@ -225,13 +232,6 @@ static int tda10021_init (struct dvb_frontend *fe)
 
        //Activate PLL
        tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
-
-       if (state->config->pll_init) {
-               lock_tuner(state);
-               state->config->pll_init(fe);
-               unlock_tuner(state);
-       }
-
        return 0;
 }
 
@@ -259,9 +259,10 @@ static int tda10021_set_parameters (struct dvb_frontend *fe,
 
        //printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate);
 
-       lock_tuner(state);
-       state->config->pll_set(fe, p);
-       unlock_tuner(state);
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, p);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+       }
 
        tda10021_set_symbolrate (state, p->u.qam.symbol_rate);
        tda10021_writereg (state, 0x34, state->pwm);
@@ -376,6 +377,18 @@ static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa
        return 0;
 }
 
+static int tda10021_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+       struct tda10021_state* state = fe->demodulator_priv;
+
+       if (enable) {
+               lock_tuner(state);
+       } else {
+               unlock_tuner(state);
+       }
+       return 0;
+}
+
 static int tda10021_sleep(struct dvb_frontend* fe)
 {
        struct tda10021_state* state = fe->demodulator_priv;
@@ -407,7 +420,6 @@ struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
        state->pwm = pwm;
        state->reg0 = tda10021_inittab[0];
 
@@ -415,7 +427,7 @@ struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
        if ((tda10021_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
@@ -448,6 +460,7 @@ static struct dvb_frontend_ops tda10021_ops = {
 
        .init = tda10021_init,
        .sleep = tda10021_sleep,
+       .i2c_gate_ctrl = tda10021_i2c_gate_ctrl,
 
        .set_frontend = tda10021_set_parameters,
        .get_frontend = tda10021_get_frontend,
index 53be939e8c5583e679f09e5afd25134224d22aab..b1df4259bee9f4d7c16a0030d34f04e062517dcf 100644 (file)
@@ -30,13 +30,11 @@ struct tda10021_config
 {
        /* the demodulator's i2c address */
        u8 demod_address;
-
-       /* PLL maintenance */
-       int (*pll_init)(struct dvb_frontend* fe);
-       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
                                            struct i2c_adapter* i2c, u8 pwm);
 
+extern int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data);
+
 #endif // TDA10021_H
index b83dafa4e12cdcc79a023fe683f1394eeb05de72..59a2ed614fca4046d4bd2474851f5f2552ac55c3 100644 (file)
@@ -47,7 +47,6 @@ enum tda1004x_demod {
 
 struct tda1004x_state {
        struct i2c_adapter* i2c;
-       struct dvb_frontend_ops ops;
        const struct tda1004x_config* config;
        struct dvb_frontend frontend;
 
@@ -600,13 +599,6 @@ static int tda10045_init(struct dvb_frontend* fe)
 
        tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC
 
-       // Init the PLL
-       if (state->config->pll_init) {
-               tda1004x_enable_tuner_i2c(state);
-               state->config->pll_init(fe);
-               tda1004x_disable_tuner_i2c(state);
-       }
-
        // tda setup
        tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
        tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream
@@ -635,16 +627,6 @@ static int tda10046_init(struct dvb_frontend* fe)
                        return -EIO;
        }
 
-       // Init the tuner PLL
-       if (state->config->pll_init) {
-               tda1004x_enable_tuner_i2c(state);
-               if (state->config->pll_init(fe)) {
-                       printk(KERN_ERR "tda1004x: pll init failed\n");
-                       return  -EIO;
-               }
-               tda1004x_disable_tuner_i2c(state);
-       }
-
        // tda setup
        tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
        tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87);    // 100 ppm crystal, select HP stream
@@ -712,12 +694,10 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
        }
 
        // set frequency
-       tda1004x_enable_tuner_i2c(state);
-       if (state->config->pll_set(fe, fe_params)) {
-               printk(KERN_ERR "tda1004x: pll set failed\n");
-               return  -EIO;
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, fe_params);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
        }
-       tda1004x_disable_tuner_i2c(state);
 
        // Hardcoded to use auto as much as possible on the TDA10045 as it
        // is very unreliable if AUTO mode is _not_ used.
@@ -1183,16 +1163,6 @@ static int tda1004x_sleep(struct dvb_frontend* fe)
                break;
 
        case TDA1004X_DEMOD_TDA10046:
-               if (state->config->pll_sleep != NULL) {
-                       tda1004x_enable_tuner_i2c(state);
-                       state->config->pll_sleep(fe);
-                       if (state->config->if_freq != TDA10046_FREQ_052) {
-                               /* special hack for Philips EUROPA Based boards:
-                                * keep the I2c bridge open for tuner access in analog mode
-                                */
-                               tda1004x_disable_tuner_i2c(state);
-                       }
-               }
                /* set outputs to tristate */
                tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff);
                tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
@@ -1202,6 +1172,17 @@ static int tda1004x_sleep(struct dvb_frontend* fe)
        return 0;
 }
 
+static int tda1004x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+       struct tda1004x_state* state = fe->demodulator_priv;
+
+       if (enable) {
+               return tda1004x_enable_tuner_i2c(state);
+       } else {
+               return tda1004x_disable_tuner_i2c(state);
+       }
+}
+
 static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
 {
        fesettings->min_delay_ms = 800;
@@ -1235,6 +1216,7 @@ static struct dvb_frontend_ops tda10045_ops = {
 
        .init = tda10045_init,
        .sleep = tda1004x_sleep,
+       .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
 
        .set_frontend = tda1004x_set_fe,
        .get_frontend = tda1004x_get_fe,
@@ -1260,7 +1242,6 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
        state->demod_type = TDA1004X_DEMOD_TDA10045;
 
        /* check if the demod is there */
@@ -1270,7 +1251,7 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
        }
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 }
@@ -1293,6 +1274,7 @@ static struct dvb_frontend_ops tda10046_ops = {
 
        .init = tda10046_init,
        .sleep = tda1004x_sleep,
+       .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
 
        .set_frontend = tda1004x_set_fe,
        .get_frontend = tda1004x_get_fe,
@@ -1318,7 +1300,6 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
        state->demod_type = TDA1004X_DEMOD_TDA10046;
 
        /* check if the demod is there */
@@ -1328,7 +1309,7 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
        }
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 }
index cc0c4af64067037312fde708aef5dea56c9b5459..b877b23ed734e07398f2ac9d2ee5d2ef58508fc0 100644 (file)
@@ -66,11 +66,6 @@ struct tda1004x_config
        /* AGC configuration */
        enum tda10046_agc agc_config;
 
-       /* PLL maintenance */
-       int (*pll_init)(struct dvb_frontend* fe);
-       void (*pll_sleep)(struct dvb_frontend* fe);
-       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
        /* request firmware for device */
        /* set this to NULL if the card has a firmware EEPROM */
        int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
index 91baa9cedd79846c90d58db1e4c12ee23551bb10..3aa45ebbac3da34252cb40d42f11c73f53abf7e6 100644 (file)
@@ -37,7 +37,6 @@
 
 struct tda8083_state {
        struct i2c_adapter* i2c;
-       struct dvb_frontend_ops ops;
        /* configuration settings */
        const struct tda8083_config* config;
        struct dvb_frontend frontend;
@@ -293,7 +292,11 @@ static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
 {
        struct tda8083_state* state = fe->demodulator_priv;
 
-       state->config->pll_set(fe, p);
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, p);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+       }
+
        tda8083_set_inversion (state, p->inversion);
        tda8083_set_fec (state, p->u.qpsk.fec_inner);
        tda8083_set_symbolrate (state, p->u.qpsk.symbol_rate);
@@ -334,8 +337,6 @@ static int tda8083_init(struct dvb_frontend* fe)
        for (i=0; i<44; i++)
                tda8083_writereg (state, i, tda8083_init_tab[i]);
 
-       if (state->config->pll_init) state->config->pll_init(fe);
-
        tda8083_writereg (state, 0x00, 0x3c);
        tda8083_writereg (state, 0x00, 0x04);
 
@@ -395,13 +396,12 @@ struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &tda8083_ops, sizeof(struct dvb_frontend_ops));
 
        /* check if the demod is there */
        if ((tda8083_readreg(state, 0x00)) != 0x05) goto error;
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &tda8083_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
index 466663307bf173693fb5cf94fd9269002a573455..e7a48f61ea2c6382e2e272f7f1b37f5e3c58d813 100644 (file)
@@ -33,10 +33,6 @@ struct tda8083_config
 {
        /* the demodulator's i2c address */
        u8 demod_address;
-
-       /* PLL maintenance */
-       int (*pll_init)(struct dvb_frontend* fe);
-       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
index ad8647a3c85e69c6caa321e2d2a334afa6e54526..6bffe85c161cd1b54cbba3758c7402879e079fb6 100644 (file)
@@ -35,7 +35,6 @@
 
 struct ves1820_state {
        struct i2c_adapter* i2c;
-       struct dvb_frontend_ops ops;
        /* configuration settings */
        const struct ves1820_config* config;
        struct dvb_frontend frontend;
@@ -204,9 +203,6 @@ static int ves1820_init(struct dvb_frontend* fe)
 
        ves1820_writereg(state, 0x34, state->pwm);
 
-       if (state->config->pll_init)
-               state->config->pll_init(fe);
-
        return 0;
 }
 
@@ -223,7 +219,11 @@ static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_p
        if (real_qam < 0 || real_qam > 4)
                return -EINVAL;
 
-       state->config->pll_set(fe, p);
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, p);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+       }
+
        ves1820_set_symbolrate(state, p->u.qam.symbol_rate);
        ves1820_writereg(state, 0x34, state->pwm);
 
@@ -380,7 +380,6 @@ struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
                goto error;
 
        /* setup the state */
-       memcpy(&state->ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
        state->reg0 = ves1820_inittab[0];
        state->config = config;
        state->i2c = i2c;
@@ -393,12 +392,12 @@ struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
        if (verbose)
                printk("ves1820: pwm=0x%02x\n", state->pwm);
 
-       state->ops.info.symbol_rate_min = (state->config->xin / 2) / 64;      /* SACLK/64 == (XIN/2)/64 */
-       state->ops.info.symbol_rate_max = (state->config->xin / 2) / 4;       /* SACLK/4 */
-
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
+       state->frontend.ops.info.symbol_rate_min = (state->config->xin / 2) / 64;      /* SACLK/64 == (XIN/2)/64 */
+       state->frontend.ops.info.symbol_rate_max = (state->config->xin / 2) / 4;       /* SACLK/4 */
        state->frontend.demodulator_priv = state;
+
        return &state->frontend;
 
 error:
index 355f130b1be8e13f35454c81c7c7ad459253b998..520f09522fbbd0bc7604738ea61c366801aef75c 100644 (file)
@@ -39,10 +39,6 @@ struct ves1820_config
 
        /* SELAGC control */
        u8 selagc:1;
-
-       /* PLL maintenance */
-       int (*pll_init)(struct dvb_frontend* fe);
-       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
index 821df8e839d056669d594ac1bcf47adb7d65e9b1..54d7b07571b8e3ac23482a5ad2acd9eb9704dd45 100644 (file)
@@ -36,7 +36,6 @@
 
 struct ves1x93_state {
        struct i2c_adapter* i2c;
-       struct dvb_frontend_ops ops;
        /* configuration settings */
        const struct ves1x93_config* config;
        struct dvb_frontend frontend;
@@ -278,12 +277,6 @@ static int ves1x93_init (struct dvb_frontend* fe)
                }
        }
 
-       if (state->config->pll_init) {
-               ves1x93_writereg(state, 0x00, 0x11);
-               state->config->pll_init(fe);
-               ves1x93_writereg(state, 0x00, 0x01);
-       }
-
        return 0;
 }
 
@@ -395,9 +388,10 @@ static int ves1x93_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
 {
        struct ves1x93_state* state = fe->demodulator_priv;
 
-       ves1x93_writereg(state, 0x00, 0x11);
-       state->config->pll_set(fe, p);
-       ves1x93_writereg(state, 0x00, 0x01);
+       if (fe->ops.tuner_ops.set_params) {
+               fe->ops.tuner_ops.set_params(fe, p);
+               if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+       }
        ves1x93_set_inversion (state, p->inversion);
        ves1x93_set_fec (state, p->u.qpsk.fec_inner);
        ves1x93_set_symbolrate (state, p->u.qpsk.symbol_rate);
@@ -442,6 +436,17 @@ static void ves1x93_release(struct dvb_frontend* fe)
        kfree(state);
 }
 
+static int ves1x93_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+       struct ves1x93_state* state = fe->demodulator_priv;
+
+       if (enable) {
+               return ves1x93_writereg(state, 0x00, 0x11);
+       } else {
+               return ves1x93_writereg(state, 0x00, 0x01);
+       }
+}
+
 static struct dvb_frontend_ops ves1x93_ops;
 
 struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
@@ -457,7 +462,6 @@ struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops));
        state->inversion = INVERSION_OFF;
 
        /* check if the demod is there + identify it */
@@ -492,7 +496,7 @@ struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
        }
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 
@@ -523,6 +527,7 @@ static struct dvb_frontend_ops ves1x93_ops = {
 
        .init = ves1x93_init,
        .sleep = ves1x93_sleep,
+       .i2c_gate_ctrl = ves1x93_i2c_gate_ctrl,
 
        .set_frontend = ves1x93_set_frontend,
        .get_frontend = ves1x93_get_frontend,
index 1627e37c57a4681c20da0d42e6eafafc4439cb98..ba88ae0855c994025b4a13c5e07ae65ab919bca7 100644 (file)
@@ -38,10 +38,6 @@ struct ves1x93_config
 
        /* should PWM be inverted? */
        u8 invert_pwm:1;
-
-       /* PLL maintenance */
-       int (*pll_init)(struct dvb_frontend* fe);
-       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
index d7d9f59d76d2be53de299ad63f6e2d85caa43520..2b95e8b6cd3973dd8613f3edbe47e97c5b4871f4 100644 (file)
@@ -34,7 +34,6 @@
 struct zl10353_state {
        struct i2c_adapter *i2c;
        struct dvb_frontend frontend;
-       struct dvb_frontend_ops ops;
 
        struct zl10353_config config;
 };
@@ -126,6 +125,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
                                  struct dvb_frontend_parameters *param)
 {
        struct zl10353_state *state = fe->demodulator_priv;
+
        u8 pllbuf[6] = { 0x67 };
 
        /* These settings set "auto-everything" and start the FSM. */
@@ -142,7 +142,30 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
        zl10353_single_write(fe, 0x66, 0xE9);
        zl10353_single_write(fe, 0x62, 0x0A);
 
-       state->config.pll_set(fe, param, pllbuf + 1);
+       // if there is no attached secondary tuner, we call set_params to program
+       // a potential tuner attached somewhere else
+       if (state->config.no_tuner) {
+               if (fe->ops.tuner_ops.set_params) {
+                       fe->ops.tuner_ops.set_params(fe, param);
+                       if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+               }
+       }
+
+       // if pllbuf is defined, retrieve the settings
+       if (fe->ops.tuner_ops.calc_regs) {
+               fe->ops.tuner_ops.calc_regs(fe, param, pllbuf+1, 5);
+               pllbuf[1] <<= 1;
+       } else {
+               // fake pllbuf settings
+               pllbuf[1] = 0x61 << 1;
+               pllbuf[2] = 0;
+               pllbuf[3] = 0;
+               pllbuf[3] = 0;
+               pllbuf[4] = 0;
+       }
+
+       // there is no call to _just_ start decoding, so we send the pllbuf anyway
+       // even if there isn't a PLL attached to the secondary bus
        zl10353_write(fe, pllbuf, sizeof(pllbuf));
 
        zl10353_single_write(fe, 0x70, 0x01);
@@ -254,14 +277,13 @@ struct dvb_frontend *zl10353_attach(const struct zl10353_config *config,
        /* setup the state */
        state->i2c = i2c;
        memcpy(&state->config, config, sizeof(struct zl10353_config));
-       memcpy(&state->ops, &zl10353_ops, sizeof(struct dvb_frontend_ops));
 
        /* check if the demod is there */
        if (zl10353_read_register(state, CHIP_ID) != ID_ZL10353)
                goto error;
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &zl10353_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
 
        return &state->frontend;
index 5cc4ae718d8c2a68e98b5b6dc9b545115ddfb479..9770cb840cfccbfc4ae96657201a69fbcb112455 100644 (file)
@@ -29,10 +29,8 @@ struct zl10353_config
        /* demodulator's I2C address */
        u8 demod_address;
 
-       /* function which configures the PLL buffer (for secondary I2C
-        * connected tuner) or tunes the PLL (for direct connected tuner) */
-       int (*pll_set)(struct dvb_frontend *fe,
-                      struct dvb_frontend_parameters *params, u8 *pllbuf);
+       /* set if no pll is connected to the secondary i2c bus */
+       int no_tuner;
 };
 
 extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
index 1c5316e209efc9993ccc4d4def81e3032e6142e6..acabea0793b6d08ab7845bad4d9d08fec2212298 100644 (file)
@@ -424,8 +424,8 @@ static inline u32 divide(u32 numerator, u32 denominator)
 }
 
 /* LG Innotek TDTE-E001P (Infineon TUA6034) */
-static int lg_tdtpe001p_pll_set(struct dvb_frontend *fe,
-                               struct dvb_frontend_parameters *p)
+static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe,
+                                        struct dvb_frontend_parameters *p)
 {
        struct pluto *pluto = frontend_to_pluto(fe);
        struct i2c_msg msg;
@@ -473,6 +473,8 @@ static int lg_tdtpe001p_pll_set(struct dvb_frontend *fe,
        msg.buf = buf;
        msg.len = sizeof(buf);
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        ret = i2c_transfer(&pluto->i2c_adap, &msg, 1);
        if (ret < 0)
                return ret;
@@ -497,8 +499,6 @@ static struct tda1004x_config pluto2_fe_config __devinitdata = {
        .xtal_freq = TDA10046_XTAL_16M,
        .agc_config = TDA10046_AGC_DEFAULT,
        .if_freq = TDA10046_FREQ_3617,
-       .pll_set = lg_tdtpe001p_pll_set,
-       .pll_sleep = NULL,
        .request_firmware = pluto2_request_firmware,
 };
 
@@ -511,11 +511,12 @@ static int __devinit frontend_init(struct pluto *pluto)
                dev_err(&pluto->pdev->dev, "could not attach frontend\n");
                return -ENODEV;
        }
+       pluto->fe->ops.tuner_ops.set_params = lg_tdtpe001p_tuner_set_params;
 
        ret = dvb_register_frontend(&pluto->dvb_adapter, pluto->fe);
        if (ret < 0) {
-               if (pluto->fe->ops->release)
-                       pluto->fe->ops->release(pluto->fe);
+               if (pluto->fe->ops.release)
+                       pluto->fe->ops.release(pluto->fe);
                return ret;
        }
 
@@ -647,7 +648,7 @@ static int __devinit pluto2_probe(struct pci_dev *pdev,
                goto err_pluto_hw_exit;
 
        /* dvb */
-       ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE);
+       ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE, &pdev->dev);
        if (ret < 0)
                goto err_i2c_bit_del_bus;
 
index b5ac7dfde52f745aef95da9cc167d9b5562fee22..987881fa988ccaba688bd6b08c6ac89e4222e8fc 100644 (file)
@@ -10,6 +10,7 @@ config DVB_AV7110
        select DVB_SP8870
        select DVB_STV0297
        select DVB_L64781
+       select DVB_LNBP21
        help
          Support for SAA7146 and AV7110 based DVB cards as produced
          by Fujitsu-Siemens, Technotrend, Hauppauge and others.
@@ -67,6 +68,7 @@ config DVB_BUDGET
        select DVB_TDA8083
        select DVB_TDA10021
        select DVB_S5H1420
+       select DVB_LNBP21
        help
          Support for simple SAA7146 based DVB cards
          (so called Budget- or Nova-PCI cards) without onboard
@@ -84,6 +86,7 @@ config DVB_BUDGET_CI
        select DVB_STV0297
        select DVB_STV0299
        select DVB_TDA1004X
+       select DVB_LNBP21
        help
          Support for simple SAA7146 based DVB cards
          (so called Budget- or Nova-PCI cards) without onboard
index a690730ac39d831054956e4a953ce560e18b7486..aa85ecdc6c8079965f8bd8db54288c064a2c2df5 100644 (file)
@@ -15,9 +15,9 @@ EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 
 hostprogs-y    := fdump
 
-ifdef CONFIG_DVB_AV7110_FIRMWARE
-$(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h
+ifeq ($(CONFIG_DVB_AV7110_FIRMWARE),y)
+$(obj)/av7110.o: $(obj)/av7110_firm.h
 
-$(obj)/av7110_firm.h:
+$(obj)/av7110_firm.h: $(obj)/fdump
        $(obj)/fdump $(CONFIG_DVB_AV7110_FIRMWARE_FILE) dvb_ttpci_fw $@
 endif
index d028245c8eede256eee4fdd6de60610ea266816f..8832f80c05f7a92b7a5a5af8cf4d5fc8af4006ee 100644 (file)
@@ -1552,7 +1552,7 @@ static int get_firmware(struct av7110* av7110)
 #endif
 
 
-static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
        struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
        u8 pwr = 0;
@@ -1575,6 +1575,8 @@ static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
        // NOTE: since we're using a prescaler of 2, we set the
        // divisor frequency to 62.5kHz and divide by 125 above
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
                return -EIO;
        return 0;
@@ -1584,10 +1586,9 @@ static struct ves1x93_config alps_bsrv2_config = {
        .demod_address = 0x08,
        .xin = 90100000UL,
        .invert_pwm = 0,
-       .pll_set = alps_bsrv2_pll_set,
 };
 
-static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
        struct av7110* av7110 = fe->dvb->priv;
        u32 div;
@@ -1601,6 +1602,8 @@ static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
        data[2] = 0x85 | ((div >> 10) & 0x60);
        data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
                return -EIO;
        return 0;
@@ -1611,14 +1614,12 @@ static struct ves1820_config alps_tdbe2_config = {
        .xin = 57840000UL,
        .invert = 1,
        .selagc = VES1820_SELAGC_SIGNAMPERR,
-       .pll_set = alps_tdbe2_pll_set,
 };
 
 
 
 
-static int grundig_29504_451_pll_set(struct dvb_frontend* fe,
-                                    struct dvb_frontend_parameters* params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
        struct av7110* av7110 = fe->dvb->priv;
        u32 div;
@@ -1631,6 +1632,8 @@ static int grundig_29504_451_pll_set(struct dvb_frontend* fe,
        data[2] = 0x8e;
        data[3] = 0x00;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
                return -EIO;
        return 0;
@@ -1638,13 +1641,11 @@ static int grundig_29504_451_pll_set(struct dvb_frontend* fe,
 
 static struct tda8083_config grundig_29504_451_config = {
        .demod_address = 0x68,
-       .pll_set = grundig_29504_451_pll_set,
 };
 
 
 
-static int philips_cd1516_pll_set(struct dvb_frontend* fe,
-                                 struct dvb_frontend_parameters* params)
+static int philips_cd1516_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
        struct av7110* av7110 = fe->dvb->priv;
        u32 div;
@@ -1659,6 +1660,8 @@ static int philips_cd1516_pll_set(struct dvb_frontend* fe,
        data[2] = 0x8e;
        data[3] = (f < 174000000 ? 0xa1 : f < 470000000 ? 0x92 : 0x34);
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
                return -EIO;
        return 0;
@@ -1669,12 +1672,11 @@ static struct ves1820_config philips_cd1516_config = {
        .xin = 57840000UL,
        .invert = 1,
        .selagc = VES1820_SELAGC_SIGNAMPERR,
-       .pll_set = philips_cd1516_pll_set,
 };
 
 
 
-static int alps_tdlb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdlb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
        struct av7110* av7110 = fe->dvb->priv;
        u32 div, pwr;
@@ -1693,6 +1695,8 @@ static int alps_tdlb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
        data[2] = 0x85;
        data[3] = pwr << 6;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
                return -EIO;
        return 0;
@@ -1708,7 +1712,6 @@ static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct fir
 static struct sp8870_config alps_tdlb7_config = {
 
        .demod_address = 0x71,
-       .pll_set = alps_tdlb7_pll_set,
        .request_firmware = alps_tdlb7_request_firmware,
 };
 
@@ -1806,7 +1809,7 @@ static u8 nexusca_stv0297_inittab[] = {
        0xff, 0xff,
 };
 
-static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int nexusca_stv0297_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
        struct av7110* av7110 = fe->dvb->priv;
        u32 div;
@@ -1832,7 +1835,8 @@ static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_
        else
                return -EINVAL;
 
-       stv0297_enable_plli2c(fe);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) {
                printk("nexusca: pll transfer failed!\n");
                return -EIO;
@@ -1840,8 +1844,8 @@ static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_
 
        // wait for PLL lock
        for(i = 0; i < 20; i++) {
-
-               stv0297_enable_plli2c(fe);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 1);
                if (i2c_transfer(&av7110->i2c_adap, &readmsg, 1) == 1)
                        if (data[0] & 0x40) break;
                msleep(10);
@@ -1855,12 +1859,12 @@ static struct stv0297_config nexusca_stv0297_config = {
        .demod_address = 0x1C,
        .inittab = nexusca_stv0297_inittab,
        .invert = 1,
-       .pll_set = nexusca_stv0297_pll_set,
+       .stop_during_read = 1,
 };
 
 
 
-static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
        struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
        u32 div;
@@ -1887,13 +1891,14 @@ static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_fronten
        data[2] = ((div >> 10) & 0x60) | cfg;
        data[3] = (cpump << 6) | band_select;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) return -EIO;
        return 0;
 }
 
 static struct l64781_config grundig_29504_401_config = {
        .demod_address = 0x55,
-       .pll_set = grundig_29504_401_pll_set,
 };
 
 
@@ -2079,6 +2084,9 @@ static int frontend_init(struct av7110 *av7110)
                case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??))
                        av7110->fe = ves1820_attach(&philips_cd1516_config,
                                                    &av7110->i2c_adap, read_pwm(av7110));
+                       if (av7110->fe) {
+                               av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
+                       }
                        break;
                }
 
@@ -2091,9 +2099,10 @@ static int frontend_init(struct av7110 *av7110)
                        // try the ALPS BSRV2 first of all
                        av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap);
                        if (av7110->fe) {
-                               av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
-                               av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
-                               av7110->fe->ops->set_tone = av7110_set_tone;
+                               av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+                               av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+                               av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+                               av7110->fe->ops.set_tone = av7110_set_tone;
                                av7110->recover = dvb_s_recover;
                                break;
                        }
@@ -2101,9 +2110,12 @@ static int frontend_init(struct av7110 *av7110)
                        // try the ALPS BSRU6 now
                        av7110->fe = stv0299_attach(&alps_bsru6_config, &av7110->i2c_adap);
                        if (av7110->fe) {
-                               av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
-                               av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
-                               av7110->fe->ops->set_tone = av7110_set_tone;
+                               av7110->fe->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+                               av7110->fe->tuner_priv = &av7110->i2c_adap;
+
+                               av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+                               av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+                               av7110->fe->ops.set_tone = av7110_set_tone;
                                av7110->recover = dvb_s_recover;
                                break;
                        }
@@ -2111,9 +2123,10 @@ static int frontend_init(struct av7110 *av7110)
                        // Try the grundig 29504-451
                        av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
                        if (av7110->fe) {
-                               av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
-                               av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
-                               av7110->fe->ops->set_tone = av7110_set_tone;
+                               av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+                               av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+                               av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+                               av7110->fe->ops.set_tone = av7110_set_tone;
                                av7110->recover = dvb_s_recover;
                                break;
                        }
@@ -2124,11 +2137,17 @@ static int frontend_init(struct av7110 *av7110)
                                /* Siemens DVB-C (full-length card) VES1820/Philips CD1516 */
                                av7110->fe = ves1820_attach(&philips_cd1516_config, &av7110->i2c_adap,
                                                        read_pwm(av7110));
+                               if (av7110->fe) {
+                                       av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
+                               }
                                break;
                        case 0x0003:
                                /* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */
                                av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap,
                                                        read_pwm(av7110));
+                               if (av7110->fe) {
+                                       av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+                               }
                                break;
                        }
                        break;
@@ -2137,20 +2156,27 @@ static int frontend_init(struct av7110 *av7110)
 
                        // ALPS TDLB7
                        av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap);
+                       if (av7110->fe) {
+                               av7110->fe->ops.tuner_ops.set_params = alps_tdlb7_tuner_set_params;
+                       }
                        break;
 
                case 0x0002: // Hauppauge/TT DVB-C premium rev2.X
 
                        av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
+                       if (av7110->fe) {
+                               av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+                       }
                        break;
 
                case 0x0004: // Galaxis DVB-S rev1.3
                        /* ALPS BSRV2 */
                        av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap);
                        if (av7110->fe) {
-                               av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
-                               av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
-                               av7110->fe->ops->set_tone = av7110_set_tone;
+                               av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+                               av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+                               av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+                               av7110->fe->ops.set_tone = av7110_set_tone;
                                av7110->recover = dvb_s_recover;
                        }
                        break;
@@ -2159,9 +2185,10 @@ static int frontend_init(struct av7110 *av7110)
                        /* Grundig 29504-451 */
                        av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
                        if (av7110->fe) {
-                               av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
-                               av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
-                               av7110->fe->ops->set_tone = av7110_set_tone;
+                               av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+                               av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+                               av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+                               av7110->fe->ops.set_tone = av7110_set_tone;
                                av7110->recover = dvb_s_recover;
                        }
                        break;
@@ -2169,12 +2196,17 @@ static int frontend_init(struct av7110 *av7110)
                case 0x0008: // Hauppauge/TT DVB-T
 
                        av7110->fe = l64781_attach(&grundig_29504_401_config, &av7110->i2c_adap);
+                       if (av7110->fe) {
+                               av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
+                       }
                        break;
 
                case 0x000A: // Hauppauge/TT Nexus-CA rev1.X
 
                        av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap);
                        if (av7110->fe) {
+                               av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params;
+
                                /* set TDA9819 into DVB mode */
                                saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD)
                                saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF)
@@ -2189,13 +2221,16 @@ static int frontend_init(struct av7110 *av7110)
                        /* ALPS BSBE1 */
                        av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap);
                        if (av7110->fe) {
-                               if (lnbp21_init(av7110->fe, &av7110->i2c_adap, 0, 0)) {
+                               av7110->fe->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
+                               av7110->fe->tuner_priv = &av7110->i2c_adap;
+
+                               if (lnbp21_attach(av7110->fe, &av7110->i2c_adap, 0, 0)) {
                                        printk("dvb-ttpci: LNBP21 not found!\n");
-                                       if (av7110->fe->ops->release)
-                                               av7110->fe->ops->release(av7110->fe);
+                                       if (av7110->fe->ops.release)
+                                               av7110->fe->ops.release(av7110->fe);
                                        av7110->fe = NULL;
                                } else {
-                                       av7110->fe->ops->dishnetwork_send_legacy_command = NULL;
+                                       av7110->fe->ops.dishnetwork_send_legacy_command = NULL;
                                        av7110->recover = dvb_s_recover;
                                }
                        }
@@ -2212,21 +2247,21 @@ static int frontend_init(struct av7110 *av7110)
                       av7110->dev->pci->subsystem_vendor,
                       av7110->dev->pci->subsystem_device);
        } else {
-               FE_FUNC_OVERRIDE(av7110->fe->ops->init, av7110->fe_init, av7110_fe_init);
-               FE_FUNC_OVERRIDE(av7110->fe->ops->read_status, av7110->fe_read_status, av7110_fe_read_status);
-               FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload);
-               FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
-               FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
-               FE_FUNC_OVERRIDE(av7110->fe->ops->set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
-               FE_FUNC_OVERRIDE(av7110->fe->ops->set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
-               FE_FUNC_OVERRIDE(av7110->fe->ops->dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
-               FE_FUNC_OVERRIDE(av7110->fe->ops->set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
+               FE_FUNC_OVERRIDE(av7110->fe->ops.init, av7110->fe_init, av7110_fe_init);
+               FE_FUNC_OVERRIDE(av7110->fe->ops.read_status, av7110->fe_read_status, av7110_fe_read_status);
+               FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload);
+               FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
+               FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
+               FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
+               FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
+               FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
+               FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
 
                ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe);
                if (ret < 0) {
                        printk("av7110: Frontend registration failed!\n");
-                       if (av7110->fe->ops->release)
-                               av7110->fe->ops->release(av7110->fe);
+                       if (av7110->fe->ops.release)
+                               av7110->fe->ops.release(av7110->fe);
                        av7110->fe = NULL;
                }
        }
@@ -2413,7 +2448,7 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
                goto err_kfree_0;
 
        ret = dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name,
-                                  THIS_MODULE);
+                                  THIS_MODULE, &dev->pci->dev);
        if (ret < 0)
                goto err_put_firmware_1;
 
index 8a7cd7d505cf533997dc76f2613f5e98a1d0c0d8..6163cb03b8f418e9859263be98d668881ad97482 100644 (file)
 
 #define DEBICICAM              0x02420000
 
+#define SLOTSTATUS_NONE         1
+#define SLOTSTATUS_PRESENT      2
+#define SLOTSTATUS_RESET        4
+#define SLOTSTATUS_READY        8
+#define SLOTSTATUS_OCCUPIED     (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
+
 struct budget_av {
        struct budget budget;
        struct video_device *vd;
@@ -58,8 +64,15 @@ struct budget_av {
        struct tasklet_struct ciintf_irq_tasklet;
        int slot_status;
        struct dvb_ca_en50221 ca;
+       u8 reinitialise_demod:1;
+       u8 tda10021_poclkp:1;
+       u8 tda10021_ts_enabled;
+       int (*tda10021_set_frontend)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
 };
 
+static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot);
+
+
 /* GPIO Connections:
  * 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*!
  * 1 - CI memory select 0=>IO memory, 1=>Attribute Memory
@@ -129,9 +142,10 @@ static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int ad
        udelay(1);
 
        result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1);
-
-       if (result == -ETIMEDOUT)
-               budget_av->slot_status = 0;
+       if (result == -ETIMEDOUT) {
+               ciintf_slot_shutdown(ca, slot);
+               printk(KERN_INFO "budget-av: cam ejected 1\n");
+       }
        return result;
 }
 
@@ -147,9 +161,10 @@ static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int a
        udelay(1);
 
        result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1);
-
-       if (result == -ETIMEDOUT)
-               budget_av->slot_status = 0;
+       if (result == -ETIMEDOUT) {
+               ciintf_slot_shutdown(ca, slot);
+               printk(KERN_INFO "budget-av: cam ejected 2\n");
+       }
        return result;
 }
 
@@ -165,9 +180,11 @@ static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 addre
        udelay(1);
 
        result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0);
-
-       if (result == -ETIMEDOUT)
-               budget_av->slot_status = 0;
+       if ((result == -ETIMEDOUT) || ((result == 0xff) && ((address & 3) < 2))) {
+               ciintf_slot_shutdown(ca, slot);
+               printk(KERN_INFO "budget-av: cam ejected 3\n");
+               return -ETIMEDOUT;
+       }
        return result;
 }
 
@@ -183,9 +200,10 @@ static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 addr
        udelay(1);
 
        result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0);
-
-       if (result == -ETIMEDOUT)
-               budget_av->slot_status = 0;
+       if (result == -ETIMEDOUT) {
+               ciintf_slot_shutdown(ca, slot);
+               printk(KERN_INFO "budget-av: cam ejected 5\n");
+       }
        return result;
 }
 
@@ -193,12 +211,12 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
 {
        struct budget_av *budget_av = (struct budget_av *) ca->data;
        struct saa7146_dev *saa = budget_av->budget.dev;
-       int timeout = 50; // 5 seconds (4.4.6 Ready)
 
        if (slot != 0)
                return -EINVAL;
 
        dprintk(1, "ciintf_slot_reset\n");
+       budget_av->slot_status = SLOTSTATUS_RESET;
 
        saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
 
@@ -208,20 +226,17 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
        msleep(20); /* 20 ms Vcc settling time */
 
        saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */
+       ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
+       msleep(20);
 
-       /* This should have been based on pin 16 READY of the pcmcia port,
-        * but AFAICS it is not routed to the saa7146 */
-       while (--timeout > 0 && ciintf_read_attribute_mem(ca, slot, 0) != 0x1d)
-               msleep(100);
-
-       /* reinitialise the frontend */
-       dvb_frontend_reinitialise(budget_av->budget.dvb_frontend);
+       /* reinitialise the frontend if necessary */
+       if (budget_av->reinitialise_demod)
+               dvb_frontend_reinitialise(budget_av->budget.dvb_frontend);
 
-       if (timeout <= 0)
-       {
-               printk(KERN_ERR "budget-av: cam reset failed (timeout).\n");
-               saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
-               return -ETIMEDOUT;
+       /* set tda10021 back to original clock configuration on reset */
+       if (budget_av->tda10021_poclkp) {
+               tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+               budget_av->tda10021_ts_enabled = 0;
        }
 
        return 0;
@@ -238,7 +253,13 @@ static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
        dprintk(1, "ciintf_slot_shutdown\n");
 
        ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
-       budget_av->slot_status = 0;
+       budget_av->slot_status = SLOTSTATUS_NONE;
+
+       /* set tda10021 back to original clock configuration when cam removed */
+       if (budget_av->tda10021_poclkp) {
+               tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+               budget_av->tda10021_ts_enabled = 0;
+       }
        return 0;
 }
 
@@ -253,6 +274,13 @@ static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
        dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status);
 
        ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
+
+       /* tda10021 seems to need a different TS clock config when data is routed to the CAM */
+       if (budget_av->tda10021_poclkp) {
+               tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1);
+               budget_av->tda10021_ts_enabled = 1;
+       }
+
        return 0;
 }
 
@@ -260,50 +288,61 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open
 {
        struct budget_av *budget_av = (struct budget_av *) ca->data;
        struct saa7146_dev *saa = budget_av->budget.dev;
-       int cam_present = 0;
+       int result;
 
        if (slot != 0)
                return -EINVAL;
 
-       if (!budget_av->slot_status)
-       {
-               // first of all test the card detect line
+       /* test the card detect line - needs to be done carefully
+        * since it never goes high for some CAMs on this interface (e.g. topuptv) */
+       if (budget_av->slot_status == SLOTSTATUS_NONE) {
                saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
                udelay(1);
-               if (saa7146_read(saa, PSR) & MASK_06)
-               {
-                       cam_present = 1;
+               if (saa7146_read(saa, PSR) & MASK_06) {
+                       if (budget_av->slot_status == SLOTSTATUS_NONE) {
+                               budget_av->slot_status = SLOTSTATUS_PRESENT;
+                               printk(KERN_INFO "budget-av: cam inserted A\n");
+                       }
                }
                saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+       }
 
-               // that is unreliable however, so try and read from IO memory
-               if (!cam_present)
-               {
-                       saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
-                       if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT)
-                       {
-                               cam_present = 1;
+       /* We also try and read from IO memory to work round the above detection bug. If
+        * there is no CAM, we will get a timeout. Only done if there is no cam
+        * present, since this test actually breaks some cams :(
+        *
+        * if the CI interface is not open, we also do the above test since we
+        * don't care if the cam has problems - we'll be resetting it on open() anyway */
+       if ((budget_av->slot_status == SLOTSTATUS_NONE) || (!open)) {
+               saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+               result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1);
+               if ((result >= 0) && (budget_av->slot_status == SLOTSTATUS_NONE)) {
+                       budget_av->slot_status = SLOTSTATUS_PRESENT;
+                       printk(KERN_INFO "budget-av: cam inserted B\n");
+               } else if (result < 0) {
+                       if (budget_av->slot_status != SLOTSTATUS_NONE) {
+                               ciintf_slot_shutdown(ca, slot);
+                               printk(KERN_INFO "budget-av: cam ejected 5\n");
+                               return 0;
                        }
                }
+       }
 
-               // did we find something?
-               if (cam_present) {
-                       printk(KERN_INFO "budget-av: cam inserted\n");
-                       budget_av->slot_status = 1;
-               }
-       } else if (!open) {
-               saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
-               if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT)
-               {
-                       printk(KERN_INFO "budget-av: cam ejected\n");
-                       saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
-                       budget_av->slot_status = 0;
+       /* read from attribute memory in reset/ready state to know when the CAM is ready */
+       if (budget_av->slot_status == SLOTSTATUS_RESET) {
+               result = ciintf_read_attribute_mem(ca, slot, 0);
+               if (result == 0x1d) {
+                       budget_av->slot_status = SLOTSTATUS_READY;
                }
        }
 
-       if (budget_av->slot_status == 1)
-               return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
-
+       /* work out correct return code */
+       if (budget_av->slot_status != SLOTSTATUS_NONE) {
+               if (budget_av->slot_status & SLOTSTATUS_READY) {
+                       return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
+               }
+               return DVB_CA_EN50221_POLL_CAM_PRESENT;
+       }
        return 0;
 }
 
@@ -333,6 +372,8 @@ static int ciintf_init(struct budget_av *budget_av)
        budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable;
        budget_av->ca.poll_slot_status = ciintf_poll_slot_status;
        budget_av->ca.data = budget_av;
+       budget_av->budget.ci_present = 1;
+       budget_av->slot_status = SLOTSTATUS_NONE;
 
        if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter,
                                          &budget_av->ca, 0, 1)) != 0) {
@@ -341,7 +382,6 @@ static int ciintf_init(struct budget_av *budget_av)
        }
 
        printk(KERN_INFO "budget-av: ci interface initialised.\n");
-       budget_av->budget.ci_present = 1;
        return 0;
 
 error:
@@ -472,12 +512,12 @@ static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 sra
        return 0;
 }
 
-static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
-                                       struct i2c_adapter *i2c,
-                                       struct dvb_frontend_parameters *params)
+static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe,
+                                                struct dvb_frontend_parameters *params)
 {
        u32 div;
        u8 buf[4];
+       struct budget *budget = (struct budget *) fe->dvb->priv;
        struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
 
        if ((params->frequency < 950000) || (params->frequency > 2150000))
@@ -501,7 +541,9 @@ static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
        else if (params->frequency < 2150000)
                buf[3] |= 0xC0;
 
-       if (i2c_transfer(i2c, &msg, 1) != 1)
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
                return -EIO;
        return 0;
 }
@@ -509,9 +551,8 @@ static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
 #define MIN2(a,b) ((a) < (b) ? (a) : (b))
 #define MIN3(a,b,c) MIN2(MIN2(a,b),c)
 
-static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe,
-                                       struct i2c_adapter *i2c,
-                                       struct dvb_frontend_parameters *params)
+static int philips_su1278sh2_tua6100_tuner_set_params(struct dvb_frontend *fe,
+                                                     struct dvb_frontend_parameters *params)
 {
        u8 reg0 [2] = { 0x00, 0x00 };
        u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 };
@@ -521,6 +562,7 @@ static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe,
        int R, A, N, P, M;
        struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = NULL,.len = 0 };
        int freq = params->frequency;
+       struct budget *budget = (struct budget *) fe->dvb->priv;
 
        first_ZF = (freq) / 1000;
 
@@ -620,21 +662,25 @@ static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe,
        reg0[1] |= 0x03;
 
        /* already enabled - do not reenable i2c repeater or TX fails */
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        msg.buf = reg0;
        msg.len = sizeof(reg0);
-       if (i2c_transfer(i2c, &msg, 1) != 1)
+       if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
                return -EIO;
 
-       stv0299_enable_plli2c(fe);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        msg.buf = reg1;
        msg.len = sizeof(reg1);
-       if (i2c_transfer(i2c, &msg, 1) != 1)
+       if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
                return -EIO;
 
-       stv0299_enable_plli2c(fe);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        msg.buf = reg2;
        msg.len = sizeof(reg2);
-       if (i2c_transfer(i2c, &msg, 1) != 1)
+       if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
                return -EIO;
 
        return 0;
@@ -692,7 +738,6 @@ static struct stv0299_config typhoon_config = {
        .volt13_op0_op1 = STV0299_VOLT13_OP0,
        .min_delay_ms = 100,
        .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
-       .pll_set = philips_su1278_ty_ci_pll_set,
 };
 
 
@@ -706,7 +751,6 @@ static struct stv0299_config cinergy_1200s_config = {
        .volt13_op0_op1 = STV0299_VOLT13_OP0,
        .min_delay_ms = 100,
        .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
-       .pll_set = philips_su1278_ty_ci_pll_set,
 };
 
 static struct stv0299_config cinergy_1200s_1894_0010_config = {
@@ -719,10 +763,9 @@ static struct stv0299_config cinergy_1200s_1894_0010_config = {
        .volt13_op0_op1 = STV0299_VOLT13_OP0,
        .min_delay_ms = 100,
        .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
-       .pll_set = philips_su1278sh2_tua6100_pll_set,
 };
 
-static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
        struct budget *budget = (struct budget *) fe->dvb->priv;
        u8 buf[4];
@@ -738,6 +781,8 @@ static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p
        buf[3] = (params->frequency < 150000000 ? 0x01 :
                  params->frequency < 445000000 ? 0x02 : 0x04);
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
                return -EIO;
        return 0;
@@ -745,19 +790,20 @@ static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p
 
 static struct tda10021_config philips_cu1216_config = {
        .demod_address = 0x0c,
-       .pll_set = philips_cu1216_pll_set,
 };
 
 
 
 
-static int philips_tu1216_pll_init(struct dvb_frontend *fe)
+static int philips_tu1216_tuner_init(struct dvb_frontend *fe)
 {
        struct budget *budget = (struct budget *) fe->dvb->priv;
        static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
        struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
 
        // setup PLL configuration
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
                return -EIO;
        msleep(1);
@@ -765,7 +811,7 @@ static int philips_tu1216_pll_init(struct dvb_frontend *fe)
        return 0;
 }
 
-static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
        struct budget *budget = (struct budget *) fe->dvb->priv;
        u8 tuner_buf[4];
@@ -839,6 +885,8 @@ static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p
        tuner_buf[2] = 0xca;
        tuner_buf[3] = (cp << 5) | (filter << 3) | band;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
                return -EIO;
 
@@ -862,9 +910,6 @@ static struct tda1004x_config philips_tu1216_config = {
        .xtal_freq = TDA10046_XTAL_4M,
        .agc_config = TDA10046_AGC_DEFAULT,
        .if_freq = TDA10046_FREQ_3617,
-       .pll_init = philips_tu1216_pll_init,
-       .pll_set = philips_tu1216_pll_set,
-       .pll_sleep = NULL,
        .request_firmware = philips_tu1216_request_firmware,
 };
 
@@ -911,13 +956,13 @@ static u8 philips_sd1878_inittab[] = {
        0xff, 0xff
 };
 
-static int philips_sd1878_tda8261_pll_set(struct dvb_frontend *fe,
-               struct i2c_adapter *i2c,
-               struct dvb_frontend_parameters *params)
+static int philips_sd1878_tda8261_tuner_set_params(struct dvb_frontend *fe,
+                                                  struct dvb_frontend_parameters *params)
 {
        u8              buf[4];
        int             rc;
        struct i2c_msg  tuner_msg = {.addr=0x60,.flags=0,.buf=buf,.len=sizeof(buf)};
+       struct budget *budget = (struct budget *) fe->dvb->priv;
 
        if((params->frequency < 950000) || (params->frequency > 2150000))
                return -EINVAL;
@@ -926,7 +971,9 @@ static int philips_sd1878_tda8261_pll_set(struct dvb_frontend *fe,
                        params->frequency, 0);
        if(rc < 0) return rc;
 
-       if(i2c_transfer(i2c, &tuner_msg, 1) != 1)
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       if(i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
                return -EIO;
 
     return 0;
@@ -969,7 +1016,7 @@ static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe,
 
 static struct stv0299_config philips_sd1878_config = {
        .demod_address = 0x68,
-       .inittab = philips_sd1878_inittab,
+     .inittab = philips_sd1878_inittab,
        .mclk = 88000000UL,
        .invert = 0,
        .skip_reinit = 0,
@@ -977,7 +1024,6 @@ static struct stv0299_config philips_sd1878_config = {
        .volt13_op0_op1 = STV0299_VOLT13_OP0,
        .min_delay_ms = 100,
        .set_symbol_rate = philips_sd1878_ci_set_symbol_rate,
-       .pll_set = philips_sd1878_tda8261_pll_set,
 };
 
 static u8 read_pwm(struct budget_av *budget_av)
@@ -1003,6 +1049,7 @@ static u8 read_pwm(struct budget_av *budget_av)
 
 #define SUBID_DVBS_TV_STAR     0x0014
 #define SUBID_DVBS_TV_STAR_CI  0x0016
+#define SUBID_DVBS_EASYWATCH_1  0x001a
 #define SUBID_DVBS_EASYWATCH   0x001e
 #define SUBID_DVBC_KNC1                0x0020
 #define SUBID_DVBC_KNC1_PLUS   0x0021
@@ -1012,17 +1059,36 @@ static u8 read_pwm(struct budget_av *budget_av)
 #define SUBID_DVBT_KNC1                0x0030
 #define SUBID_DVBT_CINERGY1200 0x1157
 
+
+static int tda10021_set_frontend(struct dvb_frontend *fe,
+                                struct dvb_frontend_parameters *p)
+{
+       struct budget_av* budget_av = fe->dvb->priv;
+       int result;
+
+       result = budget_av->tda10021_set_frontend(fe, p);
+       if (budget_av->tda10021_ts_enabled) {
+               tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1);
+       } else {
+               tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+       }
+
+       return result;
+}
+
 static void frontend_init(struct budget_av *budget_av)
 {
        struct saa7146_dev * saa = budget_av->budget.dev;
        struct dvb_frontend * fe = NULL;
 
+       /* Enable / PowerON Frontend */
+       saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
+
+       /* additional setup necessary for the PLUS cards */
        switch (saa->pci->subsystem_device) {
                case SUBID_DVBS_KNC1_PLUS:
                case SUBID_DVBC_KNC1_PLUS:
                case SUBID_DVBT_KNC1_PLUS:
-                       // Enable / PowerON Frontend
-                       saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
                        saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);
                        break;
        }
@@ -1030,12 +1096,19 @@ static void frontend_init(struct budget_av *budget_av)
        switch (saa->pci->subsystem_device) {
 
        case SUBID_DVBS_KNC1:
+       case SUBID_DVBS_EASYWATCH_1:
                if (saa->pci->subsystem_vendor == 0x1894) {
                        fe = stv0299_attach(&cinergy_1200s_1894_0010_config,
                                             &budget_av->budget.i2c_adap);
+                       if (fe) {
+                               fe->ops.tuner_ops.set_params = philips_su1278sh2_tua6100_tuner_set_params;
+                       }
                } else {
                        fe = stv0299_attach(&typhoon_config,
                                             &budget_av->budget.i2c_adap);
+                       if (fe) {
+                               fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+                       }
                }
                break;
 
@@ -1045,41 +1118,53 @@ static void frontend_init(struct budget_av *budget_av)
        case SUBID_DVBS_EASYWATCH:
                fe = stv0299_attach(&philips_sd1878_config,
                                &budget_av->budget.i2c_adap);
+               if (fe) {
+                       fe->ops.tuner_ops.set_params = philips_sd1878_tda8261_tuner_set_params;
+               }
                break;
 
        case SUBID_DVBS_KNC1_PLUS:
        case SUBID_DVBS_TYPHOON:
                fe = stv0299_attach(&typhoon_config,
                                    &budget_av->budget.i2c_adap);
+               if (fe) {
+                       fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+               }
                break;
 
        case SUBID_DVBS_CINERGY1200:
                fe = stv0299_attach(&cinergy_1200s_config,
                                    &budget_av->budget.i2c_adap);
+               if (fe) {
+                       fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+               }
                break;
 
        case SUBID_DVBC_KNC1:
        case SUBID_DVBC_KNC1_PLUS:
+       case SUBID_DVBC_CINERGY1200:
+               budget_av->reinitialise_demod = 1;
                fe = tda10021_attach(&philips_cu1216_config,
                                     &budget_av->budget.i2c_adap,
                                     read_pwm(budget_av));
+               if (fe) {
+                       budget_av->tda10021_poclkp = 1;
+                       budget_av->tda10021_set_frontend = fe->ops.set_frontend;
+                       fe->ops.set_frontend = tda10021_set_frontend;
+                       fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
+               }
                break;
 
        case SUBID_DVBT_KNC1:
        case SUBID_DVBT_KNC1_PLUS:
-               fe = tda10046_attach(&philips_tu1216_config,
-                                    &budget_av->budget.i2c_adap);
-               break;
-
-       case SUBID_DVBC_CINERGY1200:
-               fe = tda10021_attach(&philips_cu1216_config,
-                                    &budget_av->budget.i2c_adap,
-                                    read_pwm(budget_av));
-               break;
-
        case SUBID_DVBT_CINERGY1200:
+               budget_av->reinitialise_demod = 1;
                fe = tda10046_attach(&philips_tu1216_config,
                                     &budget_av->budget.i2c_adap);
+               if (fe) {
+                       fe->ops.tuner_ops.init = philips_tu1216_tuner_init;
+                       fe->ops.tuner_ops.set_params = philips_tu1216_tuner_set_params;
+               }
                break;
        }
 
@@ -1098,8 +1183,8 @@ static void frontend_init(struct budget_av *budget_av)
        if (dvb_register_frontend(&budget_av->budget.dvb_adapter,
                                  budget_av->budget.dvb_frontend)) {
                printk(KERN_ERR "budget-av: Frontend registration failed!\n");
-               if (budget_av->budget.dvb_frontend->ops->release)
-                       budget_av->budget.dvb_frontend->ops->release(budget_av->budget.dvb_frontend);
+               if (budget_av->budget.dvb_frontend->ops.release)
+                       budget_av->budget.dvb_frontend->ops.release(budget_av->budget.dvb_frontend);
                budget_av->budget.dvb_frontend = NULL;
        }
 }
@@ -1293,6 +1378,7 @@ MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C);
 MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
 MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
 MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
+MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
 MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
 MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
 MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
@@ -1309,6 +1395,7 @@ static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
        MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
        MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
+       MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
        MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
        MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
        MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
index e64a609cf4ff4825ac119047b3dd7cfddc7d7cdb..4b966eea3834b52dc07668c7f99721ce907e2a2c 100644 (file)
@@ -620,10 +620,10 @@ static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate,
        return 0;
 }
 
-static int philips_su1278_tt_pll_set(struct dvb_frontend *fe,
-                                    struct i2c_adapter *i2c,
-                                    struct dvb_frontend_parameters *params)
+static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
+                                          struct dvb_frontend_parameters *params)
 {
+       struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
        u32 div;
        u8 buf[4];
        struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
@@ -649,7 +649,9 @@ static int philips_su1278_tt_pll_set(struct dvb_frontend *fe,
        else if (params->frequency < 2150000)
                buf[3] |= 0xC0;
 
-       if (i2c_transfer(i2c, &msg, 1) != 1)
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
                return -EIO;
        return 0;
 }
@@ -665,12 +667,11 @@ static struct stv0299_config philips_su1278_tt_config = {
        .volt13_op0_op1 = STV0299_VOLT13_OP1,
        .min_delay_ms = 50,
        .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
-       .pll_set = philips_su1278_tt_pll_set,
 };
 
 
 
-static int philips_tdm1316l_pll_init(struct dvb_frontend *fe)
+static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
 {
        struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
        static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
@@ -679,6 +680,8 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend *fe)
                        sizeof(td1316_init) };
 
        // setup PLL configuration
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
                return -EIO;
        msleep(1);
@@ -687,14 +690,18 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend *fe)
        tuner_msg.addr = 0x65;
        tuner_msg.buf = disable_mc44BC374c;
        tuner_msg.len = sizeof(disable_mc44BC374c);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 1);
                i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
        }
 
        return 0;
 }
 
-static int philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
        struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
        u8 tuner_buf[4];
@@ -770,6 +777,8 @@ static int philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend
        tuner_buf[2] = 0xca;
        tuner_buf[3] = (cp << 5) | (filter << 3) | band;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
                return -EIO;
 
@@ -793,13 +802,10 @@ static struct tda1004x_config philips_tdm1316l_config = {
        .xtal_freq = TDA10046_XTAL_4M,
        .agc_config = TDA10046_AGC_DEFAULT,
        .if_freq = TDA10046_FREQ_3617,
-       .pll_init = philips_tdm1316l_pll_init,
-       .pll_set = philips_tdm1316l_pll_set,
-       .pll_sleep = NULL,
        .request_firmware = philips_tdm1316l_request_firmware,
 };
 
-static int dvbc_philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
        struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
        u8 tuner_buf[5];
@@ -857,13 +863,15 @@ static int dvbc_philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_fro
        tuner_buf[3] = (cp << 5) | (filter << 3) | band;
        tuner_buf[4] = 0x80;
 
-       stv0297_enable_plli2c(fe);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
                return -EIO;
 
        msleep(50);
 
-       stv0297_enable_plli2c(fe);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
                return -EIO;
 
@@ -969,7 +977,7 @@ static struct stv0297_config dvbc_philips_tdm1316l_config = {
        .demod_address = 0x1c,
        .inittab = dvbc_philips_tdm1316l_inittab,
        .invert = 0,
-       .pll_set = dvbc_philips_tdm1316l_pll_set,
+       .stop_during_read = 1,
 };
 
 
@@ -982,6 +990,8 @@ static void frontend_init(struct budget_ci *budget_ci)
                budget_ci->budget.dvb_frontend =
                        stv0299_attach(&alps_bsru6_config, &budget_ci->budget.i2c_adap);
                if (budget_ci->budget.dvb_frontend) {
+                       budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+                       budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
                        break;
                }
                break;
@@ -990,6 +1000,7 @@ static void frontend_init(struct budget_ci *budget_ci)
                budget_ci->budget.dvb_frontend =
                        stv0299_attach(&philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
                if (budget_ci->budget.dvb_frontend) {
+                       budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
                        break;
                }
                break;
@@ -999,6 +1010,7 @@ static void frontend_init(struct budget_ci *budget_ci)
                budget_ci->budget.dvb_frontend =
                        stv0297_attach(&dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
                if (budget_ci->budget.dvb_frontend) {
+                       budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
                        break;
                }
                break;
@@ -1008,6 +1020,8 @@ static void frontend_init(struct budget_ci *budget_ci)
                budget_ci->budget.dvb_frontend =
                        tda10045_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
                if (budget_ci->budget.dvb_frontend) {
+                       budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
+                       budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
                        break;
                }
                break;
@@ -1017,6 +1031,8 @@ static void frontend_init(struct budget_ci *budget_ci)
                budget_ci->budget.dvb_frontend =
                        tda10046_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
                if (budget_ci->budget.dvb_frontend) {
+                       budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
+                       budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
                        break;
                }
                break;
@@ -1024,11 +1040,14 @@ static void frontend_init(struct budget_ci *budget_ci)
        case 0x1017:            // TT S-1500 PCI
                budget_ci->budget.dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget_ci->budget.i2c_adap);
                if (budget_ci->budget.dvb_frontend) {
-                       budget_ci->budget.dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
-                       if (lnbp21_init(budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0)) {
+                       budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
+                       budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
+
+                       budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
+                       if (lnbp21_attach(budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0)) {
                                printk("%s: No LNBP21 found!\n", __FUNCTION__);
-                               if (budget_ci->budget.dvb_frontend->ops->release)
-                                       budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
+                               if (budget_ci->budget.dvb_frontend->ops.release)
+                                       budget_ci->budget.dvb_frontend->ops.release(budget_ci->budget.dvb_frontend);
                                budget_ci->budget.dvb_frontend = NULL;
                        }
                }
@@ -1046,8 +1065,8 @@ static void frontend_init(struct budget_ci *budget_ci)
                if (dvb_register_frontend
                    (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
                        printk("budget-ci: Frontend registration failed!\n");
-                       if (budget_ci->budget.dvb_frontend->ops->release)
-                               budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
+                       if (budget_ci->budget.dvb_frontend->ops.release)
+                               budget_ci->budget.dvb_frontend->ops.release(budget_ci->budget.dvb_frontend);
                        budget_ci->budget.dvb_frontend = NULL;
                }
        }
index ea2066d461fc95fcd9fe770d2e9c4fca34d72563..e4cf7775e07f75f21447fa2f051af771180aad63 100644 (file)
@@ -400,7 +400,9 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
                budget->dev->name, budget->buffer_width, budget->buffer_height);
        printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size);
 
-       dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner);
+       if ((ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner, &budget->dev->pci->dev)) < 0) {
+               return ret;
+       }
 
        /* set dd1 stream a & b */
        saa7146_write(dev, DD1_STREAM_B, 0x00000000);
index 1b3aaac5e7636fbdade5d426b52087bbdfaa95c7..ee60ce90a4005f562d62ed85f6b8a1b155e68a2f 100644 (file)
@@ -258,7 +258,7 @@ static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_c
        return 0;
 }
 
-static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
        struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
        u8 pwr = 0;
@@ -281,7 +281,10 @@ static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
        // NOTE: since we're using a prescaler of 2, we set the
        // divisor frequency to 62.5kHz and divide by 125 above
 
-       if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
+               return -EIO;
        return 0;
 }
 
@@ -289,10 +292,9 @@ static struct ves1x93_config alps_bsrv2_config = {
        .demod_address = 0x08,
        .xin = 90100000UL,
        .invert_pwm = 0,
-       .pll_set = alps_bsrv2_pll_set,
 };
 
-static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
        struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
        u32 div;
@@ -305,13 +307,15 @@ static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_fronten
        data[2] = 0x8e;
        data[3] = 0x00;
 
-       if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
+               return -EIO;
        return 0;
 }
 
 static struct tda8083_config grundig_29504_451_config = {
        .demod_address = 0x68,
-       .pll_set = grundig_29504_451_pll_set,
 };
 
 static void frontend_init(struct budget_patch* budget)
@@ -323,27 +327,32 @@ static void frontend_init(struct budget_patch* budget)
                // try the ALPS BSRV2 first of all
                budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
                if (budget->dvb_frontend) {
-                       budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
-                       budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
-                       budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
+                       budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+                       budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
+                       budget->dvb_frontend->ops.diseqc_send_burst = budget_patch_diseqc_send_burst;
+                       budget->dvb_frontend->ops.set_tone = budget_patch_set_tone;
                        break;
                }
 
                // try the ALPS BSRU6 now
                budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
                if (budget->dvb_frontend) {
-                       budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
-                       budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
-                       budget->dvb_frontend->ops->set_tone = budget_set_tone;
+                       budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+                       budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+
+                       budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+                       budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+                       budget->dvb_frontend->ops.set_tone = budget_set_tone;
                        break;
                }
 
                // Try the grundig 29504-451
                budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
                if (budget->dvb_frontend) {
-                       budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
-                       budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
-                       budget->dvb_frontend->ops->set_tone = budget_set_tone;
+                       budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+                       budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+                       budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+                       budget->dvb_frontend->ops.set_tone = budget_set_tone;
                        break;
                }
                break;
@@ -358,8 +367,8 @@ static void frontend_init(struct budget_patch* budget)
        } else {
                if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
                        printk("budget-av: Frontend registration failed!\n");
-                       if (budget->dvb_frontend->ops->release)
-                               budget->dvb_frontend->ops->release(budget->dvb_frontend);
+                       if (budget->dvb_frontend->ops.release)
+                               budget->dvb_frontend->ops.release(budget->dvb_frontend);
                        budget->dvb_frontend = NULL;
                }
        }
index c23c02d95641867d8b6163c2fa99dca218bd0299..35761f13c12b051fac37d2d48ffda657e7d90e75 100644 (file)
@@ -186,7 +186,7 @@ static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t m
        return 0;
 }
 
-static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
        struct budget* budget = (struct budget*) fe->dvb->priv;
        u8 pwr = 0;
@@ -209,6 +209,8 @@ static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
        // NOTE: since we're using a prescaler of 2, we set the
        // divisor frequency to 62.5kHz and divide by 125 above
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
        return 0;
 }
@@ -218,10 +220,9 @@ static struct ves1x93_config alps_bsrv2_config =
        .demod_address = 0x08,
        .xin = 90100000UL,
        .invert_pwm = 0,
-       .pll_set = alps_bsrv2_pll_set,
 };
 
-static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
        struct budget* budget = (struct budget*) fe->dvb->priv;
        u32 div;
@@ -235,6 +236,8 @@ static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
        data[2] = 0x85 | ((div >> 10) & 0x60);
        data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
        return 0;
 }
@@ -244,10 +247,9 @@ static struct ves1820_config alps_tdbe2_config = {
        .xin = 57840000UL,
        .invert = 1,
        .selagc = VES1820_SELAGC_SIGNAMPERR,
-       .pll_set = alps_tdbe2_pll_set,
 };
 
-static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
        struct budget* budget = (struct budget*) fe->dvb->priv;
        u32 div;
@@ -274,16 +276,17 @@ static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_fronten
        data[2] = ((div >> 10) & 0x60) | cfg;
        data[3] = (cpump << 6) | band_select;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
        return 0;
 }
 
 static struct l64781_config grundig_29504_401_config = {
        .demod_address = 0x55,
-       .pll_set = grundig_29504_401_pll_set,
 };
 
-static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
        struct budget* budget = (struct budget*) fe->dvb->priv;
        u32 div;
@@ -296,16 +299,17 @@ static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_fronten
        data[2] = 0x8e;
        data[3] = 0x00;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
        return 0;
 }
 
 static struct tda8083_config grundig_29504_451_config = {
        .demod_address = 0x68,
-       .pll_set = grundig_29504_451_pll_set,
 };
 
-static int s5h1420_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout)
+static int s5h1420_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
        struct budget* budget = (struct budget*) fe->dvb->priv;
        u32 div;
@@ -326,16 +330,16 @@ static int s5h1420_pll_set(struct dvb_frontend* fe, struct dvb_frontend_paramete
        else
                data[3] = 0xc0;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
 
-       *freqout = div * 1000;
        return 0;
 }
 
 static struct s5h1420_config s5h1420_config = {
        .demod_address = 0x53,
        .invert = 1,
-       .pll_set = s5h1420_pll_set,
 };
 
 static u8 read_pwm(struct budget* budget)
@@ -359,18 +363,21 @@ static void frontend_init(struct budget *budget)
                // try the ALPS BSRV2 first of all
                budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
                if (budget->dvb_frontend) {
-                       budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
-                       budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
-                       budget->dvb_frontend->ops->set_tone = budget_set_tone;
+                       budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+                       budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+                       budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+                       budget->dvb_frontend->ops.set_tone = budget_set_tone;
                        break;
                }
 
                // try the ALPS BSRU6 now
                budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
                if (budget->dvb_frontend) {
-                       budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
-                       budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
-                       budget->dvb_frontend->ops->set_tone = budget_set_tone;
+                       budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+                       budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+                       budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+                       budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+                       budget->dvb_frontend->ops.set_tone = budget_set_tone;
                        break;
                }
                break;
@@ -378,35 +385,45 @@ static void frontend_init(struct budget *budget)
        case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
 
                budget->dvb_frontend = ves1820_attach(&alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
-               if (budget->dvb_frontend) break;
+               if (budget->dvb_frontend) {
+                       budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+                       break;
+               }
                break;
 
        case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))
 
                budget->dvb_frontend = l64781_attach(&grundig_29504_401_config, &budget->i2c_adap);
-               if (budget->dvb_frontend) break;
+               if (budget->dvb_frontend) {
+                       budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
+                       break;
+               }
                break;
 
        case 0x4f60: // Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/ALPS BSRU6(tsa5059))
                budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
                if (budget->dvb_frontend) {
-                       budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
-                       budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
+                       budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+                       budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+                       budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
+                       budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
                }
                break;
 
        case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522))
                budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
                if (budget->dvb_frontend) {
-                       budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
-                       budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
+                       budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+                       budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
+                       budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
                }
                break;
 
        case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
                budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap);
                if (budget->dvb_frontend) {
-                       if (lnbp21_init(budget->dvb_frontend, &budget->i2c_adap, 0, 0)) {
+                       budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params;
+                       if (lnbp21_attach(budget->dvb_frontend, &budget->i2c_adap, 0, 0)) {
                                printk("%s: No LNBP21 found!\n", __FUNCTION__);
                                goto error_out;
                        }
@@ -428,8 +445,8 @@ static void frontend_init(struct budget *budget)
 
 error_out:
        printk("budget: Frontend registration failed!\n");
-       if (budget->dvb_frontend->ops->release)
-               budget->dvb_frontend->ops->release(budget->dvb_frontend);
+       if (budget->dvb_frontend->ops.release)
+               budget->dvb_frontend->ops.release(budget->dvb_frontend);
        budget->dvb_frontend = NULL;
        return;
 }
index 914587d52b57622131592134d7feef0e9d651c6b..92c7cdcf89815750113d68f866aa220aded41b3c 100644 (file)
@@ -6,6 +6,8 @@ config DVB_TTUSB_BUDGET
        select DVB_VES1820
        select DVB_TDA8083
        select DVB_STV0299
+       select DVB_STV0297
+       select DVB_LNBP21
        help
          Support for external USB adapters designed by Technotrend and
          produced by Hauppauge, shipped under the brand name 'Nova-USB'.
index 6ceae38125c7546990623d62028e35c56750f4a1..14559ef6153c4ead4a0468e1411a35ef70c5e5ca 100644 (file)
@@ -30,6 +30,8 @@
 #include "tda1004x.h"
 #include "stv0299.h"
 #include "tda8083.h"
+#include "stv0297.h"
+#include "lnbp21.h"
 
 #include <linux/dvb/frontend.h>
 #include <linux/dvb/dmx.h>
@@ -486,31 +488,6 @@ static int ttusb_send_diseqc(struct dvb_frontend* fe,
 }
 #endif
 
-static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
-       struct  ttusb* ttusb = (struct ttusb*)  fe->dvb->priv;
-       int ret;
-       u8 data[1];
-       struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = data, .len = sizeof(data) };
-
-       switch(voltage) {
-       case SEC_VOLTAGE_OFF:
-               data[0] = 0x00;
-               break;
-       case SEC_VOLTAGE_13:
-               data[0] = 0x44;
-               break;
-       case SEC_VOLTAGE_18:
-               data[0] = 0x4c;
-               break;
-       default:
-               return -EINVAL;
-       };
-
-       ret = i2c_transfer(&ttusb->i2c_adap, &msg, 1);
-       return (ret != 1) ? -EIO : 0;
-}
-
 static int ttusb_update_lnb(struct ttusb *ttusb)
 {
        u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1,
@@ -1048,7 +1025,7 @@ static u32 functionality(struct i2c_adapter *adapter)
 
 
 
-static int alps_tdmb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdmb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
        struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
        u8 data[4];
@@ -1062,20 +1039,21 @@ static int alps_tdmb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
        data[2] = ((div >> 10) & 0x60) | 0x85;
        data[3] = params->frequency < 592000000 ? 0x40 : 0x80;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) return -EIO;
        return 0;
 }
 
 static struct cx22700_config alps_tdmb7_config = {
        .demod_address = 0x43,
-       .pll_set = alps_tdmb7_pll_set,
 };
 
 
 
 
 
-static int philips_tdm1316l_pll_init(struct dvb_frontend* fe)
+static int philips_tdm1316l_tuner_init(struct dvb_frontend* fe)
 {
        struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
        static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
@@ -1083,6 +1061,8 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend* fe)
        struct i2c_msg tuner_msg = { .addr=0x60, .flags=0, .buf=td1316_init, .len=sizeof(td1316_init) };
 
        // setup PLL configuration
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO;
        msleep(1);
 
@@ -1090,6 +1070,8 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend* fe)
        tuner_msg.addr = 0x65;
        tuner_msg.buf = disable_mc44BC374c;
        tuner_msg.len = sizeof(disable_mc44BC374c);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
                i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1);
        }
@@ -1097,7 +1079,7 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static int philips_tdm1316l_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
        struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
        u8 tuner_buf[4];
@@ -1157,6 +1139,8 @@ static int philips_tdm1316l_pll_set(struct dvb_frontend* fe, struct dvb_frontend
        tuner_buf[2] = 0xca;
        tuner_buf[3] = (cp << 5) | (filter << 3) | band;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1)
                return -EIO;
 
@@ -1176,8 +1160,6 @@ static struct tda1004x_config philips_tdm1316l_config = {
        .demod_address = 0x8,
        .invert = 1,
        .invert_oclk = 0,
-       .pll_init = philips_tdm1316l_pll_init,
-       .pll_set = philips_tdm1316l_pll_set,
        .request_firmware = philips_tdm1316l_request_firmware,
 };
 
@@ -1299,7 +1281,7 @@ static int alps_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32
        return 0;
 }
 
-static int philips_tsa5059_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params)
+static int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
        struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
        u8 buf[4];
@@ -1322,7 +1304,9 @@ static int philips_tsa5059_pll_set(struct dvb_frontend *fe, struct i2c_adapter *
        if (ttusb->revision == TTUSB_REV_2_2)
                buf[3] |= 0x20;
 
-       if (i2c_transfer(i2c, &msg, 1) != 1)
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1)
                return -EIO;
 
        return 0;
@@ -1338,10 +1322,9 @@ static struct stv0299_config alps_stv0299_config = {
        .volt13_op0_op1 = STV0299_VOLT13_OP1,
        .min_delay_ms = 100,
        .set_symbol_rate = alps_stv0299_set_symbol_rate,
-       .pll_set = philips_tsa5059_pll_set,
 };
 
-static int ttusb_novas_grundig_29504_491_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
        struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
        u8 buf[4];
@@ -1355,6 +1338,8 @@ static int ttusb_novas_grundig_29504_491_pll_set(struct dvb_frontend *fe, struct
        buf[2] = 0x8e;
        buf[3] = 0x00;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1)
                return -EIO;
 
@@ -1364,10 +1349,9 @@ static int ttusb_novas_grundig_29504_491_pll_set(struct dvb_frontend *fe, struct
 static struct tda8083_config ttusb_novas_grundig_29504_491_config = {
 
        .demod_address = 0x68,
-       .pll_set = ttusb_novas_grundig_29504_491_pll_set,
 };
 
-static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
        struct ttusb* ttusb = fe->dvb->priv;
        u32 div;
@@ -1381,6 +1365,8 @@ static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
        data[2] = 0x85 | ((div >> 10) & 0x60);
        data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer (&ttusb->i2c_adap, &msg, 1) != 1)
                return -EIO;
 
@@ -1393,7 +1379,6 @@ static struct ves1820_config alps_tdbe2_config = {
        .xin = 57840000UL,
        .invert = 1,
        .selagc = VES1820_SELAGC_SIGNAMPERR,
-       .pll_set = alps_tdbe2_pll_set,
 };
 
 static u8 read_pwm(struct ttusb* ttusb)
@@ -1410,6 +1395,174 @@ static u8 read_pwm(struct ttusb* ttusb)
 }
 
 
+static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+       struct ttusb *ttusb = (struct ttusb *) fe->dvb->priv;
+       u8 tuner_buf[5];
+       struct i2c_msg tuner_msg = {.addr = 0x60,
+                                   .flags = 0,
+                                   .buf = tuner_buf,
+                                   .len = sizeof(tuner_buf) };
+       int tuner_frequency = 0;
+       u8 band, cp, filter;
+
+       // determine charge pump
+       tuner_frequency = params->frequency;
+       if      (tuner_frequency <  87000000) {return -EINVAL;}
+       else if (tuner_frequency < 130000000) {cp = 3; band = 1;}
+       else if (tuner_frequency < 160000000) {cp = 5; band = 1;}
+       else if (tuner_frequency < 200000000) {cp = 6; band = 1;}
+       else if (tuner_frequency < 290000000) {cp = 3; band = 2;}
+       else if (tuner_frequency < 420000000) {cp = 5; band = 2;}
+       else if (tuner_frequency < 480000000) {cp = 6; band = 2;}
+       else if (tuner_frequency < 620000000) {cp = 3; band = 4;}
+       else if (tuner_frequency < 830000000) {cp = 5; band = 4;}
+       else if (tuner_frequency < 895000000) {cp = 7; band = 4;}
+       else {return -EINVAL;}
+
+       // assume PLL filter should always be 8MHz for the moment.
+       filter = 1;
+
+       // calculate divisor
+       // (Finput + Fif)/Fref; Fif = 36125000 Hz, Fref = 62500 Hz
+       tuner_frequency = ((params->frequency + 36125000) / 62500);
+
+       // setup tuner buffer
+       tuner_buf[0] = tuner_frequency >> 8;
+       tuner_buf[1] = tuner_frequency & 0xff;
+       tuner_buf[2] = 0xc8;
+       tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+       tuner_buf[4] = 0x80;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
+               printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 1\n");
+               return -EIO;
+       }
+
+       msleep(50);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
+               printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 2\n");
+               return -EIO;
+       }
+
+       msleep(1);
+
+       return 0;
+}
+
+static u8 dvbc_philips_tdm1316l_inittab[] = {
+       0x80, 0x21,
+       0x80, 0x20,
+       0x81, 0x01,
+       0x81, 0x00,
+       0x00, 0x09,
+       0x01, 0x69,
+       0x03, 0x00,
+       0x04, 0x00,
+       0x07, 0x00,
+       0x08, 0x00,
+       0x20, 0x00,
+       0x21, 0x40,
+       0x22, 0x00,
+       0x23, 0x00,
+       0x24, 0x40,
+       0x25, 0x88,
+       0x30, 0xff,
+       0x31, 0x00,
+       0x32, 0xff,
+       0x33, 0x00,
+       0x34, 0x50,
+       0x35, 0x7f,
+       0x36, 0x00,
+       0x37, 0x20,
+       0x38, 0x00,
+       0x40, 0x1c,
+       0x41, 0xff,
+       0x42, 0x29,
+       0x43, 0x20,
+       0x44, 0xff,
+       0x45, 0x00,
+       0x46, 0x00,
+       0x49, 0x04,
+       0x4a, 0xff,
+       0x4b, 0x7f,
+       0x52, 0x30,
+       0x55, 0xae,
+       0x56, 0x47,
+       0x57, 0xe1,
+       0x58, 0x3a,
+       0x5a, 0x1e,
+       0x5b, 0x34,
+       0x60, 0x00,
+       0x63, 0x00,
+       0x64, 0x00,
+       0x65, 0x00,
+       0x66, 0x00,
+       0x67, 0x00,
+       0x68, 0x00,
+       0x69, 0x00,
+       0x6a, 0x02,
+       0x6b, 0x00,
+       0x70, 0xff,
+       0x71, 0x00,
+       0x72, 0x00,
+       0x73, 0x00,
+       0x74, 0x0c,
+       0x80, 0x00,
+       0x81, 0x00,
+       0x82, 0x00,
+       0x83, 0x00,
+       0x84, 0x04,
+       0x85, 0x80,
+       0x86, 0x24,
+       0x87, 0x78,
+       0x88, 0x00,
+       0x89, 0x00,
+       0x90, 0x01,
+       0x91, 0x01,
+       0xa0, 0x00,
+       0xa1, 0x00,
+       0xa2, 0x00,
+       0xb0, 0x91,
+       0xb1, 0x0b,
+       0xc0, 0x4b,
+       0xc1, 0x00,
+       0xc2, 0x00,
+       0xd0, 0x00,
+       0xd1, 0x00,
+       0xd2, 0x00,
+       0xd3, 0x00,
+       0xd4, 0x00,
+       0xd5, 0x00,
+       0xde, 0x00,
+       0xdf, 0x00,
+       0x61, 0x38,
+       0x62, 0x0a,
+       0x53, 0x13,
+       0x59, 0x08,
+       0x55, 0x00,
+       0x56, 0x40,
+       0x57, 0x08,
+       0x58, 0x3d,
+       0x88, 0x10,
+       0xa0, 0x00,
+       0xa0, 0x00,
+       0xa0, 0x00,
+       0xa0, 0x04,
+       0xff, 0xff,
+};
+
+static struct stv0297_config dvbc_philips_tdm1316l_config = {
+       .demod_address = 0x1c,
+       .inittab = dvbc_philips_tdm1316l_inittab,
+       .invert = 0,
+};
+
 static void frontend_init(struct ttusb* ttusb)
 {
        switch(le16_to_cpu(ttusb->dev->descriptor.idProduct)) {
@@ -1417,11 +1570,13 @@ static void frontend_init(struct ttusb* ttusb)
                // try the stv0299 based first
                ttusb->fe = stv0299_attach(&alps_stv0299_config, &ttusb->i2c_adap);
                if (ttusb->fe != NULL) {
+                       ttusb->fe->ops.tuner_ops.set_params = philips_tsa5059_tuner_set_params;
+
                        if(ttusb->revision == TTUSB_REV_2_2) { // ALPS BSBE1
                                alps_stv0299_config.inittab = alps_bsbe1_inittab;
-                               ttusb->fe->ops->set_voltage = lnbp21_set_voltage;
+                               lnbp21_attach(ttusb->fe, &ttusb->i2c_adap, 0, 0);
                        } else { // ALPS BSRU6
-                               ttusb->fe->ops->set_voltage = ttusb_set_voltage;
+                               ttusb->fe->ops.set_voltage = ttusb_set_voltage;
                        }
                        break;
                }
@@ -1429,28 +1584,41 @@ static void frontend_init(struct ttusb* ttusb)
                // Grundig 29504-491
                ttusb->fe = tda8083_attach(&ttusb_novas_grundig_29504_491_config, &ttusb->i2c_adap);
                if (ttusb->fe != NULL) {
-                       ttusb->fe->ops->set_voltage = ttusb_set_voltage;
+                       ttusb->fe->ops.tuner_ops.set_params = ttusb_novas_grundig_29504_491_tuner_set_params;
+                       ttusb->fe->ops.set_voltage = ttusb_set_voltage;
                        break;
                }
-
                break;
 
        case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
                ttusb->fe = ves1820_attach(&alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb));
-               if (ttusb->fe != NULL)
+               if (ttusb->fe != NULL) {
+                       ttusb->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+                       break;
+               }
+
+               ttusb->fe = stv0297_attach(&dvbc_philips_tdm1316l_config, &ttusb->i2c_adap);
+               if (ttusb->fe != NULL) {
+                       ttusb->fe->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
                        break;
+               }
                break;
 
        case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??))
                // try the ALPS TDMB7 first
                ttusb->fe = cx22700_attach(&alps_tdmb7_config, &ttusb->i2c_adap);
-               if (ttusb->fe != NULL)
+               if (ttusb->fe != NULL) {
+                       ttusb->fe->ops.tuner_ops.set_params = alps_tdmb7_tuner_set_params;
                        break;
+               }
 
                // Philips td1316
                ttusb->fe = tda10046_attach(&philips_tdm1316l_config, &ttusb->i2c_adap);
-               if (ttusb->fe != NULL)
+               if (ttusb->fe != NULL) {
+                       ttusb->fe->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
+                       ttusb->fe->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
                        break;
+               }
                break;
        }
 
@@ -1461,8 +1629,8 @@ static void frontend_init(struct ttusb* ttusb)
        } else {
                if (dvb_register_frontend(&ttusb->adapter, ttusb->fe)) {
                        printk("dvb-ttusb-budget: Frontend registration failed!\n");
-                       if (ttusb->fe->ops->release)
-                               ttusb->fe->ops->release(ttusb->fe);
+                       if (ttusb->fe->ops.release)
+                               ttusb->fe->ops.release(ttusb->fe);
                        ttusb->fe = NULL;
                }
        }
@@ -1507,7 +1675,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
 
        mutex_unlock(&ttusb->semi2c);
 
-       if ((result = dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE)) < 0) {
+       if ((result = dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE, &udev->dev)) < 0) {
                ttusb_free_iso_urbs(ttusb);
                kfree(ttusb);
                return result;
index 44dea32118483e9dbf14868dd927b84fdfad7ea1..6c1cb770bcf5d28ccecd3ea2d743fc7099bea056 100644 (file)
@@ -1432,7 +1432,7 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec)
        dprintk("%s\n", __FUNCTION__);
 
        if ((result = dvb_register_adapter(&dec->adapter,
-                                          dec->model_name, THIS_MODULE)) < 0) {
+                                          dec->model_name, THIS_MODULE, &dec->udev->dev)) < 0) {
                printk("%s: dvb_register_adapter failed: error %d\n",
                       __FUNCTION__, result);
 
@@ -1657,8 +1657,8 @@ static int ttusb_dec_probe(struct usb_interface *intf,
        } else {
                if (dvb_register_frontend(&dec->adapter, dec->fe)) {
                        printk("budget-ci: Frontend registration failed!\n");
-                       if (dec->fe->ops->release)
-                               dec->fe->ops->release(dec->fe);
+                       if (dec->fe->ops.release)
+                               dec->fe->ops.release(dec->fe);
                        dec->fe = NULL;
                }
        }
index a5a46175fa0969e302e59e75e14afa5a2e5cf2ab..42f39a89bc4d7a05c039e68515394e9b2c59fedc 100644 (file)
@@ -28,8 +28,6 @@
 
 struct ttusbdecfe_state {
 
-       struct dvb_frontend_ops ops;
-
        /* configuration settings */
        const struct ttusbdecfe_config* config;
 
@@ -203,10 +201,9 @@ struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* conf
 
        /* setup the state */
        state->config = config;
-       memcpy(&state->ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops));
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 }
@@ -226,10 +223,9 @@ struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* conf
        state->config = config;
        state->voltage = 0;
        state->hi_band = 0;
-       memcpy(&state->ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops));
 
        /* create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;
 }
index 3fff7576369323b5ff9bc3772408f595e32f0e58..de3128a31de825f6d31b2c9c7a2431d83f7f98b0 100644 (file)
@@ -136,7 +136,7 @@ config RADIO_GEMTEK_PCI
          Choose Y here if you have this PCI FM radio card.
 
          In order to control your radio card, you will need to use programs
-         that are compatible with the Video for Linux API.  Information on 
+         that are compatible with the Video for Linux API.  Information on
          this API and pointers to "v4l" programs may be found at
          <file:Documentation/video4linux/API.html>.
 
index 8b351945d0665caf31f31ade3a241da0b9d6aff0..e95b6805e00257ecdc752a405bc81eba2e443f8a 100644 (file)
@@ -20,3 +20,5 @@ obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
 obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
 obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
+
+EXTRA_CFLAGS += -Isound
index dc292da2605ffb4204dfcfb7c24b1ffc23256c42..c4312fa0e2f5278d071ef5eea2fe12ae82bf970a 100644 (file)
 
 /* What ever you think about the ACI, version 0x07 is not very well!
  * I can't get frequency, 'tuner status', 'tuner flags' or mute/mono
- * conditions...                Robert 
+ * conditions...                Robert
  */
 
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/videodev.h>
-#include "../../../sound/oss/aci.h"
+#include <media/v4l2-common.h>
+#include "oss/aci.h"
 #include "miropcm20-rds-core.h"
 
 static int radio_nr = -1;
@@ -123,7 +124,7 @@ static int pcm20_do_ioctl(struct inode *inode, struct file *file,
        struct video_device *dev = video_devdata(file);
        struct pcm20_device *pcm20 = dev->priv;
        int i;
-       
+
        switch(cmd)
        {
                case VIDIOCGCAP:
@@ -139,7 +140,7 @@ static int pcm20_do_ioctl(struct inode *inode, struct file *file,
                case VIDIOCGTUNER:
                {
                        struct video_tuner *v = arg;
-                       if(v->tuner)    /* Only 1 tuner */ 
+                       if(v->tuner)    /* Only 1 tuner */
                                return -EINVAL;
                        v->rangelow=87*16000;
                        v->rangehigh=108*16000;
@@ -172,7 +173,7 @@ static int pcm20_do_ioctl(struct inode *inode, struct file *file,
                        return i;
                }
                case VIDIOCGAUDIO:
-               {       
+               {
                        struct video_audio *v = arg;
                        memset(v,0, sizeof(*v));
                        v->flags=VIDEO_AUDIO_MUTABLE;
@@ -183,12 +184,12 @@ static int pcm20_do_ioctl(struct inode *inode, struct file *file,
                                v->mode|=VIDEO_SOUND_MONO;
                        /* v->step=2048; */
                        strcpy(v->name, "Radio");
-                       return 0;                       
+                       return 0;
                }
                case VIDIOCSAUDIO:
                {
                        struct video_audio *v = arg;
-                       if(v->audio) 
+                       if(v->audio)
                                return -EINVAL;
 
                        pcm20_mute(pcm20, !!(v->flags&VIDEO_AUDIO_MUTE));
@@ -237,7 +238,7 @@ static int __init pcm20_init(void)
 {
        if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO, radio_nr)==-1)
                goto video_register_device;
-               
+
        if(attach_aci_rds()<0)
                goto attach_aci_rds;
 
index b602c73e2309ea9cf3313f225d32628599175025..9428d8b2642c9b7a103eca1f8b8156d3e66e3935 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/mutex.h>
 
 #include <asm/io.h>
-#include "../../../sound/oss/aci.h"
+#include "oss/aci.h"
 #include "miropcm20-rds-core.h"
 
 #define DEBUG 0
@@ -33,24 +33,24 @@ static struct mutex aci_rds_mutex;
 #define RDS_BUSYMASK        0x10   /* Bit 4 */
 #define RDS_CLOCKMASK       0x08   /* Bit 3 */
 
-#define RDS_DATA(x)         (((x) >> RDS_DATASHIFT) & 1) 
+#define RDS_DATA(x)         (((x) >> RDS_DATASHIFT) & 1)
 
 
 #if DEBUG
 static void print_matrix(char array[], unsigned int length)
 {
-        int i, j;
-
-        for (i=0; i<length; i++) {
-                printk(KERN_DEBUG "aci-rds: ");
-                for (j=7; j>=0; j--) {
-                        printk("%d", (array[i] >> j) & 0x1);
-                }
-                if (i%8 == 0)
-                        printk(" byte-border\n");
-                else
-                        printk("\n");
-        }
+       int i, j;
+
+       for (i=0; i<length; i++) {
+               printk(KERN_DEBUG "aci-rds: ");
+               for (j=7; j>=0; j--) {
+                       printk("%d", (array[i] >> j) & 0x1);
+               }
+               if (i%8 == 0)
+                       printk(" byte-border\n");
+               else
+                       printk("\n");
+       }
 }
 #endif /* DEBUG */
 
@@ -114,7 +114,7 @@ static int rds_write(unsigned char cmd)
 {
        unsigned char sendbuffer[8];
        int i;
-       
+
        if (byte2trans(cmd, sendbuffer, 8) != 0){
                return -1;
        } else {
@@ -151,7 +151,7 @@ static int rds_read(unsigned char databuffer[], int datasize)
           I have to waitread() here */
        if (rds_waitread() < 0)
                return -1;
-       
+
        memset(databuffer, 0, datasize);
 
        for (i=0; i< READSIZE; i++)
@@ -194,7 +194,7 @@ int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize)
                ret = 0;
 
        mutex_unlock(&aci_rds_mutex);
-       
+
        return ret;
 }
 EXPORT_SYMBOL(aci_rds_cmd);
index e09214082e011ef974bdd09297786e3839eef424..87b37b7691dad387cd082b10c030b9c0829947f3 100644 (file)
@@ -48,7 +48,7 @@ static int rds_f_release(struct inode *in, struct file *fi)
 
 static void print_matrix(char *ch, char out[])
 {
-        int j;
+       int j;
 
        for (j=7; j>=0; j--) {
                 out[7-j] = ((*ch >> j) & 0x1) + '0';
index 557fb5c4af38ea59c5fad2cc3ae80cc29e125760..df22a582e7a2fae4762b07801313eec005bbc66d 100644 (file)
@@ -24,7 +24,7 @@
  *   out(port, start_increasing_volume);
  *   wait(a_wee_while);
  *   out(port, stop_changing_the_volume);
- *  
+ *
  */
 
 #include <linux/module.h>      /* Modules                      */
@@ -34,6 +34,7 @@
 #include <asm/io.h>            /* outb, outb_p                 */
 #include <asm/uaccess.h>       /* copy to/from user            */
 #include <linux/videodev.h>    /* kernel radio structs         */
+#include <media/v4l2-common.h>
 #include <linux/config.h>      /* CONFIG_RADIO_RTRACK_PORT     */
 #include <asm/semaphore.h>     /* Lock for the I/O             */
 
@@ -41,7 +42,7 @@
 #define CONFIG_RADIO_RTRACK_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_RTRACK_PORT; 
+static int io = CONFIG_RADIO_RTRACK_PORT;
 static int radio_nr = -1;
 static struct mutex lock;
 
@@ -93,12 +94,12 @@ static int rt_setvol(struct rt_device *dev, int vol)
        int i;
 
        mutex_lock(&lock);
-       
+
        if(vol == dev->curvol) {        /* requested volume = current */
                if (dev->muted) {       /* user is unmuting the card  */
                        dev->muted = 0;
                        outb (0xd8, io);        /* enable card */
-               }       
+               }
                mutex_unlock(&lock);
                return 0;
        }
@@ -114,10 +115,10 @@ static int rt_setvol(struct rt_device *dev, int vol)
 
        dev->muted = 0;
        if(vol > dev->curvol)
-               for(i = dev->curvol; i < vol; i++) 
+               for(i = dev->curvol; i < vol; i++)
                        rt_incvol();
        else
-               for(i = dev->curvol; i > vol; i--) 
+               for(i = dev->curvol; i > vol; i--)
                        rt_decvol();
 
        dev->curvol = vol;
@@ -125,7 +126,7 @@ static int rt_setvol(struct rt_device *dev, int vol)
        return 0;
 }
 
-/* the 128+64 on these outb's is to keep the volume stable while tuning 
+/* the 128+64 on these outb's is to keep the volume stable while tuning
  * without them, the volume _will_ creep up with each frequency change
  * and bit 4 (+16) is to keep the signal strength meter enabled
  */
@@ -140,7 +141,7 @@ static void send_0_byte(int port, struct rt_device *dev)
                outb_p(128+64+16+8+  1, port);  /* on + wr-enable + data low */
                outb_p(128+64+16+8+2+1, port);  /* clock */
        }
-       sleep_delay(1000); 
+       sleep_delay(1000);
 }
 
 static void send_1_byte(int port, struct rt_device *dev)
@@ -148,13 +149,13 @@ static void send_1_byte(int port, struct rt_device *dev)
        if ((dev->curvol == 0) || (dev->muted)) {
                outb_p(128+64+16+4  +1, port);   /* wr-enable+data high */
                outb_p(128+64+16+4+2+1, port);   /* clock */
-       } 
+       }
        else {
                outb_p(128+64+16+8+4  +1, port); /* on+wr-enable+data high */
                outb_p(128+64+16+8+4+2+1, port); /* clock */
        }
 
-       sleep_delay(1000); 
+       sleep_delay(1000);
 }
 
 static int rt_setfreq(struct rt_device *dev, unsigned long freq)
@@ -167,9 +168,9 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
 
        freq += 171200;                 /* Add 10.7 MHz IF              */
        freq /= 800;                    /* Convert to 50 kHz units      */
-       
+
        mutex_lock(&lock);                      /* Stop other ops interfering */
-        
+
        send_0_byte (io, dev);          /*  0: LSB of frequency         */
 
        for (i = 0; i < 13; i++)        /*   : frequency bits (1-13)    */
@@ -195,7 +196,7 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
                outb (0xd0, io);        /* volume steady + sigstr */
        else
                outb (0xd8, io);        /* volume steady + sigstr + on */
-               
+
        mutex_unlock(&lock);
 
        return 0;
@@ -213,7 +214,7 @@ static int rt_do_ioctl(struct inode *inode, struct file *file,
 {
        struct video_device *dev = video_devdata(file);
        struct rt_device *rt=dev->priv;
-       
+
        switch(cmd)
        {
                case VIDIOCGCAP:
@@ -229,7 +230,7 @@ static int rt_do_ioctl(struct inode *inode, struct file *file,
                case VIDIOCGTUNER:
                {
                        struct video_tuner *v = arg;
-                       if(v->tuner)    /* Only 1 tuner */ 
+                       if(v->tuner)    /* Only 1 tuner */
                                return -EINVAL;
                        v->rangelow=(87*16000);
                        v->rangehigh=(108*16000);
@@ -261,21 +262,21 @@ static int rt_do_ioctl(struct inode *inode, struct file *file,
                        return 0;
                }
                case VIDIOCGAUDIO:
-               {       
+               {
                        struct video_audio *v = arg;
                        memset(v,0, sizeof(*v));
                        v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
                        v->volume=rt->curvol * 6554;
                        v->step=6554;
                        strcpy(v->name, "Radio");
-                       return 0;                       
+                       return 0;
                }
                case VIDIOCSAUDIO:
                {
                        struct video_audio *v = arg;
-                       if(v->audio) 
+                       if(v->audio)
                                return -EINVAL;
-                       if(v->flags&VIDEO_AUDIO_MUTE) 
+                       if(v->flags&VIDEO_AUDIO_MUTE)
                                rt_mute(rt);
                        else
                                rt_setvol(rt,v->volume/6554);
@@ -298,7 +299,7 @@ static struct file_operations rtrack_fops = {
        .owner          = THIS_MODULE,
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
-       .ioctl          = rt_ioctl,
+       .ioctl          = rt_ioctl,
        .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
@@ -320,14 +321,14 @@ static int __init rtrack_init(void)
                return -EINVAL;
        }
 
-       if (!request_region(io, 2, "rtrack")) 
+       if (!request_region(io, 2, "rtrack"))
        {
                printk(KERN_ERR "rtrack: port 0x%x already in use\n", io);
                return -EBUSY;
        }
 
        rtrack_radio.priv=&rtrack_unit;
-       
+
        if(video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr)==-1)
        {
                release_region(io, 2);
@@ -336,10 +337,10 @@ static int __init rtrack_init(void)
        printk(KERN_INFO "AIMSlab RadioTrack/RadioReveal card driver.\n");
 
        /* Set up the I/O locking */
-       
+
        mutex_init(&lock);
-       
-       /* mute card - prevents noisy bootups */
+
+       /* mute card - prevents noisy bootups */
 
        /* this ensures that the volume is all the way down  */
        outb(0x48, io);         /* volume down but still "on"   */
index 83bdae23417d930386d600850df4f51ecab1d4b4..95e6322133ee43289c1077af080cf50a57825db8 100644 (file)
@@ -1,11 +1,11 @@
-/* radio-aztech.c - Aztech radio card driver for Linux 2.2 
+/* radio-aztech.c - Aztech radio card driver for Linux 2.2
  *
- * Adapted to support the Video for Linux API by 
+ * Adapted to support the Video for Linux API by
  * Russell Kroll <rkroll@exploits.org>.  Based on original tuner code by:
  *
  * Quay Ly
  * Donald Song
- * Jason Lewis      (jlewis@twilight.vtc.vsc.edu) 
+ * Jason Lewis      (jlewis@twilight.vtc.vsc.edu)
  * Scott McGrath    (smcgrath@twilight.vtc.vsc.edu)
  * William McGrath  (wmcgrath@twilight.vtc.vsc.edu)
  *
@@ -31,6 +31,7 @@
 #include <asm/io.h>            /* outb, outb_p                 */
 #include <asm/uaccess.h>       /* copy to/from user            */
 #include <linux/videodev.h>    /* kernel radio structs         */
+#include <media/v4l2-common.h>
 #include <linux/config.h>      /* CONFIG_RADIO_AZTECH_PORT     */
 
 /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
@@ -39,7 +40,7 @@
 #define CONFIG_RADIO_AZTECH_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_AZTECH_PORT; 
+static int io = CONFIG_RADIO_AZTECH_PORT;
 static int radio_nr = -1;
 static int radio_wait_time = 1000;
 static struct mutex lock;
@@ -53,15 +54,15 @@ struct az_device
 
 static int volconvert(int level)
 {
-       level>>=14;             /* Map 16bits down to 2 bit */
-       level&=3;
-       
+       level>>=14;             /* Map 16bits down to 2 bit */
+       level&=3;
+
        /* convert to card-friendly values */
-       switch (level) 
+       switch (level)
        {
-               case 0: 
+               case 0:
                        return 0;
-               case 1: 
+               case 1:
                        return 1;
                case 2:
                        return 4;
@@ -121,9 +122,9 @@ static int az_setfreq(struct az_device *dev, unsigned long frequency)
 
        frequency += 171200;            /* Add 10.7 MHz IF              */
        frequency /= 800;               /* Convert to 50 kHz units      */
-                                       
+
        mutex_lock(&lock);
-       
+
        send_0_byte (dev);              /*  0: LSB of frequency       */
 
        for (i = 0; i < 13; i++)        /*   : frequency bits (1-13)  */
@@ -151,7 +152,7 @@ static int az_setfreq(struct az_device *dev, unsigned long frequency)
 
        udelay (radio_wait_time);
        outb_p(128+64+volconvert(dev->curvol), io);
-       
+
        mutex_unlock(&lock);
 
        return 0;
@@ -162,7 +163,7 @@ static int az_do_ioctl(struct inode *inode, struct file *file,
 {
        struct video_device *dev = video_devdata(file);
        struct az_device *az = dev->priv;
-       
+
        switch(cmd)
        {
                case VIDIOCGCAP:
@@ -178,7 +179,7 @@ static int az_do_ioctl(struct inode *inode, struct file *file,
                case VIDIOCGTUNER:
                {
                        struct video_tuner *v = arg;
-                       if(v->tuner)    /* Only 1 tuner */ 
+                       if(v->tuner)    /* Only 1 tuner */
                                return -EINVAL;
                        v->rangelow=(87*16000);
                        v->rangehigh=(108*16000);
@@ -211,7 +212,7 @@ static int az_do_ioctl(struct inode *inode, struct file *file,
                        return 0;
                }
                case VIDIOCGAUDIO:
-               {       
+               {
                        struct video_audio *v = arg;
                        memset(v,0, sizeof(*v));
                        v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
@@ -222,17 +223,17 @@ static int az_do_ioctl(struct inode *inode, struct file *file,
                        v->volume=az->curvol;
                        v->step=16384;
                        strcpy(v->name, "Radio");
-                       return 0;                       
+                       return 0;
                }
                case VIDIOCSAUDIO:
                {
                        struct video_audio *v = arg;
-                       if(v->audio) 
+                       if(v->audio)
                                return -EINVAL;
                        az->curvol=v->volume;
 
                        az->stereo=(v->mode&VIDEO_SOUND_STEREO)?1:0;
-                       if(v->flags&VIDEO_AUDIO_MUTE) 
+                       if(v->flags&VIDEO_AUDIO_MUTE)
                                az_setvol(az,0);
                        else
                                az_setvol(az,az->curvol);
@@ -277,7 +278,7 @@ static int __init aztech_init(void)
                return -EINVAL;
        }
 
-       if (!request_region(io, 2, "aztech")) 
+       if (!request_region(io, 2, "aztech"))
        {
                printk(KERN_ERR "aztech: port 0x%x already in use\n", io);
                return -EBUSY;
@@ -285,13 +286,13 @@ static int __init aztech_init(void)
 
        mutex_init(&lock);
        aztech_radio.priv=&aztech_unit;
-       
+
        if(video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr)==-1)
        {
                release_region(io,2);
                return -EINVAL;
        }
-               
+
        printk(KERN_INFO "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n");
        /* mute card - prevents noisy bootups */
        outb (0, io);
index f1b5ac81e9d2bc734d6dd3345c12d0bd46fa235e..8641aec7baf87093e8faf1ea90331d913abe0ca9 100644 (file)
@@ -8,7 +8,7 @@
  * Russell Kroll    (rkroll@exploits.org)
  * Quay Ly
  * Donald Song
- * Jason Lewis      (jlewis@twilight.vtc.vsc.edu) 
+ * Jason Lewis      (jlewis@twilight.vtc.vsc.edu)
  * Scott McGrath    (smcgrath@twilight.vtc.vsc.edu)
  * William McGrath  (wmcgrath@twilight.vtc.vsc.edu)
  *
@@ -34,6 +34,7 @@
 #include <asm/io.h>            /* outb, outb_p                 */
 #include <asm/uaccess.h>       /* copy to/from user            */
 #include <linux/videodev.h>    /* kernel radio structs         */
+#include <media/v4l2-common.h>
 #include <linux/param.h>
 #include <linux/pnp.h>
 
@@ -55,29 +56,29 @@ static int cadet_probe(void);
 
 /*
  * Signal Strength Threshold Values
- * The V4L API spec does not define any particular unit for the signal 
+ * The V4L API spec does not define any particular unit for the signal
  * strength value.  These values are in microvolts of RF at the tuner's input.
  */
 static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}};
 
 static int cadet_getrds(void)
 {
-        int rdsstat=0;
+       int rdsstat=0;
 
        spin_lock(&cadet_io_lock);
-        outb(3,io);                 /* Select Decoder Control/Status */
+       outb(3,io);                 /* Select Decoder Control/Status */
        outb(inb(io+1)&0x7f,io+1);  /* Reset RDS detection */
        spin_unlock(&cadet_io_lock);
-       
+
        msleep(100);
 
-       spin_lock(&cadet_io_lock);      
-        outb(3,io);                 /* Select Decoder Control/Status */
+       spin_lock(&cadet_io_lock);
+       outb(3,io);                 /* Select Decoder Control/Status */
        if((inb(io+1)&0x80)!=0) {
-               rdsstat|=VIDEO_TUNER_RDS_ON;
+               rdsstat|=VIDEO_TUNER_RDS_ON;
        }
        if((inb(io+1)&0x10)!=0) {
-               rdsstat|=VIDEO_TUNER_MBS_ON;
+               rdsstat|=VIDEO_TUNER_MBS_ON;
        }
        spin_unlock(&cadet_io_lock);
        return rdsstat;
@@ -86,49 +87,49 @@ static int cadet_getrds(void)
 static int cadet_getstereo(void)
 {
        int ret = 0;
-        if(curtuner != 0)      /* Only FM has stereo capability! */
-               return 0;
+       if(curtuner != 0)       /* Only FM has stereo capability! */
+               return 0;
 
        spin_lock(&cadet_io_lock);
-        outb(7,io);          /* Select tuner control */
+       outb(7,io);          /* Select tuner control */
        if( (inb(io+1) & 0x40) == 0)
-               ret = 1;
-        spin_unlock(&cadet_io_lock);
-        return ret;
+               ret = 1;
+       spin_unlock(&cadet_io_lock);
+       return ret;
 }
 
 static unsigned cadet_gettune(void)
 {
-        int curvol,i;
+       int curvol,i;
        unsigned fifo=0;
 
-        /*
-         * Prepare for read
-         */
+       /*
+        * Prepare for read
+        */
 
        spin_lock(&cadet_io_lock);
-       
-        outb(7,io);       /* Select tuner control */
-        curvol=inb(io+1); /* Save current volume/mute setting */
-        outb(0x00,io+1);  /* Ensure WRITE-ENABLE is LOW */
+
+       outb(7,io);       /* Select tuner control */
+       curvol=inb(io+1); /* Save current volume/mute setting */
+       outb(0x00,io+1);  /* Ensure WRITE-ENABLE is LOW */
        tunestat=0xffff;
 
-        /*
-         * Read the shift register
-         */
-        for(i=0;i<25;i++) {
-                fifo=(fifo<<1)|((inb(io+1)>>7)&0x01);
-                if(i<24) {
-                        outb(0x01,io+1);
+       /*
+        * Read the shift register
+        */
+       for(i=0;i<25;i++) {
+               fifo=(fifo<<1)|((inb(io+1)>>7)&0x01);
+               if(i<24) {
+                       outb(0x01,io+1);
                        tunestat&=inb(io+1);
-                        outb(0x00,io+1);
-                }
-        }
-
-        /*
-         * Restore volume/mute setting
-         */
-        outb(curvol,io+1);
+                       outb(0x00,io+1);
+               }
+       }
+
+       /*
+        * Restore volume/mute setting
+        */
+       outb(curvol,io+1);
        spin_unlock(&cadet_io_lock);
 
        return fifo;
@@ -136,43 +137,43 @@ static unsigned cadet_gettune(void)
 
 static unsigned cadet_getfreq(void)
 {
-        int i;
-        unsigned freq=0,test,fifo=0;
+       int i;
+       unsigned freq=0,test,fifo=0;
 
        /*
         * Read current tuning
         */
        fifo=cadet_gettune();
 
-        /*
-         * Convert to actual frequency
-         */
+       /*
+        * Convert to actual frequency
+        */
        if(curtuner==0) {    /* FM */
-               test=12500;
-                for(i=0;i<14;i++) {
-                        if((fifo&0x01)!=0) {
-                                freq+=test;
-                        }
-                        test=test<<1;
-                        fifo=fifo>>1;
-                }
-                freq-=10700000;           /* IF frequency is 10.7 MHz */
-                freq=(freq*16)/1000000;   /* Make it 1/16 MHz */
+               test=12500;
+               for(i=0;i<14;i++) {
+                       if((fifo&0x01)!=0) {
+                               freq+=test;
+                       }
+                       test=test<<1;
+                       fifo=fifo>>1;
+               }
+               freq-=10700000;           /* IF frequency is 10.7 MHz */
+               freq=(freq*16)/1000000;   /* Make it 1/16 MHz */
        }
        if(curtuner==1) {    /* AM */
-               freq=((fifo&0x7fff)-2010)*16;
+               freq=((fifo&0x7fff)-2010)*16;
        }
 
-        return freq;
+       return freq;
 }
 
 static void cadet_settune(unsigned fifo)
 {
-        int i;
-       unsigned test;  
+       int i;
+       unsigned test;
 
        spin_lock(&cadet_io_lock);
-       
+
        outb(7,io);                /* Select tuner control */
        /*
         * Write the shift register
@@ -183,7 +184,7 @@ static void cadet_settune(unsigned fifo)
        outb(7,io);                /* Select tuner control */
        outb(test,io+1);           /* Initialize for write */
        for(i=0;i<25;i++) {
-               test|=0x01;              /* Toggle SCK High */
+               test|=0x01;              /* Toggle SCK High */
                outb(test,io+1);
                test&=0xfe;              /* Toggle SCK Low */
                outb(test,io+1);
@@ -196,57 +197,57 @@ static void cadet_settune(unsigned fifo)
 
 static void cadet_setfreq(unsigned freq)
 {
-        unsigned fifo;
-        int i,j,test;
-        int curvol;
+       unsigned fifo;
+       int i,j,test;
+       int curvol;
 
-        /* 
-         * Formulate a fifo command
-         */
+       /*
+        * Formulate a fifo command
+        */
        fifo=0;
        if(curtuner==0) {    /* FM */
-               test=102400;
-                freq=(freq*1000)/16;       /* Make it kHz */
-                freq+=10700;               /* IF is 10700 kHz */
-                for(i=0;i<14;i++) {
-                        fifo=fifo<<1;
-                        if(freq>=test) {
-                                fifo|=0x01;
-                                freq-=test;
-                        }
-                        test=test>>1;
-                }
+               test=102400;
+               freq=(freq*1000)/16;       /* Make it kHz */
+               freq+=10700;               /* IF is 10700 kHz */
+               for(i=0;i<14;i++) {
+                       fifo=fifo<<1;
+                       if(freq>=test) {
+                               fifo|=0x01;
+                               freq-=test;
+                       }
+                       test=test>>1;
+               }
        }
        if(curtuner==1) {    /* AM */
-                fifo=(freq/16)+2010;            /* Make it kHz */
+               fifo=(freq/16)+2010;            /* Make it kHz */
                fifo|=0x100000;            /* Select AM Band */
        }
 
-        /*
-         * Save current volume/mute setting
-         */
+       /*
+        * Save current volume/mute setting
+        */
 
        spin_lock(&cadet_io_lock);
        outb(7,io);                /* Select tuner control */
-        curvol=inb(io+1); 
-        spin_unlock(&cadet_io_lock);
+       curvol=inb(io+1);
+       spin_unlock(&cadet_io_lock);
 
        /*
         * Tune the card
         */
        for(j=3;j>-1;j--) {
-               cadet_settune(fifo|(j<<16));
-               
-               spin_lock(&cadet_io_lock);
+               cadet_settune(fifo|(j<<16));
+
+               spin_lock(&cadet_io_lock);
                outb(7,io);         /* Select tuner control */
                outb(curvol,io+1);
                spin_unlock(&cadet_io_lock);
-               
+
                msleep(100);
 
                cadet_gettune();
                if((tunestat & 0x40) == 0) {   /* Tuned */
-                       sigstrength=sigtable[curtuner][j];
+                       sigstrength=sigtable[curtuner][j];
                        return;
                }
        }
@@ -257,28 +258,28 @@ static void cadet_setfreq(unsigned freq)
 static int cadet_getvol(void)
 {
        int ret = 0;
-       
+
        spin_lock(&cadet_io_lock);
-       
-        outb(7,io);                /* Select tuner control */
-        if((inb(io + 1) & 0x20) != 0)
-               ret = 0xffff;
-        
-        spin_unlock(&cadet_io_lock);
-        return ret;
+
+       outb(7,io);                /* Select tuner control */
+       if((inb(io + 1) & 0x20) != 0)
+               ret = 0xffff;
+
+       spin_unlock(&cadet_io_lock);
+       return ret;
 }
 
 
 static void cadet_setvol(int vol)
 {
        spin_lock(&cadet_io_lock);
-        outb(7,io);                /* Select tuner control */
-        if(vol>0)
-                outb(0x20,io+1);
-        else
-                outb(0x00,io+1);
+       outb(7,io);                /* Select tuner control */
+       if(vol>0)
+               outb(0x20,io+1);
+       else
+               outb(0x00,io+1);
        spin_unlock(&cadet_io_lock);
-}  
+}
 
 static void cadet_handler(unsigned long data)
 {
@@ -288,15 +289,15 @@ static void cadet_handler(unsigned long data)
 
        if(spin_trylock(&cadet_io_lock))
        {
-               outb(0x3,io);       /* Select RDS Decoder Control */
+               outb(0x3,io);       /* Select RDS Decoder Control */
                if((inb(io+1)&0x20)!=0) {
-                       printk(KERN_CRIT "cadet: RDS fifo overflow\n");
+                       printk(KERN_CRIT "cadet: RDS fifo overflow\n");
                }
                outb(0x80,io);      /* Select RDS fifo */
                while((inb(io)&0x80)!=0) {
-                       rdsbuf[rdsin]=inb(io+1);
+                       rdsbuf[rdsin]=inb(io+1);
                        if(rdsin==rdsout)
-                               printk(KERN_WARNING "cadet: RDS buffer overflow\n");
+                               printk(KERN_WARNING "cadet: RDS buffer overflow\n");
                        else
                                rdsin++;
                }
@@ -307,9 +308,9 @@ static void cadet_handler(unsigned long data)
         * Service pending read
         */
        if( rdsin!=rdsout)
-               wake_up_interruptible(&read_queue);
+               wake_up_interruptible(&read_queue);
 
-       /* 
+       /*
         * Clean up and exit
         */
        init_timer(&readtimer);
@@ -324,12 +325,12 @@ static void cadet_handler(unsigned long data)
 static ssize_t cadet_read(struct file *file, char __user *data,
                          size_t count, loff_t *ppos)
 {
-        int i=0;
+       int i=0;
        unsigned char readbuf[RDS_BUFFER];
 
-        if(rdsstat==0) {
+       if(rdsstat==0) {
                spin_lock(&cadet_io_lock);
-               rdsstat=1;
+               rdsstat=1;
                outb(0x80,io);        /* Select RDS fifo */
                spin_unlock(&cadet_io_lock);
                init_timer(&readtimer);
@@ -339,15 +340,15 @@ static ssize_t cadet_read(struct file *file, char __user *data,
                add_timer(&readtimer);
        }
        if(rdsin==rdsout) {
-               if (file->f_flags & O_NONBLOCK)
-                       return -EWOULDBLOCK;
-               interruptible_sleep_on(&read_queue);
-       }               
+               if (file->f_flags & O_NONBLOCK)
+                       return -EWOULDBLOCK;
+               interruptible_sleep_on(&read_queue);
+       }
        while( i<count && rdsin!=rdsout)
-               readbuf[i++]=rdsbuf[rdsout++];
+               readbuf[i++]=rdsbuf[rdsout++];
 
        if (copy_to_user(data,readbuf,i))
-               return -EFAULT;
+               return -EFAULT;
        return i;
 }
 
@@ -375,29 +376,29 @@ static int cadet_do_ioctl(struct inode *inode, struct file *file,
                                return -EINVAL;
                        }
                        switch(v->tuner) {
-                               case 0:
-                               strcpy(v->name,"FM");
-                               v->rangelow=1400;     /* 87.5 MHz */
-                               v->rangehigh=1728;    /* 108.0 MHz */
-                               v->flags=0;
-                               v->mode=0;
-                               v->mode|=VIDEO_MODE_AUTO;
-                               v->signal=sigstrength;
-                               if(cadet_getstereo()==1) {
-                                       v->flags|=VIDEO_TUNER_STEREO_ON;
-                               }
+                               case 0:
+                               strcpy(v->name,"FM");
+                               v->rangelow=1400;     /* 87.5 MHz */
+                               v->rangehigh=1728;    /* 108.0 MHz */
+                               v->flags=0;
+                               v->mode=0;
+                               v->mode|=VIDEO_MODE_AUTO;
+                               v->signal=sigstrength;
+                               if(cadet_getstereo()==1) {
+                                       v->flags|=VIDEO_TUNER_STEREO_ON;
+                               }
                                v->flags|=cadet_getrds();
-                               break;
-                               case 1:
-                               strcpy(v->name,"AM");
-                               v->rangelow=8320;      /* 520 kHz */
-                               v->rangehigh=26400;    /* 1650 kHz */
-                               v->flags=0;
-                               v->flags|=VIDEO_TUNER_LOW;
-                               v->mode=0;
-                               v->mode|=VIDEO_MODE_AUTO;
-                               v->signal=sigstrength;
-                               break;
+                               break;
+                               case 1:
+                               strcpy(v->name,"AM");
+                               v->rangelow=8320;      /* 520 kHz */
+                               v->rangehigh=26400;    /* 1650 kHz */
+                               v->flags=0;
+                               v->flags|=VIDEO_TUNER_LOW;
+                               v->mode=0;
+                               v->mode|=VIDEO_MODE_AUTO;
+                               v->signal=sigstrength;
+                               break;
                        }
                        return 0;
                }
@@ -407,49 +408,49 @@ static int cadet_do_ioctl(struct inode *inode, struct file *file,
                        if((v->tuner<0)||(v->tuner>1)) {
                                return -EINVAL;
                        }
-                       curtuner=v->tuner;      
+                       curtuner=v->tuner;
                        return 0;
                }
                case VIDIOCGFREQ:
                {
-                       unsigned long *freq = arg;
+                       unsigned long *freq = arg;
                        *freq = cadet_getfreq();
                        return 0;
                }
                case VIDIOCSFREQ:
                {
-                       unsigned long *freq = arg;
+                       unsigned long *freq = arg;
                        if((curtuner==0)&&((*freq<1400)||(*freq>1728))) {
-                               return -EINVAL;
+                               return -EINVAL;
                        }
                        if((curtuner==1)&&((*freq<8320)||(*freq>26400))) {
-                               return -EINVAL;
+                               return -EINVAL;
                        }
                        cadet_setfreq(*freq);
                        return 0;
                }
                case VIDIOCGAUDIO:
-               {       
+               {
                        struct video_audio *v = arg;
                        memset(v,0, sizeof(*v));
                        v->flags=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
                        if(cadet_getstereo()==0) {
-                               v->mode=VIDEO_SOUND_MONO;
+                               v->mode=VIDEO_SOUND_MONO;
                        } else {
                                v->mode=VIDEO_SOUND_STEREO;
                        }
                        v->volume=cadet_getvol();
                        v->step=0xffff;
                        strcpy(v->name, "Radio");
-                       return 0;                       
+                       return 0;
                }
                case VIDIOCSAUDIO:
                {
                        struct video_audio *v = arg;
-                       if(v->audio) 
+                       if(v->audio)
                                return -EINVAL;
                        cadet_setvol(v->volume);
-                       if(v->flags&VIDEO_AUDIO_MUTE) 
+                       if(v->flags&VIDEO_AUDIO_MUTE)
                                cadet_setvol(0);
                        else
                                cadet_setvol(0xffff);
@@ -539,16 +540,16 @@ static struct pnp_driver cadet_pnp_driver = {
 
 static int cadet_probe(void)
 {
-        static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e};
+       static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e};
        int i;
 
        for(i=0;i<8;i++) {
-               io=iovals[i];
+               io=iovals[i];
                if (request_region(io, 2, "cadet-probe")) {
-                       cadet_setfreq(1410);
+                       cadet_setfreq(1410);
                        if(cadet_getfreq()==1410) {
                                release_region(io, 2);
-                               return io;
+                               return io;
                        }
                        release_region(io, 2);
                }
@@ -556,7 +557,7 @@ static int cadet_probe(void)
        return -1;
 }
 
-/* 
+/*
  * io should only be set if the user has used something like
  * isapnp (the userspace program) to initialize this card for us
  */
@@ -564,7 +565,7 @@ static int cadet_probe(void)
 static int __init cadet_init(void)
 {
        spin_lock_init(&cadet_io_lock);
-       
+
        /*
         *      If a probe was requested then probe ISAPnP first (safest)
         */
@@ -579,12 +580,12 @@ static int __init cadet_init(void)
        /*
         *      Else we bail out
         */
-        
-        if(io < 0) {
-#ifdef MODULE        
+
+       if(io < 0) {
+#ifdef MODULE
                printk(KERN_ERR "You must set an I/O address with io=0x???\n");
 #endif
-               goto fail;
+               goto fail;
        }
        if (!request_region(io,2,"cadet"))
                goto fail;
index 8e499b8f64c79e88474db41b93f6ae824c164db1..9f249e7e60c9b16d2a0d9b4081d18ea28a478d20 100644 (file)
@@ -1,6 +1,6 @@
 /*
  ***************************************************************************
- *     
+ *
  *     radio-gemtek-pci.c - Gemtek PCI Radio driver
  *     (C) 2001 Vladimir Shebordaev <vshebordaev@mail.ru>
  *
@@ -31,7 +31,7 @@
  *     radio device driver.
  *
  *     Please, let me know if this piece of code was useful :)
- * 
+ *
  *     TODO: multiple device support and portability were not tested
  *
  ***************************************************************************
@@ -44,6 +44,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/errno.h>
 
 #include <asm/io.h>
 #define TRUE (1)
 #endif
 
-#ifndef FALSE 
+#ifndef FALSE
 #define FALSE (0)
 #endif
 
 struct gemtek_pci_card {
        struct video_device *videodev;
-       
+
        u32 iobase;
        u32 length;
        u8  chiprev;
        u16 model;
-       
+
        u32 current_frequency;
        u8  mute;
 };
@@ -96,7 +97,7 @@ static inline u8 gemtek_pci_out( u16 value, u32 port )
        return (u8)value;
 }
 
-#define _b0( v ) *((u8 *)&v)  
+#define _b0( v ) *((u8 *)&v)
 static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
 {
        register u8 byte = *last_byte;
@@ -104,7 +105,7 @@ static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
        if ( !value ) {
                if ( !keep )
                        value = (u16)port;
-               byte &= 0xfd;   
+               byte &= 0xfd;
        } else
                byte |= 2;
 
@@ -116,7 +117,7 @@ static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
        byte &= 0xfe;
        _b0( value ) = byte;
        outw( value, port );
-       
+
        *last_byte = byte;
 }
 
@@ -193,13 +194,13 @@ static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file,
                        c->audios = 1;
                        strcpy( c->name, "Gemtek PCI Radio" );
                        return 0;
-               } 
+               }
 
                case VIDIOCGTUNER:
                {
                        struct video_tuner *t = arg;
 
-                       if ( t->tuner ) 
+                       if ( t->tuner )
                                return -EINVAL;
 
                        t->rangelow = GEMTEK_PCI_RANGE_LOW;
@@ -228,7 +229,7 @@ static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file,
                case VIDIOCSFREQ:
                {
                        unsigned long *freq = arg;
-        
+
                        if ( (*freq < GEMTEK_PCI_RANGE_LOW) ||
                             (*freq > GEMTEK_PCI_RANGE_HIGH) )
                                return -EINVAL;
@@ -239,9 +240,9 @@ static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file,
 
                        return 0;
                }
-  
+
                case VIDIOCGAUDIO:
-               {       
+               {
                        struct video_audio *a = arg;
 
                        memset( a, 0, sizeof( *a ) );
@@ -249,17 +250,17 @@ static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file,
                        a->volume = 1;
                        a->step = 65535;
                        strcpy( a->name, "Radio" );
-                       return 0;                       
+                       return 0;
                }
 
                case VIDIOCSAUDIO:
                {
                        struct video_audio *a = arg;
 
-                       if ( a->audio ) 
+                       if ( a->audio )
                                return -EINVAL;
 
-                       if ( a->flags & VIDEO_AUDIO_MUTE ) 
+                       if ( a->flags & VIDEO_AUDIO_MUTE )
                                gemtek_pci_mute( card );
                        else
                                gemtek_pci_unmute( card );
@@ -323,9 +324,9 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci
                return -ENOMEM;
        }
 
-       if ( pci_enable_device( pci_dev ) ) 
+       if ( pci_enable_device( pci_dev ) )
                goto err_pci;
-       
+
        card->iobase = pci_resource_start( pci_dev, 0 );
        card->length = pci_resource_len( pci_dev, 0 );
 
@@ -338,7 +339,7 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci
        pci_read_config_word( pci_dev, PCI_SUBSYSTEM_ID, &card->model );
 
        pci_set_drvdata( pci_dev, card );
+
        if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) {
                printk( KERN_ERR "gemtek_pci: out of memory\n" );
                goto err_video;
@@ -354,7 +355,7 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci
        devradio->priv = card;
        gemtek_pci_mute( card );
 
-       printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n", 
+       printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
                card->chiprev, card->iobase, card->iobase + card->length - 1 );
 
        return 0;
@@ -364,7 +365,7 @@ err_video:
 
 err_pci:
        kfree( card );
-       return -ENODEV;        
+       return -ENODEV;
 }
 
 static void __devexit gemtek_pci_remove( struct pci_dev *pci_dev )
@@ -375,12 +376,12 @@ static void __devexit gemtek_pci_remove( struct pci_dev *pci_dev )
        kfree( card->videodev );
 
        release_region( card->iobase, card->length );
-       
+
        if ( mx )
                gemtek_pci_mute( card );
 
        kfree( card );
-       
+
        pci_set_drvdata( pci_dev, NULL );
 }
 
index 47173be97b9fa5dbd74d84e6e5ebce0007393609..162f37d8bf9623f52d9e46dc120089c53879b628 100644 (file)
@@ -6,7 +6,7 @@
  * Besides the protocol changes, this is mostly a copy of:
  *
  *    RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
- * 
+ *
  *    Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
  *    Converted to new API by Alan Cox <Alan.Cox@linux.org>
  *    Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
@@ -22,6 +22,7 @@
 #include <asm/io.h>            /* outb, outb_p                 */
 #include <asm/uaccess.h>       /* copy to/from user            */
 #include <linux/videodev.h>    /* kernel radio structs         */
+#include <media/v4l2-common.h>
 #include <linux/config.h>      /* CONFIG_RADIO_GEMTEK_PORT     */
 #include <linux/spinlock.h>
 
@@ -29,7 +30,7 @@
 #define CONFIG_RADIO_GEMTEK_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_GEMTEK_PORT; 
+static int io = CONFIG_RADIO_GEMTEK_PORT;
 static int radio_nr = -1;
 static spinlock_t lock;
 
@@ -48,7 +49,7 @@ struct gemtek_device
  */
 static void gemtek_mute(struct gemtek_device *dev)
 {
-        if(dev->muted)
+       if(dev->muted)
                return;
        spin_lock(&lock);
        outb(0x10, io);
@@ -94,20 +95,20 @@ static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
        freq /= 100000;
 
        spin_lock(&lock);
-       
+
        /* 2 start bits */
        outb_p(0x03, io);
        udelay(5);
        outb_p(0x07, io);
        udelay(5);
 
-        /* 28 frequency bits (lsb first) */
+       /* 28 frequency bits (lsb first) */
        for (i = 0; i < 14; i++)
                if (freq & (1 << i))
                        one();
                else
                        zero();
-        /* 36 unknown bits */
+       /* 36 unknown bits */
        for (i = 0; i < 11; i++)
                zero();
        one();
@@ -123,7 +124,7 @@ static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
        udelay(5);
 
        spin_unlock(&lock);
-       
+
        return 0;
 }
 
@@ -159,7 +160,7 @@ static int gemtek_do_ioctl(struct inode *inode, struct file *file,
                case VIDIOCGTUNER:
                {
                        struct video_tuner *v = arg;
-                       if(v->tuner)    /* Only 1 tuner */ 
+                       if(v->tuner)    /* Only 1 tuner */
                                return -EINVAL;
                        v->rangelow=87*16000;
                        v->rangehigh=108*16000;
@@ -193,25 +194,25 @@ static int gemtek_do_ioctl(struct inode *inode, struct file *file,
                        return 0;
                }
                case VIDIOCGAUDIO:
-               {       
+               {
                        struct video_audio *v = arg;
                        memset(v,0, sizeof(*v));
                        v->flags|=VIDEO_AUDIO_MUTABLE;
                        v->volume=1;
                        v->step=65535;
                        strcpy(v->name, "Radio");
-                       return 0;                       
+                       return 0;
                }
                case VIDIOCSAUDIO:
                {
                        struct video_audio *v = arg;
-                       if(v->audio) 
+                       if(v->audio)
                                return -EINVAL;
 
-                       if(v->flags&VIDEO_AUDIO_MUTE) 
+                       if(v->flags&VIDEO_AUDIO_MUTE)
                                gemtek_mute(rt);
                        else
-                               gemtek_unmute(rt);
+                               gemtek_unmute(rt);
 
                        return 0;
                }
@@ -254,14 +255,14 @@ static int __init gemtek_init(void)
                return -EINVAL;
        }
 
-       if (!request_region(io, 4, "gemtek")) 
+       if (!request_region(io, 4, "gemtek"))
        {
                printk(KERN_ERR "gemtek: port 0x%x already in use\n", io);
                return -EBUSY;
        }
 
        gemtek_radio.priv=&gemtek_unit;
-       
+
        if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr)==-1)
        {
                release_region(io, 4);
@@ -274,7 +275,7 @@ static int __init gemtek_init(void)
        /* this is _maybe_ unnecessary */
        outb(0x01, io);
 
-       /* mute card - prevents noisy bootups */
+       /* mute card - prevents noisy bootups */
        gemtek_unit.muted = 0;
        gemtek_mute(&gemtek_unit);
 
index 39c1d9118636af1a03804a42cde2f0559d2ca173..fcfa6c9fe2256df1b949014831ad0b3e000819e5 100644 (file)
@@ -2,7 +2,7 @@
  * (c) 2000 A. Tlalka, atlka@pg.gda.pl
  * Notes on the hardware
  *
- *  + Frequency control is done digitally 
+ *  + Frequency control is done digitally
  *  + No volume control - only mute/unmute - you have to use Aux line volume
  *  control on Maestro card to set the volume
  *  + Radio status (tuned/not_tuned and stereo/mono) is valid some time after
@@ -26,7 +26,7 @@
 #include <linux/mutex.h>
 #include <linux/pci.h>
 #include <linux/videodev.h>
-
+#include <media/v4l2-common.h>
 
 #define DRIVER_VERSION "0.05"
 
@@ -103,7 +103,7 @@ static struct video_device maestro_radio = {
 struct radio_device {
        u16     io,     /* base of Maestro card radio io (GPIO_DATA)*/
                muted,  /* VIDEO_AUDIO_MUTE */
-               stereo, /* VIDEO_TUNER_STEREO_ON */     
+               stereo, /* VIDEO_TUNER_STEREO_ON */
                tuned;  /* signal strength (0 or 0xffff) */
        struct mutex lock;
 };
@@ -122,14 +122,14 @@ static u32 radio_bits_get(struct radio_device *dev)
        for (l=24;l--;) {
                outw(STR_CLK, io);              /* HI state */
                udelay(2);
-               if(!l) 
+               if(!l)
                        dev->tuned = inw(io) & STR_MOST ? 0 : 0xffff;
                outw(0, io);                    /* LO state */
                udelay(2);
                data <<= 1;                     /* shift data */
                rdata = inw(io);
                if(!l)
-                       dev->stereo =  rdata & STR_MOST ? 
+                       dev->stereo =  rdata & STR_MOST ?
                        0 : VIDEO_TUNER_STEREO_ON;
                else
                        if(rdata & STR_DATA)
index f0bf47bcb64cfd3859b98625b9041761f46458e2..f93d7afe7304c97d1159967f20e5ee130c41f608 100644 (file)
@@ -1,15 +1,15 @@
-/* 
- * Guillemot Maxi Radio FM 2000 PCI radio card driver for Linux 
+/*
+ * Guillemot Maxi Radio FM 2000 PCI radio card driver for Linux
  * (C) 2001 Dimitromanolakis Apostolos <apdim@grecian.net>
  *
  * Based in the radio Maestro PCI driver. Actually it uses the same chip
  * for radio but different pci controller.
  *
  * I didn't have any specs I reversed engineered the protocol from
- * the windows driver (radio.dll). 
+ * the windows driver (radio.dll).
  *
  * The card uses the TEA5757 chip that includes a search function but it
- * is useless as I haven't found any way to read back the frequency. If 
+ * is useless as I haven't found any way to read back the frequency. If
  * anybody does please mail me.
  *
  * For the pdf file see:
@@ -24,7 +24,7 @@
  *     - tiding up
  *     - removed support for multiple devices as it didn't work anyway
  *
- * BUGS: 
+ * BUGS:
  *   - card unmutes if you change frequency
  *
  */
@@ -41,6 +41,7 @@
 
 #include <linux/pci.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 
 /* version 0.75      Sun Feb  4 22:51:27 EET 2001 */
 #define DRIVER_VERSION "0.75"
@@ -80,7 +81,7 @@ static struct file_operations maxiradio_fops = {
        .owner          = THIS_MODULE,
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
-       .ioctl          = radio_ioctl,
+       .ioctl          = radio_ioctl,
        .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
@@ -97,11 +98,11 @@ static struct radio_device
 {
        __u16   io,     /* base of radio io */
                muted,  /* VIDEO_AUDIO_MUTE */
-               stereo, /* VIDEO_TUNER_STEREO_ON */     
+               stereo, /* VIDEO_TUNER_STEREO_ON */
                tuned;  /* signal strength (0 or 0xffff) */
-               
+
        unsigned long freq;
-       
+
        struct mutex lock;
 } radio_unit = {0, 0, 0, 0, };
 
@@ -114,7 +115,7 @@ static void outbit(unsigned long bit, __u16 io)
                        outb(  power|wren|data|clk ,io); udelay(4);
                        outb(  power|wren|data     ,io); udelay(4);
                }
-       else    
+       else
                {
                        outb(  power|wren          ,io); udelay(4);
                        outb(  power|wren|clk      ,io); udelay(4);
@@ -132,12 +133,12 @@ static void set_freq(__u16 io, __u32 data)
 {
        unsigned long int si;
        int bl;
-       
+
        /* TEA5757 shift register bits (see pdf) */
 
-       outbit(0,io); // 24  search 
+       outbit(0,io); // 24  search
        outbit(1,io); // 23  search up/down
-       
+
        outbit(0,io); // 22  stereo/mono
 
        outbit(0,io); // 21  band
@@ -145,24 +146,24 @@ static void set_freq(__u16 io, __u32 data)
 
        outbit(0,io); // 19  port ?
        outbit(0,io); // 18  port ?
-       
+
        outbit(0,io); // 17  search level
        outbit(0,io); // 16  search level
+
        si = 0x8000;
        for(bl = 1; bl <= 16 ; bl++) { outbit(data & si,io); si >>=1; }
-       
+
        outb(power,io);
 }
 
 static int get_stereo(__u16 io)
-{      
+{
        outb(power,io); udelay(4);
        return !(inb(io) & mo_st);
 }
 
 static int get_tune(__u16 io)
-{      
+{
        outb(power+clk,io); udelay(4);
        return !(inb(io) & mo_st);
 }
@@ -177,7 +178,7 @@ static inline int radio_function(struct inode *inode, struct file *file,
        switch(cmd) {
                case VIDIOCGCAP: {
                        struct video_capability *v = arg;
-                       
+
                        memset(v,0,sizeof(*v));
                        strcpy(v->name, "Maxi Radio FM2000 radio");
                        v->type=VID_TYPE_TUNER;
@@ -186,22 +187,22 @@ static inline int radio_function(struct inode *inode, struct file *file,
                }
                case VIDIOCGTUNER: {
                        struct video_tuner *v = arg;
-                       
+
                        if(v->tuner)
                                return -EINVAL;
-                               
+
                        card->stereo = 0xffff * get_stereo(card->io);
                        card->tuned = 0xffff * get_tune(card->io);
-                       
+
                        v->flags = VIDEO_TUNER_LOW | card->stereo;
                        v->signal = card->tuned;
-                       
+
                        strcpy(v->name, "FM");
-                       
+
                        v->rangelow = FREQ_LO;
                        v->rangehigh = FREQ_HI;
                        v->mode = VIDEO_MODE_AUTO;
-                       
+
                        return 0;
                }
                case VIDIOCSTUNER: {
@@ -212,13 +213,13 @@ static inline int radio_function(struct inode *inode, struct file *file,
                }
                case VIDIOCGFREQ: {
                        unsigned long *freq = arg;
-                       
+
                        *freq = card->freq;
                        return 0;
                }
                case VIDIOCSFREQ: {
                        unsigned long *freq = arg;
-                       
+
                        if (*freq < FREQ_LO || *freq > FREQ_HI)
                                return -EINVAL;
                        card->freq = *freq;
@@ -226,18 +227,18 @@ static inline int radio_function(struct inode *inode, struct file *file,
                        msleep(125);
                        return 0;
                }
-               case VIDIOCGAUDIO: {    
+               case VIDIOCGAUDIO: {
                        struct video_audio *v = arg;
                        memset(v,0,sizeof(*v));
                        strcpy(v->name, "Radio");
                        v->flags=VIDEO_AUDIO_MUTABLE | card->muted;
                        v->mode=VIDEO_SOUND_STEREO;
-                       return 0;               
+                       return 0;
                }
-               
+
                case VIDIOCSAUDIO: {
                        struct video_audio *v = arg;
-                       
+
                        if(v->audio)
                                return -EINVAL;
                        card->muted = v->flags & VIDEO_AUDIO_MUTE;
@@ -249,13 +250,13 @@ static inline int radio_function(struct inode *inode, struct file *file,
                }
                case VIDIOCGUNIT: {
                        struct video_unit *v = arg;
-                       
+
                        v->video=VIDEO_NO_UNIT;
                        v->vbi=VIDEO_NO_UNIT;
                        v->radio=dev->minor;
                        v->audio=0;
                        v->teletext=VIDEO_NO_UNIT;
-                       return 0;               
+                       return 0;
                }
                default: return -ENOIOCTLCMD;
        }
@@ -267,7 +268,7 @@ static int radio_ioctl(struct inode *inode, struct file *file,
        struct video_device *dev = video_devdata(file);
        struct radio_device *card=dev->priv;
        int ret;
-       
+
        mutex_lock(&card->lock);
        ret = video_usercopy(inode, file, cmd, arg, radio_function);
        mutex_unlock(&card->lock);
@@ -282,21 +283,21 @@ MODULE_LICENSE("GPL");
 static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        if(!request_region(pci_resource_start(pdev, 0),
-                          pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) {
-               printk(KERN_ERR "radio-maxiradio: can't reserve I/O ports\n");
-               goto err_out;
+                          pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) {
+               printk(KERN_ERR "radio-maxiradio: can't reserve I/O ports\n");
+               goto err_out;
        }
 
        if (pci_enable_device(pdev))
-               goto err_out_free_region;
+               goto err_out_free_region;
 
        radio_unit.io = pci_resource_start(pdev, 0);
        mutex_init(&radio_unit.lock);
        maxiradio_radio.priv = &radio_unit;
 
        if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
-               printk("radio-maxiradio: can't register device!");
-               goto err_out_free_region;
+               printk("radio-maxiradio: can't register device!");
+               goto err_out_free_region;
        }
 
        printk(KERN_INFO "radio-maxiradio: version "
index 28a47c9e7a819a4791d122d02380ca12e46ffd40..5b68ac4c7322e710c112bb787a996ef621f48e04 100644 (file)
@@ -1,5 +1,5 @@
 /* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
- * 
+ *
  * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
  * Converted to new API by Alan Cox <Alan.Cox@linux.org>
  * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
@@ -15,6 +15,7 @@
 #include <asm/io.h>            /* outb, outb_p                 */
 #include <asm/uaccess.h>       /* copy to/from user            */
 #include <linux/videodev.h>    /* kernel radio structs         */
+#include <media/v4l2-common.h>
 #include <linux/config.h>      /* CONFIG_RADIO_RTRACK2_PORT    */
 #include <linux/spinlock.h>
 
@@ -22,7 +23,7 @@
 #define CONFIG_RADIO_RTRACK2_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_RTRACK2_PORT; 
+static int io = CONFIG_RADIO_RTRACK2_PORT;
 static int radio_nr = -1;
 static spinlock_t lock;
 
@@ -38,7 +39,7 @@ struct rt_device
 
 static void rt_mute(struct rt_device *dev)
 {
-        if(dev->muted)
+       if(dev->muted)
                return;
        spin_lock(&lock);
        outb(1, io);
@@ -58,14 +59,14 @@ static void rt_unmute(struct rt_device *dev)
 
 static void zero(void)
 {
-        outb_p(1, io);
+       outb_p(1, io);
        outb_p(3, io);
        outb_p(1, io);
 }
 
 static void one(void)
 {
-        outb_p(5, io);
+       outb_p(5, io);
        outb_p(7, io);
        outb_p(5, io);
 }
@@ -75,7 +76,7 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
        int i;
 
        freq = freq / 200 + 856;
-       
+
        spin_lock(&lock);
 
        outb_p(0xc8, io);
@@ -94,7 +95,7 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
        outb_p(0xc8, io);
        if (!dev->muted)
                outb_p(0, io);
-               
+
        spin_unlock(&lock);
        return 0;
 }
@@ -127,7 +128,7 @@ static int rt_do_ioctl(struct inode *inode, struct file *file,
                case VIDIOCGTUNER:
                {
                        struct video_tuner *v = arg;
-                       if(v->tuner)    /* Only 1 tuner */ 
+                       if(v->tuner)    /* Only 1 tuner */
                                return -EINVAL;
                        v->rangelow=88*16000;
                        v->rangehigh=108*16000;
@@ -159,25 +160,25 @@ static int rt_do_ioctl(struct inode *inode, struct file *file,
                        return 0;
                }
                case VIDIOCGAUDIO:
-               {       
+               {
                        struct video_audio *v = arg;
                        memset(v,0, sizeof(*v));
                        v->flags|=VIDEO_AUDIO_MUTABLE;
                        v->volume=1;
                        v->step=65535;
                        strcpy(v->name, "Radio");
-                       return 0;                       
+                       return 0;
                }
                case VIDIOCSAUDIO:
                {
                        struct video_audio *v = arg;
-                       if(v->audio) 
+                       if(v->audio)
                                return -EINVAL;
 
-                       if(v->flags&VIDEO_AUDIO_MUTE) 
+                       if(v->flags&VIDEO_AUDIO_MUTE)
                                rt_mute(rt);
                        else
-                               rt_unmute(rt);
+                               rt_unmute(rt);
 
                        return 0;
                }
@@ -219,7 +220,7 @@ static int __init rtrack2_init(void)
                printk(KERN_ERR "You must set an I/O address with io=0x20c or io=0x30c\n");
                return -EINVAL;
        }
-       if (!request_region(io, 4, "rtrack2")) 
+       if (!request_region(io, 4, "rtrack2"))
        {
                printk(KERN_ERR "rtrack2: port 0x%x already in use\n", io);
                return -EBUSY;
@@ -227,16 +228,16 @@ static int __init rtrack2_init(void)
 
        rtrack2_radio.priv=&rtrack2_unit;
 
-       spin_lock_init(&lock);  
+       spin_lock_init(&lock);
        if(video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
        {
                release_region(io, 4);
                return -EINVAL;
        }
-               
+
        printk(KERN_INFO "AIMSlab Radiotrack II card driver.\n");
 
-       /* mute card - prevents noisy bootups */
+       /* mute card - prevents noisy bootups */
        outb(1, io);
        rtrack2_unit.muted = 1;
 
index 53073b424107ba5972478f6773bb096c11e7b554..efee6e339d15b0b7d7110160640e2c2ca35536e1 100644 (file)
@@ -12,7 +12,7 @@
  *  Frequency control is done digitally -- ie out(port,encodefreq(95.8));
  *  No volume control - only mute/unmute - you have to use line volume
  *  control on SB-part of SF16FMI
- *  
+ *
  */
 
 #include <linux/kernel.h>      /* __setup                      */
@@ -21,6 +21,7 @@
 #include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
 #include <linux/videodev.h>    /* kernel radio structs         */
+#include <media/v4l2-common.h>
 #include <linux/isapnp.h>
 #include <asm/io.h>            /* outb, outb_p                 */
 #include <asm/uaccess.h>       /* copy to/from user            */
 struct fmi_device
 {
        int port;
-        int curvol; /* 1 or 0 */
-        unsigned long curfreq; /* freq in kHz */
-        __u32 flags;
+       int curvol; /* 1 or 0 */
+       unsigned long curfreq; /* freq in kHz */
+       __u32 flags;
 };
 
-static int io = -1; 
+static int io = -1;
 static int radio_nr = -1;
 static struct pnp_dev *dev = NULL;
 static struct mutex lock;
 
 /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
 /* It is only useful to give freq in intervall of 800 (=0.05Mhz),
- * other bits will be truncated, e.g 92.7400016 -> 92.7, but 
+ * other bits will be truncated, e.g 92.7400016 -> 92.7, but
  * 92.7400017 -> 92.75
  */
 #define RSF16_ENCODE(x)        ((x)/800+214)
@@ -51,7 +52,7 @@ static struct mutex lock;
 static void outbits(int bits, unsigned int data, int port)
 {
        while(bits--) {
-               if(data & 1) {
+               if(data & 1) {
                        outb(5, port);
                        udelay(6);
                        outb(7, port);
@@ -101,7 +102,7 @@ static inline int fmi_getsigstr(struct fmi_device *dev)
        int res;
        int myport = dev->port;
 
-       
+
        mutex_lock(&lock);
        val = dev->curvol ? 0x08 : 0x00;        /* unmute/mute */
        outb(val, myport);
@@ -109,7 +110,7 @@ static inline int fmi_getsigstr(struct fmi_device *dev)
        msleep(143);            /* was schedule_timeout(HZ/7) */
        res = (int)inb(myport+1);
        outb(val, myport);
-       
+
        mutex_unlock(&lock);
        return (res & 2) ? 0 : 0xFFFF;
 }
@@ -119,7 +120,7 @@ static int fmi_do_ioctl(struct inode *inode, struct file *file,
 {
        struct video_device *dev = video_devdata(file);
        struct fmi_device *fmi=dev->priv;
-       
+
        switch(cmd)
        {
                case VIDIOCGCAP:
@@ -174,18 +175,18 @@ static int fmi_do_ioctl(struct inode *inode, struct file *file,
                                return -EINVAL;
                        /*rounding in steps of 800 to match th freq
                          that will be used */
-                       fmi->curfreq = (*freq/800)*800; 
+                       fmi->curfreq = (*freq/800)*800;
                        fmi_setfreq(fmi);
                        return 0;
                }
                case VIDIOCGAUDIO:
-               {       
+               {
                        struct video_audio *v = arg;
                        memset(v,0,sizeof(*v));
                        v->flags=( (!fmi->curvol)*VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
                        strcpy(v->name, "Radio");
                        v->mode=VIDEO_SOUND_STEREO;
-                       return 0;                       
+                       return 0;
                }
                case VIDIOCSAUDIO:
                {
@@ -193,19 +194,19 @@ static int fmi_do_ioctl(struct inode *inode, struct file *file,
                        if(v->audio)
                                return -EINVAL;
                        fmi->curvol= v->flags&VIDEO_AUDIO_MUTE ? 0 : 1;
-                       fmi->curvol ? 
+                       fmi->curvol ?
                                fmi_unmute(fmi->port) : fmi_mute(fmi->port);
                        return 0;
                }
-               case VIDIOCGUNIT:
+               case VIDIOCGUNIT:
                {
-                               struct video_unit *v = arg;
+                       struct video_unit *v = arg;
                        v->video=VIDEO_NO_UNIT;
                        v->vbi=VIDEO_NO_UNIT;
                        v->radio=dev->minor;
                        v->audio=0; /* How do we find out this??? */
                        v->teletext=VIDEO_NO_UNIT;
-                       return 0;                       
+                       return 0;
                }
                default:
                        return -ENOIOCTLCMD;
@@ -295,14 +296,14 @@ static int __init fmi_init(void)
        fmi_unit.curfreq = 0;
        fmi_unit.flags = VIDEO_TUNER_LOW;
        fmi_radio.priv = &fmi_unit;
-       
+
        mutex_init(&lock);
-       
+
        if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) == -1) {
                release_region(io, 2);
                return -EINVAL;
        }
-               
+
        printk(KERN_INFO "SF16FMx radio card driver at 0x%x\n", io);
        /* mute card - prevents noisy bootups */
        fmi_mute(io);
index bcebd8cb19ad43e0accfb4aa97088d27781837d1..3483b2c7bc9d70488c26cb99b9a2f696192c03e2 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/io.h>            /* outb, outb_p                 */
 #include <asm/uaccess.h>       /* copy to/from user            */
 #include <linux/videodev.h>    /* kernel radio structs         */
+#include <media/v4l2-common.h>
 #include <linux/mutex.h>
 
 static struct mutex lock;
@@ -202,7 +203,7 @@ static int fmr2_setvolume(struct fmr2_device *dev)
 }
 
 static int fmr2_do_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, void *arg)
+                     unsigned int cmd, void *arg)
 {
        struct video_device *dev = video_devdata(file);
        struct fmr2_device *fmr2 = dev->priv;
@@ -344,7 +345,7 @@ static int fmr2_do_ioctl(struct inode *inode, struct file *file,
 }
 
 static int fmr2_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
+                     unsigned int cmd, unsigned long arg)
  {
        return video_usercopy(inode, file, cmd, arg, fmr2_do_ioctl);
 }
index fcfde2e4f1958d47d1c4ec34d69f610cb1733e0b..dfba4ae596cd342abb3e737234274d4488ae4e23 100644 (file)
@@ -2,11 +2,11 @@
  * (c) 1999 R. Offermanns (rolf@offermanns.de)
  * based on the aimslab radio driver from M. Kirkwood
  * many thanks to Michael Becker and Friedhelm Birth (from TerraTec)
- * 
+ *
  *
  * History:
  * 1999-05-21  First preview release
- * 
+ *
  *  Notes on the hardware:
  *  There are two "main" chips on the card:
  *  - Philips OM5610 (http://www-us.semiconductors.philips.com/acrobat/datasheets/OM5610_2.pdf)
@@ -20,7 +20,7 @@
  *  (as soon i have understand how to get started :)
  *  If you can help me out with that, please contact me!!
  *
- *  
+ *
  */
 
 #include <linux/module.h>      /* Modules                      */
@@ -30,6 +30,7 @@
 #include <asm/io.h>            /* outb, outb_p                 */
 #include <asm/uaccess.h>       /* copy to/from user            */
 #include <linux/videodev.h>    /* kernel radio structs         */
+#include <media/v4l2-common.h>
 #include <linux/config.h>      /* CONFIG_RADIO_TERRATEC_PORT   */
 #include <linux/spinlock.h>
 
@@ -49,7 +50,7 @@
 #define WRT_EN         0x10
 /*******************************************************************/
 
-static int io = CONFIG_RADIO_TERRATEC_PORT; 
+static int io = CONFIG_RADIO_TERRATEC_PORT;
 static int radio_nr = -1;
 static spinlock_t lock;
 
@@ -88,15 +89,15 @@ static void tt_mute(struct tt_device *dev)
 
 static int tt_setvol(struct tt_device *dev, int vol)
 {
-       
+
 //     printk(KERN_ERR "setvol called, vol = %d\n", vol);
 
        if(vol == dev->curvol) {        /* requested volume = current */
                if (dev->muted) {       /* user is unmuting the card  */
                        dev->muted = 0;
                        cardWriteVol(vol);      /* enable card */
-               }       
-       
+               }
+
                return 0;
        }
 
@@ -107,9 +108,9 @@ static int tt_setvol(struct tt_device *dev, int vol)
        }
 
        dev->muted = 0;
-       
+
        cardWriteVol(vol);
-        
+
        dev->curvol = vol;
 
        return 0;
@@ -121,13 +122,13 @@ static int tt_setvol(struct tt_device *dev, int vol)
 /* many more or less strange things are going on here, but hey, it works :) */
 
 static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
-{      
+{
        int freq;
        int i;
        int p;
        int  temp;
        long rest;
-     
+
        unsigned char buffer[25];               /* we have to bit shift 25 registers */
        freq = freq1/160;                       /* convert the freq. to a nice to handle value */
        for(i=24;i>-1;i--)
@@ -142,9 +143,9 @@ static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
        {
                if (rest%temp  == rest)
                        buffer[i] = 0;
-               else 
+               else
                {
-                       buffer[i] = 1; 
+                       buffer[i] = 1;
                        rest = rest-temp;
                }
                i--;
@@ -153,10 +154,10 @@ static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
        }
 
        spin_lock(&lock);
-       
+
        for (i=24;i>-1;i--)                     /* bit shift the values to the radiocard */
        {
-               if (buffer[i]==1) 
+               if (buffer[i]==1)
                {
                        outb(WRT_EN|DATA, BASEPORT);
                        outb(WRT_EN|DATA|CLK_ON  , BASEPORT);
@@ -168,11 +169,11 @@ static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
                        outb(WRT_EN|0x00|CLK_ON  , BASEPORT);
                }
        }
-       outb(0x00, BASEPORT);     
-       
+       outb(0x00, BASEPORT);
+
        spin_unlock(&lock);
-  
-       return 0;
+
+       return 0;
 }
 
 static int tt_getsigstr(struct tt_device *dev)         /* TODO */
@@ -190,7 +191,7 @@ static int tt_do_ioctl(struct inode *inode, struct file *file,
 {
        struct video_device *dev = video_devdata(file);
        struct tt_device *tt=dev->priv;
-       
+
        switch(cmd)
        {
                case VIDIOCGCAP:
@@ -206,7 +207,7 @@ static int tt_do_ioctl(struct inode *inode, struct file *file,
                case VIDIOCGTUNER:
                {
                        struct video_tuner *v = arg;
-                       if(v->tuner)    /* Only 1 tuner */ 
+                       if(v->tuner)    /* Only 1 tuner */
                                return -EINVAL;
                        v->rangelow=(87*16000);
                        v->rangehigh=(108*16000);
@@ -238,21 +239,21 @@ static int tt_do_ioctl(struct inode *inode, struct file *file,
                        return 0;
                }
                case VIDIOCGAUDIO:
-               {       
+               {
                        struct video_audio *v = arg;
                        memset(v,0, sizeof(*v));
                        v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
                        v->volume=tt->curvol * 6554;
                        v->step=6554;
                        strcpy(v->name, "Radio");
-                       return 0;                       
+                       return 0;
                }
                case VIDIOCSAUDIO:
                {
                        struct video_audio *v = arg;
-                       if(v->audio) 
+                       if(v->audio)
                                return -EINVAL;
-                       if(v->flags&VIDEO_AUDIO_MUTE) 
+                       if(v->flags&VIDEO_AUDIO_MUTE)
                                tt_mute(tt);
                        else
                                tt_setvol(tt,v->volume/6554);
@@ -296,25 +297,25 @@ static int __init terratec_init(void)
                printk(KERN_ERR "You must set an I/O address with io=0x???\n");
                return -EINVAL;
        }
-       if (!request_region(io, 2, "terratec")) 
+       if (!request_region(io, 2, "terratec"))
        {
                printk(KERN_ERR "TerraTec: port 0x%x already in use\n", io);
                return -EBUSY;
        }
 
        terratec_radio.priv=&terratec_unit;
-       
+
        spin_lock_init(&lock);
-       
+
        if(video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr)==-1)
        {
                release_region(io,2);
                return -EINVAL;
        }
-               
+
        printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver.\n");
 
-       /* mute card - prevents noisy bootups */
+       /* mute card - prevents noisy bootups */
 
        /* this ensures that the volume is all the way down  */
        cardWriteVol(0);
@@ -334,7 +335,7 @@ static void __exit terratec_cleanup_module(void)
 {
        video_unregister_device(&terratec_radio);
        release_region(io,2);
-       printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n");     
+       printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n");
 }
 
 module_init(terratec_init);
index 5a099a50d4d060e1af66e7a31711d7b3182fb2c8..8da4badc22b47f399ae8c3ce3f9e80e60a3f127c 100644 (file)
@@ -1,14 +1,14 @@
-/* radio-trust.c - Trust FM Radio card driver for Linux 2.2 
+/* radio-trust.c - Trust FM Radio card driver for Linux 2.2
  * by Eric Lammerts <eric@scintilla.utwente.nl>
  *
  * Based on radio-aztech.c. Original notes:
  *
- * Adapted to support the Video for Linux API by 
+ * Adapted to support the Video for Linux API by
  * Russell Kroll <rkroll@exploits.org>.  Based on original tuner code by:
  *
  * Quay Ly
  * Donald Song
- * Jason Lewis      (jlewis@twilight.vtc.vsc.edu) 
+ * Jason Lewis      (jlewis@twilight.vtc.vsc.edu)
  * Scott McGrath    (smcgrath@twilight.vtc.vsc.edu)
  * William McGrath  (wmcgrath@twilight.vtc.vsc.edu)
  *
@@ -22,6 +22,7 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/config.h>      /* CONFIG_RADIO_TRUST_PORT      */
 
 /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
@@ -30,7 +31,7 @@
 #define CONFIG_RADIO_TRUST_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_TRUST_PORT; 
+static int io = CONFIG_RADIO_TRUST_PORT;
 static int radio_nr = -1;
 static int ioval = 0xf;
 static __u16 curvol;
@@ -135,7 +136,7 @@ static void tr_setmute(int mute)
 static int tr_getsigstr(void)
 {
        int i, v;
-       
+
        for(i = 0, v = 0; i < 100; i++) v |= inb(io);
        return (v & 1)? 0 : 0xffff;
 }
@@ -175,7 +176,7 @@ static int tr_do_ioctl(struct inode *inode, struct file *file,
                {
                        struct video_tuner *v = arg;
 
-                       if(v->tuner)    /* Only 1 tuner */ 
+                       if(v->tuner)    /* Only 1 tuner */
                                return -EINVAL;
 
                        v->rangelow = 87500 * 16;
@@ -211,28 +212,28 @@ static int tr_do_ioctl(struct inode *inode, struct file *file,
                        return 0;
                }
                case VIDIOCGAUDIO:
-               {       
+               {
                        struct video_audio *v = arg;
 
                        memset(v,0, sizeof(*v));
                        v->flags = VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME |
-                                 VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
+                                 VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
                        v->mode = curstereo? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
                        v->volume = curvol * 2048;
                        v->step = 2048;
                        v->bass = curbass * 4370;
                        v->treble = curtreble * 4370;
-                       
+
                        strcpy(v->name, "Trust FM Radio");
-                       return 0;                       
+                       return 0;
                }
                case VIDIOCSAUDIO:
                {
                        struct video_audio *v = arg;
 
-                       if(v->audio) 
+                       if(v->audio)
                                return -EINVAL;
-                       tr_setvol(v->volume);                                   
+                       tr_setvol(v->volume);
                        tr_setbass(v->bass);
                        tr_settreble(v->treble);
                        tr_setstereo(v->mode & VIDEO_SOUND_STEREO);
@@ -292,7 +293,7 @@ static int __init trust_init(void)
        write_i2c(2, TDA7318_ADDR, 0xe0);       /* speaker att. RR = 0 dB */
        write_i2c(2, TDA7318_ADDR, 0x40);       /* stereo 1 input, gain = 18.75 dB */
 
-       tr_setvol(0x8000);                                      
+       tr_setvol(0x8000);
        tr_setbass(0x8000);
        tr_settreble(0x8000);
        tr_setstereo(1);
index e50955836d6b1a829dc273846157a443866c9d76..edd0122886693183f89245d799131869be0c0475 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/io.h>            /* outb, outb_p                   */
 #include <asm/uaccess.h>       /* copy to/from user              */
 #include <linux/videodev.h>    /* kernel radio structs           */
+#include <media/v4l2-common.h>
 #include <linux/config.h>      /* CONFIG_RADIO_TYPHOON_*         */
 
 #define BANNER "Typhoon Radio Card driver v0.1\n"
@@ -361,8 +362,8 @@ static int __init typhoon_init(void)
 
 #ifdef CONFIG_RADIO_TYPHOON_PROC_FS
        if (!create_proc_info_entry("driver/radio-typhoon", 0, NULL,
-                                   typhoon_get_info)) 
-               printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n");
+                                   typhoon_get_info))
+               printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n");
 #endif
 
        return 0;
index 7bf1a4264891deca514dd6a5465497b46e02919d..59b86a6b4b0e745a008276ede9a2a1d50e30e260 100644 (file)
@@ -1,7 +1,7 @@
 /* zoltrix radio plus driver for Linux radio support
  * (c) 1998 C. van Schaik <carl@leg.uct.ac.za>
  *
- * BUGS  
+ * BUGS
  *  Due to the inconsistency in reading from the signal flags
  *  it is difficult to get an accurate tuned signal.
  *
@@ -14,7 +14,7 @@
  *
  * 1999-05-06 - (C. van Schaik)
  *           - Make signal strength and stereo scans
- *             kinder to cpu while in delay
+ *             kinder to cpu while in delay
  * 1999-01-05 - (C. van Schaik)
  *           - Changed tuning to 1/160Mhz accuracy
  *           - Added stereo support
@@ -33,6 +33,7 @@
 #include <asm/io.h>            /* outb, outb_p                   */
 #include <asm/uaccess.h>       /* copy to/from user              */
 #include <linux/videodev.h>    /* kernel radio structs           */
+#include <media/v4l2-common.h>
 #include <linux/config.h>      /* CONFIG_RADIO_ZOLTRIX_PORT      */
 
 #ifndef CONFIG_RADIO_ZOLTRIX_PORT
@@ -105,7 +106,7 @@ static int zol_setfreq(struct zol_device *dev, unsigned long freq)
        i = 45;
 
        mutex_lock(&dev->lock);
-       
+
        outb(0, io);
        outb(0, io);
        inb(io + 3);            /* Zoltrix needs to be read to confirm */
@@ -139,8 +140,8 @@ static int zol_setfreq(struct zol_device *dev, unsigned long freq)
        udelay(1000);
        inb(io+2);
 
-        udelay(1000);
-        
+       udelay(1000);
+
        if (dev->muted)
        {
                outb(0, io);
@@ -148,12 +149,12 @@ static int zol_setfreq(struct zol_device *dev, unsigned long freq)
                inb(io + 3);
                udelay(1000);
        }
-       
+
        mutex_unlock(&dev->lock);
-       
+
        if(!dev->muted)
        {
-               zol_setvol(dev, dev->curvol);
+               zol_setvol(dev, dev->curvol);
        }
        return 0;
 }
@@ -174,14 +175,14 @@ static int zol_getsigstr(struct zol_device *dev)
        b = inb(io);
 
        mutex_unlock(&dev->lock);
-       
+
        if (a != b)
                return (0);
 
-        if ((a == 0xcf) || (a == 0xdf)  /* I found this out by playing */
+       if ((a == 0xcf) || (a == 0xdf)  /* I found this out by playing */
                || (a == 0xef))       /* with a binary scanner on the card io */
                return (1);
-       return (0);
+       return (0);
 }
 
 static int zol_is_stereo (struct zol_device *dev)
@@ -189,7 +190,7 @@ static int zol_is_stereo (struct zol_device *dev)
        int x1, x2;
 
        mutex_lock(&dev->lock);
-       
+
        outb(0x00, io);
        outb(dev->curvol, io);
        msleep(20);
@@ -199,7 +200,7 @@ static int zol_is_stereo (struct zol_device *dev)
        x2 = inb(io);
 
        mutex_unlock(&dev->lock);
-       
+
        if ((x1 == x2) && (x1 == 0xcf))
                return 1;
        return 0;
@@ -226,7 +227,7 @@ static int zol_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOCGTUNER:
                {
                        struct video_tuner *v = arg;
-                       if (v->tuner)   
+                       if (v->tuner)
                                return -EINVAL;
                        strcpy(v->name, "FM");
                        v->rangelow = (int) (88.0 * 16000);
@@ -351,7 +352,7 @@ static int __init zoltrix_init(void)
        printk(KERN_INFO "Zoltrix Radio Plus card driver.\n");
 
        mutex_init(&zoltrix_unit.lock);
-       
+
        /* mute card - prevents noisy bootups */
 
        /* this ensures that the volume is all the way down  */
index 6b41970185610780327355a0f4d4af6f5a852e8e..824a63c92629ddf8566ec760f1e8bb314d4ff545 100644 (file)
@@ -224,6 +224,12 @@ config VIDEO_ZORAN_LML33R10
          support for the Linux Media Labs LML33R10 MJPEG capture/playback
          card.
 
+config VIDEO_ZORAN_AVS6EYES
+       tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
+       depends on VIDEO_ZORAN && EXPERIMENTAL && VIDEO_V4L1
+       help
+         Support for the AverMedia 6 Eyes video surveillance card.
+
 config VIDEO_ZR36120
        tristate "Zoran ZR36120/36125 Video For Linux"
        depends on PCI && I2C && VIDEO_V4L1 && BROKEN
@@ -306,17 +312,6 @@ config VIDEO_HEXIUM_GEMINI
 
 source "drivers/media/video/cx88/Kconfig"
 
-config VIDEO_OVCAMCHIP
-       tristate "OmniVision Camera Chip support"
-       depends on I2C && VIDEO_V4L1
-       ---help---
-         Support for the OmniVision OV6xxx and OV7xxx series of camera chips.
-         This driver is intended to be used with the ov511 and w9968cf USB
-         camera drivers.
-
-         To compile this driver as a module, choose M here: the
-         module will be called ovcamchip.
-
 config VIDEO_M32R_AR
        tristate "AR devices"
        depends on M32R && VIDEO_V4L1
@@ -357,6 +352,15 @@ config VIDEO_CS53L32A
          To compile this driver as a module, choose M here: the
          module will be called cs53l32a.
 
+config VIDEO_TLV320AIC23B
+       tristate "Texas Instruments TLV320AIC23B audio codec"
+       depends on VIDEO_DEV && I2C && EXPERIMENTAL
+       ---help---
+         Support for the Texas Instruments TLV320AIC23B audio codec.
+
+         To compile this driver as a module, choose M here: the
+         module will be called tlv320aic23b.
+
 config VIDEO_WM8775
        tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
        depends on VIDEO_DEV && I2C && EXPERIMENTAL
@@ -380,10 +384,10 @@ config VIDEO_WM8739
 source "drivers/media/video/cx25840/Kconfig"
 
 config VIDEO_SAA711X
-       tristate "Philips SAA7113/4/5 video decoders (OBSOLETED)"
-       depends on VIDEO_V4L1 && I2C && EXPERIMENTAL
+       tristate "Philips SAA7113/4/5 video decoders"
+       depends on VIDEO_DEV && I2C && EXPERIMENTAL
        ---help---
-         Old support for the Philips SAA7113/4 video decoders.
+         Support for the Philips SAA7113/4/5 video decoders.
 
          To compile this driver as a module, choose M here: the
          module will be called saa7115.
@@ -447,6 +451,35 @@ source "drivers/media/video/usbvideo/Kconfig"
 
 source "drivers/media/video/et61x251/Kconfig"
 
+config VIDEO_OVCAMCHIP
+       tristate "OmniVision Camera Chip support"
+       depends on I2C && VIDEO_V4L1
+       ---help---
+         Support for the OmniVision OV6xxx and OV7xxx series of camera chips.
+         This driver is intended to be used with the ov511 and w9968cf USB
+         camera drivers.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ovcamchip.
+
+config USB_W9968CF
+       tristate "USB W996[87]CF JPEG Dual Mode Camera support"
+       depends on USB && VIDEO_V4L1 && I2C
+       select 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/video4linux/w9968cf.txt> for more info.
+
+         To compile this driver as a module, choose M here: the
+         module will be called w9968cf.
+
 config USB_OV511
        tristate "USB OV511 Camera support"
        depends on USB && VIDEO_V4L1
@@ -483,24 +516,6 @@ config USB_STV680
          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_V4L1 && I2C
-       select 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/video4linux/w9968cf.txt> for more info.
-
-         To compile this driver as a module, choose M here: the
-         module will be called w9968cf.
-
 source "drivers/media/video/zc0301/Kconfig"
 
 source "drivers/media/video/pwc/Kconfig"
index e5bf2687b76de83f15508429f327ca0f3d4046df..6c401b46398a11d8615fadd5641c88d0d6b76fbb 100644 (file)
@@ -6,7 +6,7 @@ zoran-objs      :=      zr36120.o zr36120_i2c.o zr36120_mem.o
 zr36067-objs   :=      zoran_procfs.o zoran_device.o \
                        zoran_driver.o zoran_card.o
 tuner-objs     :=      tuner-core.o tuner-types.o tuner-simple.o \
-                       mt20xx.o tda8290.o tea5767.o
+                       mt20xx.o tda8290.o tea5767.o tda9887.o
 
 msp3400-objs   :=      msp3400-driver.o msp3400-kthreads.o
 
@@ -33,6 +33,7 @@ obj-$(CONFIG_VIDEO_ZORAN_DC30) += adv7175.o vpx3220.o zr36050.o \
        zr36016.o
 obj-$(CONFIG_VIDEO_ZORAN_LML33) += bt819.o bt856.o zr36060.o
 obj-$(CONFIG_VIDEO_ZORAN_LML33R10) += saa7114.o adv7170.o zr36060.o
+obj-$(CONFIG_VIDEO_ZORAN_AVS6EYES) += bt866.o ks0127.o zr36060.o
 obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o
 obj-$(CONFIG_VIDEO_PMS) += pms.o
 obj-$(CONFIG_VIDEO_PLANB) += planb.o
@@ -48,6 +49,7 @@ obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
 obj-$(CONFIG_VIDEO_EM28XX) += tvp5150.o
 obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
 obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
+obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
 obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
 obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
 obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
@@ -58,7 +60,7 @@ obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
 obj-$(CONFIG_VIDEO_DPC) += saa7111.o dpc7146.o
 obj-$(CONFIG_TUNER_3036) += tuner-3036.o
 
-obj-$(CONFIG_VIDEO_TUNER) += tuner.o tda9887.o
+obj-$(CONFIG_VIDEO_TUNER) += tuner.o
 obj-$(CONFIG_VIDEO_BUF)   += video-buf.o
 obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o
 obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
@@ -71,6 +73,7 @@ obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
 obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
 obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
 obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
+obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
 
 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
 obj-$(CONFIG_USB_DSBR)          += dsbr100.o
index dbe025170599df7c11bcd03b5730d8d05e717886..6e08e32346eb9272774c14796e81a0c36da8b7e7 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/mutex.h>
 
 #include <asm/uaccess.h>
@@ -212,7 +213,7 @@ void init_iic(void)
        ar_outl(0x0300, PLDI2CMOD);     /* I2CMOD ACK/8b-data/7b-addr/auto */
        ar_outl(0x1, PLDI2CACK);        /* I2CACK ACK                      */
 
-       /* I2C CLK */
+       /* I2C CLK */
        /* 50MH-100k */
        if (freq == 75) {
                ar_outl(369, PLDI2CFREQ);       /* BCLK = 75MHz */
diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
new file mode 100644 (file)
index 0000000..05e42bb
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+    bt866 - BT866 Digital Video Encoder (Rockwell Part)
+
+    Copyright (C) 1999 Mike Bernson <mike@mlb.org>
+    Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+    Modifications for LML33/DC10plus unified driver
+    Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+
+    This code was modify/ported from the saa7111 driver written
+    by Dave Perks.
+
+    This code was adapted for the bt866 by Christer Weinigel and ported
+    to 2.6 by Martin Samuelsson.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You 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/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+
+#include <linux/videodev.h>
+#include <asm/uaccess.h>
+
+#include <linux/video_encoder.h>
+
+MODULE_LICENSE("GPL");
+
+#define        BT866_DEVNAME   "bt866"
+#define I2C_BT866      0x88
+
+MODULE_LICENSE("GPL");
+
+#define DEBUG(x)               /* Debug driver */
+
+/* ----------------------------------------------------------------------- */
+
+struct bt866 {
+       struct i2c_client *i2c;
+       int addr;
+       unsigned char reg[128];
+
+       int norm;
+       int enable;
+       int bright;
+       int contrast;
+       int hue;
+       int sat;
+};
+
+static int bt866_write(struct bt866 *dev,
+                       unsigned char subaddr, unsigned char data);
+
+static int bt866_do_command(struct bt866 *encoder,
+                       unsigned int cmd, void *arg)
+{
+       switch (cmd) {
+       case ENCODER_GET_CAPABILITIES:
+       {
+               struct video_encoder_capability *cap = arg;
+
+               DEBUG(printk
+                     (KERN_INFO "%s: get capabilities\n",
+                      encoder->i2c->name));
+
+               cap->flags
+                       = VIDEO_ENCODER_PAL
+                       | VIDEO_ENCODER_NTSC
+                       | VIDEO_ENCODER_CCIR;
+               cap->inputs = 2;
+               cap->outputs = 1;
+       }
+       break;
+
+       case ENCODER_SET_NORM:
+       {
+               int *iarg = arg;
+
+               DEBUG(printk(KERN_INFO "%s: set norm %d\n",
+                            encoder->i2c->name, *iarg));
+
+               switch (*iarg) {
+
+               case VIDEO_MODE_NTSC:
+                       break;
+
+               case VIDEO_MODE_PAL:
+                       break;
+
+               default:
+                       return -EINVAL;
+
+               }
+               encoder->norm = *iarg;
+       }
+       break;
+
+       case ENCODER_SET_INPUT:
+       {
+               int *iarg = arg;
+               static const __u8 init[] = {
+                       0xc8, 0xcc, /* CRSCALE */
+                       0xca, 0x91, /* CBSCALE */
+                       0xcc, 0x24, /* YC16 | OSDNUM */
+                       0xda, 0x00, /*  */
+                       0xdc, 0x24, /* SETMODE | PAL */
+                       0xde, 0x02, /* EACTIVE */
+
+                       /* overlay colors */
+                       0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */
+                       0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */
+                       0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */
+                       0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */
+                       0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */
+                       0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */
+                       0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */
+                       0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */
+
+                       0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */
+                       0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */
+                       0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */
+                       0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */
+                       0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */
+                       0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */
+                       0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */
+                       0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */
+               };
+               int i;
+               u8 val;
+
+               for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
+                       bt866_write(encoder, init[i], init[i+1]);
+
+               val = encoder->reg[0xdc];
+
+               if (*iarg == 0)
+                       val |= 0x40; /* CBSWAP */
+               else
+                       val &= ~0x40; /* !CBSWAP */
+
+               bt866_write(encoder, 0xdc, val);
+
+               val = encoder->reg[0xcc];
+               if (*iarg == 2)
+                       val |= 0x01; /* OSDBAR */
+               else
+                       val &= ~0x01; /* !OSDBAR */
+               bt866_write(encoder, 0xcc, val);
+
+               DEBUG(printk(KERN_INFO "%s: set input %d\n",
+                            encoder->i2c->name, *iarg));
+
+               switch (*iarg) {
+               case 0:
+                       break;
+               case 1:
+                       break;
+               default:
+                       return -EINVAL;
+
+               }
+       }
+       break;
+
+       case ENCODER_SET_OUTPUT:
+       {
+               int *iarg = arg;
+
+               DEBUG(printk(KERN_INFO "%s: set output %d\n",
+                            encoder->i2c->name, *iarg));
+
+               /* not much choice of outputs */
+               if (*iarg != 0)
+                       return -EINVAL;
+       }
+       break;
+
+       case ENCODER_ENABLE_OUTPUT:
+       {
+               int *iarg = arg;
+               encoder->enable = !!*iarg;
+
+               DEBUG(printk
+                     (KERN_INFO "%s: enable output %d\n",
+                      encoder->i2c->name, encoder->enable));
+       }
+       break;
+
+       case 4711:
+       {
+               int *iarg = arg;
+               __u8 val;
+
+               printk("bt866: square = %d\n", *iarg);
+
+               val = encoder->reg[0xdc];
+               if (*iarg)
+                       val |= 1; /* SQUARE */
+               else
+                       val &= ~1; /* !SQUARE */
+               bt866_write(encoder, 0xdc, val);
+               break;
+       }
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int bt866_write(struct bt866 *encoder,
+                       unsigned char subaddr, unsigned char data)
+{
+       unsigned char buffer[2];
+       int err;
+
+       buffer[0] = subaddr;
+       buffer[1] = data;
+
+       encoder->reg[subaddr] = data;
+
+       DEBUG(printk
+             ("%s: write 0x%02X = 0x%02X\n",
+              encoder->i2c->name, subaddr, data));
+
+       for (err = 0; err < 3;) {
+               if (i2c_master_send(encoder->i2c, buffer, 2) == 2)
+                       break;
+               err++;
+               printk(KERN_WARNING "%s: I/O error #%d "
+                      "(write 0x%02x/0x%02x)\n",
+                      encoder->i2c->name, err, encoder->addr, subaddr);
+               schedule_timeout_interruptible(HZ/10);
+       }
+       if (err == 3) {
+               printk(KERN_WARNING "%s: giving up\n",
+                      encoder->i2c->name);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int bt866_attach(struct i2c_adapter *adapter);
+static int bt866_detach(struct i2c_client *client);
+static int bt866_command(struct i2c_client *client,
+                        unsigned int cmd, void *arg);
+
+
+/* Addresses to scan */
+static unsigned short normal_i2c[]     = {I2C_BT866>>1, I2C_CLIENT_END};
+static unsigned short probe[2]         = {I2C_CLIENT_END, I2C_CLIENT_END};
+static unsigned short ignore[2]                = {I2C_CLIENT_END, I2C_CLIENT_END};
+
+static struct i2c_client_address_data addr_data = {
+       normal_i2c,
+       probe,
+       ignore,
+};
+
+static struct i2c_driver i2c_driver_bt866 = {
+       .driver.name = BT866_DEVNAME,
+       .id = I2C_DRIVERID_BT866,
+       .attach_adapter = bt866_attach,
+       .detach_client = bt866_detach,
+       .command = bt866_command
+};
+
+
+static struct i2c_client bt866_client_tmpl =
+{
+       .name = "(nil)",
+       .addr = 0,
+       .adapter = NULL,
+       .driver = &i2c_driver_bt866,
+       .usage_count = 0
+};
+
+static int bt866_found_proc(struct i2c_adapter *adapter,
+                           int addr, int kind)
+{
+       struct bt866 *encoder;
+       struct i2c_client *client;
+
+       client = kzalloc(sizeof(*client), GFP_KERNEL);
+       if (client == NULL)
+               return -ENOMEM;
+       memcpy(client, &bt866_client_tmpl, sizeof(*client));
+
+       encoder = kzalloc(sizeof(*encoder), GFP_KERNEL);
+       if (encoder == NULL) {
+               kfree(client);
+               return -ENOMEM;
+       }
+
+       i2c_set_clientdata(client, encoder);
+       client->adapter = adapter;
+       client->addr = addr;
+       sprintf(client->name, "%s-%02x", BT866_DEVNAME, adapter->id);
+
+       encoder->i2c = client;
+       encoder->addr = addr;
+       //encoder->encoder_type = ENCODER_TYPE_UNKNOWN;
+
+       /* initialize */
+
+       i2c_attach_client(client);
+
+       return 0;
+}
+
+static int bt866_attach(struct i2c_adapter *adapter)
+{
+       if (adapter->id == I2C_HW_B_ZR36067)
+               return i2c_probe(adapter, &addr_data, bt866_found_proc);
+       return 0;
+}
+
+static int bt866_detach(struct i2c_client *client)
+{
+       struct bt866 *encoder = i2c_get_clientdata(client);
+
+       i2c_detach_client(client);
+       kfree(encoder);
+       kfree(client);
+
+       return 0;
+}
+
+static int bt866_command(struct i2c_client *client,
+                        unsigned int cmd, void *arg)
+{
+       struct bt866 *encoder = i2c_get_clientdata(client);
+       return bt866_do_command(encoder, cmd, arg);
+}
+
+static int __devinit bt866_init(void)
+{
+       i2c_add_driver(&i2c_driver_bt866);
+       return 0;
+}
+
+static void __devexit bt866_exit(void)
+{
+       i2c_del_driver(&i2c_driver_bt866);
+}
+
+module_init(bt866_init);
+module_exit(bt866_exit);
index 2b64aa835b423663a203685b6c95a9fc94348fef..3116345c93b16b1ce6af92f6dd814a68bbaa95de 100644 (file)
@@ -269,7 +269,7 @@ static struct CARD {
        { 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" },
+       { 0x010115cb, BTTV_BOARD_GMV1,          "AG GMV1" },
        { 0x010114c7, BTTV_BOARD_MODTEC_205,    "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
 
        { 0x10b42636, BTTV_BOARD_HAUPPAUGE878,  "STB ???" },
@@ -309,6 +309,7 @@ static struct CARD {
        { 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" },
+       { 0x00261822, BTTV_BOARD_TWINHAN_DST,   "DNTV Live! Mini "},
 
        { 0, -1, NULL }
 };
@@ -1903,7 +1904,7 @@ struct tvcard bttv_tvcards[] = {
                .no_tda7432     = 1,
        },
        [BTTV_BOARD_OSPREY2x0] = {
-               .name           = "Osprey 210/220",   /* 0x1(A|B)-04C0-C1 */
+               .name           = "Osprey 210/220/230",   /* 0x1(A|B)-04C0-C1 */
                .video_inputs   = 2,
                .audio_inputs   = 1,
                .tuner          = -1,
@@ -2745,7 +2746,7 @@ struct tvcard bttv_tvcards[] = {
                /* Michael Krufky <mkrufky@m1k.net> */
                .name           = "DViCO FusionHDTV 5 Lite",
                .tuner          = 0,
-               .tuner_type     = TUNER_LG_TDVS_H062F,
+               .tuner_type     = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .video_inputs   = 3,
@@ -2762,7 +2763,7 @@ struct tvcard bttv_tvcards[] = {
        },
                /* ---- card 0x88---------------------------------- */
        [BTTV_BOARD_ACORP_Y878F] = {
-               /* Mauro Carvalho Chehab <mchehab@brturbo.com.br> */
+               /* Mauro Carvalho Chehab <mchehab@infradead.org> */
                .name           = "Acorp Y878F",
                .video_inputs   = 3,
                .audio_inputs   = 1,
@@ -3790,6 +3791,7 @@ static void __devinit osprey_eeprom(struct bttv *btv)
                       break;
               case 0x0060:
               case 0x0070:
+              case 0x00A0:
                       btv->c.type = BTTV_BOARD_OSPREY2x0;
                       /* enable output on select control lines */
                       gpio_inout(0xffffff,0x000303);
index c4d5e2b70c28e12c28761b09713e5d669cb3fcdc..ba081f6f8c82c6818b93e11c50f4682c3e36bd43 100644 (file)
@@ -118,20 +118,6 @@ int bttv_sub_del_devices(struct bttv_core *core)
        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                                */
 
index 69efa0e5174d58ffb113d97479f8b82180490b65..b41f81d2372ccd8b4e0a25d95c8a57e6491d4915 100644 (file)
@@ -355,7 +355,7 @@ int bttv_input_init(struct bttv *btv)
 
        if (ir->rc5_gpio) {
                u32 gpio;
-               /* enable remote irq */
+               /* 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));
index 3a23265c153860a1efe06176576f4aa2e02ed32e..f9c9e3c4d111944cf2c42d93c45513b5a28304da 100644 (file)
@@ -350,7 +350,6 @@ struct bttv_sub_driver {
        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)
 
index ee989d2e15d9ede516d1ff51113f7c6a64a29809..d2956010f763c0cb05a58fb21c6fc629086f86dc 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/pci.h>
 #include <linux/input.h>
 #include <linux/mutex.h>
@@ -214,7 +215,6 @@ extern struct videobuf_queue_ops bttv_vbi_qops;
 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);
 
 
 /* ---------------------------------------------------------- */
index cf61c590f4ada90bb038e9e2b9610a4870336013..7d0b6e59c6e2449b3030a70a4584499039a1cd66 100644 (file)
@@ -73,6 +73,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include <linux/parport.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/mutex.h>
 #include <asm/uaccess.h>
 
@@ -759,7 +760,7 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
                {
                        struct video_picture *p = arg;
                        if(p->palette!=VIDEO_PALETTE_GREY)
-                               return -EINVAL;
+                               return -EINVAL;
                        if(p->depth!=4 && p->depth!=6)
                                return -EINVAL;
 
index 22a7386bbea6f537b8f8b30dc32965ef5609fe7f..a3989bd2f81bb99b94c49127d36d7f277ba53689 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/parport.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/mutex.h>
 
 #include <asm/uaccess.h>
index 85d84e89d8f4d9fbb7d878ae8aa3010836dc3d13..95c5aceecc5bb9566f64887d805713d4cfc28286 100644 (file)
 
 #include "cpia.h"
 
-#ifdef CONFIG_VIDEO_CPIA_PP
-extern int cpia_pp_init(void);
-#endif
-#ifdef CONFIG_VIDEO_CPIA_USB
-extern int cpia_usb_init(void);
-#endif
-
 static int video_nr = -1;
 
 #ifdef MODULE
@@ -67,10 +60,10 @@ MODULE_SUPPORTED_DEVICE("video");
 static unsigned short colorspace_conv;
 module_param(colorspace_conv, ushort, 0444);
 MODULE_PARM_DESC(colorspace_conv,
-                 " Colorspace conversion:"
-                 "\n  0 = disable, 1 = enable"
-                 "\n  Default value is 0"
-                 );
+                " Colorspace conversion:"
+                "\n  0 = disable, 1 = enable"
+                "\n  Default value is 0"
+                );
 
 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
 
@@ -4047,13 +4040,6 @@ static int __init cpia_init(void)
        proc_cpia_create();
 #endif
 
-#ifdef CONFIG_VIDEO_CPIA_PP
-       cpia_pp_init();
-#endif
-#ifdef CONFIG_VIDEO_CPIA_USB
-       cpia_usb_init();
-#endif
-
        return 0;
 }
 
index dde27a6a4a095bbc084cfe1f96d58d58466f12c3..6eaa692021c58f61c52843df4e60bea7172cddb1 100644 (file)
@@ -45,6 +45,7 @@
 
 #include <asm/uaccess.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/list.h>
 #include <linux/smp_lock.h>
 #include <linux/mutex.h>
@@ -247,7 +248,7 @@ 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 */
index 1764991b0ac98df4c26b32cefa63f17bab80dcd9..c5ecb2be5f9313d692f0c9826e6202f2b64c357b 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <linux/version.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/usb.h>
 #include <linux/poll.h>
 
index 481e178ef56df58b197463a0ba250d94811b79d3..d129db57fcd4bab57861528b200092326bf86bc4 100644 (file)
@@ -343,7 +343,9 @@ static int cpia2_close(struct inode *inode, struct file *file)
                cpia2_free_buffers(cam);
                if (!cam->present) {
                        video_unregister_device(dev);
+                       mutex_unlock(&cam->busy_lock);
                        kfree(cam);
+                       return 0;
                }
        }
 
@@ -1167,9 +1169,9 @@ static int ioctl_g_ctrl(void *arg,struct camera_data *cam)
                } else {
                    if(cam->params.flicker_control.cam_register &
                       CPIA2_VP_FLICKER_MODES_50HZ) {
-                       mode = FLICKER_50;
+                       mode = FLICKER_50;
                    } else {
-                       mode = FLICKER_60;
+                       mode = FLICKER_60;
                    }
                }
                for(i=0; i<NUM_FLICKER_CONTROLS; i++) {
index 0b00e6027dfb302669a688f0167bc7a0bf8e1377..4c89bd395d3e6d275d78fda9580d16ed3a427d4a 100644 (file)
@@ -803,7 +803,7 @@ static struct parport_driver cpia_pp_driver = {
        .detach = cpia_pp_detach,
 };
 
-int cpia_pp_init(void)
+static int cpia_pp_init(void)
 {
        printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT,
               CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER);
@@ -860,6 +860,8 @@ void cleanup_module(void)
 
 static int __init cpia_pp_setup(char *str)
 {
+       int err;
+
        if (!strncmp(str, "parport", 7)) {
                int n = simple_strtoul(str + 7, NULL, 10);
                if (parport_ptr < PARPORT_MAX) {
@@ -873,6 +875,10 @@ static int __init cpia_pp_setup(char *str)
                parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE;
        }
 
+       err=cpia_pp_init();
+       if (err)
+               return err;
+
        return 1;
 }
 
index 9c49a4b00116f1ef7075888ecd26f6b261bcb75b..2ee34a3b92807bf96654c4ce6cd89aa79a8b6ca7 100644 (file)
@@ -474,12 +474,6 @@ static int cpia_usb_close(void *privdata)
        return 0;
 }
 
-int cpia_usb_init(void)
-{
-       /* return -ENODEV; */
-       return 0;
-}
-
 /* Probing and initializing */
 
 static int cpia_probe(struct usb_interface *intf,
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
new file mode 100644 (file)
index 0000000..554813e
--- /dev/null
@@ -0,0 +1,915 @@
+/*
+ * cx2341x - generic code for cx23415/6 based devices
+ *
+ * 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.
+ */
+
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+
+#include <media/tuner.h>
+#include <media/cx2341x.h>
+#include <media/v4l2-common.h>
+
+MODULE_DESCRIPTION("cx23415/6 driver");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+const u32 cx2341x_mpeg_ctrls[] = {
+       V4L2_CID_MPEG_CLASS,
+       V4L2_CID_MPEG_STREAM_TYPE,
+       V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+       V4L2_CID_MPEG_AUDIO_ENCODING,
+       V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+       V4L2_CID_MPEG_AUDIO_MODE,
+       V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
+       V4L2_CID_MPEG_AUDIO_EMPHASIS,
+       V4L2_CID_MPEG_AUDIO_CRC,
+       V4L2_CID_MPEG_VIDEO_ENCODING,
+       V4L2_CID_MPEG_VIDEO_ASPECT,
+       V4L2_CID_MPEG_VIDEO_B_FRAMES,
+       V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+       V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
+       V4L2_CID_MPEG_VIDEO_PULLDOWN,
+       V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+       V4L2_CID_MPEG_VIDEO_BITRATE,
+       V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+       V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION,
+       V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
+       V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
+       V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
+       V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE,
+       V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE,
+       V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER,
+       V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE,
+       V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM,
+       V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
+       V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
+       V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
+       0
+};
+
+
+/* Map the control ID to the correct field in the cx2341x_mpeg_params
+   struct. Return -EINVAL if the ID is unknown, else return 0. */
+static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
+               struct v4l2_ext_control *ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+               ctrl->value = params->audio_sampling_freq;
+               break;
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+               ctrl->value = params->audio_encoding;
+               break;
+       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+               ctrl->value = params->audio_l2_bitrate;
+               break;
+       case V4L2_CID_MPEG_AUDIO_MODE:
+               ctrl->value = params->audio_mode;
+               break;
+       case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+               ctrl->value = params->audio_mode_extension;
+               break;
+       case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+               ctrl->value = params->audio_emphasis;
+               break;
+       case V4L2_CID_MPEG_AUDIO_CRC:
+               ctrl->value = params->audio_crc;
+               break;
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               ctrl->value = params->video_encoding;
+               break;
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+               ctrl->value = params->video_aspect;
+               break;
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+               ctrl->value = params->video_b_frames;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               ctrl->value = params->video_gop_size;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+               ctrl->value = params->video_gop_closure;
+               break;
+       case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+               ctrl->value = params->video_pulldown;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               ctrl->value = params->video_bitrate_mode;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               ctrl->value = params->video_bitrate;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+               ctrl->value = params->video_bitrate_peak;
+               break;
+       case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+               ctrl->value = params->video_temporal_decimation;
+               break;
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               ctrl->value = params->stream_type;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+               ctrl->value = params->video_spatial_filter_mode;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+               ctrl->value = params->video_spatial_filter;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+               ctrl->value = params->video_luma_spatial_filter_type;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+               ctrl->value = params->video_chroma_spatial_filter_type;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+               ctrl->value = params->video_temporal_filter_mode;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+               ctrl->value = params->video_temporal_filter;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+               ctrl->value = params->video_median_filter_type;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+               ctrl->value = params->video_luma_median_filter_top;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+               ctrl->value = params->video_luma_median_filter_bottom;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+               ctrl->value = params->video_chroma_median_filter_top;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+               ctrl->value = params->video_chroma_median_filter_bottom;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* Map the control ID to the correct field in the cx2341x_mpeg_params
+   struct. Return -EINVAL if the ID is unknown, else return 0. */
+static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
+               struct v4l2_ext_control *ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+               params->audio_sampling_freq = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+               params->audio_encoding = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+               params->audio_l2_bitrate = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_AUDIO_MODE:
+               params->audio_mode = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+               params->audio_mode_extension = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+               params->audio_emphasis = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_AUDIO_CRC:
+               params->audio_crc = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+               params->video_aspect = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES: {
+               int b = ctrl->value + 1;
+               int gop = params->video_gop_size;
+               params->video_b_frames = ctrl->value;
+               params->video_gop_size = b * ((gop + b - 1) / b);
+               /* Max GOP size = 34 */
+               while (params->video_gop_size > 34)
+                       params->video_gop_size -= b;
+               break;
+       }
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE: {
+               int b = params->video_b_frames + 1;
+               int gop = ctrl->value;
+               params->video_gop_size = b * ((gop + b - 1) / b);
+               /* Max GOP size = 34 */
+               while (params->video_gop_size > 34)
+                       params->video_gop_size -= b;
+               ctrl->value = params->video_gop_size;
+               break;
+       }
+       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+               params->video_gop_closure = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+               params->video_pulldown = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               /* MPEG-1 only allows CBR */
+               if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
+                   ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+                       return -EINVAL;
+               params->video_bitrate_mode = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               params->video_bitrate = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+               params->video_bitrate_peak = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+               params->video_temporal_decimation = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               params->stream_type = ctrl->value;
+               params->video_encoding =
+                       (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
+                        params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
+                       V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+               if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
+                       /* MPEG-1 implies CBR */
+                       params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+               }
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+               params->video_spatial_filter_mode = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+               params->video_spatial_filter = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+               params->video_luma_spatial_filter_type = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+               params->video_chroma_spatial_filter_type = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+               params->video_temporal_filter_mode = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+               params->video_temporal_filter = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+               params->video_median_filter_type = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+               params->video_luma_median_filter_top = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+               params->video_luma_median_filter_bottom = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+               params->video_chroma_median_filter_top = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+               params->video_chroma_median_filter_bottom = ctrl->value;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
+{
+       const char *name;
+
+       qctrl->flags = 0;
+       switch (qctrl->id) {
+       /* MPEG controls */
+       case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+               name = "Spatial Filter Mode";
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+               name = "Spatial Filter";
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+               name = "Spatial Luma Filter Type";
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+               name = "Spatial Chroma Filter Type";
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+               name = "Temporal Filter Mode";
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+               name = "Temporal Filter";
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+               name = "Median Filter Type";
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+               name = "Median Luma Filter Maximum";
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+               name = "Median Luma Filter Minimum";
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+               name = "Median Chroma Filter Maximum";
+               break;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+               name = "Median Chroma Filter Minimum";
+               break;
+
+       default:
+               return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
+       }
+       switch (qctrl->id) {
+       case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+       case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+       case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+       case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+       case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+               qctrl->type = V4L2_CTRL_TYPE_MENU;
+               min = 0;
+               step = 1;
+               break;
+       default:
+               qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+               break;
+       }
+       switch (qctrl->id) {
+       case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+       case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+       case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+               qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
+               break;
+       }
+       qctrl->minimum = min;
+       qctrl->maximum = max;
+       qctrl->step = step;
+       qctrl->default_value = def;
+       qctrl->reserved[0] = qctrl->reserved[1] = 0;
+       snprintf(qctrl->name, sizeof(qctrl->name), name);
+       return 0;
+}
+
+int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl)
+{
+       int err;
+
+       switch (qctrl->id) {
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+                               V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
+                               V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+
+       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_L2_BITRATE_192K,
+                               V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
+                               V4L2_MPEG_AUDIO_L2_BITRATE_224K);
+
+       case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+       case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+               return -EINVAL;
+
+       case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+               err = v4l2_ctrl_query_fill_std(qctrl);
+               if (err == 0 && params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
+                       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               return err;
+
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               /* this setting is read-only for the cx2341x since the
+                  V4L2_CID_MPEG_STREAM_TYPE really determines the
+                  MPEG-1/2 setting */
+               err = v4l2_ctrl_query_fill_std(qctrl);
+               if (err == 0)
+                       qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+               return err;
+
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               err = v4l2_ctrl_query_fill_std(qctrl);
+               if (err == 0 && params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+                       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               return err;
+
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+               err = v4l2_ctrl_query_fill_std(qctrl);
+               if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+                       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               return err;
+
+       /* CX23415/6 specific */
+       case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+               return cx2341x_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+                               V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
+                               V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
+
+       case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+               cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0);
+               qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+               if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+                      qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               return 0;
+
+       case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+               cx2341x_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
+                               V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, 1,
+                               V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
+               if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+                      qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               return 0;
+
+       case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+               cx2341x_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
+                               V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, 1,
+                               V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
+               if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+                      qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               return 0;
+
+       case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+               return cx2341x_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+                               V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
+                               V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
+
+       case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+               cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0);
+               qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+               if (params->video_temporal_filter_mode == V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
+                      qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               return 0;
+
+       case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+               return cx2341x_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+                               V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
+                               V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
+
+       case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+               cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
+               qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+               if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+                      qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               return 0;
+
+       case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+               cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+               qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+               if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+                      qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               return 0;
+
+       case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+               cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
+               qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+               if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+                      qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               return 0;
+
+       case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+               cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+               qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+               if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+                      qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               return 0;
+
+       default:
+               return v4l2_ctrl_query_fill_std(qctrl);
+
+       }
+}
+
+const char **cx2341x_ctrl_get_menu(u32 id)
+{
+       static const char *mpeg_stream_type[] = {
+               "MPEG-2 Program Stream",
+               "",
+               "MPEG-1 System Stream",
+               "MPEG-2 DVD-compatible Stream",
+               "MPEG-1 VCD-compatible Stream",
+               "MPEG-2 SVCD-compatible Stream",
+               NULL
+       };
+
+       static const char *cx2341x_video_spatial_filter_mode_menu[] = {
+               "Manual",
+               "Auto",
+               NULL
+       };
+
+       static const char *cx2341x_video_luma_spatial_filter_type_menu[] = {
+               "Off",
+               "1D Horizontal",
+               "1D Vertical",
+               "2D H/V Separable",
+               "2D Symmetric non-separable",
+               NULL
+       };
+
+       static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = {
+               "Off",
+               "1D Horizontal",
+               NULL
+       };
+
+       static const char *cx2341x_video_temporal_filter_mode_menu[] = {
+               "Manual",
+               "Auto",
+               NULL
+       };
+
+       static const char *cx2341x_video_median_filter_type_menu[] = {
+               "Off",
+               "Horizontal",
+               "Vertical",
+               "Horizontal/Vertical",
+               "Diagonal",
+               NULL
+       };
+
+       switch (id) {
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               return mpeg_stream_type;
+       case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+       case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+               return NULL;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+               return cx2341x_video_spatial_filter_mode_menu;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+               return cx2341x_video_luma_spatial_filter_type_menu;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+               return cx2341x_video_chroma_spatial_filter_type_menu;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+               return cx2341x_video_temporal_filter_mode_menu;
+       case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+               return cx2341x_video_median_filter_type_menu;
+       default:
+               return v4l2_ctrl_get_menu(id);
+       }
+}
+
+static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
+{
+       params->audio_properties = (params->audio_sampling_freq << 0) |
+               ((3 - params->audio_encoding) << 2) |
+               ((1 + params->audio_l2_bitrate) << 4) |
+               (params->audio_mode << 8) |
+               (params->audio_mode_extension << 10) |
+               (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ?
+                 3 :
+                 params->audio_emphasis) << 12) |
+               (params->audio_crc << 14);
+}
+
+int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
+                 struct v4l2_ext_controls *ctrls, int cmd)
+{
+       int err = 0;
+       int i;
+
+       if (cmd == VIDIOC_G_EXT_CTRLS) {
+               for (i = 0; i < ctrls->count; i++) {
+                       struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+                       err = cx2341x_get_ctrl(params, ctrl);
+                       if (err) {
+                               ctrls->error_idx = i;
+                               break;
+                       }
+               }
+               return err;
+       }
+       for (i = 0; i < ctrls->count; i++) {
+               struct v4l2_ext_control *ctrl = ctrls->controls + i;
+               struct v4l2_queryctrl qctrl;
+               const char **menu_items = NULL;
+
+               qctrl.id = ctrl->id;
+               err = cx2341x_ctrl_query(params, &qctrl);
+               if (err)
+                       break;
+               if (qctrl.type == V4L2_CTRL_TYPE_MENU)
+                       menu_items = cx2341x_ctrl_get_menu(qctrl.id);
+               err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
+               if (err)
+                       break;
+               err = cx2341x_set_ctrl(params, ctrl);
+               if (err)
+                       break;
+       }
+       if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+                       params->video_bitrate_peak < params->video_bitrate) {
+               err = -ERANGE;
+               ctrls->error_idx = ctrls->count;
+       }
+       if (err) {
+               ctrls->error_idx = i;
+       }
+       else {
+               cx2341x_calc_audio_properties(params);
+       }
+       return err;
+}
+
+void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
+{
+       static struct cx2341x_mpeg_params default_params = {
+       /* misc */
+       .port = CX2341X_PORT_MEMORY,
+       .width = 720,
+       .height = 480,
+       .is_50hz = 0,
+
+       /* stream */
+       .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+
+       /* audio */
+       .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
+       .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+       .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K,
+       .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO,
+       .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
+       .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
+       .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
+
+       /* video */
+       .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
+       .video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
+       .video_b_frames = 2,
+       .video_gop_size = 12,
+       .video_gop_closure = 1,
+       .video_pulldown = 0,
+       .video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+       .video_bitrate = 6000000,
+       .video_bitrate_peak = 8000000,
+       .video_temporal_decimation = 0,
+
+       /* encoding filters */
+       .video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+       .video_spatial_filter = 0,
+       .video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
+       .video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
+       .video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+       .video_temporal_filter = 0,
+       .video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+       .video_luma_median_filter_top = 255,
+       .video_luma_median_filter_bottom = 0,
+       .video_chroma_median_filter_top = 255,
+       .video_chroma_median_filter_bottom = 0,
+       };
+
+       *p = default_params;
+       cx2341x_calc_audio_properties(p);
+}
+
+static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ...)
+{
+       u32 data[CX2341X_MBOX_MAX_DATA];
+       va_list vargs;
+       int i;
+
+       va_start(vargs, args);
+
+       for (i = 0; i < args; i++) {
+               data[i] = va_arg(vargs, int);
+       }
+       va_end(vargs);
+       return func(priv, cmd, args, 0, data);
+}
+
+int cx2341x_update(void *priv, cx2341x_mbox_func func,
+               const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new)
+{
+       static int mpeg_stream_type[] = {
+               0,      /* MPEG-2 PS */
+               1,      /* MPEG-2 TS */
+               2,      /* MPEG-1 SS */
+               14,     /* DVD */
+               11,     /* VCD */
+               12,     /* SVCD */
+       };
+
+       int err = 0;
+
+       cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
+
+       if (old == NULL || old->is_50hz != new->is_50hz) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz);
+               if (err) return err;
+       }
+
+       if (old == NULL || old->width != new->width || old->height != new->height ||
+                       old->video_encoding != new->video_encoding) {
+               u16 w = new->width;
+               u16 h = new->height;
+
+               if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
+                       w /= 2;
+                       h /= 2;
+               }
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
+               if (err) return err;
+       }
+
+       if (old == NULL || old->stream_type != new->stream_type) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]);
+               if (err) return err;
+       }
+       if (old == NULL || old->video_aspect != new->video_aspect) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect);
+               if (err) return err;
+       }
+       if (old == NULL || old->video_b_frames != new->video_b_frames ||
+               old->video_gop_size != new->video_gop_size) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
+                               new->video_gop_size, new->video_b_frames + 1);
+               if (err) return err;
+       }
+       if (old == NULL || old->video_gop_closure != new->video_gop_closure) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure);
+               if (err) return err;
+       }
+       if (old == NULL || old->video_pulldown != new->video_pulldown) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_3_2_PULLDOWN, 1, new->video_pulldown);
+               if (err) return err;
+       }
+       if (old == NULL || old->audio_properties != new->audio_properties) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
+               if (err) return err;
+       }
+       if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode ||
+               old->video_bitrate != new->video_bitrate ||
+               old->video_bitrate_peak != new->video_bitrate_peak) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
+                               new->video_bitrate_mode, new->video_bitrate,
+                               new->video_bitrate_peak / 400, 0, 0);
+               if (err) return err;
+       }
+       if (old == NULL || old->video_spatial_filter_mode != new->video_spatial_filter_mode ||
+               old->video_temporal_filter_mode != new->video_temporal_filter_mode ||
+               old->video_median_filter_type != new->video_median_filter_type) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
+                               new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1),
+                               new->video_median_filter_type);
+               if (err) return err;
+       }
+       if (old == NULL ||
+               old->video_luma_median_filter_bottom != new->video_luma_median_filter_bottom ||
+               old->video_luma_median_filter_top != new->video_luma_median_filter_top ||
+               old->video_chroma_median_filter_bottom != new->video_chroma_median_filter_bottom ||
+               old->video_chroma_median_filter_top != new->video_chroma_median_filter_top) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
+                               new->video_luma_median_filter_bottom,
+                               new->video_luma_median_filter_top,
+                               new->video_chroma_median_filter_bottom,
+                               new->video_chroma_median_filter_top);
+               if (err) return err;
+       }
+       if (old == NULL ||
+               old->video_luma_spatial_filter_type != new->video_luma_spatial_filter_type ||
+               old->video_chroma_spatial_filter_type != new->video_chroma_spatial_filter_type) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
+                       new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type);
+               if (err) return err;
+       }
+       if (old == NULL ||
+               old->video_spatial_filter != new->video_spatial_filter ||
+               old->video_temporal_filter != new->video_temporal_filter) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
+                       new->video_spatial_filter, new->video_temporal_filter);
+               if (err) return err;
+       }
+       if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) {
+               err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1,
+                       new->video_temporal_decimation);
+               if (err) return err;
+       }
+       return 0;
+}
+
+static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id)
+{
+       const char **menu = cx2341x_ctrl_get_menu(id);
+       struct v4l2_ext_control ctrl;
+
+       if (menu == NULL)
+               goto invalid;
+       ctrl.id = id;
+       if (cx2341x_get_ctrl(p, &ctrl))
+               goto invalid;
+       while (ctrl.value-- && *menu) menu++;
+       if (*menu == NULL)
+               goto invalid;
+       return *menu;
+
+invalid:
+       return "<invalid>";
+}
+
+void cx2341x_log_status(struct cx2341x_mpeg_params *p, int card_id)
+{
+       int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+
+       /* Stream */
+       printk(KERN_INFO "cx2341x-%d: Stream: %s\n",
+               card_id,
+               cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
+
+       /* Video */
+       printk(KERN_INFO "cx2341x-%d: Video:  %dx%d, %d fps\n",
+               card_id,
+               p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
+               p->is_50hz ? 25 : 30);
+       printk(KERN_INFO "cx2341x-%d: Video:  %s, %s, %s, %d",
+               card_id,
+               cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
+               cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
+               cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
+               p->video_bitrate);
+       if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
+               printk(", Peak %d", p->video_bitrate_peak);
+       }
+       printk("\n");
+       printk(KERN_INFO "cx2341x-%d: Video:  GOP Size %d, %d B-Frames, %sGOP Closure, %s3:2 Pulldown\n",
+               card_id,
+               p->video_gop_size, p->video_b_frames,
+               p->video_gop_closure ? "" : "No ",
+               p->video_pulldown ? "" : "No ");
+       if (p->video_temporal_decimation) {
+               printk(KERN_INFO "cx2341x-%d: Video: Temporal Decimation %d\n",
+                       card_id, p->video_temporal_decimation);
+       }
+
+       /* Audio */
+       printk(KERN_INFO "cx2341x-%d: Audio:  %s, %s, %s, %s",
+               card_id,
+               cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
+               cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
+               cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
+               cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE));
+       if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) {
+               printk(", %s",
+                       cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
+       }
+       printk(", %s, %s\n",
+               cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
+               cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
+
+       /* Encoding filters */
+       printk(KERN_INFO "cx2341x-%d: Spatial Filter:  %s, Luma %s, Chroma %s, %d\n",
+               card_id,
+               cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
+               cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
+               cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
+               p->video_spatial_filter);
+       printk(KERN_INFO "cx2341x-%d: Temporal Filter: %s, %d\n",
+               card_id,
+               cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
+               p->video_temporal_filter);
+       printk(KERN_INFO "cx2341x-%d: Median Filter:   %s, Luma [%d, %d], Chroma [%d, %d]\n",
+               card_id,
+               cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
+               p->video_luma_median_filter_bottom,
+               p->video_luma_median_filter_top,
+               p->video_chroma_median_filter_bottom,
+               p->video_chroma_median_filter_top);
+}
+
+EXPORT_SYMBOL(cx2341x_fill_defaults);
+EXPORT_SYMBOL(cx2341x_ctrl_query);
+EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
+EXPORT_SYMBOL(cx2341x_ext_ctrls);
+EXPORT_SYMBOL(cx2341x_update);
+EXPORT_SYMBOL(cx2341x_log_status);
+EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
index 9a4b813152e56a4f8c9af4e825a7cb834f9b2b8d..f897c1ebd5f3d809f4bf6bf6f111b2754395a4bc 100644 (file)
@@ -30,9 +30,6 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
        if (freq != 32000 && freq != 44100 && freq != 48000)
                return -EINVAL;
 
-       /* assert soft reset */
-       cx25840_and_or(client, 0x810, ~0x1, 0x01);
-
        /* common for all inputs and rates */
        /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
        cx25840_write(client, 0x127, 0x50);
@@ -46,6 +43,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
                        /* AUX_PLL_FRAC */
                        cx25840_write4(client, 0x110, 0xee39bb01);
 
+                       if (state->is_cx25836)
+                               break;
+
                        /* src3/4/6_ctl = 0x0801f77f */
                        cx25840_write4(client, 0x900, 0x7ff70108);
                        cx25840_write4(client, 0x904, 0x7ff70108);
@@ -59,6 +59,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
                        /* AUX_PLL_FRAC */
                        cx25840_write4(client, 0x110, 0xd66bec00);
 
+                       if (state->is_cx25836)
+                               break;
+
                        /* src3/4/6_ctl = 0x08016d59 */
                        cx25840_write4(client, 0x900, 0x596d0108);
                        cx25840_write4(client, 0x904, 0x596d0108);
@@ -72,6 +75,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
                        /* AUX_PLL_FRAC */
                        cx25840_write4(client, 0x110, 0xe5d69800);
 
+                       if (state->is_cx25836)
+                               break;
+
                        /* src3/4/6_ctl = 0x08014faa */
                        cx25840_write4(client, 0x900, 0xaa4f0108);
                        cx25840_write4(client, 0x904, 0xaa4f0108);
@@ -87,6 +93,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
                        /* AUX_PLL_FRAC */
                        cx25840_write4(client, 0x110, 0x69082a01);
 
+                       if (state->is_cx25836)
+                               break;
+
                        /* src1_ctl = 0x08010000 */
                        cx25840_write4(client, 0x8f8, 0x00000108);
 
@@ -106,6 +115,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
                        /* AUX_PLL_FRAC */
                        cx25840_write4(client, 0x110, 0xd66bec00);
 
+                       if (state->is_cx25836)
+                               break;
+
                        /* src1_ctl = 0x08010000 */
                        cx25840_write4(client, 0x8f8, 0xcd600108);
 
@@ -122,6 +134,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
                        /* AUX_PLL_FRAC */
                        cx25840_write4(client, 0x110, 0xe5d69800);
 
+                       if (state->is_cx25836)
+                               break;
+
                        /* src1_ctl = 0x08010000 */
                        cx25840_write4(client, 0x8f8, 0x00800108);
 
@@ -133,9 +148,6 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
                }
        }
 
-       /* deassert soft reset */
-       cx25840_and_or(client, 0x810, ~0x1, 0x00);
-
        state->audclk_freq = freq;
 
        return 0;
@@ -148,6 +160,10 @@ void cx25840_audio_set_path(struct i2c_client *client)
        /* stop microcontroller */
        cx25840_and_or(client, 0x803, ~0x10, 0);
 
+       /* assert soft reset */
+       if (!state->is_cx25836)
+               cx25840_and_or(client, 0x810, ~0x1, 0x01);
+
        /* Mute everything to prevent the PFFT! */
        cx25840_write(client, 0x8d3, 0x1f);
 
@@ -161,13 +177,19 @@ void cx25840_audio_set_path(struct i2c_client *client)
        } else {
                /* Set Path1 to Analog Demod Main Channel */
                cx25840_write4(client, 0x8d0, 0x7038061f);
+       }
 
+       set_audclk_freq(client, state->audclk_freq);
+
+       /* deassert soft reset */
+       if (!state->is_cx25836)
+               cx25840_and_or(client, 0x810, ~0x1, 0x00);
+
+       if (state->aud_input != CX25840_AUDIO_SERIAL) {
                /* When the microcontroller detects the
                 * audio format, it will unmute the lines */
                cx25840_and_or(client, 0x803, ~0x10, 0x10);
        }
-
-       set_audclk_freq(client, state->audclk_freq);
 }
 
 static int get_volume(struct i2c_client *client)
@@ -291,11 +313,25 @@ static void set_mute(struct i2c_client *client, int mute)
 
 int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
 {
+       struct cx25840_state *state = i2c_get_clientdata(client);
        struct v4l2_control *ctrl = arg;
+       int retval;
 
        switch (cmd) {
        case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-               return set_audclk_freq(client, *(u32 *)arg);
+               if (state->aud_input != CX25840_AUDIO_SERIAL) {
+                       cx25840_and_or(client, 0x803, ~0x10, 0);
+                       cx25840_write(client, 0x8d3, 0x1f);
+               }
+               if (!state->is_cx25836)
+                       cx25840_and_or(client, 0x810, ~0x1, 1);
+               retval = set_audclk_freq(client, *(u32 *)arg);
+               if (!state->is_cx25836)
+                       cx25840_and_or(client, 0x810, ~0x1, 0);
+               if (state->aud_input != CX25840_AUDIO_SERIAL) {
+                       cx25840_and_or(client, 0x803, ~0x10, 0x10);
+               }
+               return retval;
 
        case VIDIOC_G_CTRL:
                switch (ctrl->id) {
index a961bb2ab0fdcda188618a19ba99dfedc7aab747..5c2036b40ea11e8373b101a3a9c2844ddbcf0dd5 100644 (file)
@@ -10,6 +10,9 @@
  *
  * VBI support by Hans Verkuil <hverkuil@xs4all.nl>.
  *
+ * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca>
+ * with additional fixes by 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
@@ -43,7 +46,7 @@ MODULE_LICENSE("GPL");
 static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
 
 
-static int cx25840_debug;
+int cx25840_debug;
 
 module_param_named(debug,cx25840_debug, int, 0644);
 
@@ -105,7 +108,7 @@ u32 cx25840_read4(struct i2c_client * client, u16 addr)
            (buffer[2] << 8) | buffer[3];
 }
 
-int cx25840_and_or(struct i2c_client *client, u16 addr, u8 and_mask,
+int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask,
                   u8 or_value)
 {
        return cx25840_write(client, addr,
@@ -117,7 +120,8 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, u8 and_mask,
 
 static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
                                                enum cx25840_audio_input aud_input);
-static void log_status(struct i2c_client *client);
+static void log_audio_status(struct i2c_client *client);
+static void log_video_status(struct i2c_client *client);
 
 /* ----------------------------------------------------------------------- */
 
@@ -147,6 +151,33 @@ static void init_dll2(struct i2c_client *client)
        cx25840_write(client, 0x15d, 0xe1);
 }
 
+static void cx25836_initialize(struct i2c_client *client)
+{
+       /* reset configuration is described on page 3-77 of the CX25836 datasheet */
+       /* 2. */
+       cx25840_and_or(client, 0x000, ~0x01, 0x01);
+       cx25840_and_or(client, 0x000, ~0x01, 0x00);
+       /* 3a. */
+       cx25840_and_or(client, 0x15a, ~0x70, 0x00);
+       /* 3b. */
+       cx25840_and_or(client, 0x15b, ~0x1e, 0x06);
+       /* 3c. */
+       cx25840_and_or(client, 0x159, ~0x02, 0x02);
+       /* 3d. */
+       /* There should be a 10-us delay here, but since the
+          i2c bus already has a 10-us delay we don't need to do
+          anything */
+       /* 3e. */
+       cx25840_and_or(client, 0x159, ~0x02, 0x00);
+       /* 3f. */
+       cx25840_and_or(client, 0x159, ~0xc0, 0xc0);
+       /* 3g. */
+       cx25840_and_or(client, 0x159, ~0x01, 0x00);
+       cx25840_and_or(client, 0x159, ~0x01, 0x01);
+       /* 3h. */
+       cx25840_and_or(client, 0x15b, ~0x1e, 0x10);
+}
+
 static void cx25840_initialize(struct i2c_client *client, int loadfw)
 {
        struct cx25840_state *state = i2c_get_clientdata(client);
@@ -220,17 +251,7 @@ static void input_change(struct i2c_client *client)
        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) {
-               /* Follow tuner change procedure for PAL */
-               cx25840_write(client, 0x808, 0xff);
-               cx25840_write(client, 0x80b, 0x10);
-       } else if (std & V4L2_STD_SECAM) {
-               /* Select autodetect for SECAM */
-               cx25840_write(client, 0x808, 0xff);
-               cx25840_write(client, 0x80b, 0x10);
-       } else if (std & V4L2_STD_NTSC) {
+       if (std & V4L2_STD_525_60) {
                /* Certain Hauppauge PVR150 models have a hardware bug
                   that causes audio to drop out. For these models the
                   audio standard must be set explicitly.
@@ -249,6 +270,14 @@ static void input_change(struct i2c_client *client)
                        cx25840_write(client, 0x808, hw_fix ? 0x1f : 0xf6);
                }
                cx25840_write(client, 0x80b, 0x00);
+       } else if (std & V4L2_STD_PAL) {
+               /* Follow tuner change procedure for PAL */
+               cx25840_write(client, 0x808, 0xff);
+               cx25840_write(client, 0x80b, 0x10);
+       } else if (std & V4L2_STD_SECAM) {
+               /* Select autodetect for SECAM */
+               cx25840_write(client, 0x808, 0xff);
+               cx25840_write(client, 0x80b, 0x10);
        }
 
        if (cx25840_read(client, 0x803) & 0x10) {
@@ -319,8 +348,10 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
 
        state->vid_input = vid_input;
        state->aud_input = aud_input;
-       cx25840_audio_set_path(client);
-       input_change(client);
+       if (!state->is_cx25836) {
+               cx25840_audio_set_path(client);
+               input_change(client);
+       }
        return 0;
 }
 
@@ -354,6 +385,8 @@ static int set_v4lstd(struct i2c_client *client, v4l2_std_id std)
                }
        }
 
+       v4l_dbg(1, cx25840_debug, client, "changing video std to fmt %i\n",fmt);
+
        /* 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. */
@@ -370,6 +403,7 @@ static int set_v4lstd(struct i2c_client *client, v4l2_std_id std)
 
 v4l2_std_id cx25840_get_v4lstd(struct i2c_client * client)
 {
+       struct cx25840_state *state = i2c_get_clientdata(client);
        /* check VID_FMT_SEL first */
        u8 fmt = cx25840_read(client, 0x400) & 0xf;
 
@@ -383,7 +417,7 @@ v4l2_std_id cx25840_get_v4lstd(struct i2c_client * client)
        {
                /* if the audio std is A2-M, then this is the South Korean
                   NTSC standard */
-               if (cx25840_read(client, 0x805) == 2)
+               if (!state->is_cx25836 && cx25840_read(client, 0x805) == 2)
                        return V4L2_STD_NTSC_M_KR;
                return V4L2_STD_NTSC_M;
        }
@@ -456,6 +490,8 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
        case V4L2_CID_AUDIO_TREBLE:
        case V4L2_CID_AUDIO_BALANCE:
        case V4L2_CID_AUDIO_MUTE:
+               if (state->is_cx25836)
+                       return -EINVAL;
                return cx25840_audio(client, VIDIOC_S_CTRL, ctrl);
 
        default:
@@ -490,6 +526,8 @@ static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
        case V4L2_CID_AUDIO_TREBLE:
        case V4L2_CID_AUDIO_BALANCE:
        case V4L2_CID_AUDIO_MUTE:
+               if (state->is_cx25836)
+                       return -EINVAL;
                return cx25840_audio(client, VIDIOC_G_CTRL, ctrl);
        default:
                return -EINVAL;
@@ -579,91 +617,6 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
 
 /* ----------------------------------------------------------------------- */
 
-static struct v4l2_queryctrl cx25840_qctrl[] = {
-       {
-               .id            = V4L2_CID_BRIGHTNESS,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Brightness",
-               .minimum       = 0,
-               .maximum       = 255,
-               .step          = 1,
-               .default_value = 128,
-               .flags         = 0,
-       }, {
-               .id            = V4L2_CID_CONTRAST,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Contrast",
-               .minimum       = 0,
-               .maximum       = 127,
-               .step          = 1,
-               .default_value = 64,
-               .flags         = 0,
-       }, {
-               .id            = V4L2_CID_SATURATION,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Saturation",
-               .minimum       = 0,
-               .maximum       = 127,
-               .step          = 1,
-               .default_value = 64,
-               .flags         = 0,
-       }, {
-               .id            = V4L2_CID_HUE,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Hue",
-               .minimum       = -128,
-               .maximum       = 127,
-               .step          = 1,
-               .default_value = 0,
-               .flags         = 0,
-       }, {
-               .id            = V4L2_CID_AUDIO_VOLUME,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Volume",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 65535/100,
-               .default_value = 58880,
-               .flags         = 0,
-       }, {
-               .id            = V4L2_CID_AUDIO_BALANCE,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Balance",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 65535/100,
-               .default_value = 32768,
-               .flags         = 0,
-       }, {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .step          = 1,
-               .default_value = 1,
-               .flags         = 0,
-       }, {
-               .id            = V4L2_CID_AUDIO_BASS,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Bass",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 65535/100,
-               .default_value = 32768,
-       }, {
-               .id            = V4L2_CID_AUDIO_TREBLE,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Treble",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 65535/100,
-               .default_value = 32768,
-       },
-};
-
-/* ----------------------------------------------------------------------- */
-
 static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                           void *arg)
 {
@@ -706,8 +659,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
 
        case VIDIOC_STREAMON:
                v4l_dbg(1, cx25840_debug, client, "enable output\n");
-               cx25840_write(client, 0x115, 0x8c);
-               cx25840_write(client, 0x116, 0x07);
+               cx25840_write(client, 0x115, state->is_cx25836 ? 0x0c : 0x8c);
+               cx25840_write(client, 0x116, state->is_cx25836 ? 0x04 : 0x07);
                break;
 
        case VIDIOC_STREAMOFF:
@@ -717,7 +670,9 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                break;
 
        case VIDIOC_LOG_STATUS:
-               log_status(client);
+               log_video_status(client);
+               if (!state->is_cx25836)
+                       log_audio_status(client);
                break;
 
        case VIDIOC_G_CTRL:
@@ -729,13 +684,29 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
        case VIDIOC_QUERYCTRL:
        {
                struct v4l2_queryctrl *qc = arg;
-               int i;
 
-               for (i = 0; i < ARRAY_SIZE(cx25840_qctrl); i++)
-                       if (qc->id && qc->id == cx25840_qctrl[i].id) {
-                               memcpy(qc, &cx25840_qctrl[i], sizeof(*qc));
-                               return 0;
-                       }
+               switch (qc->id) {
+                       case V4L2_CID_BRIGHTNESS:
+                       case V4L2_CID_CONTRAST:
+                       case V4L2_CID_SATURATION:
+                       case V4L2_CID_HUE:
+                               return v4l2_ctrl_query_fill_std(qc);
+                       default:
+                               break;
+               }
+               if (state->is_cx25836)
+                       return -EINVAL;
+
+               switch (qc->id) {
+                       case V4L2_CID_AUDIO_VOLUME:
+                       case V4L2_CID_AUDIO_MUTE:
+                       case V4L2_CID_AUDIO_BALANCE:
+                       case V4L2_CID_AUDIO_BASS:
+                       case V4L2_CID_AUDIO_TREBLE:
+                               return v4l2_ctrl_query_fill_std(qc);
+                       default:
+                               return -EINVAL;
+               }
                return -EINVAL;
        }
 
@@ -760,31 +731,41 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                return set_input(client, route->input, state->aud_input);
 
        case VIDIOC_INT_G_AUDIO_ROUTING:
+               if (state->is_cx25836)
+                       return -EINVAL;
                route->input = state->aud_input;
                route->output = 0;
                break;
 
        case VIDIOC_INT_S_AUDIO_ROUTING:
+               if (state->is_cx25836)
+                       return -EINVAL;
                return set_input(client, state->vid_input, route->input);
 
        case VIDIOC_S_FREQUENCY:
-               input_change(client);
+               if (!state->is_cx25836) {
+                       input_change(client);
+               }
                break;
 
        case VIDIOC_G_TUNER:
        {
-               u8 mode = cx25840_read(client, 0x804);
-               u8 vpres = cx25840_read(client, 0x80a) & 0x10;
+               u8 vpres = cx25840_read(client, 0x40e) & 0x20;
+               u8 mode;
                int val = 0;
 
                if (state->radio)
                        break;
 
+               vt->signal = vpres ? 0xffff : 0x0;
+               if (state->is_cx25836)
+                       break;
+
                vt->capability |=
                    V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
                    V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
 
-               vt->signal = vpres ? 0xffff : 0x0;
+               mode = cx25840_read(client, 0x804);
 
                /* get rxsubchans and audmode */
                if ((mode & 0xf) == 1)
@@ -804,7 +785,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
        }
 
        case VIDIOC_S_TUNER:
-               if (state->radio)
+               if (state->radio || state->is_cx25836)
                        break;
 
                switch (vt->audmode) {
@@ -846,12 +827,14 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                return set_v4lfmt(client, (struct v4l2_format *)arg);
 
        case VIDIOC_INT_RESET:
-               cx25840_initialize(client, 0);
+               if (state->is_cx25836)
+                       cx25836_initialize(client);
+               else
+                       cx25840_initialize(client, 0);
                break;
 
        case VIDIOC_INT_G_CHIP_IDENT:
-               *(enum v4l2_chip_ident *)arg =
-                       V4L2_IDENT_CX25840 + ((cx25840_read(client, 0x100) >> 4) & 0xf);
+               *(enum v4l2_chip_ident *)arg = state->id;
                break;
 
        default:
@@ -870,6 +853,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
 {
        struct i2c_client *client;
        struct cx25840_state *state;
+       enum v4l2_chip_ident id;
        u16 device_id;
 
        /* Check if the adapter supports the needed features
@@ -878,10 +862,11 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
        if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
                return 0;
 
-       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (client == 0)
+       state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
+       if (state == 0)
                return -ENOMEM;
 
+       client = &state->c;
        client->addr = address;
        client->adapter = adapter;
        client->driver = &i2c_driver_cx25840;
@@ -893,10 +878,18 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
        device_id |= cx25840_read(client, 0x100);
 
        /* The high byte of the device ID should be
-        * 0x84 if chip is present */
-       if ((device_id & 0xff00) != 0x8400) {
+        * 0x83 for the cx2583x and 0x84 for the cx2584x */
+       if ((device_id & 0xff00) == 0x8300) {
+               id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
+               state->is_cx25836 = 1;
+       }
+       else if ((device_id & 0xff00) == 0x8400) {
+               id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
+               state->is_cx25836 = 0;
+       }
+       else {
                v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
-               kfree(client);
+               kfree(state);
                return 0;
        }
 
@@ -905,21 +898,19 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
                    (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3,
                    address << 1, adapter->name);
 
-       state = kmalloc(sizeof(struct cx25840_state), GFP_KERNEL);
-       if (state == NULL) {
-               kfree(client);
-               return -ENOMEM;
-       }
-
        i2c_set_clientdata(client, state);
-       memset(state, 0, sizeof(struct cx25840_state));
        state->vid_input = CX25840_COMPOSITE7;
        state->aud_input = CX25840_AUDIO8;
        state->audclk_freq = 48000;
        state->pvr150_workaround = 0;
        state->audmode = V4L2_TUNER_MODE_LANG1;
+       state->vbi_line_offset = 8;
+       state->id = id;
 
-       cx25840_initialize(client, 1);
+       if (state->is_cx25836)
+               cx25836_initialize(client);
+       else
+               cx25840_initialize(client, 1);
 
        i2c_attach_client(client);
 
@@ -944,7 +935,6 @@ static int cx25840_detach_client(struct i2c_client *client)
        }
 
        kfree(state);
-       kfree(client);
 
        return 0;
 }
@@ -977,7 +967,7 @@ module_exit(m__exit);
 
 /* ----------------------------------------------------------------------- */
 
-static void log_status(struct i2c_client *client)
+static void log_video_status(struct i2c_client *client)
 {
        static const char *const fmt_strs[] = {
                "0x0",
@@ -989,9 +979,36 @@ static void log_status(struct i2c_client *client)
        };
 
        struct cx25840_state *state = i2c_get_clientdata(client);
-       u8 microctrl_vidfmt = cx25840_read(client, 0x80a);
        u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
        u8 gen_stat1 = cx25840_read(client, 0x40d);
+       u8 gen_stat2 = cx25840_read(client, 0x40e);
+       int vid_input = state->vid_input;
+
+       v4l_info(client, "Video signal:              %spresent\n",
+                   (gen_stat2 & 0x20) ? "" : "not ");
+       v4l_info(client, "Detected format:           %s\n",
+                   fmt_strs[gen_stat1 & 0xf]);
+
+       v4l_info(client, "Specified standard:        %s\n",
+                   vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
+
+       if (vid_input >= CX25840_COMPOSITE1 &&
+           vid_input <= CX25840_COMPOSITE8) {
+               v4l_info(client, "Specified video input:     Composite %d\n",
+                       vid_input - CX25840_COMPOSITE1 + 1);
+       } else {
+               v4l_info(client, "Specified video input:     S-Video (Luma In%d, Chroma In%d)\n",
+                       (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
+       }
+
+       v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void log_audio_status(struct i2c_client *client)
+{
+       struct cx25840_state *state = i2c_get_clientdata(client);
        u8 download_ctl = cx25840_read(client, 0x803);
        u8 mod_det_stat0 = cx25840_read(client, 0x804);
        u8 mod_det_stat1 = cx25840_read(client, 0x805);
@@ -999,15 +1016,9 @@ static void log_status(struct i2c_client *client)
        u8 pref_mode = cx25840_read(client, 0x809);
        u8 afc0 = cx25840_read(client, 0x80b);
        u8 mute_ctl = cx25840_read(client, 0x8d3);
-       int vid_input = state->vid_input;
        int aud_input = state->aud_input;
        char *p;
 
-       v4l_info(client, "Video signal:              %spresent\n",
-                   (microctrl_vidfmt & 0x10) ? "" : "not ");
-       v4l_info(client, "Detected format:           %s\n",
-                   fmt_strs[gen_stat1 & 0xf]);
-
        switch (mod_det_stat0) {
        case 0x00: p = "mono"; break;
        case 0x01: p = "stereo"; break;
@@ -1107,25 +1118,12 @@ static void log_status(struct i2c_client *client)
                v4l_info(client, "Configured audio system:   %s\n", p);
        }
 
-       v4l_info(client, "Specified standard:        %s\n",
-                   vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
-
-       if (vid_input >= CX25840_COMPOSITE1 &&
-           vid_input <= CX25840_COMPOSITE8) {
-               v4l_info(client, "Specified video input:     Composite %d\n",
-                       vid_input - CX25840_COMPOSITE1 + 1);
-       } else {
-               v4l_info(client, "Specified video input:     S-Video (Luma In%d, Chroma In%d)\n",
-                       (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
-       }
        if (aud_input) {
                v4l_info(client, "Specified audio input:     Tuner (In%d)\n", aud_input);
        } else {
                v4l_info(client, "Specified audio input:     External\n");
        }
 
-       v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
-
        switch (pref_mode & 0xf) {
        case 0: p = "mono/language A"; break;
        case 1: p = "language B"; break;
index 1736929fc20491b3548549133bf6b4d099d10ffa..28049064dd7d4d7cb02fc1314de47bf3d48d66ec 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
 
+extern int cx25840_debug;
+
 /* ENABLE_PVR150_WORKAROUND activates a workaround for a hardware bug that is
    present in Hauppauge PVR-150 (and possibly PVR-500) cards that have
    certain NTSC tuners (tveeprom tuner model numbers 85, 99 and 112). The
 #define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0)
 
 struct cx25840_state {
+       struct i2c_client c;
        int pvr150_workaround;
        int radio;
        enum cx25840_video_input vid_input;
        enum cx25840_audio_input aud_input;
        u32 audclk_freq;
        int audmode;
+       int vbi_line_offset;
+       enum v4l2_chip_ident id;
+       int is_cx25836;
 };
 
 /* ----------------------------------------------------------------------- */
@@ -47,7 +53,7 @@ int cx25840_write(struct i2c_client *client, u16 addr, u8 value);
 int cx25840_write4(struct i2c_client *client, u16 addr, u32 value);
 u8 cx25840_read(struct i2c_client *client, u16 addr);
 u32 cx25840_read4(struct i2c_client *client, u16 addr);
-int cx25840_and_or(struct i2c_client *client, u16 addr, u8 mask, u8 value);
+int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned mask, u8 value);
 v4l2_std_id cx25840_get_v4lstd(struct i2c_client *client);
 
 /* ----------------------------------------------------------------------- */
index 57feca288d2bad25635254ee186bd296014d2040..6cc8bf215e851c548beedecd46d254d626dc052f 100644 (file)
@@ -84,67 +84,140 @@ static int decode_vps(u8 * dst, u8 * p)
 
 void cx25840_vbi_setup(struct i2c_client *client)
 {
+       struct cx25840_state *state = i2c_get_clientdata(client);
        v4l2_std_id std = cx25840_get_v4lstd(client);
+       int hblank,hactive,burst,vblank,vactive,sc,vblank656,src_decimation;
+       int luma_lpf,uv_lpf, comb;
+       u32 pll_int,pll_frac,pll_post;
 
+       /* datasheet startup, step 8d */
        if (std & ~V4L2_STD_NTSC) {
-               /* datasheet startup, step 8d */
                cx25840_write(client, 0x49f, 0x11);
+       } else {
+               cx25840_write(client, 0x49f, 0x14);
+       }
 
-               cx25840_write(client, 0x470, 0x84);
-               cx25840_write(client, 0x471, 0x00);
-               cx25840_write(client, 0x472, 0x2d);
-               cx25840_write(client, 0x473, 0x5d);
-
-               cx25840_write(client, 0x474, 0x24);
-               cx25840_write(client, 0x475, 0x40);
-               cx25840_write(client, 0x476, 0x24);
-               cx25840_write(client, 0x477, 0x28);
-
-               cx25840_write(client, 0x478, 0x1f);
-               cx25840_write(client, 0x479, 0x02);
+       if (std & V4L2_STD_625_50) {
+               hblank=0x084;
+               hactive=0x2d0;
+               burst=0x5d;
+               vblank=0x024;
+               vactive=0x244;
+               vblank656=0x28;
+               src_decimation=0x21f;
 
+               luma_lpf=2;
                if (std & V4L2_STD_SECAM) {
-                       cx25840_write(client, 0x47a, 0x80);
-                       cx25840_write(client, 0x47b, 0x00);
-                       cx25840_write(client, 0x47c, 0x5f);
-                       cx25840_write(client, 0x47d, 0x42);
+                       uv_lpf=0;
+                       comb=0;
+                       sc=0x0a425f;
                } else {
-                       cx25840_write(client, 0x47a, 0x90);
-                       cx25840_write(client, 0x47b, 0x20);
-                       cx25840_write(client, 0x47c, 0x63);
-                       cx25840_write(client, 0x47d, 0x82);
+                       uv_lpf=1;
+                       comb=0x20;
+                       sc=0x0a8263;
                }
-
-               cx25840_write(client, 0x47e, 0x0a);
-               cx25840_write(client, 0x47f, 0x01);
        } else {
-               /* datasheet startup, step 8d */
-               cx25840_write(client, 0x49f, 0x14);
+               hactive=720;
+               hblank=122;
+               vactive=487;
+               luma_lpf=1;
+               uv_lpf=1;
+
+               src_decimation=0x21f;
+               if (std == V4L2_STD_PAL_M) {
+                       vblank=20;
+                       vblank656=24;
+                       burst=0x61;
+                       comb=0x20;
+
+                       sc=555452;
+               } else {
+                       vblank=26;
+                       vblank656=26;
+                       burst=0x5b;
+                       comb=0x66;
+                       sc=556063;
+               }
+       }
+
+       /* DEBUG: Displays configured PLL frequency */
+       pll_int=cx25840_read(client, 0x108);
+       pll_frac=cx25840_read4(client, 0x10c)&0x1ffffff;
+       pll_post=cx25840_read(client, 0x109);
+       v4l_dbg(1, cx25840_debug, client,
+                               "PLL regs = int: %u, frac: %u, post: %u\n",
+                               pll_int,pll_frac,pll_post);
+
+       if (pll_post) {
+               int fin, fsc;
+               int pll= (28636363L*((((u64)pll_int)<<25L)+pll_frac)) >>25L;
+
+               pll/=pll_post;
+               v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n",
+                                               pll/1000000, pll%1000000);
+               v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n",
+                                               pll/8000000, (pll/8)%1000000);
+
+               fin=((u64)src_decimation*pll)>>12;
+               v4l_dbg(1, cx25840_debug, client, "ADC Sampling freq = "
+                                               "%d.%06d MHz\n",
+                                               fin/1000000,fin%1000000);
+
+               fsc= (((u64)sc)*pll) >> 24L;
+               v4l_dbg(1, cx25840_debug, client, "Chroma sub-carrier freq = "
+                                               "%d.%06d MHz\n",
+                                               fsc/1000000,fsc%1000000);
+
+               v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, "
+                       "vblank %i , vactive %i, vblank656 %i, src_dec %i,"
+                       "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
+                       " sc 0x%06x\n",
+                       hblank, hactive, vblank, vactive, vblank656,
+                       src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
+       }
+
+       /* Sets horizontal blanking delay and active lines */
+       cx25840_write(client, 0x470, hblank);
+       cx25840_write(client, 0x471, 0xff&(((hblank>>8)&0x3)|(hactive <<4)));
+       cx25840_write(client, 0x472, hactive>>4);
+
+       /* Sets burst gate delay */
+       cx25840_write(client, 0x473, burst);
 
-               cx25840_write(client, 0x470, 0x7a);
-               cx25840_write(client, 0x471, 0x00);
-               cx25840_write(client, 0x472, 0x2d);
-               cx25840_write(client, 0x473, 0x5b);
+       /* Sets vertical blanking delay and active duration */
+       cx25840_write(client, 0x474, vblank);
+       cx25840_write(client, 0x475, 0xff&(((vblank>>8)&0x3)|(vactive <<4)));
+       cx25840_write(client, 0x476, vactive>>4);
+       cx25840_write(client, 0x477, vblank656);
 
-               cx25840_write(client, 0x474, 0x1a);
-               cx25840_write(client, 0x475, 0x70);
-               cx25840_write(client, 0x476, 0x1e);
-               cx25840_write(client, 0x477, 0x1e);
+       /* Sets src decimation rate */
+       cx25840_write(client, 0x478, 0xff&src_decimation);
+       cx25840_write(client, 0x479, 0xff&(src_decimation>>8));
 
-               cx25840_write(client, 0x478, 0x1f);
-               cx25840_write(client, 0x479, 0x02);
-               cx25840_write(client, 0x47a, 0x50);
-               cx25840_write(client, 0x47b, 0x66);
+       /* Sets Luma and UV Low pass filters */
+       cx25840_write(client, 0x47a, luma_lpf<<6|((uv_lpf<<4)&0x30));
 
-               cx25840_write(client, 0x47c, 0x1f);
-               cx25840_write(client, 0x47d, 0x7c);
-               cx25840_write(client, 0x47e, 0x08);
+       /* Enables comb filters */
+       cx25840_write(client, 0x47b, comb);
+
+       /* Sets SC Step*/
+       cx25840_write(client, 0x47c, sc);
+       cx25840_write(client, 0x47d, 0xff&sc>>8);
+       cx25840_write(client, 0x47e, 0xff&sc>>16);
+
+       /* Sets VBI parameters */
+       if (std & V4L2_STD_625_50) {
+               cx25840_write(client, 0x47f, 0x01);
+               state->vbi_line_offset = 5;
+       } else {
                cx25840_write(client, 0x47f, 0x00);
+               state->vbi_line_offset = 8;
        }
 }
 
 int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
 {
+       struct cx25840_state *state = i2c_get_clientdata(client);
        struct v4l2_format *fmt;
        struct v4l2_sliced_vbi_format *svbi;
 
@@ -182,7 +255,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
 
        case VIDIOC_S_FMT:
        {
-               int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_NTSC);
+               int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_525_60);
                int vbi_offset = is_pal ? 1 : 0;
                int i, x;
                u8 lcr[24];
@@ -211,7 +284,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
                cx25840_vbi_setup(client);
 
                /* Sliced VBI */
-               cx25840_write(client, 0x404, 0x36);     /* Ancillery data */
+               cx25840_write(client, 0x404, 0x32);     /* Ancillary data */
                cx25840_write(client, 0x406, 0x13);
                cx25840_write(client, 0x47f, vbi_offset);
 
@@ -248,8 +321,18 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
                        }
                }
 
-               for (x = 1, i = 0x424; i <= 0x434; i++, x++) {
-                       cx25840_write(client, i, lcr[6 + x]);
+               if (is_pal) {
+                       for (x = 1, i = 0x424; i <= 0x434; i++, x++) {
+                               cx25840_write(client, i, lcr[6 + x]);
+                       }
+               }
+               else {
+                       for (x = 1, i = 0x424; i <= 0x430; i++, x++) {
+                               cx25840_write(client, i, lcr[9 + x]);
+                       }
+                       for (i = 0x431; i <= 0x434; i++) {
+                               cx25840_write(client, i, 0);
+                       }
                }
 
                cx25840_write(client, 0x43c, 0x16);
@@ -257,7 +340,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
                if (is_pal) {
                        cx25840_write(client, 0x474, 0x2a);
                } else {
-                       cx25840_write(client, 0x474, 0x1a + 6);
+                       cx25840_write(client, 0x474, 0x22);
                }
                break;
        }
@@ -278,7 +361,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
                id1 = p[-1];
                id2 = p[0] & 0xf;
                l = p[2] & 0x3f;
-               l += 5;
+               l += state->vbi_line_offset;
                p += 4;
 
                switch (id2) {
index 630273992a419b05986bd00a462366db212709f4..91e1c481a164a850645e5a3b7086bedcdc966ef9 100644 (file)
@@ -11,6 +11,7 @@ config VIDEO_CX88
        select VIDEO_BUF
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
+       select VIDEO_CX2341X
        select VIDEO_IR
        ---help---
          This is a video4linux driver for Conexant 2388x based
@@ -61,6 +62,7 @@ config VIDEO_CX88_DVB_ALL_FRONTENDS
        select DVB_LGDT330X
        select DVB_NXT200X
        select DVB_CX24123
+       select DVB_ISL6421
        ---help---
          This builds cx88-dvb with all currently supported frontend
          demodulators.  If you wish to tweak your configuration, and
@@ -139,6 +141,7 @@ config VIDEO_CX88_DVB_CX24123
        default y
        depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
        select DVB_CX24123
+       select DVB_ISL6421
        ---help---
          This adds DVB-S support for cards based on the
          Connexant 2388x chip and the CX24123 demodulator.
index 320b3d9384ba1365e346ce710df52cb93ed37425..2194cbeca33b61b3c1eccf4864cbccbec44e4566 100644 (file)
@@ -4,7 +4,7 @@
  *  PCI function #1 of the cx2388x.
  *
  *    (c) 2005,2006 Ricardo Cerqueira <v4l@cerqueira.org>
- *    (c) 2005 Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ *    (c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
  *    Based on a dummy cx88 module by Gerd Knorr <kraxel@bytesex.org>
  *    Based on dummy.c by Jaroslav Kysela <perex@suse.cz>
  *
@@ -111,7 +111,7 @@ MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s).");
 
 MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards");
 MODULE_AUTHOR("Ricardo Cerqueira");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@brturbo.com.br>");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Conexant,23881},"
                        "{{Conexant,23882},"
@@ -696,7 +696,6 @@ static int __devinit snd_cx88_create(struct snd_card *card,
        chip->irq = -1;
        spin_lock_init(&chip->reg_lock);
 
-       cx88_reset(core);
        chip->core = core;
 
        /* get irq */
index e100d8ef369a250155cde5378c999a98201ba39b..67fd3302e8f2372949960b70567f4da282479f53 100644 (file)
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
+#include <media/v4l2-common.h>
+#include <media/cx2341x.h>
 
 #include "cx88.h"
-#include <media/v4l2-common.h>
 
 MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards");
 MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>, Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -53,7 +54,6 @@ static LIST_HEAD(cx8802_devlist);
 
 /* ------------------------------------------------------------------ */
 
-#define BLACKBIRD_FIRM_ENC_FILENAME "blackbird-fw-enc.bin"
 #define BLACKBIRD_FIRM_IMAGE_SIZE 256*1024
 
 /* defines below are from ivtv-driver.h */
@@ -63,8 +63,6 @@ static LIST_HEAD(cx8802_devlist);
 /* Firmware API commands */
 #define IVTV_API_STD_TIMEOUT 500
 
-#define BLACKBIRD_API_PING               0x80
-#define BLACKBIRD_API_BEGIN_CAPTURE      0x81
 enum blackbird_capture_type {
        BLACKBIRD_MPEG_CAPTURE,
        BLACKBIRD_RAW_CAPTURE,
@@ -78,205 +76,29 @@ enum blackbird_capture_bits {
        BLACKBIRD_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
        BLACKBIRD_RAW_BITS_TO_HOST_CAPTURE  = 0x10
 };
-#define BLACKBIRD_API_END_CAPTURE        0x82
 enum blackbird_capture_end {
        BLACKBIRD_END_AT_GOP, /* stop at the end of gop, generate irq */
        BLACKBIRD_END_NOW, /* stop immediately, no irq */
 };
-#define BLACKBIRD_API_SET_AUDIO_ID       0x89
-#define BLACKBIRD_API_SET_VIDEO_ID       0x8B
-#define BLACKBIRD_API_SET_PCR_ID         0x8D
-#define BLACKBIRD_API_SET_FRAMERATE      0x8F
 enum blackbird_framerate {
        BLACKBIRD_FRAMERATE_NTSC_30, /* NTSC: 30fps */
        BLACKBIRD_FRAMERATE_PAL_25   /* PAL: 25fps */
 };
-#define BLACKBIRD_API_SET_RESOLUTION     0x91
-#define BLACKBIRD_API_SET_VIDEO_BITRATE  0x95
-enum blackbird_video_bitrate_type {
-       BLACKBIRD_VIDEO_VBR,
-       BLACKBIRD_VIDEO_CBR
-};
-#define BLACKBIRD_PEAK_RATE_DIVISOR 400
-enum blackbird_mux_rate {
-       BLACKBIRD_MUX_RATE_DEFAULT,
-        /* dvd mux rate: multiply by 400 to get the actual rate */
-       BLACKBIRD_MUX_RATE_DVD = 25200
-};
-#define BLACKBIRD_API_SET_GOP_STRUCTURE  0x97
-#define BLACKBIRD_API_SET_ASPECT_RATIO   0x99
-enum blackbird_aspect_ratio {
-       BLACKBIRD_ASPECT_RATIO_FORBIDDEN,
-       BLACKBIRD_ASPECT_RATIO_1_1_SQUARE,
-       BLACKBIRD_ASPECT_RATIO_4_3,
-       BLACKBIRD_ASPECT_RATIO_16_9,
-       BLACKBIRD_ASPECT_RATIO_221_100,
-       BLACKBIRD_ASPECT_RATIO_RESERVED
-};
-#define BLACKBIRD_API_SET_DNR_MODE       0x9B
-enum blackbird_dnr_bits {
-       BLACKBIRD_DNR_BITS_MANUAL,
-       BLACKBIRD_DNR_BITS_AUTO_SPATIAL,
-       BLACKBIRD_DNR_BITS_AUTO_TEMPORAL,
-       BLACKBIRD_DNR_BITS_AUTO
-};
-enum blackbird_median_filter {
-       BLACKBIRD_MEDIAN_FILTER_DISABLED,
-       BLACKBIRD_MEDIAN_FILTER_HORIZONTAL,
-       BLACKBIRD_MEDIAN_FILTER_VERTICAL,
-       BLACKBIRD_MEDIAN_FILTER_HV,
-       BLACKBIRD_MEDIAN_FILTER_DIAGONAL
-};
-#define BLACKBIRD_API_SET_MANUAL_DNR     0x9D
-#define BLACKBIRD_API_SET_DNR_MEDIAN     0x9F
-#define BLACKBIRD_API_SET_SPATIAL_FILTER 0xA1
-enum blackbird_spatial_filter_luma {
-       BLACKBIRD_SPATIAL_FILTER_LUMA_DISABLED,
-       BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
-       BLACKBIRD_SPATIAL_FILTER_LUMA_1D_VERT,
-       BLACKBIRD_SPATIAL_FILTER_LUMA_2D_HV, /* separable, default */
-       BLACKBIRD_SPATIAL_FILTER_LUMA_2D_SYMM /* symmetric non-separable */
-};
-enum blackbird_spatial_filter_chroma {
-       BLACKBIRD_SPATIAL_FILTER_CHROMA_DISABLED,
-       BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ /* default */
-};
-#define BLACKBIRD_API_SET_3_2_PULLDOWN   0xB1
-enum blackbird_pulldown {
-       BLACKBIRD_3_2_PULLDOWN_DISABLED,
-       BLACKBIRD_3_2_PULLDOWN_ENABLED
-};
-#define BLACKBIRD_API_SET_VBI_LINE_NO    0xB7
-enum blackbird_vbi_line_bits {
-       BLACKBIRD_VBI_LINE_BITS_TOP_FIELD,
-       BLACKBIRD_VBI_LINE_BITS_BOT_FIELD = (1 << 31),
-       BLACKBIRD_VBI_LINE_BITS_ALL_LINES = 0xFFFFFFFF
-};
-enum blackbird_vbi_line {
-       BLACKBIRD_VBI_LINE_DISABLED,
-       BLACKBIRD_VBI_LINE_ENABLED
-};
-enum blackbird_vbi_slicing {
-       BLACKBIRD_VBI_SLICING_NONE,
-       BLACKBIRD_VBI_SLICING_CLOSED_CAPTION
-};
-#define BLACKBIRD_API_SET_STREAM_TYPE    0xB9
-enum blackbird_stream_type {
-       BLACKBIRD_STREAM_PROGRAM,
-       BLACKBIRD_STREAM_TRANSPORT,
-       BLACKBIRD_STREAM_MPEG1,
-       BLACKBIRD_STREAM_PES_AV,
-       BLACKBIRD_STREAM_UNKNOWN4,
-       BLACKBIRD_STREAM_PES_VIDEO,
-       BLACKBIRD_STREAM_UNKNOWN6,
-       BLACKBIRD_STREAM_PES_AUDIO,
-       BLACKBIRD_STREAM_UNKNOWN8,
-       BLACKBIRD_STREAM_UNKNOWN9, /* audio/pcm ? */
-       BLACKBIRD_STREAM_DVD,
-       BLACKBIRD_STREAM_VCD,
-       BLACKBIRD_STREAM_UNKNOWN12 /* svcd/xvcd ? */
-};
-#define BLACKBIRD_API_SET_OUTPUT_PORT    0xBB
 enum blackbird_stream_port {
        BLACKBIRD_OUTPUT_PORT_MEMORY,
        BLACKBIRD_OUTPUT_PORT_STREAMING,
        BLACKBIRD_OUTPUT_PORT_SERIAL
 };
-#define BLACKBIRD_API_SET_AUDIO_PARAMS   0xBD
-enum blackbird_audio_bits_sample_rate {
-       BLACKBIRD_AUDIO_BITS_44100HZ,
-       BLACKBIRD_AUDIO_BITS_48000HZ,
-       BLACKBIRD_AUDIO_BITS_32000HZ,
-       BLACKBIRD_AUDIO_BITS_RESERVED_HZ,
-};
-enum blackbird_audio_bits_encoding {
-       BLACKBIRD_AUDIO_BITS_LAYER_1 = 0x1 << 2,
-       BLACKBIRD_AUDIO_BITS_LAYER_2 = 0x2 << 2,
-};
-enum blackbird_audio_bits_bitrate_layer_1 {
-       BLACKBIRD_AUDIO_BITS_LAYER_1_FREE_FORMAT,
-       BLACKBIRD_AUDIO_BITS_LAYER_1_32  = 0x01 << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_1_64  = 0x02 << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_1_96  = 0x03 << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_1_128 = 0x04 << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_1_160 = 0x05 << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_1_192 = 0x06 << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_1_224 = 0x07 << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_1_256 = 0x08 << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_1_288 = 0x09 << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_1_320 = 0x0A << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_1_352 = 0x0B << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_1_384 = 0x0C << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_1_416 = 0x0D << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_1_448 = 0x0E << 4,
-};
-enum blackbird_audio_bits_bitrate_layer_2 {
-       BLACKBIRD_AUDIO_BITS_LAYER_2_FREE_FORMAT,
-       BLACKBIRD_AUDIO_BITS_LAYER_2_32  = 0x01 << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_2_48  = 0x02 << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_2_56  = 0x03 << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_2_64  = 0x04 << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_2_80  = 0x05 << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_2_96  = 0x06 << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_2_112 = 0x07 << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_2_128 = 0x08 << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_2_160 = 0x09 << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_2_192 = 0x0A << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_2_224 = 0x0B << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_2_256 = 0x0C << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_2_320 = 0x0D << 4,
-       BLACKBIRD_AUDIO_BITS_LAYER_2_384 = 0x0E << 4,
-};
-enum blackbird_audio_bits_mode {
-       BLACKBIRD_AUDIO_BITS_STEREO,
-       BLACKBIRD_AUDIO_BITS_JOINT_STEREO = 0x1 << 8,
-       BLACKBIRD_AUDIO_BITS_DUAL         = 0x2 << 8,
-       BLACKBIRD_AUDIO_BITS_MONO         = 0x3 << 8,
-};
-enum blackbird_audio_bits_mode_extension {
-       BLACKBIRD_AUDIO_BITS_BOUND_4,
-       BLACKBIRD_AUDIO_BITS_BOUND_8  = 0x1 << 10,
-       BLACKBIRD_AUDIO_BITS_BOUND_12 = 0x2 << 10,
-       BLACKBIRD_AUDIO_BITS_BOUND_16 = 0x3 << 10,
-};
-enum blackbird_audio_bits_emphasis {
-       BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE,
-       BLACKBIRD_AUDIO_BITS_EMPHASIS_50_15     = 0x1 << 12,
-       BLACKBIRD_AUDIO_BITS_EMPHASIS_RESERVED  = 0x2 << 12,
-       BLACKBIRD_AUDIO_BITS_EMPHASIS_CCITT_J17 = 0x3 << 12,
-};
-enum blackbird_audio_bits_crc {
-       BLACKBIRD_AUDIO_BITS_CRC_OFF,
-       BLACKBIRD_AUDIO_BITS_CRC_ON = 0x1 << 14,
-};
-enum blackbird_audio_bits_copyright {
-       BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF,
-       BLACKBIRD_AUDIO_BITS_COPYRIGHT_ON = 0x1 << 15,
-};
-enum blackbird_audio_bits_original {
-       BLACKBIRD_AUDIO_BITS_COPY,
-       BLACKBIRD_AUDIO_BITS_ORIGINAL = 0x1 << 16,
-};
-#define BLACKBIRD_API_HALT               0xC3
-#define BLACKBIRD_API_GET_VERSION        0xC4
-#define BLACKBIRD_API_SET_GOP_CLOSURE    0xC5
-enum blackbird_gop_closure {
-       BLACKBIRD_GOP_CLOSURE_OFF,
-       BLACKBIRD_GOP_CLOSURE_ON,
-};
-#define BLACKBIRD_API_DATA_XFER_STATUS   0xC6
 enum blackbird_data_xfer_status {
        BLACKBIRD_MORE_BUFFERS_FOLLOW,
        BLACKBIRD_LAST_BUFFER,
 };
-#define BLACKBIRD_API_PROGRAM_INDEX_INFO 0xC7
 enum blackbird_picture_mask {
        BLACKBIRD_PICTURE_MASK_NONE,
        BLACKBIRD_PICTURE_MASK_I_FRAMES,
        BLACKBIRD_PICTURE_MASK_I_P_FRAMES = 0x3,
        BLACKBIRD_PICTURE_MASK_ALL_FRAMES = 0x7,
 };
-#define BLACKBIRD_API_SET_VBI_PARAMS     0xC8
 enum blackbird_vbi_mode_bits {
        BLACKBIRD_VBI_BITS_SLICED,
        BLACKBIRD_VBI_BITS_RAW,
@@ -288,33 +110,23 @@ enum blackbird_vbi_insertion_bits {
        BLACKBIRD_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
        BLACKBIRD_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
 };
-#define BLACKBIRD_API_SET_DMA_BLOCK_SIZE 0xC9
 enum blackbird_dma_unit {
        BLACKBIRD_DMA_BYTES,
        BLACKBIRD_DMA_FRAMES,
 };
-#define BLACKBIRD_API_DMA_TRANSFER_INFO  0xCA
-#define BLACKBIRD_API_DMA_TRANSFER_STAT  0xCB
 enum blackbird_dma_transfer_status_bits {
        BLACKBIRD_DMA_TRANSFER_BITS_DONE = 0x01,
        BLACKBIRD_DMA_TRANSFER_BITS_ERROR = 0x04,
        BLACKBIRD_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
 };
-#define BLACKBIRD_API_SET_DMA2HOST_ADDR  0xCC
-#define BLACKBIRD_API_INIT_VIDEO_INPUT   0xCD
-#define BLACKBIRD_API_SET_FRAMESKIP      0xD0
-#define BLACKBIRD_API_PAUSE              0xD2
 enum blackbird_pause {
        BLACKBIRD_PAUSE_ENCODING,
        BLACKBIRD_RESUME_ENCODING,
 };
-#define BLACKBIRD_API_REFRESH_INPUT      0xD3
-#define BLACKBIRD_API_SET_COPYRIGHT      0xD4
 enum blackbird_copyright {
        BLACKBIRD_COPYRIGHT_OFF,
        BLACKBIRD_COPYRIGHT_ON,
 };
-#define BLACKBIRD_API_SET_NOTIFICATION   0xD5
 enum blackbird_notification_type {
        BLACKBIRD_NOTIFICATION_REFRESH,
 };
@@ -325,7 +137,6 @@ enum blackbird_notification_status {
 enum blackbird_notification_mailbox {
        BLACKBIRD_NOTIFICATION_NO_MAILBOX = -1,
 };
-#define BLACKBIRD_API_SET_CAPTURE_LINES  0xD6
 enum blackbird_field1_lines {
        BLACKBIRD_FIELD1_SAA7114 = 0x00EF, /* 239 */
        BLACKBIRD_FIELD1_SAA7115 = 0x00F0, /* 240 */
@@ -336,12 +147,10 @@ enum blackbird_field2_lines {
        BLACKBIRD_FIELD2_SAA7115 = 0x00F0, /* 240 */
        BLACKBIRD_FIELD2_MICRONAS = 0x0106, /* 262 */
 };
-#define BLACKBIRD_API_SET_CUSTOM_DATA    0xD7
 enum blackbird_custom_data_type {
        BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
        BLACKBIRD_CUSTOM_PRIVATE_PACKET,
 };
-#define BLACKBIRD_API_MUTE_VIDEO         0xD9
 enum blackbird_mute {
        BLACKBIRD_UNMUTE,
        BLACKBIRD_MUTE,
@@ -356,7 +165,6 @@ enum blackbird_mute_video_shift {
        BLACKBIRD_MUTE_VIDEO_U_SHIFT = 16,
        BLACKBIRD_MUTE_VIDEO_Y_SHIFT = 24,
 };
-#define BLACKBIRD_API_MUTE_AUDIO         0xDA
 
 /* Registers */
 #define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8 /*| IVTV_REG_OFFSET*/)
@@ -498,15 +306,12 @@ static int register_read(struct cx88_core *core, u32 address, u32 *value)
 
 /* ------------------------------------------------------------------ */
 
-/* We don't need to call the API often, so using just one mailbox will probably suffice */
-static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
-                            u32 inputcnt, u32 outputcnt, ...)
+static int blackbird_mbox_func(void *priv, int command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
 {
+       struct cx8802_dev *dev = priv;
        unsigned long timeout;
        u32 value, flag, retval;
        int i;
-       va_list args;
-       va_start(args, outputcnt);
 
        dprintk(1,"%s: 0x%X\n", __FUNCTION__, command);
 
@@ -530,12 +335,11 @@ static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
        /* write command + args + fill remaining with zeros */
        memory_write(dev->core, dev->mailbox + 1, command); /* command code */
        memory_write(dev->core, dev->mailbox + 3, IVTV_API_STD_TIMEOUT); /* timeout */
-       for (i = 0; i < inputcnt ; i++) {
-               value = va_arg(args, int);
-               memory_write(dev->core, dev->mailbox + 4 + i, value);
-               dprintk(1, "API Input %d = %d\n", i, value);
+       for (i = 0; i < in; i++) {
+               memory_write(dev->core, dev->mailbox + 4 + i, data[i]);
+               dprintk(1, "API Input %d = %d\n", i, data[i]);
        }
-       for (; i < 16 ; i++)
+       for (; i < CX2341X_MBOX_MAX_DATA; i++)
                memory_write(dev->core, dev->mailbox + 4 + i, 0);
 
        flag |= 3; /* tell 'em we're done writing */
@@ -555,12 +359,10 @@ static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
        }
 
        /* read output values */
-       for (i = 0; i < outputcnt ; i++) {
-               int *vptr = va_arg(args, int *);
-               memory_read(dev->core, dev->mailbox + 4 + i, vptr);
-               dprintk(1, "API Output %d = %d\n", i, *vptr);
+       for (i = 0; i < out; i++) {
+               memory_read(dev->core, dev->mailbox + 4 + i, data + i);
+               dprintk(1, "API Output %d = %d\n", i, data[i]);
        }
-       va_end(args);
 
        memory_read(dev->core, dev->mailbox + 2, &retval);
        dprintk(1, "API result = %d\n",retval);
@@ -569,7 +371,29 @@ static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
        memory_write(dev->core, dev->mailbox, flag);
        return retval;
 }
+/* ------------------------------------------------------------------ */
 
+/* We don't need to call the API often, so using just one mailbox will probably suffice */
+static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
+                            u32 inputcnt, u32 outputcnt, ...)
+{
+       u32 data[CX2341X_MBOX_MAX_DATA];
+       va_list vargs;
+       int i, err;
+
+       va_start(vargs, outputcnt);
+
+       for (i = 0; i < inputcnt; i++) {
+               data[i] = va_arg(vargs, int);
+       }
+       err = blackbird_mbox_func(dev, command, inputcnt, outputcnt, data);
+       for (i = 0; i < outputcnt; i++) {
+               int *vptr = va_arg(vargs, int *);
+               *vptr = data[i];
+       }
+       va_end(vargs);
+       return err;
+}
 
 static int blackbird_find_mailbox(struct cx8802_dev *dev)
 {
@@ -614,13 +438,13 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
        if (retval < 0)
                dprintk(0, "Error with register_write\n");
 
-       retval = request_firmware(&firmware, BLACKBIRD_FIRM_ENC_FILENAME,
+       retval = request_firmware(&firmware, CX2341X_FIRM_ENC_FILENAME,
                                  &dev->pci->dev);
 
 
        if (retval != 0) {
                dprintk(0, "ERROR: Hotplug firmware request failed (%s).\n",
-                       BLACKBIRD_FIRM_ENC_FILENAME);
+                       CX2341X_FIRM_ENC_FILENAME);
                dprintk(0, "Please fix your hotplug setup, the board will "
                        "not work without firmware loaded!\n");
                return -1;
@@ -686,12 +510,19 @@ DB* DVD | MPEG2 | 720x576PAL | CBR     | 600 :Good    | 6000 Kbps  | 25fps   | M
 *DB: "DirectBurn"
 */
 
-static struct blackbird_dnr default_dnr_params = {
-       .mode     = BLACKBIRD_DNR_BITS_MANUAL,
-       .type     = BLACKBIRD_MEDIAN_FILTER_DISABLED,
-       .spatial  = 0,
-       .temporal = 0
-};
+static void blackbird_codec_settings(struct cx8802_dev *dev)
+{
+       /* assign frame size */
+       blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
+                               dev->height, dev->width);
+
+       dev->params.width = dev->width;
+       dev->params.height = dev->height;
+       dev->params.is_50hz = (dev->core->tvnorm->id & V4L2_STD_625_50) != 0;
+
+       cx2341x_update(dev, blackbird_mbox_func, NULL, &dev->params);
+}
+
 static struct v4l2_mpeg_compression default_mpeg_params = {
        .st_type          = V4L2_MPEG_PS_2,
        .st_bitrate       = {
@@ -712,7 +543,7 @@ static struct v4l2_mpeg_compression default_mpeg_params = {
                .target   = 224,
                .max      = 224
        },
-       .au_sample_rate    = 44100,
+       .au_sample_rate    = 48000,
        .au_pesid          = 0,
        .vi_type           = V4L2_MPEG_VI_2,
        .vi_aspect_ratio   = V4L2_MPEG_ASPECT_4_3,
@@ -723,524 +554,13 @@ static struct v4l2_mpeg_compression default_mpeg_params = {
                .max       = 6000
        },
        .vi_frame_rate     = 25,
-       .vi_frames_per_gop = 15,
+       .vi_frames_per_gop = 12,
        .vi_bframes_count  = 2,
        .vi_pesid          = 0,
-       .closed_gops       = 0,
+       .closed_gops       = 1,
        .pulldown          = 0
 };
 
-static enum blackbird_stream_type mpeg_stream_types[] = {
-       [V4L2_MPEG_SS_1]   = BLACKBIRD_STREAM_MPEG1,
-       [V4L2_MPEG_PS_2]   = BLACKBIRD_STREAM_PROGRAM,
-       [V4L2_MPEG_TS_2]   = BLACKBIRD_STREAM_TRANSPORT,
-       [V4L2_MPEG_PS_DVD] = BLACKBIRD_STREAM_DVD,
-};
-static enum blackbird_aspect_ratio mpeg_stream_ratios[] = {
-       [V4L2_MPEG_ASPECT_SQUARE] = BLACKBIRD_ASPECT_RATIO_1_1_SQUARE,
-       [V4L2_MPEG_ASPECT_4_3]    = BLACKBIRD_ASPECT_RATIO_4_3,
-       [V4L2_MPEG_ASPECT_16_9]   = BLACKBIRD_ASPECT_RATIO_16_9,
-       [V4L2_MPEG_ASPECT_1_221]  = BLACKBIRD_ASPECT_RATIO_221_100,
-};
-static enum blackbird_video_bitrate_type mpeg_video_bitrates[] = {
-       [V4L2_BITRATE_NONE] = BLACKBIRD_VIDEO_CBR,
-       [V4L2_BITRATE_CBR]  = BLACKBIRD_VIDEO_CBR,
-       [V4L2_BITRATE_VBR]  = BLACKBIRD_VIDEO_VBR,
-};
-/* find the best layer I/II bitrate to fit a given numeric value */
-struct bitrate_bits {
-       u32 bits; /* layer bits for the best fit */
-       u32 rate; /* actual numeric value for the layer best fit */
-};
-struct bitrate_approximation {
-       u32                 target;   /* numeric value of the rate we want */
-       struct bitrate_bits layer[2];
-};
-static struct bitrate_approximation mpeg_audio_bitrates[] = {
-       /* target  layer[0].bits           layer[0].rate       layer[1].bits           layer[1].rate */
-       {   0, { {                                0,   0, }, {                                0,   0, }, }, },
-       {  32, { { BLACKBIRD_AUDIO_BITS_LAYER_1_32 ,  32, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_32 ,  32, }, }, },
-       {  48, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 ,  64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_48 ,  48, }, }, },
-       {  56, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 ,  64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_56 ,  56, }, }, },
-       {  64, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 ,  64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_64 ,  64, }, }, },
-       {  80, { { BLACKBIRD_AUDIO_BITS_LAYER_1_96 ,  96, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_80 ,  80, }, }, },
-       {  96, { { BLACKBIRD_AUDIO_BITS_LAYER_1_96 ,  96, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_96 ,  96, }, }, },
-       { 112, { { BLACKBIRD_AUDIO_BITS_LAYER_1_128, 128, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_112, 112, }, }, },
-       { 128, { { BLACKBIRD_AUDIO_BITS_LAYER_1_128, 128, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_128, 128, }, }, },
-       { 160, { { BLACKBIRD_AUDIO_BITS_LAYER_1_160, 160, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_160, 160, }, }, },
-       { 192, { { BLACKBIRD_AUDIO_BITS_LAYER_1_192, 192, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_192, 192, }, }, },
-       { 224, { { BLACKBIRD_AUDIO_BITS_LAYER_1_224, 224, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_224, 224, }, }, },
-       { 256, { { BLACKBIRD_AUDIO_BITS_LAYER_1_256, 256, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_256, 256, }, }, },
-       { 288, { { BLACKBIRD_AUDIO_BITS_LAYER_1_288, 288, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_320, 320, }, }, },
-       { 320, { { BLACKBIRD_AUDIO_BITS_LAYER_1_320, 320, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_320, 320, }, }, },
-       { 352, { { BLACKBIRD_AUDIO_BITS_LAYER_1_352, 352, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
-       { 384, { { BLACKBIRD_AUDIO_BITS_LAYER_1_384, 384, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
-       { 416, { { BLACKBIRD_AUDIO_BITS_LAYER_1_416, 416, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
-       { 448, { { BLACKBIRD_AUDIO_BITS_LAYER_1_448, 448, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
-};
-static const int BITRATES_SIZE = ARRAY_SIZE(mpeg_audio_bitrates);
-
-static void blackbird_set_default_params(struct cx8802_dev *dev)
-{
-       struct v4l2_mpeg_compression *params = &dev->params;
-       u32 au_params;
-
-       /* assign stream type */
-       if( params->st_type >= ARRAY_SIZE(mpeg_stream_types) )
-               params->st_type = V4L2_MPEG_PS_2;
-       if( params->st_type == V4L2_MPEG_SS_1 )
-               params->vi_type = V4L2_MPEG_VI_1;
-       else
-               params->vi_type = V4L2_MPEG_VI_2;
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, mpeg_stream_types[params->st_type]);
-
-       /* assign framerate */
-       if( params->vi_frame_rate <= 25 )
-       {
-               params->vi_frame_rate = 25;
-               blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
-       }
-       else
-       {
-               params->vi_frame_rate = 30;
-               blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_NTSC_30);
-       }
-
-       /* assign aspect ratio */
-       if( params->vi_aspect_ratio >= ARRAY_SIZE(mpeg_stream_ratios) )
-               params->vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3;
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, mpeg_stream_ratios[params->vi_aspect_ratio]);
-
-       /* assign gop properties */
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, params->vi_frames_per_gop, params->vi_bframes_count+1);
-
-       /* assign gop closure */
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, params->closed_gops);
-
-       /* assign 3 2 pulldown */
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, params->pulldown);
-
-       /* make sure the params are within bounds */
-       if( params->st_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
-               params->vi_bitrate.mode = V4L2_BITRATE_NONE;
-       if( params->vi_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
-               params->vi_bitrate.mode = V4L2_BITRATE_NONE;
-       if( params->au_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
-               params->au_bitrate.mode = V4L2_BITRATE_NONE;
-
-       /* assign audio properties */
-       /* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */
-       au_params = BLACKBIRD_AUDIO_BITS_STEREO |
-                       /* BLACKBIRD_AUDIO_BITS_BOUND_4 | */
-                       BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE |
-                       BLACKBIRD_AUDIO_BITS_CRC_OFF |
-                       BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF |
-                       BLACKBIRD_AUDIO_BITS_COPY |
-                       0;
-       if( params->au_sample_rate <= 32000 )
-       {
-               params->au_sample_rate = 32000;
-               au_params |= BLACKBIRD_AUDIO_BITS_32000HZ;
-       }
-       else if( params->au_sample_rate <= 44100 )
-       {
-               params->au_sample_rate = 44100;
-               au_params |= BLACKBIRD_AUDIO_BITS_44100HZ;
-       }
-       else
-       {
-               params->au_sample_rate = 48000;
-               au_params |= BLACKBIRD_AUDIO_BITS_48000HZ;
-       }
-       if( params->au_type == V4L2_MPEG_AU_2_I )
-       {
-               au_params |= BLACKBIRD_AUDIO_BITS_LAYER_1;
-       }
-       else
-       {
-               /* TODO: try to handle the other formats more gracefully */
-               params->au_type = V4L2_MPEG_AU_2_II;
-               au_params |= BLACKBIRD_AUDIO_BITS_LAYER_2;
-       }
-       if( params->au_bitrate.mode )
-       {
-               int layer;
-
-               if( params->au_bitrate.mode == V4L2_BITRATE_CBR )
-                       params->au_bitrate.max = params->vi_bitrate.target;
-               else
-                       params->au_bitrate.target = params->vi_bitrate.max;
-
-               layer = params->au_type;
-               if( params->au_bitrate.target == 0 )
-               {
-                       /* TODO: use the minimum possible bitrate instead of 0 ? */
-                       au_params |= 0;
-               }
-               else if( params->au_bitrate.target >=
-                        mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate )
-               {
-                       /* clamp the bitrate to the max supported by the standard */
-                       params->au_bitrate.target = mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate;
-                       params->au_bitrate.max = params->au_bitrate.target;
-                       au_params |= mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].bits;
-               }
-               else
-               {
-                       /* round up to the nearest supported bitrate */
-                       int i;
-                       for(i = 1; i < BITRATES_SIZE; i++)
-                       {
-                               if( params->au_bitrate.target > mpeg_audio_bitrates[i-1].layer[layer].rate &&
-                                   params->au_bitrate.target <= mpeg_audio_bitrates[i].layer[layer].rate )
-                               {
-                                       params->au_bitrate.target = mpeg_audio_bitrates[i].layer[layer].rate;
-                                       params->au_bitrate.max = params->au_bitrate.target;
-                                       au_params |= mpeg_audio_bitrates[i].layer[layer].bits;
-                                       break;
-                               }
-                       }
-               }
-       }
-       else
-       {
-               /* TODO: ??? */
-               params->au_bitrate.target = params->au_bitrate.max = 0;
-               au_params |= 0;
-       }
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0, au_params );
-
-       /* assign bitrates */
-       if( params->vi_bitrate.mode )
-       {
-               /* bitrate is set, let's figure out the cbr/vbr mess */
-               if( params->vi_bitrate.max < params->vi_bitrate.target )
-               {
-                       if( params->vi_bitrate.mode == V4L2_BITRATE_CBR )
-                               params->vi_bitrate.max = params->vi_bitrate.target;
-                       else
-                               params->vi_bitrate.target = params->vi_bitrate.max;
-               }
-       }
-       else
-       {
-               if( params->st_bitrate.max < params->st_bitrate.target )
-               {
-                       if( params->st_bitrate.mode == V4L2_BITRATE_VBR )
-                               params->st_bitrate.target = params->st_bitrate.max;
-                       else
-                               params->st_bitrate.max = params->st_bitrate.target;
-               }
-               /* calculate vi_bitrate = st_bitrate - au_bitrate */
-               params->vi_bitrate.max = params->st_bitrate.max - params->au_bitrate.max;
-               params->vi_bitrate.target = params->st_bitrate.target - params->au_bitrate.target;
-       }
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 4, 0,
-                               mpeg_video_bitrates[params->vi_bitrate.mode],
-                               params->vi_bitrate.target * 1000, /* kbps -> bps */
-                               params->vi_bitrate.max * 1000 / BLACKBIRD_PEAK_RATE_DIVISOR, /* peak/400 */
-                               BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/); /* encoding buffer, ckennedy */
-
-       /* TODO: implement the stream ID stuff:
-               ts_pid_pmt, ts_pid_audio, ts_pid_video, ts_pid_pcr,
-               ps_size, au_pesid, vi_pesid
-       */
-}
-#define CHECK_PARAM( name ) ( dev->params.name != params->name )
-#define IF_PARAM( name ) if( CHECK_PARAM( name ) )
-#define UPDATE_PARAM( name ) dev->params.name = params->name
-void blackbird_set_params(struct cx8802_dev *dev, struct v4l2_mpeg_compression *params)
-{
-       u32 au_params;
-
-       /* assign stream type */
-       if( params->st_type >= ARRAY_SIZE(mpeg_stream_types) )
-               params->st_type = V4L2_MPEG_PS_2;
-       if( params->st_type == V4L2_MPEG_SS_1 )
-               params->vi_type = V4L2_MPEG_VI_1;
-       else
-               params->vi_type = V4L2_MPEG_VI_2;
-       if( CHECK_PARAM( st_type ) || CHECK_PARAM( vi_type ) )
-       {
-               UPDATE_PARAM( st_type );
-               UPDATE_PARAM( vi_type );
-               blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, mpeg_stream_types[params->st_type]);
-       }
-
-       /* assign framerate */
-       if( params->vi_frame_rate <= 25 )
-               params->vi_frame_rate = 25;
-       else
-               params->vi_frame_rate = 30;
-       IF_PARAM( vi_frame_rate )
-       {
-               UPDATE_PARAM( vi_frame_rate );
-               if( params->vi_frame_rate == 25 )
-                       blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
-               else
-                       blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_NTSC_30);
-       }
-
-       /* assign aspect ratio */
-       if( params->vi_aspect_ratio >= ARRAY_SIZE(mpeg_stream_ratios) )
-               params->vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3;
-       IF_PARAM( vi_aspect_ratio )
-       {
-               UPDATE_PARAM( vi_aspect_ratio );
-               blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, mpeg_stream_ratios[params->vi_aspect_ratio]);
-       }
-
-       /* assign gop properties */
-       if( CHECK_PARAM( vi_frames_per_gop ) || CHECK_PARAM( vi_bframes_count ) )
-       {
-               UPDATE_PARAM( vi_frames_per_gop );
-               UPDATE_PARAM( vi_bframes_count );
-               blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, params->vi_frames_per_gop, params->vi_bframes_count+1);
-       }
-
-       /* assign gop closure */
-       IF_PARAM( closed_gops )
-       {
-               UPDATE_PARAM( closed_gops );
-               blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, params->closed_gops);
-       }
-
-       /* assign 3 2 pulldown */
-       IF_PARAM( pulldown )
-       {
-               UPDATE_PARAM( pulldown );
-               blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, params->pulldown);
-       }
-
-       /* make sure the params are within bounds */
-       if( params->st_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
-               params->vi_bitrate.mode = V4L2_BITRATE_NONE;
-       if( params->vi_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
-               params->vi_bitrate.mode = V4L2_BITRATE_NONE;
-       if( params->au_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
-               params->au_bitrate.mode = V4L2_BITRATE_NONE;
-
-       /* assign audio properties */
-       /* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */
-       au_params = BLACKBIRD_AUDIO_BITS_STEREO |
-                       /* BLACKBIRD_AUDIO_BITS_BOUND_4 | */
-       BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE |
-               BLACKBIRD_AUDIO_BITS_CRC_OFF |
-               BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF |
-               BLACKBIRD_AUDIO_BITS_COPY |
-               0;
-       if( params->au_sample_rate < 32000 )
-       {
-               params->au_sample_rate = 32000;
-               au_params |= BLACKBIRD_AUDIO_BITS_32000HZ;
-       }
-       else if( params->au_sample_rate < 44100 )
-       {
-               params->au_sample_rate = 44100;
-               au_params |= BLACKBIRD_AUDIO_BITS_44100HZ;
-       }
-       else
-       {
-               params->au_sample_rate = 48000;
-               au_params |= BLACKBIRD_AUDIO_BITS_48000HZ;
-       }
-       if( params->au_type == V4L2_MPEG_AU_2_I )
-       {
-               au_params |= BLACKBIRD_AUDIO_BITS_LAYER_1;
-       }
-       else
-       {
-               /* TODO: try to handle the other formats more gracefully */
-               params->au_type = V4L2_MPEG_AU_2_II;
-               au_params |= BLACKBIRD_AUDIO_BITS_LAYER_2;
-       }
-       if( params->au_bitrate.mode )
-       {
-               int layer;
-
-               if( params->au_bitrate.mode == V4L2_BITRATE_CBR )
-                       params->au_bitrate.max = params->vi_bitrate.target;
-               else
-                       params->au_bitrate.target = params->vi_bitrate.max;
-
-               layer = params->au_type;
-               if( params->au_bitrate.target == 0 )
-               {
-                       /* TODO: use the minimum possible bitrate instead of 0 ? */
-                       au_params |= 0;
-               }
-               else if( params->au_bitrate.target >=
-                        mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate )
-               {
-                       /* clamp the bitrate to the max supported by the standard */
-                       params->au_bitrate.target = mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate;
-                       params->au_bitrate.max = params->au_bitrate.target;
-                       au_params |= mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].bits;
-               }
-               else
-               {
-                       /* round up to the nearest supported bitrate */
-                       int i;
-                       for(i = 1; i < BITRATES_SIZE; i++)
-                       {
-                               if( params->au_bitrate.target > mpeg_audio_bitrates[i-1].layer[layer].rate &&
-                                   params->au_bitrate.target <= mpeg_audio_bitrates[i].layer[layer].rate )
-                               {
-                                       params->au_bitrate.target = mpeg_audio_bitrates[i].layer[layer].rate;
-                                       params->au_bitrate.max = params->au_bitrate.target;
-                                       au_params |= mpeg_audio_bitrates[i].layer[layer].bits;
-                                       break;
-                               }
-                       }
-               }
-       }
-       else
-       {
-               /* TODO: ??? */
-               params->au_bitrate.target = params->au_bitrate.max = 0;
-               au_params |= 0;
-       }
-       if( CHECK_PARAM( au_type ) || CHECK_PARAM( au_sample_rate )
-               || CHECK_PARAM( au_bitrate.mode ) || CHECK_PARAM( au_bitrate.max )
-               || CHECK_PARAM( au_bitrate.target )
-       )
-       {
-               UPDATE_PARAM( au_type );
-               UPDATE_PARAM( au_sample_rate );
-               UPDATE_PARAM( au_bitrate );
-               blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0, au_params );
-       }
-
-       /* assign bitrates */
-       if( params->vi_bitrate.mode )
-       {
-               /* bitrate is set, let's figure out the cbr/vbr mess */
-               if( params->vi_bitrate.max < params->vi_bitrate.target )
-               {
-                       if( params->vi_bitrate.mode == V4L2_BITRATE_CBR )
-                               params->vi_bitrate.max = params->vi_bitrate.target;
-                       else
-                               params->vi_bitrate.target = params->vi_bitrate.max;
-               }
-       }
-       else
-       {
-               if( params->st_bitrate.max < params->st_bitrate.target )
-               {
-                       if( params->st_bitrate.mode == V4L2_BITRATE_VBR )
-                               params->st_bitrate.target = params->st_bitrate.max;
-                       else
-                               params->st_bitrate.max = params->st_bitrate.target;
-               }
-               /* calculate vi_bitrate = st_bitrate - au_bitrate */
-               params->vi_bitrate.max = params->st_bitrate.max - params->au_bitrate.max;
-               params->vi_bitrate.target = params->st_bitrate.target - params->au_bitrate.target;
-       }
-       UPDATE_PARAM( st_bitrate );
-       if( CHECK_PARAM( vi_bitrate.mode ) || CHECK_PARAM( vi_bitrate.max )
-               || CHECK_PARAM( vi_bitrate.target )
-       )
-       {
-               UPDATE_PARAM( vi_bitrate );
-               blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 4, 0,
-                               mpeg_video_bitrates[params->vi_bitrate.mode],
-                               params->vi_bitrate.target * 1000, /* kbps -> bps */
-                               params->vi_bitrate.max * 1000 / BLACKBIRD_PEAK_RATE_DIVISOR, /* peak/400 */
-                               BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/); /* encoding buffer, ckennedy */
-       }
-
-       /* TODO: implement the stream ID stuff:
-               ts_pid_pmt, ts_pid_audio, ts_pid_video, ts_pid_pcr,
-               ps_size, au_pesid, vi_pesid
-       */
-       UPDATE_PARAM( ts_pid_pmt );
-       UPDATE_PARAM( ts_pid_audio );
-       UPDATE_PARAM( ts_pid_video );
-       UPDATE_PARAM( ts_pid_pcr );
-       UPDATE_PARAM( ps_size );
-       UPDATE_PARAM( au_pesid );
-       UPDATE_PARAM( vi_pesid );
-}
-
-static void blackbird_set_default_dnr_params(struct cx8802_dev *dev)
-{
-       /* assign dnr filter mode */
-       if( dev->dnr_params.mode > BLACKBIRD_DNR_BITS_AUTO )
-               dev->dnr_params.mode = BLACKBIRD_DNR_BITS_MANUAL;
-       if( dev->dnr_params.type > BLACKBIRD_MEDIAN_FILTER_DIAGONAL )
-               dev->dnr_params.type = BLACKBIRD_MEDIAN_FILTER_DISABLED;
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MODE, 2, 0,
-                               dev->dnr_params.mode,
-                               dev->dnr_params.type
-                       );
-
-       /* assign dnr filter props*/
-       if( dev->dnr_params.spatial > 15 )
-               dev->dnr_params.spatial = 15;
-       if( dev->dnr_params.temporal > 31 )
-               dev->dnr_params.temporal = 31;
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0,
-                               dev->dnr_params.spatial,
-                               dev->dnr_params.temporal
-                       );
-}
-#define CHECK_DNR_PARAM( name ) ( dev->dnr_params.name != dnr_params->name )
-#define UPDATE_DNR_PARAM( name ) dev->dnr_params.name = dnr_params->name
-void blackbird_set_dnr_params(struct cx8802_dev *dev, struct blackbird_dnr* dnr_params)
-{
-       /* assign dnr filter mode */
-       /* clamp values */
-       if( dnr_params->mode > BLACKBIRD_DNR_BITS_AUTO )
-               dnr_params->mode = BLACKBIRD_DNR_BITS_MANUAL;
-       if( dnr_params->type > BLACKBIRD_MEDIAN_FILTER_DIAGONAL )
-               dnr_params->type = BLACKBIRD_MEDIAN_FILTER_DISABLED;
-       /* check if the params actually changed */
-       if( CHECK_DNR_PARAM( mode ) || CHECK_DNR_PARAM( type ) )
-       {
-               UPDATE_DNR_PARAM( mode );
-               UPDATE_DNR_PARAM( type );
-               blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MODE, 2, 0, dnr_params->mode, dnr_params->type);
-       }
-
-       /* assign dnr filter props*/
-       if( dnr_params->spatial > 15 )
-               dnr_params->spatial = 15;
-       if( dnr_params->temporal > 31 )
-               dnr_params->temporal = 31;
-       if( CHECK_DNR_PARAM( spatial ) || CHECK_DNR_PARAM( temporal ) )
-       {
-               UPDATE_DNR_PARAM( spatial );
-               UPDATE_DNR_PARAM( temporal );
-               blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0, dnr_params->spatial, dnr_params->temporal);
-       }
-}
-
-static void blackbird_codec_settings(struct cx8802_dev *dev)
-{
-
-       /* assign output port */
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_OUTPUT_PORT, 1, 0, BLACKBIRD_OUTPUT_PORT_STREAMING); /* Host */
-
-       /* assign frame size */
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_RESOLUTION, 2, 0,
-                               dev->height, dev->width);
-
-       /* assign coring levels (luma_h, luma_l, chroma_h, chroma_l) */
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MEDIAN, 4, 0, 0, 255, 0, 255);
-
-       /* assign spatial filter type: luma_t: horiz_only, chroma_t: horiz_only */
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_SPATIAL_FILTER, 2, 0,
-                               BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
-                               BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ
-                       );
-
-       /* assign frame drop rate */
-       /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_DROP_RATE, 1, 0, 0); */
-
-       blackbird_set_default_params(dev);
-       blackbird_set_default_dnr_params(dev);
-}
-
 static int blackbird_initialize_codec(struct cx8802_dev *dev)
 {
        struct cx88_core *core = dev->core;
@@ -1248,7 +568,7 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
        int retval;
 
        dprintk(1,"Initialize codec\n");
-       retval = blackbird_api_cmd(dev, BLACKBIRD_API_PING, 0, 0); /* ping */
+       retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
        if (retval < 0) {
                /* ping was not successful, reset and upload firmware */
                cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */
@@ -1263,13 +583,13 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
                if (dev->mailbox < 0)
                        return -1;
 
-               retval = blackbird_api_cmd(dev, BLACKBIRD_API_PING, 0, 0); /* ping */
+               retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
                if (retval < 0) {
                        dprintk(0, "ERROR: Firmware ping failed!\n");
                        return -1;
                }
 
-               retval = blackbird_api_cmd(dev, BLACKBIRD_API_GET_VERSION, 0, 1, &version);
+               retval = blackbird_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, &version);
                if (retval < 0) {
                        dprintk(0, "ERROR: Firmware get encoder version failed!\n");
                        return -1;
@@ -1289,35 +609,35 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
        /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xef, 0xef);
           blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xf0, 0xf0);
           blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0x180, 0x180); */
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_CAPTURE_LINES, 2, 0,
+       blackbird_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
                        BLACKBIRD_FIELD1_SAA7115,
-                       BLACKBIRD_FIELD1_SAA7115
+                       BLACKBIRD_FIELD2_SAA7115
                );
 
        /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); */
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_CUSTOM_DATA, 12, 0,
+       blackbird_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
                        BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 
        /* initialize the video input */
-       blackbird_api_cmd(dev, BLACKBIRD_API_INIT_VIDEO_INPUT, 0, 0);
+       blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
 
        msleep(1);
 
-       blackbird_api_cmd(dev, BLACKBIRD_API_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE);
+       blackbird_api_cmd(dev, CX2341X_ENC_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE);
        msleep(1);
-       blackbird_api_cmd(dev, BLACKBIRD_API_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE);
+       blackbird_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE);
        msleep(1);
 
        /* start capturing to the host interface */
-       /* blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0, 0, 0x13); */
-       blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0,
+       /* blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, 0, 0x13); */
+       blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
                        BLACKBIRD_MPEG_CAPTURE,
                        BLACKBIRD_RAW_BITS_NONE
                );
        msleep(10);
 
-       blackbird_api_cmd(dev, BLACKBIRD_API_REFRESH_INPUT, 0,0);
+       blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0,0);
        return 0;
 }
 
@@ -1485,14 +805,52 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
        {
                struct v4l2_mpeg_compression *f = arg;
 
-               memcpy(f,&dev->params,sizeof(*f));
+               printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
+                                   "Replace with VIDIOC_G_EXT_CTRLS!");
+               memcpy(f,&default_mpeg_params,sizeof(*f));
                return 0;
        }
        case VIDIOC_S_MPEGCOMP:
+               printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
+                                   "Replace with VIDIOC_S_EXT_CTRLS!");
+               return 0;
+       case VIDIOC_G_EXT_CTRLS:
        {
-               struct v4l2_mpeg_compression *f = arg;
+               struct v4l2_ext_controls *f = arg;
 
-               blackbird_set_params(dev, f);
+               if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+                       return -EINVAL;
+               return cx2341x_ext_ctrls(&dev->params, f, cmd);
+       }
+       case VIDIOC_S_EXT_CTRLS:
+       case VIDIOC_TRY_EXT_CTRLS:
+       {
+               struct v4l2_ext_controls *f = arg;
+               struct cx2341x_mpeg_params p;
+               int err;
+
+               if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+                       return -EINVAL;
+               p = dev->params;
+               err = cx2341x_ext_ctrls(&p, f, cmd);
+               if (err == 0 && cmd == VIDIOC_S_EXT_CTRLS) {
+                       err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p);
+                       dev->params = p;
+               }
+               return err;
+       }
+       case VIDIOC_S_FREQUENCY:
+       {
+               blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+                                 BLACKBIRD_END_NOW,
+                                 BLACKBIRD_MPEG_CAPTURE,
+                                 BLACKBIRD_RAW_BITS_NONE);
+
+               cx88_do_ioctl( inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook );
+
+               blackbird_initialize_codec(dev);
+               cx88_set_scale(dev->core, dev->width, dev->height,
+                              fh->mpegq.field);
                return 0;
        }
 
@@ -1562,13 +920,14 @@ static int mpeg_release(struct inode *inode, struct file *file)
 {
        struct cx8802_fh  *fh  = file->private_data;
 
-       /* blackbird_api_cmd(fh->dev, BLACKBIRD_API_END_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */
-       blackbird_api_cmd(fh->dev, BLACKBIRD_API_END_CAPTURE, 3, 0,
+       /* blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */
+       blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
                        BLACKBIRD_END_NOW,
                        BLACKBIRD_MPEG_CAPTURE,
                        BLACKBIRD_RAW_BITS_NONE
                );
 
+       cx8802_cancel_buffers(fh->dev);
        /* stop mpeg capture */
        if (fh->mpegq.streaming)
                videobuf_streamoff(&fh->mpegq);
@@ -1683,19 +1042,13 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev,
        dev->core = core;
        dev->width = 720;
        dev->height = 576;
-       memcpy(&dev->params,&default_mpeg_params,sizeof(default_mpeg_params));
-       memcpy(&dev->dnr_params,&default_dnr_params,sizeof(default_dnr_params));
-
-       if (core->board == CX88_BOARD_HAUPPAUGE_ROSLYN) {
-
-               if (core->tuner_formats & V4L2_STD_525_60) {
-                       dev->height = 480;
-                       dev->params.vi_frame_rate = 30;
-               } else {
-                       dev->height = 576;
-                       dev->params.vi_frame_rate = 25;
-               }
+       cx2341x_fill_defaults(&dev->params);
+       dev->params.port = CX2341X_PORT_STREAMING;
 
+       if (core->tvnorm->id & V4L2_STD_525_60) {
+               dev->height = 480;
+       } else {
+               dev->height = 576;
        }
 
        err = cx8802_init_common(dev);
@@ -1781,8 +1134,6 @@ module_exit(blackbird_fini);
 
 EXPORT_SYMBOL(cx88_ioctl_hook);
 EXPORT_SYMBOL(cx88_ioctl_translator);
-EXPORT_SYMBOL(blackbird_set_params);
-EXPORT_SYMBOL(blackbird_set_dnr_params);
 
 /* ----------------------------------------------------------- */
 /*
index f80154b87d22977d337e4d0159472ca8b074f899..67cdd82708630fc921b94be343a61847fe24edc0 100644 (file)
@@ -114,7 +114,7 @@ struct cx88_board cx88_boards[] = {
                .radio = {
                         .type  = CX88_RADIO,
                         .gpio0 = 0xff10,
-                },
+               },
        },
        [CX88_BOARD_ATI_WONDER_PRO] = {
                .name           = "ATI TV Wonder Pro",
@@ -267,7 +267,7 @@ struct cx88_board cx88_boards[] = {
                        .gpio1  = 0x00007004,
                        .gpio2  = 0x0035d700,
                        .gpio3  = 0x02000000,
-                },
+               },
        },
        [CX88_BOARD_LEADTEK_PVR2000] = {
                // gpio values for PAL version from regspy by DScaler
@@ -413,7 +413,7 @@ struct cx88_board cx88_boards[] = {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x000027df,
-                },{
+               },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x000027df,
@@ -536,7 +536,7 @@ struct cx88_board cx88_boards[] = {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x000027df,
-                },{
+               },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x000027df,
@@ -759,7 +759,7 @@ struct cx88_board cx88_boards[] = {
        },
        [CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD] = {
                .name           = "DViCO FusionHDTV 5 Gold",
-               .tuner_type     = TUNER_LG_TDVS_H062F,
+               .tuner_type     = TUNER_LG_TDVS_H06XF, /* TDVS-H062F */
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
@@ -1050,11 +1050,7 @@ struct cx88_board cx88_boards[] = {
                .dvb            = 1,
        },
        [CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = {
-               /* FIXME: Standard video using the cx88 broadcast decoder is
-                * working, but blackbird isn't working yet, audio is only
-                * working correctly for television mode. S-Video and Composite
-                * are working for video-only, so I have them disabled for now.
-                */
+               /* FIXME: Audio not working for s-video / composite inputs. */
                .name           = "KWorld HardwareMpegTV XPert",
                .tuner_type     = TUNER_PHILIPS_TDA8290,
                .radio_type     = UNSET,
@@ -1065,12 +1061,21 @@ struct cx88_board cx88_boards[] = {
                        .vmux   = 0,
                        .gpio0  = 0x3de2,
                        .gpio2  = 0x00ff,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x3de6,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x3de6,
                }},
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x3de6,
                        .gpio2  = 0x00ff,
                },
+               .blackbird      = 1,
        },
        [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID] = {
                .name           = "DViCO FusionHDTV DVB-T Hybrid",
@@ -1093,7 +1098,102 @@ struct cx88_board cx88_boards[] = {
                }},
                .dvb            = 1,
        },
-
+       [CX88_BOARD_PCHDTV_HD5500] = {
+               .name           = "pcHDTV HD5500 HDTV",
+               .tuner_type     = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x87fd,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x87f9,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x87f9,
+               }},
+               .dvb            = 1,
+       },
+       [CX88_BOARD_KWORLD_MCE200_DELUXE] = {
+               /* FIXME: tested TV input only, disabled composite,
+                  svideo and radio until they can be tested also. */
+               .name           = "Kworld MCE 200 Deluxe",
+               .tuner_type     = TUNER_TENA_9533_DI,
+               .radio_type     = UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x0000BDE6
+               }},
+               .blackbird = 1,
+       },
+       [CX88_BOARD_PIXELVIEW_PLAYTV_P7000] = {
+               /* FIXME: SVideo, Composite and FM inputs are untested */
+               .name           = "PixelView PlayTV P7000",
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE |
+                                 TDA9887_PORT2_ACTIVE,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x5da6,
+               }},
+               .blackbird = 1,
+       },
+       [CX88_BOARD_NPGTECH_REALTV_TOP10FM] = {
+               .name           = "NPG Tech Real TV FM Top 10",
+               .tuner_type     = TUNER_TNF_5335MF, /* Actually a TNF9535 */
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x0788,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x078b,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x078b,
+               }},
+               .radio = {
+                        .type  = CX88_RADIO,
+                        .gpio0 = 0x074a,
+               },
+       },
+       [CX88_BOARD_WINFAST_DTV2000H] = {
+               /* video inputs and radio still in testing */
+               .name           = "WinFast DTV2000 H",
+               .tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x00017304,
+                       .gpio1  = 0x00008203,
+                       .gpio2  = 0x00017304,
+                       .gpio3  = 0x02000000,
+               }},
+               .dvb            = 1,
+       },
 };
 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
 
@@ -1311,6 +1411,34 @@ struct cx88_subid cx88_subids[] = {
                .subvendor = 0x18ac,
                .subdevice = 0xdb44,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
+       },{
+               .subvendor = 0x7063,
+               .subdevice = 0x5500,
+               .card      = CX88_BOARD_PCHDTV_HD5500,
+       },{
+               .subvendor = 0x17de,
+               .subdevice = 0x0841,
+               .card      = CX88_BOARD_KWORLD_MCE200_DELUXE,
+       },{
+               .subvendor = 0x1822,
+               .subdevice = 0x0019,
+               .card      = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
+       },{
+               .subvendor = 0x1554,
+               .subdevice = 0x4813,
+               .card      = CX88_BOARD_PIXELVIEW_PLAYTV_P7000,
+       },{
+               .subvendor = 0x14f1,
+               .subdevice = 0x0842,
+               .card      = CX88_BOARD_NPGTECH_REALTV_TOP10FM,
+       },{
+               .subvendor = 0x107d,
+               .subdevice = 0x665e,
+               .card      = CX88_BOARD_WINFAST_DTV2000H,
+       },{
+               .subvendor = 0x18ac,
+               .subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */
+               .card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
        },
 };
 const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
index e1092d5d4628de6d078971be4ca62ce1a92c4592..c56292d8d93bee7f47e02fb2d51e5030813055bc 100644 (file)
@@ -677,7 +677,7 @@ static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
 
 static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
 {
-       return (norm->id & V4L2_STD_625_50) ? 511 : 288;
+       return (norm->id & V4L2_STD_625_50) ? 511 : 400;
 }
 
 int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
@@ -932,9 +932,9 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
                htotal, cx_read(MO_HTOTAL), (u32)tmp64);
        cx_write(MO_HTOTAL, htotal);
 
-       // vbi stuff
-       cx_write(MO_VBI_PACKET, ((1 << 11) | /* (norm_vdelay(norm)   << 11) | */
-                                norm_vbipack(norm)));
+       // vbi stuff, set vbi offset to 10 (for 20 Clk*2 pixels), this makes
+       // the effective vbi offset ~244 samples, the same as the Bt8x8
+       cx_write(MO_VBI_PACKET, (10<<11) | norm_vbipack(norm));
 
        // this is needed as well to set all tvnorm parameter
        cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED);
index 3619a449aefd91899e9ed26453006b7f8c124b4d..dce1feddd55d16f9d6ece0457cd71c47d7a681cb 100644 (file)
@@ -51,6 +51,7 @@
 #endif
 #ifdef HAVE_LGDT330X
 # include "lgdt330x.h"
+# include "lg_h06xf.h"
 #endif
 #ifdef HAVE_NXT200X
 # include "nxt200x.h"
@@ -58,6 +59,7 @@
 #ifdef HAVE_CX24123
 # include "cx24123.h"
 #endif
+#include "isl6421.h"
 
 MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -113,21 +115,6 @@ static struct videobuf_queue_ops dvb_qops = {
 
 /* ------------------------------------------------------------------ */
 
-#if defined(HAVE_MT352) || defined(HAVE_ZL10353)
-static int zarlink_pll_set(struct dvb_frontend *fe,
-                             struct dvb_frontend_parameters *params,
-                             u8 *pllbuf)
-{
-       struct cx8802_dev *dev = fe->dvb->priv;
-
-       pllbuf[0] = dev->core->pll_addr << 1;
-       dvb_pll_configure(dev->core->pll_desc, pllbuf + 1,
-                         params->frequency,
-                         params->u.ofdm.bandwidth);
-       return 0;
-}
-#endif
-
 #ifdef HAVE_MT352
 static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
 {
@@ -196,19 +183,16 @@ static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
 static struct mt352_config dvico_fusionhdtv = {
        .demod_address = 0x0F,
        .demod_init    = dvico_fusionhdtv_demod_init,
-       .pll_set       = zarlink_pll_set,
 };
 
 static struct mt352_config dntv_live_dvbt_config = {
        .demod_address = 0x0f,
        .demod_init    = dntv_live_dvbt_demod_init,
-       .pll_set       = zarlink_pll_set,
 };
 
 static struct mt352_config dvico_fusionhdtv_dual = {
        .demod_address = 0x0F,
        .demod_init    = dvico_dual_demod_init,
-       .pll_set       = zarlink_pll_set,
 };
 
 #ifdef HAVE_VP3054_I2C
@@ -246,6 +230,8 @@ static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
                  .buf = fmd1216_init, .len = sizeof(fmd1216_init) };
        int err;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
                if (err < 0)
                        return err;
@@ -256,14 +242,14 @@ static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
        return 0;
 }
 
-static int dntv_live_dvbt_pro_pll_set(struct dvb_frontend* fe,
-                                     struct dvb_frontend_parameters* params,
-                                     u8* pllbuf)
+static int dntv_live_dvbt_pro_tuner_set_params(struct dvb_frontend* fe,
+                                              struct dvb_frontend_parameters* params)
 {
        struct cx8802_dev *dev= fe->dvb->priv;
+       u8 buf[4];
        struct i2c_msg msg =
                { .addr = dev->core->pll_addr, .flags = 0,
-                 .buf = pllbuf+1, .len = 4 };
+                 .buf = buf, .len = 4 };
        int err;
 
        /* Switch PLL to DVB mode */
@@ -272,14 +258,16 @@ static int dntv_live_dvbt_pro_pll_set(struct dvb_frontend* fe,
                return err;
 
        /* Tune PLL */
-       pllbuf[0] = dev->core->pll_addr << 1;
-       dvb_pll_configure(dev->core->pll_desc, pllbuf+1,
+       dvb_pll_configure(dev->core->pll_desc, buf,
                          params->frequency,
                          params->u.ofdm.bandwidth);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
+
                printk(KERN_WARNING "cx88-dvb: %s error "
                           "(addr %02x <- %02x, err = %i)\n",
-                          __FUNCTION__, pllbuf[0], pllbuf[1], err);
+                          __FUNCTION__, dev->core->pll_addr, buf[0], err);
                if (err < 0)
                        return err;
                else
@@ -293,27 +281,27 @@ static struct mt352_config dntv_live_dvbt_pro_config = {
        .demod_address = 0x0f,
        .no_tuner      = 1,
        .demod_init    = dntv_live_dvbt_pro_demod_init,
-       .pll_set       = dntv_live_dvbt_pro_pll_set,
 };
 #endif
 #endif
 
 #ifdef HAVE_ZL10353
-static int dvico_hybrid_tune_pll(struct dvb_frontend *fe,
-                                struct dvb_frontend_parameters *params,
-                                u8 *pllbuf)
+static int dvico_hybrid_tuner_set_params(struct dvb_frontend *fe,
+                                        struct dvb_frontend_parameters *params)
 {
+       u8 pllbuf[4];
        struct cx8802_dev *dev= fe->dvb->priv;
        struct i2c_msg msg =
                { .addr = dev->core->pll_addr, .flags = 0,
-                 .buf = pllbuf + 1, .len = 4 };
+                 .buf = pllbuf, .len = 4 };
        int err;
 
-       pllbuf[0] = dev->core->pll_addr << 1;
-       dvb_pll_configure(dev->core->pll_desc, pllbuf + 1,
+       dvb_pll_configure(dev->core->pll_desc, pllbuf,
                          params->frequency,
                          params->u.ofdm.bandwidth);
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
                printk(KERN_WARNING "cx88-dvb: %s error "
                           "(addr %02x <- %02x, err = %i)\n",
@@ -329,12 +317,11 @@ static int dvico_hybrid_tune_pll(struct dvb_frontend *fe,
 
 static struct zl10353_config dvico_fusionhdtv_hybrid = {
        .demod_address = 0x0F,
-       .pll_set       = dvico_hybrid_tune_pll,
+       .no_tuner      = 1,
 };
 
 static struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
        .demod_address = 0x0F,
-       .pll_set       = zarlink_pll_set,
 };
 #endif
 
@@ -342,21 +329,15 @@ static struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
 static struct cx22702_config connexant_refboard_config = {
        .demod_address = 0x43,
        .output_mode   = CX22702_SERIAL_OUTPUT,
-       .pll_address   = 0x60,
-       .pll_desc      = &dvb_pll_thomson_dtt7579,
 };
 
 static struct cx22702_config hauppauge_novat_config = {
        .demod_address = 0x43,
        .output_mode   = CX22702_SERIAL_OUTPUT,
-       .pll_address   = 0x61,
-       .pll_desc      = &dvb_pll_thomson_dtt759x,
 };
 static struct cx22702_config hauppauge_hvr1100_config = {
        .demod_address = 0x63,
        .output_mode   = CX22702_SERIAL_OUTPUT,
-       .pll_address   = 0x61,
-       .pll_desc      = &dvb_pll_fmd1216me,
 };
 #endif
 
@@ -371,15 +352,13 @@ static int or51132_set_ts_param(struct dvb_frontend* fe,
 
 static struct or51132_config pchdtv_hd3000 = {
        .demod_address    = 0x15,
-       .pll_address      = 0x61,
-       .pll_desc         = &dvb_pll_thomson_dtt761x,
        .set_ts_params    = or51132_set_ts_param,
 };
 #endif
 
 #ifdef HAVE_LGDT330X
-static int lgdt330x_pll_set(struct dvb_frontend* fe,
-                           struct dvb_frontend_parameters* params)
+static int lgdt3302_tuner_set_params(struct dvb_frontend* fe,
+                                    struct dvb_frontend_parameters* params)
 {
        /* FIXME make this routine use the tuner-simple code.
         * It could probably be shared with a number of ATSC
@@ -392,12 +371,12 @@ static int lgdt330x_pll_set(struct dvb_frontend* fe,
                { .addr = dev->core->pll_addr, .flags = 0, .buf = buf, .len = 4 };
        int err;
 
-       /* Put the analog decoder in standby to keep it quiet */
-       cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
-
        dvb_pll_configure(core->pll_desc, buf, params->frequency, 0);
        dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
                        __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if ((err = i2c_transfer(&core->i2c_adap, &msg, 1)) != 1) {
                printk(KERN_WARNING "cx88-dvb: %s error "
                           "(addr %02x <- %02x, err = %i)\n",
@@ -407,16 +386,21 @@ static int lgdt330x_pll_set(struct dvb_frontend* fe,
                else
                        return -EREMOTEIO;
        }
-       if (core->tuner_type == TUNER_LG_TDVS_H062F) {
-               /* Set the Auxiliary Byte. */
-               buf[2] &= ~0x20;
-               buf[2] |= 0x18;
-               buf[3] = 0x50;
-               i2c_transfer(&core->i2c_adap, &msg, 1);
-       }
        return 0;
 }
 
+static int lgdt3303_tuner_set_params(struct dvb_frontend* fe,
+                                    struct dvb_frontend_parameters* params)
+{
+       struct cx8802_dev *dev= fe->dvb->priv;
+       struct cx88_core *core = dev->core;
+
+       /* Put the analog decoder in standby to keep it quiet */
+       cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
+
+       return lg_h06xf_pll_set(fe, &core->i2c_adap, params);
+}
+
 static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index)
 {
        struct cx8802_dev *dev= fe->dvb->priv;
@@ -444,7 +428,6 @@ static struct lgdt330x_config fusionhdtv_3_gold = {
        .demod_address    = 0x0e,
        .demod_chip       = LGDT3302,
        .serial_mpeg      = 0x04, /* TPSERIAL for 3302 in TOP_CONTROL */
-       .pll_set          = lgdt330x_pll_set,
        .set_ts_params    = lgdt330x_set_ts_param,
 };
 
@@ -452,7 +435,13 @@ static struct lgdt330x_config fusionhdtv_5_gold = {
        .demod_address    = 0x0e,
        .demod_chip       = LGDT3303,
        .serial_mpeg      = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
-       .pll_set          = lgdt330x_pll_set,
+       .set_ts_params    = lgdt330x_set_ts_param,
+};
+
+static struct lgdt330x_config pchdtv_hd5500 = {
+       .demod_address    = 0x59,
+       .demod_chip       = LGDT3303,
+       .serial_mpeg      = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
        .set_ts_params    = lgdt330x_set_ts_param,
 };
 #endif
@@ -477,8 +466,6 @@ static int nxt200x_set_pll_input(u8* buf, int input)
 
 static struct nxt200x_config ati_hdtvwonder = {
        .demod_address    = 0x0a,
-       .pll_address      = 0x61,
-       .pll_desc         = &dvb_pll_tuv1236d,
        .set_pll_input    = nxt200x_set_pll_input,
        .set_ts_params    = nxt200x_set_ts_param,
 };
@@ -493,28 +480,30 @@ static int cx24123_set_ts_param(struct dvb_frontend* fe,
        return 0;
 }
 
-static void cx24123_enable_lnb_voltage(struct dvb_frontend* fe, int on)
+static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
 {
        struct cx8802_dev *dev= fe->dvb->priv;
        struct cx88_core *core = dev->core;
 
-       if (on)
-               cx_write(MO_GP0_IO, 0x000006f9);
-       else
+       if (voltage == SEC_VOLTAGE_OFF) {
                cx_write(MO_GP0_IO, 0x000006fB);
+       } else {
+               cx_write(MO_GP0_IO, 0x000006f9);
+       }
+
+       if (core->prev_set_voltage)
+               return core->prev_set_voltage(fe, voltage);
+       return 0;
 }
 
 static struct cx24123_config hauppauge_novas_config = {
        .demod_address          = 0x55,
-       .use_isl6421            = 1,
        .set_ts_params          = cx24123_set_ts_param,
 };
 
 static struct cx24123_config kworld_dvbs_100_config = {
        .demod_address          = 0x15,
-       .use_isl6421            = 0,
        .set_ts_params          = cx24123_set_ts_param,
-       .enable_lnb_voltage     = cx24123_enable_lnb_voltage,
 };
 #endif
 
@@ -530,6 +519,11 @@ static int dvb_register(struct cx8802_dev *dev)
        case CX88_BOARD_HAUPPAUGE_DVB_T1:
                dev->dvb.frontend = cx22702_attach(&hauppauge_novat_config,
                                                   &dev->core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       dvb_pll_attach(dev->dvb.frontend, 0x61,
+                                      &dev->core->i2c_adap,
+                                      &dvb_pll_thomson_dtt759x);
+               }
                break;
        case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
        case CX88_BOARD_CONEXANT_DVB_T1:
@@ -537,44 +531,92 @@ static int dvb_register(struct cx8802_dev *dev)
        case CX88_BOARD_WINFAST_DTV1000:
                dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
                                                   &dev->core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       dvb_pll_attach(dev->dvb.frontend, 0x60,
+                                      &dev->core->i2c_adap,
+                                      &dvb_pll_thomson_dtt7579);
+               }
                break;
+       case CX88_BOARD_WINFAST_DTV2000H:
        case CX88_BOARD_HAUPPAUGE_HVR1100:
        case CX88_BOARD_HAUPPAUGE_HVR1100LP:
                dev->dvb.frontend = cx22702_attach(&hauppauge_hvr1100_config,
                                                   &dev->core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       dvb_pll_attach(dev->dvb.frontend, 0x61,
+                                      &dev->core->i2c_adap,
+                                      &dvb_pll_fmd1216me);
+               }
                break;
 #endif
 #if defined(HAVE_MT352) || defined(HAVE_ZL10353)
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
-               dev->core->pll_addr = 0x60;
-               dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
 #ifdef HAVE_MT352
                dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
                                                 &dev->core->i2c_adap);
-               if (dev->dvb.frontend != NULL)
+               if (dev->dvb.frontend != NULL) {
+                       dvb_pll_attach(dev->dvb.frontend, 0x60,
+                                      &dev->core->i2c_adap,
+                                      &dvb_pll_thomson_dtt7579);
                        break;
+               }
 #endif
 #ifdef HAVE_ZL10353
                /* ZL10353 replaces MT352 on later cards */
                dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1,
                                                   &dev->core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       dvb_pll_attach(dev->dvb.frontend, 0x60,
+                                      &dev->core->i2c_adap,
+                                      &dvb_pll_thomson_dtt7579);
+               }
+#endif
+               break;
+       case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
+#ifdef HAVE_MT352
+               /* The tin box says DEE1601, but it seems to be DTT7579
+                * compatible, with a slightly different MT352 AGC gain. */
+               dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dual,
+                                                &dev->core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       dvb_pll_attach(dev->dvb.frontend, 0x61,
+                                      &dev->core->i2c_adap,
+                                      &dvb_pll_thomson_dtt7579);
+                       break;
+               }
+#endif
+#ifdef HAVE_ZL10353
+               /* ZL10353 replaces MT352 on later cards */
+               dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1,
+                                                  &dev->core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       dvb_pll_attach(dev->dvb.frontend, 0x61,
+                                      &dev->core->i2c_adap,
+                                      &dvb_pll_thomson_dtt7579);
+               }
 #endif
                break;
 #endif /* HAVE_MT352 || HAVE_ZL10353 */
 #ifdef HAVE_MT352
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
-               dev->core->pll_addr = 0x61;
-               dev->core->pll_desc = &dvb_pll_lg_z201;
                dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
                                                 &dev->core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       dvb_pll_attach(dev->dvb.frontend, 0x61,
+                                      &dev->core->i2c_adap,
+                                      &dvb_pll_lg_z201);
+               }
                break;
        case CX88_BOARD_KWORLD_DVB_T:
        case CX88_BOARD_DNTV_LIVE_DVB_T:
        case CX88_BOARD_ADSTECH_DVB_T_PCI:
-               dev->core->pll_addr = 0x61;
-               dev->core->pll_desc = &dvb_pll_unknown_1;
                dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config,
                                                 &dev->core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       dvb_pll_attach(dev->dvb.frontend, 0x61,
+                                      &dev->core->i2c_adap,
+                                      &dvb_pll_unknown_1);
+               }
                break;
        case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
 #ifdef HAVE_VP3054_I2C
@@ -582,18 +624,13 @@ static int dvb_register(struct cx8802_dev *dev)
                dev->core->pll_desc = &dvb_pll_fmd1216me;
                dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_pro_config,
                        &((struct vp3054_i2c_state *)dev->card_priv)->adap);
+               if (dev->dvb.frontend != NULL) {
+                       dev->dvb.frontend->ops.tuner_ops.set_params = dntv_live_dvbt_pro_tuner_set_params;
+               }
 #else
                printk("%s: built without vp3054 support\n", dev->core->name);
 #endif
                break;
-       case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
-               /* The tin box says DEE1601, but it seems to be DTT7579
-                * compatible, with a slightly different MT352 AGC gain. */
-               dev->core->pll_addr = 0x61;
-               dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
-               dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dual,
-                                                &dev->core->i2c_adap);
-               break;
 #endif
 #ifdef HAVE_ZL10353
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
@@ -601,12 +638,20 @@ static int dvb_register(struct cx8802_dev *dev)
                dev->core->pll_desc = &dvb_pll_thomson_fe6600;
                dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_hybrid,
                                                   &dev->core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       dev->dvb.frontend->ops.tuner_ops.set_params = dvico_hybrid_tuner_set_params;
+               }
                break;
 #endif
 #ifdef HAVE_OR51132
        case CX88_BOARD_PCHDTV_HD3000:
                dev->dvb.frontend = or51132_attach(&pchdtv_hd3000,
                                                 &dev->core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       dvb_pll_attach(dev->dvb.frontend, 0x61,
+                                      &dev->core->i2c_adap,
+                                      &dvb_pll_thomson_dtt761x);
+               }
                break;
 #endif
 #ifdef HAVE_LGDT330X
@@ -627,6 +672,9 @@ static int dvb_register(struct cx8802_dev *dev)
                dev->core->pll_desc = &dvb_pll_microtune_4042;
                dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold,
                                                    &dev->core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params;
+               }
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
@@ -643,6 +691,9 @@ static int dvb_register(struct cx8802_dev *dev)
                dev->core->pll_desc = &dvb_pll_thomson_dtt761x;
                dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold,
                                                    &dev->core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params;
+               }
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
@@ -655,10 +706,28 @@ static int dvb_register(struct cx8802_dev *dev)
                mdelay(100);
                cx_set(MO_GP0_IO, 1);
                mdelay(200);
-               dev->core->pll_addr = 0x61;
-               dev->core->pll_desc = &dvb_pll_tdvs_tua6034;
                dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_5_gold,
                                                    &dev->core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
+               }
+               }
+               break;
+       case CX88_BOARD_PCHDTV_HD5500:
+               dev->ts_gen_cntrl = 0x08;
+               {
+               /* Do a hardware reset of chip before using it. */
+               struct cx88_core *core = dev->core;
+
+               cx_clear(MO_GP0_IO, 1);
+               mdelay(100);
+               cx_set(MO_GP0_IO, 1);
+               mdelay(200);
+               dev->dvb.frontend = lgdt330x_attach(&pchdtv_hd5500,
+                                                   &dev->core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
+               }
                }
                break;
 #endif
@@ -666,6 +735,11 @@ static int dvb_register(struct cx8802_dev *dev)
        case CX88_BOARD_ATI_HDTVWONDER:
                dev->dvb.frontend = nxt200x_attach(&ati_hdtvwonder,
                                                 &dev->core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       dvb_pll_attach(dev->dvb.frontend, 0x61,
+                                      &dev->core->i2c_adap,
+                                      &dvb_pll_tuv1236d);
+               }
                break;
 #endif
 #ifdef HAVE_CX24123
@@ -673,10 +747,18 @@ static int dvb_register(struct cx8802_dev *dev)
        case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
                dev->dvb.frontend = cx24123_attach(&hauppauge_novas_config,
                        &dev->core->i2c_adap);
+               if (dev->dvb.frontend) {
+                       isl6421_attach(dev->dvb.frontend, &dev->core->i2c_adap,
+                                      0x08, 0x00, 0x00);
+               }
                break;
        case CX88_BOARD_KWORLD_DVBS_100:
                dev->dvb.frontend = cx24123_attach(&kworld_dvbs_100_config,
                        &dev->core->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+                       dev->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
+               }
                break;
 #endif
        default:
@@ -690,15 +772,15 @@ static int dvb_register(struct cx8802_dev *dev)
        }
 
        if (dev->core->pll_desc) {
-               dev->dvb.frontend->ops->info.frequency_min = dev->core->pll_desc->min;
-               dev->dvb.frontend->ops->info.frequency_max = dev->core->pll_desc->max;
+               dev->dvb.frontend->ops.info.frequency_min = dev->core->pll_desc->min;
+               dev->dvb.frontend->ops.info.frequency_max = dev->core->pll_desc->max;
        }
 
        /* Put the analog decoder in standby to keep it quiet */
        cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
 
        /* register everything */
-       return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev);
+       return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
 }
 
 /* ----------------------------------------------------------- */
index f720901e963866bec677d1bed8354c7d71a77535..7efa6def0bdeff6cb6c8e362a2a238a9ba2d9392 100644 (file)
@@ -138,13 +138,13 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
                return;
 
        if (core->dvbdev) {
-               if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl)
-                       core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
+               if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
+                       core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
 
                i2c_clients_command(&core->i2c_adap, cmd, arg);
 
-               if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl)
-                       core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
+               if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
+                       core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
        } else
                i2c_clients_command(&core->i2c_adap, cmd, arg);
 }
index 78a63b7dd380a33e806ef0f2c9d000eb523b6314..72b630a91f41e1aa06ed1e6ef6bf96d1001a34e6 100644 (file)
@@ -70,14 +70,33 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
 static void cx88_ir_handle_key(struct cx88_IR *ir)
 {
        struct cx88_core *core = ir->core;
-       u32 gpio, data;
+       u32 gpio, data, auxgpio;
 
        /* read gpio value */
        gpio = cx_read(ir->gpio_addr);
+       if (core->board == CX88_BOARD_NPGTECH_REALTV_TOP10FM) {
+               /* This board apparently uses a combination of 2 GPIO
+                  to represent the keys. Additionally, the second GPIO
+                  can be used for parity.
+
+                  Example:
+
+                  for key "5"
+                       gpio = 0x758, auxgpio = 0xe5 or 0xf5
+                  for key "Power"
+                       gpio = 0x758, auxgpio = 0xed or 0xfd
+                */
+
+               auxgpio = cx_read(MO_GP1_IO);
+               /* Take out the parity part */
+               gpio+=(gpio & 0x7fd) + (auxgpio & 0xef);
+       } else
+               auxgpio = gpio;
+
        if (ir->polling) {
-               if (ir->last_gpio == gpio)
+               if (ir->last_gpio == auxgpio)
                        return;
-               ir->last_gpio = gpio;
+               ir->last_gpio = auxgpio;
        }
 
        /* extract data */
@@ -172,12 +191,13 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                ir_type = IR_TYPE_RC5;
                ir->sampling = 1;
                break;
+       case CX88_BOARD_WINFAST_DTV2000H:
        case CX88_BOARD_WINFAST2000XP_EXPERT:
                ir_codes = ir_codes_winfast;
                ir->gpio_addr = MO_GP0_IO;
                ir->mask_keycode = 0x8f8;
                ir->mask_keyup = 0x100;
-               ir->polling = 1; /* ms */
+               ir->polling = 50; /* ms */
                break;
        case CX88_BOARD_IODATA_GVBCTV7E:
                ir_codes = ir_codes_iodata_bctv7e;
@@ -228,6 +248,12 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                ir_type = IR_TYPE_PD;
                ir->sampling = 0xff00; /* address */
                break;
+       case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
+               ir_codes = ir_codes_npgtech;
+               ir->gpio_addr = MO_GP0_IO;
+               ir->mask_keycode = 0xfa;
+               ir->polling = 50; /* ms */
+               break;
        }
 
        if (NULL == ir_codes) {
index 7d16888b4a866d2d250a1dce4c81b7b6c63a1426..a9d7795a8e143563ed155c109d474d725671012e 100644 (file)
@@ -54,7 +54,7 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
 {
        struct cx88_core *core = dev->core;
 
-       dprintk(0, "cx8802_start_dma w: %d, h: %d, f: %d\n", dev->width, dev->height, buf->vb.field);
+       dprintk(1, "cx8802_start_dma w: %d, h: %d, f: %d\n", dev->width, dev->height, buf->vb.field);
 
        /* setup fifo + format */
        cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28],
@@ -76,6 +76,7 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
                case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
                case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
                case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
+               case CX88_BOARD_PCHDTV_HD5500:
                        cx_write(TS_SOP_STAT, 1<<13);
                        break;
                case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
@@ -109,7 +110,7 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
        q->count = 1;
 
        /* enable irqs */
-       dprintk( 0, "setting the interrupt mask\n" );
+       dprintk( 1, "setting the interrupt mask\n" );
        cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04);
        cx_set(MO_TS_INTMSK,  0x1f0011);
 
@@ -122,7 +123,7 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
 static int cx8802_stop_dma(struct cx8802_dev *dev)
 {
        struct cx88_core *core = dev->core;
-       dprintk( 0, "cx8802_stop_dma\n" );
+       dprintk( 1, "cx8802_stop_dma\n" );
 
        /* stop dma */
        cx_clear(MO_TS_DMACNTRL, 0x11);
@@ -142,10 +143,43 @@ static int cx8802_restart_queue(struct cx8802_dev    *dev,
        struct cx88_buffer *buf;
        struct list_head *item;
 
-       dprintk( 0, "cx8802_restart_queue\n" );
+       dprintk( 1, "cx8802_restart_queue\n" );
        if (list_empty(&q->active))
        {
-               dprintk( 0, "cx8802_restart_queue: queue is empty\n" );
+              struct cx88_buffer *prev;
+              prev = NULL;
+
+              dprintk(1, "cx8802_restart_queue: queue is empty\n" );
+
+              for (;;) {
+                      if (list_empty(&q->queued))
+                              return 0;
+                      buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
+                      if (NULL == prev) {
+                              list_del(&buf->vb.queue);
+                              list_add_tail(&buf->vb.queue,&q->active);
+                              cx8802_start_dma(dev, q, buf);
+                              buf->vb.state = STATE_ACTIVE;
+                              buf->count    = q->count++;
+                              mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+                              dprintk(1,"[%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,&q->active);
+                              buf->vb.state = STATE_ACTIVE;
+                              buf->count    = q->count++;
+                              prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+                              dprintk(1,"[%p/%d] restart_queue - move to active\n",
+                                      buf,buf->vb.i);
+                      } else {
+                              return 0;
+                      }
+                      prev = buf;
+              }
                return 0;
        }
 
@@ -204,13 +238,13 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
        buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma);
 
        if (list_empty(&cx88q->active)) {
-               dprintk( 0, "queue is empty - first active\n" );
+               dprintk( 1, "queue is empty - first active\n" );
                list_add_tail(&buf->vb.queue,&cx88q->active);
                cx8802_start_dma(dev, cx88q, buf);
                buf->vb.state = STATE_ACTIVE;
                buf->count    = cx88q->count++;
                mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT);
-               dprintk(0,"[%p/%d] %s - first active\n",
+               dprintk(1,"[%p/%d] %s - first active\n",
                        buf, buf->vb.i, __FUNCTION__);
 
        } else {
@@ -244,7 +278,7 @@ static void do_cancel_buffers(struct cx8802_dev *dev, char *reason, int restart)
        }
        if (restart)
        {
-               dprintk(0, "restarting queue\n" );
+               dprintk(1, "restarting queue\n" );
                cx8802_restart_queue(dev,q);
        }
        spin_unlock_irqrestore(&dev->slock,flags);
index 641a0c5a64907422777039dfd9f34f0d4f321828..1e4278b588d8830c14b60de00b076bbb1cff63c8 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 #include <linux/delay.h>
+#include <linux/config.h>
 #include <linux/kthread.h>
 
 #include "cx88.h"
@@ -137,21 +138,28 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
 {
        u32 volume;
 
-#ifndef USING_CX88_ALSA
+#ifndef CONFIG_VIDEO_CX88_ALSA
        /* restart dma; This avoids buzz in NICAM and is good in others  */
        cx88_stop_audio_dma(core);
 #endif
        cx_write(AUD_RATE_THRES_DMD, 0x000000C0);
-#ifndef USING_CX88_ALSA
+#ifndef CONFIG_VIDEO_CX88_ALSA
        cx88_start_audio_dma(core);
 #endif
 
        if (cx88_boards[core->board].blackbird) {
                /* sets sound input from external adc */
-               if (core->board == CX88_BOARD_HAUPPAUGE_ROSLYN)
+               switch (core->board) {
+               case CX88_BOARD_HAUPPAUGE_ROSLYN:
+               case CX88_BOARD_KWORLD_MCE200_DELUXE:
+               case CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT:
+               case CX88_BOARD_PIXELVIEW_PLAYTV_P7000:
+               case CX88_BOARD_ASUS_PVR_416:
                        cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
-               else
+                       break;
+               default:
                        cx_set(AUD_CTL, EN_I2SIN_ENABLE);
+               }
 
                cx_write(AUD_I2SINPUTCNTL, 4);
                cx_write(AUD_BAUDRATE, 1);
index 846faadc9f1c22c20e1373cfa9d35b11a516c54f..aa2a69770098cf48b085d9f35c79f154ec20c9b6 100644 (file)
@@ -34,8 +34,8 @@ void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f)
        if (dev->core->tvnorm->id & V4L2_STD_525_60) {
                /* ntsc */
                f->fmt.vbi.sampling_rate = 28636363;
-               f->fmt.vbi.start[0] = 10 -1;
-               f->fmt.vbi.start[1] = 273 -1;
+               f->fmt.vbi.start[0] = 10;
+               f->fmt.vbi.start[1] = 273;
 
        } else if (dev->core->tvnorm->id & V4L2_STD_625_50) {
                /* pal */
index 326a25f147f67c4e96ee16cd81d92b107829c0cd..dc7bc35f18f4069f5aaada4b65202890c1e7ad9a 100644 (file)
 #include <linux/videodev2.h>
 #include <linux/kdev_t.h>
 
+#include <media/v4l2-common.h>
 #include <media/tuner.h>
 #include <media/tveeprom.h>
 #include <media/video-buf.h>
+#include <media/cx2341x.h>
 #include <media/video-buf-dvb.h>
 
 #include "btcx-risc.h"
@@ -35,7 +37,7 @@
 
 #include <linux/version.h>
 #include <linux/mutex.h>
-#define CX88_VERSION_CODE KERNEL_VERSION(0,0,5)
+#define CX88_VERSION_CODE KERNEL_VERSION(0,0,6)
 
 #ifndef TRUE
 # define TRUE (1==1)
@@ -189,6 +191,11 @@ extern struct sram_channel cx88_sram_channels[];
 #define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL 44
 #define CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT 45
 #define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID 46
+#define CX88_BOARD_PCHDTV_HD5500           47
+#define CX88_BOARD_KWORLD_MCE200_DELUXE    48
+#define CX88_BOARD_PIXELVIEW_PLAYTV_P7000  49
+#define CX88_BOARD_NPGTECH_REALTV_TOP10FM  50
+#define CX88_BOARD_WINFAST_DTV2000H        51
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
@@ -296,6 +303,7 @@ struct cx88_core {
        /* config info -- dvb */
        struct dvb_pll_desc        *pll_desc;
        unsigned int               pll_addr;
+       int                        (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
 
        /* state info */
        struct task_struct         *kthread;
@@ -391,14 +399,6 @@ struct cx8802_suspend_state {
        int                        disabled;
 };
 
-/* TODO: move this to struct v4l2_mpeg_compression ? */
-struct blackbird_dnr {
-       u32                       mode;
-       u32                       type;
-       u32                       spatial;
-       u32                       temporal;
-};
-
 struct cx8802_dev {
        struct cx88_core           *core;
        spinlock_t                 slock;
@@ -432,8 +432,7 @@ struct cx8802_dev {
        unsigned char              ts_gen_cntrl;
 
        /* mpeg params */
-       struct v4l2_mpeg_compression params;
-       struct blackbird_dnr       dnr_params;
+       struct cx2341x_mpeg_params params;
 };
 
 /* ----------------------------------------------------------- */
@@ -598,10 +597,6 @@ extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
 extern int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
                                unsigned int cmd, void *arg);
 extern unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
-void blackbird_set_params(struct cx8802_dev *dev,
-                               struct v4l2_mpeg_compression *params);
-void blackbird_set_dnr_params(struct cx8802_dev *dev,
-                               struct blackbird_dnr* dnr_params);
 
 /*
  * Local variables:
index 3b4e9985c3d76442083e1a163b791112411ef454..f7e33f9ee8e921fddbe569e0898fece377e5b97b 100644 (file)
@@ -72,6 +72,7 @@
 #include <linux/slab.h>
 #include <linux/input.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/usb.h>
 #include <linux/smp_lock.h>
 
index 3ba3439db580f605a32a5fc3b5982c810387e0f3..ed882ebc7b958a1f5fc7febf94a8b48c6c4f1497 100644 (file)
@@ -3,7 +3,7 @@
 
    Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
                      Markus Rechberger <mrechberger@gmail.com>
-                     Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+                     Mauro Carvalho Chehab <mchehab@infradead.org>
                      Sascha Sommer <saschasommer@freenet.de>
 
    This program is free software; you can redistribute it and/or modify
@@ -29,6 +29,8 @@
 #include <linux/usb.h>
 #include <media/tuner.h>
 #include <media/msp3400.h>
+#include <media/saa7115.h>
+#include <media/tvp5150.h>
 #include <media/tveeprom.h>
 #include <media/audiochip.h>
 #include <media/v4l2-common.h>
@@ -46,11 +48,11 @@ struct em28xx_board em28xx_boards[] = {
                .decoder      = EM28XX_SAA7113,
                .input           = {{
                        .type     = EM28XX_VMUX_COMPOSITE1,
-                       .vmux     = 0,
+                       .vmux     = SAA7115_COMPOSITE0,
                        .amux     = 1,
                },{
                        .type     = EM28XX_VMUX_SVIDEO,
-                       .vmux     = 9,
+                       .vmux     = SAA7115_SVIDEO3,
                        .amux     = 1,
                }},
        },
@@ -64,11 +66,11 @@ struct em28xx_board em28xx_boards[] = {
                .decoder      = EM28XX_SAA7113,
                .input           = {{
                        .type     = EM28XX_VMUX_COMPOSITE1,
-                       .vmux     = 0,
+                       .vmux     = SAA7115_COMPOSITE0,
                        .amux     = 1,
                },{
                        .type     = EM28XX_VMUX_SVIDEO,
-                       .vmux     = 9,
+                       .vmux     = SAA7115_SVIDEO3,
                        .amux     = 1,
                }},
        },
@@ -82,11 +84,11 @@ struct em28xx_board em28xx_boards[] = {
                .decoder      = EM28XX_SAA7113,
                .input           = {{
                        .type     = EM28XX_VMUX_COMPOSITE1,
-                       .vmux     = 0,
+                       .vmux     = SAA7115_COMPOSITE0,
                        .amux     = 1,
                },{
                        .type     = EM28XX_VMUX_SVIDEO,
-                       .vmux     = 9,
+                       .vmux     = SAA7115_SVIDEO3,
                        .amux     = 1,
                }},
        },
@@ -100,15 +102,15 @@ struct em28xx_board em28xx_boards[] = {
                .decoder      = EM28XX_SAA7113,
                .input          = {{
                        .type     = EM28XX_VMUX_TELEVISION,
-                       .vmux     = 2,
+                       .vmux     = SAA7115_COMPOSITE2,
                        .amux     = 1,
                },{
                        .type     = EM28XX_VMUX_COMPOSITE1,
-                       .vmux     = 0,
+                       .vmux     = SAA7115_COMPOSITE0,
                        .amux     = 1,
                },{
                        .type     = EM28XX_VMUX_SVIDEO,
-                       .vmux     = 9,
+                       .vmux     = SAA7115_SVIDEO3,
                        .amux     = 1,
                }},
        },
@@ -122,15 +124,15 @@ struct em28xx_board em28xx_boards[] = {
                .decoder      = EM28XX_SAA7113,
                .input          = {{
                        .type     = EM28XX_VMUX_TELEVISION,
-                       .vmux     = 2,
+                       .vmux     = SAA7115_COMPOSITE2,
                        .amux     = 0,
                },{
                        .type     = EM28XX_VMUX_COMPOSITE1,
-                       .vmux     = 0,
+                       .vmux     = SAA7115_COMPOSITE0,
                        .amux     = 1,
                },{
                        .type     = EM28XX_VMUX_SVIDEO,
-                       .vmux     = 9,
+                       .vmux     = SAA7115_SVIDEO3,
                        .amux     = 1,
                }},
        },
@@ -146,11 +148,11 @@ struct em28xx_board em28xx_boards[] = {
                /*FIXME: S-Video not tested */
                .input          = {{
                        .type     = EM28XX_VMUX_TELEVISION,
-                       .vmux     = 0,
+                       .vmux     = TVP5150_COMPOSITE0,
                        .amux     = MSP_INPUT_DEFAULT,
                },{
                        .type     = EM28XX_VMUX_SVIDEO,
-                       .vmux     = 2,
+                       .vmux     = TVP5150_SVIDEO,
                        .amux     = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
                                        MSP_DSP_IN_SCART, MSP_DSP_IN_SCART),
                }},
@@ -165,15 +167,15 @@ struct em28xx_board em28xx_boards[] = {
                .decoder        = EM28XX_SAA7114,
                .input          = {{
                        .type     = EM28XX_VMUX_TELEVISION,
-                       .vmux     = 4,
+                       .vmux     = SAA7115_COMPOSITE4,
                        .amux     = 0,
                },{
                        .type     = EM28XX_VMUX_COMPOSITE1,
-                       .vmux     = 0,
+                       .vmux     = SAA7115_COMPOSITE0,
                        .amux     = 1,
                },{
                        .type     = EM28XX_VMUX_SVIDEO,
-                       .vmux     = 9,
+                       .vmux     = SAA7115_SVIDEO3,
                        .amux     = 1,
                }},
        },
@@ -188,15 +190,15 @@ struct em28xx_board em28xx_boards[] = {
                .decoder      = EM28XX_SAA7113,
                .input          = {{
                        .type     = EM28XX_VMUX_TELEVISION,
-                       .vmux     = 2,
+                       .vmux     = SAA7115_COMPOSITE2,
                        .amux     = 0,
                },{
                        .type     = EM28XX_VMUX_COMPOSITE1,
-                       .vmux     = 0,
+                       .vmux     = SAA7115_COMPOSITE0,
                        .amux     = 1,
                },{
                        .type     = EM28XX_VMUX_SVIDEO,
-                       .vmux     = 9,
+                       .vmux     = SAA7115_SVIDEO3,
                        .amux     = 1,
                }},
        },
@@ -211,15 +213,15 @@ struct em28xx_board em28xx_boards[] = {
                .decoder      = EM28XX_SAA7113,
                .input          = {{
                        .type     = EM28XX_VMUX_TELEVISION,
-                       .vmux     = 2,
+                       .vmux     = SAA7115_COMPOSITE2,
                        .amux     = 0,
                },{
                        .type     = EM28XX_VMUX_COMPOSITE1,
-                       .vmux     = 0,
+                       .vmux     = SAA7115_COMPOSITE0,
                        .amux     = 1,
                },{
                        .type     = EM28XX_VMUX_SVIDEO,
-                       .vmux     = 9,
+                       .vmux     = SAA7115_SVIDEO3,
                        .amux     = 1,
                }},
        },
@@ -234,15 +236,15 @@ struct em28xx_board em28xx_boards[] = {
                .decoder      = EM28XX_SAA7113,
                .input          = {{
                        .type     = EM28XX_VMUX_TELEVISION,
-                       .vmux     = 2,
+                       .vmux     = SAA7115_COMPOSITE2,
                        .amux     = 0,
                },{
                        .type     = EM28XX_VMUX_COMPOSITE1,
-                       .vmux     = 0,
+                       .vmux     = SAA7115_COMPOSITE0,
                        .amux     = 1,
                },{
                        .type     = EM28XX_VMUX_SVIDEO,
-                       .vmux     = 9,
+                       .vmux     = SAA7115_SVIDEO3,
                        .amux     = 1,
                }},
        },
@@ -254,11 +256,11 @@ struct em28xx_board em28xx_boards[] = {
                .decoder      = EM28XX_SAA7113,
                .input          = {{
                        .type     = EM28XX_VMUX_COMPOSITE1,
-                       .vmux     = 0,
+                       .vmux     = SAA7115_COMPOSITE0,
                        .amux     = 1,
                },{
                        .type     = EM28XX_VMUX_SVIDEO,
-                       .vmux     = 9,
+                       .vmux     = SAA7115_SVIDEO3,
                        .amux     = 1,
                }},
        },
@@ -324,8 +326,4 @@ void em28xx_card_setup(struct em28xx *dev)
        }
 }
 
-EXPORT_SYMBOL(em28xx_boards);
-EXPORT_SYMBOL(em28xx_bcount);
-EXPORT_SYMBOL(em28xx_id_table);
-
 MODULE_DEVICE_TABLE (usb, em28xx_id_table);
index e5ee8bceb210c19fa606fe7248dbbdbfbbc38d5a..4350cc75b025a0ffcf24252fb1af9d5517dad938 100644 (file)
@@ -3,7 +3,7 @@
 
    Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
                      Markus Rechberger <mrechberger@gmail.com>
-                     Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+                     Mauro Carvalho Chehab <mchehab@infradead.org>
                      Sascha Sommer <saschasommer@freenet.de>
 
    This program is free software; you can redistribute it and/or modify
@@ -317,8 +317,8 @@ int em28xx_outfmt_set_yuv422(struct em28xx *dev)
        return em28xx_write_regs(dev, VINCTRL_REG, "\x11", 1);
 }
 
-int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin,
-                                 u8 ymax)
+static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
+                                 u8 ymin, u8 ymax)
 {
        em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n", xmin, ymin, xmax, ymax);
 
@@ -328,7 +328,7 @@ int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin,
        return em28xx_write_regs(dev, YMAX_REG, &ymax, 1);
 }
 
-int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
                                   u16 width, u16 height)
 {
        u8 cwidth = width;
@@ -345,7 +345,7 @@ int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
        return em28xx_write_regs(dev, OFLOW_REG, &overflow, 1);
 }
 
-int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
+static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
 {
        u8 mode;
        /* the em2800 scaler only supports scaling down to 50% */
@@ -534,7 +534,7 @@ static inline void em28xx_isoc_video_copy(struct em28xx *dev,
  * em28xx_isoIrq()
  * handles the incoming isoc urbs and fills the frames from our inqueue
  */
-void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs)
+static void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs)
 {
        struct em28xx *dev = urb->context;
        int i, status;
index 5b6cece37aee9bebcd629f9b76474fd8190d7b96..d829d8f8c1f670a11f57f856f16f666069b08bda 100644 (file)
@@ -3,7 +3,7 @@
 
    Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
                      Markus Rechberger <mrechberger@gmail.com>
-                     Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+                     Mauro Carvalho Chehab <mchehab@infradead.org>
                      Sascha Sommer <saschasommer@freenet.de>
 
    This program is free software; you can redistribute it and/or modify
@@ -399,17 +399,6 @@ static u32 functionality(struct i2c_adapter *adap)
        return I2C_FUNC_SMBUS_EMUL;
 }
 
-#ifndef I2C_PEC
-static void inc_use(struct i2c_adapter *adap)
-{
-       MOD_INC_USE_COUNT;
-}
-
-static void dec_use(struct i2c_adapter *adap)
-{
-       MOD_DEC_USE_COUNT;
-}
-#endif
 
 static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client)
 {
@@ -436,9 +425,19 @@ static int attach_inform(struct i2c_client *client)
        struct em28xx *dev = client->adapter->algo_data;
 
        switch (client->addr << 1) {
-               case 0x86:
+               case 0x43:
+               case 0x4b:
+               {
+                       struct tuner_setup tun_setup;
+
+                       tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+                       tun_setup.type = TUNER_TDA9887;
+                       tun_setup.addr = client->addr;
+
+                       em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
                        em28xx_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf);
                        break;
+               }
                case 0x42:
                        dprintk1(1,"attach_inform: saa7114 detected.\n");
                        break;
@@ -464,6 +463,7 @@ static int attach_inform(struct i2c_client *client)
                case 0xba:
                        dprintk1(1,"attach_inform: tvp5150 detected.\n");
                        break;
+
                default:
                        dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
                        dev->tuner_addr = client->addr;
@@ -480,12 +480,7 @@ static struct i2c_algorithm em28xx_algo = {
 };
 
 static struct i2c_adapter em28xx_adap_template = {
-#ifdef I2C_PEC
        .owner = THIS_MODULE,
-#else
-       .inc_use = inc_use,
-       .dec_use = dec_use,
-#endif
        .class = I2C_CLASS_TV_ANALOG,
        .name = "em28xx",
        .id = I2C_HW_B_EM28XX,
index 31e89e4f18be5764200c57a76730e3bda95f93d5..3ffb5684f127ecaa3e9bc68584df8450370edaf0 100644 (file)
@@ -3,7 +3,7 @@
 
    Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
                      Markus Rechberger <mrechberger@gmail.com>
-                     Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+                     Mauro Carvalho Chehab <mchehab@infradead.org>
                      Sascha Sommer <saschasommer@freenet.de>
 
   This program is free software; you can redistribute it and/or modify
@@ -105,7 +105,7 @@ static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        return 1;
 }
 
-static int get_key_pinnacle_usb(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
        unsigned char buf[3];
 
@@ -148,8 +148,8 @@ void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir)
                snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Terratec)");
                break;
        case (EM2820_BOARD_PINNACLE_USB_2):
-               ir->ir_codes = ir_codes_em_pinnacle_usb;
-               ir->get_key = get_key_pinnacle_usb;
+               ir->ir_codes = ir_codes_pinnacle_grey;
+               ir->get_key = get_key_pinnacle_usb_grey;
                snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Pinnacle PCTV)");
                break;
        case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
index cf7cdf9ef6178e50f3cf1596bf65b856a5fa5df6..9286090817cd2d564d97a100fd8ceeb99789e4fe 100644 (file)
@@ -3,7 +3,7 @@
 
    Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
                      Markus Rechberger <mrechberger@gmail.com>
-                     Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+                     Mauro Carvalho Chehab <mchehab@infradead.org>
                      Sascha Sommer <saschasommer@freenet.de>
 
        Some parts based on SN9C10x PC Camera Controllers GPL driver made
@@ -42,7 +42,7 @@
 
 #define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
                      "Markus Rechberger <mrechberger@gmail.com>, " \
-                     "Mauro Carvalho Chehab <mchehab@brturbo.com.br>, " \
+                     "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
                      "Sascha Sommer <saschasommer@freenet.de>"
 
 #define DRIVER_NAME         "em28xx"
@@ -170,8 +170,12 @@ static int em28xx_config(struct em28xx *dev)
 static void em28xx_config_i2c(struct em28xx *dev)
 {
        struct v4l2_frequency f;
+       struct v4l2_routing route;
+
+       route.input = INPUT(dev->ctl_input)->vmux;
+       route.output = 0;
        em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL);
-       em28xx_i2c_call_clients(dev, VIDIOC_S_INPUT, &dev->ctl_input);
+       em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
        em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
 
        /* configure tuner */
@@ -206,19 +210,19 @@ static void em28xx_empty_framequeues(struct em28xx *dev)
 
 static void video_mux(struct em28xx *dev, int index)
 {
-       int input, ainput;
+       int ainput;
+       struct v4l2_routing route;
 
-       input = INPUT(index)->vmux;
+       route.input = INPUT(index)->vmux;
+       route.output = 0;
        dev->ctl_input = index;
        dev->ctl_ainput = INPUT(index)->amux;
 
-       em28xx_i2c_call_clients(dev, VIDIOC_S_INPUT, &input);
+       em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
 
-       em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput);
+       em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,route.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);
                route.input = dev->ctl_ainput;
index e1ddc2f27a2152df39dbe8f9af74749cb2bbdb31..d8fcc9e17ac004c47e35325eb1feda1812824180 100644 (file)
@@ -3,7 +3,7 @@
 
    Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
                      Ludovico Cavedon <cavedon@sssup.it>
-                     Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+                     Mauro Carvalho Chehab <mchehab@infradead.org>
 
    Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.de>
 
@@ -319,13 +319,7 @@ int em28xx_audio_analog_set(struct em28xx *dev);
 int em28xx_colorlevels_set_default(struct em28xx *dev);
 int em28xx_capture_start(struct em28xx *dev, int start);
 int em28xx_outfmt_set_yuv422(struct em28xx *dev);
-int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin,
-                          u8 ymax);
-int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
-                           u16 width, u16 height);
-int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v);
 int em28xx_resolution_set(struct em28xx *dev);
-void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs);
 int em28xx_init_isoc(struct em28xx *dev);
 void em28xx_uninit_isoc(struct em28xx *dev);
 int em28xx_set_alternate(struct em28xx *dev);
index dfc9dd732c9d0f817fb0554b77f49d03a857b0f2..8992b6e62b9f76ee9fa03068756633c7ac67e65f 100644 (file)
@@ -2341,11 +2341,9 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
        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);
 
@@ -2392,7 +2390,6 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
        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);
 
index 7e66d83fe0ce672f6fb4cc0b4b53e28246d5b186..fba30a40e9c6fface92fe3909314e64fefd39057 100644 (file)
@@ -150,12 +150,11 @@ static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        return 1;
 }
 
-/* The new pinnacle PCTV remote (with the colored buttons)
+/* Common (grey or coloured) pinnacle PCTV remote handling
  *
- * Ricardo Cerqueira <v4l@cerqueira.org>
  */
-
-int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
+                           int parity_offset, int marker, int code_modulo)
 {
        unsigned char b[4];
        unsigned int start = 0,parity = 0,code = 0;
@@ -167,9 +166,9 @@ int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        }
 
        for (start = 0; start<4; start++) {
-               if (b[start] == 0x80) {
-                       code=b[(start+3)%4];
-                       parity=b[(start+2)%4];
+               if (b[start] == marker) {
+                       code=b[(start+parity_offset+1)%4];
+                       parity=b[(start+parity_offset)%4];
                }
        }
 
@@ -181,16 +180,14 @@ int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        if (ir->old == parity)
                return 0;
 
-
        ir->old = parity;
 
-       /* Reduce code value to fit inside IR_KEYTAB_SIZE
-        *
-        * this is the only value that results in 42 unique
-        * codes < 128
-        */
+       /* drop special codes when a key is held down a long time for the grey controller
+          In this case, the second bit of the code is asserted */
+       if (marker == 0xfe && (code & 0x40))
+               return 0;
 
-       code %= 0x88;
+       code %= code_modulo;
 
        *ir_raw = code;
        *ir_key = code;
@@ -200,7 +197,40 @@ int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        return 1;
 }
 
-EXPORT_SYMBOL_GPL(get_key_pinnacle);
+/* The grey pinnacle PCTV remote
+ *
+ *  There are one issue with this remote:
+ *   - I2c packet does not change when the same key is pressed quickly. The workaround
+ *     is to hold down each key for about half a second, so that another code is generated
+ *     in the i2c packet, and the function can distinguish key presses.
+ *
+ * Sylvain Pasche <sylvain.pasche@gmail.com>
+ */
+int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+
+       return get_key_pinnacle(ir, ir_key, ir_raw, 1, 0xfe, 0xff);
+}
+
+EXPORT_SYMBOL_GPL(get_key_pinnacle_grey);
+
+
+/* The new pinnacle PCTV remote (with the colored buttons)
+ *
+ * Ricardo Cerqueira <v4l@cerqueira.org>
+ */
+int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+       /* code_modulo parameter (0x88) is used to reduce code value to fit inside IR_KEYTAB_SIZE
+        *
+        * this is the only value that results in 42 unique
+        * codes < 128
+        */
+
+       return get_key_pinnacle(ir, ir_key, ir_raw, 2, 0x80, 0x88);
+}
+
+EXPORT_SYMBOL_GPL(get_key_pinnacle_color);
 
 /* ----------------------------------------------------------------------- */
 
diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c
new file mode 100644 (file)
index 0000000..3bf7ac4
--- /dev/null
@@ -0,0 +1,846 @@
+/*
+ * Video Capture Driver (Video for Linux 1/2)
+ * for the Matrox Marvel G200,G400 and Rainbow Runner-G series
+ *
+ * This module is an interface to the KS0127 video decoder chip.
+ *
+ * Copyright (C) 1999  Ryan Drake <stiletto@mediaone.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ *****************************************************************************
+ *
+ * Modified and extended by
+ *     Mike Bernson <mike@mlb.org>
+ *     Gerard v.d. Horst
+ *     Leon van Stuivenberg <l.vanstuivenberg@chello.nl>
+ *     Gernot Ziegler <gz@lysator.liu.se>
+ *
+ * Version History:
+ * V1.0 Ryan Drake        Initial version by Ryan Drake
+ * V1.1 Gerard v.d. Horst  Added some debugoutput, reset the video-standard
+ */
+
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include "ks0127.h"
+
+#include <linux/i2c.h>
+#include <linux/video_decoder.h>
+
+#define dprintk     if (debug) printk
+
+/* i2c identification */
+#define I2C_KS0127_ADDON   0xD8
+#define I2C_KS0127_ONBOARD 0xDA
+
+#define KS_TYPE_UNKNOWN        0
+#define KS_TYPE_0122S  1
+#define KS_TYPE_0127   2
+#define KS_TYPE_0127B  3
+
+/* ks0127 control registers */
+#define KS_STAT     0x00
+#define KS_CMDA     0x01
+#define KS_CMDB     0x02
+#define KS_CMDC     0x03
+#define KS_CMDD     0x04
+#define KS_HAVB     0x05
+#define KS_HAVE     0x06
+#define KS_HS1B     0x07
+#define KS_HS1E     0x08
+#define KS_HS2B     0x09
+#define KS_HS2E     0x0a
+#define KS_AGC      0x0b
+#define KS_HXTRA    0x0c
+#define KS_CDEM     0x0d
+#define KS_PORTAB   0x0e
+#define KS_LUMA     0x0f
+#define KS_CON      0x10
+#define KS_BRT      0x11
+#define KS_CHROMA   0x12
+#define KS_CHROMB   0x13
+#define KS_DEMOD    0x14
+#define KS_SAT      0x15
+#define KS_HUE      0x16
+#define KS_VERTIA   0x17
+#define KS_VERTIB   0x18
+#define KS_VERTIC   0x19
+#define KS_HSCLL    0x1a
+#define KS_HSCLH    0x1b
+#define KS_VSCLL    0x1c
+#define KS_VSCLH    0x1d
+#define KS_OFMTA    0x1e
+#define KS_OFMTB    0x1f
+#define KS_VBICTL   0x20
+#define KS_CCDAT2   0x21
+#define KS_CCDAT1   0x22
+#define KS_VBIL30   0x23
+#define KS_VBIL74   0x24
+#define KS_VBIL118  0x25
+#define KS_VBIL1512 0x26
+#define KS_TTFRAM   0x27
+#define KS_TESTA    0x28
+#define KS_UVOFFH   0x29
+#define KS_UVOFFL   0x2a
+#define KS_UGAIN    0x2b
+#define KS_VGAIN    0x2c
+#define KS_VAVB     0x2d
+#define KS_VAVE     0x2e
+#define KS_CTRACK   0x2f
+#define KS_POLCTL   0x30
+#define KS_REFCOD   0x31
+#define KS_INVALY   0x32
+#define KS_INVALU   0x33
+#define KS_INVALV   0x34
+#define KS_UNUSEY   0x35
+#define KS_UNUSEU   0x36
+#define KS_UNUSEV   0x37
+#define KS_USRSAV   0x38
+#define KS_USREAV   0x39
+#define KS_SHS1A    0x3a
+#define KS_SHS1B    0x3b
+#define KS_SHS1C    0x3c
+#define KS_CMDE     0x3d
+#define KS_VSDEL    0x3e
+#define KS_CMDF     0x3f
+#define KS_GAMMA0   0x40
+#define KS_GAMMA1   0x41
+#define KS_GAMMA2   0x42
+#define KS_GAMMA3   0x43
+#define KS_GAMMA4   0x44
+#define KS_GAMMA5   0x45
+#define KS_GAMMA6   0x46
+#define KS_GAMMA7   0x47
+#define KS_GAMMA8   0x48
+#define KS_GAMMA9   0x49
+#define KS_GAMMA10  0x4a
+#define KS_GAMMA11  0x4b
+#define KS_GAMMA12  0x4c
+#define KS_GAMMA13  0x4d
+#define KS_GAMMA14  0x4e
+#define KS_GAMMA15  0x4f
+#define KS_GAMMA16  0x50
+#define KS_GAMMA17  0x51
+#define KS_GAMMA18  0x52
+#define KS_GAMMA19  0x53
+#define KS_GAMMA20  0x54
+#define KS_GAMMA21  0x55
+#define KS_GAMMA22  0x56
+#define KS_GAMMA23  0x57
+#define KS_GAMMA24  0x58
+#define KS_GAMMA25  0x59
+#define KS_GAMMA26  0x5a
+#define KS_GAMMA27  0x5b
+#define KS_GAMMA28  0x5c
+#define KS_GAMMA29  0x5d
+#define KS_GAMMA30  0x5e
+#define KS_GAMMA31  0x5f
+#define KS_GAMMAD0  0x60
+#define KS_GAMMAD1  0x61
+#define KS_GAMMAD2  0x62
+#define KS_GAMMAD3  0x63
+#define KS_GAMMAD4  0x64
+#define KS_GAMMAD5  0x65
+#define KS_GAMMAD6  0x66
+#define KS_GAMMAD7  0x67
+#define KS_GAMMAD8  0x68
+#define KS_GAMMAD9  0x69
+#define KS_GAMMAD10 0x6a
+#define KS_GAMMAD11 0x6b
+#define KS_GAMMAD12 0x6c
+#define KS_GAMMAD13 0x6d
+#define KS_GAMMAD14 0x6e
+#define KS_GAMMAD15 0x6f
+#define KS_GAMMAD16 0x70
+#define KS_GAMMAD17 0x71
+#define KS_GAMMAD18 0x72
+#define KS_GAMMAD19 0x73
+#define KS_GAMMAD20 0x74
+#define KS_GAMMAD21 0x75
+#define KS_GAMMAD22 0x76
+#define KS_GAMMAD23 0x77
+#define KS_GAMMAD24 0x78
+#define KS_GAMMAD25 0x79
+#define KS_GAMMAD26 0x7a
+#define KS_GAMMAD27 0x7b
+#define KS_GAMMAD28 0x7c
+#define KS_GAMMAD29 0x7d
+#define KS_GAMMAD30 0x7e
+#define KS_GAMMAD31 0x7f
+
+
+/****************************************************************************
+* mga_dev : represents one ks0127 chip.
+****************************************************************************/
+
+struct adjust {
+       int     contrast;
+       int     bright;
+       int     hue;
+       int     ugain;
+       int     vgain;
+};
+
+struct ks0127 {
+       struct i2c_client *client;
+       unsigned char   addr;
+       int             format_width;
+       int             format_height;
+       int             cap_width;
+       int             cap_height;
+       int             norm;
+       int             ks_type;
+       u8              regs[256];
+};
+
+
+static int debug; /* insmod parameter */
+
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug output");
+MODULE_LICENSE("GPL");
+
+static u8 reg_defaults[64];
+
+
+
+static void init_reg_defaults(void)
+{
+       u8 *table = reg_defaults;
+
+       table[KS_CMDA]     = 0x2c;  /* VSE=0, CCIR 601, autodetect standard */
+       table[KS_CMDB]     = 0x12;  /* VALIGN=0, AGC control and input */
+       table[KS_CMDC]     = 0x00;  /* Test options */
+       /* clock & input select, write 1 to PORTA */
+       table[KS_CMDD]     = 0x01;
+       table[KS_HAVB]     = 0x00;  /* HAV Start Control */
+       table[KS_HAVE]     = 0x00;  /* HAV End Control */
+       table[KS_HS1B]     = 0x10;  /* HS1 Start Control */
+       table[KS_HS1E]     = 0x00;  /* HS1 End Control */
+       table[KS_HS2B]     = 0x00;  /* HS2 Start Control */
+       table[KS_HS2E]     = 0x00;  /* HS2 End Control */
+       table[KS_AGC]      = 0x53;  /* Manual setting for AGC */
+       table[KS_HXTRA]    = 0x00;  /* Extra Bits for HAV and HS1/2 */
+       table[KS_CDEM]     = 0x00;  /* Chroma Demodulation Control */
+       table[KS_PORTAB]   = 0x0f;  /* port B is input, port A output GPPORT */
+       table[KS_LUMA]     = 0x01;  /* Luma control */
+       table[KS_CON]      = 0x00;  /* Contrast Control */
+       table[KS_BRT]      = 0x00;  /* Brightness Control */
+       table[KS_CHROMA]   = 0x2a;  /* Chroma control A */
+       table[KS_CHROMB]   = 0x90;  /* Chroma control B */
+       table[KS_DEMOD]    = 0x00;  /* Chroma Demodulation Control & Status */
+       table[KS_SAT]      = 0x00;  /* Color Saturation Control*/
+       table[KS_HUE]      = 0x00;  /* Hue Control */
+       table[KS_VERTIA]   = 0x00;  /* Vertical Processing Control A */
+       /* Vertical Processing Control B, luma 1 line delayed */
+       table[KS_VERTIB]   = 0x12;
+       table[KS_VERTIC]   = 0x0b;  /* Vertical Processing Control C */
+       table[KS_HSCLL]    = 0x00;  /* Horizontal Scaling Ratio Low */
+       table[KS_HSCLH]    = 0x00;  /* Horizontal Scaling Ratio High */
+       table[KS_VSCLL]    = 0x00;  /* Vertical Scaling Ratio Low */
+       table[KS_VSCLH]    = 0x00;  /* Vertical Scaling Ratio High */
+       /* 16 bit YCbCr 4:2:2 output; I can't make the bt866 like 8 bit /Sam */
+       table[KS_OFMTA]    = 0x30;
+       table[KS_OFMTB]    = 0x00;  /* Output Control B */
+       /* VBI Decoder Control; 4bit fmt: avoid Y overflow */
+       table[KS_VBICTL]   = 0x5d;
+       table[KS_CCDAT2]   = 0x00;  /* Read Only register */
+       table[KS_CCDAT1]   = 0x00;  /* Read Only register */
+       table[KS_VBIL30]   = 0xa8;  /* VBI data decoding options */
+       table[KS_VBIL74]   = 0xaa;  /* VBI data decoding options */
+       table[KS_VBIL118]  = 0x2a;  /* VBI data decoding options */
+       table[KS_VBIL1512] = 0x00;  /* VBI data decoding options */
+       table[KS_TTFRAM]   = 0x00;  /* Teletext frame alignment pattern */
+       table[KS_TESTA]    = 0x00;  /* test register, shouldn't be written */
+       table[KS_UVOFFH]   = 0x00;  /* UV Offset Adjustment High */
+       table[KS_UVOFFL]   = 0x00;  /* UV Offset Adjustment Low */
+       table[KS_UGAIN]    = 0x00;  /* U Component Gain Adjustment */
+       table[KS_VGAIN]    = 0x00;  /* V Component Gain Adjustment */
+       table[KS_VAVB]     = 0x07;  /* VAV Begin */
+       table[KS_VAVE]     = 0x00;  /* VAV End */
+       table[KS_CTRACK]   = 0x00;  /* Chroma Tracking Control */
+       table[KS_POLCTL]   = 0x41;  /* Timing Signal Polarity Control */
+       table[KS_REFCOD]   = 0x80;  /* Reference Code Insertion Control */
+       table[KS_INVALY]   = 0x10;  /* Invalid Y Code */
+       table[KS_INVALU]   = 0x80;  /* Invalid U Code */
+       table[KS_INVALV]   = 0x80;  /* Invalid V Code */
+       table[KS_UNUSEY]   = 0x10;  /* Unused Y Code */
+       table[KS_UNUSEU]   = 0x80;  /* Unused U Code */
+       table[KS_UNUSEV]   = 0x80;  /* Unused V Code */
+       table[KS_USRSAV]   = 0x00;  /* reserved */
+       table[KS_USREAV]   = 0x00;  /* reserved */
+       table[KS_SHS1A]    = 0x00;  /* User Defined SHS1 A */
+       /* User Defined SHS1 B, ALT656=1 on 0127B */
+       table[KS_SHS1B]    = 0x80;
+       table[KS_SHS1C]    = 0x00;  /* User Defined SHS1 C */
+       table[KS_CMDE]     = 0x00;  /* Command Register E */
+       table[KS_VSDEL]    = 0x00;  /* VS Delay Control */
+       /* Command Register F, update -immediately- */
+       /* (there might come no vsync)*/
+       table[KS_CMDF]     = 0x02;
+}
+
+
+/* We need to manually read because of a bug in the KS0127 chip.
+ *
+ * An explanation from kayork@mail.utexas.edu:
+ *
+ * During I2C reads, the KS0127 only samples for a stop condition
+ * during the place where the acknoledge bit should be. Any standard
+ * I2C implementation (correctly) throws in another clock transition
+ * at the 9th bit, and the KS0127 will not recognize the stop condition
+ * and will continue to clock out data.
+ *
+ * So we have to do the read ourself.  Big deal.
+          workaround in i2c-algo-bit
+ */
+
+
+static u8 ks0127_read(struct ks0127 *ks, u8 reg)
+{
+       struct i2c_client *c = ks->client;
+       char val = 0;
+       struct i2c_msg msgs[] = {
+               {c->addr, 0, sizeof(reg), &reg},
+               {c->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val}};
+       int ret;
+
+       ret = i2c_transfer(c->adapter, msgs, ARRAY_SIZE(msgs));
+       if (ret != ARRAY_SIZE(msgs))
+               dprintk("ks0127_write error\n");
+
+       return val;
+}
+
+
+static void ks0127_write(struct ks0127 *ks, u8 reg, u8 val)
+{
+       char msg[] = {reg, val};
+
+       if (i2c_master_send(ks->client, msg, sizeof(msg)) != sizeof(msg))
+               dprintk("ks0127_write error\n");
+
+       ks->regs[reg] = val;
+}
+
+
+/* generic bit-twiddling */
+static void ks0127_and_or(struct ks0127 *ks, u8 reg, u8 and_v, u8 or_v)
+{
+       u8 val = ks->regs[reg];
+       val = (val & and_v) | or_v;
+       ks0127_write(ks, reg, val);
+}
+
+
+
+/****************************************************************************
+* ks0127 private api
+****************************************************************************/
+static void ks0127_reset(struct ks0127* ks)
+{
+       int i;
+       u8 *table = reg_defaults;
+
+       ks->ks_type = KS_TYPE_UNKNOWN;
+
+       dprintk("ks0127: reset\n");
+       msleep(1);
+
+       /* initialize all registers to known values */
+       /* (except STAT, 0x21, 0x22, TEST and 0x38,0x39) */
+
+       for(i = 1; i < 33; i++)
+               ks0127_write(ks, i, table[i]);
+
+       for(i = 35; i < 40; i++)
+               ks0127_write(ks, i, table[i]);
+
+       for(i = 41; i < 56; i++)
+               ks0127_write(ks, i, table[i]);
+
+       for(i = 58; i < 64; i++)
+               ks0127_write(ks, i, table[i]);
+
+
+       if ((ks0127_read(ks, KS_STAT) & 0x80) == 0) {
+               ks->ks_type = KS_TYPE_0122S;
+               dprintk("ks0127: ks0122s Found\n");
+               return;
+       }
+
+       switch(ks0127_read(ks, KS_CMDE) & 0x0f) {
+
+       case 0:
+               ks->ks_type = KS_TYPE_0127;
+               dprintk("ks0127: ks0127 found\n");
+               break;
+
+       case 9:
+               ks->ks_type = KS_TYPE_0127B;
+               dprintk("ks0127: ks0127B Revision A found\n");
+               break;
+
+       default:
+               dprintk("ks0127: unknown revision\n");
+               break;
+       }
+}
+
+static int ks0127_command(struct i2c_client *client,
+                         unsigned int cmd, void *arg)
+{
+       struct ks0127 *ks = i2c_get_clientdata(client);
+
+       int             *iarg = (int*)arg;
+
+       int             status;
+
+       if (!ks)
+               return -ENODEV;
+
+       switch (cmd) {
+
+       case DECODER_INIT:
+               dprintk("ks0127: command DECODER_INIT\n");
+               ks0127_reset(ks);
+               break;
+
+       case DECODER_SET_INPUT:
+               switch(*iarg) {
+               case KS_INPUT_COMPOSITE_1:
+               case KS_INPUT_COMPOSITE_2:
+               case KS_INPUT_COMPOSITE_3:
+               case KS_INPUT_COMPOSITE_4:
+               case KS_INPUT_COMPOSITE_5:
+               case KS_INPUT_COMPOSITE_6:
+                       dprintk("ks0127: command DECODER_SET_INPUT %d: "
+                               "Composite\n", *iarg);
+                       /* autodetect 50/60 Hz */
+                       ks0127_and_or(ks, KS_CMDA,   0xfc, 0x00);
+                       /* VSE=0 */
+                       ks0127_and_or(ks, KS_CMDA,   ~0x40, 0x00);
+                       /* set input line */
+                       ks0127_and_or(ks, KS_CMDB,   0xb0, *iarg);
+                       /* non-freerunning mode */
+                       ks0127_and_or(ks, KS_CMDC,   0x70, 0x0a);
+                       /* analog input */
+                       ks0127_and_or(ks, KS_CMDD,   0x03, 0x00);
+                       /* enable chroma demodulation */
+                       ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x00);
+                       /* chroma trap, HYBWR=1 */
+                       ks0127_and_or(ks, KS_LUMA,   0x00,
+                                      (reg_defaults[KS_LUMA])|0x0c);
+                       /* scaler fullbw, luma comb off */
+                       ks0127_and_or(ks, KS_VERTIA, 0x08, 0x81);
+                       /* manual chroma comb .25 .5 .25 */
+                       ks0127_and_or(ks, KS_VERTIC, 0x0f, 0x90);
+
+                       /* chroma path delay */
+                       ks0127_and_or(ks, KS_CHROMB, 0x0f, 0x90);
+
+                       ks0127_write(ks, KS_UGAIN, reg_defaults[KS_UGAIN]);
+                       ks0127_write(ks, KS_VGAIN, reg_defaults[KS_VGAIN]);
+                       ks0127_write(ks, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+                       ks0127_write(ks, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+                       break;
+
+               case KS_INPUT_SVIDEO_1:
+               case KS_INPUT_SVIDEO_2:
+               case KS_INPUT_SVIDEO_3:
+                       dprintk("ks0127: command DECODER_SET_INPUT %d: "
+                               "S-Video\n", *iarg);
+                       /* autodetect 50/60 Hz */
+                       ks0127_and_or(ks, KS_CMDA,   0xfc, 0x00);
+                       /* VSE=0 */
+                       ks0127_and_or(ks, KS_CMDA,   ~0x40, 0x00);
+                       /* set input line */
+                       ks0127_and_or(ks, KS_CMDB,   0xb0, *iarg);
+                       /* non-freerunning mode */
+                       ks0127_and_or(ks, KS_CMDC,   0x70, 0x0a);
+                       /* analog input */
+                       ks0127_and_or(ks, KS_CMDD,   0x03, 0x00);
+                       /* enable chroma demodulation */
+                       ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x00);
+                       ks0127_and_or(ks, KS_LUMA, 0x00,
+                                      reg_defaults[KS_LUMA]);
+                       /* disable luma comb */
+                       ks0127_and_or(ks, KS_VERTIA, 0x08,
+                                      (reg_defaults[KS_VERTIA]&0xf0)|0x01);
+                       ks0127_and_or(ks, KS_VERTIC, 0x0f,
+                                      reg_defaults[KS_VERTIC]&0xf0);
+
+                       ks0127_and_or(ks, KS_CHROMB, 0x0f,
+                                      reg_defaults[KS_CHROMB]&0xf0);
+
+                       ks0127_write(ks, KS_UGAIN, reg_defaults[KS_UGAIN]);
+                       ks0127_write(ks, KS_VGAIN, reg_defaults[KS_VGAIN]);
+                       ks0127_write(ks, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+                       ks0127_write(ks, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+                       break;
+
+               case KS_INPUT_YUV656:
+                       dprintk("ks0127: command DECODER_SET_INPUT 15: "
+                               "YUV656\n");
+                       if (ks->norm == VIDEO_MODE_NTSC ||
+                           ks->norm == KS_STD_PAL_M)
+                               /* force 60 Hz */
+                               ks0127_and_or(ks, KS_CMDA,   0xfc, 0x03);
+                       else
+                               /* force 50 Hz */
+                               ks0127_and_or(ks, KS_CMDA,   0xfc, 0x02);
+
+                       ks0127_and_or(ks, KS_CMDA,   0xff, 0x40); /* VSE=1 */
+                       /* set input line and VALIGN */
+                       ks0127_and_or(ks, KS_CMDB,   0xb0, (*iarg | 0x40));
+                       /* freerunning mode, */
+                       /* TSTGEN = 1 TSTGFR=11 TSTGPH=0 TSTGPK=0  VMEM=1*/
+                       ks0127_and_or(ks, KS_CMDC,   0x70, 0x87);
+                       /* digital input, SYNDIR = 0 INPSL=01 CLKDIR=0 EAV=0 */
+                       ks0127_and_or(ks, KS_CMDD,   0x03, 0x08);
+                       /* disable chroma demodulation */
+                       ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x30);
+                       /* HYPK =01 CTRAP = 0 HYBWR=0 PED=1 RGBH=1 UNIT=1 */
+                       ks0127_and_or(ks, KS_LUMA,   0x00, 0x71);
+                       ks0127_and_or(ks, KS_VERTIC, 0x0f,
+                                      reg_defaults[KS_VERTIC]&0xf0);
+
+                       /* scaler fullbw, luma comb off */
+                       ks0127_and_or(ks, KS_VERTIA, 0x08, 0x81);
+
+                       ks0127_and_or(ks, KS_CHROMB, 0x0f,
+                                      reg_defaults[KS_CHROMB]&0xf0);
+
+                       ks0127_and_or(ks, KS_CON, 0x00, 0x00);
+                       ks0127_and_or(ks, KS_BRT, 0x00, 32);    /* spec: 34 */
+                               /* spec: 229 (e5) */
+                       ks0127_and_or(ks, KS_SAT, 0x00, 0xe8);
+                       ks0127_and_or(ks, KS_HUE, 0x00, 0);
+
+                       ks0127_and_or(ks, KS_UGAIN, 0x00, 238);
+                       ks0127_and_or(ks, KS_VGAIN, 0x00, 0x00);
+
+                       /*UOFF:0x30, VOFF:0x30, TSTCGN=1 */
+                       ks0127_and_or(ks, KS_UVOFFH, 0x00, 0x4f);
+                       ks0127_and_or(ks, KS_UVOFFL, 0x00, 0x00);
+                       break;
+
+               default:
+                       dprintk("ks0127: command DECODER_SET_INPUT: "
+                               "Unknown input %d\n", *iarg);
+                       break;
+               }
+
+               /* hack: CDMLPF sometimes spontaneously switches on; */
+               /* force back off */
+               ks0127_write(ks, KS_DEMOD, reg_defaults[KS_DEMOD]);
+               break;
+
+       case DECODER_SET_OUTPUT:
+               switch(*iarg) {
+               case KS_OUTPUT_YUV656E:
+                       dprintk("ks0127: command DECODER_SET_OUTPUT: "
+                               "OUTPUT_YUV656E (Missing)\n");
+                       return -EINVAL;
+                       break;
+
+               case KS_OUTPUT_EXV:
+                       dprintk("ks0127: command DECODER_SET_OUTPUT: "
+                               "OUTPUT_EXV\n");
+                       ks0127_and_or(ks, KS_OFMTA, 0xf0, 0x09);
+                       break;
+               }
+               break;
+
+       case DECODER_SET_NORM: //sam This block mixes old and new norm names...
+               /* Set to automatic SECAM/Fsc mode */
+               ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x00);
+
+               ks->norm = *iarg;
+               switch(*iarg)
+               {
+               /* this is untested !! */
+               /* It just detects PAL_N/NTSC_M (no special frequencies) */
+               /* And you have to set the standard a second time afterwards */
+               case VIDEO_MODE_AUTO:
+                       dprintk("ks0127: command DECODER_SET_NORM: AUTO\n");
+
+                       /* The chip determines the format */
+                       /* based on the current field rate */
+                       ks0127_and_or(ks, KS_CMDA,   0xfc, 0x00);
+                       ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+                       /* This is wrong for PAL ! As I said, */
+                       /* you need to set the standard once again !! */
+                       ks->format_height = 240;
+                       ks->format_width = 704;
+                       break;
+
+               case VIDEO_MODE_NTSC:
+                       dprintk("ks0127: command DECODER_SET_NORM: NTSC_M\n");
+                       ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+                       ks->format_height = 240;
+                       ks->format_width = 704;
+                       break;
+
+               case KS_STD_NTSC_N:
+                       dprintk("ks0127: command KS0127_SET_STANDARD: "
+                               "NTSC_N (fixme)\n");
+                       ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x40);
+                       ks->format_height = 240;
+                       ks->format_width = 704;
+                       break;
+
+               case VIDEO_MODE_PAL:
+                       dprintk("ks0127: command DECODER_SET_NORM: PAL_N\n");
+                       ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+                       ks->format_height = 290;
+                       ks->format_width = 704;
+                       break;
+
+               case KS_STD_PAL_M:
+                       dprintk("ks0127: command KS0127_SET_STANDARD: "
+                               "PAL_M (fixme)\n");
+                       ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x40);
+                       ks->format_height = 290;
+                       ks->format_width = 704;
+                       break;
+
+               case VIDEO_MODE_SECAM:
+                       dprintk("ks0127: command KS0127_SET_STANDARD: "
+                               "SECAM\n");
+                       ks->format_height = 290;
+                       ks->format_width = 704;
+
+                       /* set to secam autodetection */
+                       ks0127_and_or(ks, KS_CHROMA, 0xdf, 0x20);
+                       ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x00);
+                       schedule_timeout_interruptible(HZ/10+1);
+
+                       /* did it autodetect? */
+                       if (ks0127_read(ks, KS_DEMOD) & 0x40)
+                               break;
+
+                       /* force to secam mode */
+                       ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x0f);
+                       break;
+
+               default:
+                       dprintk("ks0127: command DECODER_SET_NORM: "
+                               "Unknown norm %d\n", *iarg);
+                       break;
+               }
+               break;
+
+       case DECODER_SET_PICTURE:
+               dprintk("ks0127: command DECODER_SET_PICTURE "
+                       "not yet supported (fixme)\n");
+               return -EINVAL;
+
+       //sam todo: KS0127_SET_BRIGHTNESS: Merge into DECODER_SET_PICTURE
+       //sam todo: KS0127_SET_CONTRAST: Merge into DECODER_SET_PICTURE
+       //sam todo: KS0127_SET_HUE: Merge into DECODER_SET_PICTURE?
+       //sam todo: KS0127_SET_SATURATION: Merge into DECODER_SET_PICTURE
+       //sam todo: KS0127_SET_AGC_MODE:
+       //sam todo: KS0127_SET_AGC:
+       //sam todo: KS0127_SET_CHROMA_MODE:
+       //sam todo: KS0127_SET_PIXCLK_MODE:
+       //sam todo: KS0127_SET_GAMMA_MODE:
+       //sam todo: KS0127_SET_UGAIN:
+       //sam todo: KS0127_SET_VGAIN:
+       //sam todo: KS0127_SET_INVALY:
+       //sam todo: KS0127_SET_INVALU:
+       //sam todo: KS0127_SET_INVALV:
+       //sam todo: KS0127_SET_UNUSEY:
+       //sam todo: KS0127_SET_UNUSEU:
+       //sam todo: KS0127_SET_UNUSEV:
+       //sam todo: KS0127_SET_VSALIGN_MODE:
+
+       case DECODER_ENABLE_OUTPUT:
+       {
+
+               int *iarg = arg;
+               int enable = (*iarg != 0);
+                       if (enable) {
+                               dprintk("ks0127: command "
+                                       "DECODER_ENABLE_OUTPUT on "
+                                       "(%d)\n", enable);
+                               /* All output pins on */
+                               ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30);
+                               /* Obey the OEN pin */
+                               ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00);
+                       } else {
+                               dprintk("ks0127: command "
+                                       "DECODER_ENABLE_OUTPUT off "
+                                       "(%d)\n", enable);
+                               /* Video output pins off */
+                               ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00);
+                               /* Ignore the OEN pin */
+                               ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80);
+                       }
+       }
+               break;
+
+       //sam todo: KS0127_SET_OUTPUT_MODE:
+       //sam todo: KS0127_SET_WIDTH:
+       //sam todo: KS0127_SET_HEIGHT:
+       //sam todo: KS0127_SET_HSCALE:
+
+       case DECODER_GET_STATUS:
+               dprintk("ks0127: command DECODER_GET_STATUS\n");
+               *iarg = 0;
+               status = ks0127_read(ks, KS_STAT);
+               if (!(status & 0x20))            /* NOVID not set */
+                       *iarg = (*iarg & DECODER_STATUS_GOOD);
+               if ((status & 0x01))                  /* CLOCK set */
+                       *iarg = (*iarg & DECODER_STATUS_COLOR);
+               if ((status & 0x08))               /* PALDET set */
+                       *iarg = (*iarg & DECODER_STATUS_PAL);
+               else
+                       *iarg = (*iarg & DECODER_STATUS_NTSC);
+               break;
+
+       //Catch any unknown command
+       default:
+               dprintk("ks0127: command unknown: %04X\n", cmd);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+
+
+
+static int ks0127_probe(struct i2c_adapter *adapter);
+static int ks0127_detach(struct i2c_client *client);
+static int ks0127_command(struct i2c_client *client,
+                         unsigned int cmd, void *arg);
+
+
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {I2C_KS0127_ADDON>>1,
+                                      I2C_KS0127_ONBOARD>>1, I2C_CLIENT_END};
+static unsigned short probe[2] =       {I2C_CLIENT_END, I2C_CLIENT_END};
+static unsigned short ignore[2] =      {I2C_CLIENT_END, I2C_CLIENT_END};
+static struct i2c_client_address_data addr_data = {
+       normal_i2c,
+       probe,
+       ignore,
+};
+
+static struct i2c_driver i2c_driver_ks0127 = {
+       .driver.name = "ks0127",
+       .id             = I2C_DRIVERID_KS0127,
+       .attach_adapter = ks0127_probe,
+       .detach_client  = ks0127_detach,
+       .command        = ks0127_command
+};
+
+static struct i2c_client ks0127_client_tmpl =
+{
+       .name = "(ks0127 unset)",
+       .addr = 0,
+       .adapter = NULL,
+       .driver = &i2c_driver_ks0127,
+       .usage_count = 0
+};
+
+static int ks0127_found_proc(struct i2c_adapter *adapter, int addr, int kind)
+{
+       struct ks0127 *ks;
+       struct i2c_client *client;
+
+       client = kzalloc(sizeof(*client), GFP_KERNEL);
+       if (client == NULL)
+               return -ENOMEM;
+       memcpy(client, &ks0127_client_tmpl, sizeof(*client));
+
+       ks = kzalloc(sizeof(*ks), GFP_KERNEL);
+       if (ks == NULL) {
+               kfree(client);
+               return -ENOMEM;
+       }
+
+       i2c_set_clientdata(client, ks);
+       client->adapter = adapter;
+       client->addr = addr;
+       sprintf(client->name, "ks0127-%02x", adapter->id);
+
+       ks->client = client;
+       ks->addr = addr;
+       ks->ks_type = KS_TYPE_UNKNOWN;
+
+       /* power up */
+       ks0127_write(ks, KS_CMDA, 0x2c);
+       mdelay(10);
+
+       /* reset the device */
+       ks0127_reset(ks);
+       printk(KERN_INFO "ks0127: attach: %s video decoder\n",
+              ks->addr==(I2C_KS0127_ADDON>>1) ? "addon" : "on-board");
+
+       i2c_attach_client(client);
+       return 0;
+}
+
+
+static int ks0127_probe(struct i2c_adapter *adapter)
+{
+       if (adapter->id == I2C_HW_B_ZR36067)
+               return i2c_probe(adapter, &addr_data, ks0127_found_proc);
+       return 0;
+}
+
+static int ks0127_detach(struct i2c_client *client)
+{
+       struct ks0127 *ks = i2c_get_clientdata(client);
+
+       ks0127_write(ks, KS_OFMTA, 0x20); /*tristate*/
+       ks0127_write(ks, KS_CMDA, 0x2c | 0x80); /* power down */
+
+       i2c_detach_client(client);
+       kfree(ks);
+       kfree(client);
+
+       dprintk("ks0127: detach\n");
+       return 0;
+}
+
+
+static int __devinit ks0127_init_module(void)
+{
+       init_reg_defaults();
+       i2c_add_driver(&i2c_driver_ks0127);
+       return 0;
+}
+
+static void __devexit ks0127_cleanup_module(void)
+{
+       i2c_del_driver(&i2c_driver_ks0127);
+}
+
+
+module_init(ks0127_init_module);
+module_exit(ks0127_cleanup_module);
diff --git a/drivers/media/video/ks0127.h b/drivers/media/video/ks0127.h
new file mode 100644 (file)
index 0000000..1ec5788
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Video Capture Driver ( Video for Linux 1/2 )
+ * for the Matrox Marvel G200,G400 and Rainbow Runner-G series
+ *
+ * This module is an interface to the KS0127 video decoder chip.
+ *
+ * Copyright (C) 1999  Ryan Drake <stiletto@mediaone.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef KS0127_H
+#define KS0127_H
+
+#include <linux/videodev.h>
+
+/* input channels */
+#define KS_INPUT_COMPOSITE_1    0
+#define KS_INPUT_COMPOSITE_2    1
+#define KS_INPUT_COMPOSITE_3    2
+#define KS_INPUT_COMPOSITE_4    4
+#define KS_INPUT_COMPOSITE_5    5
+#define KS_INPUT_COMPOSITE_6    6
+
+#define KS_INPUT_SVIDEO_1       8
+#define KS_INPUT_SVIDEO_2       9
+#define KS_INPUT_SVIDEO_3       10
+
+#define KS_INPUT_YUV656                15
+#define KS_INPUT_COUNT          10
+
+/* output channels */
+#define KS_OUTPUT_YUV656E       0
+#define KS_OUTPUT_EXV           1
+
+/* video standards */
+#define KS_STD_NTSC_N           112       /* 50 Hz NTSC */
+#define KS_STD_PAL_M            113       /* 60 Hz PAL  */
+
+#endif /* KS0127_H */
+
index 850bee97090c91e169531c0d218d9933c4b9f1e1..f68ca7d9f5319b28a34e47e834022b6ea2a970c3 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <linux/delay.h>
@@ -1682,13 +1683,13 @@ static unsigned int meye_poll(struct file *file, poll_table *wait)
 
 static void meye_vm_open(struct vm_area_struct *vma)
 {
-       int idx = (int)vma->vm_private_data;
+       long idx = (long)vma->vm_private_data;
        meye.vma_use_count[idx]++;
 }
 
 static void meye_vm_close(struct vm_area_struct *vma)
 {
-       int idx = (int)vma->vm_private_data;
+       long idx = (long)vma->vm_private_data;
        meye.vma_use_count[idx]--;
 }
 
index b806999d6e0fc69e11c01c2accf67ba4a38562d5..dbb75a7db199ca6635ca2b194e204542f2c2fd66 100644 (file)
@@ -385,67 +385,6 @@ static int msp_mode_v4l1_to_v4l2(int mode)
        return V4L2_TUNER_MODE_MONO;
 }
 
-static struct v4l2_queryctrl msp_qctrl_std[] = {
-       {
-               .id            = V4L2_CID_AUDIO_VOLUME,
-               .name          = "Volume",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 65535/100,
-               .default_value = 58880,
-               .flags         = 0,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .step          = 1,
-               .default_value = 1,
-               .flags         = 0,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },
-};
-
-static struct v4l2_queryctrl msp_qctrl_sound_processing[] = {
-       {
-               .id            = V4L2_CID_AUDIO_BALANCE,
-               .name          = "Balance",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 65535/100,
-               .default_value = 32768,
-               .flags         = 0,
-               .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,
-       },{
-               .id            = V4L2_CID_AUDIO_LOUDNESS,
-               .name          = "Loudness",
-               .minimum       = 0,
-               .maximum       = 1,
-               .step          = 1,
-               .default_value = 1,
-               .flags         = 0,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },
-};
-
-
 static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
 {
        struct msp_state *state = i2c_get_clientdata(client);
@@ -674,22 +613,31 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                int sc1_out = rt->output & 0xf;
                int sc2_out = (rt->output >> 4) & 0xf;
                u16 val, reg;
+               int i;
+               int extern_input = 1;
 
                if (state->routing.input == rt->input &&
                    state->routing.output == rt->output)
                        break;
                state->routing = *rt;
+               /* check if the tuner input is used */
+               for (i = 0; i < 5; i++) {
+                       if (((rt->input >> (4 + i * 4)) & 0xf) == 0)
+                               extern_input = 0;
+               }
+               if (extern_input)
+                       state->mode = MSP_MODE_EXTERN;
+               else
+                       state->mode = MSP_MODE_AM_DETECT;
                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);
                reg = (state->opmode == OPMODE_AUTOSELECT) ? 0x30 : 0xbb;
                val = msp_read_dem(client, reg);
-               if (tuner != ((val >> 8) & 1)) {
-                       msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8));
-                       /* wake thread when a new tuner input is chosen */
-                       msp_wake_thread(client);
-               }
+               msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8));
+               /* wake thread when a new input is chosen */
+               msp_wake_thread(client);
                break;
        }
 
@@ -744,21 +692,25 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
        case VIDIOC_QUERYCTRL:
        {
                struct v4l2_queryctrl *qc = arg;
-               int i;
 
-               for (i = 0; i < ARRAY_SIZE(msp_qctrl_std); i++)
-                       if (qc->id && qc->id == msp_qctrl_std[i].id) {
-                               memcpy(qc, &msp_qctrl_std[i], sizeof(*qc));
-                               return 0;
-                       }
+               switch (qc->id) {
+                       case V4L2_CID_AUDIO_VOLUME:
+                       case V4L2_CID_AUDIO_MUTE:
+                               return v4l2_ctrl_query_fill_std(qc);
+                       default:
+                               break;
+               }
                if (!state->has_sound_processing)
                        return -EINVAL;
-               for (i = 0; i < ARRAY_SIZE(msp_qctrl_sound_processing); i++)
-                       if (qc->id && qc->id == msp_qctrl_sound_processing[i].id) {
-                               memcpy(qc, &msp_qctrl_sound_processing[i], sizeof(*qc));
-                               return 0;
-                       }
-               return -EINVAL;
+               switch (qc->id) {
+                       case V4L2_CID_AUDIO_LOUDNESS:
+                       case V4L2_CID_AUDIO_BALANCE:
+                       case V4L2_CID_AUDIO_BASS:
+                       case V4L2_CID_AUDIO_TREBLE:
+                               return v4l2_ctrl_query_fill_std(qc);
+                       default:
+                               return -EINVAL;
+               }
        }
 
        case VIDIOC_G_CTRL:
@@ -794,7 +746,9 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                case MSP_MODE_EXTERN: p = "External input"; break;
                default: p = "unknown"; break;
                }
-               if (state->opmode == OPMODE_MANUAL) {
+               if (state->mode == MSP_MODE_EXTERN) {
+                       v4l_info(client, "Mode:     %s\n", p);
+               } else if (state->opmode == OPMODE_MANUAL) {
                        v4l_info(client, "Mode:     %s (%s%s)\n", p,
                                (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",
                                (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");
index 633a1021378930261d3ff20f8b4edfc42a846fa5..f2fd9195b3ac6491468deec543c9c68fdf0af379 100644 (file)
@@ -244,19 +244,21 @@ static void msp3400c_set_audmode(struct i2c_client *client)
           the hardware does not support SAP. So the rxsubchans combination
           of STEREO | LANG2 does not occur. */
 
-       /* switch to mono if only mono is available */
-       if (state->rxsubchans == V4L2_TUNER_SUB_MONO)
-               audmode = V4L2_TUNER_MODE_MONO;
-       /* if bilingual */
-       else if (state->rxsubchans & V4L2_TUNER_SUB_LANG2) {
-               /* and mono or stereo, then fallback to lang1 */
-               if (audmode == V4L2_TUNER_MODE_MONO ||
-                   audmode == V4L2_TUNER_MODE_STEREO)
-                       audmode = V4L2_TUNER_MODE_LANG1;
+       if (state->mode != MSP_MODE_EXTERN) {
+               /* switch to mono if only mono is available */
+               if (state->rxsubchans == V4L2_TUNER_SUB_MONO)
+                       audmode = V4L2_TUNER_MODE_MONO;
+               /* if bilingual */
+               else if (state->rxsubchans & V4L2_TUNER_SUB_LANG2) {
+                       /* and mono or stereo, then fallback to lang1 */
+                       if (audmode == V4L2_TUNER_MODE_MONO ||
+                           audmode == V4L2_TUNER_MODE_STEREO)
+                               audmode = V4L2_TUNER_MODE_LANG1;
+               }
+               /* if stereo, and audmode is not mono, then switch to stereo */
+               else if (audmode != V4L2_TUNER_MODE_MONO)
+                       audmode = V4L2_TUNER_MODE_STEREO;
        }
-       /* if stereo, and audmode is not mono, then switch to stereo */
-       else if (audmode != V4L2_TUNER_MODE_MONO)
-               audmode = V4L2_TUNER_MODE_STEREO;
 
        /* switch demodulator */
        switch (state->mode) {
@@ -481,6 +483,7 @@ int msp3400c_thread(void *data)
                        /* no carrier scan, just unmute */
                        v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
                        state->scan_in_progress = 0;
+                       state->rxsubchans = V4L2_TUNER_SUB_STEREO;
                        msp_set_audio(client);
                        continue;
                }
@@ -947,6 +950,14 @@ int msp34xxg_thread(void *data)
                if (kthread_should_stop())
                        break;
 
+               if (state->mode == MSP_MODE_EXTERN) {
+                       /* no carrier scan needed, just unmute */
+                       v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
+                       state->scan_in_progress = 0;
+                       msp_set_audio(client);
+                       continue;
+               }
+
                /* setup the chip*/
                msp34xxg_reset(client);
                state->std = state->radio ? 0x40 : msp_standard;
@@ -978,6 +989,11 @@ int msp34xxg_thread(void *data)
                v4l_dbg(1, msp_debug, client, "detected standard: %s (0x%04x)\n",
                        msp_standard_std_name(state->std), state->std);
 
+               if (state->std == 9) {
+                       /* AM NICAM mode */
+                       msp_write_dsp(client, 0x0e, 0x7c00);
+               }
+
                /* unmute: dispatch sound to scart output, set scart volume */
                msp_set_audio(client);
 
index fdc8e3f139373880f68045a7c1381f26e67b0a70..a988df226aabc3aa4c709c322735c33156067dcd 100644 (file)
@@ -3239,7 +3239,7 @@ ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
                RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
 
                if (frame->scanstate == STATE_LINES) {
-                       int nextf;
+                       int nextf;
 
                        frame->grabstate = FRAME_DONE;
                        wake_up_interruptible(&frame->wq);
@@ -3405,7 +3405,7 @@ eof:
        RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
 
        if (frame->scanstate == STATE_LINES) {
-               int nextf;
+               int nextf;
 
                frame->grabstate = FRAME_DONE;
                wake_up_interruptible(&frame->wq);
index 12b3d51e1c343bdd77c0d66f99d7962562d71af7..68b082bcee1dcf2c704f53d0b194a61a1365a506 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <asm/uaccess.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/smp_lock.h>
 #include <linux/usb.h>
 #include <linux/mutex.h>
index d9e3cada52f4fba0bd349915834a811951a57247..3484e36b68016f4d2c58953ed9fa60dc3d4c6e7a 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/wait.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
index 09835ca098b169b4226c1da8f030786776559e35..5d681fa8bcb18d80504bb92d1bd58fbd90aabbff 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/io.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/mutex.h>
 
 #include <asm/uaccess.h>
@@ -804,7 +805,7 @@ static int pms_do_ioctl(struct inode *inode, struct file *file,
                        struct video_picture *p = arg;
                        if(!((p->palette==VIDEO_PALETTE_RGB565 && p->depth==16)
                            ||(p->palette==VIDEO_PALETTE_RGB555 && p->depth==15)))
-                               return -EINVAL;
+                               return -EINVAL;
                        pd->picture= *p;
 
                        /*
index 53cbc950f95c6a74066ba64c840b8fe28ac35b6e..697145e0bf15b551c7073ef727a6c602fc2e0180 100644 (file)
@@ -7,6 +7,7 @@ config USB_PWC
           * Philips PCA645, PCA646
           * Philips PCVC675, PCVC680, PCVC690
           * Philips PCVC720/40, PCVC730, PCVC740, PCVC750
+          * Philips SPC900NC
           * Askey VC010
           * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro'
             and 'Orbit'/'Sphere'
@@ -19,10 +20,18 @@ config USB_PWC
          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.
+         Some newer logitech webcams are not handled by this driver but by the
+         Usb Video Class driver (linux-uvc).
 
          The built-in microphone is enabled by selecting USB Audio support.
 
          To compile this driver as a module, choose M here: the
          module will be called pwc.
+
+config USB_PWC_DEBUG
+       bool "USB Philips Cameras verbose debug"
+       depends USB_PWC
+       help
+         Say Y here in order to have the pwc driver generate verbose debugging
+         messages.
+         A special module options 'trace' is used to control the verbosity.
index 33d60126c02499b27a29a4bfcd2628669c9f6ccc..9db2260d10ccb345c59845f7dd9ba33e5b1a8384 100644 (file)
@@ -1,3 +1,12 @@
-pwc-objs       := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-timon.o pwc-kiara.o
+pwc-objs       := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-v4l.o pwc-uncompress.o
+pwc-objs       += pwc-dec1.o pwc-dec23.o pwc-kiara.o pwc-timon.o
 
 obj-$(CONFIG_USB_PWC) += pwc.o
+
+ifeq ($(CONFIG_USB_PWC_DEBUG),y)
+EXTRA_CFLAGS += -DCONFIG_PWC_DEBUG=1
+else
+EXTRA_CFLAGS += -DCONFIG_PWC_DEBUG=0
+endif
+
+
index 4ba549bfa0e0cef6707e4955249bcaa886d425f9..0bd115588f319934a12b514fcda709736c34b916 100644 (file)
@@ -2,7 +2,7 @@
    Functions that send various control messages to the webcam, including
    video modes.
    (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 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.
 #include <asm/uaccess.h>
 #endif
 #include <asm/errno.h>
+#include <linux/version.h>
 
 #include "pwc.h"
-#include "pwc-ioctl.h"
 #include "pwc-uncompress.h"
 #include "pwc-kiara.h"
 #include "pwc-timon.h"
+#include "pwc-dec1.h"
+#include "pwc-dec23.h"
 
 /* Request types: video */
 #define SET_LUM_CTL                    0x01
 #define GET_STATUS_CTL                 0x06
 #define SET_EP_STREAM_CTL              0x07
 #define GET_EP_STREAM_CTL              0x08
+#define GET_XX_CTL                     0x09
+#define SET_XX_CTL                     0x0A
+#define GET_XY_CTL                     0x0B
+#define SET_XY_CTL                     0x0C
 #define SET_MPT_CTL                    0x0D
 #define GET_MPT_CTL                    0x0E
 
 #define READ_SHUTTER_FORMATTER                 0x0600
 #define READ_RED_GAIN_FORMATTER                        0x0700
 #define READ_BLUE_GAIN_FORMATTER               0x0800
+#define GET_STATUS_B00                         0x0B00
 #define SENSOR_TYPE_FORMATTER1                 0x0C00
+#define GET_STATUS_3000                                0x3000
 #define READ_RAW_Y_MEAN_FORMATTER              0x3100
 #define SET_POWER_SAVE_MODE_FORMATTER          0x3200
 #define MIRROR_IMAGE_FORMATTER                 0x3300
 #define LED_FORMATTER                          0x3400
+#define LOWLIGHT                               0x3500
+#define GET_STATUS_3600                                0x3600
 #define SENSOR_TYPE_FORMATTER2                 0x3700
+#define GET_STATUS_3800                                0x3800
+#define GET_STATUS_4000                                0x4000
+#define GET_STATUS_4100                                0x4100  /* Get */
+#define CTL_STATUS_4200                                0x4200  /* [GS] 1 */
 
 /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
 #define VIDEO_OUTPUT_CONTROL_FORMATTER         0x0100
@@ -138,6 +152,7 @@ static struct Nala_table_entry Nala_table[PSZ_MAX][8] =
 #include "pwc-nala.h"
 };
 
+static void pwc_set_image_buffer_size(struct pwc_device *pdev);
 
 /****************************************************************************/
 
@@ -159,31 +174,7 @@ static struct Nala_table_entry Nala_table[PSZ_MAX][8] =
                &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)
+static int send_video_command(struct usb_device *udev, int index, void *buf, int buflen)
 {
        return usb_control_msg(udev,
                usb_sndctrlpipe(udev, 0),
@@ -196,7 +187,7 @@ static inline int send_video_command(struct usb_device *udev, int index, void *b
 
 
 
-static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
+static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
 {
        unsigned char buf[3];
        int ret, fps;
@@ -229,34 +220,14 @@ static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int fra
        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);
+               PWC_DEBUG_MODULE("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;
-          }
-       }
+               pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data);
 
        pdev->cmd_len = 3;
        memcpy(pdev->cmd_buf, buf, 3);
@@ -283,7 +254,7 @@ static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int fra
 }
 
 
-static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+static 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;
@@ -315,8 +286,8 @@ static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int fr
        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); */
+       if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+               pwc_dec23_init(pdev, pdev->type, buf);
 
        pdev->cmd_len = 13;
        memcpy(pdev->cmd_buf, buf, 13);
@@ -336,7 +307,7 @@ static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int fr
 }
 
 
-static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+static 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;
@@ -350,21 +321,14 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
        fps = (frames / 5) - 1;
 
        /* special case: VGA @ 5 fps and snapshot is raw bayer mode */
-       if (size == PSZ_VGA && frames == 5 && snapshot)
+       if (size == PSZ_VGA && frames == 5 && snapshot && pdev->vpalette == VIDEO_PALETTE_RAW)
        {
                /* 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");
-               }
+               PWC_DEBUG_SIZE("Choosing VGA/5 BAYER mode.\n");
+               pChoose = &RawEntry;
        }
        else
        {
@@ -372,6 +336,7 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
                   if the preferred ratio is not available.
                   Skip this step when using RAW modes.
                */
+               snapshot = 0;
                while (compression <= 3) {
                        pChoose = &Kiara_table[size][fps][compression];
                        if (pChoose->alternate != 0)
@@ -382,7 +347,7 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
        if (pChoose == NULL || pChoose->alternate == 0)
                return -ENOENT; /* Not supported. */
 
-       Debug("Using alternate setting %d.\n", pChoose->alternate);
+       PWC_TRACE("Using alternate setting %d.\n", pChoose->alternate);
 
        /* usb_control_msg won't take staticly allocated arrays as argument?? */
        memcpy(buf, pChoose->mode, 12);
@@ -394,8 +359,8 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
        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); */
+       if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+               pwc_dec23_init(pdev, pdev->type, buf);
 
        pdev->cmd_len = 12;
        memcpy(pdev->cmd_buf, buf, 12);
@@ -410,49 +375,13 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
                pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4;
        else
                pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
+       PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vsnapshot=%d, vbandlength=%d\n",
+           pdev->frame_size,pdev->vframes,pdev->vsize,pdev->vsnapshot,pdev->vbandlength);
        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
@@ -465,50 +394,78 @@ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frame
 {
        int ret, size;
 
-       Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette);
+       PWC_DEBUG_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");
+               PWC_DEBUG_MODULE("Could not find suitable size.\n");
                return -ERANGE;
        }
-       Debug("decode_size = %d.\n", size);
+       PWC_TRACE("decode_size = %d.\n", size);
 
-       ret = -EINVAL;
-       switch(pdev->type) {
-       case 645:
-       case 646:
+       if (DEVICE_USE_CODEC1(pdev->type)) {
                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:
+       } else if (DEVICE_USE_CODEC3(pdev->type)) {
                ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot);
-               break;
+
+       } else {
+               ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
        }
        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);
-               }
+               PWC_ERROR("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);
+       PWC_DEBUG_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;
 }
 
+#define BLACK_Y 0
+#define BLACK_U 128
+#define BLACK_V 128
+
+static void pwc_set_image_buffer_size(struct pwc_device *pdev)
+{
+       int i, factor = 0;
+
+       /* for PALETTE_YUV420P */
+       switch(pdev->vpalette)
+       {
+       case VIDEO_PALETTE_YUV420P:
+               factor = 6;
+               break;
+       case VIDEO_PALETTE_RAW:
+               factor = 6; /* can be uncompressed YUV420P */
+               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 black colors */
+       for (i = 0; i < pwc_mbufs; i++) {
+               unsigned char *p = pdev->image_data + pdev->images[i].offset;
+               memset(p, BLACK_Y, pdev->view.x * pdev->view.y);
+               p += pdev->view.x * pdev->view.y;
+               memset(p, BLACK_U, pdev->view.x * pdev->view.y/4);
+               p += pdev->view.x * pdev->view.y/4;
+               memset(p, BLACK_V, pdev->view.x * pdev->view.y/4);
+       }
+}
+
+
 
 /* BRIGHTNESS */
 
@@ -520,7 +477,7 @@ int pwc_get_brightness(struct pwc_device *pdev)
        ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1);
        if (ret < 0)
                return ret;
-       return buf << 9;
+       return buf;
 }
 
 int pwc_set_brightness(struct pwc_device *pdev, int value)
@@ -545,7 +502,7 @@ int pwc_get_contrast(struct pwc_device *pdev)
        ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1);
        if (ret < 0)
                return ret;
-       return buf << 10;
+       return buf;
 }
 
 int pwc_set_contrast(struct pwc_device *pdev, int value)
@@ -570,7 +527,7 @@ int pwc_get_gamma(struct pwc_device *pdev)
        ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1);
        if (ret < 0)
                return ret;
-       return buf << 11;
+       return buf;
 }
 
 int pwc_set_gamma(struct pwc_device *pdev, int value)
@@ -588,37 +545,47 @@ int pwc_set_gamma(struct pwc_device *pdev, int value)
 
 /* SATURATION */
 
-int pwc_get_saturation(struct pwc_device *pdev)
+/* return a value between [-100 , 100] */
+int pwc_get_saturation(struct pwc_device *pdev, int *value)
 {
        char buf;
-       int ret;
+       int ret, saturation_register;
 
        if (pdev->type < 675)
-               return -1;
-       ret = RecvControlMsg(GET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
+               return -EINVAL;
+       if (pdev->type < 730)
+               saturation_register = SATURATION_MODE_FORMATTER2;
+       else
+               saturation_register = SATURATION_MODE_FORMATTER1;
+       ret = RecvControlMsg(GET_CHROM_CTL, saturation_register, 1);
        if (ret < 0)
                return ret;
-       return 32768 + buf * 327;
+       *value = (signed)buf;
+       return 0;
 }
 
+/* @param value saturation color between [-100 , 100] */
 int pwc_set_saturation(struct pwc_device *pdev, int value)
 {
        char buf;
+       int saturation_register;
 
        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);
+       if (value < -100)
+               value = -100;
+       if (value > 100)
+               value = 100;
+       if (pdev->type < 730)
+               saturation_register = SATURATION_MODE_FORMATTER2;
+       else
+               saturation_register = SATURATION_MODE_FORMATTER1;
+       return SendControlMsg(SET_CHROM_CTL, saturation_register, 1);
 }
 
 /* AGC */
 
-static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
+int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
 {
        char buf;
        int ret;
@@ -643,7 +610,7 @@ static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
        return 0;
 }
 
-static inline int pwc_get_agc(struct pwc_device *pdev, int *value)
+int pwc_get_agc(struct pwc_device *pdev, int *value)
 {
        unsigned char buf;
        int ret;
@@ -673,7 +640,7 @@ static inline int pwc_get_agc(struct pwc_device *pdev, int *value)
        return 0;
 }
 
-static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
+int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
 {
        char buf[2];
        int speed, ret;
@@ -691,23 +658,16 @@ static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int v
                        value = 0;
                if (value > 0xffff)
                        value = 0xffff;
-               switch(pdev->type) {
-               case 675:
-               case 680:
-               case 690:
+
+               if (DEVICE_USE_CODEC2(pdev->type)) {
                        /* 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:
+               } else if (DEVICE_USE_CODEC3(pdev->type)) {
                        /* 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);
@@ -715,6 +675,25 @@ static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int v
        return ret;
 }
 
+/* This function is not exported to v4l1, so output values between 0 -> 256 */
+int pwc_get_shutter_speed(struct pwc_device *pdev, int *value)
+{
+       unsigned char buf[2];
+       int ret;
+
+       ret = RecvControlMsg(GET_STATUS_CTL, READ_SHUTTER_FORMATTER, 2);
+       if (ret < 0)
+               return ret;
+       *value = buf[0] + (buf[1] << 8);
+       if (DEVICE_USE_CODEC2(pdev->type)) {
+               /* speed ranges from 0x0 to 0x290 (656) */
+               *value *= 256/656;
+       } else if (DEVICE_USE_CODEC3(pdev->type)) {
+               /* speed seems to range from 0x0 to 0xff */
+       }
+       return 0;
+}
+
 
 /* POWER */
 
@@ -736,19 +715,19 @@ int pwc_camera_power(struct pwc_device *pdev, int power)
 
 /* private calls */
 
-static inline int pwc_restore_user(struct pwc_device *pdev)
+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)
+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)
+int pwc_restore_factory(struct pwc_device *pdev)
 {
        char buf; /* dummy */
        return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0);
@@ -766,7 +745,7 @@ static inline int pwc_restore_factory(struct pwc_device *pdev)
   * 03: manual
   * 04: auto
   */
-static inline int pwc_set_awb(struct pwc_device *pdev, int mode)
+int pwc_set_awb(struct pwc_device *pdev, int mode)
 {
        char buf;
        int ret;
@@ -786,7 +765,7 @@ static inline int pwc_set_awb(struct pwc_device *pdev, int mode)
        return 0;
 }
 
-static inline int pwc_get_awb(struct pwc_device *pdev)
+int pwc_get_awb(struct pwc_device *pdev)
 {
        unsigned char buf;
        int ret;
@@ -798,7 +777,7 @@ static inline int pwc_get_awb(struct pwc_device *pdev)
        return buf;
 }
 
-static inline int pwc_set_red_gain(struct pwc_device *pdev, int value)
+int pwc_set_red_gain(struct pwc_device *pdev, int value)
 {
        unsigned char buf;
 
@@ -811,7 +790,7 @@ static inline int pwc_set_red_gain(struct pwc_device *pdev, int value)
        return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1);
 }
 
-static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value)
+int pwc_get_red_gain(struct pwc_device *pdev, int *value)
 {
        unsigned char buf;
        int ret;
@@ -824,7 +803,7 @@ static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value)
 }
 
 
-static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value)
+int pwc_set_blue_gain(struct pwc_device *pdev, int value)
 {
        unsigned char buf;
 
@@ -837,7 +816,7 @@ static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value)
        return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1);
 }
 
-static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
+int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
 {
        unsigned char buf;
        int ret;
@@ -854,7 +833,7 @@ static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
    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)
+static int pwc_read_red_gain(struct pwc_device *pdev, int *value)
 {
        unsigned char buf;
        int ret;
@@ -866,7 +845,7 @@ static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value)
        return 0;
 }
 
-static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
+static int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
 {
        unsigned char buf;
        int ret;
@@ -879,7 +858,7 @@ static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
 }
 
 
-static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
+static int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
 {
        unsigned char buf;
 
@@ -888,7 +867,7 @@ static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
        return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1);
 }
 
-static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
+static int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
 {
        unsigned char buf;
        int ret;
@@ -901,7 +880,7 @@ static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
 }
 
 
-static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
+static int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
 {
        unsigned char buf;
 
@@ -910,7 +889,7 @@ static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
        return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1);
 }
 
-static inline int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
+static int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
 {
        unsigned char buf;
        int ret;
@@ -965,7 +944,7 @@ static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
        return 0;
 }
 
-static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
+int pwc_set_contour(struct pwc_device *pdev, int contour)
 {
        unsigned char buf;
        int ret;
@@ -990,7 +969,7 @@ static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
        return 0;
 }
 
-static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
+int pwc_get_contour(struct pwc_device *pdev, int *contour)
 {
        unsigned char buf;
        int ret;
@@ -1012,7 +991,7 @@ static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
 }
 
 
-static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
+int pwc_set_backlight(struct pwc_device *pdev, int backlight)
 {
        unsigned char buf;
 
@@ -1023,7 +1002,7 @@ static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
        return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
 }
 
-static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
+int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
 {
        int ret;
        unsigned char buf;
@@ -1031,12 +1010,35 @@ static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
        ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
        if (ret < 0)
                return ret;
-       *backlight = buf;
+       *backlight = !!buf;
        return 0;
 }
 
+int pwc_set_colour_mode(struct pwc_device *pdev, int colour)
+{
+       unsigned char buf;
 
-static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
+       if (colour)
+               buf = 0xff;
+       else
+               buf = 0x0;
+       return SendControlMsg(SET_CHROM_CTL, COLOUR_MODE_FORMATTER, 1);
+}
+
+int pwc_get_colour_mode(struct pwc_device *pdev, int *colour)
+{
+       int ret;
+       unsigned char buf;
+
+       ret = RecvControlMsg(GET_CHROM_CTL, COLOUR_MODE_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       *colour = !!buf;
+       return 0;
+}
+
+
+int pwc_set_flicker(struct pwc_device *pdev, int flicker)
 {
        unsigned char buf;
 
@@ -1047,7 +1049,7 @@ static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
        return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
 }
 
-static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
+int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
 {
        int ret;
        unsigned char buf;
@@ -1055,12 +1057,11 @@ static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
        ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
        if (ret < 0)
                return ret;
-       *flicker = buf;
+       *flicker = !!buf;
        return 0;
 }
 
-
-static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
+int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
 {
        unsigned char buf;
 
@@ -1072,7 +1073,7 @@ static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int 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 pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
 {
        int ret;
        unsigned char buf;
@@ -1084,7 +1085,7 @@ static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
        return 0;
 }
 
-static int pwc_mpt_reset(struct pwc_device *pdev, int flags)
+static int _pwc_mpt_reset(struct pwc_device *pdev, int flags)
 {
        unsigned char buf;
 
@@ -1092,7 +1093,18 @@ static int pwc_mpt_reset(struct pwc_device *pdev, int flags)
        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)
+int pwc_mpt_reset(struct pwc_device *pdev, int flags)
+{
+       int ret;
+       ret = _pwc_mpt_reset(pdev, flags);
+       if (ret >= 0) {
+               pdev->pan_angle = 0;
+               pdev->tilt_angle = 0;
+       }
+       return ret;
+}
+
+static int _pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
 {
        unsigned char buf[4];
 
@@ -1110,7 +1122,35 @@ static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
        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 pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
+{
+       int ret;
+
+       /* check absolute ranges */
+       if (pan  < pdev->angle_range.pan_min  ||
+           pan  > pdev->angle_range.pan_max  ||
+           tilt < pdev->angle_range.tilt_min ||
+           tilt > pdev->angle_range.tilt_max)
+               return -ERANGE;
+
+       /* go to relative range, check again */
+       pan  -= pdev->pan_angle;
+       tilt -= pdev->tilt_angle;
+       /* angles are specified in degrees * 100, thus the limit = 36000 */
+       if (pan < -36000 || pan > 36000 || tilt < -36000 || tilt > 36000)
+               return -ERANGE;
+
+       ret = _pwc_mpt_set_angle(pdev, pan, tilt);
+       if (ret >= 0) {
+               pdev->pan_angle  += pan;
+               pdev->tilt_angle += tilt;
+       }
+       if (ret == -EPIPE) /* stall -> out of range */
+               ret = -ERANGE;
+       return ret;
+}
+
+static int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
 {
        int ret;
        unsigned char buf[5];
@@ -1151,6 +1191,26 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
  /* End of Add-Ons                                    */
  /* ************************************************* */
 
+/* Linux 2.5.something and 2.6 pass direct pointers to arguments of
+   ioctl() calls. With 2.4, you have to do tedious copy_from_user()
+   and copy_to_user() calls. With these macros we circumvent this,
+   and let me maintain only one source file. The functionality is
+   exactly the same otherwise.
+ */
+
+
+/* define local variable for arg */
+#define ARG_DEF(ARG_type, ARG_name)\
+       ARG_type *ARG_name = arg;
+/* copy arg to local variable */
+#define ARG_IN(ARG_name) /* nothing */
+/* argument itself (referenced) */
+#define ARGR(ARG_name) (*ARG_name)
+/* argument address */
+#define ARGA(ARG_name) ARG_name
+/* copy local variable to arg */
+#define ARG_OUT(ARG_name) /* nothing */
+
 
 int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 {
@@ -1180,206 +1240,243 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 
        case VIDIOCPWCSCQUAL:
        {
-               int *qual = arg;
+               ARG_DEF(int, qual)
 
-               if (*qual < 0 || *qual > 3)
+               ARG_IN(qual)
+               if (ARGR(qual) < 0 || ARGR(qual) > 3)
                        ret = -EINVAL;
                else
-                       ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, *qual, pdev->vsnapshot);
+                       ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot);
                if (ret >= 0)
-                       pdev->vcompression = *qual;
+                       pdev->vcompression = ARGR(qual);
                break;
        }
 
        case VIDIOCPWCGCQUAL:
        {
-               int *qual = arg;
-               *qual = pdev->vcompression;
+               ARG_DEF(int, qual)
+
+               ARGR(qual) = pdev->vcompression;
+               ARG_OUT(qual)
                break;
        }
 
        case VIDIOCPWCPROBE:
        {
-               struct pwc_probe *probe = arg;
-               strcpy(probe->name, pdev->vdev->name);
-               probe->type = pdev->type;
+               ARG_DEF(struct pwc_probe, probe)
+
+               strcpy(ARGR(probe).name, pdev->vdev->name);
+               ARGR(probe).type = pdev->type;
+               ARG_OUT(probe)
                break;
        }
 
        case VIDIOCPWCGSERIAL:
        {
-               struct pwc_serial *serial = arg;
-               strcpy(serial->serial, pdev->serial);
+               ARG_DEF(struct pwc_serial, serial)
+
+               strcpy(ARGR(serial).serial, pdev->serial);
+               ARG_OUT(serial)
                break;
        }
 
        case VIDIOCPWCSAGC:
        {
-               int *agc = arg;
-               if (pwc_set_agc(pdev, *agc < 0 ? 1 : 0, *agc))
+               ARG_DEF(int, agc)
+
+               ARG_IN(agc)
+               if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc)))
                        ret = -EINVAL;
                break;
        }
 
        case VIDIOCPWCGAGC:
        {
-               int *agc = arg;
+               ARG_DEF(int, agc)
 
-               if (pwc_get_agc(pdev, agc))
+               if (pwc_get_agc(pdev, ARGA(agc)))
                        ret = -EINVAL;
+               ARG_OUT(agc)
                break;
        }
 
        case VIDIOCPWCSSHUTTER:
        {
-               int *shutter_speed = arg;
-               ret = pwc_set_shutter_speed(pdev, *shutter_speed < 0 ? 1 : 0, *shutter_speed);
+               ARG_DEF(int, shutter_speed)
+
+               ARG_IN(shutter_speed)
+               ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed));
                break;
        }
 
        case VIDIOCPWCSAWB:
        {
-               struct pwc_whitebalance *wb = arg;
+               ARG_DEF(struct pwc_whitebalance, wb)
 
-               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);
+               ARG_IN(wb)
+               ret = pwc_set_awb(pdev, ARGR(wb).mode);
+               if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) {
+                       pwc_set_red_gain(pdev, ARGR(wb).manual_red);
+                       pwc_set_blue_gain(pdev, ARGR(wb).manual_blue);
                }
                break;
        }
 
        case VIDIOCPWCGAWB:
        {
-               struct pwc_whitebalance *wb = arg;
+               ARG_DEF(struct pwc_whitebalance, wb)
 
-               memset(wb, 0, sizeof(struct pwc_whitebalance));
-               wb->mode = pwc_get_awb(pdev);
-               if (wb->mode < 0)
+               memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance));
+               ARGR(wb).mode = pwc_get_awb(pdev);
+               if (ARGR(wb).mode < 0)
                        ret = -EINVAL;
                else {
-                       if (wb->mode == PWC_WB_MANUAL) {
-                               ret = pwc_get_red_gain(pdev, &wb->manual_red);
+                       if (ARGR(wb).mode == PWC_WB_MANUAL) {
+                               ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red);
                                if (ret < 0)
                                        break;
-                               ret = pwc_get_blue_gain(pdev, &wb->manual_blue);
+                               ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue);
                                if (ret < 0)
                                        break;
                        }
-                       if (wb->mode == PWC_WB_AUTO) {
-                               ret = pwc_read_red_gain(pdev, &wb->read_red);
+                       if (ARGR(wb).mode == PWC_WB_AUTO) {
+                               ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red);
                                if (ret < 0)
                                        break;
-                               ret = pwc_read_blue_gain(pdev, &wb->read_blue);
+                               ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue);
                                if (ret < 0)
                                        break;
                        }
                }
+               ARG_OUT(wb)
                break;
        }
 
        case VIDIOCPWCSAWBSPEED:
        {
-               struct pwc_wb_speed *wbs = arg;
+               ARG_DEF(struct pwc_wb_speed, wbs)
 
-               if (wbs->control_speed > 0) {
-                       ret = pwc_set_wb_speed(pdev, wbs->control_speed);
+               if (ARGR(wbs).control_speed > 0) {
+                       ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed);
                }
-               if (wbs->control_delay > 0) {
-                       ret = pwc_set_wb_delay(pdev, wbs->control_delay);
+               if (ARGR(wbs).control_delay > 0) {
+                       ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay);
                }
                break;
        }
 
        case VIDIOCPWCGAWBSPEED:
        {
-               struct pwc_wb_speed *wbs = arg;
+               ARG_DEF(struct pwc_wb_speed, wbs)
 
-               ret = pwc_get_wb_speed(pdev, &wbs->control_speed);
+               ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed);
                if (ret < 0)
                        break;
-               ret = pwc_get_wb_delay(pdev, &wbs->control_delay);
+               ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay);
                if (ret < 0)
                        break;
+               ARG_OUT(wbs)
                break;
        }
 
        case VIDIOCPWCSLED:
        {
-               struct pwc_leds *leds = arg;
-               ret = pwc_set_leds(pdev, leds->led_on, leds->led_off);
-               break;
+               ARG_DEF(struct pwc_leds, leds)
+
+               ARG_IN(leds)
+               ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off);
+               break;
        }
 
 
        case VIDIOCPWCGLED:
        {
-               struct pwc_leds *leds = arg;
-               ret = pwc_get_leds(pdev, &leds->led_on, &leds->led_off);
+               ARG_DEF(struct pwc_leds, leds)
+
+               ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off);
+               ARG_OUT(leds)
                break;
        }
 
        case VIDIOCPWCSCONTOUR:
        {
-               int *contour = arg;
-               ret = pwc_set_contour(pdev, *contour);
+               ARG_DEF(int, contour)
+
+               ARG_IN(contour)
+               ret = pwc_set_contour(pdev, ARGR(contour));
                break;
        }
 
        case VIDIOCPWCGCONTOUR:
        {
-               int *contour = arg;
-               ret = pwc_get_contour(pdev, contour);
+               ARG_DEF(int, contour)
+
+               ret = pwc_get_contour(pdev, ARGA(contour));
+               ARG_OUT(contour)
                break;
        }
 
        case VIDIOCPWCSBACKLIGHT:
        {
-               int *backlight = arg;
-               ret = pwc_set_backlight(pdev, *backlight);
+               ARG_DEF(int, backlight)
+
+               ARG_IN(backlight)
+               ret = pwc_set_backlight(pdev, ARGR(backlight));
                break;
        }
 
        case VIDIOCPWCGBACKLIGHT:
        {
-               int *backlight = arg;
-               ret = pwc_get_backlight(pdev, backlight);
+               ARG_DEF(int, backlight)
+
+               ret = pwc_get_backlight(pdev, ARGA(backlight));
+               ARG_OUT(backlight)
                break;
        }
 
        case VIDIOCPWCSFLICKER:
        {
-               int *flicker = arg;
-               ret = pwc_set_flicker(pdev, *flicker);
+               ARG_DEF(int, flicker)
+
+               ARG_IN(flicker)
+               ret = pwc_set_flicker(pdev, ARGR(flicker));
                break;
        }
 
        case VIDIOCPWCGFLICKER:
        {
-               int *flicker = arg;
-               ret = pwc_get_flicker(pdev, flicker);
+               ARG_DEF(int, flicker)
+
+               ret = pwc_get_flicker(pdev, ARGA(flicker));
+               ARG_OUT(flicker)
                break;
        }
 
        case VIDIOCPWCSDYNNOISE:
        {
-               int *dynnoise = arg;
-               ret = pwc_set_dynamic_noise(pdev, *dynnoise);
+               ARG_DEF(int, dynnoise)
+
+               ARG_IN(dynnoise)
+               ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise));
                break;
        }
 
        case VIDIOCPWCGDYNNOISE:
        {
-               int *dynnoise = arg;
-               ret = pwc_get_dynamic_noise(pdev, dynnoise);
+               ARG_DEF(int, dynnoise)
+
+               ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise));
+               ARG_OUT(dynnoise);
                break;
        }
 
        case VIDIOCPWCGREALSIZE:
        {
-               struct pwc_imagesize *size = arg;
-               size->width = pdev->image.x;
-               size->height = pdev->image.y;
+               ARG_DEF(struct pwc_imagesize, size)
+
+               ARGR(size).width = pdev->image.x;
+               ARGR(size).height = pdev->image.y;
+               ARG_OUT(size)
                break;
        }
 
@@ -1387,14 +1484,10 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        {
                if (pdev->features & FEATURE_MOTOR_PANTILT)
                {
-                       int *flags = arg;
+                       ARG_DEF(int, flags)
 
-                       ret = pwc_mpt_reset(pdev, *flags);
-                       if (ret >= 0)
-                       {
-                               pdev->pan_angle = 0;
-                               pdev->tilt_angle = 0;
-                       }
+                       ARG_IN(flags)
+                       ret = pwc_mpt_reset(pdev, ARGR(flags));
                }
                else
                {
@@ -1407,8 +1500,10 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        {
                if (pdev->features & FEATURE_MOTOR_PANTILT)
                {
-                       struct pwc_mpt_range *range = arg;
-                       *range = pdev->angle_range;
+                       ARG_DEF(struct pwc_mpt_range, range)
+
+                       ARGR(range) = pdev->angle_range;
+                       ARG_OUT(range)
                }
                else
                {
@@ -1423,48 +1518,23 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 
                if (pdev->features & FEATURE_MOTOR_PANTILT)
                {
-                       struct pwc_mpt_angles *angles = arg;
+                       ARG_DEF(struct pwc_mpt_angles, angles)
+
+                       ARG_IN(angles)
                        /* The camera can only set relative angles, so
                           do some calculations when getting an absolute angle .
                         */
-                       if (angles->absolute)
+                       if (ARGR(angles).absolute)
                        {
-                               new_pan  = angles->pan;
-                               new_tilt = angles->tilt;
+                               new_pan  = ARGR(angles).pan;
+                               new_tilt = ARGR(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;
+                               new_pan  = pdev->pan_angle  + ARGR(angles).pan;
+                               new_tilt = pdev->tilt_angle + ARGR(angles).tilt;
                        }
+                       ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
                }
                else
                {
@@ -1478,11 +1548,12 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 
                if (pdev->features & FEATURE_MOTOR_PANTILT)
                {
-                       struct pwc_mpt_angles *angles = arg;
+                       ARG_DEF(struct pwc_mpt_angles, angles)
 
-                       angles->absolute = 1;
-                       angles->pan  = pdev->pan_angle;
-                       angles->tilt = pdev->tilt_angle;
+                       ARGR(angles).absolute = 1;
+                       ARGR(angles).pan  = pdev->pan_angle;
+                       ARGR(angles).tilt = pdev->tilt_angle;
+                       ARG_OUT(angles)
                }
                else
                {
@@ -1495,8 +1566,10 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        {
                if (pdev->features & FEATURE_MOTOR_PANTILT)
                {
-                       struct pwc_mpt_status *status = arg;
-                       ret = pwc_mpt_get_status(pdev, status);
+                       ARG_DEF(struct pwc_mpt_status, status)
+
+                       ret = pwc_mpt_get_status(pdev, ARGA(status));
+                       ARG_OUT(status)
                }
                else
                {
@@ -1507,22 +1580,24 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 
        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;
+               ARG_DEF(struct pwc_video_command, cmd);
+
+               ARGR(cmd).type = pdev->type;
+               ARGR(cmd).release = pdev->release;
+               ARGR(cmd).command_len = pdev->cmd_len;
+               memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
+               ARGR(cmd).bandlength = pdev->vbandlength;
+               ARGR(cmd).frame_size = pdev->frame_size;
+               ARG_OUT(cmd)
                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);
+               ARG_DEF(struct pwc_table_init_buffer, table);
+               ARGR(table).len = pdev->cmd_len;
+               memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size);
+               ARG_OUT(table)
                break;
        }
        */
@@ -1538,4 +1613,4 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 }
 
 
-
+/* vim: set cinoptions= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc-dec1.c b/drivers/media/video/pwc/pwc-dec1.c
new file mode 100644 (file)
index 0000000..c29593f
--- /dev/null
@@ -0,0 +1,50 @@
+/* Linux driver for Philips webcam
+   Decompression for chipset version 1
+   (C) 2004-2006 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 "pwc-dec1.h"
+
+
+void pwc_dec1_init(int type, int release, void *buffer, void *table)
+{
+
+}
+
+void pwc_dec1_exit(void)
+{
+
+
+
+}
+
+int pwc_dec1_alloc(struct pwc_device *pwc)
+{
+       pwc->decompress_data = kmalloc(sizeof(struct pwc_dec1_private), GFP_KERNEL);
+       if (pwc->decompress_data == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
diff --git a/drivers/media/video/pwc/pwc-dec1.h b/drivers/media/video/pwc/pwc-dec1.h
new file mode 100644 (file)
index 0000000..8b62ddc
--- /dev/null
@@ -0,0 +1,43 @@
+/* Linux driver for Philips webcam
+   (C) 2004-2006 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_DEC1_H
+#define PWC_DEC1_H
+
+#include "pwc.h"
+
+struct pwc_dec1_private
+{
+       int version;
+
+};
+
+int  pwc_dec1_alloc(struct pwc_device *pwc);
+void pwc_dec1_init(int type, int release, void *buffer, void *private_data);
+void pwc_dec1_exit(void);
+
+#endif
+
diff --git a/drivers/media/video/pwc/pwc-dec23.c b/drivers/media/video/pwc/pwc-dec23.c
new file mode 100644 (file)
index 0000000..9e2d91f
--- /dev/null
@@ -0,0 +1,941 @@
+/* Linux driver for Philips webcam
+   Decompression for chipset version 2 et 3
+   (C) 2004-2006  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 "pwc-timon.h"
+#include "pwc-kiara.h"
+#include "pwc-dec23.h"
+#include <media/pwc-ioctl.h>
+
+#include <linux/string.h>
+
+/*
+ * USE_LOOKUP_TABLE_TO_CLAMP
+ *   0: use a C version of this tests:  {  a<0?0:(a>255?255:a) }
+ *   1: use a faster lookup table for cpu with a big cache (intel)
+ */
+#define USE_LOOKUP_TABLE_TO_CLAMP      1
+/*
+ * UNROLL_LOOP_FOR_COPYING_BLOCK
+ *   0: use a loop for a smaller code (but little slower)
+ *   1: when unrolling the loop, gcc produces some faster code (perhaps only
+ *   valid for intel processor class). Activating this option, automaticaly
+ *   activate USE_LOOKUP_TABLE_TO_CLAMP
+ */
+#define UNROLL_LOOP_FOR_COPY           1
+#if UNROLL_LOOP_FOR_COPY
+# undef USE_LOOKUP_TABLE_TO_CLAMP
+# define USE_LOOKUP_TABLE_TO_CLAMP 1
+#endif
+
+/*
+ * ENABLE_BAYER_DECODER
+ *   0: bayer decoder is not build (save some space)
+ *   1: bayer decoder is build and can be used
+ */
+#define ENABLE_BAYER_DECODER 0
+
+static void build_subblock_pattern(struct pwc_dec23_private *pdec)
+{
+       static const unsigned int initial_values[12] = {
+               -0x526500, -0x221200, 0x221200, 0x526500,
+                          -0x3de200, 0x3de200,
+               -0x6db480, -0x2d5d00, 0x2d5d00, 0x6db480,
+                          -0x12c200, 0x12c200
+
+       };
+       static const unsigned int values_derivated[12] = {
+               0xa4ca, 0x4424, -0x4424, -0xa4ca,
+                       0x7bc4, -0x7bc4,
+               0xdb69, 0x5aba, -0x5aba, -0xdb69,
+                       0x2584, -0x2584
+       };
+       unsigned int temp_values[12];
+       int i, j;
+
+       memcpy(temp_values, initial_values, sizeof(initial_values));
+       for (i = 0; i < 256; i++) {
+               for (j = 0; j < 12; j++) {
+                       pdec->table_subblock[i][j] = temp_values[j];
+                       temp_values[j] += values_derivated[j];
+               }
+       }
+}
+
+static void build_bit_powermask_table(struct pwc_dec23_private *pdec)
+{
+       unsigned char *p;
+       unsigned int bit, byte, mask, val;
+       unsigned int bitpower = 1;
+
+       for (bit = 0; bit < 8; bit++) {
+               mask = bitpower - 1;
+               p = pdec->table_bitpowermask[bit];
+               for (byte = 0; byte < 256; byte++) {
+                       val = (byte & mask);
+                       if (byte & bitpower)
+                               val = -val;
+                       *p++ = val;
+               }
+               bitpower<<=1;
+       }
+}
+
+
+static void build_table_color(const unsigned int romtable[16][8],
+                             unsigned char p0004[16][1024],
+                             unsigned char p8004[16][256])
+{
+       int compression_mode, j, k, bit, pw;
+       unsigned char *p0, *p8;
+       const unsigned int *r;
+
+       /* We have 16 compressions tables */
+       for (compression_mode = 0; compression_mode < 16; compression_mode++) {
+               p0 = p0004[compression_mode];
+               p8 = p8004[compression_mode];
+               r  = romtable[compression_mode];
+
+               for (j = 0; j < 8; j++, r++, p0 += 128) {
+
+                       for (k = 0; k < 16; k++) {
+                               if (k == 0)
+                                       bit = 1;
+                               else if (k >= 1 && k < 3)
+                                       bit = (r[0] >> 15) & 7;
+                               else if (k >= 3 && k < 6)
+                                       bit = (r[0] >> 12) & 7;
+                               else if (k >= 6 && k < 10)
+                                       bit = (r[0] >> 9) & 7;
+                               else if (k >= 10 && k < 13)
+                                       bit = (r[0] >> 6) & 7;
+                               else if (k >= 13 && k < 15)
+                                       bit = (r[0] >> 3) & 7;
+                               else
+                                       bit = (r[0]) & 7;
+                               if (k == 0)
+                                       *p8++ = 8;
+                               else
+                                       *p8++ = j - bit;
+                               *p8++ = bit;
+
+                               pw = 1 << bit;
+                               p0[k + 0x00] = (1 * pw) + 0x80;
+                               p0[k + 0x10] = (2 * pw) + 0x80;
+                               p0[k + 0x20] = (3 * pw) + 0x80;
+                               p0[k + 0x30] = (4 * pw) + 0x80;
+                               p0[k + 0x40] = (-1 * pw) + 0x80;
+                               p0[k + 0x50] = (-2 * pw) + 0x80;
+                               p0[k + 0x60] = (-3 * pw) + 0x80;
+                               p0[k + 0x70] = (-4 * pw) + 0x80;
+                       }       /* end of for (k=0; k<16; k++, p8++) */
+               }       /* end of for (j=0; j<8; j++ , table++) */
+       } /* end of foreach compression_mode */
+}
+
+/*
+ *
+ */
+static void fill_table_dc00_d800(struct pwc_dec23_private *pdec)
+{
+#define SCALEBITS 15
+#define ONE_HALF  (1UL << (SCALEBITS - 1))
+       int i;
+       unsigned int offset1 = ONE_HALF;
+       unsigned int offset2 = 0x0000;
+
+       for (i=0; i<256; i++) {
+               pdec->table_dc00[i] = offset1 & ~(ONE_HALF);
+               pdec->table_d800[i] = offset2;
+
+               offset1 += 0x7bc4;
+               offset2 += 0x7bc4;
+       }
+}
+
+/*
+ * To decode the stream:
+ *   if look_bits(2) == 0:     # op == 2 in the lookup table
+ *      skip_bits(2)
+ *      end of the stream
+ *   elif look_bits(3) == 7:   # op == 1 in the lookup table
+ *      skip_bits(3)
+ *      yyyy = get_bits(4)
+ *      xxxx = get_bits(8)
+ *   else:                     # op == 0 in the lookup table
+ *      skip_bits(x)
+ *
+ * For speedup processing, we build a lookup table and we takes the first 6 bits.
+ *
+ * struct {
+ *   unsigned char op;     // operation to execute
+ *   unsigned char bits;    // bits use to perform operation
+ *   unsigned char offset1; // offset to add to access in the table_0004 % 16
+ *   unsigned char offset2; // offset to add to access in the table_0004
+ * }
+ *
+ * How to build this table ?
+ *   op == 2 when (i%4)==0
+ *   op == 1 when (i%8)==7
+ *   op == 0 otherwise
+ *
+ */
+static const unsigned char hash_table_ops[64*4] = {
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x00,
+       0x00, 0x04, 0x01, 0x10,
+       0x00, 0x06, 0x01, 0x30,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x40,
+       0x00, 0x05, 0x01, 0x20,
+       0x01, 0x00, 0x00, 0x00,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x00,
+       0x00, 0x04, 0x01, 0x50,
+       0x00, 0x05, 0x02, 0x00,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x40,
+       0x00, 0x05, 0x03, 0x00,
+       0x01, 0x00, 0x00, 0x00,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x00,
+       0x00, 0x04, 0x01, 0x10,
+       0x00, 0x06, 0x02, 0x10,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x40,
+       0x00, 0x05, 0x01, 0x60,
+       0x01, 0x00, 0x00, 0x00,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x00,
+       0x00, 0x04, 0x01, 0x50,
+       0x00, 0x05, 0x02, 0x40,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x40,
+       0x00, 0x05, 0x03, 0x40,
+       0x01, 0x00, 0x00, 0x00,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x00,
+       0x00, 0x04, 0x01, 0x10,
+       0x00, 0x06, 0x01, 0x70,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x40,
+       0x00, 0x05, 0x01, 0x20,
+       0x01, 0x00, 0x00, 0x00,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x00,
+       0x00, 0x04, 0x01, 0x50,
+       0x00, 0x05, 0x02, 0x00,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x40,
+       0x00, 0x05, 0x03, 0x00,
+       0x01, 0x00, 0x00, 0x00,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x00,
+       0x00, 0x04, 0x01, 0x10,
+       0x00, 0x06, 0x02, 0x50,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x40,
+       0x00, 0x05, 0x01, 0x60,
+       0x01, 0x00, 0x00, 0x00,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x00,
+       0x00, 0x04, 0x01, 0x50,
+       0x00, 0x05, 0x02, 0x40,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x40,
+       0x00, 0x05, 0x03, 0x40,
+       0x01, 0x00, 0x00, 0x00
+};
+
+/*
+ *
+ */
+static const unsigned int MulIdx[16][16] = {
+       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
+       {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,},
+       {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,},
+       {4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4,},
+       {6, 7, 8, 9, 7, 10, 11, 8, 8, 11, 10, 7, 9, 8, 7, 6,},
+       {4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4,},
+       {1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2,},
+       {0, 3, 3, 0, 1, 2, 2, 1, 2, 1, 1, 2, 3, 0, 0, 3,},
+       {0, 1, 2, 3, 3, 2, 1, 0, 3, 2, 1, 0, 0, 1, 2, 3,},
+       {1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0, 2, 2, 2, 2,},
+       {7, 10, 11, 8, 9, 8, 7, 6, 6, 7, 8, 9, 8, 11, 10, 7,},
+       {4, 5, 5, 4, 5, 4, 4, 5, 5, 4, 4, 5, 4, 5, 5, 4,},
+       {7, 9, 6, 8, 10, 8, 7, 11, 11, 7, 8, 10, 8, 6, 9, 7,},
+       {1, 3, 0, 2, 2, 0, 3, 1, 2, 0, 3, 1, 1, 3, 0, 2,},
+       {1, 2, 2, 1, 3, 0, 0, 3, 0, 3, 3, 0, 2, 1, 1, 2,},
+       {10, 8, 7, 11, 8, 6, 9, 7, 7, 9, 6, 8, 11, 7, 8, 10}
+};
+
+#if USE_LOOKUP_TABLE_TO_CLAMP
+#define MAX_OUTER_CROP_VALUE   (512)
+static unsigned char pwc_crop_table[256 + 2*MAX_OUTER_CROP_VALUE];
+#define CLAMP(x) (pwc_crop_table[MAX_OUTER_CROP_VALUE+(x)])
+#else
+#define CLAMP(x) ((x)>255?255:((x)<0?0:x))
+#endif
+
+
+/* If the type or the command change, we rebuild the lookup table */
+int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd)
+{
+       int flags, version, shift, i;
+       struct pwc_dec23_private *pdec;
+
+       if (pwc->decompress_data == NULL) {
+               pdec = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
+               if (pdec == NULL)
+                       return -ENOMEM;
+               pwc->decompress_data = pdec;
+       }
+       pdec = pwc->decompress_data;
+
+       if (DEVICE_USE_CODEC3(type)) {
+               flags = cmd[2] & 0x18;
+               if (flags == 8)
+                       pdec->nbits = 7;        /* More bits, mean more bits to encode the stream, but better quality */
+               else if (flags == 0x10)
+                       pdec->nbits = 8;
+               else
+                       pdec->nbits = 6;
+
+               version = cmd[2] >> 5;
+               build_table_color(KiaraRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1);
+               build_table_color(KiaraRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2);
+
+       } else {
+
+               flags = cmd[2] & 6;
+               if (flags == 2)
+                       pdec->nbits = 7;
+               else if (flags == 4)
+                       pdec->nbits = 8;
+               else
+                       pdec->nbits = 6;
+
+               version = cmd[2] >> 3;
+               build_table_color(TimonRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1);
+               build_table_color(TimonRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2);
+       }
+
+       /* Informations can be coded on a variable number of bits but never less than 8 */
+       shift = 8 - pdec->nbits;
+       pdec->scalebits = SCALEBITS - shift;
+       pdec->nbitsmask = 0xFF >> shift;
+
+       fill_table_dc00_d800(pdec);
+       build_subblock_pattern(pdec);
+       build_bit_powermask_table(pdec);
+
+#if USE_LOOKUP_TABLE_TO_CLAMP
+       /* Build the static table to clamp value [0-255] */
+       for (i=0;i<MAX_OUTER_CROP_VALUE;i++)
+               pwc_crop_table[i] = 0;
+       for (i=0; i<256; i++)
+               pwc_crop_table[MAX_OUTER_CROP_VALUE+i] = i;
+       for (i=0; i<MAX_OUTER_CROP_VALUE; i++)
+               pwc_crop_table[MAX_OUTER_CROP_VALUE+256+i] = 255;
+#endif
+
+       return 0;
+}
+
+/*
+ * Copy the 4x4 image block to Y plane buffer
+ */
+static void copy_image_block_Y(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+       const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+       const int *c = src;
+       unsigned char *d = dst;
+
+       *d++ = cm[c[0] >> scalebits];
+       *d++ = cm[c[1] >> scalebits];
+       *d++ = cm[c[2] >> scalebits];
+       *d++ = cm[c[3] >> scalebits];
+
+       d = dst + bytes_per_line;
+       *d++ = cm[c[4] >> scalebits];
+       *d++ = cm[c[5] >> scalebits];
+       *d++ = cm[c[6] >> scalebits];
+       *d++ = cm[c[7] >> scalebits];
+
+       d = dst + bytes_per_line*2;
+       *d++ = cm[c[8] >> scalebits];
+       *d++ = cm[c[9] >> scalebits];
+       *d++ = cm[c[10] >> scalebits];
+       *d++ = cm[c[11] >> scalebits];
+
+       d = dst + bytes_per_line*3;
+       *d++ = cm[c[12] >> scalebits];
+       *d++ = cm[c[13] >> scalebits];
+       *d++ = cm[c[14] >> scalebits];
+       *d++ = cm[c[15] >> scalebits];
+#else
+       int i;
+       const int *c = src;
+       unsigned char *d = dst;
+       for (i = 0; i < 4; i++, c++)
+               *d++ = CLAMP((*c) >> scalebits);
+
+       d = dst + bytes_per_line;
+       for (i = 0; i < 4; i++, c++)
+               *d++ = CLAMP((*c) >> scalebits);
+
+       d = dst + bytes_per_line*2;
+       for (i = 0; i < 4; i++, c++)
+               *d++ = CLAMP((*c) >> scalebits);
+
+       d = dst + bytes_per_line*3;
+       for (i = 0; i < 4; i++, c++)
+               *d++ = CLAMP((*c) >> scalebits);
+#endif
+}
+
+/*
+ * Copy the 4x4 image block to a CrCb plane buffer
+ *
+ */
+static void copy_image_block_CrCb(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+       /* Unroll all loops */
+       const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+       const int *c = src;
+       unsigned char *d = dst;
+
+       *d++ = cm[c[0] >> scalebits];
+       *d++ = cm[c[4] >> scalebits];
+       *d++ = cm[c[1] >> scalebits];
+       *d++ = cm[c[5] >> scalebits];
+       *d++ = cm[c[2] >> scalebits];
+       *d++ = cm[c[6] >> scalebits];
+       *d++ = cm[c[3] >> scalebits];
+       *d++ = cm[c[7] >> scalebits];
+
+       d = dst + bytes_per_line;
+       *d++ = cm[c[12] >> scalebits];
+       *d++ = cm[c[8] >> scalebits];
+       *d++ = cm[c[13] >> scalebits];
+       *d++ = cm[c[9] >> scalebits];
+       *d++ = cm[c[14] >> scalebits];
+       *d++ = cm[c[10] >> scalebits];
+       *d++ = cm[c[15] >> scalebits];
+       *d++ = cm[c[11] >> scalebits];
+#else
+       int i;
+       const int *c1 = src;
+       const int *c2 = src + 4;
+       unsigned char *d = dst;
+
+       for (i = 0; i < 4; i++, c1++, c2++) {
+               *d++ = CLAMP((*c1) >> scalebits);
+               *d++ = CLAMP((*c2) >> scalebits);
+       }
+       c1 = src + 12;
+       d = dst + bytes_per_line;
+       for (i = 0; i < 4; i++, c1++, c2++) {
+               *d++ = CLAMP((*c1) >> scalebits);
+               *d++ = CLAMP((*c2) >> scalebits);
+       }
+#endif
+}
+
+#if ENABLE_BAYER_DECODER
+/*
+ * Format: 8x2 pixels
+ *   . G . G . G . G . G . G . G
+ *   . . . . . . . . . . . . . .
+ *   . G . G . G . G . G . G . G
+ *   . . . . . . . . . . . . . .
+ *   or
+ *   . . . . . . . . . . . . . .
+ *   G . G . G . G . G . G . G .
+ *   . . . . . . . . . . . . . .
+ *   G . G . G . G . G . G . G .
+*/
+static void copy_image_block_Green(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+       /* Unroll all loops */
+       const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+       unsigned char *d = dst;
+       const int *c = src;
+
+       d[0] = cm[c[0] >> scalebits];
+       d[2] = cm[c[1] >> scalebits];
+       d[4] = cm[c[2] >> scalebits];
+       d[6] = cm[c[3] >> scalebits];
+       d[8] = cm[c[4] >> scalebits];
+       d[10] = cm[c[5] >> scalebits];
+       d[12] = cm[c[6] >> scalebits];
+       d[14] = cm[c[7] >> scalebits];
+
+       d = dst + bytes_per_line;
+       d[0] = cm[c[8] >> scalebits];
+       d[2] = cm[c[9] >> scalebits];
+       d[4] = cm[c[10] >> scalebits];
+       d[6] = cm[c[11] >> scalebits];
+       d[8] = cm[c[12] >> scalebits];
+       d[10] = cm[c[13] >> scalebits];
+       d[12] = cm[c[14] >> scalebits];
+       d[14] = cm[c[15] >> scalebits];
+#else
+       int i;
+       unsigned char *d;
+       const int *c = src;
+
+       d = dst;
+       for (i = 0; i < 8; i++, c++)
+               d[i*2] = CLAMP((*c) >> scalebits);
+
+       d = dst + bytes_per_line;
+       for (i = 0; i < 8; i++, c++)
+               d[i*2] = CLAMP((*c) >> scalebits);
+#endif
+}
+#endif
+
+#if ENABLE_BAYER_DECODER
+/*
+ * Format: 4x4 pixels
+ *   R . R . R . R
+ *   . B . B . B .
+ *   R . R . R . R
+ *   . B . B . B .
+ */
+static void copy_image_block_RedBlue(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+       /* Unroll all loops */
+       const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+       unsigned char *d = dst;
+       const int *c = src;
+
+       d[0] = cm[c[0] >> scalebits];
+       d[2] = cm[c[1] >> scalebits];
+       d[4] = cm[c[2] >> scalebits];
+       d[6] = cm[c[3] >> scalebits];
+
+       d = dst + bytes_per_line;
+       d[1] = cm[c[4] >> scalebits];
+       d[3] = cm[c[5] >> scalebits];
+       d[5] = cm[c[6] >> scalebits];
+       d[7] = cm[c[7] >> scalebits];
+
+       d = dst + bytes_per_line*2;
+       d[0] = cm[c[8] >> scalebits];
+       d[2] = cm[c[9] >> scalebits];
+       d[4] = cm[c[10] >> scalebits];
+       d[6] = cm[c[11] >> scalebits];
+
+       d = dst + bytes_per_line*3;
+       d[1] = cm[c[12] >> scalebits];
+       d[3] = cm[c[13] >> scalebits];
+       d[5] = cm[c[14] >> scalebits];
+       d[7] = cm[c[15] >> scalebits];
+#else
+       int i;
+       unsigned char *d;
+       const int *c = src;
+
+       d = dst;
+       for (i = 0; i < 4; i++, c++)
+               d[i*2] = CLAMP((*c) >> scalebits);
+
+       d = dst + bytes_per_line;
+       for (i = 0; i < 4; i++, c++)
+               d[i*2+1] = CLAMP((*c) >> scalebits);
+
+       d = dst + bytes_per_line*2;
+       for (i = 0; i < 4; i++, c++)
+               d[i*2] = CLAMP((*c) >> scalebits);
+
+       d = dst + bytes_per_line*3;
+       for (i = 0; i < 4; i++, c++)
+               d[i*2+1] = CLAMP((*c) >> scalebits);
+#endif
+}
+#endif
+
+/*
+ * To manage the stream, we keep bits in a 32 bits register.
+ * fill_nbits(n): fill the reservoir with at least n bits
+ * skip_bits(n): discard n bits from the reservoir
+ * get_bits(n): fill the reservoir, returns the first n bits and discard the
+ *              bits from the reservoir.
+ * __get_nbits(n): faster version of get_bits(n), but asumes that the reservoir
+ *                 contains at least n bits. bits returned is discarded.
+ */
+#define fill_nbits(pdec, nbits_wanted) do { \
+   while (pdec->nbits_in_reservoir<(nbits_wanted)) \
+    { \
+      pdec->reservoir |= (*(pdec->stream)++) << (pdec->nbits_in_reservoir); \
+      pdec->nbits_in_reservoir += 8; \
+    } \
+}  while(0);
+
+#define skip_nbits(pdec, nbits_to_skip) do { \
+   pdec->reservoir >>= (nbits_to_skip); \
+   pdec->nbits_in_reservoir -= (nbits_to_skip); \
+}  while(0);
+
+#define get_nbits(pdec, nbits_wanted, result) do { \
+   fill_nbits(pdec, nbits_wanted); \
+   result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \
+   skip_nbits(pdec, nbits_wanted); \
+}  while(0);
+
+#define __get_nbits(pdec, nbits_wanted, result) do { \
+   result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \
+   skip_nbits(pdec, nbits_wanted); \
+}  while(0);
+
+#define look_nbits(pdec, nbits_wanted) \
+   ((pdec->reservoir) & ((1U<<(nbits_wanted))-1))
+
+/*
+ * Decode a 4x4 pixel block
+ */
+static void decode_block(struct pwc_dec23_private *pdec,
+                        const unsigned char *ptable0004,
+                        const unsigned char *ptable8004)
+{
+       unsigned int primary_color;
+       unsigned int channel_v, offset1, op;
+       int i;
+
+       fill_nbits(pdec, 16);
+       __get_nbits(pdec, pdec->nbits, primary_color);
+
+       if (look_nbits(pdec,2) == 0) {
+               skip_nbits(pdec, 2);
+               /* Very simple, the color is the same for all pixels of the square */
+               for (i = 0; i < 16; i++)
+                       pdec->temp_colors[i] = pdec->table_dc00[primary_color];
+
+               return;
+       }
+
+       /* This block is encoded with small pattern */
+       for (i = 0; i < 16; i++)
+               pdec->temp_colors[i] = pdec->table_d800[primary_color];
+
+       __get_nbits(pdec, 3, channel_v);
+       channel_v = ((channel_v & 1) << 2) | (channel_v & 2) | ((channel_v & 4) >> 2);
+
+       ptable0004 += (channel_v * 128);
+       ptable8004 += (channel_v * 32);
+
+       offset1 = 0;
+       do
+       {
+               unsigned int htable_idx, rows = 0;
+               const unsigned int *block;
+
+               /* [  zzzz y x x ]
+                *     xx == 00 :=> end of the block def, remove the two bits from the stream
+                *    yxx == 111
+                *    yxx == any other value
+                *
+                */
+               fill_nbits(pdec, 16);
+               htable_idx = look_nbits(pdec, 6);
+               op = hash_table_ops[htable_idx * 4];
+
+               if (op == 2) {
+                       skip_nbits(pdec, 2);
+
+               } else if (op == 1) {
+                       /* 15bits [ xxxx xxxx yyyy 111 ]
+                        * yyy => offset in the table8004
+                        * xxx => offset in the tabled004 (tree)
+                        */
+                       unsigned int mask, shift;
+                       unsigned int nbits, col1;
+                       unsigned int yyyy;
+
+                       skip_nbits(pdec, 3);
+                       /* offset1 += yyyy */
+                       __get_nbits(pdec, 4, yyyy);
+                       offset1 += 1 + yyyy;
+                       offset1 &= 0x0F;
+                       nbits = ptable8004[offset1 * 2];
+
+                       /* col1 = xxxx xxxx */
+                       __get_nbits(pdec, nbits+1, col1);
+
+                       /* Bit mask table */
+                       mask = pdec->table_bitpowermask[nbits][col1];
+                       shift = ptable8004[offset1 * 2 + 1];
+                       rows = ((mask << shift) + 0x80) & 0xFF;
+
+                       block = pdec->table_subblock[rows];
+                       for (i = 0; i < 16; i++)
+                               pdec->temp_colors[i] += block[MulIdx[offset1][i]];
+
+               } else {
+                       /* op == 0
+                        * offset1 is coded on 3 bits
+                        */
+                       unsigned int shift;
+
+                       offset1 += hash_table_ops [htable_idx * 4 + 2];
+                       offset1 &= 0x0F;
+
+                       rows = ptable0004[offset1 + hash_table_ops [htable_idx * 4 + 3]];
+                       block = pdec->table_subblock[rows];
+                       for (i = 0; i < 16; i++)
+                               pdec->temp_colors[i] += block[MulIdx[offset1][i]];
+
+                       shift = hash_table_ops[htable_idx * 4 + 1];
+                       skip_nbits(pdec, shift);
+               }
+
+       } while (op != 2);
+
+}
+
+static void DecompressBand23(struct pwc_dec23_private *pdec,
+                            const unsigned char *rawyuv,
+                            unsigned char *planar_y,
+                            unsigned char *planar_u,
+                            unsigned char *planar_v,
+                            unsigned int   compressed_image_width,
+                            unsigned int   real_image_width)
+{
+       int compression_index, nblocks;
+       const unsigned char *ptable0004;
+       const unsigned char *ptable8004;
+
+       pdec->reservoir = 0;
+       pdec->nbits_in_reservoir = 0;
+       pdec->stream = rawyuv + 1;      /* The first byte of the stream is skipped */
+
+       get_nbits(pdec, 4, compression_index);
+
+       /* pass 1: uncompress Y component */
+       nblocks = compressed_image_width / 4;
+
+       ptable0004 = pdec->table_0004_pass1[compression_index];
+       ptable8004 = pdec->table_8004_pass1[compression_index];
+
+       /* Each block decode a square of 4x4 */
+       while (nblocks) {
+               decode_block(pdec, ptable0004, ptable8004);
+               copy_image_block_Y(pdec->temp_colors, planar_y, real_image_width, pdec->scalebits);
+               planar_y += 4;
+               nblocks--;
+       }
+
+       /* pass 2: uncompress UV component */
+       nblocks = compressed_image_width / 8;
+
+       ptable0004 = pdec->table_0004_pass2[compression_index];
+       ptable8004 = pdec->table_8004_pass2[compression_index];
+
+       /* Each block decode a square of 4x4 */
+       while (nblocks) {
+               decode_block(pdec, ptable0004, ptable8004);
+               copy_image_block_CrCb(pdec->temp_colors, planar_u, real_image_width/2, pdec->scalebits);
+
+               decode_block(pdec, ptable0004, ptable8004);
+               copy_image_block_CrCb(pdec->temp_colors, planar_v, real_image_width/2, pdec->scalebits);
+
+               planar_v += 8;
+               planar_u += 8;
+               nblocks -= 2;
+       }
+
+}
+
+#if ENABLE_BAYER_DECODER
+/*
+ * Size need to be a multiple of 8 in width
+ *
+ * Return a block of four line encoded like this:
+ *
+ *   G R G R G R G R G R G R G R G R
+ *   B G B G B G B G B G B G B G B G
+ *   G R G R G R G R G R G R G R G R
+ *   B G B G B G B G B G B G B G B G
+ *
+ */
+static void DecompressBandBayer(struct pwc_dec23_private *pdec,
+                               const unsigned char *rawyuv,
+                               unsigned char *rgbbayer,
+                               unsigned int   compressed_image_width,
+                               unsigned int   real_image_width)
+{
+       int compression_index, nblocks;
+       const unsigned char *ptable0004;
+       const unsigned char *ptable8004;
+       unsigned char *dest;
+
+       pdec->reservoir = 0;
+       pdec->nbits_in_reservoir = 0;
+       pdec->stream = rawyuv + 1;      /* The first byte of the stream is skipped */
+
+       get_nbits(pdec, 4, compression_index);
+
+       /* pass 1: uncompress RB component */
+       nblocks = compressed_image_width / 4;
+
+       ptable0004 = pdec->table_0004_pass1[compression_index];
+       ptable8004 = pdec->table_8004_pass1[compression_index];
+       dest = rgbbayer;
+
+       /* Each block decode a square of 4x4 */
+       while (nblocks) {
+               decode_block(pdec, ptable0004, ptable8004);
+               copy_image_block_RedBlue(pdec->temp_colors, rgbbayer, real_image_width, pdec->scalebits);
+               dest += 8;
+               nblocks--;
+       }
+
+       /* pass 2: uncompress G component */
+       nblocks = compressed_image_width / 8;
+
+       ptable0004 = pdec->table_0004_pass2[compression_index];
+       ptable8004 = pdec->table_8004_pass2[compression_index];
+
+       /* Each block decode a square of 4x4 */
+       while (nblocks) {
+               decode_block(pdec, ptable0004, ptable8004);
+               copy_image_block_Green(pdec->temp_colors, rgbbayer+1, real_image_width, pdec->scalebits);
+
+               decode_block(pdec, ptable0004, ptable8004);
+               copy_image_block_Green(pdec->temp_colors, rgbbayer+real_image_width, real_image_width, pdec->scalebits);
+
+               rgbbayer += 16;
+               nblocks -= 2;
+       }
+}
+#endif
+
+
+/**
+ *
+ * Uncompress a pwc23 buffer.
+ *
+ * pwc.view: size of the image wanted
+ * pwc.image: size of the image returned by the camera
+ * pwc.offset: (x,y) to displayer image in the view
+ *
+ * src: raw data
+ * dst: image output
+ * flags: PWCX_FLAG_PLANAR or PWCX_FLAG_BAYER
+ */
+void pwc_dec23_decompress(const struct pwc_device *pwc,
+                         const void *src,
+                         void *dst,
+                         int flags)
+{
+       int bandlines_left, stride, bytes_per_block;
+
+       bandlines_left = pwc->image.y / 4;
+       bytes_per_block = pwc->view.x * 4;
+
+       if (flags & PWCX_FLAG_BAYER) {
+#if ENABLE_BAYER_DECODER
+               /* RGB Bayer format */
+               unsigned char *rgbout;
+
+               stride = pwc->view.x * pwc->offset.y;
+               rgbout = dst + stride + pwc->offset.x;
+
+
+               while (bandlines_left--) {
+
+                       DecompressBandBayer(pwc->decompress_data,
+                                           src,
+                                           rgbout,
+                                           pwc->image.x, pwc->view.x);
+
+                       src += pwc->vbandlength;
+                       rgbout += bytes_per_block;
+
+               }
+#else
+               memset(dst, 0, pwc->view.x * pwc->view.y);
+#endif
+
+       } else {
+               /* YUV420P image format */
+               unsigned char *pout_planar_y;
+               unsigned char *pout_planar_u;
+               unsigned char *pout_planar_v;
+               unsigned int   plane_size;
+
+               plane_size = pwc->view.x * pwc->view.y;
+
+               /* offset in Y plane */
+               stride = pwc->view.x * pwc->offset.y;
+               pout_planar_y = dst + stride + pwc->offset.x;
+
+               /* offsets in U/V planes */
+               stride = (pwc->view.x * pwc->offset.y) / 4 + pwc->offset.x / 2;
+               pout_planar_u = dst + plane_size + stride;
+               pout_planar_v = dst + plane_size + plane_size / 4 + stride;
+
+               while (bandlines_left--) {
+
+                       DecompressBand23(pwc->decompress_data,
+                                        src,
+                                        pout_planar_y, pout_planar_u, pout_planar_v,
+                                        pwc->image.x, pwc->view.x);
+                       src += pwc->vbandlength;
+                       pout_planar_y += bytes_per_block;
+                       pout_planar_u += pwc->view.x;
+                       pout_planar_v += pwc->view.x;
+
+               }
+
+       }
+
+}
+
+void pwc_dec23_exit(void)
+{
+       /* Do nothing */
+
+}
+
+/**
+ * Allocate a private structure used by lookup table.
+ * You must call kfree() to free the memory allocated.
+ */
+int pwc_dec23_alloc(struct pwc_device *pwc)
+{
+       pwc->decompress_data = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
+       if (pwc->decompress_data == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc-dec23.h b/drivers/media/video/pwc/pwc-dec23.h
new file mode 100644 (file)
index 0000000..1c55298
--- /dev/null
@@ -0,0 +1,67 @@
+/* Linux driver for Philips webcam
+   (C) 2004-2006 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_DEC23_H
+#define PWC_DEC23_H
+
+#include "pwc.h"
+
+struct pwc_dec23_private
+{
+  unsigned int scalebits;
+  unsigned int nbitsmask, nbits; /* Number of bits of a color in the compressed stream */
+
+  unsigned int reservoir;
+  unsigned int nbits_in_reservoir;
+  const unsigned char *stream;
+  int temp_colors[16];
+
+  unsigned char table_0004_pass1[16][1024];
+  unsigned char table_0004_pass2[16][1024];
+  unsigned char table_8004_pass1[16][256];
+  unsigned char table_8004_pass2[16][256];
+  unsigned int  table_subblock[256][12];
+
+  unsigned char table_bitpowermask[8][256];
+  unsigned int  table_d800[256];
+  unsigned int  table_dc00[256];
+
+};
+
+
+int pwc_dec23_alloc(struct pwc_device *pwc);
+int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd);
+void pwc_dec23_exit(void);
+void pwc_dec23_decompress(const struct pwc_device *pwc,
+                         const void *src,
+                         void *dst,
+                         int flags);
+
+
+
+#endif
+
+
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
+
index 41418294a32bc96440de0180e393c5fdf1c9a48b..47d0d83a0264445fd4f68b61b5e4b9d1f5906b23 100644 (file)
@@ -1,7 +1,7 @@
 /* Linux driver for Philips webcam
    USB and Video4Linux interface part.
    (C) 1999-2004 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 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.
 #include <linux/poll.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/version.h>
 #include <asm/io.h>
+#include <linux/moduleparam.h>
 
 #include "pwc.h"
-#include "pwc-ioctl.h"
 #include "pwc-kiara.h"
 #include "pwc-timon.h"
+#include "pwc-dec23.h"
+#include "pwc-dec1.h"
 #include "pwc-uncompress.h"
 
 /* Function prototypes and driver templates */
 
 /* hotplug device table support */
-static struct usb_device_id pwc_device_table [] = {
+static const struct usb_device_id pwc_device_table [] = {
        { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
        { USB_DEVICE(0x0471, 0x0303) },
        { USB_DEVICE(0x0471, 0x0304) },
@@ -81,9 +84,10 @@ static struct usb_device_id pwc_device_table [] = {
        { USB_DEVICE(0x0471, 0x0308) },
        { USB_DEVICE(0x0471, 0x030C) },
        { USB_DEVICE(0x0471, 0x0310) },
-       { USB_DEVICE(0x0471, 0x0311) },
+       { USB_DEVICE(0x0471, 0x0311) }, /* Philips ToUcam PRO II */
        { USB_DEVICE(0x0471, 0x0312) },
        { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
+       { USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */
        { USB_DEVICE(0x069A, 0x0001) }, /* Askey */
        { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
        { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
@@ -94,8 +98,9 @@ static struct usb_device_id pwc_device_table [] = {
        { 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(0x055D, 0x9000) }, /* Samsung MPC-C10 */
+       { USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */
+       { USB_DEVICE(0x055D, 0x9002) }, /* Samsung SNC-35E (Ver3.0) */
        { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
        { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */
        { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
@@ -122,11 +127,13 @@ static struct usb_driver pwc_driver = {
 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;
+       int pwc_mbufs = 2;      /* Default number of mmap() buffers */
+#if CONFIG_PWC_DEBUG
+       int pwc_trace = PWC_DEBUG_LEVEL;
+#endif
 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 int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */
 static struct {
        int type;
        char serial_number[30];
@@ -138,7 +145,7 @@ static struct {
 
 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,
+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,
@@ -153,7 +160,6 @@ static struct file_operations pwc_fops = {
        .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 = {
@@ -203,52 +209,44 @@ static struct video_device pwc_template = {
 /* 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)
+
+static void *pwc_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;
-               }
-       }
+       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)
+static void pwc_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);
-       }
+       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);
 }
 
 
@@ -256,100 +254,83 @@ static void rvfree(void * mem, unsigned long size)
 
 static int pwc_allocate_buffers(struct pwc_device *pdev)
 {
-       int i;
+       int i, err;
        void *kbuf;
 
-       Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
+       PWC_DEBUG_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 */
+       /* Allocate Isochronuous pipe buffers */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                if (pdev->sbuf[i].data == NULL) {
-                       kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
+                       kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
                        if (kbuf == NULL) {
-                               Err("Failed to allocate iso buffer %d.\n", i);
+                               PWC_ERROR("Failed to allocate iso buffer %d.\n", i);
                                return -ENOMEM;
                        }
-                       Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf);
+                       PWC_DEBUG_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);
+               kbuf = kzalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
                if (kbuf == NULL) {
-                       Err("Failed to allocate frame buffer structure.\n");
+                       PWC_ERROR("Failed to allocate frame buffer structure.\n");
                        return -ENOMEM;
                }
-               Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf);
+               PWC_DEBUG_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);
+                               PWC_ERROR("Failed to allocate frame buffer %d.\n", i);
                                return -ENOMEM;
                        }
-                       Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf);
+                       PWC_DEBUG_MEMORY("Allocated frame buffer %d at %p.\n", i, kbuf);
                        pdev->fbuf[i].data = kbuf;
-                       memset(kbuf, 128, PWC_FRAME_SIZE);
+                       memset(kbuf, 0, 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;
+       if (DEVICE_USE_CODEC1(pdev->type))
+               err = pwc_dec1_alloc(pdev);
+       else
+               err = pwc_dec23_alloc(pdev);
+
+       if (err) {
+               PWC_ERROR("Failed to allocate decompress table.\n");
+               return err;
+       }
 
        /* Allocate image buffer; double buffer for mmap() */
-       kbuf = rvmalloc(default_mbufs * pdev->len_per_image);
+       kbuf = pwc_rvmalloc(pwc_mbufs * pdev->len_per_image);
        if (kbuf == NULL) {
-               Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image);
+               PWC_ERROR("Failed to allocate image buffer(s). needed (%d)\n",
+                               pwc_mbufs * pdev->len_per_image);
                return -ENOMEM;
        }
-       Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf);
+       PWC_DEBUG_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;
+       for (i = 0; i < pwc_mbufs; i++) {
+               pdev->images[i].offset = i * pdev->len_per_image;
+               pdev->images[i].vma_use_count = 0;
+       }
+       for (; i < MAX_IMAGES; i++) {
+               pdev->images[i].offset = 0;
+       }
 
        kbuf = NULL;
 
-       Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n");
+       PWC_DEBUG_MEMORY("<< pwc_allocate_buffers()\n");
        return 0;
 }
 
@@ -357,21 +338,14 @@ static void pwc_free_buffers(struct pwc_device *pdev)
 {
        int i;
 
-       Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev);
+       PWC_DEBUG_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);
+                       PWC_DEBUG_MEMORY("Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
                        kfree(pdev->sbuf[i].data);
                        pdev->sbuf[i].data = NULL;
                }
@@ -380,7 +354,7 @@ static void pwc_free_buffers(struct pwc_device *pdev)
        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);
+                               PWC_DEBUG_MEMORY("Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
                                vfree(pdev->fbuf[i].data);
                                pdev->fbuf[i].data = NULL;
                        }
@@ -391,20 +365,19 @@ static void pwc_free_buffers(struct pwc_device *pdev)
 
        /* Intermediate decompression buffer & tables */
        if (pdev->decompress_data != NULL) {
-               Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data);
+               PWC_DEBUG_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);
+               PWC_DEBUG_MEMORY("Freeing image buffer at %p.\n", pdev->image_data);
+               pwc_rvfree(pdev->image_data, pwc_mbufs * pdev->len_per_image);
        }
        pdev->image_data = NULL;
 
-       Trace(TRACE_MEMORY, "Leaving free_buffers().\n");
+       PWC_DEBUG_MEMORY("Leaving free_buffers().\n");
 }
 
 /* The frame & image buffer mess.
@@ -464,7 +437,7 @@ static void pwc_free_buffers(struct pwc_device *pdev)
 /**
   \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)
+static int pwc_next_fill_frame(struct pwc_device *pdev)
 {
        int ret;
        unsigned long flags;
@@ -489,23 +462,17 @@ static inline int pwc_next_fill_frame(struct pwc_device *pdev)
        }
        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");
+                       PWC_ERROR("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;
 }
@@ -521,6 +488,8 @@ static void pwc_reset_buffers(struct pwc_device *pdev)
        int i;
        unsigned long flags;
 
+       PWC_DEBUG_MEMORY(">> %s __enter__\n", __FUNCTION__);
+
        spin_lock_irqsave(&pdev->ptrlock, flags);
        pdev->full_frames = NULL;
        pdev->full_frames_tail = NULL;
@@ -540,13 +509,15 @@ static void pwc_reset_buffers(struct pwc_device *pdev)
        pdev->image_read_pos = 0;
        pdev->fill_image = 0;
        spin_unlock_irqrestore(&pdev->ptrlock, flags);
+
+       PWC_DEBUG_MEMORY("<< %s __leaving__\n", __FUNCTION__);
 }
 
 
 /**
   \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers.
  */
-static int pwc_handle_frame(struct pwc_device *pdev)
+int pwc_handle_frame(struct pwc_device *pdev)
 {
        int ret = 0;
        unsigned long flags;
@@ -556,41 +527,40 @@ static int pwc_handle_frame(struct pwc_device *pdev)
           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");
+               PWC_ERROR("Huh? Read frame still in use?\n");
+               spin_unlock_irqrestore(&pdev->ptrlock, flags);
+               return ret;
+       }
+
+
+       if (pdev->full_frames == NULL) {
+               PWC_ERROR("Woops. No frames ready.\n");
        }
        else {
-               if (pdev->full_frames == NULL) {
-                       Err("Woops. No frames ready.\n");
+               pdev->read_frame = pdev->full_frames;
+               pdev->full_frames = pdev->full_frames->next;
+               pdev->read_frame->next = NULL;
+       }
+
+       if (pdev->read_frame != NULL) {
+               /* 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->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;
+                       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;
@@ -599,12 +569,114 @@ static int pwc_handle_frame(struct pwc_device *pdev)
 /**
   \brief Advance pointers of image buffer (after each user request)
 */
-static inline void pwc_next_image(struct pwc_device *pdev)
+void pwc_next_image(struct pwc_device *pdev)
 {
        pdev->image_used[pdev->fill_image] = 0;
-       pdev->fill_image = (pdev->fill_image + 1) % default_mbufs;
+       pdev->fill_image = (pdev->fill_image + 1) % pwc_mbufs;
 }
 
+/**
+ * Print debug information when a frame is discarded because all of our buffer
+ * is full
+ */
+static void pwc_frame_dumped(struct pwc_device *pdev)
+{
+       pdev->vframes_dumped++;
+       if (pdev->vframe_count < FRAME_LOWMARK)
+               return;
+
+       if (pdev->vframes_dumped < 20)
+               PWC_DEBUG_FLOW("Dumping frame %d\n", pdev->vframe_count);
+       else if (pdev->vframes_dumped == 20)
+               PWC_DEBUG_FLOW("Dumping frame %d (last message)\n",
+                               pdev->vframe_count);
+}
+
+static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_buf *fbuf)
+{
+       int awake = 0;
+
+       /* 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) {
+                       PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n");
+                       pdev->drop_frames += 2;
+                       pdev->vframes_error++;
+               }
+               if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+                       if (ptr[0] & 0x01) {
+                               pdev->snapshot_button_status = 1;
+                               PWC_TRACE("Snapshot button pressed.\n");
+                       }
+                       else {
+                               PWC_TRACE("Snapshot button released.\n");
+                       }
+               }
+               if ((ptr[0] ^ pdev->vmirror) & 0x02) {
+                       if (ptr[0] & 0x02)
+                               PWC_TRACE("Image is mirrored.\n");
+                       else
+                               PWC_TRACE("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++;
+       }
+       else if (pdev->type == 740 || pdev->type == 720) {
+               unsigned char *ptr = (unsigned char *)fbuf->data;
+               if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+                       if (ptr[0] & 0x01) {
+                               pdev->snapshot_button_status = 1;
+                               PWC_TRACE("Snapshot button pressed.\n");
+                       }
+                       else
+                               PWC_TRACE("Snapshot button released.\n");
+               }
+               pdev->vmirror = ptr[0] & 0x03;
+       }
+
+       /* 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) {
+                       PWC_DEBUG_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))
+                               pwc_frame_dumped(pdev);
+
+               }
+       } /* !drop_frames */
+       pdev->vframe_count++;
+       return awake;
+}
 
 /* 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.
@@ -620,17 +692,12 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
        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");
+               PWC_ERROR("isoc_handler() called with NULL device?!\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");
+               PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
                return;
        }
        if (urb->status != -EINPROGRESS && urb->status != 0) {
@@ -645,13 +712,13 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
                        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);
+               PWC_DEBUG_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");
+                       PWC_INFO("Too many ISOC errors, bailing out.\n");
                        pdev->error_status = EIO;
                        awake = 1;
                        wake_up_interruptible(&pdev->frameq);
@@ -661,7 +728,7 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
 
        fbuf = pdev->fill_frame;
        if (fbuf == NULL) {
-               Err("pwc_isoc_handler without valid fill frame.\n");
+               PWC_ERROR("pwc_isoc_handler without valid fill frame.\n");
                awake = 1;
                goto handler_end;
        }
@@ -688,7 +755,7 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
 
                                        /* ...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);
+                                               PWC_DEBUG_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++;
                                        }
@@ -704,96 +771,28 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
                                /* 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++;
+                                       if (pwc_rcv_short_packet(pdev, fbuf)) {
+                                               awake = 1;
+                                               fbuf = pdev->fill_frame;
                                        }
-
-                                       /* 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 {
+                       /* This is normally not interesting to the user, unless
+                        * you are really debugging something */
                        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);
+                               PWC_DEBUG_FLOW("Iso frame %d of USB has error %d\n", i, fst);
                }
-#endif
        }
 
 handler_end:
@@ -803,11 +802,11 @@ handler_end:
        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);
+               PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
 }
 
 
-static int pwc_isoc_init(struct pwc_device *pdev)
+int pwc_isoc_init(struct pwc_device *pdev)
 {
        struct usb_device *udev;
        struct urb *urb;
@@ -826,7 +825,6 @@ static int pwc_isoc_init(struct pwc_device *pdev)
        /* 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);
@@ -836,20 +834,21 @@ static int pwc_isoc_init(struct pwc_device *pdev)
 
        /* Search video endpoint */
        pdev->vmax_packet_size = -1;
-       for (i = 0; i < idesc->desc.bNumEndpoints; i++)
+       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");
+               PWC_ERROR("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);
+       PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate);
        ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
        if (ret < 0)
                return ret;
@@ -857,12 +856,12 @@ static int pwc_isoc_init(struct pwc_device *pdev)
        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);
+                       PWC_ERROR("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);
+               PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb);
        }
        if (ret) {
                /* De-allocate in reverse order */
@@ -899,24 +898,26 @@ static int pwc_isoc_init(struct pwc_device *pdev)
        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);
+                       PWC_ERROR("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);
+                       PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb);
        }
 
        /* All is done... */
        pdev->iso_init = 1;
-       Trace(TRACE_OPEN, "<< pwc_isoc_init()\n");
+       PWC_DEBUG_OPEN("<< pwc_isoc_init()\n");
        return 0;
 }
 
-static void pwc_isoc_cleanup(struct pwc_device *pdev)
+void pwc_isoc_cleanup(struct pwc_device *pdev)
 {
        int i;
 
-       Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n");
+       PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
        if (pdev == NULL)
                return;
+       if (pdev->iso_init == 0)
+               return;
 
        /* Unlinking ISOC buffers one by one */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
@@ -925,10 +926,10 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev)
                urb = pdev->sbuf[i].urb;
                if (urb != 0) {
                        if (pdev->iso_init) {
-                               Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb);
+                               PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
                                usb_kill_urb(urb);
                        }
-                       Trace(TRACE_MEMORY, "Freeing URB\n");
+                       PWC_DEBUG_MEMORY("Freeing URB\n");
                        usb_free_urb(urb);
                        pdev->sbuf[i].urb = NULL;
                }
@@ -938,12 +939,12 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev)
           is signalled by EPIPE)
         */
        if (pdev->error_status && pdev->error_status != EPIPE) {
-               Trace(TRACE_OPEN, "Setting alternate interface 0.\n");
+               PWC_DEBUG_OPEN("Setting alternate interface 0.\n");
                usb_set_interface(pdev->udev, 0, 0);
        }
 
        pdev->iso_init = 0;
-       Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n");
+       PWC_DEBUG_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)
@@ -957,18 +958,18 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f
        /* 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");
+               PWC_DEBUG_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");
+                       PWC_DEBUG_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");
+                       PWC_WARNING("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 */
                }
        }
@@ -976,54 +977,129 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f
        return ret; /* Return original error code */
 }
 
+/*********
+ * sysfs
+ *********/
+static struct pwc_device *cd_to_pwc(struct class_device *cd)
+{
+       struct video_device *vdev = to_video_device(cd);
+       return video_get_drvdata(vdev);
+}
+
+static ssize_t show_pan_tilt(struct class_device *class_dev, char *buf)
+{
+       struct pwc_device *pdev = cd_to_pwc(class_dev);
+       return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle);
+}
+
+static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf,
+                        size_t count)
+{
+       struct pwc_device *pdev = cd_to_pwc(class_dev);
+       int pan, tilt;
+       int ret = -EINVAL;
+
+       if (strncmp(buf, "reset", 5) == 0)
+               ret = pwc_mpt_reset(pdev, 0x3);
+
+       else if (sscanf(buf, "%d %d", &pan, &tilt) > 0)
+               ret = pwc_mpt_set_angle(pdev, pan, tilt);
+
+       if (ret < 0)
+               return ret;
+       return strlen(buf);
+}
+static CLASS_DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
+                        store_pan_tilt);
+
+static ssize_t show_snapshot_button_status(struct class_device *class_dev, char *buf)
+{
+       struct pwc_device *pdev = cd_to_pwc(class_dev);
+       int status = pdev->snapshot_button_status;
+       pdev->snapshot_button_status = 0;
+       return sprintf(buf, "%d\n", status);
+}
+
+static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
+                        NULL);
+
+static void pwc_create_sysfs_files(struct video_device *vdev)
+{
+       struct pwc_device *pdev = video_get_drvdata(vdev);
+       if (pdev->features & FEATURE_MOTOR_PANTILT)
+               video_device_create_file(vdev, &class_device_attr_pan_tilt);
+       video_device_create_file(vdev, &class_device_attr_button);
+}
+
+static void pwc_remove_sysfs_files(struct video_device *vdev)
+{
+       struct pwc_device *pdev = video_get_drvdata(vdev);
+       if (pdev->features & FEATURE_MOTOR_PANTILT)
+               video_device_remove_file(vdev, &class_device_attr_pan_tilt);
+       video_device_remove_file(vdev, &class_device_attr_button);
+}
+
+#if CONFIG_PWC_DEBUG
+static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
+{
+       switch(sensor_type) {
+               case 0x00:
+                       return "Hyundai CMOS sensor";
+               case 0x20:
+                       return "Sony CCD sensor + TDA8787";
+               case 0x2E:
+                       return "Sony CCD sensor + Exas 98L59";
+               case 0x2F:
+                       return "Sony CCD sensor + ADI 9804";
+               case 0x30:
+                       return "Sharp CCD sensor + TDA8787";
+               case 0x3E:
+                       return "Sharp CCD sensor + Exas 98L59";
+               case 0x3F:
+                       return "Sharp CCD sensor + ADI 9804";
+               case 0x40:
+                       return "UPA 1021 sensor";
+               case 0x100:
+                       return "VGA sensor";
+               case 0x101:
+                       return "PAL MR sensor";
+               default:
+                       return "unknown type of sensor";
+       }
+}
+#endif
 
 /***************************************************************************/
 /* Video4Linux functions */
 
 static int pwc_video_open(struct inode *inode, struct file *file)
 {
-       int i;
+       int i, ret;
        struct video_device *vdev = video_devdata(file);
        struct pwc_device *pdev;
 
-       Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev);
+       PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev);
 
        pdev = (struct pwc_device *)vdev->priv;
        if (pdev == NULL)
                BUG();
-       if (pdev->vopen)
+       if (pdev->vopen) {
+               PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n");
                return -EBUSY;
+       }
 
        down(&pdev->modlock);
        if (!pdev->usb_init) {
-               Trace(TRACE_OPEN, "Doing first time initialization.\n");
+               PWC_DEBUG_OPEN("Doing first time initialization.\n");
                pdev->usb_init = 1;
 
-               if (pwc_trace & TRACE_OPEN)
+               /* Query sensor type */
+               ret = pwc_get_cmos_sensor(pdev, &i);
+               if (ret >= 0)
                {
-                       /* 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);
+                       PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
+                                       pdev->vdev->name,
+                                       pwc_sensor_type_to_string(i), i);
                }
        }
 
@@ -1031,34 +1107,32 @@ static int pwc_video_open(struct inode *inode, struct file *file)
        if (power_save) {
                i = pwc_camera_power(pdev, 1);
                if (i < 0)
-                       Info("Failed to restore power to the camera! (%d)\n", i);
+                       PWC_DEBUG_OPEN("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_DEBUG_OPEN("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");
+               PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");
+               pwc_free_buffers(pdev);
                up(&pdev->modlock);
                return i;
        }
 
        /* Reset buffers & parameters */
        pwc_reset_buffers(pdev);
-       for (i = 0; i < default_mbufs; i++)
+       for (i = 0; i < pwc_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 */
@@ -1070,29 +1144,44 @@ static int pwc_video_open(struct inode *inode, struct file *file)
         */
        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);
+               unsigned int default_resolution;
+               PWC_DEBUG_OPEN("First attempt at set_video_mode failed.\n");
+               if (pdev->type>= 730)
+                       default_resolution = PSZ_QSIF;
                else
-                       i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0);
+                       default_resolution = PSZ_QCIF;
+
+               i = pwc_set_video_mode(pdev,
+                                      pwc_image_sizes[default_resolution].x,
+                                      pwc_image_sizes[default_resolution].y,
+                                      10,
+                                      pdev->vcompression,
+                                      0);
        }
        if (i) {
-               Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n");
+               PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");
+               pwc_free_buffers(pdev);
                up(&pdev->modlock);
                return i;
        }
 
        i = pwc_isoc_init(pdev);
        if (i) {
-               Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i);
+               PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i);
+               pwc_isoc_cleanup(pdev);
+               pwc_free_buffers(pdev);
                up(&pdev->modlock);
                return i;
        }
 
+       /* Initialize the webcam to sane value */
+       pwc_set_brightness(pdev, 0x7fff);
+       pwc_set_agc(pdev, 1, 0);
+
        pdev->vopen++;
        file->private_data = vdev;
        up(&pdev->modlock);
-       Trace(TRACE_OPEN, "<< video_open() returns 0.\n");
+       PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
        return 0;
 }
 
@@ -1103,35 +1192,23 @@ static int pwc_video_close(struct inode *inode, struct file *file)
        struct pwc_device *pdev;
        int i;
 
-       Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev);
+       PWC_DEBUG_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");
+               PWC_DEBUG_MODULE("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);
+               PWC_DEBUG_MODULE("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;
-        }
+       if (DEVICE_USE_CODEC1(pdev->type))
+           pwc_dec1_exit();
+       else
+           pwc_dec23_exit();
 
        pwc_isoc_cleanup(pdev);
        pwc_free_buffers(pdev);
@@ -1140,15 +1217,15 @@ static int pwc_video_close(struct inode *inode, struct file *file)
        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");
+                       PWC_DEBUG_MODULE("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);
+                               PWC_ERROR("Failed to power down camera (%d)\n", i);
                }
        }
-       pdev->vopen = 0;
-       Trace(TRACE_OPEN, "<< video_close()\n");
+       pdev->vopen--;
+       PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
        return 0;
 }
 
@@ -1164,7 +1241,7 @@ static int pwc_video_close(struct inode *inode, struct file *file)
                device is tricky anyhow.
  */
 
-static ssize_t pwc_video_read(struct file *file, char __user * buf,
+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;
@@ -1172,8 +1249,10 @@ static ssize_t pwc_video_read(struct file *file, char __user * buf,
        int noblock = file->f_flags & O_NONBLOCK;
        DECLARE_WAITQUEUE(wait, current);
        int bytes_to_read;
+       void *image_buffer_addr;
 
-       Trace(TRACE_READ, "video_read(0x%p, %p, %zu) called.\n", vdev, buf, count);
+       PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n",
+                       vdev, buf, count);
        if (vdev == NULL)
                return -EFAULT;
        pdev = vdev->priv;
@@ -1214,16 +1293,19 @@ static ssize_t pwc_video_read(struct file *file, char __user * buf,
                        return -EFAULT;
        }
 
-       Trace(TRACE_READ, "Copying data to user space.\n");
+       PWC_DEBUG_READ("Copying data to user space.\n");
        if (pdev->vpalette == VIDEO_PALETTE_RAW)
-               bytes_to_read = pdev->frame_size;
+               bytes_to_read = pdev->frame_size + sizeof(struct pwc_raw_frame);
        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))
+       image_buffer_addr = pdev->image_data;
+       image_buffer_addr += pdev->images[pdev->fill_image].offset;
+       image_buffer_addr += pdev->image_read_pos;
+       if (copy_to_user(buf, image_buffer_addr, count))
                return -EFAULT;
        pdev->image_read_pos += count;
        if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
@@ -1253,370 +1335,56 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
        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;
+       unsigned long start;
+       unsigned long size;
+       unsigned long page, pos = 0;
+       int index;
 
-       Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size);
+       PWC_DEBUG_MEMORY(">> %s\n", __FUNCTION__);
        pdev = vdev->priv;
+       size = vma->vm_end - vma->vm_start;
+       start = vma->vm_start;
 
-       vma->vm_flags |= VM_IO;
+       /* Find the idx buffer for this mapping */
+       for (index = 0; index < pwc_mbufs; index++) {
+               pos = pdev->images[index].offset;
+               if ((pos>>PAGE_SHIFT) == vma->vm_pgoff)
+                       break;
+       }
+       if (index == MAX_IMAGES)
+               return -EINVAL;
+       if (index == 0) {
+               /*
+                * Special case for v4l1. In v4l1, we map only one big buffer,
+                * but in v4l2 each buffer is mapped
+                */
+               unsigned long total_size;
+               total_size = pwc_mbufs * pdev->len_per_image;
+               if (size != pdev->len_per_image && size != total_size) {
+                       PWC_ERROR("Wrong size (%lu) needed to be len_per_image=%d or total_size=%lu\n",
+                                  size, pdev->len_per_image, total_size);
+                       return -EINVAL;
+               }
+       } else if (size > pdev->len_per_image)
+               return -EINVAL;
 
-       pos = (unsigned long)pdev->image_data;
+       vma->vm_flags |= VM_IO; /* from 2.6.9-acX */
+
+       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)
@@ -1624,7 +1392,6 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
                else
                        size = 0;
        }
-
        return 0;
 }
 
@@ -1645,10 +1412,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        int video_nr = -1; /* default: use next available device */
        char serial_number[30], *name;
 
+       vendor_id = le16_to_cpu(udev->descriptor.idVendor);
+       product_id = le16_to_cpu(udev->descriptor.idProduct);
+
        /* 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),
+       PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n",
+               vendor_id, product_id,
                intf->altsetting->desc.bInterfaceNumber);
 
        /* the interfaces are probed one by one. We are only interested in the
@@ -1658,61 +1427,63 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        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");
+                       PWC_INFO("Philips PCA645VC USB webcam detected.\n");
                        name = "Philips 645 webcam";
                        type_id = 645;
                        break;
                case 0x0303:
-                       Info("Philips PCA646VC USB webcam detected.\n");
+                       PWC_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");
+                       PWC_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");
+                       PWC_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");
+                       PWC_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");
+                       PWC_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");
+                       PWC_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");
+                       PWC_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");
+                       PWC_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");
+                       PWC_INFO("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
                        name = "Philips 720K/40 webcam";
                        type_id = 720;
                        break;
+               case 0x0329:
+                       PWC_INFO("Philips SPC 900NC USB webcam detected.\n");
+                       name = "Philips SPC 900NC webcam";
+                       type_id = 720;
+                       break;
                default:
                        return -ENODEV;
                        break;
@@ -1721,7 +1492,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        else if (vendor_id == 0x069A) {
                switch(product_id) {
                case 0x0001:
-                       Info("Askey VC010 type 1 USB webcam detected.\n");
+                       PWC_INFO("Askey VC010 type 1 USB webcam detected.\n");
                        name = "Askey VC010 webcam";
                        type_id = 645;
                        break;
@@ -1733,32 +1504,33 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        else if (vendor_id == 0x046d) {
                switch(product_id) {
                case 0x08b0:
-                       Info("Logitech QuickCam Pro 3000 USB webcam detected.\n");
+                       PWC_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");
+                       PWC_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");
+                       PWC_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");
+                       PWC_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");
+                       PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
                        name = "Logitech QuickCam Zoom";
                        type_id = 740; /* CCD sensor */
+                       power_save = 1;
                        break;
                case 0x08b5:
-                       Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
+                       PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
                        name = "Logitech QuickCam Orbit";
                        type_id = 740; /* CCD sensor */
                        features |= FEATURE_MOTOR_PANTILT;
@@ -1766,7 +1538,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                case 0x08b6:
                case 0x08b7:
                case 0x08b8:
-                       Info("Logitech QuickCam detected (reserved ID).\n");
+                       PWC_INFO("Logitech QuickCam detected (reserved ID).\n");
                        name = "Logitech QuickCam (res.)";
                        type_id = 730; /* Assuming CMOS */
                        break;
@@ -1782,15 +1554,20 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                 */
                switch(product_id) {
                case 0x9000:
-                       Info("Samsung MPC-C10 USB webcam detected.\n");
+                       PWC_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");
+                       PWC_INFO("Samsung MPC-C30 USB webcam detected.\n");
                        name = "Samsung MPC-C30";
                        type_id = 675;
                        break;
+               case 0x9002:
+                       PWC_INFO("Samsung SNC-35E (v3.0) USB webcam detected.\n");
+                       name = "Samsung MPC-C30";
+                       type_id = 740;
+                       break;
                default:
                        return -ENODEV;
                        break;
@@ -1799,12 +1576,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        else if (vendor_id == 0x041e) {
                switch(product_id) {
                case 0x400c:
-                       Info("Creative Labs Webcam 5 detected.\n");
+                       PWC_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");
+                       PWC_INFO("Creative Labs Webcam Pro Ex detected.\n");
                        name = "Creative Labs Webcam Pro Ex";
                        type_id = 740;
                        break;
@@ -1816,7 +1593,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        else if (vendor_id == 0x04cc) {
                switch(product_id) {
                case 0x8116:
-                       Info("Sotec Afina Eye USB webcam detected.\n");
+                       PWC_INFO("Sotec Afina Eye USB webcam detected.\n");
                        name = "Sotec Afina Eye";
                        type_id = 730;
                        break;
@@ -1829,7 +1606,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                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");
+                       PWC_INFO("AME Co. Afina Eye USB webcam detected.\n");
                        name = "AME Co. Afina Eye";
                        type_id = 750;
                        break;
@@ -1842,12 +1619,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        else if (vendor_id == 0x0d81) {
                switch(product_id) {
                case 0x1900:
-                       Info("Visionite VCS-UC300 USB webcam detected.\n");
+                       PWC_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");
+                       PWC_INFO("Visionite VCS-UM100 USB webcam detected.\n");
                        name = "Visionite VCS-UM100";
                        type_id = 730; /* CMOS sensor */
                        break;
@@ -1861,15 +1638,15 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
 
        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);
+       PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number);
 
        if (udev->descriptor.bNumConfigurations > 1)
-               Info("Warning: more than 1 configuration available.\n");
+               PWC_WARNING("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");
+               PWC_ERROR("Oops, could not allocate memory for pwc_device.\n");
                return -ENOMEM;
        }
        pdev->type = type_id;
@@ -1900,17 +1677,18 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        pdev->vdev = video_device_alloc();
        if (pdev->vdev == 0)
        {
-               Err("Err, cannot allocate video_device struture. Failing probe.");
+               PWC_ERROR("Err, cannot allocate video_device struture. Failing probe.");
                kfree(pdev);
                return -ENOMEM;
        }
        memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
+       pdev->vdev->dev = &(udev->dev);
        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);
+       PWC_DEBUG_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++) {
@@ -1918,10 +1696,10 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                     (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;
+                               /* match! */
+                               video_nr = device_hint[hint].device_node;
+                               PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr);
+                               break;
                        }
                }
        }
@@ -1929,21 +1707,27 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        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);
+               PWC_ERROR("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);
+               PWC_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);
+       PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
        usb_set_intfdata (intf, pdev);
+       pwc_create_sysfs_files(pdev->vdev);
+
+       /* Set the leds off */
+       pwc_set_leds(pdev, 0, 0);
+       pwc_camera_power(pdev, 0);
+
        return 0;
 }
 
@@ -1957,27 +1741,21 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
        pdev = usb_get_intfdata (intf);
        usb_set_intfdata (intf, NULL);
        if (pdev == NULL) {
-               Err("pwc_disconnect() Called without private pointer.\n");
+               PWC_ERROR("pwc_disconnect() Called without private pointer.\n");
                goto disconnect_out;
        }
        if (pdev->udev == NULL) {
-               Err("pwc_disconnect() already called for %p\n", pdev);
+               PWC_ERROR("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");
+               PWC_ERROR("pwc_disconnect() Woops: pointer mismatch udev/pdev.\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");
+               PWC_INFO("Disconnected while webcam is in use!\n");
                pdev->error_status = EPIPE;
        }
 
@@ -1987,7 +1765,8 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
        while (pdev->vopen)
                schedule();
        /* Device is now closed, so we can safely unregister it */
-       Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n");
+       PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
+       pwc_remove_sysfs_files(pdev->vdev);
        video_unregister_device(pdev->vdev);
 
        /* Free memory (don't set pdev to 0 just yet) */
@@ -2021,58 +1800,64 @@ static int pwc_atoi(const char *s)
  * 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 char *size;
+static int fps;
+static int fbufs;
+static int mbufs;
 static int compression = -1;
 static int leds[2] = { -1, -1 };
-static char *dev_hint[MAX_DEV_HINTS] = { };
+static int leds_nargs;
+static char *dev_hint[MAX_DEV_HINTS];
+static int dev_hint_nargs;
+
+module_param(size, charp, 0444);
+module_param(fps, int, 0444);
+module_param(fbufs, int, 0444);
+module_param(mbufs, int, 0444);
+#if CONFIG_PWC_DEBUG
+module_param_named(trace, pwc_trace, int, 0644);
+#endif
+module_param(power_save, int, 0444);
+module_param(compression, int, 0444);
+module_param_array(leds, int, &leds_nargs, 0444);
+module_param_array(dev_hint, charp, &dev_hint_nargs, 0444);
 
-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");
+MODULE_ALIAS("pwcx");
+MODULE_VERSION( PWC_VERSION );
 
 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");
+       PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n");
+       PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
+       PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
+       PWC_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");
+                       PWC_ERROR("Framerate out of bounds (4-30).\n");
                        return -EINVAL;
                }
                default_fps = fps;
-               Info("Default framerate set to %d.\n", default_fps);
+               PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps);
        }
 
-       if (size[0]) {
+       if (size) {
                /* string; try matching with array */
                for (sz = 0; sz < PSZ_MAX; sz++) {
                        if (!strcmp(sizenames[sz], size)) { /* Found! */
@@ -2081,41 +1866,42 @@ static int __init usb_pwc_init(void)
                        }
                }
                if (sz == PSZ_MAX) {
-                       Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
+                       PWC_ERROR("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);
+               PWC_DEBUG_MODULE("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);
+                       PWC_ERROR("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);
+               pwc_mbufs = mbufs;
+               PWC_DEBUG_MODULE("Number of image buffers set to %d.\n", pwc_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);
+                       PWC_ERROR("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);
+               PWC_DEBUG_MODULE("Number of frame buffers set to %d.\n", default_fbufs);
        }
-       if (trace >= 0) {
-               Info("Trace options: 0x%04x\n", trace);
-               pwc_trace = trace;
+#if CONFIG_PWC_DEBUG
+       if (pwc_trace >= 0) {
+               PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
        }
+#endif
        if (compression >= 0) {
                if (compression > 3) {
-                       Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
+                       PWC_ERROR("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);
+               PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression);
        }
        if (power_save)
-               Info("Enabling power save on open/close.\n");
+               PWC_DEBUG_MODULE("Enabling power save on open/close.\n");
        if (leds[0] >= 0)
                led_on = leds[0];
        if (leds[1] >= 0)
@@ -2146,14 +1932,14 @@ static int __init usb_pwc_init(void)
                                dot++;
                        /* Few sanity checks */
                        if (*dot != '\0' && dot > colon) {
-                               Err("Malformed camera hint: the colon must be after the dot.\n");
+                               PWC_ERROR("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");
+                                       PWC_ERROR("Malformed camera hint: no colon + device node given.\n");
                                        return -EINVAL;
                                }
                                else {
@@ -2178,28 +1964,27 @@ static int __init usb_pwc_init(void)
                                        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
+                       PWC_TRACE("device_hint[%d]:\n", i);
+                       PWC_TRACE("  type    : %d\n", device_hint[i].type);
+                       PWC_TRACE("  serial# : %s\n", device_hint[i].serial_number);
+                       PWC_TRACE("  node    : %d\n", device_hint[i].device_node);
                }
                else
                        device_hint[i].type = 0; /* not filled */
        } /* ..for MAX_DEV_HINTS */
 
-       Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver);
+       PWC_DEBUG_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");
+       PWC_DEBUG_MODULE("Deregistering driver.\n");
        usb_deregister(&pwc_driver);
-       Info("Philips webcam module removed.\n");
+       PWC_INFO("Philips webcam module removed.\n");
 }
 
 module_init(usb_pwc_init);
 module_exit(usb_pwc_exit);
 
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
index 4c96037f7be5f71b140cd7b188797ab9311fcf06..fec39cc5a9f1c93eec4b71e7459eebff3e10a099 100644 (file)
@@ -1,5 +1,5 @@
 /* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 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.
@@ -316,3 +316,576 @@ const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] =
    },
 };
 
+
+/*
+ * Rom table for kiara chips
+ *
+ * 32 roms tables (one for each resolution ?)
+ *  2 tables per roms (one for each passes) (Y, and U&V)
+ * 128 bytes per passes
+ */
+
+const unsigned int KiaraRomTable [8][2][16][8] =
+{
+ { /* version 0 */
+  { /* version 0, passes 0 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000001,0x00000001},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000009,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x0000124a,0x00009252,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00009252,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009292,0x00009292,0x00009493,0x000124db},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x0000a493,0x000124db,0x000124db,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x000124db,0x000126dc,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000124db,0x000136e4,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 0, passes 1 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000001,0x00000009,
+    0x00000009,0x00000009,0x00000009,0x00000001},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00001252},
+   {0x00000000,0x00000000,0x00000049,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009252,0x00009292,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009292,0x00009292,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00009292,
+    0x00009492,0x00009493,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009252,0x00009493,
+    0x000126dc,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x000136e4,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 1 */
+  { /* version 1, passes 0 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000001},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009252,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00009252,
+    0x00009492,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 1, passes 1 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000009,
+    0x00000049,0x00000009,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000000},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000249,0x00000049,0x0000024a,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000009},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009252,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009292,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009292,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009292,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x0000924a,0x0000924a,
+    0x00009492,0x00009493,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 2 */
+  { /* version 2, passes 0 */
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009493,0x00009493,0x0000a49b},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000124db,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x00009252,0x000124db,
+    0x000126dc,0x0001b724,0x0001b725,0x0001b925},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 2, passes 1 */
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x0000124a,0x0000124a,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x0000a49b,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00009252,0x0000a49b,
+    0x0001249b,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 3 */
+  { /* version 3, passes 0 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000136e4,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x0001b725,0x0001b925},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x000136e4,0x0001b925,0x00025bb6,0x00024b77},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 3, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x000126dc,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000136e4,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 4 */
+  { /* version 4, passes 0 */
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000249,0x00000249,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x00009252,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0001249b,0x000126dc,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00009252,0x00009493,
+    0x000124db,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009252,0x0000a49b,
+    0x000124db,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 4, passes 1 */
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000049,0x00000049,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00000249,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009252,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x00009252,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009493,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009252,0x000124db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 5 */
+  { /* version 5, passes 0 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x000136e4},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001c96e,0x0001b925},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001c924,0x0002496d,0x00025bb6,0x00024b77},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 5, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009252,0x00009252,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000126dc,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 6 */
+  { /* version 6, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0002496e},
+   {0x00000000,0x00000000,0x00012492,0x000126db,
+    0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 6, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x00009252,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009292,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000124db,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000126dc,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 7 */
+  { /* version 7, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x0000a49b,
+    0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b725,0x000124db},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001c96e,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001b925},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b924,0x0001c92d,0x00024b76,0x0002496e},
+   {0x00000000,0x00000000,0x00012492,0x000136db,
+    0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 7, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x00009492,0x00009292,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000124db,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000136db,
+    0x0001b724,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000136db,
+    0x0001b724,0x000126dc,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00009292,0x000136db,
+    0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00012492,0x0001b6db,
+    0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ }
+};
+
index 12929abbb1f0c54ba1ed1c9e9b20de93b7c02d0b..0bdb22547d866e2f1d0778173350422b9a729125 100644 (file)
@@ -1,5 +1,5 @@
 /* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 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.
@@ -27,7 +27,7 @@
 #ifndef PWC_KIARA_H
 #define PWC_KIARA_H
 
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
 
 struct Kiara_table_entry
 {
@@ -37,8 +37,8 @@ struct Kiara_table_entry
        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];
+extern const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4];
+extern const unsigned int KiaraRomTable[8][2][16][8];
 
 #endif
 
index 58fe7974799261ceb45198b4d4e4dc624043a8e4..589c687439da3dc7e992f0758b5eb8616e72448c 100644 (file)
@@ -1,7 +1,7 @@
 /* Linux driver for Philips webcam
    Various miscellaneous functions and tables.
    (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 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.
    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] =
+const 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 },
+       { 128,  96, 0 }, /* sqcif */
+       { 160, 120, 0 }, /* qsif */
+       { 176, 144, 0 }, /* qcif */
+       { 320, 240, 0 }, /* sif */
+       { 352, 288, 0 }, /* cif */
+       { 640, 480, 0 }, /* vga */
 };
 
 /* x,y -> PSZ_ */
@@ -52,7 +51,7 @@ int pwc_decode_size(struct pwc_device *pdev, int width, int height)
        {
                if (width > pdev->abs_max.x || height > pdev->abs_max.y)
                {
-                       Debug("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
+                       PWC_DEBUG_SIZE("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
                        return -1;
                }
        }
@@ -60,7 +59,7 @@ int pwc_decode_size(struct pwc_device *pdev, int width, int height)
        {
                if (width > pdev->view_max.x || height > pdev->view_max.y)
                {
-                       Debug("VIDEO_PALETTE_ not RAW: going beyond view_max.\n");
+                       PWC_DEBUG_SIZE("VIDEO_PALETTE_not RAW: going beyond view_max.\n");
                        return -1;
                }
        }
@@ -81,9 +80,8 @@ int pwc_decode_size(struct pwc_device *pdev, int width, int height)
 /* initialize variables depending on type and decompressor*/
 void pwc_construct(struct pwc_device *pdev)
 {
-       switch(pdev->type) {
-       case 645:
-       case 646:
+       if (DEVICE_USE_CODEC1(pdev->type)) {
+
                pdev->view_min.x = 128;
                pdev->view_min.y =  96;
                pdev->view_max.x = 352;
@@ -95,10 +93,23 @@ void pwc_construct(struct pwc_device *pdev)
                pdev->vendpoint = 4;
                pdev->frame_header_size = 0;
                pdev->frame_trailer_size = 0;
-               break;
-       case 675:
-       case 680:
-       case 690:
+
+       } else if (DEVICE_USE_CODEC3(pdev->type)) {
+
+               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;
+
+       } else /* if (DEVICE_USE_CODEC2(pdev->type)) */ {
+
                pdev->view_min.x = 128;
                pdev->view_min.y =  96;
                /* Anthill bug #38: PWC always reports max size, even without PWCX */
@@ -111,30 +122,12 @@ void pwc_construct(struct pwc_device *pdev)
                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;
+       pdev->len_per_image = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2);
 }
 
 
index 175250d089cfccedffbf256a8e335249e4c9a2d3..be65bdcd195b4100a438ecc7fd0c541d5578c9d1 100644 (file)
@@ -1,5 +1,5 @@
 /* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 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.
@@ -314,3 +314,1133 @@ const struct Timon_table_entry Timon_table[PSZ_MAX][6][4] =
    },
 };
 
+/*
+ * 16 versions:
+ *   2 tables  (one for Y, and one for U&V)
+ *   16 levels of details per tables
+ *   8 blocs
+ */
+
+const unsigned int TimonRomTable [16][2][16][8] =
+{
+ { /* version 0 */
+  { /* version 0, passes 0 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000001},
+   {0x00000000,0x00000000,0x00000001,0x00000001,
+    0x00000001,0x00000001,0x00000001,0x00000001},
+   {0x00000000,0x00000000,0x00000001,0x00000001,
+    0x00000001,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000009,0x00000001,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000009,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000249,0x00000249,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000249,0x0000124a,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009252,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 0, passes 1 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000001,0x00000001,
+    0x00000001,0x00000001,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000009,0x00000001,
+    0x00000001,0x00000009,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000009,
+    0x00000009,0x00000049,0x00000001,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000009,
+    0x00000009,0x00000049,0x00000001,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000009,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000009,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000009,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000249,0x00000249,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 1 */
+  { /* version 1, passes 0 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000001},
+   {0x00000000,0x00000000,0x00000001,0x00000001,
+    0x00000001,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000009,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00001252},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 1, passes 1 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000001,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000009,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000001,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000009,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000049,0x00000249,0x00000009,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000249,0x00000249,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009252,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 2 */
+  { /* version 2, passes 0 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000001},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009252,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00009252,
+    0x00009492,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 2, passes 1 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000009,
+    0x00000049,0x00000009,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000000},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000249,0x00000049,0x0000024a,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000009},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009252,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009292,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009292,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009292,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x0000924a,0x0000924a,
+    0x00009492,0x00009493,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 3 */
+  { /* version 3, passes 0 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x00000249,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009292,0x00009292,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009292,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00009252,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009292,0x0000a49b,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x0000a49b,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x0001b725,0x000136e4},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 3, passes 1 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x00000049,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x00001252,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009252,0x00009292,0x00000009},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009252,0x00009292,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009252,0x00009292,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009493,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009493,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009493,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x00009493,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009292,
+    0x0000a493,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 4 */
+  { /* version 4, passes 0 */
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009493,0x00009493,0x0000a49b},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000124db,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x00009252,0x000124db,
+    0x000126dc,0x0001b724,0x0001b725,0x0001b925},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 4, passes 1 */
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x0000124a,0x0000124a,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x0000a49b,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00009252,0x0000a49b,
+    0x0001249b,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 5 */
+  { /* version 5, passes 0 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009292,0x00009292,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x000124db,0x000124db,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0001249b,0x000126dc,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000126dc,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 5, passes 1 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x00009493,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x00009493,0x000124db,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x00009493,0x000124db,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x000124db,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x000124db,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009252,0x000124db,
+    0x000126dc,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 6 */
+  { /* version 6, passes 0 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000136e4,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x0001b725,0x0001b925},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x000136e4,0x0001b925,0x00025bb6,0x00024b77},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 6, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x000126dc,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000136e4,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 7 */
+  { /* version 7, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x0000a49b,0x000124db,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b725,0x0001b925},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001c96e,0x0002496e},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x000136e4,0x0001b925,0x0001c96e,0x0002496e},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x0002496d,0x00025bb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 7, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x00009493,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x000136e4,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x000136e4,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x000136e4,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x000136e4,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00012492,0x000126db,
+    0x0001b724,0x0001b925,0x0001b725,0x000136e4},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 8 */
+  { /* version 8, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b725,0x0001b925},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+   {0x00000000,0x00000000,0x00009252,0x000124db,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000126dc,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x00024b76,0x00024b77},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x000136e4,0x0001b925,0x00024b76,0x00025bbf},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x000136e4,0x0001c92d,0x00024b76,0x00025bbf},
+   {0x00000000,0x00000000,0x00012492,0x000136db,
+    0x0001b724,0x00024b6d,0x0002ddb6,0x0002efff},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 8, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000126dc,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000136e4,0x0001b724,0x0001b725,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x000136e4,0x0001b925,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x000136e4,0x0001b925,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x0002496d,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 9 */
+  { /* version 9, passes 0 */
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000249,0x00000249,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x00009252,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0001249b,0x000126dc,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00009252,0x00009493,
+    0x000124db,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009252,0x0000a49b,
+    0x000124db,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 9, passes 1 */
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000049,0x00000049,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00000249,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009252,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x00009252,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009493,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009252,0x000124db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 10 */
+  { /* version 10, passes 0 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x00009493,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000124db,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0001249b,0x000126dc,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000126dc,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009252,0x0000a49b,
+    0x000124db,0x000136e4,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000126dc,0x0001b925,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x000136e4,0x0002496d,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 10, passes 1 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00000249,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009252,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009493,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x00009493,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x00009493,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x00009492,0x00009493,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009493,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009252,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 11 */
+  { /* version 11, passes 0 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x000136e4},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001c96e,0x0001b925},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001c924,0x0002496d,0x00025bb6,0x00024b77},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 11, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009252,0x00009252,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000126dc,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 12 */
+  { /* version 12, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0002496e},
+   {0x00000000,0x00000000,0x00012492,0x000126db,
+    0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 12, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x00009252,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009292,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000124db,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000126dc,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 13 */
+  { /* version 13, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x0000a49b,
+    0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b725,0x000124db},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001c96e,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001b925},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b924,0x0001c92d,0x00024b76,0x0002496e},
+   {0x00000000,0x00000000,0x00012492,0x000136db,
+    0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 13, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x00009492,0x00009292,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000124db,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000136db,
+    0x0001b724,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000136db,
+    0x0001b724,0x000126dc,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00009292,0x000136db,
+    0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00012492,0x0001b6db,
+    0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 14 */
+  { /* version 14, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x0000a49b,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000136e4,0x0001b725,0x000124db},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000126dc,0x0001b724,0x0001b92d,0x000126dc},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001b92d,0x000126dc},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001c92d,0x0001c96e,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0001b925},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0002496e},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b924,0x0002496d,0x00024b76,0x00024b77},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b924,0x00024b6d,0x0002ddb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00012492,0x0001b6db,
+    0x00024924,0x0002db6d,0x00036db6,0x0002efff},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 14, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009292,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000136e4,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000136e4,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000136e4,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001b724,0x000136e4,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001b724,0x000136e4,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001b724,0x000136e4,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001b724,0x000136e4,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00012492,0x0001b6db,
+    0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 15 */
+  { /* version 15, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x0001b724,0x0001b92d,0x000126dc},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001c96e,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001b925},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b924,0x0002496d,0x00024b76,0x0002496e},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0002496d,0x00025bb6,0x00024b77},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x00024b6d,0x00025bb6,0x00024b77},
+   {0x00000000,0x00000000,0x00012492,0x000136db,
+    0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00012492,0x0001b6db,
+    0x00024924,0x0002db6d,0x00036db6,0x0002efff},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 15, passes 1 */
+   {0x00000000,0x00000000,0x0000924a,0x0000924a,
+    0x00009292,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000124db,0x0001b724,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x0001b724,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x0001b724,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00009292,0x000136db,
+    0x0001b724,0x0001b724,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001c924,0x0001b724,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001c924,0x0001b724,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b724,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b925,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b925,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b925,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b925,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x00012492,0x000136db,
+    0x0001c924,0x0001b925,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x00012492,0x0001b6db,
+    0x00024924,0x0002496d,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ }
+};
index a86b3782a081fa9600f8bc752a8d6b604babe1c2..eef9e2cd4320b6c141ac010225776714611c5c77 100644 (file)
@@ -1,5 +1,5 @@
 /* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 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.
@@ -42,7 +42,7 @@
 #ifndef PWC_TIMON_H
 #define PWC_TIMON_H
 
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
 
 struct Timon_table_entry
 {
@@ -52,8 +52,8 @@ struct Timon_table_entry
        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];
+extern const struct Timon_table_entry Timon_table[PSZ_MAX][6][4];
+extern const unsigned int TimonRomTable [16][2][16][8];
 
 
 #endif
index b37a89a163f98ad2db2d0340e74dc74c0c993fab..5d82028ef94229acc69f326128acefe08882af7b 100644 (file)
@@ -1,7 +1,7 @@
 /* Linux driver for Philips webcam
    Decompression frontend.
    (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 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.
@@ -22,6 +22,8 @@
    You 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
+
+   vim: set ts=8:
 */
 
 #include <asm/current.h>
@@ -29,6 +31,8 @@
 
 #include "pwc.h"
 #include "pwc-uncompress.h"
+#include "pwc-dec1.h"
+#include "pwc-dec23.h"
 
 int pwc_decompress(struct pwc_device *pdev)
 {
@@ -40,107 +44,95 @@ int pwc_decompress(struct pwc_device *pdev)
 
        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;
+       image  = pdev->image_data;
+       image += pdev->images[pdev->fill_image].offset;
 
        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);
+               struct pwc_raw_frame *raw_frame = image;
+               raw_frame->type = cpu_to_le16(pdev->type);
+               raw_frame->vbandlength = cpu_to_le16(pdev->vbandlength);
+                       /* cmd_buf is always 4 bytes, but sometimes, only the
+                        * first 3 bytes is filled (Nala case). We can
+                        * determine this using the type of the webcam */
+               memcpy(raw_frame->cmd, pdev->cmd_buf, 4);
+               memcpy(raw_frame+1, 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.
+               /* 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.
                 */
-                       /*
-                        * 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;
+               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 += (stride >> 1);
+                                       *dstv++ = *src++;
                                else
-                                       dstu += (stride >> 1);
+                                       *dstu++ = *src++;
                        }
+                       dsty += stride;
+                       if (line & 1)
+                               dstv += (stride >> 1);
+                       else
+                               dstu += (stride >> 1);
+               }
+
+               return 0;
        }
-       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
+
+       /*
+        * Compressed;
+        * the decompressor routines will write the data in planar format
+        * immediately.
+        */
+       if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) {
+               PWC_ERROR("Mode Bayer is not supported for now\n");
+               /* flags |= PWCX_FLAG_BAYER; */
+               return -ENXIO; /* No such device or address: missing decompressor */
+       }
+
+       if (DEVICE_USE_CODEC1(pdev->type)) {
+
+               /* TODO & FIXME */
+               PWC_ERROR("This chipset is not supported for now\n");
+               return -ENXIO; /* No such device or address: missing decompressor */
+
+       } else {
+               pwc_dec23_decompress(pdev, yuv, image, PWCX_FLAG_PLANAR);
        }
        return 0;
 }
 
 
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
index f75e1b6cbe19d8831c196fc25e3cbce3485ff78e..041227f6524691d5f42971acbe00bf9acdd7df0c 100644 (file)
@@ -1,5 +1,5 @@
 /* (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 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.
@@ -32,7 +32,7 @@
 
 #include <linux/config.h>
 
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
 
 /* from pwc-dec.h */
 #define PWCX_FLAG_PLANAR        0x0001
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
new file mode 100644 (file)
index 0000000..b7eb3ce
--- /dev/null
@@ -0,0 +1,1202 @@
+/* Linux driver for Philips webcam
+   USB and Video4Linux interface part.
+   (C) 1999-2004 Nemosoft Unv.
+   (C) 2004-2006 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/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"
+
+static struct v4l2_queryctrl pwc_controls[] = {
+       {
+           .id      = V4L2_CID_BRIGHTNESS,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Brightness",
+           .minimum = 0,
+           .maximum = 128,
+           .step    = 1,
+           .default_value = 64,
+       },
+       {
+           .id      = V4L2_CID_CONTRAST,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Contrast",
+           .minimum = 0,
+           .maximum = 64,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_SATURATION,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Saturation",
+           .minimum = -100,
+           .maximum = 100,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_GAMMA,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Gamma",
+           .minimum = 0,
+           .maximum = 32,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_RED_BALANCE,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Red Gain",
+           .minimum = 0,
+           .maximum = 256,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_BLUE_BALANCE,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Blue Gain",
+           .minimum = 0,
+           .maximum = 256,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_AUTO_WHITE_BALANCE,
+           .type    = V4L2_CTRL_TYPE_BOOLEAN,
+           .name    = "Auto White Balance",
+           .minimum = 0,
+           .maximum = 1,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_EXPOSURE,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Shutter Speed (Exposure)",
+           .minimum = 0,
+           .maximum = 256,
+           .step    = 1,
+           .default_value = 200,
+       },
+       {
+           .id      = V4L2_CID_AUTOGAIN,
+           .type    = V4L2_CTRL_TYPE_BOOLEAN,
+           .name    = "Auto Gain Enabled",
+           .minimum = 0,
+           .maximum = 1,
+           .step    = 1,
+           .default_value = 1,
+       },
+       {
+           .id      = V4L2_CID_GAIN,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Gain Level",
+           .minimum = 0,
+           .maximum = 256,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_PRIVATE_SAVE_USER,
+           .type    = V4L2_CTRL_TYPE_BUTTON,
+           .name    = "Save User Settings",
+           .minimum = 0,
+           .maximum = 0,
+           .step    = 0,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_PRIVATE_RESTORE_USER,
+           .type    = V4L2_CTRL_TYPE_BUTTON,
+           .name    = "Restore User Settings",
+           .minimum = 0,
+           .maximum = 0,
+           .step    = 0,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_PRIVATE_RESTORE_FACTORY,
+           .type    = V4L2_CTRL_TYPE_BUTTON,
+           .name    = "Restore Factory Settings",
+           .minimum = 0,
+           .maximum = 0,
+           .step    = 0,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_PRIVATE_COLOUR_MODE,
+           .type    = V4L2_CTRL_TYPE_BOOLEAN,
+           .name    = "Colour mode",
+           .minimum = 0,
+           .maximum = 1,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_PRIVATE_AUTOCONTOUR,
+           .type    = V4L2_CTRL_TYPE_BOOLEAN,
+           .name    = "Auto contour",
+           .minimum = 0,
+           .maximum = 1,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_PRIVATE_CONTOUR,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Contour",
+           .minimum = 0,
+           .maximum = 63,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_PRIVATE_BACKLIGHT,
+           .type    = V4L2_CTRL_TYPE_BOOLEAN,
+           .name    = "Backlight compensation",
+           .minimum = 0,
+           .maximum = 1,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+         .id      = V4L2_CID_PRIVATE_FLICKERLESS,
+           .type    = V4L2_CTRL_TYPE_BOOLEAN,
+           .name    = "Flickerless",
+           .minimum = 0,
+           .maximum = 1,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_PRIVATE_NOISE_REDUCTION,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Noise reduction",
+           .minimum = 0,
+           .maximum = 3,
+           .step    = 1,
+           .default_value = 0,
+       },
+};
+
+
+static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
+{
+       memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
+       f->fmt.pix.width        = pdev->view.x;
+       f->fmt.pix.height       = pdev->view.y;
+       f->fmt.pix.field        = V4L2_FIELD_NONE;
+       if (pdev->vpalette == VIDEO_PALETTE_YUV420P) {
+               f->fmt.pix.pixelformat  = V4L2_PIX_FMT_YUV420;
+               f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2;
+               f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+       } else {
+               /* vbandlength contains 4 lines ...  */
+               f->fmt.pix.bytesperline = pdev->vbandlength/4;
+               f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame);
+               if (DEVICE_USE_CODEC1(pdev->type))
+                       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_PWC1;
+               else
+                       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_PWC2;
+       }
+       PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() "
+                       "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n",
+                       f->fmt.pix.width,
+                       f->fmt.pix.height,
+                       f->fmt.pix.bytesperline,
+                       f->fmt.pix.sizeimage,
+                       (f->fmt.pix.pixelformat)&255,
+                       (f->fmt.pix.pixelformat>>8)&255,
+                       (f->fmt.pix.pixelformat>>16)&255,
+                       (f->fmt.pix.pixelformat>>24)&255);
+}
+
+/* ioctl(VIDIOC_TRY_FMT) */
+static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
+{
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
+               return -EINVAL;
+       }
+
+       switch (f->fmt.pix.pixelformat) {
+               case V4L2_PIX_FMT_YUV420:
+                       break;
+               case V4L2_PIX_FMT_PWC1:
+                       if (DEVICE_USE_CODEC23(pdev->type)) {
+                               PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n");
+                               return -EINVAL;
+                       }
+                       break;
+               case V4L2_PIX_FMT_PWC2:
+                       if (DEVICE_USE_CODEC1(pdev->type)) {
+                               PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n");
+                               return -EINVAL;
+                       }
+                       break;
+               default:
+                       PWC_DEBUG_IOCTL("Unsupported pixel format\n");
+                       return -EINVAL;
+
+       }
+
+       if (f->fmt.pix.width > pdev->view_max.x)
+               f->fmt.pix.width = pdev->view_max.x;
+       else if (f->fmt.pix.width < pdev->view_min.x)
+               f->fmt.pix.width = pdev->view_min.x;
+
+       if (f->fmt.pix.height > pdev->view_max.y)
+               f->fmt.pix.height = pdev->view_max.y;
+       else if (f->fmt.pix.height < pdev->view_min.y)
+               f->fmt.pix.height = pdev->view_min.y;
+
+       return 0;
+}
+
+/* ioctl(VIDIOC_SET_FMT) */
+static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
+{
+       int ret, fps, snapshot, compression, pixelformat;
+
+       ret = pwc_vidioc_try_fmt(pdev, f);
+       if (ret<0)
+               return ret;
+
+       pixelformat = f->fmt.pix.pixelformat;
+       compression = pdev->vcompression;
+       snapshot = 0;
+       fps = pdev->vframes;
+       if (f->fmt.pix.priv) {
+               compression = (f->fmt.pix.priv & PWC_QLT_MASK) >> PWC_QLT_SHIFT;
+               snapshot = !!(f->fmt.pix.priv & PWC_FPS_SNAPSHOT);
+               fps = (f->fmt.pix.priv & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
+               if (fps == 0)
+                       fps = pdev->vframes;
+       }
+
+       if (pixelformat == V4L2_PIX_FMT_YUV420)
+               pdev->vpalette = VIDEO_PALETTE_YUV420P;
+       else
+               pdev->vpalette = VIDEO_PALETTE_RAW;
+
+       PWC_DEBUG_IOCTL("Try to change format to: width=%d height=%d fps=%d "
+                       "compression=%d snapshot=%d format=%c%c%c%c\n",
+                       f->fmt.pix.width, f->fmt.pix.height, fps,
+                       compression, snapshot,
+                       (pixelformat)&255,
+                       (pixelformat>>8)&255,
+                       (pixelformat>>16)&255,
+                       (pixelformat>>24)&255);
+
+       ret = pwc_try_video_mode(pdev,
+                                f->fmt.pix.width,
+                                f->fmt.pix.height,
+                                fps,
+                                compression,
+                                snapshot);
+
+       PWC_DEBUG_IOCTL("pwc_try_video_mode(), return=%d\n", ret);
+
+       if (ret)
+               return ret;
+
+       pwc_vidioc_fill_fmt(pdev, f);
+
+       return 0;
+
+}
+
+int pwc_video_do_ioctl(struct inode *inode, struct file *file,
+                      unsigned int cmd, void *arg)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct pwc_device *pdev;
+       DECLARE_WAITQUEUE(wait, current);
+
+       if (vdev == NULL)
+               return -EFAULT;
+       pdev = vdev->priv;
+       if (pdev == NULL)
+               return -EFAULT;
+
+#if CONFIG_PWC_DEBUG
+       if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace)
+               v4l_printk_ioctl(cmd);
+#endif
+
+
+       switch (cmd) {
+               /* Query cabapilities */
+               case VIDIOCGCAP:
+               {
+                       struct video_capability *caps = arg;
+
+                       strcpy(caps->name, vdev->name);
+                       caps->type = VID_TYPE_CAPTURE;
+                       caps->channels = 1;
+                       caps->audios = 1;
+                       caps->minwidth  = pdev->view_min.x;
+                       caps->minheight = pdev->view_min.y;
+                       caps->maxwidth  = pdev->view_max.x;
+                       caps->maxheight = pdev->view_max.y;
+                       break;
+               }
+
+               /* Channel functions (simulate 1 channel) */
+               case VIDIOCGCHAN:
+               {
+                       struct video_channel *v = arg;
+
+                       if (v->channel != 0)
+                               return -EINVAL;
+                       v->flags = 0;
+                       v->tuners = 0;
+                       v->type = VIDEO_TYPE_CAMERA;
+                       strcpy(v->name, "Webcam");
+                       return 0;
+               }
+
+               case VIDIOCSCHAN:
+               {
+                       /* The spec says the argument is an integer, but
+                          the bttv driver uses a video_channel arg, which
+                          makes sense becasue it also has the norm flag.
+                        */
+                       struct video_channel *v = arg;
+                       if (v->channel != 0)
+                               return -EINVAL;
+                       return 0;
+               }
+
+
+               /* Picture functions; contrast etc. */
+               case VIDIOCGPICT:
+               {
+                       struct video_picture *p = arg;
+                       int val;
+
+                       val = pwc_get_brightness(pdev);
+                       if (val >= 0)
+                               p->brightness = (val<<9);
+                       else
+                               p->brightness = 0xffff;
+                       val = pwc_get_contrast(pdev);
+                       if (val >= 0)
+                               p->contrast = (val<<10);
+                       else
+                               p->contrast = 0xffff;
+                       /* Gamma, Whiteness, what's the difference? :) */
+                       val = pwc_get_gamma(pdev);
+                       if (val >= 0)
+                               p->whiteness = (val<<11);
+                       else
+                               p->whiteness = 0xffff;
+                       if (pwc_get_saturation(pdev, &val)<0)
+                               p->colour = 0xffff;
+                       else
+                               p->colour = 32768 + val * 327;
+                       p->depth = 24;
+                       p->palette = pdev->vpalette;
+                       p->hue = 0xFFFF; /* N/A */
+                       break;
+               }
+
+               case VIDIOCSPICT:
+               {
+                       struct video_picture *p = arg;
+                       /*
+                        *      FIXME:  Suppose we are mid read
+                               ANSWER: No problem: the firmware of the camera
+                                       can handle brightness/contrast/etc
+                                       changes at _any_ time, and the palette
+                                       is used exactly once in the uncompress
+                                       routine.
+                        */
+                       pwc_set_brightness(pdev, p->brightness);
+                       pwc_set_contrast(pdev, p->contrast);
+                       pwc_set_gamma(pdev, p->whiteness);
+                       pwc_set_saturation(pdev, (p->colour-32768)/327);
+                       if (p->palette && p->palette != pdev->vpalette) {
+                               switch (p->palette) {
+                                       case VIDEO_PALETTE_YUV420P:
+                                       case VIDEO_PALETTE_RAW:
+                                               pdev->vpalette = p->palette;
+                                               return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+                                               break;
+                                       default:
+                                               return -EINVAL;
+                                               break;
+                               }
+                       }
+                       break;
+               }
+
+               /* Window/size parameters */
+               case VIDIOCGWIN:
+               {
+                       struct video_window *vw = arg;
+
+                       vw->x = 0;
+                       vw->y = 0;
+                       vw->width = pdev->view.x;
+                       vw->height = pdev->view.y;
+                       vw->chromakey = 0;
+                       vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
+                                  (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
+                       break;
+               }
+
+               case VIDIOCSWIN:
+               {
+                       struct video_window *vw = arg;
+                       int fps, snapshot, ret;
+
+                       fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
+                       snapshot = vw->flags & PWC_FPS_SNAPSHOT;
+                       if (fps == 0)
+                               fps = pdev->vframes;
+                       if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
+                               return 0;
+                       ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
+                       if (ret)
+                               return ret;
+                       break;
+               }
+
+               /* We don't have overlay support (yet) */
+               case VIDIOCGFBUF:
+               {
+                       struct video_buffer *vb = arg;
+
+                       memset(vb,0,sizeof(*vb));
+                       break;
+               }
+
+               /* 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 = pwc_mbufs * pdev->len_per_image;
+                       vm->frames = pwc_mbufs; /* double buffering should be enough for most applications */
+                       for (i = 0; i < pwc_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;
+
+                       PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
+                       if (vm->frame < 0 || vm->frame >= pwc_mbufs)
+                               return -EINVAL;
+
+                       /* xawtv is nasty. It probes the available palettes
+                          by setting a very small image size and trying
+                          various palettes... The driver doesn't support
+                          such small images, so I'm working around it.
+                        */
+                       if (vm->format)
+                       {
+                               switch (vm->format)
+                               {
+                                       case VIDEO_PALETTE_YUV420P:
+                                       case VIDEO_PALETTE_RAW:
+                                               break;
+                                       default:
+                                               return -EINVAL;
+                                               break;
+                               }
+                       }
+
+                       if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
+                           (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
+                               int ret;
+
+                               PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
+                               ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+                               if (ret)
+                                       return ret;
+                       } /* ... size mismatch */
+
+                       /* FIXME: should we lock here? */
+                       if (pdev->image_used[vm->frame])
+                               return -EBUSY;  /* buffer wasn't available. Bummer */
+                       pdev->image_used[vm->frame] = 1;
+
+                       /* Okay, we're done here. In the SYNC call we wait until a
+                          frame comes available, then expand image into the given
+                          buffer.
+                          In contrast to the CPiA cam the Philips cams deliver a
+                          constant stream, almost like a grabber card. Also,
+                          we have separate buffers for the rawdata and the image,
+                          meaning we can nearly always expand into the requested buffer.
+                        */
+                       PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
+                       break;
+               }
+
+               case VIDIOCSYNC:
+               {
+                       /* The doc says: "Whenever a buffer is used it should
+                          call VIDIOCSYNC to free this frame up and continue."
+
+                          The only odd thing about this whole procedure is
+                          that MCAPTURE flags the buffer as "in use", and
+                          SYNC immediately unmarks it, while it isn't
+                          after SYNC that you know that the buffer actually
+                          got filled! So you better not start a CAPTURE in
+                          the same frame immediately (use double buffering).
+                          This is not a problem for this cam, since it has
+                          extra intermediate buffers, but a hardware
+                          grabber card will then overwrite the buffer
+                          you're working on.
+                        */
+                       int *mbuf = arg;
+                       int ret;
+
+                       PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf);
+
+                       /* bounds check */
+                       if (*mbuf < 0 || *mbuf >= pwc_mbufs)
+                               return -EINVAL;
+                       /* check if this buffer was requested anyway */
+                       if (pdev->image_used[*mbuf] == 0)
+                               return -EINVAL;
+
+                       /* Add ourselves to the frame wait-queue.
+
+                          FIXME: needs auditing for safety.
+                          QUESTION: In what respect? I think that using the
+                                    frameq is safe now.
+                        */
+                       add_wait_queue(&pdev->frameq, &wait);
+                       while (pdev->full_frames == NULL) {
+                               /* Check for unplugged/etc. here */
+                               if (pdev->error_status) {
+                                       remove_wait_queue(&pdev->frameq, &wait);
+                                       set_current_state(TASK_RUNNING);
+                                       return -pdev->error_status;
+                               }
+
+                               if (signal_pending(current)) {
+                                       remove_wait_queue(&pdev->frameq, &wait);
+                                       set_current_state(TASK_RUNNING);
+                                       return -ERESTARTSYS;
+                               }
+                               schedule();
+                               set_current_state(TASK_INTERRUPTIBLE);
+                       }
+                       remove_wait_queue(&pdev->frameq, &wait);
+                       set_current_state(TASK_RUNNING);
+
+                       /* The frame is ready. Expand in the image buffer
+                          requested by the user. I don't care if you
+                          mmap() 5 buffers and request data in this order:
+                          buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
+                          Grabber hardware may not be so forgiving.
+                        */
+                       PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n");
+                       pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
+                       /* Decompress, etc */
+                       ret = pwc_handle_frame(pdev);
+                       pdev->image_used[*mbuf] = 0;
+                       if (ret)
+                               return -EFAULT;
+                       break;
+               }
+
+               case VIDIOCGAUDIO:
+               {
+                       struct video_audio *v = arg;
+
+                       strcpy(v->name, "Microphone");
+                       v->audio = -1; /* unknown audio minor */
+                       v->flags = 0;
+                       v->mode = VIDEO_SOUND_MONO;
+                       v->volume = 0;
+                       v->bass = 0;
+                       v->treble = 0;
+                       v->balance = 0x8000;
+                       v->step = 1;
+                       break;
+               }
+
+               case VIDIOCSAUDIO:
+               {
+                       /* Dummy: nothing can be set */
+                       break;
+               }
+
+               case VIDIOCGUNIT:
+               {
+                       struct video_unit *vu = arg;
+
+                       vu->video = pdev->vdev->minor & 0x3F;
+                       vu->audio = -1; /* not known yet */
+                       vu->vbi = -1;
+                       vu->radio = -1;
+                       vu->teletext = -1;
+                       break;
+               }
+
+               /* V4L2 Layer */
+               case VIDIOC_QUERYCAP:
+               {
+                   struct v4l2_capability *cap = arg;
+
+                   PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\
+                                      "try to use the v4l2 layer\n");
+                   strcpy(cap->driver,PWC_NAME);
+                   strlcpy(cap->card, vdev->name, sizeof(cap->card));
+                   usb_make_path(pdev->udev,cap->bus_info,sizeof(cap->bus_info));
+                   cap->version = PWC_VERSION_CODE;
+                   cap->capabilities =
+                       V4L2_CAP_VIDEO_CAPTURE  |
+                       V4L2_CAP_STREAMING      |
+                       V4L2_CAP_READWRITE;
+                   return 0;
+               }
+
+               case VIDIOC_ENUMINPUT:
+               {
+                   struct v4l2_input *i = arg;
+
+                   if ( i->index )     /* Only one INPUT is supported */
+                         return -EINVAL;
+
+                   memset(i, 0, sizeof(struct v4l2_input));
+                   strcpy(i->name, "usb");
+                   return 0;
+               }
+
+               case VIDIOC_G_INPUT:
+               {
+                   int *i = arg;
+                   *i = 0;     /* Only one INPUT is supported */
+                   return 0;
+               }
+               case VIDIOC_S_INPUT:
+               {
+                       int *i = arg;
+
+                       if ( *i ) {     /* Only one INPUT is supported */
+                               PWC_DEBUG_IOCTL("Only one input source is"\
+                                       " supported with this webcam.\n");
+                               return -EINVAL;
+                       }
+                       return 0;
+               }
+
+               /* TODO: */
+               case VIDIOC_QUERYCTRL:
+               {
+                       struct v4l2_queryctrl *c = arg;
+                       int i;
+
+                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c->id);
+                       for (i=0; i<sizeof(pwc_controls)/sizeof(struct v4l2_queryctrl); i++) {
+                               if (pwc_controls[i].id == c->id) {
+                                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
+                                       memcpy(c,&pwc_controls[i],sizeof(struct v4l2_queryctrl));
+                                       return 0;
+                               }
+                       }
+                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");
+
+                       return -EINVAL;
+               }
+               case VIDIOC_G_CTRL:
+               {
+                       struct v4l2_control *c = arg;
+                       int ret;
+
+                       switch (c->id)
+                       {
+                               case V4L2_CID_BRIGHTNESS:
+                                       c->value = pwc_get_brightness(pdev);
+                                       if (c->value<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_CONTRAST:
+                                       c->value = pwc_get_contrast(pdev);
+                                       if (c->value<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_SATURATION:
+                                       ret = pwc_get_saturation(pdev, &c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_GAMMA:
+                                       c->value = pwc_get_gamma(pdev);
+                                       if (c->value<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_RED_BALANCE:
+                                       ret = pwc_get_red_gain(pdev, &c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       c->value >>= 8;
+                                       return 0;
+                               case V4L2_CID_BLUE_BALANCE:
+                                       ret = pwc_get_blue_gain(pdev, &c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       c->value >>= 8;
+                                       return 0;
+                               case V4L2_CID_AUTO_WHITE_BALANCE:
+                                       ret = pwc_get_awb(pdev);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       c->value = (ret == PWC_WB_MANUAL)?0:1;
+                                       return 0;
+                               case V4L2_CID_GAIN:
+                                       ret = pwc_get_agc(pdev, &c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       c->value >>= 8;
+                                       return 0;
+                               case V4L2_CID_AUTOGAIN:
+                                       ret = pwc_get_agc(pdev, &c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       c->value = (c->value < 0)?1:0;
+                                       return 0;
+                               case V4L2_CID_EXPOSURE:
+                                       ret = pwc_get_shutter_speed(pdev, &c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_PRIVATE_COLOUR_MODE:
+                                       ret = pwc_get_colour_mode(pdev, &c->value);
+                                       if (ret < 0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_PRIVATE_AUTOCONTOUR:
+                                       ret = pwc_get_contour(pdev, &c->value);
+                                       if (ret < 0)
+                                               return -EINVAL;
+                                       c->value=(c->value == -1?1:0);
+                                       return 0;
+                               case V4L2_CID_PRIVATE_CONTOUR:
+                                       ret = pwc_get_contour(pdev, &c->value);
+                                       if (ret < 0)
+                                               return -EINVAL;
+                                       c->value >>= 10;
+                                       return 0;
+                               case V4L2_CID_PRIVATE_BACKLIGHT:
+                                       ret = pwc_get_backlight(pdev, &c->value);
+                                       if (ret < 0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_PRIVATE_FLICKERLESS:
+                                       ret = pwc_get_flicker(pdev, &c->value);
+                                       if (ret < 0)
+                                               return -EINVAL;
+                                       c->value=(c->value?1:0);
+                                       return 0;
+                               case V4L2_CID_PRIVATE_NOISE_REDUCTION:
+                                       ret = pwc_get_dynamic_noise(pdev, &c->value);
+                                       if (ret < 0)
+                                               return -EINVAL;
+                                       return 0;
+
+                               case V4L2_CID_PRIVATE_SAVE_USER:
+                               case V4L2_CID_PRIVATE_RESTORE_USER:
+                               case V4L2_CID_PRIVATE_RESTORE_FACTORY:
+                                       return -EINVAL;
+                       }
+                       return -EINVAL;
+               }
+               case VIDIOC_S_CTRL:
+               {
+                       struct v4l2_control *c = arg;
+                       int ret;
+
+                       switch (c->id)
+                       {
+                               case V4L2_CID_BRIGHTNESS:
+                                       c->value <<= 9;
+                                       ret = pwc_set_brightness(pdev, c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_CONTRAST:
+                                       c->value <<= 10;
+                                       ret = pwc_set_contrast(pdev, c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_SATURATION:
+                                       ret = pwc_set_saturation(pdev, c->value);
+                                       if (ret<0)
+                                         return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_GAMMA:
+                                       c->value <<= 11;
+                                       ret = pwc_set_gamma(pdev, c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_RED_BALANCE:
+                                       c->value <<= 8;
+                                       ret = pwc_set_red_gain(pdev, c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_BLUE_BALANCE:
+                                       c->value <<= 8;
+                                       ret = pwc_set_blue_gain(pdev, c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_AUTO_WHITE_BALANCE:
+                                       c->value = (c->value == 0)?PWC_WB_MANUAL:PWC_WB_AUTO;
+                                       ret = pwc_set_awb(pdev, c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_EXPOSURE:
+                                       c->value <<= 8;
+                                       ret = pwc_set_shutter_speed(pdev, c->value?0:1, c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_AUTOGAIN:
+                                       /* autogain off means nothing without a gain */
+                                       if (c->value == 0)
+                                               return 0;
+                                       ret = pwc_set_agc(pdev, c->value, 0);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_GAIN:
+                                       c->value <<= 8;
+                                       ret = pwc_set_agc(pdev, 0, c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_PRIVATE_SAVE_USER:
+                                       if (pwc_save_user(pdev))
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_PRIVATE_RESTORE_USER:
+                                       if (pwc_restore_user(pdev))
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_PRIVATE_RESTORE_FACTORY:
+                                       if (pwc_restore_factory(pdev))
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_PRIVATE_COLOUR_MODE:
+                                       ret = pwc_set_colour_mode(pdev, c->value);
+                                       if (ret < 0)
+                                         return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_PRIVATE_AUTOCONTOUR:
+                                 c->value=(c->value == 1)?-1:0;
+                                 ret = pwc_set_contour(pdev, c->value);
+                                 if (ret < 0)
+                                   return -EINVAL;
+                                 return 0;
+                               case V4L2_CID_PRIVATE_CONTOUR:
+                                 c->value <<= 10;
+                                 ret = pwc_set_contour(pdev, c->value);
+                                 if (ret < 0)
+                                   return -EINVAL;
+                                 return 0;
+                               case V4L2_CID_PRIVATE_BACKLIGHT:
+                                 ret = pwc_set_backlight(pdev, c->value);
+                                 if (ret < 0)
+                                   return -EINVAL;
+                                 return 0;
+                               case V4L2_CID_PRIVATE_FLICKERLESS:
+                                 ret = pwc_set_flicker(pdev, c->value);
+                                 if (ret < 0)
+                                   return -EINVAL;
+                               case V4L2_CID_PRIVATE_NOISE_REDUCTION:
+                                 ret = pwc_set_dynamic_noise(pdev, c->value);
+                                 if (ret < 0)
+                                   return -EINVAL;
+                                 return 0;
+
+                       }
+                       return -EINVAL;
+               }
+
+               case VIDIOC_ENUM_FMT:
+               {
+                       struct v4l2_fmtdesc *f = arg;
+                       int index;
+
+                       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                             return -EINVAL;
+
+                       /* We only support two format: the raw format, and YUV */
+                       index = f->index;
+                       memset(f,0,sizeof(struct v4l2_fmtdesc));
+                       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                       f->index = index;
+                       switch(index)
+                       {
+                               case 0:
+                                       /* RAW format */
+                                       f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2;
+                                       f->flags = V4L2_FMT_FLAG_COMPRESSED;
+                                       strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description));
+                                       break;
+                               case 1:
+                                       f->pixelformat = V4L2_PIX_FMT_YUV420;
+                                       strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description));
+                                       break;
+                               default:
+                                       return -EINVAL;
+                       }
+                       return 0;
+               }
+
+               case VIDIOC_G_FMT:
+               {
+                       struct v4l2_format *f = arg;
+
+                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev->image.x,pdev->image.y);
+                       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                             return -EINVAL;
+
+                       pwc_vidioc_fill_fmt(pdev, f);
+
+                       return 0;
+               }
+
+               case VIDIOC_TRY_FMT:
+                       return pwc_vidioc_try_fmt(pdev, arg);
+
+               case VIDIOC_S_FMT:
+                       return pwc_vidioc_set_fmt(pdev, arg);
+
+               case VIDIOC_G_STD:
+               {
+                       v4l2_std_id *std = arg;
+                       *std = V4L2_STD_UNKNOWN;
+                       return 0;
+               }
+
+               case VIDIOC_S_STD:
+               {
+                       v4l2_std_id *std = arg;
+                       if (*std != V4L2_STD_UNKNOWN)
+                               return -EINVAL;
+                       return 0;
+               }
+
+               case VIDIOC_ENUMSTD:
+               {
+                       struct v4l2_standard *std = arg;
+                       if (std->index != 0)
+                               return -EINVAL;
+                       std->id = V4L2_STD_UNKNOWN;
+                       strncpy(std->name, "webcam", sizeof(std->name));
+                       return 0;
+               }
+
+               case VIDIOC_REQBUFS:
+               {
+                       struct v4l2_requestbuffers *rb = arg;
+                       int nbuffers;
+
+                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb->count);
+                       if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                               return -EINVAL;
+                       if (rb->memory != V4L2_MEMORY_MMAP)
+                               return -EINVAL;
+
+                       nbuffers = rb->count;
+                       if (nbuffers < 2)
+                               nbuffers = 2;
+                       else if (nbuffers > pwc_mbufs)
+                               nbuffers = pwc_mbufs;
+                       /* Force to use our # of buffers */
+                       rb->count = pwc_mbufs;
+                       return 0;
+               }
+
+               case VIDIOC_QUERYBUF:
+               {
+                       struct v4l2_buffer *buf = arg;
+                       int index;
+
+                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf->index);
+                       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                               PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
+                               return -EINVAL;
+                       }
+                       if (buf->memory != V4L2_MEMORY_MMAP) {
+                               PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
+                               return -EINVAL;
+                       }
+                       index = buf->index;
+                       if (index < 0 || index >= pwc_mbufs) {
+                               PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
+                               return -EINVAL;
+                       }
+
+                       memset(buf, 0, sizeof(struct v4l2_buffer));
+                       buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                       buf->index = index;
+                       buf->m.offset = index * pdev->len_per_image;
+                       if (pdev->vpalette == VIDEO_PALETTE_RAW)
+                               buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
+                       else
+                               buf->bytesused = pdev->view.size;
+                       buf->field = V4L2_FIELD_NONE;
+                       buf->memory = V4L2_MEMORY_MMAP;
+                       //buf->flags = V4L2_BUF_FLAG_MAPPED;
+                       buf->length = pdev->len_per_image;
+
+                       PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf->index);
+                       PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf->m.offset);
+                       PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf->bytesused);
+
+                       return 0;
+               }
+
+               case VIDIOC_QBUF:
+               {
+                       struct v4l2_buffer *buf = arg;
+
+                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf->index);
+                       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                               return -EINVAL;
+                       if (buf->memory != V4L2_MEMORY_MMAP)
+                               return -EINVAL;
+                       if (buf->index < 0 || buf->index >= pwc_mbufs)
+                               return -EINVAL;
+
+                       buf->flags |= V4L2_BUF_FLAG_QUEUED;
+                       buf->flags &= ~V4L2_BUF_FLAG_DONE;
+
+                       return 0;
+               }
+
+               case VIDIOC_DQBUF:
+               {
+                       struct v4l2_buffer *buf = arg;
+                       int ret;
+
+                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
+
+                       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                               return -EINVAL;
+
+                       /* Add ourselves to the frame wait-queue.
+
+                          FIXME: needs auditing for safety.
+                          QUESTION: In what respect? I think that using the
+                                    frameq is safe now.
+                        */
+                       add_wait_queue(&pdev->frameq, &wait);
+                       while (pdev->full_frames == NULL) {
+                               if (pdev->error_status) {
+                                       remove_wait_queue(&pdev->frameq, &wait);
+                                       set_current_state(TASK_RUNNING);
+                                       return -pdev->error_status;
+                               }
+
+                               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);
+
+                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
+                       /* Decompress data in pdev->images[pdev->fill_image] */
+                       ret = pwc_handle_frame(pdev);
+                       if (ret)
+                               return -EFAULT;
+                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
+
+                       buf->index = pdev->fill_image;
+                       if (pdev->vpalette == VIDEO_PALETTE_RAW)
+                               buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
+                       else
+                               buf->bytesused = pdev->view.size;
+                       buf->flags = V4L2_BUF_FLAG_MAPPED;
+                       buf->field = V4L2_FIELD_NONE;
+                       do_gettimeofday(&buf->timestamp);
+                       buf->sequence = 0;
+                       buf->memory = V4L2_MEMORY_MMAP;
+                       buf->m.offset = pdev->fill_image * pdev->len_per_image;
+                       buf->length = buf->bytesused;
+                       pwc_next_image(pdev);
+
+                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index);
+                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf->length);
+                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf->m.offset);
+                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf->bytesused);
+                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
+                       return 0;
+
+               }
+
+               case VIDIOC_STREAMON:
+               {
+                       /* WARNING: pwc_try_video_mode() called pwc_isoc_init */
+                       pwc_isoc_init(pdev);
+                       return 0;
+               }
+
+               case VIDIOC_STREAMOFF:
+               {
+                       pwc_isoc_cleanup(pdev);
+                       return 0;
+               }
+
+               default:
+                       return pwc_ioctl(pdev, cmd, arg);
+       } /* ..switch */
+       return 0;
+}
+
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
index 1b0ee0ced0ed385e87a660fb8a41a3bc9818d8fe..629f79e44fb6ac940d4dad4ccd4aad11988bcd9b 100644 (file)
@@ -1,5 +1,5 @@
 /* (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 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.
 #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 <linux/version.h>
 #include <asm/semaphore.h>
 #include <asm/errno.h>
+#include <linux/videodev.h>
+#include <media/v4l2-common.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
+#include <media/pwc-ioctl.h>
 
 /* Turn some debugging options on/off */
-#define PWC_DEBUG 0
+#ifndef CONFIG_PWC_DEBUG
+#define CONFIG_PWC_DEBUG 1
+#endif
+
+/* Version block */
+#define PWC_MAJOR      10
+#define PWC_MINOR      0
+#define PWC_EXTRAMINOR 12
+#define PWC_VERSION_CODE KERNEL_VERSION(PWC_MAJOR,PWC_MINOR,PWC_EXTRAMINOR)
+#define PWC_VERSION    "10.0.12"
+#define PWC_NAME       "pwc"
+#define PFX            PWC_NAME ": "
+
 
 /* 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)
+#define PWC_DEBUG_LEVEL_MODULE (1<<0)
+#define PWC_DEBUG_LEVEL_PROBE  (1<<1)
+#define PWC_DEBUG_LEVEL_OPEN   (1<<2)
+#define PWC_DEBUG_LEVEL_READ   (1<<3)
+#define PWC_DEBUG_LEVEL_MEMORY (1<<4)
+#define PWC_DEBUG_LEVEL_FLOW   (1<<5)
+#define PWC_DEBUG_LEVEL_SIZE   (1<<6)
+#define PWC_DEBUG_LEVEL_IOCTL  (1<<7)
+#define PWC_DEBUG_LEVEL_TRACE  (1<<8)
+
+#define PWC_DEBUG_MODULE(fmt, args...) PWC_DEBUG(MODULE, fmt, ##args)
+#define PWC_DEBUG_PROBE(fmt, args...) PWC_DEBUG(PROBE, fmt, ##args)
+#define PWC_DEBUG_OPEN(fmt, args...) PWC_DEBUG(OPEN, fmt, ##args)
+#define PWC_DEBUG_READ(fmt, args...) PWC_DEBUG(READ, fmt, ##args)
+#define PWC_DEBUG_MEMORY(fmt, args...) PWC_DEBUG(MEMORY, fmt, ##args)
+#define PWC_DEBUG_FLOW(fmt, args...) PWC_DEBUG(FLOW, fmt, ##args)
+#define PWC_DEBUG_SIZE(fmt, args...) PWC_DEBUG(SIZE, fmt, ##args)
+#define PWC_DEBUG_IOCTL(fmt, args...) PWC_DEBUG(IOCTL, fmt, ##args)
+#define PWC_DEBUG_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args)
+
+
+#if CONFIG_PWC_DEBUG
+
+#define PWC_DEBUG_LEVEL        (PWC_DEBUG_LEVEL_MODULE)
+
+#define PWC_DEBUG(level, fmt, args...) do {\
+         if ((PWC_DEBUG_LEVEL_ ##level) & pwc_trace) \
+            printk(KERN_DEBUG PFX fmt, ##args); \
+         } while(0)
+
+#define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args)
+#define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args)
+#define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args)
+#define PWC_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args)
+
+#else /* if ! CONFIG_PWC_DEBUG */
+
+#define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args)
+#define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args)
+#define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args)
+#define PWC_TRACE(fmt, args...) do { } while(0)
+#define PWC_DEBUG(level, fmt, args...) do { } while(0)
+
+#define pwc_trace 0
 
+#endif
 
 /* 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"
+#define FEATURE_CODEC1                 0x0002
+#define FEATURE_CODEC2                 0x0004
 
 /* Turn certain features on/off */
 #define PWC_INT_PIPE 0
 /* Absolute maximum number of buffers available for mmap() */
 #define MAX_IMAGES             10
 
+/* Some macros to quickly find the type of a webcam */
+#define DEVICE_USE_CODEC1(x) ((x)<675)
+#define DEVICE_USE_CODEC2(x) ((x)>=675 && (x)<700)
+#define DEVICE_USE_CODEC3(x) ((x)>=700)
+#define DEVICE_USE_CODEC23(x) ((x)>=675)
+
+
+#ifndef V4L2_PIX_FMT_PWC1
+#define V4L2_PIX_FMT_PWC1      v4l2_fourcc('P','W','C','1')
+#define V4L2_PIX_FMT_PWC2      v4l2_fourcc('P','W','C','2')
+#endif
+
 /* The following structures were based on cpia.h. Why reinvent the wheel? :-) */
 struct pwc_iso_buf
 {
@@ -110,17 +158,19 @@ 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
+};
+
+/* additionnal informations used when dealing image between kernel and userland */
+struct pwc_imgbuf
+{
+       unsigned long offset;   /* offset of this buffer in the big array of image_data */
+       int   vma_use_count;    /* count the number of time this memory is mapped */
 };
 
 struct pwc_device
 {
    struct video_device *vdev;
-#ifdef PWC_MAGIC
-   int magic;
-#endif
+
    /* Pointer to our usb_device */
    struct usb_device *udev;
 
@@ -177,12 +227,8 @@ struct pwc_device
    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 */
@@ -198,7 +244,7 @@ struct pwc_device
    struct pwc_coord offset;            /* offset within the viewport */
 
    void *image_data;                   /* total buffer, which is subdivided into ... */
-   void *image_ptr[MAX_IMAGES];                /* ...several images... */
+   struct pwc_imgbuf images[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 */
@@ -211,6 +257,7 @@ struct pwc_device
    struct pwc_mpt_range angle_range;
    int pan_angle;                      /* in degrees * 100 */
    int tilt_angle;                     /* absolute angle; 0,0 is home position */
+   int snapshot_button_status;         /* set to 1 when the user push the button, reset to 0 when this value is read */
 
    /*** Misc. data ***/
    wait_queue_head_t frameq;           /* When waiting for a frame to finish... */
@@ -219,20 +266,26 @@ struct pwc_device
 #endif
 };
 
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/* Global variable */
+/* Global variables */
+#if CONFIG_PWC_DEBUG
 extern int pwc_trace;
+#endif
+extern int pwc_mbufs;
 
 /** 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);
+int pwc_handle_frame(struct pwc_device *pdev);
+void pwc_next_image(struct pwc_device *pdev);
+int pwc_isoc_init(struct pwc_device *pdev);
+void pwc_isoc_cleanup(struct pwc_device *pdev);
 
 /** Functions in pwc-misc.c */
 /* sizes in pixels */
-extern struct pwc_coord pwc_image_sizes[PSZ_MAX];
+extern const 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);
@@ -240,6 +293,9 @@ 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);
+/* Calculate the number of bytes per image (not frame) */
+extern int pwc_mpt_reset(struct pwc_device *pdev, int flags);
+extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt);
 
 /* Various controls; should be obvious. Value 0..65535, or < 0 on error */
 extern int pwc_get_brightness(struct pwc_device *pdev);
@@ -248,10 +304,36 @@ 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_get_saturation(struct pwc_device *pdev, int *value);
 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);
+extern int pwc_restore_user(struct pwc_device *pdev);
+extern int pwc_save_user(struct pwc_device *pdev);
+extern int pwc_restore_factory(struct pwc_device *pdev);
+
+/* exported for use by v4l2 controls */
+extern int pwc_get_red_gain(struct pwc_device *pdev, int *value);
+extern int pwc_set_red_gain(struct pwc_device *pdev, int value);
+extern int pwc_get_blue_gain(struct pwc_device *pdev, int *value);
+extern int pwc_set_blue_gain(struct pwc_device *pdev, int value);
+extern int pwc_get_awb(struct pwc_device *pdev);
+extern int pwc_set_awb(struct pwc_device *pdev, int mode);
+extern int pwc_set_agc(struct pwc_device *pdev, int mode, int value);
+extern int pwc_get_agc(struct pwc_device *pdev, int *value);
+extern int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value);
+extern int pwc_get_shutter_speed(struct pwc_device *pdev, int *value);
+
+extern int pwc_set_colour_mode(struct pwc_device *pdev, int colour);
+extern int pwc_get_colour_mode(struct pwc_device *pdev, int *colour);
+extern int pwc_set_contour(struct pwc_device *pdev, int contour);
+extern int pwc_get_contour(struct pwc_device *pdev, int *contour);
+extern int pwc_set_backlight(struct pwc_device *pdev, int backlight);
+extern int pwc_get_backlight(struct pwc_device *pdev, int *backlight);
+extern int pwc_set_flicker(struct pwc_device *pdev, int flicker);
+extern int pwc_get_flicker(struct pwc_device *pdev, int *flicker);
+extern int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise);
+extern int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise);
 
 /* Power down or up the camera; not supported by all models */
 extern int pwc_camera_power(struct pwc_device *pdev, int power);
@@ -259,6 +341,9 @@ 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);
 
+/** Functions in pwc-v4l.c */
+extern int pwc_video_do_ioctl(struct inode *inode, struct file *file,
+                             unsigned int cmd, void *arg);
 
 /** pwc-uncompress.c */
 /* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */
@@ -270,3 +355,4 @@ extern int pwc_decompress(struct pwc_device *pdev);
 
 
 #endif
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
index dd830e0e5e96f112ff7b2181df9f771a5dfdf1b8..59a187272c831007de3dba1745759abeb0c04653 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/i2c.h>
 #include <linux/videotext.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/mutex.h>
 
 #include "saa5246a.h"
index 531e9461cb66d4fdbc7ab03f6941e4af2d8d43a9..19a8d65699f84892be0149e1cacedb48e18a0fdb 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/i2c.h>
 #include <linux/videotext.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/mutex.h>
 
 
index 41d951db6ec0f34c731644d6dfa74b71dc8b8519..676b9970eb2e2cd6d1d596064b6940e47528c78e 100644 (file)
@@ -43,6 +43,7 @@ MODULE_LICENSE("GPL");
 #define I2C_NAME(s) (s)->name
 
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/video_decoder.h>
 
 static int debug = 0;
index dceebc0b1250afbbf7f541d69a4488a958d75b12..b59c1171727351a52beb6b77286fb977f5c27903 100644 (file)
@@ -72,6 +72,10 @@ struct saa7115_state {
        int sat;
        enum v4l2_chip_ident ident;
        u32 audclk_freq;
+       u32 crystal_freq;
+       u8 ucgc;
+       u8 cgcdiv;
+       u8 apll;
 };
 
 /* ----------------------------------------------------------------------- */
@@ -375,10 +379,6 @@ static const unsigned char saa7113_init_auto_input[] = {
 };
 
 static const unsigned char saa7115_init_misc[] = {
-       0x38, 0x03,             /* audio stuff */
-       0x39, 0x10,
-       0x3a, 0x08,
-
        0x81, 0x01,             /* reg 0x15,0x16 define blanking window */
        0x82, 0x00,
        0x83, 0x01,             /* I port settings */
@@ -584,6 +584,7 @@ static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
        u32 acni;
        u32 hz;
        u64 f;
+       u8 acc = 0;     /* reg 0x3a, audio clock control */
 
        v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
 
@@ -591,18 +592,34 @@ static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
        if (freq < 32000 || freq > 48000)
                return -EINVAL;
 
+       /* The saa7113 has no audio clock */
+       if (state->ident == V4L2_IDENT_SAA7113)
+               return 0;
+
        /* hz is the refresh rate times 100 */
        hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
        /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
        acpf = (25600 * freq) / hz;
        /* acni = (256 * freq * 2^23) / crystal_frequency =
                  (freq * 2^(8+23)) / crystal_frequency =
-                 (freq << 31) / 32.11 MHz */
+                 (freq << 31) / crystal_frequency */
        f = freq;
        f = f << 31;
-       do_div(f, 32110000);
+       do_div(f, state->crystal_freq);
        acni = f;
+       if (state->ucgc) {
+               acpf = acpf * state->cgcdiv / 16;
+               acni = acni * state->cgcdiv / 16;
+               acc = 0x80;
+               if (state->cgcdiv == 3)
+                       acc |= 0x40;
+       }
+       if (state->apll)
+               acc |= 0x08;
 
+       saa7115_write(client, 0x38, 0x03);
+       saa7115_write(client, 0x39, 0x10);
+       saa7115_write(client, 0x3a, acc);
        saa7115_write(client, 0x30, acpf & 0xff);
        saa7115_write(client, 0x31, (acpf >> 8) & 0xff);
        saa7115_write(client, 0x32, (acpf >> 16) & 0x03);
@@ -1073,48 +1090,6 @@ static void saa7115_decode_vbi_line(struct i2c_client *client,
 
 /* ============ SAA7115 AUDIO settings (end) ============= */
 
-static struct v4l2_queryctrl saa7115_qctrl[] = {
-       {
-               .id            = V4L2_CID_BRIGHTNESS,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Brightness",
-               .minimum       = 0,
-               .maximum       = 255,
-               .step          = 1,
-               .default_value = 128,
-               .flags         = 0,
-       }, {
-               .id            = V4L2_CID_CONTRAST,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Contrast",
-               .minimum       = 0,
-               .maximum       = 127,
-               .step          = 1,
-               .default_value = 64,
-               .flags         = 0,
-       }, {
-               .id            = V4L2_CID_SATURATION,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Saturation",
-               .minimum       = 0,
-               .maximum       = 127,
-               .step          = 1,
-               .default_value = 64,
-               .flags         = 0,
-       }, {
-               .id            = V4L2_CID_HUE,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-               .name          = "Hue",
-               .minimum       = -128,
-               .maximum       = 127,
-               .step          = 1,
-               .default_value = 0,
-               .flags         = 0,
-       },
-};
-
-/* ----------------------------------------------------------------------- */
-
 static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
        struct saa7115_state *state = i2c_get_clientdata(client);
@@ -1158,14 +1133,16 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
        case VIDIOC_QUERYCTRL:
        {
                struct v4l2_queryctrl *qc = arg;
-               int i;
 
-               for (i = 0; i < ARRAY_SIZE(saa7115_qctrl); i++)
-                       if (qc->id && qc->id == saa7115_qctrl[i].id) {
-                               memcpy(qc, &saa7115_qctrl[i], sizeof(*qc));
-                               return 0;
-                       }
-               return -EINVAL;
+               switch (qc->id) {
+                       case V4L2_CID_BRIGHTNESS:
+                       case V4L2_CID_CONTRAST:
+                       case V4L2_CID_SATURATION:
+                       case V4L2_CID_HUE:
+                               return v4l2_ctrl_query_fill_std(qc);
+                       default:
+                               return -EINVAL;
+               }
        }
 
        case VIDIOC_G_STD:
@@ -1221,34 +1198,6 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
                break;
        }
 
-       case VIDIOC_G_INPUT:
-               *(int *)arg = state->input;
-               break;
-
-       case VIDIOC_S_INPUT:
-               v4l_dbg(1, debug, client, "decoder set input %d\n", *iarg);
-               /* inputs from 0-9 are available */
-               if (*iarg < 0 || *iarg > 9) {
-                       return -EINVAL;
-               }
-
-               if (state->input == *iarg)
-                       break;
-               v4l_dbg(1, debug, client, "now setting %s input\n",
-                       *iarg >= 6 ? "S-Video" : "Composite");
-               state->input = *iarg;
-
-               /* select mode */
-               saa7115_write(client, 0x02,
-                             (saa7115_read(client, 0x02) & 0xf0) |
-                              state->input);
-
-               /* bypass chrominance trap for modes 6..9 */
-               saa7115_write(client, 0x09,
-                             (saa7115_read(client, 0x09) & 0x7f) |
-                              (state->input < 6 ? 0x0 : 0x80));
-               break;
-
        case VIDIOC_STREAMON:
        case VIDIOC_STREAMOFF:
                v4l_dbg(1, debug, client, "%s output\n",
@@ -1260,6 +1209,21 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
                }
                break;
 
+       case VIDIOC_INT_S_CRYSTAL_FREQ:
+       {
+               struct v4l2_crystal_freq *freq = arg;
+
+               if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
+                   freq->freq != SAA7115_FREQ_24_576_MHZ)
+                       return -EINVAL;
+               state->crystal_freq = freq->freq;
+               state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
+               state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
+               state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
+               saa7115_set_audio_clock_freq(client, state->audclk_freq);
+               break;
+       }
+
        case VIDIOC_INT_DECODE_VBI_LINE:
                saa7115_decode_vbi_line(client, arg);
                break;
@@ -1401,10 +1365,13 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
        v4l_dbg(1, debug, client, "writing init values\n");
 
        /* init to 60hz/48khz */
-       if (state->ident == V4L2_IDENT_SAA7113)
+       if (state->ident == V4L2_IDENT_SAA7113) {
+               state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
                saa7115_writeregs(client, saa7113_init_auto_input);
-       else
+       } else {
+               state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
                saa7115_writeregs(client, saa7115_init_auto_input);
+       }
        saa7115_writeregs(client, saa7115_init_misc);
        saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
        saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
index c271e2e14105721e953da48d2dc2ad564370e27a..ad401bdefeaf39f30b566bffd8510f49f052925a 100644 (file)
@@ -270,7 +270,7 @@ static const char * const wss_strs[] = {
        "letterbox 16:9 top",
        "invalid",
        "invalid",
-       "16:9 full format anamorphic"
+       "16:9 full format anamorphic",
        "4:3 full format",
        "invalid",
        "invalid",
index 0e0ba50946e8923e9dc230cad0d046cc46cebe5f..de7b9e6e932a9b70aec1e53e2ff5d3ff985369c9 100644 (file)
@@ -39,6 +39,23 @@ enum saa6752hs_videoformat {
        SAA6752HS_VF_UNKNOWN,
 };
 
+struct saa6752hs_mpeg_params {
+       /* transport streams */
+       __u16                           ts_pid_pmt;
+       __u16                           ts_pid_audio;
+       __u16                           ts_pid_video;
+       __u16                           ts_pid_pcr;
+
+       /* audio */
+       enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate;
+
+       /* video */
+       enum v4l2_mpeg_video_aspect     vi_aspect;
+       enum v4l2_mpeg_video_bitrate_mode vi_bitrate_mode;
+       __u32                           vi_bitrate;
+       __u32                           vi_bitrate_peak;
+};
+
 static const struct v4l2_format v4l2_format_table[] =
 {
        [SAA6752HS_VF_D1] =
@@ -55,18 +72,19 @@ static const struct v4l2_format v4l2_format_table[] =
 
 struct saa6752hs_state {
        struct i2c_client             client;
-       struct v4l2_mpeg_compression  params;
+       struct v4l2_mpeg_compression  old_params;
+       struct saa6752hs_mpeg_params  params;
        enum saa6752hs_videoformat    video_format;
        v4l2_std_id                   standard;
 };
 
 enum saa6752hs_command {
        SAA6752HS_COMMAND_RESET = 0,
-       SAA6752HS_COMMAND_STOP = 1,
-       SAA6752HS_COMMAND_START = 2,
-       SAA6752HS_COMMAND_PAUSE = 3,
-       SAA6752HS_COMMAND_RECONFIGURE = 4,
-       SAA6752HS_COMMAND_SLEEP = 5,
+       SAA6752HS_COMMAND_STOP = 1,
+       SAA6752HS_COMMAND_START = 2,
+       SAA6752HS_COMMAND_PAUSE = 3,
+       SAA6752HS_COMMAND_RECONFIGURE = 4,
+       SAA6752HS_COMMAND_SLEEP = 5,
        SAA6752HS_COMMAND_RECONFIGURE_FORCE = 6,
 
        SAA6752HS_COMMAND_MAX
@@ -129,7 +147,22 @@ static u8 PMT[] = {
        0x00, 0x00, 0x00, 0x00 /* CRC32 */
 };
 
-static struct v4l2_mpeg_compression param_defaults =
+static struct saa6752hs_mpeg_params param_defaults =
+{
+       .ts_pid_pmt      = 16,
+       .ts_pid_video    = 260,
+       .ts_pid_audio    = 256,
+       .ts_pid_pcr      = 259,
+
+       .vi_aspect       = V4L2_MPEG_VIDEO_ASPECT_4x3,
+       .vi_bitrate      = 4000,
+       .vi_bitrate_peak = 6000,
+       .vi_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+
+       .au_l2_bitrate   = V4L2_MPEG_AUDIO_L2_BITRATE_256K,
+};
+
+static struct v4l2_mpeg_compression old_param_defaults =
 {
        .st_type         = V4L2_MPEG_TS_2,
        .st_bitrate      = {
@@ -228,45 +261,57 @@ static int saa6752hs_chip_command(struct i2c_client* client,
 
 
 static int saa6752hs_set_bitrate(struct i2c_client* client,
-                                struct v4l2_mpeg_compression* params)
+                                struct saa6752hs_mpeg_params* params)
 {
        u8 buf[3];
+       int tot_bitrate;
 
        /* set the bitrate mode */
        buf[0] = 0x71;
-       buf[1] = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ? 0 : 1;
+       buf[1] = (params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) ? 0 : 1;
        i2c_master_send(client, buf, 2);
 
        /* set the video bitrate */
-       if (params->vi_bitrate.mode == V4L2_BITRATE_VBR) {
+       if (params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
                /* set the target bitrate */
                buf[0] = 0x80;
-               buf[1] = params->vi_bitrate.target >> 8;
-               buf[2] = params->vi_bitrate.target & 0xff;
+               buf[1] = params->vi_bitrate >> 8;
+               buf[2] = params->vi_bitrate & 0xff;
                i2c_master_send(client, buf, 3);
 
                /* set the max bitrate */
                buf[0] = 0x81;
-               buf[1] = params->vi_bitrate.max >> 8;
-               buf[2] = params->vi_bitrate.max & 0xff;
+               buf[1] = params->vi_bitrate_peak >> 8;
+               buf[2] = params->vi_bitrate_peak & 0xff;
                i2c_master_send(client, buf, 3);
+               tot_bitrate = params->vi_bitrate_peak;
        } else {
                /* set the target bitrate (no max bitrate for CBR) */
                buf[0] = 0x81;
-               buf[1] = params->vi_bitrate.target >> 8;
-               buf[2] = params->vi_bitrate.target & 0xff;
+               buf[1] = params->vi_bitrate >> 8;
+               buf[2] = params->vi_bitrate & 0xff;
                i2c_master_send(client, buf, 3);
+               tot_bitrate = params->vi_bitrate;
        }
 
        /* set the audio bitrate */
        buf[0] = 0x94;
-       buf[1] = (256 == params->au_bitrate.target) ? 0 : 1;
+       buf[1] = (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 0 : 1;
        i2c_master_send(client, buf, 2);
+       tot_bitrate += (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 256 : 384;
+
+       /* Note: the total max bitrate is determined by adding the video and audio
+          bitrates together and also adding an extra 768kbit/s to stay on the
+          safe side. If more control should be required, then an extra MPEG control
+          should be added. */
+       tot_bitrate += 768;
+       if (tot_bitrate > MPEG_TOTAL_TARGET_BITRATE_MAX)
+               tot_bitrate = MPEG_TOTAL_TARGET_BITRATE_MAX;
 
        /* set the total bitrate */
        buf[0] = 0xb1;
-       buf[1] = params->st_bitrate.target >> 8;
-       buf[2] = params->st_bitrate.target & 0xff;
+       buf[1] = tot_bitrate >> 8;
+       buf[2] = tot_bitrate & 0xff;
        i2c_master_send(client, buf, 3);
 
        return 0;
@@ -318,50 +363,188 @@ static void saa6752hs_set_subsampling(struct i2c_client* client,
 }
 
 
-static void saa6752hs_set_params(struct i2c_client* client,
+static void saa6752hs_old_set_params(struct i2c_client* client,
                                 struct v4l2_mpeg_compression* params)
 {
        struct saa6752hs_state *h = i2c_get_clientdata(client);
 
        /* check PIDs */
-       if (params->ts_pid_pmt <= MPEG_PID_MAX)
+       if (params->ts_pid_pmt <= MPEG_PID_MAX) {
+               h->old_params.ts_pid_pmt = params->ts_pid_pmt;
                h->params.ts_pid_pmt = params->ts_pid_pmt;
-       if (params->ts_pid_pcr <= MPEG_PID_MAX)
+       }
+       if (params->ts_pid_pcr <= MPEG_PID_MAX) {
+               h->old_params.ts_pid_pcr = params->ts_pid_pcr;
                h->params.ts_pid_pcr = params->ts_pid_pcr;
-       if (params->ts_pid_video <= MPEG_PID_MAX)
+       }
+       if (params->ts_pid_video <= MPEG_PID_MAX) {
+               h->old_params.ts_pid_video = params->ts_pid_video;
                h->params.ts_pid_video = params->ts_pid_video;
-       if (params->ts_pid_audio <= MPEG_PID_MAX)
+       }
+       if (params->ts_pid_audio <= MPEG_PID_MAX) {
+               h->old_params.ts_pid_audio = params->ts_pid_audio;
                h->params.ts_pid_audio = params->ts_pid_audio;
+       }
 
        /* check bitrate parameters */
        if ((params->vi_bitrate.mode == V4L2_BITRATE_CBR) ||
-           (params->vi_bitrate.mode == V4L2_BITRATE_VBR))
-               h->params.vi_bitrate.mode = params->vi_bitrate.mode;
+           (params->vi_bitrate.mode == V4L2_BITRATE_VBR)) {
+               h->old_params.vi_bitrate.mode = params->vi_bitrate.mode;
+               h->params.vi_bitrate_mode = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ?
+                      V4L2_MPEG_VIDEO_BITRATE_MODE_VBR : V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+       }
        if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
-               h->params.st_bitrate.target = params->st_bitrate.target;
+               h->old_params.st_bitrate.target = params->st_bitrate.target;
        if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
-               h->params.vi_bitrate.target = params->vi_bitrate.target;
+               h->old_params.vi_bitrate.target = params->vi_bitrate.target;
        if (params->vi_bitrate.mode == V4L2_BITRATE_VBR)
-               h->params.vi_bitrate.max = params->vi_bitrate.max;
+               h->old_params.vi_bitrate.max = params->vi_bitrate.max;
        if (params->au_bitrate.mode != V4L2_BITRATE_NONE)
-               h->params.au_bitrate.target = params->au_bitrate.target;
+               h->old_params.au_bitrate.target = params->au_bitrate.target;
 
        /* aspect ratio */
        if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3 ||
-           params->vi_aspect_ratio == V4L2_MPEG_ASPECT_16_9)
-               h->params.vi_aspect_ratio = params->vi_aspect_ratio;
+           params->vi_aspect_ratio == V4L2_MPEG_ASPECT_16_9) {
+               h->old_params.vi_aspect_ratio = params->vi_aspect_ratio;
+               if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3)
+                       h->params.vi_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3;
+               else
+                       h->params.vi_aspect = V4L2_MPEG_VIDEO_ASPECT_16x9;
+       }
 
        /* range checks */
-       if (h->params.st_bitrate.target > MPEG_TOTAL_TARGET_BITRATE_MAX)
-               h->params.st_bitrate.target = MPEG_TOTAL_TARGET_BITRATE_MAX;
-       if (h->params.vi_bitrate.target > MPEG_VIDEO_TARGET_BITRATE_MAX)
-               h->params.vi_bitrate.target = MPEG_VIDEO_TARGET_BITRATE_MAX;
-       if (h->params.vi_bitrate.max > MPEG_VIDEO_MAX_BITRATE_MAX)
-               h->params.vi_bitrate.max = MPEG_VIDEO_MAX_BITRATE_MAX;
-       if (h->params.au_bitrate.target <= 256)
-               h->params.au_bitrate.target = 256;
+       if (h->old_params.st_bitrate.target > MPEG_TOTAL_TARGET_BITRATE_MAX)
+               h->old_params.st_bitrate.target = MPEG_TOTAL_TARGET_BITRATE_MAX;
+       if (h->old_params.vi_bitrate.target > MPEG_VIDEO_TARGET_BITRATE_MAX)
+               h->old_params.vi_bitrate.target = MPEG_VIDEO_TARGET_BITRATE_MAX;
+       if (h->old_params.vi_bitrate.max > MPEG_VIDEO_MAX_BITRATE_MAX)
+               h->old_params.vi_bitrate.max = MPEG_VIDEO_MAX_BITRATE_MAX;
+       h->params.vi_bitrate = params->vi_bitrate.target;
+       h->params.vi_bitrate_peak = params->vi_bitrate.max;
+       if (h->old_params.au_bitrate.target <= 256) {
+               h->old_params.au_bitrate.target = 256;
+               h->params.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
+       }
+       else {
+               h->old_params.au_bitrate.target = 384;
+               h->params.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
+       }
+}
+
+static int handle_ctrl(struct saa6752hs_mpeg_params *params,
+               struct v4l2_ext_control *ctrl, int cmd)
+{
+       int old = 0, new;
+       int set = cmd == VIDIOC_S_EXT_CTRLS;
+
+       new = ctrl->value;
+       switch (ctrl->id) {
+               case V4L2_CID_MPEG_STREAM_TYPE:
+                       old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
+                       if (set && new != old)
+                               return -ERANGE;
+                       new = old;
+                       break;
+               case V4L2_CID_MPEG_STREAM_PID_PMT:
+                       old = params->ts_pid_pmt;
+                       if (set && new > MPEG_PID_MAX)
+                               return -ERANGE;
+                       if (new > MPEG_PID_MAX)
+                               new = MPEG_PID_MAX;
+                       params->ts_pid_pmt = new;
+                       break;
+               case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+                       old = params->ts_pid_audio;
+                       if (set && new > MPEG_PID_MAX)
+                               return -ERANGE;
+                       if (new > MPEG_PID_MAX)
+                               new = MPEG_PID_MAX;
+                       params->ts_pid_audio = new;
+                       break;
+               case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+                       old = params->ts_pid_video;
+                       if (set && new > MPEG_PID_MAX)
+                               return -ERANGE;
+                       if (new > MPEG_PID_MAX)
+                               new = MPEG_PID_MAX;
+                       params->ts_pid_video = new;
+                       break;
+               case V4L2_CID_MPEG_STREAM_PID_PCR:
+                       old = params->ts_pid_pcr;
+                       if (set && new > MPEG_PID_MAX)
+                               return -ERANGE;
+                       if (new > MPEG_PID_MAX)
+                               new = MPEG_PID_MAX;
+                       params->ts_pid_pcr = new;
+                       break;
+               case V4L2_CID_MPEG_AUDIO_ENCODING:
+                       old = V4L2_MPEG_AUDIO_ENCODING_LAYER_2;
+                       if (set && new != old)
+                               return -ERANGE;
+                       new = old;
+                       break;
+               case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+                       old = params->au_l2_bitrate;
+                       if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K &&
+                                  new != V4L2_MPEG_AUDIO_L2_BITRATE_384K)
+                               return -ERANGE;
+                       if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K)
+                               new = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
+                       else
+                               new = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
+                       params->au_l2_bitrate = new;
+                       break;
+               case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+                       old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
+                       if (set && new != old)
+                               return -ERANGE;
+                       new = old;
+                       break;
+               case V4L2_CID_MPEG_VIDEO_ENCODING:
+                       old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+                       if (set && new != old)
+                               return -ERANGE;
+                       new = old;
+                       break;
+               case V4L2_CID_MPEG_VIDEO_ASPECT:
+                       old = params->vi_aspect;
+                       if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 &&
+                                  new != V4L2_MPEG_VIDEO_ASPECT_4x3)
+                               return -ERANGE;
+                       if (new != V4L2_MPEG_VIDEO_ASPECT_16x9)
+                               new = V4L2_MPEG_VIDEO_ASPECT_4x3;
+                       params->vi_aspect = new;
+                       break;
+               case V4L2_CID_MPEG_VIDEO_BITRATE:
+                       old = params->vi_bitrate * 1000;
+                       new = 1000 * (new / 1000);
+                       if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+                               return -ERANGE;
+                       if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+                               new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
+                       params->vi_bitrate = new / 1000;
+                       break;
+               case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+                       old = params->vi_bitrate_peak * 1000;
+                       new = 1000 * (new / 1000);
+                       if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+                               return -ERANGE;
+                       if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+                               new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
+                       params->vi_bitrate_peak = new / 1000;
+                       break;
+               case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+                       old = params->vi_bitrate_mode;
+                       params->vi_bitrate_mode = new;
+                       break;
+               default:
+                       return -EINVAL;
+       }
+       if (cmd == VIDIOC_G_EXT_CTRLS)
+               ctrl->value = old;
        else
-               h->params.au_bitrate.target = 384;
+               ctrl->value = new;
+       return 0;
 }
 
 static int saa6752hs_init(struct i2c_client* client)
@@ -395,22 +578,22 @@ static int saa6752hs_init(struct i2c_client* client)
        buf[2] = 0x0D;
        i2c_master_send(client,buf,3);
 
-       /* Set minimum Q-scale {4} */
+       /* Set minimum Q-scale {4} */
        buf[0] = 0x82;
        buf[1] = 0x04;
        i2c_master_send(client,buf,2);
 
-       /* Set maximum Q-scale {12} */
+       /* Set maximum Q-scale {12} */
        buf[0] = 0x83;
        buf[1] = 0x0C;
        i2c_master_send(client,buf,2);
 
-       /* Set Output Protocol */
+       /* Set Output Protocol */
        buf[0] = 0xD0;
        buf[1] = 0x81;
        i2c_master_send(client,buf,2);
 
-       /* Set video output stream format {TS} */
+       /* Set video output stream format {TS} */
        buf[0] = 0xB0;
        buf[1] = 0x05;
        i2c_master_send(client,buf,2);
@@ -441,7 +624,7 @@ static int saa6752hs_init(struct i2c_client* client)
        localPMT[sizeof(PMT) - 2] = (crc >> 8) & 0xFF;
        localPMT[sizeof(PMT) - 1] = crc & 0xFF;
 
-       /* Set Audio PID */
+       /* Set Audio PID */
        buf[0] = 0xC1;
        buf[1] = (h->params.ts_pid_audio >> 8) & 0xFF;
        buf[2] = h->params.ts_pid_audio & 0xFF;
@@ -489,11 +672,11 @@ static int saa6752hs_init(struct i2c_client* client)
        buf[3] = 0x82;
        buf[4] = 0xB0;
        buf[5] = buf2[0];
-       switch(h->params.vi_aspect_ratio) {
-       case V4L2_MPEG_ASPECT_16_9:
+       switch(h->params.vi_aspect) {
+       case V4L2_MPEG_VIDEO_ASPECT_16x9:
                buf[6] = buf2[1] | 0x40;
                break;
-       case V4L2_MPEG_ASPECT_4_3:
+       case V4L2_MPEG_VIDEO_ASPECT_4x3:
        default:
                buf[6] = buf2[1] & 0xBF;
                break;
@@ -515,6 +698,7 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
                return -ENOMEM;
        h->client = client_template;
        h->params = param_defaults;
+       h->old_params = old_param_defaults;
        h->client.adapter = adap;
        h->client.addr = addr;
 
@@ -550,20 +734,45 @@ static int
 saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
        struct saa6752hs_state *h = i2c_get_clientdata(client);
-       struct v4l2_mpeg_compression *params = arg;
+       struct v4l2_ext_controls *ctrls = arg;
+       struct v4l2_mpeg_compression *old_params = arg;
+       struct saa6752hs_mpeg_params params;
        int err = 0;
+       int i;
 
        switch (cmd) {
        case VIDIOC_S_MPEGCOMP:
-               if (NULL == params) {
+               if (NULL == old_params) {
                        /* apply settings and start encoder */
                        saa6752hs_init(client);
                        break;
                }
-               saa6752hs_set_params(client, params);
+               saa6752hs_old_set_params(client, old_params);
                /* fall through */
        case VIDIOC_G_MPEGCOMP:
-               *params = h->params;
+               *old_params = h->old_params;
+               break;
+       case VIDIOC_S_EXT_CTRLS:
+               if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+                       return -EINVAL;
+               if (ctrls->count == 0) {
+                       /* apply settings and start encoder */
+                       saa6752hs_init(client);
+                       break;
+               }
+               /* fall through */
+       case VIDIOC_TRY_EXT_CTRLS:
+       case VIDIOC_G_EXT_CTRLS:
+               if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+                       return -EINVAL;
+               params = h->params;
+               for (i = 0; i < ctrls->count; i++) {
+                       if ((err = handle_ctrl(&params, ctrls->controls + i, cmd))) {
+                               ctrls->error_idx = i;
+                               return err;
+                       }
+               }
+               h->params = params;
                break;
        case VIDIOC_G_FMT:
        {
index bb3e0ba946d34b2eb2b854a25b8b44f1a4a06e55..d77e6a8d9432db4aba09eb8b0977893f098eee00 100644 (file)
@@ -818,7 +818,7 @@ static int snd_saa7134_capsrc_put(struct snd_kcontrol * kcontrol,
                                break;
                }
 
-               /* output xbar always main channel */
+               /* output xbar always main channel */
                saa_dsp_writel(dev, SAA7133_DIGITAL_OUTPUT_SEL1, 0xbbbb10);
 
                if (left || right) { // We've got data, turn the input on
index 86eae3528330bb415316ffb6247de54d6fc0492a..927413aded10c120cedbfbddcf57970d48dceca4 100644 (file)
@@ -2160,7 +2160,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio = {
                          .name = name_radio,
                          .amux = LINE2,
-               },
+               },
        },
        [SAA7134_BOARD_GOTVIEW_7135] = {
                /* Mike Baikov <mike@baikov.com> */
@@ -2842,6 +2842,55 @@ struct saa7134_board saa7134_boards[] = {
                        .gpio = 0x000000,       /* GPIO21=Low for FM radio antenna */
                },
        },
+       [SAA7134_BOARD_FLYVIDEO3000_NTSC] = {
+               /* "Zac Bowling" <zac@zacbowling.com> */
+               .name           = "LifeView FlyVIDEO3000 (NTSC)",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_PHILIPS_NTSC,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+
+               .gpiomask       = 0xe000,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .gpio = 0x8000,
+                       .tv   = 1,
+               },{
+                       .name = name_tv_mono,
+                       .vmux = 1,
+                       .amux = LINE2,
+                       .gpio = 0x0000,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 0,
+                       .amux = LINE2,
+                       .gpio = 0x4000,
+               },{
+                       .name = name_comp2,
+                       .vmux = 3,
+                       .amux = LINE2,
+                       .gpio = 0x4000,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE2,
+                       .gpio = 0x4000,
+               }},
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+                       .gpio = 0x2000,
+               },
+                       .mute = {
+                       .name = name_mute,
+                       .amux = TV,
+                       .gpio = 0x8000,
+               },
+       },
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -2898,6 +2947,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x153b,
                .subdevice    = 0x1162,
                .driver_data  = SAA7134_BOARD_CINERGY400_CARDBUS,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x5169,
+               .subdevice    = 0x0138,
+               .driver_data  = SAA7134_BOARD_FLYVIDEO3000_NTSC,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -3459,6 +3514,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        switch (dev->board) {
        case SAA7134_BOARD_FLYVIDEO2000:
        case SAA7134_BOARD_FLYVIDEO3000:
+       case SAA7134_BOARD_FLYVIDEO3000_NTSC:
                dev->has_remote = SAA7134_REMOTE_GPIO;
                board_flyvideo(dev);
                break;
index 222a36c3891756489c20ca9b1a0c1553ed2298f2..279828b8f299bf45598b92af8d6e4b3f2b9d775d 100644 (file)
@@ -132,9 +132,8 @@ static int mt352_aver777_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static int mt352_pinnacle_pll_set(struct dvb_frontend* fe,
-                                 struct dvb_frontend_parameters* params,
-                                 u8* pllbuf)
+static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe,
+                                          struct dvb_frontend_parameters* params)
 {
        u8 off[] = { 0x00, 0xf1};
        u8 on[]  = { 0x00, 0x71};
@@ -147,30 +146,31 @@ static int mt352_pinnacle_pll_set(struct dvb_frontend* fe,
        f.tuner     = 0;
        f.type      = V4L2_TUNER_DIGITAL_TV;
        f.frequency = params->frequency / 1000 * 16 / 1000;
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(&dev->i2c_adap, &msg, 1);
        saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f);
        msg.buf = on;
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(&dev->i2c_adap, &msg, 1);
 
        pinnacle_antenna_pwr(dev, antenna_pwr);
 
        /* mt352 setup */
-       mt352_pinnacle_init(fe);
-       pllbuf[0] = 0xc2;
-       pllbuf[1] = 0x00;
-       pllbuf[2] = 0x00;
-       pllbuf[3] = 0x80;
-       pllbuf[4] = 0x00;
-       return 0;
+       return mt352_pinnacle_init(fe);
 }
 
-static int mt352_aver777_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf)
+static int mt352_aver777_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
 {
-       pllbuf[0] = 0xc2;
+       if (buf_len < 5)
+               return -EINVAL;
+
+       pllbuf[0] = 0x61;
        dvb_pll_configure(&dvb_pll_philips_td1316, pllbuf+1,
                          params->frequency,
                          params->u.ofdm.bandwidth);
-       return 0;
+       return 5;
 }
 
 static struct mt352_config pinnacle_300i = {
@@ -179,13 +179,11 @@ static struct mt352_config pinnacle_300i = {
        .if2           = 36150,
        .no_tuner      = 1,
        .demod_init    = mt352_pinnacle_init,
-       .pll_set       = mt352_pinnacle_pll_set,
 };
 
 static struct mt352_config avermedia_777 = {
        .demod_address = 0xf,
        .demod_init    = mt352_aver777_init,
-       .pll_set       = mt352_aver777_pll_set,
 };
 #endif
 
@@ -268,6 +266,8 @@ static int philips_tda6651_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_
        tuner_buf[2] = 0xca;
        tuner_buf[3] = (cp << 5) | (filter << 3) | band;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
                return -EIO;
        msleep(1);
@@ -281,6 +281,8 @@ static int philips_tda6651_pll_init(u8 addr, struct dvb_frontend *fe)
        struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
 
        /* setup PLL configuration */
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
                return -EIO;
        msleep(1);
@@ -290,12 +292,12 @@ static int philips_tda6651_pll_init(u8 addr, struct dvb_frontend *fe)
 
 /* ------------------------------------------------------------------ */
 
-static int philips_tu1216_pll_60_init(struct dvb_frontend *fe)
+static int philips_tu1216_tuner_60_init(struct dvb_frontend *fe)
 {
        return philips_tda6651_pll_init(0x60, fe);
 }
 
-static int philips_tu1216_pll_60_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tu1216_tuner_60_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
        return philips_tda6651_pll_set(0x60, fe, params);
 }
@@ -315,20 +317,17 @@ static struct tda1004x_config philips_tu1216_60_config = {
        .xtal_freq     = TDA10046_XTAL_4M,
        .agc_config    = TDA10046_AGC_DEFAULT,
        .if_freq       = TDA10046_FREQ_3617,
-       .pll_init      = philips_tu1216_pll_60_init,
-       .pll_set       = philips_tu1216_pll_60_set,
-       .pll_sleep     = NULL,
        .request_firmware = philips_tu1216_request_firmware,
 };
 
 /* ------------------------------------------------------------------ */
 
-static int philips_tu1216_pll_61_init(struct dvb_frontend *fe)
+static int philips_tu1216_tuner_61_init(struct dvb_frontend *fe)
 {
        return philips_tda6651_pll_init(0x61, fe);
 }
 
-static int philips_tu1216_pll_61_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tu1216_tuner_61_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
        return philips_tda6651_pll_set(0x61, fe, params);
 }
@@ -341,21 +340,20 @@ static struct tda1004x_config philips_tu1216_61_config = {
        .xtal_freq     = TDA10046_XTAL_4M,
        .agc_config    = TDA10046_AGC_DEFAULT,
        .if_freq       = TDA10046_FREQ_3617,
-       .pll_init      = philips_tu1216_pll_61_init,
-       .pll_set       = philips_tu1216_pll_61_set,
-       .pll_sleep     = NULL,
        .request_firmware = philips_tu1216_request_firmware,
 };
 
 /* ------------------------------------------------------------------ */
 
-static int philips_europa_pll_init(struct dvb_frontend *fe)
+static int philips_europa_tuner_init(struct dvb_frontend *fe)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
        static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab };
        struct i2c_msg init_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) };
 
        /* setup PLL configuration */
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
                return -EIO;
        msleep(1);
@@ -365,18 +363,20 @@ static int philips_europa_pll_init(struct dvb_frontend *fe)
        init_msg.len  = 0x02;
        msg[0] = 0x00;
        msg[1] = 0x40;
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
                return -EIO;
 
        return 0;
 }
 
-static int philips_td1316_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
        return philips_tda6651_pll_set(0x61, fe, params);
 }
 
-static void philips_europa_analog(struct dvb_frontend *fe)
+static int philips_europa_tuner_sleep(struct dvb_frontend *fe)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
        /* this message actually turns the tuner back to analog mode */
@@ -391,7 +391,20 @@ static void philips_europa_analog(struct dvb_frontend *fe)
        analog_msg.len  = 0x02;
        msg[0] = 0x00;
        msg[1] = 0x14;
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
+       return 0;
+}
+
+static int philips_europa_demod_sleep(struct dvb_frontend *fe)
+{
+       struct saa7134_dev *dev = fe->dvb->priv;
+
+       if (dev->original_demod_sleep)
+               dev->original_demod_sleep(fe);
+       fe->ops.i2c_gate_ctrl(fe, 1);
+       return 0;
 }
 
 static struct tda1004x_config philips_europa_config = {
@@ -402,21 +415,20 @@ static struct tda1004x_config philips_europa_config = {
        .xtal_freq     = TDA10046_XTAL_4M,
        .agc_config    = TDA10046_AGC_IFO_AUTO_POS,
        .if_freq       = TDA10046_FREQ_052,
-       .pll_init      = philips_europa_pll_init,
-       .pll_set       = philips_td1316_pll_set,
-       .pll_sleep     = philips_europa_analog,
        .request_firmware = NULL,
 };
 
 /* ------------------------------------------------------------------ */
 
-static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
+static int philips_fmd1216_tuner_init(struct dvb_frontend *fe)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
        /* this message is to set up ATC and ALC */
        static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
        struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
                return -EIO;
        msleep(1);
@@ -424,22 +436,27 @@ static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
        return 0;
 }
 
-static void philips_fmd1216_analog(struct dvb_frontend *fe)
+static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
        /* this message actually turns the tuner back to analog mode */
        static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 };
        struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
        msleep(1);
        fmd1216_init[2] = 0x86;
        fmd1216_init[3] = 0x54;
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
        msleep(1);
+       return 0;
 }
 
-static int philips_fmd1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
        u8 tuner_buf[4];
@@ -516,6 +533,8 @@ static int philips_fmd1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
        tuner_buf[2] = 0x80 | (cp << 6) | (mode  << 3) | 4;
        tuner_buf[3] = 0x40 | band;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
                return -EIO;
        return 0;
@@ -528,9 +547,6 @@ static struct tda1004x_config medion_cardbus = {
        .xtal_freq     = TDA10046_XTAL_16M,
        .agc_config    = TDA10046_AGC_IFO_AUTO_NEG,
        .if_freq       = TDA10046_FREQ_3613,
-       .pll_init      = philips_fmd1216_pll_init,
-       .pll_set       = philips_fmd1216_pll_set,
-       .pll_sleep         = philips_fmd1216_analog,
        .request_firmware = NULL,
 };
 
@@ -578,12 +594,12 @@ static struct tda827x_data tda827x_dvbt[] = {
        { .lomax =         0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}
 };
 
-static int philips_tda827x_pll_init(struct dvb_frontend *fe)
+static int philips_tda827x_tuner_init(struct dvb_frontend *fe)
 {
        return 0;
 }
 
-static int philips_tda827x_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tda827x_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
        u8 tuner_buf[14];
@@ -630,6 +646,8 @@ static int philips_tda827x_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
        tuner_buf[13] = 0x40;
 
        tuner_msg.len = 14;
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
                return -EIO;
 
@@ -638,18 +656,23 @@ static int philips_tda827x_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
        tuner_buf[0] = 0x30;
        tuner_buf[1] = 0x50 + tda827x_dvbt[i].cp;
        tuner_msg.len = 2;
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
 
        return 0;
 }
 
-static void philips_tda827x_pll_sleep(struct dvb_frontend *fe)
+static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
        static u8 tda827x_sleep[] = { 0x30, 0xd0};
        struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tda827x_sleep,
                                    .len = sizeof(tda827x_sleep) };
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
+       return 0;
 }
 
 static struct tda1004x_config tda827x_lifeview_config = {
@@ -659,9 +682,6 @@ static struct tda1004x_config tda827x_lifeview_config = {
        .xtal_freq     = TDA10046_XTAL_16M,
        .agc_config    = TDA10046_AGC_TDA827X,
        .if_freq       = TDA10046_FREQ_045,
-       .pll_init      = philips_tda827x_pll_init,
-       .pll_set       = philips_tda827x_pll_set,
-       .pll_sleep         = philips_tda827x_pll_sleep,
        .request_firmware = NULL,
 };
 
@@ -753,6 +773,8 @@ static int philips_tda827xa_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb
        tuner_buf[12] = 0x00;
        tuner_buf[13] = 0x39;  // lpsel
        msg.len = 14;
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
                return -EIO;
 
@@ -760,10 +782,14 @@ static int philips_tda827xa_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb
        msg.len = 2;
        reg2[0] = 0x60;
        reg2[1] = 0x3c;
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(&dev->i2c_adap, &msg, 1);
 
        reg2[0] = 0xa0;
        reg2[1] = 0x40;
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(&dev->i2c_adap, &msg, 1);
 
        msleep(2);
@@ -771,36 +797,43 @@ static int philips_tda827xa_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb
        reg2[0] = 0x30;
        reg2[1] = 0x10 + tda827xa_dvbt[i].scr;
        msg.len = 2;
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(&dev->i2c_adap, &msg, 1);
 
        msleep(550);
        reg2[0] = 0x50;
        reg2[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(&dev->i2c_adap, &msg, 1);
 
        return 0;
 
 }
 
-static void philips_tda827xa_pll_sleep(u8 addr, struct dvb_frontend *fe)
+static int philips_tda827xa_tuner_sleep(u8 addr, struct dvb_frontend *fe)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
        static u8 tda827xa_sleep[] = { 0x30, 0x90};
        struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tda827xa_sleep,
                                    .len = sizeof(tda827xa_sleep) };
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
-
+       return 0;
 }
 
 /* ------------------------------------------------------------------ */
 
-static int philips_tiger_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tiger_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
        int ret;
        struct saa7134_dev *dev = fe->dvb->priv;
        static u8 tda8290_close[] = { 0x21, 0xc0};
        static u8 tda8290_open[]  = { 0x21, 0x80};
        struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2};
+
        /* close tda8290 i2c bridge */
        tda8290_msg.buf = tda8290_close;
        ret = i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
@@ -816,7 +849,7 @@ static int philips_tiger_pll_set(struct dvb_frontend *fe, struct dvb_frontend_pa
        return ret;
 }
 
-static int philips_tiger_dvb_mode(struct dvb_frontend *fe)
+static int philips_tiger_tuner_init(struct dvb_frontend *fe)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
        static u8 data[] = { 0x3c, 0x33, 0x6a};
@@ -827,14 +860,15 @@ static int philips_tiger_dvb_mode(struct dvb_frontend *fe)
        return 0;
 }
 
-static void philips_tiger_analog_mode(struct dvb_frontend *fe)
+static int philips_tiger_tuner_sleep(struct dvb_frontend *fe)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
        static u8 data[] = { 0x3c, 0x33, 0x68};
        struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
 
        i2c_transfer(&dev->i2c_adap, &msg, 1);
-       philips_tda827xa_pll_sleep( 0x61, fe);
+       philips_tda827xa_tuner_sleep( 0x61, fe);
+       return 0;
 }
 
 static struct tda1004x_config philips_tiger_config = {
@@ -844,15 +878,12 @@ static struct tda1004x_config philips_tiger_config = {
        .xtal_freq     = TDA10046_XTAL_16M,
        .agc_config    = TDA10046_AGC_TDA827X,
        .if_freq       = TDA10046_FREQ_045,
-       .pll_init      = philips_tiger_dvb_mode,
-       .pll_set       = philips_tiger_pll_set,
-       .pll_sleep     = philips_tiger_analog_mode,
        .request_firmware = NULL,
 };
 
 /* ------------------------------------------------------------------ */
 
-static int lifeview_trio_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int lifeview_trio_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
        int ret;
 
@@ -860,16 +891,12 @@ static int lifeview_trio_pll_set(struct dvb_frontend *fe, struct dvb_frontend_pa
        return ret;
 }
 
-static int lifeview_trio_dvb_mode(struct dvb_frontend *fe)
+static int lifeview_trio_tuner_sleep(struct dvb_frontend *fe)
 {
+       philips_tda827xa_tuner_sleep(0x60, fe);
        return 0;
 }
 
-static void lifeview_trio_analog_mode(struct dvb_frontend *fe)
-{
-       philips_tda827xa_pll_sleep(0x60, fe);
-}
-
 static struct tda1004x_config lifeview_trio_config = {
        .demod_address = 0x09,
        .invert        = 1,
@@ -877,15 +904,12 @@ static struct tda1004x_config lifeview_trio_config = {
        .xtal_freq     = TDA10046_XTAL_16M,
        .agc_config    = TDA10046_AGC_TDA827X_GPL,
        .if_freq       = TDA10046_FREQ_045,
-       .pll_init      = lifeview_trio_dvb_mode,
-       .pll_set       = lifeview_trio_pll_set,
-       .pll_sleep     = lifeview_trio_analog_mode,
        .request_firmware = NULL,
 };
 
 /* ------------------------------------------------------------------ */
 
-static int ads_duo_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int ads_duo_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
        int ret;
 
@@ -893,7 +917,7 @@ static int ads_duo_pll_set(struct dvb_frontend *fe, struct dvb_frontend_paramete
        return ret;
 }
 
-static int ads_duo_dvb_mode(struct dvb_frontend *fe)
+static int ads_duo_tuner_init(struct dvb_frontend *fe)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
        /* route TDA8275a AGC input to the channel decoder */
@@ -901,12 +925,13 @@ static int ads_duo_dvb_mode(struct dvb_frontend *fe)
        return 0;
 }
 
-static void ads_duo_analog_mode(struct dvb_frontend *fe)
+static int ads_duo_tuner_sleep(struct dvb_frontend *fe)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
        /* route TDA8275a AGC input to the analog IF chip*/
        saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x20);
-       philips_tda827xa_pll_sleep( 0x61, fe);
+       philips_tda827xa_tuner_sleep( 0x61, fe);
+       return 0;
 }
 
 static struct tda1004x_config ads_tech_duo_config = {
@@ -916,31 +941,24 @@ static struct tda1004x_config ads_tech_duo_config = {
        .xtal_freq     = TDA10046_XTAL_16M,
        .agc_config    = TDA10046_AGC_TDA827X_GPL,
        .if_freq       = TDA10046_FREQ_045,
-       .pll_init      = ads_duo_dvb_mode,
-       .pll_set       = ads_duo_pll_set,
-       .pll_sleep     = ads_duo_analog_mode,
        .request_firmware = NULL,
 };
 
 /* ------------------------------------------------------------------ */
 
-static int tevion_dvb220rf_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int tevion_dvb220rf_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
        int ret;
        ret = philips_tda827xa_pll_set(0x60, fe, params);
        return ret;
 }
 
-static int tevion_dvb220rf_pll_init(struct dvb_frontend *fe)
+static int tevion_dvb220rf_tuner_sleep(struct dvb_frontend *fe)
 {
+       philips_tda827xa_tuner_sleep( 0x61, fe);
        return 0;
 }
 
-static void tevion_dvb220rf_pll_sleep(struct dvb_frontend *fe)
-{
-       philips_tda827xa_pll_sleep( 0x61, fe);
-}
-
 static struct tda1004x_config tevion_dvbt220rf_config = {
        .demod_address = 0x08,
        .invert        = 1,
@@ -948,9 +966,6 @@ static struct tda1004x_config tevion_dvbt220rf_config = {
        .xtal_freq     = TDA10046_XTAL_16M,
        .agc_config    = TDA10046_AGC_TDA827X,
        .if_freq       = TDA10046_FREQ_045,
-       .pll_init      = tevion_dvb220rf_pll_init,
-       .pll_set       = tevion_dvb220rf_pll_set,
-       .pll_sleep     = tevion_dvb220rf_pll_sleep,
        .request_firmware = NULL,
 };
 
@@ -961,8 +976,6 @@ static struct tda1004x_config tevion_dvbt220rf_config = {
 #ifdef HAVE_NXT200X
 static struct nxt200x_config avertvhda180 = {
        .demod_address    = 0x0a,
-       .pll_address      = 0x61,
-       .pll_desc         = &dvb_pll_tdhu2,
 };
 
 static int nxt200x_set_pll_input(u8 *buf, int input)
@@ -976,8 +989,6 @@ static int nxt200x_set_pll_input(u8 *buf, int input)
 
 static struct nxt200x_config kworldatsc110 = {
        .demod_address    = 0x0a,
-       .pll_address      = 0x61,
-       .pll_desc         = &dvb_pll_tuv1236d,
        .set_pll_input    = nxt200x_set_pll_input,
 };
 #endif
@@ -1003,78 +1014,158 @@ static int dvb_init(struct saa7134_dev *dev)
                printk("%s: pinnacle 300i dvb setup\n",dev->name);
                dev->dvb.frontend = mt352_attach(&pinnacle_300i,
                                                 &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
+               }
                break;
 
        case SAA7134_BOARD_AVERMEDIA_777:
                printk("%s: avertv 777 dvb setup\n",dev->name);
                dev->dvb.frontend = mt352_attach(&avermedia_777,
                                                 &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.tuner_ops.calc_regs = mt352_aver777_tuner_calc_regs;
+               }
                break;
 #endif
 #ifdef HAVE_TDA1004X
        case SAA7134_BOARD_MD7134:
                dev->dvb.frontend = tda10046_attach(&medion_cardbus,
                                                    &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
+                       dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
+                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+               }
                break;
        case SAA7134_BOARD_PHILIPS_TOUGH:
                dev->dvb.frontend = tda10046_attach(&philips_tu1216_60_config,
                                                    &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_60_init;
+                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_60_set_params;
+               }
                break;
        case SAA7134_BOARD_FLYDVBTDUO:
                dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
                                                    &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
+                       dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
+                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
+               }
                break;
        case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
                dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
                                                    &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
+                       dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
+                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
+               }
                break;
        case SAA7134_BOARD_PHILIPS_EUROPA:
                dev->dvb.frontend = tda10046_attach(&philips_europa_config,
                                                    &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
+                       dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+                       dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+                       dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+               }
                break;
        case SAA7134_BOARD_VIDEOMATE_DVBT_300:
                dev->dvb.frontend = tda10046_attach(&philips_europa_config,
                                                    &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+                       dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+               }
                break;
        case SAA7134_BOARD_VIDEOMATE_DVBT_200:
                dev->dvb.frontend = tda10046_attach(&philips_tu1216_61_config,
                                                    &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_61_init;
+                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_61_set_params;
+               }
                break;
        case SAA7134_BOARD_PHILIPS_TIGER:
                dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
                                                    &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
+                       dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
+                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
+               }
                break;
        case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
                dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
                                                    &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
+                       dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
+                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
+               }
                break;
        case SAA7134_BOARD_FLYDVBT_LR301:
                dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
                                                    &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
+                       dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
+                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
+               }
                break;
        case SAA7134_BOARD_FLYDVB_TRIO:
                dev->dvb.frontend = tda10046_attach(&lifeview_trio_config,
                                                    &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.tuner_ops.sleep = lifeview_trio_tuner_sleep;
+                       dev->dvb.frontend->ops.tuner_ops.set_params = lifeview_trio_tuner_set_params;
+               }
                break;
        case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
                dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config,
                                                    &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init;
+                       dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep;
+                       dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params;
+               }
                break;
        case SAA7134_BOARD_TEVION_DVBT_220RF:
                dev->dvb.frontend = tda10046_attach(&tevion_dvbt220rf_config,
                                                    &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.tuner_ops.sleep = tevion_dvb220rf_tuner_sleep;
+                       dev->dvb.frontend->ops.tuner_ops.set_params = tevion_dvb220rf_tuner_set_params;
+               }
                break;
        case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
                dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config,
                                                    &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init;
+                       dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep;
+                       dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params;
+               }
                break;
 #endif
 #ifdef HAVE_NXT200X
        case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
                dev->dvb.frontend = nxt200x_attach(&avertvhda180, &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dvb_pll_attach(dev->dvb.frontend, 0x61, &dev->i2c_adap, &dvb_pll_tdhu2);
+               }
                break;
        case SAA7134_BOARD_KWORLD_ATSC110:
                dev->dvb.frontend = nxt200x_attach(&kworldatsc110, &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dvb_pll_attach(dev->dvb.frontend, 0x61, &dev->i2c_adap, &dvb_pll_tuv1236d);
+               }
                break;
 #endif
        default:
@@ -1088,7 +1179,7 @@ static int dvb_init(struct saa7134_dev *dev)
        }
 
        /* register everything else */
-       return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev);
+       return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
 }
 
 static int dvb_fini(struct saa7134_dev *dev)
index 1d972edb3be6b2cbb3e9c167e24754c5c27cf02f..65d044086ce953b9459b377b53c880aef657f29c 100644 (file)
@@ -64,8 +64,10 @@ static void ts_reset_encoder(struct saa7134_dev* dev)
 
 static int ts_init_encoder(struct saa7134_dev* dev)
 {
+       struct v4l2_ext_controls ctrls = { V4L2_CTRL_CLASS_MPEG, 0 };
+
        ts_reset_encoder(dev);
-       saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, NULL);
+       saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, &ctrls);
        dev->empress_started = 1;
        return 0;
 }
@@ -162,6 +164,7 @@ static int ts_do_ioctl(struct inode *inode, struct file *file,
                       unsigned int cmd, void *arg)
 {
        struct saa7134_dev *dev = file->private_data;
+       struct v4l2_ext_controls *ctrls = arg;
 
        if (debug > 1)
                v4l_print_ioctl(dev->name,cmd);
@@ -278,12 +281,31 @@ static int ts_do_ioctl(struct inode *inode, struct file *file,
                return saa7134_common_ioctl(dev, cmd, arg);
 
        case VIDIOC_S_MPEGCOMP:
+               printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
+                                   "Replace with VIDIOC_S_EXT_CTRLS!");
                saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, arg);
                ts_init_encoder(dev);
                return 0;
        case VIDIOC_G_MPEGCOMP:
+               printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
+                                   "Replace with VIDIOC_G_EXT_CTRLS!");
                saa7134_i2c_call_clients(dev, VIDIOC_G_MPEGCOMP, arg);
                return 0;
+       case VIDIOC_S_EXT_CTRLS:
+               /* count == 0 is abused in saa6752hs.c, so that special
+                  case is handled here explicitly. */
+               if (ctrls->count == 0)
+                       return 0;
+               if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+                       return -EINVAL;
+               saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, arg);
+               ts_init_encoder(dev);
+               return 0;
+       case VIDIOC_G_EXT_CTRLS:
+               if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+                       return -EINVAL;
+               saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, arg);
+               return 0;
 
        default:
                return -ENOIOCTLCMD;
index 1426e4c8602faa00a519e2e6a9a2c1e47d6860bf..7c595492c56b1719cc3059e03030f60573366723 100644 (file)
@@ -37,6 +37,10 @@ static unsigned int ir_debug = 0;
 module_param(ir_debug, int, 0644);
 MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
 
+static int pinnacle_remote = 0;
+module_param(pinnacle_remote, int, 0644);    /* Choose Pinnacle PCTV remote */
+MODULE_PARM_DESC(pinnacle_remote, "Specify Pinnacle PCTV remote: 0=coloured, 1=grey (defaults to 0)");
+
 #define dprintk(fmt, arg...)   if (ir_debug) \
        printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
 #define i2cdprintk(fmt, arg...)    if (ir_debug) \
@@ -316,8 +320,13 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
        switch (dev->board) {
        case SAA7134_BOARD_PINNACLE_PCTV_110i:
                snprintf(ir->c.name, sizeof(ir->c.name), "Pinnacle PCTV");
-               ir->get_key   = get_key_pinnacle;
-               ir->ir_codes  = ir_codes_pinnacle;
+               if (pinnacle_remote == 0) {
+                       ir->get_key   = get_key_pinnacle_color;
+                       ir->ir_codes = ir_codes_pinnacle_color;
+               } else {
+                       ir->get_key   = get_key_pinnacle_grey;
+                       ir->ir_codes = ir_codes_pinnacle_grey;
+               }
                break;
        case SAA7134_BOARD_UPMOST_PURPLE_TV:
                snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV");
index 353af3a8b766b7a868e7a71e0eaf81c4a2b460be..d5ee99c574ccbefa17c617d50594d7bfc8077ab2 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <asm/io.h>
 
+#include <media/v4l2-common.h>
 #include <media/tuner.h>
 #include <media/ir-common.h>
 #include <media/ir-kbd-i2c.h>
@@ -221,6 +222,7 @@ struct saa7134_format {
 #define SAA7134_BOARD_AVERMEDIA_A169_B1 92
 #define SAA7134_BOARD_MD7134_BRIDGE_2     93
 #define SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS 94
+#define SAA7134_BOARD_FLYVIDEO3000_NTSC 95
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -531,6 +533,7 @@ struct saa7134_dev {
 
        /* SAA7134_MPEG_DVB only */
        struct videobuf_dvb        dvb;
+       int (*original_demod_sleep)(struct dvb_frontend* fe);
 };
 
 /* ----------------------------------------------------------- */
index a7a216bd4413cb4554e9ab656bff86c40363dabb..c0891b3e0018efd404cd585b28624a2a7cdc655d 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <asm/uaccess.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/smp_lock.h>
 #include <linux/mutex.h>
 
index ea4394dc9415a84f53c324cb4803878ed13fdc17..48d138a7c7235c6c1197afa6c9d9d0010cdd191a 100644 (file)
@@ -2608,11 +2608,9 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
        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);
 
@@ -2659,7 +2657,6 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
        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);
 
index 07476c71174a70d05a77164c6f4aa39afd7d59fa..6be9c1131e1fc19898c74e9406e932b0e252a3f3 100644 (file)
@@ -42,6 +42,7 @@
 #include <asm/uaccess.h>
 #include <linux/vmalloc.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 
 #include "saa7146.h"
 #include "saa7146reg.h"
index b38bda83a7c5454ce37dcb09484e4d7202554b33..351b182d921f22856edb5f48236db02185cf4f9d 100644 (file)
@@ -66,6 +66,7 @@
 #include <linux/pagemap.h>
 #include <linux/errno.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/usb.h>
 #include <linux/mutex.h>
 
index 103ccb91929260353df41e36a2e0be86ae882dc2..827633b3bb4325239ed282e96c44aac306bbbc5d 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/init.h>
@@ -163,7 +164,7 @@ static void do_tda9875_init(struct i2c_client *client)
        struct tda9875 *t = i2c_get_clientdata(client);
        dprintk("In tda9875_init\n");
        tda9875_write(client, TDA9875_CFG, 0xd0 ); /*reg de config 0 (reset)*/
-       tda9875_write(client, TDA9875_MSR, 0x03 );    /* Monitor 0b00000XXX*/
+       tda9875_write(client, TDA9875_MSR, 0x03 );    /* Monitor 0b00000XXX*/
        tda9875_write(client, TDA9875_C1MSB, 0x00 );  /*Car1(FM) MSB XMHz*/
        tda9875_write(client, TDA9875_C1MIB, 0x00 );  /*Car1(FM) MIB XMHz*/
        tda9875_write(client, TDA9875_C1LSB, 0x00 );  /*Car1(FM) LSB XMHz*/
index 0d54f6c1982bc9e66adce1d68bc2981b20e09608..b6ae969563b2ba9e3d6cefde6e51bcd21b7cbc43 100644 (file)
    TDA9886 (PAL, SECAM, NTSC)
    TDA9887 (PAL, SECAM, NTSC, FM Radio)
 
-   found on:
-   - Pinnacle PCTV (Jul.2002 Version with MT2032, bttv)
-      TDA9887 (world), TDA9885 (USA)
-      Note: OP2 of tda988x must be set to 1, else MT2032 is disabled!
-   - KNC One TV-Station RDS (saa7134)
-   - Hauppauge PVR-150/500 (possibly more)
+   Used as part of several tuners
 */
 
+#define tda9887_info(fmt, arg...) do {\
+       printk(KERN_INFO "%s %d-%04x (tda9887): " fmt, t->i2c.name, \
+                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+#define tda9887_dbg(fmt, arg...) do {\
+       if (tuner_debug) \
+               printk(KERN_INFO "%s %d-%04x (tda9887): " fmt, t->i2c.name, \
+                       i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
 
-/* Addresses to scan */
-static unsigned short normal_i2c[] = {
-       0x84 >>1,
-       0x86 >>1,
-       0x96 >>1,
-       I2C_CLIENT_END,
-};
-I2C_CLIENT_INSMOD;
-
-/* insmod options */
-static unsigned int debug = 0;
-module_param(debug, int, 0644);
-MODULE_LICENSE("GPL");
 
 /* ---------------------------------------------------------------------- */
 
 #define UNSET       (-1U)
-#define tda9887_info(fmt, arg...) do {\
-       printk(KERN_INFO "%s %d-%04x: " fmt, t->client.name, \
-                       i2c_adapter_id(t->client.adapter), t->client.addr , ##arg); } while (0)
-#define tda9887_dbg(fmt, arg...) do {\
-       if (debug) \
-               printk(KERN_INFO "%s %d-%04x: " fmt, t->client.name, \
-                       i2c_adapter_id(t->client.adapter), t->client.addr , ##arg); } while (0)
-
-struct tda9887 {
-       struct i2c_client  client;
-       v4l2_std_id        std;
-       enum tuner_mode    mode;
-       unsigned int       config;
-       unsigned int       using_v4l2;
-       unsigned int       radio_mode;
-       unsigned char      data[4];
-};
 
 struct tvnorm {
        v4l2_std_id       std;
@@ -70,9 +42,6 @@ struct tvnorm {
        unsigned char     e;
 };
 
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
 /* ---------------------------------------------------------------------- */
 
 //
@@ -281,7 +250,7 @@ static struct tvnorm radio_mono = {
 
 /* ---------------------------------------------------------------------- */
 
-static void dump_read_message(struct tda9887 *t, unsigned char *buf)
+static void dump_read_message(struct tuner *t, unsigned char *buf)
 {
        static char *afc[16] = {
                "- 12.5 kHz",
@@ -309,7 +278,7 @@ static void dump_read_message(struct tda9887 *t, unsigned char *buf)
        tda9887_info("  vfi level      : %s\n", (buf[0] & 0x80) ? "high" : "low");
 }
 
-static void dump_write_message(struct tda9887 *t, unsigned char *buf)
+static void dump_write_message(struct tuner *t, unsigned char *buf)
 {
        static char *sound[4] = {
                "AM/TV",
@@ -405,13 +374,13 @@ static void dump_write_message(struct tda9887 *t, unsigned char *buf)
 
 /* ---------------------------------------------------------------------- */
 
-static int tda9887_set_tvnorm(struct tda9887 *t, char *buf)
+static int tda9887_set_tvnorm(struct tuner *t, char *buf)
 {
        struct tvnorm *norm = NULL;
        int i;
 
-       if (t->mode == T_RADIO) {
-               if (t->radio_mode == V4L2_TUNER_MODE_MONO)
+       if (t->mode == V4L2_TUNER_RADIO) {
+               if (t->audmode == V4L2_TUNER_MODE_MONO)
                        norm = &radio_mono;
                else
                        norm = &radio_stereo;
@@ -445,7 +414,7 @@ module_param(port2, int, 0644);
 module_param(qss, int, 0644);
 module_param(adjust, int, 0644);
 
-static int tda9887_set_insmod(struct tda9887 *t, char *buf)
+static int tda9887_set_insmod(struct tuner *t, char *buf)
 {
        if (UNSET != port1) {
                if (port1)
@@ -474,27 +443,27 @@ static int tda9887_set_insmod(struct tda9887 *t, char *buf)
        return 0;
 }
 
-static int tda9887_set_config(struct tda9887 *t, char *buf)
+static int tda9887_set_config(struct tuner *t, char *buf)
 {
-       if (t->config & TDA9887_PORT1_ACTIVE)
+       if (t->tda9887_config & TDA9887_PORT1_ACTIVE)
                buf[1] &= ~cOutputPort1Inactive;
-       if (t->config & TDA9887_PORT1_INACTIVE)
+       if (t->tda9887_config & TDA9887_PORT1_INACTIVE)
                buf[1] |= cOutputPort1Inactive;
-       if (t->config & TDA9887_PORT2_ACTIVE)
+       if (t->tda9887_config & TDA9887_PORT2_ACTIVE)
                buf[1] &= ~cOutputPort2Inactive;
-       if (t->config & TDA9887_PORT2_INACTIVE)
+       if (t->tda9887_config & TDA9887_PORT2_INACTIVE)
                buf[1] |= cOutputPort2Inactive;
 
-       if (t->config & TDA9887_QSS)
+       if (t->tda9887_config & TDA9887_QSS)
                buf[1] |= cQSS;
-       if (t->config & TDA9887_INTERCARRIER)
+       if (t->tda9887_config & TDA9887_INTERCARRIER)
                buf[1] &= ~cQSS;
 
-       if (t->config & TDA9887_AUTOMUTE)
+       if (t->tda9887_config & TDA9887_AUTOMUTE)
                buf[1] |= cAutoMuteFmActive;
-       if (t->config & TDA9887_DEEMPHASIS_MASK) {
+       if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
                buf[2] &= ~0x60;
-               switch (t->config & TDA9887_DEEMPHASIS_MASK) {
+               switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
                case TDA9887_DEEMPHASIS_NONE:
                        buf[2] |= cDeemphasisOFF;
                        break;
@@ -506,153 +475,36 @@ static int tda9887_set_config(struct tda9887 *t, char *buf)
                        break;
                }
        }
-       if (t->config & TDA9887_TOP_SET) {
+       if (t->tda9887_config & TDA9887_TOP_SET) {
                buf[2] &= ~cTopMask;
-               buf[2] |= (t->config >> 8) & cTopMask;
+               buf[2] |= (t->tda9887_config >> 8) & cTopMask;
        }
-       if ((t->config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
+       if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
                buf[1] &= ~cQSS;
        return 0;
 }
 
 /* ---------------------------------------------------------------------- */
 
-static char pal[] = "--";
-static char secam[] = "--";
-static char ntsc[] = "-";
-
-module_param_string(pal, pal, sizeof(pal), 0644);
-module_param_string(secam, secam, sizeof(secam), 0644);
-module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
-
-static int tda9887_fixup_std(struct tda9887 *t)
-{
-       /* get more precise norm info from insmod option */
-       if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
-               switch (pal[0]) {
-               case 'b':
-               case 'B':
-               case 'g':
-               case 'G':
-               case 'h':
-               case 'H':
-               case 'n':
-               case 'N':
-                       if (pal[1] == 'c' || pal[1] == 'C') {
-                               tda9887_dbg("insmod fixup: PAL => PAL-Nc\n");
-                               t->std = V4L2_STD_PAL_Nc;
-                       } else {
-                               tda9887_dbg("insmod fixup: PAL => PAL-BGHN\n");
-                               t->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N;
-                       }
-                       break;
-               case 'i':
-               case 'I':
-                       tda9887_dbg("insmod fixup: PAL => PAL-I\n");
-                       t->std = V4L2_STD_PAL_I;
-                       break;
-               case 'd':
-               case 'D':
-               case 'k':
-               case 'K':
-                       tda9887_dbg("insmod fixup: PAL => PAL-DK\n");
-                       t->std = V4L2_STD_PAL_DK;
-                       break;
-               case 'm':
-               case 'M':
-                       tda9887_dbg("insmod fixup: PAL => PAL-M\n");
-                       t->std = V4L2_STD_PAL_M;
-                       break;
-               case '-':
-                       /* default parameter, do nothing */
-                       break;
-               default:
-                       tda9887_info("pal= argument not recognised\n");
-                       break;
-               }
-       }
-       if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
-               switch (secam[0]) {
-               case 'b':
-               case 'B':
-               case 'g':
-               case 'G':
-               case 'h':
-               case 'H':
-                       tda9887_dbg("insmod fixup: SECAM => SECAM-BGH\n");
-                       t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
-                       break;
-               case 'd':
-               case 'D':
-               case 'k':
-               case 'K':
-                       tda9887_dbg("insmod fixup: SECAM => SECAM-DK\n");
-                       t->std = V4L2_STD_SECAM_DK;
-                       break;
-               case 'l':
-               case 'L':
-                       if (secam[1] == 'c' || secam[1] == 'C') {
-                               tda9887_dbg("insmod fixup: SECAM => SECAM-L'\n");
-                               t->std = V4L2_STD_SECAM_LC;
-                       } else {
-                               tda9887_dbg("insmod fixup: SECAM => SECAM-L\n");
-                               t->std = V4L2_STD_SECAM_L;
-                       }
-                       break;
-               case '-':
-                       /* default parameter, do nothing */
-                       break;
-               default:
-                       tda9887_info("secam= argument not recognised\n");
-                       break;
-               }
-       }
-       if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
-               switch (ntsc[0]) {
-               case 'm':
-               case 'M':
-                       tda9887_dbg("insmod fixup: NTSC => NTSC-M\n");
-                       t->std = V4L2_STD_NTSC_M;
-                       break;
-               case 'j':
-               case 'J':
-                       tda9887_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
-                       t->std = V4L2_STD_NTSC_M_JP;
-                       break;
-               case 'k':
-               case 'K':
-                       tda9887_dbg("insmod fixup: NTSC => NTSC_M_KR\n");
-                       t->std = V4L2_STD_NTSC_M_KR;
-                       break;
-               case '-':
-                       /* default parameter, do nothing */
-                       break;
-               default:
-                       tda9887_info("ntsc= argument not recognised\n");
-                       break;
-               }
-       }
-       return 0;
-}
-
-static int tda9887_status(struct tda9887 *t)
+static int tda9887_status(struct tuner *t)
 {
        unsigned char buf[1];
        int rc;
 
        memset(buf,0,sizeof(buf));
-       if (1 != (rc = i2c_master_recv(&t->client,buf,1)))
+       if (1 != (rc = i2c_master_recv(&t->i2c,buf,1)))
                tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
        dump_read_message(t, buf);
        return 0;
 }
 
-static int tda9887_configure(struct tda9887 *t)
+static void tda9887_configure(struct i2c_client *client)
 {
+       struct tuner *t = i2c_get_clientdata(client);
        int rc;
 
-       memset(t->data,0,sizeof(t->data));
-       tda9887_set_tvnorm(t,t->data);
+       memset(t->tda9887_data,0,sizeof(t->tda9887_data));
+       tda9887_set_tvnorm(t,t->tda9887_data);
 
        /* A note on the port settings:
           These settings tend to depend on the specifics of the board.
@@ -667,249 +519,84 @@ static int tda9887_configure(struct tda9887 *t)
           the ports should be set to active (0), but, again, that may
           differ depending on the precise hardware configuration.
         */
-       t->data[1] |= cOutputPort1Inactive;
-       t->data[1] |= cOutputPort2Inactive;
+       t->tda9887_data[1] |= cOutputPort1Inactive;
+       t->tda9887_data[1] |= cOutputPort2Inactive;
 
-       tda9887_set_config(t,t->data);
-       tda9887_set_insmod(t,t->data);
+       tda9887_set_config(t,t->tda9887_data);
+       tda9887_set_insmod(t,t->tda9887_data);
 
        if (t->mode == T_STANDBY) {
-               t->data[1] |= cForcedMuteAudioON;
+               t->tda9887_data[1] |= cForcedMuteAudioON;
        }
 
        tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
-               t->data[1],t->data[2],t->data[3]);
-       if (debug > 1)
-               dump_write_message(t, t->data);
+               t->tda9887_data[1],t->tda9887_data[2],t->tda9887_data[3]);
+       if (tuner_debug > 1)
+               dump_write_message(t, t->tda9887_data);
 
-       if (4 != (rc = i2c_master_send(&t->client,t->data,4)))
+       if (4 != (rc = i2c_master_send(&t->i2c,t->tda9887_data,4)))
                tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
 
-       if (debug > 2) {
+       if (tuner_debug > 2) {
                msleep_interruptible(1000);
                tda9887_status(t);
        }
-       return 0;
 }
 
 /* ---------------------------------------------------------------------- */
 
-static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind)
+static void tda9887_tuner_status(struct i2c_client *client)
 {
-       struct tda9887 *t;
-
-       client_template.adapter = adap;
-       client_template.addr    = addr;
-
-       if (NULL == (t = kzalloc(sizeof(*t), GFP_KERNEL)))
-               return -ENOMEM;
-
-       t->client      = client_template;
-       t->std         = 0;
-       t->radio_mode = V4L2_TUNER_MODE_STEREO;
-
-       tda9887_info("chip found @ 0x%x (%s)\n", addr<<1, adap->name);
-
-       i2c_set_clientdata(&t->client, t);
-       i2c_attach_client(&t->client);
-
-       return 0;
+       struct tuner *t = i2c_get_clientdata(client);
+       tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->tda9887_data[1], t->tda9887_data[2], t->tda9887_data[3]);
 }
 
-static int tda9887_probe(struct i2c_adapter *adap)
+static int tda9887_get_afc(struct i2c_client *client)
 {
-       if (adap->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adap, &addr_data, tda9887_attach);
-       return 0;
-}
+       struct tuner *t = i2c_get_clientdata(client);
+       static int AFC_BITS_2_kHz[] = {
+               -12500,  -37500,  -62500,  -97500,
+               -112500, -137500, -162500, -187500,
+               187500,  162500,  137500,  112500,
+               97500 ,  62500,   37500 ,  12500
+       };
+       int afc=0;
+       __u8 reg = 0;
 
-static int tda9887_detach(struct i2c_client *client)
-{
-       struct tda9887 *t = i2c_get_clientdata(client);
+       if (1 == i2c_master_recv(&t->i2c,&reg,1))
+               afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
 
-       i2c_detach_client(client);
-       kfree(t);
-       return 0;
+       return afc;
 }
 
-#define SWITCH_V4L2    if (!t->using_v4l2 && debug) \
-                         tda9887_info("switching to v4l2\n"); \
-                         t->using_v4l2 = 1;
-#define CHECK_V4L2     if (t->using_v4l2) { if (debug) \
-                         tda9887_info("ignore v4l1 call\n"); \
-                         return 0; }
-
-static int
-tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static void tda9887_standby(struct i2c_client *client)
 {
-       struct tda9887 *t = i2c_get_clientdata(client);
-
-       switch (cmd) {
-
-       /* --- configuration --- */
-       case AUDC_SET_RADIO:
-       {
-               t->mode = T_RADIO;
-               tda9887_configure(t);
-               break;
-       }
-       case TUNER_SET_STANDBY:
-       {
-               t->mode = T_STANDBY;
-               tda9887_configure(t);
-               break;
-       }
-       case TDA9887_SET_CONFIG:
-       {
-               int *i = arg;
-
-               t->config = *i;
-               tda9887_configure(t);
-               break;
-       }
-       /* --- v4l ioctls --- */
-       /* take care: bttv does userspace copying, we'll get a
-          kernel pointer here... */
-       case VIDIOCSCHAN:
-       {
-               static const v4l2_std_id map[] = {
-                       [ VIDEO_MODE_PAL   ] = V4L2_STD_PAL,
-                       [ VIDEO_MODE_NTSC  ] = V4L2_STD_NTSC_M,
-                       [ VIDEO_MODE_SECAM ] = V4L2_STD_SECAM,
-                       [ 4 /* bttv */     ] = V4L2_STD_PAL_M,
-                       [ 5 /* bttv */     ] = V4L2_STD_PAL_N,
-                       [ 6 /* bttv */     ] = V4L2_STD_NTSC_M_JP,
-               };
-               struct video_channel *vc = arg;
-
-               CHECK_V4L2;
-               t->mode = T_ANALOG_TV;
-               if (vc->norm < ARRAY_SIZE(map))
-                       t->std = map[vc->norm];
-               tda9887_fixup_std(t);
-               tda9887_configure(t);
-               break;
-       }
-       case VIDIOC_S_STD:
-       {
-               v4l2_std_id *id = arg;
-
-               SWITCH_V4L2;
-               t->mode = T_ANALOG_TV;
-               t->std   = *id;
-               tda9887_fixup_std(t);
-               tda9887_configure(t);
-               break;
-       }
-       case VIDIOC_S_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
-
-               SWITCH_V4L2;
-               if (V4L2_TUNER_ANALOG_TV == f->type) {
-                       if (t->mode == T_ANALOG_TV)
-                               return 0;
-                       t->mode = T_ANALOG_TV;
-               }
-               if (V4L2_TUNER_RADIO == f->type) {
-                       if (t->mode == T_RADIO)
-                               return 0;
-                       t->mode = T_RADIO;
-               }
-               tda9887_configure(t);
-               break;
-       }
-       case VIDIOC_G_TUNER:
-       {
-               static int AFC_BITS_2_kHz[] = {
-                       -12500,  -37500,  -62500,  -97500,
-                       -112500, -137500, -162500, -187500,
-                       187500,  162500,  137500,  112500,
-                       97500 ,  62500,   37500 ,  12500
-               };
-               struct v4l2_tuner* tuner = arg;
-
-               if (t->mode == T_RADIO) {
-                       __u8 reg = 0;
-                       tuner->afc=0;
-                       if (1 == i2c_master_recv(&t->client,&reg,1))
-                               tuner->afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
-               }
-               break;
-       }
-       case VIDIOC_S_TUNER:
-       {
-               struct v4l2_tuner* tuner = arg;
-
-               if (t->mode == T_RADIO) {
-                       t->radio_mode = tuner->audmode;
-                       tda9887_configure (t);
-               }
-               break;
-       }
-       case VIDIOC_LOG_STATUS:
-       {
-               tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->data[1], t->data[2], t->data[3]);
-               break;
-       }
-       default:
-               /* nothing */
-               break;
-       }
-       return 0;
+       tda9887_configure(client);
 }
 
-static int tda9887_suspend(struct device * dev, pm_message_t state)
+static void tda9887_set_freq(struct i2c_client *client, unsigned int freq)
 {
-       struct i2c_client *c = container_of(dev, struct i2c_client, dev);
-       struct tda9887 *t = i2c_get_clientdata(c);
-
-       tda9887_dbg("suspend\n");
-       return 0;
+       tda9887_configure(client);
 }
 
-static int tda9887_resume(struct device * dev)
+int tda9887_tuner_init(struct i2c_client *c)
 {
-       struct i2c_client *c = container_of(dev, struct i2c_client, dev);
-       struct tda9887 *t = i2c_get_clientdata(c);
+       struct tuner *t = i2c_get_clientdata(c);
 
-       tda9887_dbg("resume\n");
-       tda9887_configure(t);
-       return 0;
-}
+       strlcpy(c->name, "tda9887", sizeof(c->name));
 
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver driver = {
-       .id             = I2C_DRIVERID_TDA9887,
-       .attach_adapter = tda9887_probe,
-       .detach_client  = tda9887_detach,
-       .command        = tda9887_command,
-       .driver = {
-               .name    = "tda9887",
-               .suspend = tda9887_suspend,
-               .resume  = tda9887_resume,
-       },
-};
-static struct i2c_client client_template =
-{
-       .name      = "tda9887",
-       .driver    = &driver,
-};
+       tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
+                                               t->i2c.driver->driver.name);
 
-static int __init tda9887_init_module(void)
-{
-       return i2c_add_driver(&driver);
-}
+       t->set_tv_freq = tda9887_set_freq;
+       t->set_radio_freq = tda9887_set_freq;
+       t->standby = tda9887_standby;
+       t->tuner_status=tda9887_tuner_status;
+       t->get_afc=tda9887_get_afc;
 
-static void __exit tda9887_cleanup_module(void)
-{
-       i2c_del_driver(&driver);
+       return 0;
 }
 
-module_init(tda9887_init_module);
-module_exit(tda9887_cleanup_module);
-
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * ---------------------------------------------------------------------------
index c2b98f81c19214e9b9ab464741c3c6ca319bf8da..d1c41781ccc47dd3dd00ea8d7d5d15f3a6dd5cda 100644 (file)
@@ -3,7 +3,7 @@
  * I2C address is allways 0xC0.
  *
  *
- * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br)
+ * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@infradead.org)
  * This code is placed under the terms of the GNU General Public License
  *
  * tea5767 autodetection thanks to Torsten Seeboth and Atsushi Nakagawa
diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c
new file mode 100644 (file)
index 0000000..76b2e96
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * tlv320aic23b - driver version 0.0.1
+ *
+ * Copyright (C) 2006 Scott Alfter <salfter@ssai.us>
+ *
+ * Based on wm8775 driver
+ *
+ * Copyright (C) 2004 Ulf Eklund <ivtv at eklund.to>
+ * Copyright (C) 2005 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.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
+
+MODULE_DESCRIPTION("tlv320aic23b driver");
+MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static unsigned short normal_i2c[] = { 0x34 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+
+struct tlv320aic23b_state {
+       u8 muted;
+};
+
+static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val)
+{
+       int i;
+
+       if ((reg < 0 || reg > 9) && (reg != 15)) {
+               v4l_err(client, "Invalid register R%d\n", reg);
+               return -1;
+       }
+
+       for (i = 0; i < 3; i++) {
+               if (i2c_smbus_write_byte_data(client, (reg << 1) |
+                                       (val >> 8), val & 0xff) == 0) {
+                       return 0;
+               }
+       }
+       v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
+       return -1;
+}
+
+static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd,
+                         void *arg)
+{
+       struct tlv320aic23b_state *state = i2c_get_clientdata(client);
+       struct v4l2_control *ctrl = arg;
+       u32* freq = arg;
+
+       switch (cmd) {
+       case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+               switch (*freq) {
+                       case 32000: /* set sample rate to 32 kHz */
+                               tlv320aic23b_write(client, 8, 0x018);
+                               break;
+                       case 44100: /* set sample rate to 44.1 kHz */
+                               tlv320aic23b_write(client, 8, 0x022);
+                               break;
+                       case 48000: /* set sample rate to 48 kHz */
+                               tlv320aic23b_write(client, 8, 0x000);
+                               break;
+                       default:
+                               return -EINVAL;
+               }
+               break;
+
+       case VIDIOC_G_CTRL:
+               if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+                       return -EINVAL;
+               ctrl->value = state->muted;
+               break;
+
+       case VIDIOC_S_CTRL:
+               if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+                       return -EINVAL;
+               state->muted = ctrl->value;
+               tlv320aic23b_write(client, 0, 0x180); /* mute both channels */
+               /* set gain on both channels to +3.0 dB */
+               if (!state->muted)
+                       tlv320aic23b_write(client, 0, 0x119);
+               break;
+
+       case VIDIOC_LOG_STATUS:
+               v4l_info(client, "Input: %s\n",
+                           state->muted ? "muted" : "active");
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static struct i2c_driver i2c_driver;
+
+static int tlv320aic23b_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+       struct i2c_client *client;
+       struct tlv320aic23b_state *state;
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return 0;
+
+       client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (client == 0)
+               return -ENOMEM;
+
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &i2c_driver;
+       snprintf(client->name, sizeof(client->name) - 1, "tlv320aic23b");
+
+       v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+
+       state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL);
+       if (state == NULL) {
+               kfree(client);
+               return -ENOMEM;
+       }
+       state->muted = 0;
+       i2c_set_clientdata(client, state);
+
+       /* initialize tlv320aic23b */
+       tlv320aic23b_write(client, 15, 0x000);  /* RESET */
+       tlv320aic23b_write(client, 6, 0x00A);   /* turn off DAC & mic input */
+       tlv320aic23b_write(client, 7, 0x049);   /* left-justified, 24-bit, master mode */
+       tlv320aic23b_write(client, 0, 0x119);   /* set gain on both channels to +3.0 dB */
+       tlv320aic23b_write(client, 8, 0x000);   /* set sample rate to 48 kHz */
+       tlv320aic23b_write(client, 9, 0x001);   /* activate digital interface */
+
+       i2c_attach_client(client);
+
+       return 0;
+}
+
+static int tlv320aic23b_probe(struct i2c_adapter *adapter)
+{
+       if (adapter->class & I2C_CLASS_TV_ANALOG)
+               return i2c_probe(adapter, &addr_data, tlv320aic23b_attach);
+       return 0;
+}
+
+static int tlv320aic23b_detach(struct i2c_client *client)
+{
+       int err;
+
+       err = i2c_detach_client(client);
+       if (err) {
+               return err;
+       }
+       kfree(client);
+
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver i2c_driver = {
+       .driver = {
+               .name = "tlv320aic23b",
+       },
+       .id             = I2C_DRIVERID_TLV320AIC23B,
+       .attach_adapter = tlv320aic23b_probe,
+       .detach_client  = tlv320aic23b_detach,
+       .command        = tlv320aic23b_command,
+};
+
+
+static int __init tlv320aic23b_init_module(void)
+{
+       return i2c_add_driver(&i2c_driver);
+}
+
+static void __exit tlv320aic23b_cleanup_module(void)
+{
+       i2c_del_driver(&i2c_driver);
+}
+
+module_init(tlv320aic23b_init_module);
+module_exit(tlv320aic23b_cleanup_module);
index 74ab48c09c6a448a745f3469ae08cdc9c1adf373..bdf506e6ae279a8fd296e2096f80eb75319b6ba8 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <linux/i2c.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 
 #include <media/tuner.h>
 
index 1013b4de89a278c21ebf017a452e7cf73716b226..e95792fd70f8a3193e081a8a611438f032c9bb55 100644 (file)
@@ -199,7 +199,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
                i2c_master_send(c, buffer, 4);
                default_tuner_init(c);
                break;
-       case TUNER_LG_TDVS_H062F:
+       case TUNER_LG_TDVS_H06XF:
                /* Set the Auxiliary Byte. */
                buffer[2] &= ~0x20;
                buffer[2] |= 0x18;
@@ -215,6 +215,9 @@ static void set_type(struct i2c_client *c, unsigned int type,
                i2c_master_send(c,buffer,4);
                default_tuner_init(c);
                break;
+       case TUNER_TDA9887:
+               tda9887_tuner_init(c);
+               break;
        default:
                default_tuner_init(c);
                break;
@@ -241,6 +244,8 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
 {
        struct tuner *t = i2c_get_clientdata(c);
 
+       tuner_dbg("set addr for type %i\n", t->type);
+
        if ( t->type == UNSET && ((tun_setup->addr == ADDR_UNSET &&
                (t->mode_mask & tun_setup->mode_mask)) ||
                tun_setup->addr == c->addr)) {
@@ -436,6 +441,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
        t->radio_if2 = 10700 * 1000;    /* 10.7MHz - FM radio */
        t->audmode = V4L2_TUNER_MODE_STEREO;
        t->mode_mask = T_UNINITIALIZED;
+       t->tuner_status = tuner_status;
        if (tuner_debug_old) {
                tuner_debug = tuner_debug_old;
                printk(KERN_ERR "tuner: tuner_debug is deprecated and will be removed in 2.6.17.\n");
@@ -462,10 +468,14 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
                case 0x4b:
                        /* If chip is not tda8290, don't register.
                           since it can be tda9887*/
-                       if (tda8290_probe(&t->i2c) != 0) {
-                               tuner_dbg("chip at addr %x is not a tda8290\n", addr);
-                               kfree(t);
-                               return 0;
+                       if (tda8290_probe(&t->i2c) == 0) {
+                               tuner_dbg("chip at addr %x is a tda8290\n", addr);
+                       } else {
+                               /* Default is being tda9887 */
+                               t->type = TUNER_TDA9887;
+                               t->mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
+                               t->mode = T_STANDBY;
+                               goto register_client;
                        }
                        break;
                case 0x60:
@@ -592,6 +602,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
        case TUNER_SET_STANDBY:
                if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
                        return 0;
+               t->mode = T_STANDBY;
                if (t->standby)
                        t->standby (client);
                break;
@@ -604,6 +615,14 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                /* Should be implemented, since bttv calls it */
                tuner_dbg("VIDIOCSAUDIO not implemented.\n");
                break;
+       case TDA9887_SET_CONFIG:
+       {
+               int *i = arg;
+
+               t->tda9887_config = *i;
+               set_freq(client, t->tv_freq);
+               break;
+       }
        /* --- v4l ioctls --- */
        /* take care: bttv does userspace copying, we'll get a
           kernel pointer here... */
@@ -744,6 +763,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        switch_v4l2();
 
                        tuner->type = t->mode;
+                       if (t->get_afc)
+                               tuner->afc=t->get_afc(client);
                        if (t->mode == V4L2_TUNER_ANALOG_TV)
                                tuner->capability |= V4L2_TUNER_CAP_NORM;
                        if (t->mode != V4L2_TUNER_RADIO) {
@@ -787,7 +808,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        break;
                }
        case VIDIOC_LOG_STATUS:
-               tuner_status(client);
+               if (t->tuner_status)
+                       t->tuner_status(client);
                break;
        }
 
index 5d7abed71674f179ee6797a21b33ab89ee4ea5ff..6da6f82b8c885960b671a0aadf3b4f6140496073 100644 (file)
@@ -105,7 +105,7 @@ static int tuner_stereo(struct i2c_client *c)
 
        switch (t->type) {
                case TUNER_PHILIPS_FM1216ME_MK3:
-               case TUNER_PHILIPS_FM1236_MK3:
+               case TUNER_PHILIPS_FM1236_MK3:
                case TUNER_PHILIPS_FM1256_IH3:
                        stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
                        break;
index a1ae036b44ec9cd362d452697122f06e0db83dee..9d9226cb6393c389d481c502d09e32fb179582b4 100644 (file)
@@ -874,7 +874,7 @@ static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = {
 };
 
 
-/* ------------ TUNER_LG_TDVS_H062F - INFINEON ATSC ------------ */
+/* ------ TUNER_LG_TDVS_H06XF - LG INNOTEK / INFINEON ATSC ----- */
 
 static struct tuner_range tuner_tua6034_ntsc_ranges[] = {
        { 16 * 165.00 /*MHz*/, 0x8e, 0x01 },
@@ -883,7 +883,7 @@ static struct tuner_range tuner_tua6034_ntsc_ranges[] = {
 };
 
 
-static struct tuner_params tuner_tua6034_params[] = {
+static struct tuner_params tuner_lg_tdvs_h06xf_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_tua6034_ntsc_ranges,
@@ -1024,6 +1024,22 @@ static struct tuner_params tuner_thomson_fe6600_params[] = {
        },
 };
 
+/* ------------ TUNER_SAMSUNG_TCPG_6121P30A - Samsung PAL ------------ */
+
+static struct tuner_range tuner_samsung_tcpg_6121p30a_pal_ranges[] = {
+       { 16 * 146.25 /*MHz*/, 0xce, 0x01, },
+       { 16 * 428.50 /*MHz*/, 0xce, 0x02, },
+       { 16 * 999.99        , 0xce, 0x08, },
+};
+
+static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = {
+       {
+               .type   = TUNER_PARAM_TYPE_PAL,
+               .ranges = tuner_samsung_tcpg_6121p30a_pal_ranges,
+               .count  = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_pal_ranges),
+       },
+};
+
 /* --------------------------------------------------------------------- */
 
 struct tunertype tuners[] = {
@@ -1354,10 +1370,10 @@ struct tunertype tuners[] = {
                .params = tuner_philips_fmd1216me_mk3_params,
                .count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params),
        },
-       [TUNER_LG_TDVS_H062F] = { /* LGINNOTEK ATSC */
-               .name   = "LG TDVS-H062F/TUA6034",
-               .params = tuner_tua6034_params,
-               .count  = ARRAY_SIZE(tuner_tua6034_params),
+       [TUNER_LG_TDVS_H06XF] = { /* LGINNOTEK ATSC */
+               .name   = "LG TDVS-H06xF", /* H061F, H062F & H064F */
+               .params = tuner_lg_tdvs_h06xf_params,
+               .count  = ARRAY_SIZE(tuner_lg_tdvs_h06xf_params),
        },
        [TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */
                .name   = "Ymec TVF66T5-B/DFF",
@@ -1400,6 +1416,16 @@ struct tunertype tuners[] = {
                .params = tuner_thomson_fe6600_params,
                .count  = ARRAY_SIZE(tuner_thomson_fe6600_params),
        },
+       [TUNER_SAMSUNG_TCPG_6121P30A] = { /* Samsung PAL */
+               .name   = "Samsung TCPG 6121P30A",
+               .params = tuner_samsung_tcpg_6121p30a_params,
+               .count  = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_params),
+       },
+       [TUNER_TDA9887] = { /* Philips TDA 9887 IF PLL Demodulator.
+                               This chip is part of some modern tuners */
+               .name   = "Philips TDA988[5,6,7] IF PLL Demodulator",
+               /* see tda9887.c for details */
+       },
 };
 
 unsigned const int tuner_count = ARRAY_SIZE(tuners);
index b463e996961adbb5ee5b6c62db3a045402343adb..30f8d80ddcaa9c688ec817befb8872fcd156e5fd 100644 (file)
@@ -200,7 +200,7 @@ hauppauge_tuner[] =
        { TUNER_ABSENT,        "Philips FQ1286A MK4"},
        { TUNER_ABSENT,        "Philips FQ1216ME MK5"},
        { TUNER_ABSENT,        "Philips FQ1236 MK5"},
-       { TUNER_ABSENT,        "Samsung TCPG_6121P30A"},
+       { TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"},
        { TUNER_TCL_2002MB,    "TCL 2002MB_3H"},
        { TUNER_ABSENT,        "TCL 2002MI_3H"},
        { TUNER_TCL_2002N,     "TCL 2002N 5H"},
index 9e86caeb96a7b530da89b05e18a0cb44d53d7865..1654576de10e9cd5596178d86f342dd385101ffd 100644 (file)
@@ -198,10 +198,6 @@ static int tvmixer_open(struct inode *inode, struct file *file)
 
        /* lock bttv in memory while the mixer is in use  */
        file->private_data = mix;
-#ifndef I2C_PEC
-       if (client->adapter->inc_use)
-               client->adapter->inc_use(client->adapter);
-#endif
        if (client->adapter->owner)
                try_module_get(client->adapter->owner);
        return 0;
@@ -217,10 +213,6 @@ static int tvmixer_release(struct inode *inode, struct file *file)
                return -ENODEV;
        }
 
-#ifndef I2C_PEC
-       if (client->adapter->dec_use)
-               client->adapter->dec_use(client->adapter);
-#endif
        if (client->adapter->owner)
                module_put(client->adapter->owner);
        return 0;
index dab4973bcf8261f4e5cd3eac842bec218e76f388..b167ffab25202106da0bc956b8304430a48634e8 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/delay.h>
 #include <linux/video_decoder.h>
 #include <media/v4l2-common.h>
+#include <media/tvp5150.h>
 
 #include "tvp5150_reg.h"
 
@@ -89,7 +90,7 @@ struct tvp5150 {
        struct i2c_client *client;
 
        v4l2_std_id norm;       /* Current set standard */
-       int input;
+       struct v4l2_routing route;
        int enable;
        int bright;
        int contrast;
@@ -283,29 +284,26 @@ static void dump_reg(struct i2c_client *c)
 /****************************************************************************
                        Basic functions
  ****************************************************************************/
-enum tvp5150_input {
-       TVP5150_ANALOG_CH0 = 0,
-       TVP5150_SVIDEO = 1,
-       TVP5150_ANALOG_CH1 = 2,
-       TVP5150_BLACK_SCREEN = 8
-};
 
-static inline void tvp5150_selmux(struct i2c_client *c,
-                                 enum tvp5150_input input)
+static inline void tvp5150_selmux(struct i2c_client *c)
 {
        int opmode=0;
-
        struct tvp5150 *decoder = i2c_get_clientdata(c);
+       int input = 0;
 
-       if (!decoder->enable)
-               input |= TVP5150_BLACK_SCREEN;
+       if ((decoder->route.output & TVP5150_BLACK_SCREEN) || !decoder->enable)
+               input = 8;
 
        switch (input) {
-       case TVP5150_ANALOG_CH0:
-       case TVP5150_ANALOG_CH1:
+       case TVP5150_COMPOSITE1:
+               input |= 2;
+               /* fall through */
+       case TVP5150_COMPOSITE0:
                opmode=0x30;            /* TV Mode */
                break;
+       case TVP5150_SVIDEO:
        default:
+               input |= 1;
                opmode=0;               /* Auto Mode */
                break;
        }
@@ -790,7 +788,7 @@ static inline void tvp5150_reset(struct i2c_client *c)
        tvp5150_vdp_init(c, vbi_ram_default);
 
        /* Selects decoder input */
-       tvp5150_selmux(c, decoder->input);
+       tvp5150_selmux(c);
 
        /* Initializes TVP5150 to stream enabled values */
        tvp5150_write_inittab(c, tvp5150_init_enable);
@@ -860,6 +858,21 @@ static int tvp5150_command(struct i2c_client *c,
        case VIDIOC_INT_RESET:
                tvp5150_reset(c);
                break;
+       case VIDIOC_INT_G_VIDEO_ROUTING:
+       {
+               struct v4l2_routing *route = arg;
+
+               *route = decoder->route;
+               break;
+       }
+       case VIDIOC_INT_S_VIDEO_ROUTING:
+       {
+               struct v4l2_routing *route = arg;
+
+               decoder->route = *route;
+               tvp5150_selmux(c);
+               break;
+       }
        case VIDIOC_S_STD:
                if (decoder->norm == *(v4l2_std_id *)arg)
                        break;
@@ -1063,7 +1076,7 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter,
        rv = i2c_attach_client(c);
 
        core->norm = V4L2_STD_ALL;      /* Default is autodetect */
-       core->input = 2;
+       core->route.input = TVP5150_COMPOSITE1;
        core->enable = 1;
        core->bright = 32768;
        core->contrast = 32768;
index 39269a2c5635912abcbc8b4f252a50d92a265887..59fb899f31f3548ce1b1c1a72f088a799977c6ed 100644 (file)
@@ -36,3 +36,15 @@ config USB_KONICAWC
 
          To compile this driver as a module, choose M here: the
          module will be called konicawc.
+
+config USB_QUICKCAM_MESSENGER
+       tristate "USB Logitech Quickcam Messenger"
+       depends on USB && VIDEO_DEV
+       select VIDEO_USBVIDEO
+       ---help---
+         Say Y or M here to enable support for the USB Logitech Quickcam
+         Messenger webcam.
+
+         To compile this driver as a module, choose M here: the
+         module will be called quickcam_messenger.
+
index bb52eb8dc2f9c1b501484c117772ae5ed511017f..4a1b144bee4df9f449bea41024f43f1a36a5b320 100644 (file)
@@ -2,3 +2,4 @@ obj-$(CONFIG_VIDEO_USBVIDEO)    += usbvideo.o
 obj-$(CONFIG_USB_IBMCAM)        += ibmcam.o ultracam.o
 obj-$(CONFIG_USB_KONICAWC)      += konicawc.o
 obj-$(CONFIG_USB_VICAM)         += vicam.o
+obj-$(CONFIG_USB_QUICKCAM_MESSENGER)   += quickcam_messenger.o
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
new file mode 100644 (file)
index 0000000..3f3182a
--- /dev/null
@@ -0,0 +1,1120 @@
+/*
+ * Driver for Logitech Quickcam Messenger usb video camera
+ * Copyright (C) Jaya Kumar
+ *
+ * This work was sponsored by CIS(M) Sdn Bhd.
+ * History:
+ * 05/08/2006 - Jaya Kumar
+ * I wrote this based on the konicawc by Simon Evans.
+ * -
+ * Full credit for reverse engineering and creating an initial
+ * working linux driver for the VV6422 goes to the qce-ga project by
+ * Tuukka Toivonen, Jochen Hoenicke, Peter McConnell,
+ * Cristiano De Michele, Georg Acher, Jean-Frederic Clere as well as
+ * others.
+ * ---
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/usb_input.h>
+
+#include "usbvideo.h"
+#include "quickcam_messenger.h"
+
+/*
+ * Version Information
+ */
+
+#ifdef CONFIG_USB_DEBUG
+static int debug;
+#define DEBUG(n, format, arg...) \
+       if (n <= debug) {        \
+               printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+       }
+#else
+#define DEBUG(n, arg...)
+static const int debug = 0;
+#endif
+
+#define DRIVER_VERSION "v0.01"
+#define DRIVER_DESC "Logitech Quickcam Messenger USB"
+
+#define USB_LOGITECH_VENDOR_ID 0x046D
+#define USB_QCM_PRODUCT_ID     0x08F0
+
+#define MAX_CAMERAS    1
+
+#define MAX_COLOUR     32768
+#define MAX_HUE                32768
+#define MAX_BRIGHTNESS 32768
+#define MAX_CONTRAST   32768
+#define MAX_WHITENESS  32768
+
+static int size = SIZE_320X240;
+static int colour = MAX_COLOUR;
+static int hue = MAX_HUE;
+static int brightness =        MAX_BRIGHTNESS;
+static int contrast =  MAX_CONTRAST;
+static int whiteness = MAX_WHITENESS;
+
+static struct usbvideo *cams;
+
+static struct usb_device_id qcm_table [] = {
+       { USB_DEVICE(USB_LOGITECH_VENDOR_ID, USB_QCM_PRODUCT_ID) },
+       { }
+};
+MODULE_DEVICE_TABLE(usb, qcm_table);
+
+#ifdef CONFIG_INPUT
+static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
+{
+       struct input_dev *input_dev;
+
+       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("insufficient mem for cam input device");
+               return;
+       }
+
+       input_dev->name = "QCM 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 qcm_unregister_input(struct qcm *cam)
+{
+       if (cam->input) {
+               input_unregister_device(cam->input);
+               cam->input = NULL;
+       }
+}
+
+static void qcm_report_buttonstat(struct qcm *cam)
+{
+       if (cam->input) {
+               input_report_key(cam->input, BTN_0, cam->button_sts);
+               input_sync(cam->input);
+       }
+}
+
+static void qcm_int_irq(struct urb *urb, struct pt_regs *regs)
+{
+       int ret;
+       struct uvd *uvd = urb->context;
+       struct qcm *cam;
+
+       if (!CAMERA_IS_OPERATIONAL(uvd))
+               return;
+
+       if (!uvd->streaming)
+               return;
+
+       uvd->stats.urb_count++;
+
+       if (urb->status < 0)
+               uvd->stats.iso_err_count++;
+       else {
+               if (urb->actual_length > 0 ) {
+                       cam = (struct qcm *) uvd->user_data;
+                       if (cam->button_sts_buf == 0x88)
+                               cam->button_sts = 0x0;
+                       else if (cam->button_sts_buf == 0x80)
+                               cam->button_sts = 0x1;
+                       qcm_report_buttonstat(cam);
+               }
+       }
+
+       ret = usb_submit_urb(urb, GFP_ATOMIC);
+       if (ret < 0)
+               err("usb_submit_urb error (%d)", ret);
+}
+
+static int qcm_setup_input_int(struct qcm *cam, struct uvd *uvd)
+{
+       int errflag;
+       usb_fill_int_urb(cam->button_urb, uvd->dev,
+                       usb_rcvintpipe(uvd->dev, uvd->video_endp + 1),
+                       &cam->button_sts_buf,
+                       1,
+                       qcm_int_irq,
+                       uvd, 16);
+
+       errflag = usb_submit_urb(cam->button_urb, GFP_KERNEL);
+       if (errflag)
+               err ("usb_submit_int ret %d", errflag);
+       return errflag;
+}
+
+static void qcm_stop_int_data(struct qcm *cam)
+{
+       usb_kill_urb(cam->button_urb);
+}
+
+static int qcm_alloc_int_urb(struct qcm *cam)
+{
+       cam->button_urb = usb_alloc_urb(0, GFP_KERNEL);
+
+       if (!cam->button_urb)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void qcm_free_int(struct qcm *cam)
+{
+       if (cam->button_urb)
+               usb_free_urb(cam->button_urb);
+}
+#endif /* CONFIG_INPUT */
+
+static int qcm_stv_setb(struct usb_device *dev, u16 reg, u8 val)
+{
+       int ret;
+
+       /* we'll wait up to 3 slices but no more */
+       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+               0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+               reg, 0, &val, 1, 3*HZ);
+       return ret;
+}
+
+static int qcm_stv_setw(struct usb_device *dev, u16 reg, u16 val)
+{
+       int ret;
+
+       /* we'll wait up to 3 slices but no more */
+       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+               0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+               reg, 0, &val, 2, 3*HZ);
+       return ret;
+}
+
+static int qcm_stv_getw(struct usb_device *dev, unsigned short reg,
+                                                       __le16 *val)
+{
+       int ret;
+
+       /* we'll wait up to 3 slices but no more */
+       ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+               0x04, USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
+               reg, 0, val, 2, 3*HZ);
+       return ret;
+}
+
+static int qcm_camera_on(struct uvd *uvd)
+{
+       int ret;
+       CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x01));
+       return 0;
+}
+
+static int qcm_camera_off(struct uvd *uvd)
+{
+       int ret;
+       CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
+       return 0;
+}
+
+static void qcm_hsv2rgb(u16 hue, u16 sat, u16 val, u16 *r, u16 *g, u16 *b)
+{
+       unsigned int segment, valsat;
+       signed int   h = (signed int) hue;
+       unsigned int s = (sat - 32768) * 2;     /* rescale */
+       unsigned int v = val;
+       unsigned int p;
+
+       /*
+       the registers controling gain are 8 bit of which
+       we affect only the last 4 bits with our gain.
+       we know that if saturation is 0, (unsaturated) then
+       we're grayscale (center axis of the colour cone) so
+       we set rgb=value. we use a formula obtained from
+       wikipedia to map the cone to the RGB plane. it's
+       as follows for the human value case of h=0..360,
+       s=0..1, v=0..1
+       h_i = h/60 % 6 , f = h/60 - h_i , p = v(1-s)
+       q = v(1 - f*s) , t = v(1 - (1-f)s)
+       h_i==0 => r=v , g=t, b=p
+       h_i==1 => r=q , g=v, b=p
+       h_i==2 => r=p , g=v, b=t
+       h_i==3 => r=p , g=q, b=v
+       h_i==4 => r=t , g=p, b=v
+       h_i==5 => r=v , g=p, b=q
+       the bottom side (the point) and the stuff just up
+       of that is black so we simplify those two cases.
+       */
+       if (sat < 32768) {
+               /* anything less than this is unsaturated */
+               *r = val;
+               *g = val;
+               *b = val;
+               return;
+       }
+       if (val <= (0xFFFF/8)) {
+               /* anything less than this is black */
+               *r = 0;
+               *g = 0;
+               *b = 0;
+               return;
+       }
+
+       /* the rest of this code is copying tukkat's
+       implementation of the hsv2rgb conversion as taken
+       from qc-usb-messenger code. the 10923 is 0xFFFF/6
+       to divide the cone into 6 sectors.  */
+
+       segment = (h + 10923) & 0xFFFF;
+       segment = segment*3 >> 16;              /* 0..2: 0=R, 1=G, 2=B */
+       hue -= segment * 21845;                 /* -10923..10923 */
+       h = hue;
+       h *= 3;
+       valsat = v*s >> 16;                     /* 0..65534 */
+       p = v - valsat;
+       if (h >= 0) {
+               unsigned int t = v - (valsat * (32769 - h) >> 15);
+               switch (segment) {
+               case 0: /* R-> */
+                       *r = v;
+                       *g = t;
+                       *b = p;
+                       break;
+               case 1: /* G-> */
+                       *r = p;
+                       *g = v;
+                       *b = t;
+                       break;
+               case 2: /* B-> */
+                       *r = t;
+                       *g = p;
+                       *b = v;
+                       break;
+               }
+       } else {
+               unsigned int q = v - (valsat * (32769 + h) >> 15);
+               switch (segment) {
+               case 0: /* ->R */
+                       *r = v;
+                       *g = p;
+                       *b = q;
+                       break;
+               case 1: /* ->G */
+                       *r = q;
+                       *g = v;
+                       *b = p;
+                       break;
+               case 2: /* ->B */
+                       *r = p;
+                       *g = q;
+                       *b = v;
+                       break;
+               }
+       }
+}
+
+static int qcm_sensor_set_gains(struct uvd *uvd, u16 hue,
+       u16 saturation, u16 value)
+{
+       int ret;
+       u16 r=0,g=0,b=0;
+
+       /* this code is based on qc-usb-messenger */
+       qcm_hsv2rgb(hue, saturation, value, &r, &g, &b);
+
+       r >>= 12;
+       g >>= 12;
+       b >>= 12;
+
+       /* min val is 8 */
+       r = max((u16) 8, r);
+       g = max((u16) 8, g);
+       b = max((u16) 8, b);
+
+       r |= 0x30;
+       g |= 0x30;
+       b |= 0x30;
+
+       /* set the r,g,b gain registers */
+       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x0509, r));
+       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050A, g));
+       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050B, b));
+
+       /* doing as qc-usb did */
+       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050C, 0x2A));
+       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050D, 0x01));
+       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
+
+       return 0;
+}
+
+static int qcm_sensor_set_exposure(struct uvd *uvd, int exposure)
+{
+       int ret;
+       int formedval;
+
+       /* calculation was from qc-usb-messenger driver */
+       formedval = ( exposure >> 12 );
+
+       /* max value for formedval is 14 */
+       formedval = min(formedval, 14);
+
+       CHECK_RET(ret, qcm_stv_setb(uvd->dev,
+                       0x143A, 0xF0 | formedval));
+       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
+       return 0;
+}
+
+static int qcm_sensor_setlevels(struct uvd *uvd, int brightness, int contrast,
+                                       int hue, int colour)
+{
+       int ret;
+       /* brightness is exposure, contrast is gain, colour is saturation */
+       CHECK_RET(ret,
+               qcm_sensor_set_exposure(uvd, brightness));
+       CHECK_RET(ret, qcm_sensor_set_gains(uvd, hue, colour, contrast));
+
+       return 0;
+}
+
+static int qcm_sensor_setsize(struct uvd *uvd, u8 size)
+{
+       int ret;
+
+       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x1505, size));
+       return 0;
+}
+
+static int qcm_sensor_set_shutter(struct uvd *uvd, int whiteness)
+{
+       int ret;
+       /* some rescaling as done by the qc-usb-messenger code */
+       if (whiteness > 0xC000)
+               whiteness = 0xC000 + (whiteness & 0x3FFF)*8;
+
+       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143D,
+                               (whiteness >> 8) & 0xFF));
+       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143E,
+                               (whiteness >> 16) & 0x03));
+       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
+
+       return 0;
+}
+
+static int qcm_sensor_init(struct uvd *uvd)
+{
+       struct qcm *cam = (struct qcm *) uvd->user_data;
+       int ret;
+       int i;
+
+       for (i=0; i < sizeof(regval_table)/sizeof(regval_table[0]) ; i++) {
+               CHECK_RET(ret, qcm_stv_setb(uvd->dev,
+                                       regval_table[i].reg,
+                                       regval_table[i].val));
+       }
+
+       CHECK_RET(ret, qcm_stv_setw(uvd->dev, 0x15c1,
+                               cpu_to_le16(ISOC_PACKET_SIZE)));
+       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x15c3, 0x08));
+       CHECK_RET(ret, ret = qcm_stv_setb(uvd->dev, 0x143f, 0x01));
+
+       CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
+
+       CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
+
+       CHECK_RET(ret, qcm_sensor_setlevels(uvd, uvd->vpic.brightness,
+                       uvd->vpic.contrast, uvd->vpic.hue, uvd->vpic.colour));
+
+       CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
+       CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
+
+       return 0;
+}
+
+static int qcm_set_camera_size(struct uvd *uvd)
+{
+       int ret;
+       struct qcm *cam = (struct qcm *) uvd->user_data;
+
+       CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
+       cam->width = camera_sizes[cam->size].width;
+       cam->height = camera_sizes[cam->size].height;
+       uvd->videosize = VIDEOSIZE(cam->width, cam->height);
+
+       return 0;
+}
+
+static int qcm_setup_on_open(struct uvd *uvd)
+{
+       int ret;
+
+       CHECK_RET(ret, qcm_sensor_set_gains(uvd, uvd->vpic.hue,
+                               uvd->vpic.colour, uvd->vpic.contrast));
+       CHECK_RET(ret, qcm_sensor_set_exposure(uvd, uvd->vpic.brightness));
+       CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
+       CHECK_RET(ret, qcm_set_camera_size(uvd));
+       CHECK_RET(ret, qcm_camera_on(uvd));
+       return 0;
+}
+
+static void qcm_adjust_picture(struct uvd *uvd)
+{
+       int ret;
+       struct qcm *cam = (struct qcm *) uvd->user_data;
+
+       ret = qcm_camera_off(uvd);
+       if (ret) {
+               err("can't turn camera off. abandoning pic adjustment");
+               return;
+       }
+
+       /* if there's been a change in contrast, hue, or
+       colour then we need to recalculate hsv in order
+       to update gains */
+       if ((cam->contrast != uvd->vpic.contrast) ||
+               (cam->hue != uvd->vpic.hue) ||
+               (cam->colour != uvd->vpic.colour)) {
+               cam->contrast = uvd->vpic.contrast;
+               cam->hue = uvd->vpic.hue;
+               cam->colour = uvd->vpic.colour;
+               ret = qcm_sensor_set_gains(uvd, cam->hue, cam->colour,
+                                               cam->contrast);
+               if (ret) {
+                       err("can't set gains. abandoning pic adjustment");
+                       return;
+               }
+       }
+
+       if (cam->brightness != uvd->vpic.brightness) {
+               cam->brightness = uvd->vpic.brightness;
+               ret = qcm_sensor_set_exposure(uvd, cam->brightness);
+               if (ret) {
+                       err("can't set exposure. abandoning pic adjustment");
+                       return;
+               }
+       }
+
+       if (cam->whiteness != uvd->vpic.whiteness) {
+               cam->whiteness = uvd->vpic.whiteness;
+               qcm_sensor_set_shutter(uvd, cam->whiteness);
+               if (ret) {
+                       err("can't set shutter. abandoning pic adjustment");
+                       return;
+               }
+       }
+
+       ret = qcm_camera_on(uvd);
+       if (ret) {
+               err("can't reenable camera. pic adjustment failed");
+               return;
+       }
+}
+
+static int qcm_process_frame(struct uvd *uvd, u8 *cdata, int framelen)
+{
+       int datalen;
+       int totaldata;
+       struct framehdr {
+               __be16 id;
+               __be16 len;
+       };
+       struct framehdr *fhdr;
+
+       totaldata = 0;
+       while (framelen) {
+               fhdr = (struct framehdr *) cdata;
+               datalen = be16_to_cpu(fhdr->len);
+               framelen -= 4;
+               cdata += 4;
+
+               if ((fhdr->id) == cpu_to_be16(0x8001)) {
+                       RingQueue_Enqueue(&uvd->dp, marker, 4);
+                       totaldata += 4;
+                       continue;
+               }
+               if ((fhdr->id & cpu_to_be16(0xFF00)) == cpu_to_be16(0x0200)) {
+                       RingQueue_Enqueue(&uvd->dp, cdata, datalen);
+                       totaldata += datalen;
+               }
+               framelen -= datalen;
+               cdata += datalen;
+       }
+       return totaldata;
+}
+
+static int qcm_compress_iso(struct uvd *uvd, struct urb *dataurb)
+{
+       int totlen;
+       int i;
+       unsigned char *cdata;
+
+       totlen=0;
+       for (i = 0; i < dataurb->number_of_packets; i++) {
+               int n = dataurb->iso_frame_desc[i].actual_length;
+               int st = dataurb->iso_frame_desc[i].status;
+
+               cdata = dataurb->transfer_buffer +
+                       dataurb->iso_frame_desc[i].offset;
+
+               if (st < 0) {
+                       warn("Data error: packet=%d. len=%d. status=%d.",
+                             i, n, st);
+                       uvd->stats.iso_err_count++;
+                       continue;
+               }
+               if (!n)
+                       continue;
+
+               totlen += qcm_process_frame(uvd, cdata, n);
+       }
+       return totlen;
+}
+
+static void resubmit_urb(struct uvd *uvd, struct urb *urb)
+{
+       int ret;
+
+       urb->dev = uvd->dev;
+       ret = usb_submit_urb(urb, GFP_ATOMIC);
+       if (ret)
+               err("usb_submit_urb error (%d)", ret);
+}
+
+static void qcm_isoc_irq(struct urb *urb, struct pt_regs *regs)
+{
+       int len;
+       struct uvd *uvd = urb->context;
+
+       if (!CAMERA_IS_OPERATIONAL(uvd))
+               return;
+
+       if (!uvd->streaming)
+               return;
+
+       uvd->stats.urb_count++;
+
+       if (!urb->actual_length) {
+               resubmit_urb(uvd, urb);
+               return;
+       }
+
+       len = qcm_compress_iso(uvd, urb);
+       resubmit_urb(uvd, urb);
+       uvd->stats.urb_length = len;
+       uvd->stats.data_count += len;
+       if (len)
+               RingQueue_WakeUpInterruptible(&uvd->dp);
+}
+
+static int qcm_start_data(struct uvd *uvd)
+{
+       struct qcm *cam = (struct qcm *) uvd->user_data;
+       int i;
+       int errflag;
+       int pktsz;
+       int err;
+
+       pktsz = uvd->iso_packet_len;
+       if (!CAMERA_IS_OPERATIONAL(uvd)) {
+               err("Camera is not operational");
+               return -EFAULT;
+       }
+
+       err = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltActive);
+       if (err < 0) {
+               err("usb_set_interface error");
+               uvd->last_error = err;
+               return -EBUSY;
+       }
+
+       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+               int j, k;
+               struct urb *urb = uvd->sbuf[i].urb;
+               urb->dev = uvd->dev;
+               urb->context = uvd;
+               urb->pipe = usb_rcvisocpipe(uvd->dev, uvd->video_endp);
+               urb->interval = 1;
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_buffer = uvd->sbuf[i].data;
+               urb->complete = qcm_isoc_irq;
+               urb->number_of_packets = FRAMES_PER_DESC;
+               urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
+               for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
+                       urb->iso_frame_desc[j].offset = k;
+                       urb->iso_frame_desc[j].length = pktsz;
+               }
+       }
+
+       uvd->streaming = 1;
+       uvd->curframe = -1;
+       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+               errflag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
+               if (errflag)
+                       err ("usb_submit_isoc(%d) ret %d", i, errflag);
+       }
+
+       CHECK_RET(err, qcm_setup_input_int(cam, uvd));
+       CHECK_RET(err, qcm_camera_on(uvd));
+       return 0;
+}
+
+static void qcm_stop_data(struct uvd *uvd)
+{
+       struct qcm *cam = (struct qcm *) uvd->user_data;
+       int i, j;
+       int ret;
+
+       if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
+               return;
+
+       ret = qcm_camera_off(uvd);
+       if (ret)
+               warn("couldn't turn the cam off.");
+
+       uvd->streaming = 0;
+
+       /* Unschedule all of the iso td's */
+       for (i=0; i < USBVIDEO_NUMSBUF; i++)
+               usb_kill_urb(uvd->sbuf[i].urb);
+
+       qcm_stop_int_data(cam);
+
+       if (!uvd->remove_pending) {
+               /* Set packet size to 0 */
+               j = usb_set_interface(uvd->dev, uvd->iface,
+                                       uvd->ifaceAltInactive);
+               if (j < 0) {
+                       err("usb_set_interface() error %d.", j);
+                       uvd->last_error = j;
+               }
+       }
+}
+
+static void qcm_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame)
+{
+       struct qcm *cam = (struct qcm *) uvd->user_data;
+       int x;
+       struct rgb *rgbL0;
+       struct rgb *rgbL1;
+       struct bayL0 *bayL0;
+       struct bayL1 *bayL1;
+       int hor,ver,hordel,verdel;
+       assert(frame != NULL);
+
+       switch (cam->size) {
+       case SIZE_160X120:
+               hor = 162; ver = 124; hordel = 1; verdel = 2;
+               break;
+       case SIZE_320X240:
+       default:
+               hor = 324; ver = 248; hordel = 2; verdel = 4;
+               break;
+       }
+
+       if (frame->scanstate == ScanState_Scanning) {
+               while (RingQueue_GetLength(&uvd->dp) >=
+                        4 + (hor*verdel + hordel)) {
+                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 3) == 0xff)) {
+                               frame->curline = 0;
+                               frame->scanstate = ScanState_Lines;
+                               frame->frameState = FrameState_Grabbing;
+                               RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4);
+                       /*
+                       * if we're starting, we need to discard the first
+                       * 4 lines of y bayer data
+                       * and the first 2 gr elements of x bayer data
+                       */
+                               RING_QUEUE_DEQUEUE_BYTES(&uvd->dp,
+                                                       (hor*verdel + hordel));
+                               break;
+                       }
+                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
+               }
+       }
+
+       if (frame->scanstate == ScanState_Scanning)
+               return;
+
+       /* now we can start processing bayer data so long as we have at least
+       * 2 lines worth of data. this is the simplest demosaicing method that
+       * I could think of. I use each 2x2 bayer element without interpolation
+       * to generate 4 rgb pixels.
+       */
+       while ( frame->curline < cam->height &&
+               (RingQueue_GetLength(&uvd->dp) >= hor*2)) {
+               /* get 2 lines of bayer for demosaicing
+                * into 2 lines of RGB */
+               RingQueue_Dequeue(&uvd->dp, cam->scratch, hor*2);
+               bayL0 = (struct bayL0 *) cam->scratch;
+               bayL1 = (struct bayL1 *) (cam->scratch + hor);
+               /* frame->curline is the rgb y line */
+               rgbL0 = (struct rgb *)
+                               ( frame->data + (cam->width*3*frame->curline));
+               /* w/2 because we're already doing 2 pixels */
+               rgbL1 = rgbL0 + (cam->width/2);
+
+               for (x=0; x < cam->width; x+=2) {
+                       rgbL0->r = bayL0->r;
+                       rgbL0->g = bayL0->g;
+                       rgbL0->b = bayL1->b;
+
+                       rgbL0->r2 = bayL0->r;
+                       rgbL0->g2 = bayL1->g;
+                       rgbL0->b2 = bayL1->b;
+
+                       rgbL1->r = bayL0->r;
+                       rgbL1->g = bayL1->g;
+                       rgbL1->b = bayL1->b;
+
+                       rgbL1->r2 = bayL0->r;
+                       rgbL1->g2 = bayL1->g;
+                       rgbL1->b2 = bayL1->b;
+
+                       rgbL0++;
+                       rgbL1++;
+
+                       bayL0++;
+                       bayL1++;
+               }
+
+               frame->seqRead_Length += cam->width*3*2;
+               frame->curline += 2;
+       }
+       /* See if we filled the frame */
+       if (frame->curline == cam->height) {
+               frame->frameState = FrameState_Done_Hold;
+               frame->curline = 0;
+               uvd->curframe = -1;
+               uvd->stats.frame_num++;
+       }
+}
+
+/* taken from konicawc */
+static int qcm_set_video_mode(struct uvd *uvd, struct video_window *vw)
+{
+       int ret;
+       int newsize;
+       int oldsize;
+       int x = vw->width;
+       int y = vw->height;
+       struct qcm *cam = (struct qcm *) uvd->user_data;
+
+       if (x > 0 && y > 0) {
+               DEBUG(2, "trying to find size %d,%d", x, y);
+               for (newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
+                       if ((camera_sizes[newsize].width == x) &&
+                               (camera_sizes[newsize].height == y))
+                               break;
+               }
+       } else
+               newsize = cam->size;
+
+       if (newsize > MAX_FRAME_SIZE) {
+               DEBUG(1, "couldn't find size %d,%d", x, y);
+               return -EINVAL;
+       }
+
+       if (newsize == cam->size) {
+               DEBUG(1, "Nothing to do");
+               return 0;
+       }
+
+       qcm_stop_data(uvd);
+
+       if (cam->size != newsize) {
+               oldsize = cam->size;
+               cam->size = newsize;
+               ret = qcm_set_camera_size(uvd);
+               if (ret) {
+                       err("Couldn't set camera size, err=%d",ret);
+                       /* restore the original size */
+                       cam->size = oldsize;
+                       return ret;
+               }
+       }
+
+       /* Flush the input queue and clear any current frame in progress */
+
+       RingQueue_Flush(&uvd->dp);
+       if (uvd->curframe != -1) {
+               uvd->frame[uvd->curframe].curline = 0;
+               uvd->frame[uvd->curframe].seqRead_Length = 0;
+               uvd->frame[uvd->curframe].seqRead_Index = 0;
+       }
+
+       CHECK_RET(ret, qcm_start_data(uvd));
+       return 0;
+}
+
+static int qcm_configure_video(struct uvd *uvd)
+{
+       int ret;
+       memset(&uvd->vpic, 0, sizeof(uvd->vpic));
+       memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
+
+       uvd->vpic.colour = colour;
+       uvd->vpic.hue = hue;
+       uvd->vpic.brightness = brightness;
+       uvd->vpic.contrast = contrast;
+       uvd->vpic.whiteness = whiteness;
+       uvd->vpic.depth = 24;
+       uvd->vpic.palette = VIDEO_PALETTE_RGB24;
+
+       memset(&uvd->vcap, 0, sizeof(uvd->vcap));
+       strcpy(uvd->vcap.name, "QCM USB Camera");
+       uvd->vcap.type = VID_TYPE_CAPTURE;
+       uvd->vcap.channels = 1;
+       uvd->vcap.audios = 0;
+
+       uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
+       uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
+       uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
+       uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
+
+       memset(&uvd->vchan, 0, sizeof(uvd->vchan));
+       uvd->vchan.flags = 0 ;
+       uvd->vchan.tuners = 0;
+       uvd->vchan.channel = 0;
+       uvd->vchan.type = VIDEO_TYPE_CAMERA;
+       strcpy(uvd->vchan.name, "Camera");
+
+       CHECK_RET(ret, qcm_sensor_init(uvd));
+       return 0;
+}
+
+static int qcm_probe(struct usb_interface *intf,
+                       const struct usb_device_id *devid)
+{
+       int err;
+       struct uvd *uvd;
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct qcm *cam;
+       size_t buffer_size;
+       unsigned char video_ep;
+       struct usb_host_interface *interface;
+       struct usb_endpoint_descriptor *endpoint;
+       int i,j;
+       unsigned int ifacenum, ifacenum_inact=0;
+       __le16 sensor_id;
+
+       /* we don't support multiconfig cams */
+       if (dev->descriptor.bNumConfigurations != 1)
+               return -ENODEV;
+
+       /* first check for the video interface and not
+       * the audio interface */
+       interface = &intf->cur_altsetting[0];
+       if ((interface->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
+               || (interface->desc.bInterfaceSubClass !=
+                       USB_CLASS_VENDOR_SPEC))
+               return -ENODEV;
+
+       /*
+       walk through each endpoint in each setting in the interface
+       stop when we find the one that's an isochronous IN endpoint.
+       */
+       for (i=0; i < intf->num_altsetting; i++) {
+               interface = &intf->cur_altsetting[i];
+               ifacenum = interface->desc.bAlternateSetting;
+               /* walk the end points */
+               for (j=0; j < interface->desc.bNumEndpoints; j++) {
+                       endpoint = &interface->endpoint[j].desc;
+
+                       if ((endpoint->bEndpointAddress &
+                               USB_ENDPOINT_DIR_MASK) != USB_DIR_IN)
+                               continue; /* not input then not good */
+
+                       buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+                       if (!buffer_size) {
+                               ifacenum_inact = ifacenum;
+                               continue; /* 0 pkt size is not what we want */
+                       }
+
+                       if ((endpoint->bmAttributes &
+                               USB_ENDPOINT_XFERTYPE_MASK) ==
+                               USB_ENDPOINT_XFER_ISOC) {
+                               video_ep = endpoint->bEndpointAddress;
+                               /* break out of the search */
+                               goto good_videoep;
+                       }
+               }
+       }
+       /* failed out since nothing useful was found */
+       err("No suitable endpoint was found\n");
+       return -ENODEV;
+
+good_videoep:
+       /* disable isochronous stream before doing anything else */
+       err = qcm_stv_setb(dev, STV_ISO_ENABLE, 0);
+       if (err < 0) {
+               err("Failed to disable sensor stream");
+               return -EIO;
+       }
+
+       /*
+       Check that this is the same unknown sensor that is known to work. This
+       sensor is suspected to be the ST VV6422C001. I'll check the same value
+       that the qc-usb driver checks. This value is probably not even the
+       sensor ID since it matches the USB dev ID. Oh well. If it doesn't
+       match, it's probably a diff sensor so exit and apologize.
+       */
+       err = qcm_stv_getw(dev, CMOS_SENSOR_IDREV, &sensor_id);
+       if (err < 0) {
+               err("Couldn't read sensor values. Err %d\n",err);
+               return err;
+       }
+       if (sensor_id != cpu_to_le16(0x08F0)) {
+               err("Sensor ID %x != %x. Unsupported. Sorry\n",
+                       le16_to_cpu(sensor_id), (0x08F0));
+               return -ENODEV;
+       }
+
+       uvd = usbvideo_AllocateDevice(cams);
+       if (!uvd)
+               return -ENOMEM;
+
+       cam = (struct qcm *) uvd->user_data;
+
+       /* buf for doing demosaicing */
+       cam->scratch = kmalloc(324*2, GFP_KERNEL);
+       if (!cam->scratch) /* uvd freed in dereg */
+               return -ENOMEM;
+
+       /* yes, if we fail after here, cam->scratch gets freed
+       by qcm_free_uvd */
+
+       err = qcm_alloc_int_urb(cam);
+       if (err < 0)
+               return err;
+
+       /* yes, if we fail after here, int urb gets freed
+       by qcm_free_uvd */
+
+       RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
+       cam->width = camera_sizes[size].width;
+       cam->height = camera_sizes[size].height;
+       cam->size = size;
+
+       uvd->debug = debug;
+       uvd->flags = 0;
+       uvd->dev = dev;
+       uvd->iface = intf->altsetting->desc.bInterfaceNumber;
+       uvd->ifaceAltActive = ifacenum;
+       uvd->ifaceAltInactive = ifacenum_inact;
+       uvd->video_endp = video_ep;
+       uvd->iso_packet_len = buffer_size;
+       uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
+       uvd->defaultPalette = VIDEO_PALETTE_RGB24;
+       uvd->canvas = VIDEOSIZE(320, 240);
+       uvd->videosize = VIDEOSIZE(cam->width, cam->height);
+       err = qcm_configure_video(uvd);
+       if (err) {
+               err("failed to configure video settings");
+               return err;
+       }
+
+       err = usbvideo_RegisterVideoDevice(uvd);
+       if (err) { /* the uvd gets freed in Deregister */
+               err("usbvideo_RegisterVideoDevice() failed.");
+               return err;
+       }
+
+       uvd->max_frame_size = (320 * 240 * 3);
+       qcm_register_input(cam, dev);
+       usb_set_intfdata(intf, uvd);
+       return 0;
+}
+
+static void qcm_free_uvd(struct uvd *uvd)
+{
+       struct qcm *cam = (struct qcm *) uvd->user_data;
+
+       kfree(cam->scratch);
+       qcm_unregister_input(cam);
+       qcm_free_int(cam);
+}
+
+static struct usbvideo_cb qcm_driver = {
+       .probe =                qcm_probe,
+       .setupOnOpen =          qcm_setup_on_open,
+       .processData =          qcm_process_isoc,
+       .setVideoMode =         qcm_set_video_mode,
+       .startDataPump =        qcm_start_data,
+       .stopDataPump =         qcm_stop_data,
+       .adjustPicture =        qcm_adjust_picture,
+       .userFree =             qcm_free_uvd
+};
+
+static int __init qcm_init(void)
+{
+       info(DRIVER_DESC " " DRIVER_VERSION);
+
+       return usbvideo_register(
+               &cams,
+               MAX_CAMERAS,
+               sizeof(struct qcm),
+               "QCM",
+               &qcm_driver,
+               THIS_MODULE,
+               qcm_table);
+}
+
+static void __exit qcm_exit(void)
+{
+       usbvideo_Deregister(&cams);
+}
+
+module_param(size, int, 0);
+MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 320x240");
+module_param(colour, int, 0);
+MODULE_PARM_DESC(colour, "Initial colour");
+module_param(hue, int, 0);
+MODULE_PARM_DESC(hue, "Initial hue");
+module_param(brightness, int, 0);
+MODULE_PARM_DESC(brightness, "Initial brightness");
+module_param(contrast, int, 0);
+MODULE_PARM_DESC(contrast, "Initial contrast");
+module_param(whiteness, int, 0);
+MODULE_PARM_DESC(whiteness, "Initial whiteness");
+
+#ifdef CONFIG_USB_DEBUG
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
+#endif
+
+module_init(qcm_init);
+module_exit(qcm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jaya Kumar");
+MODULE_DESCRIPTION("QCM USB Camera");
+MODULE_SUPPORTED_DEVICE("QCM USB Camera");
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.h b/drivers/media/video/usbvideo/quickcam_messenger.h
new file mode 100644 (file)
index 0000000..baab9c0
--- /dev/null
@@ -0,0 +1,126 @@
+#ifndef quickcam_messenger_h
+#define quickcam_messenger_h
+
+#ifndef CONFIG_INPUT
+/* if we're not using input we dummy out these functions */
+#define qcm_register_input(...)
+#define qcm_unregister_input(...)
+#define qcm_report_buttonstat(...)
+#define qcm_setup_input_int(...) 0
+#define qcm_stop_int_data(...)
+#define qcm_alloc_int_urb(...) 0
+#define qcm_free_int(...)
+#endif
+
+
+#define CHECK_RET(ret, expr) \
+       if ((ret = expr) < 0) return ret
+
+/* Control Registers for the STVV6422 ASIC
+ * - this define is taken from the qc-usb-messenger code
+ */
+#define STV_ISO_ENABLE         0x1440
+#define ISOC_PACKET_SIZE       1023
+
+/* Chip identification number including revision indicator */
+#define CMOS_SENSOR_IDREV      0xE00A
+
+struct rgb {
+       u8 b;
+       u8 g;
+       u8 r;
+       u8 b2;
+       u8 g2;
+       u8 r2;
+};
+
+struct bayL0 {
+#ifdef __BIG_ENDIAN
+       u8 r;
+       u8 g;
+#elif __LITTLE_ENDIAN
+       u8 g;
+       u8 r;
+#else
+#error not byte order defined
+#endif
+};
+
+struct bayL1 {
+#ifdef __BIG_ENDIAN
+       u8 g;
+       u8 b;
+#elif __LITTLE_ENDIAN
+       u8 b;
+       u8 g;
+#else
+#error not byte order defined
+#endif
+};
+
+struct cam_size {
+       u16     width;
+       u16     height;
+       u8      cmd;
+};
+
+static const struct cam_size camera_sizes[] = {
+       { 160, 120, 0xf },
+       { 320, 240, 0x2 },
+};
+
+enum frame_sizes {
+       SIZE_160X120    = 0,
+       SIZE_320X240    = 1,
+};
+
+#define MAX_FRAME_SIZE SIZE_320X240
+
+struct qcm {
+       u16 colour;
+       u16 hue;
+       u16 brightness;
+       u16 contrast;
+       u16 whiteness;
+
+       u8 size;
+       int height;
+       int width;
+       u8 *scratch;
+       struct urb *button_urb;
+       u8 button_sts;
+       u8 button_sts_buf;
+
+#ifdef CONFIG_INPUT
+       struct input_dev *input;
+       char input_physname[64];
+#endif
+};
+
+struct regval {
+       u16 reg;
+       u8 val;
+};
+/* this table is derived from the
+qc-usb-messenger code */
+static const struct regval regval_table[] = {
+       { STV_ISO_ENABLE, 0x00 },
+       { 0x1436, 0x00 }, { 0x1432, 0x03 },
+       { 0x143a, 0xF9 }, { 0x0509, 0x38 },
+       { 0x050a, 0x38 }, { 0x050b, 0x38 },
+       { 0x050c, 0x2A }, { 0x050d, 0x01 },
+       { 0x1431, 0x00 }, { 0x1433, 0x34 },
+       { 0x1438, 0x18 }, { 0x1439, 0x00 },
+       { 0x143b, 0x05 }, { 0x143c, 0x00 },
+       { 0x143e, 0x01 }, { 0x143d, 0x00 },
+       { 0x1442, 0xe2 }, { 0x1500, 0xd0 },
+       { 0x1500, 0xd0 }, { 0x1500, 0x50 },
+       { 0x1501, 0xaf }, { 0x1502, 0xc2 },
+       { 0x1503, 0x45 }, { 0x1505, 0x02 },
+       { 0x150e, 0x8e }, { 0x150f, 0x37 },
+       { 0x15c0, 0x00 },
+};
+
+static const unsigned char marker[] = { 0x00, 0xff, 0x00, 0xFF };
+
+#endif /* quickcam_messenger_h */
index 3cbf4fc499a337c263fd34833f04f6fe0e9219dd..49dbee5f5628b49a38a299385e0da4d64b17eccd 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/config.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/usb.h>
 #include <linux/mutex.h>
 
index 474a29bc1760d9feedc2bf8beb6b7d8907666783..19d3c20dc7efd73a4f1cf3b58376dbf953584011 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
index d330fa985bcc2049e4fbba5d16dc6af496583789..14e523471354b160c4d8a078d3c90791d118ca5f 100644 (file)
@@ -59,6 +59,7 @@
 #include <asm/io.h>
 #include <asm/div64.h>
 #include <linux/video_decoder.h>
+#define __OLD_VIDIOC_ /* To allow fixing old calls*/
 #include <media/v4l2-common.h>
 
 #ifdef CONFIG_KMOD
@@ -293,7 +294,10 @@ static const char *v4l2_ioctls[] = {
 #if 1
        [_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP",
 #endif
-       [_IOC_NR(VIDIOC_LOG_STATUS)]       = "VIDIOC_LOG_STATUS"
+       [_IOC_NR(VIDIOC_LOG_STATUS)]       = "VIDIOC_LOG_STATUS",
+       [_IOC_NR(VIDIOC_G_EXT_CTRLS)]      = "VIDIOC_G_EXT_CTRLS",
+       [_IOC_NR(VIDIOC_S_EXT_CTRLS)]      = "VIDIOC_S_EXT_CTRLS",
+       [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)]    = "VIDIOC_TRY_EXT_CTRLS"
 };
 #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
 
@@ -331,7 +335,8 @@ static const char *v4l2_int_ioctls[] = {
        [_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)]  = "VIDIOC_INT_S_AUDIO_ROUTING",
        [_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)]  = "VIDIOC_INT_G_AUDIO_ROUTING",
        [_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)]  = "VIDIOC_INT_S_VIDEO_ROUTING",
-       [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)]  = "VIDIOC_INT_G_VIDEO_ROUTING"
+       [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)]  = "VIDIOC_INT_G_VIDEO_ROUTING",
+       [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)]   = "VIDIOC_INT_S_CRYSTAL_FREQ"
 };
 #define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
 
@@ -423,7 +428,9 @@ 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:
+#ifdef __OLD_VIDIOC_
        case VIDIOC_OVERLAY_OLD:
+#endif
        case VIDIOC_STREAMOFF:
        case VIDIOC_G_OUTPUT:
        case VIDIOC_S_OUTPUT:
@@ -439,7 +446,9 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
        case VIDIOC_G_AUDIO:
        case VIDIOC_S_AUDIO:
        case VIDIOC_ENUMAUDIO:
+#ifdef __OLD_VIDIOC_
        case VIDIOC_G_AUDIO_OLD:
+#endif
        {
                struct v4l2_audio *p=arg;
 
@@ -450,7 +459,9 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
        case VIDIOC_G_AUDOUT:
        case VIDIOC_S_AUDOUT:
        case VIDIOC_ENUMAUDOUT:
+#ifdef __OLD_VIDIOC_
        case VIDIOC_G_AUDOUT_OLD:
+#endif
        {
                struct v4l2_audioout *p=arg;
                printk ("%s: index=%d, name=%s, capability=%d, mode=%d\n", s,
@@ -478,9 +489,9 @@ 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%08x, frames=%d, userbits=0x%p\n",
+                       "flags=0x%08x, frames=%d, userbits=0x%08x\n",
                                s,tc->hours,tc->minutes,tc->seconds,
-                               tc->type, tc->flags, tc->frames, tc->userbits);
+                               tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
                break;
        }
        case VIDIOC_QUERYCAP:
@@ -495,12 +506,31 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
        }
        case VIDIOC_G_CTRL:
        case VIDIOC_S_CTRL:
+#ifdef __OLD_VIDIOC_
        case VIDIOC_S_CTRL_OLD:
+#endif
        {
                struct v4l2_control *p=arg;
                printk ("%s: id=%d, value=%d\n", s, p->id, p->value);
                break;
        }
+       case VIDIOC_G_EXT_CTRLS:
+       case VIDIOC_S_EXT_CTRLS:
+       case VIDIOC_TRY_EXT_CTRLS:
+       {
+               struct v4l2_ext_controls *p = arg;
+               int i;
+
+               printk("%s: ctrl_class=%d, count=%d\n", s, p->ctrl_class, p->count);
+               for (i = 0; i < p->count; i++) {
+                       struct v4l2_ext_control *c = &p->controls[i];
+                       if (cmd == VIDIOC_G_EXT_CTRLS)
+                               printk("%s: id=%d\n", s, c->id);
+                       else
+                               printk("%s: id=%d, value=%d\n", s, c->id, c->value);
+               }
+               break;
+       }
        case VIDIOC_G_CROP:
        case VIDIOC_S_CROP:
        {
@@ -510,7 +540,9 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
                break;
        }
        case VIDIOC_CROPCAP:
+#ifdef __OLD_VIDIOC_
        case VIDIOC_CROPCAP_OLD:
+#endif
        {
                struct v4l2_cropcap *p=arg;
                /*FIXME: Should also show rect structs */
@@ -667,6 +699,12 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
                printk ("%s: input=0x%x, output=0x%x\n", s, p->input, p->output);
                break;
        }
+       case VIDIOC_INT_S_CRYSTAL_FREQ:
+       {
+               struct v4l2_crystal_freq *p=arg;
+               printk ("%s: freq=%u, flags=0x%x\n", s, p->freq, p->flags);
+               break;
+       }
        case VIDIOC_G_SLICED_VBI_CAP:
        {
                struct v4l2_sliced_vbi_cap *p=arg;
@@ -696,7 +734,9 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
        }
        case VIDIOC_G_PARM:
        case VIDIOC_S_PARM:
+#ifdef __OLD_VIDIOC_
        case VIDIOC_S_PARM_OLD:
+#endif
        {
                struct v4l2_streamparm *p=arg;
                printk ("%s: type=%d\n", s, p->type);
@@ -915,6 +955,484 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
 
 /* ----------------------------------------------------------------- */
 
+/* Helper functions for control handling                            */
+
+/* Check for correctness of the ctrl's value based on the data from
+   struct v4l2_queryctrl and the available menu items. Note that
+   menu_items may be NULL, in that case it is ignored. */
+int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
+               const char **menu_items)
+{
+       if (qctrl->flags & V4L2_CTRL_FLAG_DISABLED)
+               return -EINVAL;
+       if (qctrl->flags & V4L2_CTRL_FLAG_GRABBED)
+               return -EBUSY;
+       if (qctrl->type == V4L2_CTRL_TYPE_BUTTON ||
+           qctrl->type == V4L2_CTRL_TYPE_INTEGER64 ||
+           qctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
+               return 0;
+       if (ctrl->value < qctrl->minimum || ctrl->value > qctrl->maximum)
+               return -ERANGE;
+       if (qctrl->type == V4L2_CTRL_TYPE_MENU && menu_items != NULL) {
+               if (menu_items[ctrl->value] == NULL ||
+                   menu_items[ctrl->value][0] == '\0')
+                       return -EINVAL;
+       }
+       return 0;
+}
+
+/* Returns NULL or a character pointer array containing the menu for
+   the given control ID. The pointer array ends with a NULL pointer.
+   An empty string signifies a menu entry that is invalid. This allows
+   drivers to disable certain options if it is not supported. */
+const char **v4l2_ctrl_get_menu(u32 id)
+{
+       static const char *mpeg_audio_sampling_freq[] = {
+               "44.1 kHz",
+               "48 kHz",
+               "32 kHz",
+               NULL
+       };
+       static const char *mpeg_audio_encoding[] = {
+               "Layer I",
+               "Layer II",
+               "Layer III",
+               NULL
+       };
+       static const char *mpeg_audio_l1_bitrate[] = {
+               "32 kbps",
+               "64 kbps",
+               "96 kbps",
+               "128 kbps",
+               "160 kbps",
+               "192 kbps",
+               "224 kbps",
+               "256 kbps",
+               "288 kbps",
+               "320 kbps",
+               "352 kbps",
+               "384 kbps",
+               "416 kbps",
+               "448 kbps",
+               NULL
+       };
+       static const char *mpeg_audio_l2_bitrate[] = {
+               "32 kbps",
+               "48 kbps",
+               "56 kbps",
+               "64 kbps",
+               "80 kbps",
+               "96 kbps",
+               "112 kbps",
+               "128 kbps",
+               "160 kbps",
+               "192 kbps",
+               "224 kbps",
+               "256 kbps",
+               "320 kbps",
+               "384 kbps",
+               NULL
+       };
+       static const char *mpeg_audio_l3_bitrate[] = {
+               "32 kbps",
+               "40 kbps",
+               "48 kbps",
+               "56 kbps",
+               "64 kbps",
+               "80 kbps",
+               "96 kbps",
+               "112 kbps",
+               "128 kbps",
+               "160 kbps",
+               "192 kbps",
+               "224 kbps",
+               "256 kbps",
+               "320 kbps",
+               NULL
+       };
+       static const char *mpeg_audio_mode[] = {
+               "Stereo",
+               "Joint Stereo",
+               "Dual",
+               "Mono",
+               NULL
+       };
+       static const char *mpeg_audio_mode_extension[] = {
+               "Bound 4",
+               "Bound 8",
+               "Bound 12",
+               "Bound 16",
+               NULL
+       };
+       static const char *mpeg_audio_emphasis[] = {
+               "No Emphasis",
+               "50/15 us",
+               "CCITT J17",
+               NULL
+       };
+       static const char *mpeg_audio_crc[] = {
+               "No CRC",
+               "16-bit CRC",
+               NULL
+       };
+       static const char *mpeg_video_encoding[] = {
+               "MPEG-1",
+               "MPEG-2",
+               NULL
+       };
+       static const char *mpeg_video_aspect[] = {
+               "1x1",
+               "4x3",
+               "16x9",
+               "2.21x1",
+               NULL
+       };
+       static const char *mpeg_video_bitrate_mode[] = {
+               "Variable Bitrate",
+               "Constant Bitrate",
+               NULL
+       };
+       static const char *mpeg_stream_type[] = {
+               "MPEG-2 Program Stream",
+               "MPEG-2 Transport Stream",
+               "MPEG-1 System Stream",
+               "MPEG-2 DVD-compatible Stream",
+               "MPEG-1 VCD-compatible Stream",
+               "MPEG-2 SVCD-compatible Stream",
+               NULL
+       };
+
+       switch (id) {
+               case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+                       return mpeg_audio_sampling_freq;
+               case V4L2_CID_MPEG_AUDIO_ENCODING:
+                       return mpeg_audio_encoding;
+               case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+                       return mpeg_audio_l1_bitrate;
+               case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+                       return mpeg_audio_l2_bitrate;
+               case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+                       return mpeg_audio_l3_bitrate;
+               case V4L2_CID_MPEG_AUDIO_MODE:
+                       return mpeg_audio_mode;
+               case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+                       return mpeg_audio_mode_extension;
+               case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+                       return mpeg_audio_emphasis;
+               case V4L2_CID_MPEG_AUDIO_CRC:
+                       return mpeg_audio_crc;
+               case V4L2_CID_MPEG_VIDEO_ENCODING:
+                       return mpeg_video_encoding;
+               case V4L2_CID_MPEG_VIDEO_ASPECT:
+                       return mpeg_video_aspect;
+               case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+                       return mpeg_video_bitrate_mode;
+               case V4L2_CID_MPEG_STREAM_TYPE:
+                       return mpeg_stream_type;
+               default:
+                       return NULL;
+       }
+}
+
+/* Fill in a struct v4l2_queryctrl */
+int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
+{
+       const char *name;
+
+       qctrl->flags = 0;
+       switch (qctrl->id) {
+       /* USER controls */
+       case V4L2_CID_USER_CLASS:       name = "User Controls"; break;
+       case V4L2_CID_AUDIO_VOLUME:     name = "Volume"; break;
+       case V4L2_CID_AUDIO_MUTE:       name = "Mute"; break;
+       case V4L2_CID_AUDIO_BALANCE:    name = "Balance"; break;
+       case V4L2_CID_AUDIO_BASS:       name = "Bass"; break;
+       case V4L2_CID_AUDIO_TREBLE:     name = "Treble"; break;
+       case V4L2_CID_AUDIO_LOUDNESS:   name = "Loudness"; break;
+       case V4L2_CID_BRIGHTNESS:       name = "Brightness"; break;
+       case V4L2_CID_CONTRAST:         name = "Contrast"; break;
+       case V4L2_CID_SATURATION:       name = "Saturation"; break;
+       case V4L2_CID_HUE:              name = "Hue"; break;
+
+       /* MPEG controls */
+       case V4L2_CID_MPEG_CLASS:               name = "MPEG Encoder Controls"; break;
+       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: name = "Audio Sampling Frequency"; break;
+       case V4L2_CID_MPEG_AUDIO_ENCODING:      name = "Audio Encoding Layer"; break;
+       case V4L2_CID_MPEG_AUDIO_L1_BITRATE:    name = "Audio Layer I Bitrate"; break;
+       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:    name = "Audio Layer II Bitrate"; break;
+       case V4L2_CID_MPEG_AUDIO_L3_BITRATE:    name = "Audio Layer III Bitrate"; break;
+       case V4L2_CID_MPEG_AUDIO_MODE:          name = "Audio Stereo Mode"; break;
+       case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: name = "Audio Stereo Mode Extension"; break;
+       case V4L2_CID_MPEG_AUDIO_EMPHASIS:      name = "Audio Emphasis"; break;
+       case V4L2_CID_MPEG_AUDIO_CRC:           name = "Audio CRC"; break;
+       case V4L2_CID_MPEG_VIDEO_ENCODING:      name = "Video Encoding"; break;
+       case V4L2_CID_MPEG_VIDEO_ASPECT:        name = "Video Aspect"; break;
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES:      name = "Video B Frames"; break;
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:      name = "Video GOP Size"; break;
+       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:   name = "Video GOP Closure"; break;
+       case V4L2_CID_MPEG_VIDEO_PULLDOWN:      name = "Video Pulldown"; break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:  name = "Video Bitrate Mode"; break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE:       name = "Video Bitrate"; break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:  name = "Video Peak Bitrate"; break;
+       case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: name = "Video Temporal Decimation"; break;
+       case V4L2_CID_MPEG_STREAM_TYPE:         name = "Stream Type"; break;
+       case V4L2_CID_MPEG_STREAM_PID_PMT:      name = "Stream PMT Program ID"; break;
+       case V4L2_CID_MPEG_STREAM_PID_AUDIO:    name = "Stream Audio Program ID"; break;
+       case V4L2_CID_MPEG_STREAM_PID_VIDEO:    name = "Stream Video Program ID"; break;
+       case V4L2_CID_MPEG_STREAM_PID_PCR:      name = "Stream PCR Program ID"; break;
+       case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: name = "Stream PES Audio ID"; break;
+       case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: name = "Stream PES Video ID"; break;
+
+       default:
+               return -EINVAL;
+       }
+       switch (qctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+       case V4L2_CID_AUDIO_LOUDNESS:
+       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+       case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+               qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
+               min = 0;
+               max = step = 1;
+               break;
+       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+       case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+       case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+       case V4L2_CID_MPEG_AUDIO_MODE:
+       case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+       case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+       case V4L2_CID_MPEG_AUDIO_CRC:
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               qctrl->type = V4L2_CTRL_TYPE_MENU;
+               step = 1;
+               break;
+       case V4L2_CID_USER_CLASS:
+       case V4L2_CID_MPEG_CLASS:
+               qctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
+               qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+               min = max = step = def = 0;
+               break;
+       default:
+               qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+               break;
+       }
+       switch (qctrl->id) {
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+       case V4L2_CID_MPEG_AUDIO_MODE:
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
+               break;
+       case V4L2_CID_AUDIO_VOLUME:
+       case V4L2_CID_AUDIO_BALANCE:
+       case V4L2_CID_AUDIO_BASS:
+       case V4L2_CID_AUDIO_TREBLE:
+       case V4L2_CID_BRIGHTNESS:
+       case V4L2_CID_CONTRAST:
+       case V4L2_CID_SATURATION:
+       case V4L2_CID_HUE:
+               qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+               break;
+       }
+       qctrl->minimum = min;
+       qctrl->maximum = max;
+       qctrl->step = step;
+       qctrl->default_value = def;
+       qctrl->reserved[0] = qctrl->reserved[1] = 0;
+       snprintf(qctrl->name, sizeof(qctrl->name), name);
+       return 0;
+}
+
+/* Fill in a struct v4l2_queryctrl with standard values based on
+   the control ID. */
+int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl)
+{
+       switch (qctrl->id) {
+       /* USER controls */
+       case V4L2_CID_USER_CLASS:
+       case V4L2_CID_MPEG_CLASS:
+               return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
+       case V4L2_CID_AUDIO_VOLUME:
+               return v4l2_ctrl_query_fill(qctrl, 0, 65535, 65535 / 100, 58880);
+       case V4L2_CID_AUDIO_MUTE:
+       case V4L2_CID_AUDIO_LOUDNESS:
+               return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+       case V4L2_CID_AUDIO_BALANCE:
+       case V4L2_CID_AUDIO_BASS:
+       case V4L2_CID_AUDIO_TREBLE:
+               return v4l2_ctrl_query_fill(qctrl, 0, 65535, 65535 / 100, 32768);
+       case V4L2_CID_BRIGHTNESS:
+               return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
+       case V4L2_CID_CONTRAST:
+       case V4L2_CID_SATURATION:
+               return v4l2_ctrl_query_fill(qctrl, 0, 127, 1, 64);
+       case V4L2_CID_HUE:
+               return v4l2_ctrl_query_fill(qctrl, -128, 127, 1, 0);
+
+       /* MPEG controls */
+       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100,
+                               V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 1,
+                               V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_ENCODING_LAYER_1,
+                               V4L2_MPEG_AUDIO_ENCODING_LAYER_3, 1,
+                               V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+       case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_L1_BITRATE_32K,
+                               V4L2_MPEG_AUDIO_L1_BITRATE_448K, 1,
+                               V4L2_MPEG_AUDIO_L1_BITRATE_256K);
+       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_L2_BITRATE_32K,
+                               V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
+                               V4L2_MPEG_AUDIO_L2_BITRATE_224K);
+       case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_L3_BITRATE_32K,
+                               V4L2_MPEG_AUDIO_L3_BITRATE_320K, 1,
+                               V4L2_MPEG_AUDIO_L3_BITRATE_192K);
+       case V4L2_CID_MPEG_AUDIO_MODE:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_MODE_STEREO,
+                               V4L2_MPEG_AUDIO_MODE_MONO, 1,
+                               V4L2_MPEG_AUDIO_MODE_STEREO);
+       case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
+                               V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 1,
+                               V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4);
+       case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_EMPHASIS_NONE,
+                               V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 1,
+                               V4L2_MPEG_AUDIO_EMPHASIS_NONE);
+       case V4L2_CID_MPEG_AUDIO_CRC:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_CRC_NONE,
+                               V4L2_MPEG_AUDIO_CRC_CRC16, 1,
+                               V4L2_MPEG_AUDIO_CRC_NONE);
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
+                               V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
+                               V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_VIDEO_ASPECT_1x1,
+                               V4L2_MPEG_VIDEO_ASPECT_221x100, 1,
+                               V4L2_MPEG_VIDEO_ASPECT_4x3);
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+               return v4l2_ctrl_query_fill(qctrl, 0, 33, 1, 2);
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               return v4l2_ctrl_query_fill(qctrl, 1, 34, 1, 12);
+       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+               return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
+       case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+               return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+                               V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
+                               V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+               return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
+       case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+               return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+                               V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, 1,
+                               V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
+       case V4L2_CID_MPEG_STREAM_PID_PMT:
+               return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 16);
+       case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+               return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 260);
+       case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+               return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 256);
+       case V4L2_CID_MPEG_STREAM_PID_PCR:
+               return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 259);
+       case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO:
+               return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+       case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO:
+               return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+       default:
+               return -EINVAL;
+       }
+}
+
+/* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and
+   the menu. The qctrl pointer may be NULL, in which case it is ignored. */
+int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qctrl,
+              const char **menu_items)
+{
+       int i;
+
+       if (menu_items == NULL ||
+           (qctrl && (qmenu->index < qctrl->minimum || qmenu->index > qctrl->maximum)))
+               return -EINVAL;
+       for (i = 0; i < qmenu->index && menu_items[i]; i++) ;
+       if (menu_items[i] == NULL || menu_items[i][0] == '\0')
+               return -EINVAL;
+       snprintf(qmenu->name, sizeof(qmenu->name), menu_items[qmenu->index]);
+       qmenu->reserved = 0;
+       return 0;
+}
+
+/* ctrl_classes points to an array of u32 pointers, the last element is
+   a NULL pointer. Each u32 array is a 0-terminated array of control IDs.
+   Each array must be sorted low to high and belong to the same control
+   class. The array of u32 pointer must also be sorted, from low class IDs
+   to high class IDs.
+
+   This function returns the first ID that follows after the given ID.
+   When no more controls are available 0 is returned. */
+u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
+{
+       u32 ctrl_class;
+       const u32 *pctrl;
+
+       /* if no query is desired, then just return the control ID */
+       if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0)
+               return id;
+       if (ctrl_classes == NULL)
+               return 0;
+       id &= V4L2_CTRL_ID_MASK;
+       ctrl_class = V4L2_CTRL_ID2CLASS(id);
+       id++;   /* select next control */
+       /* find first class that matches (or is greater than) the class of
+          the ID */
+       while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) < ctrl_class)
+               ctrl_classes++;
+       /* no more classes */
+       if (*ctrl_classes == NULL)
+               return 0;
+       pctrl = *ctrl_classes;
+       /* find first ctrl within the class that is >= ID */
+       while (*pctrl && *pctrl < id) pctrl++;
+       if (*pctrl)
+               return *pctrl;
+       /* we are at the end of the controls of the current class. */
+       /* continue with next class if available */
+       ctrl_classes++;
+       if (*ctrl_classes == NULL)
+               return 0;
+       return **ctrl_classes;
+}
+
+/* ----------------------------------------------------------------- */
+
 EXPORT_SYMBOL(v4l2_video_std_construct);
 
 EXPORT_SYMBOL(v4l2_prio_init);
@@ -929,6 +1447,13 @@ EXPORT_SYMBOL(v4l2_type_names);
 EXPORT_SYMBOL(v4l_printk_ioctl);
 EXPORT_SYMBOL(v4l_printk_ioctl_arg);
 
+EXPORT_SYMBOL(v4l2_ctrl_next);
+EXPORT_SYMBOL(v4l2_ctrl_check);
+EXPORT_SYMBOL(v4l2_ctrl_get_menu);
+EXPORT_SYMBOL(v4l2_ctrl_query_menu);
+EXPORT_SYMBOL(v4l2_ctrl_query_fill);
+EXPORT_SYMBOL(v4l2_ctrl_query_fill_std);
+
 /*
  * Local variables:
  * c-basic-offset: 8
index caf3e7e2f21989cac195c23e88d07beb53194a64..7ee8a53cd336f1702a35b2532071b1955d9af3f2 100644 (file)
@@ -135,14 +135,15 @@ static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed)
 
 int videobuf_dvb_register(struct videobuf_dvb *dvb,
                          struct module *module,
-                         void *adapter_priv)
+                         void *adapter_priv,
+                         struct device *device)
 {
        int result;
 
        mutex_init(&dvb->lock);
 
        /* register adapter */
-       result = dvb_register_adapter(&dvb->adapter, dvb->name, module);
+       result = dvb_register_adapter(&dvb->adapter, dvb->name, module, device);
        if (result < 0) {
                printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
                       dvb->name, result);
index 5f87dd5f1d0b7fe28af648e26d10f142aa2cfab9..2dfa7f23d0ca28f7e08a2fa7167184789c32cc29 100644 (file)
@@ -1,20 +1,31 @@
 /*
- * Video capture interface for Linux
+ * Video capture interface for Linux version 2
  *
- *             A generic video device interface for the LINUX operating system
- *             using a set of device structures/vectors for low level operations.
+ *     A generic video device interface for the LINUX operating system
+ *     using a set of device structures/vectors for low level operations.
  *
- *             This program is free software; you can redistribute it and/or
- *             modify it under the terms of the GNU General Public License
- *             as published by the Free Software Foundation; either version
- *             2 of the License, or (at your option) any later version.
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
  *
- * Author:     Alan Cox, <alan@redhat.com>
+ * Authors:    Alan Cox, <alan@redhat.com> (version 1)
+ *              Mauro Carvalho Chehab <mchehab@infradead.org> (version 2)
  *
  * Fixes:      20000516  Claudio Matsuoka <claudio@conectiva.com>
  *             - Added procfs support
  */
 
+#define dbgarg(cmd, fmt, arg...) \
+               if (vfd->debug & V4L2_DEBUG_IOCTL_ARG)                  \
+                       printk (KERN_DEBUG "%s: ",  vfd->name);         \
+                       v4l_printk_ioctl(cmd);                          \
+                       printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
+
+#define dbgarg2(fmt, arg...) \
+               if (vfd->debug & V4L2_DEBUG_IOCTL_ARG)                  \
+                       printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
+#define __OLD_VIDIOC_ /* To allow fixing old calls*/
+#include <linux/videodev2.h>
+
+#ifdef CONFIG_VIDEO_V4L1
 #include <linux/videodev.h>
+#endif
+#include <media/v4l2-common.h>
 
 #define VIDEO_NUM_DEVICES      256
 #define VIDEO_NAME              "video4linux"
@@ -41,7 +58,8 @@
 
 static ssize_t show_name(struct class_device *cd, char *buf)
 {
-       struct video_device *vfd = container_of(cd, struct video_device, class_dev);
+       struct video_device *vfd = container_of(cd, struct video_device,
+                                                               class_dev);
        return sprintf(buf,"%.*s\n",(int)sizeof(vfd->name),vfd->name);
 }
 
@@ -62,7 +80,8 @@ void video_device_release(struct video_device *vfd)
 
 static void video_release(struct class_device *cd)
 {
-       struct video_device *vfd = container_of(cd, struct video_device, class_dev);
+       struct video_device *vfd = container_of(cd, struct video_device,
+                                                               class_dev);
 
 #if 1
        /* needed until all drivers are fixed */
@@ -90,7 +109,7 @@ struct video_device* video_devdata(struct file *file)
 }
 
 /*
- *     Open a video device.
+ *     Open a video device - FIXME: Obsoleted
  */
 static int video_open(struct inode *inode, struct file *file)
 {
@@ -130,6 +149,7 @@ static int video_open(struct inode *inode, struct file *file)
  * helper function -- handles userspace copying for ioctl arguments
  */
 
+#ifdef __OLD_VIDIOC_
 static unsigned int
 video_fix_command(unsigned int cmd)
 {
@@ -155,7 +175,11 @@ video_fix_command(unsigned int cmd)
        }
        return cmd;
 }
+#endif
 
+/*
+ * Obsolete usercopy function - Should be removed soon
+ */
 int
 video_usercopy(struct inode *inode, struct file *file,
               unsigned int cmd, unsigned long arg,
@@ -166,8 +190,15 @@ video_usercopy(struct inode *inode, struct file *file,
        void    *mbuf = NULL;
        void    *parg = NULL;
        int     err  = -EINVAL;
+       int     is_ext_ctrl;
+       size_t  ctrls_size = 0;
+       void __user *user_ptr = NULL;
 
+#ifdef __OLD_VIDIOC_
        cmd = video_fix_command(cmd);
+#endif
+       is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
+                      cmd == VIDIOC_TRY_EXT_CTRLS);
 
        /*  Copy arguments into temp kernel buffer  */
        switch (_IOC_DIR(cmd)) {
@@ -193,14 +224,43 @@ video_usercopy(struct inode *inode, struct file *file,
                                goto out;
                break;
        }
+       if (is_ext_ctrl) {
+               struct v4l2_ext_controls *p = parg;
+
+               /* In case of an error, tell the caller that it wasn't
+                  a specific control that caused it. */
+               p->error_idx = p->count;
+               user_ptr = (void __user *)p->controls;
+               if (p->count) {
+                       ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
+                       /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
+                       mbuf = kmalloc(ctrls_size, GFP_KERNEL);
+                       err = -ENOMEM;
+                       if (NULL == mbuf)
+                               goto out_ext_ctrl;
+                       err = -EFAULT;
+                       if (copy_from_user(mbuf, user_ptr, ctrls_size))
+                               goto out_ext_ctrl;
+                       p->controls = mbuf;
+               }
+       }
 
        /* call driver */
        err = func(inode, file, cmd, parg);
        if (err == -ENOIOCTLCMD)
                err = -EINVAL;
+       if (is_ext_ctrl) {
+               struct v4l2_ext_controls *p = parg;
+
+               p->controls = (void *)user_ptr;
+               if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
+                       err = -EFAULT;
+               goto out_ext_ctrl;
+       }
        if (err < 0)
                goto out;
 
+out_ext_ctrl:
        /*  Copy results into user buffer  */
        switch (_IOC_DIR(cmd))
        {
@@ -218,6 +278,7 @@ out:
 
 /*
  * open/release helper functions -- handle exclusive opens
+ * Should be removed soon
  */
 int video_exclusive_open(struct inode *inode, struct file *file)
 {
@@ -242,6 +303,1184 @@ int video_exclusive_release(struct inode *inode, struct file *file)
        return 0;
 }
 
+static char *v4l2_memory_names[] = {
+       [V4L2_MEMORY_MMAP]    = "mmap",
+       [V4L2_MEMORY_USERPTR] = "userptr",
+       [V4L2_MEMORY_OVERLAY] = "overlay",
+};
+
+
+/* FIXME: Those stuff are replicated also on v4l2-common.c */
+static char *v4l2_type_names_FIXME[] = {
+       [V4L2_BUF_TYPE_VIDEO_CAPTURE]      = "video-cap",
+       [V4L2_BUF_TYPE_VIDEO_OVERLAY]      = "video-over",
+       [V4L2_BUF_TYPE_VIDEO_OUTPUT]       = "video-out",
+       [V4L2_BUF_TYPE_VBI_CAPTURE]        = "vbi-cap",
+       [V4L2_BUF_TYPE_VBI_OUTPUT]         = "vbi-out",
+       [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT]  = "sliced-vbi-out",
+       [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-capture",
+       [V4L2_BUF_TYPE_PRIVATE]            = "private",
+};
+
+static char *v4l2_field_names_FIXME[] = {
+       [V4L2_FIELD_ANY]        = "any",
+       [V4L2_FIELD_NONE]       = "none",
+       [V4L2_FIELD_TOP]        = "top",
+       [V4L2_FIELD_BOTTOM]     = "bottom",
+       [V4L2_FIELD_INTERLACED] = "interlaced",
+       [V4L2_FIELD_SEQ_TB]     = "seq-tb",
+       [V4L2_FIELD_SEQ_BT]     = "seq-bt",
+       [V4L2_FIELD_ALTERNATE]  = "alternate",
+};
+
+#define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown"
+
+static void dbgbuf(unsigned int cmd, struct video_device *vfd,
+                                       struct v4l2_buffer *p)
+{
+       struct v4l2_timecode *tc=&p->timecode;
+
+       dbgarg (cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, "
+               "bytesused=%d, flags=0x%08d, "
+               "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx\n",
+                       (p->timestamp.tv_sec/3600),
+                       (int)(p->timestamp.tv_sec/60)%60,
+                       (int)(p->timestamp.tv_sec%60),
+                       p->timestamp.tv_usec,
+                       p->index,
+                       prt_names(p->type,v4l2_type_names_FIXME),
+                       p->bytesused,p->flags,
+                       p->field,p->sequence,
+                       prt_names(p->memory,v4l2_memory_names),
+                       p->m.userptr);
+       dbgarg2 ("timecode= %02d:%02d:%02d type=%d, "
+               "flags=0x%08d, frames=%d, userbits=0x%08x\n",
+                       tc->hours,tc->minutes,tc->seconds,
+                       tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
+}
+
+static inline void dbgrect(struct video_device *vfd, char *s,
+                                                       struct v4l2_rect *r)
+{
+       dbgarg2 ("%sRect start at %dx%d, size= %dx%d\n", s, r->left, r->top,
+                                               r->width, r->height);
+};
+
+static inline void v4l_print_pix_fmt (struct video_device *vfd,
+                                               struct v4l2_pix_format *fmt)
+{
+       dbgarg2 ("width=%d, height=%d, format=0x%08x, field=%s, "
+               "bytesperline=%d sizeimage=%d, colorspace=%d\n",
+               fmt->width,fmt->height,fmt->pixelformat,
+               prt_names(fmt->field,v4l2_field_names_FIXME),
+               fmt->bytesperline,fmt->sizeimage,fmt->colorspace);
+};
+
+
+static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type)
+{
+       switch (type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               if (vfd->vidioc_try_fmt_cap)
+                       return (0);
+               break;
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               if (vfd->vidioc_try_fmt_overlay)
+                       return (0);
+               break;
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               if (vfd->vidioc_try_fmt_vbi)
+                       return (0);
+               break;
+       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+               if (vfd->vidioc_try_fmt_vbi_output)
+                       return (0);
+               break;
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+               if (vfd->vidioc_try_fmt_vbi_capture)
+                       return (0);
+               break;
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+               if (vfd->vidioc_try_fmt_video_output)
+                       return (0);
+               break;
+       case V4L2_BUF_TYPE_VBI_OUTPUT:
+               if (vfd->vidioc_try_fmt_vbi_output)
+                       return (0);
+               break;
+       case V4L2_BUF_TYPE_PRIVATE:
+               if (vfd->vidioc_try_fmt_type_private)
+                       return (0);
+               break;
+       }
+       return (-EINVAL);
+}
+
+static int __video_do_ioctl(struct inode *inode, struct file *file,
+               unsigned int cmd, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       void                 *fh = file->private_data;
+       int                  ret = -EINVAL;
+
+       if ( (vfd->debug & V4L2_DEBUG_IOCTL) &&
+                               !(vfd->debug | V4L2_DEBUG_IOCTL_ARG)) {
+               v4l_print_ioctl(vfd->name, cmd);
+       }
+
+       switch(cmd) {
+       /* --- capabilities ------------------------------------------ */
+       case VIDIOC_QUERYCAP:
+       {
+               struct v4l2_capability *cap = (struct v4l2_capability*)arg;
+               memset(cap, 0, sizeof(*cap));
+
+               if (!vfd->vidioc_querycap)
+                       break;
+
+               ret=vfd->vidioc_querycap(file, fh, cap);
+               if (!ret)
+                       dbgarg (cmd, "driver=%s, card=%s, bus=%s, "
+                                       "version=0x%08x, "
+                                       "capabilities=0x%08x\n",
+                                       cap->driver,cap->card,cap->bus_info,
+                                       cap->version,
+                                       cap->capabilities);
+               break;
+       }
+
+       /* --- priority ------------------------------------------ */
+       case VIDIOC_G_PRIORITY:
+       {
+               enum v4l2_priority *p=arg;
+
+               if (!vfd->vidioc_g_priority)
+                       break;
+               ret=vfd->vidioc_g_priority(file, fh, p);
+               if (!ret)
+                       dbgarg(cmd, "priority is %d\n", *p);
+               break;
+       }
+       case VIDIOC_S_PRIORITY:
+       {
+               enum v4l2_priority *p=arg;
+
+               if (!vfd->vidioc_s_priority)
+                       break;
+               dbgarg(cmd, "setting priority to %d\n", *p);
+               ret=vfd->vidioc_s_priority(file, fh, *p);
+               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;
+               memset(f,0,sizeof(*f));
+               f->index = index;
+               f->type  = type;
+
+               switch (type) {
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+                       if (vfd->vidioc_enum_fmt_cap)
+                               ret=vfd->vidioc_enum_fmt_cap(file, fh, f);
+                       break;
+               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+                       if (vfd->vidioc_enum_fmt_overlay)
+                               ret=vfd->vidioc_enum_fmt_overlay(file, fh, f);
+                       break;
+               case V4L2_BUF_TYPE_VBI_CAPTURE:
+                       if (vfd->vidioc_enum_fmt_vbi)
+                               ret=vfd->vidioc_enum_fmt_vbi(file, fh, f);
+                       break;
+               case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+                       if (vfd->vidioc_enum_fmt_vbi_output)
+                               ret=vfd->vidioc_enum_fmt_vbi_output(file,
+                                                               fh, f);
+                       break;
+               case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+                       if (vfd->vidioc_enum_fmt_vbi_capture)
+                               ret=vfd->vidioc_enum_fmt_vbi_capture(file,
+                                                               fh, f);
+                       break;
+               case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+                       if (vfd->vidioc_enum_fmt_video_output)
+                               ret=vfd->vidioc_enum_fmt_video_output(file,
+                                                               fh, f);
+                       break;
+               case V4L2_BUF_TYPE_VBI_OUTPUT:
+                       if (vfd->vidioc_enum_fmt_vbi_output)
+                               ret=vfd->vidioc_enum_fmt_vbi_output(file,
+                                                               fh, f);
+                       break;
+               case V4L2_BUF_TYPE_PRIVATE:
+                       if (vfd->vidioc_enum_fmt_type_private)
+                               ret=vfd->vidioc_enum_fmt_type_private(file,
+                                                               fh, f);
+                       break;
+               }
+               if (!ret)
+                       dbgarg (cmd, "index=%d, type=%d, flags=%d, "
+                                       "description=%s,"
+                                       " pixelformat=0x%8x\n",
+                                       f->index, f->type, f->flags,
+                                       f->description,
+                                       f->pixelformat);
+
+               break;
+       }
+       case VIDIOC_G_FMT:
+       {
+               struct v4l2_format *f = (struct v4l2_format *)arg;
+               enum v4l2_buf_type type=f->type;
+
+               memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
+               f->type=type;
+
+               /* FIXME: Should be one dump per type */
+               dbgarg (cmd, "type=%s\n", prt_names(type,
+                                       v4l2_type_names_FIXME));
+
+               switch (type) {
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+                       if (vfd->vidioc_g_fmt_cap)
+                               ret=vfd->vidioc_g_fmt_cap(file, fh, f);
+                       if (!ret)
+                               v4l_print_pix_fmt(vfd,&f->fmt.pix);
+                       break;
+               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+                       if (vfd->vidioc_g_fmt_overlay)
+                               ret=vfd->vidioc_g_fmt_overlay(file, fh, f);
+                       break;
+               case V4L2_BUF_TYPE_VBI_CAPTURE:
+                       if (vfd->vidioc_g_fmt_vbi)
+                               ret=vfd->vidioc_g_fmt_vbi(file, fh, f);
+                       break;
+               case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+                       if (vfd->vidioc_g_fmt_vbi_output)
+                               ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
+                       break;
+               case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+                       if (vfd->vidioc_g_fmt_vbi_capture)
+                               ret=vfd->vidioc_g_fmt_vbi_capture(file, fh, f);
+                       break;
+               case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+                       if (vfd->vidioc_g_fmt_video_output)
+                               ret=vfd->vidioc_g_fmt_video_output(file,
+                                                               fh, f);
+                       break;
+               case V4L2_BUF_TYPE_VBI_OUTPUT:
+                       if (vfd->vidioc_g_fmt_vbi_output)
+                               ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
+                       break;
+               case V4L2_BUF_TYPE_PRIVATE:
+                       if (vfd->vidioc_g_fmt_type_private)
+                               ret=vfd->vidioc_g_fmt_type_private(file,
+                                                               fh, f);
+                       break;
+               }
+
+               break;
+       }
+       case VIDIOC_S_FMT:
+       {
+               struct v4l2_format *f = (struct v4l2_format *)arg;
+
+               /* FIXME: Should be one dump per type */
+               dbgarg (cmd, "type=%s\n", prt_names(f->type,
+                                       v4l2_type_names_FIXME));
+
+               switch (f->type) {
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+                       v4l_print_pix_fmt(vfd,&f->fmt.pix);
+                       if (vfd->vidioc_s_fmt_cap)
+                               ret=vfd->vidioc_s_fmt_cap(file, fh, f);
+                       break;
+               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+                       if (vfd->vidioc_s_fmt_overlay)
+                               ret=vfd->vidioc_s_fmt_overlay(file, fh, f);
+                       break;
+               case V4L2_BUF_TYPE_VBI_CAPTURE:
+                       if (vfd->vidioc_s_fmt_vbi)
+                               ret=vfd->vidioc_s_fmt_vbi(file, fh, f);
+                       break;
+               case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+                       if (vfd->vidioc_s_fmt_vbi_output)
+                               ret=vfd->vidioc_s_fmt_vbi_output(file, fh, f);
+                       break;
+               case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+                       if (vfd->vidioc_s_fmt_vbi_capture)
+                               ret=vfd->vidioc_s_fmt_vbi_capture(file, fh, f);
+                       break;
+               case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+                       if (vfd->vidioc_s_fmt_video_output)
+                               ret=vfd->vidioc_s_fmt_video_output(file,
+                                                               fh, f);
+                       break;
+               case V4L2_BUF_TYPE_VBI_OUTPUT:
+                       if (vfd->vidioc_s_fmt_vbi_output)
+                               ret=vfd->vidioc_s_fmt_vbi_output(file,
+                                                               fh, f);
+                       break;
+               case V4L2_BUF_TYPE_PRIVATE:
+                       if (vfd->vidioc_s_fmt_type_private)
+                               ret=vfd->vidioc_s_fmt_type_private(file,
+                                                               fh, f);
+                       break;
+               }
+               break;
+       }
+       case VIDIOC_TRY_FMT:
+       {
+               struct v4l2_format *f = (struct v4l2_format *)arg;
+
+               /* FIXME: Should be one dump per type */
+               dbgarg (cmd, "type=%s\n", prt_names(f->type,
+                                               v4l2_type_names_FIXME));
+               switch (f->type) {
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+                       if (vfd->vidioc_try_fmt_cap)
+                               ret=vfd->vidioc_try_fmt_cap(file, fh, f);
+                       if (!ret)
+                               v4l_print_pix_fmt(vfd,&f->fmt.pix);
+                       break;
+               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+                       if (vfd->vidioc_try_fmt_overlay)
+                               ret=vfd->vidioc_try_fmt_overlay(file, fh, f);
+                       break;
+               case V4L2_BUF_TYPE_VBI_CAPTURE:
+                       if (vfd->vidioc_try_fmt_vbi)
+                               ret=vfd->vidioc_try_fmt_vbi(file, fh, f);
+                       break;
+               case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+                       if (vfd->vidioc_try_fmt_vbi_output)
+                               ret=vfd->vidioc_try_fmt_vbi_output(file,
+                                                               fh, f);
+                       break;
+               case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+                       if (vfd->vidioc_try_fmt_vbi_capture)
+                               ret=vfd->vidioc_try_fmt_vbi_capture(file,
+                                                               fh, f);
+                       break;
+               case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+                       if (vfd->vidioc_try_fmt_video_output)
+                               ret=vfd->vidioc_try_fmt_video_output(file,
+                                                               fh, f);
+                       break;
+               case V4L2_BUF_TYPE_VBI_OUTPUT:
+                       if (vfd->vidioc_try_fmt_vbi_output)
+                               ret=vfd->vidioc_try_fmt_vbi_output(file,
+                                                               fh, f);
+                       break;
+               case V4L2_BUF_TYPE_PRIVATE:
+                       if (vfd->vidioc_try_fmt_type_private)
+                               ret=vfd->vidioc_try_fmt_type_private(file,
+                                                               fh, f);
+                       break;
+               }
+
+               break;
+       }
+       /* FIXME: Those buf reqs could be handled here,
+          with some changes on videobuf to allow its header to be included at
+          videodev2.h or being merged at videodev2.
+        */
+       case VIDIOC_REQBUFS:
+       {
+               struct v4l2_requestbuffers *p=arg;
+
+               if (!vfd->vidioc_reqbufs)
+                       break;
+               ret = check_fmt (vfd, p->type);
+               if (ret)
+                       break;
+
+               ret=vfd->vidioc_reqbufs(file, fh, p);
+               dbgarg (cmd, "count=%d, type=%s, memory=%s\n",
+                               p->count,
+                               prt_names(p->type,v4l2_type_names_FIXME),
+                               prt_names(p->memory,v4l2_memory_names));
+               break;
+       }
+       case VIDIOC_QUERYBUF:
+       {
+               struct v4l2_buffer *p=arg;
+
+               if (!vfd->vidioc_querybuf)
+                       break;
+               ret = check_fmt (vfd, p->type);
+               if (ret)
+                       break;
+
+               ret=vfd->vidioc_querybuf(file, fh, p);
+               if (!ret)
+                       dbgbuf(cmd,vfd,p);
+               break;
+       }
+       case VIDIOC_QBUF:
+       {
+               struct v4l2_buffer *p=arg;
+
+               if (!vfd->vidioc_qbuf)
+                       break;
+               ret = check_fmt (vfd, p->type);
+               if (ret)
+                       break;
+
+               ret=vfd->vidioc_qbuf(file, fh, p);
+               if (!ret)
+                       dbgbuf(cmd,vfd,p);
+               break;
+       }
+       case VIDIOC_DQBUF:
+       {
+               struct v4l2_buffer *p=arg;
+               if (!vfd->vidioc_qbuf)
+                       break;
+               ret = check_fmt (vfd, p->type);
+               if (ret)
+                       break;
+
+               ret=vfd->vidioc_qbuf(file, fh, p);
+               if (!ret)
+                       dbgbuf(cmd,vfd,p);
+               break;
+       }
+       case VIDIOC_OVERLAY:
+       {
+               int *i = arg;
+
+               if (!vfd->vidioc_overlay)
+                       break;
+               dbgarg (cmd, "value=%d\n",*i);
+               ret=vfd->vidioc_overlay(file, fh, *i);
+               break;
+       }
+#ifdef HAVE_V4L1
+       /* --- streaming capture ------------------------------------- */
+       case VIDIOCGMBUF:
+       {
+               struct video_mbuf *p=arg;
+
+               memset(p,0,sizeof(p));
+
+               if (!vfd->vidiocgmbuf)
+                       break;
+               ret=vfd->vidiocgmbuf(file, fh, p);
+               if (!ret)
+                       dbgarg (cmd, "size=%d, frames=%d, offsets=0x%08lx\n",
+                                               p->size, p->frames,
+                                               (unsigned long)p->offsets);
+               break;
+       }
+#endif
+       case VIDIOC_G_FBUF:
+       {
+               struct v4l2_framebuffer *p=arg;
+               if (!vfd->vidioc_g_fbuf)
+                       break;
+               ret=vfd->vidioc_g_fbuf(file, fh, arg);
+               if (!ret) {
+                       dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
+                                       p->capability,p->flags,
+                                       (unsigned long)p->base);
+                       v4l_print_pix_fmt (vfd, &p->fmt);
+               }
+               break;
+       }
+       case VIDIOC_S_FBUF:
+       {
+               struct v4l2_framebuffer *p=arg;
+               if (!vfd->vidioc_s_fbuf)
+                       break;
+
+               dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
+                               p->capability,p->flags,(unsigned long)p->base);
+               v4l_print_pix_fmt (vfd, &p->fmt);
+               ret=vfd->vidioc_s_fbuf(file, fh, arg);
+
+               break;
+       }
+       case VIDIOC_STREAMON:
+       {
+               enum v4l2_buf_type i = *(int *)arg;
+               if (!vfd->vidioc_streamon)
+                       break;
+               dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME));
+               ret=vfd->vidioc_streamon(file, fh,i);
+               break;
+       }
+       case VIDIOC_STREAMOFF:
+       {
+               enum v4l2_buf_type i = *(int *)arg;
+
+               if (!vfd->vidioc_streamoff)
+                       break;
+               dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME));
+               ret=vfd->vidioc_streamoff(file, fh, i);
+               break;
+       }
+       /* ---------- tv norms ---------- */
+       case VIDIOC_ENUMSTD:
+       {
+               struct v4l2_standard *p = arg;
+               unsigned int index = p->index;
+
+               if (!vfd->tvnormsize) {
+                       printk (KERN_WARNING "%s: no TV norms defined!\n",
+                                               vfd->name);
+                       break;
+               }
+
+               if (index<=0 || index >= vfd->tvnormsize) {
+                       ret=-EINVAL;
+                       break;
+               }
+               v4l2_video_std_construct(p, vfd->tvnorms[p->index].id,
+                                        vfd->tvnorms[p->index].name);
+               p->index = index;
+
+               dbgarg (cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, "
+                               "framelines=%d\n", p->index,
+                               (unsigned long long)p->id, p->name,
+                               p->frameperiod.numerator,
+                               p->frameperiod.denominator,
+                               p->framelines);
+
+               ret=0;
+               break;
+       }
+       case VIDIOC_G_STD:
+       {
+               v4l2_std_id *id = arg;
+
+               *id = vfd->current_norm;
+
+               dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
+
+               ret=0;
+               break;
+       }
+       case VIDIOC_S_STD:
+       {
+               v4l2_std_id *id = arg;
+               unsigned int i;
+
+               if (!vfd->tvnormsize) {
+                       printk (KERN_WARNING "%s: no TV norms defined!\n",
+                                               vfd->name);
+                       break;
+               }
+
+               dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
+
+               /* First search for exact match */
+               for (i = 0; i < vfd->tvnormsize; i++)
+                       if (*id == vfd->tvnorms[i].id)
+                               break;
+               /* Then for a generic video std that contains desired std */
+               if (i == vfd->tvnormsize)
+                       for (i = 0; i < vfd->tvnormsize; i++)
+                               if (*id & vfd->tvnorms[i].id)
+                                       break;
+               if (i == vfd->tvnormsize) {
+                       break;
+               }
+
+               /* Calls the specific handler */
+               if (vfd->vidioc_s_std)
+                       ret=vfd->vidioc_s_std(file, fh, i);
+               else
+                       ret=-EINVAL;
+
+               /* Updates standard information */
+               if (!ret)
+                       vfd->current_norm=*id;
+
+               break;
+       }
+       case VIDIOC_QUERYSTD:
+       {
+               v4l2_std_id *p=arg;
+
+               if (!vfd->vidioc_querystd)
+                       break;
+               ret=vfd->vidioc_querystd(file, fh, arg);
+               if (!ret)
+                       dbgarg (cmd, "detected std=%Lu\n",
+                                               (unsigned long long)*p);
+               break;
+       }
+       /* ------ input switching ---------- */
+       /* FIXME: Inputs can be handled inside videodev2 */
+       case VIDIOC_ENUMINPUT:
+       {
+               struct v4l2_input *p=arg;
+               int i=p->index;
+
+               if (!vfd->vidioc_enum_input)
+                       break;
+               memset(p, 0, sizeof(*p));
+               p->index=i;
+
+               ret=vfd->vidioc_enum_input(file, fh, p);
+               if (!ret)
+                       dbgarg (cmd, "index=%d, name=%s, type=%d, "
+                                       "audioset=%d, "
+                                       "tuner=%d, std=%Ld, status=%d\n",
+                                       p->index,p->name,p->type,p->audioset,
+                                       p->tuner,
+                                       (unsigned long long)p->std,
+                                       p->status);
+               break;
+       }
+       case VIDIOC_G_INPUT:
+       {
+               unsigned int *i = arg;
+
+               if (!vfd->vidioc_g_input)
+                       break;
+               ret=vfd->vidioc_g_input(file, fh, i);
+               if (!ret)
+                       dbgarg (cmd, "value=%d\n",*i);
+               break;
+       }
+       case VIDIOC_S_INPUT:
+       {
+               unsigned int *i = arg;
+
+               if (!vfd->vidioc_s_input)
+                       break;
+               dbgarg (cmd, "value=%d\n",*i);
+               ret=vfd->vidioc_s_input(file, fh, *i);
+               break;
+       }
+
+       /* ------ output switching ---------- */
+       case VIDIOC_G_OUTPUT:
+       {
+               unsigned int *i = arg;
+
+               if (!vfd->vidioc_g_output)
+                       break;
+               ret=vfd->vidioc_g_output(file, fh, i);
+               if (!ret)
+                       dbgarg (cmd, "value=%d\n",*i);
+               break;
+       }
+       case VIDIOC_S_OUTPUT:
+       {
+               unsigned int *i = arg;
+
+               if (!vfd->vidioc_s_output)
+                       break;
+               dbgarg (cmd, "value=%d\n",*i);
+               ret=vfd->vidioc_s_output(file, fh, *i);
+               break;
+       }
+
+       /* --- controls ---------------------------------------------- */
+       case VIDIOC_QUERYCTRL:
+       {
+               struct v4l2_queryctrl *p=arg;
+
+               if (!vfd->vidioc_queryctrl)
+                       break;
+               ret=vfd->vidioc_queryctrl(file, fh, p);
+
+               if (!ret)
+                       dbgarg (cmd, "id=%d, type=%d, name=%s, "
+                                       "min/max=%d/%d,"
+                                       " step=%d, default=%d, flags=0x%08x\n",
+                                       p->id,p->type,p->name,p->minimum,
+                                       p->maximum,p->step,p->default_value,
+                                       p->flags);
+               break;
+       }
+       case VIDIOC_G_CTRL:
+       {
+               struct v4l2_control *p = arg;
+
+               if (!vfd->vidioc_g_ctrl)
+                       break;
+               dbgarg(cmd, "Enum for index=%d\n", p->id);
+
+               ret=vfd->vidioc_g_ctrl(file, fh, p);
+               if (!ret)
+                       dbgarg2 ( "id=%d, value=%d\n", p->id, p->value);
+               break;
+       }
+       case VIDIOC_S_CTRL:
+       {
+               struct v4l2_control *p = arg;
+
+               if (!vfd->vidioc_s_ctrl)
+                       break;
+               dbgarg (cmd, "id=%d, value=%d\n", p->id, p->value);
+
+               ret=vfd->vidioc_s_ctrl(file, fh, p);
+               break;
+       }
+       case VIDIOC_G_EXT_CTRLS:
+       {
+               struct v4l2_ext_controls *p = arg;
+
+               if (vfd->vidioc_g_ext_ctrls) {
+                       dbgarg(cmd, "count=%d\n", p->count);
+
+                       ret=vfd->vidioc_g_ext_ctrls(file, fh, p);
+               }
+               break;
+       }
+       case VIDIOC_S_EXT_CTRLS:
+       {
+               struct v4l2_ext_controls *p = arg;
+
+               if (vfd->vidioc_s_ext_ctrls) {
+                       dbgarg(cmd, "count=%d\n", p->count);
+
+                       ret=vfd->vidioc_s_ext_ctrls(file, fh, p);
+               }
+               break;
+       }
+       case VIDIOC_TRY_EXT_CTRLS:
+       {
+               struct v4l2_ext_controls *p = arg;
+
+               if (vfd->vidioc_try_ext_ctrls) {
+                       dbgarg(cmd, "count=%d\n", p->count);
+
+                       ret=vfd->vidioc_try_ext_ctrls(file, fh, p);
+               }
+               break;
+       }
+       case VIDIOC_QUERYMENU:
+       {
+               struct v4l2_querymenu *p=arg;
+               if (!vfd->vidioc_querymenu)
+                       break;
+               ret=vfd->vidioc_querymenu(file, fh, p);
+               if (!ret)
+                       dbgarg (cmd, "id=%d, index=%d, name=%s\n",
+                                               p->id,p->index,p->name);
+               break;
+       }
+       /* --- audio ---------------------------------------------- */
+       case VIDIOC_ENUMAUDIO:
+       {
+               struct v4l2_audio *p=arg;
+
+               if (!vfd->vidioc_enumaudio)
+                       break;
+               dbgarg(cmd, "Enum for index=%d\n", p->index);
+               ret=vfd->vidioc_enumaudio(file, fh, p);
+               if (!ret)
+                       dbgarg2("index=%d, name=%s, capability=%d, "
+                                       "mode=%d\n",p->index,p->name,
+                                       p->capability, p->mode);
+               break;
+       }
+       case VIDIOC_G_AUDIO:
+       {
+               struct v4l2_audio *p=arg;
+
+               if (!vfd->vidioc_g_audio)
+                       break;
+               dbgarg(cmd, "Get for index=%d\n", p->index);
+               ret=vfd->vidioc_g_audio(file, fh, p);
+               if (!ret)
+                       dbgarg2("index=%d, name=%s, capability=%d, "
+                                       "mode=%d\n",p->index,
+                                       p->name,p->capability, p->mode);
+               break;
+       }
+       case VIDIOC_S_AUDIO:
+       {
+               struct v4l2_audio *p=arg;
+
+               if (!vfd->vidioc_s_audio)
+                       break;
+               dbgarg(cmd, "index=%d, name=%s, capability=%d, "
+                                       "mode=%d\n", p->index, p->name,
+                                       p->capability, p->mode);
+               ret=vfd->vidioc_s_audio(file, fh, p);
+               break;
+       }
+       case VIDIOC_ENUMAUDOUT:
+       {
+               struct v4l2_audioout *p=arg;
+
+               if (!vfd->vidioc_enumaudout)
+                       break;
+               dbgarg(cmd, "Enum for index=%d\n", p->index);
+               ret=vfd->vidioc_enumaudout(file, fh, p);
+               if (!ret)
+                       dbgarg2("index=%d, name=%s, capability=%d, "
+                                       "mode=%d\n", p->index, p->name,
+                                       p->capability,p->mode);
+               break;
+       }
+       case VIDIOC_G_AUDOUT:
+       {
+               struct v4l2_audioout *p=arg;
+
+               if (!vfd->vidioc_g_audout)
+                       break;
+               dbgarg(cmd, "Enum for index=%d\n", p->index);
+               ret=vfd->vidioc_g_audout(file, fh, p);
+               if (!ret)
+                       dbgarg2("index=%d, name=%s, capability=%d, "
+                                       "mode=%d\n", p->index, p->name,
+                                       p->capability,p->mode);
+               break;
+       }
+       case VIDIOC_S_AUDOUT:
+       {
+               struct v4l2_audioout *p=arg;
+
+               if (!vfd->vidioc_s_audout)
+                       break;
+               dbgarg(cmd, "index=%d, name=%s, capability=%d, "
+                                       "mode=%d\n", p->index, p->name,
+                                       p->capability,p->mode);
+
+               ret=vfd->vidioc_s_audout(file, fh, p);
+               break;
+       }
+       case VIDIOC_G_MODULATOR:
+       {
+               struct v4l2_modulator *p=arg;
+               if (!vfd->vidioc_g_modulator)
+                       break;
+               ret=vfd->vidioc_g_modulator(file, fh, p);
+               if (!ret)
+                       dbgarg(cmd, "index=%d, name=%s, "
+                                       "capability=%d, rangelow=%d,"
+                                       " rangehigh=%d, txsubchans=%d\n",
+                                       p->index, p->name,p->capability,
+                                       p->rangelow, p->rangehigh,
+                                       p->txsubchans);
+               break;
+       }
+       case VIDIOC_S_MODULATOR:
+       {
+               struct v4l2_modulator *p=arg;
+               if (!vfd->vidioc_s_modulator)
+                       break;
+               dbgarg(cmd, "index=%d, name=%s, capability=%d, "
+                               "rangelow=%d, rangehigh=%d, txsubchans=%d\n",
+                               p->index, p->name,p->capability,p->rangelow,
+                               p->rangehigh,p->txsubchans);
+                       ret=vfd->vidioc_s_modulator(file, fh, p);
+               break;
+       }
+       case VIDIOC_G_CROP:
+       {
+               struct v4l2_crop *p=arg;
+               if (!vfd->vidioc_g_crop)
+                       break;
+               ret=vfd->vidioc_g_crop(file, fh, p);
+               if (!ret) {
+                       dbgarg(cmd, "type=%d\n", p->type);
+                       dbgrect(vfd, "", &p->c);
+               }
+               break;
+       }
+       case VIDIOC_S_CROP:
+       {
+               struct v4l2_crop *p=arg;
+               if (!vfd->vidioc_s_crop)
+                       break;
+               dbgarg(cmd, "type=%d\n", p->type);
+               dbgrect(vfd, "", &p->c);
+               ret=vfd->vidioc_s_crop(file, fh, p);
+               break;
+       }
+       case VIDIOC_CROPCAP:
+       {
+               struct v4l2_cropcap *p=arg;
+               /*FIXME: Should also show v4l2_fract pixelaspect */
+               if (!vfd->vidioc_cropcap)
+                       break;
+               dbgarg(cmd, "type=%d\n", p->type);
+               dbgrect(vfd, "bounds ", &p->bounds);
+               dbgrect(vfd, "defrect ", &p->defrect);
+               ret=vfd->vidioc_cropcap(file, fh, p);
+               break;
+       }
+       case VIDIOC_G_MPEGCOMP:
+       {
+               struct v4l2_mpeg_compression *p=arg;
+
+               /*FIXME: Several fields not shown */
+               if (!vfd->vidioc_g_mpegcomp)
+                       break;
+               ret=vfd->vidioc_g_mpegcomp(file, fh, p);
+               if (!ret)
+                       dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d,"
+                                       " ts_pid_video=%d, ts_pid_pcr=%d, "
+                                       "ps_size=%d, au_sample_rate=%d, "
+                                       "au_pesid=%c, vi_frame_rate=%d, "
+                                       "vi_frames_per_gop=%d, "
+                                       "vi_bframes_count=%d, vi_pesid=%c\n",
+                                       p->ts_pid_pmt,p->ts_pid_audio,
+                                       p->ts_pid_video,p->ts_pid_pcr,
+                                       p->ps_size, p->au_sample_rate,
+                                       p->au_pesid, p->vi_frame_rate,
+                                       p->vi_frames_per_gop,
+                                       p->vi_bframes_count, p->vi_pesid);
+               break;
+       }
+       case VIDIOC_S_MPEGCOMP:
+       {
+               struct v4l2_mpeg_compression *p=arg;
+               /*FIXME: Several fields not shown */
+               if (!vfd->vidioc_s_mpegcomp)
+                       break;
+               dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d, "
+                               "ts_pid_video=%d, ts_pid_pcr=%d, ps_size=%d, "
+                               "au_sample_rate=%d, au_pesid=%c, "
+                               "vi_frame_rate=%d, vi_frames_per_gop=%d, "
+                               "vi_bframes_count=%d, vi_pesid=%c\n",
+                               p->ts_pid_pmt,p->ts_pid_audio, p->ts_pid_video,
+                               p->ts_pid_pcr, p->ps_size, p->au_sample_rate,
+                               p->au_pesid, p->vi_frame_rate,
+                               p->vi_frames_per_gop, p->vi_bframes_count,
+                               p->vi_pesid);
+               ret=vfd->vidioc_s_mpegcomp(file, fh, p);
+               break;
+       }
+       case VIDIOC_G_JPEGCOMP:
+       {
+               struct v4l2_jpegcompression *p=arg;
+               if (!vfd->vidioc_g_jpegcomp)
+                       break;
+               ret=vfd->vidioc_g_jpegcomp(file, fh, p);
+               if (!ret)
+                       dbgarg (cmd, "quality=%d, APPn=%d, "
+                                               "APP_len=%d, COM_len=%d, "
+                                               "jpeg_markers=%d\n",
+                                               p->quality,p->APPn,p->APP_len,
+                                               p->COM_len,p->jpeg_markers);
+               break;
+       }
+       case VIDIOC_S_JPEGCOMP:
+       {
+               struct v4l2_jpegcompression *p=arg;
+               if (!vfd->vidioc_g_jpegcomp)
+                       break;
+               dbgarg (cmd, "quality=%d, APPn=%d, APP_len=%d, "
+                                       "COM_len=%d, jpeg_markers=%d\n",
+                                       p->quality,p->APPn,p->APP_len,
+                                       p->COM_len,p->jpeg_markers);
+                       ret=vfd->vidioc_s_jpegcomp(file, fh, p);
+               break;
+       }
+       case VIDIOC_G_PARM:
+       {
+               struct v4l2_streamparm *p=arg;
+               if (!vfd->vidioc_g_parm)
+                       break;
+               ret=vfd->vidioc_g_parm(file, fh, p);
+               dbgarg (cmd, "type=%d\n", p->type);
+               break;
+       }
+       case VIDIOC_S_PARM:
+       {
+               struct v4l2_streamparm *p=arg;
+               if (!vfd->vidioc_s_parm)
+                       break;
+               dbgarg (cmd, "type=%d\n", p->type);
+               ret=vfd->vidioc_s_parm(file, fh, p);
+               break;
+       }
+       case VIDIOC_G_TUNER:
+       {
+               struct v4l2_tuner *p=arg;
+               if (!vfd->vidioc_g_tuner)
+                       break;
+               ret=vfd->vidioc_g_tuner(file, fh, p);
+               if (!ret)
+                       dbgarg (cmd, "index=%d, name=%s, type=%d, "
+                                       "capability=%d, rangelow=%d, "
+                                       "rangehigh=%d, signal=%d, afc=%d, "
+                                       "rxsubchans=%d, audmode=%d\n",
+                                       p->index, p->name, p->type,
+                                       p->capability, p->rangelow,
+                                       p->rangehigh, p->rxsubchans,
+                                       p->audmode, p->signal, p->afc);
+               break;
+       }
+       case VIDIOC_S_TUNER:
+       {
+               struct v4l2_tuner *p=arg;
+               if (!vfd->vidioc_s_tuner)
+                       break;
+               dbgarg (cmd, "index=%d, name=%s, type=%d, "
+                               "capability=%d, rangelow=%d, rangehigh=%d, "
+                               "signal=%d, afc=%d, rxsubchans=%d, "
+                               "audmode=%d\n",p->index, p->name, p->type,
+                               p->capability, p->rangelow,p->rangehigh,
+                               p->rxsubchans, p->audmode, p->signal,
+                               p->afc);
+               ret=vfd->vidioc_s_tuner(file, fh, p);
+               break;
+       }
+       case VIDIOC_G_FREQUENCY:
+       {
+               struct v4l2_frequency *p=arg;
+               if (!vfd->vidioc_g_frequency)
+                       break;
+               ret=vfd->vidioc_g_frequency(file, fh, p);
+               if (!ret)
+                       dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
+                                               p->tuner,p->type,p->frequency);
+               break;
+       }
+       case VIDIOC_S_FREQUENCY:
+       {
+               struct v4l2_frequency *p=arg;
+               if (!vfd->vidioc_s_frequency)
+                       break;
+               dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
+                               p->tuner,p->type,p->frequency);
+               ret=vfd->vidioc_s_frequency(file, fh, p);
+               break;
+       }
+       case VIDIOC_G_SLICED_VBI_CAP:
+       {
+               struct v4l2_sliced_vbi_cap *p=arg;
+               if (!vfd->vidioc_g_sliced_vbi_cap)
+                       break;
+               ret=vfd->vidioc_g_sliced_vbi_cap(file, fh, p);
+               if (!ret)
+                       dbgarg (cmd, "service_set=%d\n", p->service_set);
+               break;
+       }
+       case VIDIOC_LOG_STATUS:
+       {
+               if (!vfd->vidioc_log_status)
+                       break;
+               ret=vfd->vidioc_log_status(file, fh);
+               break;
+       }
+
+       /* --- Others --------------------------------------------- */
+
+       default:
+               ret=v4l_compat_translate_ioctl(inode,file,cmd,arg,__video_do_ioctl);
+       }
+
+       if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
+               if (ret<0) {
+                       printk ("%s: err:\n", vfd->name);
+                       v4l_print_ioctl(vfd->name, cmd);
+               }
+       }
+
+       return ret;
+}
+
+int video_ioctl2 (struct inode *inode, struct file *file,
+              unsigned int cmd, unsigned long arg)
+{
+       char    sbuf[128];
+       void    *mbuf = NULL;
+       void    *parg = NULL;
+       int     err  = -EINVAL;
+       int     is_ext_ctrl;
+       size_t  ctrls_size = 0;
+       void __user *user_ptr = NULL;
+
+#ifdef __OLD_VIDIOC_
+       cmd = video_fix_command(cmd);
+#endif
+       is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
+                      cmd == VIDIOC_TRY_EXT_CTRLS);
+
+       /*  Copy arguments into temp kernel buffer  */
+       switch (_IOC_DIR(cmd)) {
+       case _IOC_NONE:
+               parg = NULL;
+               break;
+       case _IOC_READ:
+       case _IOC_WRITE:
+       case (_IOC_WRITE | _IOC_READ):
+               if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+                       parg = sbuf;
+               } else {
+                       /* too big to allocate from stack */
+                       mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
+                       if (NULL == mbuf)
+                               return -ENOMEM;
+                       parg = mbuf;
+               }
+
+               err = -EFAULT;
+               if (_IOC_DIR(cmd) & _IOC_WRITE)
+                       if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
+                               goto out;
+               break;
+       }
+
+       if (is_ext_ctrl) {
+               struct v4l2_ext_controls *p = parg;
+
+               /* In case of an error, tell the caller that it wasn't
+                  a specific control that caused it. */
+               p->error_idx = p->count;
+               user_ptr = (void __user *)p->controls;
+               if (p->count) {
+                       ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
+                       /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
+                       mbuf = kmalloc(ctrls_size, GFP_KERNEL);
+                       err = -ENOMEM;
+                       if (NULL == mbuf)
+                               goto out_ext_ctrl;
+                       err = -EFAULT;
+                       if (copy_from_user(mbuf, user_ptr, ctrls_size))
+                               goto out_ext_ctrl;
+                       p->controls = mbuf;
+               }
+       }
+
+       /* Handles IOCTL */
+       err = __video_do_ioctl(inode, file, cmd, parg);
+       if (err == -ENOIOCTLCMD)
+               err = -EINVAL;
+       if (is_ext_ctrl) {
+               struct v4l2_ext_controls *p = parg;
+
+               p->controls = (void *)user_ptr;
+               if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
+                       err = -EFAULT;
+               goto out_ext_ctrl;
+       }
+       if (err < 0)
+               goto out;
+
+out_ext_ctrl:
+       /*  Copy results into user buffer  */
+       switch (_IOC_DIR(cmd))
+       {
+       case _IOC_READ:
+       case (_IOC_WRITE | _IOC_READ):
+               if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
+                       err = -EFAULT;
+               break;
+       }
+
+out:
+       kfree(mbuf);
+       return err;
+}
+
+
 static struct file_operations video_fops;
 
 /**
@@ -371,7 +1610,9 @@ void video_unregister_device(struct video_device *vfd)
        mutex_unlock(&videodev_lock);
 }
 
-
+/*
+ * Video fs operations
+ */
 static struct file_operations video_fops=
 {
        .owner          = THIS_MODULE,
@@ -387,7 +1628,7 @@ static int __init videodev_init(void)
 {
        int ret;
 
-       printk(KERN_INFO "Linux video capture interface: v1.00\n");
+       printk(KERN_INFO "Linux video capture interface: v2.00\n");
        if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) {
                printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR);
                return -EIO;
@@ -418,11 +1659,12 @@ EXPORT_SYMBOL(video_devdata);
 EXPORT_SYMBOL(video_usercopy);
 EXPORT_SYMBOL(video_exclusive_open);
 EXPORT_SYMBOL(video_exclusive_release);
+EXPORT_SYMBOL(video_ioctl2);
 EXPORT_SYMBOL(video_device_alloc);
 EXPORT_SYMBOL(video_device_release);
 
-MODULE_AUTHOR("Alan Cox");
-MODULE_DESCRIPTION("Device registrar for Video4Linux drivers");
+MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2");
 MODULE_LICENSE("GPL");
 
 
index a8c101494cf575f947fd804eccdde524140bb1ec..268e69fdefc6f3194fdcdc3cc2902fffbd642c3b 100644 (file)
@@ -40,7 +40,7 @@
 #include <linux/i2c-algo-sgi.h>
 
 #include <linux/videodev.h>
-#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
 #include <linux/video_decoder.h>
 #include <linux/mutex.h>
 
index 779db26771c03b5cf4cb8223dbc3a615c2f3a2ab..41d23c8acbd8b41fd283f4d39b7aaf4ebd88c849 100644 (file)
 
 #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");
+/* Declare static vars that will be used as parameters */
+static unsigned int vid_limit = 16;    /* Video memory limit, in Mb */
+static struct video_device vivi;       /* Video device */
+static int video_nr = -1;              /* /dev/videoN, -1 for autodetect */
 
 /* supported controls */
 static struct v4l2_queryctrl vivi_qctrl[] = {
@@ -129,10 +110,10 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
 
 static int qctl_regs[ARRAY_SIZE(vivi_qctrl)];
 
-#define dprintk(level,fmt, arg...)                          \
-       do {                                                 \
-               if (debug >= (level))                        \
-                       printk(KERN_DEBUG "vivi: " fmt , ## arg);    \
+#define dprintk(level,fmt, arg...)                                     \
+       do {                                                            \
+               if (vivi.debug >= (level))                              \
+                       printk(KERN_DEBUG "vivi: " fmt , ## arg);       \
        } while (0)
 
 /* ------------------------------------------------------------------
@@ -190,7 +171,7 @@ struct vivi_dev {
 
        /* various device info */
        unsigned int               resources;
-       struct video_device        video_dev;
+       struct video_device        vfd;
 
        struct vivi_dmaqueue       vidq;
 
@@ -248,7 +229,8 @@ static u8 bars[8][3] = {
 #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)
+static void prep_to_addr(struct sg_to_addr to_addr[],
+                        struct videobuf_buffer *vb)
 {
        int i, pos=0;
 
@@ -259,7 +241,7 @@ void prep_to_addr(struct sg_to_addr to_addr[],struct videobuf_buffer *vb)
        }
 }
 
-inline int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
+static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
 {
        int p1=0,p2=pages-1,p3=pages/2;
 
@@ -280,8 +262,8 @@ inline int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
        return (p1);
 }
 
-void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
-                                       int hmax, int line, char *timestr)
+static 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;
@@ -491,7 +473,7 @@ static void vivi_thread_tick(struct vivi_dmaqueue  *dma_q)
                dprintk(1,"%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
 }
 
-void vivi_sleep(struct vivi_dmaqueue  *dma_q)
+static void vivi_sleep(struct vivi_dmaqueue  *dma_q)
 {
        int timeout;
        DECLARE_WAITQUEUE(wait, current);
@@ -526,7 +508,7 @@ void vivi_sleep(struct vivi_dmaqueue  *dma_q)
        try_to_freeze();
 }
 
-int vivi_thread(void *data)
+static int vivi_thread(void *data)
 {
        struct vivi_dmaqueue  *dma_q=data;
 
@@ -542,7 +524,7 @@ int vivi_thread(void *data)
        return 0;
 }
 
-int vivi_start_thread(struct vivi_dmaqueue  *dma_q)
+static int vivi_start_thread(struct vivi_dmaqueue  *dma_q)
 {
        dma_q->frame=0;
        dma_q->ini_jiffies=jiffies;
@@ -560,7 +542,7 @@ int vivi_start_thread(struct vivi_dmaqueue  *dma_q)
        return 0;
 }
 
-void vivi_stop_thread(struct vivi_dmaqueue  *dma_q)
+static void vivi_stop_thread(struct vivi_dmaqueue  *dma_q)
 {
        dprintk(1,"%s\n",__FUNCTION__);
        /* shutdown control thread */
@@ -666,8 +648,7 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
        return 0;
 }
 
-void
-free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
+static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
 {
        dprintk(1,"%s\n",__FUNCTION__);
 
@@ -791,8 +772,8 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb
        free_buffer(vq,buf);
 }
 
-int vivi_map_sg (void *dev, struct scatterlist *sg, int nents,
-          int direction)
+static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents,
+                      int direction)
 {
        int i;
 
@@ -808,15 +789,15 @@ int vivi_map_sg (void *dev, struct scatterlist *sg, int nents,
        return nents;
 }
 
-int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages,
-                                       int direction)
+static 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)
+static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages,
+                           int direction)
 {
 //     dprintk(1,"%s\n",__FUNCTION__);
 
@@ -840,7 +821,80 @@ static struct videobuf_queue_ops vivi_video_qops = {
        IOCTL handling
    ------------------------------------------------------------------*/
 
-static int vivi_try_fmt(struct vivi_dev *dev, struct vivi_fh *fh,
+
+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 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);
+}
+
+/* ------------------------------------------------------------------
+       IOCTL vidioc handling
+   ------------------------------------------------------------------*/
+static int vidioc_querycap (struct file *file, void  *priv,
+                                       struct v4l2_capability *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;
+       return 0;
+}
+
+static int vidioc_enum_fmt_cap (struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       if (f->index > 0)
+               return -EINVAL;
+
+       strlcpy(f->description,format.name,sizeof(f->description));
+       f->pixelformat = format.fourcc;
+       return 0;
+}
+
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivi_fh  *fh=priv;
+
+       f->fmt.pix.width        = fh->width;
+       f->fmt.pix.height       = fh->height;
+       f->fmt.pix.field        = fh->vb_vidq.field;
+       f->fmt.pix.pixelformat  = fh->fmt->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;
+
+       return (0);
+}
+
+static int vidioc_try_fmt_cap (struct file *file, void *priv,
                        struct v4l2_format *f)
 {
        struct vivi_fmt *fmt;
@@ -848,7 +902,8 @@ static int vivi_try_fmt(struct vivi_dev *dev, struct vivi_fh *fh,
        unsigned int maxw, maxh;
 
        if (format.fourcc != f->fmt.pix.pixelformat) {
-               dprintk(1,"Fourcc format invalid.\n");
+               dprintk(1,"Fourcc format (0x%08x) invalid. Driver accepts "
+                       "only 0x%08x\n",f->fmt.pix.pixelformat,format.fourcc);
                return -EINVAL;
        }
        fmt=&format;
@@ -884,356 +939,196 @@ static int vivi_try_fmt(struct vivi_dev *dev, struct vivi_fh *fh,
        return 0;
 }
 
-static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
+/*FIXME: This seems to be generic enough to be at videodev2 */
+static int vidioc_s_fmt_cap (struct file *file, void *priv,
+                                       struct v4l2_format *f)
 {
-       /* 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;
+       struct vivi_fh  *fh=priv;
+       int ret = vidioc_try_fmt_cap(file,fh,f);
+       if (ret < 0)
+               return (ret);
+
+       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;
+
+       return (0);
 }
 
-static inline int res_locked(struct vivi_dev *dev)
+static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
 {
-       return (dev->resources);
-}
+       struct vivi_fh  *fh=priv;
 
-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);
+       return (videobuf_reqbufs(&fh->vb_vidq, p));
 }
 
-static int vivi_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg)
+static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
 {
-       struct vivi_fh  *fh     = file->private_data;
-       struct vivi_dev *dev    = fh->dev;
-       int ret=0;
+       struct vivi_fh  *fh=priv;
 
-       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);
-               }
-       }
+       return (videobuf_querybuf(&fh->vb_vidq, p));
+}
 
-       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;
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct vivi_fh  *fh=priv;
 
-               index = f->index;
-               type  = f->type;
+       return (videobuf_qbuf(&fh->vb_vidq, p));
+}
 
-               if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       ret=-EINVAL;
-                       break;
-               }
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct vivi_fh  *fh=priv;
 
-               switch (type) {
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                       if (index > 0){
-                               ret=-EINVAL;
-                               break;
-                       }
-                       memset(f,0,sizeof(*f));
+       return (videobuf_dqbuf(&fh->vb_vidq, p,
+                               file->f_flags & O_NONBLOCK));
+}
 
-                       f->index = index;
-                       f->type  = type;
-                       strlcpy(f->description,format.name,sizeof(f->description));
-                       f->pixelformat = format.fourcc;
-                       break;
-               default:
-                       ret=-EINVAL;
-               }
-               break;
+#ifdef HAVE_V4L1
+static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+       struct vivi_fh  *fh=priv;
+       struct videobuf_queue *q=&fh->vb_vidq;
+       struct v4l2_requestbuffers req;
+       unsigned int i, ret;
+
+       req.type   = q->type;
+       req.count  = 8;
+       req.memory = V4L2_MEMORY_MMAP;
+       ret = videobuf_reqbufs(q,&req);
+       if (ret < 0)
+               return (ret);
+
+       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;
        }
-       case VIDIOC_G_FMT:
-       {
-               struct v4l2_format *f = (struct v4l2_format *)arg;
+       return (0);
+}
+#endif
 
-               if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       ret=-EINVAL;
-                       break;
-               }
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct vivi_fh  *fh=priv;
+       struct vivi_dev *dev    = fh->dev;
 
-               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 (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (i != fh->type)
+               return -EINVAL;
 
-               if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       dprintk(1,"Only capture supported.\n");
-                       ret=-EINVAL;
-                       break;
-               }
+       if (!res_get(dev,fh))
+               return -EBUSY;
+       return (videobuf_streamon(&fh->vb_vidq));
+}
 
-               ret = vivi_try_fmt(dev,fh,f);
-               if (ret < 0)
-                       break;
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct vivi_fh  *fh=priv;
+       struct vivi_dev *dev    = fh->dev;
 
-               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;
+       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (i != fh->type)
+               return -EINVAL;
 
-               break;
-       }
-       case VIDIOC_TRY_FMT:
-       {
-               struct v4l2_format *f = arg;
-               if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       ret=-EINVAL;
-                       break;
-               }
+       videobuf_streamoff(&fh->vb_vidq);
+       res_free(dev,fh);
 
-               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:
+       return (0);
+}
+
+static struct v4l2_tvnorm tvnorms[] = {
        {
-               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;
+               .name      = "NTSC-M",
+               .id        = V4L2_STD_NTSC_M,
        }
-       /* ---------- 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");
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id a)
+{
 
-               /* Allows vivi to use different fps from video std */
-               e->frameperiod.numerator = WAKE_NUMERATOR;
-               e->frameperiod.denominator = WAKE_DENOMINATOR;
+       return 0;
+}
 
-               break;
-       }
-       case VIDIOC_G_STD:
-       {
-               v4l2_std_id *id = arg;
+/* only one input in this sample driver */
+static int vidioc_enum_input (struct file *file, void *priv,
+                               struct v4l2_input *inp)
+{
+       if (inp->index != 0)
+               return -EINVAL;
 
-               *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;
+       inp->type = V4L2_INPUT_TYPE_CAMERA;
+       inp->std = V4L2_STD_NTSC_M;
+       strcpy(inp->name,"Camera");
 
-               if (inp->index != 0) {
-                       ret=-EINVAL;
-                       break;
-               }
-               memset(inp, 0, sizeof(*inp));
+       return (0);
+}
 
-               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;
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+{
+       *i = 0;
 
-               *i = 0;
-               break;
-       }
-       case VIDIOC_S_INPUT:
-       {
-               unsigned int *i = arg;
+       return (0);
+}
+static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+{
+       if (i > 0)
+               return -EINVAL;
 
-               if (*i > 0)
-                       ret=-EINVAL;
-               break;
-       }
+       return (0);
+}
 
        /* --- 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;
-                       }
+static int vidioc_queryctrl (struct file *file, void *priv,
+                               struct v4l2_queryctrl *qc)
+{
+       int i;
 
-               ret=-EINVAL;
-               break;
-       }
-       case VIDIOC_G_CTRL:
-       {
-               struct v4l2_control *ctrl = 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));
+                       return (0);
+               }
 
-               for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
-                       if (ctrl->id == vivi_qctrl[i].id) {
-                               ctrl->value=qctl_regs[i];
-                               break;
-                       }
+       return -EINVAL;
+}
 
-               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);
-       }
+static int vidioc_g_ctrl (struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       int i;
 
-       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);
-       }
+       for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+               if (ctrl->id == vivi_qctrl[i].id) {
+                       ctrl->value=qctl_regs[i];
+                       return (0);
+               }
 
-       return ret;
+       return -EINVAL;
 }
-
-static int vivi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int vidioc_s_ctrl (struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
 {
-       return video_usercopy(inode, file, cmd, arg, vivi_do_ioctl);
+       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) {
+                                       return (-ERANGE);
+                               }
+                       qctl_regs[i]=ctrl->value;
+                       return (0);
+               }
+       return -EINVAL;
 }
 
 /* ------------------------------------------------------------------
@@ -1255,7 +1150,7 @@ static int vivi_open(struct inode *inode, struct file *file)
 
        list_for_each(list,&vivi_devlist) {
                h = list_entry(list, struct vivi_dev, vivi_devlist);
-               if (h->video_dev.minor == minor) {
+               if (h->vfd.minor == minor) {
                        dev  = h;
                        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                }
@@ -1264,6 +1159,7 @@ static int vivi_open(struct inode *inode, struct file *file)
                return -ENODEV;
 
 
+
        /* If more than one user, mutex should be added */
        dev->users++;
 
@@ -1279,6 +1175,7 @@ static int vivi_open(struct inode *inode, struct file *file)
 
        file->private_data = fh;
        fh->dev      = dev;
+
        fh->type     = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        fh->fmt      = &format;
        fh->width    = 640;
@@ -1314,7 +1211,7 @@ static int vivi_open(struct inode *inode, struct file *file)
 static ssize_t
 vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
-       struct vivi_fh *fh = file->private_data;
+       struct vivi_fh        *fh = file->private_data;
 
        if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
                if (res_locked(fh->dev))
@@ -1328,8 +1225,8 @@ vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 static unsigned int
 vivi_poll(struct file *file, struct poll_table_struct *wait)
 {
-       struct vivi_fh *fh = file->private_data;
-       struct vivi_buffer *buf;
+       struct vivi_fh        *fh = file->private_data;
+       struct vivi_buffer    *buf;
 
        dprintk(1,"%s\n",__FUNCTION__);
 
@@ -1358,8 +1255,8 @@ vivi_poll(struct file *file, struct poll_table_struct *wait)
 
 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_fh         *fh = file->private_data;
+       struct vivi_dev *dev       = fh->dev;
        struct vivi_dmaqueue *vidq = &dev->vidq;
 
        int minor = iminor(inode);
@@ -1379,7 +1276,7 @@ static int vivi_release(struct inode *inode, struct file *file)
 static int
 vivi_mmap(struct file *file, struct vm_area_struct * vma)
 {
-       struct vivi_fh *fh = file->private_data;
+       struct vivi_fh        *fh = file->private_data;
        int ret;
 
        dprintk (1,"mmap called, vma=0x%08lx\n",(unsigned long)vma);
@@ -1400,20 +1297,44 @@ static struct file_operations vivi_fops = {
        .release        = vivi_release,
        .read           = vivi_read,
        .poll           = vivi_poll,
-       .ioctl          = vivi_ioctl,
+       .ioctl          = video_ioctl2, /* V4L2 ioctl handler */
        .mmap           = vivi_mmap,
        .llseek         = no_llseek,
 };
 
 static struct video_device vivi = {
-       .name           = "VTM Virtual Video Capture Board",
+       .name           = "vivi",
        .type           = VID_TYPE_CAPTURE,
        .hardware       = 0,
        .fops           = &vivi_fops,
        .minor          = -1,
 //     .release        = video_device_release,
+
+       .vidioc_querycap      = vidioc_querycap,
+       .vidioc_enum_fmt_cap  = vidioc_enum_fmt_cap,
+       .vidioc_g_fmt_cap     = vidioc_g_fmt_cap,
+       .vidioc_try_fmt_cap   = vidioc_try_fmt_cap,
+       .vidioc_s_fmt_cap     = vidioc_s_fmt_cap,
+       .vidioc_reqbufs       = vidioc_reqbufs,
+       .vidioc_querybuf      = vidioc_querybuf,
+       .vidioc_qbuf          = vidioc_qbuf,
+       .vidioc_dqbuf         = vidioc_dqbuf,
+       .vidioc_s_std         = vidioc_s_std,
+       .vidioc_enum_input    = vidioc_enum_input,
+       .vidioc_g_input       = vidioc_g_input,
+       .vidioc_s_input       = vidioc_s_input,
+       .vidioc_queryctrl     = vidioc_queryctrl,
+       .vidioc_g_ctrl        = vidioc_g_ctrl,
+       .vidioc_s_ctrl        = vidioc_s_ctrl,
+       .vidioc_streamon      = vidioc_streamon,
+       .vidioc_streamoff     = vidioc_streamoff,
+#ifdef HAVE_V4L1
+       .vidiocgmbuf          = vidiocgmbuf,
+#endif
+       .tvnorms              = tvnorms,
+       .tvnormsize           = ARRAY_SIZE(tvnorms),
 };
-/* ------------------------------------------------------------------
+/* -----------------------------------------------------------------
        Initialization and module stuff
    ------------------------------------------------------------------*/
 
@@ -1457,3 +1378,16 @@ static void __exit vivi_exit(void)
 
 module_init(vivi_init);
 module_exit(vivi_exit);
+
+MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
+MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
+MODULE_LICENSE("Dual BSD/GPL");
+
+module_param(video_nr, int, 0);
+
+module_param_named(debug,vivi.debug, int, 0644);
+MODULE_PARM_DESC(debug,"activates debug info");
+
+module_param(vid_limit,int,0644);
+MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
+
index 40b205b91481e495812c727da02baee30017834e..1eca7e65d235e570fcb36ce5dcf7312b759c56ea 100644 (file)
@@ -34,6 +34,7 @@
 #define I2C_NAME(x) (x)->name
 
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/video_decoder.h>
 
 #define I2C_VPX3220        0x86
index 80ef8a1b8f632ddb83656626dabdc26b5722d0a3..4bdc886abc4c69e5afa2ece884d5be8977392ce8 100644 (file)
@@ -58,6 +58,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/parport.h>
 
 //#define DEBUG                                // Undef me for production
index 115833e4f4dd3b421832a0a1d81a8aabd39330ee..a859a6920189e5cc62d64e864b6cfc79d995ca2d 100644 (file)
@@ -1,9 +1,9 @@
 config USB_ZC0301
-       tristate "USB ZC0301 Image Processor and Control Chip support"
+       tristate "USB ZC0301[P] Image Processor and Control Chip support"
        depends on USB && VIDEO_V4L1
        ---help---
-         Say Y here if you want support for cameras based on the ZC0301
-         Image Processor and Control Chip.
+         Say Y here if you want support for cameras based on the ZC0301 or
+         ZC0301P Image Processors and Control Chips.
 
          See <file:Documentation/video4linux/zc0301.txt> for more info.
 
index d749199d8f06f670d20c65c3bade098a52d4a15f..d9e6d97fade640271aae639ddd933b328a8a0a10 100644 (file)
@@ -1,3 +1,3 @@
-zc0301-objs     := zc0301_core.o zc0301_pas202bcb.o
+zc0301-objs     := zc0301_core.o zc0301_pb0330.o zc0301_pas202bcb.o
 
 obj-$(CONFIG_USB_ZC0301)        += zc0301.o
index 0fad39754f7a68f2c5aa4432c2f229ca2f2ea832..1b2be2d2a3ec50c7e3fa50ba34ed3dc7a7bf2c8e 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- * Video4Linux2 driver for ZC0301 Image Processor and Control Chip         *
+ * Video4Linux2 driver for ZC0301[P] Image Processor and Control Chip      *
  *                                                                         *
  * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
  *                                                                         *
 
 /*****************************************************************************/
 
-#define ZC0301_MODULE_NAME    "V4L2 driver for ZC0301 "                       \
+#define ZC0301_MODULE_NAME    "V4L2 driver for ZC0301[P] "                    \
                              "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)
+#define ZC0301_MODULE_VERSION "1:1.05"
+#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 5)
 
 /*****************************************************************************/
 
@@ -427,10 +427,11 @@ resubmit_urb:
 static int zc0301_start_transfer(struct zc0301_device* cam)
 {
        struct usb_device *udev = cam->usbdev;
+       struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
+                                                    usb_ifnum_to_if(udev, 0),
+                                                    ZC0301_ALTERNATE_SETTING);
+       const unsigned int psz = altsetting->endpoint[0].desc.wMaxPacketSize;
        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;
 
@@ -1772,11 +1773,9 @@ static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
        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);
 
@@ -1823,7 +1822,6 @@ static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
        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);
 
@@ -1914,7 +1912,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 
        mutex_init(&cam->dev_mutex);
 
-       DBG(2, "ZC0301 Image Processor and Control Chip detected "
+       DBG(2, "ZC0301[P] Image Processor and Control Chip detected "
               "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
 
        for  (i = 0; zc0301_sensor_table[i]; i++) {
@@ -1936,7 +1934,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                cam->state |= DEV_MISCONFIGURED;
        }
 
-       strcpy(cam->v4ldev->name, "ZC0301 PC Camera");
+       strcpy(cam->v4ldev->name, "ZC0301[P] PC Camera");
        cam->v4ldev->owner = THIS_MODULE;
        cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
        cam->v4ldev->hardware = 0;
index eaadf0252049c4b17a5627c76b82f3d05de4a2ba..ecfd39a56df18814f766a46886e95e29d06cc9c7 100644 (file)
@@ -1,10 +1,10 @@
 /***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the ZC030! Image        *
+ * Plug-in for PAS202BCB image sensor connected to the ZC0301[P] 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    *
+ * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
  * driver maintained by Michel Xhaard <mxhaard@magic.fr>                   *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
diff --git a/drivers/media/video/zc0301/zc0301_pb0330.c b/drivers/media/video/zc0301/zc0301_pb0330.c
new file mode 100644 (file)
index 0000000..ed8542e
--- /dev/null
@@ -0,0 +1,187 @@
+/***************************************************************************
+ * Plug-in for PB-0330 image sensor connected to the ZC0301[P] Image       *
+ * Processor and Control Chip                                              *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
+ * driver maintained by Michel Xhaard <mxhaard@magic.fr>                   *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include <linux/delay.h>
+#include "zc0301_sensor.h"
+
+
+static struct zc0301_sensor pb0330;
+
+
+static int pb0330_init(struct zc0301_device* cam)
+{
+       int err = 0;
+
+       err += zc0301_write_reg(cam, 0x0000, 0x01);
+       err += zc0301_write_reg(cam, 0x0008, 0x03);
+       err += zc0301_write_reg(cam, 0x0010, 0x0A);
+       err += zc0301_write_reg(cam, 0x0002, 0x00);
+       err += zc0301_write_reg(cam, 0x0003, 0x02);
+       err += zc0301_write_reg(cam, 0x0004, 0x80);
+       err += zc0301_write_reg(cam, 0x0005, 0x01);
+       err += zc0301_write_reg(cam, 0x0006, 0xE0);
+       err += zc0301_write_reg(cam, 0x0001, 0x01);
+       err += zc0301_write_reg(cam, 0x0012, 0x05);
+       err += zc0301_write_reg(cam, 0x0012, 0x07);
+       err += zc0301_write_reg(cam, 0x0098, 0x00);
+       err += zc0301_write_reg(cam, 0x009A, 0x00);
+       err += zc0301_write_reg(cam, 0x011A, 0x00);
+       err += zc0301_write_reg(cam, 0x011C, 0x00);
+       err += zc0301_write_reg(cam, 0x0012, 0x05);
+
+       err += zc0301_i2c_write(cam, 0x01, 0x0006);
+       err += zc0301_i2c_write(cam, 0x02, 0x0011);
+       err += zc0301_i2c_write(cam, 0x03, 0x01E7);
+       err += zc0301_i2c_write(cam, 0x04, 0x0287);
+       err += zc0301_i2c_write(cam, 0x06, 0x0003);
+       err += zc0301_i2c_write(cam, 0x07, 0x3002);
+       err += zc0301_i2c_write(cam, 0x20, 0x1100);
+       err += zc0301_i2c_write(cam, 0x2F, 0xF7B0);
+       err += zc0301_i2c_write(cam, 0x30, 0x0005);
+       err += zc0301_i2c_write(cam, 0x31, 0x0000);
+       err += zc0301_i2c_write(cam, 0x34, 0x0100);
+       err += zc0301_i2c_write(cam, 0x35, 0x0060);
+       err += zc0301_i2c_write(cam, 0x3D, 0x068F);
+       err += zc0301_i2c_write(cam, 0x40, 0x01E0);
+       err += zc0301_i2c_write(cam, 0x58, 0x0078);
+       err += zc0301_i2c_write(cam, 0x62, 0x0411);
+
+       err += zc0301_write_reg(cam, 0x0087, 0x10);
+       err += zc0301_write_reg(cam, 0x0101, 0x37);
+       err += zc0301_write_reg(cam, 0x0012, 0x05);
+       err += zc0301_write_reg(cam, 0x0100, 0x0D);
+       err += zc0301_write_reg(cam, 0x0189, 0x06);
+       err += zc0301_write_reg(cam, 0x01AD, 0x00);
+       err += zc0301_write_reg(cam, 0x01C5, 0x03);
+       err += zc0301_write_reg(cam, 0x01CB, 0x13);
+       err += zc0301_write_reg(cam, 0x0250, 0x08);
+       err += zc0301_write_reg(cam, 0x0301, 0x08);
+       err += zc0301_write_reg(cam, 0x01A8, 0x60);
+       err += zc0301_write_reg(cam, 0x018D, 0x6C);
+       err += zc0301_write_reg(cam, 0x01AD, 0x09);
+       err += zc0301_write_reg(cam, 0x01AE, 0x15);
+       err += zc0301_write_reg(cam, 0x010A, 0x50);
+       err += zc0301_write_reg(cam, 0x010B, 0xF8);
+       err += zc0301_write_reg(cam, 0x010C, 0xF8);
+       err += zc0301_write_reg(cam, 0x010D, 0xF8);
+       err += zc0301_write_reg(cam, 0x010E, 0x50);
+       err += zc0301_write_reg(cam, 0x010F, 0xF8);
+       err += zc0301_write_reg(cam, 0x0110, 0xF8);
+       err += zc0301_write_reg(cam, 0x0111, 0xF8);
+       err += zc0301_write_reg(cam, 0x0112, 0x50);
+       err += zc0301_write_reg(cam, 0x0008, 0x03);
+       err += zc0301_write_reg(cam, 0x01C6, 0x08);
+       err += zc0301_write_reg(cam, 0x01CB, 0x0F);
+       err += zc0301_write_reg(cam, 0x010A, 0x50);
+       err += zc0301_write_reg(cam, 0x010B, 0xF8);
+       err += zc0301_write_reg(cam, 0x010C, 0xF8);
+       err += zc0301_write_reg(cam, 0x010D, 0xF8);
+       err += zc0301_write_reg(cam, 0x010E, 0x50);
+       err += zc0301_write_reg(cam, 0x010F, 0xF8);
+       err += zc0301_write_reg(cam, 0x0110, 0xF8);
+       err += zc0301_write_reg(cam, 0x0111, 0xF8);
+       err += zc0301_write_reg(cam, 0x0112, 0x50);
+       err += zc0301_write_reg(cam, 0x0180, 0x00);
+       err += zc0301_write_reg(cam, 0x0019, 0x00);
+
+       err += zc0301_i2c_write(cam, 0x05, 0x0066);
+       err += zc0301_i2c_write(cam, 0x09, 0x02B2);
+       err += zc0301_i2c_write(cam, 0x10, 0x0002);
+
+       err += zc0301_write_reg(cam, 0x011D, 0x60);
+       err += zc0301_write_reg(cam, 0x0190, 0x00);
+       err += zc0301_write_reg(cam, 0x0191, 0x07);
+       err += zc0301_write_reg(cam, 0x0192, 0x8C);
+       err += zc0301_write_reg(cam, 0x0195, 0x00);
+       err += zc0301_write_reg(cam, 0x0196, 0x00);
+       err += zc0301_write_reg(cam, 0x0197, 0x8A);
+       err += zc0301_write_reg(cam, 0x018C, 0x10);
+       err += zc0301_write_reg(cam, 0x018F, 0x20);
+       err += zc0301_write_reg(cam, 0x01A9, 0x14);
+       err += zc0301_write_reg(cam, 0x01AA, 0x24);
+       err += zc0301_write_reg(cam, 0x001D, 0xD7);
+       err += zc0301_write_reg(cam, 0x001E, 0xF0);
+       err += zc0301_write_reg(cam, 0x001F, 0xF8);
+       err += zc0301_write_reg(cam, 0x0020, 0xFF);
+       err += zc0301_write_reg(cam, 0x01AD, 0x09);
+       err += zc0301_write_reg(cam, 0x01AE, 0x15);
+       err += zc0301_write_reg(cam, 0x0180, 0x40);
+       err += zc0301_write_reg(cam, 0x0180, 0x42);
+
+       msleep(100);
+
+       return err;
+}
+
+
+static struct zc0301_sensor pb0330 = {
+       .name = "PB-0330",
+       .init = &pb0330_init,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_JPEG,
+               .priv = 8,
+       },
+};
+
+
+int zc0301_probe_pb0330(struct zc0301_device* cam)
+{
+       int r0, err = 0;
+
+       err += zc0301_write_reg(cam, 0x0000, 0x01);
+       err += zc0301_write_reg(cam, 0x0010, 0x0a);
+       err += zc0301_write_reg(cam, 0x0001, 0x01);
+       err += zc0301_write_reg(cam, 0x0012, 0x03);
+       err += zc0301_write_reg(cam, 0x0012, 0x01);
+
+       msleep(10);
+
+       r0 = zc0301_i2c_read(cam, 0x00, 2);
+
+       if (r0 < 0 || err)
+               return -EIO;
+
+       if (r0 != 0x8243)
+               return -ENODEV;
+
+       zc0301_attach_sensor(cam, &pb0330);
+
+       return 0;
+}
index 1f95c28b101520a8e8c27a41b2c161e49d7a7fd6..4363a915b1f41d085b60383cd4a205bed8bab01a 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- * API for image sensors connected to the ZC030! Image Processor and       *
+ * API for image sensors connected to the ZC0301 Image Processor and       *
  * Control Chip                                                            *
  *                                                                         *
  * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
@@ -35,11 +35,13 @@ struct zc0301_sensor;
 /*****************************************************************************/
 
 extern int zc0301_probe_pas202bcb(struct zc0301_device* cam);
+extern int zc0301_probe_pb0330(struct zc0301_device* cam);
 
 #define ZC0301_SENSOR_TABLE                                                   \
 /* Weak detections must go at the end of the list */                          \
 static int (*zc0301_sensor_table[])(struct zc0301_device*) = {                \
        &zc0301_probe_pas202bcb,                                              \
+       &zc0301_probe_pb0330,                                                 \
        NULL,                                                                 \
 };
 
@@ -58,14 +60,28 @@ zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor);
 
 #define ZC0301_ID_TABLE                                                       \
 static const struct usb_device_id zc0301_id_table[] =  {                      \
-       { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), },                         \
+       { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), }, /* ICM105 */            \
        { ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */            \
-       { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131B */           \
+       { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131 */            \
+       { ZC0301_USB_DEVICE(0x041e, 0x401f, 0xff), }, /* TAS5130 */           \
+       { ZC0301_USB_DEVICE(0x041e, 0x4022, 0xff), },                         \
        { ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */            \
        { ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */            \
-       { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202BCB */         \
+       { ZC0301_USB_DEVICE(0x041e, 0x4036, 0xff), }, /* HV7131 */            \
+       { ZC0301_USB_DEVICE(0x041e, 0x403a, 0xff), }, /* HV7131 */            \
+       { ZC0301_USB_DEVICE(0x0458, 0x7007, 0xff), }, /* TAS5130 */           \
+       { ZC0301_USB_DEVICE(0x0458, 0x700C, 0xff), }, /* TAS5130 */           \
+       { ZC0301_USB_DEVICE(0x0458, 0x700f, 0xff), }, /* TAS5130 */           \
+       { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
+       { ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */           \
+       { ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */           \
+       { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
        { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), },                         \
-       { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130D */          \
+       { ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */    \
+       { ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */           \
+       { ZC0301_USB_DEVICE(0x10fd, 0x0128, 0xff), }, /* TAS5130 */           \
+       { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130 */           \
+       { ZC0301_USB_DEVICE(0x10fd, 0x804e, 0xff), }, /* TAS5130 */           \
        { }                                                                   \
 };
 
index 0166f555a5ca1b37c5399d85b95137dd0c1705ed..ffcda95ed9d4720eba3dcfb16f1e6a473cd29e86 100644 (file)
@@ -159,7 +159,7 @@ Private IOCTL to set up for displaying MJPEG
 #define BUZ_MAX_FRAME     256  /* Must be a power of 2 */
 #define BUZ_MASK_FRAME    255  /* Must be BUZ_MAX_FRAME-1 */
 
-#define BUZ_MAX_INPUT       8
+#define BUZ_MAX_INPUT       16
 
 #if VIDEO_MAX_FRAME <= 32
 #   define   V4L_MAX_FRAME   32
@@ -191,6 +191,9 @@ enum card_type {
        /* Iomega */
        BUZ,
 
+       /* AverMedia */
+       AVS6EYES,
+
        /* total number of cards */
        NUM_CARDS
 };
@@ -379,6 +382,9 @@ struct card_info {
        /* is the /GWS line conected? */
        u8 gws_not_connected;
 
+       /* avs6eyes mux setting */
+       u8 input_mux;
+
        void (*init) (struct zoran * zr);
 };
 
index 0a85c9e7fb4824803abdf0801268bfbb9ac695bd..958c1e6fc8529a7a9e6b8d53111ac707ef692c62 100644 (file)
@@ -27,6 +27,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <linux/delay.h>
+
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -38,6 +40,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/spinlock.h>
 #include <linux/sem.h>
 #include <linux/kmod.h>
@@ -93,6 +96,11 @@ module_param(default_input, int, 0);
 MODULE_PARM_DESC(default_input,
                 "Default input (0=Composite, 1=S-Video, 2=Internal)");
 
+static int default_mux = 1;    /* 6 Eyes input selection */
+module_param(default_mux, int, 0);
+MODULE_PARM_DESC(default_mux,
+                "Default 6 Eyes mux setting (Input selection)");
+
 static int default_norm = 0;   /* 0=PAL, 1=NTSC 2=SECAM */
 module_param(default_norm, int, 0);
 MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)");
@@ -301,6 +309,30 @@ lml33_init (struct zoran *zr)
        GPIO(zr, 2, 1);         // Set Composite input/output
 }
 
+static void
+avs6eyes_init (struct zoran *zr)
+{
+       // AverMedia 6-Eyes original driver by Christer Weinigel
+
+       // Lifted straight from Christer's old driver and
+       // modified slightly by Martin Samuelsson.
+
+       int mux = default_mux; /* 1 = BT866, 7 = VID1 */
+
+       GPIO(zr, 4, 1); /* Bt866 SLEEP on */
+       udelay(2);
+
+       GPIO(zr, 0, 1); /* ZR36060 /RESET on */
+       GPIO(zr, 1, 0); /* ZR36060 /SLEEP on */
+       GPIO(zr, 2, mux & 1);   /* MUX S0 */
+       GPIO(zr, 3, 0); /* /FRAME on */
+       GPIO(zr, 4, 0); /* Bt866 SLEEP off */
+       GPIO(zr, 5, mux & 2);   /* MUX S1 */
+       GPIO(zr, 6, 0); /* ? */
+       GPIO(zr, 7, mux & 4);   /* MUX S2 */
+
+}
+
 static char *
 i2cid_to_modulename (u16 i2c_id)
 {
@@ -391,6 +423,14 @@ static struct tvnorm f60sqpixel_dc10 = { 780, 640, 0, 716, 525, 480, 12 };
 static struct tvnorm f50ccir601_lm33r10 = { 864, 720, 74+54, 804, 625, 576, 18 };
 static struct tvnorm f60ccir601_lm33r10 = { 858, 720, 56+54, 788, 525, 480, 16 };
 
+/* FIXME: The ks0127 seem incapable of swapping U and V, too, which is why I
+ * copy Maxim's left shift hack for the 6 Eyes.
+ *
+ * Christer's driver used the unshifted norms, though...
+ * /Sam  */
+static struct tvnorm f50ccir601_avs6eyes = { 864, 720, 74, 804, 625, 576, 18 };
+static struct tvnorm f60ccir601_avs6eyes = { 858, 720, 56, 788, 525, 480, 16 };
+
 static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
        {
                .type = DC10_old,
@@ -419,6 +459,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                .gpcs = { -1, 0 },
                .vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
                .gws_not_connected = 0,
+               .input_mux = 0,
                .init = &dc10_init,
        }, {
                .type = DC10_new,
@@ -445,6 +486,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                .gpcs = { -1, 1},
                .vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 },
                .gws_not_connected = 0,
+               .input_mux = 0,
                .init = &dc10plus_init,
        }, {
                .type = DC10plus,
@@ -474,6 +516,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                .gpcs = { -1, 1 },
                .vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 },
                .gws_not_connected = 0,
+               .input_mux = 0,
                .init = &dc10plus_init,
        }, {
                .type = DC30,
@@ -502,6 +545,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                .gpcs = { -1, 0 },
                .vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
                .gws_not_connected = 0,
+               .input_mux = 0,
                .init = &dc10_init,
        }, {
                .type = DC30plus,
@@ -532,6 +576,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                .gpcs = { -1, 0 },
                .vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
                .gws_not_connected = 0,
+               .input_mux = 0,
                .init = &dc10_init,
        }, {
                .type = LML33,
@@ -558,6 +603,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                .gpcs = { 3, 1 },
                .vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
                .gws_not_connected = 1,
+               .input_mux = 0,
                .init = &lml33_init,
        }, {
                .type = LML33R10,
@@ -586,6 +632,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                .gpcs = { 3, 1 },
                .vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
                .gws_not_connected = 1,
+               .input_mux = 0,
                .init = &lml33_init,
        }, {
                .type = BUZ,
@@ -614,8 +661,49 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
                .gpcs = { 3, 1 },
                .vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
                .gws_not_connected = 1,
+               .input_mux = 0,
                .init = &buz_init,
+       }, {
+               .type = AVS6EYES,
+               .name = "6-Eyes",
+               /* AverMedia chose not to brand the 6-Eyes. Thus it
+                  can't be autodetected, and requires card=x. */
+               .vendor_id = -1,
+               .device_id = -1,
+               .i2c_decoder = I2C_DRIVERID_KS0127,
+               .i2c_encoder = I2C_DRIVERID_BT866,
+               .video_codec = CODEC_TYPE_ZR36060,
+
+               .inputs = 10,
+               .input = {
+                       { 0, "Composite 1" },
+                       { 1, "Composite 2" },
+                       { 2, "Composite 3" },
+                       { 4, "Composite 4" },
+                       { 5, "Composite 5" },
+                       { 6, "Composite 6" },
+                       { 8, "S-Video 1" },
+                       { 9, "S-Video 2" },
+                       {10, "S-Video 3" },
+                       {15, "YCbCr" }
+               },
+               .norms = 2,
+               .tvn = {
+                       &f50ccir601_avs6eyes,
+                       &f60ccir601_avs6eyes,
+                       NULL
+               },
+               .jpeg_int = ZR36057_ISR_GIRQ1,
+               .vsync_int = ZR36057_ISR_GIRQ0,
+               .gpio = { 1, 0, 3, -1, -1, -1, -1, -1 },// Validity unknown /Sam
+               .gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, // Validity unknown /Sam
+               .gpcs = { 3, 1 },                       // Validity unknown /Sam
+               .vfe_pol = { 1, 0, 0, 0, 0, 1, 0, 0 },  // Validity unknown /Sam
+               .gws_not_connected = 1,
+               .input_mux = 1,
+               .init = &avs6eyes_init,
        }
+
 };
 
 /*
index c690b2ee880a4fe8f44f6496177d345703962329..02168d9c218796a8c74b7f3cdf3baf921e31078b 100644 (file)
@@ -536,7 +536,7 @@ zr36057_overlay (struct zoran *zr,
                 * All error messages are internal driver checking only! */
 
                /* video display top and bottom registers */
-               reg = (u32) zr->buffer.base +
+               reg = (long) zr->buffer.base +
                    zr->overlay_settings.x *
                    ((zr->overlay_settings.format->depth + 7) / 8) +
                    zr->overlay_settings.y *
index b5a576a37fd26d909dc0e2f492dcc27c93255c03..9711f6248ef75a0ba5001dabec60a58cf8207e86 100644 (file)
@@ -73,6 +73,7 @@
                             )
 
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include "videocodec.h"
 
 #include <asm/io.h>
@@ -2047,7 +2048,7 @@ zoran_do_ioctl (struct inode *inode,
                dprintk(3, KERN_DEBUG "%s: VIDIOCGCAP\n", ZR_DEVNAME(zr));
 
                memset(vcap, 0, sizeof(struct video_capability));
-               strncpy(vcap->name, ZR_DEVNAME(zr), sizeof(vcap->name));
+               strncpy(vcap->name, ZR_DEVNAME(zr), sizeof(vcap->name)-1);
                vcap->type = ZORAN_VID_TYPE;
 
                vcap->channels = zr->card.inputs;
@@ -2689,8 +2690,8 @@ zoran_do_ioctl (struct inode *inode,
                dprintk(3, KERN_DEBUG "%s: VIDIOC_QUERYCAP\n", ZR_DEVNAME(zr));
 
                memset(cap, 0, sizeof(*cap));
-               strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card));
-               strncpy(cap->driver, "zoran", sizeof(cap->driver));
+               strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)-1);
+               strncpy(cap->driver, "zoran", sizeof(cap->driver)-1);
                snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
                         pci_name(zr->pci_dev));
                cap->version =
@@ -2742,7 +2743,7 @@ zoran_do_ioctl (struct inode *inode,
                memset(fmt, 0, sizeof(*fmt));
                fmt->index = index;
                fmt->type = type;
-               strncpy(fmt->description, zoran_formats[i].name, 31);
+               strncpy(fmt->description, zoran_formats[i].name, sizeof(fmt->description)-1);
                fmt->pixelformat = zoran_formats[i].fourcc;
                if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED)
                        fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
@@ -3566,16 +3567,16 @@ zoran_do_ioctl (struct inode *inode,
 
                switch (ctrl->id) {
                case V4L2_CID_BRIGHTNESS:
-                       strncpy(ctrl->name, "Brightness", 31);
+                       strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)-1);
                        break;
                case V4L2_CID_CONTRAST:
-                       strncpy(ctrl->name, "Contrast", 31);
+                       strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)-1);
                        break;
                case V4L2_CID_SATURATION:
-                       strncpy(ctrl->name, "Saturation", 31);
+                       strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)-1);
                        break;
                case V4L2_CID_HUE:
-                       strncpy(ctrl->name, "Hue", 31);
+                       strncpy(ctrl->name, "Hue", sizeof(ctrl->name)-1);
                        break;
                }
 
@@ -3693,7 +3694,7 @@ zoran_do_ioctl (struct inode *inode,
                                        &caps);
                        if (caps.flags & VIDEO_DECODER_AUTO) {
                                std->id = V4L2_STD_ALL;
-                               strncpy(std->name, "Autodetect", 31);
+                               strncpy(std->name, "Autodetect", sizeof(std->name)-1);
                                return 0;
                        } else
                                return -EINVAL;
@@ -3701,21 +3702,21 @@ zoran_do_ioctl (struct inode *inode,
                switch (std->index) {
                case 0:
                        std->id = V4L2_STD_PAL;
-                       strncpy(std->name, "PAL", 31);
+                       strncpy(std->name, "PAL", sizeof(std->name)-1);
                        std->frameperiod.numerator = 1;
                        std->frameperiod.denominator = 25;
                        std->framelines = zr->card.tvn[0]->Ht;
                        break;
                case 1:
                        std->id = V4L2_STD_NTSC;
-                       strncpy(std->name, "NTSC", 31);
+                       strncpy(std->name, "NTSC", sizeof(std->name)-1);
                        std->frameperiod.numerator = 1001;
                        std->frameperiod.denominator = 30000;
                        std->framelines = zr->card.tvn[1]->Ht;
                        break;
                case 2:
                        std->id = V4L2_STD_SECAM;
-                       strncpy(std->name, "SECAM", 31);
+                       strncpy(std->name, "SECAM", sizeof(std->name)-1);
                        std->frameperiod.numerator = 1;
                        std->frameperiod.denominator = 25;
                        std->framelines = zr->card.tvn[2]->Ht;
@@ -3871,7 +3872,7 @@ zoran_do_ioctl (struct inode *inode,
                memset(outp, 0, sizeof(*outp));
                outp->index = 0;
                outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
-               strncpy(outp->name, "Autodetect", 31);
+               strncpy(outp->name, "Autodetect", sizeof(outp->name)-1);
 
                return 0;
        }
index a00fae90229a84c2236c5bde5346c5778b5ba6d2..f4ffe79bdc5b710fd446694ad3b2fc9e7f77df7b 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/seq_file.h>
 
 #include <linux/ctype.h>
+#include <linux/poll.h>
 #include <asm/io.h>
 
 #include "videocodec.h"
index 844fa74ac9ec7f6544c66fa507699d2c94fede7e..2a0d538b387fca39f69414aca82d6060ea371a0c 100644 (file)
@@ -1105,7 +1105,7 @@ static int stir421x_patch_device(struct irda_usb_cb *self)
                 return ret;
 
         /* We get a patch from userspace */
-        IRDA_MESSAGE("%s(): Received firmware %s (%u bytes)\n",
+        IRDA_MESSAGE("%s(): Received firmware %s (%zu bytes)\n",
                      __FUNCTION__, stir421x_fw_name, fw->size);
 
         ret = -EINVAL;
index d4c0002b43db658f8099891afcc5f18bad53620a..a2fad50437e67a319a7e727ef6a6c42400824747 100644 (file)
@@ -55,7 +55,7 @@ static char *version = "sun3lance.c: v1.2 1/12/2001  Sam Creasey (sammy@sammy.ne
 /* sun3/60 addr/irq for the lance chip.  If your sun is different,
    change this. */
 #define LANCE_OBIO 0x120000
-#define LANCE_IRQ IRQ3
+#define LANCE_IRQ IRQ_AUTO_3
 
 /* Debug level:
  *  0 = silent, print only serious errors
index 22e794071cf41627e48081c5177f7c03a506c68b..7628c2d81f459beffed5296155feb46638933ae2 100644 (file)
@@ -60,9 +60,9 @@
 
 static const char* version = "SDLA driver v0.30, 12 Sep 1996, mike.mclagan@linux.org";
 
-static unsigned int valid_port[] __initdata = { 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390};
+static unsigned int valid_port[] = { 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390};
 
-static unsigned int valid_mem[]  __initdata = {
+static unsigned int valid_mem[] = {
                                    0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, 
                                     0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000,
                                     0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000,
index b2e8e49c865987e42f4a3e9a9d9c0e5f353df1e4..43e521e991264208b0a519dce29155766acf6eb4 100644 (file)
@@ -108,10 +108,10 @@ static int module_load_notify(struct notifier_block * self, unsigned long val, v
                return 0;
 
        /* FIXME: should we process all CPU buffers ? */
-       down(&buffer_sem);
+       mutex_lock(&buffer_mutex);
        add_event_entry(ESCAPE_CODE);
        add_event_entry(MODULE_LOADED_CODE);
-       up(&buffer_sem);
+       mutex_unlock(&buffer_mutex);
 #endif
        return 0;
 }
@@ -501,7 +501,7 @@ void sync_buffer(int cpu)
        sync_buffer_state state = sb_buffer_start;
        unsigned long available;
 
-       down(&buffer_sem);
+       mutex_lock(&buffer_mutex);
  
        add_cpu_switch(cpu);
 
@@ -550,5 +550,5 @@ void sync_buffer(int cpu)
 
        mark_done(cpu);
 
-       up(&buffer_sem);
+       mutex_unlock(&buffer_mutex);
 }
index b80318f0342022fe53827cae6e242a66479d761b..04d641714d347f0f7e00243a5918c5eb7b6d8a6d 100644 (file)
@@ -24,7 +24,7 @@
 #include "event_buffer.h"
 #include "oprofile_stats.h"
 
-DECLARE_MUTEX(buffer_sem);
+DEFINE_MUTEX(buffer_mutex);
  
 static unsigned long buffer_opened;
 static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);
@@ -32,7 +32,7 @@ static unsigned long * event_buffer;
 static unsigned long buffer_size;
 static unsigned long buffer_watershed;
 static size_t buffer_pos;
-/* atomic_t because wait_event checks it outside of buffer_sem */
+/* atomic_t because wait_event checks it outside of buffer_mutex */
 static atomic_t buffer_ready = ATOMIC_INIT(0);
 
 /* Add an entry to the event buffer. When we
@@ -60,10 +60,10 @@ void add_event_entry(unsigned long value)
  */
 void wake_up_buffer_waiter(void)
 {
-       down(&buffer_sem);
+       mutex_lock(&buffer_mutex);
        atomic_set(&buffer_ready, 1);
        wake_up(&buffer_wait);
-       up(&buffer_sem);
+       mutex_unlock(&buffer_mutex);
 }
 
  
@@ -162,7 +162,7 @@ static ssize_t event_buffer_read(struct file * file, char __user * buf,
        if (!atomic_read(&buffer_ready))
                return -EAGAIN;
 
-       down(&buffer_sem);
+       mutex_lock(&buffer_mutex);
 
        atomic_set(&buffer_ready, 0);
 
@@ -177,7 +177,7 @@ static ssize_t event_buffer_read(struct file * file, char __user * buf,
        buffer_pos = 0;
  
 out:
-       up(&buffer_sem);
+       mutex_unlock(&buffer_mutex);
        return retval;
 }
  
index 0180236305992d390715e640b3805ec21bcd94a5..92416276e57702d7321d972d9fb571aa528a19a8 100644 (file)
@@ -11,7 +11,7 @@
 #define EVENT_BUFFER_H
 
 #include <linux/types.h> 
-#include <asm/semaphore.h>
+#include <asm/mutex.h>
  
 int alloc_event_buffer(void);
 
@@ -46,6 +46,6 @@ extern struct file_operations event_buffer_fops;
 /* mutex between sync_cpu_buffers() and the
  * file reading code.
  */
-extern struct semaphore buffer_sem;
+extern struct mutex buffer_mutex;
  
 #endif /* EVENT_BUFFER_H */
index b3f1cd6a24c151943691e074d0d693bc4d4c88f3..e5162a64018b58e6f7133eef49a55fb652f89450 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/init.h>
 #include <linux/oprofile.h>
 #include <linux/moduleparam.h>
-#include <asm/semaphore.h>
+#include <asm/mutex.h>
 
 #include "oprof.h"
 #include "event_buffer.h"
@@ -25,7 +25,7 @@ struct oprofile_operations oprofile_ops;
 unsigned long oprofile_started;
 unsigned long backtrace_depth;
 static unsigned long is_setup;
-static DECLARE_MUTEX(start_sem);
+static DEFINE_MUTEX(start_mutex);
 
 /* timer
    0 - use performance monitoring hardware if available
@@ -37,7 +37,7 @@ int oprofile_setup(void)
 {
        int err;
  
-       down(&start_sem);
+       mutex_lock(&start_mutex);
 
        if ((err = alloc_cpu_buffers()))
                goto out;
@@ -57,7 +57,7 @@ int oprofile_setup(void)
                goto out3;
 
        is_setup = 1;
-       up(&start_sem);
+       mutex_unlock(&start_mutex);
        return 0;
  
 out3:
@@ -68,7 +68,7 @@ out2:
 out1:
        free_cpu_buffers();
 out:
-       up(&start_sem);
+       mutex_unlock(&start_mutex);
        return err;
 }
 
@@ -78,7 +78,7 @@ int oprofile_start(void)
 {
        int err = -EINVAL;
  
-       down(&start_sem);
+       mutex_lock(&start_mutex);
  
        if (!is_setup)
                goto out;
@@ -95,7 +95,7 @@ int oprofile_start(void)
 
        oprofile_started = 1;
 out:
-       up(&start_sem); 
+       mutex_unlock(&start_mutex);
        return err;
 }
 
@@ -103,7 +103,7 @@ out:
 /* echo 0>/dev/oprofile/enable */
 void oprofile_stop(void)
 {
-       down(&start_sem);
+       mutex_lock(&start_mutex);
        if (!oprofile_started)
                goto out;
        oprofile_ops.stop();
@@ -111,20 +111,20 @@ void oprofile_stop(void)
        /* wake up the daemon to read what remains */
        wake_up_buffer_waiter();
 out:
-       up(&start_sem);
+       mutex_unlock(&start_mutex);
 }
 
 
 void oprofile_shutdown(void)
 {
-       down(&start_sem);
+       mutex_lock(&start_mutex);
        sync_stop();
        if (oprofile_ops.shutdown)
                oprofile_ops.shutdown();
        is_setup = 0;
        free_event_buffer();
        free_cpu_buffers();
-       up(&start_sem);
+       mutex_unlock(&start_mutex);
 }
 
 
@@ -132,7 +132,7 @@ int oprofile_set_backtrace(unsigned long val)
 {
        int err = 0;
 
-       down(&start_sem);
+       mutex_lock(&start_mutex);
 
        if (oprofile_started) {
                err = -EBUSY;
@@ -147,7 +147,7 @@ int oprofile_set_backtrace(unsigned long val)
        backtrace_depth = val;
 
 out:
-       up(&start_sem);
+       mutex_unlock(&start_mutex);
        return err;
 }
 
index 4d8dc27ea9d199043c36c85bdad8a3ca507135f8..c7fa28a28b9f0b3dc31ec0f1afefc21c05654c22 100644 (file)
@@ -136,6 +136,18 @@ config PARPORT_SUNBPP
          found on many Sun machines. Note that many of the newer Ultras
          actually have pc style hardware instead.
 
+config PARPORT_AX88796
+       tristate "AX88796 Parallel Port"
+       depends on PARPORT
+       select PARPORT_NOT_PC
+       help
+         Say Y here if you need support for the parallel port hardware on
+         the AX88796 network controller chip. This code is also available
+         as a module (say M), called parport_ax88796.
+
+         The driver is not dependant on the AX88796 network driver, and
+         should not interfere with the networking functions of the chip.
+
 config PARPORT_1284
        bool "IEEE 1284 transfer modes"
        depends on PARPORT
index a19de35f8de262b6ca04ef9ba19c4480c9e364dd..696b8d4ca8878031d8d3825671e74cacb21d8d68 100644 (file)
@@ -17,4 +17,5 @@ obj-$(CONFIG_PARPORT_MFC3)    += parport_mfc3.o
 obj-$(CONFIG_PARPORT_ATARI)    += parport_atari.o
 obj-$(CONFIG_PARPORT_SUNBPP)   += parport_sunbpp.o
 obj-$(CONFIG_PARPORT_GSC)      += parport_gsc.o
-obj-$(CONFIG_PARPORT_IP32)     += parport_ip32.o
+obj-$(CONFIG_PARPORT_AX88796)  += parport_ax88796.o
+obj-$(CONFIG_PARPORT_IP32)     += parport_ip32.o
\ No newline at end of file
index 9ee67321b630b1e727ceacd7ee773aa33fac47c7..fd41e28101eaa4b305230fccdaad77392847ab15 100644 (file)
@@ -283,7 +283,7 @@ void parport_close (struct pardevice *dev)
  *
  *     This tries to locate a device on the given parallel port,
  *     multiplexor port and daisy chain address, and returns its
- *     device number or -NXIO if no device with those coordinates
+ *     device number or %-ENXIO if no device with those coordinates
  *     exists.
  **/
 
diff --git a/drivers/parport/parport_ax88796.c b/drivers/parport/parport_ax88796.c
new file mode 100644 (file)
index 0000000..4baa719
--- /dev/null
@@ -0,0 +1,443 @@
+/* linux/drivers/parport/parport_ax88796.c
+ *
+ * (c) 2005,2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/parport.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#define AX_SPR_BUSY            (1<<7)
+#define AX_SPR_ACK             (1<<6)
+#define AX_SPR_PE              (1<<5)
+#define AX_SPR_SLCT            (1<<4)
+#define AX_SPR_ERR             (1<<3)
+
+#define AX_CPR_nDOE            (1<<5)
+#define AX_CPR_SLCTIN          (1<<3)
+#define AX_CPR_nINIT           (1<<2)
+#define AX_CPR_ATFD            (1<<1)
+#define AX_CPR_STRB            (1<<0)
+
+struct ax_drvdata {
+       struct parport          *parport;
+       struct parport_state     suspend;
+
+       struct device           *dev;
+       struct resource         *io;
+
+       unsigned char            irq_enabled;
+
+       void __iomem            *base;
+       void __iomem            *spp_data;
+       void __iomem            *spp_spr;
+       void __iomem            *spp_cpr;
+};
+
+static inline struct ax_drvdata *pp_to_drv(struct parport *p)
+{
+       return p->private_data;
+}
+
+static unsigned char
+parport_ax88796_read_data(struct parport *p)
+{
+       struct ax_drvdata *dd = pp_to_drv(p);
+
+       return readb(dd->spp_data);
+}
+
+static void
+parport_ax88796_write_data(struct parport *p, unsigned char data)
+{
+       struct ax_drvdata *dd = pp_to_drv(p);
+
+       writeb(data, dd->spp_data);
+}
+
+static unsigned char
+parport_ax88796_read_control(struct parport *p)
+{
+       struct ax_drvdata *dd = pp_to_drv(p);
+       unsigned int cpr = readb(dd->spp_cpr);
+       unsigned int ret = 0;
+
+       if (!(cpr & AX_CPR_STRB))
+               ret |= PARPORT_CONTROL_STROBE;
+
+       if (!(cpr & AX_CPR_ATFD))
+               ret |= PARPORT_CONTROL_AUTOFD;
+
+       if (cpr & AX_CPR_nINIT)
+               ret |= PARPORT_CONTROL_INIT;
+
+       if (!(cpr & AX_CPR_SLCTIN))
+               ret |= PARPORT_CONTROL_SELECT;
+
+       return ret;
+}
+
+static void
+parport_ax88796_write_control(struct parport *p, unsigned char control)
+{
+       struct ax_drvdata *dd = pp_to_drv(p);
+       unsigned int cpr = readb(dd->spp_cpr);
+
+       cpr &= AX_CPR_nDOE;
+
+       if (!(control & PARPORT_CONTROL_STROBE))
+               cpr |= AX_CPR_STRB;
+
+       if (!(control & PARPORT_CONTROL_AUTOFD))
+               cpr |= AX_CPR_ATFD;
+
+       if (control & PARPORT_CONTROL_INIT)
+               cpr |= AX_CPR_nINIT;
+
+       if (!(control & PARPORT_CONTROL_SELECT))
+               cpr |= AX_CPR_SLCTIN;
+
+       dev_dbg(dd->dev, "write_control: ctrl=%02x, cpr=%02x\n", control, cpr);
+       writeb(cpr, dd->spp_cpr);
+
+       if (parport_ax88796_read_control(p) != control) {
+               dev_err(dd->dev, "write_control: read != set (%02x, %02x)\n",
+                       parport_ax88796_read_control(p), control);
+       }
+}
+
+static unsigned char
+parport_ax88796_read_status(struct parport *p)
+{
+       struct ax_drvdata *dd = pp_to_drv(p);
+       unsigned int status = readb(dd->spp_spr);
+       unsigned int ret = 0;
+
+       if (status & AX_SPR_BUSY)
+               ret |= PARPORT_STATUS_BUSY;
+
+       if (status & AX_SPR_ACK)
+               ret |= PARPORT_STATUS_ACK;
+
+       if (status & AX_SPR_ERR)
+               ret |= PARPORT_STATUS_ERROR;
+
+       if (status & AX_SPR_SLCT)
+               ret |= PARPORT_STATUS_SELECT;
+
+       if (status & AX_SPR_PE)
+               ret |= PARPORT_STATUS_PAPEROUT;
+
+       return ret;
+}
+
+static unsigned char
+parport_ax88796_frob_control(struct parport *p, unsigned char mask,
+                            unsigned char val)
+{
+       struct ax_drvdata *dd = pp_to_drv(p);
+       unsigned char old = parport_ax88796_read_control(p);
+
+       dev_dbg(dd->dev, "frob: mask=%02x, val=%02x, old=%02x\n",
+               mask, val, old);
+
+       parport_ax88796_write_control(p, (old & ~mask) | val);
+       return old;
+}
+
+static void
+parport_ax88796_enable_irq(struct parport *p)
+{
+       struct ax_drvdata *dd = pp_to_drv(p);
+       unsigned long flags;
+
+       local_irq_save(flags);
+       if (!dd->irq_enabled) {
+               enable_irq(p->irq);
+               dd->irq_enabled = 1;
+       }
+       local_irq_restore(flags);
+}
+
+static void
+parport_ax88796_disable_irq(struct parport *p)
+{
+       struct ax_drvdata *dd = pp_to_drv(p);
+       unsigned long flags;
+
+       local_irq_save(flags);
+       if (dd->irq_enabled) {
+               disable_irq(p->irq);
+               dd->irq_enabled = 0;
+       }
+       local_irq_restore(flags);
+}
+
+static void
+parport_ax88796_data_forward(struct parport *p)
+{
+       struct ax_drvdata *dd = pp_to_drv(p);
+       void __iomem *cpr = dd->spp_cpr;
+
+       writeb((readb(cpr) & ~AX_CPR_nDOE), cpr);
+}
+
+static void
+parport_ax88796_data_reverse(struct parport *p)
+{
+       struct ax_drvdata *dd = pp_to_drv(p);
+       void __iomem *cpr = dd->spp_cpr;
+
+       writeb(readb(cpr) | AX_CPR_nDOE, cpr);
+}
+
+static void
+parport_ax88796_init_state(struct pardevice *d, struct parport_state *s)
+{
+       struct ax_drvdata *dd = pp_to_drv(d->port);
+
+       memset(s, 0, sizeof(struct parport_state));
+
+       dev_dbg(dd->dev, "init_state: %p: state=%p\n", d, s);
+       s->u.ax88796.cpr = readb(dd->spp_cpr);
+}
+
+static void
+parport_ax88796_save_state(struct parport *p, struct parport_state *s)
+{
+       struct ax_drvdata *dd = pp_to_drv(p);
+
+       dev_dbg(dd->dev, "save_state: %p: state=%p\n", p, s);
+       s->u.ax88796.cpr = readb(dd->spp_cpr);
+}
+
+static void
+parport_ax88796_restore_state(struct parport *p, struct parport_state *s)
+{
+       struct ax_drvdata *dd = pp_to_drv(p);
+
+       dev_dbg(dd->dev, "restore_state: %p: state=%p\n", p, s);
+       writeb(s->u.ax88796.cpr, dd->spp_cpr);
+}
+
+static irqreturn_t
+parport_ax88796_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+        parport_generic_irq(irq, dev_id, regs);
+        return IRQ_HANDLED;
+}
+
+
+static struct parport_operations parport_ax88796_ops = {
+       .write_data     = parport_ax88796_write_data,
+       .read_data      = parport_ax88796_read_data,
+
+       .write_control  = parport_ax88796_write_control,
+       .read_control   = parport_ax88796_read_control,
+       .frob_control   = parport_ax88796_frob_control,
+
+       .read_status    = parport_ax88796_read_status,
+
+       .enable_irq     = parport_ax88796_enable_irq,
+       .disable_irq    = parport_ax88796_disable_irq,
+
+       .data_forward   = parport_ax88796_data_forward,
+       .data_reverse   = parport_ax88796_data_reverse,
+
+       .init_state     = parport_ax88796_init_state,
+       .save_state     = parport_ax88796_save_state,
+       .restore_state  = parport_ax88796_restore_state,
+
+       .epp_write_data = parport_ieee1284_epp_write_data,
+       .epp_read_data  = parport_ieee1284_epp_read_data,
+       .epp_write_addr = parport_ieee1284_epp_write_addr,
+       .epp_read_addr  = parport_ieee1284_epp_read_addr,
+
+       .ecp_write_data = parport_ieee1284_ecp_write_data,
+       .ecp_read_data  = parport_ieee1284_ecp_read_data,
+       .ecp_write_addr = parport_ieee1284_ecp_write_addr,
+
+       .compat_write_data      = parport_ieee1284_write_compat,
+       .nibble_read_data       = parport_ieee1284_read_nibble,
+       .byte_read_data         = parport_ieee1284_read_byte,
+
+       .owner          = THIS_MODULE,
+};
+
+static int parport_ax88796_probe(struct platform_device *pdev)
+{
+       struct device *_dev = &pdev->dev;
+       struct ax_drvdata *dd;
+       struct parport *pp = NULL;
+       struct resource *res;
+       unsigned long size;
+       int spacing;
+       int irq;
+       int ret;
+
+       dd = kzalloc(sizeof(struct ax_drvdata), GFP_KERNEL);
+       if (dd == NULL) {
+               dev_err(_dev, "no memory for private data\n");
+               return -ENOMEM;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(_dev, "no MEM specified\n");
+               ret = -ENXIO;
+               goto exit_mem;
+       }
+
+       size = (res->end - res->start) + 1;
+       spacing = size / 3;
+
+       dd->io = request_mem_region(res->start, size, pdev->name);
+       if (dd->io == NULL) {
+               dev_err(_dev, "cannot reserve memory\n");
+               ret = -ENXIO;
+               goto exit_mem;
+       }
+
+       dd->base = ioremap(res->start, size);
+       if (dd->base == NULL) {
+               dev_err(_dev, "cannot ioremap region\n");
+               ret = -ENXIO;
+               goto exit_res;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0)
+               irq = PARPORT_IRQ_NONE;
+
+       pp = parport_register_port((unsigned long)dd->base, irq,
+                                  PARPORT_DMA_NONE,
+                                  &parport_ax88796_ops);
+
+       if (pp == NULL) {
+               dev_err(_dev, "failed to register parallel port\n");
+               ret = -ENOMEM;
+               goto exit_unmap;
+       }
+
+       pp->private_data = dd;
+       dd->parport = pp;
+       dd->dev = _dev;
+
+       dd->spp_data = dd->base;
+       dd->spp_spr  = dd->base + (spacing * 1);
+       dd->spp_cpr  = dd->base + (spacing * 2);
+
+       /* initialise the port controls */
+       writeb(AX_CPR_STRB, dd->spp_cpr);
+
+       if (irq >= 0) {
+               /* request irq */
+               ret = request_irq(irq, parport_ax88796_interrupt,
+                                 SA_TRIGGER_FALLING, pdev->name, pp);
+
+               if (ret < 0)
+                       goto exit_port;
+
+               dd->irq_enabled = 1;
+       }
+
+       platform_set_drvdata(pdev, pp);
+
+       dev_info(_dev, "attached parallel port driver\n");
+       parport_announce_port(pp);
+
+       return 0;
+
+ exit_port:
+       parport_remove_port(pp);
+ exit_unmap:
+       iounmap(dd->base);
+ exit_res:
+       release_resource(dd->io);
+       kfree(dd->io);
+ exit_mem:
+       kfree(dd);
+       return ret;
+}
+
+static int parport_ax88796_remove(struct platform_device *pdev)
+{
+       struct parport *p = platform_get_drvdata(pdev);
+       struct ax_drvdata *dd = pp_to_drv(p);
+
+       free_irq(p->irq, p);
+       parport_remove_port(p);
+       iounmap(dd->base);
+       release_resource(dd->io);
+       kfree(dd->io);
+       kfree(dd);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int parport_ax88796_suspend(struct platform_device *dev,
+                                  pm_message_t state)
+{
+       struct parport *p = platform_get_drvdata(dev);
+       struct ax_drvdata *dd = pp_to_drv(p);
+
+       parport_ax88796_save_state(p, &dd->suspend);
+       writeb(AX_CPR_nDOE | AX_CPR_STRB, dd->spp_cpr);
+       return 0;
+}
+
+static int parport_ax88796_resume(struct platform_device *dev)
+{
+       struct parport *p = platform_get_drvdata(dev);
+       struct ax_drvdata *dd = pp_to_drv(p);
+
+       parport_ax88796_restore_state(p, &dd->suspend);
+       return 0;
+}
+
+#else
+#define parport_ax88796_suspend NULL
+#define parport_ax88796_resume  NULL
+#endif
+
+static struct platform_driver axdrv = {
+       .driver         = {
+               .name   = "ax88796-pp",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = parport_ax88796_probe,
+       .remove         = parport_ax88796_remove,
+       .suspend        = parport_ax88796_suspend,
+       .resume         = parport_ax88796_resume,
+};
+
+static int __init parport_ax88796_init(void)
+{
+       return platform_driver_register(&axdrv);
+}
+
+static void __exit parport_ax88796_exit(void)
+{
+       platform_driver_unregister(&axdrv);
+}
+
+module_init(parport_ax88796_init)
+module_exit(parport_ax88796_exit)
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("AX88796 Parport parallel port driver");
+MODULE_LICENSE("GPL");
index bbbfd79adbafc84788d02003703e4238d15735ba..2cb22c8d3357fbe4922a54a613c9aec116265029 100644 (file)
@@ -218,7 +218,7 @@ static void free_port (struct parport *port)
  *     parport_get_port - increment a port's reference count
  *     @port: the port
  *
- *     This ensure's that a struct parport pointer remains valid
+ *     This ensures that a struct parport pointer remains valid
  *     until the matching parport_put_port() call.
  **/
 
index bb19c64073c6ddd8e8544de2c773e846e1235349..0b4adcb60df4060db26bbaef9e6a6c26dc40ff3b 100644 (file)
@@ -60,30 +60,34 @@ static void card_remove_first(struct pnp_dev * dev)
        card_remove(dev);
 }
 
-static int card_probe(struct pnp_card * card, struct pnp_card_driver * drv)
+static int card_probe(struct pnp_card *card, struct pnp_card_driver *drv)
 {
-       const struct pnp_card_device_id *id = match_card(drv,card);
-       if (id) {
-               struct pnp_card_link * clink = pnp_alloc(sizeof(struct pnp_card_link));
-               if (!clink)
-                       return 0;
-               clink->card = card;
-               clink->driver = drv;
-               clink->pm_state = PMSG_ON;
-               if (drv->probe) {
-                       if (drv->probe(clink, id)>=0)
-                               return 1;
-                       else {
-                               struct pnp_dev * dev;
-                               card_for_each_dev(card, dev) {
-                                       if (dev->card_link == clink)
-                                               pnp_release_card_device(dev);
-                               }
-                               kfree(clink);
-                       }
-               } else
-                       return 1;
+       const struct pnp_card_device_id *id;
+       struct pnp_card_link *clink;
+       struct pnp_dev *dev;
+
+       if (!drv->probe)
+               return 0;
+       id = match_card(drv,card);
+       if (!id)
+               return 0;
+
+       clink = pnp_alloc(sizeof(*clink));
+       if (!clink)
+               return 0;
+       clink->card = card;
+       clink->driver = drv;
+       clink->pm_state = PMSG_ON;
+
+       if (drv->probe(clink, id) >= 0)
+               return 1;
+
+       /* Recovery */
+       card_for_each_dev(card, dev) {
+               if (dev->card_link == clink)
+                       pnp_release_card_device(dev);
        }
+       kfree(clink);
        return 0;
 }
 
index 65d090dbef460e70ccb4aae266e08ff8ba7576c7..bccff400b198d6e0da250fd483a551ad60d992bd 100644 (file)
@@ -73,6 +73,13 @@ config RTC_INTF_DEV
          This driver can also be built as a module. If so, the module
          will be called rtc-dev.
 
+config RTC_INTF_DEV_UIE_EMUL
+       bool "RTC UIE emulation on dev interface"
+       depends on RTC_INTF_DEV
+       help
+         Provides an emulation for RTC_UIE if the underlaying rtc chip
+         driver did not provide RTC_UIE ioctls.
+
 comment "RTC drivers"
        depends on RTC_CLASS
 
@@ -86,6 +93,34 @@ config RTC_DRV_X1205
          This driver can also be built as a module. If so, the module
          will be called rtc-x1205.
 
+config RTC_DRV_DS1307
+       tristate "Dallas/Maxim DS1307 and similar I2C RTC chips"
+       depends on RTC_CLASS && I2C
+       help
+         If you say yes here you get support for various compatible RTC
+         chips (often with battery backup) connected with I2C.  This driver
+         should handle DS1307, DS1337, DS1338, DS1339, DS1340, ST M41T00,
+         and probably other chips.  In some cases the RTC must already
+         have been initialized (by manufacturing or a bootloader).
+
+         The first seven registers on these chips hold an RTC, and other
+         registers may add features such as NVRAM, a trickle charger for
+         the RTC/NVRAM backup power, and alarms.  This driver may not
+         expose all those available chip features.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-ds1307.
+
+config RTC_DRV_DS1553
+       tristate "Dallas DS1553"
+       depends on RTC_CLASS
+       help
+         If you say yes here you get support for the
+         Dallas DS1553 timekeeping chip.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-ds1553.
+
 config RTC_DRV_DS1672
        tristate "Dallas/Maxim DS1672"
        depends on RTC_CLASS && I2C
@@ -96,6 +131,16 @@ config RTC_DRV_DS1672
          This driver can also be built as a module. If so, the module
          will be called rtc-ds1672.
 
+config RTC_DRV_DS1742
+       tristate "Dallas DS1742"
+       depends on RTC_CLASS
+       help
+         If you say yes here you get support for the
+         Dallas DS1742 timekeeping chip.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-ds1742.
+
 config RTC_DRV_PCF8563
        tristate "Philips PCF8563/Epson RTC8564"
        depends on RTC_CLASS && I2C
@@ -107,6 +152,16 @@ config RTC_DRV_PCF8563
          This driver can also be built as a module. If so, the module
          will be called rtc-pcf8563.
 
+config RTC_DRV_PCF8583
+       tristate "Philips PCF8583"
+       depends on RTC_CLASS && I2C
+       help
+         If you say yes here you get support for the
+         Philips PCF8583 RTC chip.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-pcf8583.
+
 config RTC_DRV_RS5C372
        tristate "Ricoh RS5C372A/B"
        depends on RTC_CLASS && I2C
@@ -157,6 +212,22 @@ config RTC_DRV_VR41XX
          To compile this driver as a module, choose M here: the
          module will be called rtc-vr41xx.
 
+config RTC_DRV_PL031
+       tristate "ARM AMBA PL031 RTC"
+       depends on RTC_CLASS && ARM_AMBA
+       help
+         If you say Y here you will get access to ARM AMBA
+         PrimeCell PL031 UART found on certain ARM SOCs.
+
+         To compile this driver as a module, choose M here: the
+         module will be called rtc-pl031.
+
+config RTC_DRV_AT91
+       tristate "AT91RM9200"
+       depends on RTC_CLASS && ARCH_AT91RM9200
+       help
+         Driver for the Atmel AT91RM9200's internal RTC (Realtime Clock).
+
 config RTC_DRV_TEST
        tristate "Test driver/device"
        depends on RTC_CLASS
@@ -172,4 +243,24 @@ config RTC_DRV_TEST
          This driver can also be built as a module. If so, the module
          will be called rtc-test.
 
+config RTC_DRV_MAX6902
+       tristate "Maxim 6902"
+       depends on RTC_CLASS && SPI
+       help
+         If you say yes here you will get support for the
+         Maxim MAX6902 spi RTC chip.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-max6902.
+
+config RTC_DRV_V3020
+       tristate "EM Microelectronic V3020"
+       depends on RTC_CLASS
+       help
+         If you say yes here you will get support for the
+         EM Microelectronic v3020 RTC chip.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-v3020.
+
 endmenu
index a9ca0f1716868154f9e5419754864543108f07e6..900d210dd1a24e017b46801251b5bdcea46e4407 100644 (file)
@@ -13,10 +13,18 @@ obj-$(CONFIG_RTC_INTF_DEV)  += rtc-dev.o
 
 obj-$(CONFIG_RTC_DRV_X1205)    += rtc-x1205.o
 obj-$(CONFIG_RTC_DRV_TEST)     += rtc-test.o
+obj-$(CONFIG_RTC_DRV_DS1307)   += rtc-ds1307.o
 obj-$(CONFIG_RTC_DRV_DS1672)   += rtc-ds1672.o
+obj-$(CONFIG_RTC_DRV_DS1742)   += rtc-ds1742.o
 obj-$(CONFIG_RTC_DRV_PCF8563)  += rtc-pcf8563.o
+obj-$(CONFIG_RTC_DRV_PCF8583)  += rtc-pcf8583.o
 obj-$(CONFIG_RTC_DRV_RS5C372)  += rtc-rs5c372.o
 obj-$(CONFIG_RTC_DRV_M48T86)   += rtc-m48t86.o
+obj-$(CONFIG_RTC_DRV_DS1553)   += rtc-ds1553.o
 obj-$(CONFIG_RTC_DRV_EP93XX)   += rtc-ep93xx.o
 obj-$(CONFIG_RTC_DRV_SA1100)   += rtc-sa1100.o
 obj-$(CONFIG_RTC_DRV_VR41XX)   += rtc-vr41xx.o
+obj-$(CONFIG_RTC_DRV_PL031)    += rtc-pl031.o
+obj-$(CONFIG_RTC_DRV_MAX6902)  += rtc-max6902.o
+obj-$(CONFIG_RTC_DRV_V3020)    += rtc-v3020.o
+obj-$(CONFIG_RTC_DRV_AT91)     += rtc-at91.o
index 413c7d54ea10f19b9eeb5fa695b21b8ab7f11c66..5396beec30d0ca62b3d97a0c73c0ac66cb8ceccc 100644 (file)
@@ -69,6 +69,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
        rtc->id = id;
        rtc->ops = ops;
        rtc->owner = owner;
+       rtc->max_user_freq = 64;
        rtc->class_dev.dev = dev;
        rtc->class_dev.class = rtc_class;
        rtc->class_dev.release = rtc_device_release;
index 56e490709b87582fff3aaae2f17c43c7f9980a35..579cd667b16f91a116c988c6a0835f4fdc85673b 100644 (file)
@@ -229,6 +229,9 @@ int rtc_irq_set_state(struct class_device *class_dev, struct rtc_task *task, int
        unsigned long flags;
        struct rtc_device *rtc = to_rtc_device(class_dev);
 
+       if (rtc->ops->irq_set_state == NULL)
+               return -ENXIO;
+
        spin_lock_irqsave(&rtc->irq_task_lock, flags);
        if (rtc->irq_task != task)
                err = -ENXIO;
@@ -243,25 +246,12 @@ EXPORT_SYMBOL_GPL(rtc_irq_set_state);
 
 int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int freq)
 {
-       int err = 0, tmp = 0;
+       int err = 0;
        unsigned long flags;
        struct rtc_device *rtc = to_rtc_device(class_dev);
 
-       /* allowed range is 2-8192 */
-       if (freq < 2 || freq > 8192)
-               return -EINVAL;
-/*
-       FIXME: this does not belong here, will move where appropriate
-       at a later stage. It cannot hurt right now, trust me :)
-       if ((freq > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE)))
-               return -EACCES;
-*/
-       /* check if freq is a power of 2 */
-       while (freq > (1 << tmp))
-               tmp++;
-
-       if (freq != (1 << tmp))
-               return -EINVAL;
+       if (rtc->ops->irq_set_freq == NULL)
+               return -ENXIO;
 
        spin_lock_irqsave(&rtc->irq_task_lock, flags);
        if (rtc->irq_task != task)
diff --git a/drivers/rtc/rtc-at91.c b/drivers/rtc/rtc-at91.c
new file mode 100644 (file)
index 0000000..b676f44
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ *     Real Time Clock interface for Linux on Atmel AT91RM9200
+ *
+ *     Copyright (C) 2002 Rick Bronson
+ *
+ *     Converted to RTC class model by Andrew Victor
+ *
+ *     Ported to Linux 2.6 by Steven Scholz
+ *     Based on s3c2410-rtc.c Simtec Electronics
+ *
+ *     Based on sa1100-rtc.c by Nils Faerber
+ *     Based on rtc.c by Paul Gortmaker
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the 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/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/completion.h>
+
+#include <asm/uaccess.h>
+#include <asm/rtc.h>
+
+#include <asm/mach/time.h>
+
+
+#define AT91_RTC_FREQ          1
+#define AT91_RTC_EPOCH         1900UL  /* just like arch/arm/common/rtctime.c */
+
+static DECLARE_COMPLETION(at91_rtc_updated);
+static unsigned int at91_alarm_year = AT91_RTC_EPOCH;
+
+/*
+ * Decode time/date into rtc_time structure
+ */
+static void at91_rtc_decodetime(unsigned int timereg, unsigned int calreg,
+                               struct rtc_time *tm)
+{
+       unsigned int time, date;
+
+       /* must read twice in case it changes */
+       do {
+               time = at91_sys_read(timereg);
+               date = at91_sys_read(calreg);
+       } while ((time != at91_sys_read(timereg)) ||
+                       (date != at91_sys_read(calreg)));
+
+       tm->tm_sec  = BCD2BIN((time & AT91_RTC_SEC) >> 0);
+       tm->tm_min  = BCD2BIN((time & AT91_RTC_MIN) >> 8);
+       tm->tm_hour = BCD2BIN((time & AT91_RTC_HOUR) >> 16);
+
+       /*
+        * The Calendar Alarm register does not have a field for
+        * the year - so these will return an invalid value.  When an
+        * alarm is set, at91_alarm_year wille store the current year.
+        */
+       tm->tm_year  = BCD2BIN(date & AT91_RTC_CENT) * 100;     /* century */
+       tm->tm_year += BCD2BIN((date & AT91_RTC_YEAR) >> 8);    /* year */
+
+       tm->tm_wday = BCD2BIN((date & AT91_RTC_DAY) >> 21) - 1; /* day of the week [0-6], Sunday=0 */
+       tm->tm_mon  = BCD2BIN((date & AT91_RTC_MONTH) >> 16) - 1;
+       tm->tm_mday = BCD2BIN((date & AT91_RTC_DATE) >> 24);
+}
+
+/*
+ * Read current time and date in RTC
+ */
+static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
+{
+       at91_rtc_decodetime(AT91_RTC_TIMR, AT91_RTC_CALR, tm);
+       tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
+       tm->tm_year = tm->tm_year - 1900;
+
+       pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+               1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+               tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+       return 0;
+}
+
+/*
+ * Set current time and date in RTC
+ */
+static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
+{
+       unsigned long cr;
+
+       pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+               1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+               tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+       /* Stop Time/Calendar from counting */
+       cr = at91_sys_read(AT91_RTC_CR);
+       at91_sys_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM);
+
+       at91_sys_write(AT91_RTC_IER, AT91_RTC_ACKUPD);
+       wait_for_completion(&at91_rtc_updated); /* wait for ACKUPD interrupt */
+       at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD);
+
+       at91_sys_write(AT91_RTC_TIMR,
+                         BIN2BCD(tm->tm_sec) << 0
+                       | BIN2BCD(tm->tm_min) << 8
+                       | BIN2BCD(tm->tm_hour) << 16);
+
+       at91_sys_write(AT91_RTC_CALR,
+                         BIN2BCD((tm->tm_year + 1900) / 100)   /* century */
+                       | BIN2BCD(tm->tm_year % 100) << 8       /* year */
+                       | BIN2BCD(tm->tm_mon + 1) << 16         /* tm_mon starts at zero */
+                       | BIN2BCD(tm->tm_wday + 1) << 21        /* day of the week [0-6], Sunday=0 */
+                       | BIN2BCD(tm->tm_mday) << 24);
+
+       /* Restart Time/Calendar */
+       cr = at91_sys_read(AT91_RTC_CR);
+       at91_sys_write(AT91_RTC_CR, cr & ~(AT91_RTC_UPDCAL | AT91_RTC_UPDTIM));
+
+       return 0;
+}
+
+/*
+ * Read alarm time and date in RTC
+ */
+static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct rtc_time *tm = &alrm->time;
+
+       at91_rtc_decodetime(AT91_RTC_TIMALR, AT91_RTC_CALALR, tm);
+       tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
+       tm->tm_year = at91_alarm_year - 1900;
+
+       pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+               1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+               tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+       return 0;
+}
+
+/*
+ * Set alarm time and date in RTC
+ */
+static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct rtc_time tm;
+
+       at91_rtc_decodetime(AT91_RTC_TIMR, AT91_RTC_CALR, &tm);
+
+       at91_alarm_year = tm.tm_year;
+
+       tm.tm_hour = alrm->time.tm_hour;
+       tm.tm_min = alrm->time.tm_min;
+       tm.tm_sec = alrm->time.tm_sec;
+
+       at91_sys_write(AT91_RTC_TIMALR,
+                 BIN2BCD(tm.tm_sec) << 0
+               | BIN2BCD(tm.tm_min) << 8
+               | BIN2BCD(tm.tm_hour) << 16
+               | AT91_RTC_HOUREN | AT91_RTC_MINEN | AT91_RTC_SECEN);
+       at91_sys_write(AT91_RTC_CALALR,
+                 BIN2BCD(tm.tm_mon + 1) << 16          /* tm_mon starts at zero */
+               | BIN2BCD(tm.tm_mday) << 24
+               | AT91_RTC_DATEEN | AT91_RTC_MTHEN);
+
+       pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+               at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
+               tm.tm_min, tm.tm_sec);
+
+       return 0;
+}
+
+/*
+ * Handle commands from user-space
+ */
+static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
+                       unsigned long arg)
+{
+       int ret = 0;
+
+       pr_debug("%s(): cmd=%08x, arg=%08lx.\n", __FUNCTION__, cmd, arg);
+
+       switch (cmd) {
+       case RTC_AIE_OFF:       /* alarm off */
+               at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM);
+               break;
+       case RTC_AIE_ON:        /* alarm on */
+               at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM);
+               break;
+       case RTC_UIE_OFF:       /* update off */
+       case RTC_PIE_OFF:       /* periodic off */
+               at91_sys_write(AT91_RTC_IDR, AT91_RTC_SECEV);
+               break;
+       case RTC_UIE_ON:        /* update on */
+       case RTC_PIE_ON:        /* periodic on */
+               at91_sys_write(AT91_RTC_IER, AT91_RTC_SECEV);
+               break;
+       case RTC_IRQP_READ:     /* read periodic alarm frequency */
+               ret = put_user(AT91_RTC_FREQ, (unsigned long *) arg);
+               break;
+       case RTC_IRQP_SET:      /* set periodic alarm frequency */
+               if (arg != AT91_RTC_FREQ)
+                       ret = -EINVAL;
+               break;
+       default:
+               ret = -ENOIOCTLCMD;
+               break;
+       }
+
+       return ret;
+}
+
+/*
+ * Provide additional RTC information in /proc/driver/rtc
+ */
+static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+       unsigned long imr = at91_sys_read(AT91_RTC_IMR);
+
+       seq_printf(seq, "alarm_IRQ\t: %s\n",
+                       (imr & AT91_RTC_ALARM) ? "yes" : "no");
+       seq_printf(seq, "update_IRQ\t: %s\n",
+                       (imr & AT91_RTC_ACKUPD) ? "yes" : "no");
+       seq_printf(seq, "periodic_IRQ\t: %s\n",
+                       (imr & AT91_RTC_SECEV) ? "yes" : "no");
+       seq_printf(seq, "periodic_freq\t: %ld\n",
+                       (unsigned long) AT91_RTC_FREQ);
+
+       return 0;
+}
+
+/*
+ * IRQ handler for the RTC
+ */
+static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id,
+                                       struct pt_regs *regs)
+{
+       struct platform_device *pdev = dev_id;
+       struct rtc_device *rtc = platform_get_drvdata(pdev);
+       unsigned int rtsr;
+       unsigned long events = 0;
+
+       rtsr = at91_sys_read(AT91_RTC_SR) & at91_sys_read(AT91_RTC_IMR);
+       if (rtsr) {             /* this interrupt is shared!  Is it ours? */
+               if (rtsr & AT91_RTC_ALARM)
+                       events |= (RTC_AF | RTC_IRQF);
+               if (rtsr & AT91_RTC_SECEV)
+                       events |= (RTC_UF | RTC_IRQF);
+               if (rtsr & AT91_RTC_ACKUPD)
+                       complete(&at91_rtc_updated);
+
+               at91_sys_write(AT91_RTC_SCCR, rtsr);    /* clear status reg */
+
+               rtc_update_irq(&rtc->class_dev, 1, events);
+
+               pr_debug("%s(): num=%ld, events=0x%02lx\n", __FUNCTION__,
+                       events >> 8, events & 0x000000FF);
+
+               return IRQ_HANDLED;
+       }
+       return IRQ_NONE;                /* not handled */
+}
+
+static struct rtc_class_ops at91_rtc_ops = {
+       .ioctl          = at91_rtc_ioctl,
+       .read_time      = at91_rtc_readtime,
+       .set_time       = at91_rtc_settime,
+       .read_alarm     = at91_rtc_readalarm,
+       .set_alarm      = at91_rtc_setalarm,
+       .proc           = at91_rtc_proc,
+};
+
+/*
+ * Initialize and install RTC driver
+ */
+static int __init at91_rtc_probe(struct platform_device *pdev)
+{
+       struct rtc_device *rtc;
+       int ret;
+
+       at91_sys_write(AT91_RTC_CR, 0);
+       at91_sys_write(AT91_RTC_MR, 0);         /* 24 hour mode */
+
+       /* Disable all interrupts */
+       at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
+                                       AT91_RTC_SECEV | AT91_RTC_TIMEV |
+                                       AT91_RTC_CALEV);
+
+       ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt,
+                               SA_SHIRQ, "at91_rtc", pdev);
+       if (ret) {
+               printk(KERN_ERR "at91_rtc: IRQ %d already in use.\n",
+                               AT91_ID_SYS);
+               return ret;
+       }
+
+       rtc = rtc_device_register(pdev->name, &pdev->dev,
+                               &at91_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc)) {
+               free_irq(AT91_ID_SYS, pdev);
+               return PTR_ERR(rtc);
+       }
+       platform_set_drvdata(pdev, rtc);
+
+       printk(KERN_INFO "AT91 Real Time Clock driver.\n");
+       return 0;
+}
+
+/*
+ * Disable and remove the RTC driver
+ */
+static int __devexit at91_rtc_remove(struct platform_device *pdev)
+{
+       struct rtc_device *rtc = platform_get_drvdata(pdev);
+
+       /* Disable all interrupts */
+       at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
+                                       AT91_RTC_SECEV | AT91_RTC_TIMEV |
+                                       AT91_RTC_CALEV);
+       free_irq(AT91_ID_SYS, pdev);
+
+       rtc_device_unregister(rtc);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+/* AT91RM9200 RTC Power management control */
+
+static struct timespec at91_rtc_delta;
+
+static int at91_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct rtc_time tm;
+       struct timespec time;
+
+       time.tv_nsec = 0;
+
+       /* calculate time delta for suspend */
+       at91_rtc_readtime(&pdev->dev, &tm);
+       rtc_tm_to_time(&tm, &time.tv_sec);
+       save_time_delta(&at91_rtc_delta, &time);
+
+       pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+               1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
+               tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+       return 0;
+}
+
+static int at91_rtc_resume(struct platform_device *pdev)
+{
+       struct rtc_time tm;
+       struct timespec time;
+
+       time.tv_nsec = 0;
+
+       at91_rtc_readtime(&pdev->dev, &tm);
+       rtc_tm_to_time(&tm, &time.tv_sec);
+       restore_time_delta(&at91_rtc_delta, &time);
+
+       pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+               1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
+               tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+       return 0;
+}
+#else
+#define at91_rtc_suspend NULL
+#define at91_rtc_resume  NULL
+#endif
+
+static struct platform_driver at91_rtc_driver = {
+       .probe          = at91_rtc_probe,
+       .remove         = at91_rtc_remove,
+       .suspend        = at91_rtc_suspend,
+       .resume         = at91_rtc_resume,
+       .driver         = {
+               .name   = "at91_rtc",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init at91_rtc_init(void)
+{
+       return platform_driver_register(&at91_rtc_driver);
+}
+
+static void __exit at91_rtc_exit(void)
+{
+       platform_driver_unregister(&at91_rtc_driver);
+}
+
+module_init(at91_rtc_init);
+module_exit(at91_rtc_exit);
+
+MODULE_AUTHOR("Rick Bronson");
+MODULE_DESCRIPTION("RTC driver for Atmel AT91RM9200");
+MODULE_LICENSE("GPL");
index 2011567005f99a55b5072b1b7600fc616a1bd5a7..61a58259c93fe04ed5a502435763a921f3d57cc5 100644 (file)
@@ -48,6 +48,93 @@ static int rtc_dev_open(struct inode *inode, struct file *file)
        return err;
 }
 
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+/*
+ * Routine to poll RTC seconds field for change as often as possible,
+ * after first RTC_UIE use timer to reduce polling
+ */
+static void rtc_uie_task(void *data)
+{
+       struct rtc_device *rtc = data;
+       struct rtc_time tm;
+       int num = 0;
+       int err;
+
+       err = rtc_read_time(&rtc->class_dev, &tm);
+       spin_lock_irq(&rtc->irq_lock);
+       if (rtc->stop_uie_polling || err) {
+               rtc->uie_task_active = 0;
+       } else if (rtc->oldsecs != tm.tm_sec) {
+               num = (tm.tm_sec + 60 - rtc->oldsecs) % 60;
+               rtc->oldsecs = tm.tm_sec;
+               rtc->uie_timer.expires = jiffies + HZ - (HZ/10);
+               rtc->uie_timer_active = 1;
+               rtc->uie_task_active = 0;
+               add_timer(&rtc->uie_timer);
+       } else if (schedule_work(&rtc->uie_task) == 0) {
+               rtc->uie_task_active = 0;
+       }
+       spin_unlock_irq(&rtc->irq_lock);
+       if (num)
+               rtc_update_irq(&rtc->class_dev, num, RTC_UF | RTC_IRQF);
+}
+
+static void rtc_uie_timer(unsigned long data)
+{
+       struct rtc_device *rtc = (struct rtc_device *)data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rtc->irq_lock, flags);
+       rtc->uie_timer_active = 0;
+       rtc->uie_task_active = 1;
+       if ((schedule_work(&rtc->uie_task) == 0))
+               rtc->uie_task_active = 0;
+       spin_unlock_irqrestore(&rtc->irq_lock, flags);
+}
+
+static void clear_uie(struct rtc_device *rtc)
+{
+       spin_lock_irq(&rtc->irq_lock);
+       if (rtc->irq_active) {
+               rtc->stop_uie_polling = 1;
+               if (rtc->uie_timer_active) {
+                       spin_unlock_irq(&rtc->irq_lock);
+                       del_timer_sync(&rtc->uie_timer);
+                       spin_lock_irq(&rtc->irq_lock);
+                       rtc->uie_timer_active = 0;
+               }
+               if (rtc->uie_task_active) {
+                       spin_unlock_irq(&rtc->irq_lock);
+                       flush_scheduled_work();
+                       spin_lock_irq(&rtc->irq_lock);
+               }
+               rtc->irq_active = 0;
+       }
+       spin_unlock_irq(&rtc->irq_lock);
+}
+
+static int set_uie(struct rtc_device *rtc)
+{
+       struct rtc_time tm;
+       int err;
+
+       err = rtc_read_time(&rtc->class_dev, &tm);
+       if (err)
+               return err;
+       spin_lock_irq(&rtc->irq_lock);
+       if (!rtc->irq_active) {
+               rtc->irq_active = 1;
+               rtc->stop_uie_polling = 0;
+               rtc->oldsecs = tm.tm_sec;
+               rtc->uie_task_active = 1;
+               if (schedule_work(&rtc->uie_task) == 0)
+                       rtc->uie_task_active = 0;
+       }
+       rtc->irq_data = 0;
+       spin_unlock_irq(&rtc->irq_lock);
+       return 0;
+}
+#endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */
 
 static ssize_t
 rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
@@ -127,6 +214,28 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
        struct rtc_wkalrm alarm;
        void __user *uarg = (void __user *) arg;
 
+       /* check that the calles has appropriate permissions
+        * for certain ioctls. doing this check here is useful
+        * to avoid duplicate code in each driver.
+        */
+       switch (cmd) {
+       case RTC_EPOCH_SET:
+       case RTC_SET_TIME:
+               if (!capable(CAP_SYS_TIME))
+                       return -EACCES;
+               break;
+
+       case RTC_IRQP_SET:
+               if (arg > rtc->max_user_freq && !capable(CAP_SYS_RESOURCE))
+                       return -EACCES;
+               break;
+
+       case RTC_PIE_ON:
+               if (!capable(CAP_SYS_RESOURCE))
+                       return -EACCES;
+               break;
+       }
+
        /* avoid conflicting IRQ users */
        if (cmd == RTC_PIE_ON || cmd == RTC_PIE_OFF || cmd == RTC_IRQP_SET) {
                spin_lock(&rtc->irq_task_lock);
@@ -185,9 +294,6 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
                break;
 
        case RTC_SET_TIME:
-               if (!capable(CAP_SYS_TIME))
-                       return -EACCES;
-
                if (copy_from_user(&tm, uarg, sizeof(tm)))
                        return -EFAULT;
 
@@ -203,10 +309,6 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
                        err = -EINVAL;
                        break;
                }
-               if (!capable(CAP_SYS_TIME)) {
-                       err = -EACCES;
-                       break;
-               }
                rtc_epoch = arg;
                err = 0;
 #endif
@@ -232,6 +334,14 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
                        return -EFAULT;
                break;
 
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+       case RTC_UIE_OFF:
+               clear_uie(rtc);
+               return 0;
+
+       case RTC_UIE_ON:
+               return set_uie(rtc);
+#endif
        default:
                err = -ENOTTY;
                break;
@@ -244,6 +354,9 @@ static int rtc_dev_release(struct inode *inode, struct file *file)
 {
        struct rtc_device *rtc = to_rtc_device(file->private_data);
 
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+       clear_uie(rtc);
+#endif
        if (rtc->ops->release)
                rtc->ops->release(rtc->class_dev.dev);
 
@@ -284,6 +397,10 @@ static int rtc_dev_add_device(struct class_device *class_dev,
        mutex_init(&rtc->char_lock);
        spin_lock_init(&rtc->irq_lock);
        init_waitqueue_head(&rtc->irq_queue);
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+       INIT_WORK(&rtc->uie_task, rtc_uie_task, rtc);
+       setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);
+#endif
 
        cdev_init(&rtc->char_dev, &rtc_dev_fops);
        rtc->char_dev.owner = rtc->owner;
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
new file mode 100644 (file)
index 0000000..e8afb93
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * rtc-ds1307.c - RTC driver for some mostly-compatible I2C chips.
+ *
+ *  Copyright (C) 2005 James Chapman (ds1337 core)
+ *  Copyright (C) 2006 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/string.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+
+
+/* We can't determine type by probing, but if we expect pre-Linux code
+ * to have set the chip up as a clock (turning on the oscillator and
+ * setting the date and time), Linux can ignore the non-clock features.
+ * That's a natural job for a factory or repair bench.
+ *
+ * If the I2C "force" mechanism is used, we assume the chip is a ds1337.
+ * (Much better would be board-specific tables of I2C devices, along with
+ * the platform_data drivers would use to sort such issues out.)
+ */
+enum ds_type {
+       unknown = 0,
+       ds_1307,                /* or ds1338, ... */
+       ds_1337,                /* or ds1339, ... */
+       ds_1340,                /* or st m41t00, ... */
+       // rs5c372 too?  different address...
+};
+
+static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+
+
+
+/* RTC registers don't differ much, except for the century flag */
+#define DS1307_REG_SECS                0x00    /* 00-59 */
+#      define DS1307_BIT_CH            0x80
+#define DS1307_REG_MIN         0x01    /* 00-59 */
+#define DS1307_REG_HOUR                0x02    /* 00-23, or 1-12{am,pm} */
+#      define DS1340_BIT_CENTURY_EN    0x80    /* in REG_HOUR */
+#      define DS1340_BIT_CENTURY       0x40    /* in REG_HOUR */
+#define DS1307_REG_WDAY                0x03    /* 01-07 */
+#define DS1307_REG_MDAY                0x04    /* 01-31 */
+#define DS1307_REG_MONTH       0x05    /* 01-12 */
+#      define DS1337_BIT_CENTURY       0x80    /* in REG_MONTH */
+#define DS1307_REG_YEAR                0x06    /* 00-99 */
+
+/* Other registers (control, status, alarms, trickle charge, NVRAM, etc)
+ * start at 7, and they differ a lot. Only control and status matter for RTC;
+ * be careful using them.
+ */
+#define DS1307_REG_CONTROL     0x07
+#      define DS1307_BIT_OUT           0x80
+#      define DS1307_BIT_SQWE          0x10
+#      define DS1307_BIT_RS1           0x02
+#      define DS1307_BIT_RS0           0x01
+#define DS1337_REG_CONTROL     0x0e
+#      define DS1337_BIT_nEOSC         0x80
+#      define DS1337_BIT_RS2           0x10
+#      define DS1337_BIT_RS1           0x08
+#      define DS1337_BIT_INTCN         0x04
+#      define DS1337_BIT_A2IE          0x02
+#      define DS1337_BIT_A1IE          0x01
+#define DS1337_REG_STATUS      0x0f
+#      define DS1337_BIT_OSF           0x80
+#      define DS1337_BIT_A2I           0x02
+#      define DS1337_BIT_A1I           0x01
+#define DS1339_REG_TRICKLE     0x10
+
+
+
+struct ds1307 {
+       u8                      reg_addr;
+       u8                      regs[8];
+       enum ds_type            type;
+       struct i2c_msg          msg[2];
+       struct i2c_client       client;
+       struct rtc_device       *rtc;
+};
+
+
+static int ds1307_get_time(struct device *dev, struct rtc_time *t)
+{
+       struct ds1307   *ds1307 = dev_get_drvdata(dev);
+       int             tmp;
+
+       /* read the RTC registers all at once */
+       ds1307->msg[1].flags = I2C_M_RD;
+       ds1307->msg[1].len = 7;
+
+       tmp = i2c_transfer(ds1307->client.adapter, ds1307->msg, 2);
+       if (tmp != 2) {
+               dev_err(dev, "%s error %d\n", "read", tmp);
+               return -EIO;
+       }
+
+       dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
+                       "read",
+                       ds1307->regs[0], ds1307->regs[1],
+                       ds1307->regs[2], ds1307->regs[3],
+                       ds1307->regs[4], ds1307->regs[5],
+                       ds1307->regs[6]);
+
+       t->tm_sec = BCD2BIN(ds1307->regs[DS1307_REG_SECS] & 0x7f);
+       t->tm_min = BCD2BIN(ds1307->regs[DS1307_REG_MIN] & 0x7f);
+       tmp = ds1307->regs[DS1307_REG_HOUR] & 0x3f;
+       t->tm_hour = BCD2BIN(tmp);
+       t->tm_wday = BCD2BIN(ds1307->regs[DS1307_REG_WDAY] & 0x07) - 1;
+       t->tm_mday = BCD2BIN(ds1307->regs[DS1307_REG_MDAY] & 0x3f);
+       tmp = ds1307->regs[DS1307_REG_MONTH] & 0x1f;
+       t->tm_mon = BCD2BIN(tmp) - 1;
+
+       /* assume 20YY not 19YY, and ignore DS1337_BIT_CENTURY */
+       t->tm_year = BCD2BIN(ds1307->regs[DS1307_REG_YEAR]) + 100;
+
+       dev_dbg(dev, "%s secs=%d, mins=%d, "
+               "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+               "read", t->tm_sec, t->tm_min,
+               t->tm_hour, t->tm_mday,
+               t->tm_mon, t->tm_year, t->tm_wday);
+
+       return 0;
+}
+
+static int ds1307_set_time(struct device *dev, struct rtc_time *t)
+{
+       struct ds1307   *ds1307 = dev_get_drvdata(dev);
+       int             result;
+       int             tmp;
+       u8              *buf = ds1307->regs;
+
+       dev_dbg(dev, "%s secs=%d, mins=%d, "
+               "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+               "write", dt->tm_sec, dt->tm_min,
+               dt->tm_hour, dt->tm_mday,
+               dt->tm_mon, dt->tm_year, dt->tm_wday);
+
+       *buf++ = 0;             /* first register addr */
+       buf[DS1307_REG_SECS] = BIN2BCD(t->tm_sec);
+       buf[DS1307_REG_MIN] = BIN2BCD(t->tm_min);
+       buf[DS1307_REG_HOUR] = BIN2BCD(t->tm_hour);
+       buf[DS1307_REG_WDAY] = BIN2BCD(t->tm_wday + 1);
+       buf[DS1307_REG_MDAY] = BIN2BCD(t->tm_mday);
+       buf[DS1307_REG_MONTH] = BIN2BCD(t->tm_mon + 1);
+
+       /* assume 20YY not 19YY */
+       tmp = t->tm_year - 100;
+       buf[DS1307_REG_YEAR] = BIN2BCD(tmp);
+
+       if (ds1307->type == ds_1337)
+               buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY;
+       else if (ds1307->type == ds_1340)
+               buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN
+                               | DS1340_BIT_CENTURY;
+
+       ds1307->msg[1].flags = 0;
+       ds1307->msg[1].len = 8;
+
+       dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
+               "write", buf[0], buf[1], buf[2], buf[3],
+               buf[4], buf[5], buf[6]);
+
+       result = i2c_transfer(ds1307->client.adapter, &ds1307->msg[1], 1);
+       if (result != 1) {
+               dev_err(dev, "%s error %d\n", "write", tmp);
+               return -EIO;
+       }
+       return 0;
+}
+
+static struct rtc_class_ops ds13xx_rtc_ops = {
+       .read_time      = ds1307_get_time,
+       .set_time       = ds1307_set_time,
+};
+
+static struct i2c_driver ds1307_driver;
+
+static int __devinit
+ds1307_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+       struct ds1307           *ds1307;
+       int                     err = -ENODEV;
+       struct i2c_client       *client;
+       int                     tmp;
+
+       if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       client = &ds1307->client;
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &ds1307_driver;
+       client->flags = 0;
+
+       i2c_set_clientdata(client, ds1307);
+
+       ds1307->msg[0].addr = client->addr;
+       ds1307->msg[0].flags = 0;
+       ds1307->msg[0].len = 1;
+       ds1307->msg[0].buf = &ds1307->reg_addr;
+
+       ds1307->msg[1].addr = client->addr;
+       ds1307->msg[1].flags = I2C_M_RD;
+       ds1307->msg[1].len = sizeof(ds1307->regs);
+       ds1307->msg[1].buf = ds1307->regs;
+
+       /* HACK: "force" implies "needs ds1337-style-oscillator setup" */
+       if (kind >= 0) {
+               ds1307->type = ds_1337;
+
+               ds1307->reg_addr = DS1337_REG_CONTROL;
+               ds1307->msg[1].len = 2;
+
+               tmp = i2c_transfer(client->adapter, ds1307->msg, 2);
+               if (tmp != 2) {
+                       pr_debug("read error %d\n", tmp);
+                       err = -EIO;
+                       goto exit_free;
+               }
+
+               ds1307->reg_addr = 0;
+               ds1307->msg[1].len = sizeof(ds1307->regs);
+
+               /* oscillator is off; need to turn it on */
+               if ((ds1307->regs[0] & DS1337_BIT_nEOSC)
+                               || (ds1307->regs[1] & DS1337_BIT_OSF)) {
+                       printk(KERN_ERR "no ds1337 oscillator code\n");
+                       goto exit_free;
+               }
+       } else
+               ds1307->type = ds_1307;
+
+read_rtc:
+       /* read RTC registers */
+
+       tmp = i2c_transfer(client->adapter, ds1307->msg, 2);
+       if (tmp != 2) {
+               pr_debug("read error %d\n", tmp);
+               err = -EIO;
+               goto exit_free;
+       }
+
+       /* minimal sanity checking; some chips (like DS1340) don't
+        * specify the extra bits as must-be-zero, but there are
+        * still a few values that are clearly out-of-range.
+        */
+       tmp = ds1307->regs[DS1307_REG_SECS];
+       if (tmp & DS1307_BIT_CH) {
+               if (ds1307->type && ds1307->type != ds_1307) {
+                       pr_debug("not a ds1307?\n");
+                       goto exit_free;
+               }
+               ds1307->type = ds_1307;
+
+               /* this partial initialization should work for ds1307,
+                * ds1338, ds1340, st m41t00, and more.
+                */
+               dev_warn(&client->dev, "oscillator started; SET TIME!\n");
+               i2c_smbus_write_byte_data(client, 0, 0);
+               goto read_rtc;
+       }
+       tmp = BCD2BIN(tmp & 0x7f);
+       if (tmp > 60)
+               goto exit_free;
+       tmp = BCD2BIN(ds1307->regs[DS1307_REG_MIN] & 0x7f);
+       if (tmp > 60)
+               goto exit_free;
+
+       tmp = BCD2BIN(ds1307->regs[DS1307_REG_MDAY] & 0x3f);
+       if (tmp == 0 || tmp > 31)
+               goto exit_free;
+
+       tmp = BCD2BIN(ds1307->regs[DS1307_REG_MONTH] & 0x1f);
+       if (tmp == 0 || tmp > 12)
+               goto exit_free;
+
+       /* force into in 24 hour mode (most chips) or
+        * disable century bit (ds1340)
+        */
+       tmp = ds1307->regs[DS1307_REG_HOUR];
+       if (tmp & (1 << 6)) {
+               if (tmp & (1 << 5))
+                       tmp = BCD2BIN(tmp & 0x1f) + 12;
+               else
+                       tmp = BCD2BIN(tmp);
+               i2c_smbus_write_byte_data(client,
+                               DS1307_REG_HOUR,
+                               BIN2BCD(tmp));
+       }
+
+       /* FIXME chips like 1337 can generate alarm irqs too; those are
+        * worth exposing through the API (especially when the irq is
+        * wakeup-capable).
+        */
+
+       switch (ds1307->type) {
+       case unknown:
+               strlcpy(client->name, "unknown", I2C_NAME_SIZE);
+               break;
+       case ds_1307:
+               strlcpy(client->name, "ds1307", I2C_NAME_SIZE);
+               break;
+       case ds_1337:
+               strlcpy(client->name, "ds1337", I2C_NAME_SIZE);
+               break;
+       case ds_1340:
+               strlcpy(client->name, "ds1340", I2C_NAME_SIZE);
+               break;
+       }
+
+       /* Tell the I2C layer a new client has arrived */
+       if ((err = i2c_attach_client(client)))
+               goto exit_free;
+
+       ds1307->rtc = rtc_device_register(client->name, &client->dev,
+                               &ds13xx_rtc_ops, THIS_MODULE);
+       if (IS_ERR(ds1307->rtc)) {
+               err = PTR_ERR(ds1307->rtc);
+               dev_err(&client->dev,
+                       "unable to register the class device\n");
+               goto exit_detach;
+       }
+
+       return 0;
+
+exit_detach:
+       i2c_detach_client(client);
+exit_free:
+       kfree(ds1307);
+exit:
+       return err;
+}
+
+static int __devinit
+ds1307_attach_adapter(struct i2c_adapter *adapter)
+{
+       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+               return 0;
+       return i2c_probe(adapter, &addr_data, ds1307_detect);
+}
+
+static int __devexit ds1307_detach_client(struct i2c_client *client)
+{
+       int             err;
+       struct ds1307   *ds1307 = i2c_get_clientdata(client);
+
+       rtc_device_unregister(ds1307->rtc);
+       if ((err = i2c_detach_client(client)))
+               return err;
+       kfree(ds1307);
+       return 0;
+}
+
+static struct i2c_driver ds1307_driver = {
+       .driver = {
+               .name   = "ds1307",
+               .owner  = THIS_MODULE,
+       },
+       .attach_adapter = ds1307_attach_adapter,
+       .detach_client  = __devexit_p(ds1307_detach_client),
+};
+
+static int __init ds1307_init(void)
+{
+       return i2c_add_driver(&ds1307_driver);
+}
+module_init(ds1307_init);
+
+static void __exit ds1307_exit(void)
+{
+       i2c_del_driver(&ds1307_driver);
+}
+module_exit(ds1307_exit);
+
+MODULE_DESCRIPTION("RTC driver for DS1307 and similar chips");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
new file mode 100644 (file)
index 0000000..ecafbad
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * An rtc driver for the Dallas DS1553
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bcd.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRV_VERSION "0.1"
+
+#define RTC_REG_SIZE           0x2000
+#define RTC_OFFSET             0x1ff0
+
+#define RTC_FLAGS              (RTC_OFFSET + 0)
+#define RTC_SECONDS_ALARM      (RTC_OFFSET + 2)
+#define RTC_MINUTES_ALARM      (RTC_OFFSET + 3)
+#define RTC_HOURS_ALARM                (RTC_OFFSET + 4)
+#define RTC_DATE_ALARM         (RTC_OFFSET + 5)
+#define RTC_INTERRUPTS         (RTC_OFFSET + 6)
+#define RTC_WATCHDOG           (RTC_OFFSET + 7)
+#define RTC_CONTROL            (RTC_OFFSET + 8)
+#define RTC_CENTURY            (RTC_OFFSET + 8)
+#define RTC_SECONDS            (RTC_OFFSET + 9)
+#define RTC_MINUTES            (RTC_OFFSET + 10)
+#define RTC_HOURS              (RTC_OFFSET + 11)
+#define RTC_DAY                        (RTC_OFFSET + 12)
+#define RTC_DATE               (RTC_OFFSET + 13)
+#define RTC_MONTH              (RTC_OFFSET + 14)
+#define RTC_YEAR               (RTC_OFFSET + 15)
+
+#define RTC_CENTURY_MASK       0x3f
+#define RTC_SECONDS_MASK       0x7f
+#define RTC_DAY_MASK           0x07
+
+/* Bits in the Control/Century register */
+#define RTC_WRITE              0x80
+#define RTC_READ               0x40
+
+/* Bits in the Seconds register */
+#define RTC_STOP               0x80
+
+/* Bits in the Flags register */
+#define RTC_FLAGS_AF           0x40
+#define RTC_FLAGS_BLF          0x10
+
+/* Bits in the Interrupts register */
+#define RTC_INTS_AE            0x80
+
+struct rtc_plat_data {
+       struct rtc_device *rtc;
+       void __iomem *ioaddr;
+       unsigned long baseaddr;
+       unsigned long last_jiffies;
+       int irq;
+       unsigned int irqen;
+       int alrm_sec;
+       int alrm_min;
+       int alrm_hour;
+       int alrm_mday;
+};
+
+static int ds1553_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+       void __iomem *ioaddr = pdata->ioaddr;
+       u8 century;
+
+       century = BIN2BCD((tm->tm_year + 1900) / 100);
+
+       writeb(RTC_WRITE, pdata->ioaddr + RTC_CONTROL);
+
+       writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR);
+       writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH);
+       writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
+       writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE);
+       writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS);
+       writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES);
+       writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
+
+       /* RTC_CENTURY and RTC_CONTROL share same register */
+       writeb(RTC_WRITE | (century & RTC_CENTURY_MASK), ioaddr + RTC_CENTURY);
+       writeb(century & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL);
+       return 0;
+}
+
+static int ds1553_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+       void __iomem *ioaddr = pdata->ioaddr;
+       unsigned int year, month, day, hour, minute, second, week;
+       unsigned int century;
+
+       /* give enough time to update RTC in case of continuous read */
+       if (pdata->last_jiffies == jiffies)
+               msleep(1);
+       pdata->last_jiffies = jiffies;
+       writeb(RTC_READ, ioaddr + RTC_CONTROL);
+       second = readb(ioaddr + RTC_SECONDS) & RTC_SECONDS_MASK;
+       minute = readb(ioaddr + RTC_MINUTES);
+       hour = readb(ioaddr + RTC_HOURS);
+       day = readb(ioaddr + RTC_DATE);
+       week = readb(ioaddr + RTC_DAY) & RTC_DAY_MASK;
+       month = readb(ioaddr + RTC_MONTH);
+       year = readb(ioaddr + RTC_YEAR);
+       century = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK;
+       writeb(0, ioaddr + RTC_CONTROL);
+       tm->tm_sec = BCD2BIN(second);
+       tm->tm_min = BCD2BIN(minute);
+       tm->tm_hour = BCD2BIN(hour);
+       tm->tm_mday = BCD2BIN(day);
+       tm->tm_wday = BCD2BIN(week);
+       tm->tm_mon = BCD2BIN(month) - 1;
+       /* year is 1900 + tm->tm_year */
+       tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900;
+
+       if (rtc_valid_tm(tm) < 0) {
+               dev_err(dev, "retrieved date/time is not valid.\n");
+               rtc_time_to_tm(0, tm);
+       }
+       return 0;
+}
+
+static void ds1553_rtc_update_alarm(struct rtc_plat_data *pdata)
+{
+       void __iomem *ioaddr = pdata->ioaddr;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdata->rtc->irq_lock, flags);
+       writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
+              0x80 : BIN2BCD(pdata->alrm_mday),
+              ioaddr + RTC_DATE_ALARM);
+       writeb(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
+              0x80 : BIN2BCD(pdata->alrm_hour),
+              ioaddr + RTC_HOURS_ALARM);
+       writeb(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
+              0x80 : BIN2BCD(pdata->alrm_min),
+              ioaddr + RTC_MINUTES_ALARM);
+       writeb(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
+              0x80 : BIN2BCD(pdata->alrm_sec),
+              ioaddr + RTC_SECONDS_ALARM);
+       writeb(pdata->irqen ? RTC_INTS_AE : 0, ioaddr + RTC_INTERRUPTS);
+       readb(ioaddr + RTC_FLAGS);      /* clear interrupts */
+       spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags);
+}
+
+static int ds1553_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       if (pdata->irq < 0)
+               return -EINVAL;
+       pdata->alrm_mday = alrm->time.tm_mday;
+       pdata->alrm_hour = alrm->time.tm_hour;
+       pdata->alrm_min = alrm->time.tm_min;
+       pdata->alrm_sec = alrm->time.tm_sec;
+       if (alrm->enabled)
+               pdata->irqen |= RTC_AF;
+       ds1553_rtc_update_alarm(pdata);
+       return 0;
+}
+
+static int ds1553_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       if (pdata->irq < 0)
+               return -EINVAL;
+       alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday;
+       alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour;
+       alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min;
+       alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec;
+       alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0;
+       return 0;
+}
+
+static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id,
+                                       struct pt_regs *regs)
+{
+       struct platform_device *pdev = dev_id;
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+       void __iomem *ioaddr = pdata->ioaddr;
+       unsigned long events = RTC_IRQF;
+
+       /* read and clear interrupt */
+       if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF))
+               return IRQ_NONE;
+       if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80)
+               events |= RTC_UF;
+       else
+               events |= RTC_AF;
+       rtc_update_irq(&pdata->rtc->class_dev, 1, events);
+       return IRQ_HANDLED;
+}
+
+static void ds1553_rtc_release(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       if (pdata->irq >= 0) {
+               pdata->irqen = 0;
+               ds1553_rtc_update_alarm(pdata);
+       }
+}
+
+static int ds1553_rtc_ioctl(struct device *dev, unsigned int cmd,
+                           unsigned long arg)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       if (pdata->irq < 0)
+               return -ENOIOCTLCMD;
+       switch (cmd) {
+       case RTC_AIE_OFF:
+               pdata->irqen &= ~RTC_AF;
+               ds1553_rtc_update_alarm(pdata);
+               break;
+       case RTC_AIE_ON:
+               pdata->irqen |= RTC_AF;
+               ds1553_rtc_update_alarm(pdata);
+               break;
+       case RTC_UIE_OFF:
+               pdata->irqen &= ~RTC_UF;
+               ds1553_rtc_update_alarm(pdata);
+               break;
+       case RTC_UIE_ON:
+               pdata->irqen |= RTC_UF;
+               ds1553_rtc_update_alarm(pdata);
+               break;
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static struct rtc_class_ops ds1553_rtc_ops = {
+       .read_time      = ds1553_rtc_read_time,
+       .set_time       = ds1553_rtc_set_time,
+       .read_alarm     = ds1553_rtc_read_alarm,
+       .set_alarm      = ds1553_rtc_set_alarm,
+       .release        = ds1553_rtc_release,
+       .ioctl          = ds1553_rtc_ioctl,
+};
+
+static ssize_t ds1553_nvram_read(struct kobject *kobj, char *buf,
+                                loff_t pos, size_t size)
+{
+       struct platform_device *pdev =
+               to_platform_device(container_of(kobj, struct device, kobj));
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+       void __iomem *ioaddr = pdata->ioaddr;
+       ssize_t count;
+
+       for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+               *buf++ = readb(ioaddr + pos++);
+       return count;
+}
+
+static ssize_t ds1553_nvram_write(struct kobject *kobj, char *buf,
+                                 loff_t pos, size_t size)
+{
+       struct platform_device *pdev =
+               to_platform_device(container_of(kobj, struct device, kobj));
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+       void __iomem *ioaddr = pdata->ioaddr;
+       ssize_t count;
+
+       for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+               writeb(*buf++, ioaddr + pos++);
+       return count;
+}
+
+static struct bin_attribute ds1553_nvram_attr = {
+       .attr = {
+               .name = "nvram",
+               .mode = S_IRUGO | S_IWUGO,
+               .owner = THIS_MODULE,
+       },
+       .size = RTC_OFFSET,
+       .read = ds1553_nvram_read,
+       .write = ds1553_nvram_write,
+};
+
+static int __init ds1553_rtc_probe(struct platform_device *pdev)
+{
+       struct rtc_device *rtc;
+       struct resource *res;
+       unsigned int cen, sec;
+       struct rtc_plat_data *pdata = NULL;
+       void __iomem *ioaddr = NULL;
+       int ret = 0;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+       pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+       pdata->irq = -1;
+       if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) {
+               ret = -EBUSY;
+               goto out;
+       }
+       pdata->baseaddr = res->start;
+       ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE);
+       if (!ioaddr) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       pdata->ioaddr = ioaddr;
+       pdata->irq = platform_get_irq(pdev, 0);
+
+       /* turn RTC on if it was not on */
+       sec = readb(ioaddr + RTC_SECONDS);
+       if (sec & RTC_STOP) {
+               sec &= RTC_SECONDS_MASK;
+               cen = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK;
+               writeb(RTC_WRITE, ioaddr + RTC_CONTROL);
+               writeb(sec, ioaddr + RTC_SECONDS);
+               writeb(cen & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL);
+       }
+       if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_BLF)
+               dev_warn(&pdev->dev, "voltage-low detected.\n");
+
+       if (pdata->irq >= 0) {
+               writeb(0, ioaddr + RTC_INTERRUPTS);
+               if (request_irq(pdata->irq, ds1553_rtc_interrupt, SA_SHIRQ,
+                               pdev->name, pdev) < 0) {
+                       dev_warn(&pdev->dev, "interrupt not available.\n");
+                       pdata->irq = -1;
+               }
+       }
+
+       rtc = rtc_device_register(pdev->name, &pdev->dev,
+                                 &ds1553_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc)) {
+               ret = PTR_ERR(rtc);
+               goto out;
+       }
+       pdata->rtc = rtc;
+       pdata->last_jiffies = jiffies;
+       platform_set_drvdata(pdev, pdata);
+       sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
+       return 0;
+ out:
+       if (pdata->irq >= 0)
+               free_irq(pdata->irq, pdev);
+       if (ioaddr)
+               iounmap(ioaddr);
+       if (pdata->baseaddr)
+               release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+       kfree(pdata);
+       return ret;
+}
+
+static int __devexit ds1553_rtc_remove(struct platform_device *pdev)
+{
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       sysfs_remove_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
+       rtc_device_unregister(pdata->rtc);
+       if (pdata->irq >= 0) {
+               writeb(0, pdata->ioaddr + RTC_INTERRUPTS);
+               free_irq(pdata->irq, pdev);
+       }
+       iounmap(pdata->ioaddr);
+       release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+       kfree(pdata);
+       return 0;
+}
+
+static struct platform_driver ds1553_rtc_driver = {
+       .probe          = ds1553_rtc_probe,
+       .remove         = __devexit_p(ds1553_rtc_remove),
+       .driver         = {
+               .name   = "ds1553",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static __init int ds1553_init(void)
+{
+       return platform_driver_register(&ds1553_rtc_driver);
+}
+
+static __exit void ds1553_exit(void)
+{
+       return platform_driver_unregister(&ds1553_rtc_driver);
+}
+
+module_init(ds1553_init);
+module_exit(ds1553_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("Dallas DS1553 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
new file mode 100644 (file)
index 0000000..8e47e5a
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * An rtc driver for the Dallas DS1742
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bcd.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRV_VERSION "0.1"
+
+#define RTC_REG_SIZE           0x800
+#define RTC_OFFSET             0x7f8
+
+#define RTC_CONTROL            (RTC_OFFSET + 0)
+#define RTC_CENTURY            (RTC_OFFSET + 0)
+#define RTC_SECONDS            (RTC_OFFSET + 1)
+#define RTC_MINUTES            (RTC_OFFSET + 2)
+#define RTC_HOURS              (RTC_OFFSET + 3)
+#define RTC_DAY                        (RTC_OFFSET + 4)
+#define RTC_DATE               (RTC_OFFSET + 5)
+#define RTC_MONTH              (RTC_OFFSET + 6)
+#define RTC_YEAR               (RTC_OFFSET + 7)
+
+#define RTC_CENTURY_MASK       0x3f
+#define RTC_SECONDS_MASK       0x7f
+#define RTC_DAY_MASK           0x07
+
+/* Bits in the Control/Century register */
+#define RTC_WRITE              0x80
+#define RTC_READ               0x40
+
+/* Bits in the Seconds register */
+#define RTC_STOP               0x80
+
+/* Bits in the Day register */
+#define RTC_BATT_FLAG          0x80
+
+struct rtc_plat_data {
+       struct rtc_device *rtc;
+       void __iomem *ioaddr;
+       unsigned long baseaddr;
+       unsigned long last_jiffies;
+};
+
+static int ds1742_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+       void __iomem *ioaddr = pdata->ioaddr;
+       u8 century;
+
+       century = BIN2BCD((tm->tm_year + 1900) / 100);
+
+       writeb(RTC_WRITE, ioaddr + RTC_CONTROL);
+
+       writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR);
+       writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH);
+       writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
+       writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE);
+       writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS);
+       writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES);
+       writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
+
+       /* RTC_CENTURY and RTC_CONTROL share same register */
+       writeb(RTC_WRITE | (century & RTC_CENTURY_MASK), ioaddr + RTC_CENTURY);
+       writeb(century & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL);
+       return 0;
+}
+
+static int ds1742_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+       void __iomem *ioaddr = pdata->ioaddr;
+       unsigned int year, month, day, hour, minute, second, week;
+       unsigned int century;
+
+       /* give enough time to update RTC in case of continuous read */
+       if (pdata->last_jiffies == jiffies)
+               msleep(1);
+       pdata->last_jiffies = jiffies;
+       writeb(RTC_READ, ioaddr + RTC_CONTROL);
+       second = readb(ioaddr + RTC_SECONDS) & RTC_SECONDS_MASK;
+       minute = readb(ioaddr + RTC_MINUTES);
+       hour = readb(ioaddr + RTC_HOURS);
+       day = readb(ioaddr + RTC_DATE);
+       week = readb(ioaddr + RTC_DAY) & RTC_DAY_MASK;
+       month = readb(ioaddr + RTC_MONTH);
+       year = readb(ioaddr + RTC_YEAR);
+       century = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK;
+       writeb(0, ioaddr + RTC_CONTROL);
+       tm->tm_sec = BCD2BIN(second);
+       tm->tm_min = BCD2BIN(minute);
+       tm->tm_hour = BCD2BIN(hour);
+       tm->tm_mday = BCD2BIN(day);
+       tm->tm_wday = BCD2BIN(week);
+       tm->tm_mon = BCD2BIN(month) - 1;
+       /* year is 1900 + tm->tm_year */
+       tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900;
+
+       if (rtc_valid_tm(tm) < 0) {
+               dev_err(dev, "retrieved date/time is not valid.\n");
+               rtc_time_to_tm(0, tm);
+       }
+       return 0;
+}
+
+static struct rtc_class_ops ds1742_rtc_ops = {
+       .read_time      = ds1742_rtc_read_time,
+       .set_time       = ds1742_rtc_set_time,
+};
+
+static ssize_t ds1742_nvram_read(struct kobject *kobj, char *buf,
+                                loff_t pos, size_t size)
+{
+       struct platform_device *pdev =
+               to_platform_device(container_of(kobj, struct device, kobj));
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+       void __iomem *ioaddr = pdata->ioaddr;
+       ssize_t count;
+
+       for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+               *buf++ = readb(ioaddr + pos++);
+       return count;
+}
+
+static ssize_t ds1742_nvram_write(struct kobject *kobj, char *buf,
+                                 loff_t pos, size_t size)
+{
+       struct platform_device *pdev =
+               to_platform_device(container_of(kobj, struct device, kobj));
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+       void __iomem *ioaddr = pdata->ioaddr;
+       ssize_t count;
+
+       for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+               writeb(*buf++, ioaddr + pos++);
+       return count;
+}
+
+static struct bin_attribute ds1742_nvram_attr = {
+       .attr = {
+               .name = "nvram",
+               .mode = S_IRUGO | S_IWUGO,
+               .owner = THIS_MODULE,
+       },
+       .size = RTC_OFFSET,
+       .read = ds1742_nvram_read,
+       .write = ds1742_nvram_write,
+};
+
+static int __init ds1742_rtc_probe(struct platform_device *pdev)
+{
+       struct rtc_device *rtc;
+       struct resource *res;
+       unsigned int cen, sec;
+       struct rtc_plat_data *pdata = NULL;
+       void __iomem *ioaddr = NULL;
+       int ret = 0;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+       pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+       if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) {
+               ret = -EBUSY;
+               goto out;
+       }
+       pdata->baseaddr = res->start;
+       ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE);
+       if (!ioaddr) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       pdata->ioaddr = ioaddr;
+
+       /* turn RTC on if it was not on */
+       sec = readb(ioaddr + RTC_SECONDS);
+       if (sec & RTC_STOP) {
+               sec &= RTC_SECONDS_MASK;
+               cen = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK;
+               writeb(RTC_WRITE, ioaddr + RTC_CONTROL);
+               writeb(sec, ioaddr + RTC_SECONDS);
+               writeb(cen & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL);
+       }
+       if (readb(ioaddr + RTC_DAY) & RTC_BATT_FLAG)
+               dev_warn(&pdev->dev, "voltage-low detected.\n");
+
+       rtc = rtc_device_register(pdev->name, &pdev->dev,
+                                 &ds1742_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc)) {
+               ret = PTR_ERR(rtc);
+               goto out;
+       }
+       pdata->rtc = rtc;
+       pdata->last_jiffies = jiffies;
+       platform_set_drvdata(pdev, pdata);
+       sysfs_create_bin_file(&pdev->dev.kobj, &ds1742_nvram_attr);
+       return 0;
+ out:
+       if (ioaddr)
+               iounmap(ioaddr);
+       if (pdata->baseaddr)
+               release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+       kfree(pdata);
+       return ret;
+}
+
+static int __devexit ds1742_rtc_remove(struct platform_device *pdev)
+{
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       sysfs_remove_bin_file(&pdev->dev.kobj, &ds1742_nvram_attr);
+       rtc_device_unregister(pdata->rtc);
+       iounmap(pdata->ioaddr);
+       release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+       kfree(pdata);
+       return 0;
+}
+
+static struct platform_driver ds1742_rtc_driver = {
+       .probe          = ds1742_rtc_probe,
+       .remove         = __devexit_p(ds1742_rtc_remove),
+       .driver         = {
+               .name   = "ds1742",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static __init int ds1742_init(void)
+{
+       return platform_driver_register(&ds1742_rtc_driver);
+}
+
+static __exit void ds1742_exit(void)
+{
+       return platform_driver_unregister(&ds1742_rtc_driver);
+}
+
+module_init(ds1742_init);
+module_exit(ds1742_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("Dallas DS1742 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
index cfedc1d28ee1ab80529a86afff78c3a171d3a357..9812120f3a7c825c783a7c15635279740ced383d 100644 (file)
@@ -18,15 +18,34 @@ static const unsigned char rtc_days_in_month[] = {
        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
 };
 
+static const unsigned short rtc_ydays[2][13] = {
+       /* Normal years */
+       { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+       /* Leap years */
+       { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+};
+
 #define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
 #define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
 
+/*
+ * The number of days in the month.
+ */
 int rtc_month_days(unsigned int month, unsigned int year)
 {
        return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1);
 }
 EXPORT_SYMBOL(rtc_month_days);
 
+/*
+ * The number of days since January 1. (0 to 365)
+ */
+int rtc_year_days(unsigned int day, unsigned int month, unsigned int year)
+{
+       return rtc_ydays[LEAP_YEAR(year)][month] + day-1;
+}
+EXPORT_SYMBOL(rtc_year_days);
+
 /*
  * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
  */
diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c
new file mode 100644 (file)
index 0000000..2c97395
--- /dev/null
@@ -0,0 +1,286 @@
+/* drivers/char/max6902.c
+ *
+ * Copyright (C) 2006 8D Technologies inc.
+ * Copyright (C) 2004 Compulab Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Driver for MAX6902 spi RTC
+ *
+ * Changelog:
+ *
+ * 24-May-2006: Raphael Assenat <raph@8d.com>
+ *                - Major rework
+ *                             Converted to rtc_device and uses the SPI layer.
+ *
+ * ??-???-2005: Someone at Compulab
+ *                - Initial driver creation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+#include <linux/delay.h>
+
+#define MAX6902_REG_SECONDS            0x01
+#define MAX6902_REG_MINUTES            0x03
+#define MAX6902_REG_HOURS              0x05
+#define MAX6902_REG_DATE               0x07
+#define MAX6902_REG_MONTH              0x09
+#define MAX6902_REG_DAY                        0x0B
+#define MAX6902_REG_YEAR               0x0D
+#define MAX6902_REG_CONTROL            0x0F
+#define MAX6902_REG_CENTURY            0x13
+
+#undef MAX6902_DEBUG
+
+struct max6902 {
+       struct rtc_device *rtc;
+       u8 buf[9]; /* Burst read cmd + 8 registers */
+       u8 tx_buf[2];
+       u8 rx_buf[2];
+};
+
+static void max6902_set_reg(struct device *dev, unsigned char address,
+                               unsigned char data)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       unsigned char buf[2];
+
+       /* MSB must be '0' to write */
+       buf[0] = address & 0x7f;
+       buf[1] = data;
+
+       spi_write(spi, buf, 2);
+}
+
+static int max6902_get_reg(struct device *dev, unsigned char address,
+                               unsigned char *data)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct max6902 *chip = dev_get_drvdata(dev);
+       struct spi_message message;
+       struct spi_transfer xfer;
+       int status;
+
+       if (!data)
+               return -EINVAL;
+
+       /* Build our spi message */
+       spi_message_init(&message);
+       memset(&xfer, 0, sizeof(xfer));
+       xfer.len = 2;
+       /* Can tx_buf and rx_buf be equal? The doc in spi.h is not sure... */
+       xfer.tx_buf = chip->tx_buf;
+       xfer.rx_buf = chip->rx_buf;
+
+       /* Set MSB to indicate read */
+       chip->tx_buf[0] = address | 0x80;
+
+       spi_message_add_tail(&xfer, &message);
+
+       /* do the i/o */
+       status = spi_sync(spi, &message);
+       if (status == 0)
+               status = message.status;
+       else
+               return status;
+
+       *data = chip->rx_buf[1];
+
+       return status;
+}
+
+static int max6902_get_datetime(struct device *dev, struct rtc_time *dt)
+{
+       unsigned char tmp;
+       int century;
+       int err;
+       struct spi_device *spi = to_spi_device(dev);
+       struct max6902 *chip = dev_get_drvdata(dev);
+       struct spi_message message;
+       struct spi_transfer xfer;
+       int status;
+
+       err = max6902_get_reg(dev, MAX6902_REG_CENTURY, &tmp);
+       if (err)
+               return err;
+
+       /* build the message */
+       spi_message_init(&message);
+       memset(&xfer, 0, sizeof(xfer));
+       xfer.len = 1 + 7;       /* Burst read command + 7 registers */
+       xfer.tx_buf = chip->buf;
+       xfer.rx_buf = chip->buf;
+       chip->buf[0] = 0xbf;    /* Burst read */
+       spi_message_add_tail(&xfer, &message);
+
+       /* do the i/o */
+       status = spi_sync(spi, &message);
+       if (status == 0)
+               status = message.status;
+       else
+               return status;
+
+       /* The chip sends data in this order:
+        * Seconds, Minutes, Hours, Date, Month, Day, Year */
+       dt->tm_sec      = BCD2BIN(chip->buf[1]);
+       dt->tm_min      = BCD2BIN(chip->buf[2]);
+       dt->tm_hour     = BCD2BIN(chip->buf[3]);
+       dt->tm_mday     = BCD2BIN(chip->buf[4]);
+       dt->tm_mon      = BCD2BIN(chip->buf[5] - 1);
+       dt->tm_wday     = BCD2BIN(chip->buf[6]);
+       dt->tm_year = BCD2BIN(chip->buf[7]);
+
+       century = BCD2BIN(tmp) * 100;
+
+       dt->tm_year += century;
+       dt->tm_year -= 1900;
+
+#ifdef MAX6902_DEBUG
+       printk("\n%s : Read RTC values\n",__FUNCTION__);
+       printk("tm_hour: %i\n",dt->tm_hour);
+       printk("tm_min : %i\n",dt->tm_min);
+       printk("tm_sec : %i\n",dt->tm_sec);
+       printk("tm_year: %i\n",dt->tm_year);
+       printk("tm_mon : %i\n",dt->tm_mon);
+       printk("tm_mday: %i\n",dt->tm_mday);
+       printk("tm_wday: %i\n",dt->tm_wday);
+#endif
+
+       return 0;
+}
+
+static int max6902_set_datetime(struct device *dev, struct rtc_time *dt)
+{
+       dt->tm_year = dt->tm_year+1900;
+
+#ifdef MAX6902_DEBUG
+       printk("\n%s : Setting RTC values\n",__FUNCTION__);
+       printk("tm_sec : %i\n",dt->tm_sec);
+       printk("tm_min : %i\n",dt->tm_min);
+       printk("tm_hour: %i\n",dt->tm_hour);
+       printk("tm_mday: %i\n",dt->tm_mday);
+       printk("tm_wday: %i\n",dt->tm_wday);
+       printk("tm_year: %i\n",dt->tm_year);
+#endif
+
+       /* Remove write protection */
+       max6902_set_reg(dev, 0xF, 0);
+
+       max6902_set_reg(dev, 0x01, BIN2BCD(dt->tm_sec));
+       max6902_set_reg(dev, 0x03, BIN2BCD(dt->tm_min));
+       max6902_set_reg(dev, 0x05, BIN2BCD(dt->tm_hour));
+
+       max6902_set_reg(dev, 0x07, BIN2BCD(dt->tm_mday));
+       max6902_set_reg(dev, 0x09, BIN2BCD(dt->tm_mon+1));
+       max6902_set_reg(dev, 0x0B, BIN2BCD(dt->tm_wday));
+       max6902_set_reg(dev, 0x0D, BIN2BCD(dt->tm_year%100));
+       max6902_set_reg(dev, 0x13, BIN2BCD(dt->tm_year/100));
+
+       /* Compulab used a delay here. However, the datasheet
+        * does not mention a delay being required anywhere... */
+       /* delay(2000); */
+
+       /* Write protect */
+       max6902_set_reg(dev, 0xF, 0x80);
+
+       return 0;
+}
+
+static int max6902_read_time(struct device *dev, struct rtc_time *tm)
+{
+       return max6902_get_datetime(dev, tm);
+}
+
+static int max6902_set_time(struct device *dev, struct rtc_time *tm)
+{
+       return max6902_set_datetime(dev, tm);
+}
+
+static struct rtc_class_ops max6902_rtc_ops = {
+       .read_time      = max6902_read_time,
+       .set_time       = max6902_set_time,
+};
+
+static int __devinit max6902_probe(struct spi_device *spi)
+{
+       struct rtc_device *rtc;
+       unsigned char tmp;
+       struct max6902 *chip;
+       int res;
+
+       rtc = rtc_device_register("max6902",
+                               &spi->dev, &max6902_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       spi->mode = SPI_MODE_3;
+       spi->bits_per_word = 8;
+       spi_setup(spi);
+
+       chip = kzalloc(sizeof *chip, GFP_KERNEL);
+       if (!chip) {
+               rtc_device_unregister(rtc);
+               return -ENOMEM;
+       }
+       chip->rtc = rtc;
+       dev_set_drvdata(&spi->dev, chip);
+
+       res = max6902_get_reg(&spi->dev, MAX6902_REG_SECONDS, &tmp);
+       if (res) {
+               rtc_device_unregister(rtc);
+               return res;
+       }
+
+       return 0;
+}
+
+static int __devexit max6902_remove(struct spi_device *spi)
+{
+       struct max6902 *chip = platform_get_drvdata(spi);
+       struct rtc_device *rtc = chip->rtc;
+
+       if (rtc)
+               rtc_device_unregister(rtc);
+
+       kfree(chip);
+
+       return 0;
+}
+
+static struct spi_driver max6902_driver = {
+       .driver = {
+               .name   = "max6902",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe  = max6902_probe,
+       .remove = __devexit_p(max6902_remove),
+};
+
+static __init int max6902_init(void)
+{
+       printk("max6902 spi driver\n");
+       return spi_register_driver(&max6902_driver);
+}
+module_init(max6902_init);
+
+static __exit void max6902_exit(void)
+{
+       spi_unregister_driver(&max6902_driver);
+}
+module_exit(max6902_exit);
+
+MODULE_DESCRIPTION ("max6902 spi RTC driver");
+MODULE_AUTHOR ("Raphael Assenat");
+MODULE_LICENSE ("GPL");
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
new file mode 100644 (file)
index 0000000..b235a30
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ *  drivers/rtc/rtc-pcf8583.c
+ *
+ *  Copyright (C) 2000 Russell King
+ *
+ * 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.
+ *
+ *  Driver for PCF8583 RTC & RAM chip
+ *
+ *  Converted to the generic RTC susbsystem by G. Liakhovetski (2006)
+ */
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/mc146818rtc.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/bcd.h>
+
+struct rtc_mem {
+       unsigned int    loc;
+       unsigned int    nr;
+       unsigned char   *data;
+};
+
+struct pcf8583 {
+       struct i2c_client client;
+       struct rtc_device *rtc;
+       unsigned char ctrl;
+};
+
+#define CTRL_STOP      0x80
+#define CTRL_HOLD      0x40
+#define CTRL_32KHZ     0x00
+#define CTRL_MASK      0x08
+#define CTRL_ALARMEN   0x04
+#define CTRL_ALARM     0x02
+#define CTRL_TIMER     0x01
+
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+
+/* Module parameters */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver pcf8583_driver;
+
+#define get_ctrl(x)    ((struct pcf8583 *)i2c_get_clientdata(x))->ctrl
+#define set_ctrl(x, v) get_ctrl(x) = v
+
+#define CMOS_YEAR      (64 + 128)
+#define CMOS_CHECKSUM  (63)
+
+static int pcf8583_get_datetime(struct i2c_client *client, struct rtc_time *dt)
+{
+       unsigned char buf[8], addr[1] = { 1 };
+       struct i2c_msg msgs[2] = {
+               {
+                       .addr = client->addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = addr,
+               }, {
+                       .addr = client->addr,
+                       .flags = I2C_M_RD,
+                       .len = 6,
+                       .buf = buf,
+               }
+       };
+       int ret;
+
+       memset(buf, 0, sizeof(buf));
+
+       ret = i2c_transfer(client->adapter, msgs, 2);
+       if (ret == 2) {
+               dt->tm_year = buf[4] >> 6;
+               dt->tm_wday = buf[5] >> 5;
+
+               buf[4] &= 0x3f;
+               buf[5] &= 0x1f;
+
+               dt->tm_sec = BCD_TO_BIN(buf[1]);
+               dt->tm_min = BCD_TO_BIN(buf[2]);
+               dt->tm_hour = BCD_TO_BIN(buf[3]);
+               dt->tm_mday = BCD_TO_BIN(buf[4]);
+               dt->tm_mon = BCD_TO_BIN(buf[5]);
+       }
+
+       return ret == 2 ? 0 : -EIO;
+}
+
+static int pcf8583_set_datetime(struct i2c_client *client, struct rtc_time *dt, int datetoo)
+{
+       unsigned char buf[8];
+       int ret, len = 6;
+
+       buf[0] = 0;
+       buf[1] = get_ctrl(client) | 0x80;
+       buf[2] = 0;
+       buf[3] = BIN_TO_BCD(dt->tm_sec);
+       buf[4] = BIN_TO_BCD(dt->tm_min);
+       buf[5] = BIN_TO_BCD(dt->tm_hour);
+
+       if (datetoo) {
+               len = 8;
+               buf[6] = BIN_TO_BCD(dt->tm_mday) | (dt->tm_year << 6);
+               buf[7] = BIN_TO_BCD(dt->tm_mon)  | (dt->tm_wday << 5);
+       }
+
+       ret = i2c_master_send(client, (char *)buf, len);
+       if (ret != len)
+               return -EIO;
+
+       buf[1] = get_ctrl(client);
+       ret = i2c_master_send(client, (char *)buf, 2);
+
+       return ret == 2 ? 0 : -EIO;
+}
+
+static int pcf8583_get_ctrl(struct i2c_client *client, unsigned char *ctrl)
+{
+       *ctrl = get_ctrl(client);
+       return 0;
+}
+
+static int pcf8583_set_ctrl(struct i2c_client *client, unsigned char *ctrl)
+{
+       unsigned char buf[2];
+
+       buf[0] = 0;
+       buf[1] = *ctrl;
+       set_ctrl(client, *ctrl);
+
+       return i2c_master_send(client, (char *)buf, 2);
+}
+
+static int pcf8583_read_mem(struct i2c_client *client, struct rtc_mem *mem)
+{
+       unsigned char addr[1];
+       struct i2c_msg msgs[2] = {
+               {
+                       .addr = client->addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = addr,
+               }, {
+                       .addr = client->addr,
+                       .flags = I2C_M_RD,
+                       .len = mem->nr,
+                       .buf = mem->data,
+               }
+       };
+
+       if (mem->loc < 8)
+               return -EINVAL;
+
+       addr[0] = mem->loc;
+
+       return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
+}
+
+static int pcf8583_write_mem(struct i2c_client *client, struct rtc_mem *mem)
+{
+       unsigned char addr[1];
+       struct i2c_msg msgs[2] = {
+               {
+                       .addr = client->addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = addr,
+               }, {
+                       .addr = client->addr,
+                       .flags = I2C_M_NOSTART,
+                       .len = mem->nr,
+                       .buf = mem->data,
+               }
+       };
+
+       if (mem->loc < 8)
+               return -EINVAL;
+
+       addr[0] = mem->loc;
+
+       return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
+}
+
+static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       unsigned char ctrl, year[2];
+       struct rtc_mem mem = { CMOS_YEAR, sizeof(year), year };
+       int real_year, year_offset, err;
+
+       /*
+        * Ensure that the RTC is running.
+        */
+       pcf8583_get_ctrl(client, &ctrl);
+       if (ctrl & (CTRL_STOP | CTRL_HOLD)) {
+               unsigned char new_ctrl = ctrl & ~(CTRL_STOP | CTRL_HOLD);
+
+               printk(KERN_WARNING "RTC: resetting control %02x -> %02x\n",
+                      ctrl, new_ctrl);
+
+               if ((err = pcf8583_set_ctrl(client, &new_ctrl)) < 0)
+                       return err;
+       }
+
+       if (pcf8583_get_datetime(client, tm) ||
+           pcf8583_read_mem(client, &mem))
+               return -EIO;
+
+       real_year = year[0];
+
+       /*
+        * The RTC year holds the LSB two bits of the current
+        * year, which should reflect the LSB two bits of the
+        * CMOS copy of the year.  Any difference indicates
+        * that we have to correct the CMOS version.
+        */
+       year_offset = tm->tm_year - (real_year & 3);
+       if (year_offset < 0)
+               /*
+                * RTC year wrapped.  Adjust it appropriately.
+                */
+               year_offset += 4;
+
+       tm->tm_year = real_year + year_offset + year[1] * 100;
+
+       return 0;
+}
+
+static int pcf8583_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       unsigned char year[2], chk;
+       struct rtc_mem cmos_year  = { CMOS_YEAR, sizeof(year), year };
+       struct rtc_mem cmos_check = { CMOS_CHECKSUM, 1, &chk };
+       int ret;
+
+       /*
+        * The RTC's own 2-bit year must reflect the least
+        * significant two bits of the CMOS year.
+        */
+
+       ret = pcf8583_set_datetime(client, tm, 1);
+       if (ret)
+               return ret;
+
+       ret = pcf8583_read_mem(client, &cmos_check);
+       if (ret)
+               return ret;
+
+       ret = pcf8583_read_mem(client, &cmos_year);
+       if (ret)
+               return ret;
+
+       chk -= year[1] + year[0];
+
+       year[1] = tm->tm_year / 100;
+       year[0] = tm->tm_year % 100;
+
+       chk += year[1] + year[0];
+
+       ret = pcf8583_write_mem(client, &cmos_year);
+
+       if (ret)
+               return ret;
+
+       ret = pcf8583_write_mem(client, &cmos_check);
+
+       return ret;
+}
+
+static struct rtc_class_ops pcf8583_rtc_ops = {
+       .read_time      = pcf8583_rtc_read_time,
+       .set_time       = pcf8583_rtc_set_time,
+};
+
+static int pcf8583_probe(struct i2c_adapter *adap, int addr, int kind);
+
+static int pcf8583_attach(struct i2c_adapter *adap)
+{
+       return i2c_probe(adap, &addr_data, pcf8583_probe);
+}
+
+static int pcf8583_detach(struct i2c_client *client)
+{
+       int err;
+       struct pcf8583 *pcf = i2c_get_clientdata(client);
+       struct rtc_device *rtc = pcf->rtc;
+
+       if (rtc)
+               rtc_device_unregister(rtc);
+
+       if ((err = i2c_detach_client(client)))
+               return err;
+
+       kfree(pcf);
+       return 0;
+}
+
+static struct i2c_driver pcf8583_driver = {
+       .driver = {
+               .name   = "pcf8583",
+       },
+       .id             = I2C_DRIVERID_PCF8583,
+       .attach_adapter = pcf8583_attach,
+       .detach_client  = pcf8583_detach,
+};
+
+static int pcf8583_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+       struct pcf8583 *pcf;
+       struct i2c_client *client;
+       struct rtc_device *rtc;
+       unsigned char buf[1], ad[1] = { 0 };
+       int err;
+       struct i2c_msg msgs[2] = {
+               {
+                       .addr = addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = ad,
+               }, {
+                       .addr = addr,
+                       .flags = I2C_M_RD,
+                       .len = 1,
+                       .buf = buf,
+               }
+       };
+
+       pcf = kzalloc(sizeof(*pcf), GFP_KERNEL);
+       if (!pcf)
+               return -ENOMEM;
+
+       client = &pcf->client;
+
+       client->addr            = addr;
+       client->adapter = adap;
+       client->driver  = &pcf8583_driver;
+
+       strlcpy(client->name, pcf8583_driver.driver.name, I2C_NAME_SIZE);
+
+       if (i2c_transfer(client->adapter, msgs, 2) != 2) {
+               err = -EIO;
+               goto exit_kfree;
+       }
+
+       err = i2c_attach_client(client);
+
+       if (err)
+               goto exit_kfree;
+
+       rtc = rtc_device_register(pcf8583_driver.driver.name, &client->dev,
+                                 &pcf8583_rtc_ops, THIS_MODULE);
+
+       if (IS_ERR(rtc)) {
+               err = PTR_ERR(rtc);
+               goto exit_detach;
+       }
+
+       pcf->rtc = rtc;
+       i2c_set_clientdata(client, pcf);
+       set_ctrl(client, buf[0]);
+
+       return 0;
+
+exit_detach:
+       i2c_detach_client(client);
+
+exit_kfree:
+       kfree(pcf);
+
+       return err;
+}
+
+static __init int pcf8583_init(void)
+{
+       return i2c_add_driver(&pcf8583_driver);
+}
+
+static __exit void pcf8583_exit(void)
+{
+       i2c_del_driver(&pcf8583_driver);
+}
+
+module_init(pcf8583_init);
+module_exit(pcf8583_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("PCF8583 I2C RTC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
new file mode 100644 (file)
index 0000000..ee53863
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * drivers/rtc/rtc-pl031.c
+ *
+ * Real Time Clock interface for ARM AMBA PrimeCell 031 RTC
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2006 (c) MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/pm.h>
+
+#include <linux/amba/bus.h>
+
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/rtc.h>
+
+/*
+ * Register definitions
+ */
+#define        RTC_DR          0x00    /* Data read register */
+#define        RTC_MR          0x04    /* Match register */
+#define        RTC_LR          0x08    /* Data load register */
+#define        RTC_CR          0x0c    /* Control register */
+#define        RTC_IMSC        0x10    /* Interrupt mask and set register */
+#define        RTC_RIS         0x14    /* Raw interrupt status register */
+#define        RTC_MIS         0x18    /* Masked interrupt status register */
+#define        RTC_ICR         0x1c    /* Interrupt clear register */
+
+struct pl031_local {
+       struct rtc_device *rtc;
+       void __iomem *base;
+};
+
+static irqreturn_t pl031_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct rtc_device *rtc = dev_id;
+
+       rtc_update_irq(&rtc->class_dev, 1, RTC_AF);
+
+       return IRQ_HANDLED;
+}
+
+static int pl031_open(struct device *dev)
+{
+       /*
+        * We request IRQ in pl031_probe, so nothing to do here...
+        */
+       return 0;
+}
+
+static void pl031_release(struct device *dev)
+{
+}
+
+static int pl031_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+       struct pl031_local *ldata = dev_get_drvdata(dev);
+
+       switch (cmd) {
+       case RTC_AIE_OFF:
+               __raw_writel(1, ldata->base + RTC_MIS);
+               return 0;
+       case RTC_AIE_ON:
+               __raw_writel(0, ldata->base + RTC_MIS);
+               return 0;
+       }
+
+       return -ENOIOCTLCMD;
+}
+
+static int pl031_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct pl031_local *ldata = dev_get_drvdata(dev);
+
+       rtc_time_to_tm(__raw_readl(ldata->base + RTC_DR), tm);
+
+       return 0;
+}
+
+static int pl031_set_time(struct device *dev, struct rtc_time *tm)
+{
+       unsigned long time;
+       struct pl031_local *ldata = dev_get_drvdata(dev);
+
+       rtc_tm_to_time(tm, &time);
+       __raw_writel(time, ldata->base + RTC_LR);
+
+       return 0;
+}
+
+static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       struct pl031_local *ldata = dev_get_drvdata(dev);
+
+       rtc_time_to_tm(__raw_readl(ldata->base + RTC_MR), &alarm->time);
+       alarm->pending = __raw_readl(ldata->base + RTC_RIS);
+       alarm->enabled = __raw_readl(ldata->base + RTC_IMSC);
+
+       return 0;
+}
+
+static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       struct pl031_local *ldata = dev_get_drvdata(dev);
+       unsigned long time;
+
+       rtc_tm_to_time(&alarm->time, &time);
+
+       __raw_writel(time, ldata->base + RTC_MR);
+       __raw_writel(!alarm->enabled, ldata->base + RTC_MIS);
+
+       return 0;
+}
+
+static struct rtc_class_ops pl031_ops = {
+       .open = pl031_open,
+       .release = pl031_release,
+       .ioctl = pl031_ioctl,
+       .read_time = pl031_read_time,
+       .set_time = pl031_set_time,
+       .read_alarm = pl031_read_alarm,
+       .set_alarm = pl031_set_alarm,
+};
+
+static int pl031_remove(struct amba_device *adev)
+{
+       struct pl031_local *ldata = dev_get_drvdata(&adev->dev);
+
+       if (ldata) {
+               dev_set_drvdata(&adev->dev, NULL);
+               free_irq(adev->irq[0], ldata->rtc);
+               rtc_device_unregister(ldata->rtc);
+               iounmap(ldata->base);
+               kfree(ldata);
+       }
+
+       return 0;
+}
+
+static int pl031_probe(struct amba_device *adev, void *id)
+{
+       int ret;
+       struct pl031_local *ldata;
+
+
+       ldata = kmalloc(sizeof(struct pl031_local), GFP_KERNEL);
+       if (!ldata) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       dev_set_drvdata(&adev->dev, ldata);
+
+       ldata->base = ioremap(adev->res.start,
+                             adev->res.end - adev->res.start + 1);
+       if (!ldata->base) {
+               ret = -ENOMEM;
+               goto out_no_remap;
+       }
+
+       if (request_irq(adev->irq[0], pl031_interrupt, SA_INTERRUPT,
+                       "rtc-pl031", ldata->rtc)) {
+               ret = -EIO;
+               goto out_no_irq;
+       }
+
+       ldata->rtc = rtc_device_register("pl031", &adev->dev, &pl031_ops,
+                                        THIS_MODULE);
+       if (IS_ERR(ldata->rtc)) {
+               ret = PTR_ERR(ldata->rtc);
+               goto out_no_rtc;
+       }
+
+       return 0;
+
+out_no_rtc:
+       free_irq(adev->irq[0], ldata->rtc);
+out_no_irq:
+       iounmap(ldata->base);
+out_no_remap:
+       dev_set_drvdata(&adev->dev, NULL);
+       kfree(ldata);
+out:
+       return ret;
+}
+
+static struct amba_id pl031_ids[] __initdata = {
+       {
+                .id = 0x00041031,
+               .mask = 0x000fffff, },
+       {0, 0},
+};
+
+static struct amba_driver pl031_driver = {
+       .drv = {
+               .name = "rtc-pl031",
+       },
+       .id_table = pl031_ids,
+       .probe = pl031_probe,
+       .remove = pl031_remove,
+};
+
+static int __init pl031_init(void)
+{
+       return amba_driver_register(&pl031_driver);
+}
+
+static void __exit pl031_exit(void)
+{
+       amba_driver_unregister(&pl031_driver);
+}
+
+module_init(pl031_init);
+module_exit(pl031_exit);
+
+MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net");
+MODULE_DESCRIPTION("ARM AMBA PL031 RTC Driver");
+MODULE_LICENSE("GPL");
index a997529f8926e24e0d3161acabb4c30215c2d21f..ab486fbc828dab567357ab1d1ca04e2c5fc7d625 100644 (file)
@@ -229,8 +229,6 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd,
                spin_unlock_irq(&sa1100_rtc_lock);
                return 0;
        case RTC_PIE_ON:
-               if ((rtc_freq > 64) && !capable(CAP_SYS_RESOURCE))
-                       return -EACCES;
                spin_lock_irq(&sa1100_rtc_lock);
                OSMR1 = TIMER_FREQ/rtc_freq + OSCR;
                OIER |= OIER_E1;
@@ -242,8 +240,6 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd,
        case RTC_IRQP_SET:
                if (arg < 1 || arg > TIMER_FREQ)
                        return -EINVAL;
-               if ((arg > 64) && (!capable(CAP_SYS_RESOURCE)))
-                       return -EACCES;
                rtc_freq = arg;
                return 0;
        }
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c
new file mode 100644 (file)
index 0000000..a40f400
--- /dev/null
@@ -0,0 +1,264 @@
+/* drivers/rtc/rtc-v3020.c
+ *
+ * Copyright (C) 2006 8D Technologies inc.
+ * Copyright (C) 2004 Compulab Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Driver for the V3020 RTC
+ *
+ * Changelog:
+ *
+ *  10-May-2006: Raphael Assenat <raph@8d.com>
+ *                             - Converted to platform driver
+ *                             - Use the generic rtc class
+ *
+ *  ??-???-2004: Someone at Compulab
+ *                     - Initial driver creation.
+ *
+ */
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/types.h>
+#include <linux/bcd.h>
+#include <linux/rtc-v3020.h>
+
+#include <asm/io.h>
+
+#undef DEBUG
+
+struct v3020 {
+       void __iomem *ioaddress;
+       int leftshift;
+       struct rtc_device *rtc;
+};
+
+static void v3020_set_reg(struct v3020 *chip, unsigned char address,
+                       unsigned char data)
+{
+       int i;
+       unsigned char tmp;
+
+       tmp = address;
+       for (i = 0; i < 4; i++) {
+               writel((tmp & 1) << chip->leftshift, chip->ioaddress);
+               tmp >>= 1;
+       }
+
+       /* Commands dont have data */
+       if (!V3020_IS_COMMAND(address)) {
+               for (i = 0; i < 8; i++) {
+                       writel((data & 1) << chip->leftshift, chip->ioaddress);
+                       data >>= 1;
+               }
+       }
+}
+
+static unsigned char v3020_get_reg(struct v3020 *chip, unsigned char address)
+{
+       unsigned int data=0;
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               writel((address & 1) << chip->leftshift, chip->ioaddress);
+               address >>= 1;
+       }
+
+       for (i = 0; i < 8; i++) {
+               data >>= 1;
+               if (readl(chip->ioaddress) & (1 << chip->leftshift))
+                       data |= 0x80;
+       }
+
+       return data;
+}
+
+static int v3020_read_time(struct device *dev, struct rtc_time *dt)
+{
+       struct v3020 *chip = dev_get_drvdata(dev);
+       int tmp;
+
+       /* Copy the current time to ram... */
+       v3020_set_reg(chip, V3020_CMD_CLOCK2RAM, 0);
+
+       /* ...and then read constant values. */
+       tmp = v3020_get_reg(chip, V3020_SECONDS);
+       dt->tm_sec      = BCD2BIN(tmp);
+       tmp = v3020_get_reg(chip, V3020_MINUTES);
+       dt->tm_min      = BCD2BIN(tmp);
+       tmp = v3020_get_reg(chip, V3020_HOURS);
+       dt->tm_hour     = BCD2BIN(tmp);
+       tmp = v3020_get_reg(chip, V3020_MONTH_DAY);
+       dt->tm_mday     = BCD2BIN(tmp);
+       tmp = v3020_get_reg(chip, V3020_MONTH);
+       dt->tm_mon      = BCD2BIN(tmp);
+       tmp = v3020_get_reg(chip, V3020_WEEK_DAY);
+       dt->tm_wday     = BCD2BIN(tmp);
+       tmp = v3020_get_reg(chip, V3020_YEAR);
+       dt->tm_year = BCD2BIN(tmp)+100;
+
+#ifdef DEBUG
+       printk("\n%s : Read RTC values\n",__FUNCTION__);
+       printk("tm_hour: %i\n",dt->tm_hour);
+       printk("tm_min : %i\n",dt->tm_min);
+       printk("tm_sec : %i\n",dt->tm_sec);
+       printk("tm_year: %i\n",dt->tm_year);
+       printk("tm_mon : %i\n",dt->tm_mon);
+       printk("tm_mday: %i\n",dt->tm_mday);
+       printk("tm_wday: %i\n",dt->tm_wday);
+#endif
+
+       return 0;
+}
+
+
+static int v3020_set_time(struct device *dev, struct rtc_time *dt)
+{
+       struct v3020 *chip = dev_get_drvdata(dev);
+
+#ifdef DEBUG
+       printk("\n%s : Setting RTC values\n",__FUNCTION__);
+       printk("tm_sec : %i\n",dt->tm_sec);
+       printk("tm_min : %i\n",dt->tm_min);
+       printk("tm_hour: %i\n",dt->tm_hour);
+       printk("tm_mday: %i\n",dt->tm_mday);
+       printk("tm_wday: %i\n",dt->tm_wday);
+       printk("tm_year: %i\n",dt->tm_year);
+#endif
+
+       /* Write all the values to ram... */
+       v3020_set_reg(chip, V3020_SECONDS,      BIN2BCD(dt->tm_sec));
+       v3020_set_reg(chip, V3020_MINUTES,      BIN2BCD(dt->tm_min));
+       v3020_set_reg(chip, V3020_HOURS,        BIN2BCD(dt->tm_hour));
+       v3020_set_reg(chip, V3020_MONTH_DAY,    BIN2BCD(dt->tm_mday));
+       v3020_set_reg(chip, V3020_MONTH,        BIN2BCD(dt->tm_mon));
+       v3020_set_reg(chip, V3020_WEEK_DAY,     BIN2BCD(dt->tm_wday));
+       v3020_set_reg(chip, V3020_YEAR,         BIN2BCD(dt->tm_year % 100));
+
+       /* ...and set the clock. */
+       v3020_set_reg(chip, V3020_CMD_RAM2CLOCK, 0);
+
+       /* Compulab used this delay here. I dont know why,
+        * the datasheet does not specify a delay. */
+       /*mdelay(5);*/
+
+       return 0;
+}
+
+static struct rtc_class_ops v3020_rtc_ops = {
+       .read_time      = v3020_read_time,
+       .set_time       = v3020_set_time,
+};
+
+static int rtc_probe(struct platform_device *pdev)
+{
+       struct v3020_platform_data *pdata = pdev->dev.platform_data;
+       struct v3020 *chip;
+       struct rtc_device *rtc;
+       int retval = -EBUSY;
+       int i;
+       int temp;
+
+       if (pdev->num_resources != 1)
+               return -EBUSY;
+
+       if (pdev->resource[0].flags != IORESOURCE_MEM)
+               return -EBUSY;
+
+       if (pdev == NULL)
+               return -EBUSY;
+
+       chip = kzalloc(sizeof *chip, GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       chip->leftshift = pdata->leftshift;
+       chip->ioaddress = ioremap(pdev->resource[0].start, 1);
+       if (chip->ioaddress == NULL)
+               goto err_chip;
+
+       /* Make sure the v3020 expects a communication cycle
+        * by reading 8 times */
+       for (i = 0; i < 8; i++)
+               temp = readl(chip->ioaddress);
+
+       /* Test chip by doing a write/read sequence
+        * to the chip ram */
+       v3020_set_reg(chip, V3020_SECONDS, 0x33);
+       if(v3020_get_reg(chip, V3020_SECONDS) != 0x33) {
+               retval = -ENODEV;
+               goto err_io;
+       }
+
+       /* Make sure frequency measurment mode, test modes, and lock
+        * are all disabled */
+       v3020_set_reg(chip, V3020_STATUS_0, 0x0);
+
+       dev_info(&pdev->dev, "Chip available at physical address 0x%p,"
+               "data connected to D%d\n",
+               (void*)pdev->resource[0].start,
+               chip->leftshift);
+
+       platform_set_drvdata(pdev, chip);
+
+       rtc = rtc_device_register("v3020",
+                               &pdev->dev, &v3020_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc)) {
+               retval = PTR_ERR(rtc);
+               goto err_io;
+       }
+       chip->rtc = rtc;
+
+       return 0;
+
+err_io:
+       iounmap(chip->ioaddress);
+err_chip:
+       kfree(chip);
+
+       return retval;
+}
+
+static int rtc_remove(struct platform_device *dev)
+{
+       struct v3020 *chip = platform_get_drvdata(dev);
+       struct rtc_device *rtc = chip->rtc;
+
+       if (rtc)
+               rtc_device_unregister(rtc);
+
+       iounmap(chip->ioaddress);
+       kfree(chip);
+
+       return 0;
+}
+
+static struct platform_driver rtc_device_driver = {
+       .probe  = rtc_probe,
+       .remove = rtc_remove,
+       .driver = {
+               .name   = "v3020",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static __init int v3020_init(void)
+{
+       return platform_driver_register(&rtc_device_driver);
+}
+
+static __exit void v3020_exit(void)
+{
+       platform_driver_unregister(&rtc_device_driver);
+}
+
+module_init(v3020_init);
+module_exit(v3020_exit);
+
+MODULE_DESCRIPTION("V3020 RTC");
+MODULE_AUTHOR("Raphael Assenat");
+MODULE_LICENSE("GPL");
index 277596c302e30426262db9392be87355cfeb7114..33e029207e261cd2ce20f0bcb75375fa8380a768 100644 (file)
@@ -81,7 +81,6 @@ MODULE_LICENSE("GPL");
 
 #define RTC_FREQUENCY          32768
 #define MAX_PERIODIC_RATE      6553
-#define MAX_USER_PERIODIC_RATE 64
 
 static void __iomem *rtc1_base;
 static void __iomem *rtc2_base;
@@ -240,9 +239,6 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
                if (arg > MAX_PERIODIC_RATE)
                        return -EINVAL;
 
-               if (arg > MAX_USER_PERIODIC_RATE && capable(CAP_SYS_RESOURCE) == 0)
-                       return -EACCES;
-
                periodic_frequency = arg;
 
                count = RTC_FREQUENCY;
@@ -263,10 +259,6 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
                /* Doesn't support before 1900 */
                if (arg < 1900)
                        return -EINVAL;
-
-               if (capable(CAP_SYS_TIME) == 0)
-                       return -EACCES;
-
                epoch = arg;
                break;
        default:
index 56fa6916889850ddf814a5e140afb6fab6c5d094..a4c53c172db6440bc9e0892169dd7ec835e012ef 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/cpumask.h>
 #include <linux/smp.h>
 #include <linux/init.h>
+#include <linux/reboot.h>
 #include <asm/atomic.h>
 #include <asm/ptrace.h>
 #include <asm/sigp.h>
@@ -66,8 +67,6 @@ do_machine_quiesce(void)
 }
 #endif
 
-extern void ctrl_alt_del(void);
-
 /* Handler for quiesce event. Start shutdown procedure. */
 static void
 sclp_quiesce_handler(struct evbuf_header *evbuf)
index 5ae684c011f898ab295d692eff361b9278d8a7bd..31b8a5f6116f83fc88a30e4459e4fe6dbc2590b0 100644 (file)
@@ -71,7 +71,6 @@ flash_mmap(struct file *file, struct vm_area_struct *vma)
        if (vma->vm_end - (vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT)) > size)
                size = vma->vm_end - (vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT));
 
-       vma->vm_flags |= (VM_SHM | VM_LOCKED);
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
        if (io_remap_pfn_range(vma, vma->vm_start, addr, size, vma->vm_page_prot))
index dfdd6be551f3ecca3a878b159514ccf96c0c5dce..ddcd330b9e891a46291650b12d917f90923c5277 100644 (file)
@@ -623,7 +623,7 @@ static int vfc_mmap(struct file *file, struct vm_area_struct *vma)
                map_size = sizeof(struct vfc_regs);
 
        vma->vm_flags |=
-               (VM_SHM | VM_LOCKED | VM_IO | VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE);
+               (VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE);
        map_offset = (unsigned int) (long)dev->phys_regs;
        ret = io_remap_pfn_range(vma, vma->vm_start,
                                  MK_IOSPACE_PFN(dev->which_io,
index 2a419634b256d9d5598cadbfe04607fc092a8bef..5ee47555a8af62a35ab819bf7c3455e2843fca08 100644 (file)
@@ -17316,7 +17316,7 @@ AdvWaitEEPCmd(AdvPortAddr iop_base)
 /*
  * Write the EEPROM from 'cfg_buf'.
  */
-void
+void __init
 AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
 {
     ushort *wbuf;
@@ -17383,7 +17383,7 @@ AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
 /*
  * Write the EEPROM from 'cfg_buf'.
  */
-void
+void __init
 AdvSet38C0800EEPConfig(AdvPortAddr iop_base,
                        ADVEEP_38C0800_CONFIG *cfg_buf)
 {
@@ -17451,7 +17451,7 @@ AdvSet38C0800EEPConfig(AdvPortAddr iop_base,
 /*
  * Write the EEPROM from 'cfg_buf'.
  */
-void
+void __init
 AdvSet38C1600EEPConfig(AdvPortAddr iop_base,
                        ADVEEP_38C1600_CONFIG *cfg_buf)
 {
index e31fadd619044ed11b095caacebde9f407492890..118206d68c6c9702030a3b66538abbcb30cc192d 100644 (file)
@@ -43,9 +43,6 @@
 
 /* #define DEBUG_MAC_ESP */
 
-#define mac_turnon_irq(x)      mac_enable_irq(x)
-#define mac_turnoff_irq(x)     mac_disable_irq(x)
-
 extern void esp_handle(struct NCR_ESP *esp);
 extern void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
 
@@ -639,13 +636,13 @@ static void dma_init_write(struct NCR_ESP * esp, char * vaddress, int length)
 
 static void dma_ints_off(struct NCR_ESP * esp)
 {
-       mac_turnoff_irq(esp->irq);
+       disable_irq(esp->irq);
 }
 
 
 static void dma_ints_on(struct NCR_ESP * esp)
 {
-       mac_turnon_irq(esp->irq);
+       enable_irq(esp->irq);
 }
 
 /*
index 777f9bcd117932af31742e90b46d20b398309a13..a942a21dd87eaf78610e04f86933ce76b0ef7815 100644 (file)
@@ -65,9 +65,6 @@
 #define RESET_BOOT
 #define DRIVER_SETUP
 
-#define        ENABLE_IRQ()    mac_enable_irq( IRQ_MAC_SCSI ); 
-#define        DISABLE_IRQ()   mac_disable_irq( IRQ_MAC_SCSI );
-
 extern void via_scsi_clear(void);
 
 #ifdef RESET_BOOT
@@ -351,7 +348,7 @@ static void mac_scsi_reset_boot(struct Scsi_Host *instance)
        printk(KERN_INFO "Macintosh SCSI: resetting the SCSI bus..." );
 
        /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
-       mac_disable_irq(IRQ_MAC_SCSI);
+       disable_irq(IRQ_MAC_SCSI);
 
        /* get in phase */
        NCR5380_write( TARGET_COMMAND_REG,
@@ -369,7 +366,7 @@ static void mac_scsi_reset_boot(struct Scsi_Host *instance)
                barrier();
 
        /* switch on SCSI IRQ again */
-       mac_enable_irq(IRQ_MAC_SCSI);
+       enable_irq(IRQ_MAC_SCSI);
 
        printk(KERN_INFO " done\n" );
 }
index bec1424eda850f0f5b121ed9e6fcb15c10506a7b..b7caf60638e81da07ac3ae6728529df117a6fe05 100644 (file)
@@ -714,7 +714,7 @@ megaraid_io_detach(adapter_t *adapter)
  * . Allocate memory required for all the commands
  * . Use internal library of FW routines, build up complete soft state
  */
-static int __init
+static int __devinit
 megaraid_init_mbox(adapter_t *adapter)
 {
        struct pci_dev          *pdev;
index cc990bed9683a61f9b9a5488710c9f8206807277..2e2c1eb156364d4f7c10a6c138013f603792dacc 100644 (file)
@@ -332,11 +332,11 @@ static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp)
     struct scatterlist *sg = sp->SCp.buffer;
 
     while (sz >= 0) {
-           sg[sz].dvma_address = dvma_map((unsigned long)page_address(sg[sz].page) +
+           sg[sz].dma_address = dvma_map((unsigned long)page_address(sg[sz].page) +
                                           sg[sz].offset, sg[sz].length);
            sz--;
     }
-    sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dvma_address);
+    sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dma_address);
 }
 
 static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp)
@@ -350,14 +350,14 @@ static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp)
     struct scatterlist *sg = (struct scatterlist *)sp->buffer;
                         
     while(sz >= 0) {
-        dvma_unmap((char *)sg[sz].dvma_address);
+        dvma_unmap((char *)sg[sz].dma_address);
         sz--;
     }
 }
 
 static void dma_advance_sg (Scsi_Cmnd *sp)
 {
-    sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address);
+    sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dma_address);
 }
 
 static int sun3x_esp_release(struct Scsi_Host *instance)
index e55f0ee7e7e43c1b25757d48053ea20b70312e69..574955b78a2449d624d5bbfb6577a7e77daa2678 100644 (file)
@@ -1391,7 +1391,7 @@ static int wd7000_proc_info(struct Scsi_Host *host, char *buffer, char **start,
  *
  */
 
-static int wd7000_detect(struct scsi_host_template *tpnt)
+static __init int wd7000_detect(struct scsi_host_template *tpnt)
 {
        short present = 0, biosaddr_ptr, sig_ptr, i, pass;
        short biosptr[NUM_CONFIGS];
index 5a2840aeb547d26170557c03f531e592391e3091..168ede7902bdb9528e930981242c5f77c9bf6331 100644 (file)
@@ -86,6 +86,11 @@ config FB_FIRMWARE_EDID
         combination with certain motherboards and monitors are known to
         suffer from this problem.
 
+config FB_BACKLIGHT
+       bool
+       depends on FB
+       default n
+
 config FB_MODE_HELPERS
         bool "Enable Video Mode Handling Helpers"
         depends on FB
@@ -717,6 +722,16 @@ config FB_NVIDIA_I2C
          independently validate video mode parameters, you should say Y
          here.
 
+config FB_NVIDIA_BACKLIGHT
+       bool "Support for backlight control"
+       depends on FB_NVIDIA && PPC_PMAC
+       select FB_BACKLIGHT
+       select BACKLIGHT_LCD_SUPPORT
+       select BACKLIGHT_CLASS_DEVICE
+       default y
+       help
+         Say Y here if you want to control the backlight of your display.
+
 config FB_RIVA
        tristate "nVidia Riva support"
        depends on FB && PCI
@@ -755,6 +770,16 @@ config FB_RIVA_DEBUG
          of debugging informations to provide to the maintainer when
          something goes wrong.
 
+config FB_RIVA_BACKLIGHT
+       bool "Support for backlight control"
+       depends on FB_RIVA && PPC_PMAC
+       select FB_BACKLIGHT
+       select BACKLIGHT_LCD_SUPPORT
+       select BACKLIGHT_CLASS_DEVICE
+       default y
+       help
+         Say Y here if you want to control the backlight of your display.
+
 config FB_I810
        tristate "Intel 810/815 support (EXPERIMENTAL)"
        depends on FB && EXPERIMENTAL && PCI && X86_32
@@ -993,6 +1018,7 @@ config FB_RADEON
 
          There is a product page at
          http://apps.ati.com/ATIcompare/
+
 config FB_RADEON_I2C
        bool "DDC/I2C for ATI Radeon support"
        depends on FB_RADEON
@@ -1000,6 +1026,16 @@ config FB_RADEON_I2C
        help
          Say Y here if you want DDC/I2C support for your Radeon board. 
 
+config FB_RADEON_BACKLIGHT
+       bool "Support for backlight control"
+       depends on FB_RADEON && PPC_PMAC
+       select FB_BACKLIGHT
+       select BACKLIGHT_LCD_SUPPORT
+       select BACKLIGHT_CLASS_DEVICE
+       default y
+       help
+         Say Y here if you want to control the backlight of your display.
+
 config FB_RADEON_DEBUG
        bool "Lots of debug output from Radeon driver"
        depends on FB_RADEON
@@ -1024,6 +1060,16 @@ config FB_ATY128
          To compile this driver as a module, choose M here: the
          module will be called aty128fb.
 
+config FB_ATY128_BACKLIGHT
+       bool "Support for backlight control"
+       depends on FB_ATY128 && PPC_PMAC
+       select FB_BACKLIGHT
+       select BACKLIGHT_LCD_SUPPORT
+       select BACKLIGHT_CLASS_DEVICE
+       default y
+       help
+         Say Y here if you want to control the backlight of your display.
+
 config FB_ATY
        tristate "ATI Mach64 display support" if PCI || ATARI
        depends on FB && !SPARC32
@@ -1066,6 +1112,16 @@ config FB_ATY_GX
          is at
          <http://support.ati.com/products/pc/mach64/graphics_xpression.html>.
 
+config FB_ATY_BACKLIGHT
+       bool "Support for backlight control"
+       depends on FB_ATY && PPC_PMAC
+       select FB_BACKLIGHT
+       select BACKLIGHT_LCD_SUPPORT
+       select BACKLIGHT_CLASS_DEVICE
+       default y
+       help
+         Say Y here if you want to control the backlight of your display.
+
 config FB_S3TRIO
        bool "S3 Trio display support"
        depends on (FB = y) && PPC && BROKEN
index 18521397a6e3d6ad19ddd9f258ffa656f7bf5f44..a6cc0e9ec7905393584206dd203c33fdc9b444e8 100644 (file)
@@ -10,5 +10,6 @@ atyfb-objs                    := $(atyfb-y)
 
 radeonfb-y                     := radeon_base.o radeon_pm.o radeon_monitor.o radeon_accel.o
 radeonfb-$(CONFIG_FB_RADEON_I2C)       += radeon_i2c.o
+radeonfb-$(CONFIG_FB_RADEON_BACKLIGHT) += radeon_backlight.o
 radeonfb-objs                  := $(radeonfb-y)
 
index f7bbff4ddc6afcb06dc82ef812c716fb1281d62a..db878fd55fb2d8c065be5f970276cb5b4cae064f 100644 (file)
@@ -64,6 +64,7 @@
 #include <linux/pci.h>
 #include <linux/ioport.h>
 #include <linux/console.h>
+#include <linux/backlight.h>
 #include <asm/io.h>
 
 #ifdef CONFIG_PPC_PMAC
@@ -480,16 +481,6 @@ static struct fb_ops aty128fb_ops = {
        .fb_imageblit   = cfb_imageblit,
 };
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int aty128_set_backlight_enable(int on, int level, void* data);
-static int aty128_set_backlight_level(int level, void* data);
-
-static struct backlight_controller aty128_backlight_controller = {
-       aty128_set_backlight_enable,
-       aty128_set_backlight_level
-};
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
     /*
      * Functions to read from/write to the mmio registers
      * - endian conversions may possibly be avoided by
@@ -1258,19 +1249,35 @@ static void aty128_set_crt_enable(struct aty128fb_par *par, int on)
 static void aty128_set_lcd_enable(struct aty128fb_par *par, int on)
 {
        u32 reg;
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+       struct fb_info *info = pci_get_drvdata(par->pdev);
+#endif
 
        if (on) {
                reg = aty_ld_le32(LVDS_GEN_CNTL);
                reg |= LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION;
                reg &= ~LVDS_DISPLAY_DIS;
                aty_st_le32(LVDS_GEN_CNTL, reg);
-#ifdef CONFIG_PMAC_BACKLIGHT
-               aty128_set_backlight_enable(get_backlight_enable(),
-                                           get_backlight_level(), par);
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+               mutex_lock(&info->bl_mutex);
+               if (info->bl_dev) {
+                       down(&info->bl_dev->sem);
+                       info->bl_dev->props->update_status(info->bl_dev);
+                       up(&info->bl_dev->sem);
+               }
+               mutex_unlock(&info->bl_mutex);
 #endif 
        } else {
-#ifdef CONFIG_PMAC_BACKLIGHT
-               aty128_set_backlight_enable(0, 0, par);
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+               mutex_lock(&info->bl_mutex);
+               if (info->bl_dev) {
+                       down(&info->bl_dev->sem);
+                       info->bl_dev->props->brightness = 0;
+                       info->bl_dev->props->power = FB_BLANK_POWERDOWN;
+                       info->bl_dev->props->update_status(info->bl_dev);
+                       up(&info->bl_dev->sem);
+               }
+               mutex_unlock(&info->bl_mutex);
 #endif 
                reg = aty_ld_le32(LVDS_GEN_CNTL);
                reg |= LVDS_DISPLAY_DIS;
@@ -1691,6 +1698,184 @@ static int __init aty128fb_setup(char *options)
 }
 #endif  /*  MODULE  */
 
+/* Backlight */
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+#define MAX_LEVEL 0xFF
+
+static struct backlight_properties aty128_bl_data;
+
+static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
+               int level)
+{
+       struct fb_info *info = pci_get_drvdata(par->pdev);
+       int atylevel;
+
+       /* Get and convert the value */
+       mutex_lock(&info->bl_mutex);
+       atylevel = MAX_LEVEL -
+               (info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL);
+       mutex_unlock(&info->bl_mutex);
+
+       if (atylevel < 0)
+               atylevel = 0;
+       else if (atylevel > MAX_LEVEL)
+               atylevel = MAX_LEVEL;
+
+       return atylevel;
+}
+
+/* We turn off the LCD completely instead of just dimming the backlight.
+ * This provides greater power saving and the display is useless without
+ * backlight anyway
+ */
+#define BACKLIGHT_LVDS_OFF
+/* That one prevents proper CRT output with LCD off */
+#undef BACKLIGHT_DAC_OFF
+
+static int aty128_bl_update_status(struct backlight_device *bd)
+{
+       struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
+       unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
+       int level;
+
+       if (bd->props->power != FB_BLANK_UNBLANK ||
+           bd->props->fb_blank != FB_BLANK_UNBLANK ||
+           !par->lcd_on)
+               level = 0;
+       else
+               level = bd->props->brightness;
+
+       reg |= LVDS_BL_MOD_EN | LVDS_BLON;
+       if (level > 0) {
+               reg |= LVDS_DIGION;
+               if (!(reg & LVDS_ON)) {
+                       reg &= ~LVDS_BLON;
+                       aty_st_le32(LVDS_GEN_CNTL, reg);
+                       aty_ld_le32(LVDS_GEN_CNTL);
+                       mdelay(10);
+                       reg |= LVDS_BLON;
+                       aty_st_le32(LVDS_GEN_CNTL, reg);
+               }
+               reg &= ~LVDS_BL_MOD_LEVEL_MASK;
+               reg |= (aty128_bl_get_level_brightness(par, level) << LVDS_BL_MOD_LEVEL_SHIFT);
+#ifdef BACKLIGHT_LVDS_OFF
+               reg |= LVDS_ON | LVDS_EN;
+               reg &= ~LVDS_DISPLAY_DIS;
+#endif
+               aty_st_le32(LVDS_GEN_CNTL, reg);
+#ifdef BACKLIGHT_DAC_OFF
+               aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));
+#endif
+       } else {
+               reg &= ~LVDS_BL_MOD_LEVEL_MASK;
+               reg |= (aty128_bl_get_level_brightness(par, 0) << LVDS_BL_MOD_LEVEL_SHIFT);
+#ifdef BACKLIGHT_LVDS_OFF
+               reg |= LVDS_DISPLAY_DIS;
+               aty_st_le32(LVDS_GEN_CNTL, reg);
+               aty_ld_le32(LVDS_GEN_CNTL);
+               udelay(10);
+               reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);
+#endif
+               aty_st_le32(LVDS_GEN_CNTL, reg);
+#ifdef BACKLIGHT_DAC_OFF
+               aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);
+#endif
+       }
+
+       return 0;
+}
+
+static int aty128_bl_get_brightness(struct backlight_device *bd)
+{
+       return bd->props->brightness;
+}
+
+static struct backlight_properties aty128_bl_data = {
+       .owner          = THIS_MODULE,
+       .get_brightness = aty128_bl_get_brightness,
+       .update_status  = aty128_bl_update_status,
+       .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
+};
+
+static void aty128_bl_init(struct aty128fb_par *par)
+{
+       struct fb_info *info = pci_get_drvdata(par->pdev);
+       struct backlight_device *bd;
+       char name[12];
+
+       /* Could be extended to Rage128Pro LVDS output too */
+       if (par->chip_gen != rage_M3)
+               return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       if (!pmac_has_backlight_type("ati"))
+               return;
+#endif
+
+       snprintf(name, sizeof(name), "aty128bl%d", info->node);
+
+       bd = backlight_device_register(name, par, &aty128_bl_data);
+       if (IS_ERR(bd)) {
+               info->bl_dev = NULL;
+               printk("aty128: Backlight registration failed\n");
+               goto error;
+       }
+
+       mutex_lock(&info->bl_mutex);
+       info->bl_dev = bd;
+       fb_bl_default_curve(info, 0,
+                63 * FB_BACKLIGHT_MAX / MAX_LEVEL,
+               219 * FB_BACKLIGHT_MAX / MAX_LEVEL);
+       mutex_unlock(&info->bl_mutex);
+
+       up(&bd->sem);
+       bd->props->brightness = aty128_bl_data.max_brightness;
+       bd->props->power = FB_BLANK_UNBLANK;
+       bd->props->update_status(bd);
+       down(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       mutex_lock(&pmac_backlight_mutex);
+       if (!pmac_backlight)
+               pmac_backlight = bd;
+       mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+       printk("aty128: Backlight initialized (%s)\n", name);
+
+       return;
+
+error:
+       return;
+}
+
+static void aty128_bl_exit(struct aty128fb_par *par)
+{
+       struct fb_info *info = pci_get_drvdata(par->pdev);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       mutex_lock(&pmac_backlight_mutex);
+#endif
+
+       mutex_lock(&info->bl_mutex);
+       if (info->bl_dev) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+               if (pmac_backlight == info->bl_dev)
+                       pmac_backlight = NULL;
+#endif
+
+               backlight_device_unregister(info->bl_dev);
+               info->bl_dev = NULL;
+
+               printk("aty128: Backlight unloaded\n");
+       }
+       mutex_unlock(&info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
+#endif /* CONFIG_FB_ATY128_BACKLIGHT */
 
 /*
  *  Initialisation
@@ -1835,17 +2020,15 @@ static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *
        if (register_framebuffer(info) < 0)
                return 0;
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-       /* Could be extended to Rage128Pro LVDS output too */
-       if (par->chip_gen == rage_M3)
-               register_backlight_controller(&aty128_backlight_controller, par, "ati");
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
        par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
        par->pdev = pdev;
        par->asleep = 0;
        par->lock_blank = 0;
-       
+
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+       aty128_bl_init(par);
+#endif
+
        printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",
               info->node, info->fix.id, video_card);
 
@@ -1981,6 +2164,10 @@ static void __devexit aty128_remove(struct pci_dev *pdev)
 
        par = info->par;
 
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+       aty128_bl_exit(par);
+#endif
+
        unregister_framebuffer(info);
 #ifdef CONFIG_MTRR
        if (par->mtrr.vram_valid)
@@ -2011,10 +2198,14 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
        if (par->lock_blank || par->asleep)
                return 0;
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-       if (machine_is(powermac) && blank)
-               set_backlight_enable(0);
-#endif /* CONFIG_PMAC_BACKLIGHT */
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+       if (machine_is(powermac) && blank) {
+               down(&fb->bl_dev->sem);
+               fb->bl_dev->props->power = FB_BLANK_POWERDOWN;
+               fb->bl_dev->props->update_status(fb->bl_dev);
+               up(&fb->bl_dev->sem);
+       }
+#endif
 
        if (blank & FB_BLANK_VSYNC_SUSPEND)
                state |= 2;
@@ -2029,10 +2220,14 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
                aty128_set_crt_enable(par, par->crt_on && !blank);
                aty128_set_lcd_enable(par, par->lcd_on && !blank);
        }
-#ifdef CONFIG_PMAC_BACKLIGHT
-       if (machine_is(powermac) && !blank)
-               set_backlight_enable(1);
-#endif /* CONFIG_PMAC_BACKLIGHT */
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+       if (machine_is(powermac) && !blank) {
+               down(&fb->bl_dev->sem);
+               fb->bl_dev->props->power = FB_BLANK_UNBLANK;
+               fb->bl_dev->props->update_status(fb->bl_dev);
+               up(&fb->bl_dev->sem);
+       }
+#endif
        return 0;
 }
 
@@ -2138,73 +2333,6 @@ static int aty128fb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
        return -EINVAL;
 }
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int backlight_conv[] = {
-       0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
-       0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
-};
-
-/* We turn off the LCD completely instead of just dimming the backlight.
- * This provides greater power saving and the display is useless without
- * backlight anyway
- */
-#define BACKLIGHT_LVDS_OFF
-/* That one prevents proper CRT output with LCD off */
-#undef BACKLIGHT_DAC_OFF
-
-static int aty128_set_backlight_enable(int on, int level, void *data)
-{
-       struct aty128fb_par *par = data;
-       unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
-
-       if (!par->lcd_on)
-               on = 0;
-       reg |= LVDS_BL_MOD_EN | LVDS_BLON;
-       if (on && level > BACKLIGHT_OFF) {
-               reg |= LVDS_DIGION;
-               if (!(reg & LVDS_ON)) {
-                       reg &= ~LVDS_BLON;
-                       aty_st_le32(LVDS_GEN_CNTL, reg);
-                       (void)aty_ld_le32(LVDS_GEN_CNTL);
-                       mdelay(10);
-                       reg |= LVDS_BLON;
-                       aty_st_le32(LVDS_GEN_CNTL, reg);
-               }
-               reg &= ~LVDS_BL_MOD_LEVEL_MASK;
-               reg |= (backlight_conv[level] << LVDS_BL_MOD_LEVEL_SHIFT);
-#ifdef BACKLIGHT_LVDS_OFF
-               reg |= LVDS_ON | LVDS_EN;
-               reg &= ~LVDS_DISPLAY_DIS;
-#endif
-               aty_st_le32(LVDS_GEN_CNTL, reg);
-#ifdef BACKLIGHT_DAC_OFF
-               aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));
-#endif         
-       } else {
-               reg &= ~LVDS_BL_MOD_LEVEL_MASK;
-               reg |= (backlight_conv[0] << LVDS_BL_MOD_LEVEL_SHIFT);
-#ifdef BACKLIGHT_LVDS_OFF
-               reg |= LVDS_DISPLAY_DIS;
-               aty_st_le32(LVDS_GEN_CNTL, reg);
-               (void)aty_ld_le32(LVDS_GEN_CNTL);
-               udelay(10);
-               reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);
-#endif         
-               aty_st_le32(LVDS_GEN_CNTL, reg);
-#ifdef BACKLIGHT_DAC_OFF
-               aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);
-#endif         
-       }
-
-       return 0;
-}
-
-static int aty128_set_backlight_level(int level, void* data)
-{
-       return aty128_set_backlight_enable(1, level, data);
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
 #if 0
     /*
      *  Accelerated functions
index e9b7a64c1ac4009fee66247bcf2e5697a327e5d3..43d2cb58af87822ddb54c0faa14d36298c18370b 100644 (file)
@@ -151,6 +151,7 @@ struct atyfb_par {
        int lock_blank;
        unsigned long res_start;
        unsigned long res_size;
+       struct pci_dev *pdev;
 #ifdef __sparc__
        struct pci_mmap_map *mmap_map;
        u8 mmaped;
index c054bb28b1c4a1a74cba6c47bd388394514718eb..c5185f7cf4bad641e9acb030a63b2a2073403321 100644 (file)
@@ -66,6 +66,7 @@
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
+#include <linux/backlight.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -2115,45 +2116,142 @@ static int atyfb_pci_resume(struct pci_dev *pdev)
 
 #endif /*  defined(CONFIG_PM) && defined(CONFIG_PCI) */
 
-#ifdef CONFIG_PMAC_BACKLIGHT
+/* Backlight */
+#ifdef CONFIG_FB_ATY_BACKLIGHT
+#define MAX_LEVEL 0xFF
 
-    /*
-     *   LCD backlight control
-     */
+static struct backlight_properties aty_bl_data;
 
-static int backlight_conv[] = {
-       0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d,
-       0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff
-};
+static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
+{
+       struct fb_info *info = pci_get_drvdata(par->pdev);
+       int atylevel;
+
+       /* Get and convert the value */
+       mutex_lock(&info->bl_mutex);
+       atylevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
+       mutex_unlock(&info->bl_mutex);
+
+       if (atylevel < 0)
+               atylevel = 0;
+       else if (atylevel > MAX_LEVEL)
+               atylevel = MAX_LEVEL;
 
-static int aty_set_backlight_enable(int on, int level, void *data)
+       return atylevel;
+}
+
+static int aty_bl_update_status(struct backlight_device *bd)
 {
-       struct fb_info *info = (struct fb_info *) data;
-       struct atyfb_par *par = (struct atyfb_par *) info->par;
+       struct atyfb_par *par = class_get_devdata(&bd->class_dev);
        unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
+       int level;
+
+       if (bd->props->power != FB_BLANK_UNBLANK ||
+           bd->props->fb_blank != FB_BLANK_UNBLANK)
+               level = 0;
+       else
+               level = bd->props->brightness;
 
        reg |= (BLMOD_EN | BIASMOD_EN);
-       if (on && level > BACKLIGHT_OFF) {
+       if (level > 0) {
                reg &= ~BIAS_MOD_LEVEL_MASK;
-               reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT);
+               reg |= (aty_bl_get_level_brightness(par, level) << BIAS_MOD_LEVEL_SHIFT);
        } else {
                reg &= ~BIAS_MOD_LEVEL_MASK;
-               reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT);
+               reg |= (aty_bl_get_level_brightness(par, 0) << BIAS_MOD_LEVEL_SHIFT);
        }
        aty_st_lcd(LCD_MISC_CNTL, reg, par);
+
        return 0;
 }
 
-static int aty_set_backlight_level(int level, void *data)
+static int aty_bl_get_brightness(struct backlight_device *bd)
 {
-       return aty_set_backlight_enable(1, level, data);
+       return bd->props->brightness;
 }
 
-static struct backlight_controller aty_backlight_controller = {
-       aty_set_backlight_enable,
-       aty_set_backlight_level
+static struct backlight_properties aty_bl_data = {
+       .owner    = THIS_MODULE,
+       .get_brightness = aty_bl_get_brightness,
+       .update_status  = aty_bl_update_status,
+       .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
 };
-#endif /* CONFIG_PMAC_BACKLIGHT */
+
+static void aty_bl_init(struct atyfb_par *par)
+{
+       struct fb_info *info = pci_get_drvdata(par->pdev);
+       struct backlight_device *bd;
+       char name[12];
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       if (!pmac_has_backlight_type("ati"))
+               return;
+#endif
+
+       snprintf(name, sizeof(name), "atybl%d", info->node);
+
+       bd = backlight_device_register(name, par, &aty_bl_data);
+       if (IS_ERR(bd)) {
+               info->bl_dev = NULL;
+               printk("aty: Backlight registration failed\n");
+               goto error;
+       }
+
+       mutex_lock(&info->bl_mutex);
+       info->bl_dev = bd;
+       fb_bl_default_curve(info, 0,
+               0x3F * FB_BACKLIGHT_MAX / MAX_LEVEL,
+               0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL);
+       mutex_unlock(&info->bl_mutex);
+
+       up(&bd->sem);
+       bd->props->brightness = aty_bl_data.max_brightness;
+       bd->props->power = FB_BLANK_UNBLANK;
+       bd->props->update_status(bd);
+       down(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       mutex_lock(&pmac_backlight_mutex);
+       if (!pmac_backlight)
+               pmac_backlight = bd;
+       mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+       printk("aty: Backlight initialized (%s)\n", name);
+
+       return;
+
+error:
+       return;
+}
+
+static void aty_bl_exit(struct atyfb_par *par)
+{
+       struct fb_info *info = pci_get_drvdata(par->pdev);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       mutex_lock(&pmac_backlight_mutex);
+#endif
+
+       mutex_lock(&info->bl_mutex);
+       if (info->bl_dev) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+               if (pmac_backlight == info->bl_dev)
+                       pmac_backlight = NULL;
+#endif
+
+               backlight_device_unregister(info->bl_dev);
+
+               printk("aty: Backlight unloaded\n");
+       }
+       mutex_unlock(&info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
+
+#endif /* CONFIG_FB_ATY_BACKLIGHT */
 
 static void __init aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
 {
@@ -2513,9 +2611,13 @@ static int __init aty_init(struct fb_info *info, const char *name)
                /* these bits let the 101 powerbook wake up from sleep -- paulus */
                aty_st_lcd(POWER_MANAGEMENT, aty_ld_lcd(POWER_MANAGEMENT, par)
                           | (USE_F32KHZ | TRISTATE_MEM_EN), par);
-       } else if (M64_HAS(MOBIL_BUS))
-               register_backlight_controller(&aty_backlight_controller, info, "ati");
-#endif /* CONFIG_PMAC_BACKLIGHT */
+       } else
+#endif
+       if (M64_HAS(MOBIL_BUS)) {
+#ifdef CONFIG_FB_ATY_BACKLIGHT
+               aty_bl_init (par);
+#endif
+       }
 
        memset(&var, 0, sizeof(var));
 #ifdef CONFIG_PPC
@@ -2674,8 +2776,16 @@ static int atyfb_blank(int blank, struct fb_info *info)
                return 0;
 
 #ifdef CONFIG_PMAC_BACKLIGHT
-       if (machine_is(powermac) && blank > FB_BLANK_NORMAL)
-               set_backlight_enable(0);
+       if (machine_is(powermac) && blank > FB_BLANK_NORMAL) {
+               mutex_lock(&info->bl_mutex);
+               if (info->bl_dev) {
+                       down(&info->bl_dev->sem);
+                       info->bl_dev->props->power = FB_BLANK_POWERDOWN;
+                       info->bl_dev->props->update_status(info->bl_dev);
+                       up(&info->bl_dev->sem);
+               }
+               mutex_unlock(&info->bl_mutex);
+       }
 #elif defined(CONFIG_FB_ATY_GENERIC_LCD)
        if (par->lcd_table && blank > FB_BLANK_NORMAL &&
            (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
@@ -2706,8 +2816,16 @@ static int atyfb_blank(int blank, struct fb_info *info)
        aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par);
 
 #ifdef CONFIG_PMAC_BACKLIGHT
-       if (machine_is(powermac) && blank <= FB_BLANK_NORMAL)
-               set_backlight_enable(1);
+       if (machine_is(powermac) && blank <= FB_BLANK_NORMAL) {
+               mutex_lock(&info->bl_mutex);
+               if (info->bl_dev) {
+                       down(&info->bl_dev->sem);
+                       info->bl_dev->props->power = FB_BLANK_UNBLANK;
+                       info->bl_dev->props->update_status(info->bl_dev);
+                       up(&info->bl_dev->sem);
+               }
+               mutex_unlock(&info->bl_mutex);
+       }
 #elif defined(CONFIG_FB_ATY_GENERIC_LCD)
        if (par->lcd_table && blank <= FB_BLANK_NORMAL &&
            (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
@@ -3440,6 +3558,7 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi
        par->res_start = res_start;
        par->res_size = res_size;
        par->irq = pdev->irq;
+       par->pdev = pdev;
 
        /* Setup "info" structure */
 #ifdef __sparc__
@@ -3571,6 +3690,11 @@ static void __devexit atyfb_remove(struct fb_info *info)
        aty_set_crtc(par, &saved_crtc);
        par->pll_ops->set_pll(info, &saved_pll);
 
+#ifdef CONFIG_FB_ATY_BACKLIGHT
+       if (M64_HAS(MOBIL_BUS))
+               aty_bl_exit(par);
+#endif
+
        unregister_framebuffer(info);
 
 #ifdef CONFIG_MTRR
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
new file mode 100644 (file)
index 0000000..7de66b8
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * Backlight code for ATI Radeon based graphic cards
+ *
+ * Copyright (c) 2000 Ani Joshi <ajoshi@kernel.crashing.org>
+ * Copyright (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "radeonfb.h"
+#include <linux/backlight.h>
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
+#define MAX_RADEON_LEVEL 0xFF
+
+static struct backlight_properties radeon_bl_data;
+
+struct radeon_bl_privdata {
+       struct radeonfb_info *rinfo;
+       uint8_t negative;
+};
+
+static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata,
+               int level)
+{
+       struct fb_info *info = pdata->rinfo->info;
+       int rlevel;
+
+       mutex_lock(&info->bl_mutex);
+
+       /* Get and convert the value */
+       rlevel = pdata->rinfo->info->bl_curve[level] *
+                FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL;
+
+       mutex_unlock(&info->bl_mutex);
+
+       if (pdata->negative)
+               rlevel = MAX_RADEON_LEVEL - rlevel;
+
+       if (rlevel < 0)
+               rlevel = 0;
+       else if (rlevel > MAX_RADEON_LEVEL)
+               rlevel = MAX_RADEON_LEVEL;
+
+       return rlevel;
+}
+
+static int radeon_bl_update_status(struct backlight_device *bd)
+{
+       struct radeon_bl_privdata *pdata = class_get_devdata(&bd->class_dev);
+       struct radeonfb_info *rinfo = pdata->rinfo;
+       u32 lvds_gen_cntl, tmpPixclksCntl;
+       int level;
+
+       if (rinfo->mon1_type != MT_LCD)
+               return 0;
+
+       /* We turn off the LCD completely instead of just dimming the
+        * backlight. This provides some greater power saving and the display
+        * is useless without backlight anyway.
+        */
+        if (bd->props->power != FB_BLANK_UNBLANK ||
+           bd->props->fb_blank != FB_BLANK_UNBLANK)
+               level = 0;
+       else
+               level = bd->props->brightness;
+
+       del_timer_sync(&rinfo->lvds_timer);
+       radeon_engine_idle();
+
+       lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
+       if (level > 0) {
+               lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
+               if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
+                       lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
+                       lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
+                       OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+                       lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
+                       lvds_gen_cntl |=
+                               (radeon_bl_get_level_brightness(pdata, level) <<
+                                LVDS_BL_MOD_LEVEL_SHIFT);
+                       lvds_gen_cntl |= LVDS_ON;
+                       lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
+                       rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
+                       mod_timer(&rinfo->lvds_timer,
+                                 jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
+               } else {
+                       lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
+                       lvds_gen_cntl |=
+                               (radeon_bl_get_level_brightness(pdata, level) <<
+                                LVDS_BL_MOD_LEVEL_SHIFT);
+                       OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+               }
+               rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
+               rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
+                       & LVDS_STATE_MASK;
+       } else {
+               /* Asic bug, when turning off LVDS_ON, we have to make sure
+                  RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
+               */
+               tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
+               if (rinfo->is_mobility || rinfo->is_IGP)
+                       OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
+               lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
+               lvds_gen_cntl |= (radeon_bl_get_level_brightness(pdata, 0) <<
+                                 LVDS_BL_MOD_LEVEL_SHIFT);
+               lvds_gen_cntl |= LVDS_DISPLAY_DIS;
+               OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+               udelay(100);
+               lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
+               OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+               lvds_gen_cntl &= ~(LVDS_DIGON);
+               rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
+               mod_timer(&rinfo->lvds_timer,
+                         jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
+               if (rinfo->is_mobility || rinfo->is_IGP)
+                       OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
+       }
+       rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
+       rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
+
+       return 0;
+}
+
+static int radeon_bl_get_brightness(struct backlight_device *bd)
+{
+       return bd->props->brightness;
+}
+
+static struct backlight_properties radeon_bl_data = {
+       .owner          = THIS_MODULE,
+       .get_brightness = radeon_bl_get_brightness,
+       .update_status  = radeon_bl_update_status,
+       .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
+};
+
+void radeonfb_bl_init(struct radeonfb_info *rinfo)
+{
+       struct backlight_device *bd;
+       struct radeon_bl_privdata *pdata;
+       char name[12];
+
+       if (rinfo->mon1_type != MT_LCD)
+               return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       if (!pmac_has_backlight_type("ati") &&
+           !pmac_has_backlight_type("mnca"))
+               return;
+#endif
+
+       pdata = kmalloc(sizeof(struct radeon_bl_privdata), GFP_KERNEL);
+       if (!pdata) {
+               printk("radeonfb: Memory allocation failed\n");
+               goto error;
+       }
+
+       snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
+
+       bd = backlight_device_register(name, pdata, &radeon_bl_data);
+       if (IS_ERR(bd)) {
+               rinfo->info->bl_dev = NULL;
+               printk("radeonfb: Backlight registration failed\n");
+               goto error;
+       }
+
+       pdata->rinfo = rinfo;
+
+       /* Pardon me for that hack... maybe some day we can figure out in what
+        * direction backlight should work on a given panel?
+        */
+       pdata->negative =
+               (rinfo->family != CHIP_FAMILY_RV200 &&
+                rinfo->family != CHIP_FAMILY_RV250 &&
+                rinfo->family != CHIP_FAMILY_RV280 &&
+                rinfo->family != CHIP_FAMILY_RV350);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       pdata->negative = pdata->negative ||
+               machine_is_compatible("PowerBook4,3") ||
+               machine_is_compatible("PowerBook6,3") ||
+               machine_is_compatible("PowerBook6,5");
+#endif
+
+       mutex_lock(&rinfo->info->bl_mutex);
+       rinfo->info->bl_dev = bd;
+       fb_bl_default_curve(rinfo->info, 0,
+                63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL,
+               217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL);
+       mutex_unlock(&rinfo->info->bl_mutex);
+
+       up(&bd->sem);
+       bd->props->brightness = radeon_bl_data.max_brightness;
+       bd->props->power = FB_BLANK_UNBLANK;
+       bd->props->update_status(bd);
+       down(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       mutex_lock(&pmac_backlight_mutex);
+       if (!pmac_backlight)
+               pmac_backlight = bd;
+       mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+       printk("radeonfb: Backlight initialized (%s)\n", name);
+
+       return;
+
+error:
+       kfree(pdata);
+       return;
+}
+
+void radeonfb_bl_exit(struct radeonfb_info *rinfo)
+{
+#ifdef CONFIG_PMAC_BACKLIGHT
+       mutex_lock(&pmac_backlight_mutex);
+#endif
+
+       mutex_lock(&rinfo->info->bl_mutex);
+       if (rinfo->info->bl_dev) {
+               struct radeon_bl_privdata *pdata;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+               if (pmac_backlight == rinfo->info->bl_dev)
+                       pmac_backlight = NULL;
+#endif
+
+               pdata = class_get_devdata(&rinfo->info->bl_dev->class_dev);
+               backlight_device_unregister(rinfo->info->bl_dev);
+               kfree(pdata);
+               rinfo->info->bl_dev = NULL;
+
+               printk("radeonfb: Backlight unloaded\n");
+       }
+       mutex_unlock(&rinfo->info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
index 387a18a47ac24b533037368e0928f874500658af..c5ecbb02e01d588db07b48e1a0b1f2e45d2d9cc8 100644 (file)
 #include <asm/pci-bridge.h>
 #include "../macmodes.h"
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/backlight.h>
-#endif
-
 #ifdef CONFIG_BOOTX_TEXT
 #include <asm/btext.h>
 #endif
@@ -277,20 +273,6 @@ static int nomtrr = 0;
  * prototypes
  */
 
-
-#ifdef CONFIG_PPC_OF
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int radeon_set_backlight_enable(int on, int level, void *data);
-static int radeon_set_backlight_level(int level, void *data);
-static struct backlight_controller radeon_backlight_controller = {
-       radeon_set_backlight_enable,
-       radeon_set_backlight_level
-};
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
-#endif /* CONFIG_PPC_OF */
-
 static void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev)
 {
        if (!rinfo->bios_seg)
@@ -1913,116 +1895,6 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo)
         return 0;
 }
 
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-
-/* TODO: Dbl check these tables, we don't go up to full ON backlight
- * in these, possibly because we noticed MacOS doesn't, but I'd prefer
- * having some more official numbers from ATI
- */
-static int backlight_conv_m6[] = {
-       0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
-       0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
-};
-static int backlight_conv_m7[] = {
-       0x00, 0x3f, 0x4a, 0x55, 0x60, 0x6b, 0x76, 0x81,
-       0x8c, 0x97, 0xa2, 0xad, 0xb8, 0xc3, 0xce, 0xd9
-};
-
-#define BACKLIGHT_LVDS_OFF
-#undef BACKLIGHT_DAC_OFF
-
-/* We turn off the LCD completely instead of just dimming the backlight.
- * This provides some greater power saving and the display is useless
- * without backlight anyway.
- */
-static int radeon_set_backlight_enable(int on, int level, void *data)
-{
-       struct radeonfb_info *rinfo = (struct radeonfb_info *)data;
-       u32 lvds_gen_cntl, tmpPixclksCntl;
-       int* conv_table;
-
-       if (rinfo->mon1_type != MT_LCD)
-               return 0;
-
-       /* Pardon me for that hack... maybe some day we can figure
-        * out in what direction backlight should work on a given
-        * panel ?
-        */
-       if ((rinfo->family == CHIP_FAMILY_RV200 ||
-            rinfo->family == CHIP_FAMILY_RV250 ||
-            rinfo->family == CHIP_FAMILY_RV280 ||
-            rinfo->family == CHIP_FAMILY_RV350) &&
-           !machine_is_compatible("PowerBook4,3") &&
-           !machine_is_compatible("PowerBook6,3") &&
-           !machine_is_compatible("PowerBook6,5"))
-               conv_table = backlight_conv_m7;
-       else
-               conv_table = backlight_conv_m6;
-
-       del_timer_sync(&rinfo->lvds_timer);
-       radeon_engine_idle();
-
-       lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
-       if (on && (level > BACKLIGHT_OFF)) {
-               lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
-               if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
-                       lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
-                       lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
-                       OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
-                       lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
-                       lvds_gen_cntl |= (conv_table[level] <<
-                                         LVDS_BL_MOD_LEVEL_SHIFT);
-                       lvds_gen_cntl |= LVDS_ON;
-                       lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
-                       rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
-                       mod_timer(&rinfo->lvds_timer,
-                                 jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
-               } else {
-                       lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
-                       lvds_gen_cntl |= (conv_table[level] <<
-                                         LVDS_BL_MOD_LEVEL_SHIFT);
-                       OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
-               }
-               rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
-               rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
-                       & LVDS_STATE_MASK;
-       } else {
-               /* Asic bug, when turning off LVDS_ON, we have to make sure
-                  RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
-               */
-               tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
-               if (rinfo->is_mobility || rinfo->is_IGP)
-                       OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
-               lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
-               lvds_gen_cntl |= (conv_table[0] <<
-                                 LVDS_BL_MOD_LEVEL_SHIFT);
-               lvds_gen_cntl |= LVDS_DISPLAY_DIS;
-               OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
-               udelay(100);
-               lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
-               OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
-               lvds_gen_cntl &= ~(LVDS_DIGON);
-               rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
-               mod_timer(&rinfo->lvds_timer,
-                         jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
-               if (rinfo->is_mobility || rinfo->is_IGP)
-                       OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
-       }
-       rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
-       rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
-
-       return 0;
-}
-
-
-static int radeon_set_backlight_level(int level, void *data)
-{
-       return radeon_set_backlight_enable(1, level, data);
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
-
 /*
  * This reconfigure the card's internal memory map. In theory, we'd like
  * to setup the card's memory at the same address as it's PCI bus address,
@@ -2477,14 +2349,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
                                                 MTRR_TYPE_WRCOMB, 1);
 #endif
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-       if (rinfo->mon1_type == MT_LCD) {
-               register_backlight_controller(&radeon_backlight_controller,
-                                             rinfo, "ati");
-               register_backlight_controller(&radeon_backlight_controller,
-                                             rinfo, "mnca");
-       }
-#endif
+       radeonfb_bl_init(rinfo);
 
        printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name);
 
@@ -2528,7 +2393,8 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
  
         if (!rinfo)
                 return;
+
+       radeonfb_bl_exit(rinfo);
        radeonfb_pm_exit(rinfo);
 
        if (rinfo->mon1_EDID)
index 217e00ab4a2d284ba899679e39727fb9b4d5dee6..1645943b1123a43fc54af6e9d24a179c02dddfa9 100644 (file)
@@ -625,4 +625,13 @@ extern int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_
 extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
                               int reg_only);
 
+/* Backlight functions */
+#ifdef CONFIG_FB_RADEON_BACKLIGHT
+extern void radeonfb_bl_init(struct radeonfb_info *rinfo);
+extern void radeonfb_bl_exit(struct radeonfb_info *rinfo);
+#else
+static inline void radeonfb_bl_init(struct radeonfb_info *rinfo) {}
+static inline void radeonfb_bl_exit(struct radeonfb_info *rinfo) {}
+#endif
+
 #endif /* __RADEONFB_H__ */
index 72ff6bf75e5ed8cbabc87d83f882b77702fafa7a..d76bbfac92ccf15e3e9a8141547b89c3fa8dbb13 100644 (file)
@@ -148,9 +148,24 @@ static int chipsfb_set_par(struct fb_info *info)
 static int chipsfb_blank(int blank, struct fb_info *info)
 {
 #ifdef CONFIG_PMAC_BACKLIGHT
-       // used to disable backlight only for blank > 1, but it seems
-       // useful at blank = 1 too (saves battery, extends backlight life)
-       set_backlight_enable(!blank);
+       mutex_lock(&pmac_backlight_mutex);
+
+       if (pmac_backlight) {
+               down(&pmac_backlight->sem);
+
+               /* used to disable backlight only for blank > 1, but it seems
+                * useful at blank = 1 too (saves battery, extends backlight
+                * life)
+                */
+               if (blank)
+                       pmac_backlight->props->power = FB_BLANK_POWERDOWN;
+               else
+                       pmac_backlight->props->power = FB_BLANK_UNBLANK;
+               pmac_backlight->props->update_status(pmac_backlight);
+               up(&pmac_backlight->sem);
+       }
+
+       mutex_unlock(&pmac_backlight_mutex);
 #endif /* CONFIG_PMAC_BACKLIGHT */
 
        return 1;       /* get fb_blank to set the colormap to all black */
@@ -401,7 +416,14 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
 
 #ifdef CONFIG_PMAC_BACKLIGHT
        /* turn on the backlight */
-       set_backlight_enable(1);
+       mutex_lock(&pmac_backlight_mutex);
+       if (pmac_backlight) {
+               down(&pmac_backlight->sem);
+               pmac_backlight->props->power = FB_BLANK_UNBLANK;
+               pmac_backlight->props->update_status(pmac_backlight);
+               up(&pmac_backlight->sem);
+       }
+       mutex_unlock(&pmac_backlight_mutex);
 #endif /* CONFIG_PMAC_BACKLIGHT */
 
 #ifdef CONFIG_PPC
index 34e07399756b4ebd739792dff78abc1114dade2c..3ceb8c1b392e4168dfbc77a3647e5bac1f7b0e34 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/fb.h>
 #include <linux/console.h>
+#include <linux/module.h>
 
 /**
  * framebuffer_alloc - creates a new frame buffer info structure
@@ -55,6 +56,10 @@ struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
 
        info->device = dev;
 
+#ifdef CONFIG_FB_BACKLIGHT
+       mutex_init(&info->bl_mutex);
+#endif
+
        return info;
 #undef PADDING
 #undef BYTES_PER_LONG
@@ -414,6 +419,65 @@ static ssize_t show_fbstate(struct class_device *class_device, char *buf)
        return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->state);
 }
 
+#ifdef CONFIG_FB_BACKLIGHT
+static ssize_t store_bl_curve(struct class_device *class_device,
+               const char *buf, size_t count)
+{
+       struct fb_info *fb_info = class_get_devdata(class_device);
+       u8 tmp_curve[FB_BACKLIGHT_LEVELS];
+       unsigned int i;
+
+       if (count != (FB_BACKLIGHT_LEVELS / 8 * 24))
+               return -EINVAL;
+
+       for (i = 0; i < (FB_BACKLIGHT_LEVELS / 8); ++i)
+               if (sscanf(&buf[i * 24],
+                       "%2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx\n",
+                       &tmp_curve[i * 8 + 0],
+                       &tmp_curve[i * 8 + 1],
+                       &tmp_curve[i * 8 + 2],
+                       &tmp_curve[i * 8 + 3],
+                       &tmp_curve[i * 8 + 4],
+                       &tmp_curve[i * 8 + 5],
+                       &tmp_curve[i * 8 + 6],
+                       &tmp_curve[i * 8 + 7]) != 8)
+                       return -EINVAL;
+
+       /* If there has been an error in the input data, we won't
+        * reach this loop.
+        */
+       mutex_lock(&fb_info->bl_mutex);
+       for (i = 0; i < FB_BACKLIGHT_LEVELS; ++i)
+               fb_info->bl_curve[i] = tmp_curve[i];
+       mutex_unlock(&fb_info->bl_mutex);
+
+       return count;
+}
+
+static ssize_t show_bl_curve(struct class_device *class_device, char *buf)
+{
+       struct fb_info *fb_info = class_get_devdata(class_device);
+       ssize_t len = 0;
+       unsigned int i;
+
+       mutex_lock(&fb_info->bl_mutex);
+       for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8)
+               len += snprintf(&buf[len], PAGE_SIZE,
+                               "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+                               fb_info->bl_curve[i + 0],
+                               fb_info->bl_curve[i + 1],
+                               fb_info->bl_curve[i + 2],
+                               fb_info->bl_curve[i + 3],
+                               fb_info->bl_curve[i + 4],
+                               fb_info->bl_curve[i + 5],
+                               fb_info->bl_curve[i + 6],
+                               fb_info->bl_curve[i + 7]);
+       mutex_unlock(&fb_info->bl_mutex);
+
+       return len;
+}
+#endif
+
 /* When cmap is added back in it should be a binary attribute
  * not a text one. Consideration should also be given to converting
  * fbdev to use configfs instead of sysfs */
@@ -432,6 +496,9 @@ static struct class_device_attribute class_device_attrs[] = {
        __ATTR(con_rotate, S_IRUGO|S_IWUSR, show_con_rotate, store_con_rotate),
        __ATTR(con_rotate_all, S_IWUSR, NULL, store_con_rotate_all),
        __ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate),
+#ifdef CONFIG_FB_BACKLIGHT
+       __ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve),
+#endif
 };
 
 int fb_init_class_device(struct fb_info *fb_info)
@@ -454,4 +521,25 @@ void fb_cleanup_class_device(struct fb_info *fb_info)
                                         &class_device_attrs[i]);
 }
 
+#ifdef CONFIG_FB_BACKLIGHT
+/* This function generates a linear backlight curve
+ *
+ *     0: off
+ *   1-7: min
+ * 8-127: linear from min to max
+ */
+void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max)
+{
+       unsigned int i, flat, count, range = (max - min);
+
+       fb_info->bl_curve[0] = off;
 
+       for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat)
+               fb_info->bl_curve[flat] = min;
+
+       count = FB_BACKLIGHT_LEVELS * 15 / 16;
+       for (i = 0; i < count; ++i)
+               fb_info->bl_curve[flat + i] = min + (range * (i + 1) / count);
+}
+EXPORT_SYMBOL_GPL(fb_bl_default_curve);
+#endif
index 6b88050d21bfbb4ae37bd96dbab85fcda267c5b8..8a0c2d3d3805623ea891d4cc4dea6fa589e1c35d 100644 (file)
@@ -232,9 +232,6 @@ static int igafb_mmap(struct fb_info *info,
 
        size = vma->vm_end - vma->vm_start;
 
-       /* To stop the swapper from even considering these pages. */
-       vma->vm_flags |= (VM_SHM | VM_LOCKED);
-
        /* Each page, see which map applies */
        for (page = 0; page < size; ) {
                map_size = 0;
index 23c1827b2d0bb22d5e54545dbfad49e76e364185..f4ddd3431f179055e54b12118162c26b40cf2278 100644 (file)
 #include <linux/config.h>
 #include <linux/version.h>
 
+#define __OLD_VIDIOC_
+
 #include "matroxfb_base.h"
 #include "matroxfb_misc.h"
 #include "matroxfb_accel.h"
@@ -158,9 +160,9 @@ static void update_crtc2(WPMINFO unsigned int pos) {
 
        /* Make sure that displays are compatible */
        if (info && (info->fbcon.var.bits_per_pixel == ACCESS_FBINFO(fbcon).var.bits_per_pixel)
-                && (info->fbcon.var.xres_virtual == ACCESS_FBINFO(fbcon).var.xres_virtual)
-                && (info->fbcon.var.green.length == ACCESS_FBINFO(fbcon).var.green.length)
-                ) {
+                && (info->fbcon.var.xres_virtual == ACCESS_FBINFO(fbcon).var.xres_virtual)
+                && (info->fbcon.var.green.length == ACCESS_FBINFO(fbcon).var.green.length)
+                ) {
                switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
                        case 16:
                        case 32:
@@ -224,7 +226,7 @@ static irqreturn_t matrox_irq(int irq, void *dev_id, struct pt_regs *fp)
 
 int matroxfb_enable_irq(WPMINFO int reenable) {
        u_int32_t bm;
-       
+
        if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
                bm = 0x220;
        else
@@ -241,7 +243,7 @@ int matroxfb_enable_irq(WPMINFO int reenable) {
                mga_outl(M_IEN, mga_inl(M_IEN) | bm);
        } else if (reenable) {
                u_int32_t ien;
-               
+
                ien = mga_inl(M_IEN);
                if ((ien & bm) != bm) {
                        printk(KERN_DEBUG "matroxfb: someone disabled IRQ [%08X]\n", ien);
@@ -347,7 +349,7 @@ static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
                mga_setr(M_EXTVGA_INDEX, 0x00, p2);
        }
        matroxfb_DAC_unlock_irqrestore(flags);
-       
+
        update_crtc2(PMINFO pos);
 
        CRITEND
@@ -390,7 +392,7 @@ static void matroxfb_remove(WPMINFO int dummy) {
 static int matroxfb_open(struct fb_info *info, int user)
 {
        MINFO_FROM_INFO(info);
-       
+
        DBG_LOOP(__FUNCTION__)
 
        if (ACCESS_FBINFO(dead)) {
@@ -406,7 +408,7 @@ static int matroxfb_open(struct fb_info *info, int user)
 static int matroxfb_release(struct fb_info *info, int user)
 {
        MINFO_FROM_INFO(info);
-       
+
        DBG_LOOP(__FUNCTION__)
 
        if (user) {
@@ -854,7 +856,7 @@ static int matroxfb_get_vblank(WPMINFO struct fb_vblank *vblank)
                vblank->flags |= FB_VBLANK_VBLANKING;
        if (test_bit(0, &ACCESS_FBINFO(irq_flags))) {
                vblank->flags |= FB_VBLANK_HAVE_COUNT;
-               /* Only one writer, aligned int value... 
+               /* Only one writer, aligned int value...
                   it should work without lock and without atomic_t */
                vblank->count = ACCESS_FBINFO(crtc1).vsync.cnt;
        }
@@ -870,7 +872,7 @@ static int matroxfb_ioctl(struct fb_info *info,
 {
        void __user *argp = (void __user *)arg;
        MINFO_FROM_INFO(info);
-       
+
        DBG(__FUNCTION__)
 
        if (ACCESS_FBINFO(dead)) {
@@ -1081,7 +1083,7 @@ static int matroxfb_ioctl(struct fb_info *info,
                case VIDIOC_QUERYCAP:
                        {
                                struct v4l2_capability r;
-                               
+
                                memset(&r, 0, sizeof(r));
                                strcpy(r.driver, "matroxfb");
                                strcpy(r.card, "Matrox");
@@ -1091,7 +1093,7 @@ static int matroxfb_ioctl(struct fb_info *info,
                                if (copy_to_user(argp, &r, sizeof(r)))
                                        return -EFAULT;
                                return 0;
-                               
+
                        }
                case VIDIOC_QUERYCTRL:
                        {
@@ -1690,8 +1692,8 @@ static int initMatrox2(WPMINFO struct board* b){
                pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, &cmd);
                mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */
                mga_option |= MX_OPTION_BSWAP;
-                /* disable palette snooping */
-                cmd &= ~PCI_COMMAND_VGA_PALETTE;
+               /* disable palette snooping */
+               cmd &= ~PCI_COMMAND_VGA_PALETTE;
                if (pci_dev_present(intel_82437)) {
                        if (!(mga_option & 0x20000000) && !ACCESS_FBINFO(devflags.nopciretry)) {
                                printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n");
@@ -1809,12 +1811,12 @@ static int initMatrox2(WPMINFO struct board* b){
 
                if (fv) {
                        tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres
-                                 + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
+                                 + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
                        if ((tmp < fh) || (fh == 0)) fh = tmp;
                }
                if (fh) {
                        tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres
-                                 + vesafb_defined.right_margin + vesafb_defined.hsync_len);
+                                 + vesafb_defined.right_margin + vesafb_defined.hsync_len);
                        if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
                }
                tmp = (maxclk + 499) / 500;
@@ -1890,14 +1892,14 @@ static int initMatrox2(WPMINFO struct board* b){
 
        /* there is no console on this fb... but we have to initialize hardware
         * until someone tells me what is proper thing to do */
-       if (!ACCESS_FBINFO(initialized)) {
-               printk(KERN_INFO "fb%d: initializing hardware\n",
-                      ACCESS_FBINFO(fbcon.node));
-               /* We have to use FB_ACTIVATE_FORCE, as we had to put vesafb_defined to the fbcon.var
-                * already before, so register_framebuffer works correctly. */
-               vesafb_defined.activate |= FB_ACTIVATE_FORCE;
-               fb_set_var(&ACCESS_FBINFO(fbcon), &vesafb_defined);
-       }
+       if (!ACCESS_FBINFO(initialized)) {
+               printk(KERN_INFO "fb%d: initializing hardware\n",
+                      ACCESS_FBINFO(fbcon.node));
+               /* We have to use FB_ACTIVATE_FORCE, as we had to put vesafb_defined to the fbcon.var
+                * already before, so register_framebuffer works correctly. */
+               vesafb_defined.activate |= FB_ACTIVATE_FORCE;
+               fb_set_var(&ACCESS_FBINFO(fbcon), &vesafb_defined);
+       }
 
        return 0;
 failVideoIO:;
@@ -2356,7 +2358,7 @@ static int __init matroxfb_setup(char *options) {
                else if (!strncmp(this_opt, "dfp:", 4)) {
                        dfp_type = simple_strtoul(this_opt+4, NULL, 0);
                        dfp = 1;
-               }       
+               }
 #ifdef CONFIG_PPC_PMAC
                else if (!strncmp(this_opt, "vmode:", 6)) {
                        unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
index 690d37e8de5bb2deccf79917a8320ff989de8fc1..ca47432113e017115048bac8be29c8b968d8551e 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_FB_NVIDIA)          += nvidiafb.o
 nvidiafb-y                       := nvidia.o nv_hw.o nv_setup.o \
                                    nv_accel.o
 nvidiafb-$(CONFIG_FB_NVIDIA_I2C) += nv_i2c.o
+nvidiafb-$(CONFIG_FB_NVIDIA_BACKLIGHT)  += nv_backlight.o
 nvidiafb-$(CONFIG_PPC_OF)       += nv_of.o
 
-nvidiafb-objs                    := $(nvidiafb-y)
\ No newline at end of file
+nvidiafb-objs                    := $(nvidiafb-y)
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c
new file mode 100644 (file)
index 0000000..1c1c10c
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Backlight code for nVidia based graphic cards
+ *
+ * Copyright 2004 Antonino Daplas <adaplas@pol.net>
+ * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include "nv_local.h"
+#include "nv_type.h"
+#include "nv_proto.h"
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#include <asm/machdep.h>
+#endif
+
+/* We do not have any information about which values are allowed, thus
+ * we used safe values.
+ */
+#define MIN_LEVEL 0x158
+#define MAX_LEVEL 0x534
+
+static struct backlight_properties nvidia_bl_data;
+
+static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
+               int level)
+{
+       struct fb_info *info = pci_get_drvdata(par->pci_dev);
+       int nlevel;
+
+       /* Get and convert the value */
+       mutex_lock(&info->bl_mutex);
+       nlevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
+       mutex_unlock(&info->bl_mutex);
+
+       if (nlevel < 0)
+               nlevel = 0;
+       else if (nlevel < MIN_LEVEL)
+               nlevel = MIN_LEVEL;
+       else if (nlevel > MAX_LEVEL)
+               nlevel = MAX_LEVEL;
+
+       return nlevel;
+}
+
+static int nvidia_bl_update_status(struct backlight_device *bd)
+{
+       struct nvidia_par *par = class_get_devdata(&bd->class_dev);
+       u32 tmp_pcrt, tmp_pmc, fpcontrol;
+       int level;
+
+       if (!par->FlatPanel)
+               return 0;
+
+       if (bd->props->power != FB_BLANK_UNBLANK ||
+           bd->props->fb_blank != FB_BLANK_UNBLANK)
+               level = 0;
+       else
+               level = bd->props->brightness;
+
+       tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
+       tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
+       fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC;
+
+       if (level > 0) {
+               tmp_pcrt |= 0x1;
+               tmp_pmc |= (1 << 31); /* backlight bit */
+               tmp_pmc |= nvidia_bl_get_level_brightness(par, level) << 16;
+               fpcontrol |= par->fpSyncs;
+       } else
+               fpcontrol |= 0x20000022;
+
+       NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt);
+       NV_WR32(par->PMC, 0x10F0, tmp_pmc);
+       NV_WR32(par->PRAMDAC, 0x848, fpcontrol);
+
+       return 0;
+}
+
+static int nvidia_bl_get_brightness(struct backlight_device *bd)
+{
+       return bd->props->brightness;
+}
+
+static struct backlight_properties nvidia_bl_data = {
+       .owner          = THIS_MODULE,
+       .get_brightness = nvidia_bl_get_brightness,
+       .update_status  = nvidia_bl_update_status,
+       .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
+};
+
+void nvidia_bl_init(struct nvidia_par *par)
+{
+       struct fb_info *info = pci_get_drvdata(par->pci_dev);
+       struct backlight_device *bd;
+       char name[12];
+
+       if (!par->FlatPanel)
+               return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       if (!machine_is(powermac) ||
+           !pmac_has_backlight_type("mnca"))
+               return;
+#endif
+
+       snprintf(name, sizeof(name), "nvidiabl%d", info->node);
+
+       bd = backlight_device_register(name, par, &nvidia_bl_data);
+       if (IS_ERR(bd)) {
+               info->bl_dev = NULL;
+               printk("nvidia: Backlight registration failed\n");
+               goto error;
+       }
+
+       mutex_lock(&info->bl_mutex);
+       info->bl_dev = bd;
+       fb_bl_default_curve(info, 0,
+               0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
+               0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
+       mutex_unlock(&info->bl_mutex);
+
+       up(&bd->sem);
+       bd->props->brightness = nvidia_bl_data.max_brightness;
+       bd->props->power = FB_BLANK_UNBLANK;
+       bd->props->update_status(bd);
+       down(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       mutex_lock(&pmac_backlight_mutex);
+       if (!pmac_backlight)
+               pmac_backlight = bd;
+       mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+       printk("nvidia: Backlight initialized (%s)\n", name);
+
+       return;
+
+error:
+       return;
+}
+
+void nvidia_bl_exit(struct nvidia_par *par)
+{
+       struct fb_info *info = pci_get_drvdata(par->pci_dev);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       mutex_lock(&pmac_backlight_mutex);
+#endif
+
+       mutex_lock(&info->bl_mutex);
+       if (info->bl_dev) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+               if (pmac_backlight == info->bl_dev)
+                       pmac_backlight = NULL;
+#endif
+
+               backlight_device_unregister(info->bl_dev);
+
+               printk("nvidia: Backlight unloaded\n");
+       }
+       mutex_unlock(&info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
index b149a690ee0f854321717b0ec7a75e5e55ccbf02..6fba656cd56b0d29537209082ce6fdf08872301b 100644 (file)
@@ -63,4 +63,14 @@ extern void nvidiafb_imageblit(struct fb_info *info,
                               const struct fb_image *image);
 extern int nvidiafb_sync(struct fb_info *info);
 extern u8 byte_rev[256];
+
+/* in nv_backlight.h */
+#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
+extern void nvidia_bl_init(struct nvidia_par *par);
+extern void nvidia_bl_exit(struct nvidia_par *par);
+#else
+static inline void nvidia_bl_init(struct nvidia_par *par) {}
+static inline void nvidia_bl_exit(struct nvidia_par *par) {}
+#endif
+
 #endif                         /* __NV_PROTO_H__ */
index 093ab9977c7ce843bc222e478d142c0aa57ff0d9..03a7c1e9ce38ae4d619fc494e578588982e510b5 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/console.h>
+#include <linux/backlight.h>
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
 #endif
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
 #endif
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/machdep.h>
-#include <asm/backlight.h>
-#endif
 
 #include "nv_local.h"
 #include "nv_type.h"
@@ -470,75 +467,6 @@ static struct fb_var_screeninfo __devinitdata nvidiafb_default_var = {
        .vmode = FB_VMODE_NONINTERLACED
 };
 
-/*
- * Backlight control
- */
-#ifdef CONFIG_PMAC_BACKLIGHT
-
-static int nvidia_backlight_levels[] = {
-       0x158,
-       0x192,
-       0x1c6,
-       0x200,
-       0x234,
-       0x268,
-       0x2a2,
-       0x2d6,
-       0x310,
-       0x344,
-       0x378,
-       0x3b2,
-       0x3e6,
-       0x41a,
-       0x454,
-       0x534,
-};
-
-/* ------------------------------------------------------------------------- *
- *
- * Backlight operations
- *
- * ------------------------------------------------------------------------- */
-
-static int nvidia_set_backlight_enable(int on, int level, void *data)
-{
-       struct nvidia_par *par = data;
-       u32 tmp_pcrt, tmp_pmc, fpcontrol;
-
-       tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
-       tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
-       fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC;
-
-       if (on && (level > BACKLIGHT_OFF)) {
-               tmp_pcrt |= 0x1;
-               tmp_pmc |= (1 << 31);   // backlight bit
-               tmp_pmc |= nvidia_backlight_levels[level - 1] << 16;
-       }
-
-       if (on)
-               fpcontrol |= par->fpSyncs;
-       else
-               fpcontrol |= 0x20000022;
-
-       NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt);
-       NV_WR32(par->PMC, 0x10F0, tmp_pmc);
-       NV_WR32(par->PRAMDAC, 0x848, fpcontrol);
-
-       return 0;
-}
-
-static int nvidia_set_backlight_level(int level, void *data)
-{
-       return nvidia_set_backlight_enable(1, level, data);
-}
-
-static struct backlight_controller nvidia_backlight_controller = {
-       nvidia_set_backlight_enable,
-       nvidia_set_backlight_level
-};
-
-#endif                         /* CONFIG_PMAC_BACKLIGHT */
-
 static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8,
                                       u16 bg, u16 fg, u32 w, u32 h)
 {
@@ -1355,10 +1283,15 @@ static int nvidiafb_blank(int blank, struct fb_info *info)
        NVWriteSeq(par, 0x01, tmp);
        NVWriteCrtc(par, 0x1a, vesa);
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-       if (par->FlatPanel && machine_is(powermac)) {
-               set_backlight_enable(!blank);
+#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
+       mutex_lock(&info->bl_mutex);
+       if (info->bl_dev) {
+               down(&info->bl_dev->sem);
+               info->bl_dev->props->power = blank;
+               info->bl_dev->props->update_status(info->bl_dev);
+               up(&info->bl_dev->sem);
        }
+       mutex_unlock(&info->bl_mutex);
 #endif
 
        NVTRACE_LEAVE();
@@ -1741,11 +1674,9 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
               "PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n",
               info->fix.id,
               par->FbMapSize / (1024 * 1024), info->fix.smem_start);
-#ifdef CONFIG_PMAC_BACKLIGHT
-       if (par->FlatPanel && machine_is(powermac))
-               register_backlight_controller(&nvidia_backlight_controller,
-                                             par, "mnca");
-#endif
+
+       nvidia_bl_init(par);
+
        NVTRACE_LEAVE();
        return 0;
 
@@ -1775,6 +1706,8 @@ static void __exit nvidiafb_remove(struct pci_dev *pd)
 
        NVTRACE_ENTER();
 
+       nvidia_bl_exit(par);
+
        unregister_framebuffer(info);
 #ifdef CONFIG_MTRR
        if (par->mtrr.vram_valid)
index 3e9308f0f165eafcb6b4d8178d6e846e2ae4c22c..d4384ab1df653c2ff57bd4942712bdbf19129299 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/backlight.h>
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
 #endif
@@ -272,34 +273,154 @@ static const struct riva_regs reg_template = {
 /*
  * Backlight control
  */
-#ifdef CONFIG_PMAC_BACKLIGHT
+#ifdef CONFIG_FB_RIVA_BACKLIGHT
+/* We do not have any information about which values are allowed, thus
+ * we used safe values.
+ */
+#define MIN_LEVEL 0x158
+#define MAX_LEVEL 0x534
 
-static int riva_backlight_levels[] = {
-    0x158,
-    0x192,
-    0x1c6,
-    0x200,
-    0x234,
-    0x268,
-    0x2a2,
-    0x2d6,
-    0x310,
-    0x344,
-    0x378,
-    0x3b2,
-    0x3e6,
-    0x41a,
-    0x454,
-    0x534,
-};
+static struct backlight_properties riva_bl_data;
+
+static int riva_bl_get_level_brightness(struct riva_par *par,
+               int level)
+{
+       struct fb_info *info = pci_get_drvdata(par->pdev);
+       int nlevel;
+
+       /* Get and convert the value */
+       mutex_lock(&info->bl_mutex);
+       nlevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
+       mutex_unlock(&info->bl_mutex);
+
+       if (nlevel < 0)
+               nlevel = 0;
+       else if (nlevel < MIN_LEVEL)
+               nlevel = MIN_LEVEL;
+       else if (nlevel > MAX_LEVEL)
+               nlevel = MAX_LEVEL;
+
+       return nlevel;
+}
+
+static int riva_bl_update_status(struct backlight_device *bd)
+{
+       struct riva_par *par = class_get_devdata(&bd->class_dev);
+       U032 tmp_pcrt, tmp_pmc;
+       int level;
+
+       if (bd->props->power != FB_BLANK_UNBLANK ||
+           bd->props->fb_blank != FB_BLANK_UNBLANK)
+               level = 0;
+       else
+               level = bd->props->brightness;
+
+       tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF;
+       tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC;
+       if(level > 0) {
+               tmp_pcrt |= 0x1;
+               tmp_pmc |= (1 << 31); /* backlight bit */
+               tmp_pmc |= riva_bl_get_level_brightness(par, level) << 16; /* level */
+       }
+       par->riva.PCRTC0[0x081C/4] = tmp_pcrt;
+       par->riva.PMC[0x10F0/4] = tmp_pmc;
+
+       return 0;
+}
+
+static int riva_bl_get_brightness(struct backlight_device *bd)
+{
+       return bd->props->brightness;
+}
 
-static int riva_set_backlight_enable(int on, int level, void *data);
-static int riva_set_backlight_level(int level, void *data);
-static struct backlight_controller riva_backlight_controller = {
-       riva_set_backlight_enable,
-       riva_set_backlight_level
+static struct backlight_properties riva_bl_data = {
+       .owner    = THIS_MODULE,
+       .get_brightness = riva_bl_get_brightness,
+       .update_status  = riva_bl_update_status,
+       .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
 };
-#endif /* CONFIG_PMAC_BACKLIGHT */
+
+static void riva_bl_init(struct riva_par *par)
+{
+       struct fb_info *info = pci_get_drvdata(par->pdev);
+       struct backlight_device *bd;
+       char name[12];
+
+       if (!par->FlatPanel)
+               return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       if (!machine_is(powermac) ||
+           !pmac_has_backlight_type("mnca"))
+               return;
+#endif
+
+       snprintf(name, sizeof(name), "rivabl%d", info->node);
+
+       bd = backlight_device_register(name, par, &riva_bl_data);
+       if (IS_ERR(bd)) {
+               info->bl_dev = NULL;
+               printk("riva: Backlight registration failed\n");
+               goto error;
+       }
+
+       mutex_lock(&info->bl_mutex);
+       info->bl_dev = bd;
+       fb_bl_default_curve(info, 0,
+               0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
+               0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
+       mutex_unlock(&info->bl_mutex);
+
+       up(&bd->sem);
+       bd->props->brightness = riva_bl_data.max_brightness;
+       bd->props->power = FB_BLANK_UNBLANK;
+       bd->props->update_status(bd);
+       down(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       mutex_lock(&pmac_backlight_mutex);
+       if (!pmac_backlight)
+               pmac_backlight = bd;
+       mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+       printk("riva: Backlight initialized (%s)\n", name);
+
+       return;
+
+error:
+       return;
+}
+
+static void riva_bl_exit(struct riva_par *par)
+{
+       struct fb_info *info = pci_get_drvdata(par->pdev);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       mutex_lock(&pmac_backlight_mutex);
+#endif
+
+       mutex_lock(&info->bl_mutex);
+       if (info->bl_dev) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+               if (pmac_backlight == info->bl_dev)
+                       pmac_backlight = NULL;
+#endif
+
+               backlight_device_unregister(info->bl_dev);
+
+               printk("riva: Backlight unloaded\n");
+       }
+       mutex_unlock(&info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
+#else
+static inline void riva_bl_init(struct riva_par *par) {}
+static inline void riva_bl_exit(struct riva_par *par) {}
+#endif /* CONFIG_FB_RIVA_BACKLIGHT */
 
 /* ------------------------------------------------------------------------- *
  *
@@ -971,36 +1092,6 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
        return rc;
 }
 
-/* ------------------------------------------------------------------------- *
- *
- * Backlight operations
- *
- * ------------------------------------------------------------------------- */
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int riva_set_backlight_enable(int on, int level, void *data)
-{
-       struct riva_par *par = data;
-       U032 tmp_pcrt, tmp_pmc;
-
-       tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF;
-       tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC;
-       if(on && (level > BACKLIGHT_OFF)) {
-               tmp_pcrt |= 0x1;
-               tmp_pmc |= (1 << 31); // backlight bit
-               tmp_pmc |= riva_backlight_levels[level-1] << 16; // level
-       }
-       par->riva.PCRTC0[0x081C/4] = tmp_pcrt;
-       par->riva.PMC[0x10F0/4] = tmp_pmc;
-       return 0;
-}
-
-static int riva_set_backlight_level(int level, void *data)
-{
-       return riva_set_backlight_enable(1, level, data);
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
 /* ------------------------------------------------------------------------- *
  *
  * framebuffer operations
@@ -1247,10 +1338,15 @@ static int rivafb_blank(int blank, struct fb_info *info)
        SEQout(par, 0x01, tmp);
        CRTCout(par, 0x1a, vesa);
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-       if ( par->FlatPanel && machine_is(powermac)) {
-               set_backlight_enable(!blank);
+#ifdef CONFIG_FB_RIVA_BACKLIGHT
+       mutex_lock(&info->bl_mutex);
+       if (info->bl_dev) {
+               down(&info->bl_dev->sem);
+               info->bl_dev->props->power = blank;
+               info->bl_dev->props->update_status(info->bl_dev);
+               up(&info->bl_dev->sem);
        }
+       mutex_unlock(&info->bl_mutex);
 #endif
 
        NVTRACE_LEAVE();
@@ -2037,11 +2133,9 @@ static int __devinit rivafb_probe(struct pci_dev *pd,
                RIVAFB_VERSION,
                info->fix.smem_len / (1024 * 1024),
                info->fix.smem_start);
-#ifdef CONFIG_PMAC_BACKLIGHT
-       if (default_par->FlatPanel && machine_is(powermac))
-               register_backlight_controller(&riva_backlight_controller,
-                                             default_par, "mnca");
-#endif
+
+       riva_bl_init(info->par);
+
        NVTRACE_LEAVE();
        return 0;
 
@@ -2074,6 +2168,8 @@ static void __exit rivafb_remove(struct pci_dev *pd)
        
        NVTRACE_ENTER();
 
+       riva_bl_exit(par);
+
 #ifdef CONFIG_FB_RIVA_I2C
        riva_delete_i2c_busses(par);
        kfree(par->EDID);
index 9ac2d3171187855286c7869e1ea33f5f0c7cebe2..41f8c2d938924ad431359e5b2d0eaa791b26cad6 100644 (file)
@@ -551,7 +551,7 @@ static inline void enable_mmio(void)
 #define crtc_unlock()  write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F)
 
 /*  Return flat panel's maximum x resolution */
-static int __init get_nativex(void)
+static int __devinit get_nativex(void)
 {
        int x,y,tmp;
 
@@ -658,7 +658,7 @@ static void set_number_of_lines(int lines)
  * If we see that FP is active we assume we have one.
  * Otherwise we have a CRT display.User can override.
  */
-static unsigned int __init get_displaytype(void)
+static unsigned int __devinit get_displaytype(void)
 {
        if (fp)
                return DISPLAY_FP;
@@ -668,7 +668,7 @@ static unsigned int __init get_displaytype(void)
 }
 
 /* Try detecting the video memory size */
-static unsigned int __init get_memsize(void)
+static unsigned int __devinit get_memsize(void)
 {
        unsigned char tmp, tmp2;
        unsigned int k;
index 2cb87ba4b1c1fa76ab685d213ae6e0f33a53dcf8..5c6bdf82146c3618caeae2f9ff5a1f2832e89fae 100644 (file)
@@ -530,9 +530,6 @@ error:
        if (vfid)
                v9fs_fid_destroy(vfid);
 
-       if (inode)
-               iput(inode);
-
        return err;
 }
 
@@ -1054,6 +1051,9 @@ static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer,
        int ret;
        char *link = __getname();
 
+       if (unlikely(!link))
+               return -ENOMEM;
+
        if (buflen > PATH_MAX)
                buflen = PATH_MAX;
 
@@ -1171,9 +1171,6 @@ error:
        if (vfid)
                v9fs_fid_destroy(vfid);
 
-       if (inode)
-               iput(inode);
-
        return err;
 
 }
@@ -1227,6 +1224,9 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
        }
 
        name = __getname();
+       if (unlikely(!name))
+               return -ENOMEM;
+
        sprintf(name, "%d\n", oldfid->fid);
        retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name);
        __putname(name);
index 2aa4624cc0188e51973326e2b6e6354e99ce3bce..1cdc043922d518220ab51d640d2b29c55f037de2 100644 (file)
@@ -776,7 +776,8 @@ endmenu
 menu "Pseudo filesystems"
 
 config PROC_FS
-       bool "/proc file system support"
+       bool "/proc file system support" if EMBEDDED
+       default y
        help
          This is a virtual file system providing information about the status
          of the system. "Virtual" means that it doesn't take up any space on
@@ -1370,11 +1371,19 @@ config UFS_FS
 
 config UFS_FS_WRITE
        bool "UFS file system write support (DANGEROUS)"
-       depends on UFS_FS && EXPERIMENTAL && BROKEN
+       depends on UFS_FS && EXPERIMENTAL
        help
          Say Y here if you want to try writing to UFS partitions. This is
          experimental, so you should back up your UFS partitions beforehand.
 
+config UFS_DEBUG
+       bool "UFS debugging"
+       depends on UFS_FS
+       help
+         If you are experiencing any problems with the UFS filesystem, say
+         Y here.  This will result in _many_ additional debugging messages to be
+         written to the system log.
+
 endmenu
 
 menu "Network File Systems"
index 8765cba35bb96db5c3421a0280149d464dab3925..5200f4938df094a3cff4ba5a4f1547c0a2812bff 100644 (file)
@@ -271,6 +271,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
        int                      reserved;
        unsigned long            mount_flags;
        int                      tmp_flags;     /* fix remount prototype... */
+       u8                       sig[4];
 
        pr_debug("AFFS: read_super(%s)\n",data ? (const char *)data : "no options");
 
@@ -370,8 +371,9 @@ got_root:
                printk(KERN_ERR "AFFS: Cannot read boot block\n");
                goto out_error;
        }
-       chksum = be32_to_cpu(*(__be32 *)boot_bh->b_data);
+       memcpy(sig, boot_bh->b_data, 4);
        brelse(boot_bh);
+       chksum = be32_to_cpu(*(__be32 *)sig);
 
        /* Dircache filesystems are compatible with non-dircache ones
         * when reading. As long as they aren't supported, writing is
@@ -420,11 +422,11 @@ got_root:
        }
 
        if (mount_flags & SF_VERBOSE) {
-               chksum = cpu_to_be32(chksum);
-               printk(KERN_NOTICE "AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n",
-                       AFFS_ROOT_TAIL(sb, root_bh)->disk_name[0],
+               u8 len = AFFS_ROOT_TAIL(sb, root_bh)->disk_name[0];
+               printk(KERN_NOTICE "AFFS: Mounting volume \"%.*s\": Type=%.3s\\%c, Blocksize=%d\n",
+                       len > 31 ? 31 : len,
                        AFFS_ROOT_TAIL(sb, root_bh)->disk_name + 1,
-                       (char *)&chksum,((char *)&chksum)[3] + '0',blocksize);
+                       sig, sig[3] + '0', blocksize);
        }
 
        sb->s_flags |= MS_NODEV | MS_NOSUID;
index b8ce02607d66bacd03d60acad9b99ffd9e48d7d2..4456d1daa40ff5cb518f08c48507c2e906d4b94e 100644 (file)
@@ -174,6 +174,12 @@ static int autofs4_tree_busy(struct vfsmount *mnt,
                        struct autofs_info *ino = autofs4_dentry_ino(p);
                        unsigned int ino_count = atomic_read(&ino->count);
 
+                       /*
+                        * Clean stale dentries below that have not been
+                        * invalidated after a mount fail during lookup
+                        */
+                       d_invalidate(p);
+
                        /* allow for dget above and top is already dgot */
                        if (p == top)
                                ino_count += 2;
index d2c38875ab296e45741c5dcf966da56ec51d8f96..9eb9824dd3323a1a0680653ef92a598efc76a287 100644 (file)
@@ -205,38 +205,6 @@ static int do_ext3_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
        return sys_ioctl(fd, cmd, (unsigned long)compat_ptr(arg));
 }
 
-struct compat_dmx_event {
-       dmx_event_t     event;
-       compat_time_t   timeStamp;
-       union
-       {
-               dmx_scrambling_status_t scrambling;
-       } u;
-};
-
-static int do_dmx_get_event(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-       struct dmx_event kevent;
-       mm_segment_t old_fs = get_fs();
-       int err;
-
-       set_fs(KERNEL_DS);
-       err = sys_ioctl(fd, cmd, (unsigned long) &kevent);
-       set_fs(old_fs);
-
-       if (!err) {
-               struct compat_dmx_event __user *up = compat_ptr(arg);
-
-               err  = put_user(kevent.event, &up->event);
-               err |= put_user(kevent.timeStamp, &up->timeStamp);
-               err |= put_user(kevent.u.scrambling, &up->u.scrambling);
-               if (err)
-                       err = -EFAULT;
-       }
-
-       return err;
-}
-
 struct compat_video_event {
        int32_t         type;
        compat_time_t   timestamp;
@@ -2964,7 +2932,6 @@ HANDLE_IOCTL(NCP_IOC_SETPRIVATEDATA_32, do_ncp_setprivatedata)
 #endif
 
 /* dvb */
-HANDLE_IOCTL(DMX_GET_EVENT, do_dmx_get_event)
 HANDLE_IOCTL(VIDEO_GET_EVENT, do_video_get_event)
 HANDLE_IOCTL(VIDEO_STILLPICTURE, do_video_stillpicture)
 HANDLE_IOCTL(VIDEO_SET_SPU_PALETTE, do_video_set_spu_palette)
index 313b54b2b8f2cb0f074fd122f7b929f67b60cee8..b85fda360533a217fd0ee5e45e892e9c6995db35 100644 (file)
@@ -406,7 +406,7 @@ static void prune_dcache(int count, struct super_block *sb)
                cond_resched_lock(&dcache_lock);
 
                tmp = dentry_unused.prev;
-               if (unlikely(sb)) {
+               if (sb) {
                        /* Try to find a dentry for this sb, but don't try
                         * too hard, if they aren't near the tail they will
                         * be moved down again soon
index 08e7e6a555cacc71d17333bb8f9ae8510a0e00ea..9c677bbd0b0823c3bc6d28ee1bf8d2545ee22ced 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  fs/eventpoll.c ( Efficent event polling implementation )
- *  Copyright (C) 2001,...,2003         Davide Libenzi
+ *  Copyright (C) 2001,...,2006         Davide Libenzi
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -1004,7 +1004,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
 
                /* Notify waiting tasks that events are available */
                if (waitqueue_active(&ep->wq))
-                       wake_up(&ep->wq);
+                       __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE);
                if (waitqueue_active(&ep->poll_wait))
                        pwake++;
        }
@@ -1083,7 +1083,8 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
 
                                /* Notify waiting tasks that events are available */
                                if (waitqueue_active(&ep->wq))
-                                       wake_up(&ep->wq);
+                                       __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
+                                                        TASK_INTERRUPTIBLE);
                                if (waitqueue_active(&ep->poll_wait))
                                        pwake++;
                        }
@@ -1260,7 +1261,8 @@ is_linked:
         * wait list.
         */
        if (waitqueue_active(&ep->wq))
-               wake_up(&ep->wq);
+               __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
+                                TASK_INTERRUPTIBLE);
        if (waitqueue_active(&ep->poll_wait))
                pwake++;
 
@@ -1444,7 +1446,8 @@ static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist)
                 * wait list.
                 */
                if (waitqueue_active(&ep->wq))
-                       wake_up(&ep->wq);
+                       __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
+                                        TASK_INTERRUPTIBLE);
                if (waitqueue_active(&ep->poll_wait))
                        pwake++;
        }
@@ -1516,7 +1519,7 @@ retry:
                 * ep_poll_callback() when events will become available.
                 */
                init_waitqueue_entry(&wait, current);
-               add_wait_queue(&ep->wq, &wait);
+               __add_wait_queue(&ep->wq, &wait);
 
                for (;;) {
                        /*
@@ -1536,7 +1539,7 @@ retry:
                        jtimeout = schedule_timeout(jtimeout);
                        write_lock_irqsave(&ep->lock, flags);
                }
-               remove_wait_queue(&ep->wq, &wait);
+               __remove_wait_queue(&ep->wq, &wait);
 
                set_current_state(TASK_RUNNING);
        }
index c5d02da73bc3dd192d42465bc544f719ab2cba90..e0b2b43c1fdb956115e18423d19f886ca6c7272d 100644 (file)
@@ -4,7 +4,7 @@
 
 obj-$(CONFIG_EXT2_FS) += ext2.o
 
-ext2-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
+ext2-y := balloc.o dir.o file.o fsync.o ialloc.o inode.o \
          ioctl.o namei.o super.o symlink.o
 
 ext2-$(CONFIG_EXT2_FS_XATTR)    += xattr.o xattr_user.o xattr_trusted.o
index 2c00953d4b0b909b483f05f94b33da7f893c3acf..433a213a8bd9450f7f1ab3e7926002217d6cf1f9 100644 (file)
@@ -521,6 +521,26 @@ io_error:
        goto out_release;
 }
 
+#ifdef EXT2FS_DEBUG
+
+static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
+
+unsigned long ext2_count_free (struct buffer_head * map, unsigned int numchars)
+{
+       unsigned int i;
+       unsigned long sum = 0;
+
+       if (!map)
+               return (0);
+       for (i = 0; i < numchars; i++)
+               sum += nibblemap[map->b_data[i] & 0xf] +
+                       nibblemap[(map->b_data[i] >> 4) & 0xf];
+       return (sum);
+}
+
+#endif  /*  EXT2FS_DEBUG  */
+
+/* Superblock must be locked */
 unsigned long ext2_count_free_blocks (struct super_block * sb)
 {
        struct ext2_group_desc * desc;
@@ -530,7 +550,6 @@ unsigned long ext2_count_free_blocks (struct super_block * sb)
        unsigned long bitmap_count, x;
        struct ext2_super_block *es;
 
-       lock_super (sb);
        es = EXT2_SB(sb)->s_es;
        desc_count = 0;
        bitmap_count = 0;
@@ -554,7 +573,6 @@ unsigned long ext2_count_free_blocks (struct super_block * sb)
        printk("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu\n",
                (long)le32_to_cpu(es->s_free_blocks_count),
                desc_count, bitmap_count);
-       unlock_super (sb);
        return bitmap_count;
 #else
         for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {
diff --git a/fs/ext2/bitmap.c b/fs/ext2/bitmap.c
deleted file mode 100644 (file)
index e9983a0..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- *  linux/fs/ext2/bitmap.c
- *
- * Copyright (C) 1992, 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- */
-
-#ifdef EXT2FS_DEBUG
-
-#include <linux/buffer_head.h>
-
-#include "ext2.h"
-
-static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
-
-unsigned long ext2_count_free (struct buffer_head * map, unsigned int numchars)
-{
-       unsigned int i;
-       unsigned long sum = 0;
-       
-       if (!map) 
-               return (0);
-       for (i = 0; i < numchars; i++)
-               sum += nibblemap[map->b_data[i] & 0xf] +
-                       nibblemap[(map->b_data[i] >> 4) & 0xf];
-       return (sum);
-}
-
-#endif  /*  EXT2FS_DEBUG  */
-
index 3c1c9aaaca6bef152deae5d93b03e9db7e278d67..92ea8265d7d5248e046954369da84b86bb858753 100644 (file)
@@ -399,8 +399,7 @@ ino_t ext2_inode_by_name(struct inode * dir, struct dentry *dentry)
        de = ext2_find_entry (dir, dentry, &page);
        if (de) {
                res = le32_to_cpu(de->inode);
-               kunmap(page);
-               page_cache_release(page);
+               ext2_put_page(page);
        }
        return res;
 }
index c9c2e5ffa48e264a8054cff6fb54bf93447987c7..7806b9e8155bfd8c8b8043faa872e968c2a41369 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "ext2.h"
 #include <linux/smp_lock.h>
-#include <linux/buffer_head.h>         /* for fsync_inode_buffers() */
+#include <linux/buffer_head.h>         /* for sync_mapping_buffers() */
 
 
 /*
index e52765219e165eb866c4a0dafd120ce1d966806c..308c252568c6ed131a74377a0ebf9e2262002037 100644 (file)
@@ -638,6 +638,7 @@ fail:
        return ERR_PTR(err);
 }
 
+/* Superblock must be locked */
 unsigned long ext2_count_free_inodes (struct super_block * sb)
 {
        struct ext2_group_desc *desc;
@@ -649,7 +650,6 @@ unsigned long ext2_count_free_inodes (struct super_block * sb)
        unsigned long bitmap_count = 0;
        struct buffer_head *bitmap_bh = NULL;
 
-       lock_super (sb);
        es = EXT2_SB(sb)->s_es;
        for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {
                unsigned x;
@@ -672,7 +672,6 @@ unsigned long ext2_count_free_inodes (struct super_block * sb)
        printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n",
                percpu_counter_read(&EXT2_SB(sb)->s_freeinodes_counter),
                desc_count, bitmap_count);
-       unlock_super(sb);
        return desc_count;
 #else
        for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {
index ee4ba759581e45d8ccfa0bfb0704f5d4050bcdb4..d4233b2e6436ec3926110bb7c5160060ba6dd239 100644 (file)
@@ -854,7 +854,6 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
        }
        if (!ext2_check_descriptors (sb)) {
                printk ("EXT2-fs: group descriptors corrupted!\n");
-               db_count = i;
                goto failed_mount2;
        }
        sbi->s_gdb_count = db_count;
@@ -1046,6 +1045,7 @@ static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf)
        unsigned long overhead;
        int i;
 
+       lock_super(sb);
        if (test_opt (sb, MINIX_DF))
                overhead = 0;
        else {
@@ -1086,6 +1086,7 @@ static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf)
        buf->f_files = le32_to_cpu(sbi->s_es->s_inodes_count);
        buf->f_ffree = ext2_count_free_inodes (sb);
        buf->f_namelen = EXT2_NAME_LEN;
+       unlock_super(sb);
        return 0;
 }
 
index 77927d6938f61d369e0f64f4bfec1637d2ebd203..96172e89ddc3ca945eb959db272658fef495e479 100644 (file)
@@ -163,20 +163,19 @@ restart:
 #endif
 
 static int
-goal_in_my_reservation(struct ext3_reserve_window *rsv, int goal,
+goal_in_my_reservation(struct ext3_reserve_window *rsv, ext3_grpblk_t grp_goal,
                        unsigned int group, struct super_block * sb)
 {
-       unsigned long group_first_block, group_last_block;
+       ext3_fsblk_t group_first_block, group_last_block;
 
-       group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
-                               group * EXT3_BLOCKS_PER_GROUP(sb);
+       group_first_block = ext3_group_first_block_no(sb, group);
        group_last_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1;
 
        if ((rsv->_rsv_start > group_last_block) ||
            (rsv->_rsv_end < group_first_block))
                return 0;
-       if ((goal >= 0) && ((goal + group_first_block < rsv->_rsv_start)
-               || (goal + group_first_block > rsv->_rsv_end)))
+       if ((grp_goal >= 0) && ((grp_goal + group_first_block < rsv->_rsv_start)
+               || (grp_goal + group_first_block > rsv->_rsv_end)))
                return 0;
        return 1;
 }
@@ -187,7 +186,7 @@ goal_in_my_reservation(struct ext3_reserve_window *rsv, int goal,
  * Returns NULL if there are no windows or if all windows start after the goal.
  */
 static struct ext3_reserve_window_node *
-search_reserve_window(struct rb_root *root, unsigned long goal)
+search_reserve_window(struct rb_root *root, ext3_fsblk_t goal)
 {
        struct rb_node *n = root->rb_node;
        struct ext3_reserve_window_node *rsv;
@@ -223,7 +222,7 @@ void ext3_rsv_window_add(struct super_block *sb,
 {
        struct rb_root *root = &EXT3_SB(sb)->s_rsv_window_root;
        struct rb_node *node = &rsv->rsv_node;
-       unsigned int start = rsv->rsv_start;
+       ext3_fsblk_t start = rsv->rsv_start;
 
        struct rb_node ** p = &root->rb_node;
        struct rb_node * parent = NULL;
@@ -310,20 +309,20 @@ void ext3_discard_reservation(struct inode *inode)
 
 /* Free given blocks, update quota and i_blocks field */
 void ext3_free_blocks_sb(handle_t *handle, struct super_block *sb,
-                        unsigned long block, unsigned long count,
-                        int *pdquot_freed_blocks)
+                        ext3_fsblk_t block, unsigned long count,
+                        unsigned long *pdquot_freed_blocks)
 {
        struct buffer_head *bitmap_bh = NULL;
        struct buffer_head *gd_bh;
        unsigned long block_group;
-       unsigned long bit;
+       ext3_grpblk_t bit;
        unsigned long i;
        unsigned long overflow;
        struct ext3_group_desc * desc;
        struct ext3_super_block * es;
        struct ext3_sb_info *sbi;
        int err = 0, ret;
-       unsigned group_freed;
+       ext3_grpblk_t group_freed;
 
        *pdquot_freed_blocks = 0;
        sbi = EXT3_SB(sb);
@@ -333,7 +332,7 @@ void ext3_free_blocks_sb(handle_t *handle, struct super_block *sb,
            block + count > le32_to_cpu(es->s_blocks_count)) {
                ext3_error (sb, "ext3_free_blocks",
                            "Freeing blocks not in datazone - "
-                           "block = %lu, count = %lu", block, count);
+                           "block = "E3FSBLK", count = %lu", block, count);
                goto error_return;
        }
 
@@ -369,7 +368,7 @@ do_more:
                      sbi->s_itb_per_group))
                ext3_error (sb, "ext3_free_blocks",
                            "Freeing blocks in system zones - "
-                           "Block = %lu, count = %lu",
+                           "Block = "E3FSBLK", count = %lu",
                            block, count);
 
        /*
@@ -453,7 +452,8 @@ do_more:
                                                bit + i, bitmap_bh->b_data)) {
                        jbd_unlock_bh_state(bitmap_bh);
                        ext3_error(sb, __FUNCTION__,
-                               "bit already cleared for block %lu", block + i);
+                               "bit already cleared for block "E3FSBLK,
+                                block + i);
                        jbd_lock_bh_state(bitmap_bh);
                        BUFFER_TRACE(bitmap_bh, "bit already cleared");
                } else {
@@ -493,10 +493,10 @@ error_return:
 
 /* Free given blocks, update quota and i_blocks field */
 void ext3_free_blocks(handle_t *handle, struct inode *inode,
-                       unsigned long block, unsigned long count)
+                       ext3_fsblk_t block, unsigned long count)
 {
        struct super_block * sb;
-       int dquot_freed_blocks;
+       unsigned long dquot_freed_blocks;
 
        sb = inode->i_sb;
        if (!sb) {
@@ -525,7 +525,7 @@ void ext3_free_blocks(handle_t *handle, struct inode *inode,
  * data-writes at some point, and disable it for metadata allocations or
  * sync-data inodes.
  */
-static int ext3_test_allocatable(int nr, struct buffer_head *bh)
+static int ext3_test_allocatable(ext3_grpblk_t nr, struct buffer_head *bh)
 {
        int ret;
        struct journal_head *jh = bh2jh(bh);
@@ -542,11 +542,11 @@ static int ext3_test_allocatable(int nr, struct buffer_head *bh)
        return ret;
 }
 
-static int
-bitmap_search_next_usable_block(int start, struct buffer_head *bh,
-                                       int maxblocks)
+static ext3_grpblk_t
+bitmap_search_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh,
+                                       ext3_grpblk_t maxblocks)
 {
-       int next;
+       ext3_grpblk_t next;
        struct journal_head *jh = bh2jh(bh);
 
        /*
@@ -576,10 +576,11 @@ bitmap_search_next_usable_block(int start, struct buffer_head *bh,
  * the initial goal; then for a free byte somewhere in the bitmap; then
  * for any free bit in the bitmap.
  */
-static int
-find_next_usable_block(int start, struct buffer_head *bh, int maxblocks)
+static ext3_grpblk_t
+find_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh,
+                       ext3_grpblk_t maxblocks)
 {
-       int here, next;
+       ext3_grpblk_t here, next;
        char *p, *r;
 
        if (start > 0) {
@@ -591,7 +592,7 @@ find_next_usable_block(int start, struct buffer_head *bh, int maxblocks)
                 * less than EXT3_BLOCKS_PER_GROUP. Aligning up to the
                 * next 64-bit boundary is simple..
                 */
-               int end_goal = (start + 63) & ~63;
+               ext3_grpblk_t end_goal = (start + 63) & ~63;
                if (end_goal > maxblocks)
                        end_goal = maxblocks;
                here = ext3_find_next_zero_bit(bh->b_data, end_goal, start);
@@ -628,7 +629,7 @@ find_next_usable_block(int start, struct buffer_head *bh, int maxblocks)
  * zero (failure).
  */
 static inline int
-claim_block(spinlock_t *lock, int block, struct buffer_head *bh)
+claim_block(spinlock_t *lock, ext3_grpblk_t block, struct buffer_head *bh)
 {
        struct journal_head *jh = bh2jh(bh);
        int ret;
@@ -651,19 +652,18 @@ claim_block(spinlock_t *lock, int block, struct buffer_head *bh)
  * new bitmap.  In that case we must release write access to the old one via
  * ext3_journal_release_buffer(), else we'll run out of credits.
  */
-static int
+static ext3_grpblk_t
 ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group,
-                       struct buffer_head *bitmap_bh, int goal,
+                       struct buffer_head *bitmap_bh, ext3_grpblk_t grp_goal,
                        unsigned long *count, struct ext3_reserve_window *my_rsv)
 {
-       int group_first_block, start, end;
+       ext3_fsblk_t group_first_block;
+       ext3_grpblk_t start, end;
        unsigned long num = 0;
 
        /* we do allocation within the reservation window if we have a window */
        if (my_rsv) {
-               group_first_block =
-                       le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
-                       group * EXT3_BLOCKS_PER_GROUP(sb);
+               group_first_block = ext3_group_first_block_no(sb, group);
                if (my_rsv->_rsv_start >= group_first_block)
                        start = my_rsv->_rsv_start - group_first_block;
                else
@@ -673,13 +673,13 @@ ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group,
                if (end > EXT3_BLOCKS_PER_GROUP(sb))
                        /* reservation window crosses group boundary */
                        end = EXT3_BLOCKS_PER_GROUP(sb);
-               if ((start <= goal) && (goal < end))
-                       start = goal;
+               if ((start <= grp_goal) && (grp_goal < end))
+                       start = grp_goal;
                else
-                       goal = -1;
+                       grp_goal = -1;
        } else {
-               if (goal > 0)
-                       start = goal;
+               if (grp_goal > 0)
+                       start = grp_goal;
                else
                        start = 0;
                end = EXT3_BLOCKS_PER_GROUP(sb);
@@ -688,43 +688,43 @@ ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group,
        BUG_ON(start > EXT3_BLOCKS_PER_GROUP(sb));
 
 repeat:
-       if (goal < 0 || !ext3_test_allocatable(goal, bitmap_bh)) {
-               goal = find_next_usable_block(start, bitmap_bh, end);
-               if (goal < 0)
+       if (grp_goal < 0 || !ext3_test_allocatable(grp_goal, bitmap_bh)) {
+               grp_goal = find_next_usable_block(start, bitmap_bh, end);
+               if (grp_goal < 0)
                        goto fail_access;
                if (!my_rsv) {
                        int i;
 
-                       for (i = 0; i < 7 && goal > start &&
-                                       ext3_test_allocatable(goal - 1,
+                       for (i = 0; i < 7 && grp_goal > start &&
+                                       ext3_test_allocatable(grp_goal - 1,
                                                                bitmap_bh);
-                                       i++, goal--)
+                                       i++, grp_goal--)
                                ;
                }
        }
-       start = goal;
+       start = grp_goal;
 
-       if (!claim_block(sb_bgl_lock(EXT3_SB(sb), group), goal, bitmap_bh)) {
+       if (!claim_block(sb_bgl_lock(EXT3_SB(sb), group), grp_goal, bitmap_bh)) {
                /*
                 * The block was allocated by another thread, or it was
                 * allocated and then freed by another thread
                 */
                start++;
-               goal++;
+               grp_goal++;
                if (start >= end)
                        goto fail_access;
                goto repeat;
        }
        num++;
-       goal++;
-       while (num < *count && goal < end
-               && ext3_test_allocatable(goal, bitmap_bh)
-               && claim_block(sb_bgl_lock(EXT3_SB(sb), group), goal, bitmap_bh)) {
+       grp_goal++;
+       while (num < *count && grp_goal < end
+               && ext3_test_allocatable(grp_goal, bitmap_bh)
+               && claim_block(sb_bgl_lock(EXT3_SB(sb), group), grp_goal, bitmap_bh)) {
                num++;
-               goal++;
+               grp_goal++;
        }
        *count = num;
-       return goal - num;
+       return grp_goal - num;
 fail_access:
        *count = num;
        return -1;
@@ -766,12 +766,13 @@ fail_access:
 static int find_next_reservable_window(
                                struct ext3_reserve_window_node *search_head,
                                struct ext3_reserve_window_node *my_rsv,
-                               struct super_block * sb, int start_block,
-                               int last_block)
+                               struct super_block * sb,
+                               ext3_fsblk_t start_block,
+                               ext3_fsblk_t last_block)
 {
        struct rb_node *next;
        struct ext3_reserve_window_node *rsv, *prev;
-       int cur;
+       ext3_fsblk_t cur;
        int size = my_rsv->rsv_goal_size;
 
        /* TODO: make the start of the reservation window byte-aligned */
@@ -873,10 +874,10 @@ static int find_next_reservable_window(
  *
  *     @rsv: the reservation
  *
- *     @goal: The goal (group-relative).  It is where the search for a
+ *     @grp_goal: The goal (group-relative).  It is where the search for a
  *             free reservable space should start from.
- *             if we have a goal(goal >0 ), then start from there,
- *             no goal(goal = -1), we start from the first block
+ *             if we have a grp_goal(grp_goal >0 ), then start from there,
+ *             no grp_goal(grp_goal = -1), we start from the first block
  *             of the group.
  *
  *     @sb: the super block
@@ -885,25 +886,24 @@ static int find_next_reservable_window(
  *
  */
 static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
-               int goal, struct super_block *sb,
+               ext3_grpblk_t grp_goal, struct super_block *sb,
                unsigned int group, struct buffer_head *bitmap_bh)
 {
        struct ext3_reserve_window_node *search_head;
-       int group_first_block, group_end_block, start_block;
-       int first_free_block;
+       ext3_fsblk_t group_first_block, group_end_block, start_block;
+       ext3_grpblk_t first_free_block;
        struct rb_root *fs_rsv_root = &EXT3_SB(sb)->s_rsv_window_root;
        unsigned long size;
        int ret;
        spinlock_t *rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock;
 
-       group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
-                               group * EXT3_BLOCKS_PER_GROUP(sb);
+       group_first_block = ext3_group_first_block_no(sb, group);
        group_end_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1;
 
-       if (goal < 0)
+       if (grp_goal < 0)
                start_block = group_first_block;
        else
-               start_block = goal + group_first_block;
+               start_block = grp_goal + group_first_block;
 
        size = my_rsv->rsv_goal_size;
 
@@ -1057,14 +1057,15 @@ static void try_to_extend_reservation(struct ext3_reserve_window_node *my_rsv,
  * sorted double linked list should be fast.
  *
  */
-static int
+static ext3_grpblk_t
 ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
                        unsigned int group, struct buffer_head *bitmap_bh,
-                       int goal, struct ext3_reserve_window_node * my_rsv,
+                       ext3_grpblk_t grp_goal,
+                       struct ext3_reserve_window_node * my_rsv,
                        unsigned long *count, int *errp)
 {
-       unsigned long group_first_block;
-       int ret = 0;
+       ext3_fsblk_t group_first_block;
+       ext3_grpblk_t ret = 0;
        int fatal;
        unsigned long num = *count;
 
@@ -1090,17 +1091,16 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
         */
        if (my_rsv == NULL ) {
                ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh,
-                                               goal, count, NULL);
+                                               grp_goal, count, NULL);
                goto out;
        }
        /*
-        * goal is a group relative block number (if there is a goal)
-        * 0 < goal < EXT3_BLOCKS_PER_GROUP(sb)
+        * grp_goal is a group relative block number (if there is a goal)
+        * 0 < grp_goal < EXT3_BLOCKS_PER_GROUP(sb)
         * first block is a filesystem wide block number
         * first block is the block number of the first block in this group
         */
-       group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
-                       group * EXT3_BLOCKS_PER_GROUP(sb);
+       group_first_block = ext3_group_first_block_no(sb, group);
 
        /*
         * Basically we will allocate a new block from inode's reservation
@@ -1119,24 +1119,24 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
         */
        while (1) {
                if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) ||
-                       !goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb)) {
+                       !goal_in_my_reservation(&my_rsv->rsv_window, grp_goal, group, sb)) {
                        if (my_rsv->rsv_goal_size < *count)
                                my_rsv->rsv_goal_size = *count;
-                       ret = alloc_new_reservation(my_rsv, goal, sb,
+                       ret = alloc_new_reservation(my_rsv, grp_goal, sb,
                                                        group, bitmap_bh);
                        if (ret < 0)
                                break;                  /* failed */
 
-                       if (!goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb))
-                               goal = -1;
-               } else if (goal > 0 && (my_rsv->rsv_end-goal+1) < *count)
+                       if (!goal_in_my_reservation(&my_rsv->rsv_window, grp_goal, group, sb))
+                               grp_goal = -1;
+               } else if (grp_goal > 0 && (my_rsv->rsv_end-grp_goal+1) < *count)
                        try_to_extend_reservation(my_rsv, sb,
-                                       *count-my_rsv->rsv_end + goal - 1);
+                                       *count-my_rsv->rsv_end + grp_goal - 1);
 
                if ((my_rsv->rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb))
                    || (my_rsv->rsv_end < group_first_block))
                        BUG();
-               ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal,
+               ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, grp_goal,
                                           &num, &my_rsv->rsv_window);
                if (ret >= 0) {
                        my_rsv->rsv_alloc_hit += num;
@@ -1164,7 +1164,7 @@ out:
 
 static int ext3_has_free_blocks(struct ext3_sb_info *sbi)
 {
-       int free_blocks, root_blocks;
+       ext3_fsblk_t free_blocks, root_blocks;
 
        free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
        root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);
@@ -1200,19 +1200,20 @@ int ext3_should_retry_alloc(struct super_block *sb, int *retries)
  * bitmap, and then for any free bit if that fails.
  * This function also updates quota and i_blocks field.
  */
-int ext3_new_blocks(handle_t *handle, struct inode *inode,
-                       unsigned long goal, unsigned long *count, int *errp)
+ext3_fsblk_t ext3_new_blocks(handle_t *handle, struct inode *inode,
+                       ext3_fsblk_t goal, unsigned long *count, int *errp)
 {
        struct buffer_head *bitmap_bh = NULL;
        struct buffer_head *gdp_bh;
        int group_no;
        int goal_group;
-       int ret_block;
+       ext3_grpblk_t grp_target_blk;   /* blockgroup relative goal block */
+       ext3_grpblk_t grp_alloc_blk;    /* blockgroup-relative allocated block*/
+       ext3_fsblk_t ret_block;         /* filesyetem-wide allocated block */
        int bgi;                        /* blockgroup iteration index */
-       int target_block;
        int fatal = 0, err;
        int performed_allocation = 0;
-       int free_blocks;
+       ext3_grpblk_t free_blocks;      /* number of free blocks in a group */
        struct super_block *sb;
        struct ext3_group_desc *gdp;
        struct ext3_super_block *es;
@@ -1285,16 +1286,17 @@ retry:
                my_rsv = NULL;
 
        if (free_blocks > 0) {
-               ret_block = ((goal - le32_to_cpu(es->s_first_data_block)) %
+               grp_target_blk = ((goal - le32_to_cpu(es->s_first_data_block)) %
                                EXT3_BLOCKS_PER_GROUP(sb));
                bitmap_bh = read_block_bitmap(sb, group_no);
                if (!bitmap_bh)
                        goto io_error;
-               ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no,
-                                       bitmap_bh, ret_block, my_rsv, &num, &fatal);
+               grp_alloc_blk = ext3_try_to_allocate_with_rsv(sb, handle,
+                                       group_no, bitmap_bh, grp_target_blk,
+                                       my_rsv, &num, &fatal);
                if (fatal)
                        goto out;
-               if (ret_block >= 0)
+               if (grp_alloc_blk >= 0)
                        goto allocated;
        }
 
@@ -1327,11 +1329,15 @@ retry:
                bitmap_bh = read_block_bitmap(sb, group_no);
                if (!bitmap_bh)
                        goto io_error;
-               ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no,
-                                       bitmap_bh, -1, my_rsv, &num, &fatal);
+               /*
+                * try to allocate block(s) from this group, without a goal(-1).
+                */
+               grp_alloc_blk = ext3_try_to_allocate_with_rsv(sb, handle,
+                                       group_no, bitmap_bh, -1, my_rsv,
+                                       &num, &fatal);
                if (fatal)
                        goto out;
-               if (ret_block >= 0) 
+               if (grp_alloc_blk >= 0)
                        goto allocated;
        }
        /*
@@ -1360,18 +1366,18 @@ allocated:
        if (fatal)
                goto out;
 
-       target_block = ret_block + group_no * EXT3_BLOCKS_PER_GROUP(sb)
-                               + le32_to_cpu(es->s_first_data_block);
+       ret_block = grp_alloc_blk + ext3_group_first_block_no(sb, group_no);
 
-       if (in_range(le32_to_cpu(gdp->bg_block_bitmap), target_block, num) ||
-           in_range(le32_to_cpu(gdp->bg_inode_bitmap), target_block, num) ||
-           in_range(target_block, le32_to_cpu(gdp->bg_inode_table),
+       if (in_range(le32_to_cpu(gdp->bg_block_bitmap), ret_block, num) ||
+           in_range(le32_to_cpu(gdp->bg_inode_bitmap), ret_block, num) ||
+           in_range(ret_block, le32_to_cpu(gdp->bg_inode_table),
                      EXT3_SB(sb)->s_itb_per_group) ||
-           in_range(target_block + num - 1, le32_to_cpu(gdp->bg_inode_table),
+           in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table),
                      EXT3_SB(sb)->s_itb_per_group))
                ext3_error(sb, "ext3_new_block",
                            "Allocating block in system zone - "
-                           "blocks from %u, length %lu", target_block, num);
+                           "blocks from "E3FSBLK", length %lu",
+                            ret_block, num);
 
        performed_allocation = 1;
 
@@ -1380,7 +1386,7 @@ allocated:
                struct buffer_head *debug_bh;
 
                /* Record bitmap buffer state in the newly allocated block */
-               debug_bh = sb_find_get_block(sb, target_block);
+               debug_bh = sb_find_get_block(sb, ret_block);
                if (debug_bh) {
                        BUFFER_TRACE(debug_bh, "state when allocated");
                        BUFFER_TRACE2(debug_bh, bitmap_bh, "bitmap state");
@@ -1393,24 +1399,21 @@ allocated:
                int i;
 
                for (i = 0; i < num; i++) {
-                       if (ext3_test_bit(ret_block,
+                       if (ext3_test_bit(grp_alloc_blk+i,
                                        bh2jh(bitmap_bh)->b_committed_data)) {
                                printk("%s: block was unexpectedly set in "
                                        "b_committed_data\n", __FUNCTION__);
                        }
                }
        }
-       ext3_debug("found bit %d\n", ret_block);
+       ext3_debug("found bit %d\n", grp_alloc_blk);
        spin_unlock(sb_bgl_lock(sbi, group_no));
        jbd_unlock_bh_state(bitmap_bh);
 #endif
 
-       /* ret_block was blockgroup-relative.  Now it becomes fs-relative */
-       ret_block = target_block;
-
        if (ret_block + num - 1 >= le32_to_cpu(es->s_blocks_count)) {
                ext3_error(sb, "ext3_new_block",
-                           "block(%d) >= blocks count(%d) - "
+                           "block("E3FSBLK") >= blocks count(%d) - "
                            "block_group = %d, es == %p ", ret_block,
                        le32_to_cpu(es->s_blocks_count), group_no, es);
                goto out;
@@ -1421,7 +1424,7 @@ allocated:
         * list of some description.  We don't know in advance whether
         * the caller wants to use it as metadata or data.
         */
-       ext3_debug("allocating block %d. Goal hits %d of %d.\n",
+       ext3_debug("allocating block %lu. Goal hits %d of %d.\n",
                        ret_block, goal_hits, goal_attempts);
 
        spin_lock(sb_bgl_lock(sbi, group_no));
@@ -1461,23 +1464,24 @@ out:
        return 0;
 }
 
-int ext3_new_block(handle_t *handle, struct inode *inode,
-                       unsigned long goal, int *errp)
+ext3_fsblk_t ext3_new_block(handle_t *handle, struct inode *inode,
+                       ext3_fsblk_t goal, int *errp)
 {
        unsigned long count = 1;
 
        return ext3_new_blocks(handle, inode, goal, &count, errp);
 }
 
-unsigned long ext3_count_free_blocks(struct super_block *sb)
+ext3_fsblk_t ext3_count_free_blocks(struct super_block *sb)
 {
-       unsigned long desc_count;
+       ext3_fsblk_t desc_count;
        struct ext3_group_desc *gdp;
        int i;
        unsigned long ngroups = EXT3_SB(sb)->s_groups_count;
 #ifdef EXT3FS_DEBUG
        struct ext3_super_block *es;
-       unsigned long bitmap_count, x;
+       ext3_fsblk_t bitmap_count;
+       unsigned long x;
        struct buffer_head *bitmap_bh = NULL;
 
        es = EXT3_SB(sb)->s_es;
@@ -1502,8 +1506,10 @@ unsigned long ext3_count_free_blocks(struct super_block *sb)
                bitmap_count += x;
        }
        brelse(bitmap_bh);
-       printk("ext3_count_free_blocks: stored = %u, computed = %lu, %lu\n",
-              le32_to_cpu(es->s_free_blocks_count), desc_count, bitmap_count);
+       printk("ext3_count_free_blocks: stored = "E3FSBLK
+               ", computed = "E3FSBLK", "E3FSBLK"\n",
+              le32_to_cpu(es->s_free_blocks_count),
+               desc_count, bitmap_count);
        return bitmap_count;
 #else
        desc_count = 0;
@@ -1520,7 +1526,7 @@ unsigned long ext3_count_free_blocks(struct super_block *sb)
 }
 
 static inline int
-block_in_use(unsigned long block, struct super_block *sb, unsigned char *map)
+block_in_use(ext3_fsblk_t block, struct super_block *sb, unsigned char *map)
 {
        return ext3_test_bit ((block -
                le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block)) %
index dc826464f313d884a55276786a0a7aed008fe711..36546ed36a1476df87adf736bcab38a9dbcac822 100644 (file)
@@ -262,9 +262,11 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent)
        int ngroups = sbi->s_groups_count;
        int inodes_per_group = EXT3_INODES_PER_GROUP(sb);
        int freei, avefreei;
-       int freeb, avefreeb;
-       int blocks_per_dir, ndirs;
-       int max_debt, max_dirs, min_blocks, min_inodes;
+       ext3_fsblk_t freeb, avefreeb;
+       ext3_fsblk_t blocks_per_dir;
+       int ndirs;
+       int max_debt, max_dirs, min_inodes;
+       ext3_grpblk_t min_blocks;
        int group = -1, i;
        struct ext3_group_desc *desc;
        struct buffer_head *bh;
@@ -307,7 +309,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent)
        min_inodes = avefreei - inodes_per_group / 4;
        min_blocks = avefreeb - EXT3_BLOCKS_PER_GROUP(sb) / 4;
 
-       max_debt = EXT3_BLOCKS_PER_GROUP(sb) / max(blocks_per_dir, BLOCK_COST);
+       max_debt = EXT3_BLOCKS_PER_GROUP(sb) / max(blocks_per_dir, (ext3_fsblk_t)BLOCK_COST);
        if (max_debt * INODE_COST > inodes_per_group)
                max_debt = inodes_per_group / INODE_COST;
        if (max_debt > 255)
index 2edd7eec88fd90295338042bd39dcc525ae78460..0321e1b9034a9e71db80c43cc372402ef3371c8c 100644 (file)
@@ -62,7 +62,7 @@ static int ext3_inode_is_fast_symlink(struct inode *inode)
  * still needs to be revoked.
  */
 int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode,
-                       struct buffer_head *bh, int blocknr)
+                       struct buffer_head *bh, ext3_fsblk_t blocknr)
 {
        int err;
 
@@ -407,13 +407,13 @@ no_block:
  *
  *     Caller must make sure that @ind is valid and will stay that way.
  */
-static unsigned long ext3_find_near(struct inode *inode, Indirect *ind)
+static ext3_fsblk_t ext3_find_near(struct inode *inode, Indirect *ind)
 {
        struct ext3_inode_info *ei = EXT3_I(inode);
        __le32 *start = ind->bh ? (__le32*) ind->bh->b_data : ei->i_data;
        __le32 *p;
-       unsigned long bg_start;
-       unsigned long colour;
+       ext3_fsblk_t bg_start;
+       ext3_grpblk_t colour;
 
        /* Try to find previous block */
        for (p = ind->p - 1; p >= start; p--) {
@@ -429,8 +429,7 @@ static unsigned long ext3_find_near(struct inode *inode, Indirect *ind)
         * It is going to be referred to from the inode itself? OK, just put it
         * into the same cylinder group then.
         */
-       bg_start = (ei->i_block_group * EXT3_BLOCKS_PER_GROUP(inode->i_sb)) +
-               le32_to_cpu(EXT3_SB(inode->i_sb)->s_es->s_first_data_block);
+       bg_start = ext3_group_first_block_no(inode->i_sb, ei->i_block_group);
        colour = (current->pid % 16) *
                        (EXT3_BLOCKS_PER_GROUP(inode->i_sb) / 16);
        return bg_start + colour;
@@ -448,7 +447,7 @@ static unsigned long ext3_find_near(struct inode *inode, Indirect *ind)
  *     stores it in *@goal and returns zero.
  */
 
-static unsigned long ext3_find_goal(struct inode *inode, long block,
+static ext3_fsblk_t ext3_find_goal(struct inode *inode, long block,
                Indirect chain[4], Indirect *partial)
 {
        struct ext3_block_alloc_info *block_i;
@@ -516,13 +515,13 @@ static int ext3_blks_to_allocate(Indirect *branch, int k, unsigned long blks,
  *             direct blocks
  */
 static int ext3_alloc_blocks(handle_t *handle, struct inode *inode,
-                       unsigned long goal, int indirect_blks, int blks,
-                       unsigned long long new_blocks[4], int *err)
+                       ext3_fsblk_t goal, int indirect_blks, int blks,
+                       ext3_fsblk_t new_blocks[4], int *err)
 {
        int target, i;
        unsigned long count = 0;
        int index = 0;
-       unsigned long current_block = 0;
+       ext3_fsblk_t current_block = 0;
        int ret = 0;
 
        /*
@@ -592,7 +591,7 @@ failed_out:
  *     as described above and return 0.
  */
 static int ext3_alloc_branch(handle_t *handle, struct inode *inode,
-                       int indirect_blks, int *blks, unsigned long goal,
+                       int indirect_blks, int *blks, ext3_fsblk_t goal,
                        int *offsets, Indirect *branch)
 {
        int blocksize = inode->i_sb->s_blocksize;
@@ -600,8 +599,8 @@ static int ext3_alloc_branch(handle_t *handle, struct inode *inode,
        int err = 0;
        struct buffer_head *bh;
        int num;
-       unsigned long long new_blocks[4];
-       unsigned long long current_block;
+       ext3_fsblk_t new_blocks[4];
+       ext3_fsblk_t current_block;
 
        num = ext3_alloc_blocks(handle, inode, goal, indirect_blks,
                                *blks, new_blocks, &err);
@@ -688,7 +687,7 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode,
        int i;
        int err = 0;
        struct ext3_block_alloc_info *block_i;
-       unsigned long current_block;
+       ext3_fsblk_t current_block;
 
        block_i = EXT3_I(inode)->i_block_alloc_info;
        /*
@@ -795,13 +794,13 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
        int offsets[4];
        Indirect chain[4];
        Indirect *partial;
-       unsigned long goal;
+       ext3_fsblk_t goal;
        int indirect_blks;
        int blocks_to_boundary = 0;
        int depth;
        struct ext3_inode_info *ei = EXT3_I(inode);
        int count = 0;
-       unsigned long first_block = 0;
+       ext3_fsblk_t first_block = 0;
 
 
        J_ASSERT(handle != NULL || create == 0);
@@ -819,7 +818,7 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
                count++;
                /*map more blocks*/
                while (count < maxblocks && count <= blocks_to_boundary) {
-                       unsigned long blk;
+                       ext3_fsblk_t blk;
 
                        if (!verify_chain(chain, partial)) {
                                /*
@@ -1759,7 +1758,7 @@ void ext3_set_aops(struct inode *inode)
 static int ext3_block_truncate_page(handle_t *handle, struct page *page,
                struct address_space *mapping, loff_t from)
 {
-       unsigned long index = from >> PAGE_CACHE_SHIFT;
+       ext3_fsblk_t index = from >> PAGE_CACHE_SHIFT;
        unsigned offset = from & (PAGE_CACHE_SIZE-1);
        unsigned blocksize, iblock, length, pos;
        struct inode *inode = mapping->host;
@@ -1960,7 +1959,7 @@ no_top:
  * than `count' because there can be holes in there.
  */
 static void ext3_clear_blocks(handle_t *handle, struct inode *inode,
-               struct buffer_head *bh, unsigned long block_to_free,
+               struct buffer_head *bh, ext3_fsblk_t block_to_free,
                unsigned long count, __le32 *first, __le32 *last)
 {
        __le32 *p;
@@ -2022,12 +2021,12 @@ static void ext3_free_data(handle_t *handle, struct inode *inode,
                           struct buffer_head *this_bh,
                           __le32 *first, __le32 *last)
 {
-       unsigned long block_to_free = 0;    /* Starting block # of a run */
+       ext3_fsblk_t block_to_free = 0;    /* Starting block # of a run */
        unsigned long count = 0;            /* Number of blocks in the run */ 
        __le32 *block_to_free_p = NULL;     /* Pointer into inode/ind
                                               corresponding to
                                               block_to_free */
-       unsigned long nr;                   /* Current block # */
+       ext3_fsblk_t nr;                    /* Current block # */
        __le32 *p;                          /* Pointer into inode/ind
                                               for current block */
        int err;
@@ -2089,7 +2088,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode,
                               struct buffer_head *parent_bh,
                               __le32 *first, __le32 *last, int depth)
 {
-       unsigned long nr;
+       ext3_fsblk_t nr;
        __le32 *p;
 
        if (is_handle_aborted(handle))
@@ -2113,7 +2112,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode,
                         */
                        if (!bh) {
                                ext3_error(inode->i_sb, "ext3_free_branches",
-                                          "Read failure, inode=%ld, block=%ld",
+                                          "Read failure, inode=%ld, block="E3FSBLK,
                                           inode->i_ino, nr);
                                continue;
                        }
@@ -2394,11 +2393,12 @@ out_stop:
        ext3_journal_stop(handle);
 }
 
-static unsigned long ext3_get_inode_block(struct super_block *sb,
+static ext3_fsblk_t ext3_get_inode_block(struct super_block *sb,
                unsigned long ino, struct ext3_iloc *iloc)
 {
        unsigned long desc, group_desc, block_group;
-       unsigned long offset, block;
+       unsigned long offset;
+       ext3_fsblk_t block;
        struct buffer_head *bh;
        struct ext3_group_desc * gdp;
 
@@ -2448,7 +2448,7 @@ static unsigned long ext3_get_inode_block(struct super_block *sb,
 static int __ext3_get_inode_loc(struct inode *inode,
                                struct ext3_iloc *iloc, int in_mem)
 {
-       unsigned long block;
+       ext3_fsblk_t block;
        struct buffer_head *bh;
 
        block = ext3_get_inode_block(inode->i_sb, inode->i_ino, iloc);
@@ -2459,7 +2459,8 @@ static int __ext3_get_inode_loc(struct inode *inode,
        if (!bh) {
                ext3_error (inode->i_sb, "ext3_get_inode_loc",
                                "unable to read inode block - "
-                               "inode=%lu, block=%lu", inode->i_ino, block);
+                               "inode=%lu, block="E3FSBLK,
+                                inode->i_ino, block);
                return -EIO;
        }
        if (!buffer_uptodate(bh)) {
@@ -2540,7 +2541,7 @@ make_io:
                if (!buffer_uptodate(bh)) {
                        ext3_error(inode->i_sb, "ext3_get_inode_loc",
                                        "unable to read inode block - "
-                                       "inode=%lu, block=%lu",
+                                       "inode=%lu, block="E3FSBLK,
                                        inode->i_ino, block);
                        brelse(bh);
                        return -EIO;
index 8c22aa9a7fbbfe919190e6ae775442a7004aea58..3a6b012d120cedae637169ee747ec43b36b25e47 100644 (file)
@@ -204,7 +204,7 @@ flags_err:
                return 0;
        }
        case EXT3_IOC_GROUP_EXTEND: {
-               unsigned long n_blocks_count;
+               ext3_fsblk_t n_blocks_count;
                struct super_block *sb = inode->i_sb;
                int err;
 
index b8f5cd1e540d40870ed98a2a25dcdeb06be8f9b4..d9176dba36980b707512c11bbea09131d2bd45ae 100644 (file)
@@ -1379,7 +1379,6 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry,
        int     dx_fallback=0;
 #endif
        unsigned blocksize;
-       unsigned nlen, rlen;
        u32 block, blocks;
 
        sb = dir->i_sb;
@@ -1417,8 +1416,7 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry,
                return retval;
        de = (struct ext3_dir_entry_2 *) bh->b_data;
        de->inode = 0;
-       de->rec_len = cpu_to_le16(rlen = blocksize);
-       nlen = 0;
+       de->rec_len = cpu_to_le16(blocksize);
        return add_dirent_to_buf(handle, dentry, inode, de, bh);
 }
 
index 34b39e9a1e5a01588db869c02c85f2407d12221a..dfd811895d8f4564e8a2781c4786132fa1e96eba 100644 (file)
@@ -28,16 +28,16 @@ static int verify_group_input(struct super_block *sb,
 {
        struct ext3_sb_info *sbi = EXT3_SB(sb);
        struct ext3_super_block *es = sbi->s_es;
-       unsigned start = le32_to_cpu(es->s_blocks_count);
-       unsigned end = start + input->blocks_count;
+       ext3_fsblk_t start = le32_to_cpu(es->s_blocks_count);
+       ext3_fsblk_t end = start + input->blocks_count;
        unsigned group = input->group;
-       unsigned itend = input->inode_table + sbi->s_itb_per_group;
+       ext3_fsblk_t itend = input->inode_table + sbi->s_itb_per_group;
        unsigned overhead = ext3_bg_has_super(sb, group) ?
                (1 + ext3_bg_num_gdb(sb, group) +
                 le16_to_cpu(es->s_reserved_gdt_blocks)) : 0;
-       unsigned metaend = start + overhead;
+       ext3_fsblk_t metaend = start + overhead;
        struct buffer_head *bh = NULL;
-       int free_blocks_count;
+       ext3_grpblk_t free_blocks_count;
        int err = -EINVAL;
 
        input->free_blocks_count = free_blocks_count =
@@ -64,7 +64,8 @@ static int verify_group_input(struct super_block *sb,
                ext3_warning(sb, __FUNCTION__, "Bad blocks count %u",
                             input->blocks_count);
        else if (!(bh = sb_bread(sb, end - 1)))
-               ext3_warning(sb, __FUNCTION__, "Cannot read last block (%u)",
+               ext3_warning(sb, __FUNCTION__,
+                            "Cannot read last block ("E3FSBLK")",
                             end - 1);
        else if (outside(input->block_bitmap, start, end))
                ext3_warning(sb, __FUNCTION__,
@@ -77,7 +78,7 @@ static int verify_group_input(struct super_block *sb,
        else if (outside(input->inode_table, start, end) ||
                 outside(itend - 1, start, end))
                ext3_warning(sb, __FUNCTION__,
-                            "Inode table not in group (blocks %u-%u)",
+                            "Inode table not in group (blocks %u-"E3FSBLK")",
                             input->inode_table, itend - 1);
        else if (input->inode_bitmap == input->block_bitmap)
                ext3_warning(sb, __FUNCTION__,
@@ -85,24 +86,27 @@ static int verify_group_input(struct super_block *sb,
                             input->block_bitmap);
        else if (inside(input->block_bitmap, input->inode_table, itend))
                ext3_warning(sb, __FUNCTION__,
-                            "Block bitmap (%u) in inode table (%u-%u)",
+                            "Block bitmap (%u) in inode table (%u-"E3FSBLK")",
                             input->block_bitmap, input->inode_table, itend-1);
        else if (inside(input->inode_bitmap, input->inode_table, itend))
                ext3_warning(sb, __FUNCTION__,
-                            "Inode bitmap (%u) in inode table (%u-%u)",
+                            "Inode bitmap (%u) in inode table (%u-"E3FSBLK")",
                             input->inode_bitmap, input->inode_table, itend-1);
        else if (inside(input->block_bitmap, start, metaend))
                ext3_warning(sb, __FUNCTION__,
-                            "Block bitmap (%u) in GDT table (%u-%u)",
+                            "Block bitmap (%u) in GDT table"
+                            " ("E3FSBLK"-"E3FSBLK")",
                             input->block_bitmap, start, metaend - 1);
        else if (inside(input->inode_bitmap, start, metaend))
                ext3_warning(sb, __FUNCTION__,
-                            "Inode bitmap (%u) in GDT table (%u-%u)",
+                            "Inode bitmap (%u) in GDT table"
+                            " ("E3FSBLK"-"E3FSBLK")",
                             input->inode_bitmap, start, metaend - 1);
        else if (inside(input->inode_table, start, metaend) ||
                 inside(itend - 1, start, metaend))
                ext3_warning(sb, __FUNCTION__,
-                            "Inode table (%u-%u) overlaps GDT table (%u-%u)",
+                            "Inode table (%u-"E3FSBLK") overlaps"
+                            "GDT table ("E3FSBLK"-"E3FSBLK")",
                             input->inode_table, itend - 1, start, metaend - 1);
        else
                err = 0;
@@ -112,7 +116,7 @@ static int verify_group_input(struct super_block *sb,
 }
 
 static struct buffer_head *bclean(handle_t *handle, struct super_block *sb,
-                                 unsigned long blk)
+                                 ext3_fsblk_t blk)
 {
        struct buffer_head *bh;
        int err;
@@ -163,15 +167,14 @@ static int setup_new_group_blocks(struct super_block *sb,
                                  struct ext3_new_group_data *input)
 {
        struct ext3_sb_info *sbi = EXT3_SB(sb);
-       unsigned long start = input->group * sbi->s_blocks_per_group +
-               le32_to_cpu(sbi->s_es->s_first_data_block);
+       ext3_fsblk_t start = ext3_group_first_block_no(sb, input->group);
        int reserved_gdb = ext3_bg_has_super(sb, input->group) ?
                le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) : 0;
        unsigned long gdblocks = ext3_bg_num_gdb(sb, input->group);
        struct buffer_head *bh;
        handle_t *handle;
-       unsigned long block;
-       int bit;
+       ext3_fsblk_t block;
+       ext3_grpblk_t bit;
        int i;
        int err = 0, err2;
 
@@ -328,7 +331,7 @@ static unsigned ext3_list_backups(struct super_block *sb, unsigned *three,
 static int verify_reserved_gdb(struct super_block *sb,
                               struct buffer_head *primary)
 {
-       const unsigned long blk = primary->b_blocknr;
+       const ext3_fsblk_t blk = primary->b_blocknr;
        const unsigned long end = EXT3_SB(sb)->s_groups_count;
        unsigned three = 1;
        unsigned five = 5;
@@ -340,7 +343,8 @@ static int verify_reserved_gdb(struct super_block *sb,
        while ((grp = ext3_list_backups(sb, &three, &five, &seven)) < end) {
                if (le32_to_cpu(*p++) != grp * EXT3_BLOCKS_PER_GROUP(sb) + blk){
                        ext3_warning(sb, __FUNCTION__,
-                                    "reserved GDT %ld missing grp %d (%ld)",
+                                    "reserved GDT "E3FSBLK
+                                    " missing grp %d ("E3FSBLK")",
                                     blk, grp,
                                     grp * EXT3_BLOCKS_PER_GROUP(sb) + blk);
                        return -EINVAL;
@@ -372,7 +376,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
        struct super_block *sb = inode->i_sb;
        struct ext3_super_block *es = EXT3_SB(sb)->s_es;
        unsigned long gdb_num = input->group / EXT3_DESC_PER_BLOCK(sb);
-       unsigned long gdblock = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num;
+       ext3_fsblk_t gdblock = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num;
        struct buffer_head **o_group_desc, **n_group_desc;
        struct buffer_head *dind;
        int gdbackups;
@@ -417,7 +421,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
        data = (__u32 *)dind->b_data;
        if (le32_to_cpu(data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)]) != gdblock) {
                ext3_warning(sb, __FUNCTION__,
-                            "new group %u GDT block %lu not reserved",
+                            "new group %u GDT block "E3FSBLK" not reserved",
                             input->group, gdblock);
                err = -EINVAL;
                goto exit_dind;
@@ -515,7 +519,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
        struct buffer_head **primary;
        struct buffer_head *dind;
        struct ext3_iloc iloc;
-       unsigned long blk;
+       ext3_fsblk_t blk;
        __u32 *data, *end;
        int gdbackups = 0;
        int res, i;
@@ -540,7 +544,8 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
        for (res = 0; res < reserved_gdb; res++, blk++) {
                if (le32_to_cpu(*data) != blk) {
                        ext3_warning(sb, __FUNCTION__,
-                                    "reserved block %lu not at offset %ld",
+                                    "reserved block "E3FSBLK
+                                    " not at offset %ld",
                                     blk, (long)(data - (__u32 *)dind->b_data));
                        err = -EINVAL;
                        goto exit_bh;
@@ -902,15 +907,16 @@ exit_put:
  * GDT blocks are reserved to grow to the desired size.
  */
 int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
-                     unsigned long n_blocks_count)
+                     ext3_fsblk_t n_blocks_count)
 {
-       unsigned long o_blocks_count;
+       ext3_fsblk_t o_blocks_count;
        unsigned long o_groups_count;
-       unsigned long last;
-       int add;
+       ext3_grpblk_t last;
+       ext3_grpblk_t add;
        struct buffer_head * bh;
        handle_t *handle;
-       int err, freed_blocks;
+       int err;
+       unsigned long freed_blocks;
 
        /* We don't need to worry about locking wrt other resizers just
         * yet: we're going to revalidate es->s_blocks_count after
@@ -919,12 +925,22 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
        o_groups_count = EXT3_SB(sb)->s_groups_count;
 
        if (test_opt(sb, DEBUG))
-               printk(KERN_DEBUG "EXT3-fs: extending last group from %lu to %lu blocks\n",
+               printk(KERN_DEBUG "EXT3-fs: extending last group from "E3FSBLK" uto "E3FSBLK" blocks\n",
                       o_blocks_count, n_blocks_count);
 
        if (n_blocks_count == 0 || n_blocks_count == o_blocks_count)
                return 0;
 
+       if (n_blocks_count > (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {
+               printk(KERN_ERR "EXT3-fs: filesystem on %s:"
+                       " too large to resize to %lu blocks safely\n",
+                       sb->s_id, n_blocks_count);
+               if (sizeof(sector_t) < 8)
+                       ext3_warning(sb, __FUNCTION__,
+                       "CONFIG_LBD not enabled\n");
+               return -EINVAL;
+       }
+
        if (n_blocks_count < o_blocks_count) {
                ext3_warning(sb, __FUNCTION__,
                             "can't shrink FS - resize aborted");
@@ -948,7 +964,8 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
 
        if (o_blocks_count + add < n_blocks_count)
                ext3_warning(sb, __FUNCTION__,
-                            "will only finish group (%lu blocks, %u new)",
+                            "will only finish group ("E3FSBLK
+                            " blocks, %u new)",
                             o_blocks_count + add, add);
 
        /* See if the device is actually as big as what was requested */
@@ -991,10 +1008,10 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
        ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh);
        sb->s_dirt = 1;
        unlock_super(sb);
-       ext3_debug("freeing blocks %ld through %ld\n", o_blocks_count,
+       ext3_debug("freeing blocks %lu through "E3FSBLK"\n", o_blocks_count,
                   o_blocks_count + add);
        ext3_free_blocks_sb(handle, sb, o_blocks_count, add, &freed_blocks);
-       ext3_debug("freed blocks %ld through %ld\n", o_blocks_count,
+       ext3_debug("freed blocks "E3FSBLK" through "E3FSBLK"\n", o_blocks_count,
                   o_blocks_count + add);
        if ((err = ext3_journal_stop(handle)))
                goto exit_put;
index a60cc6ec130f4a1ebe5fcbe296fff141535108b8..b2891cc29db153ded6f06a87e05b9e4e47032059 100644 (file)
@@ -689,14 +689,15 @@ static match_table_t tokens = {
        {Opt_resize, "resize"},
 };
 
-static unsigned long get_sb_block(void **data)
+static ext3_fsblk_t get_sb_block(void **data)
 {
-       unsigned long   sb_block;
+       ext3_fsblk_t    sb_block;
        char            *options = (char *) *data;
 
        if (!options || strncmp(options, "sb=", 3) != 0)
                return 1;       /* Default location */
        options += 3;
+       /*todo: use simple_strtoll with >32bit ext3 */
        sb_block = simple_strtoul(options, &options, 0);
        if (*options && *options != ',') {
                printk("EXT3-fs: Invalid sb specification: %s\n",
@@ -711,7 +712,7 @@ static unsigned long get_sb_block(void **data)
 
 static int parse_options (char *options, struct super_block *sb,
                          unsigned long *inum, unsigned long *journal_devnum,
-                         unsigned long *n_blocks_count, int is_remount)
+                         ext3_fsblk_t *n_blocks_count, int is_remount)
 {
        struct ext3_sb_info *sbi = EXT3_SB(sb);
        char * p;
@@ -1128,7 +1129,7 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es,
 static int ext3_check_descriptors (struct super_block * sb)
 {
        struct ext3_sb_info *sbi = EXT3_SB(sb);
-       unsigned long block = le32_to_cpu(sbi->s_es->s_first_data_block);
+       ext3_fsblk_t block = le32_to_cpu(sbi->s_es->s_first_data_block);
        struct ext3_group_desc * gdp = NULL;
        int desc_block = 0;
        int i;
@@ -1315,15 +1316,14 @@ static loff_t ext3_max_size(int bits)
        return res;
 }
 
-static unsigned long descriptor_loc(struct super_block *sb,
-                                   unsigned long logic_sb_block,
+static ext3_fsblk_t descriptor_loc(struct super_block *sb,
+                                   ext3_fsblk_t logic_sb_block,
                                    int nr)
 {
        struct ext3_sb_info *sbi = EXT3_SB(sb);
-       unsigned long bg, first_data_block, first_meta_bg;
+       unsigned long bg, first_meta_bg;
        int has_super = 0;
 
-       first_data_block = le32_to_cpu(sbi->s_es->s_first_data_block);
        first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
 
        if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_META_BG) ||
@@ -1332,7 +1332,7 @@ static unsigned long descriptor_loc(struct super_block *sb,
        bg = sbi->s_desc_per_block * nr;
        if (ext3_bg_has_super(sb, bg))
                has_super = 1;
-       return (first_data_block + has_super + (bg * sbi->s_blocks_per_group));
+       return (has_super + ext3_group_first_block_no(sb, bg));
 }
 
 
@@ -1341,9 +1341,9 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
        struct buffer_head * bh;
        struct ext3_super_block *es = NULL;
        struct ext3_sb_info *sbi;
-       unsigned long block;
-       unsigned long sb_block = get_sb_block(&data);
-       unsigned long logic_sb_block;
+       ext3_fsblk_t block;
+       ext3_fsblk_t sb_block = get_sb_block(&data);
+       ext3_fsblk_t logic_sb_block;
        unsigned long offset = 0;
        unsigned long journal_inum = 0;
        unsigned long journal_devnum = 0;
@@ -1565,6 +1565,16 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
                goto failed_mount;
        }
 
+       if (le32_to_cpu(es->s_blocks_count) >
+                   (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {
+               printk(KERN_ERR "EXT3-fs: filesystem on %s:"
+                       " too large to mount safely\n", sb->s_id);
+               if (sizeof(sector_t) < 8)
+                       printk(KERN_WARNING "EXT3-fs: CONFIG_LBD not "
+                                       "enabled\n");
+               goto failed_mount;
+       }
+
        if (EXT3_BLOCKS_PER_GROUP(sb) == 0)
                goto cantfind_ext3;
        sbi->s_groups_count = (le32_to_cpu(es->s_blocks_count) -
@@ -1593,7 +1603,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
                }
        }
        if (!ext3_check_descriptors (sb)) {
-               printk (KERN_ERR "EXT3-fs: group descriptors corrupted !\n");
+               printk(KERN_ERR "EXT3-fs: group descriptors corrupted!\n");
                goto failed_mount2;
        }
        sbi->s_gdb_count = db_count;
@@ -1830,10 +1840,10 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb,
 {
        struct buffer_head * bh;
        journal_t *journal;
-       int start;
-       int len;
+       ext3_fsblk_t start;
+       ext3_fsblk_t len;
        int hblock, blocksize;
-       unsigned long sb_block;
+       ext3_fsblk_t sb_block;
        unsigned long offset;
        struct ext3_super_block * es;
        struct block_device *bdev;
@@ -2206,7 +2216,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
 {
        struct ext3_super_block * es;
        struct ext3_sb_info *sbi = EXT3_SB(sb);
-       unsigned long n_blocks_count = 0;
+       ext3_fsblk_t n_blocks_count = 0;
        unsigned long old_sb_flags;
        struct ext3_mount_options old_opts;
        int err;
@@ -2326,7 +2336,7 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)
        struct super_block *sb = dentry->d_sb;
        struct ext3_sb_info *sbi = EXT3_SB(sb);
        struct ext3_super_block *es = sbi->s_es;
-       unsigned long overhead;
+       ext3_fsblk_t overhead;
        int i;
 
        if (test_opt (sb, MINIX_DF))
index e8d60bf6b7df7b6bc964eccc2046d72dd5c0064e..a44a0562203a3794ac5e82389eb91708e01d036d 100644 (file)
@@ -225,7 +225,7 @@ ext3_xattr_block_get(struct inode *inode, int name_index, const char *name,
        error = -ENODATA;
        if (!EXT3_I(inode)->i_file_acl)
                goto cleanup;
-       ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl);
+       ea_idebug(inode, "reading block %u", EXT3_I(inode)->i_file_acl);
        bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
        if (!bh)
                goto cleanup;
@@ -233,7 +233,7 @@ ext3_xattr_block_get(struct inode *inode, int name_index, const char *name,
                atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
        if (ext3_xattr_check_block(bh)) {
 bad_block:     ext3_error(inode->i_sb, __FUNCTION__,
-                          "inode %ld: bad block %d", inode->i_ino,
+                          "inode %ld: bad block "E3FSBLK, inode->i_ino,
                           EXT3_I(inode)->i_file_acl);
                error = -EIO;
                goto cleanup;
@@ -366,7 +366,7 @@ ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
        error = 0;
        if (!EXT3_I(inode)->i_file_acl)
                goto cleanup;
-       ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl);
+       ea_idebug(inode, "reading block %u", EXT3_I(inode)->i_file_acl);
        bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
        error = -EIO;
        if (!bh)
@@ -375,7 +375,7 @@ ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
                atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
        if (ext3_xattr_check_block(bh)) {
                ext3_error(inode->i_sb, __FUNCTION__,
-                          "inode %ld: bad block %d", inode->i_ino,
+                          "inode %ld: bad block "E3FSBLK, inode->i_ino,
                           EXT3_I(inode)->i_file_acl);
                error = -EIO;
                goto cleanup;
@@ -647,7 +647,7 @@ ext3_xattr_block_find(struct inode *inode, struct ext3_xattr_info *i,
                        le32_to_cpu(BHDR(bs->bh)->h_refcount));
                if (ext3_xattr_check_block(bs->bh)) {
                        ext3_error(sb, __FUNCTION__,
-                               "inode %ld: bad block %d", inode->i_ino,
+                               "inode %ld: bad block "E3FSBLK, inode->i_ino,
                                EXT3_I(inode)->i_file_acl);
                        error = -EIO;
                        goto cleanup;
@@ -792,11 +792,12 @@ inserted:
                        get_bh(new_bh);
                } else {
                        /* We need to allocate a new block */
-                       int goal = le32_to_cpu(
+                       ext3_fsblk_t goal = le32_to_cpu(
                                        EXT3_SB(sb)->s_es->s_first_data_block) +
-                               EXT3_I(inode)->i_block_group *
+                               (ext3_fsblk_t)EXT3_I(inode)->i_block_group *
                                EXT3_BLOCKS_PER_GROUP(sb);
-                       int block = ext3_new_block(handle, inode, goal, &error);
+                       ext3_fsblk_t block = ext3_new_block(handle, inode,
+                                                       goal, &error);
                        if (error)
                                goto cleanup;
                        ea_idebug(inode, "creating block %d", block);
@@ -847,7 +848,7 @@ cleanup_dquot:
 
 bad_block:
        ext3_error(inode->i_sb, __FUNCTION__,
-                  "inode %ld: bad block %d", inode->i_ino,
+                  "inode %ld: bad block "E3FSBLK, inode->i_ino,
                   EXT3_I(inode)->i_file_acl);
        goto cleanup;
 
@@ -1076,14 +1077,14 @@ ext3_xattr_delete_inode(handle_t *handle, struct inode *inode)
        bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
        if (!bh) {
                ext3_error(inode->i_sb, __FUNCTION__,
-                       "inode %ld: block %d read error", inode->i_ino,
+                       "inode %ld: block "E3FSBLK" read error", inode->i_ino,
                        EXT3_I(inode)->i_file_acl);
                goto cleanup;
        }
        if (BHDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
            BHDR(bh)->h_blocks != cpu_to_le32(1)) {
                ext3_error(inode->i_sb, __FUNCTION__,
-                       "inode %ld: bad block %d", inode->i_ino,
+                       "inode %ld: bad block "E3FSBLK, inode->i_ino,
                        EXT3_I(inode)->i_file_acl);
                goto cleanup;
        }
@@ -1210,11 +1211,11 @@ again:
                bh = sb_bread(inode->i_sb, ce->e_block);
                if (!bh) {
                        ext3_error(inode->i_sb, __FUNCTION__,
-                               "inode %ld: block %ld read error",
+                               "inode %ld: block %lu read error",
                                inode->i_ino, (unsigned long) ce->e_block);
                } else if (le32_to_cpu(BHDR(bh)->h_refcount) >=
                                EXT3_XATTR_REFCOUNT_MAX) {
-                       ea_idebug(inode, "block %ld refcount %d>=%d",
+                       ea_idebug(inode, "block %lu refcount %d>=%d",
                                  (unsigned long) ce->e_block,
                                  le32_to_cpu(BHDR(bh)->h_refcount),
                                          EXT3_XATTR_REFCOUNT_MAX);
index 583bd78086d8a83e97dc821584409ccdeb20a20a..d35979a58743599adbd82e61dc83f41bc5658efd 100644 (file)
@@ -159,11 +159,11 @@ struct vxfs_sb {
  * In core superblock filesystem private data for VxFS.
  */
 struct vxfs_sb_info {
-       struct vxfs_sb          *vsi_raw;       /* raw (on disk) supeblock */
+       struct vxfs_sb          *vsi_raw;       /* raw (on disk) superblock */
        struct buffer_head      *vsi_bp;        /* buffer for raw superblock*/
        struct inode            *vsi_fship;     /* fileset header inode */
        struct inode            *vsi_ilist;     /* inode list inode */
-       struct inode            *vsi_stilist;   /* structual inode list inode */
+       struct inode            *vsi_stilist;   /* structural inode list inode */
        u_long                  vsi_iext;       /* initial inode list */
        ino_t                   vsi_fshino;     /* fileset header inode */
        daddr_t                 vsi_oltext;     /* OLT extent */
index 6dee109aeea406d853ea7d3dfc4eea41294d98d2..78948b4b189471df13f6fce9501f3bf352fd532c 100644 (file)
@@ -112,7 +112,7 @@ vxfs_read_fshead(struct super_block *sbp)
 
        vip = vxfs_blkiget(sbp, infp->vsi_iext, infp->vsi_fshino);
        if (!vip) {
-               printk(KERN_ERR "vxfs: unabled to read fsh inode\n");
+               printk(KERN_ERR "vxfs: unable to read fsh inode\n");
                return -EINVAL;
        }
        if (!VXFS_ISFSH(vip)) {
@@ -129,13 +129,13 @@ vxfs_read_fshead(struct super_block *sbp)
 
        infp->vsi_fship = vxfs_get_fake_inode(sbp, vip);
        if (!infp->vsi_fship) {
-               printk(KERN_ERR "vxfs: unabled to get fsh inode\n");
+               printk(KERN_ERR "vxfs: unable to get fsh inode\n");
                goto out_free_fship;
        }
 
        sfp = vxfs_getfsh(infp->vsi_fship, 0);
        if (!sfp) {
-               printk(KERN_ERR "vxfs: unabled to get structural fsh\n");
+               printk(KERN_ERR "vxfs: unable to get structural fsh\n");
                goto out_iput_fship;
        } 
 
@@ -145,7 +145,7 @@ vxfs_read_fshead(struct super_block *sbp)
 
        pfp = vxfs_getfsh(infp->vsi_fship, 1);
        if (!pfp) {
-               printk(KERN_ERR "vxfs: unabled to get primary fsh\n");
+               printk(KERN_ERR "vxfs: unable to get primary fsh\n");
                goto out_free_sfp;
        }
 
@@ -159,7 +159,7 @@ vxfs_read_fshead(struct super_block *sbp)
 
        infp->vsi_stilist = vxfs_get_fake_inode(sbp, tip);
        if (!infp->vsi_stilist) {
-               printk(KERN_ERR "vxfs: unabled to get structual list inode\n");
+               printk(KERN_ERR "vxfs: unable to get structural list inode\n");
                kfree(tip);
                goto out_free_pfp;
        }
@@ -174,7 +174,7 @@ vxfs_read_fshead(struct super_block *sbp)
                goto out_iput_stilist;
        infp->vsi_ilist = vxfs_get_fake_inode(sbp, tip);
        if (!infp->vsi_ilist) {
-               printk(KERN_ERR "vxfs: unabled to get inode list inode\n");
+               printk(KERN_ERR "vxfs: unable to get inode list inode\n");
                kfree(tip);
                goto out_iput_stilist;
        }
index c3e1f760cac9b4d456269dedb934adbc56036e46..72437065f6adee64994145be01efd281c482596a 100644 (file)
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_FUSE_FS) += fuse.o
 
-fuse-objs := dev.o dir.o file.o inode.o
+fuse-objs := dev.o dir.o file.o inode.o control.o
diff --git a/fs/fuse/control.c b/fs/fuse/control.c
new file mode 100644 (file)
index 0000000..a3bce3a
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2006  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU GPL.
+  See the file COPYING.
+*/
+
+#include "fuse_i.h"
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+#define FUSE_CTL_SUPER_MAGIC 0x65735543
+
+/*
+ * This is non-NULL when the single instance of the control filesystem
+ * exists.  Protected by fuse_mutex
+ */
+static struct super_block *fuse_control_sb;
+
+static struct fuse_conn *fuse_ctl_file_conn_get(struct file *file)
+{
+       struct fuse_conn *fc;
+       mutex_lock(&fuse_mutex);
+       fc = file->f_dentry->d_inode->u.generic_ip;
+       if (fc)
+               fc = fuse_conn_get(fc);
+       mutex_unlock(&fuse_mutex);
+       return fc;
+}
+
+static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf,
+                                    size_t count, loff_t *ppos)
+{
+       struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
+       if (fc) {
+               fuse_abort_conn(fc);
+               fuse_conn_put(fc);
+       }
+       return count;
+}
+
+static ssize_t fuse_conn_waiting_read(struct file *file, char __user *buf,
+                                     size_t len, loff_t *ppos)
+{
+       char tmp[32];
+       size_t size;
+
+       if (!*ppos) {
+               struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
+               if (!fc)
+                       return 0;
+
+               file->private_data=(void *)(long)atomic_read(&fc->num_waiting);
+               fuse_conn_put(fc);
+       }
+       size = sprintf(tmp, "%ld\n", (long)file->private_data);
+       return simple_read_from_buffer(buf, len, ppos, tmp, size);
+}
+
+static const struct file_operations fuse_ctl_abort_ops = {
+       .open = nonseekable_open,
+       .write = fuse_conn_abort_write,
+};
+
+static const struct file_operations fuse_ctl_waiting_ops = {
+       .open = nonseekable_open,
+       .read = fuse_conn_waiting_read,
+};
+
+static struct dentry *fuse_ctl_add_dentry(struct dentry *parent,
+                                         struct fuse_conn *fc,
+                                         const char *name,
+                                         int mode, int nlink,
+                                         struct inode_operations *iop,
+                                         const struct file_operations *fop)
+{
+       struct dentry *dentry;
+       struct inode *inode;
+
+       BUG_ON(fc->ctl_ndents >= FUSE_CTL_NUM_DENTRIES);
+       dentry = d_alloc_name(parent, name);
+       if (!dentry)
+               return NULL;
+
+       fc->ctl_dentry[fc->ctl_ndents++] = dentry;
+       inode = new_inode(fuse_control_sb);
+       if (!inode)
+               return NULL;
+
+       inode->i_mode = mode;
+       inode->i_uid = fc->user_id;
+       inode->i_gid = fc->group_id;
+       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       /* setting ->i_op to NULL is not allowed */
+       if (iop)
+               inode->i_op = iop;
+       inode->i_fop = fop;
+       inode->i_nlink = nlink;
+       inode->u.generic_ip = fc;
+       d_add(dentry, inode);
+       return dentry;
+}
+
+/*
+ * Add a connection to the control filesystem (if it exists).  Caller
+ * must host fuse_mutex
+ */
+int fuse_ctl_add_conn(struct fuse_conn *fc)
+{
+       struct dentry *parent;
+       char name[32];
+
+       if (!fuse_control_sb)
+               return 0;
+
+       parent = fuse_control_sb->s_root;
+       parent->d_inode->i_nlink++;
+       sprintf(name, "%llu", (unsigned long long) fc->id);
+       parent = fuse_ctl_add_dentry(parent, fc, name, S_IFDIR | 0500, 2,
+                                    &simple_dir_inode_operations,
+                                    &simple_dir_operations);
+       if (!parent)
+               goto err;
+
+       if (!fuse_ctl_add_dentry(parent, fc, "waiting", S_IFREG | 0400, 1,
+                               NULL, &fuse_ctl_waiting_ops) ||
+           !fuse_ctl_add_dentry(parent, fc, "abort", S_IFREG | 0200, 1,
+                                NULL, &fuse_ctl_abort_ops))
+               goto err;
+
+       return 0;
+
+ err:
+       fuse_ctl_remove_conn(fc);
+       return -ENOMEM;
+}
+
+/*
+ * Remove a connection from the control filesystem (if it exists).
+ * Caller must host fuse_mutex
+ */
+void fuse_ctl_remove_conn(struct fuse_conn *fc)
+{
+       int i;
+
+       if (!fuse_control_sb)
+               return;
+
+       for (i = fc->ctl_ndents - 1; i >= 0; i--) {
+               struct dentry *dentry = fc->ctl_dentry[i];
+               dentry->d_inode->u.generic_ip = NULL;
+               d_drop(dentry);
+               dput(dentry);
+       }
+       fuse_control_sb->s_root->d_inode->i_nlink--;
+}
+
+static int fuse_ctl_fill_super(struct super_block *sb, void *data, int silent)
+{
+       struct tree_descr empty_descr = {""};
+       struct fuse_conn *fc;
+       int err;
+
+       err = simple_fill_super(sb, FUSE_CTL_SUPER_MAGIC, &empty_descr);
+       if (err)
+               return err;
+
+       mutex_lock(&fuse_mutex);
+       BUG_ON(fuse_control_sb);
+       fuse_control_sb = sb;
+       list_for_each_entry(fc, &fuse_conn_list, entry) {
+               err = fuse_ctl_add_conn(fc);
+               if (err) {
+                       fuse_control_sb = NULL;
+                       mutex_unlock(&fuse_mutex);
+                       return err;
+               }
+       }
+       mutex_unlock(&fuse_mutex);
+
+       return 0;
+}
+
+static int fuse_ctl_get_sb(struct file_system_type *fs_type, int flags,
+                       const char *dev_name, void *raw_data,
+                       struct vfsmount *mnt)
+{
+       return get_sb_single(fs_type, flags, raw_data,
+                               fuse_ctl_fill_super, mnt);
+}
+
+static void fuse_ctl_kill_sb(struct super_block *sb)
+{
+       mutex_lock(&fuse_mutex);
+       fuse_control_sb = NULL;
+       mutex_unlock(&fuse_mutex);
+
+       kill_litter_super(sb);
+}
+
+static struct file_system_type fuse_ctl_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "fusectl",
+       .get_sb         = fuse_ctl_get_sb,
+       .kill_sb        = fuse_ctl_kill_sb,
+};
+
+int __init fuse_ctl_init(void)
+{
+       return register_filesystem(&fuse_ctl_fs_type);
+}
+
+void fuse_ctl_cleanup(void)
+{
+       unregister_filesystem(&fuse_ctl_fs_type);
+}
index 104a62dadb94c9b8fa489963b51a97bc69b3dba2..1e2006caf15842b2c2beffe11968f3cc6311f16f 100644 (file)
@@ -34,6 +34,7 @@ static void fuse_request_init(struct fuse_req *req)
 {
        memset(req, 0, sizeof(*req));
        INIT_LIST_HEAD(&req->list);
+       INIT_LIST_HEAD(&req->intr_entry);
        init_waitqueue_head(&req->waitq);
        atomic_set(&req->count, 1);
 }
@@ -64,18 +65,6 @@ static void restore_sigs(sigset_t *oldset)
        sigprocmask(SIG_SETMASK, oldset, NULL);
 }
 
-/*
- * Reset request, so that it can be reused
- *
- * The caller must be _very_ careful to make sure, that it is holding
- * the only reference to req
- */
-void fuse_reset_request(struct fuse_req *req)
-{
-       BUG_ON(atomic_read(&req->count) != 1);
-       fuse_request_init(req);
-}
-
 static void __fuse_get_request(struct fuse_req *req)
 {
        atomic_inc(&req->count);
@@ -88,6 +77,13 @@ static void __fuse_put_request(struct fuse_req *req)
        atomic_dec(&req->count);
 }
 
+static void fuse_req_init_context(struct fuse_req *req)
+{
+       req->in.h.uid = current->fsuid;
+       req->in.h.gid = current->fsgid;
+       req->in.h.pid = current->pid;
+}
+
 struct fuse_req *fuse_get_req(struct fuse_conn *fc)
 {
        struct fuse_req *req;
@@ -103,14 +99,16 @@ struct fuse_req *fuse_get_req(struct fuse_conn *fc)
        if (intr)
                goto out;
 
+       err = -ENOTCONN;
+       if (!fc->connected)
+               goto out;
+
        req = fuse_request_alloc();
        err = -ENOMEM;
        if (!req)
                goto out;
 
-       req->in.h.uid = current->fsuid;
-       req->in.h.gid = current->fsgid;
-       req->in.h.pid = current->pid;
+       fuse_req_init_context(req);
        req->waiting = 1;
        return req;
 
@@ -119,142 +117,183 @@ struct fuse_req *fuse_get_req(struct fuse_conn *fc)
        return ERR_PTR(err);
 }
 
-void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
+/*
+ * Return request in fuse_file->reserved_req.  However that may
+ * currently be in use.  If that is the case, wait for it to become
+ * available.
+ */
+static struct fuse_req *get_reserved_req(struct fuse_conn *fc,
+                                        struct file *file)
 {
-       if (atomic_dec_and_test(&req->count)) {
-               if (req->waiting)
-                       atomic_dec(&fc->num_waiting);
-               fuse_request_free(req);
-       }
+       struct fuse_req *req = NULL;
+       struct fuse_file *ff = file->private_data;
+
+       do {
+               wait_event(fc->blocked_waitq, ff->reserved_req);
+               spin_lock(&fc->lock);
+               if (ff->reserved_req) {
+                       req = ff->reserved_req;
+                       ff->reserved_req = NULL;
+                       get_file(file);
+                       req->stolen_file = file;
+               }
+               spin_unlock(&fc->lock);
+       } while (!req);
+
+       return req;
 }
 
 /*
- * Called with sbput_sem held for read (request_end) or write
- * (fuse_put_super).  By the time fuse_put_super() is finished, all
- * inodes belonging to background requests must be released, so the
- * iputs have to be done within the locked region.
+ * Put stolen request back into fuse_file->reserved_req
  */
-void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req)
+static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req)
 {
-       iput(req->inode);
-       iput(req->inode2);
+       struct file *file = req->stolen_file;
+       struct fuse_file *ff = file->private_data;
+
        spin_lock(&fc->lock);
-       list_del(&req->bg_entry);
-       if (fc->num_background == FUSE_MAX_BACKGROUND) {
-               fc->blocked = 0;
-               wake_up_all(&fc->blocked_waitq);
-       }
-       fc->num_background--;
+       fuse_request_init(req);
+       BUG_ON(ff->reserved_req);
+       ff->reserved_req = req;
+       wake_up(&fc->blocked_waitq);
        spin_unlock(&fc->lock);
+       fput(file);
 }
 
 /*
- * This function is called when a request is finished.  Either a reply
- * has arrived or it was interrupted (and not yet sent) or some error
- * occurred during communication with userspace, or the device file
- * was closed.  In case of a background request the reference to the
- * stored objects are released.  The requester thread is woken up (if
- * still waiting), the 'end' callback is called if given, else the
- * reference to the request is released
+ * Gets a requests for a file operation, always succeeds
  *
- * Releasing extra reference for foreground requests must be done
- * within the same locked region as setting state to finished.  This
- * is because fuse_reset_request() may be called after request is
- * finished and it must be the sole possessor.  If request is
- * interrupted and put in the background, it will return with an error
- * and hence never be reset and reused.
+ * This is used for sending the FLUSH request, which must get to
+ * userspace, due to POSIX locks which may need to be unlocked.
  *
- * Called with fc->lock, unlocks it
+ * If allocation fails due to OOM, use the reserved request in
+ * fuse_file.
+ *
+ * This is very unlikely to deadlock accidentally, since the
+ * filesystem should not have it's own file open.  If deadlock is
+ * intentional, it can still be broken by "aborting" the filesystem.
  */
-static void request_end(struct fuse_conn *fc, struct fuse_req *req)
+struct fuse_req *fuse_get_req_nofail(struct fuse_conn *fc, struct file *file)
 {
-       list_del(&req->list);
-       req->state = FUSE_REQ_FINISHED;
-       if (!req->background) {
-               spin_unlock(&fc->lock);
-               wake_up(&req->waitq);
-               fuse_put_request(fc, req);
-       } else {
-               void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
-               req->end = NULL;
-               spin_unlock(&fc->lock);
-               down_read(&fc->sbput_sem);
-               if (fc->mounted)
-                       fuse_release_background(fc, req);
-               up_read(&fc->sbput_sem);
+       struct fuse_req *req;
 
-               /* fput must go outside sbput_sem, otherwise it can deadlock */
-               if (req->file)
-                       fput(req->file);
+       atomic_inc(&fc->num_waiting);
+       wait_event(fc->blocked_waitq, !fc->blocked);
+       req = fuse_request_alloc();
+       if (!req)
+               req = get_reserved_req(fc, file);
 
-               if (end)
-                       end(fc, req);
+       fuse_req_init_context(req);
+       req->waiting = 1;
+       return req;
+}
+
+void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
+{
+       if (atomic_dec_and_test(&req->count)) {
+               if (req->waiting)
+                       atomic_dec(&fc->num_waiting);
+
+               if (req->stolen_file)
+                       put_reserved_req(fc, req);
                else
-                       fuse_put_request(fc, req);
+                       fuse_request_free(req);
        }
 }
 
 /*
- * Unfortunately request interruption not just solves the deadlock
- * problem, it causes problems too.  These stem from the fact, that an
- * interrupted request is continued to be processed in userspace,
- * while all the locks and object references (inode and file) held
- * during the operation are released.
- *
- * To release the locks is exactly why there's a need to interrupt the
- * request, so there's not a lot that can be done about this, except
- * introduce additional locking in userspace.
- *
- * More important is to keep inode and file references until userspace
- * has replied, otherwise FORGET and RELEASE could be sent while the
- * inode/file is still used by the filesystem.
- *
- * For this reason the concept of "background" request is introduced.
- * An interrupted request is backgrounded if it has been already sent
- * to userspace.  Backgrounding involves getting an extra reference to
- * inode(s) or file used in the request, and adding the request to
- * fc->background list.  When a reply is received for a background
- * request, the object references are released, and the request is
- * removed from the list.  If the filesystem is unmounted while there
- * are still background requests, the list is walked and references
- * are released as if a reply was received.
+ * This function is called when a request is finished.  Either a reply
+ * has arrived or it was aborted (and not yet sent) or some error
+ * occurred during communication with userspace, or the device file
+ * was closed.  The requester thread is woken up (if still waiting),
+ * the 'end' callback is called if given, else the reference to the
+ * request is released
  *
- * There's one more use for a background request.  The RELEASE message is
- * always sent as background, since it doesn't return an error or
- * data.
+ * Called with fc->lock, unlocks it
  */
-static void background_request(struct fuse_conn *fc, struct fuse_req *req)
-{
-       req->background = 1;
-       list_add(&req->bg_entry, &fc->background);
-       fc->num_background++;
-       if (fc->num_background == FUSE_MAX_BACKGROUND)
-               fc->blocked = 1;
-       if (req->inode)
-               req->inode = igrab(req->inode);
-       if (req->inode2)
-               req->inode2 = igrab(req->inode2);
+static void request_end(struct fuse_conn *fc, struct fuse_req *req)
+{
+       void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
+       req->end = NULL;
+       list_del(&req->list);
+       list_del(&req->intr_entry);
+       req->state = FUSE_REQ_FINISHED;
+       if (req->background) {
+               if (fc->num_background == FUSE_MAX_BACKGROUND) {
+                       fc->blocked = 0;
+                       wake_up_all(&fc->blocked_waitq);
+               }
+               fc->num_background--;
+       }
+       spin_unlock(&fc->lock);
+       dput(req->dentry);
+       mntput(req->vfsmount);
        if (req->file)
-               get_file(req->file);
+               fput(req->file);
+       wake_up(&req->waitq);
+       if (end)
+               end(fc, req);
+       else
+               fuse_put_request(fc, req);
 }
 
-/* Called with fc->lock held.  Releases, and then reacquires it. */
-static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
+static void wait_answer_interruptible(struct fuse_conn *fc,
+                                     struct fuse_req *req)
 {
-       sigset_t oldset;
+       if (signal_pending(current))
+               return;
 
        spin_unlock(&fc->lock);
-       block_sigs(&oldset);
        wait_event_interruptible(req->waitq, req->state == FUSE_REQ_FINISHED);
-       restore_sigs(&oldset);
        spin_lock(&fc->lock);
-       if (req->state == FUSE_REQ_FINISHED && !req->interrupted)
-               return;
+}
+
+static void queue_interrupt(struct fuse_conn *fc, struct fuse_req *req)
+{
+       list_add_tail(&req->intr_entry, &fc->interrupts);
+       wake_up(&fc->waitq);
+       kill_fasync(&fc->fasync, SIGIO, POLL_IN);
+}
+
+/* Called with fc->lock held.  Releases, and then reacquires it. */
+static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
+{
+       if (!fc->no_interrupt) {
+               /* Any signal may interrupt this */
+               wait_answer_interruptible(fc, req);
+
+               if (req->aborted)
+                       goto aborted;
+               if (req->state == FUSE_REQ_FINISHED)
+                       return;
 
-       if (!req->interrupted) {
-               req->out.h.error = -EINTR;
                req->interrupted = 1;
+               if (req->state == FUSE_REQ_SENT)
+                       queue_interrupt(fc, req);
+       }
+
+       if (req->force) {
+               spin_unlock(&fc->lock);
+               wait_event(req->waitq, req->state == FUSE_REQ_FINISHED);
+               spin_lock(&fc->lock);
+       } else {
+               sigset_t oldset;
+
+               /* Only fatal signals may interrupt this */
+               block_sigs(&oldset);
+               wait_answer_interruptible(fc, req);
+               restore_sigs(&oldset);
        }
+
+       if (req->aborted)
+               goto aborted;
+       if (req->state == FUSE_REQ_FINISHED)
+               return;
+
+       req->out.h.error = -EINTR;
+       req->aborted = 1;
+
+ aborted:
        if (req->locked) {
                /* This is uninterruptible sleep, because data is
                   being copied to/from the buffers of req.  During
@@ -268,8 +307,11 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
        if (req->state == FUSE_REQ_PENDING) {
                list_del(&req->list);
                __fuse_put_request(req);
-       } else if (req->state == FUSE_REQ_SENT)
-               background_request(fc, req);
+       } else if (req->state == FUSE_REQ_SENT) {
+               spin_unlock(&fc->lock);
+               wait_event(req->waitq, req->state == FUSE_REQ_FINISHED);
+               spin_lock(&fc->lock);
+       }
 }
 
 static unsigned len_args(unsigned numargs, struct fuse_arg *args)
@@ -283,13 +325,19 @@ static unsigned len_args(unsigned numargs, struct fuse_arg *args)
        return nbytes;
 }
 
+static u64 fuse_get_unique(struct fuse_conn *fc)
+ {
+       fc->reqctr++;
+       /* zero is special */
+       if (fc->reqctr == 0)
+               fc->reqctr = 1;
+
+       return fc->reqctr;
+}
+
 static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
 {
-       fc->reqctr++;
-       /* zero is special */
-       if (fc->reqctr == 0)
-               fc->reqctr = 1;
-       req->in.h.unique = fc->reqctr;
+       req->in.h.unique = fuse_get_unique(fc);
        req->in.h.len = sizeof(struct fuse_in_header) +
                len_args(req->in.numargs, (struct fuse_arg *) req->in.args);
        list_add_tail(&req->list, &fc->pending);
@@ -302,9 +350,6 @@ static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
        kill_fasync(&fc->fasync, SIGIO, POLL_IN);
 }
 
-/*
- * This can only be interrupted by a SIGKILL
- */
 void request_send(struct fuse_conn *fc, struct fuse_req *req)
 {
        req->isreply = 1;
@@ -327,8 +372,12 @@ void request_send(struct fuse_conn *fc, struct fuse_req *req)
 static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
 {
        spin_lock(&fc->lock);
-       background_request(fc, req);
        if (fc->connected) {
+               req->background = 1;
+               fc->num_background++;
+               if (fc->num_background == FUSE_MAX_BACKGROUND)
+                       fc->blocked = 1;
+
                queue_request(fc, req);
                spin_unlock(&fc->lock);
        } else {
@@ -352,14 +401,14 @@ void request_send_background(struct fuse_conn *fc, struct fuse_req *req)
 /*
  * Lock the request.  Up to the next unlock_request() there mustn't be
  * anything that could cause a page-fault.  If the request was already
- * interrupted bail out.
+ * aborted bail out.
  */
 static int lock_request(struct fuse_conn *fc, struct fuse_req *req)
 {
        int err = 0;
        if (req) {
                spin_lock(&fc->lock);
-               if (req->interrupted)
+               if (req->aborted)
                        err = -ENOENT;
                else
                        req->locked = 1;
@@ -369,7 +418,7 @@ static int lock_request(struct fuse_conn *fc, struct fuse_req *req)
 }
 
 /*
- * Unlock request.  If it was interrupted during being locked, the
+ * Unlock request.  If it was aborted during being locked, the
  * requester thread is currently waiting for it to be unlocked, so
  * wake it up.
  */
@@ -378,7 +427,7 @@ static void unlock_request(struct fuse_conn *fc, struct fuse_req *req)
        if (req) {
                spin_lock(&fc->lock);
                req->locked = 0;
-               if (req->interrupted)
+               if (req->aborted)
                        wake_up(&req->waitq);
                spin_unlock(&fc->lock);
        }
@@ -557,13 +606,18 @@ static int fuse_copy_args(struct fuse_copy_state *cs, unsigned numargs,
        return err;
 }
 
+static int request_pending(struct fuse_conn *fc)
+{
+       return !list_empty(&fc->pending) || !list_empty(&fc->interrupts);
+}
+
 /* Wait until a request is available on the pending list */
 static void request_wait(struct fuse_conn *fc)
 {
        DECLARE_WAITQUEUE(wait, current);
 
        add_wait_queue_exclusive(&fc->waitq, &wait);
-       while (fc->connected && list_empty(&fc->pending)) {
+       while (fc->connected && !request_pending(fc)) {
                set_current_state(TASK_INTERRUPTIBLE);
                if (signal_pending(current))
                        break;
@@ -576,12 +630,51 @@ static void request_wait(struct fuse_conn *fc)
        remove_wait_queue(&fc->waitq, &wait);
 }
 
+/*
+ * Transfer an interrupt request to userspace
+ *
+ * Unlike other requests this is assembled on demand, without a need
+ * to allocate a separate fuse_req structure.
+ *
+ * Called with fc->lock held, releases it
+ */
+static int fuse_read_interrupt(struct fuse_conn *fc, struct fuse_req *req,
+                              const struct iovec *iov, unsigned long nr_segs)
+{
+       struct fuse_copy_state cs;
+       struct fuse_in_header ih;
+       struct fuse_interrupt_in arg;
+       unsigned reqsize = sizeof(ih) + sizeof(arg);
+       int err;
+
+       list_del_init(&req->intr_entry);
+       req->intr_unique = fuse_get_unique(fc);
+       memset(&ih, 0, sizeof(ih));
+       memset(&arg, 0, sizeof(arg));
+       ih.len = reqsize;
+       ih.opcode = FUSE_INTERRUPT;
+       ih.unique = req->intr_unique;
+       arg.unique = req->in.h.unique;
+
+       spin_unlock(&fc->lock);
+       if (iov_length(iov, nr_segs) < reqsize)
+               return -EINVAL;
+
+       fuse_copy_init(&cs, fc, 1, NULL, iov, nr_segs);
+       err = fuse_copy_one(&cs, &ih, sizeof(ih));
+       if (!err)
+               err = fuse_copy_one(&cs, &arg, sizeof(arg));
+       fuse_copy_finish(&cs);
+
+       return err ? err : reqsize;
+}
+
 /*
  * Read a single request into the userspace filesystem's buffer.  This
  * function waits until a request is available, then removes it from
  * the pending list and copies request data to userspace buffer.  If
- * no reply is needed (FORGET) or request has been interrupted or
- * there was an error during the copying then it's finished by calling
+ * no reply is needed (FORGET) or request has been aborted or there
+ * was an error during the copying then it's finished by calling
  * request_end().  Otherwise add it to the processing list, and set
  * the 'sent' flag.
  */
@@ -601,7 +694,7 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
        spin_lock(&fc->lock);
        err = -EAGAIN;
        if ((file->f_flags & O_NONBLOCK) && fc->connected &&
-           list_empty(&fc->pending))
+           !request_pending(fc))
                goto err_unlock;
 
        request_wait(fc);
@@ -609,9 +702,15 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
        if (!fc->connected)
                goto err_unlock;
        err = -ERESTARTSYS;
-       if (list_empty(&fc->pending))
+       if (!request_pending(fc))
                goto err_unlock;
 
+       if (!list_empty(&fc->interrupts)) {
+               req = list_entry(fc->interrupts.next, struct fuse_req,
+                                intr_entry);
+               return fuse_read_interrupt(fc, req, iov, nr_segs);
+       }
+
        req = list_entry(fc->pending.next, struct fuse_req, list);
        req->state = FUSE_REQ_READING;
        list_move(&req->list, &fc->io);
@@ -636,10 +735,10 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
        fuse_copy_finish(&cs);
        spin_lock(&fc->lock);
        req->locked = 0;
-       if (!err && req->interrupted)
+       if (!err && req->aborted)
                err = -ENOENT;
        if (err) {
-               if (!req->interrupted)
+               if (!req->aborted)
                        req->out.h.error = -EIO;
                request_end(fc, req);
                return err;
@@ -649,6 +748,8 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
        else {
                req->state = FUSE_REQ_SENT;
                list_move_tail(&req->list, &fc->processing);
+               if (req->interrupted)
+                       queue_interrupt(fc, req);
                spin_unlock(&fc->lock);
        }
        return reqsize;
@@ -675,7 +776,7 @@ static struct fuse_req *request_find(struct fuse_conn *fc, u64 unique)
        list_for_each(entry, &fc->processing) {
                struct fuse_req *req;
                req = list_entry(entry, struct fuse_req, list);
-               if (req->in.h.unique == unique)
+               if (req->in.h.unique == unique || req->intr_unique == unique)
                        return req;
        }
        return NULL;
@@ -741,17 +842,33 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,
                goto err_unlock;
 
        req = request_find(fc, oh.unique);
-       err = -EINVAL;
        if (!req)
                goto err_unlock;
 
-       if (req->interrupted) {
+       if (req->aborted) {
                spin_unlock(&fc->lock);
                fuse_copy_finish(&cs);
                spin_lock(&fc->lock);
                request_end(fc, req);
                return -ENOENT;
        }
+       /* Is it an interrupt reply? */
+       if (req->intr_unique == oh.unique) {
+               err = -EINVAL;
+               if (nbytes != sizeof(struct fuse_out_header))
+                       goto err_unlock;
+
+               if (oh.error == -ENOSYS)
+                       fc->no_interrupt = 1;
+               else if (oh.error == -EAGAIN)
+                       queue_interrupt(fc, req);
+
+               spin_unlock(&fc->lock);
+               fuse_copy_finish(&cs);
+               return nbytes;
+       }
+
+       req->state = FUSE_REQ_WRITING;
        list_move(&req->list, &fc->io);
        req->out.h = oh;
        req->locked = 1;
@@ -764,9 +881,9 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,
        spin_lock(&fc->lock);
        req->locked = 0;
        if (!err) {
-               if (req->interrupted)
+               if (req->aborted)
                        err = -ENOENT;
-       } else if (!req->interrupted)
+       } else if (!req->aborted)
                req->out.h.error = -EIO;
        request_end(fc, req);
 
@@ -800,7 +917,7 @@ static unsigned fuse_dev_poll(struct file *file, poll_table *wait)
        spin_lock(&fc->lock);
        if (!fc->connected)
                mask = POLLERR;
-       else if (!list_empty(&fc->pending))
+       else if (request_pending(fc))
                mask |= POLLIN | POLLRDNORM;
        spin_unlock(&fc->lock);
 
@@ -826,7 +943,7 @@ static void end_requests(struct fuse_conn *fc, struct list_head *head)
 /*
  * Abort requests under I/O
  *
- * The requests are set to interrupted and finished, and the request
+ * The requests are set to aborted and finished, and the request
  * waiter is woken up.  This will make request_wait_answer() wait
  * until the request is unlocked and then return.
  *
@@ -841,7 +958,7 @@ static void end_io_requests(struct fuse_conn *fc)
                        list_entry(fc->io.next, struct fuse_req, list);
                void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
 
-               req->interrupted = 1;
+               req->aborted = 1;
                req->out.h.error = -ECONNABORTED;
                req->state = FUSE_REQ_FINISHED;
                list_del_init(&req->list);
@@ -874,19 +991,20 @@ static void end_io_requests(struct fuse_conn *fc)
  * onto the pending list is prevented by req->connected being false.
  *
  * Progression of requests under I/O to the processing list is
- * prevented by the req->interrupted flag being true for these
- * requests.  For this reason requests on the io list must be aborted
- * first.
+ * prevented by the req->aborted flag being true for these requests.
+ * For this reason requests on the io list must be aborted first.
  */
 void fuse_abort_conn(struct fuse_conn *fc)
 {
        spin_lock(&fc->lock);
        if (fc->connected) {
                fc->connected = 0;
+               fc->blocked = 0;
                end_io_requests(fc);
                end_requests(fc, &fc->pending);
                end_requests(fc, &fc->processing);
                wake_up_all(&fc->waitq);
+               wake_up_all(&fc->blocked_waitq);
                kill_fasync(&fc->fasync, SIGIO, POLL_IN);
        }
        spin_unlock(&fc->lock);
@@ -902,7 +1020,7 @@ static int fuse_dev_release(struct inode *inode, struct file *file)
                end_requests(fc, &fc->processing);
                spin_unlock(&fc->lock);
                fasync_helper(-1, file, 0, &fc->fasync);
-               kobject_put(&fc->kobj);
+               fuse_conn_put(fc);
        }
 
        return 0;
index 8d7546e832e89a28e770d09e8c6732577c41ea8f..72a74cde6de8c288793293d4e4ca4bb4ea58b793 100644 (file)
@@ -1,6 +1,6 @@
 /*
   FUSE: Filesystem in Userspace
-  Copyright (C) 2001-2005  Miklos Szeredi <miklos@szeredi.hu>
+  Copyright (C) 2001-2006  Miklos Szeredi <miklos@szeredi.hu>
 
   This program can be distributed under the terms of the GNU GPL.
   See the file COPYING.
@@ -79,7 +79,6 @@ static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
 {
        req->in.h.opcode = FUSE_LOOKUP;
        req->in.h.nodeid = get_node_id(dir);
-       req->inode = dir;
        req->in.numargs = 1;
        req->in.args[0].size = entry->d_name.len + 1;
        req->in.args[0].value = entry->d_name.name;
@@ -224,6 +223,20 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
        return NULL;
 }
 
+/*
+ * Synchronous release for the case when something goes wrong in CREATE_OPEN
+ */
+static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff,
+                             u64 nodeid, int flags)
+{
+       struct fuse_req *req;
+
+       req = fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE);
+       req->force = 1;
+       request_send(fc, req);
+       fuse_put_request(fc, req);
+}
+
 /*
  * Atomic create+open operation
  *
@@ -237,6 +250,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        struct inode *inode;
        struct fuse_conn *fc = get_fuse_conn(dir);
        struct fuse_req *req;
+       struct fuse_req *forget_req;
        struct fuse_open_in inarg;
        struct fuse_open_out outopen;
        struct fuse_entry_out outentry;
@@ -247,9 +261,14 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        if (fc->no_create)
                return -ENOSYS;
 
+       forget_req = fuse_get_req(fc);
+       if (IS_ERR(forget_req))
+               return PTR_ERR(forget_req);
+
        req = fuse_get_req(fc);
+       err = PTR_ERR(req);
        if (IS_ERR(req))
-               return PTR_ERR(req);
+               goto out_put_forget_req;
 
        err = -ENOMEM;
        ff = fuse_file_alloc();
@@ -262,7 +281,6 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        inarg.mode = mode;
        req->in.h.opcode = FUSE_CREATE;
        req->in.h.nodeid = get_node_id(dir);
-       req->inode = dir;
        req->in.numargs = 2;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -285,25 +303,23 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
                goto out_free_ff;
 
+       fuse_put_request(fc, req);
        inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
                          &outentry.attr);
-       err = -ENOMEM;
        if (!inode) {
                flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
                ff->fh = outopen.fh;
-               /* Special release, with inode = NULL, this will
-                  trigger a 'forget' request when the release is
-                  complete */
-               fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0);
-               goto out_put_request;
+               fuse_sync_release(fc, ff, outentry.nodeid, flags);
+               fuse_send_forget(fc, forget_req, outentry.nodeid, 1);
+               return -ENOMEM;
        }
-       fuse_put_request(fc, req);
+       fuse_put_request(fc, forget_req);
        d_instantiate(entry, inode);
        fuse_change_timeout(entry, &outentry);
        file = lookup_instantiate_filp(nd, entry, generic_file_open);
        if (IS_ERR(file)) {
                ff->fh = outopen.fh;
-               fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0);
+               fuse_sync_release(fc, ff, outentry.nodeid, flags);
                return PTR_ERR(file);
        }
        fuse_finish_open(inode, file, ff, &outopen);
@@ -313,6 +329,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        fuse_file_free(ff);
  out_put_request:
        fuse_put_request(fc, req);
+ out_put_forget_req:
+       fuse_put_request(fc, forget_req);
        return err;
 }
 
@@ -328,7 +346,6 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
        int err;
 
        req->in.h.nodeid = get_node_id(dir);
-       req->inode = dir;
        req->out.numargs = 1;
        req->out.args[0].size = sizeof(outarg);
        req->out.args[0].value = &outarg;
@@ -448,7 +465,6 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
 
        req->in.h.opcode = FUSE_UNLINK;
        req->in.h.nodeid = get_node_id(dir);
-       req->inode = dir;
        req->in.numargs = 1;
        req->in.args[0].size = entry->d_name.len + 1;
        req->in.args[0].value = entry->d_name.name;
@@ -480,7 +496,6 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
 
        req->in.h.opcode = FUSE_RMDIR;
        req->in.h.nodeid = get_node_id(dir);
-       req->inode = dir;
        req->in.numargs = 1;
        req->in.args[0].size = entry->d_name.len + 1;
        req->in.args[0].value = entry->d_name.name;
@@ -510,8 +525,6 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
        inarg.newdir = get_node_id(newdir);
        req->in.h.opcode = FUSE_RENAME;
        req->in.h.nodeid = get_node_id(olddir);
-       req->inode = olddir;
-       req->inode2 = newdir;
        req->in.numargs = 3;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -558,7 +571,6 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
        memset(&inarg, 0, sizeof(inarg));
        inarg.oldnodeid = get_node_id(inode);
        req->in.h.opcode = FUSE_LINK;
-       req->inode2 = inode;
        req->in.numargs = 2;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -587,7 +599,6 @@ int fuse_do_getattr(struct inode *inode)
 
        req->in.h.opcode = FUSE_GETATTR;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
        req->out.numargs = 1;
        req->out.args[0].size = sizeof(arg);
        req->out.args[0].value = &arg;
@@ -679,7 +690,6 @@ static int fuse_access(struct inode *inode, int mask)
        inarg.mask = mask;
        req->in.h.opcode = FUSE_ACCESS;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -820,7 +830,6 @@ static char *read_link(struct dentry *dentry)
        }
        req->in.h.opcode = FUSE_READLINK;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
        req->out.argvar = 1;
        req->out.numargs = 1;
        req->out.args[0].size = PAGE_SIZE - 1;
@@ -939,7 +948,6 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
        iattr_to_fattr(attr, &inarg);
        req->in.h.opcode = FUSE_SETATTR;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -1002,7 +1010,6 @@ static int fuse_setxattr(struct dentry *entry, const char *name,
        inarg.flags = flags;
        req->in.h.opcode = FUSE_SETXATTR;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
        req->in.numargs = 3;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -1041,7 +1048,6 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
        inarg.size = size;
        req->in.h.opcode = FUSE_GETXATTR;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
        req->in.numargs = 2;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -1091,7 +1097,6 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
        inarg.size = size;
        req->in.h.opcode = FUSE_LISTXATTR;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -1135,7 +1140,6 @@ static int fuse_removexattr(struct dentry *entry, const char *name)
 
        req->in.h.opcode = FUSE_REMOVEXATTR;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
        req->in.numargs = 1;
        req->in.args[0].size = strlen(name) + 1;
        req->in.args[0].value = name;
index 087f3b734f407a5d072b72cc375eb722d351a9ae..28aa81eae2cc6ddee6a2c41c5dee99254ea90f75 100644 (file)
@@ -30,7 +30,6 @@ static int fuse_send_open(struct inode *inode, struct file *file, int isdir,
        inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
        req->in.h.opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -49,8 +48,8 @@ struct fuse_file *fuse_file_alloc(void)
        struct fuse_file *ff;
        ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL);
        if (ff) {
-               ff->release_req = fuse_request_alloc();
-               if (!ff->release_req) {
+               ff->reserved_req = fuse_request_alloc();
+               if (!ff->reserved_req) {
                        kfree(ff);
                        ff = NULL;
                }
@@ -60,7 +59,7 @@ struct fuse_file *fuse_file_alloc(void)
 
 void fuse_file_free(struct fuse_file *ff)
 {
-       fuse_request_free(ff->release_req);
+       fuse_request_free(ff->reserved_req);
        kfree(ff);
 }
 
@@ -113,37 +112,22 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir)
        return err;
 }
 
-/* Special case for failed iget in CREATE */
-static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req)
+struct fuse_req *fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags,
+                                  int opcode)
 {
-       /* If called from end_io_requests(), req has more than one
-          reference and fuse_reset_request() cannot work */
-       if (fc->connected) {
-               u64 nodeid = req->in.h.nodeid;
-               fuse_reset_request(req);
-               fuse_send_forget(fc, req, nodeid, 1);
-       } else
-               fuse_put_request(fc, req);
-}
-
-void fuse_send_release(struct fuse_conn *fc, struct fuse_file *ff,
-                      u64 nodeid, struct inode *inode, int flags, int isdir)
-{
-       struct fuse_req * req = ff->release_req;
+       struct fuse_req *req = ff->reserved_req;
        struct fuse_release_in *inarg = &req->misc.release_in;
 
        inarg->fh = ff->fh;
        inarg->flags = flags;
-       req->in.h.opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE;
+       req->in.h.opcode = opcode;
        req->in.h.nodeid = nodeid;
-       req->inode = inode;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(struct fuse_release_in);
        req->in.args[0].value = inarg;
-       request_send_background(fc, req);
-       if (!inode)
-               req->end = fuse_release_end;
        kfree(ff);
+
+       return req;
 }
 
 int fuse_release_common(struct inode *inode, struct file *file, int isdir)
@@ -151,8 +135,15 @@ int fuse_release_common(struct inode *inode, struct file *file, int isdir)
        struct fuse_file *ff = file->private_data;
        if (ff) {
                struct fuse_conn *fc = get_fuse_conn(inode);
-               u64 nodeid = get_node_id(inode);
-               fuse_send_release(fc, ff, nodeid, inode, file->f_flags, isdir);
+               struct fuse_req *req;
+
+               req = fuse_release_fill(ff, get_node_id(inode), file->f_flags,
+                                       isdir ? FUSE_RELEASEDIR : FUSE_RELEASE);
+
+               /* Hold vfsmount and dentry until release is finished */
+               req->vfsmount = mntget(file->f_vfsmnt);
+               req->dentry = dget(file->f_dentry);
+               request_send_background(fc, req);
        }
 
        /* Return value is ignored by VFS */
@@ -169,6 +160,28 @@ static int fuse_release(struct inode *inode, struct file *file)
        return fuse_release_common(inode, file, 0);
 }
 
+/*
+ * Scramble the ID space with XTEA, so that the value of the files_struct
+ * pointer is not exposed to userspace.
+ */
+static u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id)
+{
+       u32 *k = fc->scramble_key;
+       u64 v = (unsigned long) id;
+       u32 v0 = v;
+       u32 v1 = v >> 32;
+       u32 sum = 0;
+       int i;
+
+       for (i = 0; i < 32; i++) {
+               v0 += ((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + k[sum & 3]);
+               sum += 0x9E3779B9;
+               v1 += ((v0 << 4 ^ v0 >> 5) + v0) ^ (sum + k[sum>>11 & 3]);
+       }
+
+       return (u64) v0 + ((u64) v1 << 32);
+}
+
 static int fuse_flush(struct file *file, fl_owner_t id)
 {
        struct inode *inode = file->f_dentry->d_inode;
@@ -184,19 +197,16 @@ static int fuse_flush(struct file *file, fl_owner_t id)
        if (fc->no_flush)
                return 0;
 
-       req = fuse_get_req(fc);
-       if (IS_ERR(req))
-               return PTR_ERR(req);
-
+       req = fuse_get_req_nofail(fc, file);
        memset(&inarg, 0, sizeof(inarg));
        inarg.fh = ff->fh;
+       inarg.lock_owner = fuse_lock_owner_id(fc, id);
        req->in.h.opcode = FUSE_FLUSH;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
-       req->file = file;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
+       req->force = 1;
        request_send(fc, req);
        err = req->out.h.error;
        fuse_put_request(fc, req);
@@ -232,8 +242,6 @@ int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
        inarg.fsync_flags = datasync ? 1 : 0;
        req->in.h.opcode = isdir ? FUSE_FSYNCDIR : FUSE_FSYNC;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
-       req->file = file;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -266,8 +274,6 @@ void fuse_read_fill(struct fuse_req *req, struct file *file,
        inarg->size = count;
        req->in.h.opcode = opcode;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
-       req->file = file;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(struct fuse_read_in);
        req->in.args[0].value = inarg;
@@ -342,6 +348,8 @@ static void fuse_send_readpages(struct fuse_req *req, struct file *file,
        req->out.page_zeroing = 1;
        fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
        if (fc->async_read) {
+               get_file(file);
+               req->file = file;
                req->end = fuse_readpages_end;
                request_send_background(fc, req);
        } else {
@@ -420,8 +428,6 @@ static size_t fuse_send_write(struct fuse_req *req, struct file *file,
        inarg.size = count;
        req->in.h.opcode = FUSE_WRITE;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
-       req->file = file;
        req->in.argpages = 1;
        req->in.numargs = 2;
        req->in.args[0].size = sizeof(struct fuse_write_in);
@@ -619,6 +625,126 @@ static int fuse_set_page_dirty(struct page *page)
        return 0;
 }
 
+static int convert_fuse_file_lock(const struct fuse_file_lock *ffl,
+                                 struct file_lock *fl)
+{
+       switch (ffl->type) {
+       case F_UNLCK:
+               break;
+
+       case F_RDLCK:
+       case F_WRLCK:
+               if (ffl->start > OFFSET_MAX || ffl->end > OFFSET_MAX ||
+                   ffl->end < ffl->start)
+                       return -EIO;
+
+               fl->fl_start = ffl->start;
+               fl->fl_end = ffl->end;
+               fl->fl_pid = ffl->pid;
+               break;
+
+       default:
+               return -EIO;
+       }
+       fl->fl_type = ffl->type;
+       return 0;
+}
+
+static void fuse_lk_fill(struct fuse_req *req, struct file *file,
+                        const struct file_lock *fl, int opcode, pid_t pid)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct fuse_conn *fc = get_fuse_conn(inode);
+       struct fuse_file *ff = file->private_data;
+       struct fuse_lk_in *arg = &req->misc.lk_in;
+
+       arg->fh = ff->fh;
+       arg->owner = fuse_lock_owner_id(fc, fl->fl_owner);
+       arg->lk.start = fl->fl_start;
+       arg->lk.end = fl->fl_end;
+       arg->lk.type = fl->fl_type;
+       arg->lk.pid = pid;
+       req->in.h.opcode = opcode;
+       req->in.h.nodeid = get_node_id(inode);
+       req->in.numargs = 1;
+       req->in.args[0].size = sizeof(*arg);
+       req->in.args[0].value = arg;
+}
+
+static int fuse_getlk(struct file *file, struct file_lock *fl)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct fuse_conn *fc = get_fuse_conn(inode);
+       struct fuse_req *req;
+       struct fuse_lk_out outarg;
+       int err;
+
+       req = fuse_get_req(fc);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       fuse_lk_fill(req, file, fl, FUSE_GETLK, 0);
+       req->out.numargs = 1;
+       req->out.args[0].size = sizeof(outarg);
+       req->out.args[0].value = &outarg;
+       request_send(fc, req);
+       err = req->out.h.error;
+       fuse_put_request(fc, req);
+       if (!err)
+               err = convert_fuse_file_lock(&outarg.lk, fl);
+
+       return err;
+}
+
+static int fuse_setlk(struct file *file, struct file_lock *fl)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct fuse_conn *fc = get_fuse_conn(inode);
+       struct fuse_req *req;
+       int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK;
+       pid_t pid = fl->fl_type != F_UNLCK ? current->tgid : 0;
+       int err;
+
+       /* Unlock on close is handled by the flush method */
+       if (fl->fl_flags & FL_CLOSE)
+               return 0;
+
+       req = fuse_get_req(fc);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       fuse_lk_fill(req, file, fl, opcode, pid);
+       request_send(fc, req);
+       err = req->out.h.error;
+       /* locking is restartable */
+       if (err == -EINTR)
+               err = -ERESTARTSYS;
+       fuse_put_request(fc, req);
+       return err;
+}
+
+static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct fuse_conn *fc = get_fuse_conn(inode);
+       int err;
+
+       if (cmd == F_GETLK) {
+               if (fc->no_lock) {
+                       if (!posix_test_lock(file, fl, fl))
+                               fl->fl_type = F_UNLCK;
+                       err = 0;
+               } else
+                       err = fuse_getlk(file, fl);
+       } else {
+               if (fc->no_lock)
+                       err = posix_lock_file_wait(file, fl);
+               else
+                       err = fuse_setlk(file, fl);
+       }
+       return err;
+}
+
 static const struct file_operations fuse_file_operations = {
        .llseek         = generic_file_llseek,
        .read           = generic_file_read,
@@ -628,6 +754,7 @@ static const struct file_operations fuse_file_operations = {
        .flush          = fuse_flush,
        .release        = fuse_release,
        .fsync          = fuse_fsync,
+       .lock           = fuse_file_lock,
        .sendfile       = generic_file_sendfile,
 };
 
@@ -639,6 +766,7 @@ static const struct file_operations fuse_direct_io_file_operations = {
        .flush          = fuse_flush,
        .release        = fuse_release,
        .fsync          = fuse_fsync,
+       .lock           = fuse_file_lock,
        /* no mmap and sendfile */
 };
 
index 0474202cb5dc09d8b0bd9c75c47d7e01a87b700a..0dbf96621841506f94ed62ae32260fd077ae19d5 100644 (file)
@@ -8,12 +8,13 @@
 
 #include <linux/fuse.h>
 #include <linux/fs.h>
+#include <linux/mount.h>
 #include <linux/wait.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
 #include <linux/backing-dev.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 /** Max number of pages that can be used in a single read request */
 #define FUSE_MAX_PAGES_PER_REQ 32
@@ -24,6 +25,9 @@
 /** It could be as large as PATH_MAX, but would that have any uses? */
 #define FUSE_NAME_MAX 1024
 
+/** Number of dentries for each connection in the control filesystem */
+#define FUSE_CTL_NUM_DENTRIES 3
+
 /** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem
     module will check permissions based on the file mode.  Otherwise no
     permission checking is done in the kernel */
     doing the mount will be allowed to access the filesystem */
 #define FUSE_ALLOW_OTHER         (1 << 1)
 
+/** List of active connections */
+extern struct list_head fuse_conn_list;
+
+/** Global mutex protecting fuse_conn_list and the control filesystem */
+extern struct mutex fuse_mutex;
 
 /** FUSE inode */
 struct fuse_inode {
@@ -56,7 +65,7 @@ struct fuse_inode {
 /** FUSE specific file data */
 struct fuse_file {
        /** Request reserved for flush and release */
-       struct fuse_req *release_req;
+       struct fuse_req *reserved_req;
 
        /** File handle used by userspace */
        u64 fh;
@@ -122,6 +131,7 @@ enum fuse_req_state {
        FUSE_REQ_PENDING,
        FUSE_REQ_READING,
        FUSE_REQ_SENT,
+       FUSE_REQ_WRITING,
        FUSE_REQ_FINISHED
 };
 
@@ -135,12 +145,15 @@ struct fuse_req {
            fuse_conn */
        struct list_head list;
 
-       /** Entry on the background list */
-       struct list_head bg_entry;
+       /** Entry on the interrupts list  */
+       struct list_head intr_entry;
 
        /** refcount */
        atomic_t count;
 
+       /** Unique ID for the interrupt request */
+       u64 intr_unique;
+
        /*
         * The following bitfields are either set once before the
         * request is queued or setting/clearing them is protected by
@@ -150,12 +163,18 @@ struct fuse_req {
        /** True if the request has reply */
        unsigned isreply:1;
 
-       /** The request was interrupted */
-       unsigned interrupted:1;
+       /** Force sending of the request even if interrupted */
+       unsigned force:1;
+
+       /** The request was aborted */
+       unsigned aborted:1;
 
        /** Request is sent in the background */
        unsigned background:1;
 
+       /** The request has been interrupted */
+       unsigned interrupted:1;
+
        /** Data is being copied to/from the request */
        unsigned locked:1;
 
@@ -181,6 +200,7 @@ struct fuse_req {
                struct fuse_init_in init_in;
                struct fuse_init_out init_out;
                struct fuse_read_in read_in;
+               struct fuse_lk_in lk_in;
        } misc;
 
        /** page vector */
@@ -192,17 +212,20 @@ struct fuse_req {
        /** offset of data on first page */
        unsigned page_offset;
 
-       /** Inode used in the request */
-       struct inode *inode;
-
-       /** Second inode used in the request (or NULL) */
-       struct inode *inode2;
-
        /** File used in the request (or NULL) */
        struct file *file;
 
+       /** vfsmount used in release */
+       struct vfsmount *vfsmount;
+
+       /** dentry used in release */
+       struct dentry *dentry;
+
        /** Request completion callback */
        void (*end)(struct fuse_conn *, struct fuse_req *);
+
+       /** Request is stolen from fuse_file->reserved_req */
+       struct file *stolen_file;
 };
 
 /**
@@ -216,6 +239,9 @@ struct fuse_conn {
        /** Lock protecting accessess to  members of this structure */
        spinlock_t lock;
 
+       /** Refcount */
+       atomic_t count;
+
        /** The user id for this mount */
        uid_t user_id;
 
@@ -243,13 +269,12 @@ struct fuse_conn {
        /** The list of requests under I/O */
        struct list_head io;
 
-       /** Requests put in the background (RELEASE or any other
-           interrupted request) */
-       struct list_head background;
-
        /** Number of requests currently in the background */
        unsigned num_background;
 
+       /** Pending interrupts */
+       struct list_head interrupts;
+
        /** Flag indicating if connection is blocked.  This will be
            the case before the INIT reply is received, and if there
            are too many outstading backgrounds requests */
@@ -258,15 +283,9 @@ struct fuse_conn {
        /** waitq for blocked connection */
        wait_queue_head_t blocked_waitq;
 
-       /** RW semaphore for exclusion with fuse_put_super() */
-       struct rw_semaphore sbput_sem;
-
        /** The next unique request id */
        u64 reqctr;
 
-       /** Mount is active */
-       unsigned mounted;
-
        /** Connection established, cleared on umount, connection
            abort and device release */
        unsigned connected;
@@ -305,12 +324,18 @@ struct fuse_conn {
        /** Is removexattr not implemented by fs? */
        unsigned no_removexattr : 1;
 
+       /** Are file locking primitives not implemented by fs? */
+       unsigned no_lock : 1;
+
        /** Is access not implemented by fs? */
        unsigned no_access : 1;
 
        /** Is create not implemented by fs? */
        unsigned no_create : 1;
 
+       /** Is interrupt not implemented by fs? */
+       unsigned no_interrupt : 1;
+
        /** The number of requests waiting for completion */
        atomic_t num_waiting;
 
@@ -320,11 +345,23 @@ struct fuse_conn {
        /** Backing dev info */
        struct backing_dev_info bdi;
 
-       /** kobject */
-       struct kobject kobj;
+       /** Entry on the fuse_conn_list */
+       struct list_head entry;
+
+       /** Unique ID */
+       u64 id;
+
+       /** Dentries in the control filesystem */
+       struct dentry *ctl_dentry[FUSE_CTL_NUM_DENTRIES];
+
+       /** number of dentries used in the above array */
+       int ctl_ndents;
 
        /** O_ASYNC requests */
        struct fasync_struct *fasync;
+
+       /** Key for lock owner ID scrambling */
+       u32 scramble_key[4];
 };
 
 static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
@@ -337,11 +374,6 @@ static inline struct fuse_conn *get_fuse_conn(struct inode *inode)
        return get_fuse_conn_super(inode->i_sb);
 }
 
-static inline struct fuse_conn *get_fuse_conn_kobj(struct kobject *obj)
-{
-       return container_of(obj, struct fuse_conn, kobj);
-}
-
 static inline struct fuse_inode *get_fuse_inode(struct inode *inode)
 {
        return container_of(inode, struct fuse_inode, inode);
@@ -383,12 +415,9 @@ void fuse_file_free(struct fuse_file *ff);
 void fuse_finish_open(struct inode *inode, struct file *file,
                      struct fuse_file *ff, struct fuse_open_out *outarg);
 
-/**
- * Send a RELEASE request
- */
-void fuse_send_release(struct fuse_conn *fc, struct fuse_file *ff,
-                      u64 nodeid, struct inode *inode, int flags, int isdir);
-
+/** */
+struct fuse_req *fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags,
+                                  int opcode);
 /**
  * Send RELEASE or RELEASEDIR request
  */
@@ -435,6 +464,9 @@ int fuse_dev_init(void);
  */
 void fuse_dev_cleanup(void);
 
+int fuse_ctl_init(void);
+void fuse_ctl_cleanup(void);
+
 /**
  * Allocate a request
  */
@@ -446,14 +478,14 @@ struct fuse_req *fuse_request_alloc(void);
 void fuse_request_free(struct fuse_req *req);
 
 /**
- * Reinitialize a request, the preallocated flag is left unmodified
+ * Get a request, may fail with -ENOMEM
  */
-void fuse_reset_request(struct fuse_req *req);
+struct fuse_req *fuse_get_req(struct fuse_conn *fc);
 
 /**
- * Reserve a preallocated request
+ * Gets a requests for a file operation, always succeeds
  */
-struct fuse_req *fuse_get_req(struct fuse_conn *fc);
+struct fuse_req *fuse_get_req_nofail(struct fuse_conn *fc, struct file *file);
 
 /**
  * Decrement reference count of a request.  If count goes to zero free
@@ -476,11 +508,6 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req);
  */
 void request_send_background(struct fuse_conn *fc, struct fuse_req *req);
 
-/**
- * Release inodes and file associated with background request
- */
-void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req);
-
 /* Abort all requests */
 void fuse_abort_conn(struct fuse_conn *fc);
 
@@ -493,3 +520,23 @@ int fuse_do_getattr(struct inode *inode);
  * Invalidate inode attributes
  */
 void fuse_invalidate_attr(struct inode *inode);
+
+/**
+ * Acquire reference to fuse_conn
+ */
+struct fuse_conn *fuse_conn_get(struct fuse_conn *fc);
+
+/**
+ * Release reference to fuse_conn
+ */
+void fuse_conn_put(struct fuse_conn *fc);
+
+/**
+ * Add connection to control filesystem
+ */
+int fuse_ctl_add_conn(struct fuse_conn *fc);
+
+/**
+ * Remove connection from control filesystem
+ */
+void fuse_ctl_remove_conn(struct fuse_conn *fc);
index 815c824f4fc8797c054f33b9907f95bfdaf5e840..dcaaabd3b9c450ad546b86c54d475c5b8ff0f0ed 100644 (file)
 #include <linux/pagemap.h>
 #include <linux/slab.h>
 #include <linux/file.h>
-#include <linux/mount.h>
 #include <linux/seq_file.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/parser.h>
 #include <linux/statfs.h>
+#include <linux/random.h>
 
 MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
 MODULE_DESCRIPTION("Filesystem in Userspace");
 MODULE_LICENSE("GPL");
 
 static kmem_cache_t *fuse_inode_cachep;
-static struct subsystem connections_subsys;
-
-struct fuse_conn_attr {
-       struct attribute attr;
-       ssize_t (*show)(struct fuse_conn *, char *);
-       ssize_t (*store)(struct fuse_conn *, const char *, size_t);
-};
+struct list_head fuse_conn_list;
+DEFINE_MUTEX(fuse_mutex);
 
 #define FUSE_SUPER_MAGIC 0x65735546
 
@@ -104,6 +99,14 @@ static void fuse_clear_inode(struct inode *inode)
        }
 }
 
+static int fuse_remount_fs(struct super_block *sb, int *flags, char *data)
+{
+       if (*flags & MS_MANDLOCK)
+               return -EINVAL;
+
+       return 0;
+}
+
 void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
 {
        if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
@@ -205,22 +208,19 @@ static void fuse_put_super(struct super_block *sb)
 {
        struct fuse_conn *fc = get_fuse_conn_super(sb);
 
-       down_write(&fc->sbput_sem);
-       while (!list_empty(&fc->background))
-               fuse_release_background(fc,
-                                       list_entry(fc->background.next,
-                                                  struct fuse_req, bg_entry));
-
        spin_lock(&fc->lock);
-       fc->mounted = 0;
        fc->connected = 0;
+       fc->blocked = 0;
        spin_unlock(&fc->lock);
-       up_write(&fc->sbput_sem);
        /* Flush all readers on this fs */
        kill_fasync(&fc->fasync, SIGIO, POLL_IN);
        wake_up_all(&fc->waitq);
-       kobject_del(&fc->kobj);
-       kobject_put(&fc->kobj);
+       wake_up_all(&fc->blocked_waitq);
+       mutex_lock(&fuse_mutex);
+       list_del(&fc->entry);
+       fuse_ctl_remove_conn(fc);
+       mutex_unlock(&fuse_mutex);
+       fuse_conn_put(fc);
 }
 
 static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
@@ -370,11 +370,6 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
        return 0;
 }
 
-static void fuse_conn_release(struct kobject *kobj)
-{
-       kfree(get_fuse_conn_kobj(kobj));
-}
-
 static struct fuse_conn *new_conn(void)
 {
        struct fuse_conn *fc;
@@ -382,24 +377,35 @@ static struct fuse_conn *new_conn(void)
        fc = kzalloc(sizeof(*fc), GFP_KERNEL);
        if (fc) {
                spin_lock_init(&fc->lock);
+               atomic_set(&fc->count, 1);
                init_waitqueue_head(&fc->waitq);
                init_waitqueue_head(&fc->blocked_waitq);
                INIT_LIST_HEAD(&fc->pending);
                INIT_LIST_HEAD(&fc->processing);
                INIT_LIST_HEAD(&fc->io);
-               INIT_LIST_HEAD(&fc->background);
-               init_rwsem(&fc->sbput_sem);
-               kobj_set_kset_s(fc, connections_subsys);
-               kobject_init(&fc->kobj);
+               INIT_LIST_HEAD(&fc->interrupts);
                atomic_set(&fc->num_waiting, 0);
                fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
                fc->bdi.unplug_io_fn = default_unplug_io_fn;
                fc->reqctr = 0;
                fc->blocked = 1;
+               get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
        }
        return fc;
 }
 
+void fuse_conn_put(struct fuse_conn *fc)
+{
+       if (atomic_dec_and_test(&fc->count))
+               kfree(fc);
+}
+
+struct fuse_conn *fuse_conn_get(struct fuse_conn *fc)
+{
+       atomic_inc(&fc->count);
+       return fc;
+}
+
 static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
 {
        struct fuse_attr attr;
@@ -415,6 +421,7 @@ static struct super_operations fuse_super_operations = {
        .destroy_inode  = fuse_destroy_inode,
        .read_inode     = fuse_read_inode,
        .clear_inode    = fuse_clear_inode,
+       .remount_fs     = fuse_remount_fs,
        .put_super      = fuse_put_super,
        .umount_begin   = fuse_umount_begin,
        .statfs         = fuse_statfs,
@@ -434,8 +441,12 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
                        ra_pages = arg->max_readahead / PAGE_CACHE_SIZE;
                        if (arg->flags & FUSE_ASYNC_READ)
                                fc->async_read = 1;
-               } else
+                       if (!(arg->flags & FUSE_POSIX_LOCKS))
+                               fc->no_lock = 1;
+               } else {
                        ra_pages = fc->max_read / PAGE_CACHE_SIZE;
+                       fc->no_lock = 1;
+               }
 
                fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
                fc->minor = arg->minor;
@@ -453,7 +464,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
        arg->major = FUSE_KERNEL_VERSION;
        arg->minor = FUSE_KERNEL_MINOR_VERSION;
        arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
-       arg->flags |= FUSE_ASYNC_READ;
+       arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS;
        req->in.h.opcode = FUSE_INIT;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(*arg);
@@ -469,10 +480,9 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
        request_send_background(fc, req);
 }
 
-static unsigned long long conn_id(void)
+static u64 conn_id(void)
 {
-       /* BKL is held for ->get_sb() */
-       static unsigned long long ctr = 1;
+       static u64 ctr = 1;
        return ctr++;
 }
 
@@ -486,6 +496,9 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
        struct fuse_req *init_req;
        int err;
 
+       if (sb->s_flags & MS_MANDLOCK)
+               return -EINVAL;
+
        if (!parse_fuse_opt((char *) data, &d))
                return -EINVAL;
 
@@ -529,25 +542,21 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
        if (!init_req)
                goto err_put_root;
 
-       err = kobject_set_name(&fc->kobj, "%llu", conn_id());
-       if (err)
-               goto err_free_req;
-
-       err = kobject_add(&fc->kobj);
-       if (err)
-               goto err_free_req;
-
-       /* Setting file->private_data can't race with other mount()
-          instances, since BKL is held for ->get_sb() */
+       mutex_lock(&fuse_mutex);
        err = -EINVAL;
        if (file->private_data)
-               goto err_kobject_del;
+               goto err_unlock;
 
+       fc->id = conn_id();
+       err = fuse_ctl_add_conn(fc);
+       if (err)
+               goto err_unlock;
+
+       list_add_tail(&fc->entry, &fuse_conn_list);
        sb->s_root = root_dentry;
-       fc->mounted = 1;
        fc->connected = 1;
-       kobject_get(&fc->kobj);
-       file->private_data = fc;
+       file->private_data = fuse_conn_get(fc);
+       mutex_unlock(&fuse_mutex);
        /*
         * atomic_dec_and_test() in fput() provides the necessary
         * memory barrier for file->private_data to be visible on all
@@ -559,15 +568,14 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
 
        return 0;
 
- err_kobject_del:
-       kobject_del(&fc->kobj);
- err_free_req:
+ err_unlock:
+       mutex_unlock(&fuse_mutex);
        fuse_request_free(init_req);
  err_put_root:
        dput(root_dentry);
  err:
        fput(file);
-       kobject_put(&fc->kobj);
+       fuse_conn_put(fc);
        return err;
 }
 
@@ -585,68 +593,8 @@ static struct file_system_type fuse_fs_type = {
        .kill_sb        = kill_anon_super,
 };
 
-static ssize_t fuse_conn_waiting_show(struct fuse_conn *fc, char *page)
-{
-       return sprintf(page, "%i\n", atomic_read(&fc->num_waiting));
-}
-
-static ssize_t fuse_conn_abort_store(struct fuse_conn *fc, const char *page,
-                                    size_t count)
-{
-       fuse_abort_conn(fc);
-       return count;
-}
-
-static struct fuse_conn_attr fuse_conn_waiting =
-       __ATTR(waiting, 0400, fuse_conn_waiting_show, NULL);
-static struct fuse_conn_attr fuse_conn_abort =
-       __ATTR(abort, 0600, NULL, fuse_conn_abort_store);
-
-static struct attribute *fuse_conn_attrs[] = {
-       &fuse_conn_waiting.attr,
-       &fuse_conn_abort.attr,
-       NULL,
-};
-
-static ssize_t fuse_conn_attr_show(struct kobject *kobj,
-                                  struct attribute *attr,
-                                  char *page)
-{
-       struct fuse_conn_attr *fca =
-               container_of(attr, struct fuse_conn_attr, attr);
-
-       if (fca->show)
-               return fca->show(get_fuse_conn_kobj(kobj), page);
-       else
-               return -EACCES;
-}
-
-static ssize_t fuse_conn_attr_store(struct kobject *kobj,
-                                   struct attribute *attr,
-                                   const char *page, size_t count)
-{
-       struct fuse_conn_attr *fca =
-               container_of(attr, struct fuse_conn_attr, attr);
-
-       if (fca->store)
-               return fca->store(get_fuse_conn_kobj(kobj), page, count);
-       else
-               return -EACCES;
-}
-
-static struct sysfs_ops fuse_conn_sysfs_ops = {
-       .show   = &fuse_conn_attr_show,
-       .store  = &fuse_conn_attr_store,
-};
-
-static struct kobj_type ktype_fuse_conn = {
-       .release        = fuse_conn_release,
-       .sysfs_ops      = &fuse_conn_sysfs_ops,
-       .default_attrs  = fuse_conn_attrs,
-};
-
 static decl_subsys(fuse, NULL, NULL);
-static decl_subsys(connections, &ktype_fuse_conn, NULL);
+static decl_subsys(connections, NULL, NULL);
 
 static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep,
                                 unsigned long flags)
@@ -720,6 +668,7 @@ static int __init fuse_init(void)
        printk("fuse init (API version %i.%i)\n",
               FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
 
+       INIT_LIST_HEAD(&fuse_conn_list);
        res = fuse_fs_init();
        if (res)
                goto err;
@@ -732,8 +681,14 @@ static int __init fuse_init(void)
        if (res)
                goto err_dev_cleanup;
 
+       res = fuse_ctl_init();
+       if (res)
+               goto err_sysfs_cleanup;
+
        return 0;
 
+ err_sysfs_cleanup:
+       fuse_sysfs_cleanup();
  err_dev_cleanup:
        fuse_dev_cleanup();
  err_fs_cleanup:
@@ -746,6 +701,7 @@ static void __exit fuse_exit(void)
 {
        printk(KERN_DEBUG "fuse exit\n");
 
+       fuse_ctl_cleanup();
        fuse_sysfs_cleanup();
        fuse_fs_cleanup();
        fuse_dev_cleanup();
index 80d7f53fd0a759dec8a019c60bb96badf7f927bb..de5bafb4e8534db59d76f86bf6352821a6458012 100644 (file)
@@ -531,6 +531,7 @@ static int do_one_pass(journal_t *journal,
                default:
                        jbd_debug(3, "Unrecognised magic %d, end of scan.\n",
                                  blocktype);
+                       brelse(bh);
                        goto done;
                }
        }
index bb4a3e40e43269944523fc4f3987d4a556ca5f84..c784e8bb57a35c6fa272ece7303095887ef65e8a 100644 (file)
@@ -2243,14 +2243,16 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
        int error;
        char * to;
 
-       if (flags != 0)
+       if ((flags & ~AT_SYMLINK_FOLLOW) != 0)
                return -EINVAL;
 
        to = getname(newname);
        if (IS_ERR(to))
                return PTR_ERR(to);
 
-       error = __user_walk_fd(olddfd, oldname, 0, &old_nd);
+       error = __user_walk_fd(olddfd, oldname,
+                              flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0,
+                              &old_nd);
        if (error)
                goto exit;
        error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
index 88292f9e4b9b58ebb4255b3de77c46b5d1bb8efe..2e42c2dcae12310d123c13642809219c5cb51126 100644 (file)
@@ -1358,7 +1358,7 @@ err_out:
        goto out;
 }
 
-static size_t __ntfs_copy_from_user_iovec(char *vaddr,
+static size_t __ntfs_copy_from_user_iovec_inatomic(char *vaddr,
                const struct iovec *iov, size_t iov_ofs, size_t bytes)
 {
        size_t total = 0;
@@ -1376,10 +1376,6 @@ static size_t __ntfs_copy_from_user_iovec(char *vaddr,
                bytes -= len;
                vaddr += len;
                if (unlikely(left)) {
-                       /*
-                        * Zero the rest of the target like __copy_from_user().
-                        */
-                       memset(vaddr, 0, bytes);
                        total -= left;
                        break;
                }
@@ -1420,11 +1416,13 @@ static inline void ntfs_set_next_iovec(const struct iovec **iovp,
  * pages (out to offset + bytes), to emulate ntfs_copy_from_user()'s
  * single-segment behaviour.
  *
- * We call the same helper (__ntfs_copy_from_user_iovec()) both when atomic and
- * when not atomic.  This is ok because __ntfs_copy_from_user_iovec() calls
- * __copy_from_user_inatomic() and it is ok to call this when non-atomic.  In
- * fact, the only difference between __copy_from_user_inatomic() and
- * __copy_from_user() is that the latter calls might_sleep().  And on many
+ * We call the same helper (__ntfs_copy_from_user_iovec_inatomic()) both
+ * when atomic and when not atomic.  This is ok because
+ * __ntfs_copy_from_user_iovec_inatomic() calls __copy_from_user_inatomic()
+ * and it is ok to call this when non-atomic.
+ * Infact, the only difference between __copy_from_user_inatomic() and
+ * __copy_from_user() is that the latter calls might_sleep() and the former
+ * should not zero the tail of the buffer on error.  And on many
  * architectures __copy_from_user_inatomic() is just defined to
  * __copy_from_user() so it makes no difference at all on those architectures.
  */
@@ -1441,14 +1439,18 @@ static inline size_t ntfs_copy_from_user_iovec(struct page **pages,
                if (len > bytes)
                        len = bytes;
                kaddr = kmap_atomic(*pages, KM_USER0);
-               copied = __ntfs_copy_from_user_iovec(kaddr + ofs,
+               copied = __ntfs_copy_from_user_iovec_inatomic(kaddr + ofs,
                                *iov, *iov_ofs, len);
                kunmap_atomic(kaddr, KM_USER0);
                if (unlikely(copied != len)) {
                        /* Do it the slow way. */
                        kaddr = kmap(*pages);
-                       copied = __ntfs_copy_from_user_iovec(kaddr + ofs,
+                       copied = __ntfs_copy_from_user_iovec_inatomic(kaddr + ofs,
                                        *iov, *iov_ofs, len);
+                       /*
+                        * Zero the rest of the target like __copy_from_user().
+                        */
+                       memset(kaddr + ofs + copied, 0, len - copied);
                        kunmap(*pages);
                        if (unlikely(copied != len))
                                goto err_out;
index 5fb16e5267dc253b16ffaf89e875aebcbc3c9739..303f06d2a7b92e8e001489cf2b1db17bdae6bd0c 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -322,7 +322,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
 
        error = locks_verify_truncate(inode, file, length);
        if (!error)
-               error = do_truncate(dentry, length, 0, file);
+               error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
 out_putf:
        fput(file);
 out:
index 464e2bce02030618779cb39e6f751679d1b8f538..efc7c91128af6946c14d013a56900895f36a7170 100644 (file)
@@ -64,6 +64,11 @@ static int openpromfs_readdir(struct file *, void *, filldir_t);
 static struct dentry *openpromfs_lookup(struct inode *, struct dentry *dentry, struct nameidata *nd);
 static int openpromfs_unlink (struct inode *, struct dentry *dentry);
 
+static inline u16 ptr_nod(void *p)
+{
+    return (long)p & 0xFFFF;
+}
+
 static ssize_t nodenum_read(struct file *file, char __user *buf,
                            size_t count, loff_t *ppos)
 {
@@ -72,7 +77,7 @@ static ssize_t nodenum_read(struct file *file, char __user *buf,
        
        if (count < 0 || !inode->u.generic_ip)
                return -EINVAL;
-       sprintf (buffer, "%8.8x\n", (u32)(long)(inode->u.generic_ip));
+       sprintf (buffer, "%8.8lx\n", (long)inode->u.generic_ip);
        if (file->f_pos >= 9)
                return 0;
        if (count > 9 - file->f_pos)
@@ -95,9 +100,9 @@ static ssize_t property_read(struct file *filp, char __user *buf,
        char buffer[64];
        
        if (!filp->private_data) {
-               node = nodes[(u16)((long)inode->u.generic_ip)].node;
+               node = nodes[ptr_nod(inode->u.generic_ip)].node;
                i = ((u32)(long)inode->u.generic_ip) >> 16;
-               if ((u16)((long)inode->u.generic_ip) == aliases) {
+               if (ptr_nod(inode->u.generic_ip) == aliases) {
                        if (i >= aliases_nodes)
                                p = NULL;
                        else
@@ -111,7 +116,7 @@ static ssize_t property_read(struct file *filp, char __user *buf,
                        return -EIO;
                i = prom_getproplen (node, p);
                if (i < 0) {
-                       if ((u16)((long)inode->u.generic_ip) == aliases)
+                       if (ptr_nod(inode->u.generic_ip) == aliases)
                                i = 0;
                        else
                                return -EIO;
@@ -123,7 +128,7 @@ static ssize_t property_read(struct file *filp, char __user *buf,
                                              GFP_KERNEL);
                if (!filp->private_data)
                        return -ENOMEM;
-               op = (openprom_property *)filp->private_data;
+               op = filp->private_data;
                op->flag = 0;
                op->alloclen = 2 * i;
                strcpy (op->name, p);
@@ -163,7 +168,7 @@ static ssize_t property_read(struct file *filp, char __user *buf,
                                op->len--;
                }
        } else
-               op = (openprom_property *)filp->private_data;
+               op = filp->private_data;
        if (!count || !(op->len || (op->flag & OPP_ASCIIZ)))
                return 0;
        if (*ppos >= 0xffffff || count >= 0xffffff)
@@ -335,7 +340,7 @@ static ssize_t property_write(struct file *filp, const char __user *buf,
                        return i;
        }
        k = *ppos;
-       op = (openprom_property *)filp->private_data;
+       op = filp->private_data;
        if (!(op->flag & OPP_STRING)) {
                u32 *first, *last;
                int first_off, last_cnt;
@@ -388,13 +393,13 @@ static ssize_t property_write(struct file *filp, const char __user *buf,
                        memcpy (b, filp->private_data,
                                sizeof (openprom_property)
                                + strlen (op->name) + op->alloclen);
-                       memset (((char *)b) + sizeof (openprom_property)
+                       memset (b + sizeof (openprom_property)
                                + strlen (op->name) + op->alloclen, 
                                0, 2 * i - op->alloclen);
-                       op = (openprom_property *)b;
+                       op = b;
                        op->alloclen = 2*i;
                        b = filp->private_data;
-                       filp->private_data = (void *)op;
+                       filp->private_data = op;
                        kfree (b);
                }
                first = ((u32 *)op->value) + (k / 9);
@@ -448,10 +453,11 @@ static ssize_t property_write(struct file *filp, const char __user *buf,
                                        *q |= simple_strtoul (tmp, NULL, 16);
                                        buf += last_cnt;
                                } else {
-                                       char tchars[17]; /* XXX yuck... */
+                                       char tchars[2 * sizeof(long) + 1];
 
-                                       if (copy_from_user(tchars, buf, 16))
+                                       if (copy_from_user(tchars, buf, sizeof(tchars) - 1))
                                                return -EFAULT;
+                                        tchars[sizeof(tchars) - 1] = '\0';
                                        *q = simple_strtoul (tchars, NULL, 16);
                                        buf += 9;
                                }
@@ -497,13 +503,13 @@ write_try_string:
                        memcpy (b, filp->private_data,
                                sizeof (openprom_property)
                                + strlen (op->name) + op->alloclen);
-                       memset (((char *)b) + sizeof (openprom_property)
+                       memset (b + sizeof (openprom_property)
                                + strlen (op->name) + op->alloclen, 
                                0, 2*(count - *ppos) - op->alloclen);
-                       op = (openprom_property *)b;
+                       op = b;
                        op->alloclen = 2*(count + *ppos);
                        b = filp->private_data;
-                       filp->private_data = (void *)op;
+                       filp->private_data = op;
                        kfree (b);
                }
                p = op->value + *ppos - ((op->flag & OPP_QUOTED) ? 1 : 0);
@@ -532,15 +538,15 @@ write_try_string:
 
 int property_release (struct inode *inode, struct file *filp)
 {
-       openprom_property *op = (openprom_property *)filp->private_data;
+       openprom_property *op = filp->private_data;
        int error;
        u32 node;
        
        if (!op)
                return 0;
        lock_kernel();
-       node = nodes[(u16)((long)inode->u.generic_ip)].node;
-       if ((u16)((long)inode->u.generic_ip) == aliases) {
+       node = nodes[ptr_nod(inode->u.generic_ip)].node;
+       if (ptr_nod(inode->u.generic_ip) == aliases) {
                if ((op->flag & OPP_DIRTY) && (op->flag & OPP_STRING)) {
                        char *p = op->name;
                        int i = (op->value - op->name) - strlen (op->name) - 1;
@@ -931,7 +937,7 @@ static int __init check_space (u16 n)
                        return -1;
 
                if (nodes) {
-                       memcpy ((char *)pages, (char *)nodes,
+                       memcpy ((char *)pages, nodes,
                                (1 << alloced) * PAGE_SIZE);
                        free_pages ((unsigned long)nodes, alloced);
                }
index 9c4f0f2604f1e3435679bd0d55499979321edf7c..33b72ba0f86f45790bd7661053266cd8336c9757 100644 (file)
@@ -746,9 +746,9 @@ out_fds:
 asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,
                        long timeout_msecs)
 {
-       s64 timeout_jiffies = 0;
+       s64 timeout_jiffies;
 
-       if (timeout_msecs) {
+       if (timeout_msecs > 0) {
 #if HZ > 1000
                /* We can only overflow if HZ > 1000 */
                if (timeout_msecs / 1000 > (s64)0x7fffffffffffffffULL / (s64)HZ)
@@ -756,6 +756,9 @@ asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,
                else
 #endif
                        timeout_jiffies = msecs_to_jiffies(timeout_msecs);
+       } else {
+               /* Infinite (< 0) or no (0) timeout */
+               timeout_jiffies = timeout_msecs;
        }
 
        return do_sys_poll(ufds, nfds, &timeout_jiffies);
index 481a97a423fa5270c1eaa6c2ae4b2db54ad24522..3f71384020cb8976962c8e1e3322810a36c579bf 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/smp_lock.h>
 #include <linux/module.h>
 #include <linux/net.h>
+#include <linux/kthread.h>
 #include <net/ip.h>
 
 #include <linux/smb_fs.h>
@@ -40,7 +41,7 @@ enum smbiod_state {
 };
 
 static enum smbiod_state smbiod_state = SMBIOD_DEAD;
-static pid_t smbiod_pid;
+static struct task_struct *smbiod_thread;
 static DECLARE_WAIT_QUEUE_HEAD(smbiod_wait);
 static LIST_HEAD(smb_servers);
 static DEFINE_SPINLOCK(servers_lock);
@@ -67,20 +68,29 @@ void smbiod_wake_up(void)
  */
 static int smbiod_start(void)
 {
-       pid_t pid;
+       struct task_struct *tsk;
+       int err = 0;
+
        if (smbiod_state != SMBIOD_DEAD)
                return 0;
        smbiod_state = SMBIOD_STARTING;
        __module_get(THIS_MODULE);
        spin_unlock(&servers_lock);
-       pid = kernel_thread(smbiod, NULL, 0);
-       if (pid < 0)
+       tsk = kthread_run(smbiod, NULL, "smbiod");
+       if (IS_ERR(tsk)) {
+               err = PTR_ERR(tsk);
                module_put(THIS_MODULE);
+       }
 
        spin_lock(&servers_lock);
-       smbiod_state = pid < 0 ? SMBIOD_DEAD : SMBIOD_RUNNING;
-       smbiod_pid = pid;
-       return pid;
+       if (err < 0) {
+               smbiod_state = SMBIOD_DEAD;
+               smbiod_thread = NULL;
+       } else {
+               smbiod_state = SMBIOD_RUNNING;
+               smbiod_thread = tsk;
+       }
+       return err;
 }
 
 /*
@@ -290,8 +300,6 @@ out:
  */
 static int smbiod(void *unused)
 {
-       daemonize("smbiod");
-
        allow_signal(SIGKILL);
 
        VERBOSE("SMB Kernel thread starting (%d) ...\n", current->pid);
index 3ada9dcf55b8bd86046a95812d6ad918b9a00f2f..95b878e5c7a077783f4971abae30cf9794c91442 100644 (file)
 #include "swab.h"
 #include "util.h"
 
-#undef UFS_BALLOC_DEBUG
-
-#ifdef UFS_BALLOC_DEBUG
-#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
 static unsigned ufs_add_fragments (struct inode *, unsigned, unsigned, unsigned, int *);
 static unsigned ufs_alloc_fragments (struct inode *, unsigned, unsigned, unsigned, int *);
 static unsigned ufs_alloccg_block (struct inode *, struct ufs_cg_private_info *, unsigned, int *);
@@ -39,7 +31,8 @@ static void ufs_clusteracct(struct super_block *, struct ufs_cg_private_info *,
 /*
  * Free 'count' fragments from fragment number 'fragment'
  */
-void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count) {
+void ufs_free_fragments(struct inode *inode, unsigned fragment, unsigned count)
+{
        struct super_block * sb;
        struct ufs_sb_private_info * uspi;
        struct ufs_super_block_first * usb1;
@@ -51,7 +44,7 @@ void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count
        uspi = UFS_SB(sb)->s_uspi;
        usb1 = ubh_get_usb_first(uspi);
        
-       UFSD(("ENTER, fragment %u, count %u\n", fragment, count))
+       UFSD("ENTER, fragment %u, count %u\n", fragment, count);
        
        if (ufs_fragnum(fragment) + count > uspi->s_fpg)
                ufs_error (sb, "ufs_free_fragments", "internal error");
@@ -68,7 +61,7 @@ void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count
        ucpi = ufs_load_cylinder (sb, cgno);
        if (!ucpi) 
                goto failed;
-       ucg = ubh_get_ucg (UCPI_UBH);
+       ucg = ubh_get_ucg (UCPI_UBH(ucpi));
        if (!ufs_cg_chkmagic(sb, ucg)) {
                ufs_panic (sb, "ufs_free_fragments", "internal error, bad magic number on cg %u", cgno);
                goto failed;
@@ -76,11 +69,11 @@ void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count
 
        end_bit = bit + count;
        bbase = ufs_blknum (bit);
-       blkmap = ubh_blkmap (UCPI_UBH, ucpi->c_freeoff, bbase);
+       blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase);
        ufs_fragacct (sb, blkmap, ucg->cg_frsum, -1);
        for (i = bit; i < end_bit; i++) {
-               if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, i))
-                       ubh_setbit (UCPI_UBH, ucpi->c_freeoff, i);
+               if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, i))
+                       ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, i);
                else 
                        ufs_error (sb, "ufs_free_fragments",
                                   "bit already cleared for fragment %u", i);
@@ -90,51 +83,52 @@ void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count
 
        
        fs32_add(sb, &ucg->cg_cs.cs_nffree, count);
-       fs32_add(sb, &usb1->fs_cstotal.cs_nffree, count);
+       uspi->cs_total.cs_nffree += count;
        fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
-       blkmap = ubh_blkmap (UCPI_UBH, ucpi->c_freeoff, bbase);
+       blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase);
        ufs_fragacct(sb, blkmap, ucg->cg_frsum, 1);
 
        /*
         * Trying to reassemble free fragments into block
         */
        blkno = ufs_fragstoblks (bbase);
-       if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, blkno)) {
+       if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
                fs32_sub(sb, &ucg->cg_cs.cs_nffree, uspi->s_fpb);
-               fs32_sub(sb, &usb1->fs_cstotal.cs_nffree, uspi->s_fpb);
+               uspi->cs_total.cs_nffree -= uspi->s_fpb;
                fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, uspi->s_fpb);
                if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
                        ufs_clusteracct (sb, ucpi, blkno, 1);
                fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
-               fs32_add(sb, &usb1->fs_cstotal.cs_nbfree, 1);
+               uspi->cs_total.cs_nbfree++;
                fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
                cylno = ufs_cbtocylno (bbase);
                fs16_add(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(bbase)), 1);
                fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1);
        }
        
-       ubh_mark_buffer_dirty (USPI_UBH);
-       ubh_mark_buffer_dirty (UCPI_UBH);
+       ubh_mark_buffer_dirty (USPI_UBH(uspi));
+       ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
        if (sb->s_flags & MS_SYNCHRONOUS) {
-               ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
-               ubh_wait_on_buffer (UCPI_UBH);
+               ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
+               ubh_wait_on_buffer (UCPI_UBH(ucpi));
        }
        sb->s_dirt = 1;
        
        unlock_super (sb);
-       UFSD(("EXIT\n"))
+       UFSD("EXIT\n");
        return;
 
 failed:
        unlock_super (sb);
-       UFSD(("EXIT (FAILED)\n"))
+       UFSD("EXIT (FAILED)\n");
        return;
 }
 
 /*
  * Free 'count' fragments from fragment number 'fragment' (free whole blocks)
  */
-void ufs_free_blocks (struct inode * inode, unsigned fragment, unsigned count) {
+void ufs_free_blocks(struct inode *inode, unsigned fragment, unsigned count)
+{
        struct super_block * sb;
        struct ufs_sb_private_info * uspi;
        struct ufs_super_block_first * usb1;
@@ -146,7 +140,7 @@ void ufs_free_blocks (struct inode * inode, unsigned fragment, unsigned count) {
        uspi = UFS_SB(sb)->s_uspi;
        usb1 = ubh_get_usb_first(uspi);
 
-       UFSD(("ENTER, fragment %u, count %u\n", fragment, count))
+       UFSD("ENTER, fragment %u, count %u\n", fragment, count);
        
        if ((fragment & uspi->s_fpbmask) || (count & uspi->s_fpbmask)) {
                ufs_error (sb, "ufs_free_blocks", "internal error, "
@@ -162,7 +156,7 @@ do_more:
        bit = ufs_dtogd (fragment);
        if (cgno >= uspi->s_ncg) {
                ufs_panic (sb, "ufs_free_blocks", "freeing blocks are outside device");
-               goto failed;
+               goto failed_unlock;
        }
        end_bit = bit + count;
        if (end_bit > uspi->s_fpg) {
@@ -173,36 +167,36 @@ do_more:
 
        ucpi = ufs_load_cylinder (sb, cgno);
        if (!ucpi) 
-               goto failed;
-       ucg = ubh_get_ucg (UCPI_UBH);
+               goto failed_unlock;
+       ucg = ubh_get_ucg (UCPI_UBH(ucpi));
        if (!ufs_cg_chkmagic(sb, ucg)) {
                ufs_panic (sb, "ufs_free_blocks", "internal error, bad magic number on cg %u", cgno);
-               goto failed;
+               goto failed_unlock;
        }
 
        for (i = bit; i < end_bit; i += uspi->s_fpb) {
                blkno = ufs_fragstoblks(i);
-               if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, blkno)) {
+               if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
                        ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
                }
-               ubh_setblock(UCPI_UBH, ucpi->c_freeoff, blkno);
+               ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
                if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
                        ufs_clusteracct (sb, ucpi, blkno, 1);
                DQUOT_FREE_BLOCK(inode, uspi->s_fpb);
 
                fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
-               fs32_add(sb, &usb1->fs_cstotal.cs_nbfree, 1);
+               uspi->cs_total.cs_nbfree++;
                fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
                cylno = ufs_cbtocylno(i);
                fs16_add(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(i)), 1);
                fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1);
        }
 
-       ubh_mark_buffer_dirty (USPI_UBH);
-       ubh_mark_buffer_dirty (UCPI_UBH);
+       ubh_mark_buffer_dirty (USPI_UBH(uspi));
+       ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
        if (sb->s_flags & MS_SYNCHRONOUS) {
-               ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
-               ubh_wait_on_buffer (UCPI_UBH);
+               ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
+               ubh_wait_on_buffer (UCPI_UBH(ucpi));
        }
 
        if (overflow) {
@@ -213,38 +207,127 @@ do_more:
 
        sb->s_dirt = 1;
        unlock_super (sb);
-       UFSD(("EXIT\n"))
+       UFSD("EXIT\n");
        return;
 
-failed:
+failed_unlock:
        unlock_super (sb);
-       UFSD(("EXIT (FAILED)\n"))
+failed:
+       UFSD("EXIT (FAILED)\n");
        return;
 }
 
+static struct page *ufs_get_locked_page(struct address_space *mapping,
+                                 unsigned long index)
+{
+       struct page *page;
+
+try_again:
+       page = find_lock_page(mapping, index);
+       if (!page) {
+               page = read_cache_page(mapping, index,
+                                      (filler_t*)mapping->a_ops->readpage,
+                                      NULL);
+               if (IS_ERR(page)) {
+                       printk(KERN_ERR "ufs_change_blocknr: "
+                              "read_cache_page error: ino %lu, index: %lu\n",
+                              mapping->host->i_ino, index);
+                       goto out;
+               }
 
+               lock_page(page);
 
-#define NULLIFY_FRAGMENTS \
-       for (i = oldcount; i < newcount; i++) { \
-               bh = sb_getblk(sb, result + i); \
-               memset (bh->b_data, 0, sb->s_blocksize); \
-               set_buffer_uptodate(bh); \
-               mark_buffer_dirty (bh); \
-               if (IS_SYNC(inode)) \
-                       sync_dirty_buffer(bh); \
-               brelse (bh); \
+               if (!PageUptodate(page) || PageError(page)) {
+                       unlock_page(page);
+                       page_cache_release(page);
+
+                       printk(KERN_ERR "ufs_change_blocknr: "
+                              "can not read page: ino %lu, index: %lu\n",
+                              mapping->host->i_ino, index);
+
+                       page = ERR_PTR(-EIO);
+                       goto out;
+               }
        }
 
-unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment,
-       unsigned goal, unsigned count, int * err )
+       if (unlikely(!page->mapping || !page_has_buffers(page))) {
+               unlock_page(page);
+               page_cache_release(page);
+               goto try_again;/*we really need these buffers*/
+       }
+out:
+       return page;
+}
+
+/*
+ * Modify inode page cache in such way:
+ * have - blocks with b_blocknr equal to oldb...oldb+count-1
+ * get - blocks with b_blocknr equal to newb...newb+count-1
+ * also we suppose that oldb...oldb+count-1 blocks
+ * situated at the end of file.
+ *
+ * We can come here from ufs_writepage or ufs_prepare_write,
+ * locked_page is argument of these functions, so we already lock it.
+ */
+static void ufs_change_blocknr(struct inode *inode, unsigned int baseblk,
+                              unsigned int count, unsigned int oldb,
+                              unsigned int newb, struct page *locked_page)
+{
+       unsigned int blk_per_page = 1 << (PAGE_CACHE_SHIFT - inode->i_blkbits);
+       struct address_space *mapping = inode->i_mapping;
+       pgoff_t index, cur_index = locked_page->index;
+       unsigned int i, j;
+       struct page *page;
+       struct buffer_head *head, *bh;
+
+       UFSD("ENTER, ino %lu, count %u, oldb %u, newb %u\n",
+             inode->i_ino, count, oldb, newb);
+
+       BUG_ON(!PageLocked(locked_page));
+
+       for (i = 0; i < count; i += blk_per_page) {
+               index = (baseblk+i) >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
+
+               if (likely(cur_index != index)) {
+                       page = ufs_get_locked_page(mapping, index);
+                       if (IS_ERR(page))
+                               continue;
+               } else
+                       page = locked_page;
+
+               j = i;
+               head = page_buffers(page);
+               bh = head;
+               do {
+                       if (likely(bh->b_blocknr == j + oldb && j < count)) {
+                               unmap_underlying_metadata(bh->b_bdev,
+                                                         bh->b_blocknr);
+                               bh->b_blocknr = newb + j++;
+                               mark_buffer_dirty(bh);
+                       }
+
+                       bh = bh->b_this_page;
+               } while (bh != head);
+
+               set_page_dirty(page);
+
+               if (likely(cur_index != index)) {
+                       unlock_page(page);
+                       page_cache_release(page);
+               }
+       }
+       UFSD("EXIT\n");
+}
+
+unsigned ufs_new_fragments(struct inode * inode, __fs32 * p, unsigned fragment,
+                          unsigned goal, unsigned count, int * err, struct page *locked_page)
 {
        struct super_block * sb;
        struct ufs_sb_private_info * uspi;
        struct ufs_super_block_first * usb1;
-       struct buffer_head * bh;
-       unsigned cgno, oldcount, newcount, tmp, request, i, result;
+       unsigned cgno, oldcount, newcount, tmp, request, result;
        
-       UFSD(("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count))
+       UFSD("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count);
        
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
@@ -273,14 +356,14 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment,
                        return (unsigned)-1;
                }
                if (fragment < UFS_I(inode)->i_lastfrag) {
-                       UFSD(("EXIT (ALREADY ALLOCATED)\n"))
+                       UFSD("EXIT (ALREADY ALLOCATED)\n");
                        unlock_super (sb);
                        return 0;
                }
        }
        else {
                if (tmp) {
-                       UFSD(("EXIT (ALREADY ALLOCATED)\n"))
+                       UFSD("EXIT (ALREADY ALLOCATED)\n");
                        unlock_super(sb);
                        return 0;
                }
@@ -289,9 +372,9 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment,
        /*
         * There is not enough space for user on the device
         */
-       if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(usb1, UFS_MINFREE) <= 0) {
+       if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(uspi, UFS_MINFREE) <= 0) {
                unlock_super (sb);
-               UFSD(("EXIT (FAILED)\n"))
+               UFSD("EXIT (FAILED)\n");
                return 0;
        }
 
@@ -310,12 +393,10 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment,
                if (result) {
                        *p = cpu_to_fs32(sb, result);
                        *err = 0;
-                       inode->i_blocks += count << uspi->s_nspfshift;
                        UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
-                       NULLIFY_FRAGMENTS
                }
                unlock_super(sb);
-               UFSD(("EXIT, result %u\n", result))
+               UFSD("EXIT, result %u\n", result);
                return result;
        }
 
@@ -325,11 +406,9 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment,
        result = ufs_add_fragments (inode, tmp, oldcount, newcount, err);
        if (result) {
                *err = 0;
-               inode->i_blocks += count << uspi->s_nspfshift;
                UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
-               NULLIFY_FRAGMENTS
                unlock_super(sb);
-               UFSD(("EXIT, result %u\n", result))
+               UFSD("EXIT, result %u\n", result);
                return result;
        }
 
@@ -339,8 +418,8 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment,
        switch (fs32_to_cpu(sb, usb1->fs_optim)) {
            case UFS_OPTSPACE:
                request = newcount;
-               if (uspi->s_minfree < 5 || fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree) 
-                   > uspi->s_dsize * uspi->s_minfree / (2 * 100) )
+               if (uspi->s_minfree < 5 || uspi->cs_total.cs_nffree
+                   > uspi->s_dsize * uspi->s_minfree / (2 * 100))
                        break;
                usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
                break;
@@ -349,7 +428,7 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment,
        
            case UFS_OPTTIME:
                request = uspi->s_fpb;
-               if (fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree) < uspi->s_dsize *
+               if (uspi->cs_total.cs_nffree < uspi->s_dsize *
                    (uspi->s_minfree - 2) / 100)
                        break;
                usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
@@ -357,39 +436,22 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment,
        }
        result = ufs_alloc_fragments (inode, cgno, goal, request, err);
        if (result) {
-               for (i = 0; i < oldcount; i++) {
-                       bh = sb_bread(sb, tmp + i);
-                       if(bh)
-                       {
-                               clear_buffer_dirty(bh);
-                               bh->b_blocknr = result + i;
-                               mark_buffer_dirty (bh);
-                               if (IS_SYNC(inode))
-                                       sync_dirty_buffer(bh);
-                               brelse (bh);
-                       }
-                       else
-                       {
-                               printk(KERN_ERR "ufs_new_fragments: bread fail\n");
-                               unlock_super(sb);
-                               return 0;
-                       }
-               }
+               ufs_change_blocknr(inode, fragment - oldcount, oldcount, tmp,
+                                  result, locked_page);
+
                *p = cpu_to_fs32(sb, result);
                *err = 0;
-               inode->i_blocks += count << uspi->s_nspfshift;
                UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
-               NULLIFY_FRAGMENTS
                unlock_super(sb);
                if (newcount < request)
                        ufs_free_fragments (inode, result + newcount, request - newcount);
                ufs_free_fragments (inode, tmp, oldcount);
-               UFSD(("EXIT, result %u\n", result))
+               UFSD("EXIT, result %u\n", result);
                return result;
        }
 
        unlock_super(sb);
-       UFSD(("EXIT (FAILED)\n"))
+       UFSD("EXIT (FAILED)\n");
        return 0;
 }              
 
@@ -404,7 +466,7 @@ ufs_add_fragments (struct inode * inode, unsigned fragment,
        struct ufs_cylinder_group * ucg;
        unsigned cgno, fragno, fragoff, count, fragsize, i;
        
-       UFSD(("ENTER, fragment %u, oldcount %u, newcount %u\n", fragment, oldcount, newcount))
+       UFSD("ENTER, fragment %u, oldcount %u, newcount %u\n", fragment, oldcount, newcount);
        
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
@@ -419,7 +481,7 @@ ufs_add_fragments (struct inode * inode, unsigned fragment,
        ucpi = ufs_load_cylinder (sb, cgno);
        if (!ucpi)
                return 0;
-       ucg = ubh_get_ucg (UCPI_UBH);
+       ucg = ubh_get_ucg (UCPI_UBH(ucpi));
        if (!ufs_cg_chkmagic(sb, ucg)) {
                ufs_panic (sb, "ufs_add_fragments",
                        "internal error, bad magic number on cg %u", cgno);
@@ -429,14 +491,14 @@ ufs_add_fragments (struct inode * inode, unsigned fragment,
        fragno = ufs_dtogd (fragment);
        fragoff = ufs_fragnum (fragno);
        for (i = oldcount; i < newcount; i++)
-               if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, fragno + i))
+               if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
                        return 0;
        /*
         * Block can be extended
         */
        ucg->cg_time = cpu_to_fs32(sb, get_seconds());
        for (i = newcount; i < (uspi->s_fpb - fragoff); i++)
-               if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, fragno + i))
+               if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
                        break;
        fragsize = i - oldcount;
        if (!fs32_to_cpu(sb, ucg->cg_frsum[fragsize]))
@@ -446,7 +508,7 @@ ufs_add_fragments (struct inode * inode, unsigned fragment,
        if (fragsize != count)
                fs32_add(sb, &ucg->cg_frsum[fragsize - count], 1);
        for (i = oldcount; i < newcount; i++)
-               ubh_clrbit (UCPI_UBH, ucpi->c_freeoff, fragno + i);
+               ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i);
        if(DQUOT_ALLOC_BLOCK(inode, count)) {
                *err = -EDQUOT;
                return 0;
@@ -454,17 +516,17 @@ ufs_add_fragments (struct inode * inode, unsigned fragment,
 
        fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
        fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
-       fs32_sub(sb, &usb1->fs_cstotal.cs_nffree, count);
+       uspi->cs_total.cs_nffree -= count;
        
-       ubh_mark_buffer_dirty (USPI_UBH);
-       ubh_mark_buffer_dirty (UCPI_UBH);
+       ubh_mark_buffer_dirty (USPI_UBH(uspi));
+       ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
        if (sb->s_flags & MS_SYNCHRONOUS) {
-               ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
-               ubh_wait_on_buffer (UCPI_UBH);
+               ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
+               ubh_wait_on_buffer (UCPI_UBH(ucpi));
        }
        sb->s_dirt = 1;
 
-       UFSD(("EXIT, fragment %u\n", fragment))
+       UFSD("EXIT, fragment %u\n", fragment);
        
        return fragment;
 }
@@ -487,7 +549,7 @@ static unsigned ufs_alloc_fragments (struct inode * inode, unsigned cgno,
        struct ufs_cylinder_group * ucg;
        unsigned oldcg, i, j, k, result, allocsize;
        
-       UFSD(("ENTER, ino %lu, cgno %u, goal %u, count %u\n", inode->i_ino, cgno, goal, count))
+       UFSD("ENTER, ino %lu, cgno %u, goal %u, count %u\n", inode->i_ino, cgno, goal, count);
 
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
@@ -521,14 +583,14 @@ static unsigned ufs_alloc_fragments (struct inode * inode, unsigned cgno,
                UFS_TEST_FREE_SPACE_CG
        }
        
-       UFSD(("EXIT (FAILED)\n"))
+       UFSD("EXIT (FAILED)\n");
        return 0;
 
 cg_found:
        ucpi = ufs_load_cylinder (sb, cgno);
        if (!ucpi)
                return 0;
-       ucg = ubh_get_ucg (UCPI_UBH);
+       ucg = ubh_get_ucg (UCPI_UBH(ucpi));
        if (!ufs_cg_chkmagic(sb, ucg)) 
                ufs_panic (sb, "ufs_alloc_fragments",
                        "internal error, bad magic number on cg %u", cgno);
@@ -551,12 +613,12 @@ cg_found:
                        return 0;
                goal = ufs_dtogd (result);
                for (i = count; i < uspi->s_fpb; i++)
-                       ubh_setbit (UCPI_UBH, ucpi->c_freeoff, goal + i);
+                       ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i);
                i = uspi->s_fpb - count;
                DQUOT_FREE_BLOCK(inode, i);
 
                fs32_add(sb, &ucg->cg_cs.cs_nffree, i);
-               fs32_add(sb, &usb1->fs_cstotal.cs_nffree, i);
+               uspi->cs_total.cs_nffree += i;
                fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, i);
                fs32_add(sb, &ucg->cg_frsum[i], 1);
                goto succed;
@@ -570,10 +632,10 @@ cg_found:
                return 0;
        }
        for (i = 0; i < count; i++)
-               ubh_clrbit (UCPI_UBH, ucpi->c_freeoff, result + i);
+               ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, result + i);
        
        fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
-       fs32_sub(sb, &usb1->fs_cstotal.cs_nffree, count);
+       uspi->cs_total.cs_nffree -= count;
        fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
        fs32_sub(sb, &ucg->cg_frsum[allocsize], 1);
 
@@ -581,16 +643,16 @@ cg_found:
                fs32_add(sb, &ucg->cg_frsum[allocsize - count], 1);
 
 succed:
-       ubh_mark_buffer_dirty (USPI_UBH);
-       ubh_mark_buffer_dirty (UCPI_UBH);
+       ubh_mark_buffer_dirty (USPI_UBH(uspi));
+       ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
        if (sb->s_flags & MS_SYNCHRONOUS) {
-               ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
-               ubh_wait_on_buffer (UCPI_UBH);
+               ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
+               ubh_wait_on_buffer (UCPI_UBH(ucpi));
        }
        sb->s_dirt = 1;
 
        result += cgno * uspi->s_fpg;
-       UFSD(("EXIT3, result %u\n", result))
+       UFSD("EXIT3, result %u\n", result);
        return result;
 }
 
@@ -603,12 +665,12 @@ static unsigned ufs_alloccg_block (struct inode * inode,
        struct ufs_cylinder_group * ucg;
        unsigned result, cylno, blkno;
 
-       UFSD(("ENTER, goal %u\n", goal))
+       UFSD("ENTER, goal %u\n", goal);
 
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
        usb1 = ubh_get_usb_first(uspi);
-       ucg = ubh_get_ucg(UCPI_UBH);
+       ucg = ubh_get_ucg(UCPI_UBH(ucpi));
 
        if (goal == 0) {
                goal = ucpi->c_rotor;
@@ -620,7 +682,7 @@ static unsigned ufs_alloccg_block (struct inode * inode,
        /*
         * If the requested block is available, use it.
         */
-       if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, ufs_fragstoblks(goal))) {
+       if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, ufs_fragstoblks(goal))) {
                result = goal;
                goto gotit;
        }
@@ -632,7 +694,7 @@ norot:
        ucpi->c_rotor = result;
 gotit:
        blkno = ufs_fragstoblks(result);
-       ubh_clrblock (UCPI_UBH, ucpi->c_freeoff, blkno);
+       ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
        if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
                ufs_clusteracct (sb, ucpi, blkno, -1);
        if(DQUOT_ALLOC_BLOCK(inode, uspi->s_fpb)) {
@@ -641,31 +703,76 @@ gotit:
        }
 
        fs32_sub(sb, &ucg->cg_cs.cs_nbfree, 1);
-       fs32_sub(sb, &usb1->fs_cstotal.cs_nbfree, 1);
+       uspi->cs_total.cs_nbfree--;
        fs32_sub(sb, &UFS_SB(sb)->fs_cs(ucpi->c_cgx).cs_nbfree, 1);
        cylno = ufs_cbtocylno(result);
        fs16_sub(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(result)), 1);
        fs32_sub(sb, &ubh_cg_blktot(ucpi, cylno), 1);
        
-       UFSD(("EXIT, result %u\n", result))
+       UFSD("EXIT, result %u\n", result);
 
        return result;
 }
 
-static unsigned ufs_bitmap_search (struct super_block * sb,
-       struct ufs_cg_private_info * ucpi, unsigned goal, unsigned count)
+static unsigned ubh_scanc(struct ufs_sb_private_info *uspi,
+                         struct ufs_buffer_head *ubh,
+                         unsigned begin, unsigned size,
+                         unsigned char *table, unsigned char mask)
 {
-       struct ufs_sb_private_info * uspi;
-       struct ufs_super_block_first * usb1;
-       struct ufs_cylinder_group * ucg;
-       unsigned start, length, location, result;
-       unsigned possition, fragsize, blockmap, mask;
-       
-       UFSD(("ENTER, cg %u, goal %u, count %u\n", ucpi->c_cgx, goal, count))
+       unsigned rest, offset;
+       unsigned char *cp;
+       
+
+       offset = begin & ~uspi->s_fmask;
+       begin >>= uspi->s_fshift;
+       for (;;) {
+               if ((offset + size) < uspi->s_fsize)
+                       rest = size;
+               else
+                       rest = uspi->s_fsize - offset;
+               size -= rest;
+               cp = ubh->bh[begin]->b_data + offset;
+               while ((table[*cp++] & mask) == 0 && --rest)
+                       ;
+               if (rest || !size)
+                       break;
+               begin++;
+               offset = 0;
+       }
+       return (size + rest);
+}
+
+/*
+ * Find a block of the specified size in the specified cylinder group.
+ * @sp: pointer to super block
+ * @ucpi: pointer to cylinder group info
+ * @goal: near which block we want find new one
+ * @count: specified size
+ */
+static unsigned ufs_bitmap_search(struct super_block *sb,
+                                 struct ufs_cg_private_info *ucpi,
+                                 unsigned goal, unsigned count)
+{
+       /*
+        * Bit patterns for identifying fragments in the block map
+        * used as ((map & mask_arr) == want_arr)
+        */
+       static const int mask_arr[9] = {
+               0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff
+       };
+       static const int want_arr[9] = {
+               0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
+       };
+       struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
+       struct ufs_super_block_first *usb1;
+       struct ufs_cylinder_group *ucg;
+       unsigned start, length, loc, result;
+       unsigned pos, want, blockmap, mask, end;
+
+       UFSD("ENTER, cg %u, goal %u, count %u\n", ucpi->c_cgx, goal, count);
 
-       uspi = UFS_SB(sb)->s_uspi;
        usb1 = ubh_get_usb_first (uspi);
-       ucg = ubh_get_ucg(UCPI_UBH);
+       ucg = ubh_get_ucg(UCPI_UBH(ucpi));
 
        if (goal)
                start = ufs_dtogd(goal) >> 3;
@@ -673,53 +780,50 @@ static unsigned ufs_bitmap_search (struct super_block * sb,
                start = ucpi->c_frotor >> 3;
                
        length = ((uspi->s_fpg + 7) >> 3) - start;
-       location = ubh_scanc(UCPI_UBH, ucpi->c_freeoff + start, length,
+       loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff + start, length,
                (uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
                1 << (count - 1 + (uspi->s_fpb & 7))); 
-       if (location == 0) {
+       if (loc == 0) {
                length = start + 1;
-               location = ubh_scanc(UCPI_UBH, ucpi->c_freeoff, length, 
-                       (uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
-                       1 << (count - 1 + (uspi->s_fpb & 7)));
-               if (location == 0) {
-                       ufs_error (sb, "ufs_bitmap_search",
-                       "bitmap corrupted on cg %u, start %u, length %u, count %u, freeoff %u\n",
-                       ucpi->c_cgx, start, length, count, ucpi->c_freeoff);
+               loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, length,
+                               (uspi->s_fpb == 8) ? ufs_fragtable_8fpb :
+                               ufs_fragtable_other,
+                               1 << (count - 1 + (uspi->s_fpb & 7)));
+               if (loc == 0) {
+                       ufs_error(sb, "ufs_bitmap_search",
+                                 "bitmap corrupted on cg %u, start %u,"
+                                 " length %u, count %u, freeoff %u\n",
+                                 ucpi->c_cgx, start, length, count,
+                                 ucpi->c_freeoff);
                        return (unsigned)-1;
                }
                start = 0;
        }
-       result = (start + length - location) << 3;
+       result = (start + length - loc) << 3;
        ucpi->c_frotor = result;
 
        /*
         * found the byte in the map
         */
-       blockmap = ubh_blkmap(UCPI_UBH, ucpi->c_freeoff, result);
-       fragsize = 0;
-       for (possition = 0, mask = 1; possition < 8; possition++, mask <<= 1) {
-               if (blockmap & mask) {
-                       if (!(possition & uspi->s_fpbmask))
-                               fragsize = 1;
-                       else 
-                               fragsize++;
-               }
-               else {
-                       if (fragsize == count) {
-                               result += possition - count;
-                               UFSD(("EXIT, result %u\n", result))
-                               return result;
-                       }
-                       fragsize = 0;
-               }
-       }
-       if (fragsize == count) {
-               result += possition - count;
-               UFSD(("EXIT, result %u\n", result))
-               return result;
-       }
-       ufs_error (sb, "ufs_bitmap_search", "block not in map on cg %u\n", ucpi->c_cgx);
-       UFSD(("EXIT (FAILED)\n"))
+
+       for (end = result + 8; result < end; result += uspi->s_fpb) {
+               blockmap = ubh_blkmap(UCPI_UBH(ucpi), ucpi->c_freeoff, result);
+               blockmap <<= 1;
+               mask = mask_arr[count];
+               want = want_arr[count];
+               for (pos = 0; pos <= uspi->s_fpb - count; pos++) {
+                       if ((blockmap & mask) == want) {
+                               UFSD("EXIT, result %u\n", result);
+                               return result + pos;
+                       }
+                       mask <<= 1;
+                       want <<= 1;
+               }
+       }
+
+       ufs_error(sb, "ufs_bitmap_search", "block not in map on cg %u\n",
+                 ucpi->c_cgx);
+       UFSD("EXIT (FAILED)\n");
        return (unsigned)-1;
 }
 
@@ -734,9 +838,9 @@ static void ufs_clusteracct(struct super_block * sb,
                return;
 
        if (cnt > 0)
-               ubh_setbit(UCPI_UBH, ucpi->c_clusteroff, blkno);
+               ubh_setbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno);
        else
-               ubh_clrbit(UCPI_UBH, ucpi->c_clusteroff, blkno);
+               ubh_clrbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno);
 
        /*
         * Find the size of the cluster going forward.
@@ -745,7 +849,7 @@ static void ufs_clusteracct(struct super_block * sb,
        end = start + uspi->s_contigsumsize;
        if ( end >= ucpi->c_nclusterblks)
                end = ucpi->c_nclusterblks;
-       i = ubh_find_next_zero_bit (UCPI_UBH, ucpi->c_clusteroff, end, start);
+       i = ubh_find_next_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, end, start);
        if (i > end)
                i = end;
        forw = i - start;
@@ -757,7 +861,7 @@ static void ufs_clusteracct(struct super_block * sb,
        end = start - uspi->s_contigsumsize;
        if (end < 0 ) 
                end = -1;
-       i = ubh_find_last_zero_bit (UCPI_UBH, ucpi->c_clusteroff, start, end);
+       i = ubh_find_last_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, start, end);
        if ( i < end) 
                i = end;
        back = start - i;
@@ -769,11 +873,11 @@ static void ufs_clusteracct(struct super_block * sb,
        i = back + forw + 1;
        if (i > uspi->s_contigsumsize)
                i = uspi->s_contigsumsize;
-       fs32_add(sb, (__fs32*)ubh_get_addr(UCPI_UBH, ucpi->c_clustersumoff + (i << 2)), cnt);
+       fs32_add(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (i << 2)), cnt);
        if (back > 0)
-               fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH, ucpi->c_clustersumoff + (back << 2)), cnt);
+               fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (back << 2)), cnt);
        if (forw > 0)
-               fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH, ucpi->c_clustersumoff + (forw << 2)), cnt);
+               fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (forw << 2)), cnt);
 }
 
 
index 14abb8b835f77953854477d489035cbf86294700..09c39e5e638631a784faed8106835dbe7e49ff47 100644 (file)
 #include "swab.h"
 #include "util.h"
 
-#undef UFS_CYLINDER_DEBUG
-
-#ifdef UFS_CYLINDER_DEBUG
-#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
-
 /*
  * Read cylinder group into cache. The memory space for ufs_cg_private_info
  * structure is already allocated during ufs_read_super.
@@ -42,19 +33,19 @@ static void ufs_read_cylinder (struct super_block * sb,
        struct ufs_cylinder_group * ucg;
        unsigned i, j;
 
-       UFSD(("ENTER, cgno %u, bitmap_nr %u\n", cgno, bitmap_nr))
+       UFSD("ENTER, cgno %u, bitmap_nr %u\n", cgno, bitmap_nr);
        uspi = sbi->s_uspi;
        ucpi = sbi->s_ucpi[bitmap_nr];
        ucg = (struct ufs_cylinder_group *)sbi->s_ucg[cgno]->b_data;
 
-       UCPI_UBH->fragment = ufs_cgcmin(cgno);
-       UCPI_UBH->count = uspi->s_cgsize >> sb->s_blocksize_bits;
+       UCPI_UBH(ucpi)->fragment = ufs_cgcmin(cgno);
+       UCPI_UBH(ucpi)->count = uspi->s_cgsize >> sb->s_blocksize_bits;
        /*
         * We have already the first fragment of cylinder group block in buffer
         */
-       UCPI_UBH->bh[0] = sbi->s_ucg[cgno];
-       for (i = 1; i < UCPI_UBH->count; i++)
-               if (!(UCPI_UBH->bh[i] = sb_bread(sb, UCPI_UBH->fragment + i)))
+       UCPI_UBH(ucpi)->bh[0] = sbi->s_ucg[cgno];
+       for (i = 1; i < UCPI_UBH(ucpi)->count; i++)
+               if (!(UCPI_UBH(ucpi)->bh[i] = sb_bread(sb, UCPI_UBH(ucpi)->fragment + i)))
                        goto failed;
        sbi->s_cgno[bitmap_nr] = cgno;
                        
@@ -73,7 +64,7 @@ static void ufs_read_cylinder (struct super_block * sb,
        ucpi->c_clustersumoff = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_clustersumoff);
        ucpi->c_clusteroff = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_clusteroff);
        ucpi->c_nclusterblks = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_nclusterblks);
-       UFSD(("EXIT\n"))
+       UFSD("EXIT\n");
        return; 
        
 failed:
@@ -95,15 +86,15 @@ void ufs_put_cylinder (struct super_block * sb, unsigned bitmap_nr)
        struct ufs_cylinder_group * ucg;
        unsigned i;
 
-       UFSD(("ENTER, bitmap_nr %u\n", bitmap_nr))
+       UFSD("ENTER, bitmap_nr %u\n", bitmap_nr);
 
        uspi = sbi->s_uspi;
        if (sbi->s_cgno[bitmap_nr] == UFS_CGNO_EMPTY) {
-               UFSD(("EXIT\n"))
+               UFSD("EXIT\n");
                return;
        }
        ucpi = sbi->s_ucpi[bitmap_nr];
-       ucg = ubh_get_ucg(UCPI_UBH);
+       ucg = ubh_get_ucg(UCPI_UBH(ucpi));
 
        if (uspi->s_ncg > UFS_MAX_GROUP_LOADED && bitmap_nr >= sbi->s_cg_loaded) {
                ufs_panic (sb, "ufs_put_cylinder", "internal error");
@@ -116,13 +107,13 @@ void ufs_put_cylinder (struct super_block * sb, unsigned bitmap_nr)
        ucg->cg_rotor = cpu_to_fs32(sb, ucpi->c_rotor);
        ucg->cg_frotor = cpu_to_fs32(sb, ucpi->c_frotor);
        ucg->cg_irotor = cpu_to_fs32(sb, ucpi->c_irotor);
-       ubh_mark_buffer_dirty (UCPI_UBH);
-       for (i = 1; i < UCPI_UBH->count; i++) {
-               brelse (UCPI_UBH->bh[i]);
+       ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
+       for (i = 1; i < UCPI_UBH(ucpi)->count; i++) {
+               brelse (UCPI_UBH(ucpi)->bh[i]);
        }
 
        sbi->s_cgno[bitmap_nr] = UFS_CGNO_EMPTY;
-       UFSD(("EXIT\n"))
+       UFSD("EXIT\n");
 }
 
 /*
@@ -139,7 +130,7 @@ struct ufs_cg_private_info * ufs_load_cylinder (
        struct ufs_cg_private_info * ucpi;
        unsigned cg, i, j;
 
-       UFSD(("ENTER, cgno %u\n", cgno))
+       UFSD("ENTER, cgno %u\n", cgno);
 
        uspi = sbi->s_uspi;
        if (cgno >= uspi->s_ncg) {
@@ -150,7 +141,7 @@ struct ufs_cg_private_info * ufs_load_cylinder (
         * Cylinder group number cg it in cache and it was last used
         */
        if (sbi->s_cgno[0] == cgno) {
-               UFSD(("EXIT\n"))
+               UFSD("EXIT\n");
                return sbi->s_ucpi[0];
        }
        /*
@@ -160,16 +151,16 @@ struct ufs_cg_private_info * ufs_load_cylinder (
                if (sbi->s_cgno[cgno] != UFS_CGNO_EMPTY) {
                        if (sbi->s_cgno[cgno] != cgno) {
                                ufs_panic (sb, "ufs_load_cylinder", "internal error, wrong number of cg in cache");
-                               UFSD(("EXIT (FAILED)\n"))
+                               UFSD("EXIT (FAILED)\n");
                                return NULL;
                        }
                        else {
-                               UFSD(("EXIT\n"))
+                               UFSD("EXIT\n");
                                return sbi->s_ucpi[cgno];
                        }
                } else {
                        ufs_read_cylinder (sb, cgno, cgno);
-                       UFSD(("EXIT\n"))
+                       UFSD("EXIT\n");
                        return sbi->s_ucpi[cgno];
                }
        }
@@ -204,6 +195,6 @@ struct ufs_cg_private_info * ufs_load_cylinder (
                sbi->s_ucpi[0] = ucpi;
                ufs_read_cylinder (sb, cgno, 0);
        }
-       UFSD(("EXIT\n"))
+       UFSD("EXIT\n");
        return sbi->s_ucpi[0];
 }
index 1a561202d3f44d33712ebd9e95609a0a436f5e44..7f0a0aa63584e729d53d01177ed74a0372ea830a 100644 (file)
  * 4.4BSD (FreeBSD) support added on February 1st 1998 by
  * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
  * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
+ *
+ * Migration to usage of "page cache" on May 2006 by
+ * Evgeniy Dushistov <dushistov@mail.ru> based on ext2 code base.
  */
 
 #include <linux/time.h>
 #include <linux/fs.h>
 #include <linux/ufs_fs.h>
 #include <linux/smp_lock.h>
-#include <linux/buffer_head.h>
 #include <linux/sched.h>
 
 #include "swab.h"
 #include "util.h"
 
-#undef UFS_DIR_DEBUG
-
-#ifdef UFS_DIR_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
-static int
-ufs_check_dir_entry (const char *, struct inode *, struct ufs_dir_entry *,
-                    struct buffer_head *, unsigned long);
-
-
 /*
  * NOTE! unlike strncmp, ufs_match returns 1 for success, 0 for failure.
  *
@@ -51,495 +40,541 @@ static inline int ufs_match(struct super_block *sb, int len,
        return !memcmp(name, de->d_name, len);
 }
 
-/*
- * This is blatantly stolen from ext2fs
- */
-static int
-ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
+static int ufs_commit_chunk(struct page *page, unsigned from, unsigned to)
 {
-       struct inode *inode = filp->f_dentry->d_inode;
-       int error = 0;
-       unsigned long offset, lblk;
-       int i, stored;
-       struct buffer_head * bh;
-       struct ufs_dir_entry * de;
-       struct super_block * sb;
-       int de_reclen;
-       unsigned flags;
-       u64     blk= 0L;
-
-       lock_kernel();
-
-       sb = inode->i_sb;
-       flags = UFS_SB(sb)->s_flags;
-
-       UFSD(("ENTER, ino %lu  f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos))
-
-       stored = 0;
-       bh = NULL;
-       offset = filp->f_pos & (sb->s_blocksize - 1);
-
-       while (!error && !stored && filp->f_pos < inode->i_size) {
-               lblk = (filp->f_pos) >> sb->s_blocksize_bits;
-               blk = ufs_frag_map(inode, lblk);
-               if (!blk || !(bh = sb_bread(sb, blk))) {
-                       /* XXX - error - skip to the next block */
-                       printk("ufs_readdir: "
-                              "dir inode %lu has a hole at offset %lu\n",
-                              inode->i_ino, (unsigned long int)filp->f_pos);
-                       filp->f_pos += sb->s_blocksize - offset;
-                       continue;
-               }
-
-revalidate:
-               /* If the dir block has changed since the last call to
-                * readdir(2), then we might be pointing to an invalid
-                * dirent right now.  Scan from the start of the block
-                * to make sure. */
-               if (filp->f_version != inode->i_version) {
-                       for (i = 0; i < sb->s_blocksize && i < offset; ) {
-                               de = (struct ufs_dir_entry *)(bh->b_data + i);
-                               /* It's too expensive to do a full
-                                * dirent test each time round this
-                                * loop, but we do have to test at
-                                * least that it is non-zero.  A
-                                * failure will be detected in the
-                                * dirent test below. */
-                               de_reclen = fs16_to_cpu(sb, de->d_reclen);
-                               if (de_reclen < 1)
-                                       break;
-                               i += de_reclen;
-                       }
-                       offset = i;
-                       filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
-                               | offset;
-                       filp->f_version = inode->i_version;
-               }
+       struct inode *dir = page->mapping->host;
+       int err = 0;
+       dir->i_version++;
+       page->mapping->a_ops->commit_write(NULL, page, from, to);
+       if (IS_DIRSYNC(dir))
+               err = write_one_page(page, 1);
+       else
+               unlock_page(page);
+       return err;
+}
 
-               while (!error && filp->f_pos < inode->i_size
-                      && offset < sb->s_blocksize) {
-                       de = (struct ufs_dir_entry *) (bh->b_data + offset);
-                       /* XXX - put in a real ufs_check_dir_entry() */
-                       if ((de->d_reclen == 0) || (ufs_get_de_namlen(sb, de) == 0)) {
-                               filp->f_pos = (filp->f_pos &
-                                             (sb->s_blocksize - 1)) +
-                                              sb->s_blocksize;
-                               brelse(bh);
-                               unlock_kernel();
-                               return stored;
-                       }
-                       if (!ufs_check_dir_entry ("ufs_readdir", inode, de,
-                                                  bh, offset)) {
-                               /* On error, skip the f_pos to the
-                                  next block. */
-                               filp->f_pos = (filp->f_pos |
-                                             (sb->s_blocksize - 1)) +
-                                              1;
-                               brelse (bh);
-                               unlock_kernel();
-                               return stored;
-                       }
-                       offset += fs16_to_cpu(sb, de->d_reclen);
-                       if (de->d_ino) {
-                               /* We might block in the next section
-                                * if the data destination is
-                                * currently swapped out.  So, use a
-                                * version stamp to detect whether or
-                                * not the directory has been modified
-                                * during the copy operation. */
-                               unsigned long version = filp->f_version;
-                               unsigned char d_type = DT_UNKNOWN;
+static inline void ufs_put_page(struct page *page)
+{
+       kunmap(page);
+       page_cache_release(page);
+}
 
-                               UFSD(("filldir(%s,%u)\n", de->d_name,
-                                                       fs32_to_cpu(sb, de->d_ino)))
-                               UFSD(("namlen %u\n", ufs_get_de_namlen(sb, de)))
+static inline unsigned long ufs_dir_pages(struct inode *inode)
+{
+       return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT;
+}
 
-                               if ((flags & UFS_DE_MASK) == UFS_DE_44BSD)
-                                       d_type = de->d_u.d_44.d_type;
-                               error = filldir(dirent, de->d_name,
-                                               ufs_get_de_namlen(sb, de), filp->f_pos,
-                                               fs32_to_cpu(sb, de->d_ino), d_type);
-                               if (error)
-                                       break;
-                               if (version != filp->f_version)
-                                       goto revalidate;
-                               stored ++;
-                       }
-                       filp->f_pos += fs16_to_cpu(sb, de->d_reclen);
-               }
-               offset = 0;
-               brelse (bh);
+ino_t ufs_inode_by_name(struct inode *dir, struct dentry *dentry)
+{
+       ino_t res = 0;
+       struct ufs_dir_entry *de;
+       struct page *page;
+       
+       de = ufs_find_entry(dir, dentry, &page);
+       if (de) {
+               res = fs32_to_cpu(dir->i_sb, de->d_ino);
+               ufs_put_page(page);
        }
-       unlock_kernel();
-       return 0;
+       return res;
 }
 
-/*
- * define how far ahead to read directories while searching them.
- */
-#define NAMEI_RA_CHUNKS  2
-#define NAMEI_RA_BLOCKS  4
-#define NAMEI_RA_SIZE        (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
-#define NAMEI_RA_INDEX(c,b)  (((c) * NAMEI_RA_BLOCKS) + (b))
 
-/*
- *     ufs_find_entry()
- *
- * finds an entry in the specified directory with the wanted name. It
- * returns the cache buffer in which the entry was found, and the entry
- * itself (as a parameter - res_bh). It does NOT read the inode of the
- * entry - you'll have to do that yourself if you want to.
- */
-struct ufs_dir_entry * ufs_find_entry (struct dentry *dentry,
-       struct buffer_head ** res_bh)
+/* Releases the page */
+void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
+                 struct page *page, struct inode *inode)
 {
-       struct super_block * sb;
-       struct buffer_head * bh_use[NAMEI_RA_SIZE];
-       struct buffer_head * bh_read[NAMEI_RA_SIZE];
-       unsigned long offset;
-       int block, toread, i, err;
-       struct inode *dir = dentry->d_parent->d_inode;
-       const char *name = dentry->d_name.name;
-       int namelen = dentry->d_name.len;
+       unsigned from = (char *) de - (char *) page_address(page);
+       unsigned to = from + fs16_to_cpu(dir->i_sb, de->d_reclen);
+       int err;
 
-       UFSD(("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen))
-       
-       *res_bh = NULL;
-       
-       sb = dir->i_sb;
-       
-       if (namelen > UFS_MAXNAMLEN)
-               return NULL;
+       lock_page(page);
+       err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
+       BUG_ON(err);
+       de->d_ino = cpu_to_fs32(dir->i_sb, inode->i_ino);
+       ufs_set_de_type(dir->i_sb, de, inode->i_mode);
+       err = ufs_commit_chunk(page, from, to);
+       ufs_put_page(page);
+       dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+       mark_inode_dirty(dir);
+}
 
-       memset (bh_use, 0, sizeof (bh_use));
-       toread = 0;
-       for (block = 0; block < NAMEI_RA_SIZE; ++block) {
-               struct buffer_head * bh;
 
-               if ((block << sb->s_blocksize_bits) >= dir->i_size)
-                       break;
-               bh = ufs_getfrag (dir, block, 0, &err);
-               bh_use[block] = bh;
-               if (bh && !buffer_uptodate(bh))
-                       bh_read[toread++] = bh;
+static void ufs_check_page(struct page *page)
+{
+       struct inode *dir = page->mapping->host;
+       struct super_block *sb = dir->i_sb;
+       char *kaddr = page_address(page);
+       unsigned offs, rec_len;
+       unsigned limit = PAGE_CACHE_SIZE;
+       struct ufs_dir_entry *p;
+       char *error;
+
+       if ((dir->i_size >> PAGE_CACHE_SHIFT) == page->index) {
+               limit = dir->i_size & ~PAGE_CACHE_MASK;
+               if (limit & (UFS_SECTOR_SIZE - 1))
+                       goto Ebadsize;
+               if (!limit)
+                       goto out;
        }
+       for (offs = 0; offs <= limit - UFS_DIR_REC_LEN(1); offs += rec_len) {
+               p = (struct ufs_dir_entry *)(kaddr + offs);
+               rec_len = fs16_to_cpu(sb, p->d_reclen);
+
+               if (rec_len < UFS_DIR_REC_LEN(1))
+                       goto Eshort;
+               if (rec_len & 3)
+                       goto Ealign;
+               if (rec_len < UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, p)))
+                       goto Enamelen;
+               if (((offs + rec_len - 1) ^ offs) & ~(UFS_SECTOR_SIZE-1))
+                       goto Espan;
+               if (fs32_to_cpu(sb, p->d_ino) > (UFS_SB(sb)->s_uspi->s_ipg *
+                                                 UFS_SB(sb)->s_uspi->s_ncg))
+                       goto Einumber;
+       }
+       if (offs != limit)
+               goto Eend;
+out:
+       SetPageChecked(page);
+       return;
+
+       /* Too bad, we had an error */
+
+Ebadsize:
+       ufs_error(sb, "ufs_check_page",
+                 "size of directory #%lu is not a multiple of chunk size",
+                 dir->i_ino
+       );
+       goto fail;
+Eshort:
+       error = "rec_len is smaller than minimal";
+       goto bad_entry;
+Ealign:
+       error = "unaligned directory entry";
+       goto bad_entry;
+Enamelen:
+       error = "rec_len is too small for name_len";
+       goto bad_entry;
+Espan:
+       error = "directory entry across blocks";
+       goto bad_entry;
+Einumber:
+       error = "inode out of bounds";
+bad_entry:
+       ufs_error (sb, "ufs_check_page", "bad entry in directory #%lu: %s - "
+                  "offset=%lu, rec_len=%d, name_len=%d",
+                  dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
+                  rec_len, ufs_get_de_namlen(sb, p));
+       goto fail;
+Eend:
+       p = (struct ufs_dir_entry *)(kaddr + offs);
+       ufs_error (sb, "ext2_check_page",
+                  "entry in directory #%lu spans the page boundary"
+                  "offset=%lu",
+                  dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs);
+fail:
+       SetPageChecked(page);
+       SetPageError(page);
+}
 
-       for (block = 0, offset = 0; offset < dir->i_size; block++) {
-               struct buffer_head * bh;
-               struct ufs_dir_entry * de;
-               char * dlimit;
-
-               if ((block % NAMEI_RA_BLOCKS) == 0 && toread) {
-                       ll_rw_block (READ, toread, bh_read);
-                       toread = 0;
-               }
-               bh = bh_use[block % NAMEI_RA_SIZE];
-               if (!bh) {
-                       ufs_error (sb, "ufs_find_entry", 
-                               "directory #%lu contains a hole at offset %lu",
-                               dir->i_ino, offset);
-                       offset += sb->s_blocksize;
-                       continue;
-               }
-               wait_on_buffer (bh);
-               if (!buffer_uptodate(bh)) {
-                       /*
-                        * read error: all bets are off
-                        */
-                       break;
-               }
-
-               de = (struct ufs_dir_entry *) bh->b_data;
-               dlimit = bh->b_data + sb->s_blocksize;
-               while ((char *) de < dlimit && offset < dir->i_size) {
-                       /* this code is executed quadratically often */
-                       /* do minimal checking by hand */
-                       int de_len;
-
-                       if ((char *) de + namelen <= dlimit &&
-                           ufs_match(sb, namelen, name, de)) {
-                               /* found a match -
-                               just to be sure, do a full check */
-                               if (!ufs_check_dir_entry("ufs_find_entry",
-                                   dir, de, bh, offset))
-                                       goto failed;
-                               for (i = 0; i < NAMEI_RA_SIZE; ++i) {
-                                       if (bh_use[i] != bh)
-                                               brelse (bh_use[i]);
-                               }
-                               *res_bh = bh;
-                               return de;
-                       }
-                        /* prevent looping on a bad block */
-                       de_len = fs16_to_cpu(sb, de->d_reclen);
-                       if (de_len <= 0)
-                               goto failed;
-                       offset += de_len;
-                       de = (struct ufs_dir_entry *) ((char *) de + de_len);
-               }
-
-               brelse (bh);
-               if (((block + NAMEI_RA_SIZE) << sb->s_blocksize_bits ) >=
-                   dir->i_size)
-                       bh = NULL;
-               else
-                       bh = ufs_getfrag (dir, block + NAMEI_RA_SIZE, 0, &err);
-               bh_use[block % NAMEI_RA_SIZE] = bh;
-               if (bh && !buffer_uptodate(bh))
-                       bh_read[toread++] = bh;
+static struct page *ufs_get_page(struct inode *dir, unsigned long n)
+{
+       struct address_space *mapping = dir->i_mapping;
+       struct page *page = read_cache_page(mapping, n,
+                               (filler_t*)mapping->a_ops->readpage, NULL);
+       if (!IS_ERR(page)) {
+               wait_on_page_locked(page);
+               kmap(page);
+               if (!PageUptodate(page))
+                       goto fail;
+               if (!PageChecked(page))
+                       ufs_check_page(page);
+               if (PageError(page))
+                       goto fail;
        }
+       return page;
 
-failed:
-       for (i = 0; i < NAMEI_RA_SIZE; ++i) brelse (bh_use[i]);
-       UFSD(("EXIT\n"))
-       return NULL;
+fail:
+       ufs_put_page(page);
+       return ERR_PTR(-EIO);
 }
 
-static int
-ufs_check_dir_entry (const char *function, struct inode *dir,
-                    struct ufs_dir_entry *de, struct buffer_head *bh,
-                    unsigned long offset)
+/*
+ * Return the offset into page `page_nr' of the last valid
+ * byte in that page, plus one.
+ */
+static unsigned
+ufs_last_byte(struct inode *inode, unsigned long page_nr)
 {
-       struct super_block *sb = dir->i_sb;
-       const char *error_msg = NULL;
-       int rlen = fs16_to_cpu(sb, de->d_reclen);
-
-       if (rlen < UFS_DIR_REC_LEN(1))
-               error_msg = "reclen is smaller than minimal";
-       else if (rlen % 4 != 0)
-               error_msg = "reclen % 4 != 0";
-       else if (rlen < UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)))
-               error_msg = "reclen is too small for namlen";
-       else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize)
-               error_msg = "directory entry across blocks";
-       else if (fs32_to_cpu(sb, de->d_ino) > (UFS_SB(sb)->s_uspi->s_ipg *
-                                     UFS_SB(sb)->s_uspi->s_ncg))
-               error_msg = "inode out of bounds";
-
-       if (error_msg != NULL)
-               ufs_error (sb, function, "bad entry in directory #%lu, size %Lu: %s - "
-                           "offset=%lu, inode=%lu, reclen=%d, namlen=%d",
-                           dir->i_ino, dir->i_size, error_msg, offset,
-                           (unsigned long)fs32_to_cpu(sb, de->d_ino),
-                           rlen, ufs_get_de_namlen(sb, de));
-       
-       return (error_msg == NULL ? 1 : 0);
+       unsigned last_byte = inode->i_size;
+
+       last_byte -= page_nr << PAGE_CACHE_SHIFT;
+       if (last_byte > PAGE_CACHE_SIZE)
+               last_byte = PAGE_CACHE_SIZE;
+       return last_byte;
 }
 
-struct ufs_dir_entry *ufs_dotdot(struct inode *dir, struct buffer_head **p)
+static inline struct ufs_dir_entry *
+ufs_next_entry(struct super_block *sb, struct ufs_dir_entry *p)
 {
-       int err;
-       struct buffer_head *bh = ufs_bread (dir, 0, 0, &err);
-       struct ufs_dir_entry *res = NULL;
-
-       if (bh) {
-               res = (struct ufs_dir_entry *) bh->b_data;
-               res = (struct ufs_dir_entry *)((char *)res +
-                       fs16_to_cpu(dir->i_sb, res->d_reclen));
-       }
-       *p = bh;
-       return res;
+       return (struct ufs_dir_entry *)((char *)p +
+                                       fs16_to_cpu(sb, p->d_reclen));
 }
-ino_t ufs_inode_by_name(struct inode * dir, struct dentry *dentry)
+
+struct ufs_dir_entry *ufs_dotdot(struct inode *dir, struct page **p)
 {
-       ino_t res = 0;
-       struct ufs_dir_entry * de;
-       struct buffer_head *bh;
+       struct page *page = ufs_get_page(dir, 0);
+       struct ufs_dir_entry *de = NULL;
 
-       de = ufs_find_entry (dentry, &bh);
-       if (de) {
-               res = fs32_to_cpu(dir->i_sb, de->d_ino);
-               brelse(bh);
+       if (!IS_ERR(page)) {
+               de = ufs_next_entry(dir->i_sb,
+                                   (struct ufs_dir_entry *)page_address(page));
+               *p = page;
        }
-       return res;
+       return de;
 }
 
-void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
-               struct buffer_head *bh, struct inode *inode)
+/*
+ *     ufs_find_entry()
+ *
+ * finds an entry in the specified directory with the wanted name. It
+ * returns the page in which the entry was found, and the entry itself
+ * (as a parameter - res_dir). Page is returned mapped and unlocked.
+ * Entry is guaranteed to be valid.
+ */
+struct ufs_dir_entry *ufs_find_entry(struct inode *dir, struct dentry *dentry,
+                                    struct page **res_page)
 {
-       dir->i_version++;
-       de->d_ino = cpu_to_fs32(dir->i_sb, inode->i_ino);
-       mark_buffer_dirty(bh);
-       if (IS_DIRSYNC(dir))
-               sync_dirty_buffer(bh);
-       brelse (bh);
+       struct super_block *sb = dir->i_sb;
+       const char *name = dentry->d_name.name;
+       int namelen = dentry->d_name.len;
+       unsigned reclen = UFS_DIR_REC_LEN(namelen);
+       unsigned long start, n;
+       unsigned long npages = ufs_dir_pages(dir);
+       struct page *page = NULL;
+       struct ufs_inode_info *ui = UFS_I(dir);
+       struct ufs_dir_entry *de;
+
+       UFSD("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen);
+
+       if (npages == 0 || namelen > UFS_MAXNAMLEN)
+               goto out;
+
+       /* OFFSET_CACHE */
+       *res_page = NULL;
+
+       start = ui->i_dir_start_lookup;
+
+       if (start >= npages)
+               start = 0;
+       n = start;
+       do {
+               char *kaddr;
+               page = ufs_get_page(dir, n);
+               if (!IS_ERR(page)) {
+                       kaddr = page_address(page);
+                       de = (struct ufs_dir_entry *) kaddr;
+                       kaddr += ufs_last_byte(dir, n) - reclen;
+                       while ((char *) de <= kaddr) {
+                               if (de->d_reclen == 0) {
+                                       ufs_error(dir->i_sb, __FUNCTION__,
+                                                 "zero-length directory entry");
+                                       ufs_put_page(page);
+                                       goto out;
+                               }
+                               if (ufs_match(sb, namelen, name, de))
+                                       goto found;
+                               de = ufs_next_entry(sb, de);
+                       }
+                       ufs_put_page(page);
+               }
+               if (++n >= npages)
+                       n = 0;
+       } while (n != start);
+out:
+       return NULL;
+
+found:
+       *res_page = page;
+       ui->i_dir_start_lookup = n;
+       return de;
 }
 
 /*
- *     ufs_add_entry()
- *
- * adds a file entry to the specified directory, using the same
- * semantics as ufs_find_entry(). It returns NULL if it failed.
+ *     Parent is locked.
  */
 int ufs_add_link(struct dentry *dentry, struct inode *inode)
 {
-       struct super_block * sb;
-       struct ufs_sb_private_info * uspi;
-       unsigned long offset;
-       unsigned fragoff;
-       unsigned short rec_len;
-       struct buffer_head * bh;
-       struct ufs_dir_entry * de, * de1;
        struct inode *dir = dentry->d_parent->d_inode;
        const char *name = dentry->d_name.name;
        int namelen = dentry->d_name.len;
+       struct super_block *sb = dir->i_sb;
+       unsigned reclen = UFS_DIR_REC_LEN(namelen);
+       unsigned short rec_len, name_len;
+       struct page *page = NULL;
+       struct ufs_dir_entry *de;
+       unsigned long npages = ufs_dir_pages(dir);
+       unsigned long n;
+       char *kaddr;
+       unsigned from, to;
        int err;
 
-       UFSD(("ENTER, name %s, namelen %u\n", name, namelen))
-       
-       sb = dir->i_sb;
-       uspi = UFS_SB(sb)->s_uspi;
-
-       if (!namelen)
-               return -EINVAL;
-       bh = ufs_bread (dir, 0, 0, &err);
-       if (!bh)
-               return err;
-       rec_len = UFS_DIR_REC_LEN(namelen);
-       offset = 0;
-       de = (struct ufs_dir_entry *) bh->b_data;
-       while (1) {
-               if ((char *)de >= UFS_SECTOR_SIZE + bh->b_data) {
-                       fragoff = offset & ~uspi->s_fmask;
-                       if (fragoff != 0 && fragoff != UFS_SECTOR_SIZE)
-                               ufs_error (sb, "ufs_add_entry", "internal error"
-                                       " fragoff %u", fragoff);
-                       if (!fragoff) {
-                               brelse (bh);
-                               bh = ufs_bread (dir, offset >> sb->s_blocksize_bits, 1, &err);
-                               if (!bh)
-                                       return err;
-                       }
-                       if (dir->i_size <= offset) {
-                               if (dir->i_size == 0) {
-                                       brelse(bh);
-                                       return -ENOENT;
-                               }
-                               de = (struct ufs_dir_entry *) (bh->b_data + fragoff);
-                               de->d_ino = 0;
+       UFSD("ENTER, name %s, namelen %u\n", name, namelen);
+
+       /*
+        * We take care of directory expansion in the same loop.
+        * This code plays outside i_size, so it locks the page
+        * to protect that region.
+        */
+       for (n = 0; n <= npages; n++) {
+               char *dir_end;
+
+               page = ufs_get_page(dir, n);
+               err = PTR_ERR(page);
+               if (IS_ERR(page))
+                       goto out;
+               lock_page(page);
+               kaddr = page_address(page);
+               dir_end = kaddr + ufs_last_byte(dir, n);
+               de = (struct ufs_dir_entry *)kaddr;
+               kaddr += PAGE_CACHE_SIZE - reclen;
+               while ((char *)de <= kaddr) {
+                       if ((char *)de == dir_end) {
+                               /* We hit i_size */
+                               name_len = 0;
+                               rec_len = UFS_SECTOR_SIZE;
                                de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE);
-                               ufs_set_de_namlen(sb, de, 0);
-                               dir->i_size = offset + UFS_SECTOR_SIZE;
-                               mark_inode_dirty(dir);
-                       } else {
-                               de = (struct ufs_dir_entry *) bh->b_data;
+                               de->d_ino = 0;
+                               goto got_it;
                        }
+                       if (de->d_reclen == 0) {
+                               ufs_error(dir->i_sb, __FUNCTION__,
+                                         "zero-length directory entry");
+                               err = -EIO;
+                               goto out_unlock;
+                       }
+                       err = -EEXIST;
+                       if (ufs_match(sb, namelen, name, de))
+                               goto out_unlock;
+                       name_len = UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de));
+                       rec_len = fs16_to_cpu(sb, de->d_reclen);
+                       if (!de->d_ino && rec_len >= reclen)
+                               goto got_it;
+                       if (rec_len >= name_len + reclen)
+                               goto got_it;
+                       de = (struct ufs_dir_entry *) ((char *) de + rec_len);
                }
-               if (!ufs_check_dir_entry ("ufs_add_entry", dir, de, bh, offset)) {
-                       brelse (bh);
-                       return -ENOENT;
-               }
-               if (ufs_match(sb, namelen, name, de)) {
-                       brelse (bh);
-                       return -EEXIST;
-               }
-               if (de->d_ino == 0 && fs16_to_cpu(sb, de->d_reclen) >= rec_len)
-                       break;
-                       
-               if (fs16_to_cpu(sb, de->d_reclen) >=
-                    UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)) + rec_len)
-                       break;
-               offset += fs16_to_cpu(sb, de->d_reclen);
-               de = (struct ufs_dir_entry *) ((char *) de + fs16_to_cpu(sb, de->d_reclen));
+               unlock_page(page);
+               ufs_put_page(page);
        }
-
+       BUG();
+       return -EINVAL;
+
+got_it:
+       from = (char*)de - (char*)page_address(page);
+       to = from + rec_len;
+       err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
+       if (err)
+               goto out_unlock;
        if (de->d_ino) {
-               de1 = (struct ufs_dir_entry *) ((char *) de +
-                       UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)));
-               de1->d_reclen =
-                       cpu_to_fs16(sb, fs16_to_cpu(sb, de->d_reclen) -
-                               UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)));
-               de->d_reclen =
-                       cpu_to_fs16(sb, UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)));
+               struct ufs_dir_entry *de1 =
+                       (struct ufs_dir_entry *) ((char *) de + name_len);
+               de1->d_reclen = cpu_to_fs16(sb, rec_len - name_len);
+               de->d_reclen = cpu_to_fs16(sb, name_len);
+
                de = de1;
        }
-       de->d_ino = 0;
+
        ufs_set_de_namlen(sb, de, namelen);
-       memcpy (de->d_name, name, namelen + 1);
+       memcpy(de->d_name, name, namelen + 1);
        de->d_ino = cpu_to_fs32(sb, inode->i_ino);
        ufs_set_de_type(sb, de, inode->i_mode);
-       mark_buffer_dirty(bh);
-       if (IS_DIRSYNC(dir))
-               sync_dirty_buffer(bh);
-       brelse (bh);
+
+       err = ufs_commit_chunk(page, from, to);
        dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
-       dir->i_version++;
+
        mark_inode_dirty(dir);
+       /* OFFSET_CACHE */
+out_put:
+       ufs_put_page(page);
+out:
+       return err;
+out_unlock:
+       unlock_page(page);
+       goto out_put;
+}
 
-       UFSD(("EXIT\n"))
+static inline unsigned
+ufs_validate_entry(struct super_block *sb, char *base,
+                  unsigned offset, unsigned mask)
+{
+       struct ufs_dir_entry *de = (struct ufs_dir_entry*)(base + offset);
+       struct ufs_dir_entry *p = (struct ufs_dir_entry*)(base + (offset&mask));
+       while ((char*)p < (char*)de) {
+               if (p->d_reclen == 0)
+                       break;
+               p = ufs_next_entry(sb, p);
+       }
+       return (char *)p - base;
+}
+
+
+/*
+ * This is blatantly stolen from ext2fs
+ */
+static int
+ufs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+       loff_t pos = filp->f_pos;
+       struct inode *inode = filp->f_dentry->d_inode;
+       struct super_block *sb = inode->i_sb;
+       unsigned int offset = pos & ~PAGE_CACHE_MASK;
+       unsigned long n = pos >> PAGE_CACHE_SHIFT;
+       unsigned long npages = ufs_dir_pages(inode);
+       unsigned chunk_mask = ~(UFS_SECTOR_SIZE - 1);
+       int need_revalidate = filp->f_version != inode->i_version;
+       unsigned flags = UFS_SB(sb)->s_flags;
+
+       UFSD("BEGIN\n");
+
+       if (pos > inode->i_size - UFS_DIR_REC_LEN(1))
+               return 0;
+
+       for ( ; n < npages; n++, offset = 0) {
+               char *kaddr, *limit;
+               struct ufs_dir_entry *de;
+
+               struct page *page = ufs_get_page(inode, n);
+
+               if (IS_ERR(page)) {
+                       ufs_error(sb, __FUNCTION__,
+                                 "bad page in #%lu",
+                                 inode->i_ino);
+                       filp->f_pos += PAGE_CACHE_SIZE - offset;
+                       return -EIO;
+               }
+               kaddr = page_address(page);
+               if (unlikely(need_revalidate)) {
+                       if (offset) {
+                               offset = ufs_validate_entry(sb, kaddr, offset, chunk_mask);
+                               filp->f_pos = (n<<PAGE_CACHE_SHIFT) + offset;
+                       }
+                       filp->f_version = inode->i_version;
+                       need_revalidate = 0;
+               }
+               de = (struct ufs_dir_entry *)(kaddr+offset);
+               limit = kaddr + ufs_last_byte(inode, n) - UFS_DIR_REC_LEN(1);
+               for ( ;(char*)de <= limit; de = ufs_next_entry(sb, de)) {
+                       if (de->d_reclen == 0) {
+                               ufs_error(sb, __FUNCTION__,
+                                       "zero-length directory entry");
+                               ufs_put_page(page);
+                               return -EIO;
+                       }
+                       if (de->d_ino) {
+                               int over;
+                               unsigned char d_type = DT_UNKNOWN;
+
+                               offset = (char *)de - kaddr;
+
+                               UFSD("filldir(%s,%u)\n", de->d_name,
+                                     fs32_to_cpu(sb, de->d_ino));
+                               UFSD("namlen %u\n", ufs_get_de_namlen(sb, de));
+
+                               if ((flags & UFS_DE_MASK) == UFS_DE_44BSD)
+                                       d_type = de->d_u.d_44.d_type;
+
+                               over = filldir(dirent, de->d_name,
+                                              ufs_get_de_namlen(sb, de),
+                                               (n<<PAGE_CACHE_SHIFT) | offset,
+                                              fs32_to_cpu(sb, de->d_ino), d_type);
+                               if (over) {
+                                       ufs_put_page(page);
+                                       return 0;
+                               }
+                       }
+                       filp->f_pos += fs16_to_cpu(sb, de->d_reclen);
+               }
+               ufs_put_page(page);
+       }
        return 0;
 }
 
+
 /*
  * ufs_delete_entry deletes a directory entry by merging it with the
  * previous entry.
  */
-int ufs_delete_entry (struct inode * inode, struct ufs_dir_entry * dir,
-       struct buffer_head * bh )
-       
+int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir,
+                    struct page * page)
 {
-       struct super_block * sb;
-       struct ufs_dir_entry * de, * pde;
-       unsigned i;
-       
-       UFSD(("ENTER\n"))
+       struct super_block *sb = inode->i_sb;
+       struct address_space *mapping = page->mapping;
+       char *kaddr = page_address(page);
+       unsigned from = ((char*)dir - kaddr) & ~(UFS_SECTOR_SIZE - 1);
+       unsigned to = ((char*)dir - kaddr) + fs16_to_cpu(sb, dir->d_reclen);
+       struct ufs_dir_entry *pde = NULL;
+       struct ufs_dir_entry *de = (struct ufs_dir_entry *) (kaddr + from);
+       int err;
 
-       sb = inode->i_sb;
-       i = 0;
-       pde = NULL;
-       de = (struct ufs_dir_entry *) bh->b_data;
-       
-       UFSD(("ino %u, reclen %u, namlen %u, name %s\n",
-               fs32_to_cpu(sb, de->d_ino),
-               fs16_to_cpu(sb, de->d_reclen),
-               ufs_get_de_namlen(sb, de), de->d_name))
-
-       while (i < bh->b_size) {
-               if (!ufs_check_dir_entry ("ufs_delete_entry", inode, de, bh, i)) {
-                       brelse(bh);
-                       return -EIO;
-               }
-               if (de == dir)  {
-                       if (pde)
-                               fs16_add(sb, &pde->d_reclen,
-                                       fs16_to_cpu(sb, dir->d_reclen));
-                       dir->d_ino = 0;
-                       inode->i_version++;
-                       inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
-                       mark_inode_dirty(inode);
-                       mark_buffer_dirty(bh);
-                       if (IS_DIRSYNC(inode))
-                               sync_dirty_buffer(bh);
-                       brelse(bh);
-                       UFSD(("EXIT\n"))
-                       return 0;
+       UFSD("ENTER\n");
+
+       UFSD("ino %u, reclen %u, namlen %u, name %s\n",
+             fs32_to_cpu(sb, de->d_ino),
+             fs16_to_cpu(sb, de->d_reclen),
+             ufs_get_de_namlen(sb, de), de->d_name);
+
+       while ((char*)de < (char*)dir) {
+               if (de->d_reclen == 0) {
+                       ufs_error(inode->i_sb, __FUNCTION__,
+                                 "zero-length directory entry");
+                       err = -EIO;
+                       goto out;
                }
-               i += fs16_to_cpu(sb, de->d_reclen);
-               if (i == UFS_SECTOR_SIZE) pde = NULL;
-               else pde = de;
-               de = (struct ufs_dir_entry *)
-                   ((char *) de + fs16_to_cpu(sb, de->d_reclen));
-               if (i == UFS_SECTOR_SIZE && de->d_reclen == 0)
-                       break;
+               pde = de;
+               de = ufs_next_entry(sb, de);
        }
-       UFSD(("EXIT\n"))
-       brelse(bh);
-       return -ENOENT;
+       if (pde)
+               from = (char*)pde - (char*)page_address(page);
+       lock_page(page);
+       err = mapping->a_ops->prepare_write(NULL, page, from, to);
+       BUG_ON(err);
+       if (pde)
+               pde->d_reclen = cpu_to_fs16(sb, to-from);
+       dir->d_ino = 0;
+       err = ufs_commit_chunk(page, from, to);
+       inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+       mark_inode_dirty(inode);
+out:
+       ufs_put_page(page);
+       UFSD("EXIT\n");
+       return err;
 }
 
 int ufs_make_empty(struct inode * inode, struct inode *dir)
 {
        struct super_block * sb = dir->i_sb;
-       struct buffer_head * dir_block;
+       struct address_space *mapping = inode->i_mapping;
+       struct page *page = grab_cache_page(mapping, 0);
        struct ufs_dir_entry * de;
+       char *base;
        int err;
 
-       dir_block = ufs_bread (inode, 0, 1, &err);
-       if (!dir_block)
-               return err;
+       if (!page)
+               return -ENOMEM;
+       kmap(page);
+       err = mapping->a_ops->prepare_write(NULL, page, 0, UFS_SECTOR_SIZE);
+       if (err) {
+               unlock_page(page);
+               goto fail;
+       }
+
+
+       base = (char*)page_address(page);
+       memset(base, 0, PAGE_CACHE_SIZE);
+
+       de = (struct ufs_dir_entry *) base;
 
-       inode->i_blocks = sb->s_blocksize / UFS_SECTOR_SIZE;
-       de = (struct ufs_dir_entry *) dir_block->b_data;
        de->d_ino = cpu_to_fs32(sb, inode->i_ino);
        ufs_set_de_type(sb, de, inode->i_mode);
        ufs_set_de_namlen(sb, de, 1);
@@ -552,72 +587,65 @@ int ufs_make_empty(struct inode * inode, struct inode *dir)
        de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE - UFS_DIR_REC_LEN(1));
        ufs_set_de_namlen(sb, de, 2);
        strcpy (de->d_name, "..");
-       mark_buffer_dirty(dir_block);
-       brelse (dir_block);
-       mark_inode_dirty(inode);
-       return 0;
+
+       err = ufs_commit_chunk(page, 0, UFS_SECTOR_SIZE);
+fail:
+       kunmap(page);
+       page_cache_release(page);
+       return err;
 }
 
 /*
  * routine to check that the specified directory is empty (for rmdir)
  */
-int ufs_empty_dir (struct inode * inode)
+int ufs_empty_dir(struct inode * inode)
 {
-       struct super_block * sb;
-       unsigned long offset;
-       struct buffer_head * bh;
-       struct ufs_dir_entry * de, * de1;
-       int err;
-       
-       sb = inode->i_sb;
-
-       if (inode->i_size < UFS_DIR_REC_LEN(1) + UFS_DIR_REC_LEN(2) ||
-           !(bh = ufs_bread (inode, 0, 0, &err))) {
-               ufs_warning (inode->i_sb, "empty_dir",
-                             "bad directory (dir #%lu) - no data block",
-                             inode->i_ino);
-               return 1;
-       }
-       de = (struct ufs_dir_entry *) bh->b_data;
-       de1 = (struct ufs_dir_entry *)
-               ((char *)de + fs16_to_cpu(sb, de->d_reclen));
-       if (fs32_to_cpu(sb, de->d_ino) != inode->i_ino || de1->d_ino == 0 ||
-            strcmp (".", de->d_name) || strcmp ("..", de1->d_name)) {
-               ufs_warning (inode->i_sb, "empty_dir",
-                             "bad directory (dir #%lu) - no `.' or `..'",
-                             inode->i_ino);
-               return 1;
-       }
-       offset = fs16_to_cpu(sb, de->d_reclen) + fs16_to_cpu(sb, de1->d_reclen);
-       de = (struct ufs_dir_entry *)
-               ((char *)de1 + fs16_to_cpu(sb, de1->d_reclen));
-       while (offset < inode->i_size ) {
-               if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
-                       brelse (bh);
-                       bh = ufs_bread (inode, offset >> sb->s_blocksize_bits, 1, &err);
-                       if (!bh) {
-                               ufs_error (sb, "empty_dir",
-                                           "directory #%lu contains a hole at offset %lu",
-                                           inode->i_ino, offset);
-                               offset += sb->s_blocksize;
-                               continue;
+       struct super_block *sb = inode->i_sb;
+       struct page *page = NULL;
+       unsigned long i, npages = ufs_dir_pages(inode);
+
+       for (i = 0; i < npages; i++) {
+               char *kaddr;
+               struct ufs_dir_entry *de;
+               page = ufs_get_page(inode, i);
+
+               if (IS_ERR(page))
+                       continue;
+
+               kaddr = page_address(page);
+               de = (struct ufs_dir_entry *)kaddr;
+               kaddr += ufs_last_byte(inode, i) - UFS_DIR_REC_LEN(1);
+
+               while ((char *)de <= kaddr) {
+                       if (de->d_reclen == 0) {
+                               ufs_error(inode->i_sb, __FUNCTION__,
+                                       "zero-length directory entry: "
+                                       "kaddr=%p, de=%p\n", kaddr, de);
+                               goto not_empty;
                        }
-                       de = (struct ufs_dir_entry *) bh->b_data;
-               }
-               if (!ufs_check_dir_entry ("empty_dir", inode, de, bh, offset)) {
-                       brelse (bh);
-                       return 1;
-               }
-               if (de->d_ino) {
-                       brelse (bh);
-                       return 0;
+                       if (de->d_ino) {
+                               u16 namelen=ufs_get_de_namlen(sb, de);
+                               /* check for . and .. */
+                               if (de->d_name[0] != '.')
+                                       goto not_empty;
+                               if (namelen > 2)
+                                       goto not_empty;
+                               if (namelen < 2) {
+                                       if (inode->i_ino !=
+                                           fs32_to_cpu(sb, de->d_ino))
+                                               goto not_empty;
+                               } else if (de->d_name[1] != '.')
+                                       goto not_empty;
+                       }
+                       de = ufs_next_entry(sb, de);
                }
-               offset += fs16_to_cpu(sb, de->d_reclen);
-               de = (struct ufs_dir_entry *)
-                       ((char *)de + fs16_to_cpu(sb, de->d_reclen));
+               ufs_put_page(page);
        }
-       brelse (bh);
        return 1;
+
+not_empty:
+       ufs_put_page(page);
+       return 0;
 }
 
 const struct file_operations ufs_dir_operations = {
index 312fd3f86313b61a7d6f7230699cc2f763d69008..0e5001512a9d85f0d176c247096aa96ededddda1 100644 (file)
 
 #include <linux/fs.h>
 #include <linux/ufs_fs.h>
+#include <linux/buffer_head.h> /* for sync_mapping_buffers() */
+
+static int ufs_sync_file(struct file *file, struct dentry *dentry, int datasync)
+{
+       struct inode *inode = dentry->d_inode;
+       int err;
+       int ret;
+
+       ret = sync_mapping_buffers(inode->i_mapping);
+       if (!(inode->i_state & I_DIRTY))
+               return ret;
+       if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+               return ret;
+
+       err = ufs_sync_inode(inode);
+       if (ret == 0)
+               ret = err;
+       return ret;
+}
+
 
 /*
  * We have mostly NULL's here: the current defaults are ok for
@@ -37,6 +57,7 @@ const struct file_operations ufs_file_operations = {
        .write          = generic_file_write,
        .mmap           = generic_file_mmap,
        .open           = generic_file_open,
+       .fsync          = ufs_sync_file,
        .sendfile       = generic_file_sendfile,
 };
 
index c7a47ed4f430d28ab0613b1d8b3986f79e0b528a..9501dcd3b2132b4c0235fd0e187cb11648fc0708 100644 (file)
 #include "swab.h"
 #include "util.h"
 
-#undef UFS_IALLOC_DEBUG
-
-#ifdef UFS_IALLOC_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
 /*
  * NOTE! When we get the inode, we're the only people
  * that have access to it, and as such there are no
@@ -68,7 +60,7 @@ void ufs_free_inode (struct inode * inode)
        int is_directory;
        unsigned ino, cg, bit;
        
-       UFSD(("ENTER, ino %lu\n", inode->i_ino))
+       UFSD("ENTER, ino %lu\n", inode->i_ino);
 
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
@@ -91,7 +83,7 @@ void ufs_free_inode (struct inode * inode)
                unlock_super (sb);
                return;
        }
-       ucg = ubh_get_ucg(UCPI_UBH);
+       ucg = ubh_get_ucg(UCPI_UBH(ucpi));
        if (!ufs_cg_chkmagic(sb, ucg))
                ufs_panic (sb, "ufs_free_fragments", "internal error, bad cg magic number");
 
@@ -104,33 +96,33 @@ void ufs_free_inode (struct inode * inode)
 
        clear_inode (inode);
 
-       if (ubh_isclr (UCPI_UBH, ucpi->c_iusedoff, bit))
+       if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit))
                ufs_error(sb, "ufs_free_inode", "bit already cleared for inode %u", ino);
        else {
-               ubh_clrbit (UCPI_UBH, ucpi->c_iusedoff, bit);
+               ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit);
                if (ino < ucpi->c_irotor)
                        ucpi->c_irotor = ino;
                fs32_add(sb, &ucg->cg_cs.cs_nifree, 1);
-               fs32_add(sb, &usb1->fs_cstotal.cs_nifree, 1);
+               uspi->cs_total.cs_nifree++;
                fs32_add(sb, &UFS_SB(sb)->fs_cs(cg).cs_nifree, 1);
 
                if (is_directory) {
                        fs32_sub(sb, &ucg->cg_cs.cs_ndir, 1);
-                       fs32_sub(sb, &usb1->fs_cstotal.cs_ndir, 1);
+                       uspi->cs_total.cs_ndir--;
                        fs32_sub(sb, &UFS_SB(sb)->fs_cs(cg).cs_ndir, 1);
                }
        }
 
-       ubh_mark_buffer_dirty (USPI_UBH);
-       ubh_mark_buffer_dirty (UCPI_UBH);
+       ubh_mark_buffer_dirty (USPI_UBH(uspi));
+       ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
        if (sb->s_flags & MS_SYNCHRONOUS) {
-               ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **) &ucpi);
-               ubh_wait_on_buffer (UCPI_UBH);
+               ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
+               ubh_wait_on_buffer (UCPI_UBH(ucpi));
        }
        
        sb->s_dirt = 1;
        unlock_super (sb);
-       UFSD(("EXIT\n"))
+       UFSD("EXIT\n");
 }
 
 /*
@@ -155,7 +147,7 @@ struct inode * ufs_new_inode(struct inode * dir, int mode)
        unsigned cg, bit, i, j, start;
        struct ufs_inode_info *ufsi;
 
-       UFSD(("ENTER\n"))
+       UFSD("ENTER\n");
        
        /* Cannot create files in a deleted directory */
        if (!dir || !dir->i_nlink)
@@ -213,43 +205,43 @@ cg_found:
        ucpi = ufs_load_cylinder (sb, cg);
        if (!ucpi)
                goto failed;
-       ucg = ubh_get_ucg(UCPI_UBH);
+       ucg = ubh_get_ucg(UCPI_UBH(ucpi));
        if (!ufs_cg_chkmagic(sb, ucg)) 
                ufs_panic (sb, "ufs_new_inode", "internal error, bad cg magic number");
 
        start = ucpi->c_irotor;
-       bit = ubh_find_next_zero_bit (UCPI_UBH, ucpi->c_iusedoff, uspi->s_ipg, start);
+       bit = ubh_find_next_zero_bit (UCPI_UBH(ucpi), ucpi->c_iusedoff, uspi->s_ipg, start);
        if (!(bit < uspi->s_ipg)) {
-               bit = ubh_find_first_zero_bit (UCPI_UBH, ucpi->c_iusedoff, start);
+               bit = ubh_find_first_zero_bit (UCPI_UBH(ucpi), ucpi->c_iusedoff, start);
                if (!(bit < start)) {
                        ufs_error (sb, "ufs_new_inode",
                            "cylinder group %u corrupted - error in inode bitmap\n", cg);
                        goto failed;
                }
        }
-       UFSD(("start = %u, bit = %u, ipg = %u\n", start, bit, uspi->s_ipg))
-       if (ubh_isclr (UCPI_UBH, ucpi->c_iusedoff, bit))
-               ubh_setbit (UCPI_UBH, ucpi->c_iusedoff, bit);
+       UFSD("start = %u, bit = %u, ipg = %u\n", start, bit, uspi->s_ipg);
+       if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit))
+               ubh_setbit (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit);
        else {
                ufs_panic (sb, "ufs_new_inode", "internal error");
                goto failed;
        }
        
        fs32_sub(sb, &ucg->cg_cs.cs_nifree, 1);
-       fs32_sub(sb, &usb1->fs_cstotal.cs_nifree, 1);
+       uspi->cs_total.cs_nifree--;
        fs32_sub(sb, &sbi->fs_cs(cg).cs_nifree, 1);
        
        if (S_ISDIR(mode)) {
                fs32_add(sb, &ucg->cg_cs.cs_ndir, 1);
-               fs32_add(sb, &usb1->fs_cstotal.cs_ndir, 1);
+               uspi->cs_total.cs_ndir++;
                fs32_add(sb, &sbi->fs_cs(cg).cs_ndir, 1);
        }
 
-       ubh_mark_buffer_dirty (USPI_UBH);
-       ubh_mark_buffer_dirty (UCPI_UBH);
+       ubh_mark_buffer_dirty (USPI_UBH(uspi));
+       ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
        if (sb->s_flags & MS_SYNCHRONOUS) {
-               ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **) &ucpi);
-               ubh_wait_on_buffer (UCPI_UBH);
+               ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
+               ubh_wait_on_buffer (UCPI_UBH(ucpi));
        }
        sb->s_dirt = 1;
 
@@ -272,6 +264,7 @@ cg_found:
        ufsi->i_shadow = 0;
        ufsi->i_osync = 0;
        ufsi->i_oeftflag = 0;
+       ufsi->i_dir_start_lookup = 0;
        memset(&ufsi->i_u1, 0, sizeof(ufsi->i_u1));
 
        insert_inode_hash(inode);
@@ -287,14 +280,14 @@ cg_found:
                return ERR_PTR(-EDQUOT);
        }
 
-       UFSD(("allocating inode %lu\n", inode->i_ino))
-       UFSD(("EXIT\n"))
+       UFSD("allocating inode %lu\n", inode->i_ino);
+       UFSD("EXIT\n");
        return inode;
 
 failed:
        unlock_super (sb);
        make_bad_inode(inode);
        iput (inode);
-       UFSD(("EXIT (FAILED)\n"))
+       UFSD("EXIT (FAILED)\n");
        return ERR_PTR(-ENOSPC);
 }
index 3c3f62ce2ad9a926e71b5e52bb76f6b763009425..f2dbdf5a8769765d4ca175250e19e0659bb5f7c8 100644 (file)
 #include "swab.h"
 #include "util.h"
 
-#undef UFS_INODE_DEBUG
-#undef UFS_INODE_DEBUG_MORE
-
-#ifdef UFS_INODE_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
+static u64 ufs_frag_map(struct inode *inode, sector_t frag);
 
 static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t offsets[4])
 {
@@ -61,7 +54,7 @@ static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t off
        int n = 0;
 
 
-       UFSD(("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks));
+       UFSD("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks);
        if (i_block < 0) {
                ufs_warning(inode->i_sb, "ufs_block_to_path", "block < 0");
        } else if (i_block < direct_blocks) {
@@ -89,7 +82,7 @@ static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t off
  * the begining of the filesystem.
  */
 
-u64  ufs_frag_map(struct inode *inode, sector_t frag)
+static u64 ufs_frag_map(struct inode *inode, sector_t frag)
 {
        struct ufs_inode_info *ufsi = UFS_I(inode);
        struct super_block *sb = inode->i_sb;
@@ -104,8 +97,8 @@ u64  ufs_frag_map(struct inode *inode, sector_t frag)
        unsigned flags = UFS_SB(sb)->s_flags;
        u64 temp = 0L;
 
-       UFSD((": frag = %llu  depth = %d\n", (unsigned long long)frag, depth));
-       UFSD((": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n",uspi->s_fpbshift,uspi->s_apbmask,mask));
+       UFSD(": frag = %llu  depth = %d\n", (unsigned long long)frag, depth);
+       UFSD(": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n",uspi->s_fpbshift,uspi->s_apbmask,mask);
 
        if (depth == 0)
                return 0;
@@ -161,26 +154,64 @@ out:
        return ret;
 }
 
-static struct buffer_head * ufs_inode_getfrag (struct inode *inode,
-       unsigned int fragment, unsigned int new_fragment,
-       unsigned int required, int *err, int metadata, long *phys, int *new)
+static void ufs_clear_frag(struct inode *inode, struct buffer_head *bh)
+{
+       lock_buffer(bh);
+       memset(bh->b_data, 0, inode->i_sb->s_blocksize);
+       set_buffer_uptodate(bh);
+       mark_buffer_dirty(bh);
+       unlock_buffer(bh);
+       if (IS_SYNC(inode))
+               sync_dirty_buffer(bh);
+}
+
+static struct buffer_head *
+ufs_clear_frags(struct inode *inode, sector_t beg,
+               unsigned int n)
+{
+       struct buffer_head *res, *bh;
+       sector_t end = beg + n;
+
+       res = sb_getblk(inode->i_sb, beg);
+       ufs_clear_frag(inode, res);
+       for (++beg; beg < end; ++beg) {
+               bh = sb_getblk(inode->i_sb, beg);
+               ufs_clear_frag(inode, bh);
+               brelse(bh);
+       }
+       return res;
+}
+
+/**
+ * ufs_inode_getfrag() - allocate new fragment(s)
+ * @inode - pointer to inode
+ * @fragment - number of `fragment' which hold pointer
+ *   to new allocated fragment(s)
+ * @new_fragment - number of new allocated fragment(s)
+ * @required - how many fragment(s) we require
+ * @err - we set it if something wrong
+ * @phys - pointer to where we save physical number of new allocated fragments,
+ *   NULL if we allocate not data(indirect blocks for example).
+ * @new - we set it if we allocate new block
+ * @locked_page - for ufs_new_fragments()
+ */
+static struct buffer_head *
+ufs_inode_getfrag(struct inode *inode, unsigned int fragment,
+                 sector_t new_fragment, unsigned int required, int *err,
+                 long *phys, int *new, struct page *locked_page)
 {
        struct ufs_inode_info *ufsi = UFS_I(inode);
-       struct super_block * sb;
-       struct ufs_sb_private_info * uspi;
+       struct super_block *sb = inode->i_sb;
+       struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
        struct buffer_head * result;
        unsigned block, blockoff, lastfrag, lastblock, lastblockoff;
        unsigned tmp, goal;
        __fs32 * p, * p2;
-       unsigned flags = 0;
 
-       UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u, required %u\n",
-               inode->i_ino, fragment, new_fragment, required))         
+       UFSD("ENTER, ino %lu, fragment %u, new_fragment %llu, required %u, "
+            "metadata %d\n", inode->i_ino, fragment,
+            (unsigned long long)new_fragment, required, !phys);
 
-       sb = inode->i_sb;
-       uspi = UFS_SB(sb)->s_uspi;
-
-       flags = UFS_SB(sb)->s_flags;
         /* TODO : to be done for write support
         if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
              goto ufs2;
@@ -195,16 +226,16 @@ repeat:
        tmp = fs32_to_cpu(sb, *p);
        lastfrag = ufsi->i_lastfrag;
        if (tmp && fragment < lastfrag) {
-               if (metadata) {
+               if (!phys) {
                        result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff);
                        if (tmp == fs32_to_cpu(sb, *p)) {
-                               UFSD(("EXIT, result %u\n", tmp + blockoff))
+                               UFSD("EXIT, result %u\n", tmp + blockoff);
                                return result;
                        }
                        brelse (result);
                        goto repeat;
                } else {
-                       *phys = tmp;
+                       *phys = tmp + blockoff;
                        return NULL;
                }
        }
@@ -221,7 +252,8 @@ repeat:
                if (lastblockoff) {
                        p2 = ufsi->i_u1.i_data + lastblock;
                        tmp = ufs_new_fragments (inode, p2, lastfrag, 
-                               fs32_to_cpu(sb, *p2), uspi->s_fpb - lastblockoff, err);
+                                                fs32_to_cpu(sb, *p2), uspi->s_fpb - lastblockoff,
+                                                err, locked_page);
                        if (!tmp) {
                                if (lastfrag != ufsi->i_lastfrag)
                                        goto repeat;
@@ -233,14 +265,16 @@ repeat:
                }
                goal = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock]) + uspi->s_fpb;
                tmp = ufs_new_fragments (inode, p, fragment - blockoff, 
-                       goal, required + blockoff, err);
+                                        goal, required + blockoff,
+                                        err, locked_page);
        }
        /*
         * We will extend last allocated block
         */
        else if (lastblock == block) {
-               tmp = ufs_new_fragments (inode, p, fragment - (blockoff - lastblockoff),
-                       fs32_to_cpu(sb, *p), required +  (blockoff - lastblockoff), err);
+               tmp = ufs_new_fragments(inode, p, fragment - (blockoff - lastblockoff),
+                                       fs32_to_cpu(sb, *p), required +  (blockoff - lastblockoff),
+                                       err, locked_page);
        }
        /*
         * We will allocate new block before last allocated block
@@ -248,8 +282,8 @@ repeat:
        else /* (lastblock > block) */ {
                if (lastblock && (tmp = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock-1])))
                        goal = tmp + uspi->s_fpb;
-               tmp = ufs_new_fragments (inode, p, fragment - blockoff, 
-                       goal, uspi->s_fpb, err);
+               tmp = ufs_new_fragments(inode, p, fragment - blockoff,
+                                       goal, uspi->s_fpb, err, locked_page);
        }
        if (!tmp) {
                if ((!blockoff && *p) || 
@@ -259,14 +293,10 @@ repeat:
                return NULL;
        }
 
-       /* The nullification of framgents done in ufs/balloc.c is
-        * something I don't have the stomache to move into here right
-        * now. -DaveM
-        */
-       if (metadata) {
-               result = sb_getblk(inode->i_sb, tmp + blockoff);
+       if (!phys) {
+               result = ufs_clear_frags(inode, tmp + blockoff, required);
        } else {
-               *phys = tmp;
+               *phys = tmp + blockoff;
                result = NULL;
                *err = 0;
                *new = 1;
@@ -276,7 +306,7 @@ repeat:
        if (IS_SYNC(inode))
                ufs_sync_inode (inode);
        mark_inode_dirty(inode);
-       UFSD(("EXIT, result %u\n", tmp + blockoff))
+       UFSD("EXIT, result %u\n", tmp + blockoff);
        return result;
 
      /* This part : To be implemented ....
@@ -295,22 +325,35 @@ repeat2:
      */
 }
 
-static struct buffer_head * ufs_block_getfrag (struct inode *inode,
-       struct buffer_head *bh, unsigned int fragment, unsigned int new_fragment, 
-       unsigned int blocksize, int * err, int metadata, long *phys, int *new)
+/**
+ * ufs_inode_getblock() - allocate new block
+ * @inode - pointer to inode
+ * @bh - pointer to block which hold "pointer" to new allocated block
+ * @fragment - number of `fragment' which hold pointer
+ *   to new allocated block
+ * @new_fragment - number of new allocated fragment
+ *  (block will hold this fragment and also uspi->s_fpb-1)
+ * @err - see ufs_inode_getfrag()
+ * @phys - see ufs_inode_getfrag()
+ * @new - see ufs_inode_getfrag()
+ * @locked_page - see ufs_inode_getfrag()
+ */
+static struct buffer_head *
+ufs_inode_getblock(struct inode *inode, struct buffer_head *bh,
+                 unsigned int fragment, sector_t new_fragment, int *err,
+                 long *phys, int *new, struct page *locked_page)
 {
-       struct super_block * sb;
-       struct ufs_sb_private_info * uspi;
+       struct super_block *sb = inode->i_sb;
+       struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
        struct buffer_head * result;
        unsigned tmp, goal, block, blockoff;
        __fs32 * p;
 
-       sb = inode->i_sb;
-       uspi = UFS_SB(sb)->s_uspi;
        block = ufs_fragstoblks (fragment);
        blockoff = ufs_fragnum (fragment);
 
-       UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u\n", inode->i_ino, fragment, new_fragment))  
+       UFSD("ENTER, ino %lu, fragment %u, new_fragment %llu, metadata %d\n",
+            inode->i_ino, fragment, (unsigned long long)new_fragment, !phys);
 
        result = NULL;
        if (!bh)
@@ -326,14 +369,14 @@ static struct buffer_head * ufs_block_getfrag (struct inode *inode,
 repeat:
        tmp = fs32_to_cpu(sb, *p);
        if (tmp) {
-               if (metadata) {
+               if (!phys) {
                        result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff);
                        if (tmp == fs32_to_cpu(sb, *p))
                                goto out;
                        brelse (result);
                        goto repeat;
                } else {
-                       *phys = tmp;
+                       *phys = tmp + blockoff;
                        goto out;
                }
        }
@@ -342,21 +385,19 @@ repeat:
                goal = tmp + uspi->s_fpb;
        else
                goal = bh->b_blocknr + uspi->s_fpb;
-       tmp = ufs_new_fragments (inode, p, ufs_blknum(new_fragment), goal, uspi->s_fpb, err);
+       tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), goal,
+                               uspi->s_fpb, err, locked_page);
        if (!tmp) {
                if (fs32_to_cpu(sb, *p))
                        goto repeat;
                goto out;
        }               
 
-       /* The nullification of framgents done in ufs/balloc.c is
-        * something I don't have the stomache to move into here right
-        * now. -DaveM
-        */
-       if (metadata) {
-               result = sb_getblk(sb, tmp + blockoff);
+
+       if (!phys) {
+               result = ufs_clear_frags(inode, tmp + blockoff, uspi->s_fpb);
        } else {
-               *phys = tmp;
+               *phys = tmp + blockoff;
                *new = 1;
        }
 
@@ -365,18 +406,19 @@ repeat:
                sync_dirty_buffer(bh);
        inode->i_ctime = CURRENT_TIME_SEC;
        mark_inode_dirty(inode);
-       UFSD(("result %u\n", tmp + blockoff));
+       UFSD("result %u\n", tmp + blockoff);
 out:
        brelse (bh);
-       UFSD(("EXIT\n"));
+       UFSD("EXIT\n");
        return result;
 }
 
-/*
- * This function gets the block which contains the fragment.
+/**
+ * ufs_getfrag_bloc() - `get_block_t' function, interface between UFS and
+ * readpage, writepage and so on
  */
 
-int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create)
+int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create)
 {
        struct super_block * sb = inode->i_sb;
        struct ufs_sb_private_info * uspi = UFS_SB(sb)->s_uspi;
@@ -387,7 +429,7 @@ int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_hea
        
        if (!create) {
                phys64 = ufs_frag_map(inode, fragment);
-               UFSD(("phys64 = %llu \n",phys64));
+               UFSD("phys64 = %llu \n",phys64);
                if (phys64)
                        map_bh(bh_result, sb, phys64);
                return 0;
@@ -402,7 +444,7 @@ int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_hea
 
        lock_kernel();
 
-       UFSD(("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment))
+       UFSD("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment);
        if (fragment < 0)
                goto abort_negative;
        if (fragment >
@@ -418,15 +460,15 @@ int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_hea
         * it much more readable:
         */
 #define GET_INODE_DATABLOCK(x) \
-               ufs_inode_getfrag(inode, x, fragment, 1, &err, 0, &phys, &new)
+       ufs_inode_getfrag(inode, x, fragment, 1, &err, &phys, &new, bh_result->b_page)
 #define GET_INODE_PTR(x) \
-               ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, 1, NULL, NULL)
+       ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, NULL, NULL, bh_result->b_page)
 #define GET_INDIRECT_DATABLOCK(x) \
-               ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \
-                                 &err, 0, &phys, &new);
+       ufs_inode_getblock(inode, bh, x, fragment,      \
+                         &err, &phys, &new, bh_result->b_page);
 #define GET_INDIRECT_PTR(x) \
-               ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \
-                                 &err, 1, NULL, NULL);
+       ufs_inode_getblock(inode, bh, x, fragment,      \
+                         &err, NULL, NULL, bh_result->b_page);
 
        if (ptr < UFS_NDIR_FRAGMENT) {
                bh = GET_INODE_DATABLOCK(ptr);
@@ -474,8 +516,9 @@ abort_too_big:
        goto abort;
 }
 
-struct buffer_head *ufs_getfrag(struct inode *inode, unsigned int fragment,
-                               int create, int *err)
+static struct buffer_head *ufs_getfrag(struct inode *inode,
+                                      unsigned int fragment,
+                                      int create, int *err)
 {
        struct buffer_head dummy;
        int error;
@@ -502,7 +545,7 @@ struct buffer_head * ufs_bread (struct inode * inode, unsigned fragment,
 {
        struct buffer_head * bh;
 
-       UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
+       UFSD("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment);
        bh = ufs_getfrag (inode, fragment, create, err);
        if (!bh || buffer_uptodate(bh))                 
                return bh;
@@ -540,6 +583,28 @@ struct address_space_operations ufs_aops = {
        .bmap = ufs_bmap
 };
 
+static void ufs_set_inode_ops(struct inode *inode)
+{
+       if (S_ISREG(inode->i_mode)) {
+               inode->i_op = &ufs_file_inode_operations;
+               inode->i_fop = &ufs_file_operations;
+               inode->i_mapping->a_ops = &ufs_aops;
+       } else if (S_ISDIR(inode->i_mode)) {
+               inode->i_op = &ufs_dir_inode_operations;
+               inode->i_fop = &ufs_dir_operations;
+               inode->i_mapping->a_ops = &ufs_aops;
+       } else if (S_ISLNK(inode->i_mode)) {
+               if (!inode->i_blocks)
+                       inode->i_op = &ufs_fast_symlink_inode_operations;
+               else {
+                       inode->i_op = &page_symlink_inode_operations;
+                       inode->i_mapping->a_ops = &ufs_aops;
+               }
+       } else
+               init_special_inode(inode, inode->i_mode,
+                                  ufs_get_inode_dev(inode->i_sb, UFS_I(inode)));
+}
+
 void ufs_read_inode (struct inode * inode)
 {
        struct ufs_inode_info *ufsi = UFS_I(inode);
@@ -552,7 +617,7 @@ void ufs_read_inode (struct inode * inode)
        unsigned i;
        unsigned flags;
        
-       UFSD(("ENTER, ino %lu\n", inode->i_ino))
+       UFSD("ENTER, ino %lu\n", inode->i_ino);
        
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
@@ -603,38 +668,22 @@ void ufs_read_inode (struct inode * inode)
        ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow);
        ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag);
        ufsi->i_lastfrag = (inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift;
+       ufsi->i_dir_start_lookup = 0;
        
        if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) {
                for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++)
                        ufsi->i_u1.i_data[i] = ufs_inode->ui_u2.ui_addr.ui_db[i];
-       }
-       else {
+       } else {
                for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++)
                        ufsi->i_u1.i_symlink[i] = ufs_inode->ui_u2.ui_symlink[i];
        }
        ufsi->i_osync = 0;
 
-       if (S_ISREG(inode->i_mode)) {
-               inode->i_op = &ufs_file_inode_operations;
-               inode->i_fop = &ufs_file_operations;
-               inode->i_mapping->a_ops = &ufs_aops;
-       } else if (S_ISDIR(inode->i_mode)) {
-               inode->i_op = &ufs_dir_inode_operations;
-               inode->i_fop = &ufs_dir_operations;
-       } else if (S_ISLNK(inode->i_mode)) {
-               if (!inode->i_blocks)
-                       inode->i_op = &ufs_fast_symlink_inode_operations;
-               else {
-                       inode->i_op = &page_symlink_inode_operations;
-                       inode->i_mapping->a_ops = &ufs_aops;
-               }
-       } else
-               init_special_inode(inode, inode->i_mode,
-                       ufs_get_inode_dev(sb, ufsi));
+       ufs_set_inode_ops(inode);
 
        brelse (bh);
 
-       UFSD(("EXIT\n"))
+       UFSD("EXIT\n");
        return;
 
 bad_inode:
@@ -642,7 +691,7 @@ bad_inode:
        return;
 
 ufs2_inode :
-       UFSD(("Reading ufs2 inode, ino %lu\n", inode->i_ino))
+       UFSD("Reading ufs2 inode, ino %lu\n", inode->i_ino);
 
        ufs2_inode = (struct ufs2_inode *)(bh->b_data + sizeof(struct ufs2_inode) * ufs_inotofsbo(inode->i_ino));
 
@@ -690,27 +739,11 @@ ufs2_inode :
        }
        ufsi->i_osync = 0;
 
-       if (S_ISREG(inode->i_mode)) {
-               inode->i_op = &ufs_file_inode_operations;
-               inode->i_fop = &ufs_file_operations;
-               inode->i_mapping->a_ops = &ufs_aops;
-       } else if (S_ISDIR(inode->i_mode)) {
-               inode->i_op = &ufs_dir_inode_operations;
-               inode->i_fop = &ufs_dir_operations;
-       } else if (S_ISLNK(inode->i_mode)) {
-               if (!inode->i_blocks)
-                       inode->i_op = &ufs_fast_symlink_inode_operations;
-               else {
-                       inode->i_op = &page_symlink_inode_operations;
-                       inode->i_mapping->a_ops = &ufs_aops;
-               }
-       } else   /* TODO  : here ...*/
-               init_special_inode(inode, inode->i_mode,
-                       ufs_get_inode_dev(sb, ufsi));
+       ufs_set_inode_ops(inode);
 
        brelse(bh);
 
-       UFSD(("EXIT\n"))
+       UFSD("EXIT\n");
        return;
 }
 
@@ -724,7 +757,7 @@ static int ufs_update_inode(struct inode * inode, int do_sync)
        unsigned i;
        unsigned flags;
 
-       UFSD(("ENTER, ino %lu\n", inode->i_ino))
+       UFSD("ENTER, ino %lu\n", inode->i_ino);
 
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
@@ -785,7 +818,7 @@ static int ufs_update_inode(struct inode * inode, int do_sync)
                sync_dirty_buffer(bh);
        brelse (bh);
        
-       UFSD(("EXIT\n"))
+       UFSD("EXIT\n");
        return 0;
 }
 
index 8d5f98a01c7484010803d732124398f9124b30e7..abd5f23a426d5918f0bbe5b41ce4f6600a63d19f 100644 (file)
@@ -1,6 +1,9 @@
 /*
  * linux/fs/ufs/namei.c
  *
+ * Migration to usage of "page cache" on May 2006 by
+ * Evgeniy Dushistov <dushistov@mail.ru> based on ext2 code base.
+ *
  * Copyright (C) 1998
  * Daniel Pirkl <daniel.pirkl@email.cz>
  * Charles University, Faculty of Mathematics and Physics
 #include <linux/fs.h>
 #include <linux/ufs_fs.h>
 #include <linux/smp_lock.h>
-#include <linux/buffer_head.h>
 #include "swab.h"      /* will go away - see comment in mknod() */
 #include "util.h"
 
-/*
-#undef UFS_NAMEI_DEBUG
-*/
-#define UFS_NAMEI_DEBUG
-
-#ifdef UFS_NAMEI_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
 static inline int ufs_add_nondir(struct dentry *dentry, struct inode *inode)
 {
        int err = ufs_add_link(dentry, inode);
@@ -88,8 +79,13 @@ static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, stru
 static int ufs_create (struct inode * dir, struct dentry * dentry, int mode,
                struct nameidata *nd)
 {
-       struct inode * inode = ufs_new_inode(dir, mode);
-       int err = PTR_ERR(inode);
+       struct inode *inode;
+       int err;
+
+       UFSD("BEGIN\n");
+       inode = ufs_new_inode(dir, mode);
+       err = PTR_ERR(inode);
+
        if (!IS_ERR(inode)) {
                inode->i_op = &ufs_file_inode_operations;
                inode->i_fop = &ufs_file_operations;
@@ -99,6 +95,7 @@ static int ufs_create (struct inode * dir, struct dentry * dentry, int mode,
                err = ufs_add_nondir(dentry, inode);
                unlock_kernel();
        }
+       UFSD("END: err=%d\n", err);
        return err;
 }
 
@@ -205,6 +202,7 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
 
        inode->i_op = &ufs_dir_inode_operations;
        inode->i_fop = &ufs_dir_operations;
+       inode->i_mapping->a_ops = &ufs_aops;
 
        inode_inc_link_count(inode);
 
@@ -231,19 +229,18 @@ out_dir:
        goto out;
 }
 
-static int ufs_unlink(struct inode * dir, struct dentry *dentry)
+static int ufs_unlink(struct inode *dir, struct dentry *dentry)
 {
        struct inode * inode = dentry->d_inode;
-       struct buffer_head * bh;
-       struct ufs_dir_entry * de;
+       struct ufs_dir_entry *de;
+       struct page *page;
        int err = -ENOENT;
 
-       lock_kernel();
-       de = ufs_find_entry (dentry, &bh);
+       de = ufs_find_entry(dir, dentry, &page);
        if (!de)
                goto out;
 
-       err = ufs_delete_entry (dir, de, bh);
+       err = ufs_delete_entry(dir, de, page);
        if (err)
                goto out;
 
@@ -251,7 +248,6 @@ static int ufs_unlink(struct inode * dir, struct dentry *dentry)
        inode_dec_link_count(inode);
        err = 0;
 out:
-       unlock_kernel();
        return err;
 }
 
@@ -273,42 +269,42 @@ static int ufs_rmdir (struct inode * dir, struct dentry *dentry)
        return err;
 }
 
-static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
-       struct inode * new_dir, struct dentry * new_dentry )
+static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
+                     struct inode *new_dir, struct dentry *new_dentry)
 {
        struct inode *old_inode = old_dentry->d_inode;
        struct inode *new_inode = new_dentry->d_inode;
-       struct buffer_head *dir_bh = NULL;
-       struct ufs_dir_entry *dir_de = NULL;
-       struct buffer_head *old_bh;
+       struct page *dir_page = NULL;
+       struct ufs_dir_entry * dir_de = NULL;
+       struct page *old_page;
        struct ufs_dir_entry *old_de;
        int err = -ENOENT;
 
-       lock_kernel();
-       old_de = ufs_find_entry (old_dentry, &old_bh);
+       old_de = ufs_find_entry(old_dir, old_dentry, &old_page);
        if (!old_de)
                goto out;
 
        if (S_ISDIR(old_inode->i_mode)) {
                err = -EIO;
-               dir_de = ufs_dotdot(old_inode, &dir_bh);
+               dir_de = ufs_dotdot(old_inode, &dir_page);
                if (!dir_de)
                        goto out_old;
        }
 
        if (new_inode) {
-               struct buffer_head *new_bh;
+               struct page *new_page;
                struct ufs_dir_entry *new_de;
 
                err = -ENOTEMPTY;
-               if (dir_de && !ufs_empty_dir (new_inode))
+               if (dir_de && !ufs_empty_dir(new_inode))
                        goto out_dir;
+
                err = -ENOENT;
-               new_de = ufs_find_entry (new_dentry, &new_bh);
+               new_de = ufs_find_entry(new_dir, new_dentry, &new_page);
                if (!new_de)
                        goto out_dir;
                inode_inc_link_count(old_inode);
-               ufs_set_link(new_dir, new_de, new_bh, old_inode);
+               ufs_set_link(new_dir, new_de, new_page, old_inode);
                new_inode->i_ctime = CURRENT_TIME_SEC;
                if (dir_de)
                        new_inode->i_nlink--;
@@ -329,24 +325,32 @@ static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
                        inode_inc_link_count(new_dir);
        }
 
-       ufs_delete_entry (old_dir, old_de, old_bh);
+       /*
+        * Like most other Unix systems, set the ctime for inodes on a
+        * rename.
+        * inode_dec_link_count() will mark the inode dirty.
+        */
+       old_inode->i_ctime = CURRENT_TIME_SEC;
 
+       ufs_delete_entry(old_dir, old_de, old_page);
        inode_dec_link_count(old_inode);
 
        if (dir_de) {
-               ufs_set_link(old_inode, dir_de, dir_bh, new_dir);
+               ufs_set_link(old_inode, dir_de, dir_page, new_dir);
                inode_dec_link_count(old_dir);
        }
-       unlock_kernel();
        return 0;
 
+
 out_dir:
-       if (dir_de)
-               brelse(dir_bh);
+       if (dir_de) {
+               kunmap(dir_page);
+               page_cache_release(dir_page);
+       }
 out_old:
-       brelse (old_bh);
+       kunmap(old_page);
+       page_cache_release(old_page);
 out:
-       unlock_kernel();
        return err;
 }
 
index fe5ab2aa289936f062ce2c5fe43a8f6ed220315e..74ef5e9bedffaf764c5e51a5492c803a0ff15f31 100644 (file)
 #include "swab.h"
 #include "util.h"
 
-#undef UFS_SUPER_DEBUG
-#undef UFS_SUPER_DEBUG_MORE
-
-
-#undef UFS_SUPER_DEBUG_MORE
-#ifdef UFS_SUPER_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
-#ifdef UFS_SUPER_DEBUG_MORE
+#ifdef CONFIG_UFS_DEBUG
 /*
  * Print contents of ufs_super_block, useful for debugging
  */
-void ufs_print_super_stuff(struct super_block *sb,
-       struct ufs_super_block_first * usb1,
-       struct ufs_super_block_second * usb2, 
-       struct ufs_super_block_third * usb3)
+static void ufs_print_super_stuff(struct super_block *sb, unsigned flags,
+                                 struct ufs_super_block_first *usb1,
+                                 struct ufs_super_block_second *usb2,
+                                 struct ufs_super_block_third *usb3)
 {
        printk("ufs_print_super_stuff\n");
-       printk("size of usb:     %u\n", sizeof(struct ufs_super_block));
-       printk("  magic:         0x%x\n", fs32_to_cpu(sb, usb3->fs_magic));
-       printk("  sblkno:        %u\n", fs32_to_cpu(sb, usb1->fs_sblkno));
-       printk("  cblkno:        %u\n", fs32_to_cpu(sb, usb1->fs_cblkno));
-       printk("  iblkno:        %u\n", fs32_to_cpu(sb, usb1->fs_iblkno));
-       printk("  dblkno:        %u\n", fs32_to_cpu(sb, usb1->fs_dblkno));
-       printk("  cgoffset:      %u\n", fs32_to_cpu(sb, usb1->fs_cgoffset));
-       printk("  ~cgmask:       0x%x\n", ~fs32_to_cpu(sb, usb1->fs_cgmask));
-       printk("  size:          %u\n", fs32_to_cpu(sb, usb1->fs_size));
-       printk("  dsize:         %u\n", fs32_to_cpu(sb, usb1->fs_dsize));
-       printk("  ncg:           %u\n", fs32_to_cpu(sb, usb1->fs_ncg));
-       printk("  bsize:         %u\n", fs32_to_cpu(sb, usb1->fs_bsize));
-       printk("  fsize:         %u\n", fs32_to_cpu(sb, usb1->fs_fsize));
-       printk("  frag:          %u\n", fs32_to_cpu(sb, usb1->fs_frag));
-       printk("  fragshift:     %u\n", fs32_to_cpu(sb, usb1->fs_fragshift));
-       printk("  ~fmask:        %u\n", ~fs32_to_cpu(sb, usb1->fs_fmask));
-       printk("  fshift:        %u\n", fs32_to_cpu(sb, usb1->fs_fshift));
-       printk("  sbsize:        %u\n", fs32_to_cpu(sb, usb1->fs_sbsize));
-       printk("  spc:           %u\n", fs32_to_cpu(sb, usb1->fs_spc));
-       printk("  cpg:           %u\n", fs32_to_cpu(sb, usb1->fs_cpg));
-       printk("  ipg:           %u\n", fs32_to_cpu(sb, usb1->fs_ipg));
-       printk("  fpg:           %u\n", fs32_to_cpu(sb, usb1->fs_fpg));
-       printk("  csaddr:        %u\n", fs32_to_cpu(sb, usb1->fs_csaddr));
-       printk("  cssize:        %u\n", fs32_to_cpu(sb, usb1->fs_cssize));
-       printk("  cgsize:        %u\n", fs32_to_cpu(sb, usb1->fs_cgsize));
-       printk("  fstodb:        %u\n", fs32_to_cpu(sb, usb1->fs_fsbtodb));
-       printk("  contigsumsize: %d\n", fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_contigsumsize));
-       printk("  postblformat:  %u\n", fs32_to_cpu(sb, usb3->fs_postblformat));
-       printk("  nrpos:         %u\n", fs32_to_cpu(sb, usb3->fs_nrpos));
-       printk("  ndir           %u\n", fs32_to_cpu(sb, usb1->fs_cstotal.cs_ndir));
-       printk("  nifree         %u\n", fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree));
-       printk("  nbfree         %u\n", fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree));
-       printk("  nffree         %u\n", fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree));
-       printk("\n");
-}
-
-/*
- * Print contents of ufs2 ufs_super_block, useful for debugging
- */
-void ufs2_print_super_stuff(
-     struct super_block *sb,
-      struct ufs_super_block *usb)
-{
-       printk("ufs_print_super_stuff\n");
-       printk("size of usb:     %u\n", sizeof(struct ufs_super_block));
-       printk("  magic:         0x%x\n", fs32_to_cpu(sb, usb->fs_magic));
-       printk("  fs_size:   %u\n",fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_size));
-       printk("  fs_dsize:  %u\n",fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize));
-       printk("  bsize:         %u\n", fs32_to_cpu(usb, usb->fs_bsize));
-       printk("  fsize:         %u\n", fs32_to_cpu(usb, usb->fs_fsize));
-       printk("  fs_volname:  %s\n", usb->fs_u11.fs_u2.fs_volname);
-       printk("  fs_fsmnt:  %s\n", usb->fs_u11.fs_u2.fs_fsmnt);
-       printk("  fs_sblockloc: %u\n",fs64_to_cpu(sb,
-                       usb->fs_u11.fs_u2.fs_sblockloc));
-       printk("  cs_ndir(No of dirs):  %u\n",fs64_to_cpu(sb,
-                       usb->fs_u11.fs_u2.fs_cstotal.cs_ndir));
-       printk("  cs_nbfree(No of free blocks):  %u\n",fs64_to_cpu(sb,
-                       usb->fs_u11.fs_u2.fs_cstotal.cs_nbfree));
+       printk("  magic:     0x%x\n", fs32_to_cpu(sb, usb3->fs_magic));
+       if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+               printk("  fs_size:   %llu\n", (unsigned long long)
+                      fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_size));
+               printk("  fs_dsize:  %llu\n", (unsigned long long)
+                      fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_dsize));
+               printk("  bsize:         %u\n",
+                      fs32_to_cpu(sb, usb1->fs_bsize));
+               printk("  fsize:         %u\n",
+                      fs32_to_cpu(sb, usb1->fs_fsize));
+               printk("  fs_volname:  %s\n", usb2->fs_un.fs_u2.fs_volname);
+               printk("  fs_sblockloc: %llu\n", (unsigned long long)
+                      fs64_to_cpu(sb, usb2->fs_un.fs_u2.fs_sblockloc));
+               printk("  cs_ndir(No of dirs):  %llu\n", (unsigned long long)
+                      fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_ndir));
+               printk("  cs_nbfree(No of free blocks):  %llu\n",
+                      (unsigned long long)
+                      fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_nbfree));
+       } else {
+               printk(" sblkno:      %u\n", fs32_to_cpu(sb, usb1->fs_sblkno));
+               printk(" cblkno:      %u\n", fs32_to_cpu(sb, usb1->fs_cblkno));
+               printk(" iblkno:      %u\n", fs32_to_cpu(sb, usb1->fs_iblkno));
+               printk(" dblkno:      %u\n", fs32_to_cpu(sb, usb1->fs_dblkno));
+               printk(" cgoffset:    %u\n",
+                      fs32_to_cpu(sb, usb1->fs_cgoffset));
+               printk(" ~cgmask:     0x%x\n",
+                      ~fs32_to_cpu(sb, usb1->fs_cgmask));
+               printk(" size:        %u\n", fs32_to_cpu(sb, usb1->fs_size));
+               printk(" dsize:       %u\n", fs32_to_cpu(sb, usb1->fs_dsize));
+               printk(" ncg:         %u\n", fs32_to_cpu(sb, usb1->fs_ncg));
+               printk(" bsize:       %u\n", fs32_to_cpu(sb, usb1->fs_bsize));
+               printk(" fsize:       %u\n", fs32_to_cpu(sb, usb1->fs_fsize));
+               printk(" frag:        %u\n", fs32_to_cpu(sb, usb1->fs_frag));
+               printk(" fragshift:   %u\n",
+                      fs32_to_cpu(sb, usb1->fs_fragshift));
+               printk(" ~fmask:      %u\n", ~fs32_to_cpu(sb, usb1->fs_fmask));
+               printk(" fshift:      %u\n", fs32_to_cpu(sb, usb1->fs_fshift));
+               printk(" sbsize:      %u\n", fs32_to_cpu(sb, usb1->fs_sbsize));
+               printk(" spc:         %u\n", fs32_to_cpu(sb, usb1->fs_spc));
+               printk(" cpg:         %u\n", fs32_to_cpu(sb, usb1->fs_cpg));
+               printk(" ipg:         %u\n", fs32_to_cpu(sb, usb1->fs_ipg));
+               printk(" fpg:         %u\n", fs32_to_cpu(sb, usb1->fs_fpg));
+               printk(" csaddr:      %u\n", fs32_to_cpu(sb, usb1->fs_csaddr));
+               printk(" cssize:      %u\n", fs32_to_cpu(sb, usb1->fs_cssize));
+               printk(" cgsize:      %u\n", fs32_to_cpu(sb, usb1->fs_cgsize));
+               printk(" fstodb:      %u\n",
+                      fs32_to_cpu(sb, usb1->fs_fsbtodb));
+               printk(" nrpos:       %u\n", fs32_to_cpu(sb, usb3->fs_nrpos));
+               printk(" ndir         %u\n",
+                      fs32_to_cpu(sb, usb1->fs_cstotal.cs_ndir));
+               printk(" nifree       %u\n",
+                      fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree));
+               printk(" nbfree       %u\n",
+                      fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree));
+               printk(" nffree       %u\n",
+                      fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree));
+       }
        printk("\n");
 }
 
 /*
  * Print contents of ufs_cylinder_group, useful for debugging
  */
-void ufs_print_cylinder_stuff(struct super_block *sb, struct ufs_cylinder_group *cg)
+static void ufs_print_cylinder_stuff(struct super_block *sb,
+                                    struct ufs_cylinder_group *cg)
 {
        printk("\nufs_print_cylinder_stuff\n");
-       printk("size of ucg: %u\n", sizeof(struct ufs_cylinder_group));
+       printk("size of ucg: %zu\n", sizeof(struct ufs_cylinder_group));
        printk("  magic:        %x\n", fs32_to_cpu(sb, cg->cg_magic));
        printk("  time:         %u\n", fs32_to_cpu(sb, cg->cg_time));
        printk("  cgx:          %u\n", fs32_to_cpu(sb, cg->cg_cgx));
@@ -202,12 +191,18 @@ void ufs_print_cylinder_stuff(struct super_block *sb, struct ufs_cylinder_group
        printk("  iuseoff:      %u\n", fs32_to_cpu(sb, cg->cg_iusedoff));
        printk("  freeoff:      %u\n", fs32_to_cpu(sb, cg->cg_freeoff));
        printk("  nextfreeoff:  %u\n", fs32_to_cpu(sb, cg->cg_nextfreeoff));
-       printk("  clustersumoff %u\n", fs32_to_cpu(sb, cg->cg_u.cg_44.cg_clustersumoff));
-       printk("  clusteroff    %u\n", fs32_to_cpu(sb, cg->cg_u.cg_44.cg_clusteroff));
-       printk("  nclusterblks  %u\n", fs32_to_cpu(sb, cg->cg_u.cg_44.cg_nclusterblks));
+       printk("  clustersumoff %u\n",
+              fs32_to_cpu(sb, cg->cg_u.cg_44.cg_clustersumoff));
+       printk("  clusteroff    %u\n",
+              fs32_to_cpu(sb, cg->cg_u.cg_44.cg_clusteroff));
+       printk("  nclusterblks  %u\n",
+              fs32_to_cpu(sb, cg->cg_u.cg_44.cg_nclusterblks));
        printk("\n");
 }
-#endif /* UFS_SUPER_DEBUG_MORE */
+#else
+#  define ufs_print_super_stuff(sb, flags, usb1, usb2, usb3) /**/
+#  define ufs_print_cylinder_stuff(sb, cg) /**/
+#endif /* CONFIG_UFS_DEBUG */
 
 static struct super_operations ufs_super_ops;
 
@@ -225,7 +220,7 @@ void ufs_error (struct super_block * sb, const char * function,
        
        if (!(sb->s_flags & MS_RDONLY)) {
                usb1->fs_clean = UFS_FSBAD;
-               ubh_mark_buffer_dirty(USPI_UBH);
+               ubh_mark_buffer_dirty(USPI_UBH(uspi));
                sb->s_dirt = 1;
                sb->s_flags |= MS_RDONLY;
        }
@@ -257,7 +252,7 @@ void ufs_panic (struct super_block * sb, const char * function,
        
        if (!(sb->s_flags & MS_RDONLY)) {
                usb1->fs_clean = UFS_FSBAD;
-               ubh_mark_buffer_dirty(USPI_UBH);
+               ubh_mark_buffer_dirty(USPI_UBH(uspi));
                sb->s_dirt = 1;
        }
        va_start (args, fmt);
@@ -309,7 +304,7 @@ static int ufs_parse_options (char * options, unsigned * mount_options)
 {
        char * p;
        
-       UFSD(("ENTER\n"))
+       UFSD("ENTER\n");
        
        if (!options)
                return 1;
@@ -385,28 +380,58 @@ static int ufs_parse_options (char * options, unsigned * mount_options)
        return 1;
 }
 
+/*
+ * Diffrent types of UFS hold fs_cstotal in different
+ * places, and use diffrent data structure for it.
+ * To make things simplier we just copy fs_cstotal to ufs_sb_private_info
+ */
+static void ufs_setup_cstotal(struct super_block *sb)
+{
+       struct ufs_sb_info *sbi = UFS_SB(sb);
+       struct ufs_sb_private_info *uspi = sbi->s_uspi;
+       struct ufs_super_block_first *usb1;
+       struct ufs_super_block_second *usb2;
+       struct ufs_super_block_third *usb3;
+       unsigned mtype = sbi->s_mount_opt & UFS_MOUNT_UFSTYPE;
+
+       UFSD("ENTER, mtype=%u\n", mtype);
+       usb1 = ubh_get_usb_first(uspi);
+       usb2 = ubh_get_usb_second(uspi);
+       usb3 = ubh_get_usb_third(uspi);
+
+       if ((mtype == UFS_MOUNT_UFSTYPE_44BSD &&
+            (usb1->fs_flags & UFS_FLAGS_UPDATED)) ||
+           mtype == UFS_MOUNT_UFSTYPE_UFS2) {
+               /*we have statistic in different place, then usual*/
+               uspi->cs_total.cs_ndir = fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_ndir);
+               uspi->cs_total.cs_nbfree = fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_nbfree);
+               uspi->cs_total.cs_nifree = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.cs_nifree);
+               uspi->cs_total.cs_nffree = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.cs_nffree);
+       } else {
+               uspi->cs_total.cs_ndir = fs32_to_cpu(sb, usb1->fs_cstotal.cs_ndir);
+               uspi->cs_total.cs_nbfree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree);
+               uspi->cs_total.cs_nifree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree);
+               uspi->cs_total.cs_nffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree);
+       }
+       UFSD("EXIT\n");
+}
+
 /*
  * Read on-disk structures associated with cylinder groups
  */
-static int ufs_read_cylinder_structures (struct super_block *sb)
+static int ufs_read_cylinder_structures(struct super_block *sb)
 {
-       struct ufs_sb_info * sbi = UFS_SB(sb);
-       struct ufs_sb_private_info * uspi;
-       struct ufs_super_block *usb;
+       struct ufs_sb_info *sbi = UFS_SB(sb);
+       struct ufs_sb_private_info *uspi = sbi->s_uspi;
+       unsigned flags = sbi->s_flags;
        struct ufs_buffer_head * ubh;
        unsigned char * base, * space;
        unsigned size, blks, i;
-       unsigned flags = 0;
-       
-       UFSD(("ENTER\n"))
-       
-       uspi = sbi->s_uspi;
+       struct ufs_super_block_third *usb3;
 
-       usb  = (struct ufs_super_block *)
-               ((struct ufs_buffer_head *)uspi)->bh[0]->b_data;
+       UFSD("ENTER\n");
 
-        flags = UFS_SB(sb)->s_flags;
-       
+       usb3 = ubh_get_usb_third(uspi);
        /*
         * Read cs structures from (usually) first data block
         * on the device. 
@@ -424,7 +449,7 @@ static int ufs_read_cylinder_structures (struct super_block *sb)
 
                if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) 
                        ubh = ubh_bread(sb,
-                               fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_csaddr) + i, size);
+                               fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_csaddr) + i, size);
                else 
                        ubh = ubh_bread(sb, uspi->s_csaddr + i, size);
                
@@ -451,14 +476,13 @@ static int ufs_read_cylinder_structures (struct super_block *sb)
                sbi->s_cgno[i] = UFS_CGNO_EMPTY;
        }
        for (i = 0; i < uspi->s_ncg; i++) {
-               UFSD(("read cg %u\n", i))
+               UFSD("read cg %u\n", i);
                if (!(sbi->s_ucg[i] = sb_bread(sb, ufs_cgcmin(i))))
                        goto failed;
                if (!ufs_cg_chkmagic (sb, (struct ufs_cylinder_group *) sbi->s_ucg[i]->b_data))
                        goto failed;
-#ifdef UFS_SUPER_DEBUG_MORE
+
                ufs_print_cylinder_stuff(sb, (struct ufs_cylinder_group *) sbi->s_ucg[i]->b_data);
-#endif
        }
        for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
                if (!(sbi->s_ucpi[i] = kmalloc (sizeof(struct ufs_cg_private_info), GFP_KERNEL)))
@@ -466,7 +490,7 @@ static int ufs_read_cylinder_structures (struct super_block *sb)
                sbi->s_cgno[i] = UFS_CGNO_EMPTY;
        }
        sbi->s_cg_loaded = 0;
-       UFSD(("EXIT\n"))
+       UFSD("EXIT\n");
        return 1;
 
 failed:
@@ -479,26 +503,69 @@ failed:
                for (i = 0; i < UFS_MAX_GROUP_LOADED; i++)
                        kfree (sbi->s_ucpi[i]);
        }
-       UFSD(("EXIT (FAILED)\n"))
+       UFSD("EXIT (FAILED)\n");
        return 0;
 }
 
 /*
- * Put on-disk structures associated with cylinder groups and 
- * write them back to disk
+ * Sync our internal copy of fs_cstotal with disk
  */
-static void ufs_put_cylinder_structures (struct super_block *sb)
+static void ufs_put_cstotal(struct super_block *sb)
 {
-       struct ufs_sb_info * sbi = UFS_SB(sb);
-       struct ufs_sb_private_info * uspi;
+       unsigned mtype = UFS_SB(sb)->s_mount_opt & UFS_MOUNT_UFSTYPE;
+       struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
+       struct ufs_super_block_first *usb1;
+       struct ufs_super_block_second *usb2;
+       struct ufs_super_block_third *usb3;
+
+       UFSD("ENTER\n");
+       usb1 = ubh_get_usb_first(uspi);
+       usb2 = ubh_get_usb_second(uspi);
+       usb3 = ubh_get_usb_third(uspi);
+
+       if ((mtype == UFS_MOUNT_UFSTYPE_44BSD &&
+            (usb1->fs_flags & UFS_FLAGS_UPDATED)) ||
+           mtype == UFS_MOUNT_UFSTYPE_UFS2) {
+               /*we have statistic in different place, then usual*/
+               usb2->fs_un.fs_u2.cs_ndir =
+                       cpu_to_fs64(sb, uspi->cs_total.cs_ndir);
+               usb2->fs_un.fs_u2.cs_nbfree =
+                       cpu_to_fs64(sb, uspi->cs_total.cs_nbfree);
+               usb3->fs_un1.fs_u2.cs_nifree =
+                       cpu_to_fs64(sb, uspi->cs_total.cs_nifree);
+               usb3->fs_un1.fs_u2.cs_nffree =
+                       cpu_to_fs64(sb, uspi->cs_total.cs_nffree);
+       } else {
+               usb1->fs_cstotal.cs_ndir =
+                       cpu_to_fs32(sb, uspi->cs_total.cs_ndir);
+               usb1->fs_cstotal.cs_nbfree =
+                       cpu_to_fs32(sb, uspi->cs_total.cs_nbfree);
+               usb1->fs_cstotal.cs_nifree =
+                       cpu_to_fs32(sb, uspi->cs_total.cs_nifree);
+               usb1->fs_cstotal.cs_nffree =
+                       cpu_to_fs32(sb, uspi->cs_total.cs_nffree);
+       }
+       ubh_mark_buffer_dirty(USPI_UBH(uspi));
+       UFSD("EXIT\n");
+}
+
+/**
+ * ufs_put_super_internal() - put on-disk intrenal structures
+ * @sb: pointer to super_block structure
+ * Put on-disk structures associated with cylinder groups
+ * and write them back to disk, also update cs_total on disk
+ */
+static void ufs_put_super_internal(struct super_block *sb)
+{
+       struct ufs_sb_info *sbi = UFS_SB(sb);
+       struct ufs_sb_private_info *uspi = sbi->s_uspi;
        struct ufs_buffer_head * ubh;
        unsigned char * base, * space;
        unsigned blks, size, i;
-       
-       UFSD(("ENTER\n"))
-       
-       uspi = sbi->s_uspi;
 
+       
+       UFSD("ENTER\n");
+       ufs_put_cstotal(sb);
        size = uspi->s_cssize;
        blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift;
        base = space = (char*) sbi->s_csp;
@@ -523,7 +590,7 @@ static void ufs_put_cylinder_structures (struct super_block *sb)
                brelse (sbi->s_ucg[i]);
        kfree (sbi->s_ucg);
        kfree (base);
-       UFSD(("EXIT\n"))
+       UFSD("EXIT\n");
 }
 
 static int ufs_fill_super(struct super_block *sb, void *data, int silent)
@@ -533,7 +600,6 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
        struct ufs_super_block_first * usb1;
        struct ufs_super_block_second * usb2;
        struct ufs_super_block_third * usb3;
-       struct ufs_super_block *usb;
        struct ufs_buffer_head * ubh;   
        struct inode *inode;
        unsigned block_size, super_block_size;
@@ -544,7 +610,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
        ubh = NULL;
        flags = 0;
        
-       UFSD(("ENTER\n"))
+       UFSD("ENTER\n");
                
        sbi = kmalloc(sizeof(struct ufs_sb_info), GFP_KERNEL);
        if (!sbi)
@@ -552,7 +618,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_fs_info = sbi;
        memset(sbi, 0, sizeof(struct ufs_sb_info));
 
-       UFSD(("flag %u\n", (int)(sb->s_flags & MS_RDONLY)))
+       UFSD("flag %u\n", (int)(sb->s_flags & MS_RDONLY));
        
 #ifndef CONFIG_UFS_FS_WRITE
        if (!(sb->s_flags & MS_RDONLY)) {
@@ -593,7 +659,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
           the rules */
        switch (sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) {
        case UFS_MOUNT_UFSTYPE_44BSD:
-               UFSD(("ufstype=44bsd\n"))
+               UFSD("ufstype=44bsd\n");
                uspi->s_fsize = block_size = 512;
                uspi->s_fmask = ~(512 - 1);
                uspi->s_fshift = 9;
@@ -602,7 +668,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
                flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD;
                break;
        case UFS_MOUNT_UFSTYPE_UFS2:
-               UFSD(("ufstype=ufs2\n"));
+               UFSD("ufstype=ufs2\n");
                super_block_offset=SBLOCK_UFS2;
                uspi->s_fsize = block_size = 512;
                uspi->s_fmask = ~(512 - 1);
@@ -617,7 +683,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
                break;
                
        case UFS_MOUNT_UFSTYPE_SUN:
-               UFSD(("ufstype=sun\n"))
+               UFSD("ufstype=sun\n");
                uspi->s_fsize = block_size = 1024;
                uspi->s_fmask = ~(1024 - 1);
                uspi->s_fshift = 10;
@@ -628,7 +694,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
                break;
 
        case UFS_MOUNT_UFSTYPE_SUNx86:
-               UFSD(("ufstype=sunx86\n"))
+               UFSD("ufstype=sunx86\n");
                uspi->s_fsize = block_size = 1024;
                uspi->s_fmask = ~(1024 - 1);
                uspi->s_fshift = 10;
@@ -639,7 +705,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
                break;
 
        case UFS_MOUNT_UFSTYPE_OLD:
-               UFSD(("ufstype=old\n"))
+               UFSD("ufstype=old\n");
                uspi->s_fsize = block_size = 1024;
                uspi->s_fmask = ~(1024 - 1);
                uspi->s_fshift = 10;
@@ -654,7 +720,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
                break;
        
        case UFS_MOUNT_UFSTYPE_NEXTSTEP:
-               UFSD(("ufstype=nextstep\n"))
+               UFSD("ufstype=nextstep\n");
                uspi->s_fsize = block_size = 1024;
                uspi->s_fmask = ~(1024 - 1);
                uspi->s_fshift = 10;
@@ -669,7 +735,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
                break;
        
        case UFS_MOUNT_UFSTYPE_NEXTSTEP_CD:
-               UFSD(("ufstype=nextstep-cd\n"))
+               UFSD("ufstype=nextstep-cd\n");
                uspi->s_fsize = block_size = 2048;
                uspi->s_fmask = ~(2048 - 1);
                uspi->s_fshift = 11;
@@ -684,7 +750,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
                break;
        
        case UFS_MOUNT_UFSTYPE_OPENSTEP:
-               UFSD(("ufstype=openstep\n"))
+               UFSD("ufstype=openstep\n");
                uspi->s_fsize = block_size = 1024;
                uspi->s_fmask = ~(1024 - 1);
                uspi->s_fshift = 10;
@@ -699,7 +765,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
                break;
        
        case UFS_MOUNT_UFSTYPE_HP:
-               UFSD(("ufstype=hp\n"))
+               UFSD("ufstype=hp\n");
                uspi->s_fsize = block_size = 1024;
                uspi->s_fmask = ~(1024 - 1);
                uspi->s_fshift = 10;
@@ -737,8 +803,6 @@ again:
        usb1 = ubh_get_usb_first(uspi);
        usb2 = ubh_get_usb_second(uspi);
        usb3 = ubh_get_usb_third(uspi);
-       usb  = (struct ufs_super_block *)
-               ((struct ufs_buffer_head *)uspi)->bh[0]->b_data ;
 
        /*
         * Check ufs magic number
@@ -820,16 +884,12 @@ magic_found:
                ubh = NULL;
                block_size = uspi->s_fsize;
                super_block_size = uspi->s_sbsize;
-               UFSD(("another value of block_size or super_block_size %u, %u\n", block_size, super_block_size))
+               UFSD("another value of block_size or super_block_size %u, %u\n", block_size, super_block_size);
                goto again;
        }
 
-#ifdef UFS_SUPER_DEBUG_MORE
-        if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
-               ufs2_print_super_stuff(sb,usb);
-        else
-               ufs_print_super_stuff(sb, usb1, usb2, usb3);
-#endif
+
+       ufs_print_super_stuff(sb, flags, usb1, usb2, usb3);
 
        /*
         * Check, if file system was correctly unmounted.
@@ -842,13 +902,13 @@ magic_found:
          (ufs_get_fs_state(sb, usb1, usb3) == (UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time))))) {
                switch(usb1->fs_clean) {
                case UFS_FSCLEAN:
-                       UFSD(("fs is clean\n"))
+                       UFSD("fs is clean\n");
                        break;
                case UFS_FSSTABLE:
-                       UFSD(("fs is stable\n"))
+                       UFSD("fs is stable\n");
                        break;
                case UFS_FSOSF1:
-                       UFSD(("fs is DEC OSF/1\n"))
+                       UFSD("fs is DEC OSF/1\n");
                        break;
                case UFS_FSACTIVE:
                        printk("ufs_read_super: fs is active\n");
@@ -863,8 +923,7 @@ magic_found:
                        sb->s_flags |= MS_RDONLY;
                        break;
                }
-       }
-       else {
+       } else {
                printk("ufs_read_super: fs needs fsck\n");
                sb->s_flags |= MS_RDONLY;
        }
@@ -884,10 +943,9 @@ magic_found:
        uspi->s_cgmask = fs32_to_cpu(sb, usb1->fs_cgmask);
 
        if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
-               uspi->s_u2_size  = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_size);
-               uspi->s_u2_dsize = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize);
-       }
-       else {
+               uspi->s_u2_size  = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_size);
+               uspi->s_u2_dsize = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_dsize);
+       } else {
                uspi->s_size  =  fs32_to_cpu(sb, usb1->fs_size);
                uspi->s_dsize =  fs32_to_cpu(sb, usb1->fs_dsize);
        }
@@ -901,8 +959,8 @@ magic_found:
        uspi->s_fmask = fs32_to_cpu(sb, usb1->fs_fmask);
        uspi->s_bshift = fs32_to_cpu(sb, usb1->fs_bshift);
        uspi->s_fshift = fs32_to_cpu(sb, usb1->fs_fshift);
-       UFSD(("uspi->s_bshift = %d,uspi->s_fshift = %d", uspi->s_bshift,
-               uspi->s_fshift));
+       UFSD("uspi->s_bshift = %d,uspi->s_fshift = %d", uspi->s_bshift,
+               uspi->s_fshift);
        uspi->s_fpbshift = fs32_to_cpu(sb, usb1->fs_fragshift);
        uspi->s_fsbtodb = fs32_to_cpu(sb, usb1->fs_fsbtodb);
        /* s_sbsize already set */
@@ -922,8 +980,8 @@ magic_found:
        uspi->s_spc = fs32_to_cpu(sb, usb1->fs_spc);
        uspi->s_ipg = fs32_to_cpu(sb, usb1->fs_ipg);
        uspi->s_fpg = fs32_to_cpu(sb, usb1->fs_fpg);
-       uspi->s_cpc = fs32_to_cpu(sb, usb2->fs_cpc);
-       uspi->s_contigsumsize = fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_contigsumsize);
+       uspi->s_cpc = fs32_to_cpu(sb, usb2->fs_un.fs_u1.fs_cpc);
+       uspi->s_contigsumsize = fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_contigsumsize);
        uspi->s_qbmask = ufs_get_fs_qbmask(sb, usb3);
        uspi->s_qfmask = ufs_get_fs_qfmask(sb, usb3);
        uspi->s_postblformat = fs32_to_cpu(sb, usb3->fs_postblformat);
@@ -935,12 +993,11 @@ magic_found:
         * Compute another frequently used values
         */
        uspi->s_fpbmask = uspi->s_fpb - 1;
-       if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+       if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
                uspi->s_apbshift = uspi->s_bshift - 3;
-       }
-       else {
+       else
                uspi->s_apbshift = uspi->s_bshift - 2;
-       }
+
        uspi->s_2apbshift = uspi->s_apbshift * 2;
        uspi->s_3apbshift = uspi->s_apbshift * 3;
        uspi->s_apb = 1 << uspi->s_apbshift;
@@ -956,7 +1013,7 @@ magic_found:
        if ((sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) ==
            UFS_MOUNT_UFSTYPE_44BSD)
                uspi->s_maxsymlinklen =
-                   fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_maxsymlinklen);
+                   fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_maxsymlinklen);
        
        sbi->s_flags = flags;
 
@@ -967,7 +1024,7 @@ magic_found:
        if (!sb->s_root)
                goto dalloc_failed;
 
-
+       ufs_setup_cstotal(sb);
        /*
         * Read cylinder group structures
         */
@@ -975,7 +1032,7 @@ magic_found:
                if (!ufs_read_cylinder_structures(sb))
                        goto failed;
 
-       UFSD(("EXIT\n"))
+       UFSD("EXIT\n");
        return 0;
 
 dalloc_failed:
@@ -986,15 +1043,16 @@ failed:
        kfree (uspi);
        kfree(sbi);
        sb->s_fs_info = NULL;
-       UFSD(("EXIT (FAILED)\n"))
+       UFSD("EXIT (FAILED)\n");
        return -EINVAL;
 
 failed_nomem:
-       UFSD(("EXIT (NOMEM)\n"))
+       UFSD("EXIT (NOMEM)\n");
        return -ENOMEM;
 }
 
-static void ufs_write_super (struct super_block *sb) {
+static void ufs_write_super(struct super_block *sb)
+{
        struct ufs_sb_private_info * uspi;
        struct ufs_super_block_first * usb1;
        struct ufs_super_block_third * usb3;
@@ -1002,7 +1060,7 @@ static void ufs_write_super (struct super_block *sb) {
 
        lock_kernel();
 
-       UFSD(("ENTER\n"))
+       UFSD("ENTER\n");
        flags = UFS_SB(sb)->s_flags;
        uspi = UFS_SB(sb)->s_uspi;
        usb1 = ubh_get_usb_first(uspi);
@@ -1014,26 +1072,27 @@ static void ufs_write_super (struct super_block *sb) {
                  || (flags & UFS_ST_MASK) == UFS_ST_SUNx86)
                        ufs_set_fs_state(sb, usb1, usb3,
                                        UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time));
-               ubh_mark_buffer_dirty (USPI_UBH);
+               ufs_put_cstotal(sb);
        }
        sb->s_dirt = 0;
-       UFSD(("EXIT\n"))
+       UFSD("EXIT\n");
        unlock_kernel();
 }
 
-static void ufs_put_super (struct super_block *sb)
+static void ufs_put_super(struct super_block *sb)
 {
        struct ufs_sb_info * sbi = UFS_SB(sb);
                
-       UFSD(("ENTER\n"))
+       UFSD("ENTER\n");
 
        if (!(sb->s_flags & MS_RDONLY))
-               ufs_put_cylinder_structures (sb);
+               ufs_put_super_internal(sb);
        
        ubh_brelse_uspi (sbi->s_uspi);
        kfree (sbi->s_uspi);
        kfree (sbi);
        sb->s_fs_info = NULL;
+       UFSD("EXIT\n");
        return;
 }
 
@@ -1062,8 +1121,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)
                return -EINVAL;
        if (!(new_mount_opt & UFS_MOUNT_UFSTYPE)) {
                new_mount_opt |= ufstype;
-       }
-       else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) {
+       } else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) {
                printk("ufstype can't be changed during remount\n");
                return -EINVAL;
        }
@@ -1077,20 +1135,19 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)
         * fs was mouted as rw, remounting ro
         */
        if (*mount_flags & MS_RDONLY) {
-               ufs_put_cylinder_structures(sb);
+               ufs_put_super_internal(sb);
                usb1->fs_time = cpu_to_fs32(sb, get_seconds());
                if ((flags & UFS_ST_MASK) == UFS_ST_SUN
                  || (flags & UFS_ST_MASK) == UFS_ST_SUNx86) 
                        ufs_set_fs_state(sb, usb1, usb3,
                                UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time));
-               ubh_mark_buffer_dirty (USPI_UBH);
+               ubh_mark_buffer_dirty (USPI_UBH(uspi));
                sb->s_dirt = 0;
                sb->s_flags |= MS_RDONLY;
-       }
+       } else {
        /*
         * fs was mounted as ro, remounting rw
         */
-       else {
 #ifndef CONFIG_UFS_FS_WRITE
                printk("ufs was compiled with read-only support, "
                "can't be mounted as read-write\n");
@@ -1102,7 +1159,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)
                        printk("this ufstype is read-only supported\n");
                        return -EINVAL;
                }
-               if (!ufs_read_cylinder_structures (sb)) {
+               if (!ufs_read_cylinder_structures(sb)) {
                        printk("failed during remounting\n");
                        return -EPERM;
                }
@@ -1113,37 +1170,31 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)
        return 0;
 }
 
-static int ufs_statfs (struct dentry *dentry, struct kstatfs *buf)
+static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
-       struct ufs_sb_private_info * uspi;
-       struct ufs_super_block_first * usb1;
-       struct ufs_super_block * usb;
-       unsigned  flags = 0;
+       struct ufs_sb_private_info *uspi= UFS_SB(sb)->s_uspi;
+       unsigned  flags = UFS_SB(sb)->s_flags;
+       struct ufs_super_block_first *usb1;
+       struct ufs_super_block_second *usb2;
+       struct ufs_super_block_third *usb3;
 
        lock_kernel();
 
-       uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first (uspi);
-       usb  = (struct ufs_super_block *)
-               ((struct ufs_buffer_head *)uspi)->bh[0]->b_data ;
+       usb1 = ubh_get_usb_first(uspi);
+       usb2 = ubh_get_usb_second(uspi);
+       usb3 = ubh_get_usb_third(uspi);
        
-       flags = UFS_SB(sb)->s_flags;
        if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
                buf->f_type = UFS2_MAGIC;
-               buf->f_blocks = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize);
-               buf->f_bfree = ufs_blkstofrags(fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_cstotal.cs_nbfree)) +
-                       fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_cstotal.cs_nffree);
-               buf->f_ffree = fs64_to_cpu(sb,
-                       usb->fs_u11.fs_u2.fs_cstotal.cs_nifree);
-       }
-       else {
+               buf->f_blocks = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_dsize);
+       } else {
                buf->f_type = UFS_MAGIC;
                buf->f_blocks = uspi->s_dsize;
-               buf->f_bfree = ufs_blkstofrags(fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree)) +
-                       fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree);
-               buf->f_ffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree);
        }
+       buf->f_bfree = ufs_blkstofrags(uspi->cs_total.cs_nbfree) +
+               uspi->cs_total.cs_nffree;
+       buf->f_ffree = uspi->cs_total.cs_nifree;
        buf->f_bsize = sb->s_blocksize;
        buf->f_bavail = (buf->f_bfree > (((long)buf->f_blocks / 100) * uspi->s_minfree))
                ? (buf->f_bfree - (((long)buf->f_blocks / 100) * uspi->s_minfree)) : 0;
index 02e86291ef8adfde874aac0e72b37fd2f51bad85..3c3b301f87014eeec6327e7480befd367d8ac336 100644 (file)
 #include "swab.h"
 #include "util.h"
 
-#undef UFS_TRUNCATE_DEBUG
-
-#ifdef UFS_TRUNCATE_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
 /*
  * Secure deletion currently doesn't work. It interacts very badly
  * with buffers shared with memory mappings, and for that reason
@@ -82,7 +74,7 @@ static int ufs_trunc_direct (struct inode * inode)
        unsigned i, tmp;
        int retry;
        
-       UFSD(("ENTER\n"))
+       UFSD("ENTER\n");
 
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
@@ -105,7 +97,7 @@ static int ufs_trunc_direct (struct inode * inode)
                block2 = ufs_fragstoblks (frag3);
        }
 
-       UFSD(("frag1 %u, frag2 %u, block1 %u, block2 %u, frag3 %u, frag4 %u\n", frag1, frag2, block1, block2, frag3, frag4))
+       UFSD("frag1 %u, frag2 %u, block1 %u, block2 %u, frag3 %u, frag4 %u\n", frag1, frag2, block1, block2, frag3, frag4);
 
        if (frag1 >= frag2)
                goto next1;             
@@ -120,9 +112,8 @@ static int ufs_trunc_direct (struct inode * inode)
        frag1 = ufs_fragnum (frag1);
        frag2 = ufs_fragnum (frag2);
 
-       inode->i_blocks -= (frag2-frag1) << uspi->s_nspfshift;
-       mark_inode_dirty(inode);
        ufs_free_fragments (inode, tmp + frag1, frag2 - frag1);
+       mark_inode_dirty(inode);
        frag_to_free = tmp + frag1;
 
 next1:
@@ -136,8 +127,7 @@ next1:
                        continue;
 
                *p = 0;
-               inode->i_blocks -= uspi->s_nspb;
-               mark_inode_dirty(inode);
+
                if (free_count == 0) {
                        frag_to_free = tmp;
                        free_count = uspi->s_fpb;
@@ -148,6 +138,7 @@ next1:
                        frag_to_free = tmp;
                        free_count = uspi->s_fpb;
                }
+               mark_inode_dirty(inode);
        }
        
        if (free_count > 0)
@@ -166,12 +157,12 @@ next1:
        frag4 = ufs_fragnum (frag4);
 
        *p = 0;
-       inode->i_blocks -= frag4 << uspi->s_nspfshift;
-       mark_inode_dirty(inode);
+
        ufs_free_fragments (inode, tmp, frag4);
+       mark_inode_dirty(inode);
  next3:
 
-       UFSD(("EXIT\n"))
+       UFSD("EXIT\n");
        return retry;
 }
 
@@ -186,7 +177,7 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p)
        unsigned frag_to_free, free_count;
        int retry;
 
-       UFSD(("ENTER\n"))
+       UFSD("ENTER\n");
                
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
@@ -227,7 +218,7 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p)
                        frag_to_free = tmp;
                        free_count = uspi->s_fpb;
                }
-               inode->i_blocks -= uspi->s_nspb;
+
                mark_inode_dirty(inode);
        }
 
@@ -238,26 +229,21 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p)
                if (*ubh_get_addr32(ind_ubh,i))
                        break;
        if (i >= uspi->s_apb) {
-               if (ubh_max_bcount(ind_ubh) != 1) {
-                       retry = 1;
-               }
-               else {
-                       tmp = fs32_to_cpu(sb, *p);
-                       *p = 0;
-                       inode->i_blocks -= uspi->s_nspb;
-                       mark_inode_dirty(inode);
-                       ufs_free_blocks (inode, tmp, uspi->s_fpb);
-                       ubh_bforget(ind_ubh);
-                       ind_ubh = NULL;
-               }
+               tmp = fs32_to_cpu(sb, *p);
+               *p = 0;
+
+               ufs_free_blocks (inode, tmp, uspi->s_fpb);
+               mark_inode_dirty(inode);
+               ubh_bforget(ind_ubh);
+               ind_ubh = NULL;
        }
        if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) {
-               ubh_ll_rw_block (SWRITE, 1, &ind_ubh);
+               ubh_ll_rw_block(SWRITE, ind_ubh);
                ubh_wait_on_buffer (ind_ubh);
        }
        ubh_brelse (ind_ubh);
        
-       UFSD(("EXIT\n"))
+       UFSD("EXIT\n");
        
        return retry;
 }
@@ -271,7 +257,7 @@ static int ufs_trunc_dindirect (struct inode *inode, unsigned offset, __fs32 *p)
        __fs32 * dind;
        int retry = 0;
        
-       UFSD(("ENTER\n"))
+       UFSD("ENTER\n");
        
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
@@ -306,25 +292,21 @@ static int ufs_trunc_dindirect (struct inode *inode, unsigned offset, __fs32 *p)
                if (*ubh_get_addr32 (dind_bh, i))
                        break;
        if (i >= uspi->s_apb) {
-               if (ubh_max_bcount(dind_bh) != 1)
-                       retry = 1;
-               else {
-                       tmp = fs32_to_cpu(sb, *p);
-                       *p = 0;
-                       inode->i_blocks -= uspi->s_nspb;
-                       mark_inode_dirty(inode);
-                       ufs_free_blocks (inode, tmp, uspi->s_fpb);
-                       ubh_bforget(dind_bh);
-                       dind_bh = NULL;
-               }
+               tmp = fs32_to_cpu(sb, *p);
+               *p = 0;
+
+               ufs_free_blocks(inode, tmp, uspi->s_fpb);
+               mark_inode_dirty(inode);
+               ubh_bforget(dind_bh);
+               dind_bh = NULL;
        }
        if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) {
-               ubh_ll_rw_block (SWRITE, 1, &dind_bh);
+               ubh_ll_rw_block(SWRITE, dind_bh);
                ubh_wait_on_buffer (dind_bh);
        }
        ubh_brelse (dind_bh);
        
-       UFSD(("EXIT\n"))
+       UFSD("EXIT\n");
        
        return retry;
 }
@@ -339,7 +321,7 @@ static int ufs_trunc_tindirect (struct inode * inode)
        __fs32 * tind, * p;
        int retry;
        
-       UFSD(("ENTER\n"))
+       UFSD("ENTER\n");
 
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
@@ -370,25 +352,21 @@ static int ufs_trunc_tindirect (struct inode * inode)
                if (*ubh_get_addr32 (tind_bh, i))
                        break;
        if (i >= uspi->s_apb) {
-               if (ubh_max_bcount(tind_bh) != 1)
-                       retry = 1;
-               else {
-                       tmp = fs32_to_cpu(sb, *p);
-                       *p = 0;
-                       inode->i_blocks -= uspi->s_nspb;
-                       mark_inode_dirty(inode);
-                       ufs_free_blocks (inode, tmp, uspi->s_fpb);
-                       ubh_bforget(tind_bh);
-                       tind_bh = NULL;
-               }
+               tmp = fs32_to_cpu(sb, *p);
+               *p = 0;
+
+               ufs_free_blocks(inode, tmp, uspi->s_fpb);
+               mark_inode_dirty(inode);
+               ubh_bforget(tind_bh);
+               tind_bh = NULL;
        }
        if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) {
-               ubh_ll_rw_block (SWRITE, 1, &tind_bh);
+               ubh_ll_rw_block(SWRITE, tind_bh);
                ubh_wait_on_buffer (tind_bh);
        }
        ubh_brelse (tind_bh);
        
-       UFSD(("EXIT\n"))
+       UFSD("EXIT\n");
        return retry;
 }
                
@@ -399,7 +377,7 @@ void ufs_truncate (struct inode * inode)
        struct ufs_sb_private_info * uspi;
        int retry;
        
-       UFSD(("ENTER\n"))
+       UFSD("ENTER\n");
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
 
@@ -430,5 +408,5 @@ void ufs_truncate (struct inode * inode)
        ufsi->i_lastfrag = DIRECT_FRAGMENT;
        unlock_kernel();
        mark_inode_dirty(inode);
-       UFSD(("EXIT\n"))
+       UFSD("EXIT\n");
 }
index 59acc8f073acf5c8c8a384e44960557e788ad2e5..a2f13f45708b7d0fa6d688579f3551176465f3bd 100644 (file)
 #include "swab.h"
 #include "util.h"
 
-#undef UFS_UTILS_DEBUG
-
-#ifdef UFS_UTILS_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
-
 struct ufs_buffer_head * _ubh_bread_ (struct ufs_sb_private_info * uspi,
        struct super_block *sb, u64 fragment, u64 size)
 {
@@ -63,17 +54,17 @@ struct ufs_buffer_head * ubh_bread_uspi (struct ufs_sb_private_info * uspi,
        count = size >> uspi->s_fshift;
        if (count <= 0 || count > UFS_MAXFRAG)
                return NULL;
-       USPI_UBH->fragment = fragment;
-       USPI_UBH->count = count;
+       USPI_UBH(uspi)->fragment = fragment;
+       USPI_UBH(uspi)->count = count;
        for (i = 0; i < count; i++)
-               if (!(USPI_UBH->bh[i] = sb_bread(sb, fragment + i)))
+               if (!(USPI_UBH(uspi)->bh[i] = sb_bread(sb, fragment + i)))
                        goto failed;
        for (; i < UFS_MAXFRAG; i++)
-               USPI_UBH->bh[i] = NULL;
-       return USPI_UBH;
+               USPI_UBH(uspi)->bh[i] = NULL;
+       return USPI_UBH(uspi);
 failed:
        for (j = 0; j < i; j++)
-               brelse (USPI_UBH->bh[j]);
+               brelse (USPI_UBH(uspi)->bh[j]);
        return NULL;
 }
 
@@ -90,11 +81,11 @@ void ubh_brelse (struct ufs_buffer_head * ubh)
 void ubh_brelse_uspi (struct ufs_sb_private_info * uspi)
 {
        unsigned i;
-       if (!USPI_UBH)
+       if (!USPI_UBH(uspi))
                return;
-       for ( i = 0; i < USPI_UBH->count; i++ ) {
-               brelse (USPI_UBH->bh[i]);
-               USPI_UBH->bh[i] = NULL;
+       for ( i = 0; i < USPI_UBH(uspi)->count; i++ ) {
+               brelse (USPI_UBH(uspi)->bh[i]);
+               USPI_UBH(uspi)->bh[i] = NULL;
        }
 }
 
@@ -121,13 +112,12 @@ void ubh_mark_buffer_uptodate (struct ufs_buffer_head * ubh, int flag)
        }
 }
 
-void ubh_ll_rw_block (int rw, unsigned nr, struct ufs_buffer_head * ubh[])
+void ubh_ll_rw_block(int rw, struct ufs_buffer_head *ubh)
 {
-       unsigned i;
        if (!ubh)
                return;
-       for ( i = 0; i < nr; i++ )
-               ll_rw_block (rw, ubh[i]->count, ubh[i]->bh);
+
+       ll_rw_block(rw, ubh->count, ubh->bh);
 }
 
 void ubh_wait_on_buffer (struct ufs_buffer_head * ubh)
@@ -139,18 +129,6 @@ void ubh_wait_on_buffer (struct ufs_buffer_head * ubh)
                wait_on_buffer (ubh->bh[i]);
 }
 
-unsigned ubh_max_bcount (struct ufs_buffer_head * ubh)
-{
-       unsigned i;
-       unsigned max = 0;
-       if (!ubh)
-               return 0;
-       for ( i = 0; i < ubh->count; i++ ) 
-               if ( atomic_read(&ubh->bh[i]->b_count) > max )
-                       max = atomic_read(&ubh->bh[i]->b_count);
-       return max;
-}
-
 void ubh_bforget (struct ufs_buffer_head * ubh)
 {
        unsigned i;
index 48d6d9bcc15770ce05cd8a8c8bb08e3e5f88e26e..406981fff5e7ca01317a7aa26c34f803827ec7fc 100644 (file)
 #define in_range(b,first,len)  ((b)>=(first)&&(b)<(first)+(len))
 
 /*
- * macros used for retyping
+ * functions used for retyping
  */
-#define UCPI_UBH ((struct ufs_buffer_head *)ucpi)
-#define USPI_UBH ((struct ufs_buffer_head *)uspi)
+static inline struct ufs_buffer_head *UCPI_UBH(struct ufs_cg_private_info *cpi)
+{
+       return &cpi->c_ubh;
+}
+static inline struct ufs_buffer_head *USPI_UBH(struct ufs_sb_private_info *spi)
+{
+       return &spi->s_ubh;
+}
 
 
 
@@ -33,12 +39,12 @@ ufs_get_fs_state(struct super_block *sb, struct ufs_super_block_first *usb1,
 {
        switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
        case UFS_ST_SUN:
-               return fs32_to_cpu(sb, usb3->fs_u2.fs_sun.fs_state);
+               return fs32_to_cpu(sb, usb3->fs_un2.fs_sun.fs_state);
        case UFS_ST_SUNx86:
                return fs32_to_cpu(sb, usb1->fs_u1.fs_sunx86.fs_state);
        case UFS_ST_44BSD:
        default:
-               return fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_state);
+               return fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_state);
        }
 }
 
@@ -48,13 +54,13 @@ ufs_set_fs_state(struct super_block *sb, struct ufs_super_block_first *usb1,
 {
        switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
        case UFS_ST_SUN:
-               usb3->fs_u2.fs_sun.fs_state = cpu_to_fs32(sb, value);
+               usb3->fs_un2.fs_sun.fs_state = cpu_to_fs32(sb, value);
                break;
        case UFS_ST_SUNx86:
                usb1->fs_u1.fs_sunx86.fs_state = cpu_to_fs32(sb, value);
                break;
        case UFS_ST_44BSD:
-               usb3->fs_u2.fs_44.fs_state = cpu_to_fs32(sb, value);
+               usb3->fs_un2.fs_44.fs_state = cpu_to_fs32(sb, value);
                break;
        }
 }
@@ -64,7 +70,7 @@ ufs_get_fs_npsect(struct super_block *sb, struct ufs_super_block_first *usb1,
                  struct ufs_super_block_third *usb3)
 {
        if ((UFS_SB(sb)->s_flags & UFS_ST_MASK) == UFS_ST_SUNx86)
-               return fs32_to_cpu(sb, usb3->fs_u2.fs_sunx86.fs_npsect);
+               return fs32_to_cpu(sb, usb3->fs_un2.fs_sunx86.fs_npsect);
        else
                return fs32_to_cpu(sb, usb1->fs_u1.fs_sun.fs_npsect);
 }
@@ -76,16 +82,16 @@ ufs_get_fs_qbmask(struct super_block *sb, struct ufs_super_block_third *usb3)
 
        switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
        case UFS_ST_SUN:
-               ((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_sun.fs_qbmask[0];
-               ((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_sun.fs_qbmask[1];
+               ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sun.fs_qbmask[0];
+               ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sun.fs_qbmask[1];
                break;
        case UFS_ST_SUNx86:
-               ((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_sunx86.fs_qbmask[0];
-               ((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_sunx86.fs_qbmask[1];
+               ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sunx86.fs_qbmask[0];
+               ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sunx86.fs_qbmask[1];
                break;
        case UFS_ST_44BSD:
-               ((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_44.fs_qbmask[0];
-               ((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_44.fs_qbmask[1];
+               ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_44.fs_qbmask[0];
+               ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_44.fs_qbmask[1];
                break;
        }
 
@@ -99,16 +105,16 @@ ufs_get_fs_qfmask(struct super_block *sb, struct ufs_super_block_third *usb3)
 
        switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
        case UFS_ST_SUN:
-               ((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_sun.fs_qfmask[0];
-               ((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_sun.fs_qfmask[1];
+               ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sun.fs_qfmask[0];
+               ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sun.fs_qfmask[1];
                break;
        case UFS_ST_SUNx86:
-               ((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_sunx86.fs_qfmask[0];
-               ((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_sunx86.fs_qfmask[1];
+               ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sunx86.fs_qfmask[0];
+               ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sunx86.fs_qfmask[1];
                break;
        case UFS_ST_44BSD:
-               ((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_44.fs_qfmask[0];
-               ((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_44.fs_qfmask[1];
+               ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_44.fs_qfmask[0];
+               ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_44.fs_qfmask[1];
                break;
        }
 
@@ -236,9 +242,8 @@ extern void ubh_brelse (struct ufs_buffer_head *);
 extern void ubh_brelse_uspi (struct ufs_sb_private_info *);
 extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *);
 extern void ubh_mark_buffer_uptodate (struct ufs_buffer_head *, int);
-extern void ubh_ll_rw_block (int, unsigned, struct ufs_buffer_head **);
+extern void ubh_ll_rw_block(int, struct ufs_buffer_head *);
 extern void ubh_wait_on_buffer (struct ufs_buffer_head *);
-extern unsigned ubh_max_bcount (struct ufs_buffer_head *);
 extern void ubh_bforget (struct ufs_buffer_head *);
 extern int  ubh_buffer_dirty (struct ufs_buffer_head *);
 #define ubh_ubhcpymem(mem,ubh,size) _ubh_ubhcpymem_(uspi,mem,ubh,size)
@@ -297,40 +302,26 @@ static inline void *get_usb_offset(struct ufs_sb_private_info *uspi,
 #define ubh_blkmap(ubh,begin,bit) \
        ((*ubh_get_addr(ubh, (begin) + ((bit) >> 3)) >> ((bit) & 7)) & (0xff >> (UFS_MAXFRAG - uspi->s_fpb)))
 
-
-/*
- * Macros for access to superblock array structures
- */
-#define ubh_postbl(ubh,cylno,i) \
-       ((uspi->s_postblformat != UFS_DYNAMICPOSTBLFMT) \
-       ? (*(__s16*)(ubh_get_addr(ubh, \
-       (unsigned)(&((struct ufs_super_block *)0)->fs_opostbl) \
-       + (((cylno) * 16 + (i)) << 1) ) )) \
-       : (*(__s16*)(ubh_get_addr(ubh, \
-       uspi->s_postbloff + (((cylno) * uspi->s_nrpos + (i)) << 1) ))))
-
-#define ubh_rotbl(ubh,i) \
-       ((uspi->s_postblformat != UFS_DYNAMICPOSTBLFMT) \
-       ? (*(__u8*)(ubh_get_addr(ubh, \
-       (unsigned)(&((struct ufs_super_block *)0)->fs_space) + (i)))) \
-       : (*(__u8*)(ubh_get_addr(ubh, uspi->s_rotbloff + (i)))))
-
 /*
  * Determine the number of available frags given a
  * percentage to hold in reserve.
  */
-#define ufs_freespace(usb, percentreserved) \
-       (ufs_blkstofrags(fs32_to_cpu(sb, (usb)->fs_cstotal.cs_nbfree)) + \
-       fs32_to_cpu(sb, (usb)->fs_cstotal.cs_nffree) - (uspi->s_dsize * (percentreserved) / 100))
+static inline u64
+ufs_freespace(struct ufs_sb_private_info *uspi, int percentreserved)
+{
+       return ufs_blkstofrags(uspi->cs_total.cs_nbfree) +
+               uspi->cs_total.cs_nffree -
+               (uspi->s_dsize * (percentreserved) / 100);
+}
 
 /*
  * Macros to access cylinder group array structures
  */
 #define ubh_cg_blktot(ucpi,cylno) \
-       (*((__fs32*)ubh_get_addr(UCPI_UBH, (ucpi)->c_btotoff + ((cylno) << 2))))
+       (*((__fs32*)ubh_get_addr(UCPI_UBH(ucpi), (ucpi)->c_btotoff + ((cylno) << 2))))
 
 #define ubh_cg_blks(ucpi,cylno,rpos) \
-       (*((__fs16*)ubh_get_addr(UCPI_UBH, \
+       (*((__fs16*)ubh_get_addr(UCPI_UBH(ucpi), \
        (ucpi)->c_boff + (((cylno) * uspi->s_nrpos + (rpos)) << 1 ))))
 
 /*
@@ -508,29 +499,3 @@ static inline void ufs_fragacct (struct super_block * sb, unsigned blockmap,
        if (fragsize > 0 && fragsize < uspi->s_fpb)
                fs32_add(sb, &fraglist[fragsize], cnt);
 }
-
-#define ubh_scanc(ubh,begin,size,table,mask) _ubh_scanc_(uspi,ubh,begin,size,table,mask)
-static inline unsigned _ubh_scanc_(struct ufs_sb_private_info * uspi, struct ufs_buffer_head * ubh, 
-       unsigned begin, unsigned size, unsigned char * table, unsigned char mask)
-{
-       unsigned rest, offset;
-       unsigned char * cp;
-       
-
-       offset = begin & ~uspi->s_fmask;
-       begin >>= uspi->s_fshift;
-       for (;;) {
-               if ((offset + size) < uspi->s_fsize)
-                       rest = size;
-               else
-                       rest = uspi->s_fsize - offset;
-               size -= rest;
-               cp = ubh->bh[begin]->b_data + offset;
-               while ((table[*cp++] & mask) == 0 && --rest);
-               if (rest || !size)
-                       break;
-               begin++;
-               offset = 0;
-       }
-       return (size + rest);
-}
index e177d4180f83610d92ab5be68853eb3516896dfc..21816d35ef899fb4773dba6b4c390bebf968fa9a 100644 (file)
@@ -25,9 +25,8 @@
 #define fd_enable_irq()         enable_irq(FLOPPY_IRQ)
 #define fd_disable_irq()        disable_irq(FLOPPY_IRQ)
 #define fd_cacheflush(addr,size) /* nothing */
-#define fd_request_irq()        request_irq(FLOPPY_IRQ, floppy_interrupt, \
-                                           SA_INTERRUPT|SA_SAMPLE_RANDOM, \
-                                           "floppy", NULL)
+#define fd_request_irq()        request_irq(FLOPPY_IRQ, floppy_interrupt,\
+                                           SA_INTERRUPT, "floppy", NULL)
 #define fd_free_irq()           free_irq(FLOPPY_IRQ, NULL);
 
 #ifdef CONFIG_PCI
index 6ea657c886b98859056bf06d9aee865299a985ed..aa0c8d28d8d946ae6b3de0785c5a5aef0b6701e5 100644 (file)
@@ -25,7 +25,7 @@
 
 #define fd_inb(port)           inb((port))
 #define fd_request_irq()       request_irq(IRQ_FLOPPYDISK,floppy_interrupt,\
-                                       SA_INTERRUPT|SA_SAMPLE_RANDOM,"floppy",NULL)
+                                           SA_INTERRUPT,"floppy",NULL)
 #define fd_free_irq()          free_irq(IRQ_FLOPPYDISK,NULL)
 #define fd_disable_irq()       disable_irq(IRQ_FLOPPYDISK)
 #define fd_enable_irq()                enable_irq(IRQ_FLOPPYDISK)
index 9e090ad7e47702047db5cf768495e0ecc5bc1973..a18af069ca28844ea155ad79f23393933f716dc8 100644 (file)
@@ -22,7 +22,7 @@
 
 #define fd_inb(port)           inb((port))
 #define fd_request_irq()       request_irq(IRQ_FLOPPYDISK,floppy_interrupt,\
-                                       SA_INTERRUPT|SA_SAMPLE_RANDOM,"floppy",NULL)
+                                       SA_INTERRUPT,"floppy",NULL)
 #define fd_free_irq()          free_irq(IRQ_FLOPPYDISK,NULL)
 #define fd_disable_irq()       disable_irq(IRQ_FLOPPYDISK)
 #define fd_enable_irq()                enable_irq(IRQ_FLOPPYDISK)
index 0cd9711895faaf6259baeaf3a66cf6484d41804a..845cb67ad8ea5d40bcb707462d30879255247b81 100644 (file)
 #endif
 #endif
 
+#define WARN_ON_ONCE(condition)                                \
+({                                                     \
+       static int __warn_once = 1;                     \
+       int __ret = 0;                                  \
+                                                       \
+       if (unlikely((condition) && __warn_once)) {     \
+               __warn_once = 0;                        \
+               WARN_ON(1);                             \
+               __ret = 1;                              \
+       }                                               \
+       __ret;                                          \
+})
+
 #endif
index c0caf433a7d76dc99b8473f4145c250f3446e877..c745211574614bfdc5f8a63c7510bbc4a79e749f 100644 (file)
@@ -14,6 +14,7 @@ extern unsigned long __per_cpu_offset[NR_CPUS];
 /* var is in discarded region: offset to particular copy we want */
 #define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]))
 #define __get_cpu_var(var) per_cpu(var, smp_processor_id())
+#define __raw_get_cpu_var(var) per_cpu(var, raw_smp_processor_id())
 
 /* A macro to avoid #include hell... */
 #define percpu_modcopy(pcpudst, src, size)                     \
@@ -30,6 +31,7 @@ do {                                                          \
 
 #define per_cpu(var, cpu)                      (*((void)(cpu), &per_cpu__##var))
 #define __get_cpu_var(var)                     per_cpu__##var
+#define __raw_get_cpu_var(var)                 per_cpu__##var
 
 #endif /* SMP */
 
index 03403045c182945230f9729d3bcbebbc380d3580..9cb2793eb211d1597c40ebe19e9cdd7bd6cb819e 100644 (file)
@@ -147,9 +147,8 @@ static int fd_request_irq(void)
                return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
                                                   "floppy", NULL);
        else
-               return request_irq(FLOPPY_IRQ, floppy_interrupt,
-                                                  SA_INTERRUPT|SA_SAMPLE_RANDOM,
-                                                  "floppy", NULL);     
+               return request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT,
+                                  "floppy", NULL);
 
 }
 
diff --git a/include/asm-i386/mach-default/setup_arch_post.h b/include/asm-i386/mach-default/setup_arch_post.h
deleted file mode 100644 (file)
index 2fc4888..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * machine_specific_memory_setup - Hook for machine specific memory setup.
- *
- * Description:
- *     This is included late in kernel/setup.c so that it can make
- *     use of all of the static functions.
- **/
-
-static char * __init machine_specific_memory_setup(void)
-{
-       char *who;
-
-
-       who = "BIOS-e820";
-
-       /*
-        * Try to copy the BIOS-supplied E820-map.
-        *
-        * Otherwise fake a memory map; one section from 0k->640k,
-        * the next section from 1mb->appropriate_mem_k
-        */
-       sanitize_e820_map(E820_MAP, &E820_MAP_NR);
-       if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
-               unsigned long mem_size;
-
-               /* compare results from other methods and take the greater */
-               if (ALT_MEM_K < EXT_MEM_K) {
-                       mem_size = EXT_MEM_K;
-                       who = "BIOS-88";
-               } else {
-                       mem_size = ALT_MEM_K;
-                       who = "BIOS-e801";
-               }
-
-               e820.nr_map = 0;
-               add_memory_region(0, LOWMEMSIZE(), E820_RAM);
-               add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
-       }
-       return who;
-}
diff --git a/include/asm-i386/mach-visws/setup_arch_post.h b/include/asm-i386/mach-visws/setup_arch_post.h
deleted file mode 100644 (file)
index cdbd895..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Hook for machine specific memory setup.
- *
- * This is included late in kernel/setup.c so that it can make use of all of
- * the static functions. */
-
-#define MB (1024 * 1024)
-
-unsigned long sgivwfb_mem_phys;
-unsigned long sgivwfb_mem_size;
-
-long long mem_size __initdata = 0;
-
-static char * __init machine_specific_memory_setup(void)
-{
-       long long gfx_mem_size = 8 * MB;
-
-       mem_size = ALT_MEM_K;
-
-       if (!mem_size) {
-               printk(KERN_WARNING "Bootloader didn't set memory size, upgrade it !\n");
-               mem_size = 128 * MB;
-       }
-
-       /*
-        * this hardcodes the graphics memory to 8 MB
-        * it really should be sized dynamically (or at least
-        * set as a boot param)
-        */
-       if (!sgivwfb_mem_size) {
-               printk(KERN_WARNING "Defaulting to 8 MB framebuffer size\n");
-               sgivwfb_mem_size = 8 * MB;
-       }
-
-       /*
-        * Trim to nearest MB
-        */
-       sgivwfb_mem_size &= ~((1 << 20) - 1);
-       sgivwfb_mem_phys = mem_size - gfx_mem_size;
-
-       add_memory_region(0, LOWMEMSIZE(), E820_RAM);
-       add_memory_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM);
-       add_memory_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED);
-
-       return "PROM";
-
-       /* Remove gcc warnings */
-       (void) sanitize_e820_map(NULL, NULL);
-       (void) copy_e820_map(NULL, 0);
-}
similarity index 97%
rename from include/asm-i386/mach-voyager/setup_arch_pre.h
rename to include/asm-i386/mach-voyager/setup_arch.h
index 48f7e6ff49a56093d86c5bee139f15c57676013a..84d01ad334593a99083ec0dcc96873b10e3c611e 100644 (file)
@@ -3,7 +3,7 @@
 
 /* Hook to call BIOS initialisation function */
 
-/* for voyager, pass the voyager BIOS/SUS info area to the detection 
+/* for voyager, pass the voyager BIOS/SUS info area to the detection
  * routines */
 
 #define ARCH_SETUP     voyager_detect(VOYAGER_BIOS_INFO);
diff --git a/include/asm-i386/mach-voyager/setup_arch_post.h b/include/asm-i386/mach-voyager/setup_arch_post.h
deleted file mode 100644 (file)
index f6f6c2c..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Hook for machine specific memory setup.
- *
- * This is included late in kernel/setup.c so that it can make use of all of
- * the static functions. */
-
-static char * __init machine_specific_memory_setup(void)
-{
-       char *who;
-
-       who = "NOT VOYAGER";
-
-       if(voyager_level == 5) {
-               __u32 addr, length;
-               int i;
-
-               who = "Voyager-SUS";
-
-               e820.nr_map = 0;
-               for(i=0; voyager_memory_detect(i, &addr, &length); i++) {
-                       add_memory_region(addr, length, E820_RAM);
-               }
-               return who;
-       } else if(voyager_level == 4) {
-               __u32 tom;
-               __u16 catbase = inb(VOYAGER_SSPB_RELOCATION_PORT)<<8;
-               /* select the DINO config space */
-               outb(VOYAGER_DINO, VOYAGER_CAT_CONFIG_PORT);
-               /* Read DINO top of memory register */
-               tom = ((inb(catbase + 0x4) & 0xf0) << 16)
-                       + ((inb(catbase + 0x5) & 0x7f) << 24);
-
-               if(inb(catbase) != VOYAGER_DINO) {
-                       printk(KERN_ERR "Voyager: Failed to get DINO for L4, setting tom to EXT_MEM_K\n");
-                       tom = (EXT_MEM_K)<<10;
-               }
-               who = "Voyager-TOM";
-               add_memory_region(0, 0x9f000, E820_RAM);
-               /* map from 1M to top of memory */
-               add_memory_region(1*1024*1024, tom - 1*1024*1024, E820_RAM);
-               /* FIXME: Should check the ASICs to see if I need to
-                * take out the 8M window.  Just do it at the moment
-                * */
-               add_memory_region(8*1024*1024, 8*1024*1024, E820_RESERVED);
-               return who;
-       }
-
-       who = "BIOS-e820";
-
-       /*
-        * Try to copy the BIOS-supplied E820-map.
-        *
-        * Otherwise fake a memory map; one section from 0k->640k,
-        * the next section from 1mb->appropriate_mem_k
-        */
-       sanitize_e820_map(E820_MAP, &E820_MAP_NR);
-       if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
-               unsigned long mem_size;
-
-               /* compare results from other methods and take the greater */
-               if (ALT_MEM_K < EXT_MEM_K) {
-                       mem_size = EXT_MEM_K;
-                       who = "BIOS-88";
-               } else {
-                       mem_size = ALT_MEM_K;
-                       who = "BIOS-e801";
-               }
-
-               e820.nr_map = 0;
-               add_memory_region(0, LOWMEMSIZE(), E820_RAM);
-               add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
-       }
-       return who;
-}
index ee941457b55dcd6e979c43845d625b1274cb86a5..f737e423029ecb6570d3b5051688353abc45156b 100644 (file)
@@ -59,6 +59,21 @@ extern unsigned char boot_params[PARAM_SIZE];
 #define EDD_MBR_SIGNATURE ((unsigned int *) (PARAM+EDD_MBR_SIG_BUF))
 #define EDD_BUF     ((struct edd_info *) (PARAM+EDDBUF))
 
+/*
+ * Do NOT EVER look at the BIOS memory size location.
+ * It does not work on many machines.
+ */
+#define LOWMEMSIZE()   (0x9f000)
+
+struct e820entry;
+
+char * __init machine_specific_memory_setup(void);
+
+int __init copy_e820_map(struct e820entry * biosmap, int nr_map);
+int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map);
+void __init add_memory_region(unsigned long long start,
+                             unsigned long long size, int type);
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _i386_SETUP_H */
index 8462f8e0e658fda0f0cdb630b559ff0098526ef9..54d905ebc63dd9738e00f592ee0787b371ef1e62 100644 (file)
@@ -390,8 +390,12 @@ unsigned long __must_check __copy_to_user_ll(void __user *to,
                                const void *from, unsigned long n);
 unsigned long __must_check __copy_from_user_ll(void *to,
                                const void __user *from, unsigned long n);
+unsigned long __must_check __copy_from_user_ll_nozero(void *to,
+                               const void __user *from, unsigned long n);
 unsigned long __must_check __copy_from_user_ll_nocache(void *to,
                                const void __user *from, unsigned long n);
+unsigned long __must_check __copy_from_user_ll_nocache_nozero(void *to,
+                               const void __user *from, unsigned long n);
 
 /*
  * Here we special-case 1, 2 and 4-byte copy_*_user invocations.  On a fault
@@ -458,10 +462,41 @@ __copy_to_user(void __user *to, const void *from, unsigned long n)
  *
  * If some data could not be copied, this function will pad the copied
  * data to the requested size using zero bytes.
+ *
+ * An alternate version - __copy_from_user_inatomic() - may be called from
+ * atomic context and will fail rather than sleep.  In this case the
+ * uncopied bytes will *NOT* be padded with zeros.  See fs/filemap.h
+ * for explanation of why this is needed.
  */
 static __always_inline unsigned long
 __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
 {
+       /* Avoid zeroing the tail if the copy fails..
+        * If 'n' is constant and 1, 2, or 4, we do still zero on a failure,
+        * but as the zeroing behaviour is only significant when n is not
+        * constant, that shouldn't be a problem.
+        */
+       if (__builtin_constant_p(n)) {
+               unsigned long ret;
+
+               switch (n) {
+               case 1:
+                       __get_user_size(*(u8 *)to, from, 1, ret, 1);
+                       return ret;
+               case 2:
+                       __get_user_size(*(u16 *)to, from, 2, ret, 2);
+                       return ret;
+               case 4:
+                       __get_user_size(*(u32 *)to, from, 4, ret, 4);
+                       return ret;
+               }
+       }
+       return __copy_from_user_ll_nozero(to, from, n);
+}
+static __always_inline unsigned long
+__copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+       might_sleep();
        if (__builtin_constant_p(n)) {
                unsigned long ret;
 
@@ -482,9 +517,10 @@ __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
 
 #define ARCH_HAS_NOCACHE_UACCESS
 
-static __always_inline unsigned long __copy_from_user_inatomic_nocache(void *to,
+static __always_inline unsigned long __copy_from_user_nocache(void *to,
                                const void __user *from, unsigned long n)
 {
+       might_sleep();
        if (__builtin_constant_p(n)) {
                unsigned long ret;
 
@@ -504,17 +540,9 @@ static __always_inline unsigned long __copy_from_user_inatomic_nocache(void *to,
 }
 
 static __always_inline unsigned long
-__copy_from_user(void *to, const void __user *from, unsigned long n)
+__copy_from_user_inatomic_nocache(void *to, const void __user *from, unsigned long n)
 {
-       might_sleep();
-       return __copy_from_user_inatomic(to, from, n);
-}
-
-static __always_inline unsigned long
-__copy_from_user_nocache(void *to, const void __user *from, unsigned long n)
-{
-       might_sleep();
-       return __copy_from_user_inatomic_nocache(to, from, n);
+       return __copy_from_user_ll_nocache_nozero(to, from, n);
 }
 
 unsigned long __must_check copy_to_user(void __user *to,
index ae357d504fba81ddd0827df421f6ec317c71e6b0..24d898b650c5ddd0142c4747db2ea8ed06c6f61e 100644 (file)
@@ -42,6 +42,7 @@ DECLARE_PER_CPU(unsigned long, local_per_cpu_offset);
 
 #define per_cpu(var, cpu)  (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]))
 #define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __ia64_per_cpu_var(local_per_cpu_offset)))
+#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __ia64_per_cpu_var(local_per_cpu_offset)))
 
 extern void percpu_modcopy(void *pcpudst, const void *src, unsigned long size);
 extern void setup_per_cpu_areas (void);
@@ -51,6 +52,7 @@ extern void *per_cpu_init(void);
 
 #define per_cpu(var, cpu)                      (*((void)(cpu), &per_cpu__##var))
 #define __get_cpu_var(var)                     per_cpu__##var
+#define __raw_get_cpu_var(var)                 per_cpu__##var
 #define per_cpu_init()                         (__phys_per_cpu_start)
 
 #endif /* SMP */
index aa968d014bb6b9502a55160682a0b101a34f9f29..7c8713468fd28409f8d7c2d348a4ec24d13992e3 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef _ASMm68k_AMIGAINTS_H_
 #define _ASMm68k_AMIGAINTS_H_
 
+#include <asm/irq.h>
+
 /*
 ** Amiga Interrupt sources.
 **
 #define CIA_IRQS            (5)
 #define AMI_IRQS            (32) /* AUTO_IRQS+AMI_STD_IRQS+2*CIA_IRQS */
 
-/* vertical blanking interrupt */
-#define IRQ_AMIGA_VERTB     0
+/* builtin serial port interrupts */
+#define IRQ_AMIGA_TBE          (IRQ_USER+0)
+#define IRQ_AMIGA_RBF          (IRQ_USER+11)
 
-/* copper interrupt */
-#define IRQ_AMIGA_COPPER    1
+/* floppy disk interrupts */
+#define IRQ_AMIGA_DSKBLK       (IRQ_USER+1)
+#define IRQ_AMIGA_DSKSYN       (IRQ_USER+12)
 
-/* Audio interrupts */
-#define IRQ_AMIGA_AUD0     2
-#define IRQ_AMIGA_AUD1     3
-#define IRQ_AMIGA_AUD2     4
-#define IRQ_AMIGA_AUD3     5
+/* software interrupts */
+#define IRQ_AMIGA_SOFT         (IRQ_USER+2)
 
-/* Blitter done interrupt */
-#define IRQ_AMIGA_BLIT     6
+/* interrupts from external hardware */
+#define IRQ_AMIGA_PORTS                IRQ_AUTO_2
+#define IRQ_AMIGA_EXTER                IRQ_AUTO_6
 
-/* floppy disk interrupts */
-#define IRQ_AMIGA_DSKSYN    7
-#define IRQ_AMIGA_DSKBLK    8
+/* copper interrupt */
+#define IRQ_AMIGA_COPPER       (IRQ_USER+4)
 
-/* builtin serial port interrupts */
-#define IRQ_AMIGA_RBF      9
-#define IRQ_AMIGA_TBE      10
+/* vertical blanking interrupt */
+#define IRQ_AMIGA_VERTB                (IRQ_USER+5)
 
-/* software interrupts */
-#define IRQ_AMIGA_SOFT      11
+/* Blitter done interrupt */
+#define IRQ_AMIGA_BLIT         (IRQ_USER+6)
 
-/* interrupts from external hardware */
-#define IRQ_AMIGA_PORTS            12
-#define IRQ_AMIGA_EXTER            13
+/* Audio interrupts */
+#define IRQ_AMIGA_AUD0         (IRQ_USER+7)
+#define IRQ_AMIGA_AUD1         (IRQ_USER+8)
+#define IRQ_AMIGA_AUD2         (IRQ_USER+9)
+#define IRQ_AMIGA_AUD3         (IRQ_USER+10)
 
 /* CIA interrupt sources */
-#define IRQ_AMIGA_CIAA      14
-#define IRQ_AMIGA_CIAA_TA   14
-#define IRQ_AMIGA_CIAA_TB   15
-#define IRQ_AMIGA_CIAA_ALRM 16
-#define IRQ_AMIGA_CIAA_SP   17
-#define IRQ_AMIGA_CIAA_FLG  18
-#define IRQ_AMIGA_CIAB      19
-#define IRQ_AMIGA_CIAB_TA   19
-#define IRQ_AMIGA_CIAB_TB   20
-#define IRQ_AMIGA_CIAB_ALRM 21
-#define IRQ_AMIGA_CIAB_SP   22
-#define IRQ_AMIGA_CIAB_FLG  23
-
-/* auto-vector interrupts */
-#define IRQ_AMIGA_AUTO      24
-#define IRQ_AMIGA_AUTO_0    24 /* This is just a dummy */
-#define IRQ_AMIGA_AUTO_1    25
-#define IRQ_AMIGA_AUTO_2    26
-#define IRQ_AMIGA_AUTO_3    27
-#define IRQ_AMIGA_AUTO_4    28
-#define IRQ_AMIGA_AUTO_5    29
-#define IRQ_AMIGA_AUTO_6    30
-#define IRQ_AMIGA_AUTO_7    31
-
-#define IRQ_FLOPPY         IRQ_AMIGA_DSKBLK
+#define IRQ_AMIGA_CIAA         (IRQ_USER+14)
+#define IRQ_AMIGA_CIAA_TA      (IRQ_USER+14)
+#define IRQ_AMIGA_CIAA_TB      (IRQ_USER+15)
+#define IRQ_AMIGA_CIAA_ALRM    (IRQ_USER+16)
+#define IRQ_AMIGA_CIAA_SP      (IRQ_USER+17)
+#define IRQ_AMIGA_CIAA_FLG     (IRQ_USER+18)
+#define IRQ_AMIGA_CIAB         (IRQ_USER+19)
+#define IRQ_AMIGA_CIAB_TA      (IRQ_USER+19)
+#define IRQ_AMIGA_CIAB_TB      (IRQ_USER+20)
+#define IRQ_AMIGA_CIAB_ALRM    (IRQ_USER+21)
+#define IRQ_AMIGA_CIAB_SP      (IRQ_USER+22)
+#define IRQ_AMIGA_CIAB_FLG     (IRQ_USER+23)
 
-/* INTREQR masks */
-#define IRQ1_MASK   0x0007     /* INTREQR mask for IRQ 1 */
-#define IRQ2_MASK   0x0008     /* INTREQR mask for IRQ 2 */
-#define IRQ3_MASK   0x0070     /* INTREQR mask for IRQ 3 */
-#define IRQ4_MASK   0x0780     /* INTREQR mask for IRQ 4 */
-#define IRQ5_MASK   0x1800     /* INTREQR mask for IRQ 5 */
-#define IRQ6_MASK   0x2000     /* INTREQR mask for IRQ 6 */
-#define IRQ7_MASK   0x4000     /* INTREQR mask for IRQ 7 */
 
+/* INTREQR masks */
 #define IF_SETCLR   0x8000      /* set/clr bit */
 #define IF_INTEN    0x4000     /* master interrupt bit in INT* registers */
 #define IF_EXTER    0x2000     /* external level 6 and CIA B interrupt */
 #define IF_DSKBLK   0x0002     /* diskblock DMA finished */
 #define IF_TBE     0x0001      /* serial transmit buffer empty interrupt */
 
-extern void amiga_do_irq(int irq, struct pt_regs *fp);
-extern void amiga_do_irq_list(int irq, struct pt_regs *fp);
-
 /* CIA interrupt control register bits */
 
 #define CIA_ICR_TA     0x01
@@ -125,6 +104,7 @@ extern void amiga_do_irq_list(int irq, struct pt_regs *fp);
 
 extern struct ciabase ciaa_base, ciab_base;
 
+extern void cia_init_IRQ(struct ciabase *base);
 extern unsigned char cia_set_irq(struct ciabase *base, unsigned char mask);
 extern unsigned char cia_able_irq(struct ciabase *base, unsigned char mask);
 
index 4304e1c33e17583eace379046460e4ac8336aa1c..a1373b9aa2811535728a5e95c07fdd827b6099b1 100644 (file)
@@ -3,6 +3,8 @@
 #ifndef _ASMm68k_APOLLOHW_H_
 #define _ASMm68k_APOLLOHW_H_
 
+#include <linux/types.h>
+
 /*
    apollo models
 */
@@ -101,4 +103,6 @@ extern u_long timer_physaddr;
 
 #define isaIO2mem(x) (((((x) & 0x3f8)  << 7) | (((x) & 0xfc00) >> 6) | ((x) & 0x7)) + 0x40000 + IO_BASE)
 
+#define IRQ_APOLLO     IRQ_USER
+
 #endif
index 64f92880ce43f7f4e160cbf0538946af2a9b9138..b4eadf8527387292c19023b7c4dca8c36b8db7cd 100644 (file)
@@ -3,7 +3,7 @@
 #define _atari_stdma_h
 
 
-#include <asm/irq.h>
+#include <linux/interrupt.h>
 
 
 /***************************** Prototypes *****************************/
index 42952c890593a6b19854adcef9859a3054be1ff7..0ed454fc24bb5416e0b4f0c1c17b1c95fc15fe6e 100644 (file)
 #define IRQ_TYPE_FAST     1
 #define IRQ_TYPE_PRIO     2
 
-#define        IRQ_SPURIOUS      (0)
-
-/* auto-vector interrupts */
-#define IRQ_AUTO_1        (1)
-#define IRQ_AUTO_2        (2)
-#define IRQ_AUTO_3        (3)
-#define IRQ_AUTO_4        (4)
-#define IRQ_AUTO_5        (5)
-#define IRQ_AUTO_6        (6)
-#define IRQ_AUTO_7        (7)
-
 /* ST-MFP interrupts */
 #define IRQ_MFP_BUSY      (8)
 #define IRQ_MFP_DCD       (9)
index 28a859b039590a95a2b61b95ea4b41104725cfca..f40d2f8510ee9c536f0a49efc03c22bac1a50028 100644 (file)
@@ -109,23 +109,23 @@ typedef struct {
 
 #define BVME_IRQ_TYPE_PRIO     0
 
-#define BVME_IRQ_PRN           0x54
-#define BVME_IRQ_I596          0x1a
-#define BVME_IRQ_SCSI          0x1b
-#define BVME_IRQ_TIMER         0x59
-#define BVME_IRQ_RTC           0x1e
-#define BVME_IRQ_ABORT         0x1f
+#define BVME_IRQ_PRN           (IRQ_USER+20)
+#define BVME_IRQ_TIMER         (IRQ_USER+25)
+#define BVME_IRQ_I596          IRQ_AUTO_2
+#define BVME_IRQ_SCSI          IRQ_AUTO_3
+#define BVME_IRQ_RTC           IRQ_AUTO_6
+#define BVME_IRQ_ABORT         IRQ_AUTO_7
 
 /* SCC interrupts */
-#define BVME_IRQ_SCC_BASE              0x40
-#define BVME_IRQ_SCCB_TX               0x40
-#define BVME_IRQ_SCCB_STAT             0x42
-#define BVME_IRQ_SCCB_RX               0x44
-#define BVME_IRQ_SCCB_SPCOND           0x46
-#define BVME_IRQ_SCCA_TX               0x48
-#define BVME_IRQ_SCCA_STAT             0x4a
-#define BVME_IRQ_SCCA_RX               0x4c
-#define BVME_IRQ_SCCA_SPCOND           0x4e
+#define BVME_IRQ_SCC_BASE              IRQ_USER
+#define BVME_IRQ_SCCB_TX               IRQ_USER
+#define BVME_IRQ_SCCB_STAT             (IRQ_USER+2)
+#define BVME_IRQ_SCCB_RX               (IRQ_USER+4)
+#define BVME_IRQ_SCCB_SPCOND           (IRQ_USER+6)
+#define BVME_IRQ_SCCA_TX               (IRQ_USER+8)
+#define BVME_IRQ_SCCA_STAT             (IRQ_USER+10)
+#define BVME_IRQ_SCCA_RX               (IRQ_USER+12)
+#define BVME_IRQ_SCCA_SPCOND           (IRQ_USER+14)
 
 /* Address control registers */
 
index 8aba971b13684e8ff0d9c26867a4d12b2af59170..24d3ff44913570cbccb4632b83bf5e3c37747299 100644 (file)
@@ -3,26 +3,30 @@
 
 #include <linux/mm.h>
 
+/* cache code */
+#define FLUSH_I_AND_D  (0x00000808)
+#define FLUSH_I                (0x00000008)
+
 /*
  * Cache handling functions
  */
 
-#define flush_icache()                                         \
-({                                                             \
-       if (CPU_IS_040_OR_060)                                  \
-               __asm__ __volatile__("nop\n\t"                  \
-                                    ".chip 68040\n\t"          \
-                                    "cinva %%ic\n\t"           \
-                                    ".chip 68k" : );           \
-       else {                                                  \
-               unsigned long _tmp;                             \
-               __asm__ __volatile__("movec %%cacr,%0\n\t"      \
-                                    "orw %1,%0\n\t"            \
-                                    "movec %0,%%cacr"          \
-                                    : "=&d" (_tmp)             \
-                                    : "id" (FLUSH_I)); \
-       }                                                       \
-})
+static inline void flush_icache(void)
+{
+       if (CPU_IS_040_OR_060)
+               asm volatile (  "nop\n"
+                       "       .chip   68040\n"
+                       "       cpusha  %bc\n"
+                       "       .chip   68k");
+       else {
+               unsigned long tmp;
+               asm volatile (  "movec  %%cacr,%0\n"
+                       "       or.w    %1,%0\n"
+                       "       movec   %0,%%cacr"
+                       : "=&d" (tmp)
+                       : "id" (FLUSH_I));
+       }
+}
 
 /*
  * invalidate the cache for the specified memory range.
@@ -43,10 +47,6 @@ extern void cache_push(unsigned long paddr, int len);
  */
 extern void cache_push_v(unsigned long vaddr, int len);
 
-/* cache code */
-#define FLUSH_I_AND_D  (0x00000808)
-#define FLUSH_I                (0x00000008)
-
 /* This is needed whenever the virtual mapping of the current
    process changes.  */
 #define __flush_cache_all()                                    \
index dffd59cf136496c57d392f2908cf5e23d210107f..cebbb03370eca37fdb33d3ab8a71611be0280489 100644 (file)
@@ -1,11 +1,91 @@
 #ifndef _M68K_DMA_MAPPING_H
 #define _M68K_DMA_MAPPING_H
 
+#include <asm/cache.h>
 
-#ifdef CONFIG_PCI
-#include <asm-generic/dma-mapping.h>
-#else
-#include <asm-generic/dma-mapping-broken.h>
-#endif
+struct scatterlist;
+
+static inline int dma_supported(struct device *dev, u64 mask)
+{
+       return 1;
+}
+
+static inline int dma_set_mask(struct device *dev, u64 mask)
+{
+       return 0;
+}
+
+static inline int dma_get_cache_alignment(void)
+{
+       return 1 << L1_CACHE_SHIFT;
+}
+
+static inline int dma_is_consistent(dma_addr_t dma_addr)
+{
+       return 0;
+}
+
+extern void *dma_alloc_coherent(struct device *, size_t,
+                               dma_addr_t *, int);
+extern void dma_free_coherent(struct device *, size_t,
+                             void *, dma_addr_t);
+
+static inline void *dma_alloc_noncoherent(struct device *dev, size_t size,
+                                         dma_addr_t *handle, int flag)
+{
+       return dma_alloc_coherent(dev, size, handle, flag);
+}
+static inline void dma_free_noncoherent(struct device *dev, size_t size,
+                                       void *addr, dma_addr_t handle)
+{
+       dma_free_coherent(dev, size, addr, handle);
+}
+static inline void dma_cache_sync(void *vaddr, size_t size,
+                                 enum dma_data_direction dir)
+{
+       /* we use coherent allocation, so not much to do here. */
+}
+
+extern dma_addr_t dma_map_single(struct device *, void *, size_t,
+                                enum dma_data_direction);
+static inline void dma_unmap_single(struct device *dev, dma_addr_t addr,
+                                   size_t size, enum dma_data_direction dir)
+{
+}
+
+extern dma_addr_t dma_map_page(struct device *, struct page *,
+                              unsigned long, size_t size,
+                              enum dma_data_direction);
+static inline void dma_unmap_page(struct device *dev, dma_addr_t address,
+                                 size_t size, enum dma_data_direction dir)
+{
+}
+
+extern int dma_map_sg(struct device *, struct scatterlist *, int,
+                     enum dma_data_direction);
+static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+                               int nhwentries, enum dma_data_direction dir)
+{
+}
+
+extern void dma_sync_single_for_device(struct device *, dma_addr_t, size_t,
+                                      enum dma_data_direction);
+extern void dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
+                                  enum dma_data_direction);
+
+static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle,
+                                          size_t size, enum dma_data_direction dir)
+{
+}
+
+static inline void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+                                      int nents, enum dma_data_direction dir)
+{
+}
+
+static inline int dma_mapping_error(dma_addr_t handle)
+{
+       return 0;
+}
 
 #endif  /* _M68K_DMA_MAPPING_H */
index 9727ca9d9f26bd26b5769bdaa6669b5ef6374ff2..f4ae7d8feac682cc9190e795f3cbdaf2a43280a3 100644 (file)
@@ -1,13 +1,9 @@
 #ifndef _M68K_IRQ_H_
 #define _M68K_IRQ_H_
 
-#include <linux/interrupt.h>
-
-/*
- * # of m68k interrupts
- */
-
-#define SYS_IRQS 8
+#include <linux/linkage.h>
+#include <linux/hardirq.h>
+#include <linux/spinlock_types.h>
 
 /*
  * This should be the same as the max(NUM_X_SOURCES) for all the
  * Currently the Atari has 72 and the Amiga 24, but if both are
  * supported in the kernel it is better to make room for 72.
  */
-#if defined(CONFIG_ATARI) || defined(CONFIG_MAC)
-#define NR_IRQS (72+SYS_IRQS)
+#if defined(CONFIG_VME) || defined(CONFIG_SUN3) || defined(CONFIG_SUN3X)
+#define NR_IRQS 200
+#elif defined(CONFIG_ATARI) || defined(CONFIG_MAC)
+#define NR_IRQS 72
+#elif defined(CONFIG_Q40)
+#define NR_IRQS        43
+#elif defined(CONFIG_AMIGA)
+#define NR_IRQS        32
+#elif defined(CONFIG_APOLLO)
+#define NR_IRQS        24
+#elif defined(CONFIG_HP300)
+#define NR_IRQS        8
 #else
-#define NR_IRQS (24+SYS_IRQS)
+#error unknown nr of irqs
 #endif
 
 /*
  * that routine requires service.
  */
 
-#define IRQ1           (1)     /* level 1 interrupt */
-#define IRQ2           (2)     /* level 2 interrupt */
-#define IRQ3           (3)     /* level 3 interrupt */
-#define IRQ4           (4)     /* level 4 interrupt */
-#define IRQ5           (5)     /* level 5 interrupt */
-#define IRQ6           (6)     /* level 6 interrupt */
-#define IRQ7           (7)     /* level 7 interrupt (non-maskable) */
+#define IRQ_SPURIOUS   0
 
-/*
- * "Generic" interrupt sources
- */
-
-#define IRQ_SCHED_TIMER        (8)    /* interrupt source for scheduling timer */
+#define IRQ_AUTO_1     1       /* level 1 interrupt */
+#define IRQ_AUTO_2     2       /* level 2 interrupt */
+#define IRQ_AUTO_3     3       /* level 3 interrupt */
+#define IRQ_AUTO_4     4       /* level 4 interrupt */
+#define IRQ_AUTO_5     5       /* level 5 interrupt */
+#define IRQ_AUTO_6     6       /* level 6 interrupt */
+#define IRQ_AUTO_7     7       /* level 7 interrupt (non-maskable) */
 
-static __inline__ int irq_canonicalize(int irq)
-{
-       return irq;
-}
-
-/*
- * Machine specific interrupt sources.
- *
- * Adding an interrupt service routine for a source with this bit
- * set indicates a special machine specific interrupt source.
- * The machine specific files define these sources.
- *
- * The IRQ_MACHSPEC bit is now gone - the only thing it did was to
- * introduce unnecessary overhead.
- *
- * All interrupt handling is actually machine specific so it is better
- * to use function pointers, as used by the Sparc port, and select the
- * interrupt handling functions when initializing the kernel. This way
- * we save some unnecessary overhead at run-time.
- *                                                      01/11/97 - Jes
- */
+#define IRQ_USER       8
 
-extern void (*enable_irq)(unsigned int);
-extern void (*disable_irq)(unsigned int);
+extern unsigned int irq_canonicalize(unsigned int irq);
+extern void enable_irq(unsigned int);
+extern void disable_irq(unsigned int);
 #define disable_irq_nosync     disable_irq
 
 struct pt_regs;
 
-extern int cpu_request_irq(unsigned int,
-                          irqreturn_t (*)(int, void *, struct pt_regs *),
-                          unsigned long, const char *, void *);
-extern void cpu_free_irq(unsigned int, void *);
-
 /*
  * various flags for request_irq() - the Amiga now uses the standard
  * mechanism like all other architectures - SA_INTERRUPT and SA_SHIRQ
@@ -105,29 +83,45 @@ extern void cpu_free_irq(unsigned int, void *);
  * interrupt source (if it supports chaining).
  */
 typedef struct irq_node {
-       irqreturn_t     (*handler)(int, void *, struct pt_regs *);
-       unsigned long   flags;
+       int             (*handler)(int, void *, struct pt_regs *);
        void            *dev_id;
-       const char      *devname;
        struct irq_node *next;
+       unsigned long   flags;
+       const char      *devname;
 } irq_node_t;
 
 /*
  * This structure has only 4 elements for speed reasons
  */
 typedef struct irq_handler {
-       irqreturn_t     (*handler)(int, void *, struct pt_regs *);
+       int             (*handler)(int, void *, struct pt_regs *);
        unsigned long   flags;
        void            *dev_id;
        const char      *devname;
 } irq_handler_t;
 
-/* count of spurious interrupts */
-extern volatile unsigned int num_spurious;
+struct irq_controller {
+       const char *name;
+       spinlock_t lock;
+       int (*startup)(unsigned int irq);
+       void (*shutdown)(unsigned int irq);
+       void (*enable)(unsigned int irq);
+       void (*disable)(unsigned int irq);
+};
+
+extern int m68k_irq_startup(unsigned int);
+extern void m68k_irq_shutdown(unsigned int);
 
 /*
  * This function returns a new irq_node_t
  */
 extern irq_node_t *new_irq_node(void);
 
+extern void m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *));
+extern void m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt,
+                                     void (*handler)(unsigned int, struct pt_regs *));
+extern void m68k_setup_irq_controller(struct irq_controller *, unsigned int, unsigned int);
+
+asmlinkage void m68k_handle_int(unsigned int, struct pt_regs *);
+
 #endif /* _M68K_IRQ_H_ */
index 7644a639cd6c5b6bccc7363b902e6f37058fa093..7221f7251934b996c817ac11636241478cb24bf8 100644 (file)
 
 #define OSS_IRQLEV_DISABLED    0
 #define OSS_IRQLEV_IOPISM      1       /* ADB? */
-#define OSS_IRQLEV_SCSI                2
-#define OSS_IRQLEV_NUBUS             /* keep this on its own level */
-#define OSS_IRQLEV_IOPSCC            /* matches VIA alternate mapping */
-#define OSS_IRQLEV_SOUND             /* matches VIA alternate mapping */
+#define OSS_IRQLEV_SCSI                IRQ_AUTO_2
+#define OSS_IRQLEV_NUBUS       IRQ_AUTO_3      /* keep this on its own level */
+#define OSS_IRQLEV_IOPSCC      IRQ_AUTO_4      /* matches VIA alternate mapping */
+#define OSS_IRQLEV_SOUND       IRQ_AUTO_5      /* matches VIA alternate mapping */
 #define OSS_IRQLEV_60HZ                6       /* matches VIA alternate mapping */
-#define OSS_IRQLEV_VIA1                      /* matches VIA alternate mapping */
+#define OSS_IRQLEV_VIA1                IRQ_AUTO_6      /* matches VIA alternate mapping */
 #define OSS_IRQLEV_PARITY      7       /* matches VIA alternate mapping */
 
 #ifndef __ASSEMBLY__
index 7d3fee342369e7c169bd7af227ffe2118da36044..df898f27e4346e33fc54ec542d3f71ee0c304f0b 100644 (file)
@@ -13,14 +13,8 @@ struct buffer_head;
 extern void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *));
 /* machine dependent irq functions */
 extern void (*mach_init_IRQ) (void);
-extern irqreturn_t (*(*mach_default_handler)[]) (int, void *, struct pt_regs *);
-extern int (*mach_request_irq) (unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                                unsigned long flags, const char *devname, void *dev_id);
-extern void (*mach_free_irq) (unsigned int irq, void *dev_id);
 extern void (*mach_get_model) (char *model);
 extern int (*mach_get_hardware_list) (char *buffer);
-extern int (*mach_get_irq_list) (struct seq_file *p, void *v);
-extern irqreturn_t (*mach_process_int) (int irq, struct pt_regs *fp);
 /* machine dependent timer functions */
 extern unsigned long (*mach_gettimeoffset)(void);
 extern int (*mach_hwclk)(int, struct rtc_time*);
index 6fc3d19512d147da77573fa075030ff349bef57a..27d11da2b47961a04ad930d04183dcf6e7b1f874 100644 (file)
 extern void mac_reset(void);
 extern void mac_poweroff(void);
 extern void mac_init_IRQ(void);
-extern int mac_request_irq (unsigned int, irqreturn_t (*)(int, void *,
-                               struct pt_regs *),
-                               unsigned long, const char *, void *);
-extern void mac_free_irq(unsigned int, void *);
-extern void mac_enable_irq(unsigned int);
-extern void mac_disable_irq(unsigned int);
 extern int mac_irq_pending(unsigned int);
-extern int show_mac_interrupts(struct seq_file *, void *);
-#if 0
-extern void mac_default_handler(int irq);
-#endif
 extern void mac_identify(void);
 extern void mac_report_hardware(void);
 extern void mac_debugging_penguin(int);
index fd8c3a9fea4d3bf4f7f0b07a7520e6e0688cc486..679c48ab44076c3e31006c6b17406c6909df0106 100644 (file)
 #define IRQ_SRC(irq)   (irq >> 3)
 #define        IRQ_IDX(irq)    (irq & 7)
 
-#define        IRQ_SPURIOUS      (0)
-
-/* auto-vector interrupts */
-#define IRQ_AUTO_1        (1)
-#define IRQ_AUTO_2        (2)
-#define IRQ_AUTO_3        (3)
-#define IRQ_AUTO_4        (4)
-#define IRQ_AUTO_5        (5)
-#define IRQ_AUTO_6        (6)
-#define IRQ_AUTO_7        (7)
-
 /* VIA1 interrupts */
 #define IRQ_VIA1_0       (8)           /* one second int. */
 #define IRQ_VIA1_1        (9)          /* VBlank int. */
 #define INT_CLK   24576            /* CLK while int_clk =2.456MHz and divide = 100 */
 #define INT_TICKS 246      /* to make sched_time = 99.902... HZ */
 
-extern irq_node_t *mac_irq_list[NUM_MAC_SOURCES];
-extern void mac_do_irq_list(int irq, struct pt_regs *);
-
 #endif /* asm/macints.h */
index f245139f3671c8103bce64860699851ca10782fe..b8104310847226a1184df565b03c2f6abbb47649 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _MVME147HW_H_
 #define _MVME147HW_H_
 
+#include <asm/irq.h>
+
 typedef struct {
        unsigned char
                ctrl,
@@ -72,39 +74,39 @@ struct pcc_regs {
 #define PCC_LEVEL_SCSI_PORT    0x04
 #define PCC_LEVEL_SCSI_DMA     0x04
 
-#define PCC_IRQ_AC_FAIL                0x40
-#define PCC_IRQ_BERR           0x41
-#define PCC_IRQ_ABORT          0x42
-/* #define PCC_IRQ_SERIAL      0x43 */
-#define PCC_IRQ_PRINTER                0x47
-#define PCC_IRQ_TIMER1         0x48
-#define PCC_IRQ_TIMER2         0x49
-#define PCC_IRQ_SOFTWARE1      0x4a
-#define PCC_IRQ_SOFTWARE2      0x4b
+#define PCC_IRQ_AC_FAIL                (IRQ_USER+0)
+#define PCC_IRQ_BERR           (IRQ_USER+1)
+#define PCC_IRQ_ABORT          (IRQ_USER+2)
+/* #define PCC_IRQ_SERIAL      (IRQ_USER+3) */
+#define PCC_IRQ_PRINTER                (IRQ_USER+7)
+#define PCC_IRQ_TIMER1         (IRQ_USER+8)
+#define PCC_IRQ_TIMER2         (IRQ_USER+9)
+#define PCC_IRQ_SOFTWARE1      (IRQ_USER+10)
+#define PCC_IRQ_SOFTWARE2      (IRQ_USER+11)
 
 
 #define M147_SCC_A_ADDR                0xfffe3002
 #define M147_SCC_B_ADDR                0xfffe3000
 #define M147_SCC_PCLK          5000000
 
-#define MVME147_IRQ_SCSI_PORT  0x45
-#define MVME147_IRQ_SCSI_DMA   0x46
+#define MVME147_IRQ_SCSI_PORT  (IRQ_USER+0x45)
+#define MVME147_IRQ_SCSI_DMA   (IRQ_USER+0x46)
 
 /* SCC interrupts, for MVME147 */
 
 #define MVME147_IRQ_TYPE_PRIO  0
-#define MVME147_IRQ_SCC_BASE           0x60
-#define MVME147_IRQ_SCCB_TX            0x60
-#define MVME147_IRQ_SCCB_STAT          0x62
-#define MVME147_IRQ_SCCB_RX            0x64
-#define MVME147_IRQ_SCCB_SPCOND                0x66
-#define MVME147_IRQ_SCCA_TX            0x68
-#define MVME147_IRQ_SCCA_STAT          0x6a
-#define MVME147_IRQ_SCCA_RX            0x6c
-#define MVME147_IRQ_SCCA_SPCOND                0x6e
+#define MVME147_IRQ_SCC_BASE           (IRQ_USER+32)
+#define MVME147_IRQ_SCCB_TX            (IRQ_USER+32)
+#define MVME147_IRQ_SCCB_STAT          (IRQ_USER+34)
+#define MVME147_IRQ_SCCB_RX            (IRQ_USER+36)
+#define MVME147_IRQ_SCCB_SPCOND                (IRQ_USER+38)
+#define MVME147_IRQ_SCCA_TX            (IRQ_USER+40)
+#define MVME147_IRQ_SCCA_STAT          (IRQ_USER+42)
+#define MVME147_IRQ_SCCA_RX            (IRQ_USER+44)
+#define MVME147_IRQ_SCCA_SPCOND                (IRQ_USER+46)
 
 #define MVME147_LANCE_BASE     0xfffe1800
-#define MVME147_LANCE_IRQ      0x44
+#define MVME147_LANCE_IRQ      (IRQ_USER+4)
 
 #define ETHERNET_ADDRESS 0xfffe0778
 
index 5d07231d24261021c668ea7f71c7ed2f07c8249c..6117f56653d28d3c14bcbee597a552b18cf6cecd 100644 (file)
@@ -66,28 +66,28 @@ typedef struct {
 
 #define MVME162_IRQ_TYPE_PRIO  0
 
-#define MVME167_IRQ_PRN                0x54
-#define MVME16x_IRQ_I596       0x57
-#define MVME16x_IRQ_SCSI       0x55
-#define MVME16x_IRQ_FLY                0x7f
-#define MVME167_IRQ_SER_ERR    0x5c
-#define MVME167_IRQ_SER_MODEM  0x5d
-#define MVME167_IRQ_SER_TX     0x5e
-#define MVME167_IRQ_SER_RX     0x5f
-#define MVME16x_IRQ_TIMER      0x59
-#define MVME167_IRQ_ABORT      0x6e
-#define MVME162_IRQ_ABORT      0x5e
+#define MVME167_IRQ_PRN                (IRQ_USER+20)
+#define MVME16x_IRQ_I596       (IRQ_USER+23)
+#define MVME16x_IRQ_SCSI       (IRQ_USER+21)
+#define MVME16x_IRQ_FLY                (IRQ_USER+63)
+#define MVME167_IRQ_SER_ERR    (IRQ_USER+28)
+#define MVME167_IRQ_SER_MODEM  (IRQ_USER+29)
+#define MVME167_IRQ_SER_TX     (IRQ_USER+30)
+#define MVME167_IRQ_SER_RX     (IRQ_USER+31)
+#define MVME16x_IRQ_TIMER      (IRQ_USER+25)
+#define MVME167_IRQ_ABORT      (IRQ_USER+46)
+#define MVME162_IRQ_ABORT      (IRQ_USER+30)
 
 /* SCC interrupts, for MVME162 */
-#define MVME162_IRQ_SCC_BASE           0x40
-#define MVME162_IRQ_SCCB_TX            0x40
-#define MVME162_IRQ_SCCB_STAT          0x42
-#define MVME162_IRQ_SCCB_RX            0x44
-#define MVME162_IRQ_SCCB_SPCOND                0x46
-#define MVME162_IRQ_SCCA_TX            0x48
-#define MVME162_IRQ_SCCA_STAT          0x4a
-#define MVME162_IRQ_SCCA_RX            0x4c
-#define MVME162_IRQ_SCCA_SPCOND                0x4e
+#define MVME162_IRQ_SCC_BASE           (IRQ_USER+0)
+#define MVME162_IRQ_SCCB_TX            (IRQ_USER+0)
+#define MVME162_IRQ_SCCB_STAT          (IRQ_USER+2)
+#define MVME162_IRQ_SCCB_RX            (IRQ_USER+4)
+#define MVME162_IRQ_SCCB_SPCOND                (IRQ_USER+6)
+#define MVME162_IRQ_SCCA_TX            (IRQ_USER+8)
+#define MVME162_IRQ_SCCA_STAT          (IRQ_USER+10)
+#define MVME162_IRQ_SCCA_RX            (IRQ_USER+12)
+#define MVME162_IRQ_SCCA_SPCOND                (IRQ_USER+14)
 
 /* MVME162 version register */
 
index d7c9b5c5e6c7c59a697a30d7e7c5d5a64265bb15..8e612266da51bb1bcc6871bf55663b144d1d2d12 100644 (file)
@@ -2,18 +2,17 @@
 #define _M68K_SCATTERLIST_H
 
 struct scatterlist {
-       /* These two are only valid if ADDRESS member of this
-        * struct is NULL.
-        */
        struct page *page;
        unsigned int offset;
-
        unsigned int length;
 
-       __u32 dvma_address; /* A place to hang host-specific addresses at. */
+       __u32 dma_address;      /* A place to hang host-specific addresses at. */
 };
 
 /* This is bogus and should go away. */
 #define ISA_DMA_THRESHOLD (0x00ffffff)
 
+#define sg_dma_address(sg)     ((sg)->dma_address)
+#define sg_dma_len(sg)         ((sg)->length)
+
 #endif /* !(_M68K_SCATTERLIST_H) */
index b7b7ea20caaba7097438391491de756cad26bbc4..85037a3d3e8e0cb0e1505c466ed05298e6eee08a 100644 (file)
@@ -156,13 +156,17 @@ typedef struct sigaltstack {
 
 static inline void sigaddset(sigset_t *set, int _sig)
 {
-       __asm__("bfset %0{%1,#1}" : "=m" (*set) : "id" ((_sig - 1) ^ 31)
+       asm ("bfset %0{%1,#1}"
+               : "+od" (*set)
+               : "id" ((_sig - 1) ^ 31)
                : "cc");
 }
 
 static inline void sigdelset(sigset_t *set, int _sig)
 {
-       __asm__("bfclr %0{%1,#1}" : "=m"(*set) : "id"((_sig - 1) ^ 31)
+       asm ("bfclr %0{%1,#1}"
+               : "+od" (*set)
+               : "id" ((_sig - 1) ^ 31)
                : "cc");
 }
 
@@ -175,8 +179,10 @@ static inline int __const_sigismember(sigset_t *set, int _sig)
 static inline int __gen_sigismember(sigset_t *set, int _sig)
 {
        int ret;
-       __asm__("bfextu %1{%2,#1},%0"
-               : "=d"(ret) : "m"(*set), "id"((_sig-1) ^ 31));
+       asm ("bfextu %1{%2,#1},%0"
+               : "=d" (ret)
+               : "od" (*set), "id" ((_sig-1) ^ 31)
+               : "cc");
        return ret;
 }
 
@@ -187,7 +193,10 @@ static inline int __gen_sigismember(sigset_t *set, int _sig)
 
 static inline int sigfindinword(unsigned long word)
 {
-       __asm__("bfffo %1{#0,#0},%0" : "=d"(word) : "d"(word & -word) : "cc");
+       asm ("bfffo %1{#0,#0},%0"
+               : "=d" (word)
+               : "d" (word & -word)
+               : "cc");
        return word ^ 31;
 }
 
index bd038fccb64b8c7f6dbb85b545cff2375000074d..de91fa071b995f3d1aa5fbac3bcc48cb7177dfac 100644 (file)
 #define SUN3INTS_H
 
 #include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
 #include <linux/interrupt.h>
-#include <linux/seq_file.h>
-#include <asm/segment.h>
 #include <asm/intersil.h>
 #include <asm/oplib.h>
+#include <asm/traps.h>
 
 #define SUN3_INT_VECS 192
 
 void sun3_enable_irq(unsigned int irq);
 void sun3_disable_irq(unsigned int irq);
-int sun3_request_irq(unsigned int irq,
-                     irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                     unsigned long flags, const char *devname, void *dev_id
-                   );
 extern void sun3_init_IRQ (void);
-extern irqreturn_t (*sun3_default_handler[]) (int, void *, struct pt_regs *);
-extern void sun3_free_irq (unsigned int irq, void *dev_id);
 extern void sun3_enable_interrupts (void);
 extern void sun3_disable_interrupts (void);
-extern int show_sun3_interrupts(struct seq_file *, void *);
-extern irqreturn_t sun3_process_int(int, struct pt_regs *);
 extern volatile unsigned char* sun3_intreg;
 
 /* master list of VME vectors -- don't fuck with this */
-#define SUN3_VEC_FLOPPY 0x40
-#define SUN3_VEC_VMESCSI0 0x40
-#define SUN3_VEC_VMESCSI1 0x41
-#define SUN3_VEC_CG 0xA8
+#define SUN3_VEC_FLOPPY                (IRQ_USER+0)
+#define SUN3_VEC_VMESCSI0      (IRQ_USER+0)
+#define SUN3_VEC_VMESCSI1      (IRQ_USER+1)
+#define SUN3_VEC_CG            (IRQ_USER+104)
 
 
 #endif /* SUN3INTS_H */
index 47505619125281f1fd59397a584cf1c9a55200cf..8caef25624c7decedaca65c84693cab98a2a65e9 100644 (file)
 
 #ifndef __ASSEMBLY__
 
+#include <linux/linkage.h>
+#include <asm/ptrace.h>
+
 typedef void (*e_vector)(void);
 
+asmlinkage void auto_inthandler(void);
+asmlinkage void user_inthandler(void);
+asmlinkage void bad_inthandler(void);
+
 extern e_vector vectors[];
 
 #endif
index b761ef218ceac1df13ae556b9906322171aad6c3..88b1f47400e17f8bfb4137e66c849373fef9fac2 100644 (file)
@@ -181,144 +181,164 @@ asm volatile ("\n"                                      \
 unsigned long __generic_copy_from_user(void *to, const void __user *from, unsigned long n);
 unsigned long __generic_copy_to_user(void __user *to, const void *from, unsigned long n);
 
+#define __constant_copy_from_user_asm(res, to, from, tmp, n, s1, s2, s3)\
+       asm volatile ("\n"                                              \
+               "1:     moves."#s1"     (%2)+,%3\n"                     \
+               "       move."#s1"      %3,(%1)+\n"                     \
+               "2:     moves."#s2"     (%2)+,%3\n"                     \
+               "       move."#s2"      %3,(%1)+\n"                     \
+               "       .ifnc   \""#s3"\",\"\"\n"                       \
+               "3:     moves."#s3"     (%2)+,%3\n"                     \
+               "       move."#s3"      %3,(%1)+\n"                     \
+               "       .endif\n"                                       \
+               "4:\n"                                                  \
+               "       .section __ex_table,\"a\"\n"                    \
+               "       .align  4\n"                                    \
+               "       .long   1b,10f\n"                               \
+               "       .long   2b,20f\n"                               \
+               "       .ifnc   \""#s3"\",\"\"\n"                       \
+               "       .long   3b,30f\n"                               \
+               "       .endif\n"                                       \
+               "       .previous\n"                                    \
+               "\n"                                                    \
+               "       .section .fixup,\"ax\"\n"                       \
+               "       .even\n"                                        \
+               "10:    clr."#s1"       (%1)+\n"                        \
+               "20:    clr."#s2"       (%1)+\n"                        \
+               "       .ifnc   \""#s3"\",\"\"\n"                       \
+               "30:    clr."#s3"       (%1)+\n"                        \
+               "       .endif\n"                                       \
+               "       moveq.l #"#n",%0\n"                             \
+               "       jra     4b\n"                                   \
+               "       .previous\n"                                    \
+               : "+d" (res), "+&a" (to), "+a" (from), "=&d" (tmp)      \
+               : : "memory")
+
 static __always_inline unsigned long
 __constant_copy_from_user(void *to, const void __user *from, unsigned long n)
 {
        unsigned long res = 0, tmp;
 
-       /* limit the inlined version to 3 moves */
-       if (n == 11 || n > 12)
-               return __generic_copy_from_user(to, from, n);
-
        switch (n) {
        case 1:
                __get_user_asm(res, *(u8 *)to, (u8 *)from, u8, b, d, 1);
-               return res;
+               break;
        case 2:
                __get_user_asm(res, *(u16 *)to, (u16 *)from, u16, w, d, 2);
-               return res;
+               break;
+       case 3:
+               __constant_copy_from_user_asm(res, to, from, tmp, 3, w, b,);
+               break;
        case 4:
                __get_user_asm(res, *(u32 *)to, (u32 *)from, u32, l, r, 4);
-               return res;
+               break;
+       case 5:
+               __constant_copy_from_user_asm(res, to, from, tmp, 5, l, b,);
+               break;
+       case 6:
+               __constant_copy_from_user_asm(res, to, from, tmp, 6, l, w,);
+               break;
+       case 7:
+               __constant_copy_from_user_asm(res, to, from, tmp, 7, l, w, b);
+               break;
+       case 8:
+               __constant_copy_from_user_asm(res, to, from, tmp, 8, l, l,);
+               break;
+       case 9:
+               __constant_copy_from_user_asm(res, to, from, tmp, 9, l, l, b);
+               break;
+       case 10:
+               __constant_copy_from_user_asm(res, to, from, tmp, 10, l, l, w);
+               break;
+       case 12:
+               __constant_copy_from_user_asm(res, to, from, tmp, 12, l, l, l);
+               break;
+       default:
+               /* we limit the inlined version to 3 moves */
+               return __generic_copy_from_user(to, from, n);
        }
 
-       asm volatile ("\n"
-               "       .ifndef .Lfrom_user\n"
-               "       .set    .Lfrom_user,1\n"
-               "       .macro  copy_from_user to,from,tmp\n"
-               "       .if     .Lcnt >= 4\n"
-               "1:     moves.l (\\from)+,\\tmp\n"
-               "       move.l  \\tmp,(\\to)+\n"
-               "       .set    .Lcnt,.Lcnt-4\n"
-               "       .elseif .Lcnt & 2\n"
-               "1:     moves.w (\\from)+,\\tmp\n"
-               "       move.w  \\tmp,(\\to)+\n"
-               "       .set    .Lcnt,.Lcnt-2\n"
-               "       .elseif .Lcnt & 1\n"
-               "1:     moves.b (\\from)+,\\tmp\n"
-               "       move.b  \\tmp,(\\to)+\n"
-               "       .set    .Lcnt,.Lcnt-1\n"
-               "       .else\n"
-               "       .exitm\n"
-               "       .endif\n"
-               "\n"
-               "       .section __ex_table,\"a\"\n"
-               "       .align  4\n"
-               "       .long   1b,3f\n"
-               "       .previous\n"
-               "       .endm\n"
-               "       .endif\n"
-               "\n"
-               "       .set    .Lcnt,%c4\n"
-               "       copy_from_user %1,%2,%3\n"
-               "       copy_from_user %1,%2,%3\n"
-               "       copy_from_user %1,%2,%3\n"
-               "2:\n"
-               "       .section .fixup,\"ax\"\n"
-               "       .even\n"
-               "3:     moveq.l %4,%0\n"
-               "       move.l  %5,%1\n"
-               "       .rept   %c4 / 4\n"
-               "       clr.l   (%1)+\n"
-               "       .endr\n"
-               "       .if     %c4 & 2\n"
-               "       clr.w   (%1)+\n"
-               "       .endif\n"
-               "       .if     %c4 & 1\n"
-               "       clr.b   (%1)+\n"
-               "       .endif\n"
-               "       jra     2b\n"
-               "       .previous\n"
-               : "+r" (res), "+a" (to), "+a" (from), "=&d" (tmp)
-               : "i" (n), "g" (to)
-               : "memory");
-
        return res;
 }
 
+#define __constant_copy_to_user_asm(res, to, from, tmp, n, s1, s2, s3) \
+       asm volatile ("\n"                                              \
+               "       move."#s1"      (%2)+,%3\n"                     \
+               "11:    moves."#s1"     %3,(%1)+\n"                     \
+               "12:    move."#s2"      (%2)+,%3\n"                     \
+               "21:    moves."#s2"     %3,(%1)+\n"                     \
+               "22:\n"                                                 \
+               "       .ifnc   \""#s3"\",\"\"\n"                       \
+               "       move."#s3"      (%2)+,%3\n"                     \
+               "31:    moves."#s3"     %3,(%1)+\n"                     \
+               "32:\n"                                                 \
+               "       .endif\n"                                       \
+               "4:\n"                                                  \
+               "\n"                                                    \
+               "       .section __ex_table,\"a\"\n"                    \
+               "       .align  4\n"                                    \
+               "       .long   11b,5f\n"                               \
+               "       .long   12b,5f\n"                               \
+               "       .long   21b,5f\n"                               \
+               "       .long   22b,5f\n"                               \
+               "       .ifnc   \""#s3"\",\"\"\n"                       \
+               "       .long   31b,5f\n"                               \
+               "       .long   32b,5f\n"                               \
+               "       .endif\n"                                       \
+               "       .previous\n"                                    \
+               "\n"                                                    \
+               "       .section .fixup,\"ax\"\n"                       \
+               "       .even\n"                                        \
+               "5:     moveq.l #"#n",%0\n"                             \
+               "       jra     4b\n"                                   \
+               "       .previous\n"                                    \
+               : "+d" (res), "+a" (to), "+a" (from), "=&d" (tmp)       \
+               : : "memory")
+
 static __always_inline unsigned long
 __constant_copy_to_user(void __user *to, const void *from, unsigned long n)
 {
        unsigned long res = 0, tmp;
 
-       /* limit the inlined version to 3 moves */
-       if (n == 11 || n > 12)
-               return __generic_copy_to_user(to, from, n);
-
        switch (n) {
        case 1:
                __put_user_asm(res, *(u8 *)from, (u8 *)to, b, d, 1);
-               return res;
+               break;
        case 2:
                __put_user_asm(res, *(u16 *)from, (u16 *)to, w, d, 2);
-               return res;
+               break;
+       case 3:
+               __constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,);
+               break;
        case 4:
                __put_user_asm(res, *(u32 *)from, (u32 *)to, l, r, 4);
-               return res;
+               break;
+       case 5:
+               __constant_copy_to_user_asm(res, to, from, tmp, 5, l, b,);
+               break;
+       case 6:
+               __constant_copy_to_user_asm(res, to, from, tmp, 6, l, w,);
+               break;
+       case 7:
+               __constant_copy_to_user_asm(res, to, from, tmp, 7, l, w, b);
+               break;
+       case 8:
+               __constant_copy_to_user_asm(res, to, from, tmp, 8, l, l,);
+               break;
+       case 9:
+               __constant_copy_to_user_asm(res, to, from, tmp, 9, l, l, b);
+               break;
+       case 10:
+               __constant_copy_to_user_asm(res, to, from, tmp, 10, l, l, w);
+               break;
+       case 12:
+               __constant_copy_to_user_asm(res, to, from, tmp, 12, l, l, l);
+               break;
+       default:
+               /* limit the inlined version to 3 moves */
+               return __generic_copy_to_user(to, from, n);
        }
 
-       asm volatile ("\n"
-               "       .ifndef .Lto_user\n"
-               "       .set    .Lto_user,1\n"
-               "       .macro  copy_to_user to,from,tmp\n"
-               "       .if     .Lcnt >= 4\n"
-               "       move.l  (\\from)+,\\tmp\n"
-               "11:    moves.l \\tmp,(\\to)+\n"
-               "12:    .set    .Lcnt,.Lcnt-4\n"
-               "       .elseif .Lcnt & 2\n"
-               "       move.w  (\\from)+,\\tmp\n"
-               "11:    moves.w \\tmp,(\\to)+\n"
-               "12:    .set    .Lcnt,.Lcnt-2\n"
-               "       .elseif .Lcnt & 1\n"
-               "       move.b  (\\from)+,\\tmp\n"
-               "11:    moves.b \\tmp,(\\to)+\n"
-               "12:    .set    .Lcnt,.Lcnt-1\n"
-               "       .else\n"
-               "       .exitm\n"
-               "       .endif\n"
-               "\n"
-               "       .section __ex_table,\"a\"\n"
-               "       .align  4\n"
-               "       .long   11b,3f\n"
-               "       .long   12b,3f\n"
-               "       .previous\n"
-               "       .endm\n"
-               "       .endif\n"
-               "\n"
-               "       .set    .Lcnt,%c4\n"
-               "       copy_to_user %1,%2,%3\n"
-               "       copy_to_user %1,%2,%3\n"
-               "       copy_to_user %1,%2,%3\n"
-               "2:\n"
-               "       .section .fixup,\"ax\"\n"
-               "       .even\n"
-               "3:     moveq.l %4,%0\n"
-               "       jra     2b\n"
-               "       .previous\n"
-               : "+r" (res), "+a" (to), "+a" (from), "=&d" (tmp)
-               : "i" (n)
-               : "memory");
-
        return res;
 }
 
index 986511db54a671d05780824a17d2aa6b09c88e98..900f472fdd2b5fc92fc6547893d5a9938a71731f 100644 (file)
@@ -145,8 +145,5 @@ static inline void __user *compat_alloc_user_space(long len)
 
        return (void __user *) (regs->regs[29] - len);
 }
-#if defined (__MIPSEL__)
-#define __COMPAT_ENDIAN_SWAP__         1
-#endif
 
 #endif /* _ASM_COMPAT_H */
index 682a5858f8d711ffe04fb187236db84b7377b2f5..83cd69e30ec3f6024a1e316dcbb4531beb1bf96d 100644 (file)
@@ -98,7 +98,7 @@ static inline void fd_disable_irq(void)
 static inline int fd_request_irq(void)
 {
        return request_irq(FLOPPY_IRQ, floppy_interrupt,
-                          SA_INTERRUPT | SA_SAMPLE_RANDOM, "floppy", NULL);
+                          SA_INTERRUPT, "floppy", NULL);
 }
 
 static inline void fd_free_irq(void)
index c9dad99b12324aaaffa8a55c62367b865740266d..9413117915f49716eba65ee75f136b2836c3af3b 100644 (file)
@@ -90,7 +90,7 @@ static inline void fd_disable_irq(void)
 static inline int fd_request_irq(void)
 {
        return request_irq(FLOPPY_IRQ, floppy_interrupt,
-                          SA_INTERRUPT | SA_SAMPLE_RANDOM, "floppy", NULL);
+                          SA_INTERRUPT, "floppy", NULL);
 }
 
 static inline void fd_free_irq(void)
index ca3aed768cdc1a8d3a528790bf073401f38acc19..458cdb2a753075d2a2acf2125b1c619a4be75a00 100644 (file)
@@ -159,10 +159,8 @@ static int fd_request_irq(void)
                return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
                                                   "floppy", NULL);
        else
-               return request_irq(FLOPPY_IRQ, floppy_interrupt,
-                                                  SA_INTERRUPT|SA_SAMPLE_RANDOM,
-                                                  "floppy", NULL);     
-
+               return request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT,
+                                  "floppy", NULL);
 }
 
 static unsigned long dma_mem_alloc(unsigned long size)
index 1ba1f27a0b63cee6a68a4222bf5503b904fe732f..a5e9e656e33267dde3e62a1e4da4ceb94853e676 100644 (file)
@@ -2,30 +2,30 @@
  * Routines for handling backlight control on PowerBooks
  *
  * For now, implementation resides in
- * arch/powerpc/platforms/powermac/pmac_support.c
+ * arch/powerpc/platforms/powermac/backlight.c
  *
  */
 #ifndef __ASM_POWERPC_BACKLIGHT_H
 #define __ASM_POWERPC_BACKLIGHT_H
 #ifdef __KERNEL__
 
-/* Abstract values */
-#define BACKLIGHT_OFF  0
-#define BACKLIGHT_MIN  1
-#define BACKLIGHT_MAX  0xf
+#include <linux/fb.h>
+#include <linux/mutex.h>
 
-struct backlight_controller {
-       int (*set_enable)(int enable, int level, void *data);
-       int (*set_level)(int level, void *data);
-};
+/* For locking instructions, see the implementation file */
+extern struct backlight_device *pmac_backlight;
+extern struct mutex pmac_backlight_mutex;
 
-extern void register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type);
-extern void unregister_backlight_controller(struct backlight_controller *ctrler, void *data);
+extern void pmac_backlight_calc_curve(struct fb_info*);
+extern int pmac_backlight_curve_lookup(struct fb_info *info, int value);
 
-extern int set_backlight_enable(int enable);
-extern int get_backlight_enable(void);
-extern int set_backlight_level(int level);
-extern int get_backlight_level(void);
+extern int pmac_has_backlight_type(const char *type);
+
+extern void pmac_backlight_key_up(void);
+extern void pmac_backlight_key_down(void);
+
+extern int pmac_backlight_set_legacy_brightness(int brightness);
+extern int pmac_backlight_get_legacy_brightness(void);
 
 #endif /* __KERNEL__ */
 #endif
index 7e2d169ee8569b74ceccfdfe78e442ef253266c3..9c8d91bf5a0d95c50e28d2883ae520edfa609a41 100644 (file)
@@ -27,8 +27,7 @@
 #define fd_disable_irq()        disable_irq(FLOPPY_IRQ)
 #define fd_cacheflush(addr,size) /* nothing */
 #define fd_request_irq()        request_irq(FLOPPY_IRQ, floppy_interrupt, \
-                                           SA_INTERRUPT|SA_SAMPLE_RANDOM, \
-                                           "floppy", NULL)
+                                           SA_INTERRUPT, "floppy", NULL)
 #define fd_free_irq()           free_irq(FLOPPY_IRQ, NULL);
 
 #ifdef CONFIG_PCI
index 184a7a4d2fdfe15fb957a55fe828c5945dc2d5a7..faa1fc70305368993778aa8fc3ece4f181b333d2 100644 (file)
@@ -22,6 +22,7 @@
 /* var is in discarded region: offset to particular copy we want */
 #define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu)))
 #define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()))
+#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()))
 
 /* A macro to avoid #include hell... */
 #define percpu_modcopy(pcpudst, src, size)                     \
@@ -41,6 +42,7 @@ extern void setup_per_cpu_areas(void);
 
 #define per_cpu(var, cpu)                      (*((void)(cpu), &per_cpu__##var))
 #define __get_cpu_var(var)                     per_cpu__##var
+#define __raw_get_cpu_var(var)                 per_cpu__##var
 
 #endif /* SMP */
 
index 8ccd4a276fe99bf68967298edeed96e5a9aa55ed..2ba191eba4482dda70005de3093914f4922912ac 100644 (file)
@@ -99,10 +99,8 @@ static int fd_request_irq(void)
                return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
                                                   "floppy", NULL);
        else
-               return request_irq(FLOPPY_IRQ, floppy_interrupt,
-                                                  SA_INTERRUPT|SA_SAMPLE_RANDOM,
-                                                  "floppy", NULL);
-
+               return request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT,
+                                  "floppy", NULL);
 }
 
 static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io)
index 436d216601e56c10f5a6d5063b1bb8b32a9250c9..d9a8cca9b653ad149003583e140a133fe914cf40 100644 (file)
@@ -40,6 +40,7 @@ extern unsigned long __per_cpu_offset[NR_CPUS];
     __typeof__(type) per_cpu__##name
 
 #define __get_cpu_var(var) __reloc_hide(var,S390_lowcore.percpu_offset)
+#define __raw_get_cpu_var(var) __reloc_hide(var,S390_lowcore.percpu_offset)
 #define per_cpu(var,cpu) __reloc_hide(var,__per_cpu_offset[cpu])
 
 /* A macro to avoid #include hell... */
@@ -57,6 +58,7 @@ do {                                                          \
     __typeof__(type) per_cpu__##name
 
 #define __get_cpu_var(var) __reloc_hide(var,0)
+#define __raw_get_cpu_var(var) __reloc_hide(var,0)
 #define per_cpu(var,cpu) __reloc_hide(var,0)
 
 #endif /* SMP */
index 38d7a2942476dff07e61e396cf2175778df08c6a..307d9ce9f9ed6bfbeec86c15fb32f3b6e15ab3b1 100644 (file)
@@ -147,11 +147,10 @@ static int fd_request_irq(void)
 {
        if(can_use_virtual_dma)
                return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
-                                                  "floppy", NULL);
+                                  "floppy", NULL);
        else
-               return request_irq(FLOPPY_IRQ, floppy_interrupt,
-                                                  SA_INTERRUPT|SA_SAMPLE_RANDOM,
-                                                  "floppy", NULL);     
+               return request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT,
+                                  "floppy", NULL);
 
 }
 
index baef13b589525f7b7b9e21fe4dde913def2e40e4..a6ece06b83dbc8144b7475c89c3423ce9b0b5360 100644 (file)
@@ -21,6 +21,7 @@ register unsigned long __local_per_cpu_offset asm("g5");
 /* var is in discarded region: offset to particular copy we want */
 #define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu)))
 #define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __local_per_cpu_offset))
+#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __local_per_cpu_offset))
 
 /* A macro to avoid #include hell... */
 #define percpu_modcopy(pcpudst, src, size)                     \
@@ -37,6 +38,7 @@ do {                                                          \
 
 #define per_cpu(var, cpu)                      (*((void)cpu, &per_cpu__##var))
 #define __get_cpu_var(var)                     per_cpu__##var
+#define __raw_get_cpu_var(var)                 per_cpu__##var
 
 #endif /* SMP */
 
index 52825ce689f21a3f897641fa042f52fd4be4b1bd..006291e89b4a12e60b0947fc1d18b9c4f1410aae 100644 (file)
@@ -147,10 +147,8 @@ static int fd_request_irq(void)
                return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
                                                   "floppy", NULL);
        else
-               return request_irq(FLOPPY_IRQ, floppy_interrupt,
-                                                  SA_INTERRUPT|SA_SAMPLE_RANDOM,
-                                                  "floppy", NULL);     
-
+               return request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT,
+                                  "floppy", NULL);
 }
 
 static unsigned long dma_mem_alloc(unsigned long size)
index 7f33aaf9f7b1870c1b58d9de974712c004809182..549eb929b2c0b551952cc9f41aa3e50cbe914f4a 100644 (file)
@@ -21,6 +21,7 @@
 /* var is in discarded region: offset to particular copy we want */
 #define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu)))
 #define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()))
+#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()))
 
 /* A macro to avoid #include hell... */
 #define percpu_modcopy(pcpudst, src, size)                     \
@@ -40,6 +41,7 @@ extern void setup_per_cpu_areas(void);
 
 #define per_cpu(var, cpu)                      (*((void)(cpu), &per_cpu__##var))
 #define __get_cpu_var(var)                     per_cpu__##var
+#define __raw_get_cpu_var(var)                 per_cpu__##var
 
 #endif /* SMP */
 
index 3d54fbcf969e60ddee19968455593f871b223d97..e86bae7324d2f7eac86826f6686c69f66b532977 100644 (file)
@@ -121,13 +121,17 @@ struct vfsmount;
 struct super_block;
 extern void acct_auto_close_mnt(struct vfsmount *m);
 extern void acct_auto_close(struct super_block *sb);
-extern void acct_process(long exitcode);
+extern void acct_init_pacct(struct pacct_struct *pacct);
+extern void acct_collect(long exitcode, int group_dead);
+extern void acct_process(void);
 extern void acct_update_integrals(struct task_struct *tsk);
 extern void acct_clear_integrals(struct task_struct *tsk);
 #else
 #define acct_auto_close_mnt(x) do { } while (0)
 #define acct_auto_close(x)     do { } while (0)
-#define acct_process(x)                do { } while (0)
+#define acct_init_pacct(x)     do { } while (0)
+#define acct_collect(x,y)      do { } while (0)
+#define acct_process()         do { } while (0)
 #define acct_update_integrals(x)               do { } while (0)
 #define acct_clear_integrals(task)     do { } while (0)
 #endif
index b60ffe32cd21b34acfeee792d8d5ff3f66f94bd7..76bdaeab6f622240fe8f898a9caf0815770f7c38 100644 (file)
@@ -47,7 +47,7 @@
 #define BIO_BUG_ON
 #endif
 
-#define BIO_MAX_PAGES          (256)
+#define BIO_MAX_PAGES          256
 #define BIO_MAX_SIZE           (BIO_MAX_PAGES << PAGE_CACHE_SHIFT)
 #define BIO_MAX_SECTORS                (BIO_MAX_SIZE >> 9)
 
index 08734e660d4182c11c9bc55a6a7e2632f1d3e917..d0f8a8009490bea35186211a792714c9aa2ff459 100644 (file)
@@ -87,6 +87,7 @@ void give_up_console(const struct consw *sw);
 #define CON_CONSDEV    (2) /* Last on the command line */
 #define CON_ENABLED    (4)
 #define CON_BOOT       (8)
+#define CON_ANYTIME    (16) /* Safe to call when cpu is offline */
 
 struct console
 {
index 9cbb781d6f808b361a9f7f1a4df50f8ee9bde9a9..b268a3c0c37628d23231754f1ad9047ac47a74b8 100644 (file)
@@ -317,7 +317,8 @@ static inline void __cpus_remap(cpumask_t *dstp, const cpumask_t *srcp,
                (cpu) < NR_CPUS;                \
                (cpu) = next_cpu((cpu), (mask)))
 #else /* NR_CPUS == 1 */
-#define for_each_cpu_mask(cpu, mask) for ((cpu) = 0; (cpu) < 1; (cpu)++)
+#define for_each_cpu_mask(cpu, mask)           \
+       for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
 #endif /* NR_CPUS */
 
 /*
@@ -405,7 +406,6 @@ int __any_online_cpu(const cpumask_t *mask);
 #define any_online_cpu(mask)           0
 #endif
 
-#define for_each_cpu(cpu)  for_each_cpu_mask((cpu), cpu_possible_map)
 #define for_each_possible_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)
index 2787b8a22ff1b772e2bc42cddeff33f6512de2fa..c6a2353c4e68f2831db0007fcc9d9070da1202ae 100644 (file)
@@ -88,20 +88,6 @@ typedef enum
 #define DMX_PES_PCR      DMX_PES_PCR0
 
 
-typedef enum
-{
-       DMX_SCRAMBLING_EV,
-       DMX_FRONTEND_EV
-} dmx_event_t;
-
-
-typedef enum
-{
-       DMX_SCRAMBLING_OFF,
-       DMX_SCRAMBLING_ON
-} dmx_scrambling_status_t;
-
-
 typedef struct dmx_filter
 {
        __u8  filter[DMX_FILTER_SIZE];
@@ -132,17 +118,6 @@ struct dmx_pes_filter_params
        __u32          flags;
 };
 
-
-struct dmx_event
-{
-       dmx_event_t         event;
-       time_t              timeStamp;
-       union
-       {
-               dmx_scrambling_status_t scrambling;
-       } u;
-};
-
 typedef struct dmx_caps {
        __u32 caps;
        int num_decoders;
@@ -171,7 +146,6 @@ struct dmx_stc {
 #define DMX_SET_FILTER           _IOW('o', 43, struct dmx_sct_filter_params)
 #define DMX_SET_PES_FILTER       _IOW('o', 44, struct dmx_pes_filter_params)
 #define DMX_SET_BUFFER_SIZE      _IO('o', 45)
-#define DMX_GET_EVENT            _IOR('o', 46, struct dmx_event)
 #define DMX_GET_PES_PIDS         _IOR('o', 47, __u16[5])
 #define DMX_GET_CAPS             _IOR('o', 48, dmx_caps_t)
 #define DMX_SET_SOURCE           _IOW('o', 49, dmx_source_t)
index 1e4bdfcf83a2efafa37fea7f24482014983fe4fa..84cfa8bbdc3698fc3a1fdb998d8c606e4d6e9ced 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  include/linux/eventpoll.h ( Efficent event polling implementation )
- *  Copyright (C) 2001,...,2003         Davide Libenzi
+ *  Copyright (C) 2001,...,2006         Davide Libenzi
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 757d54d8f1a58f3a15c5467df00438b5f9d6e075..5607e6457a65b8fc9df2bcd081532a833d41599c 100644 (file)
@@ -710,6 +710,14 @@ struct dir_private_info {
        __u32           next_hash;
 };
 
+/* calculate the first block number of the group */
+static inline ext3_fsblk_t
+ext3_group_first_block_no(struct super_block *sb, unsigned long group_no)
+{
+       return group_no * (ext3_fsblk_t)EXT3_BLOCKS_PER_GROUP(sb) +
+               le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block);
+}
+
 /*
  * Special error return code only used by dx_probe() and its callers.
  */
@@ -730,14 +738,16 @@ struct dir_private_info {
 /* balloc.c */
 extern int ext3_bg_has_super(struct super_block *sb, int group);
 extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group);
-extern int ext3_new_block (handle_t *, struct inode *, unsigned long, int *);
-extern int ext3_new_blocks (handle_t *, struct inode *, unsigned long,
-                       unsigned long *, int *);
-extern void ext3_free_blocks (handle_t *, struct inode *, unsigned long,
-                             unsigned long);
-extern void ext3_free_blocks_sb (handle_t *, struct super_block *,
-                                unsigned long, unsigned long, int *);
-extern unsigned long ext3_count_free_blocks (struct super_block *);
+extern ext3_fsblk_t ext3_new_block (handle_t *handle, struct inode *inode,
+                       ext3_fsblk_t goal, int *errp);
+extern ext3_fsblk_t ext3_new_blocks (handle_t *handle, struct inode *inode,
+                       ext3_fsblk_t goal, unsigned long *count, int *errp);
+extern void ext3_free_blocks (handle_t *handle, struct inode *inode,
+                       ext3_fsblk_t block, unsigned long count);
+extern void ext3_free_blocks_sb (handle_t *handle, struct super_block *sb,
+                                ext3_fsblk_t block, unsigned long count,
+                               unsigned long *pdquot_freed_blocks);
+extern ext3_fsblk_t ext3_count_free_blocks (struct super_block *);
 extern void ext3_check_blocks_bitmap (struct super_block *);
 extern struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb,
                                                    unsigned int block_group,
@@ -773,7 +783,8 @@ extern unsigned long ext3_count_free (struct buffer_head *, unsigned);
 
 
 /* inode.c */
-int ext3_forget(handle_t *, int, struct inode *, struct buffer_head *, int);
+int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode,
+               struct buffer_head *bh, ext3_fsblk_t blocknr);
 struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *);
 struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *);
 int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
@@ -808,7 +819,7 @@ extern int ext3_group_add(struct super_block *sb,
                                struct ext3_new_group_data *input);
 extern int ext3_group_extend(struct super_block *sb,
                                struct ext3_super_block *es,
-                               unsigned long n_blocks_count);
+                               ext3_fsblk_t n_blocks_count);
 
 /* super.c */
 extern void ext3_error (struct super_block *, const char *, const char *, ...)
index 7abf9014718023ef8042d78131a2a3fe4c319d25..2f18b9511f211f728bf1e631a554b53d1dd124ee 100644 (file)
 #include <linux/seqlock.h>
 #include <linux/mutex.h>
 
+/* data type for block offset of block group */
+typedef int ext3_grpblk_t;
+
+/* data type for filesystem-wide blocks number */
+typedef unsigned long ext3_fsblk_t;
+
+#define E3FSBLK "%lu"
+
 struct ext3_reserve_window {
-       __u32                   _rsv_start;     /* First byte reserved */
-       __u32                   _rsv_end;       /* Last byte reserved or 0 */
+       ext3_fsblk_t    _rsv_start;     /* First byte reserved */
+       ext3_fsblk_t    _rsv_end;       /* Last byte reserved or 0 */
 };
 
 struct ext3_reserve_window_node {
@@ -50,7 +58,7 @@ struct ext3_block_alloc_info {
         * allocated to this file.  This give us the goal (target) for the next
         * allocation when we detect linearly ascending requests.
         */
-       __u32                   last_alloc_physical_block;
+       ext3_fsblk_t            last_alloc_physical_block;
 };
 
 #define rsv_start rsv_window._rsv_start
@@ -67,7 +75,7 @@ struct ext3_inode_info {
        __u8    i_frag_no;
        __u8    i_frag_size;
 #endif
-       __u32   i_file_acl;
+       ext3_fsblk_t    i_file_acl;
        __u32   i_dir_acl;
        __u32   i_dtime;
 
index 315d89740ddff87fd578931a0e82feea5ecbabd8..f1281687e549ec4fe663b6778f5c79a8b7a01690 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _LINUX_FB_H
 #define _LINUX_FB_H
 
+#include <linux/backlight.h>
 #include <asm/types.h>
 
 /* Definitions of frame buffers                                                */
@@ -366,6 +367,12 @@ struct fb_cursor {
        struct fb_image image;  /* Cursor image */
 };
 
+#ifdef CONFIG_FB_BACKLIGHT
+/* Settings for the generic backlight code */
+#define FB_BACKLIGHT_LEVELS    128
+#define FB_BACKLIGHT_MAX       0xFF
+#endif
+
 #ifdef __KERNEL__
 
 #include <linux/fs.h>
@@ -756,6 +763,21 @@ struct fb_info {
        struct fb_cmap cmap;            /* Current cmap */
        struct list_head modelist;      /* mode list */
        struct fb_videomode *mode;      /* current mode */
+
+#ifdef CONFIG_FB_BACKLIGHT
+       /* Lock ordering:
+        * bl_mutex (protects bl_dev and bl_curve)
+        *   bl_dev->sem (backlight class)
+        */
+       struct mutex bl_mutex;
+
+       /* assigned backlight device */
+       struct backlight_device *bl_dev;
+
+       /* Backlight level curve */
+       u8 bl_curve[FB_BACKLIGHT_LEVELS];
+#endif
+
        struct fb_ops *fbops;
        struct device *device;
        struct class_device *class_device; /* sysfs per device attrs */
@@ -895,6 +917,7 @@ extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev);
 extern void framebuffer_release(struct fb_info *info);
 extern int fb_init_class_device(struct fb_info *fb_info);
 extern void fb_cleanup_class_device(struct fb_info *head);
+extern void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max);
 
 /* drivers/video/fbmon.c */
 #define FB_MAXTIMINGS          0
index c52a63755fdd5b69e9bd63353b13e6aa82c738c9..996f5611cd59dc73ed9d01b2dec84f0708dcf7d9 100644 (file)
@@ -29,6 +29,7 @@
 #define AT_SYMLINK_NOFOLLOW    0x100   /* Do not follow symbolic links.  */
 #define AT_REMOVEDIR           0x200   /* Remove directory instead of
                                            unlinking file.  */
+#define AT_SYMLINK_FOLLOW      0x400   /* Follow symbolic links.  */
 
 #ifdef __KERNEL__
 
index 5425b60021e36193877aac02e6911db800808c4b..9fc48a674b82dc31c78aeb438b88862a9d28fbab 100644 (file)
@@ -1,6 +1,6 @@
 /*
     FUSE: Filesystem in Userspace
-    Copyright (C) 2001-2005  Miklos Szeredi <miklos@szeredi.hu>
+    Copyright (C) 2001-2006  Miklos Szeredi <miklos@szeredi.hu>
 
     This program can be distributed under the terms of the GNU GPL.
     See the file COPYING.
@@ -9,18 +9,19 @@
 /* This file defines the kernel interface of FUSE */
 
 #include <asm/types.h>
+#include <linux/major.h>
 
 /** Version number of this interface */
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 6
+#define FUSE_KERNEL_MINOR_VERSION 7
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
 
 /** The major number of the fuse character device */
-#define FUSE_MAJOR 10
+#define FUSE_MAJOR MISC_MAJOR
 
 /** The minor number of the fuse character device */
 #define FUSE_MINOR 229
@@ -58,6 +59,13 @@ struct fuse_kstatfs {
        __u32   spare[6];
 };
 
+struct fuse_file_lock {
+       __u64   start;
+       __u64   end;
+       __u32   type;
+       __u32   pid; /* tgid */
+};
+
 /**
  * Bitmasks for fuse_setattr_in.valid
  */
@@ -82,6 +90,7 @@ struct fuse_kstatfs {
  * INIT request/reply flags
  */
 #define FUSE_ASYNC_READ                (1 << 0)
+#define FUSE_POSIX_LOCKS       (1 << 1)
 
 enum fuse_opcode {
        FUSE_LOOKUP        = 1,
@@ -112,8 +121,12 @@ enum fuse_opcode {
        FUSE_READDIR       = 28,
        FUSE_RELEASEDIR    = 29,
        FUSE_FSYNCDIR      = 30,
+       FUSE_GETLK         = 31,
+       FUSE_SETLK         = 32,
+       FUSE_SETLKW        = 33,
        FUSE_ACCESS        = 34,
-       FUSE_CREATE        = 35
+       FUSE_CREATE        = 35,
+       FUSE_INTERRUPT     = 36,
 };
 
 /* The read buffer is required to be at least 8k, but may be much larger */
@@ -199,6 +212,7 @@ struct fuse_flush_in {
        __u64   fh;
        __u32   flush_flags;
        __u32   padding;
+       __u64   lock_owner;
 };
 
 struct fuse_read_in {
@@ -247,6 +261,16 @@ struct fuse_getxattr_out {
        __u32   padding;
 };
 
+struct fuse_lk_in {
+       __u64   fh;
+       __u64   owner;
+       struct fuse_file_lock lk;
+};
+
+struct fuse_lk_out {
+       struct fuse_file_lock lk;
+};
+
 struct fuse_access_in {
        __u32   mask;
        __u32   padding;
@@ -268,6 +292,10 @@ struct fuse_init_out {
        __u32   max_write;
 };
 
+struct fuse_interrupt_in {
+       __u64   unique;
+};
+
 struct fuse_in_header {
        __u32   len;
        __u32   opcode;
index 7d2a1b974c5edd4657d647a07b8c62416ae22476..07d7305f131e6a5f1997b9d5af9c1a28412895f8 100644 (file)
@@ -40,7 +40,6 @@ struct hrtimer_base;
 
 /**
  * struct hrtimer - the basic hrtimer structure
- *
  * @node:      red black tree node for time ordered insertion
  * @expires:   the absolute expiry time in the hrtimers internal
  *             representation. The time is related to the clock on
@@ -59,7 +58,6 @@ struct hrtimer {
 
 /**
  * struct hrtimer_sleeper - simple sleeper structure
- *
  * @timer:     embedded timer structure
  * @task:      task to wake up
  *
@@ -72,7 +70,6 @@ struct hrtimer_sleeper {
 
 /**
  * struct hrtimer_base - the timer base for a specific clock
- *
  * @index:             clock type index for per_cpu support when moving a timer
  *                     to a base on another cpu.
  * @lock:              lock protecting the base and associated timers
index c8b81f419fd8e49aa6f42d6994204ab96884c4c5..21338bb3441d6b9387e327e9ec208fdaab2ec391 100644 (file)
 #define I2C_DRIVERID_X1205     82      /* Xicor/Intersil X1205 RTC     */
 #define I2C_DRIVERID_PCF8563   83      /* Philips PCF8563 RTC          */
 #define I2C_DRIVERID_RS5C372   84      /* Ricoh RS5C372 RTC            */
+#define I2C_DRIVERID_BT866     85      /* Conexant bt866 video encoder */
+#define I2C_DRIVERID_KS0127    86      /* Samsung ks0127 video decoder */
+#define I2C_DRIVERID_TLV320AIC23B 87   /* TI TLV320AIC23B audio codec  */
 
 #define I2C_DRIVERID_I2CDEV    900
 #define I2C_DRIVERID_ARP        902    /* SMBus ARP Client              */
index 77e66d055f5b64338db137aaebb471cb3fcfb16e..ef7bef207f48d3ae0b458c063e788eaf69f803d3 100644 (file)
@@ -630,6 +630,7 @@ typedef struct ide_drive_s {
        unsigned int    usage;          /* current "open()" count for drive */
        unsigned int    failures;       /* current failure count */
        unsigned int    max_failures;   /* maximum allowed failure count */
+       u64             probed_capacity;/* initial reported media capacity (ide-cd only currently) */
 
        u64             capacity64;     /* total number of sectors */
 
@@ -1005,6 +1006,8 @@ extern    ide_hwif_t      ide_hwifs[];            /* master data repository */
 extern int noautodma;
 
 extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs);
+int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
+                            int uptodate, int nr_sectors);
 
 /*
  * This is used on exit from the driver to designate the next irq handler
index 8c21aaa248b4ee1917340283846c6bdc8651ed6c..3c5e4c2e517dd8aa867336c2bc70c560f510f556 100644 (file)
@@ -117,6 +117,8 @@ extern int scnprintf(char * buf, size_t size, const char * fmt, ...)
        __attribute__ ((format (printf, 3, 4)));
 extern int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
        __attribute__ ((format (printf, 3, 0)));
+extern char *kasprintf(gfp_t gfp, const char *fmt, ...)
+       __attribute__ ((format (printf, 2, 3)));
 
 extern int sscanf(const char *, const char *, ...)
        __attribute__ ((format (scanf, 2, 3)));
index ebdd41fd1082dfd77c7096e84ac9ec491ed82f8c..7cce5dfa092f2a7bb2e6f401202dd5d6755ddff8 100644 (file)
@@ -4,37 +4,19 @@
 #include <linux/err.h>
 #include <linux/sched.h>
 
-/**
- * kthread_create: create a kthread.
- * @threadfn: the function to run until signal_pending(current).
- * @data: data ptr for @threadfn.
- * @namefmt: printf-style name for the thread.
- *
- * Description: This helper function creates and names a kernel
- * thread.  The thread will be stopped: use wake_up_process() to start
- * it.  See also kthread_run(), kthread_create_on_cpu().
- *
- * When woken, the thread will run @threadfn() with @data as its
- * argument. @threadfn can either call do_exit() directly if it is a
- * standalone thread for which noone will call kthread_stop(), or
- * return when 'kthread_should_stop()' is true (which means
- * kthread_stop() has been called).  The return value should be zero
- * or a negative error number: it will be passed to kthread_stop().
- *
- * Returns a task_struct or ERR_PTR(-ENOMEM).
- */
 struct task_struct *kthread_create(int (*threadfn)(void *data),
                                   void *data,
                                   const char namefmt[], ...);
 
 /**
- * kthread_run: create and wake a thread.
+ * kthread_run - create and wake a thread.
  * @threadfn: the function to run until signal_pending(current).
  * @data: data ptr for @threadfn.
  * @namefmt: printf-style name for the thread.
  *
  * Description: Convenient wrapper for kthread_create() followed by
- * wake_up_process().  Returns the kthread, or ERR_PTR(-ENOMEM). */
+ * wake_up_process().  Returns the kthread or ERR_PTR(-ENOMEM).
+ */
 #define kthread_run(threadfn, data, namefmt, ...)                         \
 ({                                                                        \
        struct task_struct *__k                                            \
@@ -44,50 +26,9 @@ struct task_struct *kthread_create(int (*threadfn)(void *data),
        __k;                                                               \
 })
 
-/**
- * kthread_bind: bind a just-created kthread to a cpu.
- * @k: thread created by kthread_create().
- * @cpu: cpu (might not be online, must be possible) for @k to run on.
- *
- * Description: This function is equivalent to set_cpus_allowed(),
- * except that @cpu doesn't need to be online, and the thread must be
- * stopped (ie. just returned from kthread_create().
- */
 void kthread_bind(struct task_struct *k, unsigned int cpu);
-
-/**
- * kthread_stop: stop a thread created by kthread_create().
- * @k: thread created by kthread_create().
- *
- * Sets kthread_should_stop() for @k to return true, wakes it, and
- * waits for it to exit.  Your threadfn() must not call do_exit()
- * itself if you use this function!  This can also be called after
- * kthread_create() instead of calling wake_up_process(): the thread
- * will exit without calling threadfn().
- *
- * Returns the result of threadfn(), or -EINTR if wake_up_process()
- * was never called. */
 int kthread_stop(struct task_struct *k);
-
-/**
- * kthread_stop_sem: stop a thread created by kthread_create().
- * @k: thread created by kthread_create().
- * @s: semaphore that @k waits on while idle.
- *
- * Does essentially the same thing as kthread_stop() above, but wakes
- * @k by calling up(@s).
- *
- * Returns the result of threadfn(), or -EINTR if wake_up_process()
- * was never called. */
 int kthread_stop_sem(struct task_struct *k, struct semaphore *s);
-
-/**
- * kthread_should_stop: should this kthread return now?
- *
- * When someone calls kthread_stop on your kthread, it will be woken
- * and this will return true.  You should then return, and your return
- * value will be passed through to kthread_stop().
- */
 int kthread_should_stop(void);
 
 #endif /* _LINUX_KTHREAD_H */
index 62bc57580707c6b3deb36c080fbc7e353f22963d..ed3396dcc4f753d0d7cdfe8780c679f7315bc65d 100644 (file)
@@ -66,7 +66,6 @@ typedef union {
 
 /**
  * ktime_set - Set a ktime_t variable from a seconds/nanoseconds value
- *
  * @secs:      seconds to set
  * @nsecs:     nanoseconds to set
  *
@@ -138,7 +137,6 @@ static inline ktime_t ktime_set(const long secs, const unsigned long nsecs)
 
 /**
  * ktime_sub - subtract two ktime_t variables
- *
  * @lhs:       minuend
  * @rhs:       subtrahend
  *
@@ -157,7 +155,6 @@ static inline ktime_t ktime_sub(const ktime_t lhs, const ktime_t rhs)
 
 /**
  * ktime_add - add two ktime_t variables
- *
  * @add1:      addend1
  * @add2:      addend2
  *
@@ -184,7 +181,6 @@ static inline ktime_t ktime_add(const ktime_t add1, const ktime_t add2)
 
 /**
  * ktime_add_ns - Add a scalar nanoseconds value to a ktime_t variable
- *
  * @kt:                addend
  * @nsec:      the scalar nsec value to add
  *
@@ -194,7 +190,6 @@ extern ktime_t ktime_add_ns(const ktime_t kt, u64 nsec);
 
 /**
  * timespec_to_ktime - convert a timespec to ktime_t format
- *
  * @ts:                the timespec variable to convert
  *
  * Returns a ktime_t variable with the converted timespec value
@@ -207,7 +202,6 @@ static inline ktime_t timespec_to_ktime(const struct timespec ts)
 
 /**
  * timeval_to_ktime - convert a timeval to ktime_t format
- *
  * @tv:                the timeval variable to convert
  *
  * Returns a ktime_t variable with the converted timeval value
@@ -220,7 +214,6 @@ static inline ktime_t timeval_to_ktime(const struct timeval tv)
 
 /**
  * ktime_to_timespec - convert a ktime_t variable to timespec format
- *
  * @kt:                the ktime_t variable to convert
  *
  * Returns the timespec representation of the ktime value
@@ -233,7 +226,6 @@ static inline struct timespec ktime_to_timespec(const ktime_t kt)
 
 /**
  * ktime_to_timeval - convert a ktime_t variable to timeval format
- *
  * @kt:                the ktime_t variable to convert
  *
  * Returns the timeval representation of the ktime value
index a02642e4710ae06d4e005f61e3f35fe1a521ad37..37ca31b21bb7a29cda46861f5e3d97a25ed83622 100644 (file)
@@ -281,16 +281,17 @@ static inline int list_empty(const struct list_head *head)
 }
 
 /**
- * list_empty_careful - tests whether a list is
- * empty _and_ checks that no other CPU might be
- * in the process of still modifying either member
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
  *
  * NOTE: using list_empty_careful() without synchronization
  * can only be safe if the only activity that can happen
  * to the list entry is list_del_init(). Eg. it cannot be used
  * if another CPU could re-list_add() it.
- *
- * @head: the list to test.
  */
 static inline int list_empty_careful(const struct list_head *head)
 {
@@ -350,7 +351,7 @@ static inline void list_splice_init(struct list_head *list,
 
 /**
  * list_for_each       -       iterate over a list
- * @pos:       the &struct list_head to use as a loop counter.
+ * @pos:       the &struct list_head to use as a loop cursor.
  * @head:      the head for your list.
  */
 #define list_for_each(pos, head) \
@@ -359,7 +360,7 @@ static inline void list_splice_init(struct list_head *list,
 
 /**
  * __list_for_each     -       iterate over a list
- * @pos:       the &struct list_head to use as a loop counter.
+ * @pos:       the &struct list_head to use as a loop cursor.
  * @head:      the head for your list.
  *
  * This variant differs from list_for_each() in that it's the
@@ -372,7 +373,7 @@ static inline void list_splice_init(struct list_head *list,
 
 /**
  * list_for_each_prev  -       iterate over a list backwards
- * @pos:       the &struct list_head to use as a loop counter.
+ * @pos:       the &struct list_head to use as a loop cursor.
  * @head:      the head for your list.
  */
 #define list_for_each_prev(pos, head) \
@@ -380,8 +381,8 @@ static inline void list_splice_init(struct list_head *list,
                pos = pos->prev)
 
 /**
- * list_for_each_safe  -       iterate over a list safe against removal of list entry
- * @pos:       the &struct list_head to use as a loop counter.
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos:       the &struct list_head to use as a loop cursor.
  * @n:         another &struct list_head to use as temporary storage
  * @head:      the head for your list.
  */
@@ -391,7 +392,7 @@ static inline void list_splice_init(struct list_head *list,
 
 /**
  * list_for_each_entry -       iterate over list of given type
- * @pos:       the type * to use as a loop counter.
+ * @pos:       the type * to use as a loop cursor.
  * @head:      the head for your list.
  * @member:    the name of the list_struct within the struct.
  */
@@ -402,7 +403,7 @@ static inline void list_splice_init(struct list_head *list,
 
 /**
  * list_for_each_entry_reverse - iterate backwards over list of given type.
- * @pos:       the type * to use as a loop counter.
+ * @pos:       the type * to use as a loop cursor.
  * @head:      the head for your list.
  * @member:    the name of the list_struct within the struct.
  */
@@ -412,21 +413,24 @@ static inline void list_splice_init(struct list_head *list,
             pos = list_entry(pos->member.prev, typeof(*pos), member))
 
 /**
- * list_prepare_entry - prepare a pos entry for use as a start point in
- *                     list_for_each_entry_continue
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue
  * @pos:       the type * to use as a start point
  * @head:      the head of the list
  * @member:    the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue.
  */
 #define list_prepare_entry(pos, head, member) \
        ((pos) ? : list_entry(head, typeof(*pos), member))
 
 /**
- * list_for_each_entry_continue -      iterate over list of given type
- *                     continuing after existing point
- * @pos:       the type * to use as a loop counter.
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos:       the type * to use as a loop cursor.
  * @head:      the head for your list.
  * @member:    the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
  */
 #define list_for_each_entry_continue(pos, head, member)                \
        for (pos = list_entry(pos->member.next, typeof(*pos), member);  \
@@ -434,11 +438,12 @@ static inline void list_splice_init(struct list_head *list,
             pos = list_entry(pos->member.next, typeof(*pos), member))
 
 /**
- * list_for_each_entry_from -  iterate over list of given type
- *                     continuing from existing point
- * @pos:       the type * to use as a loop counter.
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos:       the type * to use as a loop cursor.
  * @head:      the head for your list.
  * @member:    the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
  */
 #define list_for_each_entry_from(pos, head, member)                    \
        for (; prefetch(pos->member.next), &pos->member != (head);      \
@@ -446,7 +451,7 @@ static inline void list_splice_init(struct list_head *list,
 
 /**
  * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @pos:       the type * to use as a loop counter.
+ * @pos:       the type * to use as a loop cursor.
  * @n:         another type * to use as temporary storage
  * @head:      the head for your list.
  * @member:    the name of the list_struct within the struct.
@@ -458,12 +463,14 @@ static inline void list_splice_init(struct list_head *list,
             pos = n, n = list_entry(n->member.next, typeof(*n), member))
 
 /**
- * list_for_each_entry_safe_continue - iterate over list of given type
- *                     continuing after existing point safe against removal of list entry
- * @pos:       the type * to use as a loop counter.
+ * list_for_each_entry_safe_continue
+ * @pos:       the type * to use as a loop cursor.
  * @n:         another type * to use as temporary storage
  * @head:      the head for your list.
  * @member:    the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
  */
 #define list_for_each_entry_safe_continue(pos, n, head, member)                \
        for (pos = list_entry(pos->member.next, typeof(*pos), member),          \
@@ -472,12 +479,14 @@ static inline void list_splice_init(struct list_head *list,
             pos = n, n = list_entry(n->member.next, typeof(*n), member))
 
 /**
- * list_for_each_entry_safe_from - iterate over list of given type
- *                     from existing point safe against removal of list entry
- * @pos:       the type * to use as a loop counter.
+ * list_for_each_entry_safe_from
+ * @pos:       the type * to use as a loop cursor.
  * @n:         another type * to use as temporary storage
  * @head:      the head for your list.
  * @member:    the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
  */
 #define list_for_each_entry_safe_from(pos, n, head, member)                    \
        for (n = list_entry(pos->member.next, typeof(*pos), member);            \
@@ -485,12 +494,14 @@ static inline void list_splice_init(struct list_head *list,
             pos = n, n = list_entry(n->member.next, typeof(*n), member))
 
 /**
- * list_for_each_entry_safe_reverse - iterate backwards over list of given type safe against
- *                                   removal of list entry
- * @pos:       the type * to use as a loop counter.
+ * list_for_each_entry_safe_reverse
+ * @pos:       the type * to use as a loop cursor.
  * @n:         another type * to use as temporary storage
  * @head:      the head for your list.
  * @member:    the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
  */
 #define list_for_each_entry_safe_reverse(pos, n, head, member)         \
        for (pos = list_entry((head)->prev, typeof(*pos), member),      \
@@ -500,7 +511,7 @@ static inline void list_splice_init(struct list_head *list,
 
 /**
  * list_for_each_rcu   -       iterate over an rcu-protected list
- * @pos:       the &struct list_head to use as a loop counter.
+ * @pos:       the &struct list_head to use as a loop cursor.
  * @head:      the head for your list.
  *
  * This list-traversal primitive may safely run concurrently with
@@ -518,12 +529,13 @@ static inline void list_splice_init(struct list_head *list,
                pos = pos->next)
 
 /**
- * list_for_each_safe_rcu      -       iterate over an rcu-protected list safe
- *                                     against removal of list entry
- * @pos:       the &struct list_head to use as a loop counter.
+ * list_for_each_safe_rcu
+ * @pos:       the &struct list_head to use as a loop cursor.
  * @n:         another &struct list_head to use as temporary storage
  * @head:      the head for your list.
  *
+ * Iterate over an rcu-protected list, safe against removal of list entry.
+ *
  * This list-traversal primitive may safely run concurrently with
  * the _rcu list-mutation primitives such as list_add_rcu()
  * as long as the traversal is guarded by rcu_read_lock().
@@ -535,7 +547,7 @@ static inline void list_splice_init(struct list_head *list,
 
 /**
  * list_for_each_entry_rcu     -       iterate over rcu list of given type
- * @pos:       the type * to use as a loop counter.
+ * @pos:       the type * to use as a loop cursor.
  * @head:      the head for your list.
  * @member:    the name of the list_struct within the struct.
  *
@@ -551,11 +563,12 @@ static inline void list_splice_init(struct list_head *list,
 
 
 /**
- * list_for_each_continue_rcu  -       iterate over an rcu-protected list
- *                     continuing after existing point.
- * @pos:       the &struct list_head to use as a loop counter.
+ * list_for_each_continue_rcu
+ * @pos:       the &struct list_head to use as a loop cursor.
  * @head:      the head for your list.
  *
+ * Iterate over an rcu-protected list, continuing after current point.
+ *
  * This list-traversal primitive may safely run concurrently with
  * the _rcu list-mutation primitives such as list_add_rcu()
  * as long as the traversal is guarded by rcu_read_lock().
@@ -681,11 +694,14 @@ static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
 
 
 /**
- * hlist_add_head_rcu - adds the specified element to the specified hlist,
- * while permitting racing traversals.
+ * hlist_add_head_rcu
  * @n: the element to add to the hash list.
  * @h: the list to add to.
  *
+ * Description:
+ * Adds the specified element to the specified hlist,
+ * while permitting racing traversals.
+ *
  * The caller must take whatever precautions are necessary
  * (such as holding appropriate locks) to avoid racing
  * with another list-mutation primitive, such as hlist_add_head_rcu()
@@ -730,11 +746,14 @@ static inline void hlist_add_after(struct hlist_node *n,
 }
 
 /**
- * hlist_add_before_rcu - adds the specified element to the specified hlist
- * before the specified node while permitting racing traversals.
+ * hlist_add_before_rcu
  * @n: the new element to add to the hash list.
  * @next: the existing element to add the new element before.
  *
+ * Description:
+ * Adds the specified element to the specified hlist
+ * before the specified node while permitting racing traversals.
+ *
  * The caller must take whatever precautions are necessary
  * (such as holding appropriate locks) to avoid racing
  * with another list-mutation primitive, such as hlist_add_head_rcu()
@@ -755,11 +774,14 @@ static inline void hlist_add_before_rcu(struct hlist_node *n,
 }
 
 /**
- * hlist_add_after_rcu - adds the specified element to the specified hlist
- * after the specified node while permitting racing traversals.
+ * hlist_add_after_rcu
  * @prev: the existing element to add the new element after.
  * @n: the new element to add to the hash list.
  *
+ * Description:
+ * Adds the specified element to the specified hlist
+ * after the specified node while permitting racing traversals.
+ *
  * The caller must take whatever precautions are necessary
  * (such as holding appropriate locks) to avoid racing
  * with another list-mutation primitive, such as hlist_add_head_rcu()
@@ -792,8 +814,8 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
 
 /**
  * hlist_for_each_entry        - iterate over list of given type
- * @tpos:      the type * to use as a loop counter.
- * @pos:       the &struct hlist_node to use as a loop counter.
+ * @tpos:      the type * to use as a loop cursor.
+ * @pos:       the &struct hlist_node to use as a loop cursor.
  * @head:      the head for your list.
  * @member:    the name of the hlist_node within the struct.
  */
@@ -804,9 +826,9 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
             pos = pos->next)
 
 /**
- * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point
- * @tpos:      the type * to use as a loop counter.
- * @pos:       the &struct hlist_node to use as a loop counter.
+ * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
+ * @tpos:      the type * to use as a loop cursor.
+ * @pos:       the &struct hlist_node to use as a loop cursor.
  * @member:    the name of the hlist_node within the struct.
  */
 #define hlist_for_each_entry_continue(tpos, pos, member)                \
@@ -816,9 +838,9 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
             pos = pos->next)
 
 /**
- * hlist_for_each_entry_from - iterate over a hlist continuing from existing point
- * @tpos:      the type * to use as a loop counter.
- * @pos:       the &struct hlist_node to use as a loop counter.
+ * hlist_for_each_entry_from - iterate over a hlist continuing from current point
+ * @tpos:      the type * to use as a loop cursor.
+ * @pos:       the &struct hlist_node to use as a loop cursor.
  * @member:    the name of the hlist_node within the struct.
  */
 #define hlist_for_each_entry_from(tpos, pos, member)                    \
@@ -828,8 +850,8 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
 
 /**
  * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @tpos:      the type * to use as a loop counter.
- * @pos:       the &struct hlist_node to use as a loop counter.
+ * @tpos:      the type * to use as a loop cursor.
+ * @pos:       the &struct hlist_node to use as a loop cursor.
  * @n:         another &struct hlist_node to use as temporary storage
  * @head:      the head for your list.
  * @member:    the name of the hlist_node within the struct.
@@ -842,8 +864,8 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
 
 /**
  * hlist_for_each_entry_rcu - iterate over rcu list of given type
- * @tpos:      the type * to use as a loop counter.
- * @pos:       the &struct hlist_node to use as a loop counter.
+ * @tpos:      the type * to use as a loop cursor.
+ * @pos:       the &struct hlist_node to use as a loop cursor.
  * @head:      the head for your list.
  * @member:    the name of the hlist_node within the struct.
  *
index e76c7611d6cc56e115ad71a49aa25861cc2208f6..bf3d2345ce99ccafe7f85ace5a23cd836b9d5285 100644 (file)
@@ -59,7 +59,7 @@ struct loop_device {
        struct bio              *lo_bio;
        struct bio              *lo_biotail;
        int                     lo_state;
-       struct completion       lo_done;
+       struct task_struct      *lo_thread;
        struct completion       lo_bh_done;
        struct mutex            lo_ctl_mutex;
        int                     lo_pending;
index 5dba23a1c0d0e0d75dc0bb465aaba2836bca5bcc..48148e0cdbd179725de653eff14a229c26ad6153 100644 (file)
@@ -16,7 +16,9 @@ extern int fail_migrate_page(struct address_space *,
                        struct page *, struct page *);
 
 extern int migrate_prep(void);
-
+extern int migrate_vmas(struct mm_struct *mm,
+               const nodemask_t *from, const nodemask_t *to,
+               unsigned long flags);
 #else
 
 static inline int isolate_lru_page(struct page *p, struct list_head *list)
@@ -30,6 +32,13 @@ static inline int migrate_pages_to(struct list_head *pagelist,
 
 static inline int migrate_prep(void) { return -ENOSYS; }
 
+static inline int migrate_vmas(struct mm_struct *mm,
+               const nodemask_t *from, const nodemask_t *to,
+               unsigned long flags)
+{
+       return -ENOSYS;
+}
+
 /* Possible settings for the migrate_page() method in address_operations */
 #define migrate_page NULL
 #define fail_migrate_page NULL
index 3b09444121d926376c3d24ca06a76e83802697f1..a929ea197e4844da5d11fc9f43da506138b276f7 100644 (file)
@@ -145,7 +145,6 @@ extern unsigned int kobjsize(const void *objp);
 
 #define VM_GROWSDOWN   0x00000100      /* general info on the segment */
 #define VM_GROWSUP     0x00000200
-#define VM_SHM         0x00000000      /* Means nothing: delete it later */
 #define VM_PFNMAP      0x00000400      /* Page-ranges managed without "struct page", just pure PFN */
 #define VM_DENYWRITE   0x00000800      /* ETXTBSY on write attempts.. */
 
@@ -207,6 +206,8 @@ struct vm_operations_struct {
        int (*set_policy)(struct vm_area_struct *vma, struct mempolicy *new);
        struct mempolicy *(*get_policy)(struct vm_area_struct *vma,
                                        unsigned long addr);
+       int (*migrate)(struct vm_area_struct *vma, const nodemask_t *from,
+               const nodemask_t *to, unsigned long flags);
 #endif
 };
 
index 1d7cdd20b5530677a8140feed5ac1483089108ca..e712e7d47cc22a6c0f6e3071bbabbf6770506b16 100644 (file)
@@ -77,11 +77,11 @@ struct nbd_device {
  * server. All data are in network byte order.
  */
 struct nbd_request {
-       __u32 magic;
-       __u32 type;     /* == READ || == WRITE  */
+       __be32 magic;
+       __be32 type;    /* == READ || == WRITE  */
        char handle[8];
-       __u64 from;
-       __u32 len;
+       __be64 from;
+       __be32 len;
 }
 #ifdef __GNUC__
        __attribute__ ((packed))
@@ -93,8 +93,8 @@ struct nbd_request {
  * it has completed an I/O request (or an error occurs).
  */
 struct nbd_reply {
-       __u32 magic;
-       __u32 error;            /* 0 = ok, else error   */
+       __be32 magic;
+       __be32 error;           /* 0 = ok, else error   */
        char handle[8];         /* handle you got from request  */
 };
 #endif
index d42737eeee067783195346a34ae3b973cb828fa6..5bf321e82c998ed78c37ed87179cbb0e65597b19 100644 (file)
@@ -127,6 +127,10 @@ struct amiga_parport_state {
        unsigned char statusdir;/* ciab.ddrb & 7 */
 };
 
+struct ax88796_parport_state {
+       unsigned char cpr;
+};
+
 struct ip32_parport_state {
        unsigned int dcr;
        unsigned int ecr;
@@ -138,6 +142,7 @@ struct parport_state {
                /* ARC has no state. */
                struct ax_parport_state ax;
                struct amiga_parport_state amiga;
+               struct ax88796_parport_state ax88796;
                /* Atari has not state. */
                struct ip32_parport_state ip32;
                void *misc; 
index ecce5912f4d6149254eaab42dee3b443e20354bb..2ed807ddc08c1cb1e1919a09c8a16e32a3bc1058 100644 (file)
@@ -230,4 +230,8 @@ extern int pmu_battery_count;
 extern struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES];
 extern unsigned int pmu_power_flags;
 
+/* Backlight */
+extern int disable_kernel_backlight;
+extern void pmu_backlight_init(struct device_node*);
+
 #endif /* __KERNEL__ */
index 015297ff73fa0f590bdf2c5a55c3f4132cd4d727..1dd1c707311fa0f1e5683547540d1f3edac48e21 100644 (file)
@@ -59,13 +59,13 @@ extern void machine_crash_shutdown(struct pt_regs *);
  * Architecture independent implemenations of sys_reboot commands.
  */
 
-extern void kernel_restart_prepare(char *cmd);
 extern void kernel_shutdown_prepare(enum system_states state);
 
 extern void kernel_restart(char *cmd);
 extern void kernel_halt(void);
 extern void kernel_power_off(void);
-extern void kernel_kexec(void);
+
+void ctrl_alt_del(void);
 
 /*
  * Emergency restart, callable from an interrupt handler.
index 21a86cb6acdb63a95f91da65872b3643d700b2ff..ae13db714742a91f95e644f582e3517f5e85651e 100644 (file)
@@ -3,6 +3,8 @@
 
 #include <linux/time.h>
 
+struct task_struct;
+
 /*
  * Resource control/accounting header file for linux
  */
@@ -67,4 +69,6 @@ struct rlimit {
  */
 #include <asm/resource.h>
 
+int getrusage(struct task_struct *p, int who, struct rusage __user *ru);
+
 #endif
diff --git a/include/linux/rtc-v3020.h b/include/linux/rtc-v3020.h
new file mode 100644 (file)
index 0000000..bf74e63
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * v3020.h - Registers definition and platform data structure for the v3020 RTC.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2006, 8D Technologies inc.
+ */
+#ifndef __LINUX_V3020_H
+#define __LINUX_V3020_H
+
+/* The v3020 has only one data pin but which one
+ * is used depends on the board. */
+struct v3020_platform_data {
+       int leftshift; /* (1<<(leftshift)) & readl() */
+};
+
+#define V3020_STATUS_0 0x00
+#define V3020_STATUS_1 0x01
+#define V3020_SECONDS  0x02
+#define V3020_MINUTES  0x03
+#define V3020_HOURS            0x04
+#define V3020_MONTH_DAY        0x05
+#define V3020_MONTH            0x06
+#define V3020_YEAR             0x07
+#define V3020_WEEK_DAY 0x08
+#define V3020_WEEK             0x09
+
+#define V3020_IS_COMMAND(val) ((val)>=0x0E)
+
+#define V3020_CMD_RAM2CLOCK    0x0E
+#define V3020_CMD_CLOCK2RAM    0x0F
+
+#endif /* __LINUX_V3020_H */
index ab61cd1199f262031bd6940a9171224b02a34a03..36e2bf4b43151317fe21141e1ea360fbda8ca83a 100644 (file)
@@ -102,6 +102,7 @@ struct rtc_pll_info {
 #include <linux/interrupt.h>
 
 extern int rtc_month_days(unsigned int month, unsigned int year);
+extern int rtc_year_days(unsigned int day, unsigned int month, unsigned int year);
 extern int rtc_valid_tm(struct rtc_time *tm);
 extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time);
 extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm);
@@ -155,6 +156,17 @@ struct rtc_device
        struct rtc_task *irq_task;
        spinlock_t irq_task_lock;
        int irq_freq;
+       int max_user_freq;
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+       struct work_struct uie_task;
+       struct timer_list uie_timer;
+       /* Those fields are protected by rtc->irq_lock */
+       unsigned int oldsecs;
+       unsigned int irq_active:1;
+       unsigned int stop_uie_polling:1;
+       unsigned int uie_task_active:1;
+       unsigned int uie_timer_active:1;
+#endif
 };
 #define to_rtc_device(d) container_of(d, struct rtc_device, class_dev)
 
index 38b4791e6a5da17cd527054dcdc4e4cda000db5b..8d11d9310db0a0fb14e042f94c1b3335a20a4c63 100644 (file)
@@ -358,6 +358,14 @@ struct sighand_struct {
        spinlock_t              siglock;
 };
 
+struct pacct_struct {
+       int                     ac_flag;
+       long                    ac_exitcode;
+       unsigned long           ac_mem;
+       cputime_t               ac_utime, ac_stime;
+       unsigned long           ac_minflt, ac_majflt;
+};
+
 /*
  * NOTE! "signal_struct" does not have it's own
  * locking, because a shared signal_struct always
@@ -449,6 +457,9 @@ struct signal_struct {
        struct key *session_keyring;    /* keyring inherited over fork */
        struct key *process_keyring;    /* keyring private to this process */
 #endif
+#ifdef CONFIG_BSD_PROCESS_ACCT
+       struct pacct_struct pacct;      /* per-process accounting information */
+#endif
 };
 
 /* Context switch must be unlocked if interrupts are to be enabled */
index 2993302f792391afe961826389c55f7fe3824af5..0577f5284cbc9c4f73beb031d9c53834456f354c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SyncLink Multiprotocol Serial Adapter Driver
  *
- * $Id: synclink.h,v 3.11 2006/02/06 21:20:29 paulkf Exp $
+ * $Id: synclink.h,v 3.13 2006/05/23 18:25:06 paulkf Exp $
  *
  * Copyright (C) 1998-2000 by Microgate Corporation
  *
@@ -97,6 +97,8 @@
 #define HDLC_TXIDLE_ALT_MARK_SPACE     4
 #define HDLC_TXIDLE_SPACE              5
 #define HDLC_TXIDLE_MARK               6
+#define HDLC_TXIDLE_CUSTOM_8            0x10000000
+#define HDLC_TXIDLE_CUSTOM_16           0x20000000
 
 #define HDLC_ENCODING_NRZ                      0
 #define HDLC_ENCODING_NRZB                     1
@@ -170,6 +172,7 @@ typedef struct _MGSL_PARAMS
 #define SYNCLINK_GT_DEVICE_ID 0x0070
 #define SYNCLINK_GT4_DEVICE_ID 0x0080
 #define SYNCLINK_AC_DEVICE_ID  0x0090
+#define SYNCLINK_GT2_DEVICE_ID 0x00A0
 #define MGSL_MAX_SERIAL_NUMBER 30
 
 /*
index c7132029af0f1d954ca71948e15e46ff2dcd706b..6a60770984e9235ea96f4c3c0df23709455a75d0 100644 (file)
@@ -55,7 +55,7 @@ enum
        CTL_KERN=1,             /* General kernel info and control */
        CTL_VM=2,               /* VM management */
        CTL_NET=3,              /* Networking */
-       CTL_PROC=4,             /* Process info */
+       /* was CTL_PROC */
        CTL_FS=5,               /* Filesystems */
        CTL_DEBUG=6,            /* Debugging */
        CTL_DEV=7,              /* Devices */
@@ -767,8 +767,6 @@ enum {
        NET_BRIDGE_NF_FILTER_VLAN_TAGGED = 4,
 };
 
-/* CTL_PROC names: */
-
 /* CTL_FS names: */
 enum
 {
index 86b5b4271b5a7b5e9d00c1d2092005eea53f8ae1..914f911325be9483cc29ab481f3014e0e27df879 100644 (file)
@@ -220,6 +220,19 @@ typedef __u16 __bitwise __fs16;
  */
 #define UFS_MINFREE         5
 #define UFS_DEFAULTOPT      UFS_OPTTIME
+
+/*
+ * Debug code
+ */
+#ifdef CONFIG_UFS_DEBUG
+#      define UFSD(f, a...)    {                                       \
+               printk ("UFSD (%s, %d): %s:",                           \
+                       __FILE__, __LINE__, __FUNCTION__);              \
+               printk (f, ## a);                                       \
+       }
+#else
+#      define UFSD(f, a...)    /**/
+#endif
             
 /*
  * Turn file system block numbers into disk block addresses.
@@ -338,8 +351,23 @@ struct ufs2_csum_total {
        __fs64   cs_spare[3];   /* future expansion */
 };
 
+/*
+ * File system flags
+ */
+#define UFS_UNCLEAN      0x01    /* file system not clean at mount (unused) */
+#define UFS_DOSOFTDEP    0x02    /* file system using soft dependencies */
+#define UFS_NEEDSFSCK    0x04    /* needs sync fsck (FreeBSD compat, unused) */
+#define UFS_INDEXDIRS    0x08    /* kernel supports indexed directories */
+#define UFS_ACLS         0x10    /* file system has ACLs enabled */
+#define UFS_MULTILABEL   0x20    /* file system is MAC multi-label */
+#define UFS_FLAGS_UPDATED 0x80   /* flags have been moved to new location */
+
+#if 0
 /*
  * This is the actual superblock, as it is laid out on the disk.
+ * Do NOT use this structure, because of sizeof(ufs_super_block) > 512 and
+ * it may occupy several blocks, use
+ * struct ufs_super_block_(first,second,third) instead.
  */
 struct ufs_super_block {
        __fs32  fs_link;        /* UNUSED */
@@ -416,7 +444,7 @@ struct ufs_super_block {
        __s8    fs_fmod;        /* super block modified flag */
        __s8    fs_clean;       /* file system is clean flag */
        __s8    fs_ronly;       /* mounted read-only flag */
-       __s8    fs_flags;       /* currently unused flag */
+       __s8    fs_flags;
        union {
                struct {
                        __s8    fs_fsmnt[UFS_MAXMNTLEN];/* name mounted on */
@@ -485,6 +513,7 @@ struct ufs_super_block {
        __fs32  fs_magic;               /* magic number */
        __u8    fs_space[1];            /* list of blocks for each rotation */
 };
+#endif/*struct ufs_super_block*/
 
 /*
  * Preference for optimization.
@@ -666,7 +695,7 @@ struct ufs_buffer_head {
 };
 
 struct ufs_cg_private_info {
-       struct ufs_cylinder_group ucg;
+       struct ufs_buffer_head c_ubh;
        __u32   c_cgx;          /* number of cylidner group */
        __u16   c_ncyl;         /* number of cyl's this cg */
        __u16   c_niblk;        /* number of inode blocks this cg */
@@ -686,6 +715,7 @@ struct ufs_cg_private_info {
 
 struct ufs_sb_private_info {
        struct ufs_buffer_head s_ubh; /* buffer containing super block */
+       struct ufs2_csum_total cs_total;
        __u32   s_sblkno;       /* offset of super-blocks in filesys */
        __u32   s_cblkno;       /* offset of cg-block in filesys */
        __u32   s_iblkno;       /* offset of inode-blocks in filesys */
@@ -824,16 +854,54 @@ struct ufs_super_block_first {
 };
 
 struct ufs_super_block_second {
-       __s8    fs_fsmnt[212];
-       __fs32  fs_cgrotor;
-       __fs32  fs_csp[UFS_MAXCSBUFS];
-       __fs32  fs_maxcluster;
-       __fs32  fs_cpc;
-       __fs16  fs_opostbl[82];
-};     
+       union {
+               struct {
+                       __s8    fs_fsmnt[212];
+                       __fs32  fs_cgrotor;
+                       __fs32  fs_csp[UFS_MAXCSBUFS];
+                       __fs32  fs_maxcluster;
+                       __fs32  fs_cpc;
+                       __fs16  fs_opostbl[82];
+               } fs_u1;
+               struct {
+                       __s8  fs_fsmnt[UFS2_MAXMNTLEN - UFS_MAXMNTLEN + 212];
+                       __u8   fs_volname[UFS2_MAXVOLLEN];
+                       __fs64  fs_swuid;
+                       __fs32  fs_pad;
+                       __fs32   fs_cgrotor;
+                       __fs32   fs_ocsp[UFS2_NOCSPTRS];
+                       __fs32   fs_contigdirs;
+                       __fs32   fs_csp;
+                       __fs32   fs_maxcluster;
+                       __fs32   fs_active;
+                       __fs32   fs_old_cpc;
+                       __fs32   fs_maxbsize;
+                       __fs64   fs_sparecon64[17];
+                       __fs64   fs_sblockloc;
+                       __fs64  cs_ndir;
+                       __fs64  cs_nbfree;
+               } fs_u2;
+       } fs_un;
+};
 
 struct ufs_super_block_third {
-       __fs16  fs_opostbl[46];
+       union {
+               struct {
+                       __fs16  fs_opostbl[46];
+               } fs_u1;
+               struct {
+                       __fs64  cs_nifree;      /* number of free inodes */
+                       __fs64  cs_nffree;      /* number of free frags */
+                       __fs64   cs_numclusters;        /* number of free clusters */
+                       __fs64   cs_spare[3];   /* future expansion */
+                       struct  ufs_timeval    fs_time;         /* last time written */
+                       __fs64    fs_size;              /* number of blocks in fs */
+                       __fs64    fs_dsize;     /* number of data blocks in fs */
+                       __fs64   fs_csaddr;     /* blk addr of cyl grp summary area */
+                       __fs64    fs_pendingblocks;/* blocks in process of being freed */
+                       __fs32    fs_pendinginodes;/*inodes in process of being freed */
+               } fs_u2;
+       } fs_un1;
        union {
                struct {
                        __fs32  fs_sparecon[53];/* reserved for future constants */
@@ -861,7 +929,7 @@ struct ufs_super_block_third {
                        __fs32  fs_qfmask[2];   /* ~usb_fmask */
                        __fs32  fs_state;       /* file system state time stamp */
                } fs_44;
-       } fs_u2;
+       } fs_un2;
        __fs32  fs_postblformat;
        __fs32  fs_nrpos;
        __fs32  fs_postbloff;
@@ -875,7 +943,8 @@ struct ufs_super_block_third {
 /* balloc.c */
 extern void ufs_free_fragments (struct inode *, unsigned, unsigned);
 extern void ufs_free_blocks (struct inode *, unsigned, unsigned);
-extern unsigned ufs_new_fragments (struct inode *, __fs32 *, unsigned, unsigned, unsigned, int *);
+extern unsigned ufs_new_fragments(struct inode *, __fs32 *, unsigned, unsigned,
+                                 unsigned, int *, struct page *);
 
 /* cylinder.c */
 extern struct ufs_cg_private_info * ufs_load_cylinder (struct super_block *, unsigned);
@@ -886,11 +955,12 @@ extern struct inode_operations ufs_dir_inode_operations;
 extern int ufs_add_link (struct dentry *, struct inode *);
 extern ino_t ufs_inode_by_name(struct inode *, struct dentry *);
 extern int ufs_make_empty(struct inode *, struct inode *);
-extern struct ufs_dir_entry * ufs_find_entry (struct dentry *, struct buffer_head **);
-extern int ufs_delete_entry (struct inode *, struct ufs_dir_entry *, struct buffer_head *);
+extern struct ufs_dir_entry *ufs_find_entry(struct inode *, struct dentry *, struct page **);
+extern int ufs_delete_entry(struct inode *, struct ufs_dir_entry *, struct page *);
 extern int ufs_empty_dir (struct inode *);
-extern struct ufs_dir_entry * ufs_dotdot (struct inode *, struct buffer_head **);
-extern void ufs_set_link(struct inode *, struct ufs_dir_entry *, struct buffer_head *, struct inode *);
+extern struct ufs_dir_entry *ufs_dotdot(struct inode *, struct page **);
+extern void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
+                        struct page *page, struct inode *inode);
 
 /* file.c */
 extern struct inode_operations ufs_file_inode_operations;
@@ -903,13 +973,11 @@ extern void ufs_free_inode (struct inode *inode);
 extern struct inode * ufs_new_inode (struct inode *, int);
 
 /* inode.c */
-extern u64  ufs_frag_map (struct inode *, sector_t);
 extern void ufs_read_inode (struct inode *);
 extern void ufs_put_inode (struct inode *);
 extern int ufs_write_inode (struct inode *, int);
 extern int ufs_sync_inode (struct inode *);
 extern void ufs_delete_inode (struct inode *);
-extern struct buffer_head * ufs_getfrag (struct inode *, unsigned, int, int *);
 extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *);
 extern int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create);
 
index 21665a9539783726556a4435e94fe86a5b533fa8..f50ce3b0cd524ed41454f8345cb2fffc4ee7b443 100644 (file)
@@ -27,6 +27,7 @@ struct ufs_inode_info {
        __u32   i_oeftflag;
        __u16   i_osync;
        __u32   i_lastfrag;
+       __u32   i_dir_start_lookup;
        struct inode vfs_inode;
 };
 
index 91140091ced2f2b510a3ac2bf05d79d738078f0e..41bc7e9603cdf690debf168fc936252e9dad798e 100644 (file)
@@ -1,49 +1,21 @@
+/*
+ *     Video for Linux version 1 - OBSOLETE
+ *
+ *     Header file for v4l1 drivers and applications, for
+ *     Linux kernels 2.2.x or 2.4.x.
+ *
+ *     Provides header for legacy drivers and applications
+ *
+ *     See http://linuxtv.org for more info
+ *
+ */
 #ifndef __LINUX_VIDEODEV_H
 #define __LINUX_VIDEODEV_H
 
-#include <linux/types.h>
-
 #define HAVE_V4L1 1
 
 #include <linux/videodev2.h>
 
-#ifdef __KERNEL__
-
-#include <linux/mm.h>
-
-extern struct video_device* video_devdata(struct file*);
-
-#define to_video_device(cd) container_of(cd, struct video_device, class_dev)
-static inline void
-video_device_create_file(struct video_device *vfd,
-                        struct class_device_attribute *attr)
-{
-       class_device_create_file(&vfd->class_dev, attr);
-}
-static inline void
-video_device_remove_file(struct video_device *vfd,
-                        struct class_device_attribute *attr)
-{
-       class_device_remove_file(&vfd->class_dev, attr);
-}
-
-#if OBSOLETE_OWNER /* to be removed in 2.6.15 */
-/* helper functions to access driver private data. */
-static inline void *video_get_drvdata(struct video_device *dev)
-{
-       return dev->priv;
-}
-
-static inline void video_set_drvdata(struct video_device *dev, void *data)
-{
-       dev->priv = data;
-}
-#endif
-
-extern int video_exclusive_open(struct inode *inode, struct file *file);
-extern int video_exclusive_release(struct inode *inode, struct file *file);
-#endif /* __KERNEL__ */
-
 struct video_capability
 {
        char name[32];
@@ -363,6 +335,7 @@ struct video_code
 #define VID_HARDWARE_SAA7114H   37
 #define VID_HARDWARE_SN9C102   38
 #define VID_HARDWARE_ARV       39
+
 #endif /* __LINUX_VIDEODEV_H */
 
 /*
index ad7fa9c86c1008157211021ce5f23829368d6ff0..4f428547ec090ac7752d80b86b792538d5d491c3 100644 (file)
@@ -1,35 +1,33 @@
-#ifndef __LINUX_VIDEODEV2_H
-#define __LINUX_VIDEODEV2_H
 /*
  *     Video for Linux Two
  *
- *     Header file for v4l or V4L2 drivers and applications, for
- *     Linux kernels 2.2.x or 2.4.x.
+ *     Header file for v4l or V4L2 drivers and applications
+ * with public API.
+ * All kernel-specific stuff were moved to media/v4l2-dev.h, so
+ * no #if __KERNEL tests are allowed here
  *
- *     See http://bytesex.org/v4l/ for API specs and other
- *     v4l2 documentation.
+ *     See http://linuxtv.org for more info
  *
  *     Author: Bill Dirks <bdirks@pacbell.net>
  *             Justin Schoeman
  *             et al.
  */
+#ifndef __LINUX_VIDEODEV2_H
+#define __LINUX_VIDEODEV2_H
 #ifdef __KERNEL__
-#include <linux/time.h> /* need struct timeval */
-#include <linux/poll.h>
-#include <linux/device.h>
-#include <linux/mutex.h>
-#endif
+#include <linux/time.h>     /* need struct timeval */
 #include <linux/compiler.h> /* need __user */
+#else
+#define __user
+#endif
+#include <linux/types.h>
 
-
-#define OBSOLETE_OWNER 1 /* It will be removed for 2.6.17 */
 #define HAVE_V4L2 1
 
 /*
  * Common stuff for both V4L1 and V4L2
  * Moved from videodev.h
  */
-
 #define VIDEO_MAX_FRAME               32
 
 #define VID_TYPE_CAPTURE       1       /* Can capture */
 #define VID_TYPE_MJPEG_DECODER 4096    /* Can decode MJPEG streams */
 #define VID_TYPE_MJPEG_ENCODER 8192    /* Can encode MJPEG streams */
 
-#ifdef __KERNEL__
-
-/* Minor device allocation */
-#define MINOR_VFL_TYPE_GRABBER_MIN   0
-#define MINOR_VFL_TYPE_GRABBER_MAX  63
-#define MINOR_VFL_TYPE_RADIO_MIN    64
-#define MINOR_VFL_TYPE_RADIO_MAX   127
-#define MINOR_VFL_TYPE_VTX_MIN     192
-#define MINOR_VFL_TYPE_VTX_MAX     223
-#define MINOR_VFL_TYPE_VBI_MIN     224
-#define MINOR_VFL_TYPE_VBI_MAX     255
-
-#define VFL_TYPE_GRABBER       0
-#define VFL_TYPE_VBI           1
-#define VFL_TYPE_RADIO         2
-#define VFL_TYPE_VTX           3
-
-struct video_device
-{
-       /* device info */
-       struct device *dev;
-       char name[32];
-       int type;       /* v4l1 */
-       int type2;      /* v4l2 */
-       int hardware;
-       int minor;
-
-       /* device ops + callbacks */
-       const struct file_operations *fops;
-       void (*release)(struct video_device *vfd);
-
-
-#if OBSOLETE_OWNER /* to be removed in 2.6.15 */
-       /* obsolete -- fops->owner is used instead */
-       struct module *owner;
-       /* dev->driver_data will be used instead some day.
-        * Use the video_{get|set}_drvdata() helper functions,
-        * so the switch over will be transparent for you.
-        * Or use {pci|usb}_{get|set}_drvdata() directly. */
-       void *priv;
-#endif
-
-       /* for videodev.c intenal usage -- please don't touch */
-       int users;                     /* video_exclusive_{open|close} ... */
-       struct mutex lock;             /* ... helper function uses these   */
-       char devfs_name[64];           /* devfs */
-       struct class_device class_dev; /* sysfs */
-};
-
-#define VIDEO_MAJOR    81
-
-extern int video_register_device(struct video_device *, int type, int nr);
-extern void video_unregister_device(struct video_device *);
-extern int video_usercopy(struct inode *inode, struct file *file,
-                         unsigned int cmd, unsigned long arg,
-                         int (*func)(struct inode *inode, struct file *file,
-                                     unsigned int cmd, void *arg));
-
-/* helper functions to alloc / release struct video_device, the
-   later can be used for video_device->release() */
-struct video_device *video_device_alloc(void);
-void video_device_release(struct video_device *vfd);
-
-#endif
-
 /*
  *     M I S C E L L A N E O U S
  */
@@ -172,6 +105,8 @@ enum v4l2_ctrl_type {
        V4L2_CTRL_TYPE_BOOLEAN       = 2,
        V4L2_CTRL_TYPE_MENU          = 3,
        V4L2_CTRL_TYPE_BUTTON        = 4,
+       V4L2_CTRL_TYPE_INTEGER64     = 5,
+       V4L2_CTRL_TYPE_CTRL_CLASS    = 6,
 };
 
 enum v4l2_tuner_type {
@@ -270,7 +205,6 @@ struct v4l2_capability
 /*
  *     V I D E O   I M A G E   F O R M A T
  */
-
 struct v4l2_pix_format
 {
        __u32                   width;
@@ -283,7 +217,7 @@ struct v4l2_pix_format
        __u32                   priv;           /* private data, depends on pixelformat */
 };
 
-/*           Pixel format    FOURCC                  depth  Description   */
+/*      Pixel format         FOURCC                        depth  Description  */
 #define V4L2_PIX_FMT_RGB332  v4l2_fourcc('R','G','B','1') /*  8  RGB-3-3-2     */
 #define V4L2_PIX_FMT_RGB555  v4l2_fourcc('R','G','B','O') /* 16  RGB-5-5-5     */
 #define V4L2_PIX_FMT_RGB565  v4l2_fourcc('R','G','B','P') /* 16  RGB-5-6-5     */
@@ -319,7 +253,7 @@ struct v4l2_pix_format
 #define V4L2_PIX_FMT_MJPEG    v4l2_fourcc('M','J','P','G') /* Motion-JPEG   */
 #define V4L2_PIX_FMT_JPEG     v4l2_fourcc('J','P','E','G') /* JFIF JPEG     */
 #define V4L2_PIX_FMT_DV       v4l2_fourcc('d','v','s','d') /* 1394          */
-#define V4L2_PIX_FMT_MPEG     v4l2_fourcc('M','P','E','G') /* MPEG          */
+#define V4L2_PIX_FMT_MPEG     v4l2_fourcc('M','P','E','G') /* MPEG-1/2/4    */
 
 /*  Vendor-specific formats   */
 #define V4L2_PIX_FMT_WNVA     v4l2_fourcc('W','N','V','A') /* Winnov hw compress */
@@ -343,7 +277,6 @@ struct v4l2_fmtdesc
 
 #define V4L2_FMT_FLAG_COMPRESSED 0x0001
 
-
 /*
  *     T I M E C O D E
  */
@@ -373,16 +306,15 @@ struct v4l2_timecode
 #define V4L2_TC_USERBITS_8BITCHARS     0x0008
 /* The above is based on SMPTE timecodes */
 
-
+#ifdef __KERNEL__
 /*
  *     M P E G   C O M P R E S S I O N   P A R A M E T E R S
  *
- *  ### WARNING: this is still work-in-progress right now, most likely
- *  ###          there will be some incompatible changes.
+ *  ### WARNING: This experimental MPEG compression API is obsolete.
+ *  ###          It is replaced by the MPEG controls API.
+ *  ###          This old API will disappear in the near future!
  *
  */
-
-
 enum v4l2_bitrate_mode {
        V4L2_BITRATE_NONE = 0,  /* not specified */
        V4L2_BITRATE_CBR,       /* constant bitrate */
@@ -460,6 +392,7 @@ struct v4l2_mpeg_compression {
        /* I don't expect the above being perfect yet ;) */
        __u32                           reserved_5[8];
 };
+#endif
 
 struct v4l2_jpegcompression
 {
@@ -491,7 +424,6 @@ struct v4l2_jpegcompression
                                        * allways use APP0 */
 };
 
-
 /*
  *     M E M O R Y - M A P P I N G   B U F F E R S
  */
@@ -573,7 +505,6 @@ struct v4l2_window
        void                    __user *bitmap;
 };
 
-
 /*
  *     C A P T U R E   P A R A M E T E R S
  */
@@ -586,6 +517,7 @@ struct v4l2_captureparm
        __u32              readbuffers;   /*  # of buffers for read */
        __u32              reserved[4];
 };
+
 /*  Flags for 'capability' and 'capturemode' fields */
 #define V4L2_MODE_HIGHQUALITY  0x0001  /*  High quality imaging mode */
 #define V4L2_CAP_TIMEPERFRAME  0x1000  /*  timeperframe field is supported */
@@ -603,7 +535,6 @@ struct v4l2_outputparm
 /*
  *     I N P U T   I M A G E   C R O P P I N G
  */
-
 struct v4l2_cropcap {
        enum v4l2_buf_type      type;
        struct v4l2_rect        bounds;
@@ -710,7 +641,6 @@ struct v4l2_standard
        __u32                reserved[4];
 };
 
-
 /*
  *     V I D E O   I N P U T S
  */
@@ -725,6 +655,7 @@ struct v4l2_input
        __u32        status;
        __u32        reserved[4];
 };
+
 /*  Values for the 'type' field */
 #define V4L2_INPUT_TYPE_TUNER          1
 #define V4L2_INPUT_TYPE_CAMERA         2
@@ -775,6 +706,34 @@ struct v4l2_control
        __s32                value;
 };
 
+struct v4l2_ext_control
+{
+       __u32 id;
+       __u32 reserved2[2];
+       union {
+               __s32 value;
+               __s64 value64;
+               void *reserved;
+       };
+};
+
+struct v4l2_ext_controls
+{
+       __u32 ctrl_class;
+       __u32 count;
+       __u32 error_idx;
+       __u32 reserved[2];
+       struct v4l2_ext_control *controls;
+};
+
+/*  Values for ctrl_class field */
+#define V4L2_CTRL_CLASS_USER 0x00980000        /* Old-style 'user' controls */
+#define V4L2_CTRL_CLASS_MPEG 0x00990000        /* MPEG-compression controls */
+
+#define V4L2_CTRL_ID_MASK                (0x0fffffff)
+#define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
+#define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000)
+
 /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
 struct v4l2_queryctrl
 {
@@ -801,12 +760,21 @@ struct v4l2_querymenu
 /*  Control flags  */
 #define V4L2_CTRL_FLAG_DISABLED                0x0001
 #define V4L2_CTRL_FLAG_GRABBED         0x0002
+#define V4L2_CTRL_FLAG_READ_ONLY       0x0004
+#define V4L2_CTRL_FLAG_UPDATE          0x0008
+#define V4L2_CTRL_FLAG_INACTIVE        0x0010
+#define V4L2_CTRL_FLAG_SLIDER          0x0020
+
+/*  Query flag, to be ORed with the control ID */
+#define V4L2_CTRL_FLAG_NEXT_CTRL       0x80000000
 
-/*  Control IDs defined by V4L2 */
-#define V4L2_CID_BASE                  0x00980900
+/*  User-class control IDs defined by V4L2 */
+#define V4L2_CID_BASE                  (V4L2_CTRL_CLASS_USER | 0x900)
+#define V4L2_CID_USER_BASE             V4L2_CID_BASE
 /*  IDs reserved for driver specific controls */
 #define V4L2_CID_PRIVATE_BASE          0x08000000
 
+#define V4L2_CID_USER_CLASS            (V4L2_CTRL_CLASS_USER | 1)
 #define V4L2_CID_BRIGHTNESS            (V4L2_CID_BASE+0)
 #define V4L2_CID_CONTRAST              (V4L2_CID_BASE+1)
 #define V4L2_CID_SATURATION            (V4L2_CID_BASE+2)
@@ -833,6 +801,183 @@ struct v4l2_querymenu
 #define V4L2_CID_VCENTER               (V4L2_CID_BASE+23)
 #define V4L2_CID_LASTP1                        (V4L2_CID_BASE+24) /* last CID + 1 */
 
+/*  MPEG-class control IDs defined by V4L2 */
+#define V4L2_CID_MPEG_BASE                     (V4L2_CTRL_CLASS_MPEG | 0x900)
+#define V4L2_CID_MPEG_CLASS                    (V4L2_CTRL_CLASS_MPEG | 1)
+
+/*  MPEG streams */
+#define V4L2_CID_MPEG_STREAM_TYPE              (V4L2_CID_MPEG_BASE+0)
+enum v4l2_mpeg_stream_type {
+       V4L2_MPEG_STREAM_TYPE_MPEG2_PS   = 0, /* MPEG-2 program stream */
+       V4L2_MPEG_STREAM_TYPE_MPEG2_TS   = 1, /* MPEG-2 transport stream */
+       V4L2_MPEG_STREAM_TYPE_MPEG1_SS   = 2, /* MPEG-1 system stream */
+       V4L2_MPEG_STREAM_TYPE_MPEG2_DVD  = 3, /* MPEG-2 DVD-compatible stream */
+       V4L2_MPEG_STREAM_TYPE_MPEG1_VCD  = 4, /* MPEG-1 VCD-compatible stream */
+       V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD = 5, /* MPEG-2 SVCD-compatible stream */
+};
+#define V4L2_CID_MPEG_STREAM_PID_PMT           (V4L2_CID_MPEG_BASE+1)
+#define V4L2_CID_MPEG_STREAM_PID_AUDIO                 (V4L2_CID_MPEG_BASE+2)
+#define V4L2_CID_MPEG_STREAM_PID_VIDEO                 (V4L2_CID_MPEG_BASE+3)
+#define V4L2_CID_MPEG_STREAM_PID_PCR           (V4L2_CID_MPEG_BASE+4)
+#define V4L2_CID_MPEG_STREAM_PES_ID_AUDIO      (V4L2_CID_MPEG_BASE+5)
+#define V4L2_CID_MPEG_STREAM_PES_ID_VIDEO      (V4L2_CID_MPEG_BASE+6)
+
+/*  MPEG audio */
+#define V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ      (V4L2_CID_MPEG_BASE+100)
+enum v4l2_mpeg_audio_sampling_freq {
+       V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100 = 0,
+       V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 = 1,
+       V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000 = 2,
+};
+#define V4L2_CID_MPEG_AUDIO_ENCODING           (V4L2_CID_MPEG_BASE+101)
+enum v4l2_mpeg_audio_encoding {
+       V4L2_MPEG_AUDIO_ENCODING_LAYER_1 = 0,
+       V4L2_MPEG_AUDIO_ENCODING_LAYER_2 = 1,
+       V4L2_MPEG_AUDIO_ENCODING_LAYER_3 = 2,
+};
+#define V4L2_CID_MPEG_AUDIO_L1_BITRATE                 (V4L2_CID_MPEG_BASE+102)
+enum v4l2_mpeg_audio_l1_bitrate {
+       V4L2_MPEG_AUDIO_L1_BITRATE_32K  = 0,
+       V4L2_MPEG_AUDIO_L1_BITRATE_64K  = 1,
+       V4L2_MPEG_AUDIO_L1_BITRATE_96K  = 2,
+       V4L2_MPEG_AUDIO_L1_BITRATE_128K = 3,
+       V4L2_MPEG_AUDIO_L1_BITRATE_160K = 4,
+       V4L2_MPEG_AUDIO_L1_BITRATE_192K = 5,
+       V4L2_MPEG_AUDIO_L1_BITRATE_224K = 6,
+       V4L2_MPEG_AUDIO_L1_BITRATE_256K = 7,
+       V4L2_MPEG_AUDIO_L1_BITRATE_288K = 8,
+       V4L2_MPEG_AUDIO_L1_BITRATE_320K = 9,
+       V4L2_MPEG_AUDIO_L1_BITRATE_352K = 10,
+       V4L2_MPEG_AUDIO_L1_BITRATE_384K = 11,
+       V4L2_MPEG_AUDIO_L1_BITRATE_416K = 12,
+       V4L2_MPEG_AUDIO_L1_BITRATE_448K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_L2_BITRATE                 (V4L2_CID_MPEG_BASE+103)
+enum v4l2_mpeg_audio_l2_bitrate {
+       V4L2_MPEG_AUDIO_L2_BITRATE_32K  = 0,
+       V4L2_MPEG_AUDIO_L2_BITRATE_48K  = 1,
+       V4L2_MPEG_AUDIO_L2_BITRATE_56K  = 2,
+       V4L2_MPEG_AUDIO_L2_BITRATE_64K  = 3,
+       V4L2_MPEG_AUDIO_L2_BITRATE_80K  = 4,
+       V4L2_MPEG_AUDIO_L2_BITRATE_96K  = 5,
+       V4L2_MPEG_AUDIO_L2_BITRATE_112K = 6,
+       V4L2_MPEG_AUDIO_L2_BITRATE_128K = 7,
+       V4L2_MPEG_AUDIO_L2_BITRATE_160K = 8,
+       V4L2_MPEG_AUDIO_L2_BITRATE_192K = 9,
+       V4L2_MPEG_AUDIO_L2_BITRATE_224K = 10,
+       V4L2_MPEG_AUDIO_L2_BITRATE_256K = 11,
+       V4L2_MPEG_AUDIO_L2_BITRATE_320K = 12,
+       V4L2_MPEG_AUDIO_L2_BITRATE_384K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_L3_BITRATE                 (V4L2_CID_MPEG_BASE+104)
+enum v4l2_mpeg_audio_l3_bitrate {
+       V4L2_MPEG_AUDIO_L3_BITRATE_32K  = 0,
+       V4L2_MPEG_AUDIO_L3_BITRATE_40K  = 1,
+       V4L2_MPEG_AUDIO_L3_BITRATE_48K  = 2,
+       V4L2_MPEG_AUDIO_L3_BITRATE_56K  = 3,
+       V4L2_MPEG_AUDIO_L3_BITRATE_64K  = 4,
+       V4L2_MPEG_AUDIO_L3_BITRATE_80K  = 5,
+       V4L2_MPEG_AUDIO_L3_BITRATE_96K  = 6,
+       V4L2_MPEG_AUDIO_L3_BITRATE_112K = 7,
+       V4L2_MPEG_AUDIO_L3_BITRATE_128K = 8,
+       V4L2_MPEG_AUDIO_L3_BITRATE_160K = 9,
+       V4L2_MPEG_AUDIO_L3_BITRATE_192K = 10,
+       V4L2_MPEG_AUDIO_L3_BITRATE_224K = 11,
+       V4L2_MPEG_AUDIO_L3_BITRATE_256K = 12,
+       V4L2_MPEG_AUDIO_L3_BITRATE_320K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_MODE               (V4L2_CID_MPEG_BASE+105)
+enum v4l2_mpeg_audio_mode {
+       V4L2_MPEG_AUDIO_MODE_STEREO       = 0,
+       V4L2_MPEG_AUDIO_MODE_JOINT_STEREO = 1,
+       V4L2_MPEG_AUDIO_MODE_DUAL         = 2,
+       V4L2_MPEG_AUDIO_MODE_MONO         = 3,
+};
+#define V4L2_CID_MPEG_AUDIO_MODE_EXTENSION     (V4L2_CID_MPEG_BASE+106)
+enum v4l2_mpeg_audio_mode_extension {
+       V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4  = 0,
+       V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8  = 1,
+       V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12 = 2,
+       V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16 = 3,
+};
+#define V4L2_CID_MPEG_AUDIO_EMPHASIS           (V4L2_CID_MPEG_BASE+107)
+enum v4l2_mpeg_audio_emphasis {
+       V4L2_MPEG_AUDIO_EMPHASIS_NONE         = 0,
+       V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS = 1,
+       V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17    = 2,
+};
+#define V4L2_CID_MPEG_AUDIO_CRC                (V4L2_CID_MPEG_BASE+108)
+enum v4l2_mpeg_audio_crc {
+       V4L2_MPEG_AUDIO_CRC_NONE  = 0,
+       V4L2_MPEG_AUDIO_CRC_CRC16 = 1,
+};
+
+/*  MPEG video */
+#define V4L2_CID_MPEG_VIDEO_ENCODING           (V4L2_CID_MPEG_BASE+200)
+enum v4l2_mpeg_video_encoding {
+       V4L2_MPEG_VIDEO_ENCODING_MPEG_1 = 0,
+       V4L2_MPEG_VIDEO_ENCODING_MPEG_2 = 1,
+};
+#define V4L2_CID_MPEG_VIDEO_ASPECT             (V4L2_CID_MPEG_BASE+201)
+enum v4l2_mpeg_video_aspect {
+       V4L2_MPEG_VIDEO_ASPECT_1x1     = 0,
+       V4L2_MPEG_VIDEO_ASPECT_4x3     = 1,
+       V4L2_MPEG_VIDEO_ASPECT_16x9    = 2,
+       V4L2_MPEG_VIDEO_ASPECT_221x100 = 3,
+};
+#define V4L2_CID_MPEG_VIDEO_B_FRAMES           (V4L2_CID_MPEG_BASE+202)
+#define V4L2_CID_MPEG_VIDEO_GOP_SIZE           (V4L2_CID_MPEG_BASE+203)
+#define V4L2_CID_MPEG_VIDEO_GOP_CLOSURE        (V4L2_CID_MPEG_BASE+204)
+#define V4L2_CID_MPEG_VIDEO_PULLDOWN           (V4L2_CID_MPEG_BASE+205)
+#define V4L2_CID_MPEG_VIDEO_BITRATE_MODE       (V4L2_CID_MPEG_BASE+206)
+enum v4l2_mpeg_video_bitrate_mode {
+       V4L2_MPEG_VIDEO_BITRATE_MODE_VBR = 0,
+       V4L2_MPEG_VIDEO_BITRATE_MODE_CBR = 1,
+};
+#define V4L2_CID_MPEG_VIDEO_BITRATE            (V4L2_CID_MPEG_BASE+207)
+#define V4L2_CID_MPEG_VIDEO_BITRATE_PEAK       (V4L2_CID_MPEG_BASE+208)
+#define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_MPEG_BASE+209)
+
+/*  MPEG-class control IDs specific to the CX2584x driver as defined by V4L2 */
+#define V4L2_CID_MPEG_CX2341X_BASE                             (V4L2_CTRL_CLASS_MPEG | 0x1000)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE        (V4L2_CID_MPEG_CX2341X_BASE+0)
+enum v4l2_mpeg_cx2341x_video_spatial_filter_mode {
+       V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL = 0,
+       V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO   = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER             (V4L2_CID_MPEG_CX2341X_BASE+1)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE   (V4L2_CID_MPEG_CX2341X_BASE+2)
+enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type {
+       V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF                  = 0,
+       V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR               = 1,
+       V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT              = 2,
+       V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE      = 3,
+       V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE = 4,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE         (V4L2_CID_MPEG_CX2341X_BASE+3)
+enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type {
+       V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF    = 0,
+       V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE       (V4L2_CID_MPEG_CX2341X_BASE+4)
+enum v4l2_mpeg_cx2341x_video_temporal_filter_mode {
+       V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL = 0,
+       V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO   = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER            (V4L2_CID_MPEG_CX2341X_BASE+5)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE                 (V4L2_CID_MPEG_CX2341X_BASE+6)
+enum v4l2_mpeg_cx2341x_video_median_filter_type {
+       V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF      = 0,
+       V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR      = 1,
+       V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT     = 2,
+       V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT = 3,
+       V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG     = 4,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM  (V4L2_CID_MPEG_CX2341X_BASE+7)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP     (V4L2_CID_MPEG_CX2341X_BASE+8)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM        (V4L2_CID_MPEG_CX2341X_BASE+9)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP   (V4L2_CID_MPEG_CX2341X_BASE+10)
+
 /*
  *     T U N I N G
  */
@@ -904,6 +1049,7 @@ struct v4l2_audio
        __u32   mode;
        __u32   reserved[2];
 };
+
 /*  Flags for the 'capability' field */
 #define V4L2_AUDCAP_STEREO             0x00001
 #define V4L2_AUDCAP_AVL                        0x00002
@@ -927,7 +1073,6 @@ struct v4l2_audioout
  */
 
 /* Raw VBI */
-
 struct v4l2_vbi_format
 {
        __u32   sampling_rate;          /* in 1 Hz */
@@ -1034,8 +1179,6 @@ struct v4l2_streamparm
        } parm;
 };
 
-
-
 /*
  *     I O C T L   C O D E S   F O R   V I D E O   D E V I C E S
  *
@@ -1045,8 +1188,10 @@ struct v4l2_streamparm
 #define VIDIOC_ENUM_FMT         _IOWR ('V',  2, struct v4l2_fmtdesc)
 #define VIDIOC_G_FMT           _IOWR ('V',  4, struct v4l2_format)
 #define VIDIOC_S_FMT           _IOWR ('V',  5, struct v4l2_format)
+#ifdef __KERNEL__
 #define VIDIOC_G_MPEGCOMP       _IOR  ('V',  6, struct v4l2_mpeg_compression)
 #define VIDIOC_S_MPEGCOMP      _IOW  ('V',  7, struct v4l2_mpeg_compression)
+#endif
 #define VIDIOC_REQBUFS         _IOWR ('V',  8, struct v4l2_requestbuffers)
 #define VIDIOC_QUERYBUF                _IOWR ('V',  9, struct v4l2_buffer)
 #define VIDIOC_G_FBUF          _IOR  ('V', 10, struct v4l2_framebuffer)
@@ -1096,7 +1241,11 @@ struct v4l2_streamparm
 #define VIDIOC_G_SLICED_VBI_CAP _IOR  ('V', 69, struct v4l2_sliced_vbi_cap)
 #endif
 #define VIDIOC_LOG_STATUS       _IO   ('V', 70)
+#define VIDIOC_G_EXT_CTRLS     _IOWR ('V', 71, struct v4l2_ext_controls)
+#define VIDIOC_S_EXT_CTRLS     _IOWR ('V', 72, struct v4l2_ext_controls)
+#define VIDIOC_TRY_EXT_CTRLS   _IOWR ('V', 73, struct v4l2_ext_controls)
 
+#ifdef __OLD_VIDIOC_
 /* for compatibility, will go away some day */
 #define VIDIOC_OVERLAY_OLD             _IOWR ('V', 14, int)
 #define VIDIOC_S_PARM_OLD              _IOW  ('V', 22, struct v4l2_streamparm)
@@ -1104,57 +1253,10 @@ struct v4l2_streamparm
 #define VIDIOC_G_AUDIO_OLD             _IOWR ('V', 33, struct v4l2_audio)
 #define VIDIOC_G_AUDOUT_OLD            _IOWR ('V', 49, struct v4l2_audioout)
 #define VIDIOC_CROPCAP_OLD             _IOR  ('V', 58, struct v4l2_cropcap)
-
-#define BASE_VIDIOC_PRIVATE    192             /* 192-255 are private */
-
-
-#ifdef __KERNEL__
-/*
- *
- *     V 4 L 2   D R I V E R   H E L P E R   A P I
- *
- *     Some commonly needed functions for drivers (v4l2-common.o module)
- */
-#include <linux/fs.h>
-
-/*  Video standard functions  */
-extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs);
-extern int v4l2_video_std_construct(struct v4l2_standard *vs,
-                                   int id, char *name);
-
-/* prority handling */
-struct v4l2_prio_state {
-       atomic_t prios[4];
-};
-int v4l2_prio_init(struct v4l2_prio_state *global);
-int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
-                    enum v4l2_priority new);
-int v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local);
-int v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority *local);
-enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global);
-int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local);
-
-/* names for fancy debug output */
-extern char *v4l2_field_names[];
-extern char *v4l2_type_names[];
-
-/*  Compatibility layer interface  --  v4l1-compat module */
-typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file,
-                          unsigned int cmd, void *arg);
-
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-int v4l_compat_translate_ioctl(struct inode *inode, struct file *file,
-                              int cmd, void *arg, v4l2_kioctl driver_ioctl);
-#else
-#define v4l_compat_translate_ioctl(inode,file,cmd,arg,ioctl) -EINVAL
 #endif
 
-/* 32 Bits compatibility layer for 64 bits processors */
-extern long v4l_compat_ioctl32(struct file *file, unsigned int cmd,
-                               unsigned long arg);
-
+#define BASE_VIDIOC_PRIVATE    192             /* 192-255 are private */
 
-#endif /* __KERNEL__ */
 #endif /* __LINUX_VIDEODEV2_H */
 
 /*
diff --git a/include/media/cx2341x.h b/include/media/cx2341x.h
new file mode 100644 (file)
index 0000000..51fb06b
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+    cx23415/6 header containing common defines.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You 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 CX2341X_H
+#define CX2341X_H
+
+enum cx2341x_port {
+       CX2341X_PORT_MEMORY    = 0,
+       CX2341X_PORT_STREAMING = 1,
+       CX2341X_PORT_SERIAL    = 2
+};
+
+struct cx2341x_mpeg_params {
+       /* misc */
+       enum cx2341x_port port;
+       u16 width;
+       u16 height;
+       u16 is_50hz;
+
+       /* stream */
+       enum v4l2_mpeg_stream_type stream_type;
+
+       /* audio */
+       enum v4l2_mpeg_audio_sampling_freq audio_sampling_freq;
+       enum v4l2_mpeg_audio_encoding audio_encoding;
+       enum v4l2_mpeg_audio_l2_bitrate audio_l2_bitrate;
+       enum v4l2_mpeg_audio_mode audio_mode;
+       enum v4l2_mpeg_audio_mode_extension audio_mode_extension;
+       enum v4l2_mpeg_audio_emphasis audio_emphasis;
+       enum v4l2_mpeg_audio_crc audio_crc;
+       u8 audio_properties;
+
+       /* video */
+       enum v4l2_mpeg_video_encoding video_encoding;
+       enum v4l2_mpeg_video_aspect video_aspect;
+       u16 video_b_frames;
+       u16 video_gop_size;
+       u16 video_gop_closure;
+       u16 video_pulldown;
+       enum v4l2_mpeg_video_bitrate_mode video_bitrate_mode;
+       u32 video_bitrate;
+       u32 video_bitrate_peak;
+       u16 video_temporal_decimation;
+
+       /* encoding filters */
+       enum v4l2_mpeg_cx2341x_video_spatial_filter_mode video_spatial_filter_mode;
+       u16 video_spatial_filter;
+       enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type video_luma_spatial_filter_type;
+       enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type video_chroma_spatial_filter_type;
+       enum v4l2_mpeg_cx2341x_video_temporal_filter_mode video_temporal_filter_mode;
+       u16 video_temporal_filter;
+       enum v4l2_mpeg_cx2341x_video_median_filter_type video_median_filter_type;
+       u16 video_luma_median_filter_top;
+       u16 video_luma_median_filter_bottom;
+       u16 video_chroma_median_filter_top;
+       u16 video_chroma_median_filter_bottom;
+};
+
+#define CX2341X_MBOX_MAX_DATA 16
+
+extern const u32 cx2341x_mpeg_ctrls[];
+typedef int (*cx2341x_mbox_func)(void *priv, int cmd, int in, int out,
+               u32 data[CX2341X_MBOX_MAX_DATA]);
+int cx2341x_update(void *priv, cx2341x_mbox_func func,
+               const struct cx2341x_mpeg_params *old,
+               const struct cx2341x_mpeg_params *new);
+int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params,
+               struct v4l2_queryctrl *qctrl);
+const char **cx2341x_ctrl_get_menu(u32 id);
+int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
+               struct v4l2_ext_controls *ctrls, int cmd);
+void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p);
+void cx2341x_log_status(struct cx2341x_mpeg_params *p, int cardid);
+
+/* Firmware names */
+#define CX2341X_FIRM_ENC_FILENAME "v4l-cx2341x-enc.fw"
+/* Decoder firmware for the cx23415 only */
+#define CX2341X_FIRM_DEC_FILENAME "v4l-cx2341x-dec.fw"
+
+/* Firmware API commands */
+
+/* MPEG decoder API, specific to the cx23415 */
+#define CX2341X_DEC_PING_FW                    0x00
+#define CX2341X_DEC_START_PLAYBACK             0x01
+#define CX2341X_DEC_STOP_PLAYBACK              0x02
+#define CX2341X_DEC_SET_PLAYBACK_SPEED                 0x03
+#define CX2341X_DEC_STEP_VIDEO                         0x05
+#define CX2341X_DEC_SET_DMA_BLOCK_SIZE                 0x08
+#define CX2341X_DEC_GET_XFER_INFO              0x09
+#define CX2341X_DEC_GET_DMA_STATUS             0x0a
+#define CX2341X_DEC_SCHED_DMA_FROM_HOST                0x0b
+#define CX2341X_DEC_PAUSE_PLAYBACK             0x0d
+#define CX2341X_DEC_HALT_FW                    0x0e
+#define CX2341X_DEC_SET_STANDARD               0x10
+#define CX2341X_DEC_GET_VERSION                        0x11
+#define CX2341X_DEC_SET_STREAM_INPUT           0x14
+#define CX2341X_DEC_GET_TIMING_INFO            0x15
+#define CX2341X_DEC_SET_AUDIO_MODE             0x16
+#define CX2341X_DEC_SET_EVENT_NOTIFICATION     0x17
+#define CX2341X_DEC_SET_DISPLAY_BUFFERS                0x18
+#define CX2341X_DEC_EXTRACT_VBI                0x19
+#define CX2341X_DEC_SET_DECODER_SOURCE                 0x1a
+#define CX2341X_DEC_SET_AUDIO_OUTPUT           0x1b
+#define CX2341X_DEC_SET_AV_DELAY               0x1c
+#define CX2341X_DEC_SET_PREBUFFERING           0x1e
+
+/* MPEG encoder API */
+#define CX2341X_ENC_PING_FW                    0x80
+#define CX2341X_ENC_START_CAPTURE              0x81
+#define CX2341X_ENC_STOP_CAPTURE               0x82
+#define CX2341X_ENC_SET_AUDIO_ID               0x89
+#define CX2341X_ENC_SET_VIDEO_ID               0x8b
+#define CX2341X_ENC_SET_PCR_ID                         0x8d
+#define CX2341X_ENC_SET_FRAME_RATE             0x8f
+#define CX2341X_ENC_SET_FRAME_SIZE             0x91
+#define CX2341X_ENC_SET_BIT_RATE               0x95
+#define CX2341X_ENC_SET_GOP_PROPERTIES                 0x97
+#define CX2341X_ENC_SET_ASPECT_RATIO           0x99
+#define CX2341X_ENC_SET_DNR_FILTER_MODE        0x9b
+#define CX2341X_ENC_SET_DNR_FILTER_PROPS       0x9d
+#define CX2341X_ENC_SET_CORING_LEVELS          0x9f
+#define CX2341X_ENC_SET_SPATIAL_FILTER_TYPE    0xa1
+#define CX2341X_ENC_SET_3_2_PULLDOWN           0xb1
+#define CX2341X_ENC_SET_VBI_LINE               0xb7
+#define CX2341X_ENC_SET_STREAM_TYPE            0xb9
+#define CX2341X_ENC_SET_OUTPUT_PORT            0xbb
+#define CX2341X_ENC_SET_AUDIO_PROPERTIES       0xbd
+#define CX2341X_ENC_HALT_FW                    0xc3
+#define CX2341X_ENC_GET_VERSION                        0xc4
+#define CX2341X_ENC_SET_GOP_CLOSURE            0xc5
+#define CX2341X_ENC_GET_SEQ_END                0xc6
+#define CX2341X_ENC_SET_PGM_INDEX_INFO                 0xc7
+#define CX2341X_ENC_SET_VBI_CONFIG             0xc8
+#define CX2341X_ENC_SET_DMA_BLOCK_SIZE                 0xc9
+#define CX2341X_ENC_GET_PREV_DMA_INFO_MB_10    0xca
+#define CX2341X_ENC_GET_PREV_DMA_INFO_MB_9     0xcb
+#define CX2341X_ENC_SCHED_DMA_TO_HOST          0xcc
+#define CX2341X_ENC_INITIALIZE_INPUT           0xcd
+#define CX2341X_ENC_SET_FRAME_DROP_RATE        0xd0
+#define CX2341X_ENC_PAUSE_ENCODER              0xd2
+#define CX2341X_ENC_REFRESH_INPUT              0xd3
+#define CX2341X_ENC_SET_COPYRIGHT              0xd4
+#define CX2341X_ENC_SET_EVENT_NOTIFICATION     0xd5
+#define CX2341X_ENC_SET_NUM_VSYNC_LINES        0xd6
+#define CX2341X_ENC_SET_PLACEHOLDER            0xd7
+#define CX2341X_ENC_MUTE_VIDEO                         0xd9
+#define CX2341X_ENC_MUTE_AUDIO                         0xda
+#define CX2341X_ENC_UNKNOWN                    0xdb
+#define CX2341X_ENC_MISC                       0xdc
+
+/* OSD API, specific to the cx23415 */
+#define CX2341X_OSD_GET_FRAMEBUFFER            0x41
+#define CX2341X_OSD_GET_PIXEL_FORMAT           0x42
+#define CX2341X_OSD_SET_PIXEL_FORMAT           0x43
+#define CX2341X_OSD_GET_STATE                  0x44
+#define CX2341X_OSD_SET_STATE                  0x45
+#define CX2341X_OSD_GET_OSD_COORDS             0x46
+#define CX2341X_OSD_SET_OSD_COORDS             0x47
+#define CX2341X_OSD_GET_SCREEN_COORDS          0x48
+#define CX2341X_OSD_SET_SCREEN_COORDS          0x49
+#define CX2341X_OSD_GET_GLOBAL_ALPHA           0x4a
+#define CX2341X_OSD_SET_GLOBAL_ALPHA           0x4b
+#define CX2341X_OSD_SET_BLEND_COORDS           0x4c
+#define CX2341X_OSD_GET_FLICKER_STATE          0x4f
+#define CX2341X_OSD_SET_FLICKER_STATE          0x50
+#define CX2341X_OSD_BLT_COPY                   0x52
+#define CX2341X_OSD_BLT_FILL                   0x53
+#define CX2341X_OSD_BLT_TEXT                   0x54
+#define CX2341X_OSD_SET_FRAMEBUFFER_WINDOW     0x56
+#define CX2341X_OSD_SET_CHROMA_KEY             0x60
+#define CX2341X_OSD_GET_ALPHA_CONTENT_INDEX    0x61
+#define CX2341X_OSD_SET_ALPHA_CONTENT_INDEX    0x62
+
+#endif /* CX2341X_H */
index 302d5b3946e704f37a41d1d68c53b340cbd854f4..7bab09b0ed451ae2f1f1569ceeaeb3ce2b8ab52a 100644 (file)
@@ -73,7 +73,7 @@ extern IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_flydvb[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_cinergy[IR_KEYTAB_SIZE];
@@ -87,8 +87,9 @@ extern IR_KEYTAB_TYPE ir_codes_pctv_sedna[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pinnacle_color[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE];
 
 #endif
 
index 730f21ed91db18aa28b705147da6e377c517ac14..a455f7ce5ee8cbfdf423d4e5d0409b57954b7eb1 100644 (file)
@@ -20,5 +20,6 @@ struct IR_i2c {
        int                    (*get_key)(struct IR_i2c*, u32*, u32*);
 };
 
-int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
+int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
+int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
 #endif
index 8138983adcedd57f3db7f905f1c6e8074c6e9763..0f43451f8bb3599db431e12789cd498b71ecc168 100644 (file)
@@ -15,6 +15,7 @@
 #define __LINUX_OVCAMCHIP_H
 
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/i2c.h>
 
 /* --------------------------------- */
diff --git a/include/media/pwc-ioctl.h b/include/media/pwc-ioctl.h
new file mode 100644 (file)
index 0000000..adc1254
--- /dev/null
@@ -0,0 +1,325 @@
+#ifndef PWC_IOCTL_H
+#define PWC_IOCTL_H
+
+/* (C) 2001-2004 Nemosoft Unv.
+   (C) 2004-2006 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 10.0.10
+   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
+   2006/01/01  Luc Saillard Add raw format definition
+ */
+
+/* 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
+ */
+
+#include <linux/types.h>
+#include <linux/version.h>
+
+
+ /* 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.
+   This value can also be passing using the private flag when using v4l2 and
+   VIDIOC_S_FMT ioctl.
+
+   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
+#define PWC_QLT_MASK           0x03000000
+#define PWC_QLT_SHIFT          24
+
+
+/* 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)
+
+/*
+ * This is private command used when communicating with v4l2.
+ * In the future all private ioctl will be remove/replace to
+ * use interface offer by v4l2.
+ */
+
+#define V4L2_CID_PRIVATE_SAVE_USER       (V4L2_CID_PRIVATE_BASE + 0)
+#define V4L2_CID_PRIVATE_RESTORE_USER    (V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_PRIVATE_RESTORE_FACTORY (V4L2_CID_PRIVATE_BASE + 2)
+#define V4L2_CID_PRIVATE_COLOUR_MODE     (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_PRIVATE_AUTOCONTOUR     (V4L2_CID_PRIVATE_BASE + 4)
+#define V4L2_CID_PRIVATE_CONTOUR         (V4L2_CID_PRIVATE_BASE + 5)
+#define V4L2_CID_PRIVATE_BACKLIGHT       (V4L2_CID_PRIVATE_BASE + 6)
+#define V4L2_CID_PRIVATE_FLICKERLESS     (V4L2_CID_PRIVATE_BASE + 7)
+#define V4L2_CID_PRIVATE_NOISE_REDUCTION (V4L2_CID_PRIVATE_BASE + 8)
+
+struct pwc_raw_frame {
+   __le16 type;                /* type of the webcam */
+   __le16 vbandlength; /* Size of 4lines compressed (used by the decompressor) */
+   __u8   cmd[4];      /* the four byte of the command (in case of nala,
+                          only the first 3 bytes is filled) */
+   __u8   rawframe[0]; /* frame_size = H/4*vbandlength */
+} __attribute__ ((packed));
+
+
+#endif
index 6b4836f3f057280782aa0b78947eceb86322ad91..9f0e2285a099f0c63765477ea417670ac827abad 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    saa7115.h - definition for saa7113/4/5 inputs
+    saa7115.h - definition for saa7113/4/5 inputs and frequency flags
 
     Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
 
 #define SAA7115_SVIDEO2    8
 #define SAA7115_SVIDEO3    9
 
+/* SAA7115 v4l2_crystal_freq frequency values */
+#define SAA7115_FREQ_32_11_MHZ  32110000   /* 32.11 MHz crystal, SAA7114/5 only */
+#define SAA7115_FREQ_24_576_MHZ 24576000   /* 24.576 MHz crystal */
+
+/* SAA7115 v4l2_crystal_freq audio clock control flags */
+#define SAA7115_FREQ_FL_UCGC   (1 << 0)           /* SA 3A[7], UCGC, SAA7115 only */
+#define SAA7115_FREQ_FL_CGCDIV (1 << 1)           /* SA 3A[6], CGCDIV, SAA7115 only */
+#define SAA7115_FREQ_FL_APLL   (1 << 2)           /* SA 3A[3], APLL, SAA7114/5 only */
+
 #endif
 
index 4507cb61ae9379e9e3c4715859854630c7b8c45d..83fe2e3d1e25a43d1c3fefcab1255baf1194ea30 100644 (file)
@@ -2,7 +2,7 @@
 #define __SAA7146_VV__
 
 #include <linux/videodev.h>
-
+#include <media/v4l2-common.h>
 #include <media/saa7146.h>
 #include <media/video-buf.h>
 
index 017fed7d5e4d24fee81d3b7a3994ab24d401939e..2f7b00b08e8817224c5827ab09e7f13bd376d883 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/videodev2.h>
 #include <media/tuner-types.h>
 
+extern int tuner_debug;
+
 #define ADDR_UNSET (255)
 
 #define TUNER_TEMIC_PAL                        0        /* 4002 FH5 (3X 7756, 9483) */
 #define TUNER_TEA5767                  62      /* Only FM Radio Tuner */
 #define TUNER_PHILIPS_FMD1216ME_MK3    63
 
-#define TUNER_LG_TDVS_H062F            64      /* DViCO FusionHDTV 5 */
+#define TUNER_LG_TDVS_H06XF            64      /* TDVS H061F, H062F, H064F */
 #define TUNER_YMEC_TVF66T5_B_DFF       65      /* Acorp Y878F */
 #define TUNER_LG_TALN                  66
 #define TUNER_PHILIPS_TD1316           67
 #define TUNER_XCEIVE_XC3028            71
 
 #define TUNER_THOMSON_FE6600           72      /* DViCO FusionHDTV DVB-T Hybrid */
+#define TUNER_SAMSUNG_TCPG_6121P30A     73     /* Hauppauge PVR-500 PAL */
+#define TUNER_TDA9887                   74      /* This tuner should be used only internally */
 
 /* tv card specific */
 #define TDA9887_PRESENT                (1<<0)
@@ -190,6 +194,10 @@ struct tuner {
 
        int          using_v4l2;
 
+       /* used by tda9887 */
+       unsigned int       tda9887_config;
+       unsigned char      tda9887_data[4];
+
        /* used by MT2032 */
        unsigned int xogc;
        unsigned int radio_if2;
@@ -206,6 +214,8 @@ struct tuner {
        void (*set_radio_freq)(struct i2c_client *c, unsigned int freq);
        int  (*has_signal)(struct i2c_client *c);
        int  (*is_stereo)(struct i2c_client *c);
+       int  (*get_afc)(struct i2c_client *c);
+       void (*tuner_status)(struct i2c_client *c);
        void (*standby)(struct i2c_client *c);
 };
 
@@ -218,6 +228,7 @@ extern int tda8290_probe(struct i2c_client *c);
 extern int tea5767_tuner_init(struct i2c_client *c);
 extern int default_tuner_init(struct i2c_client *c);
 extern int tea5767_autodetection(struct i2c_client *c);
+extern int tda9887_tuner_init(struct i2c_client *c);
 
 #define tuner_warn(fmt, arg...) do {\
        printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
diff --git a/include/media/tvp5150.h b/include/media/tvp5150.h
new file mode 100644 (file)
index 0000000..72bd2a2
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+    tvp5150.h - definition for tvp5150 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 _TVP5150_H_
+#define _TVP5150_H_
+
+/* TVP5150 HW inputs */
+#define TVP5150_COMPOSITE0 0
+#define TVP5150_COMPOSITE1 1
+#define TVP5150_SVIDEO     2
+
+/* TVP5150 HW outputs */
+#define TVP5150_NORMAL       0
+#define TVP5150_BLACK_SCREEN 1
+
+#endif
+
index 642520acdfa7b41da7a77cd78206b7a1b5d7ce77..5564db13c0d5f1d1897dadb20309c1d06219480a 100644 (file)
 #ifndef V4L2_COMMON_H_
 #define V4L2_COMMON_H_
 
+#include <media/v4l2-dev.h>
+
 /* v4l debugging and diagnostics */
 
+/* Debug bitmask flags to be used on V4L2 */
+#define V4L2_DEBUG_IOCTL     0x01
+#define V4L2_DEBUG_IOCTL_ARG 0x02
+
 /* Common printk constucts for v4l-i2c drivers. These macros create a unique
    prefix consisting of the driver name, the adapter number and the i2c
    address. */
@@ -78,6 +84,19 @@ extern void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg);
 
 /* ------------------------------------------------------------------------- */
 
+/* Control helper functions */
+
+int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
+               const char **menu_items);
+const char **v4l2_ctrl_get_menu(u32 id);
+int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def);
+int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl);
+int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu,
+               struct v4l2_queryctrl *qctrl, const char **menu_items);
+u32 v4l2_ctrl_next(const u32 * const *ctrl_classes, u32 id);
+
+/* ------------------------------------------------------------------------- */
+
 /* Internal ioctls */
 
 /* VIDIOC_INT_G_REGISTER and VIDIOC_INT_S_REGISTER */
@@ -112,6 +131,8 @@ enum v4l2_chip_ident {
        V4L2_IDENT_SAA7129 = 159,
 
        /* module cx25840: reserved range 200-249 */
+       V4L2_IDENT_CX25836 = 236,
+       V4L2_IDENT_CX25837 = 237,
        V4L2_IDENT_CX25840 = 240,
        V4L2_IDENT_CX25841 = 241,
        V4L2_IDENT_CX25842 = 242,
@@ -211,4 +232,15 @@ struct v4l2_routing {
 #define        VIDIOC_INT_S_VIDEO_ROUTING      _IOW ('d', 111, struct v4l2_routing)
 #define        VIDIOC_INT_G_VIDEO_ROUTING      _IOR ('d', 112, struct v4l2_routing)
 
+struct v4l2_crystal_freq {
+       u32 freq;       /* frequency in Hz of the crystal */
+       u32 flags;      /* device specific flags */
+};
+
+/* Sets the frequency of the crystal used to generate the clocks.
+   An extra flags field allows device specific configuration regarding
+   clock frequency dividers, etc. If not used, then set flags to 0.
+   If the frequency is not supported, then -EINVAL is returned. */
+#define VIDIOC_INT_S_CRYSTAL_FREQ      _IOW ('d', 113, struct v4l2_crystal_freq)
+
 #endif /* V4L2_COMMON_H_ */
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
new file mode 100644 (file)
index 0000000..a1b4731
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ *
+ *     V 4 L 2   D R I V E R   H E L P E R   A P I
+ *
+ * Moved from videodev2.h
+ *
+ *     Some commonly needed functions for drivers (v4l2-common.o module)
+ */
+#ifndef _V4L2_DEV_H
+#define _V4L2_DEV_H
+
+#define OBSOLETE_OWNER 1 /* to be removed soon */
+
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/compiler.h> /* need __user */
+#ifdef CONFIG_VIDEO_V4L1
+#include <linux/videodev.h>
+#else
+#include <linux/videodev2.h>
+#endif
+
+#include <linux/fs.h>
+
+#define VIDEO_MAJOR    81
+/* Minor device allocation */
+#define MINOR_VFL_TYPE_GRABBER_MIN   0
+#define MINOR_VFL_TYPE_GRABBER_MAX  63
+#define MINOR_VFL_TYPE_RADIO_MIN    64
+#define MINOR_VFL_TYPE_RADIO_MAX   127
+#define MINOR_VFL_TYPE_VTX_MIN     192
+#define MINOR_VFL_TYPE_VTX_MAX     223
+#define MINOR_VFL_TYPE_VBI_MIN     224
+#define MINOR_VFL_TYPE_VBI_MAX     255
+
+#define VFL_TYPE_GRABBER       0
+#define VFL_TYPE_VBI           1
+#define VFL_TYPE_RADIO         2
+#define VFL_TYPE_VTX           3
+
+/*  Video standard functions  */
+extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs);
+extern int v4l2_video_std_construct(struct v4l2_standard *vs,
+                                   int id, char *name);
+
+/* prority handling */
+struct v4l2_prio_state {
+       atomic_t prios[4];
+};
+int v4l2_prio_init(struct v4l2_prio_state *global);
+int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
+                    enum v4l2_priority new);
+int v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local);
+int v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority *local);
+enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global);
+int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local);
+
+/* names for fancy debug output */
+extern char *v4l2_field_names[];
+extern char *v4l2_type_names[];
+
+/*  Compatibility layer interface  --  v4l1-compat module */
+typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file,
+                          unsigned int cmd, void *arg);
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+int v4l_compat_translate_ioctl(struct inode *inode, struct file *file,
+                              int cmd, void *arg, v4l2_kioctl driver_ioctl);
+#else
+#define v4l_compat_translate_ioctl(inode,file,cmd,arg,ioctl) -EINVAL
+#endif
+
+/* 32 Bits compatibility layer for 64 bits processors */
+extern long v4l_compat_ioctl32(struct file *file, unsigned int cmd,
+                               unsigned long arg);
+
+/*
+ * Newer version of video_device, handled by videodev2.c
+ *     This version moves redundant code from video device code to
+ *     the common handler
+ */
+struct v4l2_tvnorm {
+       char          *name;
+       v4l2_std_id   id;
+
+       void          *priv_data;
+};
+
+struct video_device
+{
+       /* device ops */
+       const struct file_operations *fops;
+
+       /* device info */
+       struct device *dev;
+       char name[32];
+       int type;       /* v4l1 */
+       int type2;      /* v4l2 */
+       int hardware;
+       int minor;
+
+       int debug;      /* Activates debug level*/
+
+       /* Video standard vars */
+       int tvnormsize; /* Size of tvnorm array */
+       v4l2_std_id current_norm; /* Current tvnorm */
+       struct v4l2_tvnorm *tvnorms;
+
+       /* callbacks */
+       void (*release)(struct video_device *vfd);
+
+       /* ioctl callbacks */
+
+       /* VIDIOC_QUERYCAP handler */
+       int (*vidioc_querycap)(struct file *file, void *fh, struct v4l2_capability *cap);
+
+       /* Priority handling */
+       int (*vidioc_g_priority)   (struct file *file, void *fh,
+                                   enum v4l2_priority *p);
+       int (*vidioc_s_priority)   (struct file *file, void *fh,
+                                   enum v4l2_priority p);
+
+       /* VIDIOC_ENUM_FMT handlers */
+       int (*vidioc_enum_fmt_cap)         (struct file *file, void *fh,
+                                           struct v4l2_fmtdesc *f);
+       int (*vidioc_enum_fmt_overlay)     (struct file *file, void *fh,
+                                           struct v4l2_fmtdesc *f);
+       int (*vidioc_enum_fmt_vbi)         (struct file *file, void *fh,
+                                           struct v4l2_fmtdesc *f);
+       int (*vidioc_enum_fmt_vbi_capture) (struct file *file, void *fh,
+                                           struct v4l2_fmtdesc *f);
+       int (*vidioc_enum_fmt_video_output)(struct file *file, void *fh,
+                                           struct v4l2_fmtdesc *f);
+       int (*vidioc_enum_fmt_vbi_output)  (struct file *file, void *fh,
+                                           struct v4l2_fmtdesc *f);
+       int (*vidioc_enum_fmt_type_private)(struct file *file, void *fh,
+                                           struct v4l2_fmtdesc *f);
+
+       /* VIDIOC_G_FMT handlers */
+       int (*vidioc_g_fmt_cap)        (struct file *file, void *fh,
+                                       struct v4l2_format *f);
+       int (*vidioc_g_fmt_overlay)    (struct file *file, void *fh,
+                                       struct v4l2_format *f);
+       int (*vidioc_g_fmt_vbi)        (struct file *file, void *fh,
+                                       struct v4l2_format *f);
+       int (*vidioc_g_fmt_vbi_output) (struct file *file, void *fh,
+                                       struct v4l2_format *f);
+       int (*vidioc_g_fmt_vbi_capture)(struct file *file, void *fh,
+                                       struct v4l2_format *f);
+       int (*vidioc_g_fmt_video_output)(struct file *file, void *fh,
+                                       struct v4l2_format *f);
+       int (*vidioc_g_fmt_type_private)(struct file *file, void *fh,
+                                       struct v4l2_format *f);
+
+       /* VIDIOC_S_FMT handlers */
+       int (*vidioc_s_fmt_cap)        (struct file *file, void *fh,
+                                       struct v4l2_format *f);
+
+       int (*vidioc_s_fmt_overlay)    (struct file *file, void *fh,
+                                       struct v4l2_format *f);
+       int (*vidioc_s_fmt_vbi)        (struct file *file, void *fh,
+                                       struct v4l2_format *f);
+       int (*vidioc_s_fmt_vbi_output) (struct file *file, void *fh,
+                                       struct v4l2_format *f);
+       int (*vidioc_s_fmt_vbi_capture)(struct file *file, void *fh,
+                                       struct v4l2_format *f);
+       int (*vidioc_s_fmt_video_output)(struct file *file, void *fh,
+                                       struct v4l2_format *f);
+       int (*vidioc_s_fmt_type_private)(struct file *file, void *fh,
+                                       struct v4l2_format *f);
+
+       /* VIDIOC_TRY_FMT handlers */
+       int (*vidioc_try_fmt_cap)        (struct file *file, void *fh,
+                                         struct v4l2_format *f);
+       int (*vidioc_try_fmt_overlay)    (struct file *file, void *fh,
+                                         struct v4l2_format *f);
+       int (*vidioc_try_fmt_vbi)        (struct file *file, void *fh,
+                                         struct v4l2_format *f);
+       int (*vidioc_try_fmt_vbi_output) (struct file *file, void *fh,
+                                         struct v4l2_format *f);
+       int (*vidioc_try_fmt_vbi_capture)(struct file *file, void *fh,
+                                         struct v4l2_format *f);
+       int (*vidioc_try_fmt_video_output)(struct file *file, void *fh,
+                                         struct v4l2_format *f);
+       int (*vidioc_try_fmt_type_private)(struct file *file, void *fh,
+                                         struct v4l2_format *f);
+
+       /* Buffer handlers */
+       int (*vidioc_reqbufs) (struct file *file, void *fh, struct v4l2_requestbuffers *b);
+       int (*vidioc_querybuf)(struct file *file, void *fh, struct v4l2_buffer *b);
+       int (*vidioc_qbuf)    (struct file *file, void *fh, struct v4l2_buffer *b);
+       int (*vidioc_dqbuf)   (struct file *file, void *fh, struct v4l2_buffer *b);
+
+
+       int (*vidioc_overlay) (struct file *file, void *fh, unsigned int i);
+#ifdef HAVE_V4L1
+                       /* buffer type is struct vidio_mbuf * */
+       int (*vidiocgmbuf)  (struct file *file, void *fh, struct video_mbuf *p);
+#endif
+       int (*vidioc_g_fbuf)   (struct file *file, void *fh,
+                               struct v4l2_framebuffer *a);
+       int (*vidioc_s_fbuf)   (struct file *file, void *fh,
+                               struct v4l2_framebuffer *a);
+
+               /* Stream on/off */
+       int (*vidioc_streamon) (struct file *file, void *fh, enum v4l2_buf_type i);
+       int (*vidioc_streamoff)(struct file *file, void *fh, enum v4l2_buf_type i);
+
+               /* Standard handling
+                       G_STD and ENUMSTD are handled by videodev.c
+                */
+       int (*vidioc_s_std)    (struct file *file, void *fh, v4l2_std_id a);
+       int (*vidioc_querystd) (struct file *file, void *fh, v4l2_std_id *a);
+
+               /* Input handling */
+       int (*vidioc_enum_input)(struct file *file, void *fh,
+                                struct v4l2_input *inp);
+       int (*vidioc_g_input)   (struct file *file, void *fh, unsigned int *i);
+       int (*vidioc_s_input)   (struct file *file, void *fh, unsigned int i);
+
+               /* Output handling */
+       int (*vidioc_enumoutput) (struct file *file, void *fh,
+                                 struct v4l2_output *a);
+       int (*vidioc_g_output)   (struct file *file, void *fh, unsigned int *i);
+       int (*vidioc_s_output)   (struct file *file, void *fh, unsigned int i);
+
+               /* Control handling */
+       int (*vidioc_queryctrl)        (struct file *file, void *fh,
+                                       struct v4l2_queryctrl *a);
+       int (*vidioc_g_ctrl)           (struct file *file, void *fh,
+                                       struct v4l2_control *a);
+       int (*vidioc_s_ctrl)           (struct file *file, void *fh,
+                                       struct v4l2_control *a);
+       int (*vidioc_g_ext_ctrls)      (struct file *file, void *fh,
+                                       struct v4l2_ext_controls *a);
+       int (*vidioc_s_ext_ctrls)      (struct file *file, void *fh,
+                                       struct v4l2_ext_controls *a);
+       int (*vidioc_try_ext_ctrls)    (struct file *file, void *fh,
+                                       struct v4l2_ext_controls *a);
+       int (*vidioc_querymenu)        (struct file *file, void *fh,
+                                       struct v4l2_querymenu *a);
+
+       /* Audio ioctls */
+       int (*vidioc_enumaudio)        (struct file *file, void *fh,
+                                       struct v4l2_audio *a);
+       int (*vidioc_g_audio)          (struct file *file, void *fh,
+                                       struct v4l2_audio *a);
+       int (*vidioc_s_audio)          (struct file *file, void *fh,
+                                       struct v4l2_audio *a);
+
+       /* Audio out ioctls */
+       int (*vidioc_enumaudout)       (struct file *file, void *fh,
+                                       struct v4l2_audioout *a);
+       int (*vidioc_g_audout)         (struct file *file, void *fh,
+                                       struct v4l2_audioout *a);
+       int (*vidioc_s_audout)         (struct file *file, void *fh,
+                                       struct v4l2_audioout *a);
+       int (*vidioc_g_modulator)      (struct file *file, void *fh,
+                                       struct v4l2_modulator *a);
+       int (*vidioc_s_modulator)      (struct file *file, void *fh,
+                                       struct v4l2_modulator *a);
+       /* Crop ioctls */
+       int (*vidioc_cropcap)          (struct file *file, void *fh,
+                                       struct v4l2_cropcap *a);
+       int (*vidioc_g_crop)           (struct file *file, void *fh,
+                                       struct v4l2_crop *a);
+       int (*vidioc_s_crop)           (struct file *file, void *fh,
+                                       struct v4l2_crop *a);
+       /* Compression ioctls */
+       int (*vidioc_g_mpegcomp)       (struct file *file, void *fh,
+                                       struct v4l2_mpeg_compression *a);
+       int (*vidioc_s_mpegcomp)       (struct file *file, void *fh,
+                                       struct v4l2_mpeg_compression *a);
+       int (*vidioc_g_jpegcomp)       (struct file *file, void *fh,
+                                       struct v4l2_jpegcompression *a);
+       int (*vidioc_s_jpegcomp)       (struct file *file, void *fh,
+                                       struct v4l2_jpegcompression *a);
+
+       /* Stream type-dependent parameter ioctls */
+       int (*vidioc_g_parm)           (struct file *file, void *fh,
+                                       struct v4l2_streamparm *a);
+       int (*vidioc_s_parm)           (struct file *file, void *fh,
+                                       struct v4l2_streamparm *a);
+
+       /* Tuner ioctls */
+       int (*vidioc_g_tuner)          (struct file *file, void *fh,
+                                       struct v4l2_tuner *a);
+       int (*vidioc_s_tuner)          (struct file *file, void *fh,
+                                       struct v4l2_tuner *a);
+       int (*vidioc_g_frequency)      (struct file *file, void *fh,
+                                       struct v4l2_frequency *a);
+       int (*vidioc_s_frequency)      (struct file *file, void *fh,
+                                       struct v4l2_frequency *a);
+
+       /* Sliced VBI cap */
+       int (*vidioc_g_sliced_vbi_cap) (struct file *file, void *fh,
+                                       struct v4l2_sliced_vbi_cap *a);
+
+       /* Log status ioctl */
+       int (*vidioc_log_status)       (struct file *file, void *fh);
+
+
+#ifdef OBSOLETE_OWNER /* to be removed soon */
+/* obsolete -- fops->owner is used instead */
+struct module *owner;
+/* dev->driver_data will be used instead some day.
+       * Use the video_{get|set}_drvdata() helper functions,
+       * so the switch over will be transparent for you.
+       * Or use {pci|usb}_{get|set}_drvdata() directly. */
+void *priv;
+#endif
+
+       /* for videodev.c intenal usage -- please don't touch */
+       int users;                     /* video_exclusive_{open|close} ... */
+       struct mutex lock;             /* ... helper function uses these   */
+       char devfs_name[64];           /* devfs */
+       struct class_device class_dev; /* sysfs */
+};
+
+/* Version 2 functions */
+extern int video_register_device(struct video_device *vfd, int type, int nr);
+void video_unregister_device(struct video_device *);
+extern int video_ioctl2(struct inode *inode, struct file *file,
+                         unsigned int cmd, unsigned long arg);
+
+/* helper functions to alloc / release struct video_device, the
+   later can be used for video_device->release() */
+struct video_device *video_device_alloc(void);
+void video_device_release(struct video_device *vfd);
+
+/* Include support for obsoleted stuff */
+extern int video_usercopy(struct inode *inode, struct file *file,
+                         unsigned int cmd, unsigned long arg,
+                         int (*func)(struct inode *inode, struct file *file,
+                                     unsigned int cmd, void *arg));
+
+
+#ifdef HAVE_V4L1
+#include <linux/mm.h>
+
+extern struct video_device* video_devdata(struct file*);
+
+#define to_video_device(cd) container_of(cd, struct video_device, class_dev)
+static inline void
+video_device_create_file(struct video_device *vfd,
+                        struct class_device_attribute *attr)
+{
+       class_device_create_file(&vfd->class_dev, attr);
+}
+static inline void
+video_device_remove_file(struct video_device *vfd,
+                        struct class_device_attribute *attr)
+{
+       class_device_remove_file(&vfd->class_dev, attr);
+}
+
+#ifdef OBSOLETE_OWNER /* to be removed soon */
+/* helper functions to access driver private data. */
+static inline void *video_get_drvdata(struct video_device *dev)
+{
+       return dev->priv;
+}
+
+static inline void video_set_drvdata(struct video_device *dev, void *data)
+{
+       dev->priv = data;
+}
+#endif
+
+extern int video_exclusive_open(struct inode *inode, struct file *file);
+extern int video_exclusive_release(struct inode *inode, struct file *file);
+#endif /* HAVE_V4L1 */
+
+#endif /* _V4L2_DEV_H */
index b78d90fe629fb0b816f336015e07126116ce6af8..8233cafdeef6de74970ed18f752294e42005c525 100644 (file)
@@ -26,7 +26,8 @@ struct videobuf_dvb {
 
 int videobuf_dvb_register(struct videobuf_dvb *dvb,
                          struct module *module,
-                         void *adapter_priv);
+                         void *adapter_priv,
+                         struct device *device);
 void videobuf_dvb_unregister(struct videobuf_dvb *dvb);
 
 /*
index fff3fd0fbf94056248c1921a0fc057512b7b7c26..1115a256969f0468e6ec079567aa6d32e6c338d5 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include <linux/videodev2.h>
+#include <linux/poll.h>
 
 #define UNSET (-1U)
 
index a4f5545201975da167e6b3dddb0eba96766d1c78..b5067d3c2387c469d7b86672b51d018948d1d7f8 100644 (file)
  *   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/videodev.h>
+#include <media/v4l2-dev.h>
 
 struct snd_tea575x;
 
index df864a3582217b648786ff3ad48d2ce64fe6457e..e0358f3946a11e883a1b5bb49ed738d5470fb872 100644 (file)
@@ -151,7 +151,8 @@ config BSD_PROCESS_ACCT_V3
          at <http://www.physik3.uni-rostock.de/tim/kernel/utils/acct/>.
 
 config SYSCTL
-       bool "Sysctl support"
+       bool "Sysctl support" if EMBEDDED
+       default y
        ---help---
          The sysctl interface provides a means of dynamically changing
          certain kernel parameters and variables on the fly without requiring
index 6802020e0ceb07c4078e591373ed4df38471b27a..368c4f03fe0e9fd0b7426b650d83a847badb05d7 100644 (file)
@@ -75,7 +75,7 @@ int acct_parm[3] = {4, 2, 30};
 /*
  * External references and all of the globals.
  */
-static void do_acct_process(long, struct file *);
+static void do_acct_process(struct file *);
 
 /*
  * This structure is used so that all the data protected by lock
@@ -196,7 +196,7 @@ static void acct_file_reopen(struct file *file)
        if (old_acct) {
                mnt_unpin(old_acct->f_vfsmnt);
                spin_unlock(&acct_globals.lock);
-               do_acct_process(0, old_acct);
+               do_acct_process(old_acct);
                filp_close(old_acct, NULL);
                spin_lock(&acct_globals.lock);
        }
@@ -419,16 +419,15 @@ static u32 encode_float(u64 value)
 /*
  *  do_acct_process does all actual work. Caller holds the reference to file.
  */
-static void do_acct_process(long exitcode, struct file *file)
+static void do_acct_process(struct file *file)
 {
+       struct pacct_struct *pacct = &current->signal->pacct;
        acct_t ac;
        mm_segment_t fs;
-       unsigned long vsize;
        unsigned long flim;
        u64 elapsed;
        u64 run_time;
        struct timespec uptime;
-       unsigned long jiffies;
 
        /*
         * First check to see if there is enough free_space to continue
@@ -469,12 +468,6 @@ static void do_acct_process(long exitcode, struct file *file)
 #endif
        do_div(elapsed, AHZ);
        ac.ac_btime = xtime.tv_sec - elapsed;
-       jiffies = cputime_to_jiffies(cputime_add(current->utime,
-                                                current->signal->utime));
-       ac.ac_utime = encode_comp_t(jiffies_to_AHZ(jiffies));
-       jiffies = cputime_to_jiffies(cputime_add(current->stime,
-                                                current->signal->stime));
-       ac.ac_stime = encode_comp_t(jiffies_to_AHZ(jiffies));
        /* we really need to bite the bullet and change layout */
        ac.ac_uid = current->uid;
        ac.ac_gid = current->gid;
@@ -496,37 +489,18 @@ static void do_acct_process(long exitcode, struct file *file)
                old_encode_dev(tty_devnum(current->signal->tty)) : 0;
        read_unlock(&tasklist_lock);
 
-       ac.ac_flag = 0;
-       if (current->flags & PF_FORKNOEXEC)
-               ac.ac_flag |= AFORK;
-       if (current->flags & PF_SUPERPRIV)
-               ac.ac_flag |= ASU;
-       if (current->flags & PF_DUMPCORE)
-               ac.ac_flag |= ACORE;
-       if (current->flags & PF_SIGNALED)
-               ac.ac_flag |= AXSIG;
-
-       vsize = 0;
-       if (current->mm) {
-               struct vm_area_struct *vma;
-               down_read(&current->mm->mmap_sem);
-               vma = current->mm->mmap;
-               while (vma) {
-                       vsize += vma->vm_end - vma->vm_start;
-                       vma = vma->vm_next;
-               }
-               up_read(&current->mm->mmap_sem);
-       }
-       vsize = vsize / 1024;
-       ac.ac_mem = encode_comp_t(vsize);
+       spin_lock(&current->sighand->siglock);
+       ac.ac_utime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_utime)));
+       ac.ac_stime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_stime)));
+       ac.ac_flag = pacct->ac_flag;
+       ac.ac_mem = encode_comp_t(pacct->ac_mem);
+       ac.ac_minflt = encode_comp_t(pacct->ac_minflt);
+       ac.ac_majflt = encode_comp_t(pacct->ac_majflt);
+       ac.ac_exitcode = pacct->ac_exitcode;
+       spin_unlock(&current->sighand->siglock);
        ac.ac_io = encode_comp_t(0 /* current->io_usage */);    /* %% */
        ac.ac_rw = encode_comp_t(ac.ac_io / 1024);
-       ac.ac_minflt = encode_comp_t(current->signal->min_flt +
-                                    current->min_flt);
-       ac.ac_majflt = encode_comp_t(current->signal->maj_flt +
-                                    current->maj_flt);
        ac.ac_swaps = encode_comp_t(0);
-       ac.ac_exitcode = exitcode;
 
        /*
          * Kernel segment override to datasegment and write it
@@ -545,13 +519,64 @@ static void do_acct_process(long exitcode, struct file *file)
        set_fs(fs);
 }
 
+/**
+ * acct_init_pacct - initialize a new pacct_struct
+ */
+void acct_init_pacct(struct pacct_struct *pacct)
+{
+       memset(pacct, 0, sizeof(struct pacct_struct));
+       pacct->ac_utime = pacct->ac_stime = cputime_zero;
+}
+
+/**
+ * acct_collect - collect accounting information into pacct_struct
+ * @exitcode: task exit code
+ * @group_dead: not 0, if this thread is the last one in the process.
+ */
+void acct_collect(long exitcode, int group_dead)
+{
+       struct pacct_struct *pacct = &current->signal->pacct;
+       unsigned long vsize = 0;
+
+       if (group_dead && current->mm) {
+               struct vm_area_struct *vma;
+               down_read(&current->mm->mmap_sem);
+               vma = current->mm->mmap;
+               while (vma) {
+                       vsize += vma->vm_end - vma->vm_start;
+                       vma = vma->vm_next;
+               }
+               up_read(&current->mm->mmap_sem);
+       }
+
+       spin_lock_irq(&current->sighand->siglock);
+       if (group_dead)
+               pacct->ac_mem = vsize / 1024;
+       if (thread_group_leader(current)) {
+               pacct->ac_exitcode = exitcode;
+               if (current->flags & PF_FORKNOEXEC)
+                       pacct->ac_flag |= AFORK;
+       }
+       if (current->flags & PF_SUPERPRIV)
+               pacct->ac_flag |= ASU;
+       if (current->flags & PF_DUMPCORE)
+               pacct->ac_flag |= ACORE;
+       if (current->flags & PF_SIGNALED)
+               pacct->ac_flag |= AXSIG;
+       pacct->ac_utime = cputime_add(pacct->ac_utime, current->utime);
+       pacct->ac_stime = cputime_add(pacct->ac_stime, current->stime);
+       pacct->ac_minflt += current->min_flt;
+       pacct->ac_majflt += current->maj_flt;
+       spin_unlock_irq(&current->sighand->siglock);
+}
+
 /**
  * acct_process - now just a wrapper around do_acct_process
  * @exitcode: task exit code
  *
  * handles process accounting for an exiting task
  */
-void acct_process(long exitcode)
+void acct_process()
 {
        struct file *file = NULL;
 
@@ -570,7 +595,7 @@ void acct_process(long exitcode)
        get_file(file);
        spin_unlock(&acct_globals.lock);
 
-       do_acct_process(exitcode, file);
+       do_acct_process(file);
        fput(file);
 }
 
@@ -599,9 +624,7 @@ void acct_update_integrals(struct task_struct *tsk)
  */
 void acct_clear_integrals(struct task_struct *tsk)
 {
-       if (tsk) {
-               tsk->acct_stimexpd = 0;
-               tsk->acct_rss_mem1 = 0;
-               tsk->acct_vm_mem1 = 0;
-       }
+       tsk->acct_stimexpd = 0;
+       tsk->acct_rss_mem1 = 0;
+       tsk->acct_vm_mem1 = 0;
 }
index 2f672332430f08484ded8f07c2c61ae544bc5465..126dee9530aacc13a37d304ee8a4b54f69355a82 100644 (file)
@@ -730,17 +730,10 @@ void
 sigset_from_compat (sigset_t *set, compat_sigset_t *compat)
 {
        switch (_NSIG_WORDS) {
-#if defined (__COMPAT_ENDIAN_SWAP__)
-       case 4: set->sig[3] = compat->sig[7] | (((long)compat->sig[6]) << 32 );
-       case 3: set->sig[2] = compat->sig[5] | (((long)compat->sig[4]) << 32 );
-       case 2: set->sig[1] = compat->sig[3] | (((long)compat->sig[2]) << 32 );
-       case 1: set->sig[0] = compat->sig[1] | (((long)compat->sig[0]) << 32 );
-#else
        case 4: set->sig[3] = compat->sig[6] | (((long)compat->sig[7]) << 32 );
        case 3: set->sig[2] = compat->sig[4] | (((long)compat->sig[5]) << 32 );
        case 2: set->sig[1] = compat->sig[2] | (((long)compat->sig[3]) << 32 );
        case 1: set->sig[0] = compat->sig[0] | (((long)compat->sig[1]) << 32 );
-#endif
        }
 }
 
index a3baf92462bd6d1acf855938f619c1888ba011f1..e76bd02e930ed6417c8df5f6b5f31d0a12da9abc 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/compat.h>
 #include <linux/pipe_fs_i.h>
 #include <linux/audit.h> /* for audit_free() */
+#include <linux/resource.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -45,8 +46,6 @@
 extern void sem_exit (void);
 extern struct task_struct *child_reaper;
 
-int getrusage(struct task_struct *, int, struct rusage __user *);
-
 static void exit_mm(struct task_struct * tsk);
 
 static void __unhash_process(struct task_struct *p)
@@ -895,11 +894,11 @@ fastcall NORET_TYPE void do_exit(long code)
        if (group_dead) {
                hrtimer_cancel(&tsk->signal->real_timer);
                exit_itimers(tsk->signal);
-               acct_process(code);
        }
+       acct_collect(code, group_dead);
        if (unlikely(tsk->robust_list))
                exit_robust_list(tsk);
-#ifdef CONFIG_COMPAT
+#if defined(CONFIG_FUTEX) && defined(CONFIG_COMPAT)
        if (unlikely(tsk->compat_robust_list))
                compat_exit_robust_list(tsk);
 #endif
@@ -907,6 +906,8 @@ fastcall NORET_TYPE void do_exit(long code)
                audit_free(tsk);
        exit_mm(tsk);
 
+       if (group_dead)
+               acct_process();
        exit_sem(tsk);
        __exit_files(tsk);
        __exit_fs(tsk);
index 49adc0e8d47ccf3b51af4e5b32ffd4210aeaf955..dfd10cb370c388119685a5983511b5ad60c74191 100644 (file)
@@ -874,6 +874,7 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts
                tsk->it_prof_expires =
                        secs_to_cputime(sig->rlim[RLIMIT_CPU].rlim_cur);
        }
+       acct_init_pacct(&sig->pacct);
 
        return 0;
 }
index 18324305724a0b5b6753c1e4dec2219d3e15e9fc..55601b3ce60e92717fa6c6d771bc1a67dea7a03e 100644 (file)
@@ -98,7 +98,6 @@ static DEFINE_PER_CPU(struct hrtimer_base, hrtimer_bases[MAX_HRTIMER_BASES]) =
 
 /**
  * ktime_get_ts - get the monotonic clock in timespec format
- *
  * @ts:                pointer to timespec variable
  *
  * The function calculates the monotonic clock from the realtime
@@ -238,7 +237,6 @@ lock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags)
 # ifndef CONFIG_KTIME_SCALAR
 /**
  * ktime_add_ns - Add a scalar nanoseconds value to a ktime_t variable
- *
  * @kt:                addend
  * @nsec:      the scalar nsec value to add
  *
@@ -299,7 +297,6 @@ void unlock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags)
 
 /**
  * hrtimer_forward - forward the timer expiry
- *
  * @timer:     hrtimer to forward
  * @now:       forward past this time
  * @interval:  the interval to forward
@@ -411,7 +408,6 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_base *base)
 
 /**
  * hrtimer_start - (re)start an relative timer on the current CPU
- *
  * @timer:     the timer to be added
  * @tim:       expiry time
  * @mode:      expiry mode: absolute (HRTIMER_ABS) or relative (HRTIMER_REL)
@@ -460,14 +456,13 @@ EXPORT_SYMBOL_GPL(hrtimer_start);
 
 /**
  * hrtimer_try_to_cancel - try to deactivate a timer
- *
  * @timer:     hrtimer to stop
  *
  * Returns:
  *  0 when the timer was not active
  *  1 when the timer was active
  * -1 when the timer is currently excuting the callback function and
- *    can not be stopped
+ *    cannot be stopped
  */
 int hrtimer_try_to_cancel(struct hrtimer *timer)
 {
@@ -489,7 +484,6 @@ EXPORT_SYMBOL_GPL(hrtimer_try_to_cancel);
 
 /**
  * hrtimer_cancel - cancel a timer and wait for the handler to finish.
- *
  * @timer:     the timer to be cancelled
  *
  * Returns:
@@ -510,7 +504,6 @@ EXPORT_SYMBOL_GPL(hrtimer_cancel);
 
 /**
  * hrtimer_get_remaining - get remaining time for the timer
- *
  * @timer:     the timer to read
  */
 ktime_t hrtimer_get_remaining(const struct hrtimer *timer)
@@ -564,7 +557,6 @@ ktime_t hrtimer_get_next_event(void)
 
 /**
  * hrtimer_init - initialize a timer to the given clock
- *
  * @timer:     the timer to be initialized
  * @clock_id:  the clock to be used
  * @mode:      timer mode abs/rel
@@ -576,7 +568,7 @@ void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
 
        memset(timer, 0, sizeof(struct hrtimer));
 
-       bases = per_cpu(hrtimer_bases, raw_smp_processor_id());
+       bases = __raw_get_cpu_var(hrtimer_bases);
 
        if (clock_id == CLOCK_REALTIME && mode != HRTIMER_ABS)
                clock_id = CLOCK_MONOTONIC;
@@ -588,7 +580,6 @@ EXPORT_SYMBOL_GPL(hrtimer_init);
 
 /**
  * hrtimer_get_res - get the timer resolution for a clock
- *
  * @which_clock: which clock to query
  * @tp:                 pointer to timespec variable to store the resolution
  *
@@ -599,7 +590,7 @@ int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp)
 {
        struct hrtimer_base *bases;
 
-       bases = per_cpu(hrtimer_bases, raw_smp_processor_id());
+       bases = __raw_get_cpu_var(hrtimer_bases);
        *tp = ktime_to_timespec(bases[which_clock].resolution);
 
        return 0;
index c5f3c6613b6d77dd21d6a0bfcedfbe44d624f802..24be714b04c775bb23fd47baaec588ca92e8c6ba 100644 (file)
@@ -45,6 +45,13 @@ struct kthread_stop_info
 static DEFINE_MUTEX(kthread_stop_lock);
 static struct kthread_stop_info kthread_stop_info;
 
+/**
+ * kthread_should_stop - should this kthread return now?
+ *
+ * When someone calls kthread_stop on your kthread, it will be woken
+ * and this will return true.  You should then return, and your return
+ * value will be passed through to kthread_stop().
+ */
 int kthread_should_stop(void)
 {
        return (kthread_stop_info.k == current);
@@ -122,6 +129,25 @@ static void keventd_create_kthread(void *_create)
        complete(&create->done);
 }
 
+/**
+ * kthread_create - create a kthread.
+ * @threadfn: the function to run until signal_pending(current).
+ * @data: data ptr for @threadfn.
+ * @namefmt: printf-style name for the thread.
+ *
+ * Description: This helper function creates and names a kernel
+ * thread.  The thread will be stopped: use wake_up_process() to start
+ * it.  See also kthread_run(), kthread_create_on_cpu().
+ *
+ * When woken, the thread will run @threadfn() with @data as its
+ * argument. @threadfn can either call do_exit() directly if it is a
+ * standalone thread for which noone will call kthread_stop(), or
+ * return when 'kthread_should_stop()' is true (which means
+ * kthread_stop() has been called).  The return value should be zero
+ * or a negative error number; it will be passed to kthread_stop().
+ *
+ * Returns a task_struct or ERR_PTR(-ENOMEM).
+ */
 struct task_struct *kthread_create(int (*threadfn)(void *data),
                                   void *data,
                                   const char namefmt[],
@@ -156,6 +182,15 @@ struct task_struct *kthread_create(int (*threadfn)(void *data),
 }
 EXPORT_SYMBOL(kthread_create);
 
+/**
+ * kthread_bind - bind a just-created kthread to a cpu.
+ * @k: thread created by kthread_create().
+ * @cpu: cpu (might not be online, must be possible) for @k to run on.
+ *
+ * Description: This function is equivalent to set_cpus_allowed(),
+ * except that @cpu doesn't need to be online, and the thread must be
+ * stopped (i.e., just returned from kthread_create().
+ */
 void kthread_bind(struct task_struct *k, unsigned int cpu)
 {
        BUG_ON(k->state != TASK_INTERRUPTIBLE);
@@ -166,12 +201,36 @@ void kthread_bind(struct task_struct *k, unsigned int cpu)
 }
 EXPORT_SYMBOL(kthread_bind);
 
+/**
+ * kthread_stop - stop a thread created by kthread_create().
+ * @k: thread created by kthread_create().
+ *
+ * Sets kthread_should_stop() for @k to return true, wakes it, and
+ * waits for it to exit.  Your threadfn() must not call do_exit()
+ * itself if you use this function!  This can also be called after
+ * kthread_create() instead of calling wake_up_process(): the thread
+ * will exit without calling threadfn().
+ *
+ * Returns the result of threadfn(), or %-EINTR if wake_up_process()
+ * was never called.
+ */
 int kthread_stop(struct task_struct *k)
 {
        return kthread_stop_sem(k, NULL);
 }
 EXPORT_SYMBOL(kthread_stop);
 
+/**
+ * kthread_stop_sem - stop a thread created by kthread_create().
+ * @k: thread created by kthread_create().
+ * @s: semaphore that @k waits on while idle.
+ *
+ * Does essentially the same thing as kthread_stop() above, but wakes
+ * @k by calling up(@s).
+ *
+ * Returns the result of threadfn(), or %-EINTR if wake_up_process()
+ * was never called.
+ */
 int kthread_stop_sem(struct task_struct *k, struct semaphore *s)
 {
        int ret;
@@ -210,5 +269,5 @@ static __init int helper_init(void)
 
        return 0;
 }
-core_initcall(helper_init);
 
+core_initcall(helper_init);
index bbe04862e1b09113dd12dd49749f551cd9fbeecf..d75275de1c28dee01633b126185784f3561eb46f 100644 (file)
@@ -1326,7 +1326,7 @@ int is_exported(const char *name, const struct module *mod)
        if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab))
                return 1;
        else
-               if (lookup_symbol(name, mod->syms, mod->syms + mod->num_syms))
+               if (mod && lookup_symbol(name, mod->syms, mod->syms + mod->num_syms))
                        return 1;
                else
                        return 0;
index cdf315e794fff7ea7a3e68a548e8f7ade471c993..fc311a4673a25e451e94c1eef38c00bc425acf5a 100644 (file)
@@ -38,7 +38,7 @@ config PM_DEBUG
 
 config PM_TRACE
        bool "Suspend/resume event tracing"
-       depends on PM && PM_DEBUG && X86
+       depends on PM && PM_DEBUG && X86_32
        default y
        ---help---
        This enables some cheesy code to save the last PM event point in the
index 81d4d982f3f097f55f02f427381f8871cac6f8cf..e13e740678456c6e20e97af70724fdebe2106dcd 100644 (file)
@@ -231,7 +231,7 @@ static int software_resume(void)
 late_initcall(software_resume);
 
 
-static char * pm_disk_modes[] = {
+static const char * const pm_disk_modes[] = {
        [PM_DISK_FIRMWARE]      = "firmware",
        [PM_DISK_PLATFORM]      = "platform",
        [PM_DISK_SHUTDOWN]      = "shutdown",
index cdf0f07af92f91dc58b1a441dcb66ff035b77db4..6d295c77679414f0e2c66a6a0ba3db643dc7d659 100644 (file)
@@ -145,7 +145,7 @@ static void suspend_finish(suspend_state_t state)
 
 
 
-static char *pm_states[PM_SUSPEND_MAX] = {
+static const char * const pm_states[PM_SUSPEND_MAX] = {
        [PM_SUSPEND_STANDBY]    = "standby",
        [PM_SUSPEND_MEM]        = "mem",
 #ifdef CONFIG_SOFTWARE_SUSPEND
@@ -262,7 +262,7 @@ static ssize_t state_show(struct subsystem * subsys, char * buf)
 static ssize_t state_store(struct subsystem * subsys, const char * buf, size_t n)
 {
        suspend_state_t state = PM_SUSPEND_STANDBY;
-       char ** s;
+       const char * const *s;
        char *p;
        int error;
        int len;
index 19a95561929478ffc99ac1552cf3ab645ec16bc1..95b7fe17f124c259a54d0227ac1d0a08ddb62800 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/console.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/interrupt.h>                   /* For in_interrupt() */
 #include <linux/config.h>
 #include <linux/delay.h>
@@ -327,7 +328,9 @@ static void __call_console_drivers(unsigned long start, unsigned long end)
        struct console *con;
 
        for (con = console_drivers; con; con = con->next) {
-               if ((con->flags & CON_ENABLED) && con->write)
+               if ((con->flags & CON_ENABLED) && con->write &&
+                               (cpu_online(smp_processor_id()) ||
+                               (con->flags & CON_ANYTIME)))
                        con->write(con, &LOG_BUF(start), end - start);
        }
 }
@@ -437,6 +440,7 @@ static int printk_time = 1;
 #else
 static int printk_time = 0;
 #endif
+module_param(printk_time, int, S_IRUGO | S_IWUSR);
 
 static int __init printk_time_setup(char *str)
 {
@@ -453,6 +457,18 @@ __attribute__((weak)) unsigned long long printk_clock(void)
        return sched_clock();
 }
 
+/* Check if we have any console registered that can be called early in boot. */
+static int have_callable_console(void)
+{
+       struct console *con;
+
+       for (con = console_drivers; con; con = con->next)
+               if (con->flags & CON_ANYTIME)
+                       return 1;
+
+       return 0;
+}
+
 /**
  * printk - print a kernel message
  * @fmt: format string
@@ -566,27 +582,29 @@ asmlinkage int vprintk(const char *fmt, va_list args)
                        log_level_unknown = 1;
        }
 
-       if (!cpu_online(smp_processor_id())) {
+       if (!down_trylock(&console_sem)) {
                /*
-                * Some console drivers may assume that per-cpu resources have
-                * been allocated.  So don't allow them to be called by this
-                * CPU until it is officially up.  We shouldn't be calling into
-                * random console drivers on a CPU which doesn't exist yet..
+                * We own the drivers.  We can drop the spinlock and
+                * let release_console_sem() print the text, maybe ...
                 */
+               console_locked = 1;
                printk_cpu = UINT_MAX;
                spin_unlock_irqrestore(&logbuf_lock, flags);
-               goto out;
-       }
-       if (!down_trylock(&console_sem)) {
-               console_locked = 1;
+
                /*
-                * We own the drivers.  We can drop the spinlock and let
-                * release_console_sem() print the text
+                * Console drivers may assume that per-cpu resources have
+                * been allocated. So unless they're explicitly marked as
+                * being able to cope (CON_ANYTIME) don't call them until
+                * this CPU is officially up.
                 */
-               printk_cpu = UINT_MAX;
-               spin_unlock_irqrestore(&logbuf_lock, flags);
-               console_may_schedule = 0;
-               release_console_sem();
+               if (cpu_online(smp_processor_id()) || have_callable_console()) {
+                       console_may_schedule = 0;
+                       release_console_sem();
+               } else {
+                       /* Release by hand to avoid flushing the buffer. */
+                       console_locked = 0;
+                       up(&console_sem);
+               }
        } else {
                /*
                 * Someone else owns the drivers.  We drop the spinlock, which
@@ -596,7 +614,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
                printk_cpu = UINT_MAX;
                spin_unlock_irqrestore(&logbuf_lock, flags);
        }
-out:
+
        preempt_enable();
        return printed_len;
 }
index 5dbc426944779a33eaf30e2cc476906c4b39983a..f06d059edef5e551746c4f67a79d28970a9726ff 100644 (file)
@@ -4152,7 +4152,7 @@ EXPORT_SYMBOL(yield);
  */
 void __sched io_schedule(void)
 {
-       struct runqueue *rq = &per_cpu(runqueues, raw_smp_processor_id());
+       struct runqueue *rq = &__raw_get_cpu_var(runqueues);
 
        atomic_inc(&rq->nr_iowait);
        schedule();
@@ -4163,7 +4163,7 @@ EXPORT_SYMBOL(io_schedule);
 
 long __sched io_schedule_timeout(long timeout)
 {
-       struct runqueue *rq = &per_cpu(runqueues, raw_smp_processor_id());
+       struct runqueue *rq = &__raw_get_cpu_var(runqueues);
        long ret;
 
        atomic_inc(&rq->nr_iowait);
@@ -4756,6 +4756,8 @@ static int migration_call(struct notifier_block *nfb, unsigned long action,
                break;
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_UP_CANCELED:
+               if (!cpu_rq(cpu)->migration_thread)
+                       break;
                /* Unbind it from offline cpu so it can run.  Fall thru. */
                kthread_bind(cpu_rq(cpu)->migration_thread,
                             any_online_cpu(cpu_online_map));
index 336f92d64e2ec04bb56d7146a4fc1e1eeb1141f5..9e2f1c6e73d7b341958c74baa8af54169c88c119 100644 (file)
@@ -470,6 +470,8 @@ static int cpu_callback(struct notifier_block *nfb,
                break;
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_UP_CANCELED:
+               if (!per_cpu(ksoftirqd, hotcpu))
+                       break;
                /* Unbind so it can run.  Fall thru. */
                kthread_bind(per_cpu(ksoftirqd, hotcpu),
                             any_online_cpu(cpu_online_map));
index 14c7faf02909e8e4879a057406416a43a34b3fdf..b5c3b94e01ce7408a9f3d0dae310cff0a6939a36 100644 (file)
@@ -36,7 +36,7 @@ static struct notifier_block panic_block = {
 
 void touch_softlockup_watchdog(void)
 {
-       per_cpu(touch_timestamp, raw_smp_processor_id()) = jiffies;
+       __raw_get_cpu_var(touch_timestamp) = jiffies;
 }
 EXPORT_SYMBOL(touch_softlockup_watchdog);
 
@@ -127,6 +127,8 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
                break;
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_UP_CANCELED:
+               if (!per_cpu(watchdog_task, hotcpu))
+                       break;
                /* Unbind so it can run.  Fall thru. */
                kthread_bind(per_cpu(watchdog_task, hotcpu),
                             any_online_cpu(cpu_online_map));
index dcfb5d731466257f7f003ba5eb84083f0185d22c..2c0aacc37c5513b0a3898f49e937683501f66ae2 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/cpu.h>
 #include <linux/err.h>
 #include <linux/syscalls.h>
+#include <linux/kthread.h>
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
@@ -25,13 +26,11 @@ static unsigned int stopmachine_num_threads;
 static atomic_t stopmachine_thread_ack;
 static DECLARE_MUTEX(stopmachine_mutex);
 
-static int stopmachine(void *cpu)
+static int stopmachine(void *unused)
 {
        int irqs_disabled = 0;
        int prepared = 0;
 
-       set_cpus_allowed(current, cpumask_of_cpu((int)(long)cpu));
-
        /* Ack: we are alive */
        smp_mb(); /* Theoretically the ack = 0 might not be on this CPU yet. */
        atomic_inc(&stopmachine_thread_ack);
@@ -85,7 +84,8 @@ static void stopmachine_set_state(enum stopmachine_state state)
 
 static int stop_machine(void)
 {
-       int i, ret = 0;
+       int ret = 0;
+       unsigned int i;
        struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
 
        /* One high-prio thread per cpu.  We'll do this one. */
@@ -96,11 +96,16 @@ static int stop_machine(void)
        stopmachine_state = STOPMACHINE_WAIT;
 
        for_each_online_cpu(i) {
+               struct task_struct *tsk;
                if (i == raw_smp_processor_id())
                        continue;
-               ret = kernel_thread(stopmachine, (void *)(long)i,CLONE_KERNEL);
-               if (ret < 0)
+               tsk = kthread_create(stopmachine, NULL, "stopmachine");
+               if (IS_ERR(tsk)) {
+                       ret = PTR_ERR(tsk);
                        break;
+               }
+               kthread_bind(tsk, i);
+               wake_up_process(tsk);
                stopmachine_num_threads++;
        }
 
index 90930b28d2ca1ae77f643aaf44242d3f018f2e2f..2d5179c67cec727f40476e2f9e75fbb9eeeb8d8c 100644 (file)
@@ -137,14 +137,15 @@ static int __kprobes notifier_call_chain(struct notifier_block **nl,
                unsigned long val, void *v)
 {
        int ret = NOTIFY_DONE;
-       struct notifier_block *nb;
+       struct notifier_block *nb, *next_nb;
 
        nb = rcu_dereference(*nl);
        while (nb) {
+               next_nb = rcu_dereference(nb->next);
                ret = nb->notifier_call(nb, val, v);
                if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
                        break;
-               nb = rcu_dereference(nb->next);
+               nb = next_nb;
        }
        return ret;
 }
@@ -588,7 +589,7 @@ void emergency_restart(void)
 }
 EXPORT_SYMBOL_GPL(emergency_restart);
 
-void kernel_restart_prepare(char *cmd)
+static void kernel_restart_prepare(char *cmd)
 {
        blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
        system_state = SYSTEM_RESTART;
@@ -622,7 +623,7 @@ EXPORT_SYMBOL_GPL(kernel_restart);
  *     Move into place and start executing a preloaded standalone
  *     executable.  If nothing was preloaded return an error.
  */
-void kernel_kexec(void)
+static void kernel_kexec(void)
 {
 #ifdef CONFIG_KEXEC
        struct kimage *image;
@@ -636,7 +637,6 @@ void kernel_kexec(void)
        machine_kexec(image);
 #endif
 }
-EXPORT_SYMBOL_GPL(kernel_kexec);
 
 void kernel_shutdown_prepare(enum system_states state)
 {
index eb8bd214e7d7b8f682819ffb5e29b75c28c24d3c..2c0e6581944804eee1391161224afd89972b34e1 100644 (file)
@@ -143,7 +143,6 @@ static struct ctl_table_header root_table_header =
 
 static ctl_table kern_table[];
 static ctl_table vm_table[];
-static ctl_table proc_table[];
 static ctl_table fs_table[];
 static ctl_table debug_table[];
 static ctl_table dev_table[];
@@ -202,12 +201,6 @@ static ctl_table root_table[] = {
                .child          = net_table,
        },
 #endif
-       {
-               .ctl_name       = CTL_PROC,
-               .procname       = "proc",
-               .mode           = 0555,
-               .child          = proc_table,
-       },
        {
                .ctl_name       = CTL_FS,
                .procname       = "fs",
@@ -927,10 +920,6 @@ static ctl_table vm_table[] = {
        { .ctl_name = 0 }
 };
 
-static ctl_table proc_table[] = {
-       { .ctl_name = 0 }
-};
-
 static ctl_table fs_table[] = {
        {
                .ctl_name       = FS_NRINODE,
index f35b3939e9372c5139f0588a9f728b681d225d17..eb97371b87d8fab6cef055b873a3ca4333c8656c 100644 (file)
@@ -146,7 +146,7 @@ static void internal_add_timer(tvec_base_t *base, struct timer_list *timer)
 void fastcall init_timer(struct timer_list *timer)
 {
        timer->entry.next = NULL;
-       timer->base = per_cpu(tvec_bases, raw_smp_processor_id());
+       timer->base = __raw_get_cpu_var(tvec_bases);
 }
 EXPORT_SYMBOL(init_timer);
 
index 740c5abceb07bdf2e1072a816594ada2fcff3e70..565cf7a1febda94b88582c6e9326d782fb29f96c 100644 (file)
@@ -428,22 +428,34 @@ int schedule_delayed_work_on(int cpu,
        return ret;
 }
 
-int schedule_on_each_cpu(void (*func) (void *info), void *info)
+/**
+ * schedule_on_each_cpu - call a function on each online CPU from keventd
+ * @func: the function to call
+ * @info: a pointer to pass to func()
+ *
+ * Returns zero on success.
+ * Returns -ve errno on failure.
+ *
+ * Appears to be racy against CPU hotplug.
+ *
+ * schedule_on_each_cpu() is very slow.
+ */
+int schedule_on_each_cpu(void (*func)(void *info), void *info)
 {
        int cpu;
-       struct work_struct *work;
+       struct work_struct *works;
 
-       work = kmalloc(NR_CPUS * sizeof(struct work_struct), GFP_KERNEL);
-
-       if (!work)
+       works = alloc_percpu(struct work_struct);
+       if (!works)
                return -ENOMEM;
+
        for_each_online_cpu(cpu) {
-               INIT_WORK(work + cpu, func, info);
+               INIT_WORK(per_cpu_ptr(works, cpu), func, info);
                __queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu),
-                               work + cpu);
+                               per_cpu_ptr(works, cpu));
        }
        flush_workqueue(keventd_wq);
-       kfree(work);
+       free_percpu(works);
        return 0;
 }
 
@@ -578,6 +590,8 @@ static int workqueue_cpu_callback(struct notifier_block *nfb,
 
        case CPU_UP_CANCELED:
                list_for_each_entry(wq, &workqueues, list) {
+                       if (!per_cpu_ptr(wq->cpu_wq, hotcpu)->thread)
+                               continue;
                        /* Unbind so it can run. */
                        kthread_bind(per_cpu_ptr(wq->cpu_wq, hotcpu)->thread,
                                     any_online_cpu(cpu_online_map));
index ed2ae3b0cd066244b1ddef1dc3345bbe582247d1..d71e38c54ea50444c5d76c91471c3827c4beaf64 100644 (file)
@@ -317,16 +317,16 @@ EXPORT_SYMBOL(bitmap_scnprintf);
 
 /**
  * bitmap_parse - convert an ASCII hex string into a bitmap.
- * @buf: pointer to buffer in user space containing string.
- * @buflen: buffer size in bytes.  If string is smaller than this
+ * @ubuf: pointer to buffer in user space containing string.
+ * @ubuflen: buffer size in bytes.  If string is smaller than this
  *    then it must be terminated with a \0.
  * @maskp: pointer to bitmap array that will contain result.
  * @nmaskbits: size of bitmap, in bits.
  *
  * Commas group hex digits into chunks.  Each chunk defines exactly 32
  * bits of the resultant bitmask.  No chunk may specify a value larger
- * than 32 bits (-EOVERFLOW), and if a chunk specifies a smaller value
- * then leading 0-bits are prepended.  -EINVAL is returned for illegal
+ * than 32 bits (%-EOVERFLOW), and if a chunk specifies a smaller value
+ * then leading 0-bits are prepended.  %-EINVAL is returned for illegal
  * characters and for grouping errors such as "1,,5", ",44", "," and "".
  * Leading and trailing whitespace accepted, but not embedded whitespace.
  */
@@ -452,8 +452,8 @@ EXPORT_SYMBOL(bitmap_scnlistprintf);
 
 /**
  * bitmap_parselist - convert list format ASCII string to bitmap
- * @buf: read nul-terminated user string from this buffer
- * @mask: write resulting mask here
+ * @bp: read nul-terminated user string from this buffer
+ * @maskp: write resulting mask here
  * @nmaskbits: number of bits in mask to be written
  *
  * Input format is a comma-separated list of decimal numbers and
@@ -461,10 +461,11 @@ EXPORT_SYMBOL(bitmap_scnlistprintf);
  * decimal numbers, the smallest and largest bit numbers set in
  * the range.
  *
- * Returns 0 on success, -errno on invalid input strings:
- *    -EINVAL:   second number in range smaller than first
- *    -EINVAL:   invalid character in string
- *    -ERANGE:   bit number specified too large for mask
+ * Returns 0 on success, -errno on invalid input strings.
+ * Error values:
+ *    %-EINVAL: second number in range smaller than first
+ *    %-EINVAL: invalid character in string
+ *    %-ERANGE: bit number specified too large for mask
  */
 int bitmap_parselist(const char *bp, unsigned long *maskp, int nmaskbits)
 {
@@ -625,10 +626,10 @@ EXPORT_SYMBOL(bitmap_remap);
 
 /**
  * bitmap_bitremap - Apply map defined by a pair of bitmaps to a single bit
- *     @oldbit - bit position to be mapped
- *      @old: defines domain of map
- *      @new: defines range of map
- *      @bits: number of bits in each of these bitmaps
+ *     @oldbit: bit position to be mapped
+ *     @old: defines domain of map
+ *     @new: defines range of map
+ *     @bits: number of bits in each of these bitmaps
  *
  * Let @old and @new define a mapping of bit positions, such that
  * whatever position is held by the n-th set bit in @old is mapped
@@ -790,7 +791,7 @@ EXPORT_SYMBOL(bitmap_release_region);
  *
  * Allocate (set bits in) a specified region of a bitmap.
  *
- * Return 0 on success, or -EBUSY if specified region wasn't
+ * Return 0 on success, or %-EBUSY if specified region wasn't
  * free (not all bits were zero).
  */
 int bitmap_allocate_region(unsigned long *bitmap, int pos, int order)
index 115d149af407216a188c1c42021882e08f33e23c..7f6dd68d2d09e50f012d15a08c2d76ed68bb4395 100644 (file)
@@ -53,9 +53,9 @@ EXPORT_SYMBOL(crc_ccitt_table);
 
 /**
  *     crc_ccitt - recompute the CRC for the data buffer
- *     @crc - previous CRC value
- *     @buffer - data pointer
- *     @len - number of bytes in the buffer
+ *     @crc: previous CRC value
+ *     @buffer: data pointer
+ *     @len: number of bytes in the buffer
  */
 u16 crc_ccitt(u16 crc, u8 const *buffer, size_t len)
 {
index 011fe573c666fa2a970f405c22b9099308372225..8737b084d1f93703ea5e62268ae3f89ebd5c4360 100644 (file)
@@ -47,12 +47,12 @@ u16 const crc16_table[256] = {
 EXPORT_SYMBOL(crc16_table);
 
 /**
- * Compute the CRC-16 for the data buffer
+ * crc16 - compute the CRC-16 for the data buffer
+ * @crc:       previous CRC value
+ * @buffer:    data pointer
+ * @len:       number of bytes in the buffer
  *
- * @param crc     previous CRC value
- * @param buffer  data pointer
- * @param len     number of bytes in the buffer
- * @return        the updated CRC value
+ * Returns the updated CRC value.
  */
 u16 crc16(u16 crc, u8 const *buffer, size_t len)
 {
index 065198f98b3f5fc3aebb16ed8b9b81749ec8f741..285fd9bc61be1b089441663b587f34ff409fb1ba 100644 (file)
@@ -42,20 +42,21 @@ MODULE_AUTHOR("Matt Domsch <Matt_Domsch@dell.com>");
 MODULE_DESCRIPTION("Ethernet CRC32 calculations");
 MODULE_LICENSE("GPL");
 
+/**
+ * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
+ * @crc: seed value for computation.  ~0 for Ethernet, sometimes 0 for
+ *     other uses, or the previous crc32 value if computing incrementally.
+ * @p: pointer to buffer over which CRC is run
+ * @len: length of buffer @p
+ */
+u32 __attribute_pure__ crc32_le(u32 crc, unsigned char const *p, size_t len);
+
 #if CRC_LE_BITS == 1
 /*
  * In fact, the table-based code will work in this case, but it can be
  * simplified by inlining the table in ?: form.
  */
 
-/**
- * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
- * @crc - seed value for computation.  ~0 for Ethernet, sometimes 0 for
- *        other uses, or the previous crc32 value if computing incrementally.
- * @p   - pointer to buffer over which CRC is run
- * @len - length of buffer @p
- * 
- */
 u32 __attribute_pure__ crc32_le(u32 crc, unsigned char const *p, size_t len)
 {
        int i;
@@ -68,14 +69,6 @@ u32 __attribute_pure__ crc32_le(u32 crc, unsigned char const *p, size_t len)
 }
 #else                          /* Table-based approach */
 
-/**
- * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
- * @crc - seed value for computation.  ~0 for Ethernet, sometimes 0 for
- *        other uses, or the previous crc32 value if computing incrementally.
- * @p   - pointer to buffer over which CRC is run
- * @len - length of buffer @p
- * 
- */
 u32 __attribute_pure__ crc32_le(u32 crc, unsigned char const *p, size_t len)
 {
 # if CRC_LE_BITS == 8
@@ -145,20 +138,21 @@ u32 __attribute_pure__ crc32_le(u32 crc, unsigned char const *p, size_t len)
 }
 #endif
 
+/**
+ * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
+ * @crc: seed value for computation.  ~0 for Ethernet, sometimes 0 for
+ *     other uses, or the previous crc32 value if computing incrementally.
+ * @p: pointer to buffer over which CRC is run
+ * @len: length of buffer @p
+ */
+u32 __attribute_pure__ crc32_be(u32 crc, unsigned char const *p, size_t len);
+
 #if CRC_BE_BITS == 1
 /*
  * In fact, the table-based code will work in this case, but it can be
  * simplified by inlining the table in ?: form.
  */
 
-/**
- * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
- * @crc - seed value for computation.  ~0 for Ethernet, sometimes 0 for
- *        other uses, or the previous crc32 value if computing incrementally.
- * @p   - pointer to buffer over which CRC is run
- * @len - length of buffer @p
- * 
- */
 u32 __attribute_pure__ crc32_be(u32 crc, unsigned char const *p, size_t len)
 {
        int i;
@@ -173,14 +167,6 @@ u32 __attribute_pure__ crc32_be(u32 crc, unsigned char const *p, size_t len)
 }
 
 #else                          /* Table-based approach */
-/**
- * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
- * @crc - seed value for computation.  ~0 for Ethernet, sometimes 0 for
- *        other uses, or the previous crc32 value if computing incrementally.
- * @p   - pointer to buffer over which CRC is run
- * @len - length of buffer @p
- * 
- */
 u32 __attribute_pure__ crc32_be(u32 crc, unsigned char const *p, size_t len)
 {
 # if CRC_BE_BITS == 8
@@ -249,6 +235,10 @@ u32 __attribute_pure__ crc32_be(u32 crc, unsigned char const *p, size_t len)
 }
 #endif
 
+/**
+ * bitreverse - reverse the order of bits in a u32 value
+ * @x: value to be bit-reversed
+ */
 u32 bitreverse(u32 x)
 {
        x = (x >> 16) | (x << 16);
index d226259c3c28e5f8406123ff048367aed5d0aa60..de19030a999bada012fc63c2ed53a1b3807eb245 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -48,15 +48,21 @@ static struct idr_layer *alloc_layer(struct idr *idp)
        return(p);
 }
 
+/* only called when idp->lock is held */
+static void __free_layer(struct idr *idp, struct idr_layer *p)
+{
+       p->ary[0] = idp->id_free;
+       idp->id_free = p;
+       idp->id_free_cnt++;
+}
+
 static void free_layer(struct idr *idp, struct idr_layer *p)
 {
        /*
         * Depends on the return element being zeroed.
         */
        spin_lock(&idp->lock);
-       p->ary[0] = idp->id_free;
-       idp->id_free = p;
-       idp->id_free_cnt++;
+       __free_layer(idp, p);
        spin_unlock(&idp->lock);
 }
 
@@ -184,12 +190,14 @@ build_up:
                         * The allocation failed.  If we built part of
                         * the structure tear it down.
                         */
+                       spin_lock(&idp->lock);
                        for (new = p; p && p != idp->top; new = p) {
                                p = p->ary[0];
                                new->ary[0] = NULL;
                                new->bitmap = new->count = 0;
-                               free_layer(idp, new);
+                               __free_layer(idp, new);
                        }
+                       spin_unlock(&idp->lock);
                        return -1;
                }
                new->ary[0] = p;
index 52b6dc144ce3376aa70f59bb6cb50bf34689ac47..60f46803af3f1c82ea6650bf12a40e9f3ac5aefc 100644 (file)
@@ -88,7 +88,7 @@ crc32c_le(u32 crc, unsigned char const *p, size_t len)
  * reflect output bytes = true
  */
 
-static u32 crc32c_table[256] = {
+static const u32 crc32c_table[256] = {
        0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
        0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
        0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
index b32efae7688e316e8825df6fd76a316a2c6f18bf..637d55608de55b463974afeb62eb704977426bbc 100644 (file)
@@ -530,7 +530,7 @@ int radix_tree_tag_get(struct radix_tree_root *root,
                        int ret = tag_get(slot, tag, offset);
 
                        BUG_ON(ret && saw_unset_tag);
-                       return ret;
+                       return !!ret;
                }
                slot = slot->slots[offset];
                shift -= RADIX_TREE_MAP_SHIFT;
index f8ac9fa95de12cde5f786c46aca67ffdb343b0bb..2cc11faa4ff127aa20086acf83d749ec6865f7e3 100644 (file)
@@ -54,7 +54,6 @@ static DEFINE_MUTEX(rslistlock);
 
 /**
  * rs_init - Initialize a Reed-Solomon codec
- *
  * @symsize:   symbol size, bits (1-8)
  * @gfpoly:    Field generator polynomial coefficients
  * @fcr:       first root of RS code generator polynomial, index form
@@ -62,7 +61,7 @@ static DEFINE_MUTEX(rslistlock);
  * @nroots:    RS code generator polynomial degree (number of roots)
  *
  * Allocate a control structure and the polynom arrays for faster
- * en/decoding. Fill the arrays according to the given parameters
+ * en/decoding. Fill the arrays according to the given parameters.
  */
 static struct rs_control *rs_init(int symsize, int gfpoly, int fcr,
                                   int prim, int nroots)
@@ -155,8 +154,7 @@ errrs:
 
 
 /**
- *  free_rs - Free the rs control structure, if its not longer used
- *
+ *  free_rs - Free the rs control structure, if it is no longer used
  *  @rs:       the control structure which is not longer used by the
  *             caller
  */
@@ -176,7 +174,6 @@ void free_rs(struct rs_control *rs)
 
 /**
  * init_rs - Find a matching or allocate a new rs control structure
- *
  *  @symsize:  the symbol size (number of bits)
  *  @gfpoly:   the extended Galois field generator polynomial coefficients,
  *             with the 0th coefficient in the low order bit. The polynomial
@@ -236,7 +233,6 @@ out:
 #ifdef CONFIG_REED_SOLOMON_ENC8
 /**
  *  encode_rs8 - Calculate the parity for data values (8bit data width)
- *
  *  @rs:       the rs control structure
  *  @data:     data field of a given type
  *  @len:      data length
@@ -258,7 +254,6 @@ EXPORT_SYMBOL_GPL(encode_rs8);
 #ifdef CONFIG_REED_SOLOMON_DEC8
 /**
  *  decode_rs8 - Decode codeword (8bit data width)
- *
  *  @rs:       the rs control structure
  *  @data:     data field of a given type
  *  @par:      received parity data field
@@ -285,7 +280,6 @@ EXPORT_SYMBOL_GPL(decode_rs8);
 #ifdef CONFIG_REED_SOLOMON_ENC16
 /**
  *  encode_rs16 - Calculate the parity for data values (16bit data width)
- *
  *  @rs:       the rs control structure
  *  @data:     data field of a given type
  *  @len:      data length
@@ -305,7 +299,6 @@ EXPORT_SYMBOL_GPL(encode_rs16);
 #ifdef CONFIG_REED_SOLOMON_DEC16
 /**
  *  decode_rs16 - Decode codeword (16bit data width)
- *
  *  @rs:       the rs control structure
  *  @data:     data field of a given type
  *  @par:      received parity data field
index b07db5ca3f66febf20041ac5a6606d097dea2a15..797428afd1114f3dc1ad3c239917b9f04ceccd55 100644 (file)
@@ -187,49 +187,49 @@ static char * number(char * buf, char * end, unsigned long long num, int base, i
        size -= precision;
        if (!(type&(ZEROPAD+LEFT))) {
                while(size-->0) {
-                       if (buf <= end)
+                       if (buf < end)
                                *buf = ' ';
                        ++buf;
                }
        }
        if (sign) {
-               if (buf <= end)
+               if (buf < end)
                        *buf = sign;
                ++buf;
        }
        if (type & SPECIAL) {
                if (base==8) {
-                       if (buf <= end)
+                       if (buf < end)
                                *buf = '0';
                        ++buf;
                } else if (base==16) {
-                       if (buf <= end)
+                       if (buf < end)
                                *buf = '0';
                        ++buf;
-                       if (buf <= end)
+                       if (buf < end)
                                *buf = digits[33];
                        ++buf;
                }
        }
        if (!(type & LEFT)) {
                while (size-- > 0) {
-                       if (buf <= end)
+                       if (buf < end)
                                *buf = c;
                        ++buf;
                }
        }
        while (i < precision--) {
-               if (buf <= end)
+               if (buf < end)
                        *buf = '0';
                ++buf;
        }
        while (i-- > 0) {
-               if (buf <= end)
+               if (buf < end)
                        *buf = tmp[i];
                ++buf;
        }
        while (size-- > 0) {
-               if (buf <= end)
+               if (buf < end)
                        *buf = ' ';
                ++buf;
        }
@@ -272,7 +272,8 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
                                /* 'z' changed to 'Z' --davidm 1/25/99 */
                                /* 't' added for ptrdiff_t */
 
-       /* Reject out-of-range values early */
+       /* Reject out-of-range values early.  Large positive sizes are
+          used for unknown buffer sizes. */
        if (unlikely((int) size < 0)) {
                /* There can be only one.. */
                static int warn = 1;
@@ -282,16 +283,17 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
        }
 
        str = buf;
-       end = buf + size - 1;
+       end = buf + size;
 
-       if (end < buf - 1) {
-               end = ((void *) -1);
-               size = end - buf + 1;
+       /* Make sure end is always >= buf */
+       if (end < buf) {
+               end = ((void *)-1);
+               size = end - buf;
        }
 
        for (; *fmt ; ++fmt) {
                if (*fmt != '%') {
-                       if (str <= end)
+                       if (str < end)
                                *str = *fmt;
                        ++str;
                        continue;
@@ -357,17 +359,17 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
                        case 'c':
                                if (!(flags & LEFT)) {
                                        while (--field_width > 0) {
-                                               if (str <= end)
+                                               if (str < end)
                                                        *str = ' ';
                                                ++str;
                                        }
                                }
                                c = (unsigned char) va_arg(args, int);
-                               if (str <= end)
+                               if (str < end)
                                        *str = c;
                                ++str;
                                while (--field_width > 0) {
-                                       if (str <= end)
+                                       if (str < end)
                                                *str = ' ';
                                        ++str;
                                }
@@ -382,18 +384,18 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
 
                                if (!(flags & LEFT)) {
                                        while (len < field_width--) {
-                                               if (str <= end)
+                                               if (str < end)
                                                        *str = ' ';
                                                ++str;
                                        }
                                }
                                for (i = 0; i < len; ++i) {
-                                       if (str <= end)
+                                       if (str < end)
                                                *str = *s;
                                        ++str; ++s;
                                }
                                while (len < field_width--) {
-                                       if (str <= end)
+                                       if (str < end)
                                                *str = ' ';
                                        ++str;
                                }
@@ -426,7 +428,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
                                continue;
 
                        case '%':
-                               if (str <= end)
+                               if (str < end)
                                        *str = '%';
                                ++str;
                                continue;
@@ -449,11 +451,11 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
                                break;
 
                        default:
-                               if (str <= end)
+                               if (str < end)
                                        *str = '%';
                                ++str;
                                if (*fmt) {
-                                       if (str <= end)
+                                       if (str < end)
                                                *str = *fmt;
                                        ++str;
                                } else {
@@ -483,14 +485,13 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
                str = number(str, end, num, base,
                                field_width, precision, flags);
        }
-       if (str <= end)
-               *str = '\0';
-       else if (size > 0)
-               /* don't write out a null byte if the buf size is zero */
-               *end = '\0';
-       /* the trailing null byte doesn't count towards the total
-       * ++str;
-       */
+       if (size > 0) {
+               if (str < end)
+                       *str = '\0';
+               else
+                       *end = '\0';
+       }
+       /* the trailing null byte doesn't count towards the total */
        return str-buf;
 }
 
@@ -848,3 +849,26 @@ int sscanf(const char * buf, const char * fmt, ...)
 }
 
 EXPORT_SYMBOL(sscanf);
+
+
+/* Simplified asprintf. */
+char *kasprintf(gfp_t gfp, const char *fmt, ...)
+{
+       va_list ap;
+       unsigned int len;
+       char *p;
+
+       va_start(ap, fmt);
+       len = vsnprintf(NULL, 0, fmt, ap);
+       va_end(ap);
+
+       p = kmalloc(len+1, gfp);
+       if (!p)
+               return NULL;
+       va_start(ap, fmt);
+       vsnprintf(p, len+1, fmt, ap);
+       va_end(ap);
+       return p;
+}
+
+EXPORT_SYMBOL(kasprintf);
index 807a463fd5ed69b1d39d5268dddf92464c81ed0f..9c7334bafda8da5150f4a9f0a7556bda113b8a19 100644 (file)
@@ -828,6 +828,32 @@ grab_cache_page_nowait(struct address_space *mapping, unsigned long index)
 }
 EXPORT_SYMBOL(grab_cache_page_nowait);
 
+/*
+ * CD/DVDs are error prone. When a medium error occurs, the driver may fail
+ * a _large_ part of the i/o request. Imagine the worst scenario:
+ *
+ *      ---R__________________________________________B__________
+ *         ^ reading here                             ^ bad block(assume 4k)
+ *
+ * read(R) => miss => readahead(R...B) => media error => frustrating retries
+ * => failing the whole request => read(R) => read(R+1) =>
+ * readahead(R+1...B+1) => bang => read(R+2) => read(R+3) =>
+ * readahead(R+3...B+2) => bang => read(R+3) => read(R+4) =>
+ * readahead(R+4...B+3) => bang => read(R+4) => read(R+5) => ......
+ *
+ * It is going insane. Fix it by quickly scaling down the readahead size.
+ */
+static void shrink_readahead_size_eio(struct file *filp,
+                                       struct file_ra_state *ra)
+{
+       if (!ra->ra_pages)
+               return;
+
+       ra->ra_pages /= 4;
+       printk(KERN_WARNING "Reducing readahead size to %luK\n",
+                       ra->ra_pages << (PAGE_CACHE_SHIFT - 10));
+}
+
 /**
  * do_generic_mapping_read - generic file read routine
  * @mapping:   address_space to be read
@@ -985,6 +1011,7 @@ readpage:
                                }
                                unlock_page(page);
                                error = -EIO;
+                               shrink_readahead_size_eio(filp, &ra);
                                goto readpage_error;
                        }
                        unlock_page(page);
@@ -1522,6 +1549,7 @@ page_not_uptodate:
         * Things didn't work out. Return zero to tell the
         * mm layer so, possibly freeing the page cache page first.
         */
+       shrink_readahead_size_eio(file, ra);
        page_cache_release(page);
        return NULL;
 }
@@ -1892,7 +1920,7 @@ int remove_suid(struct dentry *dentry)
 EXPORT_SYMBOL(remove_suid);
 
 size_t
-__filemap_copy_from_user_iovec(char *vaddr, 
+__filemap_copy_from_user_iovec_inatomic(char *vaddr,
                        const struct iovec *iov, size_t base, size_t bytes)
 {
        size_t copied = 0, left = 0;
@@ -1908,12 +1936,8 @@ __filemap_copy_from_user_iovec(char *vaddr,
                vaddr += copy;
                iov++;
 
-               if (unlikely(left)) {
-                       /* zero the rest of the target like __copy_from_user */
-                       if (bytes)
-                               memset(vaddr, 0, bytes);
+               if (unlikely(left))
                        break;
-               }
        }
        return copied - left;
 }
index 5683cde22055f39e86c5bb9f670e615007c24b7c..536979fb4ba717443be39b9e0e8a95dfd012200c 100644 (file)
 #include <linux/uaccess.h>
 
 size_t
-__filemap_copy_from_user_iovec(char *vaddr,
-                              const struct iovec *iov,
-                              size_t base,
-                              size_t bytes);
+__filemap_copy_from_user_iovec_inatomic(char *vaddr,
+                                       const struct iovec *iov,
+                                       size_t base,
+                                       size_t bytes);
 
 /*
  * Copy as much as we can into the page and return the number of bytes which
  * were sucessfully copied.  If a fault is encountered then clear the page
  * out to (offset+bytes) and return the number of bytes which were copied.
+ *
+ * NOTE: For this to work reliably we really want copy_from_user_inatomic_nocache
+ * to *NOT* zero any tail of the buffer that it failed to copy.  If it does,
+ * and if the following non-atomic copy succeeds, then there is a small window
+ * where the target page contains neither the data before the write, nor the
+ * data after the write (it contains zero).  A read at this time will see
+ * data that is inconsistent with any ordering of the read and the write.
+ * (This has been detected in practice).
  */
 static inline size_t
 filemap_copy_from_user(struct page *page, unsigned long offset,
@@ -60,13 +68,15 @@ filemap_copy_from_user_iovec(struct page *page, unsigned long offset,
        size_t copied;
 
        kaddr = kmap_atomic(page, KM_USER0);
-       copied = __filemap_copy_from_user_iovec(kaddr + offset, iov,
-                                               base, bytes);
+       copied = __filemap_copy_from_user_iovec_inatomic(kaddr + offset, iov,
+                                                        base, bytes);
        kunmap_atomic(kaddr, KM_USER0);
        if (copied != bytes) {
                kaddr = kmap(page);
-               copied = __filemap_copy_from_user_iovec(kaddr + offset, iov,
-                                                       base, bytes);
+               copied = __filemap_copy_from_user_iovec_inatomic(kaddr + offset, iov,
+                                                                base, bytes);
+               if (bytes - copied)
+                       memset(kaddr + offset + copied, 0, bytes - copied);
                kunmap(page);
        }
        return copied;
index ec4a1a950df9eb60b71f2c12582ac3cde9d23fb9..73e0f23b7f51e0b65d06c2e5033964eb4c41ef44 100644 (file)
@@ -632,6 +632,10 @@ int do_migrate_pages(struct mm_struct *mm,
 
        down_read(&mm->mmap_sem);
 
+       err = migrate_vmas(mm, from_nodes, to_nodes, flags);
+       if (err)
+               goto out;
+
 /*
  * Find a 'source' bit set in 'tmp' whose corresponding 'dest'
  * bit in 'to' is not also set in 'tmp'.  Clear the found 'source'
@@ -691,7 +695,7 @@ int do_migrate_pages(struct mm_struct *mm,
                if (err < 0)
                        break;
        }
-
+out:
        up_read(&mm->mmap_sem);
        if (err < 0)
                return err;
index 1c2a71aa05cd425a2863a1abc20f1ea6f7636085..3f1e0c2c942c90d59c565e92ee119479861f7c47 100644 (file)
@@ -616,15 +616,13 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
        /*
         * Establish migration ptes or remove ptes
         */
-       if (try_to_unmap(page, 1) != SWAP_FAIL) {
-               if (!page_mapped(page))
-                       rc = move_to_new_page(newpage, page);
-       } else
-               /* A vma has VM_LOCKED set -> permanent failure */
-               rc = -EPERM;
+       try_to_unmap(page, 1);
+       if (!page_mapped(page))
+               rc = move_to_new_page(newpage, page);
 
        if (rc)
                remove_migration_ptes(page, page);
+
 unlock:
        unlock_page(page);
 
@@ -976,3 +974,23 @@ out2:
 }
 #endif
 
+/*
+ * Call migration functions in the vma_ops that may prepare
+ * memory in a vm for migration. migration functions may perform
+ * the migration for vmas that do not have an underlying page struct.
+ */
+int migrate_vmas(struct mm_struct *mm, const nodemask_t *to,
+       const nodemask_t *from, unsigned long flags)
+{
+       struct vm_area_struct *vma;
+       int err = 0;
+
+       for(vma = mm->mmap; vma->vm_next && !err; vma = vma->vm_next) {
+               if (vma->vm_ops && vma->vm_ops->migrate) {
+                       err = vma->vm_ops->migrate(vma, to, from, flags);
+                       if (err)
+                               break;
+               }
+       }
+       return err;
+}
index 423db0db7c02697089960e4894b94a398172d82d..6c1174fcf52c9fd3fbac567ad19f6c42242ba849 100644 (file)
@@ -957,8 +957,7 @@ restart:
                goto got_pg;
 
        do {
-               if (cpuset_zone_allowed(*z, gfp_mask|__GFP_HARDWALL))
-                       wakeup_kswapd(*z, order);
+               wakeup_kswapd(*z, order);
        } while (*(++z));
 
        /*
index df7e50b8f70c1350a404d446a62e0845b6235bf1..b02102feeb4be03d346583f2c81c8e7aba4e3ed8 100644 (file)
@@ -104,21 +104,20 @@ static int __pdflush(struct pdflush_work *my_work)
                list_move(&my_work->list, &pdflush_list);
                my_work->when_i_went_to_sleep = jiffies;
                spin_unlock_irq(&pdflush_lock);
-
                schedule();
-               if (try_to_freeze()) {
-                       spin_lock_irq(&pdflush_lock);
-                       continue;
-               }
-
+               try_to_freeze();
                spin_lock_irq(&pdflush_lock);
                if (!list_empty(&my_work->list)) {
-                       printk("pdflush: bogus wakeup!\n");
+                       /*
+                        * Someone woke us up, but without removing our control
+                        * structure from the global list.  swsusp will do this
+                        * in try_to_freeze()->refrigerator().  Handle it.
+                        */
                        my_work->fn = NULL;
                        continue;
                }
                if (my_work->fn == NULL) {
-                       printk("pdflush: NULL work function\n");
+                       printk("pdflush: bogus wakeup\n");
                        continue;
                }
                spin_unlock_irq(&pdflush_lock);
index 0f142a40984b1674228e067f491159d42b13f32d..e39e416860d7892227368669dc26b60c577b48d4 100644 (file)
@@ -118,8 +118,7 @@ static inline unsigned long get_next_ra_size(struct file_ra_state *ra)
 #define list_to_page(head) (list_entry((head)->prev, struct page, lru))
 
 /**
- * read_cache_pages - populate an address space with some pages, and
- *                     start reads against them.
+ * read_cache_pages - populate an address space with some pages & start reads against them
  * @mapping: the address_space
  * @pages: The address of a list_head which contains the target pages.  These
  *   pages have their ->index populated and are otherwise uninitialised.
@@ -182,14 +181,11 @@ static int read_pages(struct address_space *mapping, struct file *filp,
                list_del(&page->lru);
                if (!add_to_page_cache(page, mapping,
                                        page->index, GFP_KERNEL)) {
-                       ret = mapping->a_ops->readpage(filp, page);
-                       if (ret != AOP_TRUNCATED_PAGE) {
-                               if (!pagevec_add(&lru_pvec, page))
-                                       __pagevec_lru_add(&lru_pvec);
-                               continue;
-                       } /* else fall through to release */
-               }
-               page_cache_release(page);
+                       mapping->a_ops->readpage(filp, page);
+                       if (!pagevec_add(&lru_pvec, page))
+                               __pagevec_lru_add(&lru_pvec);
+               } else
+                       page_cache_release(page);
        }
        pagevec_lru_add(&lru_pvec);
        ret = 0;
index 882a85826bb2d2c6cf5ef61ee7d3fb982b125e9b..e76909e880ca8c2847b3b405f03ed56b453a4a44 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -562,9 +562,8 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
         * If it's recently referenced (perhaps page_referenced
         * skipped over this mm) then we should reactivate it.
         */
-       if ((vma->vm_flags & VM_LOCKED) ||
-                       (ptep_clear_flush_young(vma, address, pte)
-                               && !migration)) {
+       if (!migration && ((vma->vm_flags & VM_LOCKED) ||
+                       (ptep_clear_flush_young(vma, address, pte)))) {
                ret = SWAP_FAIL;
                goto out_unmap;
        }
@@ -771,7 +770,7 @@ static int try_to_unmap_file(struct page *page, int migration)
 
        list_for_each_entry(vma, &mapping->i_mmap_nonlinear,
                                                shared.vm_set.list) {
-               if (vma->vm_flags & VM_LOCKED)
+               if ((vma->vm_flags & VM_LOCKED) && !migration)
                        continue;
                cursor = (unsigned long) vma->vm_private_data;
                if (cursor > max_nl_cursor)
@@ -805,7 +804,7 @@ static int try_to_unmap_file(struct page *page, int migration)
        do {
                list_for_each_entry(vma, &mapping->i_mmap_nonlinear,
                                                shared.vm_set.list) {
-                       if (vma->vm_flags & VM_LOCKED)
+                       if ((vma->vm_flags & VM_LOCKED) && !migration)
                                continue;
                        cursor = (unsigned long) vma->vm_private_data;
                        while ( cursor < max_nl_cursor &&
index cee3397ec27765dcdeab77890847ac59b2cb2434..706c0025ec5e43768c7c9dadfb30e3782c275d67 100644 (file)
@@ -1761,7 +1761,7 @@ translate_compat_table(const char *name,
                goto free_newinfo;
 
        /* And one copy for every other CPU */
-       for_each_cpu(i)
+       for_each_possible_cpu(i)
                if (newinfo->entries[i] && newinfo->entries[i] != entry1)
                        memcpy(newinfo->entries[i], entry1, newinfo->size);
 
index cc9423de7311fcac8845b38a055b6ea008b22ec7..60b11aece5c3971a321411b9247723b367ea4538 100644 (file)
@@ -244,7 +244,7 @@ static unsigned int         rt_hash_rnd;
 
 static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat);
 #define RT_CACHE_STAT_INC(field) \
-       (per_cpu(rt_cache_stat, raw_smp_processor_id()).field++)
+       (__raw_get_cpu_var(rt_cache_stat).field++)
 
 static int rt_intern_hash(unsigned hash, struct rtable *rth,
                                struct rtable **res);
index 75f21d843c1d5f814176bf6d33a37313146ad529..ce59fc2d8de496ee6c12e4032949136a27ee3b62 100755 (executable)
@@ -18,7 +18,8 @@ def getsizes(file):
     for l in os.popen("nm --size-sort " + file).readlines():
         size, type, name = l[:-1].split()
         if type in "tTdDbB":
-            sym[name] = int(size, 16)
+            if "." in name: name = "static." + name.split(".")[0]
+            sym[name] = sym.get(name, 0) + int(size, 16)
     return sym
 
 old = getsizes(sys.argv[1])
index dadfa20ffec0106ecea591e607a4ca3f722f3e27..b34924663ac1f749d385efe70d09e226aff6bf45 100755 (executable)
@@ -89,11 +89,21 @@ sub bysize($) {
 #
 my $funcre = qr/^$x* <(.*)>:$/;
 my $func;
+my $file, $lastslash;
+
 while (my $line = <STDIN>) {
        if ($line =~ m/$funcre/) {
                $func = $1;
        }
-       if ($line =~ m/$re/) {
+       elsif ($line =~ m/(.*):\s*file format/) {
+               $file = $1;
+               $file =~ s/\.ko//;
+               $lastslash = rindex($file, "/");
+               if ($lastslash != -1) {
+                       $file = substr($file, $lastslash + 1);
+               }
+       }
+       elsif ($line =~ m/$re/) {
                my $size = $1;
                $size = hex($size) if ($size =~ /^0x/);
 
@@ -109,7 +119,7 @@ while (my $line = <STDIN>) {
                $addr =~ s/ /0/g;
                $addr = "0x$addr";
 
-               my $intro = "$addr $func:";
+               my $intro = "$addr $func [$file]:";
                my $padlen = 56 - length($intro);
                while ($padlen > 0) {
                        $intro .= '     ';
index 99fe4b7fb2f1733a5b4412553c1734a58b39ec2f..00e21297aefef05c64c415ce19a1ab3979256992 100755 (executable)
@@ -253,6 +253,7 @@ my $lineprefix="";
 # 3 - scanning prototype.
 # 4 - documentation block
 my $state;
+my $in_doc_sect;
 
 #declaration types: can be
 # 'function', 'struct', 'union', 'enum', 'typedef'
@@ -1064,7 +1065,7 @@ sub output_struct_man(%) {
     }
     print "};\n.br\n";
 
-    print ".SH Arguments\n";
+    print ".SH Members\n";
     foreach $parameter (@{$args{'parameterlist'}}) {
        ($parameter =~ /^#/) && next;
 
@@ -1673,6 +1674,9 @@ sub process_state3_type($$) {
 # replace <, >, and &
 sub xml_escape($) {
        my $text = shift;
+       if (($output_mode eq "text") || ($output_mode eq "man")) {
+               return $text;
+       }
        $text =~ s/\&/\\\\\\amp;/g;
        $text =~ s/\</\\\\\\lt;/g;
        $text =~ s/\>/\\\\\\gt;/g;
@@ -1706,6 +1710,7 @@ sub process_file($) {
        if ($state == 0) {
            if (/$doc_start/o) {
                $state = 1;             # next line is always the function name
+               $in_doc_sect = 0;
            }
        } elsif ($state == 1) { # this line is the function name (always)
            if (/$doc_block/o) {
@@ -1756,12 +1761,20 @@ sub process_file($) {
                $newcontents = $2;
 
                if ($contents ne "") {
+                   if (!$in_doc_sect && $verbose) {
+                       print STDERR "Warning(${file}:$.): contents before sections\n";
+                       ++$warnings;
+                   }
                    dump_section($section, xml_escape($contents));
                    $section = $section_default;
                }
 
+               $in_doc_sect = 1;
                $contents = $newcontents;
                if ($contents ne "") {
+                   if (substr($contents, 0, 1) eq " ") {
+                       $contents = substr($contents, 1);
+                   }
                    $contents .= "\n";
                }
                $section = $newsection;
@@ -1776,7 +1789,7 @@ sub process_file($) {
                $prototype = "";
                $state = 3;
                $brcount = 0;
-#          print STDERR "end of doc comment, looking for prototype\n";
+#              print STDERR "end of doc comment, looking for prototype\n";
            } elsif (/$doc_content/) {
                # miguel-style comment kludge, look for blank lines after
                # @parameter line to signify start of description
@@ -1793,7 +1806,7 @@ sub process_file($) {
                print STDERR "Warning(${file}:$.): bad line: $_";
                ++$warnings;
            }
-       } elsif ($state == 3) { # scanning for function { (end of prototype)
+       } elsif ($state == 3) { # scanning for function '{' (end of prototype)
            if ($decl_type eq 'function') {
                process_state3_function($_, $file);
            } else {
index 080ab036b67a791c49b8ed3073dc63489cea8637..95754e2f71b8c680173bb5f33773f5eb1a7b2028 100644 (file)
@@ -114,8 +114,9 @@ config SOUND_VRC5477
          with the AC97 codec.
 
 config SOUND_AU1550_AC97
-       tristate "Au1550 AC97 Sound"
-       depends on SOUND_PRIME && SOC_AU1550
+       tristate "Au1550/Au1200 AC97 Sound"
+       select SND_AC97_CODEC
+       depends on SOUND_PRIME && (SOC_AU1550 || SOC_AU1200)
 
 config SOUND_TRIDENT
        tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core"
index 9011abe241abdb5be10596d66ccd39ad43ca9b7e..4cdb86252d6759ecbff54b6a6981ed3fb1eca6c5 100644 (file)
@@ -213,7 +213,8 @@ rdcodec(struct ac97_codec *codec, u8 addr)
        }
        if (i == POLL_COUNT) {
                err("rdcodec: read poll expired!");
-               return 0;
+               data = 0;
+               goto out;
        }
 
        /* wait for command done?
@@ -226,7 +227,8 @@ rdcodec(struct ac97_codec *codec, u8 addr)
        }
        if (i == POLL_COUNT) {
                err("rdcodec: read cmdwait expired!");
-               return 0;
+               data = 0;
+               goto out;
        }
 
        data = au_readl(PSC_AC97CDC) & 0xffff;
@@ -237,6 +239,7 @@ rdcodec(struct ac97_codec *codec, u8 addr)
        au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT);
        au_sync();
 
+ out:
        spin_unlock_irqrestore(&s->lock, flags);
 
        return data;
@@ -1892,6 +1895,8 @@ static /*const */ struct file_operations au1550_audio_fops = {
 
 MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com");
 MODULE_DESCRIPTION("Au1550 AC97 Audio Driver");
+MODULE_LICENSE("GPL");
+
 
 static int __devinit
 au1550_probe(void)
index 25ae8e4a488db955db707f25c4dc876ef94f3d5b..8ac77df86397134c3087e0b87b0eeae1ede96946 100644 (file)
@@ -45,7 +45,7 @@
 #include "../sound_config.h"
 #endif
 
-static DEFINE_SPINLOCK(midi_spinlock __attribute((unused)));
+static DEFINE_SPINLOCK(midi_spinlock);
 
 static void init_midi_hdr(struct midi_hdr *midihdr)
 {
index 5dbfc0f9c3c7bf32abb87475283ea4c4f21c65b9..ba38d6200099f883f3f188d6e9255bf07afa80b6 100644 (file)
@@ -47,7 +47,7 @@
 static multisound_dev_t                *devs[MSND_MAX_DEVS];
 static int                     num_devs;
 
-int __init msnd_register(multisound_dev_t *dev)
+int msnd_register(multisound_dev_t *dev)
 {
        int i;