Merge master.kernel.org:/home/rmk/linux-2.6-arm
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Mon, 26 Feb 2007 21:19:17 +0000 (13:19 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Mon, 26 Feb 2007 21:19:17 +0000 (13:19 -0800)
* master.kernel.org:/home/rmk/linux-2.6-arm:
  [ARM] CLPS7500 doesn't have IO ports
  [ARM] Fix more apm-emulation.h
  [ARM] 4234/1: Introduce get_irqnr_preamble and arch_ret_to_user for ns9xxx.
  [ARM] 4233/1: nand/s3c2410.c: warning fix
  [ARM] 4226/1: initial .data and .bss mappings of XIP kernel should be TEXT_OFFSET
  [ARM] 4224/2: allow XIP kernel to boot again
  [ARM] 4232/1: AT91: Generic GPIO bug
  [ARM] 4231/1: AT91: Merge and typo fixes.
  [ARM] 4229/1: S3C2410: Add MACH_QT2410 to s3c2410_defconfig
  [ARM] 4228/2: S3C24XX: update s3c2410_defconfig for 2.6.21-rc1

601 files changed:
CREDITS
Documentation/filesystems/vfs.txt
Documentation/kdump/kdump.txt
Documentation/kernel-parameters.txt
Documentation/magic-number.txt
Documentation/oops-tracing.txt
Documentation/video4linux/CARDLIST.bttv
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CQcam.txt
Documentation/video4linux/Zoran
Documentation/video4linux/cx2341x/fw-decoder-api.txt
Documentation/video4linux/cx2341x/fw-decoder-regs.txt [new file with mode: 0644]
Documentation/video4linux/cx2341x/fw-dma.txt
Documentation/video4linux/cx2341x/fw-encoder-api.txt
Documentation/video4linux/cx2341x/fw-memory.txt
Documentation/video4linux/et61x251.txt
Documentation/video4linux/sn9c102.txt
Documentation/video4linux/zc0301.txt
MAINTAINERS
Makefile
arch/arm/mach-pxa/generic.c
arch/arm/mach-sa1100/generic.c
arch/i386/Makefile
arch/i386/kernel/apic.c
arch/i386/kernel/cpu/mcheck/p4.c
arch/i386/kernel/io_apic.c
arch/i386/kernel/irq.c
arch/i386/kernel/process.c
arch/i386/kernel/smp.c
arch/ia64/kernel/msi_ia64.c
arch/ia64/sn/kernel/msi_sn.c
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/cobalt/mtd.c
arch/mips/configs/atlas_defconfig
arch/mips/configs/bigsur_defconfig
arch/mips/configs/capcella_defconfig
arch/mips/configs/cobalt_defconfig
arch/mips/configs/db1000_defconfig
arch/mips/configs/db1100_defconfig
arch/mips/configs/db1200_defconfig
arch/mips/configs/db1500_defconfig
arch/mips/configs/db1550_defconfig
arch/mips/configs/ddb5477_defconfig
arch/mips/configs/decstation_defconfig
arch/mips/configs/e55_defconfig
arch/mips/configs/emma2rh_defconfig
arch/mips/configs/ev64120_defconfig
arch/mips/configs/excite_defconfig
arch/mips/configs/ip22_defconfig
arch/mips/configs/ip27_defconfig
arch/mips/configs/ip32_defconfig
arch/mips/configs/jaguar-atx_defconfig
arch/mips/configs/jazz_defconfig
arch/mips/configs/jmr3927_defconfig
arch/mips/configs/lasat200_defconfig
arch/mips/configs/malta_defconfig
arch/mips/configs/mipssim_defconfig
arch/mips/configs/mpc30x_defconfig
arch/mips/configs/ocelot_3_defconfig
arch/mips/configs/ocelot_c_defconfig
arch/mips/configs/ocelot_defconfig
arch/mips/configs/ocelot_g_defconfig
arch/mips/configs/pb1100_defconfig
arch/mips/configs/pb1500_defconfig
arch/mips/configs/pb1550_defconfig
arch/mips/configs/pnx8550-jbs_defconfig
arch/mips/configs/pnx8550-stb810_defconfig
arch/mips/configs/pnx8550-v2pci_defconfig
arch/mips/configs/qemu_defconfig
arch/mips/configs/rbhma4500_defconfig
arch/mips/configs/rm200_defconfig
arch/mips/configs/sb1250-swarm_defconfig
arch/mips/configs/sead_defconfig
arch/mips/configs/tb0226_defconfig
arch/mips/configs/tb0229_defconfig
arch/mips/configs/tb0287_defconfig
arch/mips/configs/workpad_defconfig
arch/mips/configs/wrppmc_defconfig
arch/mips/configs/yosemite_defconfig
arch/mips/defconfig
arch/mips/kernel/asm-offsets.c
arch/mips/kernel/ptrace.c
arch/mips/kernel/signal.c
arch/mips/kernel/smp.c
arch/mips/kernel/traps.c
arch/mips/mm/ioremap.c
arch/mips/momentum/jaguar_atx/platform.c
arch/mips/momentum/ocelot_3/platform.c
arch/mips/momentum/ocelot_c/platform.c
arch/parisc/Kconfig
arch/parisc/Makefile
arch/parisc/hpux/entry_hpux.S
arch/parisc/hpux/fs.c
arch/parisc/hpux/gate.S
arch/parisc/hpux/sys_hpux.c
arch/parisc/hpux/wrappers.S
arch/parisc/kernel/asm-offsets.c
arch/parisc/kernel/cache.c
arch/parisc/kernel/drivers.c
arch/parisc/kernel/entry.S
arch/parisc/kernel/firmware.c
arch/parisc/kernel/head.S
arch/parisc/kernel/hpmc.S
arch/parisc/kernel/inventory.c
arch/parisc/kernel/irq.c
arch/parisc/kernel/module.c
arch/parisc/kernel/pacache.S
arch/parisc/kernel/parisc_ksyms.c
arch/parisc/kernel/pci-dma.c
arch/parisc/kernel/pci.c
arch/parisc/kernel/perf_asm.S
arch/parisc/kernel/process.c
arch/parisc/kernel/processor.c
arch/parisc/kernel/ptrace.c
arch/parisc/kernel/real2.S
arch/parisc/kernel/setup.c
arch/parisc/kernel/signal.c
arch/parisc/kernel/signal32.c
arch/parisc/kernel/smp.c
arch/parisc/kernel/syscall.S
arch/parisc/kernel/syscall_table.S
arch/parisc/kernel/time.c
arch/parisc/kernel/traps.c
arch/parisc/kernel/unaligned.c
arch/parisc/kernel/unwind.c
arch/parisc/kernel/vmlinux.lds.S
arch/parisc/lib/bitops.c
arch/parisc/lib/fixup.S
arch/parisc/lib/lusercopy.S
arch/parisc/lib/memcpy.c
arch/parisc/mm/fault.c
arch/parisc/mm/init.c
arch/parisc/mm/ioremap.c
arch/parisc/mm/kmap.c [deleted file]
arch/parisc/oprofile/init.c
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/defconfig
arch/s390/kernel/early.c
arch/s390/kernel/head31.S
arch/s390/kernel/head64.S
arch/s390/kernel/ipl.c
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
arch/s390/kernel/time.c
arch/s390/lib/delay.c
arch/s390/mm/init.c
arch/sparc64/defconfig
arch/sparc64/kernel/irq.c
arch/sparc64/kernel/pci.c
arch/x86_64/kernel/entry.S
arch/x86_64/kernel/i8259.c
arch/x86_64/kernel/io_apic.c
block/genhd.c
block/ioctl.c
drivers/ata/pata_pcmcia.c
drivers/auxdisplay/cfag12864b.c
drivers/auxdisplay/cfag12864bfb.c
drivers/auxdisplay/ks0108.c
drivers/base/class.c
drivers/base/core.c
drivers/block/floppy.c
drivers/block/pktcdvd.c
drivers/bluetooth/bcm203x.c
drivers/bluetooth/bfusb.c
drivers/bluetooth/bt3c_cs.c
drivers/char/agp/Makefile
drivers/char/agp/agp.h
drivers/char/agp/ali-agp.c
drivers/char/agp/amd-k7-agp.c
drivers/char/agp/amd64-agp.c
drivers/char/agp/ati-agp.c
drivers/char/agp/efficeon-agp.c
drivers/char/agp/generic.c
drivers/char/agp/hp-agp.c
drivers/char/agp/i460-agp.c
drivers/char/agp/intel-agp.c
drivers/char/agp/nvidia-agp.c
drivers/char/agp/parisc-agp.c
drivers/char/agp/sgi-agp.c
drivers/char/agp/sis-agp.c
drivers/char/agp/sworks-agp.c
drivers/char/agp/uninorth-agp.c
drivers/char/agp/via-agp.c
drivers/char/hvc_console.c
drivers/char/ip2/i2lib.c
drivers/char/mwave/3780i.c
drivers/char/tty_io.c
drivers/infiniband/core/cm.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/verbs.c
drivers/infiniband/hw/cxgb3/Makefile
drivers/infiniband/hw/cxgb3/cxio_hal.c
drivers/infiniband/hw/cxgb3/cxio_hal.h
drivers/infiniband/hw/cxgb3/cxio_resource.c
drivers/infiniband/hw/cxgb3/iwch_cm.c
drivers/infiniband/hw/cxgb3/iwch_provider.c
drivers/infiniband/hw/cxgb3/iwch_provider.h
drivers/infiniband/hw/cxgb3/iwch_qp.c
drivers/infiniband/hw/mthca/mthca_mr.c
drivers/infiniband/ulp/ipoib/ipoib.h
drivers/infiniband/ulp/ipoib/ipoib_cm.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/ipoib/ipoib_multicast.c
drivers/isdn/gigaset/Makefile
drivers/isdn/gigaset/asyncdata.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-cobalt.c [new file with mode: 0644]
drivers/leds/leds-h1940.c [new file with mode: 0644]
drivers/media/Kconfig
drivers/media/common/Kconfig
drivers/media/common/ir-functions.c
drivers/media/common/ir-keymaps.c
drivers/media/common/saa7146_fops.c
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
drivers/media/dvb/bt8xx/bt878.c
drivers/media/dvb/bt8xx/dst.c
drivers/media/dvb/bt8xx/dvb-bt8xx.c
drivers/media/dvb/cinergyT2/cinergyT2.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvbdev.c
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/Makefile
drivers/media/dvb/dvb-usb/au6610.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/au6610.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dvb-usb-remote.c
drivers/media/dvb/dvb-usb/gl861.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/gl861.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/m920x.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/m920x.h [new file with mode: 0644]
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/cx24110.c
drivers/media/dvb/frontends/cx24123.c
drivers/media/dvb/frontends/dib3000mc.c
drivers/media/dvb/frontends/qt1010.c [new file with mode: 0644]
drivers/media/dvb/frontends/qt1010.h [new file with mode: 0644]
drivers/media/dvb/frontends/qt1010_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv0297.c
drivers/media/dvb/frontends/stv0299.c
drivers/media/dvb/frontends/tda10021.c
drivers/media/dvb/frontends/tda1004x.c
drivers/media/dvb/frontends/zl10353.c
drivers/media/dvb/frontends/zl10353.h
drivers/media/dvb/frontends/zl10353_priv.h
drivers/media/dvb/ttpci/av7110.c
drivers/media/dvb/ttpci/av7110.h
drivers/media/dvb/ttpci/av7110_av.c
drivers/media/dvb/ttpci/av7110_ca.c
drivers/media/dvb/ttpci/av7110_ir.c
drivers/media/dvb/ttpci/av7110_v4l.c
drivers/media/dvb/ttpci/budget-av.c
drivers/media/dvb/ttpci/budget-ci.c
drivers/media/dvb/ttusb-dec/ttusb_dec.c
drivers/media/radio/radio-aztech.c
drivers/media/radio/radio-gemtek-pci.c
drivers/media/radio/radio-maxiradio.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttv-input.c
drivers/media/video/bt8xx/bttv-risc.c
drivers/media/video/bt8xx/bttv-vbi.c
drivers/media/video/bt8xx/bttv.h
drivers/media/video/bt8xx/bttvp.h
drivers/media/video/cafe_ccic.c
drivers/media/video/cpia.c
drivers/media/video/cx2341x.c
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/cx88/Makefile
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-tvaudio.c
drivers/media/video/cx88/cx88-vbi.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/et61x251/et61x251.h
drivers/media/video/et61x251/et61x251_core.c
drivers/media/video/et61x251/et61x251_sensor.h
drivers/media/video/et61x251/et61x251_tas5130d1b.c
drivers/media/video/pvrusb2/pvrusb2-audio.c
drivers/media/video/pvrusb2/pvrusb2-context.c
drivers/media/video/pvrusb2/pvrusb2-ctrl.c
drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
drivers/media/video/pvrusb2/pvrusb2-debugifc.c
drivers/media/video/pvrusb2/pvrusb2-eeprom.c
drivers/media/video/pvrusb2/pvrusb2-encoder.c
drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-hdw.h
drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
drivers/media/video/pvrusb2/pvrusb2-io.c
drivers/media/video/pvrusb2/pvrusb2-ioread.c
drivers/media/video/pvrusb2/pvrusb2-std.c
drivers/media/video/pvrusb2/pvrusb2-sysfs.c
drivers/media/video/pvrusb2/pvrusb2-tuner.c
drivers/media/video/pvrusb2/pvrusb2-v4l2.c
drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
drivers/media/video/pvrusb2/pvrusb2-wm8775.c
drivers/media/video/pwc/Makefile
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc-v4l.c
drivers/media/video/pwc/pwc.h
drivers/media/video/saa5246a.c
drivers/media/video/saa5246a.h
drivers/media/video/saa5249.c
drivers/media/video/saa7115.c
drivers/media/video/saa7127.c
drivers/media/video/saa7134/Makefile
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-i2c.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/sn9c102/Kconfig
drivers/media/video/sn9c102/Makefile
drivers/media/video/sn9c102/sn9c102.h
drivers/media/video/sn9c102/sn9c102_config.h [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_core.c
drivers/media/video/sn9c102/sn9c102_devtable.h [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_hv7131d.c
drivers/media/video/sn9c102/sn9c102_mi0343.c
drivers/media/video/sn9c102/sn9c102_ov7630.c
drivers/media/video/sn9c102/sn9c102_ov7660.c [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_pas106b.c
drivers/media/video/sn9c102/sn9c102_pas202bca.c [deleted file]
drivers/media/video/sn9c102/sn9c102_pas202bcb.c
drivers/media/video/sn9c102/sn9c102_sensor.h
drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
drivers/media/video/tvmixer.c
drivers/media/video/tvp5150.c
drivers/media/video/upd64031a.c
drivers/media/video/upd64083.c
drivers/media/video/usbvision/Kconfig
drivers/media/video/usbvision/usbvision-core.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/usbvision/usbvision.h
drivers/media/video/v4l1-compat.c
drivers/media/video/v4l2-common.c
drivers/media/video/video-buf.c
drivers/media/video/videodev.c
drivers/media/video/vivi.c
drivers/media/video/zc0301/zc0301.h
drivers/media/video/zc0301/zc0301_core.c
drivers/media/video/zc0301/zc0301_pas202bcb.c
drivers/media/video/zc0301/zc0301_pb0330.c
drivers/media/video/zc0301/zc0301_sensor.h
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/sm501.c [new file with mode: 0644]
drivers/net/Kconfig
drivers/net/e1000/e1000_main.c
drivers/net/lasi_82596.c
drivers/net/tg3.c
drivers/net/tg3.h
drivers/parisc/hppb.c
drivers/parisc/iosapic_private.h
drivers/parisc/lba_pci.c
drivers/parisc/led.c
drivers/parisc/power.c
drivers/parisc/sba_iommu.c
drivers/parport/parport_pc.c
drivers/pcmcia/hd64465_ss.c
drivers/pcmcia/m32r_cfc.c
drivers/pcmcia/m8xx_pcmcia.c
drivers/pcmcia/omap_cf.c
drivers/pcmcia/rsrc_mgr.c
drivers/pcmcia/vrc4171_card.c
drivers/rtc/Kconfig
drivers/rtc/rtc-at91rm9200.c
drivers/rtc/rtc-sa1100.c
drivers/s390/char/sclp_quiesce.c
drivers/s390/cio/cio.c
drivers/sbus/char/Kconfig
drivers/sbus/char/Makefile
drivers/sbus/char/aurora.c [deleted file]
drivers/sbus/char/aurora.h [deleted file]
drivers/sbus/char/bbc_i2c.c
drivers/sbus/char/cd180.h [deleted file]
drivers/sbus/char/uctrl.c
drivers/serial/8250.c
drivers/serial/mux.c
drivers/serial/serial_txx9.c
drivers/spi/atmel_spi.c
drivers/spi/omap_uwire.c
drivers/spi/spi_imx.c
drivers/spi/spi_s3c24xx_gpio.c
drivers/usb/core/Makefile
drivers/usb/core/driver.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/quirks.c [new file with mode: 0644]
drivers/usb/core/sysfs.c
drivers/usb/core/usb.c
drivers/usb/core/usb.h
drivers/usb/gadget/inode.c
drivers/usb/host/uhci-debug.c
drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-hcd.h
drivers/usb/host/uhci-q.c
drivers/usb/input/usbkbd.c
drivers/usb/input/usbmouse.c
drivers/usb/input/wacom_wac.c
drivers/usb/input/wacom_wac.h
drivers/usb/misc/Kconfig
drivers/usb/misc/Makefile
drivers/usb/misc/iowarrior.c [new file with mode: 0644]
drivers/usb/mon/mon_bin.c
drivers/usb/mon/mon_text.c
drivers/usb/mon/usb_mon.h
drivers/usb/net/Kconfig
drivers/usb/net/Makefile
drivers/usb/net/asix.c
drivers/usb/net/dm9601.c [new file with mode: 0644]
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio.h
drivers/usb/serial/option.c
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/i810/i810_main.c
drivers/video/s3fb.c
drivers/video/sm501fb.c [new file with mode: 0644]
fs/affs/affs.h
fs/affs/inode.c
fs/affs/super.c
fs/autofs4/autofs_i.h
fs/autofs4/inode.c
fs/autofs4/root.c
fs/autofs4/waitq.c
fs/block_dev.c
fs/buffer.c
fs/char_dev.c
fs/cifs/cifsfs.c
fs/cifs/cifspdu.h
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/link.c
fs/cifs/readdir.c
fs/ext2/balloc.c
fs/ext3/balloc.c
fs/ext4/balloc.c
fs/fat/inode.c
fs/jfs/jfs_txnmgr.c
fs/libfs.c
fs/proc/base.c
fs/sysfs/file.c
fs/sysfs/sysfs.h
fs/xfs/linux-2.6/xfs_super.c
include/asm-arm/arch-pxa/gpio.h
include/asm-arm/arch-pxa/hardware.h
include/asm-arm/arch-s3c2410/gpio.h
include/asm-arm/arch-sa1100/gpio.h
include/asm-i386/idle.h [deleted file]
include/asm-i386/processor.h
include/asm-mips/ptrace.h
include/asm-mips/sigcontext.h
include/asm-mips/stackframe.h
include/asm-parisc/assembly.h
include/asm-parisc/atomic.h
include/asm-parisc/bitops.h
include/asm-parisc/bug.h
include/asm-parisc/cache.h
include/asm-parisc/cacheflush.h
include/asm-parisc/dma-mapping.h
include/asm-parisc/elf.h
include/asm-parisc/hardware.h
include/asm-parisc/io.h
include/asm-parisc/led.h
include/asm-parisc/linkage.h
include/asm-parisc/mmzone.h
include/asm-parisc/module.h
include/asm-parisc/msgbuf.h
include/asm-parisc/page.h
include/asm-parisc/parisc-device.h
include/asm-parisc/pdc.h
include/asm-parisc/pdcpat.h
include/asm-parisc/pgalloc.h
include/asm-parisc/pgtable.h
include/asm-parisc/posix_types.h
include/asm-parisc/processor.h
include/asm-parisc/sembuf.h
include/asm-parisc/shmbuf.h
include/asm-parisc/signal.h
include/asm-parisc/smp.h
include/asm-parisc/spinlock_types.h
include/asm-parisc/statfs.h
include/asm-parisc/system.h
include/asm-parisc/thread_info.h
include/asm-parisc/tlbflush.h
include/asm-parisc/types.h
include/asm-parisc/uaccess.h
include/asm-parisc/unistd.h
include/asm-s390/atomic.h
include/asm-s390/ipl.h [new file with mode: 0644]
include/asm-s390/local.h
include/asm-s390/processor.h
include/asm-s390/sections.h
include/asm-s390/setup.h
include/asm-x86_64/hw_irq.h
include/linux/auto_fs4.h
include/linux/cdrom.h
include/linux/cfag12864b.h
include/linux/cpumask.h
include/linux/device.h
include/linux/irq.h
include/linux/kdev_t.h
include/linux/kmod.h
include/linux/ks0108.h
include/linux/minix_fs.h
include/linux/mod_devicetable.h
include/linux/nodemask.h
include/linux/pm.h
include/linux/sched.h
include/linux/sm501-regs.h [new file with mode: 0644]
include/linux/sm501.h [new file with mode: 0644]
include/linux/sunrpc/sched.h
include/linux/swapops.h
include/linux/sysfs.h
include/linux/usb.h
include/linux/usb/ch9.h
include/linux/usb/iowarrior.h [new file with mode: 0644]
include/linux/usb/quirks.h [new file with mode: 0644]
include/linux/videodev2.h
include/media/cx2341x.h
include/media/ir-common.h
include/media/saa7115.h
include/media/v4l2-common.h
include/media/v4l2-dev.h
include/media/video-buf.h
include/net/irda/irda.h
init/main.c
ipc/shm.c
kernel/irq/migration.c
kernel/kmod.c
kernel/kprobes.c
kernel/lockdep.c
kernel/module.c
kernel/params.c
kernel/power/main.c
kernel/signal.c
kernel/time/tick-common.c
kernel/time/tick-sched.c
lib/Kconfig.debug
lib/cpumask.c
lib/fault-inject.c
lib/genalloc.c
mm/mempolicy.c
mm/page_alloc.c
mm/slab.c
net/bluetooth/hidp/Kconfig
net/bluetooth/hidp/core.c
net/bluetooth/hidp/hidp.h
net/bluetooth/hidp/sock.c
net/bluetooth/rfcomm/tty.c
net/bridge/br_if.c
net/bridge/br_notify.c
net/bridge/br_private.h
net/bridge/netfilter/ebtables.c
net/ipv4/Kconfig
net/ipv4/devinet.c
net/ipv4/multipath_random.c
net/ipv4/multipath_wrandom.c
net/ipv4/tcp.c
net/ipv4/xfrm4_mode_tunnel.c
net/ipv4/xfrm4_policy.c
net/ipv6/Makefile
net/ipv6/addrconf.c
net/ipv6/addrconf_core.c [new file with mode: 0644]
net/ipv6/af_inet6.c
net/ipv6/ip6_tunnel.c
net/ipv6/ipv6_syms.c
net/ipv6/xfrm6_policy.c
net/irda/irmod.c
net/packet/af_packet.c
net/sctp/outqueue.c
net/sctp/sm_statefuns.c
net/sunrpc/svc.c
scripts/kernel-doc
scripts/mod/file2alias.c
scripts/mod/modpost.c
security/selinux/hooks.c
security/selinux/ss/avtab.c
security/selinux/ss/policydb.c
security/selinux/ss/services.c
security/selinux/ss/sidtab.c
sound/parisc/harmony.c
sound/pci/bt87x.c

diff --git a/CREDITS b/CREDITS
index a4e5599..6bd8ab8 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -2678,7 +2678,7 @@ S: Ottawa, Ontario
 S: Canada K2P 0X8
 
 N: Mikael Pettersson
-E: mikpe@csd.uu.se
+E: mikpe@it.uu.se
 W: http://www.csd.uu.se/~mikpe/
 D: Miscellaneous fixes
 
index 7737bfd..ea271f2 100644 (file)
@@ -617,6 +617,11 @@ struct address_space_operations {
        In this case the prepare_write will be retried one the lock is
        regained.
 
+       Note: the page _must not_ be marked uptodate in this function
+       (or anywhere else) unless it actually is uptodate right now. As
+       soon as a page is marked uptodate, it is possible for a concurrent
+       read(2) to copy it to userspace.
+
   commit_write: If prepare_write succeeds, new data will be copied
         into the page and then commit_write will be called.  It will
         typically update the size of the file (if appropriate) and
index 79775a4..2fedc08 100644 (file)
@@ -30,6 +30,10 @@ 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.
 
+Similarly on PPC64 machines first 32KB of physical memory is needed for
+booting regardless of where the kernel is loaded and to support 64K page
+size kexec backs up the first 64KB memory.
+
 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
@@ -224,7 +228,7 @@ Dump-capture kernel config options (Arch Dependent, x86_64)
 Dump-capture kernel config options (Arch Dependent, ppc64)
 ----------------------------------------------------------
 
--  Make and install the kernel and its modules. DO NOT add this kernel
+*  Make and install the kernel and its modules. DO NOT add this kernel
    to the boot loader configuration files.
 
 Dump-capture kernel config options (Arch Dependent, ia64)
@@ -251,8 +255,8 @@ Dump-capture kernel config options (Arch Dependent, ia64)
 Boot into System Kernel
 =======================
 
-1) Make and install the kernel and its modules. Update the boot loader
-   (such as grub, yaboot, or lilo) configuration files as necessary.
+1) Update the boot loader (such as grub, yaboot, or lilo) configuration
+   files as necessary.
 
 2) Boot the system kernel with the boot parameter "crashkernel=Y@X",
    where Y specifies how much memory to reserve for the dump-capture kernel
@@ -356,10 +360,11 @@ 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 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 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.
+"echo c > /proc/sysrq-trigger" or write a module to force the panic.
 
 Write Out the Dump File
 =======================
@@ -410,12 +415,9 @@ format. Crash is available on Dave Anderson's site at the following URL:
 To Do
 =====
 
-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.
+1) Provide relocatable kernels for all architectures to help in maintaining
+   multiple kernels for crash_dump, and the same kernel as the system kernel
+   can be used to capture the dump.
 
 
 Contact
index c479d30..03eb5ed 100644 (file)
@@ -1758,6 +1758,13 @@ and is between 256 and 4096 characters. It is defined in the file
                        Note that genuine overcurrent events won't be
                        reported either.
 
+       usbcore.autosuspend=
+                       [USB] The autosuspend time delay (in seconds) used
+                       for newly-detected USB devices (default 2).  This
+                       is the time required before an idle device will be
+                       autosuspended.  Devices for which the delay is set
+                       to 0 won't be autosuspended at all.
+
        usbhid.mousepoll=
                        [USBHID] The interval which mice are to be polled at.
 
index af67fac..0e740c8 100644 (file)
@@ -65,7 +65,6 @@ CMAGIC                0x0111      user              include/linux/a.out.h
 MKISS_DRIVER_MAGIC    0x04bf      mkiss_channel     drivers/net/mkiss.h
 RISCOM8_MAGIC         0x0907      riscom_port       drivers/char/riscom8.h
 SPECIALIX_MAGIC       0x0907      specialix_port    drivers/char/specialix_io8.h
-AURORA_MAGIC          0x0A18      Aurora_port       drivers/sbus/char/aurora.h
 HDLC_MAGIC            0x239e      n_hdlc            drivers/char/n_hdlc.c
 APM_BIOS_MAGIC        0x4101      apm_user          arch/i386/kernel/apm.c
 CYCLADES_MAGIC        0x4359      cyclades_port     include/linux/cyclades.h
index 2503404..ea55ea8 100644 (file)
@@ -234,6 +234,12 @@ characters, each representing a particular tainted value.
   6: 'B' if a page-release function has found a bad page reference or
      some unexpected page flags.
 
+  7: 'U' if a user specifically requested that the Tainted flag be set,
+     ' ' otherwise.
+
+  7: 'U' if a user or user application specifically requested that the
+     Tainted flag be set, ' ' otherwise.
+
 The primary reason for the 'Tainted: ' string is to tell kernel
 debuggers if this is a clean kernel or if anything unusual has
 occurred.  Tainting is permanent: even if an offending module is
index 4efa464..fc2fe9b 100644 (file)
 125 -> MATRIX Vision Sigma-SQ
 126 -> MATRIX Vision Sigma-SLC
 127 -> APAC Viewcomp 878(AMAX)
-128 -> DViCO FusionHDTV DVB-T Lite                         [18ac:db10]
+128 -> DViCO FusionHDTV DVB-T Lite                         [18ac:db10,18ac:db11]
 129 -> V-Gear MyVCD
 130 -> Super TV Tuner
 131 -> Tibet Systems 'Progress DVR' CS16
index f6201cc..a12246a 100644 (file)
 103 -> Compro Videomate DVB-T200A
 104 -> Hauppauge WinTV-HVR1110 DVB-T/Hybrid     [0070:6701]
 105 -> Terratec Cinergy HT PCMCIA               [153b:1172]
+106 -> Encore ENLTV                             [1131:2342,1131:2341,3016:2344]
+107 -> Encore ENLTV-FM                          [1131:230f]
+108 -> Terratec Cinergy HT PCI                  [153b:1175]
index ade8651..04986ef 100644 (file)
@@ -197,10 +197,10 @@ Use the ../../Maintainers file, particularly the  VIDEO FOR LINUX and PARALLEL
 PORT SUPPORT sections
 
 The video4linux page:
-  http://roadrunner.swansea.linux.org.uk/v4l.shtml
+  http://linuxtv.org
 
-The video4linux2 page:
-  http://millennium.diads.com/bdirks/v4l2.htm
+The V4L2 API spec:
+  http://v4l2spec.bytesex.org/
 
 Some web pages about the quickcams:
    http://www.dkfz-heidelberg.de/Macromol/wedemann/mini-HOWTO-cqcam.html
index deb218f..85c575a 100644 (file)
@@ -339,9 +339,9 @@ Information - video4linux/mjpeg extensions:
 (also see below)
 
 Information - video4linux2:
-http://www.thedirks.org/v4l2/
+http://linuxtv.org
+http://v4l2spec.bytesex.org/
 /usr/include/linux/videodev2.h
-http://www.bytesex.org/v4l/
 
 More information on the video4linux/mjpeg extensions, by Serguei
 Miridonovi and Rainer Johanni:
index 78bf5f2..8c317b7 100644 (file)
@@ -21,7 +21,7 @@ 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.
+       audio resumes. (This is not implemented in the firmware, leave at 0)
 
 -------------------------------------------------------------------------------
 
@@ -32,6 +32,10 @@ Description
        playback stops at specified PTS.
 Param[0]
        Display 0=last frame, 1=black
+       Note: this takes effect immediately, so if you want to wait for a PTS,
+       then use '0', otherwise the screen goes to black at once.
+       You can call this later (even if there is no playback) with a 1 value
+       to set the screen to black.
 Param[1]
        PTS low
 Param[2]
@@ -60,8 +64,12 @@ Param[0]
            31   Speed:
                     '0' slow
                     '1' fast
+       Note: n is limited to 2. Anything higher does not result in
+       faster playback. Instead the host should start dropping frames.
 Param[1]
        Direction: 0=forward, 1=reverse
+       Note: to make reverse playback work you have to write full GOPs in
+       reverse order.
 Param[2]
        Picture mask:
            1=I frames
@@ -69,13 +77,16 @@ Param[2]
            7=I, P, B frames
 Param[3]
        B frames per GOP (for reverse play only)
+       Note: for reverse playback the Picture Mask should be set to I or I, P.
+       Adding B frames to the mask will result in corrupt video. This field
+       has to be set to the correct value in order to keep the timing correct.
 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.
+       resumes. (Not implemented in the firmware, leave at 0)
 
 -------------------------------------------------------------------------------
 
@@ -212,6 +223,7 @@ Description
        Select audio mode
 Param[0]
        Dual mono mode action
+           0=Stereo, 1=Left, 2=Right, 3=Mono, 4=Swap, -1=Unchanged
 Param[1]
        Stereo mode action:
            0=Stereo, 1=Left, 2=Right, 3=Mono, 4=Swap, -1=Unchanged
@@ -224,7 +236,10 @@ 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
+       Event: 0=Audio mode change between mono, (joint) stereo and dual channel.
+       Event: 3=Decoder started
+       Event: 4=Unknown: goes off 10-15 times per second while decoding.
+       Event: 5=Some sync event: goes off once per frame.
 Param[1]
        Notification 0=disabled, 1=enabled
 Param[2]
@@ -273,43 +288,6 @@ Param[3]
 
 -------------------------------------------------------------------------------
 
-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
diff --git a/Documentation/video4linux/cx2341x/fw-decoder-regs.txt b/Documentation/video4linux/cx2341x/fw-decoder-regs.txt
new file mode 100644 (file)
index 0000000..db2366c
--- /dev/null
@@ -0,0 +1,815 @@
+PVR350 Video decoder registers 0x02002800 -> 0x02002B00
+=======================================================
+
+This list has been worked out through trial and error. There will be mistakes
+and omissions. Some registers have no obvious effect so it's hard to say what
+they do, while others interact with each other, or require a certain load
+sequence. Horizontal filter setup is one example, with six registers working
+in unison and requiring a certain load sequence to correctly configure. The
+indexed colour palette is much easier to set at just two registers, but again
+it requires a certain load sequence.
+
+Some registers are fussy about what they are set to. Load in a bad value & the
+decoder will fail. A firmware reload will often recover, but sometimes a reset
+is required. For registers containing size information, setting them to 0 is
+generally a bad idea. For other control registers i.e. 2878, you'll only find
+out what values are bad when it hangs.
+
+--------------------------------------------------------------------------------
+2800
+      bit 0
+       Decoder enable
+         0 = disable
+         1 = enable
+--------------------------------------------------------------------------------
+2804
+      bits 0:31
+       Decoder horizontal Y alias register 1
+---------------
+2808
+      bits 0:31
+       Decoder horizontal Y alias register 2
+---------------
+280C
+      bits 0:31
+       Decoder horizontal Y alias register 3
+---------------
+2810
+      bits 0:31
+       Decoder horizontal Y alias register 4
+---------------
+2814
+      bits 0:31
+       Decoder horizontal Y alias register 5
+---------------
+2818
+      bits 0:31
+       Decoder horizontal Y alias trigger
+
+     These six registers control the horizontal aliasing filter for the Y plane.
+     The first five registers must all be loaded before accessing the trigger
+     (2818), as this register actually clocks the data through for the first
+     five.
+
+     To correctly program set the filter, this whole procedure must be done 16
+     times. The actual register contents are copied from a lookup-table in the
+     firmware which contains 4 different filter settings.
+
+--------------------------------------------------------------------------------
+281C
+      bits 0:31
+       Decoder horizontal UV alias register 1
+---------------
+2820
+      bits 0:31
+       Decoder horizontal UV alias register 2
+---------------
+2824
+      bits 0:31
+       Decoder horizontal UV alias register 3
+---------------
+2828
+      bits 0:31
+       Decoder horizontal UV alias register 4
+---------------
+282C
+      bits 0:31
+       Decoder horizontal UV alias register 5
+---------------
+2830
+      bits 0:31
+       Decoder horizontal UV alias trigger
+
+     These six registers control the horizontal aliasing for the UV plane.
+     Operation is the same as the Y filter, with 2830 being the trigger
+     register.
+
+--------------------------------------------------------------------------------
+2834
+      bits 0:15
+       Decoder Y source width in pixels
+
+      bits 16:31
+       Decoder Y destination width in pixels
+---------------
+2838
+      bits 0:15
+       Decoder UV source width in pixels
+
+      bits 16:31
+       Decoder UV destination width in pixels
+
+     NOTE: For both registers, the resulting image must be fully visible on
+     screen. If the image exceeds the right edge both the source and destination
+     size must be adjusted to reflect the visible portion. For the source width,
+     you must take into account the scaling when calculating the new value.
+--------------------------------------------------------------------------------
+
+283C
+      bits 0:31
+       Decoder Y horizontal scaling
+                   Normally = Reg 2854 >> 2
+---------------
+2840
+      bits 0:31
+       Decoder ?? unknown - horizontal scaling
+         Usually 0x00080514
+---------------
+2844
+      bits 0:31
+       Decoder UV horizontal scaling
+         Normally = Reg 2854 >> 2
+---------------
+2848
+      bits 0:31
+       Decoder ?? unknown - horizontal scaling
+         Usually 0x00100514
+---------------
+284C
+      bits 0:31
+       Decoder ?? unknown - Y plane
+         Usually 0x00200020
+---------------
+2850
+      bits 0:31
+       Decoder ?? unknown - UV plane
+         Usually 0x00200020
+---------------
+2854
+      bits 0:31
+       Decoder 'master' value for horizontal scaling
+---------------
+2858
+      bits 0:31
+       Decoder ?? unknown
+         Usually 0
+---------------
+285C
+      bits 0:31
+       Decoder ?? unknown
+         Normally = Reg 2854 >> 1
+---------------
+2860
+      bits 0:31
+       Decoder ?? unknown
+         Usually 0
+---------------
+2864
+      bits 0:31
+       Decoder ?? unknown
+         Normally = Reg 2854 >> 1
+---------------
+2868
+      bits 0:31
+       Decoder ?? unknown
+         Usually 0
+
+     Most of these registers either control horizontal scaling, or appear linked
+     to it in some way. Register 2854 contains the 'master' value & the other
+     registers can be calculated from that one. You must also remember to
+     correctly set the divider in Reg 2874.
+
+     To enlarge:
+            Reg 2854 = (source_width * 0x00200000) / destination_width
+            Reg 2874 = No divide
+
+     To reduce from full size down to half size:
+            Reg 2854 = (source_width/2 * 0x00200000) / destination width
+            Reg 2874 = Divide by 2
+
+     To reduce from half size down to quarter size:
+            Reg 2854 = (source_width/4 * 0x00200000) / destination width
+            Reg 2874 = Divide by 4
+
+     The result is always rounded up.
+
+--------------------------------------------------------------------------------
+286C
+      bits 0:15
+       Decoder horizontal Y buffer offset
+
+      bits 15:31
+       Decoder horizontal UV buffer offset
+
+     Offset into the video image buffer. If the offset is gradually incremented,
+     the on screen image will move left & wrap around higher up on the right.
+
+--------------------------------------------------------------------------------
+2870
+      bits 0:15
+       Decoder horizontal Y output offset
+
+      bits 16:31
+       Decoder horizontal UV output offset
+
+     Offsets the actual video output. Controls output alignment of the Y & UV
+     planes. The higher the value, the greater the shift to the left. Use
+     reg 2890 to move the image right.
+
+--------------------------------------------------------------------------------
+2874
+      bits 0:1
+       Decoder horizontal Y output size divider
+         00 = No divide
+         01 = Divide by 2
+         10 = Divide by 3
+
+      bits 4:5
+       Decoder horizontal UV output size divider
+         00 = No divide
+         01 = Divide by 2
+         10 = Divide by 3
+
+      bit 8
+       Decoder ?? unknown
+         0 = Normal
+         1 = Affects video output levels
+
+      bit 16
+       Decoder ?? unknown
+         0 = Normal
+         1 = Disable horizontal filter
+
+--------------------------------------------------------------------------------
+2878
+      bit 0
+       ?? unknown
+
+      bit 1
+       osd on/off
+         0 = osd off
+         1 = osd on
+
+      bit 2
+       Decoder + osd video timing
+         0 = NTSC
+         1 = PAL
+
+      bits 3:4
+       ?? unknown
+
+      bit 5
+       Decoder + osd
+         Swaps upper & lower fields
+
+--------------------------------------------------------------------------------
+287C
+      bits 0:10
+       Decoder & osd ?? unknown
+         Moves entire screen horizontally. Starts at 0x005 with the screen
+         shifted heavily to the right. Incrementing in steps of 0x004 will
+         gradually shift the screen to the left.
+
+      bits 11:31
+       ?? unknown
+
+     Normally contents are 0x00101111 (NTSC) or 0x1010111d (PAL)
+
+--------------------------------------------------------------------------------
+2880  --------    ?? unknown
+2884  --------    ?? unknown
+--------------------------------------------------------------------------------
+2888
+      bit 0
+       Decoder + osd ?? unknown
+         0 = Normal
+         1 = Misaligned fields (Correctable through 289C & 28A4)
+
+      bit 4
+       ?? unknown
+
+      bit 8
+       ?? unknown
+
+     Warning: Bad values will require a firmware reload to recover.
+                Known to be bad are 0x000,0x011,0x100,0x111
+--------------------------------------------------------------------------------
+288C
+      bits 0:15
+       osd ?? unknown
+         Appears to affect the osd position stability. The higher the value the
+         more unstable it becomes. Decoder output remains stable.
+
+      bits 16:31
+       osd ?? unknown
+         Same as bits 0:15
+
+--------------------------------------------------------------------------------
+2890
+      bits 0:11
+       Decoder output horizontal offset.
+
+     Horizontal offset moves the video image right. A small left shift is
+     possible, but it's better to use reg 2870 for that due to its greater
+     range.
+
+     NOTE: Video corruption will occur if video window is shifted off the right
+     edge. To avoid this read the notes for 2834 & 2838.
+--------------------------------------------------------------------------------
+2894
+      bits 0:23
+       Decoder output video surround colour.
+
+     Contains the colour (in yuv) used to fill the screen when the video is
+     running in a window.
+--------------------------------------------------------------------------------
+2898
+      bits 0:23
+       Decoder video window colour
+         Contains the colour (in yuv) used to fill the video window when the
+         video is turned off.
+
+      bit 24
+       Decoder video output
+         0 = Video on
+         1 = Video off
+
+      bit 28
+       Decoder plane order
+         0 = Y,UV
+         1 = UV,Y
+
+      bit 29
+       Decoder second plane byte order
+         0 = Normal (UV)
+         1 = Swapped (VU)
+
+     In normal usage, the first plane is Y & the second plane is UV. Though the
+     order of the planes can be swapped, only the byte order of the second plane
+     can be swapped. This isn't much use for the Y plane, but can be useful for
+     the UV plane.
+
+--------------------------------------------------------------------------------
+289C
+      bits 0:15
+       Decoder vertical field offset 1
+
+      bits 16:31
+       Decoder vertical field offset 2
+
+     Controls field output vertical alignment. The higher the number, the lower
+     the image on screen. Known starting values are 0x011E0017 (NTSC) &
+     0x01500017 (PAL)
+--------------------------------------------------------------------------------
+28A0
+      bits 0:15
+       Decoder & osd width in pixels
+
+      bits 16:31
+       Decoder & osd height in pixels
+
+     All output from the decoder & osd are disabled beyond this area. Decoder
+     output will simply go black outside of this region. If the osd tries to
+     exceed this area it will become corrupt.
+--------------------------------------------------------------------------------
+28A4
+      bits 0:11
+       osd left shift.
+
+     Has a range of 0x770->0x7FF. With the exception of 0, any value outside of
+     this range corrupts the osd.
+--------------------------------------------------------------------------------
+28A8
+      bits 0:15
+       osd vertical field offset 1
+
+      bits 16:31
+       osd vertical field offset 2
+
+     Controls field output vertical alignment. The higher the number, the lower
+     the image on screen. Known starting values are 0x011E0017 (NTSC) &
+     0x01500017 (PAL)
+--------------------------------------------------------------------------------
+28AC  --------    ?? unknown
+ |
+ V
+28BC  --------    ?? unknown
+--------------------------------------------------------------------------------
+28C0
+      bit 0
+       Current output field
+         0 = first field
+         1 = second field
+
+      bits 16:31
+       Current scanline
+         The scanline counts from the top line of the first field
+         through to the last line of the second field.
+--------------------------------------------------------------------------------
+28C4  --------    ?? unknown
+ |
+ V
+28F8  --------    ?? unknown
+--------------------------------------------------------------------------------
+28FC
+      bit 0
+       ?? unknown
+         0 = Normal
+         1 = Breaks decoder & osd output
+--------------------------------------------------------------------------------
+2900
+      bits 0:31
+       Decoder vertical Y alias register 1
+---------------
+2904
+      bits 0:31
+       Decoder vertical Y alias register 2
+---------------
+2908
+      bits 0:31
+       Decoder vertical Y alias trigger
+
+     These three registers control the vertical aliasing filter for the Y plane.
+     Operation is similar to the horizontal Y filter (2804). The only real
+     difference is that there are only two registers to set before accessing
+     the trigger register (2908). As for the horizontal filter, the values are
+     taken from a lookup table in the firmware, and the procedure must be
+     repeated 16 times to fully program the filter.
+--------------------------------------------------------------------------------
+290C
+      bits 0:31
+       Decoder vertical UV alias register 1
+---------------
+2910
+      bits 0:31
+       Decoder vertical UV alias register 2
+---------------
+2914
+      bits 0:31
+       Decoder vertical UV alias trigger
+
+     These three registers control the vertical aliasing filter for the UV
+     plane. Operation is the same as the Y filter, with 2914 being the trigger.
+--------------------------------------------------------------------------------
+2918
+      bits 0:15
+       Decoder Y source height in pixels
+
+      bits 16:31
+       Decoder Y destination height in pixels
+---------------
+291C
+      bits 0:15
+       Decoder UV source height in pixels divided by 2
+
+      bits 16:31
+       Decoder UV destination height in pixels
+
+     NOTE: For both registers, the resulting image must be fully visible on
+     screen. If the image exceeds the bottom edge both the source and
+     destination size must be adjusted to reflect the visible portion. For the
+     source height, you must take into account the scaling when calculating the
+     new value.
+--------------------------------------------------------------------------------
+2920
+      bits 0:31
+       Decoder Y vertical scaling
+         Normally = Reg 2930 >> 2
+---------------
+2924
+      bits 0:31
+       Decoder Y vertical scaling
+         Normally = Reg 2920 + 0x514
+---------------
+2928
+      bits 0:31
+       Decoder UV vertical scaling
+         When enlarging = Reg 2930 >> 2
+         When reducing = Reg 2930 >> 3
+---------------
+292C
+      bits 0:31
+       Decoder UV vertical scaling
+         Normally = Reg 2928 + 0x514
+---------------
+2930
+      bits 0:31
+       Decoder 'master' value for vertical scaling
+---------------
+2934
+      bits 0:31
+       Decoder ?? unknown - Y vertical scaling
+---------------
+2938
+      bits 0:31
+       Decoder Y vertical scaling
+         Normally = Reg 2930
+---------------
+293C
+      bits 0:31
+       Decoder ?? unknown - Y vertical scaling
+---------------
+2940
+      bits 0:31
+       Decoder UV vertical scaling
+         When enlarging = Reg 2930 >> 1
+         When reducing = Reg 2930
+---------------
+2944
+      bits 0:31
+       Decoder ?? unknown - UV vertical scaling
+---------------
+2948
+      bits 0:31
+       Decoder UV vertical scaling
+         Normally = Reg 2940
+---------------
+294C
+      bits 0:31
+       Decoder ?? unknown - UV vertical scaling
+
+     Most of these registers either control vertical scaling, or appear linked
+     to it in some way. Register 2930 contains the 'master' value & all other
+     registers can be calculated from that one. You must also remember to
+     correctly set the divider in Reg 296C
+
+     To enlarge:
+            Reg 2930 = (source_height * 0x00200000) / destination_height
+            Reg 296C = No divide
+
+     To reduce from full size down to half size:
+            Reg 2930 = (source_height/2 * 0x00200000) / destination height
+            Reg 296C = Divide by 2
+
+      To reduce from half down to quarter.
+            Reg 2930 = (source_height/4 * 0x00200000) / destination height
+            Reg 296C = Divide by 4
+
+--------------------------------------------------------------------------------
+2950
+      bits 0:15
+       Decoder Y line index into display buffer, first field
+
+      bits 16:31
+       Decoder Y vertical line skip, first field
+--------------------------------------------------------------------------------
+2954
+      bits 0:15
+       Decoder Y line index into display buffer, second field
+
+      bits 16:31
+       Decoder Y vertical line skip, second field
+--------------------------------------------------------------------------------
+2958
+      bits 0:15
+       Decoder UV line index into display buffer, first field
+
+      bits 16:31
+       Decoder UV vertical line skip, first field
+--------------------------------------------------------------------------------
+295C
+      bits 0:15
+       Decoder UV line index into display buffer, second field
+
+      bits 16:31
+       Decoder UV vertical line skip, second field
+--------------------------------------------------------------------------------
+2960
+      bits 0:15
+       Decoder destination height minus 1
+
+      bits 16:31
+       Decoder destination height divided by 2
+--------------------------------------------------------------------------------
+2964
+      bits 0:15
+       Decoder Y vertical offset, second field
+
+      bits 16:31
+       Decoder Y vertical offset, first field
+
+     These two registers shift the Y plane up. The higher the number, the
+     greater the shift.
+--------------------------------------------------------------------------------
+2968
+      bits 0:15
+       Decoder UV vertical offset, second field
+
+      bits 16:31
+       Decoder UV vertical offset, first field
+
+     These two registers shift the UV plane up. The higher the number, the
+     greater the shift.
+--------------------------------------------------------------------------------
+296C
+      bits 0:1
+       Decoder vertical Y output size divider
+         00 = No divide
+         01 = Divide by 2
+         10 = Divide by 4
+
+      bits 8:9
+       Decoder vertical UV output size divider
+         00 = No divide
+         01 = Divide by 2
+         10 = Divide by 4
+--------------------------------------------------------------------------------
+2970
+      bit 0
+       Decoder ?? unknown
+         0 = Normal
+         1 = Affect video output levels
+
+      bit 16
+       Decoder ?? unknown
+         0 = Normal
+         1 = Disable vertical filter
+
+--------------------------------------------------------------------------------
+2974  --------   ?? unknown
+ |
+ V
+29EF  --------   ?? unknown
+--------------------------------------------------------------------------------
+2A00
+      bits 0:2
+       osd colour mode
+         001 = 16 bit (565)
+         010 = 15 bit (555)
+         011 = 12 bit (444)
+         100 = 32 bit (8888)
+         101 = 8 bit indexed
+
+      bits 4:5
+       osd display bpp
+         01 = 8 bit
+         10 = 16 bit
+         11 = 32 bit
+
+      bit 8
+       osd global alpha
+         0 = Off
+         1 = On
+
+      bit 9
+       osd local alpha
+         0 = Off
+         1 = On
+
+      bit 10
+       osd colour key
+         0 = Off
+         1 = On
+
+      bit 11
+       osd ?? unknown
+         Must be 1
+
+      bit 13
+       osd colour space
+         0 = ARGB
+         1 = AYVU
+
+      bits 16:31
+       osd ?? unknown
+         Must be 0x001B (some kind of buffer pointer ?)
+
+     When the bits-per-pixel is set to 8, the colour mode is ignored and
+     assumed to be 8 bit indexed. For 16 & 32 bits-per-pixel the colour depth
+     is honoured, and when using a colour depth that requires fewer bytes than
+     allocated the extra bytes are used as padding. So for a 32 bpp with 8 bit
+     index colour, there are 3 padding bytes per pixel. It's also possible to
+     select 16bpp with a 32 bit colour mode. This results in the pixel width
+     being doubled, but the color key will not work as expected in this mode.
+
+     Colour key is as it suggests. You designate a colour which will become
+     completely transparent. When using 565, 555 or 444 colour modes, the
+     colour key is always 16 bits wide. The colour to key on is set in Reg 2A18.
+
+     Local alpha is a per-pixel 256 step transparency, with 0 being transparent
+     and 255 being solid. This is only available in 32 bit & 8 bit indexed
+     colour modes.
+
+     Global alpha is a 256 step transparency that applies to the entire osd,
+     with 0 being transparent & 255 being solid.
+
+     It's possible to combine colour key, local alpha & global alpha.
+--------------------------------------------------------------------------------
+2A04
+      bits 0:15
+       osd x coord for left edge
+
+      bits 16:31
+       osd y coord for top edge
+---------------
+2A08
+      bits 0:15
+       osd x coord for right edge
+
+      bits 16:31
+       osd y coord for bottom edge
+
+     For both registers, (0,0) = top left corner of the display area. These
+     registers do not control the osd size, only where it's positioned & how
+     much is visible. The visible osd area cannot exceed the right edge of the
+     display, otherwise the osd will become corrupt. See reg 2A10 for
+     setting osd width.
+--------------------------------------------------------------------------------
+2A0C
+      bits 0:31
+       osd buffer index
+
+     An index into the osd buffer. Slowly incrementing this moves the osd left,
+     wrapping around onto the right edge
+--------------------------------------------------------------------------------
+2A10
+      bits 0:11
+       osd buffer 32 bit word width
+
+     Contains the width of the osd measured in 32 bit words. This means that all
+     colour modes are restricted to a byte width which is divisible by 4.
+--------------------------------------------------------------------------------
+2A14
+      bits 0:15
+       osd height in pixels
+
+      bits 16:32
+       osd line index into buffer
+         osd will start displaying from this line.
+--------------------------------------------------------------------------------
+2A18
+      bits 0:31
+       osd colour key
+
+     Contains the colour value which will be transparent.
+--------------------------------------------------------------------------------
+2A1C
+      bits 0:7
+       osd global alpha
+
+     Contains the global alpha value (equiv ivtvfbctl --alpha XX)
+--------------------------------------------------------------------------------
+2A20  --------    ?? unknown
+ |
+ V
+2A2C  --------    ?? unknown
+--------------------------------------------------------------------------------
+2A30
+      bits 0:7
+       osd colour to change in indexed palette
+---------------
+2A34
+      bits 0:31
+       osd colour for indexed palette
+
+     To set the new palette, first load the index of the colour to change into
+     2A30, then load the new colour into 2A34. The full palette is 256 colours,
+     so the index range is 0x00-0xFF
+--------------------------------------------------------------------------------
+2A38  --------    ?? unknown
+2A3C  --------    ?? unknown
+--------------------------------------------------------------------------------
+2A40
+      bits 0:31
+       osd ?? unknown
+
+     Affects overall brightness, wrapping around to black
+--------------------------------------------------------------------------------
+2A44
+      bits 0:31
+       osd ?? unknown
+
+     Green tint
+--------------------------------------------------------------------------------
+2A48
+      bits 0:31
+       osd ?? unknown
+
+     Red tint
+--------------------------------------------------------------------------------
+2A4C
+      bits 0:31
+       osd ?? unknown
+
+     Affects overall brightness, wrapping around to black
+--------------------------------------------------------------------------------
+2A50
+      bits 0:31
+       osd ?? unknown
+
+     Colour shift
+--------------------------------------------------------------------------------
+2A54
+      bits 0:31
+       osd ?? unknown
+
+     Colour shift
+--------------------------------------------------------------------------------
+2A58  --------    ?? unknown
+ |
+ V
+2AFC  --------    ?? unknown
+--------------------------------------------------------------------------------
+2B00
+      bit 0
+       osd filter control
+         0 = filter off
+         1 = filter on
+
+      bits 1:4
+       osd ?? unknown
+
+--------------------------------------------------------------------------------
+
+v0.3 - 2 February 2007 - Ian Armstrong (ian@iarmst.demon.co.uk)
+
index 8123e26..be52b6f 100644 (file)
@@ -22,6 +22,8 @@ urged to choose a smaller block size and learn the scatter-gather technique.
 
 Mailbox #10 is reserved for DMA transfer information.
 
+Note: the hardware expects little-endian data ('intel format').
+
 Flow
 ====
 
@@ -64,7 +66,7 @@ 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
+entire 32 bits. The lowest 18 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
@@ -78,8 +80,8 @@ Array Element:
 
 - 32-bit Source Address
 - 32-bit Destination Address
-- 16-bit reserved (high bit is the last flag)
-- 16-bit byte count
+- 14-bit reserved (high bit is the last flag)
+- 18-bit byte count
 
 DMA Transfer Status
 ===================
@@ -87,8 +89,8 @@ 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
+1   write completed
+2   DMA read error
+3   DMA write error
+4   Scatter-Gather array error
index 15df0df..242104c 100644 (file)
@@ -213,16 +213,6 @@ Param[1]
 
 -------------------------------------------------------------------------------
 
-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
@@ -332,9 +322,7 @@ Param[0]
                '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.
+               Note: the cx23415 cannot decode Joint Stereo properly.
 
          10:11 Mode Extension used in joint_stereo mode.
                In Layer I and II they indicate which subbands are in
@@ -413,16 +401,34 @@ Name      CX2341X_ENC_SET_PGM_INDEX_INFO
 Enum   199/0xC7
 Description
        Sets the Program Index Information.
+       The information is stored as follows:
+
+       struct info {
+               u32 length;             // Length of this frame
+               u32 offset_low;         // Offset in the file of the
+               u32 offset_high;        // start of this frame
+               u32 mask1;              // Bits 0-1 are the type mask:
+                                       // 1=I, 2=P, 4=B
+               u32 pts;                // The PTS of the frame
+               u32 mask2;              // Bit 0 is bit 32 of the pts.
+       };
+       u32 table_ptr;
+       struct info index[400];
+
+       The table_ptr is the encoder memory address in the table were
+       *new* entries will be written. Note that this is a ringbuffer,
+       so the table_ptr will wraparound.
 Param[0]
        Picture Mask:
            0=No index capture
            1=I frames
            3=I,P frames
            7=I,P,B frames
+       (Seems to be ignored, it always indexes I, P and B frames)
 Param[1]
        Elements requested (up to 400)
 Result[0]
-       Offset in SDF memory of the table.
+       Offset in the encoder memory of the start of the table.
 Result[1]
        Number of allocated elements up to a maximum of Param[1]
 
@@ -492,12 +498,14 @@ 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.
+       bit 27 or 18 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
+               0   read completed
+               1   write completed
+               2   DMA read error
+               3   DMA write error
+               4   Scatter-Gather array error
 Result[1]
        DMA type
 Result[2]
@@ -672,7 +680,7 @@ Description
        the value.
 Param[0]
        Command number:
-        1=set initial SCR value when starting encoding.
+        1=set initial SCR value when starting encoding (works).
         2=set quality mode (apparently some test setting).
         3=setup advanced VIM protection handling (supposedly only for the cx23416
           for raw YUV).
@@ -681,7 +689,11 @@ Param[0]
         4=generate artificial PTS timestamps
         5=USB flush mode
         6=something to do with the quantization matrix
-        7=set navigation pack insertion for DVD
+        7=set navigation pack insertion for DVD: adds 0xbf (private stream 2)
+          packets to the MPEG. The size of these packets is 2048 bytes (including
+          the header of 6 bytes: 0x000001bf + length). The payload is zeroed and
+          it is up to the application to fill them in. These packets are apparently
+          inserted every four frames.
         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
index ef0aad3..9d736fe 100644 (file)
@@ -1,6 +1,8 @@
 This document describes the cx2341x memory map and documents some of the register
 space.
 
+Note: the memory long words are little-endian ('intel format').
+
 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
@@ -67,7 +69,7 @@ DMA Registers 0x000-0xff:
  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
+ 0x8c-0xdc - 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
@@ -123,12 +125,8 @@ Bit
 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
+24 Decoder audio mode change detection event (through event notification)
 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)
index 1bdee8f..1247566 100644 (file)
@@ -23,7 +23,7 @@ Index
 
 1. Copyright
 ============
-Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>
+Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>
 
 
 2. Disclaimer
@@ -135,8 +135,9 @@ And finally:
 6. Module loading
 =================
 To use the driver, it is necessary to load the "et61x251" module into memory
-after every other module required: "videodev", "usbcore" and, depending on
-the USB host controller you have, "ehci-hcd", "uhci-hcd" or "ohci-hcd".
+after every other module required: "videodev", "v4l2_common", "compat_ioctl32",
+"usbcore" and, depending on the USB host controller you have, "ehci-hcd",
+"uhci-hcd" or "ohci-hcd".
 
 Loading can be done as shown below:
 
index 8cda472..2913da3 100644 (file)
@@ -1,5 +1,5 @@
 
-                        SN9C10x PC Camera Controllers
+                        SN9C1xx PC Camera Controllers
                                Driver for Linux
                         =============================
 
@@ -53,20 +53,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 4. Overview and features
 ========================
-This driver attempts to support the video interface of the devices mounting the
-SONiX SN9C101, SN9C102 and SN9C103 PC Camera Controllers.
-
-It's worth to note that SONiX has never collaborated with the author during the
-development of this project, despite several requests for enough detailed
-specifications of the register tables, compression engine and video data format
-of the above chips. Nevertheless, these informations are no longer necessary,
-because all the aspects related to these chips are known and have been
-described in detail in this documentation.
+This driver attempts to support the video interface of the devices assembling
+the SONiX SN9C101, SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers
+("SN9C1xx" from now on).
 
 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 SN9C10x driver can be found at the following URL:
+The latest version of the SN9C1xx driver can be found at the following URL:
 http://www.linux-projects.org/
 
 Some of the features of the driver are:
@@ -85,11 +79,11 @@ Some of the features of the driver are:
   high compression quality (see also "Notes for V4L2 application developers"
   and "Video frame formats" paragraphs);
 - full support for the capabilities of many of the possible image sensors that
-  can be connected to the SN9C10x bridges, including, for instance, red, green,
+  can be connected to the SN9C1xx bridges, including, for instance, red, green,
   blue and global gain adjustments and exposure (see "Supported devices"
   paragraph for details);
 - use of default color settings for sunlight conditions;
-- dynamic I/O interface for both SN9C10x and image sensor control and
+- dynamic I/O interface for both SN9C1xx and image sensor control and
   monitoring (see "Optional device control through 'sysfs'" paragraph);
 - dynamic driver control thanks to various module parameters (see "Module
   parameters" paragraph);
@@ -130,8 +124,8 @@ necessary:
        CONFIG_USB_UHCI_HCD=m
        CONFIG_USB_OHCI_HCD=m
 
-The SN9C103 controller also provides a built-in microphone interface. It is
-supported by the USB Audio driver thanks to the ALSA API:
+The SN9C103, SN9c105 and SN9C120 controllers also provide a built-in microphone
+interface. It is supported by the USB Audio driver thanks to the ALSA API:
 
        # Sound
        #
@@ -155,18 +149,27 @@ And finally:
 6. Module loading
 =================
 To use the driver, it is necessary to load the "sn9c102" module into memory
-after every other module required: "videodev", "usbcore" and, depending on
-the USB host controller you have, "ehci-hcd", "uhci-hcd" or "ohci-hcd".
+after every other module required: "videodev", "v4l2_common", "compat_ioctl32",
+"usbcore" and, depending on the USB host controller you have, "ehci-hcd",
+"uhci-hcd" or "ohci-hcd".
 
 Loading can be done as shown below:
 
        [root@localhost home]# modprobe sn9c102
 
-At this point the devices should be recognized. You can invoke "dmesg" to
-analyze kernel messages and verify that the loading process has gone well:
+Note that the module is called "sn9c102" for historic reasons, althought it
+does not just support the SN9C102.
+
+At this point all the devices supported by the driver and connected to the USB
+ports should be recognized. You can invoke "dmesg" to analyze kernel messages
+and verify that the loading process has gone well:
 
        [user@localhost home]$ dmesg
 
+or, to isolate all the kernel messages generated by the driver:
+
+       [user@localhost home]$ dmesg | grep sn9c102
+
 
 7. Module parameters
 ====================
@@ -198,10 +201,11 @@ 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.
+Syntax:         <0|n[,...]>
+Description:    Timeout for a video frame in seconds before returning an I/O
+               error; 0 for infinity. This parameter is specific for each
+               detected camera and can be changed at runtime thanks to the
+               /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 Name:           debug
@@ -223,20 +227,21 @@ Default:        2
 8. Optional device control through "sysfs" [1]
 ==========================================
 If the kernel has been compiled with the CONFIG_VIDEO_ADV_DEBUG option enabled,
-it is possible to read and write both the SN9C10x and the image sensor
+it is possible to read and write both the SN9C1xx and the image sensor
 registers by using the "sysfs" filesystem interface.
 
 Every time a supported device is recognized, a write-only file named "green" is
 created in the /sys/class/video4linux/videoX directory. You can set the green
 channel's gain by writing the desired value to it. The value may range from 0
-to 15 for SN9C101 or SN9C102 bridges, from 0 to 127 for SN9C103 bridges.
-Similarly, only for SN9C103 controllers, blue and red gain control files are
-available in the same directory, for which accepted values may range from 0 to
-127.
+to 15 for the SN9C101 or SN9C102 bridges, from 0 to 127 for the SN9C103,
+SN9C105 and SN9C120 bridges.
+Similarly, only for the SN9C103, SN9C105 and SN9120 controllers, blue and red
+gain control files are available in the same directory, for which accepted
+values may range from 0 to 127.
 
 There are other four entries in the directory above for each registered camera:
 "reg", "val", "i2c_reg" and "i2c_val". The first two files control the
-SN9C10x bridge, while the other two control the sensor chip. "reg" and
+SN9C1xx bridge, while the other two control the sensor chip. "reg" and
 "i2c_reg" hold the values of the current register index where the following
 reading/writing operations are addressed at through "val" and "i2c_val". Their
 use is not intended for end-users. Note that "i2c_reg" and "i2c_val" will not
@@ -259,61 +264,84 @@ Now let's set the green gain's register of the SN9C101 or SN9C102 chips to 2:
        [root@localhost #] echo 0x11 > reg
        [root@localhost #] echo 2 > val
 
-Note that the SN9C10x always returns 0 when some of its registers are read.
+Note that the SN9C1xx always returns 0 when some of its registers are read.
 To avoid race conditions, all the I/O accesses to the above files are
 serialized.
-
 The sysfs interface also provides the "frame_header" entry, which exports the
 frame header of the most recent requested and captured video frame. The header
-is always 18-bytes long and is appended to every video frame by the SN9C10x
+is always 18-bytes long and is appended to every video frame by the SN9C1xx
 controllers. As an example, this additional information can be used by the user
 application for implementing auto-exposure features via software.
 
-The following table describes the frame header:
-
-Byte #  Value         Description
-------  -----         -----------
-0x00    0xFF          Frame synchronisation pattern.
-0x01    0xFF          Frame synchronisation pattern.
-0x02    0x00          Frame synchronisation pattern.
-0x03    0xC4          Frame synchronisation pattern.
-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.
-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).
-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.
-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.
-
-The following bytes are used by the SN9C103 bridge only:
-
-0x0C    0xXX          Unknown meaning
-0x0D    0xXX          Unknown meaning
-0x0E    0xXX          Unknown meaning
-0x0F    0xXX          Unknown meaning
-0x10    0xXX          Unknown meaning
-0x11    0xXX          Unknown meaning
+The following table describes the frame header exported by the SN9C101 and
+SN9C102:
+
+Byte #  Value or bits Description
+------  ------------- -----------
+0x00    0xFF          Frame synchronisation pattern
+0x01    0xFF          Frame synchronisation pattern
+0x02    0x00          Frame synchronisation pattern
+0x03    0xC4          Frame synchronisation pattern
+0x04    0xC4          Frame synchronisation pattern
+0x05    0x96          Frame synchronisation pattern
+0x06    [3:0]         Read channel gain control = (1+R_GAIN/8)
+       [7:4]         Blue channel gain control = (1+B_GAIN/8)
+0x07    [ 0 ]         Compression mode. 0=No compression, 1=Compression enabled
+       [2:1]         Maximum scale factor for compression
+       [ 3 ]         1 = USB fifo(2K bytes) is full
+       [ 4 ]         1 = Digital gain is finish
+       [ 5 ]         1 = Exposure is finish
+       [7:6]         Frame index
+0x08    [7:0]         Y sum inside Auto-Exposure area (low-byte)
+0x09    [7:0]         Y sum inside Auto-Exposure area (high-byte)
+                     where Y sum = (R/4 + 5G/16 + B/8) / 32
+0x0A    [7:0]         Y sum outside Auto-Exposure area (low-byte)
+0x0B    [7:0]         Y sum outside Auto-Exposure area (high-byte)
+                     where Y sum = (R/4 + 5G/16 + B/8) / 128
+0x0C    0xXX          Not used
+0x0D    0xXX          Not used
+0x0E    0xXX          Not used
+0x0F    0xXX          Not used
+0x10    0xXX          Not used
+0x11    0xXX          Not used
+
+The following table describes the frame header exported by the SN9C103:
+
+Byte #  Value or bits Description
+------  ------------- -----------
+0x00    0xFF          Frame synchronisation pattern
+0x01    0xFF          Frame synchronisation pattern
+0x02    0x00          Frame synchronisation pattern
+0x03    0xC4          Frame synchronisation pattern
+0x04    0xC4          Frame synchronisation pattern
+0x05    0x96          Frame synchronisation pattern
+0x06    [6:0]         Read channel gain control = (1/2+R_GAIN/64)
+0x07    [6:0]         Blue channel gain control = (1/2+B_GAIN/64)
+       [7:4]
+0x08    [ 0 ]         Compression mode. 0=No compression, 1=Compression enabled
+       [2:1]         Maximum scale factor for compression
+       [ 3 ]         1 = USB fifo(2K bytes) is full
+       [ 4 ]         1 = Digital gain is finish
+       [ 5 ]         1 = Exposure is finish
+       [7:6]         Frame index
+0x09    [7:0]         Y sum inside Auto-Exposure area (low-byte)
+0x0A    [7:0]         Y sum inside Auto-Exposure area (high-byte)
+                     where Y sum = (R/4 + 5G/16 + B/8) / 32
+0x0B    [7:0]         Y sum outside Auto-Exposure area (low-byte)
+0x0C    [7:0]         Y sum outside Auto-Exposure area (high-byte)
+                     where Y sum = (R/4 + 5G/16 + B/8) / 128
+0x0D    [1:0]         Audio frame number
+       [ 2 ]         1 = Audio is recording
+0x0E    [7:0]         Audio summation (low-byte)
+0x0F    [7:0]         Audio summation (high-byte)
+0x10    [7:0]         Audio sample count
+0x11    [7:0]         Audio peak data in audio frame
 
 The AE area (sx, sy, ex, ey) in the active window can be set by programming the
-registers 0x1c, 0x1d, 0x1e and 0x1f of the SN9C10x controllers, where one unit
+registers 0x1c, 0x1d, 0x1e and 0x1f of the SN9C1xx controllers, where one unit
 corresponds to 32 pixels.
 
-[1] Part of the meaning of the frame header has been documented by Bertrik
-    Sikken.
+[1] The frame headers exported by the SN9C105 and SN9C120 are not described.
 
 
 9. Supported devices
@@ -323,15 +351,19 @@ here. They have never collaborated with the author, so no advertising.
 
 From the point of view of a driver, what unambiguously identify a device are
 its vendor and product USB identifiers. Below is a list of known identifiers of
-devices mounting the SN9C10x PC camera controllers:
+devices assembling the SN9C1xx PC camera controllers:
 
 Vendor ID  Product ID
 ---------  ----------
+0x0471     0x0327
+0x0471     0x0328
 0x0c45     0x6001
 0x0c45     0x6005
 0x0c45     0x6007
 0x0c45     0x6009
 0x0c45     0x600d
+0x0c45     0x6011
+0x0c45     0x6019
 0x0c45     0x6024
 0x0c45     0x6025
 0x0c45     0x6028
@@ -342,6 +374,7 @@ Vendor ID  Product ID
 0x0c45     0x602d
 0x0c45     0x602e
 0x0c45     0x6030
+0x0c45     0x603f
 0x0c45     0x6080
 0x0c45     0x6082
 0x0c45     0x6083
@@ -368,24 +401,40 @@ Vendor ID  Product ID
 0x0c45     0x60bb
 0x0c45     0x60bc
 0x0c45     0x60be
+0x0c45     0x60c0
+0x0c45     0x60c8
+0x0c45     0x60cc
+0x0c45     0x60ea
+0x0c45     0x60ec
+0x0c45     0x60fa
+0x0c45     0x60fb
+0x0c45     0x60fc
+0x0c45     0x60fe
+0x0c45     0x6130
+0x0c45     0x613a
+0x0c45     0x613b
+0x0c45     0x613c
+0x0c45     0x613e
 
 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;
-kernel messages will always tell you whether this is the case:
+until now only the ones that assemble the following image sensors are
+supported; kernel messages will always tell you whether this is the case (see
+"Module loading" paragraph):
 
 Model       Manufacturer
 -----       ------------
 HV7131D     Hynix Semiconductor, Inc.
 MI-0343     Micron Technology, Inc.
 OV7630      OmniVision Technologies, Inc.
+OV7660      OmniVision Technologies, Inc.
 PAS106B     PixArt Imaging, Inc.
 PAS202BCA   PixArt Imaging, Inc.
 PAS202BCB   PixArt Imaging, Inc.
 TAS5110C1B  Taiwan Advanced Sensor Corporation
 TAS5130D1B  Taiwan Advanced Sensor Corporation
 
-All the available control settings of each image sensor are supported through
-the V4L2 interface.
+Some of the available control settings of each image sensor are supported
+through the V4L2 interface.
 
 Donations of new models for further testing and support would be much
 appreciated. Non-available hardware will not be supported by the author of this
@@ -429,12 +478,15 @@ supplied by this driver).
 
 11. Video frame formats [1]
 =======================
-The SN9C10x PC Camera Controllers can send images in two possible video
-formats over the USB: either native "Sequential RGB Bayer" or Huffman
-compressed. The latter is used to achieve high frame rates. The current video
-format may be selected or queried from the user application by calling the
-VIDIOC_S_FMT or VIDIOC_G_FMT ioctl's, as described in the V4L2 API
-specifications.
+The SN9C1xx PC Camera Controllers can send images in two possible video
+formats over the USB: either native "Sequential RGB Bayer" or compressed.
+The compression is used to achieve high frame rates. With regard to the
+SN9C101, SN9C102 and SN9C103, the compression is based on the Huffman encoding
+algorithm described below, while the SN9C105 and SN9C120 the compression is
+based on the JPEG standard.
+The current video format may be selected or queried from the user application
+by calling the VIDIOC_S_FMT or VIDIOC_G_FMT ioctl's, as described in the V4L2
+API specifications.
 
 The name "Sequential Bayer" indicates the organization of the red, green and
 blue pixels in one video frame. Each pixel is associated with a 8-bit long
@@ -447,14 +499,14 @@ G[m]   R[m+1]  G[m+2]  R[m+2]  ...   G[2m-2]        R[2m-1]
 ...                                  G[n(m-2)]      R[n(m-1)]
 
 The above matrix also represents the sequential or progressive read-out mode of
-the (n, m) Bayer color filter array used in many CCD/CMOS image sensors.
+the (n, m) Bayer color filter array used in many CCD or CMOS image sensors.
 
-One compressed video frame consists of a bitstream that encodes for every R, G,
-or B pixel the difference between the value of the pixel itself and some
-reference pixel value. Pixels are organised in the Bayer pattern and the Bayer
-sub-pixels are tracked individually and alternatingly. For example, in the
-first line values for the B and G1 pixels are alternatingly encoded, while in
-the second line values for the G2 and R pixels are alternatingly encoded.
+The Huffman compressed video frame consists of a bitstream that encodes for
+every R, G, or B pixel the difference between the value of the pixel itself and
+some reference pixel value. Pixels are organised in the Bayer pattern and the
+Bayer sub-pixels are tracked individually and alternatingly. For example, in
+the first line values for the B and G1 pixels are alternatingly encoded, while
+in the second line values for the G2 and R pixels are alternatingly encoded.
 
 The pixel reference value is calculated as follows:
 - the 4 top left pixels are encoded in raw uncompressed 8-bit format;
@@ -470,8 +522,9 @@ The pixel reference value is calculated as follows:
   decoding.
 
 The algorithm purely describes the conversion from compressed Bayer code used
-in the SN9C10x chips to uncompressed Bayer. Additional steps are required to
-convert this to a color image (i.e. a color interpolation algorithm).
+in the SN9C101, SN9C102 and SN9C103 chips to uncompressed Bayer. Additional
+steps are required to convert this to a color image (i.e. a color interpolation
+algorithm).
 
 The following Huffman codes have been found:
 0: +0 (relative to reference pixel value)
@@ -506,13 +559,18 @@ order):
 - Philippe Coval for having helped testing the PAS202BCA image sensor;
 - Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the
   donation of a webcam;
+- Dennis Heitmann for the donation of a webcam;
 - Jon Hollstrom for the donation of a webcam;
+- Nick McGill for the donation of a webcam;
 - Carlos Eduardo Medaglia Dyonisio, who added the support for the PAS202BCB
   image sensor;
 - Stefano Mozzi, who donated 45 EU;
 - Andrew Pearce for the donation of a webcam;
+- John Pullan for the donation of a webcam;
 - Bertrik Sikken, who reverse-engineered and documented the Huffman compression
-  algorithm used in the SN9C10x controllers and implemented the first decoder;
+  algorithm used in the SN9C101, SN9C102 and SN9C103 controllers and
+  implemented the first decoder;
 - Mizuno Takafumi for the donation of a webcam;
 - an "anonymous" donator (who didn't want his name to be revealed) for the
   donation of a webcam.
+- an anonymous donator for the donation of four webcams.
index f406f5e..befdfda 100644 (file)
@@ -23,7 +23,7 @@ Index
 
 1. Copyright
 ============
-Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>
+Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>
 
 
 2. Disclaimer
@@ -125,8 +125,9 @@ And finally:
 6. Module loading
 =================
 To use the driver, it is necessary to load the "zc0301" module into memory
-after every other module required: "videodev", "usbcore" and, depending on
-the USB host controller you have, "ehci-hcd", "uhci-hcd" or "ohci-hcd".
+after every other module required: "videodev", "v4l2_common", "compat_ioctl32",
+"usbcore" and, depending on the USB host controller you have, "ehci-hcd",
+"uhci-hcd" or "ohci-hcd".
 
 Loading can be done as shown below:
 
@@ -211,12 +212,11 @@ Vendor ID  Product ID
 0x041e     0x4036
 0x041e     0x403a
 0x0458     0x7007
-0x0458     0x700C
+0x0458     0x700c
 0x0458     0x700f
 0x046d     0x08ae
 0x055f     0xd003
 0x055f     0xd004
-0x046d     0x08ae
 0x0ac8     0x0301
 0x0ac8     0x301b
 0x0ac8     0x303b
index 6fc033f..10054b4 100644 (file)
@@ -1306,7 +1306,7 @@ S:        Maintained
 ETHERNET BRIDGE
 P:     Stephen Hemminger
 M:     shemminger@linux-foundation.org
-L:     bridge@osdl.org
+L:     bridge@lists.osdl.org
 W:     http://bridge.sourceforge.net/
 S:     Maintained
 
@@ -1321,13 +1321,13 @@ S:      Maintained
 
 EXT3 FILE SYSTEM
 P:     Stephen Tweedie, Andrew Morton
-M:     sct@redhat.com, akpm@osdl.org, adilger@clusterfs.com
+M:     sct@redhat.com, akpm@linux-foundation.org, adilger@clusterfs.com
 L:     linux-ext4@vger.kernel.org
 S:     Maintained
 
 EXT4 FILE SYSTEM
 P:     Stephen Tweedie, Andrew Morton
-M:     sct@redhat.com, akpm@osdl.org, adilger@clusterfs.com
+M:     sct@redhat.com, akpm@linux-foundation.org, adilger@clusterfs.com
 L:     linux-ext4@vger.kernel.org
 S:     Maintained
 
@@ -1494,6 +1494,12 @@ M:       jkosina@suse.cz
 L:     linux-input@atrey.karlin.mff.cuni.cz
 S:     Maintained
 
+HIGH-RESOLUTION TIMERS, CLOCKEVENTS, DYNTICKS
+P:     Thomas Gleixner
+M:     tglx@linutronix.de
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+
 HIGH-SPEED SCC DRIVER FOR AX.25
 P:     Klaus Kudielka
 M:     klaus.kudielka@ieee.org
@@ -1924,7 +1930,7 @@ S:        Supported
 
 JOURNALLING LAYER FOR BLOCK DEVICES (JBD)
 P:     Stephen Tweedie, Andrew Morton
-M:     sct@redhat.com, akpm@osdl.org
+M:     sct@redhat.com, akpm@linux-foundation.org
 L:     linux-ext4@vger.kernel.org
 S:     Maintained
 
@@ -1995,7 +2001,7 @@ P:        Eric Biederman
 M:     ebiederm@xmission.com
 W:     http://www.xmission.com/~ebiederm/files/kexec/
 L:     linux-kernel@vger.kernel.org
-L:     fastboot@osdl.org
+L:     fastboot@lists.osdl.org
 S:     Maintained
 
 KPROBES
@@ -2333,7 +2339,7 @@ S:        Maintained
 NETEM NETWORK EMULATOR
 P:     Stephen Hemminger
 M:     shemminger@linux-foundation.org
-L:     netem@osdl.org
+L:     netem@lists.osdl.org
 S:     Maintained
 
 NETFILTER/IPTABLES/IPCHAINS
@@ -2372,7 +2378,7 @@ S:        Maintained
 
 NETWORK DEVICE DRIVERS
 P:     Andrew Morton
-M:     akpm@osdl.org
+M:     akpm@linux-foundation.org
 P:     Jeff Garzik
 M:     jgarzik@pobox.com
 L:     netdev@vger.kernel.org
@@ -2748,7 +2754,7 @@ S:        Supported
 PVRUSB2 VIDEO4LINUX DRIVER
 P:     Mike Isely
 M:     isely@pobox.com
-L:     pvrusb2@isely.net
+L:     pvrusb2@isely.net       (subscribers-only)
 L:     video4linux-list@redhat.com
 W:     http://www.isely.net/pvrusb2/
 S:     Maintained
@@ -3067,7 +3073,7 @@ S:        Supported
 SOFTWARE SUSPEND:
 P:     Pavel Machek
 M:     pavel@suse.cz
-L:     linux-pm@osdl.org
+L:     linux-pm@lists.osdl.org
 S:     Maintained
 
 SONIC NETWORK DRIVER
@@ -3392,6 +3398,13 @@ L:       linux-usb-devel@lists.sourceforge.net
 S:     Maintained
 W:     http://www.kroah.com/linux-usb/
 
+USB DAVICOM DM9601 DRIVER
+P:     Peter Korsgaard
+M:     jacmet@sunsite.dk
+L:     linux-usb-devel@lists.sourceforge.net
+W:     http://www.linux-usb.org/usbnet
+S:     Maintained
+
 USB EHCI DRIVER
 P:     David Brownell
 M:     dbrownell@users.sourceforge.net
index b6c8790..30b66e2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
-SUBLEVEL = 20
-EXTRAVERSION =
+SUBLEVEL = 21
+EXTRAVERSION = -rc1
 NAME = Homicidal Dwarf Hamster
 
 # *DOCUMENTATION*
index 390524c..b8cb79f 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/mach/map.h>
 
 #include <asm/arch/pxa-regs.h>
+#include <asm/arch/gpio.h>
 #include <asm/arch/udc.h>
 #include <asm/arch/pxafb.h>
 #include <asm/arch/mmc.h>
@@ -106,13 +107,16 @@ unsigned long long sched_clock(void)
  * Handy function to set GPIO alternate functions
  */
 
-void pxa_gpio_mode(int gpio_mode)
+int pxa_gpio_mode(int gpio_mode)
 {
        unsigned long flags;
        int gpio = gpio_mode & GPIO_MD_MASK_NR;
        int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8;
        int gafr;
 
+       if (gpio > PXA_LAST_GPIO)
+               return -EINVAL;
+
        local_irq_save(flags);
        if (gpio_mode & GPIO_DFLT_LOW)
                GPCR(gpio) = GPIO_bit(gpio);
@@ -125,11 +129,33 @@ void pxa_gpio_mode(int gpio_mode)
        gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2));
        GAFR(gpio) = gafr |  (fn  << (((gpio) & 0xf)*2));
        local_irq_restore(flags);
+
+       return 0;
 }
 
 EXPORT_SYMBOL(pxa_gpio_mode);
 
 /*
+ * Return GPIO level
+ */
+int pxa_gpio_get_value(unsigned gpio)
+{
+       return __gpio_get_value(gpio);
+}
+
+EXPORT_SYMBOL(pxa_gpio_get_value);
+
+/*
+ * Set output GPIO level
+ */
+void pxa_gpio_set_value(unsigned gpio, int value)
+{
+       __gpio_set_value(gpio, value);
+}
+
+EXPORT_SYMBOL(pxa_gpio_set_value);
+
+/*
  * Routine to safely enable or disable a clock in the CKEN
  */
 void pxa_set_cken(int clock, int enable)
index e510295..192a5a2 100644 (file)
@@ -138,6 +138,36 @@ unsigned long long sched_clock(void)
        return v;
 }
 
+int gpio_direction_input(unsigned gpio)
+{
+       unsigned long flags;
+
+       if (gpio > GPIO_MAX)
+               return -EINVAL;
+
+       local_irq_save(flags);
+       GPDR &= ~GPIO_GPIO(gpio);
+       local_irq_restore(flags);
+       return 0;
+}
+
+EXPORT_SYMBOL(gpio_direction_input);
+
+int gpio_direction_output(unsigned gpio)
+{
+       unsigned long flags;
+
+       if (gpio > GPIO_MAX)
+               return -EINVAL;
+
+       local_irq_save(flags);
+       GPDR |= GPIO_GPIO(gpio);
+       local_irq_restore(flags);
+       return 0;
+}
+
+EXPORT_SYMBOL(gpio_direction_output);
+
 /*
  * Default power-off for SA1100
  */
index f7ac1ae..bd28f9f 100644 (file)
@@ -31,7 +31,7 @@ LDFLAGS_vmlinux := --emit-relocs
 endif
 CHECKFLAGS     += -D__i386__
 
-CFLAGS += -pipe -msoft-float -mregparm=3
+CFLAGS += -pipe -msoft-float -mregparm=3 -freg-struct-return
 
 # prevent gcc from keeping the stack 16 byte aligned
 CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2)
index 9655c23..7a2c9cb 100644 (file)
@@ -38,7 +38,6 @@
 #include <asm/hpet.h>
 #include <asm/i8253.h>
 #include <asm/nmi.h>
-#include <asm/idle.h>
 
 #include <mach_apic.h>
 #include <mach_apicdef.h>
@@ -561,7 +560,6 @@ void fastcall smp_apic_timer_interrupt(struct pt_regs *regs)
         * Besides, if we don't timer interrupts ignore the global
         * interrupt lock, which is the WrongThing (tm) to do.
         */
-       exit_idle();
        irq_enter();
        local_apic_timer_interrupt();
        irq_exit();
@@ -1221,7 +1219,6 @@ void smp_spurious_interrupt(struct pt_regs *regs)
 {
        unsigned long v;
 
-       exit_idle();
        irq_enter();
        /*
         * Check if this really is a spurious interrupt and ACK it
@@ -1245,7 +1242,6 @@ void smp_error_interrupt(struct pt_regs *regs)
 {
        unsigned long v, v1;
 
-       exit_idle();
        irq_enter();
        /* First tickle the hardware, only then report what went on. -- REW */
        v = apic_read(APIC_ESR);
index 8359c19..504434a 100644 (file)
@@ -12,7 +12,6 @@
 #include <asm/system.h>
 #include <asm/msr.h>
 #include <asm/apic.h>
-#include <asm/idle.h>
 
 #include <asm/therm_throt.h>
 
@@ -60,7 +59,6 @@ static void (*vendor_thermal_interrupt)(struct pt_regs *regs) = unexpected_therm
 
 fastcall void smp_thermal_interrupt(struct pt_regs *regs)
 {
-       exit_idle();
        irq_enter();
        vendor_thermal_interrupt(regs);
        irq_exit();
index 4ccebd4..6fec4da 100644 (file)
@@ -343,7 +343,7 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
                        break;
                entry = irq_2_pin + entry->next;
        }
-       set_native_irq_info(irq, cpumask);
+       irq_desc[irq].affinity = cpumask;
        spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
@@ -1354,7 +1354,7 @@ static void __init setup_IO_APIC_irqs(void)
                }
                spin_lock_irqsave(&ioapic_lock, flags);
                __ioapic_write_entry(apic, pin, entry);
-               set_native_irq_info(irq, TARGET_CPUS);
+               irq_desc[irq].affinity = TARGET_CPUS;
                spin_unlock_irqrestore(&ioapic_lock, flags);
        }
        }
@@ -2585,7 +2585,7 @@ static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
        msg.address_lo |= MSI_ADDR_DEST_ID(dest);
 
        write_msi_msg(irq, &msg);
-       set_native_irq_info(irq, mask);
+       irq_desc[irq].affinity = mask;
 }
 #endif /* CONFIG_SMP */
 
@@ -2669,7 +2669,7 @@ static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
        dest = cpu_mask_to_apicid(mask);
 
        target_ht_irq(irq, dest);
-       set_native_irq_info(irq, mask);
+       irq_desc[irq].affinity = mask;
 }
 #endif
 
@@ -2875,7 +2875,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a
 
        spin_lock_irqsave(&ioapic_lock, flags);
        __ioapic_write_entry(ioapic, pin, entry);
-       set_native_irq_info(irq, TARGET_CPUS);
+       irq_desc[irq].affinity = TARGET_CPUS;
        spin_unlock_irqrestore(&ioapic_lock, flags);
 
        return 0;
index 0f2ca59..8db8d51 100644 (file)
@@ -18,8 +18,6 @@
 #include <linux/cpu.h>
 #include <linux/delay.h>
 
-#include <asm/idle.h>
-
 #include <asm/apic.h>
 #include <asm/uaccess.h>
 
@@ -77,7 +75,6 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
        union irq_ctx *curctx, *irqctx;
        u32 *isp;
 #endif
-       exit_idle();
 
        if (unlikely((unsigned)irq >= NR_IRQS)) {
                printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
index bea304d..393a67d 100644 (file)
@@ -49,7 +49,6 @@
 #include <asm/i387.h>
 #include <asm/desc.h>
 #include <asm/vm86.h>
-#include <asm/idle.h>
 #ifdef CONFIG_MATH_EMULATION
 #include <asm/math_emu.h>
 #endif
@@ -82,42 +81,6 @@ void (*pm_idle)(void);
 EXPORT_SYMBOL(pm_idle);
 static DEFINE_PER_CPU(unsigned int, cpu_idle_state);
 
-static ATOMIC_NOTIFIER_HEAD(idle_notifier);
-
-void idle_notifier_register(struct notifier_block *n)
-{
-       atomic_notifier_chain_register(&idle_notifier, n);
-}
-
-void idle_notifier_unregister(struct notifier_block *n)
-{
-       atomic_notifier_chain_unregister(&idle_notifier, n);
-}
-
-static DEFINE_PER_CPU(volatile unsigned long, idle_state);
-
-void enter_idle(void)
-{
-       /* needs to be atomic w.r.t. interrupts, not against other CPUs */
-       __set_bit(0, &__get_cpu_var(idle_state));
-       atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL);
-}
-
-static void __exit_idle(void)
-{
-       /* needs to be atomic w.r.t. interrupts, not against other CPUs */
-       if (__test_and_clear_bit(0, &__get_cpu_var(idle_state)) == 0)
-               return;
-       atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL);
-}
-
-void exit_idle(void)
-{
-       if (current->pid)
-               return;
-       __exit_idle();
-}
-
 void disable_hlt(void)
 {
        hlt_counter++;
@@ -168,7 +131,6 @@ EXPORT_SYMBOL(default_idle);
  */
 static void poll_idle (void)
 {
-       local_irq_enable();
        cpu_relax();
 }
 
@@ -229,16 +191,7 @@ void cpu_idle(void)
                                play_dead();
 
                        __get_cpu_var(irq_stat).idle_timestamp = jiffies;
-
-                       /*
-                        * Idle routines should keep interrupts disabled
-                        * from here on, until they go to idle.
-                        * Otherwise, idle callbacks can misfire.
-                        */
-                       local_irq_disable();
-                       enter_idle();
                        idle();
-                       __exit_idle();
                }
                tick_nohz_restart_sched_tick();
                preempt_enable_no_resched();
@@ -293,11 +246,7 @@ void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
                __monitor((void *)&current_thread_info()->flags, 0, 0);
                smp_mb();
                if (!need_resched())
-                       __sti_mwait(eax, ecx);
-               else
-                       local_irq_enable();
-       } else {
-               local_irq_enable();
+                       __mwait(eax, ecx);
        }
 }
 
index 9bd9637..0e89778 100644 (file)
@@ -23,7 +23,6 @@
 
 #include <asm/mtrr.h>
 #include <asm/tlbflush.h>
-#include <asm/idle.h>
 #include <mach_apic.h>
 
 /*
@@ -624,7 +623,6 @@ fastcall void smp_call_function_interrupt(struct pt_regs *regs)
        /*
         * At this point the info structure may be out of scope unless wait==1
         */
-       exit_idle();
        irq_enter();
        (*func)(info);
        irq_exit();
index 0d05450..e722090 100644 (file)
@@ -60,7 +60,7 @@ static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
        msg.address_lo = addr;
 
        write_msi_msg(irq, &msg);
-       set_native_irq_info(irq, cpu_mask);
+       irq_desc[irq].affinity = cpu_mask;
 }
 #endif /* CONFIG_SMP */
 
index ea3dc38..49873aa 100644 (file)
@@ -204,7 +204,7 @@ static void sn_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
        msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);
 
        write_msi_msg(irq, &msg);
-       set_native_irq_info(irq, cpu_mask);
+       irq_desc[irq].affinity = cpu_mask;
 }
 #endif /* CONFIG_SMP */
 
index c6f74f1..58e9788 100644 (file)
@@ -274,6 +274,7 @@ config MIPS_ATLAS
        select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_SUPPORTS_LITTLE_ENDIAN
        select SYS_SUPPORTS_MULTITHREADING if EXPERIMENTAL
+       select SYS_SUPPORTS_SMARTMIPS
        select GENERIC_HARDIRQS_NO__DO_IRQ
        help
          This enables support for the MIPS Technologies Atlas evaluation
@@ -305,6 +306,7 @@ config MIPS_MALTA
        select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_SUPPORTS_LITTLE_ENDIAN
        select SYS_SUPPORTS_MULTITHREADING
+       select SYS_SUPPORTS_SMARTMIPS
        help
          This enables support for the MIPS Technologies Malta evaluation
          board.
@@ -322,6 +324,7 @@ config MIPS_SEAD
        select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
        select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_SUPPORTS_LITTLE_ENDIAN
+       select SYS_SUPPORTS_SMARTMIPS
        help
          This enables support for the MIPS Technologies SEAD evaluation
          board.
@@ -1641,6 +1644,18 @@ config 64BIT_PHYS_ADDR
 config CPU_HAS_LLSC
        bool
 
+config CPU_HAS_SMARTMIPS
+       depends on SYS_SUPPORTS_SMARTMIPS
+       bool "Support for the SmartMIPS ASE"
+       help
+         SmartMIPS is a extension of the MIPS32 architecture aimed at
+         increased security at both hardware and software level for
+         smartcards.  Enabling this option will allow proper use of the
+         SmartMIPS instructions by Linux applications.  However a kernel with
+         this option will not work on a MIPS core without SmartMIPS core.  If
+         you don't know you probably don't have SmartMIPS and should say N
+         here.
+
 config CPU_HAS_WB
        bool
 
@@ -1704,6 +1719,9 @@ config CPU_SUPPORTS_HIGHMEM
 config SYS_SUPPORTS_HIGHMEM
        bool
 
+config SYS_SUPPORTS_SMARTMIPS
+       bool
+
 config ARCH_FLATMEM_ENABLE
        def_bool y
        depends on !NUMA
index c68b5d3..92bca6a 100644 (file)
@@ -103,6 +103,8 @@ predef-le += -DMIPSEL -D_MIPSEL -D__MIPSEL -D__MIPSEL__
 cflags-$(CONFIG_CPU_BIG_ENDIAN)                += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' && echo -EB $(undef-all) $(predef-be))
 cflags-$(CONFIG_CPU_LITTLE_ENDIAN)     += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' || echo -EL $(undef-all) $(predef-le))
 
+cflags-$(CONFIG_CPU_HAS_SMARTMIPS)     += $(call cc-option,-msmartmips)
+
 cflags-$(CONFIG_SB1XXX_CORELIS)        += $(call cc-option,-mno-sched-prolog) \
                                   -fno-omit-frame-pointer
 
index 01d8ec7..2b088ef 100644 (file)
@@ -24,7 +24,7 @@
 
 static struct mtd_partition cobalt_mtd_partitions[] = {
        {
-               .name   = "Colo",
+               .name   = "firmware",
                .offset = 0x0,
                .size   = 0x80000,
        },
index 45874d1..4588949 100644 (file)
@@ -139,10 +139,12 @@ CONFIG_MIPS_MT_DISABLED=y
 CONFIG_SYS_SUPPORTS_MULTITHREADING=y
 # CONFIG_64BIT_PHYS_ADDR is not set
 CONFIG_CPU_HAS_LLSC=y
+# CONFIG_CPU_HAS_SMARTMIPS is not set
 CONFIG_CPU_HAS_SYNC=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_SYS_SUPPORTS_SMARTMIPS=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
index b4cdd3e..aa05e29 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:35 2007
+# Tue Feb 20 21:47:22 2007
 #
 CONFIG_MIPS=y
 
@@ -417,6 +417,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -589,6 +590,7 @@ CONFIG_NET_SB1250_MAC=y
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 # CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -1025,7 +1027,6 @@ CONFIG_FORCED_INLINING=y
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
 # CONFIG_DEBUG_STACK_USAGE is not set
-# CONFIG_KGDB is not set
 # CONFIG_SB1XXX_CORELIS is not set
 # CONFIG_RUNTIME_DEBUG is not set
 
index b05469e..b2594fa 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:36 2007
+# Tue Feb 20 21:47:22 2007
 #
 CONFIG_MIPS=y
 
@@ -388,6 +388,7 @@ CONFIG_CONNECTOR=m
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
index f88c40f..9090a7a 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Mon Feb 19 14:51:58 2007
+# Tue Feb 20 21:47:24 2007
 #
 CONFIG_MIPS=y
 
@@ -425,7 +425,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
 CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_PHYSMAP_START=0x0
-CONFIG_MTD_PHYSMAP_LEN=0
+CONFIG_MTD_PHYSMAP_LEN=0x0
 CONFIG_MTD_PHYSMAP_BANKWIDTH=0
 # CONFIG_MTD_PLATRAM is not set
 
@@ -449,7 +449,6 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=0
 # NAND Flash Device Drivers
 #
 # CONFIG_MTD_NAND is not set
-# CONFIG_MTD_NAND_CAFE is not set
 
 #
 # OneNAND Flash Device Drivers
@@ -464,6 +463,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=0
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -658,6 +658,7 @@ CONFIG_TULIP=y
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 CONFIG_QLA3XXX=y
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
index 1db19f1..4cb8cf4 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:39 2007
+# Tue Feb 20 21:47:24 2007
 #
 CONFIG_MIPS=y
 
@@ -548,6 +548,7 @@ CONFIG_MTD_ALCHEMY=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -1103,6 +1104,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
+CONFIG_SYS_SUPPORTS_KGDB=y
 
 #
 # Security options
index 529e6eb..d86dedf 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:39 2007
+# Tue Feb 20 21:47:24 2007
 #
 CONFIG_MIPS=y
 
@@ -537,6 +537,7 @@ CONFIG_MTD_ALCHEMY=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -1103,6 +1104,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
+CONFIG_SYS_SUPPORTS_KGDB=y
 
 #
 # Security options
index 9e86dcd..c24b600 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:40 2007
+# Tue Feb 20 21:47:25 2007
 #
 CONFIG_MIPS=y
 
@@ -541,6 +541,7 @@ CONFIG_MTD_NAND_IDS=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -1185,6 +1186,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE="mem=48M"
+CONFIG_SYS_SUPPORTS_KGDB=y
 
 #
 # Security options
index 9c94461..baad2c5 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:41 2007
+# Tue Feb 20 21:47:26 2007
 #
 CONFIG_MIPS=y
 
@@ -542,7 +542,6 @@ CONFIG_MTD_ALCHEMY=y
 # NAND Flash Device Drivers
 #
 # CONFIG_MTD_NAND is not set
-# CONFIG_MTD_NAND_CAFE is not set
 
 #
 # OneNAND Flash Device Drivers
@@ -557,6 +556,7 @@ CONFIG_MTD_ALCHEMY=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -715,6 +715,7 @@ CONFIG_MIPS_AU1X00_ENET=y
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 CONFIG_QLA3XXX=m
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -1145,6 +1146,7 @@ CONFIG_USB_MON=y
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
@@ -1402,6 +1404,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
+CONFIG_SYS_SUPPORTS_KGDB=y
 
 #
 # Security options
index 5b18d5d..c29fdab 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:42 2007
+# Tue Feb 20 21:47:27 2007
 #
 CONFIG_MIPS=y
 
@@ -562,6 +562,7 @@ CONFIG_MTD_NAND_AU1550=m
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -751,6 +752,7 @@ CONFIG_MIPS_AU1X00_ENET=y
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 CONFIG_QLA3XXX=m
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -1219,6 +1221,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
+CONFIG_SYS_SUPPORTS_KGDB=y
 
 #
 # Security options
index 1210188..f4b316d 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:43 2007
+# Tue Feb 20 21:47:28 2007
 #
 CONFIG_MIPS=y
 
@@ -386,6 +386,7 @@ CONFIG_PROC_EVENTS=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -925,6 +926,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE="ip=any"
+CONFIG_SYS_SUPPORTS_KGDB=y
 
 #
 # Security options
index 2d71745..9c38e5c 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:44 2007
+# Tue Feb 20 21:47:28 2007
 #
 CONFIG_MIPS=y
 
@@ -398,6 +398,7 @@ CONFIG_CONNECTOR=m
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
index 0ee2fbb..922af37 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:44 2007
+# Tue Feb 20 21:47:28 2007
 #
 CONFIG_MIPS=y
 
@@ -294,6 +294,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # Plug and Play support
 #
 # CONFIG_PNP is not set
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
index 218fe6e..c0db8f1 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:46 2007
+# Tue Feb 20 21:47:29 2007
 #
 CONFIG_MIPS=y
 
@@ -611,7 +611,6 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
 # NAND Flash Device Drivers
 #
 # CONFIG_MTD_NAND is not set
-# CONFIG_MTD_NAND_CAFE is not set
 
 #
 # OneNAND Flash Device Drivers
@@ -626,6 +625,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -1039,6 +1039,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
 # CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ADM9240 is not set
 # CONFIG_SENSORS_ASB100 is not set
index 5ad4870..ce088b3 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:46 2007
+# Tue Feb 20 21:47:30 2007
 #
 CONFIG_MIPS=y
 
@@ -391,6 +391,7 @@ CONFIG_CONNECTOR=m
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -520,6 +521,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 CONFIG_QLA3XXX=m
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -914,6 +916,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs rw nfsroot=192.168.1.1:/mnt/disk2/fs.gal ip=192.168.1.211:192.168.1.1:::gt::"
+CONFIG_SYS_SUPPORTS_KGDB=y
 
 #
 # Security options
index 5e179fe..82f204d 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:47 2007
+# Tue Feb 20 21:47:31 2007
 #
 CONFIG_MIPS=y
 
@@ -451,6 +451,7 @@ CONFIG_MTD_NAND_VERIFY_WRITE=y
 # CONFIG_MTD_NAND_ECC_SMC is not set
 CONFIG_MTD_NAND_IDS=y
 # CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_BASLER_EXCITE is not set
 # CONFIG_MTD_NAND_CAFE is not set
 # CONFIG_MTD_NAND_NANDSIM is not set
 
@@ -467,6 +468,7 @@ CONFIG_MTD_NAND_IDS=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -638,6 +640,7 @@ CONFIG_NETDEVICES=y
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 CONFIG_QLA3XXX=m
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -1008,6 +1011,7 @@ CONFIG_USB_HID=m
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
@@ -1277,6 +1281,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
+CONFIG_SYS_SUPPORTS_KGDB=y
 
 #
 # Security options
index 864de21..cb81f13 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:48 2007
+# Tue Feb 20 21:47:32 2007
 #
 CONFIG_MIPS=y
 
@@ -620,6 +620,7 @@ CONFIG_CONNECTOR=m
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
index 7b2f5f8..46f6ac4 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:49 2007
+# Tue Feb 20 21:47:32 2007
 #
 CONFIG_MIPS=y
 
@@ -456,6 +456,7 @@ CONFIG_CONNECTOR=m
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -672,6 +673,7 @@ CONFIG_SGI_IOC3_ETH=y
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 CONFIG_QLA3XXX=m
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -1060,6 +1062,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_LOG_BUF_SHIFT=15
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
+CONFIG_SYS_SUPPORTS_KGDB=y
 
 #
 # Security options
index 14398e8..d9e5000 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:50 2007
+# Tue Feb 20 21:47:33 2007
 #
 CONFIG_MIPS=y
 
@@ -396,6 +396,7 @@ CONFIG_PROC_EVENTS=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -600,6 +601,7 @@ CONFIG_SGI_O2MACE_ETH=y
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 CONFIG_QLA3XXX=y
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
index b389787..57ef0c4 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:51 2007
+# Tue Feb 20 21:47:33 2007
 #
 CONFIG_MIPS=y
 
@@ -375,6 +375,7 @@ CONFIG_CONNECTOR=m
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -518,9 +519,6 @@ CONFIG_EEPRO100=y
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 CONFIG_MV643XX_ETH=y
-CONFIG_MV643XX_ETH_0=y
-CONFIG_MV643XX_ETH_1=y
-CONFIG_MV643XX_ETH_2=y
 CONFIG_QLA3XXX=m
 
 #
@@ -833,6 +831,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
+CONFIG_SYS_SUPPORTS_KGDB=y
 
 #
 # Security options
index dacf0a6..21d979f 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:52 2007
+# Tue Feb 20 21:47:33 2007
 #
 CONFIG_MIPS=y
 
@@ -646,6 +646,7 @@ CONFIG_PARPORT_1284=y
 # Plug and Play support
 #
 # CONFIG_PNP is not set
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
index 29ed772..9ebb522 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:53 2007
+# Tue Feb 20 21:47:34 2007
 #
 CONFIG_MIPS=y
 
@@ -384,6 +384,7 @@ CONFIG_PROC_EVENTS=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -513,6 +514,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 CONFIG_QLA3XXX=y
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
index a1437b3..b3f767f 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:54 2007
+# Tue Feb 20 21:47:34 2007
 #
 CONFIG_MIPS=y
 
@@ -454,7 +454,6 @@ CONFIG_MTD_LASAT=y
 # NAND Flash Device Drivers
 #
 # CONFIG_MTD_NAND is not set
-# CONFIG_MTD_NAND_CAFE is not set
 
 #
 # OneNAND Flash Device Drivers
@@ -469,6 +468,7 @@ CONFIG_MTD_LASAT=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -654,6 +654,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 CONFIG_QLA3XXX=m
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
index 8d21bb9..a5f379d 100644 (file)
@@ -145,6 +145,7 @@ CONFIG_SYS_SUPPORTS_MULTITHREADING=y
 CONFIG_MIPS_MT_FPAFF=y
 # CONFIG_64BIT_PHYS_ADDR is not set
 CONFIG_CPU_HAS_LLSC=y
+# CONFIG_CPU_HAS_SMARTMIPS is not set
 CONFIG_CPU_MIPSR2_IRQ_VI=y
 CONFIG_CPU_MIPSR2_SRS=y
 CONFIG_CPU_HAS_SYNC=y
@@ -152,6 +153,7 @@ CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_IRQ_PER_CPU=y
 CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_SYS_SUPPORTS_SMARTMIPS=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
index 2acb99b..5ff53e1 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:56 2007
+# Tue Feb 20 21:47:35 2007
 #
 CONFIG_MIPS=y
 
@@ -436,6 +436,7 @@ CONFIG_FIB_RULES=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -878,7 +879,6 @@ CONFIG_FORCED_INLINING=y
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE="nfsroot=192.168.192.169:/u1/mipsel,timeo=20 ip=dhcp"
 # CONFIG_DEBUG_STACK_USAGE is not set
-# CONFIG_KGDB is not set
 # CONFIG_RUNTIME_DEBUG is not set
 # CONFIG_MIPS_UNCACHED is not set
 
index d52a5a4..750e644 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:56 2007
+# Tue Feb 20 21:47:35 2007
 #
 CONFIG_MIPS=y
 
@@ -405,6 +405,7 @@ CONFIG_CONNECTOR=m
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -531,6 +532,7 @@ CONFIG_MII=m
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 CONFIG_QLA3XXX=m
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -883,6 +885,7 @@ CONFIG_USB_PEGASUS=m
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
index 746106b..2febd0a 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:58 2007
+# Tue Feb 20 21:47:35 2007
 #
 CONFIG_MIPS=y
 
@@ -496,6 +496,7 @@ CONFIG_CONNECTOR=m
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -713,9 +714,6 @@ CONFIG_E100=y
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 CONFIG_MV643XX_ETH=y
-CONFIG_MV643XX_ETH_0=y
-CONFIG_MV643XX_ETH_1=y
-CONFIG_MV643XX_ETH_2=y
 CONFIG_QLA3XXX=m
 # CONFIG_ATL1 is not set
 
index 4b32b27..b8f4573 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:58 2007
+# Tue Feb 20 21:47:36 2007
 #
 CONFIG_MIPS=y
 
@@ -393,6 +393,7 @@ CONFIG_PROC_EVENTS=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -523,6 +524,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_BNX2 is not set
 # CONFIG_MV643XX_ETH is not set
 CONFIG_QLA3XXX=y
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
index 674631b..8ade072 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:59 2007
+# Tue Feb 20 21:47:36 2007
 #
 CONFIG_MIPS=y
 
@@ -390,6 +390,7 @@ CONFIG_PROC_EVENTS=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -854,6 +855,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
+CONFIG_SYS_SUPPORTS_KGDB=y
 
 #
 # Security options
index 2600263..d20a221 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:28:00 2007
+# Tue Feb 20 21:47:36 2007
 #
 CONFIG_MIPS=y
 
@@ -392,6 +392,7 @@ CONFIG_PROC_EVENTS=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -522,6 +523,7 @@ CONFIG_GALILEO_64240_ETH=y
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 CONFIG_QLA3XXX=y
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
index 05a33a2..33fcc81 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:28:01 2007
+# Tue Feb 20 21:47:37 2007
 #
 CONFIG_MIPS=y
 
@@ -549,6 +549,7 @@ CONFIG_MTD_ALCHEMY=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -1096,6 +1097,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
+CONFIG_SYS_SUPPORTS_KGDB=y
 
 #
 # Security options
index 34a6bee..e07c55d 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:28:02 2007
+# Tue Feb 20 21:47:37 2007
 #
 CONFIG_MIPS=y
 
@@ -541,7 +541,6 @@ CONFIG_MTD_ALCHEMY=y
 # NAND Flash Device Drivers
 #
 # CONFIG_MTD_NAND is not set
-# CONFIG_MTD_NAND_CAFE is not set
 
 #
 # OneNAND Flash Device Drivers
@@ -556,6 +555,7 @@ CONFIG_MTD_ALCHEMY=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -745,6 +745,7 @@ CONFIG_MIPS_AU1X00_ENET=y
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 CONFIG_QLA3XXX=m
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -1213,6 +1214,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
+CONFIG_SYS_SUPPORTS_KGDB=y
 
 #
 # Security options
index e3bff46..df210dd 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:28:03 2007
+# Tue Feb 20 21:47:37 2007
 #
 CONFIG_MIPS=y
 
@@ -542,7 +542,6 @@ CONFIG_MTD_ALCHEMY=y
 # NAND Flash Device Drivers
 #
 # CONFIG_MTD_NAND is not set
-# CONFIG_MTD_NAND_CAFE is not set
 
 #
 # OneNAND Flash Device Drivers
@@ -557,6 +556,7 @@ CONFIG_MTD_ALCHEMY=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -746,6 +746,7 @@ CONFIG_MIPS_AU1X00_ENET=y
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 CONFIG_QLA3XXX=m
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -1206,6 +1207,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
+CONFIG_SYS_SUPPORTS_KGDB=y
 
 #
 # Security options
index 009b3f8..106a164 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:28:04 2007
+# Tue Feb 20 21:47:38 2007
 #
 CONFIG_MIPS=y
 
@@ -389,6 +389,7 @@ CONFIG_FW_LOADER=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -962,6 +963,7 @@ CONFIG_USB_MON=y
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
@@ -1229,6 +1231,7 @@ CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE="console=ttyS1,38400n8 kgdb=ttyS0 root=/dev/nfs ip=bootp"
 # CONFIG_DEBUG_STACK_USAGE is not set
 # CONFIG_KGDB is not set
+CONFIG_SYS_SUPPORTS_KGDB=y
 # CONFIG_RUNTIME_DEBUG is not set
 # CONFIG_MIPS_UNCACHED is not set
 
index 5bd377b..8caa2cd 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:28:04 2007
+# Tue Feb 20 21:47:38 2007
 #
 CONFIG_MIPS=y
 
@@ -386,6 +386,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -952,6 +953,7 @@ CONFIG_USB_MON=y
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
@@ -1219,6 +1221,7 @@ CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE="console=ttyS1,38400n8 kgdb=ttyS0 root=/dev/nfs ip=bootp"
 # CONFIG_DEBUG_STACK_USAGE is not set
 # CONFIG_KGDB is not set
+CONFIG_SYS_SUPPORTS_KGDB=y
 # CONFIG_RUNTIME_DEBUG is not set
 # CONFIG_MIPS_UNCACHED is not set
 
index cc69470..43f1bec 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:28:06 2007
+# Tue Feb 20 21:47:39 2007
 #
 CONFIG_MIPS=y
 
@@ -474,6 +474,7 @@ CONFIG_FW_LOADER=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -987,6 +988,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
 # CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ADM9240 is not set
 # CONFIG_SENSORS_ASB100 is not set
@@ -1209,6 +1211,7 @@ CONFIG_USB_MON=y
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
@@ -1466,6 +1469,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
+CONFIG_SYS_SUPPORTS_KGDB=y
 
 #
 # Security options
index c18c5e7..f68396d 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:28:06 2007
+# Tue Feb 20 21:47:39 2007
 #
 CONFIG_MIPS=y
 
@@ -348,6 +348,7 @@ CONFIG_PROC_EVENTS=y
 # Plug and Play support
 #
 # CONFIG_PNP is not set
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
index 678f232..a6a824f 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:28:07 2007
+# Tue Feb 20 21:47:39 2007
 #
 CONFIG_MIPS=y
 
@@ -560,7 +560,6 @@ CONFIG_MTD_CFI_UTIL=y
 # NAND Flash Device Drivers
 #
 # CONFIG_MTD_NAND is not set
-# CONFIG_MTD_NAND_CAFE is not set
 
 #
 # OneNAND Flash Device Drivers
@@ -576,6 +575,7 @@ CONFIG_MTD_CFI_UTIL=y
 # Plug and Play support
 #
 # CONFIG_PNP is not set
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -1191,6 +1191,7 @@ CONFIG_USB_MON=y
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
@@ -1462,6 +1463,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
+CONFIG_SYS_SUPPORTS_KGDB=y
 
 #
 # Security options
index 0417e86..bee3702 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:28:09 2007
+# Tue Feb 20 21:47:40 2007
 #
 CONFIG_MIPS=y
 
@@ -661,6 +661,7 @@ CONFIG_PARPORT_NOT_PC=y
 # Plug and Play support
 #
 # CONFIG_PNP is not set
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -1397,6 +1398,7 @@ CONFIG_USB_AUERSWALD=m
 CONFIG_USB_RIO500=m
 CONFIG_USB_LEGOTOWER=m
 CONFIG_USB_LCD=m
+# CONFIG_USB_BERRY_CHARGE is not set
 CONFIG_USB_LED=m
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 CONFIG_USB_CYTHERM=m
index 533df6f..3c891ed 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:28:09 2007
+# Tue Feb 20 21:47:40 2007
 #
 CONFIG_MIPS=y
 
@@ -424,6 +424,7 @@ CONFIG_CONNECTOR=m
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -581,6 +582,7 @@ CONFIG_NET_SB1250_MAC=y
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 CONFIG_QLA3XXX=m
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -945,6 +947,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_LOG_BUF_SHIFT=15
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
+CONFIG_SYS_SUPPORTS_KGDB=y
 # CONFIG_SB1XXX_CORELIS is not set
 
 #
index 38816fe..e31d964 100644 (file)
@@ -129,10 +129,12 @@ CONFIG_MIPS_MT_DISABLED=y
 # CONFIG_MIPS_VPE_LOADER is not set
 # CONFIG_64BIT_PHYS_ADDR is not set
 CONFIG_CPU_HAS_LLSC=y
+# CONFIG_CPU_HAS_SMARTMIPS is not set
 CONFIG_CPU_HAS_SYNC=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_SYS_SUPPORTS_SMARTMIPS=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
index c2f7c8c..5771c1a 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:28:11 2007
+# Tue Feb 20 21:47:41 2007
 #
 CONFIG_MIPS=y
 
@@ -396,6 +396,7 @@ CONFIG_CONNECTOR=m
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -920,6 +921,7 @@ CONFIG_USB_STORAGE=y
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
index 33b7880..a8eb4b1 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:28:12 2007
+# Tue Feb 20 21:47:41 2007
 #
 CONFIG_MIPS=y
 
@@ -397,6 +397,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -530,6 +531,7 @@ CONFIG_R8169=y
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 CONFIG_QLA3XXX=m
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -819,6 +821,7 @@ CONFIG_USB_MON=y
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
index d180586..69b8730 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:28:13 2007
+# Tue Feb 20 21:47:41 2007
 #
 CONFIG_MIPS=y
 
@@ -409,6 +409,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -675,6 +676,7 @@ CONFIG_R8169=y
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 # CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -1016,6 +1018,7 @@ CONFIG_USB_MON=y
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
index 570f0c1..2abbd68 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:28:13 2007
+# Tue Feb 20 21:47:42 2007
 #
 CONFIG_MIPS=y
 
@@ -396,6 +396,7 @@ CONFIG_CONNECTOR=m
 # Plug and Play support
 #
 # CONFIG_PNP is not set
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
index 08f3190..44b6b7c 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:28:14 2007
+# Tue Feb 20 21:47:42 2007
 #
 CONFIG_MIPS=y
 
@@ -400,6 +400,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
index aa69fee..f24e1c6 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:28:15 2007
+# Tue Feb 20 21:47:42 2007
 #
 CONFIG_MIPS=y
 
@@ -381,6 +381,7 @@ CONFIG_CONNECTOR=m
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -841,6 +842,7 @@ CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
 # CONFIG_DEBUG_STACK_USAGE is not set
 # CONFIG_KGDB is not set
+CONFIG_SYS_SUPPORTS_KGDB=y
 # CONFIG_RUNTIME_DEBUG is not set
 
 #
index 6c2a233..8cb8f59 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.20
-# Sun Feb 18 21:27:34 2007
+# Tue Feb 20 21:47:14 2007
 #
 CONFIG_MIPS=y
 
@@ -620,6 +620,7 @@ CONFIG_CONNECTOR=m
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
index c0b089d..222de46 100644 (file)
@@ -64,6 +64,9 @@ void output_ptreg_defines(void)
        offset("#define PT_R31    ", struct pt_regs, regs[31]);
        offset("#define PT_LO     ", struct pt_regs, lo);
        offset("#define PT_HI     ", struct pt_regs, hi);
+#ifdef CONFIG_CPU_HAS_SMARTMIPS
+       offset("#define PT_ACX    ", struct pt_regs, acx);
+#endif
        offset("#define PT_EPC    ", struct pt_regs, cp0_epc);
        offset("#define PT_BVADDR ", struct pt_regs, cp0_badvaddr);
        offset("#define PT_STATUS ", struct pt_regs, cp0_status);
@@ -246,6 +249,7 @@ void output_sc_defines(void)
        text("/* Linux sigcontext offsets. */");
        offset("#define SC_REGS       ", struct sigcontext, sc_regs);
        offset("#define SC_FPREGS     ", struct sigcontext, sc_fpregs);
+       offset("#define SC_ACX        ", struct sigcontext, sc_acx);
        offset("#define SC_MDHI       ", struct sigcontext, sc_mdhi);
        offset("#define SC_MDLO       ", struct sigcontext, sc_mdlo);
        offset("#define SC_PC         ", struct sigcontext, sc_pc);
index 258d74f..201ae19 100644 (file)
@@ -236,6 +236,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                case MMLO:
                        tmp = regs->lo;
                        break;
+#ifdef CONFIG_CPU_HAS_SMARTMIPS
+               case ACX:
+                       tmp = regs->acx;
+                       break;
+#endif
                case FPC_CSR:
                        tmp = child->thread.fpu.fcr31;
                        break;
@@ -362,6 +367,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                case MMLO:
                        regs->lo = data;
                        break;
+#ifdef CONFIG_CPU_HAS_SMARTMIPS
+               case ACX:
+                       regs->acx = data;
+                       break;
+#endif
                case FPC_CSR:
                        child->thread.fpu.fcr31 = data;
                        break;
index adbfb95..f091786 100644 (file)
@@ -89,6 +89,9 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
        for (i = 1; i < 32; i++)
                err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
 
+#ifdef CONFIG_CPU_HAS_SMARTMIPS
+       err |= __put_user(regs->acx, &sc->sc_acx);
+#endif
        err |= __put_user(regs->hi, &sc->sc_mdhi);
        err |= __put_user(regs->lo, &sc->sc_mdlo);
        if (cpu_has_dsp) {
@@ -132,6 +135,10 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
        current_thread_info()->restart_block.fn = do_no_restart_syscall;
 
        err |= __get_user(regs->cp0_epc, &sc->sc_pc);
+
+#ifdef CONFIG_CPU_HAS_SMARTMIPS
+       err |= __get_user(regs->acx, &sc->sc_acx);
+#endif
        err |= __get_user(regs->hi, &sc->sc_mdhi);
        err |= __get_user(regs->lo, &sc->sc_mdlo);
        if (cpu_has_dsp) {
index 0555fc5..c46e479 100644 (file)
@@ -51,31 +51,14 @@ int __cpu_logical_map[NR_CPUS];             /* Map logical to physical */
 EXPORT_SYMBOL(phys_cpu_present_map);
 EXPORT_SYMBOL(cpu_online_map);
 
+/* This happens early in bootup, can't really do it better */
 static void smp_tune_scheduling (void)
 {
        struct cache_desc *cd = &current_cpu_data.scache;
-       unsigned long cachesize;       /* kB   */
-       unsigned long cpu_khz;
+       unsigned long cachesize = cd->linesz * cd->sets * cd->ways;
 
-       /*
-        * Crude estimate until we actually meassure ...
-        */
-       cpu_khz = loops_per_jiffy * 2 * HZ / 1000;
-
-       /*
-        * Rough estimation for SMP scheduling, this is the number of
-        * cycles it takes for a fully memory-limited process to flush
-        * the SMP-local cache.
-        *
-        * (For a P5 this pretty much means we will choose another idle
-        *  CPU almost always at wakeup time (this is due to the small
-        *  L1 cache), on PIIs it's around 50-100 usecs, depending on
-        *  the cache size)
-        */
-       if (!cpu_khz)
-               return;
-
-       cachesize = cd->linesz * cd->sets * cd->ways;
+       if (cachesize > max_cache_size)
+               max_cache_size = cachesize;
 }
 
 extern void __init calibrate_delay(void);
index 2aa208b..18f56a9 100644 (file)
@@ -229,6 +229,9 @@ void show_regs(struct pt_regs *regs)
                        printk("\n");
        }
 
+#ifdef CONFIG_CPU_HAS_SMARTMIPS
+       printk("Acx    : %0*lx\n", field, regs->acx);
+#endif
        printk("Hi    : %0*lx\n", field, regs->hi);
        printk("Lo    : %0*lx\n", field, regs->lo);
 
index fc2c96f..cea7d0e 100644 (file)
@@ -6,13 +6,98 @@
  * (C) Copyright 1995 1996 Linus Torvalds
  * (C) Copyright 2001, 2002 Ralf Baechle
  */
-#include <linux/mm.h>
 #include <linux/module.h>
 #include <asm/addrspace.h>
 #include <asm/byteorder.h>
 
 #include <linux/vmalloc.h>
-#include <linux/io.h>
+#include <asm/cacheflush.h>
+#include <asm/io.h>
+#include <asm/tlbflush.h>
+
+static inline void remap_area_pte(pte_t * pte, unsigned long address,
+       phys_t size, phys_t phys_addr, unsigned long flags)
+{
+       phys_t end;
+       unsigned long pfn;
+       pgprot_t pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | __READABLE
+                                  | __WRITEABLE | flags);
+
+       address &= ~PMD_MASK;
+       end = address + size;
+       if (end > PMD_SIZE)
+               end = PMD_SIZE;
+       if (address >= end)
+               BUG();
+       pfn = phys_addr >> PAGE_SHIFT;
+       do {
+               if (!pte_none(*pte)) {
+                       printk("remap_area_pte: page already exists\n");
+                       BUG();
+               }
+               set_pte(pte, pfn_pte(pfn, pgprot));
+               address += PAGE_SIZE;
+               pfn++;
+               pte++;
+       } while (address && (address < end));
+}
+
+static inline int remap_area_pmd(pmd_t * pmd, unsigned long address,
+       phys_t size, phys_t phys_addr, unsigned long flags)
+{
+       phys_t end;
+
+       address &= ~PGDIR_MASK;
+       end = address + size;
+       if (end > PGDIR_SIZE)
+               end = PGDIR_SIZE;
+       phys_addr -= address;
+       if (address >= end)
+               BUG();
+       do {
+               pte_t * pte = pte_alloc_kernel(pmd, address);
+               if (!pte)
+                       return -ENOMEM;
+               remap_area_pte(pte, address, end - address, address + phys_addr, flags);
+               address = (address + PMD_SIZE) & PMD_MASK;
+               pmd++;
+       } while (address && (address < end));
+       return 0;
+}
+
+static int remap_area_pages(unsigned long address, phys_t phys_addr,
+       phys_t size, unsigned long flags)
+{
+       int error;
+       pgd_t * dir;
+       unsigned long end = address + size;
+
+       phys_addr -= address;
+       dir = pgd_offset(&init_mm, address);
+       flush_cache_all();
+       if (address >= end)
+               BUG();
+       do {
+               pud_t *pud;
+               pmd_t *pmd;
+
+               error = -ENOMEM;
+               pud = pud_alloc(&init_mm, dir, address);
+               if (!pud)
+                       break;
+               pmd = pmd_alloc(&init_mm, pud, address);
+               if (!pmd)
+                       break;
+               if (remap_area_pmd(pmd, address, end - address,
+                                        phys_addr + address, flags))
+                       break;
+               error = 0;
+               address = (address + PGDIR_SIZE) & PGDIR_MASK;
+               dir++;
+       } while (address && (address < end));
+       flush_tlb_all();
+       return error;
+}
 
 /*
  * Generic mapping function (not visible outside):
@@ -36,7 +121,6 @@ void __iomem * __ioremap(phys_t phys_addr, phys_t size, unsigned long flags)
        unsigned long offset;
        phys_t last_addr;
        void * addr;
-       pgprot_t pgprot;
 
        phys_addr = fixup_bigphys_addr(phys_addr, size);
 
@@ -68,9 +152,6 @@ void __iomem * __ioremap(phys_t phys_addr, phys_t size, unsigned long flags)
                                return NULL;
        }
 
-       pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | __READABLE
-                         | __WRITEABLE | flags);
-
        /*
         * Mappings have to be page-aligned
         */
@@ -85,8 +166,7 @@ void __iomem * __ioremap(phys_t phys_addr, phys_t size, unsigned long flags)
        if (!area)
                return NULL;
        addr = area->addr;
-       if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
-                              phys_addr, pgprot)) {
+       if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
                vunmap(addr);
                return NULL;
        }
index c78ba30..3df36ed 100644 (file)
@@ -200,7 +200,7 @@ static int __init mv643xx_eth_add_pds(void)
        int ret;
 
        get_mac(mac);
-       eth_mac_add(eth1_mac_addr, mac, 0);
+       eth_mac_add(eth0_mac_addr, mac, 0);
        eth_mac_add(eth1_mac_addr, mac, 1);
        eth_mac_add(eth2_mac_addr, mac, 2);
        ret = platform_add_devices(mv643xx_eth_pd_devs,
index 0ab8d23..024aef2 100644 (file)
@@ -200,7 +200,7 @@ static int __init mv643xx_eth_add_pds(void)
        int ret;
 
        get_mac(mac);
-       eth_mac_add(eth1_mac_addr, mac, 0);
+       eth_mac_add(eth0_mac_addr, mac, 0);
        eth_mac_add(eth1_mac_addr, mac, 1);
        eth_mac_add(eth2_mac_addr, mac, 2);
        ret = platform_add_devices(mv643xx_eth_pd_devs,
index 8e381d4..fac8b24 100644 (file)
@@ -174,7 +174,7 @@ static int __init mv643xx_eth_add_pds(void)
        int ret;
 
        get_mac(mac);
-       eth_mac_add(eth1_mac_addr, mac, 0);
+       eth_mac_add(eth0_mac_addr, mac, 0);
        eth_mac_add(eth1_mac_addr, mac, 1);
        ret = platform_add_devices(mv643xx_eth_pd_devs,
                        ARRAY_SIZE(mv643xx_eth_pd_devs));
index 28da4e7..3d73545 100644 (file)
@@ -37,6 +37,11 @@ config GENERIC_FIND_NEXT_BIT
        bool
        default y
 
+config GENERIC_BUG
+       bool
+       default y
+       depends on BUG
+
 config GENERIC_HWEIGHT
        bool
        default y
@@ -45,6 +50,10 @@ config GENERIC_CALIBRATE_DELAY
        bool
        default y
 
+config GENERIC_TIME
+       bool
+       default y
+
 config TIME_LOW_RES
        bool
        depends on SMP
index 9b7e424..760567a 100644 (file)
@@ -35,12 +35,8 @@ FINAL_LD=$(CROSS_COMPILE)ld --warn-common --warn-section-align
 
 OBJCOPY_FLAGS =-O binary -R .note -R .comment -S
 
-GCC_VERSION     := $(call cc-version)
-ifneq ($(shell if [ -z $(GCC_VERSION) ] ; then echo "bad"; fi ;),)
-$(error Sorry, couldn't find ($(cc-version)).)
-endif
-ifneq ($(shell if [ $(GCC_VERSION) -lt 0303 ] ; then echo "bad"; fi ;),)
-$(error Sorry, your compiler is too old ($(GCC_VERSION)).  GCC v3.3 or above is required.)
+ifneq ($(call cc-ifversion, -lt, 0303, "bad"),)
+$(error Sorry, GCC v3.3 or above is required.)
 endif
 
 cflags-y       := -pipe
index 31c8ccc..d15a413 100644 (file)
  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <asm/unistd.h>
+#include <asm/assembly.h>
 #include <linux/sys.h>
 #include <linux/linkage.h>
-#include <asm/unistd.h>
 
-#define ENTRY_NAME(_name_) .word _name_
+#define ENTRY_NAME(_name_) ASM_ULONG_INSN _name_
 
        .section .rodata,"a"
-       .align 4
-       .export hpux_call_table
        .import hpux_unimplemented_wrapper
-hpux_call_table:
+ENTRY(hpux_call_table)
        ENTRY_NAME(sys_ni_syscall)      /* 0 */
        ENTRY_NAME(sys_exit)
        ENTRY_NAME(hpux_fork_wrapper)
@@ -542,5 +541,6 @@ hpux_call_table:
        ENTRY_NAME(hpux_unimplemented_wrapper)      /* 510 */
        ENTRY_NAME(hpux_unimplemented_wrapper)
        ENTRY_NAME(hpux_unimplemented_wrapper)
+END(hpux_call_table)
 .end
 
index 4204cd1..c7a81a2 100644 (file)
@@ -35,13 +35,13 @@ int hpux_execve(struct pt_regs *regs)
        int error;
        char *filename;
 
-       filename = getname((char *) regs->gr[26]);
+       filename = getname((char __user *) regs->gr[26]);
        error = PTR_ERR(filename);
        if (IS_ERR(filename))
                goto out;
 
-       error = do_execve(filename, (char **) regs->gr[25],
-               (char **)regs->gr[24], regs);
+       error = do_execve(filename, (char __user * __user *) regs->gr[25],
+               (char __user * __user *) regs->gr[24], regs);
 
        if (error == 0) {
                task_lock(current);
@@ -63,19 +63,19 @@ struct hpux_dirent {
 };
 
 struct getdents_callback {
-       struct hpux_dirent *current_dir;
-       struct hpux_dirent *previous;
+       struct hpux_dirent __user *current_dir;
+       struct hpux_dirent __user *previous;
        int count;
        int error;
 };
 
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
 #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
 
 static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
                u64 ino, unsigned d_type)
 {
-       struct hpux_dirent * dirent;
+       struct hpux_dirent __user * dirent;
        struct getdents_callback * buf = (struct getdents_callback *) __buf;
        ino_t d_ino;
        int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
@@ -105,10 +105,10 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
 #undef NAME_OFFSET
 #undef ROUND_UP
 
-int hpux_getdents(unsigned int fd, struct hpux_dirent *dirent, unsigned int count)
+int hpux_getdents(unsigned int fd, struct hpux_dirent __user *dirent, unsigned int count)
 {
        struct file * file;
-       struct hpux_dirent * lastdirent;
+       struct hpux_dirent __user * lastdirent;
        struct getdents_callback buf;
        int error = -EBADF;
 
@@ -143,7 +143,7 @@ int hpux_mount(const char *fs, const char *path, int mflag,
        return -ENOSYS;
 }
 
-static int cp_hpux_stat(struct kstat *stat, struct hpux_stat64 *statbuf)
+static int cp_hpux_stat(struct kstat *stat, struct hpux_stat64 __user *statbuf)
 {
        struct hpux_stat64 tmp;
 
@@ -169,7 +169,7 @@ static int cp_hpux_stat(struct kstat *stat, struct hpux_stat64 *statbuf)
        return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
 }
 
-long hpux_stat64(char *filename, struct hpux_stat64 *statbuf)
+long hpux_stat64(char __user *filename, struct hpux_stat64 __user *statbuf)
 {
        struct kstat stat;
        int error = vfs_stat(filename, &stat);
@@ -180,7 +180,7 @@ long hpux_stat64(char *filename, struct hpux_stat64 *statbuf)
        return error;
 }
 
-long hpux_fstat64(unsigned int fd, struct hpux_stat64 *statbuf)
+long hpux_fstat64(unsigned int fd, struct hpux_stat64 __user *statbuf)
 {
        struct kstat stat;
        int error = vfs_fstat(fd, &stat);
@@ -191,7 +191,7 @@ long hpux_fstat64(unsigned int fd, struct hpux_stat64 *statbuf)
        return error;
 }
 
-long hpux_lstat64(char *filename, struct hpux_stat64 *statbuf)
+long hpux_lstat64(char __user *filename, struct hpux_stat64 __user *statbuf)
 {
        struct kstat stat;
        int error = vfs_lstat(filename, &stat);
index aaaf330..0b9d5b1 100644 (file)
 #include <asm/asm-offsets.h>
 #include <asm/unistd.h>
 #include <asm/errno.h>
+#include <linux/linkage.h>
 
-#ifdef __LP64__
-       .level          2.0w
-#else
-       .level          1.1
-#endif
+       .level  LEVEL
        .text
 
-#ifdef __LP64__
-#define FRAME_SIZE     128
-#else
-#define FRAME_SIZE     64
-#endif
        .import hpux_call_table
        .import hpux_syscall_exit,code
-       .export hpux_gateway_page
 
        .align 4096
-hpux_gateway_page:
+ENTRY(hpux_gateway_page)
        nop
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 #warning NEEDS WORK for 64-bit
 #endif
        ldw     -64(%r30), %r29                 ;! 8th argument
@@ -101,7 +92,7 @@ hpux_gateway_page:
        ldo     R%hpux_call_table(%r21), %r21
        comiclr,>>=     __NR_HPUX_syscalls, %r22, %r0
        b,n     syscall_nosys
-       ldwx,s  %r22(%r21), %r21
+       LDREGX  %r22(%r21), %r21
        ldil    L%hpux_syscall_exit,%r2
        be      0(%sr7,%r21)
        ldo     R%hpux_syscall_exit(%r2),%r2
@@ -110,7 +101,7 @@ syscall_nosys:
        ldil    L%hpux_syscall_exit,%r1
        be      R%hpux_syscall_exit(%sr7,%r1)
        ldo     -ENOSYS(%r0),%r28
+ENDPROC(hpux_gateway_page)
 
        .align 4096
-       .export end_hpux_gateway_page
-end_hpux_gateway_page:
+ENTRY(end_hpux_gateway_page)
index 04c2ff4..3e025df 100644 (file)
@@ -61,7 +61,7 @@ int hpux_ptrace(void)
        return -ENOSYS;
 }
 
-int hpux_wait(int *stat_loc)
+int hpux_wait(int __user *stat_loc)
 {
        return sys_waitpid(-1, stat_loc, 0);
 }
@@ -255,7 +255,7 @@ asmlinkage long hpux_fstatfs(unsigned int fd, struct hpux_statfs __user * buf)
 /*  TODO: Are these put_user calls OK?  Should they pass an int?
  *        (I copied it from sys_i386.c like this.)
  */
-static int hpux_uname(struct hpux_utsname *name)
+static int hpux_uname(struct hpux_utsname __user *name)
 {
        int error;
 
@@ -300,14 +300,14 @@ static int hpux_uname(struct hpux_utsname *name)
 /*  Note: HP-UX just uses the old suser() function to check perms
  *  in this system call.  We'll use capable(CAP_SYS_ADMIN).
  */
-int hpux_utssys(char *ubuf, int n, int type)
+int hpux_utssys(char __user *ubuf, int n, int type)
 {
        int len;
        int error;
        switch( type ) {
        case 0:
                /*  uname():  */
-               return( hpux_uname( (struct hpux_utsname *)ubuf ) );
+               return hpux_uname((struct hpux_utsname __user *)ubuf);
                break ;
        case 1:
                /*  Obsolete (used to be umask().)  */
@@ -315,8 +315,9 @@ int hpux_utssys(char *ubuf, int n, int type)
                break ;
        case 2:
                /*  ustat():  */
-               return( hpux_ustat(new_decode_dev(n), (struct hpux_ustat *)ubuf) );
-               break ;
+               return hpux_ustat(new_decode_dev(n),
+                                 (struct hpux_ustat __user *)ubuf);
+               break;
        case 3:
                /*  setuname():
                 *
@@ -332,7 +333,7 @@ int hpux_utssys(char *ubuf, int n, int type)
                        return -EINVAL ;
                /*  Unlike Linux, HP-UX truncates it if n is too big:  */
                len = (n <= __NEW_UTS_LEN) ? n : __NEW_UTS_LEN ;
-               return( sys_sethostname(ubuf, len) );
+               return sys_sethostname(ubuf, len);
                break ;
        case 4:
                /*  sethostname():
@@ -346,7 +347,7 @@ int hpux_utssys(char *ubuf, int n, int type)
                        return -EINVAL ;
                /*  Unlike Linux, HP-UX truncates it if n is too big:  */
                len = (n <= __NEW_UTS_LEN) ? n : __NEW_UTS_LEN ;
-               return( sys_sethostname(ubuf, len) );
+               return sys_sethostname(ubuf, len);
                break ;
        case 5:
                /*  gethostname():
@@ -356,7 +357,7 @@ int hpux_utssys(char *ubuf, int n, int type)
                /*  Unlike Linux, HP-UX returns an error if n==0:  */
                if ( n <= 0 )
                        return -EINVAL ;
-               return( sys_gethostname(ubuf, n) );
+               return sys_gethostname(ubuf, n);
                break ;
        case 6:
                /*  Supposedly called from setuname() in libc.
@@ -420,7 +421,7 @@ int hpux_utssys(char *ubuf, int n, int type)
        }
 }
 
-int hpux_getdomainname(char *name, int len)
+int hpux_getdomainname(char __user *name, int len)
 {
        int nlen;
        int err = -EFAULT;
@@ -471,17 +472,18 @@ int hpux_sysfs(int opcode, unsigned long arg1, unsigned long arg2)
        printk(KERN_DEBUG "hpux_sysfs called with arg1='%lx'\n", arg1);
 
        if ( opcode == 1 ) { /* GETFSIND */     
-               len = strlen_user((char *)arg1);
+               char __user *user_fsname = (char __user *)arg1;
+               len = strlen_user(user_fsname);
                printk(KERN_DEBUG "len of arg1 = %d\n", len);
                if (len == 0)
                        return 0;
                fsname = kmalloc(len, GFP_KERNEL);
-               if ( !fsname ) {
+               if (!fsname) {
                        printk(KERN_DEBUG "failed to kmalloc fsname\n");
                        return 0;
                }
 
-               if ( copy_from_user(fsname, (char *)arg1, len) ) {
+               if (copy_from_user(fsname, user_fsname, len)) {
                        printk(KERN_DEBUG "failed to copy_from_user fsname\n");
                        kfree(fsname);
                        return 0;
@@ -495,7 +497,7 @@ int hpux_sysfs(int opcode, unsigned long arg1, unsigned long arg2)
                        fstype = 0;
                } else {
                        fstype = 0;
-               };
+               }
 
                kfree(fsname);
 
@@ -509,7 +511,7 @@ int hpux_sysfs(int opcode, unsigned long arg1, unsigned long arg2)
 
 
 /* Table of syscall names and handle for unimplemented routines */
-static const char *syscall_names[] = {
+static const char * const syscall_names[] = {
        "nosys",                  /* 0 */
        "exit",                  
        "fork",                  
index 0b0c3a6..58c53c8 100644 (file)
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 #warning PA64 support needs more work...did first cut
 #endif
 
 #include <asm/asm-offsets.h>
 #include <asm/assembly.h>
 #include <asm/signal.h>
+#include <linux/linkage.h>
 
-#ifdef __LP64__
-       .level          2.0w
-#else
-       .level          1.1
-#endif
+       .level  LEVEL
        .text
 
        /* These should probably go in a header file somewhere.
@@ -41,7 +38,7 @@
         * register save/restore macros.
         */
        .macro  reg_save regs
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 #warning NEEDS WORK for 64-bit
 #endif
        STREG   %r3, PT_GR3(\regs)
        .endm
 
 
-       .export hpux_fork_wrapper
-       .export hpux_child_return
        .import sys_fork
 
-hpux_fork_wrapper:
+ENTRY(hpux_fork_wrapper)
        ldo     TASK_REGS-TASK_SZ_ALGN-64(%r30),%r1         ;! get pt regs
                                                            ;! pointer in task
        reg_save %r1
@@ -128,27 +123,26 @@ fork_return:
 fork_exit:
        bv      %r0(%r2)
        nop
+ENDPROC(hpux_fork_wrapper)
 
        /* Set the return value for the child */
 
-hpux_child_return:
+ENTRY(hpux_child_return)
 #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
-       bl      schedule_tail, %r2
-       nop
+       bl,n    schedule_tail, %r2
 #endif
 
        LDREG   TASK_PT_GR19-TASK_SZ_ALGN-128(%r30),%r2
        b fork_return
        copy %r0,%r28
+ENDPROC(hpux_child_return)
 
-       .export hpux_execve_wrapper
-       .export hpux_execv_wrapper
        .import hpux_execve
 
-hpux_execv_wrapper:
+ENTRY(hpux_execv_wrapper)
        copy %r0,%r24  /* NULL environment */
 
-hpux_execve_wrapper:
+ENTRY(hpux_execve_wrapper)
 
        ldo     TASK_REGS-TASK_SZ_ALGN-64(%r30),%r1         ;! get pt regs
 
@@ -187,13 +181,13 @@ hpux_execve_wrapper:
 exec_error:
        bv %r0(%r19)
        nop
+ENDPROC(hpux_execv_wrapper)
 
-       .export hpux_pipe_wrapper
        .import hpux_pipe
 
        /* HP-UX expects pipefd's returned in r28 & r29 */
 
-hpux_pipe_wrapper:
+ENTRY(hpux_pipe_wrapper)
        STREG %r2,-20(%r30)
        ldo 64(%r30),%r30
        bl hpux_pipe,%r2
@@ -212,12 +206,11 @@ hpux_pipe_wrapper:
 pipe_exit:
        bv %r0(%r2)
        ldo -64(%r30),%r30
+ENDPROC(hpux_pipe_wrapper)
 
-       .export hpux_syscall_exit
        .import syscall_exit
 
-hpux_syscall_exit:
-
+ENTRY(hpux_syscall_exit)
        /*
         *
         * HP-UX call return conventions:
@@ -246,12 +239,12 @@ hpux_syscall_exit:
        ldo 1(%r0),%r22
 
 no_error:
-       b syscall_exit
-       nop
+       b,n syscall_exit
+ENDPROC(hpux_syscall_exit)
 
-       .export hpux_unimplemented_wrapper
        .import hpux_unimplemented
 
-hpux_unimplemented_wrapper:
+ENTRY(hpux_unimplemented_wrapper)
        b hpux_unimplemented
        STREG %r22,-64(%r30)  /* overwrite arg8 with syscall number */
+ENDPROC(hpux_unimplemented_wrapper)
index c11a5bc..54fdb95 100644 (file)
@@ -44,7 +44,7 @@
 
 #define BLANK() asm volatile("\n->" : : )
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 #define FRAME_SIZE     128
 #else
 #define FRAME_SIZE     64
index 0be51e9..0dc924c 100644 (file)
@@ -68,16 +68,6 @@ flush_cache_all_local(void)
 }
 EXPORT_SYMBOL(flush_cache_all_local);
 
-/* flushes EVERYTHING (tlb & cache) */
-
-void
-flush_all_caches(void)
-{
-       flush_cache_all();
-       flush_tlb_all();
-}
-EXPORT_SYMBOL(flush_all_caches);
-
 void
 update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 {
@@ -99,7 +89,7 @@ show_cache_info(struct seq_file *m)
 
        seq_printf(m, "I-cache\t\t: %ld KB\n", 
                cache_info.ic_size/1024 );
-       if (cache_info.dc_loop == 1)
+       if (cache_info.dc_loop != 1)
                snprintf(buf, 32, "%lu-way associative", cache_info.dc_loop);
        seq_printf(m, "D-cache\t\t: %ld KB (%s%s, %s)\n",
                cache_info.dc_size/1024,
@@ -270,6 +260,83 @@ void disable_sr_hashing(void)
                panic("SpaceID hashing is still on!\n");
 }
 
+/* Simple function to work out if we have an existing address translation
+ * for a user space vma. */
+static inline int translation_exists(struct vm_area_struct *vma,
+                               unsigned long addr, unsigned long pfn)
+{
+       pgd_t *pgd = pgd_offset(vma->vm_mm, addr);
+       pmd_t *pmd;
+       pte_t pte;
+
+       if(pgd_none(*pgd))
+               return 0;
+
+       pmd = pmd_offset(pgd, addr);
+       if(pmd_none(*pmd) || pmd_bad(*pmd))
+               return 0;
+
+       /* We cannot take the pte lock here: flush_cache_page is usually
+        * called with pte lock already held.  Whereas flush_dcache_page
+        * takes flush_dcache_mmap_lock, which is lower in the hierarchy:
+        * the vma itself is secure, but the pte might come or go racily.
+        */
+       pte = *pte_offset_map(pmd, addr);
+       /* But pte_unmap() does nothing on this architecture */
+
+       /* Filter out coincidental file entries and swap entries */
+       if (!(pte_val(pte) & (_PAGE_FLUSH|_PAGE_PRESENT)))
+               return 0;
+
+       return pte_pfn(pte) == pfn;
+}
+
+/* Private function to flush a page from the cache of a non-current
+ * process.  cr25 contains the Page Directory of the current user
+ * process; we're going to hijack both it and the user space %sr3 to
+ * temporarily make the non-current process current.  We have to do
+ * this because cache flushing may cause a non-access tlb miss which
+ * the handlers have to fill in from the pgd of the non-current
+ * process. */
+static inline void
+flush_user_cache_page_non_current(struct vm_area_struct *vma,
+                                 unsigned long vmaddr)
+{
+       /* save the current process space and pgd */
+       unsigned long space = mfsp(3), pgd = mfctl(25);
+
+       /* we don't mind taking interrups since they may not
+        * do anything with user space, but we can't
+        * be preempted here */
+       preempt_disable();
+
+       /* make us current */
+       mtctl(__pa(vma->vm_mm->pgd), 25);
+       mtsp(vma->vm_mm->context, 3);
+
+       flush_user_dcache_page(vmaddr);
+       if(vma->vm_flags & VM_EXEC)
+               flush_user_icache_page(vmaddr);
+
+       /* put the old current process back */
+       mtsp(space, 3);
+       mtctl(pgd, 25);
+       preempt_enable();
+}
+
+
+static inline void
+__flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr)
+{
+       if (likely(vma->vm_mm->context == mfsp(3))) {
+               flush_user_dcache_page(vmaddr);
+               if (vma->vm_flags & VM_EXEC)
+                       flush_user_icache_page(vmaddr);
+       } else {
+               flush_user_cache_page_non_current(vma, vmaddr);
+       }
+}
+
 void flush_dcache_page(struct page *page)
 {
        struct address_space *mapping = page_mapping(page);
@@ -342,7 +409,7 @@ void clear_user_page_asm(void *page, unsigned long vaddr)
 #define FLUSH_THRESHOLD 0x80000 /* 0.5MB */
 int parisc_cache_flush_threshold __read_mostly = FLUSH_THRESHOLD;
 
-void parisc_setup_cache_timing(void)
+void __init parisc_setup_cache_timing(void)
 {
        unsigned long rangetime, alltime;
        unsigned long size;
@@ -366,6 +433,9 @@ void parisc_setup_cache_timing(void)
        if (!parisc_cache_flush_threshold)
                parisc_cache_flush_threshold = FLUSH_THRESHOLD;
 
+       if (parisc_cache_flush_threshold > cache_info.dc_size)
+               parisc_cache_flush_threshold = cache_info.dc_size;
+
        printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus());
 }
 
@@ -410,3 +480,97 @@ void kunmap_parisc(void *addr)
 }
 EXPORT_SYMBOL(kunmap_parisc);
 #endif
+
+void __flush_tlb_range(unsigned long sid, unsigned long start,
+                      unsigned long end)
+{
+       unsigned long npages;
+
+       npages = ((end - (start & PAGE_MASK)) + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+       if (npages >= 512)  /* 2MB of space: arbitrary, should be tuned */
+               flush_tlb_all();
+       else {
+               mtsp(sid, 1);
+               purge_tlb_start();
+               if (split_tlb) {
+                       while (npages--) {
+                               pdtlb(start);
+                               pitlb(start);
+                               start += PAGE_SIZE;
+                       }
+               } else {
+                       while (npages--) {
+                               pdtlb(start);
+                               start += PAGE_SIZE;
+                       }
+               }
+               purge_tlb_end();
+       }
+}
+
+static void cacheflush_h_tmp_function(void *dummy)
+{
+       flush_cache_all_local();
+}
+
+void flush_cache_all(void)
+{
+       on_each_cpu(cacheflush_h_tmp_function, NULL, 1, 1);
+}
+
+void flush_cache_mm(struct mm_struct *mm)
+{
+#ifdef CONFIG_SMP
+       flush_cache_all();
+#else
+       flush_cache_all_local();
+#endif
+}
+
+void
+flush_user_dcache_range(unsigned long start, unsigned long end)
+{
+       if ((end - start) < parisc_cache_flush_threshold)
+               flush_user_dcache_range_asm(start,end);
+       else
+               flush_data_cache();
+}
+
+void
+flush_user_icache_range(unsigned long start, unsigned long end)
+{
+       if ((end - start) < parisc_cache_flush_threshold)
+               flush_user_icache_range_asm(start,end);
+       else
+               flush_instruction_cache();
+}
+
+
+void flush_cache_range(struct vm_area_struct *vma,
+               unsigned long start, unsigned long end)
+{
+       int sr3;
+
+       if (!vma->vm_mm->context) {
+               BUG();
+               return;
+       }
+
+       sr3 = mfsp(3);
+       if (vma->vm_mm->context == sr3) {
+               flush_user_dcache_range(start,end);
+               flush_user_icache_range(start,end);
+       } else {
+               flush_cache_all();
+       }
+}
+
+void
+flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long pfn)
+{
+       BUG_ON(!vma->vm_mm->context);
+
+       if (likely(translation_exists(vma, vmaddr, pfn)))
+               __flush_cache_page(vma, vmaddr);
+
+}
index d6c486e..2ca654b 100644 (file)
@@ -562,12 +562,23 @@ pa_dev_attr(rev, id.hversion_rev, "0x%x\n");
 pa_dev_attr_id(hversion, "0x%03x\n");
 pa_dev_attr_id(sversion, "0x%05x\n");
 
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct parisc_device *padev = to_parisc_device(dev);
+       struct parisc_device_id *id = &padev->id;
+
+       return sprintf(buf, "parisc:t%02Xhv%04Xrev%02Xsv%08X\n",
+               (u8)id->hw_type, (u16)id->hversion, (u8)id->hversion_rev,
+               (u32)id->sversion);
+}
+
 static struct device_attribute parisc_device_attrs[] = {
        __ATTR_RO(irq),
        __ATTR_RO(hw_type),
        __ATTR_RO(rev),
        __ATTR_RO(hversion),
        __ATTR_RO(sversion),
+       __ATTR_RO(modalias),
        __ATTR_NULL,
 };
 
@@ -689,7 +700,9 @@ parse_tree_node(struct device *parent, int index, struct hardware_path *modpath)
                .fn     = check_parent,
        };
 
-       device_for_each_child(parent, &recurse_data, descend_children);
+       if (device_for_each_child(parent, &recurse_data, descend_children))
+               /* nothing */;
+
        return d.dev;
 }
 
@@ -835,8 +848,8 @@ static void print_parisc_device(struct parisc_device *dev)
        static int count;
 
        print_pa_hwpath(dev, hw_path);
-       printk(KERN_INFO "%d. %s at 0x%lx [%s] { %d, 0x%x, 0x%.3x, 0x%.5x }",
-               ++count, dev->name, dev->hpa.start, hw_path, dev->id.hw_type,
+       printk(KERN_INFO "%d. %s at 0x%p [%s] { %d, 0x%x, 0x%.3x, 0x%.5x }",
+               ++count, dev->name, (void*) dev->hpa.start, hw_path, dev->id.hw_type,
                dev->id.hversion_rev, dev->id.hversion, dev->id.sversion);
 
        if (dev->num_addrs) {
index 340b5e8..8474f9e 100644 (file)
@@ -37,6 +37,8 @@
 #include <asm/unistd.h>
 #include <asm/thread_info.h>
 
+#include <linux/linkage.h>
+
 #ifdef CONFIG_64BIT
 #define CMPIB           cmpib,*
 #define CMPB            cmpb,*
         * the static part of the kernel address space.
         */
 
-       .export fault_vector_20
-
        .text
 
        .align 4096
 
-fault_vector_20:
+ENTRY(fault_vector_20)
        /* First vector is invalid (0) */
        .ascii  "cows can fly"
        .byte 0
@@ -695,14 +695,13 @@ fault_vector_20:
        def             29
        def             30
        def             31
+END(fault_vector_20)
 
 #ifndef CONFIG_64BIT
 
-       .export fault_vector_11
-       
        .align 2048
 
-fault_vector_11:
+ENTRY(fault_vector_11)
        /* First vector is invalid (0) */
        .ascii  "cows can fly"
        .byte 0
@@ -743,6 +742,7 @@ fault_vector_11:
        def             29
        def             30
        def             31
+END(fault_vector_11)
 
 #endif
 
@@ -762,9 +762,8 @@ fault_vector_11:
 #define CLONE_VM 0x100 /* Must agree with <linux/sched.h> */
 #define CLONE_UNTRACED 0x00800000
 
-       .export __kernel_thread, code
        .import do_fork
-__kernel_thread:
+ENTRY(__kernel_thread)
        STREG   %r2, -RP_OFFSET(%r30)
 
        copy    %r30, %r1
@@ -797,6 +796,7 @@ __kernel_thread:
        ldo     -PT_SZ_ALGN(%r30), %r30
        bv      %r0(%r2)
        nop
+ENDPROC(__kernel_thread)
 
        /*
         * Child Returns here
@@ -805,8 +805,7 @@ __kernel_thread:
         * into task save area.
         */
 
-       .export ret_from_kernel_thread
-ret_from_kernel_thread:
+ENTRY(ret_from_kernel_thread)
 
        /* Call schedule_tail first though */
        BL      schedule_tail, %r2
@@ -833,10 +832,10 @@ ret_from_kernel_thread:
        bv      %r0(%r1)
 #endif
        ldi     0, %r26
+ENDPROC(ret_from_kernel_thread)
 
        .import sys_execve, code
-       .export __execve, code
-__execve:
+ENTRY(__execve)
        copy    %r2, %r15
        copy    %r30, %r16
        ldo     PT_SZ_ALGN(%r30), %r30
@@ -856,16 +855,15 @@ __execve:
        copy    %r16, %r30
        bv      %r0(%r2)
        nop
+ENDPROC(__execve)
 
-       .align 4
 
        /*
         * struct task_struct *_switch_to(struct task_struct *prev,
         *      struct task_struct *next)
         *
         * switch kernel stacks and return prev */
-       .export _switch_to, code
-_switch_to:
+ENTRY(_switch_to)
        STREG    %r2, -RP_OFFSET(%r30)
 
        callee_save_float
@@ -890,6 +888,7 @@ _switch_to_ret:
        LDREG   -RP_OFFSET(%r30), %r2
        bv      %r0(%r2)
        copy    %r26, %r28
+ENDPROC(_switch_to)
 
        /*
         * Common rfi return path for interruptions, kernel execve, and
@@ -907,8 +906,7 @@ _switch_to_ret:
 
        .align 4096
 
-       .export syscall_exit_rfi
-syscall_exit_rfi:
+ENTRY(syscall_exit_rfi)
        mfctl   %cr30,%r16
        LDREG   TI_TASK(%r16), %r16     /* thread_info -> task_struct */
        ldo     TASK_REGS(%r16),%r16
@@ -978,11 +976,36 @@ intr_check_resched:
        LDREG   TI_FLAGS(%r1),%r19      /* sched.h: TIF_NEED_RESCHED */
        bb,<,n  %r19,31-TIF_NEED_RESCHED,intr_do_resched /* forward */
 
+       .import do_notify_resume,code
 intr_check_sig:
        /* As above */
        mfctl   %cr30,%r1
-       LDREG   TI_FLAGS(%r1),%r19      /* sched.h: TIF_SIGPENDING */
-       bb,<,n %r19, 31-TIF_SIGPENDING, intr_do_signal /* forward */
+       LDREG   TI_FLAGS(%r1),%r19
+       ldi     (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK), %r20
+       and,COND(<>)    %r19, %r20, %r0
+       b,n     intr_restore    /* skip past if we've nothing to do */
+
+       /* This check is critical to having LWS
+        * working. The IASQ is zero on the gateway
+        * page and we cannot deliver any signals until
+        * we get off the gateway page.
+        *
+        * Only do signals if we are returning to user space
+        */
+       LDREG   PT_IASQ0(%r16), %r20
+       CMPIB=,n 0,%r20,intr_restore /* backward */
+       LDREG   PT_IASQ1(%r16), %r20
+       CMPIB=,n 0,%r20,intr_restore /* backward */
+
+       copy    %r0, %r25                       /* long in_syscall = 0 */
+#ifdef CONFIG_64BIT
+       ldo     -16(%r30),%r29                  /* Reference param save area */
+#endif
+
+       BL      do_notify_resume,%r2
+       copy    %r16, %r26                      /* struct pt_regs *regs */
+
+       b,n     intr_check_sig
 
 intr_restore:
        copy            %r16,%r29
@@ -1072,35 +1095,6 @@ intr_do_preempt:
        b,n     intr_restore            /* ssm PSW_SM_I done by intr_restore */
 #endif /* CONFIG_PREEMPT */
 
-       .import do_signal,code
-intr_do_signal:
-       /* 
-               This check is critical to having LWS
-               working. The IASQ is zero on the gateway
-               page and we cannot deliver any signals until
-               we get off the gateway page.
-
-               Only do signals if we are returning to user space 
-       */
-       LDREG   PT_IASQ0(%r16), %r20
-       CMPIB= 0,%r20,intr_restore /* backward */
-       nop
-       LDREG   PT_IASQ1(%r16), %r20
-       CMPIB= 0,%r20,intr_restore /* backward */
-       nop
-
-       copy    %r0, %r24                       /* unsigned long in_syscall */
-       copy    %r16, %r25                      /* struct pt_regs *regs */
-#ifdef CONFIG_64BIT
-       ldo     -16(%r30),%r29                  /* Reference param save area */
-#endif
-
-       BL      do_signal,%r2
-       copy    %r0, %r26                       /* sigset_t *oldset = NULL */
-
-       b       intr_check_sig
-       nop
-
        /*
         * External interrupts.
         */
@@ -1115,11 +1109,7 @@ intr_extint:
        mfctl   %cr31,%r1
        copy    %r30,%r17
        /* FIXME! depi below has hardcoded idea of interrupt stack size (32k)*/
-#ifdef CONFIG_64BIT
-       depdi   0,63,15,%r17
-#else
-       depi    0,31,15,%r17
-#endif
+       DEPI    0,31,15,%r17
        CMPB=,n %r1,%r17,2f
        get_stack_use_cr31
        b,n 3f
@@ -1148,13 +1138,12 @@ intr_extint:
 
        b       do_cpu_irq_mask
        ldo     R%intr_return(%r2), %r2 /* return to intr_return, not here */
+ENDPROC(syscall_exit_rfi)
 
 
        /* Generic interruptions (illegal insn, unaligned, page fault, etc) */
 
-       .export         intr_save, code /* for os_hpmc */
-
-intr_save:
+ENTRY(intr_save)               /* for os_hpmc */
        mfsp    %sr7,%r16
        CMPIB=,n 0,%r16,1f
        get_stack_use_cr30
@@ -1229,6 +1218,7 @@ skip_save_ior:
 
        b               handle_interruption
        ldo             R%intr_check_sig(%r2), %r2
+ENDPROC(intr_save)
 
 
        /*
@@ -1814,9 +1804,7 @@ dtlb_fault:
        LDREG   PT_GR18(\regs),%r18
        .endm
 
-       .export sys_fork_wrapper
-       .export child_return
-sys_fork_wrapper:
+ENTRY(sys_fork_wrapper)
        LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
        ldo     TASK_REGS(%r1),%r1
        reg_save %r1
@@ -1853,9 +1841,10 @@ wrapper_exit:
        ldi     __NR_fork,%r20
        bv %r0(%r2)
        STREG   %r20,PT_GR20(%r1)
+ENDPROC(sys_fork_wrapper)
 
        /* Set the return value for the child */
-child_return:
+ENTRY(child_return)
        BL      schedule_tail, %r2
        nop
 
@@ -1863,10 +1852,10 @@ child_return:
        LDREG   TASK_PT_GR19(%r1),%r2
        b       wrapper_exit
        copy    %r0,%r28
+ENDPROC(child_return)
 
-       
-       .export sys_clone_wrapper
-sys_clone_wrapper:
+
+ENTRY(sys_clone_wrapper)
        LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
        ldo     TASK_REGS(%r1),%r1      /* get pt regs */
        reg_save %r1
@@ -1887,9 +1876,10 @@ sys_clone_wrapper:
 
        b       wrapper_exit
        LDREG   -RP_OFFSET-FRAME_SIZE(%r30),%r2
+ENDPROC(sys_clone_wrapper)
+
 
-       .export sys_vfork_wrapper
-sys_vfork_wrapper:
+ENTRY(sys_vfork_wrapper)
        LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
        ldo     TASK_REGS(%r1),%r1      /* get pt regs */
        reg_save %r1
@@ -1910,6 +1900,7 @@ sys_vfork_wrapper:
 
        b       wrapper_exit
        LDREG   -RP_OFFSET-FRAME_SIZE(%r30),%r2
+ENDPROC(sys_vfork_wrapper)
 
        
        .macro  execve_wrapper execve
@@ -1946,22 +1937,19 @@ error_\execve:
        nop
        .endm
 
-       .export sys_execve_wrapper
        .import sys_execve
-
-sys_execve_wrapper:
+ENTRY(sys_execve_wrapper)
        execve_wrapper sys_execve
+ENDPROC(sys_execve_wrapper)
 
 #ifdef CONFIG_64BIT
-       .export sys32_execve_wrapper
        .import sys32_execve
-
-sys32_execve_wrapper:
+ENTRY(sys32_execve_wrapper)
        execve_wrapper sys32_execve
+ENDPROC(sys32_execve_wrapper)
 #endif
 
-       .export sys_rt_sigreturn_wrapper
-sys_rt_sigreturn_wrapper:
+ENTRY(sys_rt_sigreturn_wrapper)
        LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26
        ldo     TASK_REGS(%r26),%r26    /* get pt regs */
        /* Don't save regs, we are going to restore them from sigcontext. */
@@ -1989,9 +1977,9 @@ sys_rt_sigreturn_wrapper:
         */
        bv      %r0(%r2)
        LDREG   PT_GR28(%r1),%r28  /* reload original r28 for syscall_exit */
+ENDPROC(sys_rt_sigreturn_wrapper)
 
-       .export sys_sigaltstack_wrapper
-sys_sigaltstack_wrapper:
+ENTRY(sys_sigaltstack_wrapper)
        /* Get the user stack pointer */
        LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
        ldo     TASK_REGS(%r1),%r24     /* get pt regs */
@@ -1999,10 +1987,10 @@ sys_sigaltstack_wrapper:
        STREG   %r2, -RP_OFFSET(%r30)
 #ifdef CONFIG_64BIT
        ldo     FRAME_SIZE(%r30), %r30
-       b,l     do_sigaltstack,%r2
+       BL      do_sigaltstack,%r2
        ldo     -16(%r30),%r29          /* Reference param save area */
 #else
-       bl      do_sigaltstack,%r2
+       BL      do_sigaltstack,%r2
        ldo     FRAME_SIZE(%r30), %r30
 #endif
 
@@ -2010,53 +1998,26 @@ sys_sigaltstack_wrapper:
        LDREG   -RP_OFFSET(%r30), %r2
        bv      %r0(%r2)
        nop
+ENDPROC(sys_sigaltstack_wrapper)
 
 #ifdef CONFIG_64BIT
-       .export sys32_sigaltstack_wrapper
-sys32_sigaltstack_wrapper:
+ENTRY(sys32_sigaltstack_wrapper)
        /* Get the user stack pointer */
        LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r24
        LDREG   TASK_PT_GR30(%r24),%r24
        STREG   %r2, -RP_OFFSET(%r30)
        ldo     FRAME_SIZE(%r30), %r30
-       b,l     do_sigaltstack32,%r2
+       BL      do_sigaltstack32,%r2
        ldo     -16(%r30),%r29          /* Reference param save area */
 
        ldo     -FRAME_SIZE(%r30), %r30
        LDREG   -RP_OFFSET(%r30), %r2
        bv      %r0(%r2)
        nop
+ENDPROC(sys32_sigaltstack_wrapper)
 #endif
 
-       .export sys_rt_sigsuspend_wrapper
-sys_rt_sigsuspend_wrapper:
-       LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
-       ldo     TASK_REGS(%r1),%r24
-       reg_save %r24
-
-       STREG   %r2, -RP_OFFSET(%r30)
-#ifdef CONFIG_64BIT
-       ldo     FRAME_SIZE(%r30), %r30
-       b,l     sys_rt_sigsuspend,%r2
-       ldo     -16(%r30),%r29          /* Reference param save area */
-#else
-       bl      sys_rt_sigsuspend,%r2
-       ldo     FRAME_SIZE(%r30), %r30
-#endif
-
-       ldo     -FRAME_SIZE(%r30), %r30
-       LDREG   -RP_OFFSET(%r30), %r2
-
-       LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
-       ldo     TASK_REGS(%r1),%r1
-       reg_restore %r1
-
-       bv      %r0(%r2)
-       nop
-
-       .export syscall_exit
-syscall_exit:
-
+ENTRY(syscall_exit)
        /* NOTE: HP-UX syscalls also come through here
         * after hpux_syscall_exit fixes up return
         * values. */
@@ -2119,9 +2080,35 @@ syscall_check_resched:
        LDREG   TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19   /* long */
        bb,<,n  %r19, 31-TIF_NEED_RESCHED, syscall_do_resched /* forward */
 
+       .import do_signal,code
 syscall_check_sig:
-       LDREG   TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19    /* get ti flags */
-       bb,<,n  %r19, 31-TIF_SIGPENDING, syscall_do_signal /* forward */
+       LDREG   TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19
+       ldi     (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK), %r26
+       and,COND(<>)    %r19, %r26, %r0
+       b,n     syscall_restore /* skip past if we've nothing to do */
+
+syscall_do_signal:
+       /* Save callee-save registers (for sigcontext).
+        * FIXME: After this point the process structure should be
+        * consistent with all the relevant state of the process
+        * before the syscall.  We need to verify this.
+        */
+       LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
+       ldo     TASK_REGS(%r1), %r26            /* struct pt_regs *regs */
+       reg_save %r26
+
+#ifdef CONFIG_64BIT
+       ldo     -16(%r30),%r29                  /* Reference param save area */
+#endif
+
+       BL      do_notify_resume,%r2
+       ldi     1, %r25                         /* long in_syscall = 1 */
+
+       LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
+       ldo     TASK_REGS(%r1), %r20            /* reload pt_regs */
+       reg_restore %r20
+
+       b,n     syscall_check_sig
 
 syscall_restore:
        /* Are we being ptraced? */
@@ -2259,31 +2246,10 @@ syscall_do_resched:
 #endif
        b       syscall_check_bh  /* if resched, we start over again */
        nop
+ENDPROC(syscall_exit)
 
-       .import do_signal,code
-syscall_do_signal:
-       /* Save callee-save registers (for sigcontext).
-          FIXME: After this point the process structure should be
-          consistent with all the relevant state of the process
-          before the syscall.  We need to verify this. */
-       LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 
-       ldo     TASK_REGS(%r1), %r25            /* struct pt_regs *regs */
-       reg_save %r25
-
-       ldi     1, %r24                         /* unsigned long in_syscall */
-
-#ifdef CONFIG_64BIT
-       ldo     -16(%r30),%r29                  /* Reference param save area */
-#endif
-       BL      do_signal,%r2
-       copy    %r0, %r26                       /* sigset_t *oldset = NULL */
-
-       LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
-       ldo     TASK_REGS(%r1), %r20            /* reload pt_regs */
-       reg_restore %r20
-
-       b,n     syscall_check_sig
 
+get_register:
        /*
         * get_register is used by the non access tlb miss handlers to
         * copy the value of the general register specified in r8 into
@@ -2294,8 +2260,6 @@ syscall_do_signal:
         * a -1 in it, but that is OK, it just means that we will have
         * to use the slow path instead).
         */
-
-get_register:
        blr     %r8,%r0
        nop
        bv      %r0(%r25)    /* r0 */
@@ -2363,13 +2327,13 @@ get_register:
        bv      %r0(%r25)    /* r31 */
        copy    %r31,%r1
 
+
+set_register:
        /*
         * set_register is used by the non access tlb miss handlers to
         * copy the value of r1 into the general register specified in
         * r8.
         */
-
-set_register:
        blr     %r8,%r0
        nop
        bv      %r0(%r25)    /* r0 (silly, but it is a place holder) */
@@ -2436,3 +2400,4 @@ set_register:
        copy    %r1,%r30
        bv      %r0(%r25)    /* r31 */
        copy    %r1,%r31
+
index 9158b70..39dc835 100644 (file)
@@ -74,7 +74,7 @@ static DEFINE_SPINLOCK(pdc_lock);
 static unsigned long pdc_result[32] __attribute__ ((aligned (8)));
 static unsigned long pdc_result2[32] __attribute__ ((aligned (8)));
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 #define WIDE_FIRMWARE 0x1
 #define NARROW_FIRMWARE 0x2
 
@@ -94,12 +94,12 @@ int parisc_narrow_firmware __read_mostly = 1;
  * when running a 64-bit kernel on such boxes (e.g. C200 or C360).
  */
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 long real64_call(unsigned long function, ...);
 #endif
 long real32_call(unsigned long function, ...);
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 #   define MEM_PDC (unsigned long)(PAGE0->mem_pdc_hi) << 32 | PAGE0->mem_pdc
 #   define mem_pdc_call(args...) unlikely(parisc_narrow_firmware) ? real32_call(MEM_PDC, args) : real64_call(MEM_PDC, args)
 #else
@@ -117,7 +117,7 @@ long real32_call(unsigned long function, ...);
  */
 static unsigned long f_extend(unsigned long address)
 {
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        if(unlikely(parisc_narrow_firmware)) {
                if((address & 0xff000000) == 0xf0000000)
                        return 0xf0f0f0f000000000UL | (u32)address;
@@ -139,7 +139,7 @@ static unsigned long f_extend(unsigned long address)
  */
 static void convert_to_wide(unsigned long *addr)
 {
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        int i;
        unsigned int *p = (unsigned int *)addr;
 
@@ -158,7 +158,7 @@ static void convert_to_wide(unsigned long *addr)
  */
 void __init set_firmware_width(void)
 {
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        int retval;
        unsigned long flags;
 
@@ -238,7 +238,7 @@ int __init pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_inf
  * 
  * Must be correctly formatted or expect system crash
  */
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 int pdc_pat_chassis_send_log(unsigned long state, unsigned long data)
 {
        int retval = 0;
@@ -949,7 +949,7 @@ int pdc_tod_set(unsigned long sec, unsigned long usec)
 }
 EXPORT_SYMBOL(pdc_tod_set);
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr,
                struct pdc_memory_table *tbl, unsigned long entries)
 {
@@ -965,7 +965,7 @@ int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr,
 
        return retval;
 }
-#endif /* __LP64__ */
+#endif /* CONFIG_64BIT */
 
 /* FIXME: Is this pdc used?  I could not find type reference to ftc_bitmap
  * so I guessed at unsigned long.  Someone who knows what this does, can fix
@@ -1204,7 +1204,7 @@ int pdc_sti_call(unsigned long func, unsigned long flags,
 }
 EXPORT_SYMBOL(pdc_sti_call);
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 /**
  * pdc_pat_cell_get_number - Returns the cell number.
  * @cell_info: The return buffer.
@@ -1387,7 +1387,7 @@ int pdc_pat_io_pci_cfg_write(unsigned long pci_addr, int pci_size, u32 val)
 
        return retval;
 }
-#endif /* __LP64__ */
+#endif /* CONFIG_64BIT */
 
 
 /***************** 32-bit real-mode calls ***********/
@@ -1445,7 +1445,7 @@ long real32_call(unsigned long fn, ...)
        return real32_call_asm(&real_stack.sp, &real_stack.arg0, fn);
 }
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 /***************** 64-bit real-mode calls ***********/
 
 struct wide_stack {
@@ -1496,5 +1496,5 @@ long real64_call(unsigned long fn, ...)
        return real64_call_asm(&real64_stack.sp, &real64_stack.arg0, fn);
 }
 
-#endif /* __LP64__ */
+#endif /* CONFIG_64BIT */
 
index eaad232..9676c48 100644 (file)
@@ -2,7 +2,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1999 by Helge Deller
+ * Copyright (C) 1999-2007 by Helge Deller <deller@gmx.de>
  * Copyright 1999 SuSE GmbH (Philipp Rumpf)
  * Copyright 1999 Philipp Rumpf (prumpf@tux.org)
  * Copyright 2000 Hewlett Packard (Paul Bame, bame@puffin.external.hp.com)
 #include <asm/assembly.h>
 #include <asm/pgtable.h>
 
+#include <linux/linkage.h>
+
        .level  LEVEL
 
        .data
-
-       .export boot_args
-boot_args:
+ENTRY(boot_args)
        .word 0 /* arg0 */
        .word 0 /* arg1 */
        .word 0 /* arg2 */
        .word 0 /* arg3 */
+END(boot_args)
 
        .text
        .align  4
@@ -38,10 +39,9 @@ boot_args:
         .import fault_vector_11,code    /* IVA parisc 1.1 32 bit */
        .import $global$                /* forward declaration */
 #endif /*!CONFIG_64BIT*/
-       .export stext
        .export _stext,data             /* Kernel want it this way! */
 _stext:
-stext:
+ENTRY(stext)
        .proc
        .callinfo
 
@@ -343,6 +343,9 @@ smp_slave_stext:
 
        .procend
 #endif /* CONFIG_SMP */
+
+ENDPROC(stext)
+
 #ifndef CONFIG_64BIT
        .data
 
index c412c0a..d8baa15 100644 (file)
@@ -46,6 +46,8 @@
 #include <asm/assembly.h>
 #include <asm/pdc.h>
 
+#include <linux/linkage.h>
+
        /*
         * stack for os_hpmc, the HPMC handler.
         * buffer for IODC procedures (for the HPMC handler).
@@ -69,17 +71,15 @@ hpmc_raddr:
 
 #define HPMC_PIM_DATA_SIZE 896 /* Enough to hold all architected 2.0 state */
 
-       .export hpmc_pim_data, data
        .align 8
-hpmc_pim_data:
+ENTRY(hpmc_pim_data)
        .block HPMC_PIM_DATA_SIZE
+END(hpmc_pim_data)
 
        .text
 
-       .export os_hpmc, code
        .import intr_save, code
-
-os_hpmc:
+ENTRY(os_hpmc)
 
        /*
         * registers modified:
@@ -294,11 +294,9 @@ os_hpmc_6:
 
        b .
        nop
+ENDPROC(os_hpmc)
 
        /* this label used to compute os_hpmc checksum */
-
-       .export os_hpmc_end, code
-
-os_hpmc_end:
+ENTRY(os_hpmc_end)
 
        nop
index 4e847ba..4845a64 100644 (file)
@@ -47,7 +47,7 @@ void __init setup_pdc(void)
        struct pdc_system_map_mod_info module_result;
        struct pdc_module_path module_path;
        struct pdc_model model;
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        struct pdc_pat_cell_num cell_info;
 #endif
 
@@ -73,7 +73,7 @@ void __init setup_pdc(void)
         * clearer message.
         */
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        status = pdc_pat_cell_get_number(&cell_info);
        if (status == PDC_OK) {
                pdc_type = PDC_TYPE_PAT;
@@ -152,7 +152,7 @@ static void __init pagezero_memconfig(void)
        npmem_ranges = 1;
 }
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 
 /* All of the PDC PAT specific code is 64-bit only */
 
@@ -408,13 +408,13 @@ static void __init sprockets_memconfig(void)
        }
 }
 
-#else   /* !__LP64__ */
+#else   /* !CONFIG_64BIT */
 
 #define pat_inventory() do { } while (0)
 #define pat_memconfig() do { } while (0)
 #define sprockets_memconfig() pagezero_memconfig()
 
-#endif /* !__LP64__ */
+#endif /* !CONFIG_64BIT */
 
 
 #ifndef CONFIG_PA20
index b39c5b9..e9d09b0 100644 (file)
@@ -336,11 +336,7 @@ unsigned int txn_alloc_data(unsigned int virt_irq)
 
 static inline int eirr_to_irq(unsigned long eirr)
 {
-#ifdef CONFIG_64BIT
-       int bit = fls64(eirr);
-#else
-       int bit = fls(eirr);
-#endif
+       int bit = fls_long(eirr);
        return (BITS_PER_LONG - bit) + TIMER_IRQ;
 }
 
index f50b982..fdacdd4 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/fs.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/bug.h>
 
 #include <asm/unwind.h>
 
@@ -96,7 +97,7 @@ static inline int in_local_section(struct module *me, void *loc, void *dot)
 }
 
 
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
 struct got_entry {
        Elf32_Addr addr;
 };
@@ -176,7 +177,7 @@ void *module_alloc(unsigned long size)
        return vmalloc(size);
 }
 
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
 static inline unsigned long count_gots(const Elf_Rela *rela, unsigned long n)
 {
        return 0;
@@ -319,7 +320,7 @@ int module_frob_arch_sections(CONST Elf_Ehdr *hdr,
        return 0;
 }
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 static Elf64_Word get_got(struct module *me, unsigned long value, long addend)
 {
        unsigned int i;
@@ -342,9 +343,9 @@ static Elf64_Word get_got(struct module *me, unsigned long value, long addend)
               value);
        return i * sizeof(struct got_entry);
 }
-#endif /* __LP64__ */
+#endif /* CONFIG_64BIT */
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 static Elf_Addr get_fdesc(struct module *me, unsigned long value)
 {
        Elf_Fdesc *fdesc = me->module_core + me->arch.fdesc_offset;
@@ -368,7 +369,7 @@ static Elf_Addr get_fdesc(struct module *me, unsigned long value)
        fdesc->gp = (Elf_Addr)me->module_core + me->arch.got_offset;
        return (Elf_Addr)fdesc;
 }
-#endif /* __LP64__ */
+#endif /* CONFIG_64BIT */
 
 enum elf_stub_type {
        ELF_STUB_GOT,
@@ -394,7 +395,7 @@ static Elf_Addr get_stub(struct module *me, unsigned long value, long addend,
                        i * sizeof(struct stub_entry);
        }
 
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
 /* for 32-bit the stub looks like this:
  *     ldil L'XXX,%r1
  *     be,n R'XXX(%sr4,%r1)
@@ -472,7 +473,7 @@ int apply_relocate(Elf_Shdr *sechdrs,
        return -ENOEXEC;
 }
 
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
 int apply_relocate_add(Elf_Shdr *sechdrs,
                       const char *strtab,
                       unsigned int symindex,
@@ -822,7 +823,8 @@ int module_finalize(const Elf_Ehdr *hdr,
               me->name, strtab, symhdr);
 
        if(me->arch.got_count > MAX_GOTS) {
-               printk(KERN_ERR "%s: Global Offset Table overflow (used %ld, allowed %d\n", me->name, me->arch.got_count, MAX_GOTS);
+               printk(KERN_ERR "%s: Global Offset Table overflow (used %ld, allowed %d)\n",
+                               me->name, me->arch.got_count, MAX_GOTS);
                return -EINVAL;
        }
        
@@ -850,10 +852,11 @@ int module_finalize(const Elf_Ehdr *hdr,
        nsyms = newptr - (Elf_Sym *)symhdr->sh_addr;
        DEBUGP("NEW num_symtab %lu\n", nsyms);
        symhdr->sh_size = nsyms * sizeof(Elf_Sym);
-       return 0;
+       return module_bug_finalize(hdr, sechdrs, me);
 }
 
 void module_arch_cleanup(struct module *mod)
 {
        deregister_unwind_table(mod);
+       module_bug_cleanup(mod);
 }
index e81c993..90b2408 100644 (file)
  */
 
 #ifdef CONFIG_64BIT
-#define ADDIB  addib,*
-#define CMPB   cmpb,*
-#define ANDCM  andcm,*
-
        .level  2.0w
 #else
-#define ADDIB  addib,
-#define CMPB   cmpb,
-#define ANDCM  andcm
-
        .level  2.0
 #endif
 
-
 #include <asm/psw.h>
 #include <asm/assembly.h>
 #include <asm/pgtable.h>
 #include <asm/cache.h>
+#include <linux/linkage.h>
 
        .text
        .align  128
 
-       .export flush_tlb_all_local,code
-
-flush_tlb_all_local:
+ENTRY(flush_tlb_all_local)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -200,11 +190,11 @@ fdtdone:
 
        .exit
        .procend
+ENDPROC(flush_tlb_all_local)
 
-       .export flush_instruction_cache_local,code
        .import cache_info,data
 
-flush_instruction_cache_local:
+ENTRY(flush_instruction_cache_local)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -241,11 +231,11 @@ fisync:
        .exit
 
        .procend
+ENDPROC(flush_instruction_cache_local)
 
-       .export flush_data_cache_local, code
-       .import cache_info, data
 
-flush_data_cache_local:
+       .import cache_info, data
+ENTRY(flush_data_cache_local)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -283,11 +273,11 @@ fdsync:
        .exit
 
        .procend
+ENDPROC(flush_data_cache_local)
 
-       .export copy_user_page_asm,code
        .align  16
 
-copy_user_page_asm:
+ENTRY(copy_user_page_asm)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -409,6 +399,7 @@ copy_user_page_asm:
        .exit
 
        .procend
+ENDPROC(copy_user_page_asm)
 
 /*
  * NOTE: Code in clear_user_page has a hard coded dependency on the
@@ -446,9 +437,7 @@ copy_user_page_asm:
         * lobby for such a change.
         */
 
-       .export copy_user_page_asm,code
-
-copy_user_page_asm:
+ENTRY(copy_user_page_asm)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -534,11 +523,10 @@ copy_user_page_asm:
        .exit
 
        .procend
+ENDPROC(copy_user_page_asm)
 #endif
 
-       .export __clear_user_page_asm,code
-
-__clear_user_page_asm:
+ENTRY(__clear_user_page_asm)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -618,10 +606,9 @@ __clear_user_page_asm:
        .exit
 
        .procend
+ENDPROC(__clear_user_page_asm)
 
-       .export flush_kernel_dcache_page_asm
-
-flush_kernel_dcache_page_asm:
+ENTRY(flush_kernel_dcache_page_asm)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -662,10 +649,9 @@ flush_kernel_dcache_page_asm:
        .exit
 
        .procend
+ENDPROC(flush_kernel_dcache_page_asm)
        
-       .export flush_user_dcache_page
-
-flush_user_dcache_page:
+ENTRY(flush_user_dcache_page)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -706,10 +692,9 @@ flush_user_dcache_page:
        .exit
 
        .procend
+ENDPROC(flush_user_dcache_page)
 
-       .export flush_user_icache_page
-
-flush_user_icache_page:
+ENTRY(flush_user_icache_page)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -750,11 +735,10 @@ flush_user_icache_page:
        .exit
 
        .procend
+ENDPROC(flush_user_icache_page)
 
 
-       .export purge_kernel_dcache_page
-
-purge_kernel_dcache_page:
+ENTRY(purge_kernel_dcache_page)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -794,15 +778,14 @@ purge_kernel_dcache_page:
        .exit
 
        .procend
+ENDPROC(purge_kernel_dcache_page)
 
 #if 0
        /* Currently not used, but it still is a possible alternate
         * solution.
         */
 
-       .export flush_alias_page
-
-flush_alias_page:
+ENTRY(flush_alias_page)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -882,10 +865,9 @@ flush_user_dcache_range_asm:
        .exit
 
        .procend
+ENDPROC(flush_alias_page)
 
-       .export flush_kernel_dcache_range_asm
-
-flush_kernel_dcache_range_asm:
+ENTRY(flush_kernel_dcache_range_asm)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -905,10 +887,9 @@ flush_kernel_dcache_range_asm:
        .exit
 
        .procend
+ENDPROC(flush_kernel_dcache_range_asm)
 
-       .export flush_user_icache_range_asm
-
-flush_user_icache_range_asm:
+ENTRY(flush_user_icache_range_asm)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -927,10 +908,9 @@ flush_user_icache_range_asm:
        .exit
 
        .procend
+ENDPROC(flush_user_icache_range_asm)
 
-       .export flush_kernel_icache_page
-
-flush_kernel_icache_page:
+ENTRY(flush_kernel_icache_page)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -971,10 +951,9 @@ flush_kernel_icache_page:
        .exit
 
        .procend
+ENDPROC(flush_kernel_icache_page)
 
-       .export flush_kernel_icache_range_asm
-
-flush_kernel_icache_range_asm:
+ENTRY(flush_kernel_icache_range_asm)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -992,14 +971,13 @@ flush_kernel_icache_range_asm:
        nop
        .exit
        .procend
+ENDPROC(flush_kernel_icache_range_asm)
 
        /* align should cover use of rfi in disable_sr_hashing_asm and
         * srdis_done.
         */
        .align  256
-       .export disable_sr_hashing_asm,code
-
-disable_sr_hashing_asm:
+ENTRY(disable_sr_hashing_asm)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -1088,5 +1066,6 @@ srdis_done:
        .exit
 
        .procend
+ENDPROC(disable_sr_hashing_asm)
 
        .end
index 8f6a0b3..7aca704 100644 (file)
@@ -7,7 +7,7 @@
  *    Copyright (C) 2001-2003 Grant Grundler <grundler with parisc-linux.org>
  *    Copyright (C) 2002-2003 Matthew Wilcox <willy at parisc-linux.org>
  *    Copyright (C) 2002 Randolph Chung <tausq at parisc-linux.org>
- *    Copyright (C) 2002-2003 Helge Deller <deller with parisc-linux.org>
+ *    Copyright (C) 2002-2007 Helge Deller <deller with parisc-linux.org>
  * 
  *    This program is free software; you can redistribute it and/or modify
  *    it under the terms of the GNU General Public License as published by
@@ -38,7 +38,7 @@ EXPORT_SYMBOL(__cmpxchg_u32);
 #ifdef CONFIG_SMP
 EXPORT_SYMBOL(__atomic_hash);
 #endif
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 EXPORT_SYMBOL(__xchg64);
 EXPORT_SYMBOL(__cmpxchg_u64);
 #endif
@@ -58,7 +58,7 @@ EXPORT_SYMBOL(fixup_get_user_skip_2);
 EXPORT_SYMBOL(fixup_put_user_skip_1);
 EXPORT_SYMBOL(fixup_put_user_skip_2);
 
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
 /* Needed so insmod can set dp value */
 extern int $global$;
 EXPORT_SYMBOL($global$);
@@ -135,7 +135,7 @@ EXPORT_SYMBOL(__muldi3);
 asmlinkage void * __canonicalize_funcptr_for_compare(void *);
 EXPORT_SYMBOL(__canonicalize_funcptr_for_compare);
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 extern void __divdi3(void);
 extern void __udivdi3(void);
 extern void __umoddi3(void);
@@ -147,7 +147,7 @@ EXPORT_SYMBOL(__umoddi3);
 EXPORT_SYMBOL(__moddi3);
 #endif
 
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
 extern void $$dyncall(void);
 EXPORT_SYMBOL($$dyncall);
 #endif
index a6caf10..0c3aecb 100644 (file)
@@ -342,7 +342,7 @@ pcxl_dma_init(void)
        pcxl_res_map = (char *)__get_free_pages(GFP_KERNEL,
                                            get_order(pcxl_res_size));
        memset(pcxl_res_map, 0, pcxl_res_size);
-       proc_gsc_root = proc_mkdir("gsc", 0);
+       proc_gsc_root = proc_mkdir("gsc", NULL);
        if (!proc_gsc_root)
                printk(KERN_WARNING
                        "pcxl_dma_init: Unable to create gsc /proc dir entry\n");
index 199887a..563df00 100644 (file)
@@ -200,8 +200,8 @@ static void
 pcibios_link_hba_resources( struct resource *hba_res, struct resource *r)
 {
        if (!r->parent) {
-               printk(KERN_EMERG "PCI: resource not parented! [%lx-%lx]\n",
-                               r->start, r->end);
+               printk(KERN_EMERG "PCI: resource not parented! [%p-%p]\n",
+                               (void*) r->start, (void*) r->end);
                r->parent = hba_res;
 
                /* reverse link is harder *sigh*  */
index 5e7bb90..43874ca 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include <asm/assembly.h>
+#include <linux/linkage.h>
 
 #ifdef CONFIG_64BIT
        .level          2.0w
 ; starting/stopping the coprocessor with the pmenb/pmdis.
 ;
        .text
-       .align 32
 
-       .export perf_intrigue_enable_perf_counters,code
-perf_intrigue_enable_perf_counters:
+ENTRY(perf_intrigue_enable_perf_counters)
        .proc
        .callinfo  frame=0,NO_CALLS
        .entry
@@ -69,9 +68,9 @@ perf_intrigue_enable_perf_counters:
        nop
        .exit
        .procend
+ENDPROC(perf_intrigue_enable_perf_counters)
 
-       .export perf_intrigue_disable_perf_counters,code
-perf_intrigue_disable_perf_counters:
+ENTRY(perf_intrigue_disable_perf_counters)
        .proc
        .callinfo  frame=0,NO_CALLS
        .entry
@@ -86,6 +85,7 @@ perf_intrigue_disable_perf_counters:
        mtctl   %r26,ccr                 ; turn off performance coprocessor
        .exit
        .procend
+ENDPROC(perf_intrigue_disable_perf_counters)
 
 ;***********************************************************************
 ;*
@@ -117,8 +117,7 @@ perf_intrigue_disable_perf_counters:
 ;*
 ;***********************************************************************
 
-       .export perf_rdr_shift_in_W,code
-perf_rdr_shift_in_W:
+ENTRY(perf_rdr_shift_in_W)
        .proc
        .callinfo frame=0,NO_CALLS
        .entry
@@ -550,6 +549,7 @@ perf_rdr_shift_in_W_leave:
        .exit
        MTDIAG_2        (24)                    ; restore DR2
        .procend
+ENDPROC(perf_rdr_shift_in_W)
 
 
 ;***********************************************************************
@@ -575,8 +575,7 @@ perf_rdr_shift_in_W_leave:
 ;*
 ;***********************************************************************
 
-       .export perf_rdr_shift_out_W,code
-perf_rdr_shift_out_W:
+ENTRY(perf_rdr_shift_out_W)
        .proc
        .callinfo frame=0,NO_CALLS
        .entry
@@ -983,6 +982,7 @@ perf_rdr_shift_out_W_leave:
        .exit
        MTDIAG_2        (23)                    ; restore DR2
        .procend
+ENDPROC(perf_rdr_shift_out_W)
 
 
 ;***********************************************************************
@@ -1012,8 +1012,7 @@ perf_rdr_shift_out_W_leave:
 ;*
 ;***********************************************************************
 
-       .export perf_rdr_shift_in_U,code
-perf_rdr_shift_in_U:
+ENTRY(perf_rdr_shift_in_U)
        .proc
        .callinfo frame=0,NO_CALLS
        .entry
@@ -1343,6 +1342,7 @@ perf_rdr_shift_in_U_leave:
        .exit
        MTDIAG_2        (24)                    ; restore DR2
        .procend
+ENDPROC(perf_rdr_shift_in_U)
 
 ;***********************************************************************
 ;*
@@ -1369,8 +1369,7 @@ perf_rdr_shift_in_U_leave:
 ;*
 ;***********************************************************************
 
-       .export perf_rdr_shift_out_U,code
-perf_rdr_shift_out_U:
+ENTRY(perf_rdr_shift_out_U)
        .proc
        .callinfo frame=0,NO_CALLS
        .entry
@@ -1687,4 +1686,5 @@ perf_rdr_shift_out_U_leave:
        .exit
        MTDIAG_2        (23)                    ; restore DR2
        .procend
+ENDPROC(perf_rdr_shift_out_U)
 
index 2f9f9df..0dd3847 100644 (file)
@@ -13,7 +13,7 @@
  *    Copyright (C) 2000 Grant Grundler <grundler with parisc-linux.org>
  *    Copyright (C) 2001 Alan Modra <amodra at parisc-linux.org>
  *    Copyright (C) 2001-2002 Ryan Bradetich <rbrad at parisc-linux.org>
- *    Copyright (C) 2001-2002 Helge Deller <deller at parisc-linux.org>
+ *    Copyright (C) 2001-2007 Helge Deller <deller at parisc-linux.org>
  *    Copyright (C) 2002 Randolph Chung <tausq with parisc-linux.org>
  *
  *
@@ -303,7 +303,7 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
                 * Copy function and argument to be called from
                 * ret_from_kernel_thread.
                 */
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
                cregs->gr[27] = pregs->gr[27];
 #endif
                cregs->gr[26] = pregs->gr[26];
@@ -355,8 +355,8 @@ asmlinkage int sys_execve(struct pt_regs *regs)
        error = PTR_ERR(filename);
        if (IS_ERR(filename))
                goto out;
-       error = do_execve(filename, (char __user **) regs->gr[25],
-               (char __user **) regs->gr[24], regs);
+       error = do_execve(filename, (char __user * __user *) regs->gr[25],
+               (char __user * __user *) regs->gr[24], regs);
        if (error == 0) {
                task_lock(current);
                current->ptrace &= ~PT_DTRACE;
index fb81e56..7c056dc 100644 (file)
@@ -93,7 +93,7 @@ static int __init processor_probe(struct parisc_device *dev)
        cpuid = boot_cpu_data.cpu_count;
        txn_addr = dev->hpa.start;      /* for legacy PDC */
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        if (is_pdc_pat()) {
                ulong status;
                unsigned long bytecnt;
@@ -153,8 +153,6 @@ static int __init processor_probe(struct parisc_device *dev)
        p->cpuid = cpuid;       /* save CPU id */
        p->txn_addr = txn_addr; /* save CPU IRQ address */
 #ifdef CONFIG_SMP
-       spin_lock_init(&p->lock);
-
        /*
        ** FIXME: review if any other initialization is clobbered
        **      for boot_cpu by the above memset().
@@ -311,11 +309,11 @@ int __init init_per_cpu(int cpunum)
        } else {
                printk(KERN_WARNING  "WARNING: No FP CoProcessor?!"
                        " (coproc_cfg.ccr_functional == 0x%lx, expected 0xc0)\n"
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
                        "Halting Machine - FP required\n"
 #endif
                        , coproc_cfg.ccr_functional);
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
                mdelay(100);    /* previous chars get pushed to console */
                panic("FP CoProc not reported");
 #endif
@@ -339,9 +337,6 @@ show_cpuinfo (struct seq_file *m, void *v)
 #ifdef CONFIG_SMP
                if (0 == cpu_data[n].hpa)
                        continue;
-#ifdef ENTRY_SYS_CPUS
-#error iCOD support wants to show CPU state here
-#endif
 #endif
                seq_printf(m, "processor\t: %d\n"
                                "cpu family\t: PA-RISC %s\n",
index 3f28de9..0d0d617 100644 (file)
@@ -36,7 +36,7 @@
 #define DBG(x...)
 #endif
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 
 /* This function is needed to translate 32 bit pt_regs offsets in to
  * 64 bit pt_regs offsets.  For example, a 32 bit gdb under a 64 bit kernel
@@ -90,7 +90,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
        case PTRACE_PEEKDATA: {
                int copied;
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
                if (__is_compat_task(child)) {
                        unsigned int tmp;
 
@@ -122,7 +122,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
        case PTRACE_POKETEXT: /* write the word at location addr. */
        case PTRACE_POKEDATA:
                ret = 0;
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
                if (__is_compat_task(child)) {
                        unsigned int tmp = (unsigned int)data;
                        DBG("sys_ptrace(POKE%s, %d, %lx, %lx)\n",
@@ -145,7 +145,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
           processes, the kernel saves all regs on a syscall. */
        case PTRACE_PEEKUSR: {
                ret = -EIO;
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
                if (__is_compat_task(child)) {
                        unsigned int tmp;
 
@@ -204,7 +204,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        ret = 0;
                        goto out_tsk;
                }
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
                if (__is_compat_task(child)) {
                        if (addr & (sizeof(int)-1))
                                goto out_tsk;
index 789061f..7a92695 100644 (file)
@@ -11,6 +11,8 @@
 #include <asm/psw.h>
 #include <asm/assembly.h>
 
+#include <linux/linkage.h>
+
        .section        .bss
        .export real_stack
        .export real32_stack
@@ -39,8 +41,6 @@ save_cr_end:
 
        .text
 
-       .export real32_call_asm
-
        /* unsigned long real32_call_asm(unsigned int *sp,
         *              unsigned int *arg0p,
         *              unsigned int iodc_fn)
@@ -49,7 +49,7 @@ save_cr_end:
         *      iodc_fn is the IODC function to call
         */
 
-real32_call_asm:
+ENTRY(real32_call_asm)
        STREG   %rp, -RP_OFFSET(%sp)    /* save RP */
 #ifdef CONFIG_64BIT
        callee_save
@@ -107,6 +107,7 @@ ric_ret:
        LDREG   -RP_OFFSET(%sp), %rp    /* restore RP */
        bv      0(%rp)
        nop
+ENDPROC(real32_call_asm)
 
 
 #  define PUSH_CR(r, where) mfctl r, %r1 ! STREG,ma %r1, REG_SZ(where)
@@ -218,7 +219,6 @@ rfi_r2v_1:
 /************************ 64-bit real-mode calls ***********************/
 /* This is only usable in wide kernels right now and will probably stay so */
        .text
-       .export real64_call_asm
        /* unsigned long real64_call_asm(unsigned long *sp,
         *              unsigned long *arg0p,
         *              unsigned long fn)
@@ -226,7 +226,7 @@ rfi_r2v_1:
         *      arg0p points to where saved arg values may be found
         *      iodc_fn is the IODC function to call
         */
-real64_call_asm:
+ENTRY(real64_call_asm)
        std     %rp, -0x10(%sp)         /* save RP */
        std     %sp, -8(%arg0)          /* save SP on real-mode stack */
        copy    %arg0, %sp              /* adopt the real-mode SP */
@@ -272,19 +272,21 @@ r64_ret:
        ldd     -0x10(%sp), %rp         /* restore RP */
        bv      0(%rp)
        nop
+ENDPROC(real64_call_asm)
 
 #endif
 
-       .export __canonicalize_funcptr_for_compare
        .text
        /* http://lists.parisc-linux.org/hypermail/parisc-linux/10916.html
        **      GCC 3.3 and later has a new function in libgcc.a for
        **      comparing function pointers.
        */
-__canonicalize_funcptr_for_compare:
+ENTRY(__canonicalize_funcptr_for_compare)
 #ifdef CONFIG_64BIT
        bve (%r2)
 #else
        bv %r0(%r2)
 #endif
        copy %r26,%r28
+ENDPROC(__canonicalize_funcptr_for_compare)
+
index 74b3686..bd2116e 100644 (file)
@@ -120,13 +120,13 @@ extern void collect_boot_cpu_data(void);
 
 void __init setup_arch(char **cmdline_p)
 {
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        extern int parisc_narrow_firmware;
 #endif
 
        init_per_cpu(smp_processor_id());       /* Set Modes & Enable FP */
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        printk(KERN_INFO "The 64-bit Kernel has started...\n");
 #else
        printk(KERN_INFO "The 32-bit Kernel has started...\n");
@@ -134,7 +134,7 @@ void __init setup_arch(char **cmdline_p)
 
        pdc_console_init();
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        if(parisc_narrow_firmware) {
                printk(KERN_INFO "Kernel is using PDC in 32-bit mode.\n");
        }
index ee6653e..9784e40 100644 (file)
  * this. */
 #define A(__x) ((unsigned long)(__x))
 
-int do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall);
-
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 #include "sys32.h"
 #endif
 
-asmlinkage int
-sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs)
-{
-       sigset_t saveset, newset;
-#ifdef __LP64__
-       compat_sigset_t newset32;
-
-       if (is_compat_task()) {
-               /* XXX: Don't preclude handling different sized sigset_t's.  */
-               if (sigsetsize != sizeof(compat_sigset_t))
-                       return -EINVAL;
-               if (copy_from_user(&newset32, (compat_sigset_t __user *)unewset, sizeof(newset32)))
-                       return -EFAULT;
-               sigset_32to64(&newset,&newset32);
-               
-       } else 
-#endif
-       {
-               /* XXX: Don't preclude handling different sized sigset_t's.  */
-               if (sigsetsize != sizeof(sigset_t))
-                       return -EINVAL;
-       
-               if (copy_from_user(&newset, unewset, sizeof(newset)))
-                       return -EFAULT;
-       }
-
-       sigdelsetmask(&newset, ~_BLOCKABLE);
-
-       spin_lock_irq(&current->sighand->siglock);
-       saveset = current->blocked;
-       current->blocked = newset;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
-       regs->gr[28] = -EINTR;
-       while (1) {
-               current->state = TASK_INTERRUPTIBLE;
-               schedule();
-               if (do_signal(&saveset, regs, 1))
-                       return -EINTR;
-       }
-}
-
 /*
  * Do a signal return - restore sigcontext.
  */
@@ -148,7 +103,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
        sigset_t set;
        unsigned long usp = (regs->gr[30] & ~(0x01UL));
        unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE;
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        compat_sigset_t compat_set;
        struct compat_rt_sigframe __user * compat_frame;
        
@@ -162,7 +117,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
                (usp - sigframe_size);
        DBG(2,"sys_rt_sigreturn: frame is %p\n", frame);
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        compat_frame = (struct compat_rt_sigframe __user *)frame;
        
        if (is_compat_task()) {
@@ -184,7 +139,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
        spin_unlock_irq(&current->sighand->siglock);
 
        /* Good thing we saved the old gr[30], eh? */
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        if (is_compat_task()) {
                DBG(1,"sys_rt_sigreturn: compat_frame->uc.uc_mcontext 0x%p\n",
                                &compat_frame->uc.uc_mcontext);
@@ -296,7 +251,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        unsigned long rp, usp;
        unsigned long haddr, sigframe_size;
        int err = 0;
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        compat_int_t compat_val;
        struct compat_rt_sigframe __user * compat_frame;
        compat_sigset_t compat_set;
@@ -310,7 +265,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        DBG(1,"setup_rt_frame: frame %p info %p\n", frame, info);
 
        
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 
        compat_frame = (struct compat_rt_sigframe __user *)frame;
        
@@ -390,7 +345,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 
        haddr = A(ka->sa.sa_handler);
        /* The sa_handler may be a pointer to a function descriptor */
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        if (is_compat_task()) {
 #endif
                if (haddr & PA_PLABEL_FDESC) {
@@ -405,7 +360,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                        haddr = fdesc.addr;
                        regs->gr[19] = fdesc.gp;
                }
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        } else {
                Elf64_Fdesc fdesc;
                Elf64_Fdesc __user *ufdesc = (Elf64_Fdesc __user *)A(haddr & ~3);
@@ -425,19 +380,19 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        /* The syscall return path will create IAOQ values from r31.
         */
        sigframe_size = PARISC_RT_SIGFRAME_SIZE;
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        if (is_compat_task())
                sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
 #endif
        if (in_syscall) {
                regs->gr[31] = haddr;
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
                if (!test_thread_flag(TIF_32BIT))
                        sigframe_size |= 1;
 #endif
        } else {
                unsigned long psw = USER_PSW;
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
                if (!test_thread_flag(TIF_32BIT))
                        psw |= PSW_W;
 #endif
@@ -462,7 +417,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        regs->gr[2]  = rp;                /* userland return pointer */
        regs->gr[26] = sig;               /* signal number */
        
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        if (is_compat_task()) {
                regs->gr[25] = A(&compat_frame->info); /* siginfo pointer */
                regs->gr[24] = A(&compat_frame->uc);   /* ucontext pointer */
@@ -516,6 +471,97 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
        return 1;
 }
 
+static inline void
+syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
+{
+       /* Check the return code */
+       switch (regs->gr[28]) {
+       case -ERESTART_RESTARTBLOCK:
+               current_thread_info()->restart_block.fn =
+                       do_no_restart_syscall;
+       case -ERESTARTNOHAND:
+               DBG(1,"ERESTARTNOHAND: returning -EINTR\n");
+               regs->gr[28] = -EINTR;
+               break;
+
+       case -ERESTARTSYS:
+               if (!(ka->sa.sa_flags & SA_RESTART)) {
+                       DBG(1,"ERESTARTSYS: putting -EINTR\n");
+                       regs->gr[28] = -EINTR;
+                       break;
+               }
+               /* fallthrough */
+       case -ERESTARTNOINTR:
+               /* A syscall is just a branch, so all
+                * we have to do is fiddle the return pointer.
+                */
+               regs->gr[31] -= 8; /* delayed branching */
+               /* Preserve original r28. */
+               regs->gr[28] = regs->orig_r28;
+               break;
+       }
+}
+
+static inline void
+insert_restart_trampoline(struct pt_regs *regs)
+{
+       switch(regs->gr[28]) {
+       case -ERESTART_RESTARTBLOCK: {
+               /* Restart the system call - no handlers present */
+               unsigned int *usp = (unsigned int *)regs->gr[30];
+
+               /* Setup a trampoline to restart the syscall
+                * with __NR_restart_syscall
+                *
+                *  0: <return address (orig r31)>
+                *  4: <2nd half for 64-bit>
+                *  8: ldw 0(%sp), %r31
+                * 12: be 0x100(%sr2, %r0)
+                * 16: ldi __NR_restart_syscall, %r20
+                */
+#ifdef CONFIG_64BIT
+               put_user(regs->gr[31] >> 32, &usp[0]);
+               put_user(regs->gr[31] & 0xffffffff, &usp[1]);
+               put_user(0x0fc010df, &usp[2]);
+#else
+               put_user(regs->gr[31], &usp[0]);
+               put_user(0x0fc0109f, &usp[2]);
+#endif
+               put_user(0xe0008200, &usp[3]);
+               put_user(0x34140000, &usp[4]);
+
+               /* Stack is 64-byte aligned, and we only need
+                * to flush 1 cache line.
+                * Flushing one cacheline is cheap.
+                * "sync" on bigger (> 4 way) boxes is not.
+                */
+               flush_icache_range(regs->gr[30], regs->gr[30] + 4);
+
+               regs->gr[31] = regs->gr[30] + 8;
+               /* Preserve original r28. */
+               regs->gr[28] = regs->orig_r28;
+
+               return;
+       }
+       case -ERESTARTNOHAND:
+       case -ERESTARTSYS:
+       case -ERESTARTNOINTR: {
+               /* Hooray for delayed branching.  We don't
+                * have to restore %r20 (the system call
+                * number) because it gets loaded in the delay
+                * slot of the branch external instruction.
+                */
+               regs->gr[31] -= 8;
+               /* Preserve original r28. */
+               regs->gr[28] = regs->orig_r28;
+
+               return;
+       }
+       default:
+               break;
+       }
+}
+
 /*
  * Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
@@ -527,13 +573,13 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
  * registers).  As noted below, the syscall number gets restored for
  * us due to the magic of delayed branching.
  */
-
-asmlinkage int
-do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall)
+asmlinkage void
+do_signal(struct pt_regs *regs, long in_syscall)
 {
        siginfo_t info;
        struct k_sigaction ka;
        int signr;
+       sigset_t *oldset;
 
        DBG(1,"\ndo_signal: oldset=0x%p, regs=0x%p, sr7 %#lx, in_syscall=%d\n",
               oldset, regs, regs->sr[7], in_syscall);
@@ -543,7 +589,9 @@ do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall)
           we would be called in that case, but for some reason we
           are. */
 
-       if (!oldset)
+       if (test_thread_flag(TIF_RESTORE_SIGMASK))
+               oldset = &current->saved_sigmask;
+       else
                oldset = &current->blocked;
 
        DBG(1,"do_signal: oldset %08lx / %08lx\n", 
@@ -560,98 +608,41 @@ do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall)
                  break;
                
                /* Restart a system call if necessary. */
-               if (in_syscall) {
-                       /* Check the return code */
-                       switch (regs->gr[28]) {
-                       case -ERESTART_RESTARTBLOCK:
-                               current_thread_info()->restart_block.fn = do_no_restart_syscall;
-                       case -ERESTARTNOHAND:
-                               DBG(1,"ERESTARTNOHAND: returning -EINTR\n");
-                               regs->gr[28] = -EINTR;
-                               break;
-
-                       case -ERESTARTSYS:
-                               if (!(ka.sa.sa_flags & SA_RESTART)) {
-                                       DBG(1,"ERESTARTSYS: putting -EINTR\n");
-                                       regs->gr[28] = -EINTR;
-                                       break;
-                               }
-                       /* fallthrough */
-                       case -ERESTARTNOINTR:
-                               /* A syscall is just a branch, so all
-                                  we have to do is fiddle the return pointer. */
-                               regs->gr[31] -= 8; /* delayed branching */
-                               /* Preserve original r28. */
-                               regs->gr[28] = regs->orig_r28;
-                               break;
-                       }
-               }
+               if (in_syscall)
+                       syscall_restart(regs, &ka);
+
                /* Whee!  Actually deliver the signal.  If the
                   delivery failed, we need to continue to iterate in
                   this loop so we can deliver the SIGSEGV... */
-               if (handle_signal(signr, &info, &ka, oldset, regs, in_syscall)) {
+               if (handle_signal(signr, &info, &ka, oldset,
+                                 regs, in_syscall)) {
                        DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n",
                                regs->gr[28]);
-                       return 1;
+                       if (test_thread_flag(TIF_RESTORE_SIGMASK))
+                               clear_thread_flag(TIF_RESTORE_SIGMASK);
+                       return;
                }
        }
        /* end of while(1) looping forever if we can't force a signal */
 
        /* Did we come from a system call? */
-       if (in_syscall) {
-               /* Restart the system call - no handlers present */
-               if (regs->gr[28] == -ERESTART_RESTARTBLOCK) {
-                       unsigned int *usp = (unsigned int *)regs->gr[30];
-
-                       /* Setup a trampoline to restart the syscall
-                        * with __NR_restart_syscall
-                        *
-                        *  0: <return address (orig r31)>
-                        *  4: <2nd half for 64-bit>
-                        *  8: ldw 0(%sp), %r31
-                        * 12: be 0x100(%sr2, %r0)
-                        * 16: ldi __NR_restart_syscall, %r20
-                        */
-#ifndef __LP64__
-                       put_user(regs->gr[31], &usp[0]);
-                       put_user(0x0fc0109f, &usp[2]);
-#else
-                       put_user(regs->gr[31] >> 32, &usp[0]);
-                       put_user(regs->gr[31] & 0xffffffff, &usp[1]);
-                       put_user(0x0fc010df, &usp[2]);
-#endif
-                       put_user(0xe0008200, &usp[3]);
-                       put_user(0x34140000, &usp[4]);
-
-                       /* Stack is 64-byte aligned, and we only need
-                        * to flush 1 cache line.
-                        * Flushing one cacheline is cheap.
-                        * "sync" on bigger (> 4 way) boxes is not.
-                        */
-                       asm("fdc %%r0(%%sr3, %0)\n"
-                           "sync\n"
-                           "fic %%r0(%%sr3, %0)\n"
-                           "sync\n"
-                           : : "r"(regs->gr[30]));
-
-                       regs->gr[31] = regs->gr[30] + 8;
-                       /* Preserve original r28. */
-                       regs->gr[28] = regs->orig_r28;
-               } else if (regs->gr[28] == -ERESTARTNOHAND ||
-                          regs->gr[28] == -ERESTARTSYS ||
-                          regs->gr[28] == -ERESTARTNOINTR) {
-                       /* Hooray for delayed branching.  We don't
-                           have to restore %r20 (the system call
-                           number) because it gets loaded in the delay
-                           slot of the branch external instruction. */
-                       regs->gr[31] -= 8;
-                       /* Preserve original r28. */
-                       regs->gr[28] = regs->orig_r28;
-               }
-       }
+       if (in_syscall)
+               insert_restart_trampoline(regs);
        
        DBG(1,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n", 
                regs->gr[28]);
 
-       return 0;
+       if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+               clear_thread_flag(TIF_RESTORE_SIGMASK);
+               sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+       }
+
+       return;
+}
+
+void do_notify_resume(struct pt_regs *regs, long in_syscall)
+{
+       if (test_thread_flag(TIF_SIGPENDING) ||
+           test_thread_flag(TIF_RESTORE_SIGMASK))
+               do_signal(regs, in_syscall);
 }
index a6b4231..1c1a37f 100644 (file)
@@ -1,6 +1,8 @@
 /*    Signal support for 32-bit kernel builds
  *
  *    Copyright (C) 2001 Matthew Wilcox <willy at parisc-linux.org>
+ *    Copyright (C) 2006 Kyle McMartin <kyle at parisc-linux.org>
+ *
  *    Code was mostly borrowed from kernel/signal.c.
  *    See kernel/signal.c for additional Copyrights.
  *
@@ -401,7 +403,7 @@ setup_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __
 int
 copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from)
 {
-       unsigned long tmp;
+       compat_uptr_t addr;
        int err;
 
        if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
@@ -424,8 +426,8 @@ copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from)
                        err |= __get_user(to->si_uid, &from->si_uid);
                        break;
                      case __SI_FAULT >> 16:
-                       err |= __get_user(tmp, &from->si_addr);
-                       to->si_addr = (void __user *) tmp;
+                       err |= __get_user(addr, &from->si_addr);
+                       to->si_addr = compat_ptr(addr);
                        break;
                      case __SI_POLL >> 16:
                        err |= __get_user(to->si_band, &from->si_band);
@@ -445,7 +447,8 @@ copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from)
 int
 copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from)
 {
-       unsigned int addr;
+       compat_uptr_t addr;
+       compat_int_t val;
        int err;
 
        if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
@@ -474,8 +477,8 @@ copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from)
                        err |= __put_user(from->si_uid, &to->si_uid);
                        break;
                case __SI_FAULT >> 16:
-                       /* avoid type-checking warnings by copying _pad[0] in lieu of si_addr... */
-                       err |= __put_user(from->_sifields._pad[0], &to->si_addr);
+                       addr = ptr_to_compat(from->si_addr);
+                       err |= __put_user(addr, &to->si_addr);
                        break;
                case __SI_POLL >> 16:
                        err |= __put_user(from->si_band, &to->si_band);
@@ -484,17 +487,36 @@ copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from)
                case __SI_TIMER >> 16:
                        err |= __put_user(from->si_tid, &to->si_tid);
                        err |= __put_user(from->si_overrun, &to->si_overrun);
-                       addr = (unsigned long) from->si_ptr;
-                       err |= __put_user(addr, &to->si_ptr);
+                       val = (compat_int_t)from->si_int;
+                       err |= __put_user(val, &to->si_int);
                        break;
                case __SI_RT >> 16:     /* Not generated by the kernel as of now.  */
                case __SI_MESGQ >> 16:
                        err |= __put_user(from->si_uid, &to->si_uid);
                        err |= __put_user(from->si_pid, &to->si_pid);
-                       addr = (unsigned long) from->si_ptr;
-                       err |= __put_user(addr, &to->si_ptr);
+                       val = (compat_int_t)from->si_int;
+                       err |= __put_user(val, &to->si_int);
                        break;
                }
        }
        return err;
 }
+
+asmlinkage long compat_sys_rt_sigqueueinfo(int pid, int sig,
+       struct compat_siginfo __user *uinfo)
+{
+       siginfo_t info;
+
+       if (copy_siginfo_from_user32(&info, uinfo))
+               return -EFAULT;
+
+       /* Not even root can pretend to send signals from the kernel.
+          Nor can they impersonate a kill(), which adds source info.  */
+       if (info.si_code >= 0)
+               return -EPERM;
+       info.si_signo = sig;
+
+       /* POSIX.1b doesn't mention process groups.  */
+       return kill_proc_info(sig, &info, pid);
+}
+
index 12cc019..6ba9257 100644 (file)
@@ -16,9 +16,6 @@
 **      the Free Software Foundation; either version 2 of the License, or
 **      (at your option) any later version.
 */
-#undef ENTRY_SYS_CPUS  /* syscall support for iCOD-like functionality */
-
-
 #include <linux/types.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <asm/unistd.h>
 #include <asm/cacheflush.h>
 
-#define kDEBUG 0
+#undef DEBUG_SMP
+#ifdef DEBUG_SMP
+static int smp_debug_lvl = 0;
+#define smp_debug(lvl, printargs...)           \
+               if (lvl >= smp_debug_lvl)       \
+                       printk(printargs);
+#else
+#define smp_debug(lvl, ...)
+#endif /* DEBUG_SMP */
 
 DEFINE_SPINLOCK(smp_lock);
 
@@ -76,6 +81,7 @@ cpumask_t cpu_possible_map __read_mostly = CPU_MASK_ALL;      /* Bitmap of Present CP
 EXPORT_SYMBOL(cpu_online_map);
 EXPORT_SYMBOL(cpu_possible_map);
 
+DEFINE_PER_CPU(spinlock_t, ipi_lock) = SPIN_LOCK_UNLOCKED;
 
 struct smp_call_struct {
        void (*func) (void *info);
@@ -107,13 +113,6 @@ enum ipi_message_type {
 static void
 ipi_init(int cpuid)
 {
-
-       /* If CPU is present ... */
-#ifdef ENTRY_SYS_CPUS
-       /* *and* running (not stopped) ... */
-#error iCOD support wants state checked here.
-#endif
-
 #error verify IRQ_OFFSET(IPI_IRQ) is ipi_interrupt() in new IRQ region
 
        if(cpu_online(cpuid) )
@@ -133,23 +132,12 @@ ipi_init(int cpuid)
 static void
 halt_processor(void) 
 {
-#ifdef ENTRY_SYS_CPUS
-#error halt_processor() needs rework
-/*
-** o migrate I/O interrupts off this CPU.
-** o leave IPI enabled - __cli() will disable IPI.
-** o leave CPU in online map - just change the state
-*/
-       cpu_data[this_cpu].state = STATE_STOPPED;
-       mark_bh(IPI_BH);
-#else
        /* REVISIT : redirect I/O Interrupts to another CPU? */
        /* REVISIT : does PM *know* this CPU isn't available? */
        cpu_clear(smp_processor_id(), cpu_online_map);
        local_irq_disable();
        for (;;)
                ;
-#endif
 }
 
 
@@ -167,10 +155,11 @@ ipi_interrupt(int irq, void *dev_id)
        mb();   /* Order interrupt and bit testing. */
 
        for (;;) {
-               spin_lock_irqsave(&(p->lock),flags);
+               spinlock_t *lock = &per_cpu(ipi_lock, this_cpu);
+               spin_lock_irqsave(lock, flags);
                ops = p->pending_ipi;
                p->pending_ipi = 0;
-               spin_unlock_irqrestore(&(p->lock),flags);
+               spin_unlock_irqrestore(lock, flags);
 
                mb(); /* Order bit clearing and data access. */
 
@@ -184,15 +173,11 @@ ipi_interrupt(int irq, void *dev_id)
 
                        switch (which) {
                        case IPI_NOP:
-#if (kDEBUG>=100)
-                               printk(KERN_DEBUG "CPU%d IPI_NOP\n",this_cpu);
-#endif /* kDEBUG */
+                               smp_debug(100, KERN_DEBUG "CPU%d IPI_NOP\n", this_cpu);
                                break;
                                
                        case IPI_RESCHEDULE:
-#if (kDEBUG>=100)
-                               printk(KERN_DEBUG "CPU%d IPI_RESCHEDULE\n",this_cpu);
-#endif /* kDEBUG */
+                               smp_debug(100, KERN_DEBUG "CPU%d IPI_RESCHEDULE\n", this_cpu);
                                /*
                                 * Reschedule callback.  Everything to be
                                 * done is done by the interrupt return path.
@@ -200,9 +185,7 @@ ipi_interrupt(int irq, void *dev_id)
                                break;
 
                        case IPI_CALL_FUNC:
-#if (kDEBUG>=100)
-                               printk(KERN_DEBUG "CPU%d IPI_CALL_FUNC\n",this_cpu);
-#endif /* kDEBUG */
+                               smp_debug(100, KERN_DEBUG "CPU%d IPI_CALL_FUNC\n", this_cpu);
                                {
                                        volatile struct smp_call_struct *data;
                                        void (*func)(void *info);
@@ -233,28 +216,16 @@ ipi_interrupt(int irq, void *dev_id)
                                break;
 
                        case IPI_CPU_START:
-#if (kDEBUG>=100)
-                               printk(KERN_DEBUG "CPU%d IPI_CPU_START\n",this_cpu);
-#endif /* kDEBUG */
-#ifdef ENTRY_SYS_CPUS
-                               p->state = STATE_RUNNING;
-#endif
+                               smp_debug(100, KERN_DEBUG "CPU%d IPI_CPU_START\n", this_cpu);
                                break;
 
                        case IPI_CPU_STOP:
-#if (kDEBUG>=100)
-                               printk(KERN_DEBUG "CPU%d IPI_CPU_STOP\n",this_cpu);
-#endif /* kDEBUG */
-#ifdef ENTRY_SYS_CPUS
-#else
+                               smp_debug(100, KERN_DEBUG "CPU%d IPI_CPU_STOP\n", this_cpu);
                                halt_processor();
-#endif
                                break;
 
                        case IPI_CPU_TEST:
-#if (kDEBUG>=100)
-                               printk(KERN_DEBUG "CPU%d is alive!\n",this_cpu);
-#endif /* kDEBUG */
+                               smp_debug(100, KERN_DEBUG "CPU%d is alive!\n", this_cpu);
                                break;
 
                        default:
@@ -275,12 +246,13 @@ static inline void
 ipi_send(int cpu, enum ipi_message_type op)
 {
        struct cpuinfo_parisc *p = &cpu_data[cpu];
+       spinlock_t *lock = &per_cpu(ipi_lock, cpu);
        unsigned long flags;
 
-       spin_lock_irqsave(&(p->lock),flags);
+       spin_lock_irqsave(lock, flags);
        p->pending_ipi |= 1 << op;
        gsc_writel(IPI_IRQ - CPU_IRQ_BASE, cpu_data[cpu].hpa);
-       spin_unlock_irqrestore(&(p->lock),flags);
+       spin_unlock_irqrestore(lock, flags);
 }
 
 
@@ -560,13 +532,8 @@ int __init smp_boot_one_cpu(int cpuid)
 
 alive:
        /* Remember the Slave data */
-#if (kDEBUG>=100)
-       printk(KERN_DEBUG "SMP: CPU:%d came alive after %ld _us\n",
+       smp_debug(100, KERN_DEBUG "SMP: CPU:%d came alive after %ld _us\n",
                cpuid, timeout * 100);
-#endif /* kDEBUG */
-#ifdef ENTRY_SYS_CPUS
-       cpu_data[cpuid].state = STATE_RUNNING;
-#endif
        return 0;
 }
 
@@ -574,10 +541,6 @@ void __devinit smp_prepare_boot_cpu(void)
 {
        int bootstrap_processor=cpu_data[0].cpuid;      /* CPU ID of BSP */
 
-#ifdef ENTRY_SYS_CPUS
-       cpu_data[0].state = STATE_RUNNING;
-#endif
-
        /* Setup BSP mappings */
        printk("SMP: bootstrap CPU ID is %d\n",bootstrap_processor);
 
@@ -616,101 +579,6 @@ int __cpuinit __cpu_up(unsigned int cpu)
        return cpu_online(cpu) ? 0 : -ENOSYS;
 }
 
-
-
-#ifdef ENTRY_SYS_CPUS
-/* Code goes along with:
-**    entry.s:        ENTRY_NAME(sys_cpus)   / * 215, for cpu stat * /
-*/
-int sys_cpus(int argc, char **argv)
-{
-       int i,j=0;
-       extern int current_pid(int cpu);
-
-       if( argc > 2 ) {
-               printk("sys_cpus:Only one argument supported\n");
-               return (-1);
-       }
-       if ( argc == 1 ){
-       
-#ifdef DUMP_MORE_STATE
-               for_each_online_cpu(i) {
-                       int cpus_per_line = 4;
-
-                       if (j++ % cpus_per_line)
-                               printk(" %3d",i);
-                       else
-                               printk("\n %3d",i);
-               }
-               printk("\n"); 
-#else
-               printk("\n 0\n"); 
-#endif
-       } else if((argc==2) && !(strcmp(argv[1],"-l"))) {
-               printk("\nCPUSTATE  TASK CPUNUM CPUID HARDCPU(HPA)\n");
-#ifdef DUMP_MORE_STATE
-               for_each_online_cpu(i) {
-                       if (cpu_data[i].cpuid != NO_PROC_ID) {
-                               switch(cpu_data[i].state) {
-                                       case STATE_RENDEZVOUS:
-                                               printk("RENDEZVS ");
-                                               break;
-                                       case STATE_RUNNING:
-                                               printk((current_pid(i)!=0) ? "RUNNING  " : "IDLING   ");
-                                               break;
-                                       case STATE_STOPPED:
-                                               printk("STOPPED  ");
-                                               break;
-                                       case STATE_HALTED:
-                                               printk("HALTED   ");
-                                               break;
-                                       default:
-                                               printk("%08x?", cpu_data[i].state);
-                                               break;
-                               }
-                               if(cpu_online(i)) {
-                                       printk(" %4d",current_pid(i));
-                               }       
-                               printk(" %6d",cpu_number_map(i));
-                               printk(" %5d",i);
-                               printk(" 0x%lx\n",cpu_data[i].hpa);
-                       }       
-               }
-#else
-               printk("\n%s  %4d      0     0 --------",
-                       (current->pid)?"RUNNING ": "IDLING  ",current->pid); 
-#endif
-       } else if ((argc==2) && !(strcmp(argv[1],"-s"))) { 
-#ifdef DUMP_MORE_STATE
-               printk("\nCPUSTATE   CPUID\n");
-               for_each_online_cpu(i) {
-                       if (cpu_data[i].cpuid != NO_PROC_ID) {
-                               switch(cpu_data[i].state) {
-                                       case STATE_RENDEZVOUS:
-                                               printk("RENDEZVS");break;
-                                       case STATE_RUNNING:
-                                               printk((current_pid(i)!=0) ? "RUNNING " : "IDLING");
-                                               break;
-                                       case STATE_STOPPED:
-                                               printk("STOPPED ");break;
-                                       case STATE_HALTED:
-                                               printk("HALTED  ");break;
-                                       default:
-                               }
-                               printk("  %5d\n",i);
-                       }       
-               }
-#else
-               printk("\n%s    CPU0",(current->pid==0)?"RUNNING ":"IDLING  "); 
-#endif
-       } else {
-               printk("sys_cpus:Unknown request\n");
-               return (-1);
-       }
-       return 0;
-}
-#endif /* ENTRY_SYS_CPUS */
-
 #ifdef CONFIG_PROC_FS
 int __init
 setup_profiling_timer(unsigned int multiplier)
index a058004..10859f5 100644 (file)
 #include <asm/errno.h>
 #include <asm/psw.h>
 #include <asm/thread_info.h>
-
 #include <asm/assembly.h>
 #include <asm/processor.h>
 
+#include <linux/linkage.h>
+
        /* We fill the empty parts of the gateway page with
         * something that will kill the kernel or a
         * userspace application.
         */
 #define KILL_INSN      break   0,0
 
-#ifdef CONFIG_64BIT
-       .level          2.0w
-#else
-       .level          1.1
-#endif
+       .level          LEVEL
 
        .text
 
        .import syscall_exit,code
        .import syscall_exit_rfi,code
-       .export linux_gateway_page
 
        /* Linux gateway page is aliased to virtual page 0 in the kernel
         * address space. Since it is a gateway page it cannot be
@@ -43,7 +39,7 @@
         */
 
        .align ASM_PAGE_SIZE
-linux_gateway_page:
+ENTRY(linux_gateway_page)
 
         /* ADDRESS 0x00 to 0xb0 = 176 bytes / 4 bytes per insn = 44 insns */
        .rept 44
@@ -595,73 +591,43 @@ cas_action:
           the other for the store. Either return -EFAULT.
           Each of the entries must be relocated. */
        .section __ex_table,"aw"
-#ifdef CONFIG_64BIT
-       /* Pad the address calculation */
-       .word   0,(2b - linux_gateway_page)
-       .word   0,(3b - linux_gateway_page)
-#else
-       .word   (2b - linux_gateway_page)
-       .word   (3b - linux_gateway_page)
-#endif
+       ASM_ULONG_INSN (1b - linux_gateway_page), (3b - linux_gateway_page)
+       ASM_ULONG_INSN (2b - linux_gateway_page), (3b - linux_gateway_page)
        .previous
 
-       .section __ex_table,"aw"
-#ifdef CONFIG_64BIT
-       /* Pad the address calculation */
-       .word   0,(1b - linux_gateway_page)
-       .word   0,(3b - linux_gateway_page)
-#else
-       .word   (1b - linux_gateway_page)
-       .word   (3b - linux_gateway_page)
-#endif
-       .previous
-
-end_compare_and_swap:
 
        /* Make sure nothing else is placed on this page */
        .align ASM_PAGE_SIZE
-       .export end_linux_gateway_page
-end_linux_gateway_page:
+END(linux_gateway_page)
+ENTRY(end_linux_gateway_page)
 
        /* Relocate symbols assuming linux_gateway_page is mapped
           to virtual address 0x0 */
-#ifdef CONFIG_64BIT
-       /* FIXME: The code will always be on the gateay page
-                 and thus it will be on the first 4k, the
-                 assembler seems to think that the final
-                 subtraction result is only a word in
-                 length, so we pad the value.
-       */
-#define LWS_ENTRY(_name_) .word 0,(lws_##_name_ - linux_gateway_page)
-#else
-#define LWS_ENTRY(_name_) .word  (lws_##_name_ - linux_gateway_page)
-#endif
+
+#define LWS_ENTRY(_name_) ASM_ULONG_INSN (lws_##_name_ - linux_gateway_page)
 
        .section .rodata,"a"
 
        .align ASM_PAGE_SIZE
        /* Light-weight-syscall table */
        /* Start of lws table. */
-       .export lws_table
-.Llws_table:
-lws_table:
+ENTRY(lws_table)
        LWS_ENTRY(compare_and_swap32)   /* 0 - ELF32 Atomic compare and swap */
        LWS_ENTRY(compare_and_swap64)   /* 1 - ELF64 Atomic compare and swap */
+END(lws_table)
        /* End of lws table */
 
        .align ASM_PAGE_SIZE
-       .export sys_call_table
-.Lsys_call_table:
-sys_call_table:
+ENTRY(sys_call_table)
 #include "syscall_table.S"
+END(sys_call_table)
 
 #ifdef CONFIG_64BIT
        .align ASM_PAGE_SIZE
-       .export sys_call_table64
-.Lsys_call_table64:
-sys_call_table64:
+ENTRY(sys_call_table64)
 #define SYSCALL_TABLE_64BIT
 #include "syscall_table.S"
+END(sys_call_table64)
 #endif
 
 #ifdef CONFIG_SMP
@@ -671,9 +637,7 @@ sys_call_table64:
        */
        .section .data
        .align 4096
-       .export lws_lock_start
-.Llws_lock_start:
-lws_lock_start:
+ENTRY(lws_lock_start)
        /* lws locks */
        .align 16
        .rept 16
@@ -683,6 +647,7 @@ lws_lock_start:
        .word 0
        .word 0
        .endr
+END(lws_lock_start)
        .previous
 #endif
 /* CONFIG_SMP for lws_lock_start */
index be8eb9a..8bf87e5 100644 (file)
@@ -10,7 +10,7 @@
  *    Copyright (C) 2000 Grant Grundler <grundler at parisc-linux.org>
  *    Copyright (C) 2001 Richard Hirst <rhirst with parisc-linux.org>
  *    Copyright (C) 2001-2002 Ryan Bradetich <rbrad at parisc-linux.org>
- *    Copyright (C) 2001 Helge Deller <deller at parisc-linux.org>
+ *    Copyright (C) 2001-2007 Helge Deller <deller at parisc-linux.org>
  *    Copyright (C) 2000-2001 Thomas Bogendoerfer <tsbogend at parisc-linux.org>
  *    Copyright (C) 2002 Randolph Chung <tausq with parisc-linux.org>
  *    Copyright (C) 2005-2006 Kyle McMartin <kyle at parisc-linux.org>
         * to worry about faulting trying to copy in a larger 64-bit
         * struct from a 32-bit user-space app.
         */
-       ENTRY_SAME(rt_sigqueueinfo)
-       ENTRY_SAME(rt_sigsuspend_wrapper) /* not really SAME -- see the code */
+       ENTRY_COMP(rt_sigqueueinfo)
+       ENTRY_COMP(rt_sigsuspend)
        ENTRY_SAME(chown)               /* 180 */
        /* setsockopt() used by iptables: SO_SET_REPLACE/SO_SET_ADD_COUNTERS */
        ENTRY_COMP(setsockopt)
        ENTRY_SAME(inotify_init)
        ENTRY_SAME(inotify_add_watch)   /* 270 */
        ENTRY_SAME(inotify_rm_watch)
-       ENTRY_SAME(ni_syscall)          /* 271 ENTRY_COMP(pselect6) */
-       ENTRY_SAME(ni_syscall)          /* 272 ENTRY_COMP(ppoll) */
        ENTRY_SAME(migrate_pages)
+       ENTRY_COMP(pselect6)
+       ENTRY_COMP(ppoll)
        ENTRY_COMP(openat)              /* 275 */
        ENTRY_SAME(mkdirat)
        ENTRY_SAME(mknodat)
        ENTRY_SAME(splice)
        ENTRY_OURS(sync_file_range)
        ENTRY_SAME(tee)
+       ENTRY_COMP(vmsplice)
+       ENTRY_COMP(move_pages)          /* 295 */
+       ENTRY_SAME(getcpu)
+       ENTRY_SAME(epoll_pwait)
+       ENTRY_COMP(statfs64)
+       ENTRY_COMP(fstatfs64)
        /* Nothing yet */
 
index 5f1b51a..d1db8e5 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <linux/profile.h>
+#include <linux/clocksource.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -98,7 +99,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id)
         * cycles after the IT fires. But it's arbitrary how much time passes
         * before we call it "late". I've picked one second.
         */
-       if (ticks_elapsed > HZ) {
+       if (unlikely(ticks_elapsed > HZ)) {
                /* Scenario 3: very long delay?  bad in any case */
                printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!"
                        " cycles %lX rem %lX "
@@ -147,10 +148,6 @@ irqreturn_t timer_interrupt(int irq, void *dev_id)
                write_sequnlock(&xtime_lock);
        }
 
-       /* check soft power switch status */
-       if (cpu == 0 && !atomic_read(&power_tasklet.count))
-               tasklet_schedule(&power_tasklet);
-
        return IRQ_HANDLED;
 }
 
@@ -172,121 +169,41 @@ unsigned long profile_pc(struct pt_regs *regs)
 EXPORT_SYMBOL(profile_pc);
 
 
-/*
- * Return the number of micro-seconds that elapsed since the last
- * update to wall time (aka xtime).  The xtime_lock
- * must be at least read-locked when calling this routine.
- */
-static inline unsigned long gettimeoffset (void)
-{
-#ifndef CONFIG_SMP
-       /*
-        * FIXME: This won't work on smp because jiffies are updated by cpu 0.
-        *    Once parisc-linux learns the cr16 difference between processors,
-        *    this could be made to work.
-        */
-       unsigned long now;
-       unsigned long prev_tick;
-       unsigned long next_tick;
-       unsigned long elapsed_cycles;
-       unsigned long usec;
-       unsigned long cpuid = smp_processor_id();
-       unsigned long cpt = clocktick;
-
-       next_tick = cpu_data[cpuid].it_value;
-       now = mfctl(16);        /* Read the hardware interval timer.  */
+/* clock source code */
 
-       prev_tick = next_tick - cpt;
+static cycle_t read_cr16(void)
+{
+       return get_cycles();
+}
 
-       /* Assume Scenario 1: "now" is later than prev_tick.  */
-       elapsed_cycles = now - prev_tick;
+static int cr16_update_callback(void);
 
-/* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */
-#if HZ == 1000
-       if (elapsed_cycles > (cpt << 10) )
-#elif HZ == 250
-       if (elapsed_cycles > (cpt << 8) )
-#elif HZ == 100
-       if (elapsed_cycles > (cpt << 7) )
-#else
-#warn WTF is HZ set to anyway?
-       if (elapsed_cycles > (HZ * cpt) )
-#endif
-       {
-               /* Scenario 3: clock ticks are missing. */
-               printk (KERN_CRIT "gettimeoffset(CPU %ld): missing %ld ticks!"
-                       " cycles %lX prev/now/next %lX/%lX/%lX  clock %lX\n",
-                       cpuid, elapsed_cycles / cpt,
-                       elapsed_cycles, prev_tick, now, next_tick, cpt);
-       }
+static struct clocksource clocksource_cr16 = {
+       .name                   = "cr16",
+       .rating                 = 300,
+       .read                   = read_cr16,
+       .mask                   = CLOCKSOURCE_MASK(BITS_PER_LONG),
+       .mult                   = 0, /* to be set */
+       .shift                  = 22,
+       .update_callback        = cr16_update_callback,
+       .is_continuous          = 1,
+};
 
-       /* FIXME: Can we improve the precision? Not with PAGE0. */
-       usec = (elapsed_cycles * 10000) / PAGE0->mem_10msec;
-       return usec;
-#else
-       return 0;
-#endif
-}
-
-void
-do_gettimeofday (struct timeval *tv)
+static int cr16_update_callback(void)
 {
-       unsigned long flags, seq, usec, sec;
-
-       /* Hold xtime_lock and adjust timeval.  */
-       do {
-               seq = read_seqbegin_irqsave(&xtime_lock, flags);
-               usec = gettimeoffset();
-               sec = xtime.tv_sec;
-               usec += (xtime.tv_nsec / 1000);
-       } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-
-       /* Move adjusted usec's into sec's.  */
-       while (usec >= USEC_PER_SEC) {
-               usec -= USEC_PER_SEC;
-               ++sec;
+       int change = 0;
+
+       /* since the cr16 cycle counters are not syncronized across CPUs,
+          we'll check if we should switch to a safe clocksource: */
+       if (clocksource_cr16.rating != 0 && num_online_cpus() > 1) {
+               clocksource_cr16.rating = 0;
+               clocksource_reselect();
+               change = 1;
        }
 
-       /* Return adjusted result.  */
-       tv->tv_sec = sec;
-       tv->tv_usec = usec;
+       return change;
 }
 
-EXPORT_SYMBOL(do_gettimeofday);
-
-int
-do_settimeofday (struct timespec *tv)
-{
-       time_t wtm_sec, sec = tv->tv_sec;
-       long wtm_nsec, nsec = tv->tv_nsec;
-
-       if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
-               return -EINVAL;
-
-       write_seqlock_irq(&xtime_lock);
-       {
-               /*
-                * This is revolting. We need to set "xtime"
-                * correctly. However, the value in this location is
-                * the value at the most recent update of wall time.
-                * Discover what correction gettimeofday would have
-                * done, and then undo it!
-                */
-               nsec -= gettimeoffset() * 1000;
-
-               wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
-               wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
-
-               set_normalized_timespec(&xtime, sec, nsec);
-               set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
-
-               ntp_clear();
-       }
-       write_sequnlock_irq(&xtime_lock);
-       clock_was_set();
-       return 0;
-}
-EXPORT_SYMBOL(do_settimeofday);
 
 void __init start_cpu_itimer(void)
 {
@@ -301,11 +218,18 @@ void __init start_cpu_itimer(void)
 void __init time_init(void)
 {
        static struct pdc_tod tod_data;
+       unsigned long current_cr16_khz;
 
        clocktick = (100 * PAGE0->mem_10msec) / HZ;
 
        start_cpu_itimer();     /* get CPU 0 started */
 
+       /* register at clocksource framework */
+       current_cr16_khz = PAGE0->mem_10msec/10;  /* kHz */
+       clocksource_cr16.mult = clocksource_khz2mult(current_cr16_khz,
+                                               clocksource_cr16.shift);
+       clocksource_register(&clocksource_cr16);
+
        if (pdc_tod_read(&tod_data) == 0) {
                unsigned long flags;
 
index 65cd6ca..55bc147 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/interrupt.h>
 #include <linux/console.h>
 #include <linux/kallsyms.h>
+#include <linux/bug.h>
 
 #include <asm/assembly.h>
 #include <asm/system.h>
@@ -39,6 +40,8 @@
 #include <asm/pdc.h>
 #include <asm/pdc_chassis.h>
 #include <asm/unwind.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
 
 #include "../math-emu/math-emu.h"      /* for handle_fpe() */
 
@@ -49,7 +52,7 @@
 DEFINE_SPINLOCK(pa_dbit_lock);
 #endif
 
-int printbinary(char *buf, unsigned long x, int nbits)
+static int printbinary(char *buf, unsigned long x, int nbits)
 {
        unsigned long mask = 1UL << (nbits - 1);
        while (mask != 0) {
@@ -61,7 +64,7 @@ int printbinary(char *buf, unsigned long x, int nbits)
        return nbits;
 }
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 #define RFMT "%016lx"
 #else
 #define RFMT "%08lx"
@@ -160,13 +163,13 @@ static void do_show_stack(struct unwind_frame_info *info)
 {
        int i = 1;
 
-       printk("Backtrace:\n");
+       printk(KERN_CRIT "Backtrace:\n");
        while (i <= 16) {
                if (unwind_once(info) < 0 || info->ip == 0)
                        break;
 
                if (__kernel_text_address(info->ip)) {
-                       printk(" [<" RFMT ">] ", info->ip);
+                       printk("%s [<" RFMT ">] ", (i&0x3)==1 ? KERN_CRIT : "", info->ip);
 #ifdef CONFIG_KALLSYMS
                        print_symbol("%s\n", info->ip);
 #else
@@ -185,18 +188,19 @@ void show_stack(struct task_struct *task, unsigned long *s)
 
        if (!task) {
                unsigned long sp;
-               struct pt_regs *r;
 
 HERE:
                asm volatile ("copy %%r30, %0" : "=r"(sp));
-               r = kzalloc(sizeof(struct pt_regs), GFP_KERNEL);
-               if (!r)
-                       return;
-               r->iaoq[0] = (unsigned long)&&HERE;
-               r->gr[2] = (unsigned long)__builtin_return_address(0);
-               r->gr[30] = sp;
-               unwind_frame_init(&info, current, r);
-               kfree(r);
+               {
+                       struct pt_regs r;
+
+                       memset(&r, 0, sizeof(struct pt_regs));
+                       r.iaoq[0] = (unsigned long)&&HERE;
+                       r.gr[2] = (unsigned long)__builtin_return_address(0);
+                       r.gr[30] = sp;
+
+                       unwind_frame_init(&info, current, &r);
+               }
        } else {
                unwind_frame_init_from_blocked_task(&info, task);
        }
@@ -204,6 +208,11 @@ HERE:
        do_show_stack(&info);
 }
 
+int is_valid_bugaddr(unsigned long iaoq)
+{
+       return 1;
+}
+
 void die_if_kernel(char *str, struct pt_regs *regs, long err)
 {
        if (user_mode(regs)) {
@@ -222,15 +231,15 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
        oops_in_progress = 1;
 
        /* Amuse the user in a SPARC fashion */
-       printk(
-"      _______________________________ \n"
-"     < Your System ate a SPARC! Gah! >\n"
-"      ------------------------------- \n"
-"             \\   ^__^\n"
-"              \\  (xx)\\_______\n"
-"                 (__)\\       )\\/\\\n"
-"                  U  ||----w |\n"
-"                     ||     ||\n");
+       if (err) printk(
+KERN_CRIT "      _______________________________ \n"
+KERN_CRIT "     < Your System ate a SPARC! Gah! >\n"
+KERN_CRIT "      ------------------------------- \n"
+KERN_CRIT "             \\   ^__^\n"
+KERN_CRIT "              \\  (xx)\\_______\n"
+KERN_CRIT "                 (__)\\       )\\/\\\n"
+KERN_CRIT "                  U  ||----w |\n"
+KERN_CRIT "                     ||     ||\n");
        
        /* unlock the pdc lock if necessary */
        pdc_emergency_unlock();
@@ -242,9 +251,20 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
        if (!console_drivers)
                pdc_console_restart();
        
-       printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n",
-               current->comm, current->pid, str, err);
+       if (err)
+               printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n",
+                       current->comm, current->pid, str, err);
+
+       /* Wot's wrong wif bein' racy? */
+       if (current->thread.flags & PARISC_KERNEL_DEATH) {
+               printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__);
+               local_irq_enable();
+               while (1);
+       }
+       current->thread.flags |= PARISC_KERNEL_DEATH;
+
        show_regs(regs);
+       dump_stack();
 
        if (in_interrupt())
                panic("Fatal exception in interrupt");
@@ -255,14 +275,6 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
                panic("Fatal exception");
        }
 
-       /* Wot's wrong wif bein' racy? */
-       if (current->thread.flags & PARISC_KERNEL_DEATH) {
-               printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__);
-               local_irq_enable();
-               while (1);
-       }
-
-       current->thread.flags |= PARISC_KERNEL_DEATH;
        do_exit(SIGSEGV);
 }
 
@@ -273,61 +285,45 @@ int syscall_ipi(int (*syscall) (struct pt_regs *), struct pt_regs *regs)
 
 /* gdb uses break 4,8 */
 #define GDB_BREAK_INSN 0x10004
-void handle_gdb_break(struct pt_regs *regs, int wot)
+static void handle_gdb_break(struct pt_regs *regs, int wot)
 {
        struct siginfo si;
 
-       si.si_code = wot;
-       si.si_addr = (void __user *) (regs->iaoq[0] & ~3);
        si.si_signo = SIGTRAP;
        si.si_errno = 0;
+       si.si_code = wot;
+       si.si_addr = (void __user *) (regs->iaoq[0] & ~3);
        force_sig_info(SIGTRAP, &si, current);
 }
 
-void handle_break(unsigned iir, struct pt_regs *regs)
+static void handle_break(struct pt_regs *regs)
 {
-       struct siginfo si;
-
-       switch(iir) {
-       case 0x00:
-#ifdef PRINT_USER_FAULTS
-               printk(KERN_DEBUG "break 0,0: pid=%d command='%s'\n",
-                      current->pid, current->comm);
-#endif
-               die_if_kernel("Breakpoint", regs, 0);
-#ifdef PRINT_USER_FAULTS
-               show_regs(regs);
-#endif
-               si.si_code = TRAP_BRKPT;
-               si.si_addr = (void __user *) (regs->iaoq[0] & ~3);
-               si.si_signo = SIGTRAP;
-               force_sig_info(SIGTRAP, &si, current);
-               break;
-
-       case GDB_BREAK_INSN:
-               die_if_kernel("Breakpoint", regs, 0);
-               handle_gdb_break(regs, TRAP_BRKPT);
-               break;
+       unsigned iir = regs->iir;
+
+       if (unlikely(iir == PARISC_BUG_BREAK_INSN && !user_mode(regs))) {
+               /* check if a BUG() or WARN() trapped here.  */
+               enum bug_trap_type tt;
+               tt = report_bug(regs->iaoq[0] & ~3);
+               if (tt == BUG_TRAP_TYPE_WARN) {
+                       regs->iaoq[0] += 4;
+                       regs->iaoq[1] += 4;
+                       return; /* return to next instruction when WARN_ON().  */
+               }
+               die_if_kernel("Unknown kernel breakpoint", regs,
+                       (tt == BUG_TRAP_TYPE_NONE) ? 9 : 0);
+       }
 
-       default:
 #ifdef PRINT_USER_FAULTS
-               printk(KERN_DEBUG "break %#08x: pid=%d command='%s'\n",
-                      iir, current->pid, current->comm);
+       if (unlikely(iir != GDB_BREAK_INSN)) {
+               printk(KERN_DEBUG "break %d,%d: pid=%d command='%s'\n",
+                       iir & 31, (iir>>13) & ((1<<13)-1),
+                       current->pid, current->comm);
                show_regs(regs);
-#endif
-               si.si_signo = SIGTRAP;
-               si.si_code = TRAP_BRKPT;
-               si.si_addr = (void __user *) (regs->iaoq[0] & ~3);
-               force_sig_info(SIGTRAP, &si, current);
-               return;
        }
-}
-
+#endif
 
-int handle_toc(void)
-{
-       printk(KERN_CRIT "TOC call.\n");
-       return 0;
+       /* send standard GDB signal */
+       handle_gdb_break(regs, TRAP_BRKPT);
 }
 
 static void default_trap(int code, struct pt_regs *regs)
@@ -336,7 +332,7 @@ static void default_trap(int code, struct pt_regs *regs)
        show_regs(regs);
 }
 
-void (*cpu_lpmc) (int code, struct pt_regs *regs) = default_trap;
+void (*cpu_lpmc) (int code, struct pt_regs *regs) __read_mostly = default_trap;
 
 
 void transfer_pim_to_trap_frame(struct pt_regs *regs)
@@ -554,7 +550,8 @@ void handle_interruption(int code, struct pt_regs *regs)
                /* Low-priority machine check */
                pdc_chassis_send_status(PDC_CHASSIS_DIRECT_LPMC);
                
-               flush_all_caches();
+               flush_cache_all();
+               flush_tlb_all();
                cpu_lpmc(5, regs);
                return;
 
@@ -572,7 +569,7 @@ void handle_interruption(int code, struct pt_regs *regs)
 
        case  9:
                /* Break instruction trap */
-               handle_break(regs->iir,regs);
+               handle_break(regs);
                return;
        
        case 10:
@@ -840,7 +837,7 @@ int __init check_ivt(void *iva)
        return 0;
 }
        
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
 extern const void fault_vector_11;
 #endif
 extern const void fault_vector_20;
@@ -852,7 +849,7 @@ void __init trap_init(void)
        if (boot_cpu_data.cpu_type >= pcxu)
                iva = (void *) &fault_vector_20;
        else
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
                panic("Can't boot 64-bit OS on PA1.1 processor!");
 #else
                iva = (void *) &fault_vector_11;
index bd2230d..347bb92 100644 (file)
  *
  */
 
+#include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
 #include <asm/uaccess.h>
 
 /* #define DEBUG_UNALIGNED 1 */
@@ -32,7 +35,7 @@
 #define DPRINTF(fmt, args...)
 #endif
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 #define RFMT "%016lx"
 #else
 #define RFMT "%08lx"
@@ -147,15 +150,8 @@ static int emulate_ldh(struct pt_regs *regs, int toreg)
 "4:    ldi     -2, %1\n"
        FIXUP_BRANCH(3b)
 "      .previous\n"
-"      .section __ex_table,\"aw\"\n"
-#ifdef __LP64__
-"      .dword  1b,4b\n"
-"      .dword  2b,4b\n"
-#else
-"      .word   1b,4b\n"
-"      .word   2b,4b\n"
-#endif
-"      .previous\n"
+       ASM_EXCEPTIONTABLE_ENTRY(1b, 4b)
+       ASM_EXCEPTIONTABLE_ENTRY(2b, 4b)
        : "=r" (val), "=r" (ret)
        : "0" (val), "r" (saddr), "r" (regs->isr)
        : "r20", FIXUP_BRANCH_CLOBBER );
@@ -192,15 +188,8 @@ static int emulate_ldw(struct pt_regs *regs, int toreg, int flop)
 "4:    ldi     -2, %1\n"
        FIXUP_BRANCH(3b)
 "      .previous\n"
-"      .section __ex_table,\"aw\"\n"
-#ifdef __LP64__
-"      .dword  1b,4b\n"
-"      .dword  2b,4b\n"
-#else
-"      .word   1b,4b\n"
-"      .word   2b,4b\n"
-#endif
-"      .previous\n"
+       ASM_EXCEPTIONTABLE_ENTRY(1b, 4b)
+       ASM_EXCEPTIONTABLE_ENTRY(2b, 4b)
        : "=r" (val), "=r" (ret)
        : "0" (val), "r" (saddr), "r" (regs->isr)
        : "r19", "r20", FIXUP_BRANCH_CLOBBER );
@@ -224,7 +213,7 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop)
                regs->isr, regs->ior, toreg);
 #ifdef CONFIG_PA20
 
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
        if (!flop)
                return -1;
 #endif
@@ -243,15 +232,8 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop)
 "4:    ldi     -2, %1\n"
        FIXUP_BRANCH(3b)
 "      .previous\n"
-"      .section __ex_table,\"aw\"\n"
-#ifdef __LP64__
-"      .dword  1b,4b\n"
-"      .dword  2b,4b\n"
-#else
-"      .word   1b,4b\n"
-"      .word   2b,4b\n"
-#endif
-"      .previous\n"
+       ASM_EXCEPTIONTABLE_ENTRY(1b,4b)
+       ASM_EXCEPTIONTABLE_ENTRY(2b,4b)
        : "=r" (val), "=r" (ret)
        : "0" (val), "r" (saddr), "r" (regs->isr)
        : "r19", "r20", FIXUP_BRANCH_CLOBBER );
@@ -275,17 +257,9 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop)
 "5:    ldi     -2, %2\n"
        FIXUP_BRANCH(4b)
 "      .previous\n"
-"      .section __ex_table,\"aw\"\n"
-#ifdef __LP64__
-"      .dword  1b,5b\n"
-"      .dword  2b,5b\n"
-"      .dword  3b,5b\n"
-#else
-"      .word   1b,5b\n"
-"      .word   2b,5b\n"
-"      .word   3b,5b\n"
-#endif
-"      .previous\n"
+       ASM_EXCEPTIONTABLE_ENTRY(1b,5b)
+       ASM_EXCEPTIONTABLE_ENTRY(2b,5b)
+       ASM_EXCEPTIONTABLE_ENTRY(3b,5b)
        : "=r" (valh), "=r" (vall), "=r" (ret)
        : "0" (valh), "1" (vall), "r" (saddr), "r" (regs->isr)
        : "r19", "r20", FIXUP_BRANCH_CLOBBER );
@@ -325,15 +299,8 @@ static int emulate_sth(struct pt_regs *regs, int frreg)
 "4:    ldi     -2, %0\n"
        FIXUP_BRANCH(3b)
 "      .previous\n"
-"      .section __ex_table,\"aw\"\n"
-#ifdef __LP64__
-"      .dword  1b,4b\n"
-"      .dword  2b,4b\n"
-#else
-"      .word   1b,4b\n"
-"      .word   2b,4b\n"
-#endif
-"      .previous\n"
+       ASM_EXCEPTIONTABLE_ENTRY(1b,4b)
+       ASM_EXCEPTIONTABLE_ENTRY(2b,4b)
        : "=r" (ret)
        : "r" (val), "r" (regs->ior), "r" (regs->isr)
        : "r19", FIXUP_BRANCH_CLOBBER );
@@ -379,15 +346,8 @@ static int emulate_stw(struct pt_regs *regs, int frreg, int flop)
 "4:    ldi     -2, %0\n"
        FIXUP_BRANCH(3b)
 "      .previous\n"
-"      .section __ex_table,\"aw\"\n"
-#ifdef __LP64__
-"      .dword  1b,4b\n"
-"      .dword  2b,4b\n"
-#else
-"      .word   1b,4b\n"
-"      .word   2b,4b\n"
-#endif
-"      .previous\n"
+       ASM_EXCEPTIONTABLE_ENTRY(1b,4b)
+       ASM_EXCEPTIONTABLE_ENTRY(2b,4b)
        : "=r" (ret)
        : "r" (val), "r" (regs->ior), "r" (regs->isr)
        : "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER );
@@ -410,7 +370,7 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop)
                val,  regs->isr, regs->ior);
 
 #ifdef CONFIG_PA20
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
        if (!flop)
                return -1;
 #endif
@@ -436,19 +396,10 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop)
 "6:    ldi     -2, %0\n"
        FIXUP_BRANCH(5b)
 "      .previous\n"
-"      .section __ex_table,\"aw\"\n"
-#ifdef __LP64__
-"      .dword  1b,6b\n"
-"      .dword  2b,6b\n"
-"      .dword  3b,6b\n"
-"      .dword  4b,6b\n"
-#else
-"      .word   1b,6b\n"
-"      .word   2b,6b\n"
-"      .word   3b,6b\n"
-"      .word   4b,6b\n"
-#endif
-"      .previous\n"
+       ASM_EXCEPTIONTABLE_ENTRY(1b,6b)
+       ASM_EXCEPTIONTABLE_ENTRY(2b,6b)
+       ASM_EXCEPTIONTABLE_ENTRY(3b,6b)
+       ASM_EXCEPTIONTABLE_ENTRY(4b,6b)
        : "=r" (ret)
        : "r" (val), "r" (regs->ior), "r" (regs->isr)
        : "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER );
@@ -479,21 +430,11 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop)
 "7:    ldi     -2, %0\n"
        FIXUP_BRANCH(6b)
 "      .previous\n"
-"      .section __ex_table,\"aw\"\n"
-#ifdef __LP64__
-"      .dword  1b,7b\n"
-"      .dword  2b,7b\n"
-"      .dword  3b,7b\n"
-"      .dword  4b,7b\n"
-"      .dword  5b,7b\n"
-#else
-"      .word   1b,7b\n"
-"      .word   2b,7b\n"
-"      .word   3b,7b\n"
-"      .word   4b,7b\n"
-"      .word   5b,7b\n"
-#endif
-"      .previous\n"
+       ASM_EXCEPTIONTABLE_ENTRY(1b,7b)
+       ASM_EXCEPTIONTABLE_ENTRY(2b,7b)
+       ASM_EXCEPTIONTABLE_ENTRY(3b,7b)
+       ASM_EXCEPTIONTABLE_ENTRY(4b,7b)
+       ASM_EXCEPTIONTABLE_ENTRY(5b,7b)
        : "=r" (ret)
        : "r" (valh), "r" (vall), "r" (regs->ior), "r" (regs->isr)
        : "r19", "r20", "r21", "r1", FIXUP_BRANCH_CLOBBER );
index c10ab47..5f75b3e 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/kallsyms.h>
 
index 3b78c27..2a82533 100644 (file)
@@ -68,6 +68,8 @@ SECTIONS
 
   RODATA
 
+  BUG_TABLE
+
   /* writeable */
   . = ALIGN(ASM_PAGE_SIZE);    /* Make sure this is page aligned so
                                   that we can properly leave these
index f352666..e3eb739 100644 (file)
@@ -17,7 +17,7 @@ raw_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned = {
 };
 #endif
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 unsigned long __xchg64(unsigned long x, unsigned long *ptr)
 {
        unsigned long temp, flags;
@@ -56,7 +56,7 @@ unsigned long __xchg8(char x, char *ptr)
 }
 
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 unsigned long __cmpxchg_u64(volatile unsigned long *ptr, unsigned long old, unsigned long new)
 {
        unsigned long flags;
index ecce3d3..d172d42 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/assembly.h>
 #include <asm/errno.h>
+#include <linux/linkage.h>
 
 #ifdef CONFIG_SMP
        .macro  get_fault_ip t1 t2
@@ -30,7 +31,7 @@
        /* t2 = smp_processor_id() */
        mfctl 30,\t2
        ldw TI_CPU(\t2),\t2
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        extrd,u \t2,63,32,\t2
 #endif
        /* t2 = &__per_cpu_offset[smp_processor_id()]; */
        .section .fixup, "ax"
 
        /* get_user() fixups, store -EFAULT in r8, and 0 in r9 */
-       .export fixup_get_user_skip_1
-fixup_get_user_skip_1:
+ENTRY(fixup_get_user_skip_1)
        get_fault_ip %r1,%r8
        ldo 4(%r1), %r1
        ldi -EFAULT, %r8
        bv %r0(%r1)
        copy %r0, %r9
+ENDPROC(fixup_get_user_skip_1)
 
-       .export fixup_get_user_skip_2
-fixup_get_user_skip_2:
+ENTRY(fixup_get_user_skip_2)
        get_fault_ip %r1,%r8
        ldo 8(%r1), %r1
        ldi -EFAULT, %r8
        bv %r0(%r1)
        copy %r0, %r9
+ENDPROC(fixup_get_user_skip_2)
 
        /* put_user() fixups, store -EFAULT in r8 */
-       .export fixup_put_user_skip_1
-fixup_put_user_skip_1:
+ENTRY(fixup_put_user_skip_1)
        get_fault_ip %r1,%r8
        ldo 4(%r1), %r1
        bv %r0(%r1)
        ldi -EFAULT, %r8
+ENDPROC(fixup_put_user_skip_1)
 
-       .export fixup_put_user_skip_2
-fixup_put_user_skip_2:
+ENTRY(fixup_put_user_skip_2)
        get_fault_ip %r1,%r8
        ldo 8(%r1), %r1
        bv %r0(%r1)
        ldi -EFAULT, %r8
+ENDPROC(fixup_put_user_skip_2)
+
index a050985..1bd23cc 100644 (file)
@@ -37,6 +37,7 @@
        
 #include <asm/assembly.h>
 #include <asm/errno.h>
+#include <linux/linkage.h>
 
        /*
         * get_sr gets the appropriate space value into
@@ -67,8 +68,7 @@
         *         otherwise strlen (i.e. excludes zero byte)
         */
 
-       .export lstrncpy_from_user,code
-lstrncpy_from_user:
+ENTRY(lstrncpy_from_user)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -87,6 +87,7 @@ $lsfu_exit:
        bv          %r0(%r2)
        nop
        .exit
+ENDPROC(lstrncpy_from_user)
 
        .section .fixup,"ax"
 3:      fixup_branch $lsfu_exit
@@ -94,13 +95,8 @@ $lsfu_exit:
        .previous
 
        .section __ex_table,"aw"
-#ifdef __LP64__
-       .dword      1b,3b
-       .dword      2b,3b
-#else
-       .word       1b,3b
-       .word       2b,3b
-#endif
+       ASM_ULONG_INSN 1b,3b
+       ASM_ULONG_INSN 2b,3b
        .previous
 
        .procend
@@ -112,8 +108,7 @@ $lsfu_exit:
         * otherwise, returns number of bytes not transferred.
         */
 
-       .export lclear_user,code
-lclear_user:
+ENTRY(lclear_user)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -127,6 +122,7 @@ $lclu_done:
        bv          %r0(%r2)
        copy        %r25,%r28
        .exit
+ENDPROC(lclear_user)
 
        .section .fixup,"ax"
 2:      fixup_branch $lclu_done
@@ -134,11 +130,7 @@ $lclu_done:
        .previous
 
        .section __ex_table,"aw"
-#ifdef __LP64__
-       .dword      1b,2b
-#else
-       .word       1b,2b
-#endif
+       ASM_ULONG_INSN 1b,2b
        .previous
 
        .procend
@@ -151,8 +143,7 @@ $lclu_done:
         *         else strlen + 1 (i.e. includes zero byte).
         */
 
-       .export lstrnlen_user,code
-lstrnlen_user:
+ENTRY(lstrnlen_user)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -172,6 +163,7 @@ $lslen_done:
 $lslen_nzero:
        b           $lslen_done
        ldo         1(%r26),%r26 /* special case for N == 0 */
+ENDPROC(lstrnlen_user)
 
        .section .fixup,"ax"
 3:      fixup_branch $lslen_done
@@ -179,13 +171,8 @@ $lslen_nzero:
        .previous
 
        .section __ex_table,"aw"
-#ifdef __LP64__
-       .dword      1b,3b
-       .dword      2b,3b
-#else
-       .word       1b,3b
-       .word       2b,3b
-#endif
+       ASM_ULONG_INSN 1b,3b
+       ASM_ULONG_INSN 2b,3b
        .previous
 
        .procend
index 5575e41..2c43ebe 100644 (file)
@@ -96,30 +96,18 @@ DECLARE_PER_CPU(struct exception_data, exception_data);
 #define DPRINTF(fmt, args...)
 #endif
 
-#ifndef __LP64__
-#define EXC_WORD ".word"
-#else
-#define EXC_WORD ".dword"
-#endif
-
 #define def_load_ai_insn(_insn,_sz,_tt,_s,_a,_t,_e)    \
        __asm__ __volatile__ (                          \
-       "1:\t" #_insn ",ma " #_sz "(" _s ",%1), %0\n"   \
-       "\t.section __ex_table,\"aw\"\n"                \
-       "\t" EXC_WORD "\t1b\n"                          \
-       "\t" EXC_WORD "\t" #_e "\n"                     \
-       "\t.previous\n"                                 \
+       "1:\t" #_insn ",ma " #_sz "(" _s ",%1), %0\n\t" \
+       ASM_EXCEPTIONTABLE_ENTRY(1b,_e)                 \
        : _tt(_t), "+r"(_a)                             \
        :                                               \
        : "r8")
 
 #define def_store_ai_insn(_insn,_sz,_tt,_s,_a,_t,_e)   \
        __asm__ __volatile__ (                          \
-       "1:\t" #_insn ",ma %1, " #_sz "(" _s ",%0)\n"   \
-       "\t.section __ex_table,\"aw\"\n"                \
-       "\t" EXC_WORD "\t1b\n"                          \
-       "\t" EXC_WORD "\t" #_e "\n"                     \
-       "\t.previous\n"                                 \
+       "1:\t" #_insn ",ma %1, " #_sz "(" _s ",%0)\n\t" \
+       ASM_EXCEPTIONTABLE_ENTRY(1b,_e)                 \
        : "+r"(_a)                                      \
        : _tt(_t)                                       \
        : "r8")
@@ -133,22 +121,16 @@ DECLARE_PER_CPU(struct exception_data, exception_data);
 
 #define def_load_insn(_insn,_tt,_s,_o,_a,_t,_e)        \
        __asm__ __volatile__ (                          \
-       "1:\t" #_insn " " #_o "(" _s ",%1), %0\n"       \
-       "\t.section __ex_table,\"aw\"\n"                \
-       "\t" EXC_WORD "\t1b\n"                          \
-       "\t" EXC_WORD "\t" #_e "\n"                     \
-       "\t.previous\n"                                 \
+       "1:\t" #_insn " " #_o "(" _s ",%1), %0\n\t"     \
+       ASM_EXCEPTIONTABLE_ENTRY(1b,_e)                 \
        : _tt(_t)                                       \
        : "r"(_a)                                       \
        : "r8")
 
 #define def_store_insn(_insn,_tt,_s,_t,_o,_a,_e)       \
        __asm__ __volatile__ (                          \
-       "1:\t" #_insn " %0, " #_o "(" _s ",%1)\n"       \
-       "\t.section __ex_table,\"aw\"\n"                \
-       "\t" EXC_WORD "\t1b\n"                          \
-       "\t" EXC_WORD "\t" #_e "\n"                     \
-       "\t.previous\n"                                 \
+       "1:\t" #_insn " %0, " #_o "(" _s ",%1)\n\t"     \
+       ASM_EXCEPTIONTABLE_ENTRY(1b,_e)                 \
        :                                               \
        : _tt(_t), "r"(_a)                              \
        : "r8")
@@ -167,8 +149,8 @@ extern inline void prefetch_dst(const void *addr)
        __asm__("ldd 0(" d_space ",%0), %%r0" : : "r" (addr));
 }
 #else
-#define prefetch_src(addr)
-#define prefetch_dst(addr)
+#define prefetch_src(addr) do { } while(0)
+#define prefetch_dst(addr) do { } while(0)
 #endif
 
 /* Copy from a not-aligned src to an aligned dst, using shifts. Handles 4 words
index 641f9c9..f6f6755 100644 (file)
                         /*  dumped to the console via printk)          */
 
 
-/* Defines for parisc_acctyp() */
-#define READ           0
-#define WRITE          1
-
 /* Various important other fields */
 #define bit22set(x)            (x & 0x00000200)
 #define bits23_25set(x)                (x & 0x000001c0)
index 12117db..75ea9f2 100644 (file)
@@ -6,7 +6,7 @@
  *    changed by Philipp Rumpf
  *  Copyright 1999 Philipp Rumpf (prumpf@tux.org)
  *  Copyright 2004 Randolph Chung (tausq@debian.org)
- *  Copyright 2006 Helge Deller (deller@gmx.de)
+ *  Copyright 2006-2007 Helge Deller (deller@gmx.de)
  *
  */
 
@@ -24,6 +24,7 @@
 #include <linux/pagemap.h>     /* for release_pages and page_cache_release */
 
 #include <asm/pgalloc.h>
+#include <asm/pgtable.h>
 #include <asm/tlb.h>
 #include <asm/pdc_chassis.h>
 #include <asm/mmzone.h>
@@ -65,11 +66,11 @@ static struct resource sysram_resources[MAX_PHYSMEM_RANGES] __read_mostly;
 physmem_range_t pmem_ranges[MAX_PHYSMEM_RANGES] __read_mostly;
 int npmem_ranges __read_mostly;
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 #define MAX_MEM         (~0UL)
-#else /* !__LP64__ */
+#else /* !CONFIG_64BIT */
 #define MAX_MEM         (3584U*1024U*1024U)
-#endif /* !__LP64__ */
+#endif /* !CONFIG_64BIT */
 
 static unsigned long mem_limit __read_mostly = MAX_MEM;
 
@@ -452,6 +453,8 @@ unsigned long pcxl_dma_start __read_mostly;
 
 void __init mem_init(void)
 {
+       int codesize, reservedpages, datasize, initsize;
+
        high_memory = __va((max_pfn << PAGE_SHIFT));
 
 #ifndef CONFIG_DISCONTIGMEM
@@ -466,7 +469,32 @@ void __init mem_init(void)
        }
 #endif
 
-       printk(KERN_INFO "Memory: %luk available\n", num_physpages << (PAGE_SHIFT-10));
+       codesize = (unsigned long)_etext - (unsigned long)_text;
+       datasize = (unsigned long)_edata - (unsigned long)_etext;
+       initsize = (unsigned long)__init_end - (unsigned long)__init_begin;
+
+       reservedpages = 0;
+{
+       unsigned long pfn;
+#ifdef CONFIG_DISCONTIGMEM
+       int i;
+
+       for (i = 0; i < npmem_ranges; i++) {
+               for (pfn = node_start_pfn(i); pfn < node_end_pfn(i); pfn++) {
+                       if (PageReserved(pfn_to_page(pfn)))
+                               reservedpages++;
+               }
+       }
+#else /* !CONFIG_DISCONTIGMEM */
+       for (pfn = 0; pfn < max_pfn; pfn++) {
+               /*
+                * Only count reserved RAM pages
+                */
+               if (PageReserved(pfn_to_page(pfn)))
+                       reservedpages++;
+       }
+#endif
+}
 
 #ifdef CONFIG_PA11
        if (hppa_dma_ops == &pcxl_dma_ops) {
@@ -480,6 +508,38 @@ void __init mem_init(void)
        vmalloc_start = SET_MAP_OFFSET(MAP_START);
 #endif
 
+       printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n",
+               (unsigned long)nr_free_pages() << (PAGE_SHIFT-10),
+               num_physpages << (PAGE_SHIFT-10),
+               codesize >> 10,
+               reservedpages << (PAGE_SHIFT-10),
+               datasize >> 10,
+               initsize >> 10
+       );
+
+#ifdef CONFIG_DEBUG_KERNEL /* double-sanity-check paranoia */
+       printk("virtual kernel memory layout:\n"
+              "    vmalloc : 0x%p - 0x%p   (%4ld MB)\n"
+              "    memory  : 0x%p - 0x%p   (%4ld MB)\n"
+              "      .init : 0x%p - 0x%p   (%4ld kB)\n"
+              "      .data : 0x%p - 0x%p   (%4ld kB)\n"
+              "      .text : 0x%p - 0x%p   (%4ld kB)\n",
+
+              (void*)VMALLOC_START, (void*)VMALLOC_END,
+              (VMALLOC_END - VMALLOC_START) >> 20,
+
+              __va(0), high_memory,
+              ((unsigned long)high_memory - (unsigned long)__va(0)) >> 20,
+
+              __init_begin, __init_end,
+              ((unsigned long)__init_end - (unsigned long)__init_begin) >> 10,
+
+              _etext, _edata,
+              ((unsigned long)_edata - (unsigned long)_etext) >> 10,
+
+              _text, _etext,
+              ((unsigned long)_etext - (unsigned long)_text) >> 10);
+#endif
 }
 
 unsigned long *empty_zero_page __read_mostly;
@@ -547,7 +607,7 @@ void show_mem(void)
 
                                printk("Zone list for zone %d on node %d: ", j, i);
                                for (k = 0; zl->zones[k] != NULL; k++) 
-                                       printk("[%d/%s] ", zone_to_nid(zl->zones[k]), zl->zones[k]->name);
+                                       printk("[%ld/%s] ", zone_to_nid(zl->zones[k]), zl->zones[k]->name);
                                printk("\n");
                        }
                }
index 44b42c7..92d496a 100644 (file)
@@ -26,7 +26,7 @@
  */
 void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
 {
-       void *addr;
+       void __iomem *addr;
        struct vm_struct *area;
        unsigned long offset, last_addr;
        pgprot_t pgprot;
@@ -80,14 +80,14 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l
        if (!area)
                return NULL;
 
-       addr = area->addr;
+       addr = (void __iomem *) area->addr;
        if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
                               phys_addr, pgprot)) {
                vfree(addr);
                return NULL;
        }
 
-       return (void __iomem *) (offset + (char *)addr);
+       return (void __iomem *) (offset + (char __iomem *)addr);
 }
 EXPORT_SYMBOL(__ioremap);
 
diff --git a/arch/parisc/mm/kmap.c b/arch/parisc/mm/kmap.c
deleted file mode 100644 (file)
index 1b1acd5..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/* 
- *    kmap/page table map and unmap support routines
- *
- *    Copyright 1999,2000 Hewlett-Packard Company
- *    Copyright 2000 John Marvin <jsm at hp.com>
- *    Copyright 2000 Grant Grundler <grundler at parisc-linux.org>
- *    Copyright 2000 Philipp Rumpf <prumpf@tux.org>
- *
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-/*
-** Stolen mostly from arch/parisc/kernel/pci-dma.c
-*/
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
-
-#include <asm/io.h>
-#include <asm/page.h>          /* get_order */
-
-#undef flush_cache_all
-#define flush_cache_all flush_all_caches
-
-typedef void (*pte_iterator_t) (pte_t * pte, unsigned long arg);
-
-#if 0
-/* XXX This routine could be used with iterate_page() to replace
- * unmap_uncached_page() and save a little code space but I didn't
- * do that since I'm not certain whether this is the right path. -PB
- */
-static void unmap_cached_pte(pte_t * pte, unsigned long addr, unsigned long arg)
-{
-       pte_t page = *pte;
-       pte_clear(&init_mm, addr, pte);
-       if (!pte_none(page)) {
-               if (pte_present(page)) {
-                       unsigned long map_nr = pte_pagenr(page);
-                       if (map_nr < max_mapnr)
-                               __free_page(mem_map + map_nr);
-               } else {
-                       printk(KERN_CRIT
-                              "Whee.. Swapped out page in kernel page table\n");
-               }
-       }
-}
-#endif
-
-/* These two routines should probably check a few things... */
-static void set_uncached(pte_t * pte, unsigned long arg)
-{
-       pte_val(*pte) |= _PAGE_NO_CACHE;
-}
-
-static void set_cached(pte_t * pte, unsigned long arg)
-{
-       pte_val(*pte) &= ~_PAGE_NO_CACHE;
-}
-
-static inline void iterate_pte(pmd_t * pmd, unsigned long address,
-                              unsigned long size, pte_iterator_t op,
-                              unsigned long arg)
-{
-       pte_t *pte;
-       unsigned long end;
-
-       if (pmd_none(*pmd))
-               return;
-       if (pmd_bad(*pmd)) {
-               pmd_ERROR(*pmd);
-               pmd_clear(pmd);
-               return;
-       }
-       pte = pte_offset(pmd, address);
-       address &= ~PMD_MASK;
-       end = address + size;
-       if (end > PMD_SIZE)
-               end = PMD_SIZE;
-       do {
-               op(pte, arg);
-               address += PAGE_SIZE;
-               pte++;
-       } while (address < end);
-}
-
-static inline void iterate_pmd(pgd_t * dir, unsigned long address,
-                              unsigned long size, pte_iterator_t op,
-                              unsigned long arg)
-{
-       pmd_t *pmd;
-       unsigned long end;
-
-       if (pgd_none(*dir))
-               return;
-       if (pgd_bad(*dir)) {
-               pgd_ERROR(*dir);
-               pgd_clear(dir);
-               return;
-       }
-       pmd = pmd_offset(dir, address);
-       address &= ~PGDIR_MASK;
-       end = address + size;
-       if (end > PGDIR_SIZE)
-               end = PGDIR_SIZE;
-       do {
-               iterate_pte(pmd, address, end - address, op, arg);
-               address = (address + PMD_SIZE) & PMD_MASK;
-               pmd++;
-       } while (address < end);
-}
-
-static void iterate_pages(unsigned long address, unsigned long size,
-                         pte_iterator_t op, unsigned long arg)
-{
-       pgd_t *dir;
-       unsigned long end = address + size;
-
-       dir = pgd_offset_k(address);
-       flush_cache_all();
-       do {
-               iterate_pmd(dir, address, end - address, op, arg);
-               address = (address + PGDIR_SIZE) & PGDIR_MASK;
-               dir++;
-       } while (address && (address < end));
-       flush_tlb_all();
-}
-
-void
-kernel_set_cachemode(unsigned long vaddr, unsigned long size, int what)
-{
-       switch (what) {
-       case IOMAP_FULL_CACHING:
-               iterate_pages(vaddr, size, set_cached, 0);
-               flush_tlb_range(NULL, vaddr, size);
-               break;
-       case IOMAP_NOCACHE_SER:
-               iterate_pages(vaddr, size, set_uncached, 0);
-               flush_tlb_range(NULL, vaddr, size);
-               break;
-       default:
-               printk(KERN_CRIT
-                      "kernel_set_cachemode mode %d not understood\n",
-                      what);
-               break;
-       }
-}
index a5b898c..113f513 100644 (file)
@@ -18,6 +18,6 @@ int __init oprofile_arch_init(struct oprofile_operations * ops)
 }
 
 
-void oprofile_arch_exit()
+void oprofile_arch_exit(void)
 {
 }
index eaaac37..d9425f5 100644 (file)
@@ -8,8 +8,8 @@ config MMU
        default y
 
 config ZONE_DMA
-       bool
-       default y
+       def_bool y
+       depends on 64BIT
 
 config LOCKDEP_SUPPORT
        bool
index 6598e52..b1e5584 100644 (file)
@@ -82,18 +82,18 @@ AFLAGS              += $(aflags-y)
 OBJCOPYFLAGS   := -O binary
 LDFLAGS_vmlinux := -e start
 
-head-y         := arch/$(ARCH)/kernel/head.o arch/$(ARCH)/kernel/init_task.o
+head-y         := arch/s390/kernel/head.o arch/s390/kernel/init_task.o
 
-core-y         += arch/$(ARCH)/mm/ arch/$(ARCH)/kernel/ arch/$(ARCH)/crypto/ \
-                  arch/$(ARCH)/appldata/ arch/$(ARCH)/hypfs/
-libs-y         += arch/$(ARCH)/lib/
+core-y         += arch/s390/mm/ arch/s390/kernel/ arch/s390/crypto/ \
+                  arch/s390/appldata/ arch/s390/hypfs/
+libs-y         += arch/s390/lib/
 drivers-y      += drivers/s390/
-drivers-$(CONFIG_MATHEMU) += arch/$(ARCH)/math-emu/
+drivers-$(CONFIG_MATHEMU) += arch/s390/math-emu/
 
 # must be linked after kernel
 drivers-$(CONFIG_OPROFILE)     += arch/s390/oprofile/
 
-boot           := arch/$(ARCH)/boot
+boot           := arch/s390/boot
 
 all: image
 
index 1406400..741d2bb 100644 (file)
@@ -1,9 +1,10 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20-rc1
-# Fri Dec 15 16:52:28 2006
+# Linux kernel version: 2.6.21-rc1
+# Wed Feb 21 10:44:30 2007
 #
 CONFIG_MMU=y
+CONFIG_ZONE_DMA=y
 CONFIG_LOCKDEP_SUPPORT=y
 CONFIG_STACKTRACE_SUPPORT=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
@@ -11,6 +12,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_TIME=y
+CONFIG_NO_IOMEM=y
 CONFIG_S390=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
@@ -29,6 +31,7 @@ CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
@@ -133,6 +136,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_RESOURCES_64BIT=y
+CONFIG_ZONE_DMA_FLAG=1
 CONFIG_HOLES_IN_ZONE=y
 
 #
@@ -178,7 +182,9 @@ CONFIG_UNIX=y
 CONFIG_XFRM=y
 # CONFIG_XFRM_USER is not set
 # CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
 CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
 CONFIG_IUCV=m
 CONFIG_AFIUCV=m
 CONFIG_INET=y
@@ -195,7 +201,7 @@ CONFIG_IP_FIB_HASH=y
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
 # CONFIG_INET_XFRM_TUNNEL is not set
-# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
 CONFIG_INET_XFRM_MODE_TRANSPORT=y
 CONFIG_INET_XFRM_MODE_TUNNEL=y
 CONFIG_INET_XFRM_MODE_BEET=y
@@ -313,6 +319,7 @@ CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_FW_LOADER is not set
 # CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
 CONFIG_SYS_HYPERVISOR=y
 
 #
@@ -686,13 +693,13 @@ CONFIG_HEADERS_CHECK=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=17
 # CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_SLAB is not set
 CONFIG_DEBUG_PREEMPT=y
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
 CONFIG_DEBUG_SPINLOCK=y
 CONFIG_DEBUG_MUTEXES=y
-# CONFIG_DEBUG_RWSEMS is not set
 # CONFIG_DEBUG_LOCK_ALLOC is not set
 # CONFIG_PROVE_LOCKING is not set
 CONFIG_DEBUG_SPINLOCK_SLEEP=y
@@ -702,10 +709,10 @@ CONFIG_DEBUG_SPINLOCK_SLEEP=y
 # CONFIG_DEBUG_VM is not set
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_FRAME_POINTER is not set
-# CONFIG_UNWIND_INFO is not set
 CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
 
 #
 # Security options
@@ -733,8 +740,10 @@ CONFIG_CRYPTO_MANAGER=y
 # CONFIG_CRYPTO_GF128MUL is not set
 CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
 # CONFIG_CRYPTO_LRW is not set
 # CONFIG_CRYPTO_DES is not set
+CONFIG_CRYPTO_FCRYPT=m
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_TWOFISH is not set
 # CONFIG_CRYPTO_SERPENT is not set
@@ -748,6 +757,7 @@ CONFIG_CRYPTO_CBC=y
 # CONFIG_CRYPTO_DEFLATE is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
 # CONFIG_CRYPTO_CRC32C is not set
+CONFIG_CRYPTO_CAMELLIA=m
 # CONFIG_CRYPTO_TEST is not set
 
 #
@@ -768,4 +778,3 @@ CONFIG_BITREVERSE=m
 CONFIG_CRC32=m
 # CONFIG_LIBCRC32C is not set
 CONFIG_PLIST=y
-CONFIG_IOMAP_COPY=y
index e518dd5..afca1c6 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/pfn.h>
 #include <linux/uaccess.h>
+#include <asm/ipl.h>
 #include <asm/lowcore.h>
 #include <asm/processor.h>
 #include <asm/sections.h>
@@ -109,7 +110,7 @@ static inline void create_kernel_nss(void) { }
  */
 static noinline __init void clear_bss_section(void)
 {
-       memset(__bss_start, 0, _end - __bss_start);
+       memset(__bss_start, 0, __bss_stop - __bss_start);
 }
 
 /*
@@ -129,7 +130,7 @@ static noinline __init void detect_machine_type(void)
 {
        struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data;
 
-       asm volatile("stidp %0" : "=m" (S390_lowcore.cpu_data.cpu_id));
+       get_cpu_id(&S390_lowcore.cpu_data.cpu_id);
 
        /* Running under z/VM ? */
        if (cpuinfo->cpu_id.version == 0xff)
index 453fd3b..da7c8bb 100644 (file)
@@ -148,20 +148,9 @@ startup_continue:
 .Lstartup_init:
            .long startup_init
 
-       .globl ipl_schib
-ipl_schib:
-       .rept 13
-       .long 0
-       .endr
-
-       .globl ipl_flags
-ipl_flags:
-       .long 0
-       .globl ipl_devno
-ipl_devno:
-       .word 0
-
        .org    0x12000
+       .globl  _ehead
+_ehead:
 #ifdef CONFIG_SHARED_KERNEL
        .org    0x100000
 #endif
index b8fec4e..af09e18 100644 (file)
@@ -154,21 +154,9 @@ startup_continue:
 .Lparmaddr:
        .quad   PARMAREA
 
-       .globl  ipl_schib
-ipl_schib:
-       .rept 13
-       .long 0
-       .endr
-
-       .globl  ipl_flags
-ipl_flags:
-       .long   0
-       .globl  ipl_devno
-ipl_devno:
-       .word 0
-
        .org    0x12000
-
+       .globl  _ehead
+_ehead:
 #ifdef CONFIG_SHARED_KERNEL
        .org    0x100000
 #endif
index 0522595..5a863a3 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/delay.h>
 #include <linux/reboot.h>
 #include <linux/ctype.h>
+#include <asm/ipl.h>
 #include <asm/smp.h>
 #include <asm/setup.h>
 #include <asm/cpcmd.h>
@@ -42,6 +43,13 @@ enum ipl_type {
 #define IPL_FCP_STR     "fcp"
 #define IPL_NSS_STR     "nss"
 
+/*
+ * Must be in data section since the bss section
+ * is not cleared when these are accessed.
+ */
+u16 ipl_devno __attribute__((__section__(".data"))) = 0;
+u32 ipl_flags __attribute__((__section__(".data"))) = 0;
+
 static char *ipl_type_str(enum ipl_type type)
 {
        switch (type) {
@@ -90,31 +98,10 @@ static char *shutdown_action_str(enum shutdown_action action)
        case SHUTDOWN_STOP:
                return SHUTDOWN_STOP_STR;
        default:
-               BUG();
+               return NULL;
        }
 }
 
-enum diag308_subcode  {
-       DIAG308_IPL   = 3,
-       DIAG308_DUMP  = 4,
-       DIAG308_SET   = 5,
-       DIAG308_STORE = 6,
-};
-
-enum diag308_ipl_type {
-       DIAG308_IPL_TYPE_FCP = 0,
-       DIAG308_IPL_TYPE_CCW = 2,
-};
-
-enum diag308_opt {
-       DIAG308_IPL_OPT_IPL  = 0x10,
-       DIAG308_IPL_OPT_DUMP = 0x20,
-};
-
-enum diag308_rc {
-       DIAG308_RC_OK = 1,
-};
-
 static int diag308_set_works = 0;
 
 static int reipl_capabilities = IPL_TYPE_UNKNOWN;
@@ -134,7 +121,7 @@ static struct ipl_parameter_block *dump_block_ccw;
 
 static enum shutdown_action on_panic_action = SHUTDOWN_STOP;
 
-static int diag308(unsigned long subcode, void *addr)
+int diag308(unsigned long subcode, void *addr)
 {
        register unsigned long _addr asm("0") = (unsigned long) addr;
        register unsigned long _rc asm("1") = 0;
index 50c5210..863c8d0 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/ctype.h>
 #include <linux/reboot.h>
 
+#include <asm/ipl.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/smp.h>
@@ -106,7 +107,7 @@ void __devinit cpu_init (void)
         /*
          * Store processor id in lowcore (used e.g. in timer_interrupt)
          */
-       asm volatile("stidp %0": "=m" (S390_lowcore.cpu_data.cpu_id));
+       get_cpu_id(&S390_lowcore.cpu_data.cpu_id);
         S390_lowcore.cpu_data.cpu_addr = addr;
 
         /*
@@ -689,9 +690,14 @@ setup_memory(void)
        psw_set_key(PAGE_DEFAULT_KEY);
 
        free_bootmem_with_active_regions(0, max_pfn);
-       reserve_bootmem(0, PFN_PHYS(start_pfn));
 
        /*
+        * Reserve memory used for lowcore/command line/kernel image.
+        */
+       reserve_bootmem(0, (unsigned long)_ehead);
+       reserve_bootmem((unsigned long)_stext,
+                       PFN_PHYS(start_pfn) - (unsigned long)_stext);
+       /*
         * Reserve the bootmem bitmap itself as well. We do this in two
         * steps (first step was init_bootmem()) because this catches
         * the (very unlikely) case of us accidentally initializing the
index 83a4ea6..ecaa432 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/interrupt.h>
 #include <linux/cpu.h>
 #include <linux/timex.h>
+#include <asm/ipl.h>
 #include <asm/setup.h>
 #include <asm/sigp.h>
 #include <asm/pgalloc.h>
@@ -54,19 +55,18 @@ cpumask_t cpu_possible_map = CPU_MASK_NONE;
 static struct task_struct *current_set[NR_CPUS];
 
 static void smp_ext_bitcall(int, ec_bit_sig);
-static void smp_ext_bitcall_others(ec_bit_sig);
 
 /*
- * Structure and data for smp_call_function(). This is designed to minimise
- * static memory requirements. It also looks cleaner.
+ * Structure and data for __smp_call_function_map(). This is designed to
+ * minimise static memory requirements. It also looks cleaner.
  */
 static DEFINE_SPINLOCK(call_lock);
 
 struct call_data_struct {
        void (*func) (void *info);
        void *info;
-       atomic_t started;
-       atomic_t finished;
+       cpumask_t started;
+       cpumask_t finished;
        int wait;
 };
 
@@ -81,118 +81,113 @@ static void do_call_function(void)
        void *info = call_data->info;
        int wait = call_data->wait;
 
-       atomic_inc(&call_data->started);
+       cpu_set(smp_processor_id(), call_data->started);
        (*func)(info);
        if (wait)
-               atomic_inc(&call_data->finished);
+               cpu_set(smp_processor_id(), call_data->finished);;
 }
 
-/*
- * this function sends a 'generic call function' IPI to all other CPUs
- * in the system.
- */
-
-int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
-                       int wait)
-/*
- * [SUMMARY] Run a function on all other CPUs.
- * <func> The function to run. This must be fast and non-blocking.
- * <info> An arbitrary pointer to pass to the function.
- * <nonatomic> currently unused.
- * <wait> If true, wait (atomically) until function has completed on other CPUs.
- * [RETURNS] 0 on success, else a negative status code. Does not return until
- * remote CPUs are nearly ready to execute <<func>> or are or have executed.
- *
- * You must not call this function with disabled interrupts or from a
- * hardware interrupt handler.
- */
+static void __smp_call_function_map(void (*func) (void *info), void *info,
+                                   int nonatomic, int wait, cpumask_t map)
 {
        struct call_data_struct data;
-       int cpus = num_online_cpus()-1;
+       int cpu, local = 0;
 
-       if (cpus <= 0)
-               return 0;
+       /*
+        * Can deadlock when interrupts are disabled or if in wrong context,
+        * caller must disable preemption
+        */
+       WARN_ON(irqs_disabled() || in_irq() || preemptible());
 
-       /* Can deadlock when interrupts are disabled or if in wrong context */
-       WARN_ON(irqs_disabled() || in_irq());
+       /*
+        * Check for local function call. We have to have the same call order
+        * as in on_each_cpu() because of machine_restart_smp().
+        */
+       if (cpu_isset(smp_processor_id(), map)) {
+               local = 1;
+               cpu_clear(smp_processor_id(), map);
+       }
+
+       cpus_and(map, map, cpu_online_map);
+       if (cpus_empty(map))
+               goto out;
 
        data.func = func;
        data.info = info;
-       atomic_set(&data.started, 0);
+       data.started = CPU_MASK_NONE;
        data.wait = wait;
        if (wait)
-               atomic_set(&data.finished, 0);
+               data.finished = CPU_MASK_NONE;
 
        spin_lock_bh(&call_lock);
        call_data = &data;
-       /* Send a message to all other CPUs and wait for them to respond */
-        smp_ext_bitcall_others(ec_call_function);
+
+       for_each_cpu_mask(cpu, map)
+               smp_ext_bitcall(cpu, ec_call_function);
 
        /* Wait for response */
-       while (atomic_read(&data.started) != cpus)
+       while (!cpus_equal(map, data.started))
                cpu_relax();
 
        if (wait)
-               while (atomic_read(&data.finished) != cpus)
+               while (!cpus_equal(map, data.finished))
                        cpu_relax();
+
        spin_unlock_bh(&call_lock);
 
-       return 0;
+out:
+       local_irq_disable();
+       if (local)
+               func(info);
+       local_irq_enable();
 }
 
 /*
- * Call a function on one CPU
- * cpu : the CPU the function should be executed on
+ * smp_call_function:
+ * @func: the function to run; this must be fast and non-blocking
+ * @info: an arbitrary pointer to pass to the function
+ * @nonatomic: unused
+ * @wait: if true, wait (atomically) until function has completed on other CPUs
  *
- * You must not call this function with disabled interrupts or from a
- * hardware interrupt handler. You may call it from a bottom half.
+ * Run a function on all other CPUs.
  *
- * It is guaranteed that the called function runs on the specified CPU,
- * preemption is disabled.
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler. Must be called with preemption disabled.
+ * You may call it from a bottom half.
  */
-int smp_call_function_on(void (*func) (void *info), void *info,
-                        int nonatomic, int wait, int cpu)
+int smp_call_function(void (*func) (void *info), void *info, int nonatomic,
+                     int wait)
 {
-       struct call_data_struct data;
-       int curr_cpu;
-
-       if (!cpu_online(cpu))
-               return -EINVAL;
-
-       /* Can deadlock when interrupts are disabled or if in wrong context */
-       WARN_ON(irqs_disabled() || in_irq());
-
-       /* disable preemption for local function call */
-       curr_cpu = get_cpu();
-
-       if (curr_cpu == cpu) {
-               /* direct call to function */
-               func(info);
-               put_cpu();
-               return 0;
-       }
-
-       data.func = func;
-       data.info = info;
-       atomic_set(&data.started, 0);
-       data.wait = wait;
-       if (wait)
-               atomic_set(&data.finished, 0);
-
-       spin_lock_bh(&call_lock);
-       call_data = &data;
-       smp_ext_bitcall(cpu, ec_call_function);
+       cpumask_t map;
 
-       /* Wait for response */
-       while (atomic_read(&data.started) != 1)
-               cpu_relax();
+       map = cpu_online_map;
+       cpu_clear(smp_processor_id(), map);
+       __smp_call_function_map(func, info, nonatomic, wait, map);
+       return 0;
+}
+EXPORT_SYMBOL(smp_call_function);
 
-       if (wait)
-               while (atomic_read(&data.finished) != 1)
-                       cpu_relax();
+/*
+ * smp_call_function_on:
+ * @func: the function to run; this must be fast and non-blocking
+ * @info: an arbitrary pointer to pass to the function
+ * @nonatomic: unused
+ * @wait: if true, wait (atomically) until function has completed on other CPUs
+ * @cpu: the CPU where func should run
+ *
+ * Run a function on one processor.
+ *
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler. Must be called with preemption disabled.
+ * You may call it from a bottom half.
+ */
+int smp_call_function_on(void (*func) (void *info), void *info, int nonatomic,
+                         int wait, int cpu)
+{
+       cpumask_t map = CPU_MASK_NONE;
 
-       spin_unlock_bh(&call_lock);
-       put_cpu();
+       cpu_set(cpu, map);
+       __smp_call_function_map(func, info, nonatomic, wait, map);
        return 0;
 }
 EXPORT_SYMBOL(smp_call_function_on);
@@ -325,26 +320,6 @@ static void smp_ext_bitcall(int cpu, ec_bit_sig sig)
                udelay(10);
 }
 
-/*
- * Send an external call sigp to every other cpu in the system and
- * return without waiting for its completion.
- */
-static void smp_ext_bitcall_others(ec_bit_sig sig)
-{
-        int cpu;
-
-       for_each_online_cpu(cpu) {
-               if (cpu == smp_processor_id())
-                        continue;
-                /*
-                 * Set signaling bit in lowcore of target cpu and kick it
-                 */
-               set_bit(sig, (unsigned long *) &lowcore_ptr[cpu]->ext_call_fast);
-               while (signal_processor(cpu, sigp_emergency_signal) == sigp_busy)
-                       udelay(10);
-        }
-}
-
 #ifndef CONFIG_64BIT
 /*
  * this function sends a 'purge tlb' signal to another CPU.
@@ -807,6 +782,5 @@ EXPORT_SYMBOL(cpu_possible_map);
 EXPORT_SYMBOL(lowcore_ptr);
 EXPORT_SYMBOL(smp_ctl_set_bit);
 EXPORT_SYMBOL(smp_ctl_clear_bit);
-EXPORT_SYMBOL(smp_call_function);
 EXPORT_SYMBOL(smp_get_cpu);
 EXPORT_SYMBOL(smp_put_cpu);
index ee9fd7b..e1ad464 100644 (file)
@@ -747,6 +747,7 @@ static void etr_adjust_time(unsigned long long clock, unsigned long long delay)
        }
 }
 
+#ifdef CONFIG_SMP
 static void etr_sync_cpu_start(void *dummy)
 {
        int *in_sync = dummy;
@@ -758,8 +759,14 @@ static void etr_sync_cpu_start(void *dummy)
         * __udelay will stop the cpu on an enabled wait psw until the
         * TOD is running again.
         */
-       while (*in_sync == 0)
+       while (*in_sync == 0) {
                __udelay(1);
+               /*
+                * A different cpu changes *in_sync. Therefore use
+                * barrier() to force memory access.
+                */
+               barrier();
+       }
        if (*in_sync != 1)
                /* Didn't work. Clear per-cpu in sync bit again. */
                etr_disable_sync_clock(NULL);
@@ -773,6 +780,7 @@ static void etr_sync_cpu_start(void *dummy)
 static void etr_sync_cpu_end(void *dummy)
 {
 }
+#endif /* CONFIG_SMP */
 
 /*
  * Sync the TOD clock using the port refered to by aibp. This port
index 0285444..70f2a86 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/delay.h>
 #include <linux/timex.h>
 #include <linux/irqflags.h>
+#include <linux/interrupt.h>
 
 void __delay(unsigned long loops)
 {
@@ -35,7 +36,11 @@ void __udelay(unsigned long usecs)
 {
        u64 end, time, jiffy_timer = 0;
        unsigned long flags, cr0, mask, dummy;
+       int irq_context;
 
+       irq_context = in_interrupt();
+       if (!irq_context)
+               local_bh_disable();
        local_irq_save(flags);
        if (raw_irqs_disabled_flags(flags)) {
                jiffy_timer = S390_lowcore.jiffy_timer;
@@ -62,6 +67,8 @@ void __udelay(unsigned long usecs)
                __ctl_load(cr0, 0, 0);
                S390_lowcore.jiffy_timer = jiffy_timer;
        }
+       if (!irq_context)
+               _local_bh_enable();
        set_clock_comparator(S390_lowcore.jiffy_timer);
        local_irq_restore(flags);
 }
index b3e7c45..916b72a 100644 (file)
@@ -141,7 +141,9 @@ void __init paging_init(void)
        __raw_local_irq_ssm(ssm_mask);
 
        memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+#ifdef CONFIG_ZONE_DMA
        max_zone_pfns[ZONE_DMA] = PFN_DOWN(MAX_DMA_ADDRESS);
+#endif
        max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
        free_area_init_nodes(max_zone_pfns);
 }
index 0f44a6a..59eef40 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20
-# Sun Feb 11 23:47:40 2007
+# Linux kernel version: 2.6.21-rc1
+# Mon Feb 26 10:45:21 2007
 #
 CONFIG_SPARC=y
 CONFIG_SPARC64=y
@@ -41,6 +41,7 @@ CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
@@ -322,6 +323,7 @@ CONFIG_CONNECTOR=m
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -787,6 +789,7 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_OCORES is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PASEMI is not set
 # CONFIG_I2C_PROSAVAGE is not set
 # CONFIG_I2C_SAVAGE4 is not set
 # CONFIG_I2C_SIS5595 is not set
@@ -833,6 +836,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
 # CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ADM9240 is not set
 # CONFIG_SENSORS_ASB100 is not set
@@ -874,6 +878,11 @@ CONFIG_HWMON=y
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -887,16 +896,22 @@ CONFIG_HWMON=y
 #
 # Graphics support
 #
-# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
 CONFIG_FB_DDC=y
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_SVGALIB is not set
 # CONFIG_FB_MACMODES is not set
 # CONFIG_FB_BACKLIGHT is not set
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_TILEBLITTING=y
+
+#
+# Frambuffer hardware drivers
+#
 # CONFIG_FB_CIRRUS is not set
 # CONFIG_FB_PM2 is not set
 # CONFIG_FB_ASILIANT is not set
@@ -908,9 +923,11 @@ CONFIG_FB_TILEBLITTING=y
 # CONFIG_FB_MATROX is not set
 CONFIG_FB_RADEON=y
 CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_BACKLIGHT is not set
 # CONFIG_FB_RADEON_DEBUG is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
 # CONFIG_FB_SAVAGE is not set
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_NEOMAGIC is not set
@@ -947,7 +964,6 @@ CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_VGA16 is not set
 # CONFIG_LOGO_LINUX_CLUT224 is not set
 CONFIG_LOGO_SUN_CLUT224=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -1192,6 +1208,7 @@ CONFIG_USB_HIDDEV=y
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
@@ -1445,9 +1462,11 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
 CONFIG_LOG_BUF_SHIFT=18
 CONFIG_DETECT_SOFTLOCKUP=y
 CONFIG_SCHEDSTATS=y
+# CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
@@ -1465,6 +1484,7 @@ CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
 # CONFIG_DEBUG_DCFLUSH is not set
 # CONFIG_STACK_DEBUG is not set
index b5ff3ee..c443db1 100644 (file)
@@ -109,6 +109,7 @@ static unsigned char virt_irq_alloc(unsigned int real_irq)
        return ent;
 }
 
+#ifdef CONFIG_PCI_MSI
 static void virt_irq_free(unsigned int virt_irq)
 {
        unsigned int real_irq;
@@ -121,6 +122,7 @@ static void virt_irq_free(unsigned int virt_irq)
 
        __bucket(real_irq)->virt_irq = 0;
 }
+#endif
 
 static unsigned int virt_to_real_irq(unsigned char virt_irq)
 {
index 6b740eb..6fedfb9 100644 (file)
@@ -668,7 +668,7 @@ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
 
 void arch_teardown_msi_irq(unsigned int virt_irq)
 {
-       struct msi_desc *entry = get_irq_data(virt_irq);
+       struct msi_desc *entry = get_irq_msi(virt_irq);
        struct pci_dev *pdev = entry->dev;
        struct pcidev_cookie *pcp = pdev->sysdata;
        struct pci_pbm_info *pbm = pcp->pbm;
index 9f5dac6..ed4350c 100644 (file)
@@ -675,6 +675,9 @@ END(invalidate_interrupt\num)
 ENTRY(call_function_interrupt)
        apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
 END(call_function_interrupt)
+ENTRY(irq_move_cleanup_interrupt)
+       apicinterrupt IRQ_MOVE_CLEANUP_VECTOR,smp_irq_move_cleanup_interrupt
+END(irq_move_cleanup_interrupt)
 #endif
 
 ENTRY(apic_timer_interrupt)
index 01e2cf0..21d95b7 100644 (file)
@@ -299,7 +299,7 @@ void init_8259A(int auto_eoi)
         * outb_p - this has to work on a wide range of PC hardware.
         */
        outb_p(0x11, 0x20);     /* ICW1: select 8259A-1 init */
-       outb_p(0x20 + 0, 0x21); /* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */
+       outb_p(IRQ0_VECTOR, 0x21);      /* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */
        outb_p(0x04, 0x21);     /* 8259A-1 (the master) has a slave on IR2 */
        if (auto_eoi)
                outb_p(0x03, 0x21);     /* master does Auto EOI */
@@ -307,7 +307,7 @@ void init_8259A(int auto_eoi)
                outb_p(0x01, 0x21);     /* master expects normal EOI */
 
        outb_p(0x11, 0xA0);     /* ICW1: select 8259A-2 init */
-       outb_p(0x20 + 8, 0xA1); /* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */
+       outb_p(IRQ8_VECTOR, 0xA1);      /* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */
        outb_p(0x02, 0xA1);     /* 8259A-2 is a slave on master's IR2 */
        outb_p(0x01, 0xA1);     /* (slave's support for AEOI in flat mode
                                    is to be investigated) */
@@ -398,24 +398,24 @@ device_initcall(i8259A_init_sysfs);
 
 static struct irqaction irq2 = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL};
 DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
-       [0 ... FIRST_EXTERNAL_VECTOR - 1] = -1,
-       [FIRST_EXTERNAL_VECTOR + 0] = 0,
-       [FIRST_EXTERNAL_VECTOR + 1] = 1,
-       [FIRST_EXTERNAL_VECTOR + 2] = 2,
-       [FIRST_EXTERNAL_VECTOR + 3] = 3,
-       [FIRST_EXTERNAL_VECTOR + 4] = 4,
-       [FIRST_EXTERNAL_VECTOR + 5] = 5,
-       [FIRST_EXTERNAL_VECTOR + 6] = 6,
-       [FIRST_EXTERNAL_VECTOR + 7] = 7,
-       [FIRST_EXTERNAL_VECTOR + 8] = 8,
-       [FIRST_EXTERNAL_VECTOR + 9] = 9,
-       [FIRST_EXTERNAL_VECTOR + 10] = 10,
-       [FIRST_EXTERNAL_VECTOR + 11] = 11,
-       [FIRST_EXTERNAL_VECTOR + 12] = 12,
-       [FIRST_EXTERNAL_VECTOR + 13] = 13,
-       [FIRST_EXTERNAL_VECTOR + 14] = 14,
-       [FIRST_EXTERNAL_VECTOR + 15] = 15,
-       [FIRST_EXTERNAL_VECTOR + 16 ... NR_VECTORS - 1] = -1
+       [0 ... IRQ0_VECTOR - 1] = -1,
+       [IRQ0_VECTOR] = 0,
+       [IRQ1_VECTOR] = 1,
+       [IRQ2_VECTOR] = 2,
+       [IRQ3_VECTOR] = 3,
+       [IRQ4_VECTOR] = 4,
+       [IRQ5_VECTOR] = 5,
+       [IRQ6_VECTOR] = 6,
+       [IRQ7_VECTOR] = 7,
+       [IRQ8_VECTOR] = 8,
+       [IRQ9_VECTOR] = 9,
+       [IRQ10_VECTOR] = 10,
+       [IRQ11_VECTOR] = 11,
+       [IRQ12_VECTOR] = 12,
+       [IRQ13_VECTOR] = 13,
+       [IRQ14_VECTOR] = 14,
+       [IRQ15_VECTOR] = 15,
+       [IRQ15_VECTOR + 1 ... NR_VECTORS - 1] = -1
 };
 
 void __init init_ISA_irqs (void)
@@ -450,6 +450,7 @@ void spurious_interrupt(void);
 void error_interrupt(void);
 void reschedule_interrupt(void);
 void call_function_interrupt(void);
+void irq_move_cleanup_interrupt(void);
 void invalidate_interrupt0(void);
 void invalidate_interrupt1(void);
 void invalidate_interrupt2(void);
@@ -520,12 +521,6 @@ void __init init_IRQ(void)
 
 #ifdef CONFIG_SMP
        /*
-        * IRQ0 must be given a fixed assignment and initialized,
-        * because it's used before the IO-APIC is set up.
-        */
-       __get_cpu_var(vector_irq)[FIRST_DEVICE_VECTOR] = 0;
-
-       /*
         * The reschedule interrupt is a CPU-to-CPU reschedule-helper
         * IPI, driven by wakeup.
         */
@@ -543,7 +538,10 @@ void __init init_IRQ(void)
 
        /* IPI for generic function call */
        set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
-#endif 
+
+       /* Low priority IPI to cleanup after moving an irq */
+       set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt);
+#endif
        set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
        set_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt);
 
index 950682f..48593f6 100644 (file)
@@ -36,6 +36,7 @@
 #include <acpi/acpi_bus.h>
 #endif
 
+#include <asm/idle.h>
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/desc.h>
 #include <asm/msidef.h>
 #include <asm/hypertransport.h>
 
-static int assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result);
+struct irq_cfg {
+       cpumask_t domain;
+       cpumask_t old_domain;
+       unsigned move_cleanup_count;
+       u8 vector;
+       u8 move_in_progress : 1;
+};
+
+/* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
+struct irq_cfg irq_cfg[NR_IRQS] __read_mostly = {
+       [0]  = { .domain = CPU_MASK_ALL, .vector = IRQ0_VECTOR,  },
+       [1]  = { .domain = CPU_MASK_ALL, .vector = IRQ1_VECTOR,  },
+       [2]  = { .domain = CPU_MASK_ALL, .vector = IRQ2_VECTOR,  },
+       [3]  = { .domain = CPU_MASK_ALL, .vector = IRQ3_VECTOR,  },
+       [4]  = { .domain = CPU_MASK_ALL, .vector = IRQ4_VECTOR,  },
+       [5]  = { .domain = CPU_MASK_ALL, .vector = IRQ5_VECTOR,  },
+       [6]  = { .domain = CPU_MASK_ALL, .vector = IRQ6_VECTOR,  },
+       [7]  = { .domain = CPU_MASK_ALL, .vector = IRQ7_VECTOR,  },
+       [8]  = { .domain = CPU_MASK_ALL, .vector = IRQ8_VECTOR,  },
+       [9]  = { .domain = CPU_MASK_ALL, .vector = IRQ9_VECTOR,  },
+       [10] = { .domain = CPU_MASK_ALL, .vector = IRQ10_VECTOR, },
+       [11] = { .domain = CPU_MASK_ALL, .vector = IRQ11_VECTOR, },
+       [12] = { .domain = CPU_MASK_ALL, .vector = IRQ12_VECTOR, },
+       [13] = { .domain = CPU_MASK_ALL, .vector = IRQ13_VECTOR, },
+       [14] = { .domain = CPU_MASK_ALL, .vector = IRQ14_VECTOR, },
+       [15] = { .domain = CPU_MASK_ALL, .vector = IRQ15_VECTOR, },
+};
+
+static int assign_irq_vector(int irq, cpumask_t mask);
 
 #define __apicdebuginit  __init
 
@@ -74,7 +103,7 @@ int nr_ioapic_registers[MAX_IO_APICS];
  * Rough estimation of how many shared IRQs there are, can
  * be changed anytime.
  */
-#define MAX_PLUS_SHARED_IRQS NR_IRQ_VECTORS
+#define MAX_PLUS_SHARED_IRQS NR_IRQS
 #define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)
 
 /*
@@ -149,11 +178,11 @@ static inline void io_apic_sync(unsigned int apic)
                reg = io_apic_read(entry->apic, 0x10 + R + pin*2);      \
                reg ACTION;                                             \
                io_apic_modify(entry->apic, reg);                       \
+               FINAL;                                                  \
                if (!entry->next)                                       \
                        break;                                          \
                entry = irq_2_pin + entry->next;                        \
        }                                                               \
-       FINAL;                                                          \
 }
 
 union entry_union {
@@ -237,21 +266,19 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector)
 
 static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
 {
+       struct irq_cfg *cfg = irq_cfg + irq;
        unsigned long flags;
        unsigned int dest;
        cpumask_t tmp;
-       int vector;
 
        cpus_and(tmp, mask, cpu_online_map);
        if (cpus_empty(tmp))
-               tmp = TARGET_CPUS;
-
-       cpus_and(mask, tmp, CPU_MASK_ALL);
+               return;
 
-       vector = assign_irq_vector(irq, mask, &tmp);
-       if (vector < 0)
+       if (assign_irq_vector(irq, mask))
                return;
 
+       cpus_and(tmp, cfg->domain, mask);
        dest = cpu_mask_to_apicid(tmp);
 
        /*
@@ -260,8 +287,8 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
        dest = SET_APIC_LOGICAL_ID(dest);
 
        spin_lock_irqsave(&ioapic_lock, flags);
-       __target_IO_APIC_irq(irq, dest, vector);
-       set_native_irq_info(irq, mask);
+       __target_IO_APIC_irq(irq, dest, cfg->vector);
+       irq_desc[irq].affinity = mask;
        spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 #endif
@@ -615,63 +642,7 @@ static int pin_2_irq(int idx, int apic, int pin)
        return irq;
 }
 
-static inline int IO_APIC_irq_trigger(int irq)
-{
-       int apic, idx, pin;
-
-       for (apic = 0; apic < nr_ioapics; apic++) {
-               for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
-                       idx = find_irq_entry(apic,pin,mp_INT);
-                       if ((idx != -1) && (irq == pin_2_irq(idx,apic,pin)))
-                               return irq_trigger(idx);
-               }
-       }
-       /*
-        * nonexistent IRQs are edge default
-        */
-       return 0;
-}
-
-/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
-static u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = {
-       [0] = FIRST_EXTERNAL_VECTOR + 0,
-       [1] = FIRST_EXTERNAL_VECTOR + 1,
-       [2] = FIRST_EXTERNAL_VECTOR + 2,
-       [3] = FIRST_EXTERNAL_VECTOR + 3,
-       [4] = FIRST_EXTERNAL_VECTOR + 4,
-       [5] = FIRST_EXTERNAL_VECTOR + 5,
-       [6] = FIRST_EXTERNAL_VECTOR + 6,
-       [7] = FIRST_EXTERNAL_VECTOR + 7,
-       [8] = FIRST_EXTERNAL_VECTOR + 8,
-       [9] = FIRST_EXTERNAL_VECTOR + 9,
-       [10] = FIRST_EXTERNAL_VECTOR + 10,
-       [11] = FIRST_EXTERNAL_VECTOR + 11,
-       [12] = FIRST_EXTERNAL_VECTOR + 12,
-       [13] = FIRST_EXTERNAL_VECTOR + 13,
-       [14] = FIRST_EXTERNAL_VECTOR + 14,
-       [15] = FIRST_EXTERNAL_VECTOR + 15,
-};
-
-static cpumask_t irq_domain[NR_IRQ_VECTORS] __read_mostly = {
-       [0] = CPU_MASK_ALL,
-       [1] = CPU_MASK_ALL,
-       [2] = CPU_MASK_ALL,
-       [3] = CPU_MASK_ALL,
-       [4] = CPU_MASK_ALL,
-       [5] = CPU_MASK_ALL,
-       [6] = CPU_MASK_ALL,
-       [7] = CPU_MASK_ALL,
-       [8] = CPU_MASK_ALL,
-       [9] = CPU_MASK_ALL,
-       [10] = CPU_MASK_ALL,
-       [11] = CPU_MASK_ALL,
-       [12] = CPU_MASK_ALL,
-       [13] = CPU_MASK_ALL,
-       [14] = CPU_MASK_ALL,
-       [15] = CPU_MASK_ALL,
-};
-
-static int __assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result)
+static int __assign_irq_vector(int irq, cpumask_t mask)
 {
        /*
         * NOTE! The local APIC isn't very good at handling
@@ -685,20 +656,25 @@ static int __assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result)
         * 0x80, because int 0x80 is hm, kind of importantish. ;)
         */
        static int current_vector = FIRST_DEVICE_VECTOR, current_offset = 0;
-       int old_vector = -1;
+       unsigned int old_vector;
        int cpu;
+       struct irq_cfg *cfg;
 
-       BUG_ON((unsigned)irq >= NR_IRQ_VECTORS);
+       BUG_ON((unsigned)irq >= NR_IRQS);
+       cfg = &irq_cfg[irq];
 
        /* Only try and allocate irqs on cpus that are present */
        cpus_and(mask, mask, cpu_online_map);
 
-       if (irq_vector[irq] > 0)
-               old_vector = irq_vector[irq];
-       if (old_vector > 0) {
-               cpus_and(*result, irq_domain[irq], mask);
-               if (!cpus_empty(*result))
-                       return old_vector;
+       if ((cfg->move_in_progress) || cfg->move_cleanup_count)
+               return -EBUSY;
+
+       old_vector = cfg->vector;
+       if (old_vector) {
+               cpumask_t tmp;
+               cpus_and(tmp, cfg->domain, mask);
+               if (!cpus_empty(tmp))
+                       return 0;
        }
 
        for_each_cpu_mask(cpu, mask) {
@@ -728,48 +704,47 @@ next:
                /* Found one! */
                current_vector = vector;
                current_offset = offset;
-               if (old_vector >= 0) {
-                       cpumask_t old_mask;
-                       int old_cpu;
-                       cpus_and(old_mask, irq_domain[irq], cpu_online_map);
-                       for_each_cpu_mask(old_cpu, old_mask)
-                               per_cpu(vector_irq, old_cpu)[old_vector] = -1;
+               if (old_vector) {
+                       cfg->move_in_progress = 1;
+                       cfg->old_domain = cfg->domain;
                }
                for_each_cpu_mask(new_cpu, new_mask)
                        per_cpu(vector_irq, new_cpu)[vector] = irq;
-               irq_vector[irq] = vector;
-               irq_domain[irq] = domain;
-               cpus_and(*result, domain, mask);
-               return vector;
+               cfg->vector = vector;
+               cfg->domain = domain;
+               return 0;
        }
        return -ENOSPC;
 }
 
-static int assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result)
+static int assign_irq_vector(int irq, cpumask_t mask)
 {
-       int vector;
+       int err;
        unsigned long flags;
 
        spin_lock_irqsave(&vector_lock, flags);
-       vector = __assign_irq_vector(irq, mask, result);
+       err = __assign_irq_vector(irq, mask);
        spin_unlock_irqrestore(&vector_lock, flags);
-       return vector;
+       return err;
 }
 
 static void __clear_irq_vector(int irq)
 {
+       struct irq_cfg *cfg;
        cpumask_t mask;
        int cpu, vector;
 
-       BUG_ON(!irq_vector[irq]);
+       BUG_ON((unsigned)irq >= NR_IRQS);
+       cfg = &irq_cfg[irq];
+       BUG_ON(!cfg->vector);
 
-       vector = irq_vector[irq];
-       cpus_and(mask, irq_domain[irq], cpu_online_map);
+       vector = cfg->vector;
+       cpus_and(mask, cfg->domain, cpu_online_map);
        for_each_cpu_mask(cpu, mask)
                per_cpu(vector_irq, cpu)[vector] = -1;
 
-       irq_vector[irq] = 0;
-       irq_domain[irq] = CPU_MASK_NONE;
+       cfg->vector = 0;
+       cfg->domain = CPU_MASK_NONE;
 }
 
 void __setup_vector_irq(int cpu)
@@ -779,10 +754,10 @@ void __setup_vector_irq(int cpu)
        int irq, vector;
 
        /* Mark the inuse vectors */
-       for (irq = 0; irq < NR_IRQ_VECTORS; ++irq) {
-               if (!cpu_isset(cpu, irq_domain[irq]))
+       for (irq = 0; irq < NR_IRQS; ++irq) {
+               if (!cpu_isset(cpu, irq_cfg[irq].domain))
                        continue;
-               vector = irq_vector[irq];
+               vector = irq_cfg[irq].vector;
                per_cpu(vector_irq, cpu)[vector] = irq;
        }
        /* Mark the free vectors */
@@ -790,36 +765,46 @@ void __setup_vector_irq(int cpu)
                irq = per_cpu(vector_irq, cpu)[vector];
                if (irq < 0)
                        continue;
-               if (!cpu_isset(cpu, irq_domain[irq]))
+               if (!cpu_isset(cpu, irq_cfg[irq].domain))
                        per_cpu(vector_irq, cpu)[vector] = -1;
        }
 }
 
 
-extern void (*interrupt[NR_IRQS])(void);
-
 static struct irq_chip ioapic_chip;
 
-#define IOAPIC_AUTO    -1
-#define IOAPIC_EDGE    0
-#define IOAPIC_LEVEL   1
-
-static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
+static void ioapic_register_intr(int irq, unsigned long trigger)
 {
-       if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
-                       trigger == IOAPIC_LEVEL)
+       if (trigger)
                set_irq_chip_and_handler_name(irq, &ioapic_chip,
                                              handle_fasteoi_irq, "fasteoi");
        else
                set_irq_chip_and_handler_name(irq, &ioapic_chip,
                                              handle_edge_irq, "edge");
 }
-static void __init setup_IO_APIC_irq(int apic, int pin, int idx, int irq)
+
+static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq,
+                             int trigger, int polarity)
 {
+       struct irq_cfg *cfg = irq_cfg + irq;
        struct IO_APIC_route_entry entry;
-       int vector;
+       cpumask_t mask;
        unsigned long flags;
 
+       if (!IO_APIC_IRQ(irq))
+               return;
+
+       mask = TARGET_CPUS;
+       if (assign_irq_vector(irq, mask))
+               return;
+
+       cpus_and(mask, cfg->domain, mask);
+
+       apic_printk(APIC_VERBOSE,KERN_DEBUG
+                   "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> "
+                   "IRQ %d Mode:%i Active:%i)\n",
+                   apic, mp_ioapics[apic].mpc_apicid, pin, cfg->vector,
+                   irq, trigger, polarity);
 
        /*
         * add it to the IO-APIC irq-routing table:
@@ -828,41 +813,27 @@ static void __init setup_IO_APIC_irq(int apic, int pin, int idx, int irq)
 
        entry.delivery_mode = INT_DELIVERY_MODE;
        entry.dest_mode = INT_DEST_MODE;
+       entry.dest = cpu_mask_to_apicid(mask);
        entry.mask = 0;                         /* enable IRQ */
-       entry.dest = cpu_mask_to_apicid(TARGET_CPUS);
-
-       entry.trigger = irq_trigger(idx);
-       entry.polarity = irq_polarity(idx);
+       entry.trigger = trigger;
+       entry.polarity = polarity;
+       entry.vector = cfg->vector;
 
-       if (irq_trigger(idx)) {
-               entry.trigger = 1;
+       /* Mask level triggered irqs.
+        * Use IRQ_DELAYED_DISABLE for edge triggered irqs.
+        */
+       if (trigger)
                entry.mask = 1;
-               entry.dest = cpu_mask_to_apicid(TARGET_CPUS);
-       }
-
-       if (!apic && !IO_APIC_IRQ(irq))
-               return;
-
-       if (IO_APIC_IRQ(irq)) {
-               cpumask_t mask;
-               vector = assign_irq_vector(irq, TARGET_CPUS, &mask);
-               if (vector < 0)
-                       return;
-
-               entry.dest = cpu_mask_to_apicid(mask);
-               entry.vector = vector;
 
-               ioapic_register_intr(irq, vector, IOAPIC_AUTO);
-               if (!apic && (irq < 16))
-                       disable_8259A_irq(irq);
-       }
+       ioapic_register_intr(irq, trigger);
+       if (irq < 16)
+               disable_8259A_irq(irq);
 
        ioapic_write_entry(apic, pin, entry);
 
        spin_lock_irqsave(&ioapic_lock, flags);
-       set_native_irq_info(irq, TARGET_CPUS);
+       irq_desc[irq].affinity = TARGET_CPUS;
        spin_unlock_irqrestore(&ioapic_lock, flags);
-
 }
 
 static void __init setup_IO_APIC_irqs(void)
@@ -887,8 +858,8 @@ static void __init setup_IO_APIC_irqs(void)
                irq = pin_2_irq(idx, apic, pin);
                add_pin_to_irq(irq, apic, pin);
 
-               setup_IO_APIC_irq(apic, pin, idx, irq);
-
+               setup_IO_APIC_irq(apic, pin, irq,
+                                 irq_trigger(idx), irq_polarity(idx));
        }
        }
 
@@ -1373,16 +1344,15 @@ static unsigned int startup_ioapic_irq(unsigned int irq)
 
 static int ioapic_retrigger_irq(unsigned int irq)
 {
+       struct irq_cfg *cfg = &irq_cfg[irq];
        cpumask_t mask;
-       unsigned vector;
        unsigned long flags;
 
        spin_lock_irqsave(&vector_lock, flags);
-       vector = irq_vector[irq];
        cpus_clear(mask);
-       cpu_set(first_cpu(irq_domain[irq]), mask);
+       cpu_set(first_cpu(cfg->domain), mask);
 
-       send_IPI_mask(mask, vector);
+       send_IPI_mask(mask, cfg->vector);
        spin_unlock_irqrestore(&vector_lock, flags);
 
        return 1;
@@ -1397,8 +1367,68 @@ static int ioapic_retrigger_irq(unsigned int irq)
  * races.
  */
 
+#ifdef CONFIG_SMP
+asmlinkage void smp_irq_move_cleanup_interrupt(void)
+{
+       unsigned vector, me;
+       ack_APIC_irq();
+       exit_idle();
+       irq_enter();
+
+       me = smp_processor_id();
+       for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
+               unsigned int irq;
+               struct irq_desc *desc;
+               struct irq_cfg *cfg;
+               irq = __get_cpu_var(vector_irq)[vector];
+               if (irq >= NR_IRQS)
+                       continue;
+
+               desc = irq_desc + irq;
+               cfg = irq_cfg + irq;
+               spin_lock(&desc->lock);
+               if (!cfg->move_cleanup_count)
+                       goto unlock;
+
+               if ((vector == cfg->vector) && cpu_isset(me, cfg->domain))
+                       goto unlock;
+
+               __get_cpu_var(vector_irq)[vector] = -1;
+               cfg->move_cleanup_count--;
+unlock:
+               spin_unlock(&desc->lock);
+       }
+
+       irq_exit();
+}
+
+static void irq_complete_move(unsigned int irq)
+{
+       struct irq_cfg *cfg = irq_cfg + irq;
+       unsigned vector, me;
+
+       if (likely(!cfg->move_in_progress))
+               return;
+
+       vector = ~get_irq_regs()->orig_rax;
+       me = smp_processor_id();
+       if ((vector == cfg->vector) &&
+           cpu_isset(smp_processor_id(), cfg->domain)) {
+               cpumask_t cleanup_mask;
+
+               cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map);
+               cfg->move_cleanup_count = cpus_weight(cleanup_mask);
+               send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
+               cfg->move_in_progress = 0;
+       }
+}
+#else
+static inline void irq_complete_move(unsigned int irq) {}
+#endif
+
 static void ack_apic_edge(unsigned int irq)
 {
+       irq_complete_move(irq);
        move_native_irq(irq);
        ack_APIC_irq();
 }
@@ -1407,6 +1437,7 @@ static void ack_apic_level(unsigned int irq)
 {
        int do_unmask_irq = 0;
 
+       irq_complete_move(irq);
 #if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
        /* If we are moving the irq we need to mask it */
        if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) {
@@ -1457,7 +1488,7 @@ static inline void init_IO_APIC_traps(void)
         */
        for (irq = 0; irq < NR_IRQS ; irq++) {
                int tmp = irq;
-               if (IO_APIC_IRQ(tmp) && !irq_vector[tmp]) {
+               if (IO_APIC_IRQ(tmp) && !irq_cfg[tmp].vector) {
                        /*
                         * Hmm.. We don't have an entry for this,
                         * so default to an old-fashioned 8259
@@ -1596,15 +1627,14 @@ static inline void unlock_ExtINT_logic(void)
  */
 static inline void check_timer(void)
 {
+       struct irq_cfg *cfg = irq_cfg + 0;
        int apic1, pin1, apic2, pin2;
-       int vector;
-       cpumask_t mask;
 
        /*
         * get/set the timer IRQ vector:
         */
        disable_8259A_irq(0);
-       vector = assign_irq_vector(0, TARGET_CPUS, &mask);
+       assign_irq_vector(0, TARGET_CPUS);
 
        /*
         * Subtle, code in do_timer_interrupt() expects an AEOI
@@ -1624,7 +1654,7 @@ static inline void check_timer(void)
        apic2 = ioapic_i8259.apic;
 
        apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n",
-               vector, apic1, pin1, apic2, pin2);
+               cfg->vector, apic1, pin1, apic2, pin2);
 
        if (pin1 != -1) {
                /*
@@ -1655,7 +1685,7 @@ static inline void check_timer(void)
                /*
                 * legacy devices should be connected to IO APIC #0
                 */
-               setup_ExtINT_IRQ0_pin(apic2, pin2, vector);
+               setup_ExtINT_IRQ0_pin(apic2, pin2, cfg->vector);
                if (timer_irq_works()) {
                        apic_printk(APIC_VERBOSE," works.\n");
                        nmi_watchdog_default();
@@ -1680,14 +1710,14 @@ static inline void check_timer(void)
 
        disable_8259A_irq(0);
        irq_desc[0].chip = &lapic_irq_type;
-       apic_write(APIC_LVT0, APIC_DM_FIXED | vector);  /* Fixed mode */
+       apic_write(APIC_LVT0, APIC_DM_FIXED | cfg->vector);     /* Fixed mode */
        enable_8259A_irq(0);
 
        if (timer_irq_works()) {
                apic_printk(APIC_VERBOSE," works.\n");
                return;
        }
-       apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | vector);
+       apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | cfg->vector);
        apic_printk(APIC_VERBOSE," failed.\n");
 
        apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as ExtINT IRQ...");
@@ -1834,19 +1864,16 @@ int create_irq(void)
        /* Allocate an unused irq */
        int irq;
        int new;
-       int vector = 0;
        unsigned long flags;
-       cpumask_t mask;
 
        irq = -ENOSPC;
        spin_lock_irqsave(&vector_lock, flags);
        for (new = (NR_IRQS - 1); new >= 0; new--) {
                if (platform_legacy_irq(new))
                        continue;
-               if (irq_vector[new] != 0)
+               if (irq_cfg[new].vector != 0)
                        continue;
-               vector = __assign_irq_vector(new, TARGET_CPUS, &mask);
-               if (likely(vector > 0))
+               if (__assign_irq_vector(new, TARGET_CPUS) == 0)
                        irq = new;
                break;
        }
@@ -1875,12 +1902,15 @@ void destroy_irq(unsigned int irq)
 #ifdef CONFIG_PCI_MSI
 static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
 {
-       int vector;
+       struct irq_cfg *cfg = irq_cfg + irq;
+       int err;
        unsigned dest;
        cpumask_t tmp;
 
-       vector = assign_irq_vector(irq, TARGET_CPUS, &tmp);
-       if (vector >= 0) {
+       tmp = TARGET_CPUS;
+       err = assign_irq_vector(irq, tmp);
+       if (!err) {
+               cpus_and(tmp, cfg->domain, tmp);
                dest = cpu_mask_to_apicid(tmp);
 
                msg->address_hi = MSI_ADDR_BASE_HI;
@@ -1900,40 +1930,38 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
                        ((INT_DELIVERY_MODE != dest_LowestPrio) ?
                                MSI_DATA_DELIVERY_FIXED:
                                MSI_DATA_DELIVERY_LOWPRI) |
-                       MSI_DATA_VECTOR(vector);
+                       MSI_DATA_VECTOR(cfg->vector);
        }
-       return vector;
+       return err;
 }
 
 #ifdef CONFIG_SMP
 static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
 {
+       struct irq_cfg *cfg = irq_cfg + irq;
        struct msi_msg msg;
        unsigned int dest;
        cpumask_t tmp;
-       int vector;
 
        cpus_and(tmp, mask, cpu_online_map);
        if (cpus_empty(tmp))
-               tmp = TARGET_CPUS;
-
-       cpus_and(mask, tmp, CPU_MASK_ALL);
+               return;
 
-       vector = assign_irq_vector(irq, mask, &tmp);
-       if (vector < 0)
+       if (assign_irq_vector(irq, mask))
                return;
 
+       cpus_and(tmp, cfg->domain, mask);
        dest = cpu_mask_to_apicid(tmp);
 
        read_msi_msg(irq, &msg);
 
        msg.data &= ~MSI_DATA_VECTOR_MASK;
-       msg.data |= MSI_DATA_VECTOR(vector);
+       msg.data |= MSI_DATA_VECTOR(cfg->vector);
        msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
        msg.address_lo |= MSI_ADDR_DEST_ID(dest);
 
        write_msi_msg(irq, &msg);
-       set_native_irq_info(irq, mask);
+       irq_desc[irq].affinity = mask;
 }
 #endif /* CONFIG_SMP */
 
@@ -2004,24 +2032,22 @@ static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
 
 static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
 {
+       struct irq_cfg *cfg = irq_cfg + irq;
        unsigned int dest;
        cpumask_t tmp;
-       int vector;
 
        cpus_and(tmp, mask, cpu_online_map);
        if (cpus_empty(tmp))
-               tmp = TARGET_CPUS;
-
-       cpus_and(mask, tmp, CPU_MASK_ALL);
+               return;
 
-       vector = assign_irq_vector(irq, mask, &tmp);
-       if (vector < 0)
+       if (assign_irq_vector(irq, mask))
                return;
 
+       cpus_and(tmp, cfg->domain, mask);
        dest = cpu_mask_to_apicid(tmp);
 
-       target_ht_irq(irq, dest, vector);
-       set_native_irq_info(irq, mask);
+       target_ht_irq(irq, dest, cfg->vector);
+       irq_desc[irq].affinity = mask;
 }
 #endif
 
@@ -2038,14 +2064,17 @@ static struct irq_chip ht_irq_chip = {
 
 int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
 {
-       int vector;
+       struct irq_cfg *cfg = irq_cfg + irq;
+       int err;
        cpumask_t tmp;
 
-       vector = assign_irq_vector(irq, TARGET_CPUS, &tmp);
-       if (vector >= 0) {
+       tmp = TARGET_CPUS;
+       err = assign_irq_vector(irq, tmp);
+       if (!err) {
                struct ht_irq_msg msg;
                unsigned dest;
 
+               cpus_and(tmp, cfg->domain, tmp);
                dest = cpu_mask_to_apicid(tmp);
 
                msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest);
@@ -2053,7 +2082,7 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
                msg.address_lo =
                        HT_IRQ_LOW_BASE |
                        HT_IRQ_LOW_DEST_ID(dest) |
-                       HT_IRQ_LOW_VECTOR(vector) |
+                       HT_IRQ_LOW_VECTOR(cfg->vector) |
                        ((INT_DEST_MODE == 0) ?
                                HT_IRQ_LOW_DM_PHYSICAL :
                                HT_IRQ_LOW_DM_LOGICAL) |
@@ -2068,7 +2097,7 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
                set_irq_chip_and_handler_name(irq, &ht_irq_chip,
                                              handle_edge_irq, "edge");
        }
-       return vector;
+       return err;
 }
 #endif /* CONFIG_HT_IRQ */
 
@@ -2095,11 +2124,6 @@ int __init io_apic_get_redir_entries (int ioapic)
 
 int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int polarity)
 {
-       struct IO_APIC_route_entry entry;
-       unsigned long flags;
-       int vector;
-       cpumask_t mask;
-
        if (!IO_APIC_IRQ(irq)) {
                apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
                        ioapic);
@@ -2112,42 +2136,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p
        if (irq >= 16)
                add_pin_to_irq(irq, ioapic, pin);
 
-
-       vector = assign_irq_vector(irq, TARGET_CPUS, &mask);
-       if (vector < 0)
-               return vector;
-
-       /*
-        * Generate a PCI IRQ routing entry and program the IOAPIC accordingly.
-        * Note that we mask (disable) IRQs now -- these get enabled when the
-        * corresponding device driver registers for this IRQ.
-        */
-
-       memset(&entry,0,sizeof(entry));
-
-       entry.delivery_mode = INT_DELIVERY_MODE;
-       entry.dest_mode = INT_DEST_MODE;
-       entry.dest = cpu_mask_to_apicid(mask);
-       entry.trigger = triggering;
-       entry.polarity = polarity;
-       entry.mask = 1;                                  /* Disabled (masked) */
-       entry.vector = vector & 0xff;
-
-       apic_printk(APIC_VERBOSE,KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> "
-               "IRQ %d Mode:%i Active:%i)\n", ioapic, 
-              mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq,
-              triggering, polarity);
-
-       ioapic_register_intr(irq, entry.vector, triggering);
-
-       if (!ioapic && (irq < 16))
-               disable_8259A_irq(irq);
-
-       ioapic_write_entry(ioapic, pin, entry);
-
-       spin_lock_irqsave(&ioapic_lock, flags);
-       set_native_irq_info(irq, TARGET_CPUS);
-       spin_unlock_irqrestore(&ioapic_lock, flags);
+       setup_IO_APIC_irq(ioapic, pin, irq, triggering, polarity);
 
        return 0;
 }
@@ -2179,8 +2168,10 @@ void __init setup_ioapic_dest(void)
                         * when you have too many devices, because at that time only boot
                         * cpu is online.
                         */
-                       if(!irq_vector[irq])
-                               setup_IO_APIC_irq(ioapic, pin, irq_entry, irq);
+                       if (!irq_cfg[irq].vector)
+                               setup_IO_APIC_irq(ioapic, pin, irq,
+                                                 irq_trigger(irq_entry),
+                                                 irq_polarity(irq_entry));
                        else
                                set_ioapic_affinity_irq(irq, TARGET_CPUS);
                }
index 36bd3e1..050a1f0 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/genhd.h>
+#include <linux/kdev_t.h>
 #include <linux/kernel.h>
 #include <linux/blkdev.h>
 #include <linux/init.h>
@@ -61,13 +62,7 @@ int register_blkdev(unsigned int major, const char *name)
        /* temporary */
        if (major == 0) {
                for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) {
-                       /*
-                        * Disallow the LANANA-assigned LOCAL/EXPERIMENTAL
-                        * majors
-                        */
-                       if ((60 <= index && index <= 63) ||
-                                       (120 <= index && index <= 127) ||
-                                       (240 <= index && index <= 254))
+                       if (is_lanana_major(index))
                                continue;
                        if (major_names[index] == NULL)
                                break;
index e3f5eb9..e06dbe9 100644 (file)
@@ -82,7 +82,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
                        fsync_bdev(bdevp);
                        invalidate_bdev(bdevp, 0);
 
-                       mutex_lock(&bdev->bd_mutex);
+                       mutex_lock_nested(&bdev->bd_mutex, 1);
                        delete_partition(disk, part);
                        mutex_unlock(&bdev->bd_mutex);
                        mutex_unlock(&bdevp->bd_mutex);
index 36468ec..8928a6d 100644 (file)
@@ -308,7 +308,6 @@ static void pcmcia_remove_one(struct pcmcia_device *pdev)
                if (info->ndev) {
                        struct ata_host *host = dev_get_drvdata(dev);
                        ata_host_detach(host);
-                       dev_set_drvdata(dev, NULL);
                }
                info->ndev = 0;
                pdev->priv = NULL;
index 889583d..cb44cb4 100644 (file)
@@ -312,6 +312,17 @@ EXPORT_SYMBOL_GPL(cfag12864b_disable);
 EXPORT_SYMBOL_GPL(cfag12864b_isenabled);
 
 /*
+ * Is the module inited?
+ */
+
+static unsigned char cfag12864b_inited;
+unsigned char cfag12864b_isinited(void)
+{
+       return cfag12864b_inited;
+}
+EXPORT_SYMBOL_GPL(cfag12864b_isinited);
+
+/*
  * Module Init & Exit
  */
 
@@ -319,6 +330,13 @@ static int __init cfag12864b_init(void)
 {
        int ret = -EINVAL;
 
+       /* ks0108_init() must be called first */
+       if (!ks0108_isinited()) {
+               printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
+                       "ks0108 is not initialized\n");
+               goto none;
+       }
+
        if (PAGE_SIZE < CFAG12864B_SIZE) {
                printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
                        "page size (%i) < cfag12864b size (%i)\n",
@@ -354,6 +372,7 @@ static int __init cfag12864b_init(void)
        cfag12864b_clear();
        cfag12864b_on();
 
+       cfag12864b_inited = 1;
        return 0;
 
 cachealloced:
index 94765e7..66fafbb 100644 (file)
@@ -137,7 +137,14 @@ static struct platform_device *cfag12864bfb_device;
 
 static int __init cfag12864bfb_init(void)
 {
-       int ret;
+       int ret = -EINVAL;
+
+       /* cfag12864b_init() must be called first */
+       if (!cfag12864b_isinited()) {
+               printk(KERN_ERR CFAG12864BFB_NAME ": ERROR: "
+                       "cfag12864b is not initialized\n");
+               goto none;
+       }
 
        if (cfag12864b_enable()) {
                printk(KERN_ERR CFAG12864BFB_NAME ": ERROR: "
@@ -162,6 +169,7 @@ static int __init cfag12864bfb_init(void)
                }
        }
 
+none:
        return ret;
 }
 
index a637575..e6c3646 100644 (file)
@@ -111,6 +111,17 @@ EXPORT_SYMBOL_GPL(ks0108_address);
 EXPORT_SYMBOL_GPL(ks0108_page);
 
 /*
+ * Is the module inited?
+ */
+
+static unsigned char ks0108_inited;
+unsigned char ks0108_isinited(void)
+{
+       return ks0108_inited;
+}
+EXPORT_SYMBOL_GPL(ks0108_isinited);
+
+/*
  * Module Init & Exit
  */
 
@@ -142,6 +153,7 @@ static int __init ks0108_init(void)
                goto registered;
        }
 
+       ks0108_inited = 1;
        return 0;
 
 registered:
index 1417e5c..d596812 100644 (file)
@@ -840,48 +840,6 @@ void class_device_destroy(struct class *cls, dev_t devt)
                class_device_unregister(class_dev);
 }
 
-int class_device_rename(struct class_device *class_dev, char *new_name)
-{
-       int error = 0;
-       char *old_class_name = NULL, *new_class_name = NULL;
-
-       class_dev = class_device_get(class_dev);
-       if (!class_dev)
-               return -EINVAL;
-
-       pr_debug("CLASS: renaming '%s' to '%s'\n", class_dev->class_id,
-                new_name);
-
-#ifdef CONFIG_SYSFS_DEPRECATED
-       if (class_dev->dev)
-               old_class_name = make_class_name(class_dev->class->name,
-                                                &class_dev->kobj);
-#endif
-
-       strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN);
-
-       error = kobject_rename(&class_dev->kobj, new_name);
-
-#ifdef CONFIG_SYSFS_DEPRECATED
-       if (class_dev->dev) {
-               new_class_name = make_class_name(class_dev->class->name,
-                                                &class_dev->kobj);
-               if (new_class_name)
-                       sysfs_create_link(&class_dev->dev->kobj,
-                                         &class_dev->kobj, new_class_name);
-               if (old_class_name)
-                       sysfs_remove_link(&class_dev->dev->kobj,
-                                               old_class_name);
-       }
-#endif
-       class_device_put(class_dev);
-
-       kfree(old_class_name);
-       kfree(new_class_name);
-
-       return error;
-}
-
 struct class_device * class_device_get(struct class_device *class_dev)
 {
        if (class_dev)
index a8ac34b..cf2a398 100644 (file)
@@ -28,6 +28,20 @@ int (*platform_notify)(struct device * dev) = NULL;
 int (*platform_notify_remove)(struct device * dev) = NULL;
 
 /*
+ * Detect the LANANA-assigned LOCAL/EXPERIMENTAL majors
+ */
+bool is_lanana_major(unsigned int major)
+{
+       if (major >= 60 && major <= 63)
+               return 1;
+       if (major >= 120 && major <= 127)
+               return 1;
+       if (major >= 240 && major <= 254)
+               return 1;
+       return 0;
+}
+
+/*
  * sysfs bindings for devices.
  */
 
@@ -623,12 +637,41 @@ int device_add(struct device *dev)
                                             BUS_NOTIFY_DEL_DEVICE, dev);
        device_remove_groups(dev);
  GroupError:
-       device_remove_attrs(dev);
+       device_remove_attrs(dev);
  AttrsError:
        if (dev->devt_attr) {
                device_remove_file(dev, dev->devt_attr);
                kfree(dev->devt_attr);
        }
+
+       if (dev->class) {
+               sysfs_remove_link(&dev->kobj, "subsystem");
+               /* If this is not a "fake" compatible device, remove the
+                * symlink from the class to the device. */
+               if (dev->kobj.parent != &dev->class->subsys.kset.kobj)
+                       sysfs_remove_link(&dev->class->subsys.kset.kobj,
+                                         dev->bus_id);
+#ifdef CONFIG_SYSFS_DEPRECATED
+               if (parent) {
+                       char *class_name = make_class_name(dev->class->name,
+                                                          &dev->kobj);
+                       if (class_name)
+                               sysfs_remove_link(&dev->parent->kobj,
+                                                 class_name);
+                       kfree(class_name);
+                       sysfs_remove_link(&dev->kobj, "device");
+               }
+#endif
+
+               down(&dev->class->sem);
+               /* notify any interfaces that the device is now gone */
+               list_for_each_entry(class_intf, &dev->class->interfaces, node)
+                       if (class_intf->remove_dev)
+                               class_intf->remove_dev(dev, class_intf);
+               /* remove the device from the class list */
+               list_del_init(&dev->node);
+               up(&dev->class->sem);
+       }
  ueventattrError:
        device_remove_file(dev, &dev->uevent_attr);
  attrError:
index 3f1b382..5231ed7 100644 (file)
@@ -297,17 +297,17 @@ static int initialising = 1;
 #define DRS (&drive_state[current_drive])
 #define DRWE (&write_errors[current_drive])
 #define FDCS (&fdc_state[fdc])
-#define CLEARF(x) (clear_bit(x##_BIT, &DRS->flags))
-#define SETF(x) (set_bit(x##_BIT, &DRS->flags))
-#define TESTF(x) (test_bit(x##_BIT, &DRS->flags))
+#define CLEARF(x) clear_bit(x##_BIT, &DRS->flags)
+#define SETF(x) set_bit(x##_BIT, &DRS->flags)
+#define TESTF(x) test_bit(x##_BIT, &DRS->flags)
 
 #define UDP (&drive_params[drive])
 #define UDRS (&drive_state[drive])
 #define UDRWE (&write_errors[drive])
 #define UFDCS (&fdc_state[FDC(drive)])
-#define UCLEARF(x) (clear_bit(x##_BIT, &UDRS->flags))
-#define USETF(x) (set_bit(x##_BIT, &UDRS->flags))
-#define UTESTF(x) (test_bit(x##_BIT, &UDRS->flags))
+#define UCLEARF(x) clear_bit(x##_BIT, &UDRS->flags)
+#define USETF(x) set_bit(x##_BIT, &UDRS->flags)
+#define UTESTF(x) test_bit(x##_BIT, &UDRS->flags)
 
 #define DPRINT(format, args...) printk(DEVICE_NAME "%d: " format, current_drive , ## args)
 
index 93fb6ed..a4fb703 100644 (file)
@@ -765,7 +765,7 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
                        goto out;
        }
 
-       rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
+       rq->cmd_len = COMMAND_SIZE(cgc->cmd[0]);
        memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE);
        if (sizeof(rq->cmd) > CDROM_PACKET_SIZE)
                memset(rq->cmd + CDROM_PACKET_SIZE, 0, sizeof(rq->cmd) - CDROM_PACKET_SIZE);
index 9256985..8919ccf 100644 (file)
@@ -307,3 +307,5 @@ MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Broadcom Blutonium firmware driver ver " VERSION);
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("BCM2033-MD.hex");
+MODULE_FIRMWARE("BCM2033-FW.bin");
index 27cceb6..4c766f3 100644 (file)
@@ -801,3 +801,4 @@ MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("BlueFRITZ! USB driver ver " VERSION);
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("bfubase.frm");
index 34e5555..18b0f39 100644 (file)
@@ -63,6 +63,7 @@
 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>");
 MODULE_DESCRIPTION("Bluetooth driver for the 3Com Bluetooth PCMCIA card");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("BT3CPCC.bin");
 
 
 
index a0d04a2..627f542 100644 (file)
@@ -1,7 +1,8 @@
 agpgart-y := backend.o frontend.o generic.o isoch.o
 
+agpgart-$(CONFIG_COMPAT)       += compat_ioctl.o
+
 obj-$(CONFIG_AGP)              += agpgart.o
-obj-$(CONFIG_COMPAT)           += compat_ioctl.o
 obj-$(CONFIG_AGP_ALI)          += ali-agp.o
 obj-$(CONFIG_AGP_ATI)          += ati-agp.o
 obj-$(CONFIG_AGP_AMD)          += amd-k7-agp.o
index 9bd68d9..fdbca25 100644 (file)
@@ -93,12 +93,12 @@ struct aper_size_info_fixed {
 
 struct agp_bridge_driver {
        struct module *owner;
-       void *aperture_sizes;
+       const void *aperture_sizes;
        int num_aperture_sizes;
        enum aper_size_type size_type;
        int cant_use_aperture;
        int needs_scratch_page;
-       struct gatt_mask *masks;
+       const struct gatt_mask *masks;
        int (*fetch_size)(void);
        int (*configure)(void);
        void (*agp_enable)(struct agp_bridge_data *, u32);
@@ -119,7 +119,7 @@ struct agp_bridge_driver {
 
 struct agp_bridge_data {
        const struct agp_version *version;
-       struct agp_bridge_driver *driver;
+       const struct agp_bridge_driver *driver;
        struct vm_operations_struct *vm_ops;
        void *previous_size;
        void *current_size;
@@ -290,7 +290,7 @@ void agp3_generic_cleanup(void);
 
 /* aperture sizes have been standardised since v3 */
 #define AGP_GENERIC_SIZES_ENTRIES 11
-extern struct aper_size_info_16 agp3_generic_sizes[];
+extern const struct aper_size_info_16 agp3_generic_sizes[];
 
 #define virt_to_gart(x) (phys_to_gart(virt_to_phys(x)))
 #define gart_to_virt(x) (phys_to_virt(gart_to_phys(x)))
index 98177a9..5b684fd 100644 (file)
@@ -182,7 +182,7 @@ static void m1541_destroy_page(void * addr)
 
 /* Setup function */
 
-static struct aper_size_info_32 ali_generic_sizes[7] =
+static const struct aper_size_info_32 ali_generic_sizes[7] =
 {
        {256, 65536, 6, 10},
        {128, 32768, 5, 9},
@@ -193,7 +193,7 @@ static struct aper_size_info_32 ali_generic_sizes[7] =
        {4, 1024, 0, 3}
 };
 
-static struct agp_bridge_driver ali_generic_bridge = {
+static const struct agp_bridge_driver ali_generic_bridge = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = ali_generic_sizes,
        .size_type              = U32_APER_SIZE,
@@ -217,7 +217,7 @@ static struct agp_bridge_driver ali_generic_bridge = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static struct agp_bridge_driver ali_m1541_bridge = {
+static const struct agp_bridge_driver ali_m1541_bridge = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = ali_generic_sizes,
        .size_type              = U32_APER_SIZE,
index 3d8d448..e6c534e 100644 (file)
@@ -344,7 +344,7 @@ static int amd_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
        return 0;
 }
 
-static struct aper_size_info_lvl2 amd_irongate_sizes[7] =
+static const struct aper_size_info_lvl2 amd_irongate_sizes[7] =
 {
        {2048, 524288, 0x0000000c},
        {1024, 262144, 0x0000000a},
@@ -355,12 +355,12 @@ static struct aper_size_info_lvl2 amd_irongate_sizes[7] =
        {32, 8192, 0x00000000}
 };
 
-static struct gatt_mask amd_irongate_masks[] =
+static const struct gatt_mask amd_irongate_masks[] =
 {
        {.mask = 1, .type = 0}
 };
 
-static struct agp_bridge_driver amd_irongate_driver = {
+static const struct agp_bridge_driver amd_irongate_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = amd_irongate_sizes,
        .size_type              = LVL2_APER_SIZE,
index 636d984..4857204 100644 (file)
@@ -192,7 +192,7 @@ static u64 amd64_configure (struct pci_dev *hammer, u64 gatt_table)
 }
 
 
-static struct aper_size_info_32 amd_8151_sizes[7] =
+static const struct aper_size_info_32 amd_8151_sizes[7] =
 {
        {2048, 524288, 9, 0x00000000 }, /* 0 0 0 0 0 0 */
        {1024, 262144, 8, 0x00000400 }, /* 1 0 0 0 0 0 */
@@ -232,7 +232,7 @@ static void amd64_cleanup(void)
 }
 
 
-static struct agp_bridge_driver amd_8151_driver = {
+static const struct agp_bridge_driver amd_8151_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = amd_8151_sizes,
        .size_type              = U32_APER_SIZE,
index 77c9ad6..780e59e 100644 (file)
@@ -24,7 +24,7 @@
 #define ATI_GART_CACHE_ENTRY_CNTRL     0x10
 
 
-static struct aper_size_info_lvl2 ati_generic_sizes[7] =
+static const struct aper_size_info_lvl2 ati_generic_sizes[7] =
 {
        {2048, 524288, 0x0000000c},
        {1024, 262144, 0x0000000a},
@@ -410,7 +410,7 @@ static int ati_free_gatt_table(struct agp_bridge_data *bridge)
        return 0;
 }
 
-static struct agp_bridge_driver ati_generic_bridge = {
+static const struct agp_bridge_driver ati_generic_bridge = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = ati_generic_sizes,
        .size_type              = LVL2_APER_SIZE,
index 658cb1a..df8da72 100644 (file)
@@ -59,7 +59,7 @@ static struct _efficeon_private {
        unsigned long l1_table[EFFICEON_L1_SIZE];
 } efficeon_private;
 
-static struct gatt_mask efficeon_generic_masks[] =
+static const struct gatt_mask efficeon_generic_masks[] =
 {
        {.mask = 0x00000001, .type = 0}
 };
@@ -70,7 +70,7 @@ static inline unsigned long efficeon_mask_memory(unsigned long addr)
        return addr | 0x00000001;
 }
 
-static struct aper_size_info_lvl2 efficeon_generic_sizes[4] =
+static const struct aper_size_info_lvl2 efficeon_generic_sizes[4] =
 {
        {256, 65536, 0},
        {128, 32768, 32},
@@ -309,7 +309,7 @@ static int efficeon_remove_memory(struct agp_memory * mem, off_t pg_start, int t
 }
 
 
-static struct agp_bridge_driver efficeon_driver = {
+static const struct agp_bridge_driver efficeon_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = efficeon_generic_sizes,
        .size_type              = LVL2_APER_SIZE,
index 7923337..f902d71 100644 (file)
@@ -1340,7 +1340,7 @@ void agp3_generic_cleanup(void)
 }
 EXPORT_SYMBOL(agp3_generic_cleanup);
 
-struct aper_size_info_16 agp3_generic_sizes[AGP_GENERIC_SIZES_ENTRIES] =
+const struct aper_size_info_16 agp3_generic_sizes[AGP_GENERIC_SIZES_ENTRIES] =
 {
        {4096, 1048576, 10,0x000},
        {2048,  524288, 9, 0x800},
index 847deab..79f7c01 100644 (file)
@@ -419,7 +419,7 @@ hp_zx1_enable (struct agp_bridge_data *bridge, u32 mode)
        agp_device_command(command, (mode & AGP8X_MODE) != 0);
 }
 
-struct agp_bridge_driver hp_zx1_driver = {
+struct const agp_bridge_driver hp_zx1_driver = {
        .owner                  = THIS_MODULE,
        .size_type              = FIXED_APER_SIZE,
        .configure              = hp_zx1_configure,
index 3e76186..1cde376 100644 (file)
@@ -78,7 +78,7 @@ static struct {
        } *lp_desc;
 } i460;
 
-static struct aper_size_info_8 i460_sizes[3] =
+static const struct aper_size_info_8 i460_sizes[3] =
 {
        /*
         * The 32GB aperture is only available with a 4M GART page size.  Due to the
@@ -550,7 +550,7 @@ static unsigned long i460_mask_memory (struct agp_bridge_data *bridge,
                | (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xfffff000) >> 12);
 }
 
-struct agp_bridge_driver intel_i460_driver = {
+struct const agp_bridge_driver intel_i460_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = i460_sizes,
        .size_type              = U8_APER_SIZE,
index 06b0bb6..e542a62 100644 (file)
@@ -63,7 +63,7 @@ extern int agp_memory_reserved;
 #define INTEL_I7505_AGPCTRL    0x70
 #define INTEL_I7505_MCHCFG     0x50
 
-static struct aper_size_info_fixed intel_i810_sizes[] =
+static const struct aper_size_info_fixed intel_i810_sizes[] =
 {
        {64, 16384, 4},
        /* The 32M mode still requires a 64k gatt */
@@ -1365,18 +1365,18 @@ static int intel_7505_configure(void)
 }
 
 /* Setup function */
-static struct gatt_mask intel_generic_masks[] =
+static const struct gatt_mask intel_generic_masks[] =
 {
        {.mask = 0x00000017, .type = 0}
 };
 
-static struct aper_size_info_8 intel_815_sizes[2] =
+static const struct aper_size_info_8 intel_815_sizes[2] =
 {
        {64, 16384, 4, 0},
        {32, 8192, 3, 8},
 };
 
-static struct aper_size_info_8 intel_8xx_sizes[7] =
+static const struct aper_size_info_8 intel_8xx_sizes[7] =
 {
        {256, 65536, 6, 0},
        {128, 32768, 5, 32},
@@ -1387,7 +1387,7 @@ static struct aper_size_info_8 intel_8xx_sizes[7] =
        {4, 1024, 0, 63}
 };
 
-static struct aper_size_info_16 intel_generic_sizes[7] =
+static const struct aper_size_info_16 intel_generic_sizes[7] =
 {
        {256, 65536, 6, 0},
        {128, 32768, 5, 32},
@@ -1398,7 +1398,7 @@ static struct aper_size_info_16 intel_generic_sizes[7] =
        {4, 1024, 0, 63}
 };
 
-static struct aper_size_info_8 intel_830mp_sizes[4] =
+static const struct aper_size_info_8 intel_830mp_sizes[4] =
 {
        {256, 65536, 6, 0},
        {128, 32768, 5, 32},
@@ -1406,7 +1406,7 @@ static struct aper_size_info_8 intel_830mp_sizes[4] =
        {32, 8192, 3, 56}
 };
 
-static struct agp_bridge_driver intel_generic_driver = {
+static const struct agp_bridge_driver intel_generic_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_generic_sizes,
        .size_type              = U16_APER_SIZE,
@@ -1430,7 +1430,7 @@ static struct agp_bridge_driver intel_generic_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static struct agp_bridge_driver intel_810_driver = {
+static const struct agp_bridge_driver intel_810_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_i810_sizes,
        .size_type              = FIXED_APER_SIZE,
@@ -1455,7 +1455,7 @@ static struct agp_bridge_driver intel_810_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static struct agp_bridge_driver intel_815_driver = {
+static const struct agp_bridge_driver intel_815_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_815_sizes,
        .size_type              = U8_APER_SIZE,
@@ -1479,7 +1479,7 @@ static struct agp_bridge_driver intel_815_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static struct agp_bridge_driver intel_830_driver = {
+static const struct agp_bridge_driver intel_830_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_i830_sizes,
        .size_type              = FIXED_APER_SIZE,
@@ -1504,7 +1504,7 @@ static struct agp_bridge_driver intel_830_driver = {
        .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
 };
 
-static struct agp_bridge_driver intel_820_driver = {
+static const struct agp_bridge_driver intel_820_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_8xx_sizes,
        .size_type              = U8_APER_SIZE,
@@ -1528,7 +1528,7 @@ static struct agp_bridge_driver intel_820_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static struct agp_bridge_driver intel_830mp_driver = {
+static const struct agp_bridge_driver intel_830mp_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_830mp_sizes,
        .size_type              = U8_APER_SIZE,
@@ -1552,7 +1552,7 @@ static struct agp_bridge_driver intel_830mp_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static struct agp_bridge_driver intel_840_driver = {
+static const struct agp_bridge_driver intel_840_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_8xx_sizes,
        .size_type              = U8_APER_SIZE,
@@ -1576,7 +1576,7 @@ static struct agp_bridge_driver intel_840_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static struct agp_bridge_driver intel_845_driver = {
+static const struct agp_bridge_driver intel_845_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_8xx_sizes,
        .size_type              = U8_APER_SIZE,
@@ -1600,7 +1600,7 @@ static struct agp_bridge_driver intel_845_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static struct agp_bridge_driver intel_850_driver = {
+static const struct agp_bridge_driver intel_850_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_8xx_sizes,
        .size_type              = U8_APER_SIZE,
@@ -1624,7 +1624,7 @@ static struct agp_bridge_driver intel_850_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static struct agp_bridge_driver intel_860_driver = {
+static const struct agp_bridge_driver intel_860_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_8xx_sizes,
        .size_type              = U8_APER_SIZE,
@@ -1648,7 +1648,7 @@ static struct agp_bridge_driver intel_860_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static struct agp_bridge_driver intel_915_driver = {
+static const struct agp_bridge_driver intel_915_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_i830_sizes,
        .size_type              = FIXED_APER_SIZE,
@@ -1673,7 +1673,7 @@ static struct agp_bridge_driver intel_915_driver = {
        .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
 };
 
-static struct agp_bridge_driver intel_i965_driver = {
+static const struct agp_bridge_driver intel_i965_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_i830_sizes,
        .size_type              = FIXED_APER_SIZE,
@@ -1698,7 +1698,7 @@ static struct agp_bridge_driver intel_i965_driver = {
        .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
 };
 
-static struct agp_bridge_driver intel_7505_driver = {
+static const struct agp_bridge_driver intel_7505_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_8xx_sizes,
        .size_type              = U8_APER_SIZE,
index 2563286..0c9dab5 100644 (file)
@@ -272,7 +272,7 @@ static void nvidia_tlbflush(struct agp_memory *mem)
 }
 
 
-static struct aper_size_info_8 nvidia_generic_sizes[5] =
+static const struct aper_size_info_8 nvidia_generic_sizes[5] =
 {
        {512, 131072, 7, 0},
        {256, 65536, 6, 8},
@@ -283,13 +283,13 @@ static struct aper_size_info_8 nvidia_generic_sizes[5] =
 };
 
 
-static struct gatt_mask nvidia_generic_masks[] =
+static const struct gatt_mask nvidia_generic_masks[] =
 {
        { .mask = 1, .type = 0}
 };
 
 
-static struct agp_bridge_driver nvidia_driver = {
+static const struct agp_bridge_driver nvidia_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = nvidia_generic_sizes,
        .size_type              = U8_APER_SIZE,
index b7b4590..3c8f3d6 100644 (file)
@@ -210,7 +210,7 @@ parisc_agp_enable(struct agp_bridge_data *bridge, u32 mode)
        agp_device_command(command, (mode & AGP8X_MODE) != 0);
 }
 
-struct agp_bridge_driver parisc_agp_driver = {
+struct const agp_bridge_driver parisc_agp_driver = {
        .owner                  = THIS_MODULE,
        .size_type              = FIXED_APER_SIZE,
        .configure              = parisc_agp_configure,
@@ -236,7 +236,7 @@ static int __init
 agp_ioc_init(void __iomem *ioc_regs)
 {
        struct _parisc_agp_info *info = &parisc_agp_info;
-        u64 *iova_base, *io_pdir, io_tlb_ps;
+        u64 iova_base, *io_pdir, io_tlb_ps;
         int io_tlb_shift;
 
         printk(KERN_INFO DRVPFX "IO PDIR shared with sba_iommu\n");
index 92d1dc4..e12773a 100644 (file)
@@ -247,7 +247,7 @@ static struct agp_bridge_data *sgi_tioca_find_bridge(struct pci_dev *pdev)
        return bridge;
 }
 
-struct agp_bridge_driver sgi_tioca_driver = {
+struct const agp_bridge_driver sgi_tioca_driver = {
        .owner = THIS_MODULE,
        .size_type = U16_APER_SIZE,
        .configure = sgi_tioca_configure,
index 60342b7..125f428 100644 (file)
@@ -108,7 +108,7 @@ static void sis_delayed_enable(struct agp_bridge_data *bridge, u32 mode)
        }
 }
 
-static struct aper_size_info_8 sis_generic_sizes[7] =
+static const struct aper_size_info_8 sis_generic_sizes[7] =
 {
        {256, 65536, 6, 99},
        {128, 32768, 5, 83},
index 9f5ae77..55212a3 100644 (file)
@@ -385,12 +385,12 @@ static int serverworks_remove_memory(struct agp_memory *mem, off_t pg_start,
        return 0;
 }
 
-static struct gatt_mask serverworks_masks[] =
+static const struct gatt_mask serverworks_masks[] =
 {
        {.mask = 1, .type = 0}
 };
 
-static struct aper_size_info_lvl2 serverworks_sizes[7] =
+static const struct aper_size_info_lvl2 serverworks_sizes[7] =
 {
        {2048, 524288, 0x80000000},
        {1024, 262144, 0xc0000000},
@@ -423,7 +423,7 @@ static void serverworks_agp_enable(struct agp_bridge_data *bridge, u32 mode)
        agp_device_command(command, 0);
 }
 
-static struct agp_bridge_driver sworks_driver = {
+static const struct agp_bridge_driver sworks_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = serverworks_sizes,
        .size_type              = LVL2_APER_SIZE,
index 6c45702..292b4ad 100644 (file)
@@ -460,7 +460,7 @@ void null_cache_flush(void)
 
 /* Setup function */
 
-static struct aper_size_info_32 uninorth_sizes[7] =
+static const struct aper_size_info_32 uninorth_sizes[7] =
 {
 #if 0 /* Not sure uninorth supports that high aperture sizes */
        {256, 65536, 6, 64},
@@ -477,7 +477,7 @@ static struct aper_size_info_32 uninorth_sizes[7] =
  * Not sure that u3 supports that high aperture sizes but it
  * would strange if it did not :)
  */
-static struct aper_size_info_32 u3_sizes[8] =
+static const struct aper_size_info_32 u3_sizes[8] =
 {
        {512, 131072, 7, 128},
        {256, 65536, 6, 64},
@@ -489,7 +489,7 @@ static struct aper_size_info_32 u3_sizes[8] =
        {4, 1024, 0, 1}
 };
 
-struct agp_bridge_driver uninorth_agp_driver = {
+struct const agp_bridge_driver uninorth_agp_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = (void *)uninorth_sizes,
        .size_type              = U32_APER_SIZE,
@@ -514,7 +514,7 @@ struct agp_bridge_driver uninorth_agp_driver = {
        .cant_use_aperture      = 1,
 };
 
-struct agp_bridge_driver u3_agp_driver = {
+struct const agp_bridge_driver u3_agp_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = (void *)u3_sizes,
        .size_type              = U32_APER_SIZE,
index 2e7c043..a2bb4ec 100644 (file)
@@ -89,7 +89,7 @@ static void via_tlbflush(struct agp_memory *mem)
 }
 
 
-static struct aper_size_info_8 via_generic_sizes[9] =
+static const struct aper_size_info_8 via_generic_sizes[9] =
 {
        {256, 65536, 6, 0},
        {128, 32768, 5, 128},
@@ -170,7 +170,7 @@ static void via_tlbflush_agp3(struct agp_memory *mem)
 }
 
 
-static struct agp_bridge_driver via_agp3_driver = {
+static const struct agp_bridge_driver via_agp3_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = agp3_generic_sizes,
        .size_type              = U8_APER_SIZE,
@@ -194,7 +194,7 @@ static struct agp_bridge_driver via_agp3_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static struct agp_bridge_driver via_driver = {
+static const struct agp_bridge_driver via_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = via_generic_sizes,
        .size_type              = U8_APER_SIZE,
index cc2cd46..a0a88aa 100644 (file)
@@ -316,7 +316,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
 {
        struct hvc_struct *hp;
        unsigned long flags;
-       int irq = NO_IRQ;
+       int irq = 0;
        int rc = 0;
        struct kobject *kobjp;
 
@@ -338,14 +338,14 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
        hp->tty = tty;
        /* Save for request_irq outside of spin_lock. */
        irq = hp->irq;
-       if (irq != NO_IRQ)
+       if (irq)
                hp->irq_requested = 1;
 
        kobjp = &hp->kobj;
 
        spin_unlock_irqrestore(&hp->lock, flags);
        /* check error, fallback to non-irq */
-       if (irq != NO_IRQ)
+       if (irq)
                rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED, "hvc_console", hp);
 
        /*
@@ -373,7 +373,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
 {
        struct hvc_struct *hp;
        struct kobject *kobjp;
-       int irq = NO_IRQ;
+       int irq = 0;
        unsigned long flags;
 
        if (tty_hung_up_p(filp))
@@ -407,7 +407,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
                 */
                tty_wait_until_sent(tty, HVC_CLOSE_WAIT);
 
-               if (irq != NO_IRQ)
+               if (irq)
                        free_irq(irq, hp);
 
        } else {
@@ -424,7 +424,7 @@ static void hvc_hangup(struct tty_struct *tty)
 {
        struct hvc_struct *hp = tty->driver_data;
        unsigned long flags;
-       int irq = NO_IRQ;
+       int irq = 0;
        int temp_open_count;
        struct kobject *kobjp;
 
@@ -453,7 +453,7 @@ static void hvc_hangup(struct tty_struct *tty)
                irq = hp->irq;
        hp->irq_requested = 0;
        spin_unlock_irqrestore(&hp->lock, flags);
-       if (irq != NO_IRQ)
+       if (irq)
                free_irq(irq, hp);
        while(temp_open_count) {
                --temp_open_count;
@@ -583,7 +583,7 @@ static int hvc_poll(struct hvc_struct *hp)
        /* If we aren't interrupt driven and aren't throttled, we always
         * request a reschedule
         */
-       if (hp->irq == NO_IRQ)
+       if (hp->irq == 0)
                poll_mask |= HVC_POLL_READ;
 
        /* Read data if any */
index f86fa0c..e46120d 100644 (file)
@@ -80,7 +80,7 @@ static int i2RetryFlushOutput(i2ChanStrPtr);
 // Not a documented part of the library routines (careful...) but the Diagnostic
 // i2diag.c finds them useful to help the throughput in certain limited
 // single-threaded operations.
-static inline void iiSendPendingMail(i2eBordStrPtr);
+static void iiSendPendingMail(i2eBordStrPtr);
 static void serviceOutgoingFifo(i2eBordStrPtr);
 
 // Functions defined in ip2.c as part of interrupt handling
@@ -166,7 +166,7 @@ static void iiSendPendingMail_t(unsigned long data)
 // If any outgoing mail bits are set and there is outgoing mailbox is empty,
 // send the mail and clear the bits.
 //******************************************************************************
-static inline void
+static void
 iiSendPendingMail(i2eBordStrPtr pB)
 {
        if (pB->i2eOutMailWaiting && (!pB->i2eWaitingForEmptyFifo) )
index 4e4865e..492dbfb 100644 (file)
@@ -63,8 +63,6 @@
 #include "3780i.h"
 
 static DEFINE_SPINLOCK(dsp_lock);
-static unsigned long flags;
-
 
 static void PaceMsaAccess(unsigned short usDspBaseIO)
 {
@@ -76,6 +74,7 @@ static void PaceMsaAccess(unsigned short usDspBaseIO)
 unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO,
                                    unsigned long ulMsaAddr)
 {
+       unsigned long flags;
        unsigned short val;
 
        PRINTK_3(TRACE_3780I,
@@ -96,6 +95,7 @@ unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO,
 void dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO,
                           unsigned long ulMsaAddr, unsigned short usValue)
 {
+       unsigned long flags;
 
        PRINTK_4(TRACE_3780I,
                "3780i::dsp3780i_WriteMsaCfg entry usDspBaseIO %x ulMsaAddr %lx usValue %x\n",
@@ -175,6 +175,7 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
                        unsigned short *pIrqMap,
                        unsigned short *pDmaMap)
 {
+       unsigned long flags;
        unsigned short usDspBaseIO = pSettings->usDspBaseIO;
        int i;
        DSP_UART_CFG_1 rUartCfg1;
@@ -354,6 +355,7 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
 
 int dsp3780I_DisableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings)
 {
+       unsigned long flags;
        unsigned short usDspBaseIO = pSettings->usDspBaseIO;
        DSP_ISA_SLAVE_CONTROL rSlaveControl;
 
@@ -383,6 +385,7 @@ int dsp3780I_DisableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings)
 
 int dsp3780I_Reset(DSP_3780I_CONFIG_SETTINGS * pSettings)
 {
+       unsigned long flags;
        unsigned short usDspBaseIO = pSettings->usDspBaseIO;
        DSP_BOOT_DOMAIN rBootDomain;
        DSP_HBRIDGE_CONTROL rHBridgeControl;
@@ -427,6 +430,7 @@ int dsp3780I_Reset(DSP_3780I_CONFIG_SETTINGS * pSettings)
 
 int dsp3780I_Run(DSP_3780I_CONFIG_SETTINGS * pSettings)
 {
+       unsigned long flags;
        unsigned short usDspBaseIO = pSettings->usDspBaseIO;
        DSP_BOOT_DOMAIN rBootDomain;
        DSP_HBRIDGE_CONTROL rHBridgeControl;
@@ -473,6 +477,7 @@ int dsp3780I_Run(DSP_3780I_CONFIG_SETTINGS * pSettings)
 int dsp3780I_ReadDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
                         unsigned uCount, unsigned long ulDSPAddr)
 {
+       unsigned long flags;
        unsigned short __user *pusBuffer = pvBuffer;
        unsigned short val;
 
@@ -514,6 +519,7 @@ int dsp3780I_ReadAndClearDStore(unsigned short usDspBaseIO,
                                 void __user *pvBuffer, unsigned uCount,
                                 unsigned long ulDSPAddr)
 {
+       unsigned long flags;
        unsigned short __user *pusBuffer = pvBuffer;
        unsigned short val;
 
@@ -555,6 +561,7 @@ int dsp3780I_ReadAndClearDStore(unsigned short usDspBaseIO,
 int dsp3780I_WriteDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
                          unsigned uCount, unsigned long ulDSPAddr)
 {
+       unsigned long flags;
        unsigned short __user *pusBuffer = pvBuffer;
 
 
@@ -596,6 +603,7 @@ int dsp3780I_WriteDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
 int dsp3780I_ReadIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
                         unsigned uCount, unsigned long ulDSPAddr)
 {
+       unsigned long flags;
        unsigned short __user *pusBuffer = pvBuffer;
 
        PRINTK_5(TRACE_3780I,
@@ -643,6 +651,7 @@ int dsp3780I_ReadIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
 int dsp3780I_WriteIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
                          unsigned uCount, unsigned long ulDSPAddr)
 {
+       unsigned long flags;
        unsigned short __user *pusBuffer = pvBuffer;
 
        PRINTK_5(TRACE_3780I,
@@ -691,6 +700,7 @@ int dsp3780I_WriteIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
 int dsp3780I_GetIPCSource(unsigned short usDspBaseIO,
                           unsigned short *pusIPCSource)
 {
+       unsigned long flags;
        DSP_HBRIDGE_CONTROL rHBridgeControl;
        unsigned short temp;
 
index df46728..f24c26d 100644 (file)
@@ -1533,7 +1533,7 @@ void disassociate_ctty(int on_exit)
 
        spin_lock_irq(&current->sighand->siglock);
        tty_pgrp = current->signal->tty_old_pgrp;
-       current->signal->tty_old_pgrp = 0;
+       current->signal->tty_old_pgrp = NULL;
        spin_unlock_irq(&current->sighand->siglock);
        put_pid(tty_pgrp);
 
index d446998..842cd0b 100644 (file)
@@ -88,7 +88,6 @@ struct cm_port {
 struct cm_device {
        struct list_head list;
        struct ib_device *device;
-       __be64 ca_guid;
        struct cm_port port[0];
 };
 
@@ -739,8 +738,8 @@ retest:
                ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
                ib_send_cm_rej(cm_id, IB_CM_REJ_TIMEOUT,
-                              &cm_id_priv->av.port->cm_dev->ca_guid,
-                              sizeof cm_id_priv->av.port->cm_dev->ca_guid,
+                              &cm_id_priv->id.device->node_guid,
+                              sizeof cm_id_priv->id.device->node_guid,
                               NULL, 0);
                break;
        case IB_CM_REQ_RCVD:
@@ -883,7 +882,7 @@ static void cm_format_req(struct cm_req_msg *req_msg,
 
        req_msg->local_comm_id = cm_id_priv->id.local_id;
        req_msg->service_id = param->service_id;
-       req_msg->local_ca_guid = cm_id_priv->av.port->cm_dev->ca_guid;
+       req_msg->local_ca_guid = cm_id_priv->id.device->node_guid;
        cm_req_set_local_qpn(req_msg, cpu_to_be32(param->qp_num));
        cm_req_set_resp_res(req_msg, param->responder_resources);
        cm_req_set_init_depth(req_msg, param->initiator_depth);
@@ -1442,7 +1441,7 @@ static void cm_format_rep(struct cm_rep_msg *rep_msg,
        cm_rep_set_flow_ctrl(rep_msg, param->flow_control);
        cm_rep_set_rnr_retry_count(rep_msg, param->rnr_retry_count);
        cm_rep_set_srq(rep_msg, param->srq);
-       rep_msg->local_ca_guid = cm_id_priv->av.port->cm_dev->ca_guid;
+       rep_msg->local_ca_guid = cm_id_priv->id.device->node_guid;
 
        if (param->private_data && param->private_data_len)
                memcpy(rep_msg->private_data, param->private_data,
@@ -3385,7 +3384,6 @@ static void cm_add_one(struct ib_device *device)
                return;
 
        cm_dev->device = device;
-       cm_dev->ca_guid = device->node_guid;
 
        set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask);
        for (i = 1; i <= device->phys_port_cnt; i++) {
index f8d69b3..d441815 100644 (file)
@@ -77,7 +77,6 @@ static int next_port;
 struct cma_device {
        struct list_head        list;
        struct ib_device        *device;
-       __be64                  node_guid;
        struct completion       comp;
        atomic_t                refcount;
        struct list_head        id_list;
@@ -1492,11 +1491,13 @@ static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms,
        ib_addr_get_dgid(addr, &path_rec.dgid);
        path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(addr));
        path_rec.numb_path = 1;
+       path_rec.reversible = 1;
 
        id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device,
                                id_priv->id.port_num, &path_rec,
                                IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID |
-                               IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH,
+                               IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH |
+                               IB_SA_PATH_REC_REVERSIBLE,
                                timeout_ms, GFP_KERNEL,
                                cma_query_handler, work, &id_priv->query);
 
@@ -2672,7 +2673,6 @@ static void cma_add_one(struct ib_device *device)
                return;
 
        cma_dev->device = device;
-       cma_dev->node_guid = device->node_guid;
 
        init_completion(&cma_dev->comp);
        atomic_set(&cma_dev->refcount, 1);
index df1efbc..4fd75af 100644 (file)
@@ -622,8 +622,10 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
        obj->umem.virt_base = cmd.hca_va;
 
        pd = idr_read_pd(cmd.pd_handle, file->ucontext);
-       if (!pd)
+       if (!pd) {
+               ret = -EINVAL;
                goto err_release;
+       }
 
        mr = pd->device->reg_user_mr(pd, &obj->umem, cmd.access_flags, &udata);
        if (IS_ERR(mr)) {
index 8b5dd36..ccdf93d 100644 (file)
@@ -167,7 +167,7 @@ int ib_init_ah_from_wc(struct ib_device *device, u8 port_num, struct ib_wc *wc,
                ah_attr->grh.sgid_index = (u8) gid_index;
                flow_class = be32_to_cpu(grh->version_tclass_flow);
                ah_attr->grh.flow_label = flow_class & 0xFFFFF;
-               ah_attr->grh.hop_limit = grh->hop_limit;
+               ah_attr->grh.hop_limit = 0xFF;
                ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF;
        }
        return 0;
index 0e110f3..36b9898 100644 (file)
@@ -8,5 +8,4 @@ iw_cxgb3-y :=  iwch_cm.o iwch_ev.o iwch_cq.o iwch_qp.o iwch_mem.o \
 
 ifdef CONFIG_INFINIBAND_CXGB3_DEBUG
 EXTRA_CFLAGS += -DDEBUG
-iw_cxgb3-y += cxio_dbg.o
 endif
index 114ac3b..d737c73 100644 (file)
@@ -45,7 +45,7 @@
 static LIST_HEAD(rdev_list);
 static cxio_hal_ev_callback_func_t cxio_ev_cb = NULL;
 
-static inline struct cxio_rdev *cxio_hal_find_rdev_by_name(char *dev_name)
+static struct cxio_rdev *cxio_hal_find_rdev_by_name(char *dev_name)
 {
        struct cxio_rdev *rdev;
 
@@ -55,8 +55,7 @@ static inline struct cxio_rdev *cxio_hal_find_rdev_by_name(char *dev_name)
        return NULL;
 }
 
-static inline struct cxio_rdev *cxio_hal_find_rdev_by_t3cdev(struct t3cdev
-                                                            *tdev)
+static struct cxio_rdev *cxio_hal_find_rdev_by_t3cdev(struct t3cdev *tdev)
 {
        struct cxio_rdev *rdev;
 
@@ -118,7 +117,7 @@ int cxio_hal_cq_op(struct cxio_rdev *rdev_p, struct t3_cq *cq,
        return 0;
 }
 
-static inline int cxio_hal_clear_cq_ctx(struct cxio_rdev *rdev_p, u32 cqid)
+static int cxio_hal_clear_cq_ctx(struct cxio_rdev *rdev_p, u32 cqid)
 {
        struct rdma_cq_setup setup;
        setup.id = cqid;
@@ -130,7 +129,7 @@ static inline int cxio_hal_clear_cq_ctx(struct cxio_rdev *rdev_p, u32 cqid)
        return (rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_CQ_SETUP, &setup));
 }
 
-int cxio_hal_clear_qp_ctx(struct cxio_rdev *rdev_p, u32 qpid)
+static int cxio_hal_clear_qp_ctx(struct cxio_rdev *rdev_p, u32 qpid)
 {
        u64 sge_cmd;
        struct t3_modify_qp_wr *wqe;
@@ -425,7 +424,7 @@ void cxio_flush_hw_cq(struct t3_cq *cq)
        }
 }
 
-static inline int cqe_completes_wr(struct t3_cqe *cqe, struct t3_wq *wq)
+static int cqe_completes_wr(struct t3_cqe *cqe, struct t3_wq *wq)
 {
        if (CQE_OPCODE(*cqe) == T3_TERMINATE)
                return 0;
@@ -760,17 +759,6 @@ ret:
        return err;
 }
 
-/* IN : stag key, pdid, pbl_size
- * Out: stag index, actaul pbl_size, and pbl_addr allocated.
- */
-int cxio_allocate_stag(struct cxio_rdev *rdev_p, u32 * stag, u32 pdid,
-                      enum tpt_mem_perm perm, u32 * pbl_size, u32 * pbl_addr)
-{
-       *stag = T3_STAG_UNSET;
-       return (__cxio_tpt_op(rdev_p, 0, stag, 0, pdid, TPT_NON_SHARED_MR,
-                             perm, 0, 0ULL, 0, 0, NULL, pbl_size, pbl_addr));
-}
-
 int cxio_register_phys_mem(struct cxio_rdev *rdev_p, u32 *stag, u32 pdid,
                           enum tpt_mem_perm perm, u32 zbva, u64 to, u32 len,
                           u8 page_size, __be64 *pbl, u32 *pbl_size,
@@ -1029,7 +1017,7 @@ void __exit cxio_hal_exit(void)
        cxio_hal_destroy_rhdl_resource();
 }
 
-static inline void flush_completed_wrs(struct t3_wq *wq, struct t3_cq *cq)
+static void flush_completed_wrs(struct t3_wq *wq, struct t3_cq *cq)
 {
        struct t3_swsq *sqp;
        __u32 ptr = wq->sq_rptr;
@@ -1058,9 +1046,8 @@ static inline void flush_completed_wrs(struct t3_wq *wq, struct t3_cq *cq)
                        break;
 }
 
-static inline void create_read_req_cqe(struct t3_wq *wq,
-                                      struct t3_cqe *hw_cqe,
-                                      struct t3_cqe *read_cqe)
+static void create_read_req_cqe(struct t3_wq *wq, struct t3_cqe *hw_cqe,
+                               struct t3_cqe *read_cqe)
 {
        read_cqe->u.scqe.wrid_hi = wq->oldest_read->sq_wptr;
        read_cqe->len = wq->oldest_read->read_len;
@@ -1073,7 +1060,7 @@ static inline void create_read_req_cqe(struct t3_wq *wq,
 /*
  * Return a ptr to the next read wr in the SWSQ or NULL.
  */
-static inline void advance_oldest_read(struct t3_wq *wq)
+static void advance_oldest_read(struct t3_wq *wq)
 {
 
        u32 rptr = wq->oldest_read - wq->sq + 1;
index 8ab04a7..99543d6 100644 (file)
@@ -143,7 +143,6 @@ int cxio_rdev_open(struct cxio_rdev *rdev);
 void cxio_rdev_close(struct cxio_rdev *rdev);
 int cxio_hal_cq_op(struct cxio_rdev *rdev, struct t3_cq *cq,
                   enum t3_cq_opcode op, u32 credit);
-int cxio_hal_clear_qp_ctx(struct cxio_rdev *rdev, u32 qpid);
 int cxio_create_cq(struct cxio_rdev *rdev, struct t3_cq *cq);
 int cxio_destroy_cq(struct cxio_rdev *rdev, struct t3_cq *cq);
 int cxio_resize_cq(struct cxio_rdev *rdev, struct t3_cq *cq);
@@ -154,8 +153,6 @@ int cxio_create_qp(struct cxio_rdev *rdev, u32 kernel_domain, struct t3_wq *wq,
 int cxio_destroy_qp(struct cxio_rdev *rdev, struct t3_wq *wq,
                    struct cxio_ucontext *uctx);
 int cxio_peek_cq(struct t3_wq *wr, struct t3_cq *cq, int opcode);
-int cxio_allocate_stag(struct cxio_rdev *rdev, u32 * stag, u32 pdid,
-                      enum tpt_mem_perm perm, u32 * pbl_size, u32 * pbl_addr);
 int cxio_register_phys_mem(struct cxio_rdev *rdev, u32 * stag, u32 pdid,
                           enum tpt_mem_perm perm, u32 zbva, u64 to, u32 len,
                           u8 page_size, __be64 *pbl, u32 *pbl_size,
@@ -171,8 +168,6 @@ int cxio_deallocate_window(struct cxio_rdev *rdev, u32 stag);
 int cxio_rdma_init(struct cxio_rdev *rdev, struct t3_rdma_init_attr *attr);
 void cxio_register_ev_cb(cxio_hal_ev_callback_func_t ev_cb);
 void cxio_unregister_ev_cb(cxio_hal_ev_callback_func_t ev_cb);
-u32 cxio_hal_get_rhdl(void);
-void cxio_hal_put_rhdl(u32 rhdl);
 u32 cxio_hal_get_pdid(struct cxio_hal_resource *rscp);
 void cxio_hal_put_pdid(struct cxio_hal_resource *rscp, u32 pdid);
 int __init cxio_hal_init(void);
index 65bf577..d3095ae 100644 (file)
@@ -179,7 +179,7 @@ tpt_err:
 /*
  * returns 0 if no resource available
  */
-static inline u32 cxio_hal_get_resource(struct kfifo *fifo)
+static u32 cxio_hal_get_resource(struct kfifo *fifo)
 {
        u32 entry;
        if (kfifo_get(fifo, (unsigned char *) &entry, sizeof(u32)))
@@ -188,21 +188,11 @@ static inline u32 cxio_hal_get_resource(struct kfifo *fifo)
                return 0;       /* fifo emptry */
 }
 
-static inline void cxio_hal_put_resource(struct kfifo *fifo, u32 entry)
+static void cxio_hal_put_resource(struct kfifo *fifo, u32 entry)
 {
        BUG_ON(kfifo_put(fifo, (unsigned char *) &entry, sizeof(u32)) == 0);
 }
 
-u32 cxio_hal_get_rhdl(void)
-{
-       return cxio_hal_get_resource(rhdl_fifo);
-}
-
-void cxio_hal_put_rhdl(u32 rhdl)
-{
-       cxio_hal_put_resource(rhdl_fifo, rhdl);
-}
-
 u32 cxio_hal_get_stag(struct cxio_hal_resource *rscp)
 {
        return cxio_hal_get_resource(rscp->tpt_fifo);
index e5442e3..b21fde8 100644 (file)
@@ -209,8 +209,7 @@ static enum iwch_ep_state state_read(struct iwch_ep_common *epc)
        return state;
 }
 
-static inline void __state_set(struct iwch_ep_common *epc,
-                              enum iwch_ep_state new)
+static void __state_set(struct iwch_ep_common *epc, enum iwch_ep_state new)
 {
        epc->state = new;
 }
@@ -1459,7 +1458,7 @@ static int peer_close(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
 /*
  * Returns whether an ABORT_REQ_RSS message is a negative advice.
  */
-static inline int is_neg_adv_abort(unsigned int status)
+static int is_neg_adv_abort(unsigned int status)
 {
        return status == CPL_ERR_RTX_NEG_ADVICE ||
               status == CPL_ERR_PERSIST_NEG_ADVICE;
@@ -1635,6 +1634,7 @@ static int ec_status(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
 
                printk(KERN_ERR MOD "%s BAD CLOSE - Aborting tid %u\n",
                       __FUNCTION__, ep->hwtid);
+               stop_ep_timer(ep);
                attrs.next_state = IWCH_QP_STATE_ERROR;
                iwch_modify_qp(ep->com.qp->rhp,
                               ep->com.qp, IWCH_QP_ATTR_NEXT_STATE,
index 2aef122..9947a14 100644 (file)
@@ -948,7 +948,7 @@ void iwch_qp_rem_ref(struct ib_qp *qp)
                wake_up(&(to_iwch_qp(qp)->wait));
 }
 
-struct ib_qp *iwch_get_qp(struct ib_device *dev, int qpn)
+static struct ib_qp *iwch_get_qp(struct ib_device *dev, int qpn)
 {
        PDBG("%s ib_dev %p qpn 0x%x\n", __FUNCTION__, dev, qpn);
        return (struct ib_qp *)get_qhp(to_iwch_dev(dev), qpn);
index 2af3e93..de0fe1b 100644 (file)
@@ -178,7 +178,6 @@ static inline struct iwch_qp *to_iwch_qp(struct ib_qp *ibqp)
 
 void iwch_qp_add_ref(struct ib_qp *qp);
 void iwch_qp_rem_ref(struct ib_qp *qp);
-struct ib_qp *iwch_get_qp(struct ib_device *dev, int qpn);
 
 struct iwch_ucontext {
        struct ib_ucontext ibucontext;
index 4dda2f6..9ea00cc 100644 (file)
@@ -36,8 +36,8 @@
 
 #define NO_SUPPORT -1
 
-static inline int iwch_build_rdma_send(union t3_wr *wqe, struct ib_send_wr *wr,
-                                      u8 * flit_cnt)
+static int iwch_build_rdma_send(union t3_wr *wqe, struct ib_send_wr *wr,
+                               u8 * flit_cnt)
 {
        int i;
        u32 plen;
@@ -96,8 +96,8 @@ static inline int iwch_build_rdma_send(union t3_wr *wqe, struct ib_send_wr *wr,
        return 0;
 }
 
-static inline int iwch_build_rdma_write(union t3_wr *wqe, struct ib_send_wr *wr,
-                                       u8 *flit_cnt)
+static int iwch_build_rdma_write(union t3_wr *wqe, struct ib_send_wr *wr,
+                                u8 *flit_cnt)
 {
        int i;
        u32 plen;
@@ -137,8 +137,8 @@ static inline int iwch_build_rdma_write(union t3_wr *wqe, struct ib_send_wr *wr,
        return 0;
 }
 
-static inline int iwch_build_rdma_read(union t3_wr *wqe, struct ib_send_wr *wr,
-                                      u8 *flit_cnt)
+static int iwch_build_rdma_read(union t3_wr *wqe, struct ib_send_wr *wr,
+                               u8 *flit_cnt)
 {
        if (wr->num_sge > 1)
                return -EINVAL;
@@ -158,9 +158,8 @@ static inline int iwch_build_rdma_read(union t3_wr *wqe, struct ib_send_wr *wr,
 /*
  * TBD: this is going to be moved to firmware. Missing pdid/qpid check for now.
  */
-static inline int iwch_sgl2pbl_map(struct iwch_dev *rhp,
-                                  struct ib_sge *sg_list, u32 num_sgle,
-                                  u32 * pbl_addr, u8 * page_size)
+static int iwch_sgl2pbl_map(struct iwch_dev *rhp, struct ib_sge *sg_list,
+                           u32 num_sgle, u32 * pbl_addr, u8 * page_size)
 {
        int i;
        struct iwch_mr *mhp;
@@ -206,9 +205,8 @@ static inline int iwch_sgl2pbl_map(struct iwch_dev *rhp,
        return 0;
 }
 
-static inline int iwch_build_rdma_recv(struct iwch_dev *rhp,
-                                                   union t3_wr *wqe,
-                                                   struct ib_recv_wr *wr)
+static int iwch_build_rdma_recv(struct iwch_dev *rhp, union t3_wr *wqe,
+                               struct ib_recv_wr *wr)
 {
        int i, err = 0;
        u32 pbl_addr[4];
@@ -473,8 +471,7 @@ int iwch_bind_mw(struct ib_qp *qp,
        return err;
 }
 
-static inline void build_term_codes(int t3err, u8 *layer_type, u8 *ecode,
-                                   int tagged)
+static void build_term_codes(int t3err, u8 *layer_type, u8 *ecode, int tagged)
 {
        switch (t3err) {
        case TPT_ERR_STAG:
@@ -672,7 +669,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
        spin_lock_irqsave(&qhp->lock, *flag);
 }
 
-static inline void flush_qp(struct iwch_qp *qhp, unsigned long *flag)
+static void flush_qp(struct iwch_qp *qhp, unsigned long *flag)
 {
        if (t3b_device(qhp->rhp))
                cxio_set_wq_in_error(&qhp->wq);
@@ -684,7 +681,7 @@ static inline void flush_qp(struct iwch_qp *qhp, unsigned long *flag)
 /*
  * Return non zero if at least one RECV was pre-posted.
  */
-static inline int rqes_posted(struct iwch_qp *qhp)
+static int rqes_posted(struct iwch_qp *qhp)
 {
        return fw_riwrh_opcode((struct fw_riwrh *)qhp->wq.queue) == T3_WR_RCV;
 }
index 6037dd3..8e4846b 100644 (file)
@@ -310,8 +310,9 @@ int mthca_write_mtt_size(struct mthca_dev *dev)
        return mthca_is_memfree(dev) ? (PAGE_SIZE / sizeof (u64)) : 0x7ffffff;
 }
 
-void mthca_tavor_write_mtt_seg(struct mthca_dev *dev, struct mthca_mtt *mtt,
-                             int start_index, u64 *buffer_list, int list_len)
+static void mthca_tavor_write_mtt_seg(struct mthca_dev *dev,
+                                     struct mthca_mtt *mtt, int start_index,
+                                     u64 *buffer_list, int list_len)
 {
        u64 __iomem *mtts;
        int i;
@@ -323,8 +324,9 @@ void mthca_tavor_write_mtt_seg(struct mthca_dev *dev, struct mthca_mtt *mtt,
                                  mtts + i);
 }
 
-void mthca_arbel_write_mtt_seg(struct mthca_dev *dev, struct mthca_mtt *mtt,
-                             int start_index, u64 *buffer_list, int list_len)
+static void mthca_arbel_write_mtt_seg(struct mthca_dev *dev,
+                                     struct mthca_mtt *mtt, int start_index,
+                                     u64 *buffer_list, int list_len)
 {
        __be64 *mtts;
        dma_addr_t dma_handle;
index 2594db2..fd55826 100644 (file)
@@ -219,7 +219,6 @@ struct ipoib_dev_priv {
 
        union ib_gid local_gid;
        u16          local_lid;
-       u8           local_rate;
 
        unsigned int admin_mtu;
        unsigned int mcast_mtu;
index 4d59682..3484e8b 100644 (file)
@@ -65,14 +65,14 @@ struct ipoib_cm_id {
 static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id,
                               struct ib_cm_event *event);
 
-static void ipoib_cm_dma_unmap_rx(struct ipoib_dev_priv *priv,
+static void ipoib_cm_dma_unmap_rx(struct ipoib_dev_priv *priv, int frags,
                                  u64 mapping[IPOIB_CM_RX_SG])
 {
        int i;
 
        ib_dma_unmap_single(priv->ca, mapping[0], IPOIB_CM_HEAD_SIZE, DMA_FROM_DEVICE);
 
-       for (i = 0; i < IPOIB_CM_RX_SG - 1; ++i)
+       for (i = 0; i < frags; ++i)
                ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE);
 }
 
@@ -90,7 +90,8 @@ static int ipoib_cm_post_receive(struct net_device *dev, int id)
        ret = ib_post_srq_recv(priv->cm.srq, &priv->cm.rx_wr, &bad_wr);
        if (unlikely(ret)) {
                ipoib_warn(priv, "post srq failed for buf %d (%d)\n", id, ret);
-               ipoib_cm_dma_unmap_rx(priv, priv->cm.srq_ring[id].mapping);
+               ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
+                                     priv->cm.srq_ring[id].mapping);
                dev_kfree_skb_any(priv->cm.srq_ring[id].skb);
                priv->cm.srq_ring[id].skb = NULL;
        }
@@ -98,8 +99,8 @@ static int ipoib_cm_post_receive(struct net_device *dev, int id)
        return ret;
 }
 
-static int ipoib_cm_alloc_rx_skb(struct net_device *dev, int id,
-                                u64 mapping[IPOIB_CM_RX_SG])
+static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, int frags,
+                                            u64 mapping[IPOIB_CM_RX_SG])
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct sk_buff *skb;
@@ -107,7 +108,7 @@ static int ipoib_cm_alloc_rx_skb(struct net_device *dev, int id,
 
        skb = dev_alloc_skb(IPOIB_CM_HEAD_SIZE + 12);
        if (unlikely(!skb))
-               return -ENOMEM;
+               return NULL;
 
        /*
         * IPoIB adds a 4 byte header. So we need 12 more bytes to align the
@@ -119,10 +120,10 @@ static int ipoib_cm_alloc_rx_skb(struct net_device *dev, int id,
                                       DMA_FROM_DEVICE);
        if (unlikely(ib_dma_mapping_error(priv->ca, mapping[0]))) {
                dev_kfree_skb_any(skb);
-               return -EIO;
+               return NULL;
        }
 
-       for (i = 0; i < IPOIB_CM_RX_SG - 1; i++) {
+       for (i = 0; i < frags; i++) {
                struct page *page = alloc_page(GFP_ATOMIC);
 
                if (!page)
@@ -136,7 +137,7 @@ static int ipoib_cm_alloc_rx_skb(struct net_device *dev, int id,
        }
 
        priv->cm.srq_ring[id].skb = skb;
-       return 0;
+       return skb;
 
 partial_error:
 
@@ -146,7 +147,7 @@ partial_error:
                ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE);
 
        dev_kfree_skb_any(skb);
-       return -ENOMEM;
+       return NULL;
 }
 
 static struct ib_qp *ipoib_cm_create_rx_qp(struct net_device *dev,
@@ -309,7 +310,7 @@ static int ipoib_cm_rx_handler(struct ib_cm_id *cm_id,
 }
 /* Adjust length of skb with fragments to match received data */
 static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space,
-                         unsigned int length)
+                         unsigned int length, struct sk_buff *toskb)
 {
        int i, num_frags;
        unsigned int size;
@@ -326,7 +327,7 @@ static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space,
 
                if (length == 0) {
                        /* don't need this page */
-                       __free_page(frag->page);
+                       skb_fill_page_desc(toskb, i, frag->page, 0, PAGE_SIZE);
                        --skb_shinfo(skb)->nr_frags;
                } else {
                        size = min(length, (unsigned) PAGE_SIZE);
@@ -344,10 +345,11 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        unsigned int wr_id = wc->wr_id & ~IPOIB_CM_OP_SRQ;
-       struct sk_buff *skb;
+       struct sk_buff *skb, *newskb;
        struct ipoib_cm_rx *p;
        unsigned long flags;
        u64 mapping[IPOIB_CM_RX_SG];
+       int frags;
 
        ipoib_dbg_data(priv, "cm recv completion: id %d, op %d, status: %d\n",
                       wr_id, wc->opcode, wc->status);
@@ -383,7 +385,11 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
                }
        }
 
-       if (unlikely(ipoib_cm_alloc_rx_skb(dev, wr_id, mapping))) {
+       frags = PAGE_ALIGN(wc->byte_len - min(wc->byte_len,
+                                             (unsigned)IPOIB_CM_HEAD_SIZE)) / PAGE_SIZE;
+
+       newskb = ipoib_cm_alloc_rx_skb(dev, wr_id, frags, mapping);
+       if (unlikely(!newskb)) {
                /*
                 * If we can't allocate a new RX buffer, dump
                 * this packet and reuse the old buffer.
@@ -393,13 +399,13 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
                goto repost;
        }
 
-       ipoib_cm_dma_unmap_rx(priv, priv->cm.srq_ring[wr_id].mapping);
-       memcpy(priv->cm.srq_ring[wr_id].mapping, mapping, sizeof mapping);
+       ipoib_cm_dma_unmap_rx(priv, frags, priv->cm.srq_ring[wr_id].mapping);
+       memcpy(priv->cm.srq_ring[wr_id].mapping, mapping, (frags + 1) * sizeof *mapping);
 
        ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n",
                       wc->byte_len, wc->slid);
 
-       skb_put_frags(skb, IPOIB_CM_HEAD_SIZE, wc->byte_len);
+       skb_put_frags(skb, IPOIB_CM_HEAD_SIZE, wc->byte_len, newskb);
 
        skb->protocol = ((struct ipoib_header *) skb->data)->proto;
        skb->mac.raw = skb->data;
@@ -1193,7 +1199,8 @@ int ipoib_cm_dev_init(struct net_device *dev)
        priv->cm.rx_wr.num_sge = IPOIB_CM_RX_SG;
 
        for (i = 0; i < ipoib_recvq_size; ++i) {
-               if (ipoib_cm_alloc_rx_skb(dev, i, priv->cm.srq_ring[i].mapping)) {
+               if (!ipoib_cm_alloc_rx_skb(dev, i, IPOIB_CM_RX_SG - 1,
+                                          priv->cm.srq_ring[i].mapping)) {
                        ipoib_warn(priv, "failed to allocate receive buffer %d\n", i);
                        ipoib_cm_dev_cleanup(dev);
                        return -ENOMEM;
@@ -1228,7 +1235,8 @@ void ipoib_cm_dev_cleanup(struct net_device *dev)
                return;
        for (i = 0; i < ipoib_recvq_size; ++i)
                if (priv->cm.srq_ring[i].skb) {
-                       ipoib_cm_dma_unmap_rx(priv, priv->cm.srq_ring[i].mapping);
+                       ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
+                                             priv->cm.srq_ring[i].mapping);
                        dev_kfree_skb_any(priv->cm.srq_ring[i].skb);
                        priv->cm.srq_ring[i].skb = NULL;
                }
index 18d27fd..f9dbc6f 100644 (file)
@@ -385,7 +385,7 @@ static void path_rec_completion(int status,
        struct sk_buff *skb;
        unsigned long flags;
 
-       if (pathrec)
+       if (!status)
                ipoib_dbg(priv, "PathRec LID 0x%04x for GID " IPOIB_GID_FMT "\n",
                          be16_to_cpu(pathrec->dlid), IPOIB_GID_ARG(pathrec->dgid));
        else
index b303ce6..bb2e3d5 100644 (file)
@@ -527,11 +527,9 @@ void ipoib_mcast_join_task(struct work_struct *work)
        {
                struct ib_port_attr attr;
 
-               if (!ib_query_port(priv->ca, priv->port, &attr)) {
-                       priv->local_lid  = attr.lid;
-                       priv->local_rate = attr.active_speed *
-                               ib_width_enum_to_int(attr.active_width);
-               } else
+               if (!ib_query_port(priv->ca, priv->port, &attr))
+                       priv->local_lid = attr.lid;
+               else
                        ipoib_warn(priv, "ib_query_port failed\n");
        }
 
index 077e297..5158be0 100644 (file)
@@ -1,7 +1,7 @@
-gigaset-y := common.o interface.o proc.o ev-layer.o i4l.o
-usb_gigaset-y := usb-gigaset.o asyncdata.o
+gigaset-y := common.o interface.o proc.o ev-layer.o i4l.o asyncdata.o
+usb_gigaset-y := usb-gigaset.o
 bas_gigaset-y := bas-gigaset.o isocdata.o
-ser_gigaset-y := ser-gigaset.o asyncdata.o
+ser_gigaset-y := ser-gigaset.o
 
 obj-$(CONFIG_GIGASET_M105) += usb_gigaset.o gigaset.o
 obj-$(CONFIG_GIGASET_BASE) += bas_gigaset.o gigaset.o
index ddf5e92..f2f108f 100644 (file)
@@ -444,6 +444,7 @@ nextbyte:
                atomic_set(&inbuf->head, head);
        }
 }
+EXPORT_SYMBOL_GPL(gigaset_m10x_input);
 
 
 /* == data output ========================================================== */
@@ -591,3 +592,4 @@ int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb)
 
        return len;     /* ok so far */
 }
+EXPORT_SYMBOL_GPL(gigaset_m10x_send_skb);
index 7399ba7..80acd08 100644 (file)
@@ -82,6 +82,18 @@ config LEDS_WRAP
        help
          This option enables support for the PCEngines WRAP programmable LEDs.
 
+config LEDS_H1940
+       tristate "LED Support for iPAQ H1940 device"
+       depends LEDS_CLASS && ARCH_H1940
+       help
+         This option enables support for the LEDs on the h1940.
+
+config LEDS_COBALT
+       tristate "LED Support for Cobalt Server front LED"
+       depends on LEDS_CLASS && MIPS_COBALT
+       help
+         This option enables support for the front LED on Cobalt Server
+
 comment "LED Triggers"
 
 config LEDS_TRIGGERS
index 500de3d..aa2c18e 100644 (file)
@@ -14,6 +14,8 @@ obj-$(CONFIG_LEDS_S3C24XX)            += leds-s3c24xx.o
 obj-$(CONFIG_LEDS_AMS_DELTA)           += leds-ams-delta.o
 obj-$(CONFIG_LEDS_NET48XX)             += leds-net48xx.o
 obj-$(CONFIG_LEDS_WRAP)                        += leds-wrap.o
+obj-$(CONFIG_LEDS_H1940)               += leds-h1940.o
+obj-$(CONFIG_LEDS_COBALT)              += leds-cobalt.o
 
 # LED Triggers
 obj-$(CONFIG_LEDS_TRIGGER_TIMER)       += ledtrig-timer.o
diff --git a/drivers/leds/leds-cobalt.c b/drivers/leds/leds-cobalt.c
new file mode 100644 (file)
index 0000000..d16439c
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2006 - Florian Fainelli <florian@openwrt.org>
+ *
+ * Control the Cobalt Qube/RaQ front LED
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/leds.h>
+#include <asm/mach-cobalt/cobalt.h>
+
+static void cobalt_led_set(struct led_classdev *led_cdev, enum led_brightness brightness)
+{
+       if (brightness)
+               COBALT_LED_PORT = COBALT_LED_BAR_LEFT | COBALT_LED_BAR_RIGHT;
+       else
+               COBALT_LED_PORT = 0;
+}
+
+static struct led_classdev cobalt_led = {
+       .name = "cobalt-front-led",
+       .brightness_set = cobalt_led_set,
+       .default_trigger = "ide-disk",
+};
+
+static int __init cobalt_led_init(void)
+{
+       return led_classdev_register(NULL, &cobalt_led);
+}
+
+static void __exit cobalt_led_exit(void)
+{
+       led_classdev_unregister(&cobalt_led);
+}
+
+module_init(cobalt_led_init);
+module_exit(cobalt_led_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Front LED support for Cobalt Server");
+MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
diff --git a/drivers/leds/leds-h1940.c b/drivers/leds/leds-h1940.c
new file mode 100644 (file)
index 0000000..1d49d2a
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * drivers/leds/h1940-leds.c
+ * Copyright (c) Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ * 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.
+ *
+ * H1940 leds driver
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/leds.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/hardware.h>
+#include <asm/arch/h1940-latch.h>
+
+/*
+ * Green led.
+ */
+void h1940_greenled_set(struct led_classdev *led_dev, enum led_brightness value)
+{
+       switch (value) {
+               case LED_HALF:
+                       h1940_latch_control(0,H1940_LATCH_LED_FLASH);
+                       s3c2410_gpio_setpin(S3C2410_GPA7,1);
+                       break;
+               case LED_FULL:
+                       h1940_latch_control(0,H1940_LATCH_LED_GREEN);
+                       s3c2410_gpio_setpin(S3C2410_GPA7,1);
+                       break;
+               default:
+               case LED_OFF:
+                       h1940_latch_control(H1940_LATCH_LED_FLASH,0);
+                       h1940_latch_control(H1940_LATCH_LED_GREEN,0);
+                       s3c2410_gpio_setpin(S3C2410_GPA7,0);
+                       break;
+       }
+}
+
+static struct led_classdev h1940_greenled = {
+       .name                   = "h1940:green",
+       .brightness_set         = h1940_greenled_set,
+       .default_trigger        = "h1940-charger",
+};
+
+/*
+ * Red led.
+ */
+void h1940_redled_set(struct led_classdev *led_dev, enum led_brightness value)
+{
+       switch (value) {
+               case LED_HALF:
+                       h1940_latch_control(0,H1940_LATCH_LED_FLASH);
+                       s3c2410_gpio_setpin(S3C2410_GPA1,1);
+                       break;
+               case LED_FULL:
+                       h1940_latch_control(0,H1940_LATCH_LED_RED);
+                       s3c2410_gpio_setpin(S3C2410_GPA1,1);
+                       break;
+               default:
+               case LED_OFF:
+                       h1940_latch_control(H1940_LATCH_LED_FLASH,0);
+                       h1940_latch_control(H1940_LATCH_LED_RED,0);
+                       s3c2410_gpio_setpin(S3C2410_GPA1,0);
+                       break;
+       }
+}
+
+static struct led_classdev h1940_redled = {
+       .name                   = "h1940:red",
+       .brightness_set         = h1940_redled_set,
+       .default_trigger        = "h1940-charger",
+};
+
+/*
+ * Blue led.
+ * (it can only be blue flashing led)
+ */
+void h1940_blueled_set(struct led_classdev *led_dev, enum led_brightness value)
+{
+       if (value) {
+               /* flashing Blue */
+               h1940_latch_control(0,H1940_LATCH_LED_FLASH);
+               s3c2410_gpio_setpin(S3C2410_GPA3,1);
+       } else {
+               h1940_latch_control(H1940_LATCH_LED_FLASH,0);
+               s3c2410_gpio_setpin(S3C2410_GPA3,0);
+       }
+
+}
+
+static struct led_classdev h1940_blueled = {
+       .name                   = "h1940:blue",
+       .brightness_set         = h1940_blueled_set,
+       .default_trigger        = "h1940-bluetooth",
+};
+
+static int __init h1940leds_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       ret = led_classdev_register(&pdev->dev, &h1940_greenled);
+       if (ret)
+               goto err_green;
+
+       ret = led_classdev_register(&pdev->dev, &h1940_redled);
+       if (ret)
+               goto err_red;
+
+       ret = led_classdev_register(&pdev->dev, &h1940_blueled);
+       if (ret)
+               goto err_blue;
+
+       return 0;
+
+err_blue:
+       led_classdev_unregister(&h1940_redled);
+err_red:
+       led_classdev_unregister(&h1940_greenled);
+err_green:
+       return ret;
+}
+
+static int h1940leds_remove(struct platform_device *pdev)
+{
+       led_classdev_unregister(&h1940_greenled);
+       led_classdev_unregister(&h1940_redled);
+       led_classdev_unregister(&h1940_blueled);
+       return 0;
+}
+
+
+static struct platform_driver h1940leds_driver = {
+       .driver         = {
+               .name   = "h1940-leds",
+       },
+       .probe          = h1940leds_probe,
+       .remove         = h1940leds_remove,
+};
+
+
+static int __init h1940leds_init(void)
+{
+       return platform_driver_register(&h1940leds_driver);
+}
+
+static void __exit h1940leds_exit(void)
+{
+       platform_driver_unregister(&h1940leds_driver);
+}
+
+module_init(h1940leds_init);
+module_exit(h1940leds_exit);
+
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
+MODULE_DESCRIPTION("LED driver for the iPAQ H1940");
+MODULE_LICENSE("GPL");
index 87410db..91d2579 100644 (file)
@@ -70,6 +70,7 @@ config VIDEO_TUNER
        depends on I2C
 
 config VIDEO_BUF
+       depends on PCI
        tristate
 
 config VIDEO_BUF_DVB
index f33e5d9..c120114 100644 (file)
@@ -5,8 +5,4 @@ config VIDEO_SAA7146
 config VIDEO_SAA7146_VV
        tristate
        select VIDEO_BUF
-       select VIDEO_VIDEOBUF
        select VIDEO_SAA7146
-
-config VIDEO_VIDEOBUF
-       tristate
index 9a8dd87..cbf7c05 100644 (file)
@@ -256,6 +256,112 @@ int ir_decode_biphase(u32 *samples, int count, int low, int high)
        return value;
 }
 
+/* RC5 decoding stuff, moved from bttv-input.c to share it with
+ * saa7134 */
+
+/* decode raw bit pattern to RC5 code */
+u32 ir_rc5_decode(unsigned int code)
+{
+       unsigned int org_code = code;
+       unsigned int pair;
+       unsigned int rc5 = 0;
+       int i;
+
+       for (i = 0; i < 14; ++i) {
+               pair = code & 0x3;
+               code >>= 2;
+
+               rc5 <<= 1;
+               switch (pair) {
+               case 0:
+               case 2:
+                       break;
+               case 1:
+                       rc5 |= 1;
+                       break;
+               case 3:
+                       dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);
+                       return 0;
+               }
+       }
+       dprintk(1, "ir-common: code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
+               "instr=%x\n", rc5, org_code, RC5_START(rc5),
+               RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
+       return rc5;
+}
+
+void ir_rc5_timer_end(unsigned long data)
+{
+       struct card_ir *ir = (struct card_ir *)data;
+       struct timeval tv;
+       unsigned long current_jiffies, timeout;
+       u32 gap;
+       u32 rc5 = 0;
+
+       /* get time */
+       current_jiffies = jiffies;
+       do_gettimeofday(&tv);
+
+       /* avoid overflow with gap >1s */
+       if (tv.tv_sec - ir->base_time.tv_sec > 1) {
+               gap = 200000;
+       } else {
+               gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+                   tv.tv_usec - ir->base_time.tv_usec;
+       }
+
+       /* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */
+       if (gap < 28000) {
+               dprintk(1, "ir-common: spurious timer_end\n");
+               return;
+       }
+
+       ir->active = 0;
+       if (ir->last_bit < 20) {
+               /* ignore spurious codes (caused by light/other remotes) */
+               dprintk(1, "ir-common: short code: %x\n", ir->code);
+       } else {
+               ir->code = (ir->code << ir->shift_by) | 1;
+               rc5 = ir_rc5_decode(ir->code);
+
+               /* two start bits? */
+               if (RC5_START(rc5) != ir->start) {
+                       dprintk(1, "ir-common: rc5 start bits invalid: %u\n", RC5_START(rc5));
+
+                       /* right address? */
+               } else if (RC5_ADDR(rc5) == ir->addr) {
+                       u32 toggle = RC5_TOGGLE(rc5);
+                       u32 instr = RC5_INSTR(rc5);
+
+                       /* Good code, decide if repeat/repress */
+                       if (toggle != RC5_TOGGLE(ir->last_rc5) ||
+                           instr != RC5_INSTR(ir->last_rc5)) {
+                               dprintk(1, "ir-common: instruction %x, toggle %x\n", instr,
+                                       toggle);
+                               ir_input_nokey(ir->dev, &ir->ir);
+                               ir_input_keydown(ir->dev, &ir->ir, instr,
+                                                instr);
+                       }
+
+                       /* Set/reset key-up timer */
+                       timeout = current_jiffies + (500 + ir->rc5_key_timeout
+                                                    * HZ) / 1000;
+                       mod_timer(&ir->timer_keyup, timeout);
+
+                       /* Save code for repeat test */
+                       ir->last_rc5 = rc5;
+               }
+       }
+}
+
+void ir_rc5_timer_keyup(unsigned long data)
+{
+       struct card_ir *ir = (struct card_ir *)data;
+
+       dprintk(1, "ir-common: key released\n");
+       ir_input_nokey(ir->dev, &ir->ir);
+}
+
 EXPORT_SYMBOL_GPL(ir_input_init);
 EXPORT_SYMBOL_GPL(ir_input_nokey);
 EXPORT_SYMBOL_GPL(ir_input_keydown);
@@ -265,6 +371,10 @@ EXPORT_SYMBOL_GPL(ir_dump_samples);
 EXPORT_SYMBOL_GPL(ir_decode_biphase);
 EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
 
+EXPORT_SYMBOL_GPL(ir_rc5_decode);
+EXPORT_SYMBOL_GPL(ir_rc5_timer_end);
+EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup);
+
 /*
  * Local variables:
  * c-basic-offset: 8
index 0e948a5..03b47a2 100644 (file)
@@ -1606,3 +1606,174 @@ IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE] = {
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_budget_ci_old);
+
+/*
+ * Marc Fargas <telenieko@telenieko.com>
+ * this is the remote control that comes with the asus p7131
+ * which has a label saying is "Model PC-39"
+ */
+IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE] = {
+       /* Keys 0 to 9 */
+       [ 0x15 ] = KEY_0,
+       [ 0x29 ] = KEY_1,
+       [ 0x2d ] = KEY_2,
+       [ 0x2b ] = KEY_3,
+       [ 0x09 ] = KEY_4,
+       [ 0x0d ] = KEY_5,
+       [ 0x0b ] = KEY_6,
+       [ 0x31 ] = KEY_7,
+       [ 0x35 ] = KEY_8,
+       [ 0x33 ] = KEY_9,
+
+       [ 0x3e ] = KEY_RADIO,           /* radio */
+       [ 0x03 ] = KEY_MENU,            /* dvd/menu */
+       [ 0x2a ] = KEY_VOLUMEUP,
+       [ 0x19 ] = KEY_VOLUMEDOWN,
+       [ 0x37 ] = KEY_UP,
+       [ 0x3b ] = KEY_DOWN,
+       [ 0x27 ] = KEY_LEFT,
+       [ 0x2f ] = KEY_RIGHT,
+       [ 0x25 ] = KEY_VIDEO,           /* video */
+       [ 0x39 ] = KEY_AUDIO,           /* music */
+
+       [ 0x21 ] = KEY_TV,              /* tv */
+       [ 0x1d ] = KEY_EXIT,            /* back */
+       [ 0x0a ] = KEY_CHANNELUP,       /* channel / program + */
+       [ 0x1b ] = KEY_CHANNELDOWN,     /* channel / program - */
+       [ 0x1a ] = KEY_ENTER,           /* enter */
+
+       [ 0x06 ] = KEY_PAUSE,           /* play/pause */
+       [ 0x1e ] = KEY_PREVIOUS,        /* rew */
+       [ 0x26 ] = KEY_NEXT,            /* forward */
+       [ 0x0e ] = KEY_REWIND,          /* backward << */
+       [ 0x3a ] = KEY_FASTFORWARD,     /* forward >> */
+       [ 0x36 ] = KEY_STOP,
+       [ 0x2e ] = KEY_RECORD,          /* recording */
+       [ 0x16 ] = KEY_POWER,           /* the button that reads "close" */
+
+       [ 0x11 ] = KEY_ZOOM,            /* full screen */
+       [ 0x13 ] = KEY_MACRO,           /* recall */
+       [ 0x23 ] = KEY_HOME,            /* home */
+       [ 0x05 ] = KEY_PVR,             /* picture */
+       [ 0x3d ] = KEY_MUTE,            /* mute */
+       [ 0x01 ] = KEY_DVD,             /* dvd */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_asus_pc39);
+
+
+/* Encore ENLTV-FM  - black plastic, white front cover with white glowing buttons
+    Juan Pablo Sormani <sorman@gmail.com> */
+IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE] = {
+
+       /* Power button does nothing, neither in Windows app,
+        although it sends data (used for BIOS wakeup?) */
+       [ 0x0d ] = KEY_MUTE,
+
+       [ 0x1e ] = KEY_TV,
+       [ 0x00 ] = KEY_VIDEO,
+       [ 0x01 ] = KEY_AUDIO,           /* music */
+       [ 0x02 ] = KEY_MHP,             /* picture */
+
+       [ 0x1f ] = KEY_1,
+       [ 0x03 ] = KEY_2,
+       [ 0x04 ] = KEY_3,
+       [ 0x05 ] = KEY_4,
+       [ 0x1c ] = KEY_5,
+       [ 0x06 ] = KEY_6,
+       [ 0x07 ] = KEY_7,
+       [ 0x08 ] = KEY_8,
+       [ 0x1d ] = KEY_9,
+       [ 0x0a ] = KEY_0,
+
+       [ 0x09 ] = KEY_LIST,        /* -/-- */
+       [ 0x0b ] = KEY_LAST,        /* recall */
+
+       [ 0x14 ] = KEY_HOME,            /* win start menu */
+       [ 0x15 ] = KEY_EXIT,            /* exit */
+       [ 0x16 ] = KEY_UP,
+       [ 0x12 ] = KEY_DOWN,
+       [ 0x0c ] = KEY_RIGHT,
+       [ 0x17 ] = KEY_LEFT,
+
+       [ 0x18 ] = KEY_ENTER,           /* OK */
+
+       [ 0x0e ] = KEY_ESC,
+       [ 0x13 ] = KEY_D,               /* desktop */
+       [ 0x11 ] = KEY_TAB,
+       [ 0x19 ] = KEY_SWITCHVIDEOMODE, /* switch */
+
+       [ 0x1a ] = KEY_MENU,
+       [ 0x1b ] = KEY_ZOOM,            /* fullscreen */
+       [ 0x44 ] = KEY_TIME,            /* time shift */
+       [ 0x40 ] = KEY_MODE,            /* source */
+
+       [ 0x5a ] = KEY_RECORD,
+       [ 0x42 ] = KEY_PLAY,            /* play/pause */
+       [ 0x45 ] = KEY_STOP,
+       [ 0x43 ] = KEY_CAMERA,          /* camera icon */
+
+       [ 0x48 ] = KEY_REWIND,
+       [ 0x4a ] = KEY_FASTFORWARD,
+       [ 0x49 ] = KEY_PREVIOUS,
+       [ 0x4b ] = KEY_NEXT,
+
+       [ 0x4c ] = KEY_FAVORITES,       /* tv wall */
+       [ 0x4d ] = KEY_SOUND,           /* DVD sound */
+       [ 0x4e ] = KEY_LANGUAGE,        /* DVD lang */
+       [ 0x4f ] = KEY_TEXT,            /* DVD text */
+
+       [ 0x50 ] = KEY_SLEEP,           /* shutdown */
+       [ 0x51 ] = KEY_MODE,            /* stereo > main */
+       [ 0x52 ] = KEY_SELECT,          /* stereo > sap */
+       [ 0x53 ] = KEY_PROG1,           /* teletext */
+
+
+       [ 0x59 ] = KEY_RED,             /* AP1 */
+       [ 0x41 ] = KEY_GREEN,           /* AP2 */
+       [ 0x47 ] = KEY_YELLOW,          /* AP3 */
+       [ 0x57 ] = KEY_BLUE,            /* AP4 */
+
+
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_encore_enltv);
+
+/* for the Technotrend 1500 bundled remote: */
+IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = {
+       [ 0x01 ] = KEY_POWER,
+       [ 0x02 ] = KEY_SHUFFLE, /* ? double-arrow key */
+       [ 0x03 ] = KEY_1,
+       [ 0x04 ] = KEY_2,
+       [ 0x05 ] = KEY_3,
+       [ 0x06 ] = KEY_4,
+       [ 0x07 ] = KEY_5,
+       [ 0x08 ] = KEY_6,
+       [ 0x09 ] = KEY_7,
+       [ 0x0a ] = KEY_8,
+       [ 0x0b ] = KEY_9,
+       [ 0x0c ] = KEY_0,
+       [ 0x0d ] = KEY_UP,
+       [ 0x0e ] = KEY_LEFT,
+       [ 0x0f ] = KEY_OK,
+       [ 0x10 ] = KEY_RIGHT,
+       [ 0x11 ] = KEY_DOWN,
+       [ 0x12 ] = KEY_INFO,
+       [ 0x13 ] = KEY_EXIT,
+       [ 0x14 ] = KEY_RED,
+       [ 0x15 ] = KEY_GREEN,
+       [ 0x16 ] = KEY_YELLOW,
+       [ 0x17 ] = KEY_BLUE,
+       [ 0x18 ] = KEY_MUTE,
+       [ 0x19 ] = KEY_TEXT,
+       [ 0x1a ] = KEY_MODE,    /* ? TV/Radio */
+       [ 0x21 ] = KEY_OPTION,
+       [ 0x22 ] = KEY_EPG,
+       [ 0x23 ] = KEY_CHANNELUP,
+       [ 0x24 ] = KEY_CHANNELDOWN,
+       [ 0x25 ] = KEY_VOLUMEUP,
+       [ 0x26 ] = KEY_VOLUMEDOWN,
+       [ 0x27 ] = KEY_SETUP,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_tt_1500);
index b8dcfa1..c18a5da 100644 (file)
@@ -508,7 +508,7 @@ int saa7146_vv_release(struct saa7146_dev* dev)
 
        DEB_EE(("dev:%p\n",dev));
 
-       pci_free_consistent(dev->pci, SAA7146_RPS_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
+       pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
        kfree(vv);
        dev->vv_data = NULL;
        dev->vv_callback = NULL;
index c2b35e3..752cf79 100644 (file)
@@ -385,9 +385,9 @@ static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
        else buf[3] = 0x88;
 
        if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
+               fe->ops.i2c_gate_ctrl(fe, 0);
        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);
+       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;
@@ -398,91 +398,71 @@ static u8 alps_tdee4_stv0297_inittab[] = {
        0x80, 0x00,
        0x81, 0x01,
        0x81, 0x00,
-       0x00, 0x09,
-       0x01, 0x69,
+       0x00, 0x48,
+       0x01, 0x58,
        0x03, 0x00,
        0x04, 0x00,
        0x07, 0x00,
        0x08, 0x00,
-       0x20, 0x00,
-       0x21, 0x40,
-       0x22, 0x00,
-       0x23, 0x00,
-       0x24, 0x40,
-       0x25, 0x88,
        0x30, 0xff,
-       0x31, 0x00,
+       0x31, 0x9d,
        0x32, 0xff,
        0x33, 0x00,
-       0x34, 0x50,
-       0x35, 0x7f,
-       0x36, 0x00,
-       0x37, 0x20,
-       0x38, 0x00,
-       0x40, 0x1c,
-       0x41, 0xff,
-       0x42, 0x29,
+       0x34, 0x29,
+       0x35, 0x55,
+       0x36, 0x80,
+       0x37, 0x6e,
+       0x38, 0x9c,
+       0x40, 0x1a,
+       0x41, 0xfe,
+       0x42, 0x33,
        0x43, 0x00,
        0x44, 0xff,
        0x45, 0x00,
        0x46, 0x00,
        0x49, 0x04,
-       0x4a, 0x00,
+       0x4a, 0x51,
        0x4b, 0xf8,
        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,
+       0x53, 0x06,
+       0x59, 0x06,
+       0x5a, 0x5e,
+       0x5b, 0x04,
+       0x61, 0x49,
+       0x62, 0x0a,
        0x70, 0xff,
-       0x71, 0x00,
+       0x71, 0x04,
        0x72, 0x00,
        0x73, 0x00,
        0x74, 0x0c,
-       0x80, 0x00,
+       0x80, 0x20,
        0x81, 0x00,
-       0x82, 0x00,
+       0x82, 0x30,
        0x83, 0x00,
        0x84, 0x04,
-       0x85, 0x80,
-       0x86, 0x24,
-       0x87, 0x78,
-       0x88, 0x10,
+       0x85, 0x22,
+       0x86, 0x08,
+       0x87, 0x1b,
+       0x88, 0x00,
        0x89, 0x00,
-       0x90, 0x01,
-       0x91, 0x01,
-       0xa0, 0x04,
+       0x90, 0x00,
+       0x91, 0x04,
+       0xa0, 0x86,
        0xa1, 0x00,
        0xa2, 0x00,
        0xb0, 0x91,
        0xb1, 0x0b,
-       0xc0, 0x53,
-       0xc1, 0x70,
+       0xc0, 0x5b,
+       0xc1, 0x10,
        0xc2, 0x12,
-       0xd0, 0x00,
+       0xd0, 0x02,
        0xd1, 0x00,
        0xd2, 0x00,
        0xd3, 0x00,
-       0xd4, 0x00,
+       0xd4, 0x02,
        0xd5, 0x00,
        0xde, 0x00,
-       0xdf, 0x00,
-       0x61, 0x49,
-       0x62, 0x0b,
-       0x53, 0x08,
-       0x59, 0x08,
+       0xdf, 0x01,
        0xff, 0xff,
 };
 
index 329a51c..83b090e 100644 (file)
@@ -390,6 +390,7 @@ static struct cards card_list[] __devinitdata = {
        { 0xfc00270f, BTTV_BOARD_TWINHAN_DST,                   "ChainTech digitop DST-1000 DVB-S" },
        { 0x07711461, BTTV_BOARD_AVDVBT_771,                    "AVermedia AverTV DVB-T 771" },
        { 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE,               "DViCO FusionHDTV DVB-T Lite" },
+       { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE,               "Ultraview DVB-T Lite" },
        { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,       "DViCO FusionHDTV 5 Lite" },
        { 0x20007063, BTTV_BOARD_PC_HDTV,                       "pcHDTV HD-2000 TV" },
        { 0x00261822, BTTV_BOARD_TWINHAN_DST,                   "DNTV Live! Mini" },
index 9f72b70..0393a3d 100644 (file)
@@ -1161,7 +1161,7 @@ static int dst_get_device_id(struct dst_state *state)
                }
        }
 
-       if (i >= sizeof (dst_tlist) / sizeof (dst_tlist [0])) {
+       if (i >= ARRAY_SIZE(dst_tlist)) {
                dprintk(verbose, DST_ERROR, 1, "Unable to recognize %s or %s", &state->rxbuffer[0], &state->rxbuffer[1]);
                dprintk(verbose, DST_ERROR, 1, "please email linux-dvb@linuxtv.org with this type in");
                use_dst_type = DST_TYPE_IS_SAT;
index 3e35931..58f69f6 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
+#include <linux/kernel.h>
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -213,7 +214,7 @@ static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend
                freq = 2150000; /* satellite IF is 950..2150MHz */
 
        /* decide which VCO to use for the input frequency */
-       for(i=1;(i<sizeof(osci)/sizeof(osci[0]))&&(osci[i]<freq);i++);
+       for(i = 1; (i < ARRAY_SIZE(osci)) && (osci[i] < freq); i++);
        printk("cx24108 debug: select vco #%d (f=%d)\n",i,freq);
        band=bandsel[i];
        /* the gain values must be set by SetSymbolrate */
index d64b96c..a6cbbdd 100644 (file)
@@ -819,6 +819,11 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
                set_bit(rc_keys[i + 2], input_dev->keybit);
        input_dev->keycodesize = 0;
        input_dev->keycodemax = 0;
+       input_dev->id.bustype = BUS_USB;
+       input_dev->id.vendor = cinergyt2->udev->descriptor.idVendor;
+       input_dev->id.product = cinergyt2->udev->descriptor.idProduct;
+       input_dev->id.version = 1;
+       input_dev->cdev.dev = &cinergyt2->udev->dev;
 
        err = input_register_device(input_dev);
        if (err) {
index 7c42d53..a21a894 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/list.h>
 #include <linux/freezer.h>
 #include <linux/jiffies.h>
+#include <linux/kthread.h>
 #include <asm/processor.h>
 
 #include "dvb_frontend.h"
@@ -100,7 +101,7 @@ struct dvb_frontend_private {
        struct semaphore sem;
        struct list_head list_head;
        wait_queue_head_t wait_queue;
-       pid_t thread_pid;
+       struct task_struct *thread;
        unsigned long release_jiffies;
        unsigned int exit;
        unsigned int wakeup;
@@ -508,19 +509,11 @@ static int dvb_frontend_thread(void *data)
        struct dvb_frontend *fe = data;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
        unsigned long timeout;
-       char name [15];
        fe_status_t s;
        struct dvb_frontend_parameters *params;
 
        dprintk("%s\n", __FUNCTION__);
 
-       snprintf (name, sizeof(name), "kdvb-fe-%i", fe->dvb->num);
-
-       lock_kernel();
-       daemonize(name);
-       sigfillset(&current->blocked);
-       unlock_kernel();
-
        fepriv->check_wrapped = 0;
        fepriv->quality = 0;
        fepriv->delay = 3*HZ;
@@ -532,16 +525,18 @@ static int dvb_frontend_thread(void *data)
 
        while (1) {
                up(&fepriv->sem);           /* is locked when we enter the thread... */
-
+restart:
                timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
-                                                          dvb_frontend_should_wakeup(fe),
-                                                          fepriv->delay);
-               if (0 != dvb_frontend_is_exiting(fe)) {
+                       dvb_frontend_should_wakeup(fe) || kthread_should_stop(),
+                       fepriv->delay);
+
+               if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
                        /* got signal or quitting */
                        break;
                }
 
-               try_to_freeze();
+               if (try_to_freeze())
+                       goto restart;
 
                if (down_interruptible(&fepriv->sem))
                        break;
@@ -591,7 +586,7 @@ static int dvb_frontend_thread(void *data)
                        fe->ops.sleep(fe);
        }
 
-       fepriv->thread_pid = 0;
+       fepriv->thread = NULL;
        mb();
 
        dvb_frontend_wakeup(fe);
@@ -600,7 +595,6 @@ static int dvb_frontend_thread(void *data)
 
 static void dvb_frontend_stop(struct dvb_frontend *fe)
 {
-       unsigned long ret;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
 
        dprintk ("%s\n", __FUNCTION__);
@@ -608,33 +602,17 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
        fepriv->exit = 1;
        mb();
 
-       if (!fepriv->thread_pid)
+       if (!fepriv->thread)
                return;
 
-       /* check if the thread is really alive */
-       if (kill_proc(fepriv->thread_pid, 0, 1) == -ESRCH) {
-               printk("dvb_frontend_stop: thread PID %d already died\n",
-                               fepriv->thread_pid);
-               /* make sure the mutex was not held by the thread */
-               init_MUTEX (&fepriv->sem);
-               return;
-       }
-
-       /* wake up the frontend thread, so it notices that fe->exit == 1 */
-       dvb_frontend_wakeup(fe);
-
-       /* wait until the frontend thread has exited */
-       ret = wait_event_interruptible(fepriv->wait_queue,0 == fepriv->thread_pid);
-       if (-ERESTARTSYS != ret) {
-               fepriv->state = FESTATE_IDLE;
-               return;
-       }
+       kthread_stop(fepriv->thread);
+       init_MUTEX (&fepriv->sem);
        fepriv->state = FESTATE_IDLE;
 
        /* paranoia check in case a signal arrived */
-       if (fepriv->thread_pid)
-               printk("dvb_frontend_stop: warning: thread PID %d won't exit\n",
-                               fepriv->thread_pid);
+       if (fepriv->thread)
+               printk("dvb_frontend_stop: warning: thread %p won't exit\n",
+                               fepriv->thread);
 }
 
 s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime)
@@ -684,10 +662,11 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
 {
        int ret;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct task_struct *fe_thread;
 
        dprintk ("%s\n", __FUNCTION__);
 
-       if (fepriv->thread_pid) {
+       if (fepriv->thread) {
                if (!fepriv->exit)
                        return 0;
                else
@@ -701,18 +680,18 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
 
        fepriv->state = FESTATE_IDLE;
        fepriv->exit = 0;
-       fepriv->thread_pid = 0;
+       fepriv->thread = NULL;
        mb();
 
-       ret = kernel_thread (dvb_frontend_thread, fe, 0);
-
-       if (ret < 0) {
-               printk("dvb_frontend_start: failed to start kernel_thread (%d)\n", ret);
+       fe_thread = kthread_run(dvb_frontend_thread, fe,
+               "kdvb-fe-%i", fe->dvb->num);
+       if (IS_ERR(fe_thread)) {
+               ret = PTR_ERR(fe_thread);
+               printk("dvb_frontend_start: failed to start kthread (%d)\n", ret);
                up(&fepriv->sem);
                return ret;
        }
-       fepriv->thread_pid = ret;
-
+       fepriv->thread = fe_thread;
        return 0;
 }
 
index 826b47f..490337b 100644 (file)
@@ -199,12 +199,14 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
                        const struct dvb_device *template, void *priv, int type)
 {
        struct dvb_device *dvbdev;
+       struct file_operations *dvbdevfops;
+
        int id;
 
        if (mutex_lock_interruptible(&dvbdev_register_lock))
                return -ERESTARTSYS;
 
-       if ((id = dvbdev_get_free_id (adap, type)) < 0) {
+       if ((id = dvbdev_get_free_id (adap, type)) < 0){
                mutex_unlock(&dvbdev_register_lock);
                *pdvbdev = NULL;
                printk ("%s: could get find free device id...\n", __FUNCTION__);
@@ -213,7 +215,15 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
 
        *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL);
 
-       if (!dvbdev) {
+       if (!dvbdev){
+               mutex_unlock(&dvbdev_register_lock);
+               return -ENOMEM;
+       }
+
+       dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
+
+       if (!dvbdevfops){
+               kfree (dvbdev);
                mutex_unlock(&dvbdev_register_lock);
                return -ENOMEM;
        }
@@ -223,7 +233,9 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
        dvbdev->id = id;
        dvbdev->adapter = adap;
        dvbdev->priv = priv;
+       dvbdev->fops = dvbdevfops;
 
+       memcpy(dvbdev->fops, template->fops, sizeof(struct file_operations));
        dvbdev->fops->owner = adap->module;
 
        list_add_tail (&dvbdev->list_head, &adap->device_list);
@@ -251,6 +263,7 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
                                        dvbdev->type, dvbdev->id)));
 
        list_del (&dvbdev->list_head);
+       kfree (dvbdev->fops);
        kfree (dvbdev);
 }
 EXPORT_SYMBOL(dvb_unregister_device);
index ad52143..80f67a5 100644 (file)
@@ -109,6 +109,34 @@ config DVB_USB_CXUSB
          Medion MD95700 hybrid USB2.0 device.
          DViCO FusionHDTV (Bluebird) USB2.0 devices
 
+config DVB_USB_M920X
+       tristate "Uli m920x DVB-T USB2.0 support"
+       depends on DVB_USB
+       select DVB_MT352 if !DVB_FE_CUSTOMISE
+       select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+       help
+         Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
+         Currently, only devices with a product id of
+         "DTV USB MINI" (in cold state) are supported.
+         Firmware required.
+
+config DVB_USB_GL861
+       tristate "Genesys Logic GL861 USB2.0 support"
+       depends on DVB_USB
+       select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+       select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+       help
+         Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0
+         receiver with USB ID 0db0:5581.
+
+config DVB_USB_AU6610
+       tristate "Alcor Micro AU6610 USB2.0 support"
+       depends on DVB_USB
+       select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+       select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+       help
+         Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver.
+
 config DVB_USB_DIGITV
        tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
        depends on DVB_USB
index 154d593..40f28f5 100644 (file)
@@ -30,6 +30,15 @@ obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-dibusb-common.o dvb-usb-nova-t-usb2
 dvb-usb-umt-010-objs = umt-010.o
 obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o
 
+dvb-usb-m920x-objs = m920x.o
+obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o
+
+dvb-usb-gl861-objs = gl861.o
+obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o
+
+dvb-usb-au6610-objs = au6610.o
+obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o
+
 dvb-usb-digitv-objs = digitv.o
 obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o
 
diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c
new file mode 100644 (file)
index 0000000..0dc66a8
--- /dev/null
@@ -0,0 +1,255 @@
+/* DVB USB compliant linux driver for Sigmatek DVB-110 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+
+#include "au6610.h"
+
+#include "zl10353.h"
+#include "qt1010.h"
+
+/* debug */
+static int dvb_usb_au6610_debug;
+module_param_named(debug, dvb_usb_au6610_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+
+static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
+                         u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+       int ret;
+       u16 index;
+       u8 usb_buf[6]; /* enough for all known requests,
+                         read returns 5 and write 6 bytes */
+       switch (wlen) {
+       case 1:
+               index = wbuf[0] << 8;
+               break;
+       case 2:
+               index = wbuf[0] << 8;
+               index += wbuf[1];
+               break;
+       default:
+               warn("wlen = %x, aborting.", wlen);
+               return -EINVAL;
+       }
+
+       ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
+                             USB_TYPE_VENDOR|USB_DIR_IN, addr, index, usb_buf,
+                             sizeof(usb_buf), AU6610_USB_TIMEOUT);
+
+       if (ret < 0)
+               return ret;
+
+       switch (operation) {
+       case AU6610_REQ_I2C_READ:
+       case AU6610_REQ_USB_READ:
+               /* requested value is always 5th byte in buffer */
+               rbuf[0] = usb_buf[4];
+       }
+
+       return ret;
+}
+
+static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr,
+                         u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+       u8 request;
+       u8 wo = (rbuf == NULL || rlen == 0); /* write-only */
+
+       if (wo) {
+               request = AU6610_REQ_I2C_WRITE;
+       } else { /* rw */
+               request = AU6610_REQ_I2C_READ;
+       }
+
+       return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen);
+}
+
+
+/* I2C */
+static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+                          int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int i;
+
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       if (num > 2)
+               return -EINVAL;
+
+       for (i = 0; i < num; i++) {
+               /* write/read request */
+               if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+                       if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
+                                          msg[i].len, msg[i+1].buf,
+                                          msg[i+1].len) < 0)
+                               break;
+                       i++;
+               } else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
+                                              msg[i].len, NULL, 0) < 0)
+                               break;
+       }
+
+       mutex_unlock(&d->i2c_mutex);
+       return i;
+}
+
+
+static u32 au6610_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm au6610_i2c_algo = {
+       .master_xfer   = au6610_i2c_xfer,
+       .functionality = au6610_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static int au6610_identify_state(struct usb_device *udev,
+                                struct dvb_usb_device_properties *props,
+                                struct dvb_usb_device_description **desc,
+                                int *cold)
+{
+       *cold = 0;
+       return 0;
+}
+
+static struct zl10353_config au6610_zl10353_config = {
+       .demod_address = 0x1e,
+       .no_tuner = 1,
+       .parallel_ts = 1,
+};
+
+static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       if ((adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
+                                  &adap->dev->i2c_adap)) != NULL) {
+               return 0;
+       }
+
+       return -EIO;
+}
+
+static struct qt1010_config au6610_qt1010_config = {
+       .i2c_address = 0xc4
+};
+
+static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       return dvb_attach(qt1010_attach,
+                         adap->fe, &adap->dev->i2c_adap,
+                         &au6610_qt1010_config) == NULL ? -ENODEV : 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties au6610_properties;
+
+static int au6610_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       struct dvb_usb_device *d;
+       struct usb_host_interface *alt;
+       int ret;
+
+       if (intf->num_altsetting < AU6610_ALTSETTING_COUNT)
+               return -ENODEV;
+
+       if ((ret = dvb_usb_device_init(intf, &au6610_properties, THIS_MODULE, &d)) == 0) {
+               alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING);
+
+               if (alt == NULL) {
+                       deb_rc("no alt found!\n");
+                       return -ENODEV;
+               }
+               ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
+                                       alt->desc.bAlternateSetting);
+       }
+
+       return ret;
+}
+
+
+static struct usb_device_id au6610_table [] = {
+       { USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) },
+       { }             /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, au6610_table);
+
+static struct dvb_usb_device_properties au6610_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+       .usb_ctrl = DEVICE_SPECIFIC,
+       .size_of_priv     = 0,
+       .identify_state   = au6610_identify_state,
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .frontend_attach  = au6610_zl10353_frontend_attach,
+                       .tuner_attach     = au6610_qt1010_tuner_attach,
+
+                       .stream = {
+                               .type = USB_ISOC,
+                               .count = 5,
+                               .endpoint = 0x82,
+                               .u = {
+                                       .isoc = {
+                                               .framesperurb = 40,
+                                               .framesize = 942,   /* maximum packet size */
+                                               .interval = 1.25,   /* 125 us */
+                                       }
+                               }
+                       },
+               }
+       },
+       .i2c_algo = &au6610_i2c_algo,
+       .num_device_descs = 1,
+       .devices = {
+               {
+                       "Sigmatek DVB-110 DVB-T USB2.0",
+                       { &au6610_table[0], NULL },
+                       { NULL },
+               },
+       }
+};
+
+static struct usb_driver au6610_driver = {
+       .name       = "dvb_usb_au6610",
+       .probe      = au6610_probe,
+       .disconnect = dvb_usb_device_exit,
+       .id_table   = au6610_table,
+};
+
+/* module stuff */
+static int __init au6610_module_init(void)
+{
+       int ret;
+
+       if ((ret = usb_register(&au6610_driver))) {
+               err("usb_register failed. Error number %d", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void __exit au6610_module_exit(void)
+{
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&au6610_driver);
+}
+
+module_init (au6610_module_init);
+module_exit (au6610_module_exit);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Driver Sigmatek DVB-110 DVB-T USB2.0 / AU6610");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/au6610.h b/drivers/media/dvb/dvb-usb/au6610.h
new file mode 100644 (file)
index 0000000..4161b05
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _DVB_USB_AU6610_H_
+#define _DVB_USB_AU6610_H_
+
+#define DVB_USB_LOG_PREFIX "au6610"
+#include "dvb-usb.h"
+
+#define deb_rc(args...)   dprintk(dvb_usb_au6610_debug,0x01,args)
+
+#define AU6610_REQ_I2C_WRITE   0x14
+#define AU6610_REQ_I2C_READ    0x13
+#define AU6610_REQ_USB_WRITE   0x16
+#define AU6610_REQ_USB_READ    0x15
+
+#define AU6610_USB_TIMEOUT 1000
+
+#define AU6610_ALTSETTING_COUNT 6
+#define AU6610_ALTSETTING       5
+
+#endif
index 299382d..148386a 100644 (file)
@@ -11,6 +11,7 @@
 
 /* Vendor IDs */
 #define USB_VID_ADSTECH                                0x06e1
+#define USB_VID_ALCOR_MICRO            0x058f
 #define USB_VID_ANCHOR                         0x0547
 #define USB_VID_AVERMEDIA                      0x07ca
 #define USB_VID_COMPRO                         0x185b
@@ -29,6 +30,7 @@
 #define USB_VID_LEADTEK                                0x0413
 #define USB_VID_LITEON                         0x04ca
 #define USB_VID_MEDION                         0x1660
+#define USB_VID_MSI                            0x0db0
 #define USB_VID_PINNACLE                       0x2304
 #define USB_VID_VISIONPLUS                     0x13d3
 #define USB_VID_TWINHAN                                0x1822
 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD                0xdb54
 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM                0xdb55
 #define USB_PID_MEDION_MD95700                         0x0932
+#define USB_PID_MSI_MEGASKY580                         0x5580
+#define USB_PID_MSI_MEGASKY580_55801                   0x5581
 #define USB_PID_KYE_DVB_T_COLD                         0x701e
 #define USB_PID_KYE_DVB_T_WARM                         0x701f
 #define USB_PID_PCTV_200E                              0x020e
 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P            0x6f00
 #define USB_PID_GENPIX_8PSK_COLD                       0x0200
 #define USB_PID_GENPIX_8PSK_WARM                       0x0201
+#define USB_PID_SIGMATEK_DVB_110                       0x6610
 
 
 #endif
index 19ff597..9511a31 100644 (file)
@@ -151,7 +151,7 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
 int dvb_usb_remote_exit(struct dvb_usb_device *d)
 {
        if (d->state & DVB_USB_STATE_REMOTE) {
-               cancel_delayed_work(&d->rc_query_work);
+               cancel_rearming_delayed_work(&d->rc_query_work);
                flush_scheduled_work();
                input_unregister_device(d->rc_input_dev);
        }
diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c
new file mode 100644 (file)
index 0000000..c9f38a5
--- /dev/null
@@ -0,0 +1,231 @@
+/* DVB USB compliant linux driver for GL861 USB2.0 devices.
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "gl861.h"
+
+#include "zl10353.h"
+#include "qt1010.h"
+
+/* debug */
+int dvb_usb_gl861_debug;
+module_param_named(debug,dvb_usb_gl861_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+
+static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
+                        u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+       u16 index;
+       u16 value = addr << 8;
+       int wo = (rbuf == NULL || rlen == 0); /* write-only */
+       u8 req, type;
+
+       if (wo) {
+               req = GL861_REQ_I2C_WRITE;
+               type = GL861_WRITE;
+       } else { /* rw */
+               req = GL861_REQ_I2C_READ;
+               type = GL861_READ;
+       }
+
+       switch (wlen) {
+       case 1:
+               index = wbuf[0];
+               break;
+       case 2:
+               index = wbuf[0];
+               value = value + wbuf[1];
+               break;
+       default:
+               warn("wlen = %x, aborting.", wlen);
+               return -EINVAL;
+       }
+
+       return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type,
+                              value, index, rbuf, rlen, 2000);
+}
+
+/* I2C */
+static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+                         int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int i;
+
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       if (num > 2)
+               return -EINVAL;
+
+       for (i = 0; i < num; i++) {
+               /* write/read request */
+               if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+                       if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
+                                         msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
+                               break;
+                       i++;
+               } else
+                       if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
+                                         msg[i].len, NULL, 0) < 0)
+                               break;
+       }
+
+       mutex_unlock(&d->i2c_mutex);
+       return i;
+}
+
+static u32 gl861_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm gl861_i2c_algo = {
+       .master_xfer   = gl861_i2c_xfer,
+       .functionality = gl861_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static int gl861_identify_state(struct usb_device *udev,
+                               struct dvb_usb_device_properties *props,
+                               struct dvb_usb_device_description **desc,
+                               int *cold)
+{
+       *cold = 0;
+
+       return 0;
+}
+
+static struct zl10353_config gl861_zl10353_config = {
+       .demod_address = 0x1e,
+       .no_tuner = 1,
+       .parallel_ts = 1,
+};
+
+static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       if ((adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
+                                  &adap->dev->i2c_adap)) != NULL) {
+               return 0;
+       }
+
+       return -EIO;
+}
+
+static struct qt1010_config gl861_qt1010_config = {
+       .i2c_address = 0xc4
+};
+
+static int gl861_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       return dvb_attach(qt1010_attach,
+                         adap->fe, &adap->dev->i2c_adap,
+                         &gl861_qt1010_config) == NULL ? -ENODEV : 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties gl861_properties;
+
+static int gl861_probe(struct usb_interface *intf,
+                      const struct usb_device_id *id)
+{
+       struct dvb_usb_device *d;
+       struct usb_host_interface *alt;
+       int ret;
+
+       if (intf->num_altsetting < 2)
+               return -ENODEV;
+
+       if ((ret = dvb_usb_device_init(intf, &gl861_properties, THIS_MODULE, &d)) == 0) {
+               alt = usb_altnum_to_altsetting(intf, 0);
+
+               if (alt == NULL) {
+                       deb_rc("not alt found!\n");
+                       return -ENODEV;
+               }
+
+               ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
+                                       alt->desc.bAlternateSetting);
+       }
+
+       return ret;
+}
+
+static struct usb_device_id gl861_table [] = {
+               { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) },
+               { }             /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, gl861_table);
+
+static struct dvb_usb_device_properties gl861_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+       .usb_ctrl = DEVICE_SPECIFIC,
+
+       .size_of_priv     = 0,
+
+       .identify_state   = gl861_identify_state,
+       .num_adapters = 1,
+       .adapter = {{
+
+               .frontend_attach  = gl861_frontend_attach,
+               .tuner_attach     = gl861_tuner_attach,
+
+               .stream = {
+                       .type = USB_BULK,
+                       .count = 7,
+                       .endpoint = 0x81,
+                       .u = {
+                               .bulk = {
+                                       .buffersize = 512,
+                               }
+                       }
+               },
+       }},
+       .i2c_algo         = &gl861_i2c_algo,
+
+       .num_device_descs = 1,
+       .devices = {
+               {   "MSI Mega Sky 55801 DVB-T USB2.0",
+                       { &gl861_table[0], NULL },
+                       { NULL },
+               },
+       }
+};
+
+static struct usb_driver gl861_driver = {
+       .name           = "dvb_usb_gl861",
+       .probe          = gl861_probe,
+       .disconnect     = dvb_usb_device_exit,
+       .id_table       = gl861_table,
+};
+
+/* module stuff */
+static int __init gl861_module_init(void)
+{
+       int ret;
+
+       if ((ret = usb_register(&gl861_driver))) {
+               err("usb_register failed. Error number %d", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void __exit gl861_module_exit(void)
+{
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&gl861_driver);
+}
+
+module_init (gl861_module_init);
+module_exit (gl861_module_exit);
+
+MODULE_AUTHOR("Carl Lundqvist <comabug@gmail.com>");
+MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/gl861.h b/drivers/media/dvb/dvb-usb/gl861.h
new file mode 100644 (file)
index 0000000..72a51af
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _DVB_USB_GL861_H_
+#define _DVB_USB_GL861_H_
+
+#define DVB_USB_LOG_PREFIX "gl861"
+#include "dvb-usb.h"
+
+#define deb_rc(args...)   dprintk(dvb_usb_gl861_debug,0x01,args)
+
+#define GL861_WRITE            0x40
+#define GL861_READ             0xc0
+
+#define GL861_REQ_I2C_WRITE    0x01
+#define GL861_REQ_I2C_READ     0x02
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
new file mode 100644 (file)
index 0000000..d48b24d
--- /dev/null
@@ -0,0 +1,541 @@
+/* DVB USB compliant linux driver for MSI Mega Sky 580 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2006 Aapo Tahkola (aet@rasterburn.org)
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the Free
+ *     Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+
+#include "m920x.h"
+
+#include "mt352.h"
+#include "mt352_priv.h"
+#include "qt1010.h"
+
+/* debug */
+static int dvb_usb_m920x_debug;
+module_param_named(debug,dvb_usb_m920x_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+
+static struct dvb_usb_rc_key megasky_rc_keys [] = {
+       { 0x0, 0x12, KEY_POWER },
+       { 0x0, 0x1e, KEY_CYCLEWINDOWS }, /* min/max */
+       { 0x0, 0x02, KEY_CHANNELUP },
+       { 0x0, 0x05, KEY_CHANNELDOWN },
+       { 0x0, 0x03, KEY_VOLUMEUP },
+       { 0x0, 0x06, KEY_VOLUMEDOWN },
+       { 0x0, 0x04, KEY_MUTE },
+       { 0x0, 0x07, KEY_OK }, /* TS */
+       { 0x0, 0x08, KEY_STOP },
+       { 0x0, 0x09, KEY_MENU }, /* swap */
+       { 0x0, 0x0a, KEY_REWIND },
+       { 0x0, 0x1b, KEY_PAUSE },
+       { 0x0, 0x1f, KEY_FASTFORWARD },
+       { 0x0, 0x0c, KEY_RECORD },
+       { 0x0, 0x0d, KEY_CAMERA }, /* screenshot */
+       { 0x0, 0x0e, KEY_COFFEE }, /* "MTS" */
+};
+
+static inline int m9206_read(struct usb_device *udev, u8 request, u16 value,\
+                            u16 index, void *data, int size)
+{
+       int ret;
+
+       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+                             request, USB_TYPE_VENDOR | USB_DIR_IN,
+                             value, index, data, size, 2000);
+       if (ret < 0)
+               return ret;
+
+       if (ret != size)
+               return -EIO;
+
+       return 0;
+}
+
+static inline int m9206_write(struct usb_device *udev, u8 request,
+                             u16 value, u16 index)
+{
+       int ret;
+
+       ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                             request, USB_TYPE_VENDOR | USB_DIR_OUT,
+                             value, index, NULL, 0, 2000);
+       return ret;
+}
+
+static int m9206_rc_init(struct usb_device *udev)
+{
+       int ret = 0;
+
+       /* Remote controller init. */
+       if ((ret = m9206_write(udev, M9206_CORE, 0xa8, M9206_RC_INIT2)) != 0)
+               return ret;
+
+       if ((ret = m9206_write(udev, M9206_CORE, 0x51, M9206_RC_INIT1)) != 0)
+               return ret;
+
+       return ret;
+}
+
+static int m9206_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+       struct m9206_state *m = d->priv;
+       int i, ret = 0;
+       u8 rc_state[2];
+
+
+       if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0)
+               goto unlock;
+
+       if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0)
+               goto unlock;
+
+       for (i = 0; i < ARRAY_SIZE(megasky_rc_keys); i++)
+               if (megasky_rc_keys[i].data == rc_state[1]) {
+                       *event = megasky_rc_keys[i].event;
+
+                       switch(rc_state[0]) {
+                       case 0x80:
+                               *state = REMOTE_NO_KEY_PRESSED;
+                               goto unlock;
+
+                       case 0x93:
+                       case 0x92:
+                               m->rep_count = 0;
+                               *state = REMOTE_KEY_PRESSED;
+                               goto unlock;
+
+                       case 0x91:
+                               /* For comfort. */
+                               if (++m->rep_count > 2)
+                                       *state = REMOTE_KEY_REPEAT;
+                               goto unlock;
+
+                       default:
+                               deb_rc("Unexpected rc response %x\n", rc_state[0]);
+                               *state = REMOTE_NO_KEY_PRESSED;
+                               goto unlock;
+                       }
+               }
+
+       if (rc_state[1] != 0)
+               deb_rc("Unknown rc key %x\n", rc_state[1]);
+
+       *state = REMOTE_NO_KEY_PRESSED;
+
+       unlock:
+
+       return ret;
+}
+
+/* I2C */
+static int m9206_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+                         int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       struct m9206_state *m = d->priv;
+       int i;
+       int ret = 0;
+
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       if (num > 2)
+               return -EINVAL;
+
+       for (i = 0; i < num; i++) {
+               if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].addr, 0x80)) != 0)
+                       goto unlock;
+
+               if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[0], 0x0)) != 0)
+                       goto unlock;
+
+               if (i + 1 < num && msg[i + 1].flags & I2C_M_RD) {
+                       int i2c_i;
+
+                       for (i2c_i = 0; i2c_i < M9206_I2C_MAX; i2c_i++)
+                               if (msg[i].addr == m->i2c_r[i2c_i].addr)
+                                       break;
+
+                       if (i2c_i >= M9206_I2C_MAX) {
+                               deb_rc("No magic for i2c addr!\n");
+                               ret = -EINVAL;
+                               goto unlock;
+                       }
+
+                       if ((ret = m9206_write(d->udev, M9206_I2C, m->i2c_r[i2c_i].magic, 0x80)) != 0)
+                               goto unlock;
+
+                       if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x60, msg[i + 1].buf, msg[i + 1].len)) != 0)
+                               goto unlock;
+
+                       i++;
+               } else {
+                       if (msg[i].len != 2)
+                               return -EINVAL;
+
+                       if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[1], 0x40)) != 0)
+                               goto unlock;
+               }
+       }
+       ret = i;
+       unlock:
+       mutex_unlock(&d->i2c_mutex);
+
+       return ret;
+}
+
+static u32 m9206_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm m9206_i2c_algo = {
+       .master_xfer   = m9206_i2c_xfer,
+       .functionality = m9206_i2c_func,
+};
+
+
+static int m9206_set_filter(struct dvb_usb_adapter *adap, int type, int idx,
+                           int pid)
+{
+       int ret = 0;
+
+       if (pid >= 0x8000)
+               return -EINVAL;
+
+       pid |= 0x8000;
+
+       if ((ret = m9206_write(adap->dev->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0)
+               return ret;
+
+       if ((ret = m9206_write(adap->dev->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0)
+               return ret;
+
+       return ret;
+}
+
+static int m9206_update_filters(struct dvb_usb_adapter *adap)
+{
+       struct m9206_state *m = adap->dev->priv;
+       int enabled = m->filtering_enabled;
+       int i, ret = 0, filter = 0;
+
+       for (i = 0; i < M9206_MAX_FILTERS; i++)
+               if (m->filters[i] == 8192)
+                       enabled = 0;
+
+       /* Disable all filters */
+       if ((ret = m9206_set_filter(adap, 0x81, 1, enabled)) != 0)
+               return ret;
+
+       for (i = 0; i < M9206_MAX_FILTERS; i++)
+               if ((ret = m9206_set_filter(adap, 0x81, i + 2, 0)) != 0)
+                       return ret;
+
+       if ((ret = m9206_set_filter(adap, 0x82, 0, 0x0)) != 0)
+               return ret;
+
+       /* Set */
+       if (enabled) {
+               for (i = 0; i < M9206_MAX_FILTERS; i++) {
+                       if (m->filters[i] == 0)
+                               continue;
+
+                       if ((ret = m9206_set_filter(adap, 0x81, filter + 2, m->filters[i])) != 0)
+                               return ret;
+
+                       filter++;
+               }
+       }
+
+       if ((ret = m9206_set_filter(adap, 0x82, 0, 0x02f5)) != 0)
+               return ret;
+
+       return ret;
+}
+
+static int m9206_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+       struct m9206_state *m = adap->dev->priv;
+
+       m->filtering_enabled = onoff ? 1 : 0;
+
+       return m9206_update_filters(adap);
+}
+
+static int m9206_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
+                           int onoff)
+{
+       struct m9206_state *m = adap->dev->priv;
+
+       m->filters[index] = onoff ? pid : 0;
+
+       return m9206_update_filters(adap);
+}
+
+static int m9206_firmware_download(struct usb_device *udev,
+                                  const struct firmware *fw)
+{
+       u16 value, index, size;
+       u8 read[4], *buff;
+       int i, pass, ret = 0;
+
+       buff = kmalloc(65536, GFP_KERNEL);
+
+       if ((ret = m9206_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0)
+               goto done;
+       deb_rc("%x %x %x %x\n", read[0], read[1], read[2], read[3]);
+
+       if ((ret = m9206_read(udev, M9206_FW, 0x0, 0x0, read, 1)) != 0)
+               goto done;
+       deb_rc("%x\n", read[0]);
+
+       for (pass = 0; pass < 2; pass++) {
+               for (i = 0; i + (sizeof(u16) * 3) < fw->size;) {
+                       value = le16_to_cpu(*(u16 *)(fw->data + i));
+                       i += sizeof(u16);
+
+                       index = le16_to_cpu(*(u16 *)(fw->data + i));
+                       i += sizeof(u16);
+
+                       size = le16_to_cpu(*(u16 *)(fw->data + i));
+                       i += sizeof(u16);
+
+                       if (pass == 1) {
+                               /* Will stall if using fw->data ... */
+                               memcpy(buff, fw->data + i, size);
+
+                               ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0),
+                                           M9206_FW,
+                                           USB_TYPE_VENDOR | USB_DIR_OUT,
+                                           value, index, buff, size, 20);
+                               if (ret != size) {
+                                       deb_rc("error while uploading fw!\n");
+                                       ret = -EIO;
+                                       goto done;
+                               }
+                               msleep(3);
+                       }
+                       i += size;
+               }
+               if (i != fw->size) {
+                       ret = -EINVAL;
+                       goto done;
+               }
+       }
+
+       msleep(36);
+
+       /* m9206 will disconnect itself from the bus after this. */
+       (void) m9206_write(udev, M9206_CORE, 0x01, M9206_FW_GO);
+       deb_rc("firmware uploaded!\n");
+
+       done:
+       kfree(buff);
+
+       return ret;
+}
+
+/* Callbacks for DVB USB */
+static int megasky_identify_state(struct usb_device *udev,
+                                 struct dvb_usb_device_properties *props,
+                                 struct dvb_usb_device_description **desc,
+                                 int *cold)
+{
+       struct usb_host_interface *alt;
+
+       alt = usb_altnum_to_altsetting(usb_ifnum_to_if(udev, 0), 1);
+       *cold = (alt == NULL) ? 1 : 0;
+
+       return 0;
+}
+
+static int megasky_mt352_demod_init(struct dvb_frontend *fe)
+{
+       u8 config[] = { CONFIG, 0x3d };
+       u8 clock[] = { CLOCK_CTL, 0x30 };
+       u8 reset[] = { RESET, 0x80 };
+       u8 adc_ctl[] = { ADC_CTL_1, 0x40 };
+       u8 agc[] = { AGC_TARGET, 0x1c, 0x20 };
+       u8 sec_agc[] = { 0x69, 0x00, 0xff, 0xff, 0x40, 0xff, 0x00, 0x40, 0x40 };
+       u8 unk1[] = { 0x93, 0x1a };
+       u8 unk2[] = { 0xb5, 0x7a };
+
+       mt352_write(fe, config, ARRAY_SIZE(config));
+       mt352_write(fe, clock, ARRAY_SIZE(clock));
+       mt352_write(fe, reset, ARRAY_SIZE(reset));
+       mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl));
+       mt352_write(fe, agc, ARRAY_SIZE(agc));
+       mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc));
+       mt352_write(fe, unk1, ARRAY_SIZE(unk1));
+       mt352_write(fe, unk2, ARRAY_SIZE(unk2));
+
+       deb_rc("Demod init!\n");
+
+       return 0;
+}
+
+static struct mt352_config megasky_mt352_config = {
+       .demod_address = 0x1e,
+       .no_tuner = 1,
+       .demod_init = megasky_mt352_demod_init,
+};
+
+static int megasky_mt352_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct m9206_state *m = adap->dev->priv;
+
+       deb_rc("megasky_frontend_attach!\n");
+
+       m->i2c_r[M9206_I2C_DEMOD].addr = megasky_mt352_config.demod_address;
+       m->i2c_r[M9206_I2C_DEMOD].magic = 0x1f;
+
+       if ((adap->fe = dvb_attach(mt352_attach, &megasky_mt352_config, &adap->dev->i2c_adap)) == NULL)
+               return -EIO;
+
+       return 0;
+}
+
+static struct qt1010_config megasky_qt1010_config = {
+       .i2c_address = 0xc4
+};
+
+static int megasky_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct m9206_state *m = adap->dev->priv;
+
+       m->i2c_r[M9206_I2C_TUNER].addr = megasky_qt1010_config.i2c_address;
+       m->i2c_r[M9206_I2C_TUNER].magic = 0xc5;
+
+       if (dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap,
+                      &megasky_qt1010_config) == NULL)
+               return -ENODEV;
+
+       return 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties megasky_properties;
+
+static int m920x_probe(struct usb_interface *intf,
+                      const struct usb_device_id *id)
+{
+       struct dvb_usb_device *d;
+       struct usb_host_interface *alt;
+       int ret;
+
+       if ((ret = dvb_usb_device_init(intf, &megasky_properties, THIS_MODULE, &d)) == 0) {
+               deb_rc("probed!\n");
+
+               alt = usb_altnum_to_altsetting(intf, 1);
+               if (alt == NULL) {
+                       deb_rc("not alt found!\n");
+                       return -ENODEV;
+               }
+
+               ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
+                                       alt->desc.bAlternateSetting);
+               if (ret < 0)
+                       return ret;
+
+               deb_rc("Changed to alternate setting!\n");
+
+               if ((ret = m9206_rc_init(d->udev)) != 0)
+                       return ret;
+       }
+       return ret;
+}
+
+static struct usb_device_id m920x_table [] = {
+               { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) },
+               { }             /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, m920x_table);
+
+static struct dvb_usb_device_properties megasky_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+       .usb_ctrl = DEVICE_SPECIFIC,
+       .firmware = "dvb-usb-megasky-02.fw",
+       .download_firmware = m9206_firmware_download,
+
+       .rc_interval      = 100,
+       .rc_key_map       = megasky_rc_keys,
+       .rc_key_map_size  = ARRAY_SIZE(megasky_rc_keys),
+       .rc_query         = m9206_rc_query,
+
+       .size_of_priv     = sizeof(struct m9206_state),
+
+       .identify_state   = megasky_identify_state,
+       .num_adapters = 1,
+       .adapter = {{
+               .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+                       DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+               .pid_filter_count = 8,
+               .pid_filter       = m9206_pid_filter,
+               .pid_filter_ctrl  = m9206_pid_filter_ctrl,
+
+               .frontend_attach  = megasky_mt352_frontend_attach,
+               .tuner_attach     = megasky_qt1010_tuner_attach,
+
+               .stream = {
+                       .type = USB_BULK,
+                       .count = 8,
+                       .endpoint = 0x81,
+                       .u = {
+                               .bulk = {
+                                       .buffersize = 512,
+                               }
+                       }
+               },
+       }},
+       .i2c_algo         = &m9206_i2c_algo,
+
+       .num_device_descs = 1,
+       .devices = {
+               {   "MSI Mega Sky 580 DVB-T USB2.0",
+                       { &m920x_table[0], NULL },
+                       { NULL },
+               },
+       }
+};
+
+static struct usb_driver m920x_driver = {
+       .name           = "dvb_usb_m920x",
+       .probe          = m920x_probe,
+       .disconnect     = dvb_usb_device_exit,
+       .id_table       = m920x_table,
+};
+
+/* module stuff */
+static int __init m920x_module_init(void)
+{
+       int ret;
+
+       if ((ret = usb_register(&m920x_driver))) {
+               err("usb_register failed. Error number %d", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void __exit m920x_module_exit(void)
+{
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&m920x_driver);
+}
+
+module_init (m920x_module_init);
+module_exit (m920x_module_exit);
+
+MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
+MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / Uli m920x");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/m920x.h b/drivers/media/dvb/dvb-usb/m920x.h
new file mode 100644 (file)
index 0000000..c354196
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _DVB_USB_M920X_H_
+#define _DVB_USB_M920X_H_
+
+#define DVB_USB_LOG_PREFIX "m920x"
+#include "dvb-usb.h"
+
+#define deb_rc(args...)   dprintk(dvb_usb_m920x_debug,0x01,args)
+
+#define M9206_CORE     0x22
+#define M9206_RC_STATE 0xff51
+#define M9206_RC_KEY   0xff52
+#define M9206_RC_INIT1 0xff54
+#define M9206_RC_INIT2 0xff55
+#define M9206_FW_GO    0xff69
+
+#define M9206_I2C      0x23
+#define M9206_FILTER   0x25
+#define M9206_FW       0x30
+
+#define M9206_MAX_FILTERS 8
+
+#define M9206_I2C_TUNER        0
+#define M9206_I2C_DEMOD        1
+#define M9206_I2C_MAX  2
+
+struct m9206_state {
+       u16 filters[M9206_MAX_FILTERS];
+       int filtering_enabled;
+       int rep_count;
+       struct {
+               unsigned char addr;
+               unsigned char magic;
+       }i2c_r[M9206_I2C_MAX];
+};
+#endif
index af314bb..22c2cf2 100644 (file)
@@ -290,6 +290,13 @@ config DVB_TDA826X
        help
          A DVB-S silicon tuner module. Say Y when you want to support this tuner.
 
+config DVB_TUNER_QT1010
+       tristate "Quantek QT1010 silicon tuner"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A driver for the silicon tuner QT1010 from Quantek.
+
 config DVB_TUNER_MT2060
        tristate "Microtune MT2060 silicon IF tuner"
        depends on I2C
index 3fa6e5d..a646d99 100644 (file)
@@ -38,5 +38,6 @@ obj-$(CONFIG_DVB_ISL6421) += isl6421.o
 obj-$(CONFIG_DVB_TDA10086) += tda10086.o
 obj-$(CONFIG_DVB_TDA826X) += tda826x.o
 obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
+obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
 obj-$(CONFIG_DVB_TUA6100) += tua6100.o
 obj-$(CONFIG_DVB_TUNER_LGH06XF) += lgh06xf.o
index ae96395..10fc0c8 100644 (file)
@@ -254,7 +254,7 @@ static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
        if (srate<500000)
                srate=500000;
 
-       for(i=0;(i<sizeof(bands)/sizeof(bands[0]))&&(srate>bands[i]);i++)
+       for(i = 0; (i < ARRAY_SIZE(bands)) && (srate>bands[i]); i++)
                ;
        /* first, check which sample rate is appropriate: 45, 60 80 or 90 MHz,
           and set the PLL accordingly (R07[1:0] Fclk, R06[7:4] PLLmult,
@@ -361,7 +361,7 @@ static int cx24110_initfe(struct dvb_frontend* fe)
 
        dprintk("%s: init chip\n", __FUNCTION__);
 
-       for(i=0;i<sizeof(cx24110_regdata)/sizeof(cx24110_regdata[0]);i++) {
+       for(i = 0; i < ARRAY_SIZE(cx24110_regdata); i++) {
                cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);
        };
 
index a356d28..732e94a 100644 (file)
@@ -507,7 +507,7 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa
        int i = 0;
        int pump = 2;
        int band = 0;
-       int num_bands = sizeof(cx24123_bandselect_vals) / sizeof(cx24123_bandselect_vals[0]);
+       int num_bands = ARRAY_SIZE(cx24123_bandselect_vals);
 
        /* Defaults for low freq, low rate */
        state->VCAarg = cx24123_AGC_vals[0].VCAprogdata;
@@ -516,7 +516,7 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa
        vco_div = cx24123_bandselect_vals[0].VCOdivider;
 
        /* For the given symbol rate, determine the VCA, VGA and FILTUNE programming bits */
-       for (i = 0; i < sizeof(cx24123_AGC_vals) / sizeof(cx24123_AGC_vals[0]); i++)
+       for (i = 0; i < ARRAY_SIZE(cx24123_AGC_vals); i++)
        {
                if ((cx24123_AGC_vals[i].symbolrate_low <= p->u.qpsk.symbol_rate) &&
                    (cx24123_AGC_vals[i].symbolrate_high >= p->u.qpsk.symbol_rate) ) {
@@ -658,7 +658,7 @@ static int cx24123_initfe(struct dvb_frontend* fe)
        dprintk("%s:  init frontend\n",__FUNCTION__);
 
        /* Configure the demod to a good set of defaults */
-       for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
+       for (i = 0; i < ARRAY_SIZE(cx24123_regdata); i++)
                cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
 
        /* Set the LNB polarity */
index 23aa75a..054d7e6 100644 (file)
@@ -475,7 +475,7 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx
        tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha;
        dib3000mc_write_word(state, 0, tmp);
 
-       dib3000mc_write_word(state, 5, seq);
+       dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4));
 
        tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp);
        if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp))
diff --git a/drivers/media/dvb/frontends/qt1010.c b/drivers/media/dvb/frontends/qt1010.c
new file mode 100644 (file)
index 0000000..825aa14
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+ *  Driver for Quantek QT1010 silicon tuner
+ *
+ *  Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ *                     Aapo Tahkola <aet@rasterburn.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include "qt1010.h"
+#include "qt1010_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(args...) \
+       do { \
+               if (debug) printk(KERN_DEBUG "QT1010: " args); \
+       } while (0)
+
+/* read single register */
+static int qt1010_readreg(struct qt1010_priv *priv, u8 reg, u8 *val)
+{
+       struct i2c_msg msg[2] = {
+               { .addr = priv->cfg->i2c_address,
+                 .flags = 0, .buf = &reg, .len = 1 },
+               { .addr = priv->cfg->i2c_address,
+                 .flags = I2C_M_RD, .buf = val, .len = 1 },
+       };
+
+       if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+               printk(KERN_WARNING "qt1010 I2C read failed\n");
+               return -EREMOTEIO;
+       }
+       return 0;
+}
+
+/* write single register */
+static int qt1010_writereg(struct qt1010_priv *priv, u8 reg, u8 val)
+{
+       u8 buf[2] = { reg, val };
+       struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+                              .flags = 0, .buf = buf, .len = 2 };
+
+       if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+               printk(KERN_WARNING "qt1010 I2C write failed\n");
+               return -EREMOTEIO;
+       }
+       return 0;
+}
+
+/* dump all registers */
+static void qt1010_dump_regs(struct qt1010_priv *priv)
+{
+       char buf[52], buf2[4];
+       u8 reg, val;
+
+       for (reg = 0; ; reg++) {
+               if (reg % 16 == 0) {
+                       if (reg)
+                               printk("%s\n", buf);
+                       sprintf(buf, "%02x: ", reg);
+               }
+               if (qt1010_readreg(priv, reg, &val) == 0)
+                       sprintf(buf2, "%02x ", val);
+               else
+                       strcpy(buf2, "-- ");
+               strcat(buf, buf2);
+               if (reg == 0x2f)
+                       break;
+       }
+       printk("%s\n", buf);
+}
+
+static int qt1010_set_params(struct dvb_frontend *fe,
+                            struct dvb_frontend_parameters *params)
+{
+       struct qt1010_priv *priv;
+       int err;
+       u32 freq, div, mod1, mod2;
+       u8 i, tmpval, reg05;
+       qt1010_i2c_oper_t rd[48] = {
+               { QT1010_WR, 0x01, 0x80 },
+               { QT1010_WR, 0x02, 0x3f },
+               { QT1010_WR, 0x05, 0xff }, /* 02 c write */
+               { QT1010_WR, 0x06, 0x44 },
+               { QT1010_WR, 0x07, 0xff }, /* 04 c write */
+               { QT1010_WR, 0x08, 0x08 },
+               { QT1010_WR, 0x09, 0xff }, /* 06 c write */
+               { QT1010_WR, 0x0a, 0xff }, /* 07 c write */
+               { QT1010_WR, 0x0b, 0xff }, /* 08 c write */
+               { QT1010_WR, 0x0c, 0xe1 },
+               { QT1010_WR, 0x1a, 0xff }, /* 10 c write */
+               { QT1010_WR, 0x1b, 0x00 },
+               { QT1010_WR, 0x1c, 0x89 },
+               { QT1010_WR, 0x11, 0xff }, /* 13 c write */
+               { QT1010_WR, 0x12, 0xff }, /* 14 c write */
+               { QT1010_WR, 0x22, 0xff }, /* 15 c write */
+               { QT1010_WR, 0x1e, 0x00 },
+               { QT1010_WR, 0x1e, 0xd0 },
+               { QT1010_RD, 0x22, 0xff }, /* 16 c read */
+               { QT1010_WR, 0x1e, 0x00 },
+               { QT1010_RD, 0x05, 0xff }, /* 20 c read */
+               { QT1010_RD, 0x22, 0xff }, /* 21 c read */
+               { QT1010_WR, 0x23, 0xd0 },
+               { QT1010_WR, 0x1e, 0x00 },
+               { QT1010_WR, 0x1e, 0xe0 },
+               { QT1010_RD, 0x23, 0xff }, /* 25 c read */
+               { QT1010_RD, 0x23, 0xff }, /* 26 c read */
+               { QT1010_WR, 0x1e, 0x00 },
+               { QT1010_WR, 0x24, 0xd0 },
+               { QT1010_WR, 0x1e, 0x00 },
+               { QT1010_WR, 0x1e, 0xf0 },
+               { QT1010_RD, 0x24, 0xff }, /* 31 c read */
+               { QT1010_WR, 0x1e, 0x00 },
+               { QT1010_WR, 0x14, 0x7f },
+               { QT1010_WR, 0x15, 0x7f },
+               { QT1010_WR, 0x05, 0xff }, /* 35 c write */
+               { QT1010_WR, 0x06, 0x00 },
+               { QT1010_WR, 0x15, 0x1f },
+               { QT1010_WR, 0x16, 0xff },
+               { QT1010_WR, 0x18, 0xff },
+               { QT1010_WR, 0x1f, 0xff }, /* 40 c write */
+               { QT1010_WR, 0x20, 0xff }, /* 41 c write */
+               { QT1010_WR, 0x21, 0x53 },
+               { QT1010_WR, 0x25, 0xff }, /* 43 c write */
+               { QT1010_WR, 0x26, 0x15 },
+               { QT1010_WR, 0x00, 0xff }, /* 45 c write */
+               { QT1010_WR, 0x02, 0x00 },
+               { QT1010_WR, 0x01, 0x00 }
+       };
+
+#define FREQ1 32000000 /* 32 MHz */
+#define FREQ2  4000000 /* 4 MHz Quartz oscillator in the stick? */
+
+       priv = fe->tuner_priv;
+       freq = params->frequency;
+       div = (freq + QT1010_OFFSET) / QT1010_STEP;
+       freq = (div * QT1010_STEP) - QT1010_OFFSET;
+       mod1 = (freq + QT1010_OFFSET) % FREQ1;
+       mod2 = (freq + QT1010_OFFSET) % FREQ2;
+       priv->bandwidth =
+               (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+       priv->frequency = freq;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+       /* reg 05 base value */
+       if      (freq < 290000000) reg05 = 0x14; /* 290 MHz */
+       else if (freq < 610000000) reg05 = 0x34; /* 610 MHz */
+       else if (freq < 802000000) reg05 = 0x54; /* 802 MHz */
+       else                       reg05 = 0x74;
+
+       /* 0x5 */
+       rd[2].val = reg05;
+
+       /* 07 - set frequency: 32 MHz scale */
+       rd[4].val = (freq + QT1010_OFFSET) / FREQ1;
+
+       /* 09 - changes every 8/24 MHz */
+       if (mod1 < 8000000) rd[6].val = 0x1d;
+       else                rd[6].val = 0x1c;
+
+       /* 0a - set frequency: 4 MHz scale (max 28 MHz) */
+       if      (mod1 < 1*FREQ2) rd[7].val = 0x09; /*  +0 MHz */
+       else if (mod1 < 2*FREQ2) rd[7].val = 0x08; /*  +4 MHz */
+       else if (mod1 < 3*FREQ2) rd[7].val = 0x0f; /*  +8 MHz */
+       else if (mod1 < 4*FREQ2) rd[7].val = 0x0e; /* +12 MHz */
+       else if (mod1 < 5*FREQ2) rd[7].val = 0x0d; /* +16 MHz */
+       else if (mod1 < 6*FREQ2) rd[7].val = 0x0c; /* +20 MHz */
+       else if (mod1 < 7*FREQ2) rd[7].val = 0x0b; /* +24 MHz */
+       else                     rd[7].val = 0x0a; /* +28 MHz */
+
+       /* 0b - changes every 2/2 MHz */
+       if (mod2 < 2000000) rd[8].val = 0x45;
+       else                rd[8].val = 0x44;
+
+       /* 1a - set frequency: 125 kHz scale (max 3875 kHz)*/
+       tmpval = 0x78; /* byte, overflows intentionally */
+       rd[10].val = tmpval-((mod2/QT1010_STEP)*0x08);
+
+       /* 11 */
+       rd[13].val = 0xfd; /* TODO: correct value calculation */
+
+       /* 12 */
+       rd[14].val = 0x91; /* TODO: correct value calculation */
+
+       /* 22 */
+       if      (freq < 450000000) rd[15].val = 0xd0; /* 450 MHz */
+       else if (freq < 482000000) rd[15].val = 0xd1; /* 482 MHz */
+       else if (freq < 514000000) rd[15].val = 0xd4; /* 514 MHz */
+       else if (freq < 546000000) rd[15].val = 0xd7; /* 546 MHz */
+       else if (freq < 610000000) rd[15].val = 0xda; /* 610 MHz */
+       else                       rd[15].val = 0xd0;
+
+       /* 05 */
+       rd[35].val = (reg05 & 0xf0);
+
+       /* 1f */
+       if      (mod1 <  8000000) tmpval = 0x00;
+       else if (mod1 < 12000000) tmpval = 0x01;
+       else if (mod1 < 16000000) tmpval = 0x02;
+       else if (mod1 < 24000000) tmpval = 0x03;
+       else if (mod1 < 28000000) tmpval = 0x04;
+       else                      tmpval = 0x05;
+       rd[40].val = (priv->reg1f_init_val + 0x0e + tmpval);
+
+       /* 20 */
+       if      (mod1 <  8000000) tmpval = 0x00;
+       else if (mod1 < 12000000) tmpval = 0x01;
+       else if (mod1 < 20000000) tmpval = 0x02;
+       else if (mod1 < 24000000) tmpval = 0x03;
+       else if (mod1 < 28000000) tmpval = 0x04;
+       else                      tmpval = 0x05;
+       rd[41].val = (priv->reg20_init_val + 0x0d + tmpval);
+
+       /* 25 */
+       rd[43].val = priv->reg25_init_val;
+
+       /* 00 */
+       rd[45].val = 0x92; /* TODO: correct value calculation */
+
+       dprintk("freq:%u 05:%02x 07:%02x 09:%02x 0a:%02x 0b:%02x " \
+               "1a:%02x 11:%02x 12:%02x 22:%02x 05:%02x 1f:%02x " \
+               "20:%02x 25:%02x 00:%02x", \
+               freq, rd[2].val, rd[4].val, rd[6].val, rd[7].val, rd[8].val, \
+               rd[10].val, rd[13].val, rd[14].val, rd[15].val, rd[35].val, \
+               rd[40].val, rd[41].val, rd[43].val, rd[45].val);
+
+       for (i = 0; i < ARRAY_SIZE(rd); i++) {
+               if (rd[i].oper == QT1010_WR) {
+                       err = qt1010_writereg(priv, rd[i].reg, rd[i].val);
+               } else { /* read is required to proper locking */
+                       err = qt1010_readreg(priv, rd[i].reg, &tmpval);
+               }
+               if (err) return err;
+       }
+
+       if (debug)
+               qt1010_dump_regs(priv);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+       return 0;
+}
+
+static int qt1010_init_meas1(struct qt1010_priv *priv,
+                            u8 oper, u8 reg, u8 reg_init_val, u8 *retval)
+{
+       u8 i, val1, val2;
+       int err;
+
+       qt1010_i2c_oper_t i2c_data[] = {
+               { QT1010_WR, reg, reg_init_val },
+               { QT1010_WR, 0x1e, 0x00 },
+               { QT1010_WR, 0x1e, oper },
+               { QT1010_RD, reg, 0xff }
+       };
+
+       for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
+               if (i2c_data[i].oper == QT1010_WR) {
+                       err = qt1010_writereg(priv, i2c_data[i].reg,
+                                             i2c_data[i].val);
+               } else {
+                       err = qt1010_readreg(priv, i2c_data[i].reg, &val2);
+               }
+               if (err) return err;
+       }
+
+       do {
+               val1 = val2;
+               err = qt1010_readreg(priv, reg, &val2);
+               if (err) return err;
+               dprintk("compare reg:%02x %02x %02x", reg, val1, val2);
+       } while (val1 != val2);
+       *retval = val1;
+
+       return qt1010_writereg(priv, 0x1e, 0x00);
+}
+
+static u8 qt1010_init_meas2(struct qt1010_priv *priv,
+                           u8 reg_init_val, u8 *retval)
+{
+       u8 i, val;
+       int err;
+       qt1010_i2c_oper_t i2c_data[] = {
+               { QT1010_WR, 0x07, reg_init_val },
+               { QT1010_WR, 0x22, 0xd0 },
+               { QT1010_WR, 0x1e, 0x00 },
+               { QT1010_WR, 0x1e, 0xd0 },
+               { QT1010_RD, 0x22, 0xff },
+               { QT1010_WR, 0x1e, 0x00 },
+               { QT1010_WR, 0x22, 0xff }
+       };
+       for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
+               if (i2c_data[i].oper == QT1010_WR) {
+                       err = qt1010_writereg(priv, i2c_data[i].reg,
+                                             i2c_data[i].val);
+               } else {
+                       err = qt1010_readreg(priv, i2c_data[i].reg, &val);
+               }
+               if (err) return err;
+       }
+       *retval = val;
+       return 0;
+}
+
+static int qt1010_init(struct dvb_frontend *fe)
+{
+       struct qt1010_priv *priv = fe->tuner_priv;
+       struct dvb_frontend_parameters params;
+       int err = 0;
+       u8 i, tmpval, *valptr = NULL;
+
+       qt1010_i2c_oper_t i2c_data[] = {
+               { QT1010_WR, 0x01, 0x80 },
+               { QT1010_WR, 0x0d, 0x84 },
+               { QT1010_WR, 0x0e, 0xb7 },
+               { QT1010_WR, 0x2a, 0x23 },
+               { QT1010_WR, 0x2c, 0xdc },
+               { QT1010_M1, 0x25, 0x40 }, /* get reg 25 init value */
+               { QT1010_M1, 0x81, 0xff }, /* get reg 25 init value */
+               { QT1010_WR, 0x2b, 0x70 },
+               { QT1010_WR, 0x2a, 0x23 },
+               { QT1010_M1, 0x26, 0x08 },
+               { QT1010_M1, 0x82, 0xff },
+               { QT1010_WR, 0x05, 0x14 },
+               { QT1010_WR, 0x06, 0x44 },
+               { QT1010_WR, 0x07, 0x28 },
+               { QT1010_WR, 0x08, 0x0b },
+               { QT1010_WR, 0x11, 0xfd },
+               { QT1010_M1, 0x22, 0x0d },
+               { QT1010_M1, 0xd0, 0xff },
+               { QT1010_WR, 0x06, 0x40 },
+               { QT1010_WR, 0x16, 0xf0 },
+               { QT1010_WR, 0x02, 0x38 },
+               { QT1010_WR, 0x03, 0x18 },
+               { QT1010_WR, 0x20, 0xe0 },
+               { QT1010_M1, 0x1f, 0x20 }, /* get reg 1f init value */
+               { QT1010_M1, 0x84, 0xff }, /* get reg 1f init value */
+               { QT1010_RD, 0x20, 0x20 }, /* get reg 20 init value */
+               { QT1010_WR, 0x03, 0x19 },
+               { QT1010_WR, 0x02, 0x3f },
+               { QT1010_WR, 0x21, 0x53 },
+               { QT1010_RD, 0x21, 0xff },
+               { QT1010_WR, 0x11, 0xfd },
+               { QT1010_WR, 0x05, 0x34 },
+               { QT1010_WR, 0x06, 0x44 },
+               { QT1010_WR, 0x08, 0x08 }
+       };
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+       for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
+               switch (i2c_data[i].oper) {
+               case QT1010_WR:
+                       err = qt1010_writereg(priv, i2c_data[i].reg,
+                                             i2c_data[i].val);
+                       break;
+               case QT1010_RD:
+                       if (i2c_data[i].val == 0x20)
+                               valptr = &priv->reg20_init_val;
+                       else
+                               valptr = &tmpval;
+                       err = qt1010_readreg(priv, i2c_data[i].reg, valptr);
+                       break;
+               case QT1010_M1:
+                       if (i2c_data[i].val == 0x25)
+                               valptr = &priv->reg25_init_val;
+                       else if (i2c_data[i].val == 0x1f)
+                               valptr = &priv->reg1f_init_val;
+                       else
+                               valptr = &tmpval;
+                       err = qt1010_init_meas1(priv, i2c_data[i+1].reg,
+                                               i2c_data[i].reg,
+                                               i2c_data[i].val, valptr);
+                       i++;
+                       break;
+               }
+               if (err) return err;
+       }
+
+       for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */
+               if ((err = qt1010_init_meas2(priv, i, &tmpval)))
+                       return err;
+
+       params.frequency = 545000000; /* Sigmatek DVB-110 545000000 */
+                                     /* MSI Megasky 580 GL861 533000000 */
+       return qt1010_set_params(fe, &params);
+}
+
+static int qt1010_release(struct dvb_frontend *fe)
+{
+       kfree(fe->tuner_priv);
+       fe->tuner_priv = NULL;
+       return 0;
+}
+
+static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct qt1010_priv *priv = fe->tuner_priv;
+       *frequency = priv->frequency;
+       return 0;
+}
+
+static int qt1010_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+       struct qt1010_priv *priv = fe->tuner_priv;
+       *bandwidth = priv->bandwidth;
+       return 0;
+}
+
+static const struct dvb_tuner_ops qt1010_tuner_ops = {
+       .info = {
+               .name           = "Quantek QT1010",
+               .frequency_min  = QT1010_MIN_FREQ,
+               .frequency_max  = QT1010_MAX_FREQ,
+               .frequency_step = QT1010_STEP,
+       },
+
+       .release       = qt1010_release,
+       .init          = qt1010_init,
+       /* TODO: implement sleep */
+
+       .set_params    = qt1010_set_params,
+       .get_frequency = qt1010_get_frequency,
+       .get_bandwidth = qt1010_get_bandwidth
+};
+
+struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe,
+                                   struct i2c_adapter *i2c,
+                                   struct qt1010_config *cfg)
+{
+       struct qt1010_priv *priv = NULL;
+       u8 id;
+
+       priv = kzalloc(sizeof(struct qt1010_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return NULL;
+
+       priv->cfg = cfg;
+       priv->i2c = i2c;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+
+       /* Try to detect tuner chip. Probably this is not correct register. */
+       if (qt1010_readreg(priv, 0x29, &id) != 0 || (id != 0x39)) {
+               kfree(priv);
+               return NULL;
+       }
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+       printk(KERN_INFO "Quantek QT1010 successfully identified.\n");
+       memcpy(&fe->ops.tuner_ops, &qt1010_tuner_ops,
+              sizeof(struct dvb_tuner_ops));
+
+       fe->tuner_priv = priv;
+       return fe;
+}
+EXPORT_SYMBOL(qt1010_attach);
+
+MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/qt1010.h b/drivers/media/dvb/frontends/qt1010.h
new file mode 100644 (file)
index 0000000..3ab4aa0
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  Driver for Quantek QT1010 silicon tuner
+ *
+ *  Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ *                     Aapo Tahkola <aet@rasterburn.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef QT1010_H
+#define QT1010_H
+
+#include "dvb_frontend.h"
+
+struct qt1010_config {
+       u8 i2c_address;
+};
+
+/**
+ * Attach a qt1010 tuner to the supplied frontend structure.
+ *
+ * @param fe   frontend to attach to
+ * @param i2c  i2c adapter to use
+ * @param cfg  tuner hw based configuration
+ * @return fe  pointer on success, NULL on failure
+ */
+#if defined(CONFIG_DVB_TUNER_QT1010) || (defined(CONFIG_DVB_TUNER_QT1010_MODULE) && defined(MODULE))
+extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe,
+                                         struct i2c_adapter *i2c,
+                                         struct qt1010_config *cfg);
+#else
+static inline struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe,
+                                                struct i2c_adapter *i2c,
+                                                struct qt1010_config *cfg)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+       return NULL;
+}
+#endif // CONFIG_DVB_TUNER_QT1010
+
+#endif
diff --git a/drivers/media/dvb/frontends/qt1010_priv.h b/drivers/media/dvb/frontends/qt1010_priv.h
new file mode 100644 (file)
index 0000000..090cf47
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ *  Driver for Quantek QT1010 silicon tuner
+ *
+ *  Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ *                     Aapo Tahkola <aet@rasterburn.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef QT1010_PRIV_H
+#define QT1010_PRIV_H
+
+/*
+reg def meaning
+=== === =======
+00  00  ?
+01  a0  ? operation start/stop; start=80, stop=00
+02  00  ?
+03  19  ?
+04  00  ?
+05  00  ? maybe band selection
+06  00  ?
+07  2b  set frequency: 32 MHz scale, n*32 MHz
+08  0b  ?
+09  10  ? changes every 8/24 MHz; values 1d/1c
+0a  08  set frequency: 4 MHz scale, n*4 MHz
+0b  41  ? changes every 2/2 MHz; values 45/45
+0c  e1  ?
+0d  94  ?
+0e  b6  ?
+0f  2c  ?
+10  10  ?
+11  f1  ? maybe device specified adjustment
+12  11  ? maybe device specified adjustment
+13  3f  ?
+14  1f  ?
+15  3f  ?
+16  ff  ?
+17  ff  ?
+18  f7  ?
+19  80  ?
+1a  d0  set frequency: 125 kHz scale, n*125 kHz
+1b  00  ?
+1c  89  ?
+1d  00  ?
+1e  00  ? looks like operation register; write cmd here, read result from 1f-26
+1f  20  ? chip initialization
+20  e0  ? chip initialization
+21  20  ?
+22  d0  ?
+23  d0  ?
+24  d0  ?
+25  40  ? chip initialization
+26  08  ?
+27  29  ?
+28  55  ?
+29  39  ?
+2a  13  ?
+2b  01  ?
+2c  ea  ?
+2d  00  ?
+2e  00  ? not used?
+2f  00  ? not used?
+*/
+
+#define QT1010_STEP         125000 /*  125 kHz used by Windows drivers,
+                                     hw could be more precise but we don't
+                                     know how to use */
+#define QT1010_MIN_FREQ   48000000 /*   48 MHz */
+#define QT1010_MAX_FREQ  860000000 /*  860 MHz */
+#define QT1010_OFFSET   1246000000 /* 1246 MHz */
+
+#define QT1010_WR 0
+#define QT1010_RD 1
+#define QT1010_M1 3
+
+typedef struct {
+       u8 oper, reg, val;
+} qt1010_i2c_oper_t;
+
+struct qt1010_priv {
+       struct qt1010_config *cfg;
+       struct i2c_adapter   *i2c;
+
+       u8 reg1f_init_val;
+       u8 reg20_init_val;
+       u8 reg25_init_val;
+
+       u32 frequency;
+       u32 bandwidth;
+};
+
+#endif
index 1ca6424..9a34397 100644 (file)
@@ -35,6 +35,7 @@ struct stv0297_state {
        const struct stv0297_config *config;
        struct dvb_frontend frontend;
 
+       unsigned long last_ber;
        unsigned long base_freq;
 };
 
@@ -310,6 +311,8 @@ static int stv0297_init(struct dvb_frontend *fe)
                stv0297_writereg(state, state->config->inittab[i], state->config->inittab[i+1]);
        msleep(200);
 
+       state->last_ber = 0;
+
        return 0;
 }
 
@@ -340,11 +343,13 @@ static int stv0297_read_ber(struct dvb_frontend *fe, u32 * ber)
        struct stv0297_state *state = fe->demodulator_priv;
        u8 BER[3];
 
-       stv0297_writereg(state, 0xA0, 0x80);    // Start Counting bit errors for 4096 Bytes
-       mdelay(25);             // Hopefully got 4096 Bytes
        stv0297_readregs(state, 0xA0, BER, 3);
-       mdelay(25);
-       *ber = (BER[2] << 8 | BER[1]) / (8 * 4096);
+       if (!(BER[0] & 0x80)) {
+               state->last_ber = BER[2] << 8 | BER[1];
+               stv0297_writereg_mask(state, 0xA0, 0x80, 0x80);
+       }
+
+       *ber = state->last_ber;
 
        return 0;
 }
@@ -376,9 +381,14 @@ static int stv0297_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
 {
        struct stv0297_state *state = fe->demodulator_priv;
 
+       stv0297_writereg_mask(state, 0xDF, 0x03, 0x03); /* freeze the counters */
+
        *ucblocks = (stv0297_readreg(state, 0xD5) << 8)
                | stv0297_readreg(state, 0xD4);
 
+       stv0297_writereg_mask(state, 0xDF, 0x03, 0x02); /* clear the counters */
+       stv0297_writereg_mask(state, 0xDF, 0x03, 0x01); /* re-enable the counters */
+
        return 0;
 }
 
@@ -648,6 +658,7 @@ struct dvb_frontend *stv0297_attach(const struct stv0297_config *config,
        /* setup the state */
        state->config = config;
        state->i2c = i2c;
+       state->last_ber = 0;
        state->base_freq = 0;
 
        /* check if the demod is there */
index 9348376..18768d2 100644 (file)
@@ -92,7 +92,7 @@ static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data)
        return (ret != 1) ? -EREMOTEIO : 0;
 }
 
-int stv0299_write(struct dvb_frontend* fe, u8 *buf, int len)
+static int stv0299_write(struct dvb_frontend* fe, u8 *buf, int len)
 {
        struct stv0299_state* state = fe->demodulator_priv;
 
index dca8917..5b9c5bb 100644 (file)
@@ -201,7 +201,7 @@ static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate
        return 0;
 }
 
-int tda10021_write(struct dvb_frontend* fe, u8 *buf, int len)
+static int tda10021_write(struct dvb_frontend* fe, u8 *buf, int len)
 {
        struct tda10021_state* state = fe->demodulator_priv;
 
index 00e4bcd..f4a9cf9 100644 (file)
@@ -579,7 +579,7 @@ static int tda1004x_decode_fec(int tdafec)
        return -1;
 }
 
-int tda1004x_write(struct dvb_frontend* fe, u8 *buf, int len)
+static int tda1004x_write(struct dvb_frontend* fe, u8 *buf, int len)
 {
        struct tda1004x_state* state = fe->demodulator_priv;
 
index 0e9b59a..245f9b7 100644 (file)
@@ -38,6 +38,12 @@ struct zl10353_state {
        struct zl10353_config config;
 };
 
+static int debug;
+#define dprintk(args...) \
+       do { \
+               if (debug) printk(KERN_DEBUG "zl10353: " args); \
+       } while (0)
+
 static int debug_regs = 0;
 
 static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
@@ -54,7 +60,7 @@ static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
        return 0;
 }
 
-int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen)
+static int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen)
 {
        int err, i;
        for (i = 0; i < ilen - 1; i++)
@@ -113,6 +119,36 @@ static void zl10353_dump_regs(struct dvb_frontend *fe)
        printk(KERN_DEBUG "%s\n", buf);
 }
 
+static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
+                                     enum fe_bandwidth bandwidth,
+                                     u16 *nominal_rate)
+{
+       u32 adc_clock = 22528; /* 20.480 MHz on the board(!?) */
+       u8 bw;
+       struct zl10353_state *state = fe->demodulator_priv;
+
+       if (state->config.adc_clock)
+               adc_clock = state->config.adc_clock;
+
+       switch (bandwidth) {
+       case BANDWIDTH_6_MHZ:
+               bw = 6;
+               break;
+       case BANDWIDTH_7_MHZ:
+               bw = 7;
+               break;
+       case BANDWIDTH_8_MHZ:
+       default:
+               bw = 8;
+               break;
+       }
+
+       *nominal_rate = (64 * bw * (1<<16) / (7 * 8) * 4000 / adc_clock + 2) / 4;
+
+       dprintk("%s: bw %d, adc_clock %d => 0x%x\n",
+               __FUNCTION__, bw, adc_clock, *nominal_rate);
+}
+
 static int zl10353_sleep(struct dvb_frontend *fe)
 {
        static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 };
@@ -125,7 +161,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
                                  struct dvb_frontend_parameters *param)
 {
        struct zl10353_state *state = fe->demodulator_priv;
-
+       u16 nominal_rate;
        u8 pllbuf[6] = { 0x67 };
 
        /* These settings set "auto-everything" and start the FSM. */
@@ -138,18 +174,23 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
        zl10353_single_write(fe, 0x56, 0x28);
        zl10353_single_write(fe, 0x89, 0x20);
        zl10353_single_write(fe, 0x5E, 0x00);
-       zl10353_single_write(fe, 0x65, 0x5A);
-       zl10353_single_write(fe, 0x66, 0xE9);
+
+       zl10353_calc_nominal_rate(fe, param->u.ofdm.bandwidth, &nominal_rate);
+       zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate));
+       zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate));
+
        zl10353_single_write(fe, 0x6C, 0xCD);
        zl10353_single_write(fe, 0x6D, 0x7E);
-       zl10353_single_write(fe, 0x62, 0x0A);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
 
        // 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 (fe->ops.i2c_gate_ctrl)
+                               fe->ops.i2c_gate_ctrl(fe, 0);
                }
        }
 
@@ -213,6 +254,29 @@ static int zl10353_read_status(struct dvb_frontend *fe, fe_status_t *status)
        return 0;
 }
 
+static int zl10353_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       struct zl10353_state *state = fe->demodulator_priv;
+
+       *ber = zl10353_read_register(state, RS_ERR_CNT_2) << 16 |
+              zl10353_read_register(state, RS_ERR_CNT_1) << 8 |
+              zl10353_read_register(state, RS_ERR_CNT_0);
+
+       return 0;
+}
+
+static int zl10353_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       struct zl10353_state *state = fe->demodulator_priv;
+
+       u16 signal = zl10353_read_register(state, AGC_GAIN_1) << 10 |
+                    zl10353_read_register(state, AGC_GAIN_0) << 2 | 3;
+
+       *strength = ~signal;
+
+       return 0;
+}
+
 static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
        struct zl10353_state *state = fe->demodulator_priv;
@@ -227,6 +291,16 @@ static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr)
        return 0;
 }
 
+static int zl10353_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       struct zl10353_state *state = fe->demodulator_priv;
+
+       *ucblocks = zl10353_read_register(state, RS_UBC_1) << 8 |
+                   zl10353_read_register(state, RS_UBC_0);
+
+       return 0;
+}
+
 static int zl10353_get_tune_settings(struct dvb_frontend *fe,
                                     struct dvb_frontend_tune_settings
                                         *fe_tune_settings)
@@ -261,6 +335,16 @@ static int zl10353_init(struct dvb_frontend *fe)
        return 0;
 }
 
+static int zl10353_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+       u8 val = 0x0a;
+
+       if (enable)
+               val |= 0x10;
+
+       return zl10353_single_write(fe, 0x62, val);
+}
+
 static void zl10353_release(struct dvb_frontend *fe)
 {
        struct zl10353_state *state = fe->demodulator_priv;
@@ -319,15 +403,22 @@ static struct dvb_frontend_ops zl10353_ops = {
 
        .init = zl10353_init,
        .sleep = zl10353_sleep,
+       .i2c_gate_ctrl = zl10353_i2c_gate_ctrl,
        .write = zl10353_write,
 
        .set_frontend = zl10353_set_parameters,
        .get_tune_settings = zl10353_get_tune_settings,
 
        .read_status = zl10353_read_status,
+       .read_ber = zl10353_read_ber,
+       .read_signal_strength = zl10353_read_signal_strength,
        .read_snr = zl10353_read_snr,
+       .read_ucblocks = zl10353_read_ucblocks,
 };
 
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
 module_param(debug_regs, int, 0644);
 MODULE_PARM_DESC(debug_regs, "Turn on/off frontend register dumps (default:off).");
 
index 0bc0109..cb274dc 100644 (file)
@@ -29,6 +29,9 @@ struct zl10353_config
        /* demodulator's I2C address */
        u8 demod_address;
 
+       /* frequencies in kHz */
+       int adc_clock;  // default: 22528
+
        /* set if no pll is connected to the secondary i2c bus */
        int no_tuner;
 
index b72224b..4962434 100644 (file)
 
 #define ID_ZL10353     0x14
 
+#define msb(x) (((x) >> 8) & 0xff)
+#define lsb(x) ((x) & 0xff)
+
 enum zl10353_reg_addr {
-       INTERRUPT_0     = 0x00,
-       INTERRUPT_1     = 0x01,
-       INTERRUPT_2     = 0x02,
-       INTERRUPT_3     = 0x03,
-       INTERRUPT_4     = 0x04,
-       INTERRUPT_5     = 0x05,
-       STATUS_6        = 0x06,
-       STATUS_7        = 0x07,
-       STATUS_8        = 0x08,
-       STATUS_9        = 0x09,
-       SNR             = 0x10,
-       CHIP_ID         = 0x7F,
+       INTERRUPT_0        = 0x00,
+       INTERRUPT_1        = 0x01,
+       INTERRUPT_2        = 0x02,
+       INTERRUPT_3        = 0x03,
+       INTERRUPT_4        = 0x04,
+       INTERRUPT_5        = 0x05,
+       STATUS_6           = 0x06,
+       STATUS_7           = 0x07,
+       STATUS_8           = 0x08,
+       STATUS_9           = 0x09,
+       AGC_GAIN_1         = 0x0A,
+       AGC_GAIN_0         = 0x0B,
+       SNR                = 0x10,
+       RS_ERR_CNT_2       = 0x11,
+       RS_ERR_CNT_1       = 0x12,
+       RS_ERR_CNT_0       = 0x13,
+       RS_UBC_1           = 0x14,
+       RS_UBC_0           = 0x15,
+       TRL_NOMINAL_RATE_1 = 0x65,
+       TRL_NOMINAL_RATE_0 = 0x66,
+       CHIP_ID            = 0x7F,
 };
 
 #endif                          /* _ZL10353_PRIV_ */
index 366c137..29ed532 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/firmware.h>
 #include <linux/crc32.h>
 #include <linux/i2c.h>
+#include <linux/kthread.h>
 
 #include <asm/system.h>
 
@@ -223,11 +224,10 @@ static void recover_arm(struct av7110 *av7110)
 
 static void av7110_arm_sync(struct av7110 *av7110)
 {
-       av7110->arm_rmmod = 1;
-       wake_up_interruptible(&av7110->arm_wait);
+       if (av7110->arm_thread)
+               kthread_stop(av7110->arm_thread);
 
-       while (av7110->arm_thread)
-               msleep(1);
+       av7110->arm_thread = NULL;
 }
 
 static int arm_thread(void *data)
@@ -238,17 +238,11 @@ static int arm_thread(void *data)
 
        dprintk(4, "%p\n",av7110);
 
-       lock_kernel();
-       daemonize("arm_mon");
-       sigfillset(&current->blocked);
-       unlock_kernel();
-
-       av7110->arm_thread = current;
-
        for (;;) {
                timeout = wait_event_interruptible_timeout(av7110->arm_wait,
-                                                          av7110->arm_rmmod, 5 * HZ);
-               if (-ERESTARTSYS == timeout || av7110->arm_rmmod) {
+                       kthread_should_stop(), 5 * HZ);
+
+               if (-ERESTARTSYS == timeout || kthread_should_stop()) {
                        /* got signal or told to quit*/
                        break;
                }
@@ -276,7 +270,6 @@ static int arm_thread(void *data)
                av7110->arm_errors = 0;
        }
 
-       av7110->arm_thread = NULL;
        return 0;
 }
 
@@ -695,8 +688,8 @@ static void gpioirq(unsigned long data)
 static int dvb_osd_ioctl(struct inode *inode, struct file *file,
                         unsigned int cmd, void *parg)
 {
-       struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
-       struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+       struct dvb_device *dvbdev = file->private_data;
+       struct av7110 *av7110 = dvbdev->priv;
 
        dprintk(4, "%p\n", av7110);
 
@@ -786,7 +779,7 @@ int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
 static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter)
 {
        struct dvb_demux_feed *dvbdmxfeed = dvbdmxfilter->feed;
-       struct av7110 *av7110 = (struct av7110 *) dvbdmxfeed->demux->priv;
+       struct av7110 *av7110 = dvbdmxfeed->demux->priv;
        u16 buf[20];
        int ret, i;
        u16 handle;
@@ -835,7 +828,7 @@ static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter)
 
 static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
 {
-       struct av7110 *av7110 = (struct av7110 *) dvbdmxfilter->feed->demux->priv;
+       struct av7110 *av7110 = dvbdmxfilter->feed->demux->priv;
        u16 buf[3];
        u16 answ[2];
        int ret;
@@ -871,7 +864,7 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
 static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
 {
        struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-       struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv;
+       struct av7110 *av7110 = dvbdmx->priv;
        u16 *pid = dvbdmx->pids, npids[5];
        int i;
        int ret = 0;
@@ -914,7 +907,7 @@ static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
 static int dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed)
 {
        struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-       struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv;
+       struct av7110 *av7110 = dvbdmx->priv;
        u16 *pid = dvbdmx->pids, npids[5];
        int i;
 
@@ -1103,9 +1096,9 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,
 
        /* pointer casting paranoia... */
        BUG_ON(!demux);
-       dvbdemux = (struct dvb_demux *) demux->priv;
+       dvbdemux = demux->priv;
        BUG_ON(!dvbdemux);
-       av7110 = (struct av7110 *) dvbdemux->priv;
+       av7110 = dvbdemux->priv;
 
        dprintk(4, "%p\n", av7110);
 
@@ -1137,7 +1130,7 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,
 
 static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
 {
-       struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+       struct av7110* av7110 = fe->dvb->priv;
 
        switch (tone) {
        case SEC_TONE_ON:
@@ -1197,7 +1190,7 @@ static int start_ts_capture(struct av7110 *budget)
 static int budget_start_feed(struct dvb_demux_feed *feed)
 {
        struct dvb_demux *demux = feed->demux;
-       struct av7110 *budget = (struct av7110 *) demux->priv;
+       struct av7110 *budget = demux->priv;
        int status;
 
        dprintk(2, "av7110: %p\n", budget);
@@ -1212,7 +1205,7 @@ static int budget_start_feed(struct dvb_demux_feed *feed)
 static int budget_stop_feed(struct dvb_demux_feed *feed)
 {
        struct dvb_demux *demux = feed->demux;
-       struct av7110 *budget = (struct av7110 *) demux->priv;
+       struct av7110 *budget = demux->priv;
        int status;
 
        dprintk(2, "budget: %p\n", budget);
@@ -1551,7 +1544,7 @@ static int get_firmware(struct av7110* av7110)
 
 static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
-       struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+       struct av7110* av7110 = fe->dvb->priv;
        u8 pwr = 0;
        u8 buf[4];
        struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
@@ -1702,7 +1695,7 @@ static int alps_tdlb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_front
 static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
 {
 #if defined(CONFIG_DVB_SP8870) || defined(CONFIG_DVB_SP8870_MODULE)
-       struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+       struct av7110* av7110 = fe->dvb->priv;
 
        return request_firmware(fw, name, &av7110->dev->pci->dev);
 #else
@@ -1867,7 +1860,7 @@ static struct stv0297_config nexusca_stv0297_config = {
 
 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;
+       struct av7110* av7110 = fe->dvb->priv;
        u32 div;
        u8 cfg, cpump, band_select;
        u8 data[4];
@@ -2338,6 +2331,7 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
        const int length = TS_WIDTH * TS_HEIGHT;
        struct pci_dev *pdev = dev->pci;
        struct av7110 *av7110;
+       struct task_struct *thread;
        int ret, count = 0;
 
        dprintk(4, "dev: %p\n", dev);
@@ -2622,9 +2616,12 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
                printk ("dvb-ttpci: Warning, firmware version 0x%04x is too old. "
                        "System might be unstable!\n", FW_VERSION(av7110->arm_app));
 
-       ret = kernel_thread(arm_thread, (void *) av7110, 0);
-       if (ret < 0)
+       thread = kthread_run(arm_thread, (void *) av7110, "arm_mon");
+       if (IS_ERR(thread)) {
+               ret = PTR_ERR(thread);
                goto err_stop_arm_9;
+       }
+       av7110->arm_thread = thread;
 
        /* set initial volume in mixer struct */
        av7110->mixer.volume_left  = volume;
index 9c79696..b98bd45 100644 (file)
@@ -35,7 +35,6 @@
 
 #define ANALOG_TUNER_VES1820 1
 #define ANALOG_TUNER_STV0297 2
-#define ANALOG_TUNER_VBI     0x100
 
 extern int av7110_debug;
 
@@ -205,7 +204,6 @@ struct av7110 {
        struct task_struct *arm_thread;
        wait_queue_head_t   arm_wait;
        u16                 arm_loops;
-       int                 arm_rmmod;
 
        void               *debi_virt;
        dma_addr_t          debi_bus;
index 795e6e9..e719af8 100644 (file)
@@ -880,8 +880,8 @@ static int dvb_video_get_event (struct av7110 *av7110, struct video_event *event
 
 static unsigned int dvb_video_poll(struct file *file, poll_table *wait)
 {
-       struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
-       struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+       struct dvb_device *dvbdev = file->private_data;
+       struct av7110 *av7110 = dvbdev->priv;
        unsigned int mask = 0;
 
        dprintk(2, "av7110:%p, \n", av7110);
@@ -908,8 +908,8 @@ static unsigned int dvb_video_poll(struct file *file, poll_table *wait)
 static ssize_t dvb_video_write(struct file *file, const char __user *buf,
                               size_t count, loff_t *ppos)
 {
-       struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
-       struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+       struct dvb_device *dvbdev = file->private_data;
+       struct av7110 *av7110 = dvbdev->priv;
 
        dprintk(2, "av7110:%p, \n", av7110);
 
@@ -924,8 +924,8 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf,
 
 static unsigned int dvb_audio_poll(struct file *file, poll_table *wait)
 {
-       struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
-       struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+       struct dvb_device *dvbdev = file->private_data;
+       struct av7110 *av7110 = dvbdev->priv;
        unsigned int mask = 0;
 
        dprintk(2, "av7110:%p, \n", av7110);
@@ -944,8 +944,8 @@ static unsigned int dvb_audio_poll(struct file *file, poll_table *wait)
 static ssize_t dvb_audio_write(struct file *file, const char __user *buf,
                               size_t count, loff_t *ppos)
 {
-       struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
-       struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+       struct dvb_device *dvbdev = file->private_data;
+       struct av7110 *av7110 = dvbdev->priv;
 
        dprintk(2, "av7110:%p, \n", av7110);
 
@@ -989,8 +989,8 @@ static int play_iframe(struct av7110 *av7110, u8 __user *buf, unsigned int len,
 static int dvb_video_ioctl(struct inode *inode, struct file *file,
                           unsigned int cmd, void *parg)
 {
-       struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
-       struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+       struct dvb_device *dvbdev = file->private_data;
+       struct av7110 *av7110 = dvbdev->priv;
        unsigned long arg = (unsigned long) parg;
        int ret = 0;
 
@@ -1203,8 +1203,8 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
 static int dvb_audio_ioctl(struct inode *inode, struct file *file,
                           unsigned int cmd, void *parg)
 {
-       struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
-       struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+       struct dvb_device *dvbdev = file->private_data;
+       struct av7110 *av7110 = dvbdev->priv;
        unsigned long arg = (unsigned long) parg;
        int ret = 0;
 
@@ -1349,8 +1349,8 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
 
 static int dvb_video_open(struct inode *inode, struct file *file)
 {
-       struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
-       struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+       struct dvb_device *dvbdev = file->private_data;
+       struct av7110 *av7110 = dvbdev->priv;
        int err;
 
        dprintk(2, "av7110:%p, \n", av7110);
@@ -1374,8 +1374,8 @@ static int dvb_video_open(struct inode *inode, struct file *file)
 
 static int dvb_video_release(struct inode *inode, struct file *file)
 {
-       struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
-       struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+       struct dvb_device *dvbdev = file->private_data;
+       struct av7110 *av7110 = dvbdev->priv;
 
        dprintk(2, "av7110:%p, \n", av7110);
 
@@ -1388,9 +1388,9 @@ static int dvb_video_release(struct inode *inode, struct file *file)
 
 static int dvb_audio_open(struct inode *inode, struct file *file)
 {
-       struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
-       struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
-       int err=dvb_generic_open(inode, file);
+       struct dvb_device *dvbdev = file->private_data;
+       struct av7110 *av7110 = dvbdev->priv;
+       int err = dvb_generic_open(inode, file);
 
        dprintk(2, "av7110:%p, \n", av7110);
 
@@ -1403,8 +1403,8 @@ static int dvb_audio_open(struct inode *inode, struct file *file)
 
 static int dvb_audio_release(struct inode *inode, struct file *file)
 {
-       struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
-       struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+       struct dvb_device *dvbdev = file->private_data;
+       struct av7110 *av7110 = dvbdev->priv;
 
        dprintk(2, "av7110:%p, \n", av7110);
 
index 4251a97..e9b4e88 100644 (file)
@@ -214,8 +214,8 @@ static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file,
 
 static int dvb_ca_open(struct inode *inode, struct file *file)
 {
-       struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
-       struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+       struct dvb_device *dvbdev = file->private_data;
+       struct av7110 *av7110 = dvbdev->priv;
        int err = dvb_generic_open(inode, file);
 
        dprintk(8, "av7110:%p\n",av7110);
@@ -228,8 +228,8 @@ static int dvb_ca_open(struct inode *inode, struct file *file)
 
 static unsigned int dvb_ca_poll (struct file *file, poll_table *wait)
 {
-       struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
-       struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+       struct dvb_device *dvbdev = file->private_data;
+       struct av7110 *av7110 = dvbdev->priv;
        struct dvb_ringbuffer *rbuf = &av7110->ci_rbuffer;
        struct dvb_ringbuffer *wbuf = &av7110->ci_wbuffer;
        unsigned int mask = 0;
@@ -251,8 +251,8 @@ static unsigned int dvb_ca_poll (struct file *file, poll_table *wait)
 static int dvb_ca_ioctl(struct inode *inode, struct file *file,
                 unsigned int cmd, void *parg)
 {
-       struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
-       struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+       struct dvb_device *dvbdev = file->private_data;
+       struct av7110 *av7110 = dvbdev->priv;
        unsigned long arg = (unsigned long) parg;
 
        dprintk(8, "av7110:%p\n",av7110);
@@ -329,8 +329,8 @@ static int dvb_ca_ioctl(struct inode *inode, struct file *file,
 static ssize_t dvb_ca_write(struct file *file, const char __user *buf,
                            size_t count, loff_t *ppos)
 {
-       struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
-       struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+       struct dvb_device *dvbdev = file->private_data;
+       struct av7110 *av7110 = dvbdev->priv;
 
        dprintk(8, "av7110:%p\n",av7110);
        return ci_ll_write(&av7110->ci_wbuffer, file, buf, count, ppos);
@@ -339,15 +339,13 @@ static ssize_t dvb_ca_write(struct file *file, const char __user *buf,
 static ssize_t dvb_ca_read(struct file *file, char __user *buf,
                           size_t count, loff_t *ppos)
 {
-       struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
-       struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+       struct dvb_device *dvbdev = file->private_data;
+       struct av7110 *av7110 = dvbdev->priv;
 
        dprintk(8, "av7110:%p\n",av7110);
        return ci_ll_read(&av7110->ci_rbuffer, file, buf, count, ppos);
 }
 
-
-
 static struct file_operations dvb_ca_fops = {
        .owner          = THIS_MODULE,
        .read           = dvb_ca_read,
index e4544ea..f59465b 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/moduleparam.h>
 #include <linux/input.h>
 #include <linux/proc_fs.h>
+#include <linux/kernel.h>
 #include <asm/bitops.h>
 
 #include "av7110.h"
@@ -16,6 +17,7 @@
 static int av_cnt;
 static struct av7110 *av_list[4];
 static struct input_dev *input_dev;
+static char input_phys[32];
 
 static u8 delay_timer_finished;
 
@@ -217,7 +219,7 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
        static struct proc_dir_entry *e;
        int err;
 
-       if (av_cnt >= sizeof av_list/sizeof av_list[0])
+       if (av_cnt >= ARRAY_SIZE(av_list))
                return -ENOSPC;
 
        av7110_setup_irc_config(av7110, 0x0001);
@@ -231,8 +233,22 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
                if (!input_dev)
                        return -ENOMEM;
 
+               snprintf(input_phys, sizeof(input_phys),
+                       "pci-%s/ir0", pci_name(av7110->dev->pci));
+
                input_dev->name = "DVB on-card IR receiver";
 
+               input_dev->phys = input_phys;
+               input_dev->id.bustype = BUS_PCI;
+               input_dev->id.version = 1;
+               if (av7110->dev->pci->subsystem_vendor) {
+                       input_dev->id.vendor = av7110->dev->pci->subsystem_vendor;
+                       input_dev->id.product = av7110->dev->pci->subsystem_device;
+               } else {
+                       input_dev->id.vendor = av7110->dev->pci->vendor;
+                       input_dev->id.product = av7110->dev->pci->device;
+               }
+               input_dev->cdev.dev = &av7110->dev->pci->dev;
                set_bit(EV_KEY, input_dev->evbit);
                set_bit(EV_REP, input_dev->evbit);
                input_register_keys();
index dbfd5e7..cde5d3a 100644 (file)
@@ -140,17 +140,6 @@ static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
        return 0;
 }
 
-static int stv0297_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
-{
-       u8 buf [] = { reg, data };
-       struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 2 };
-
-       if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1))
-               return -1;
-       return 0;
-}
-
-
 static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4])
 {
        struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
@@ -193,6 +182,7 @@ static int ves1820_set_tv_freq(struct saa7146_dev *dev, u32 freq)
 
 static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq)
 {
+       struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
        u32 div;
        u8 data[4];
 
@@ -213,8 +203,8 @@ static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq)
        else
                return -EINVAL;
 
-       stv0297_writereg(dev, 0x1C, 0x87, 0x78);
-       stv0297_writereg(dev, 0x1C, 0x86, 0xc8);
+       if (av7110->fe->ops.i2c_gate_ctrl)
+               av7110->fe->ops.i2c_gate_ctrl(av7110->fe, 1);
        return tuner_write(dev, 0x63, data);
 }
 
@@ -817,20 +807,20 @@ int av7110_init_v4l(struct av7110 *av7110)
                saa7146_vv_release(dev);
                return -ENODEV;
        }
-       if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
+       if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI))
                ERR(("cannot register vbi v4l2 device. skipping.\n"));
-       } else {
-               if (av7110->analog_tuner_flags)
-                       av7110->analog_tuner_flags |= ANALOG_TUNER_VBI;
-       }
        return 0;
 }
 
 int av7110_exit_v4l(struct av7110 *av7110)
 {
+       struct saa7146_dev* dev = av7110->dev;
+
        saa7146_unregister_device(&av7110->v4l_dev, av7110->dev);
-       if (av7110->analog_tuner_flags & ANALOG_TUNER_VBI)
-               saa7146_unregister_device(&av7110->vbi_dev, av7110->dev);
+       saa7146_unregister_device(&av7110->vbi_dev, av7110->dev);
+
+       saa7146_vv_release(dev);
+
        return 0;
 }
 
index 89ab4b5..3035b22 100644 (file)
@@ -1089,6 +1089,8 @@ static int budget_av_detach(struct saa7146_dev *dev)
                msleep(200);
 
                saa7146_unregister_device(&budget_av->vd, dev);
+
+               saa7146_vv_release(dev);
        }
 
        if (budget_av->budget.ci_present)
@@ -1145,6 +1147,7 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
                if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
                        /* fixme: proper cleanup here */
                        ERR(("cannot register capture v4l2 device.\n"));
+                       saa7146_vv_release(dev);
                        return err;
                }
 
index f2066b4..464feaf 100644 (file)
@@ -29,8 +29,6 @@
  * the project's page is at http://www.linuxtv.org/dvb/
  */
 
-#include "budget.h"
-
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
@@ -39,6 +37,8 @@
 #include <linux/spinlock.h>
 #include <media/ir-common.h>
 
+#include "budget.h"
+
 #include "dvb_ca_en50221.h"
 #include "stv0299.h"
 #include "stv0297.h"
@@ -130,6 +130,7 @@ static void msp430_ir_interrupt(unsigned long data)
        int toggle;
        static int prev_toggle = -1;
        static u32 ir_key;
+       static int state = 0;
        u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
 
        /*
@@ -138,21 +139,34 @@ static void msp430_ir_interrupt(unsigned long data)
         * type1: X1CCCCCC, C = command bits (0 - 63)
         * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit
         *
-        * More than one command byte may be generated before the device byte
-        * Only when we have both, a correct keypress is generated
+        * Each signal from the remote control can generate one or more command
+        * bytes and one or more device bytes. For the repeated bytes, the
+        * highest bit (X) is set. The first command byte is always generated
+        * before the first device byte. Other than that, no specific order
+        * seems to apply.
+        *
+        * Only when we have a command and device byte, a keypress is
+        * generated.
         */
 
+       if (ir_debug)
+               printk("budget_ci: received byte 0x%02x\n", command);
+
+       /* Is this a repeated byte? */
+       if (command & 0x80)
+               return;
+
        /* Is this a RC5 command byte? */
        if (command & 0x40) {
-               if (ir_debug)
-                       printk("budget_ci: received command byte 0x%02x\n", command);
+               state = 1;
                ir_key = command & 0x3f;
                return;
        }
 
        /* It's a RC5 device byte */
-       if (ir_debug)
-               printk("budget_ci: received device byte 0x%02x\n", command);
+       if (!state)
+               return;
+       state = 0;
        device = command & 0x1f;
        toggle = command & 0x20;
 
@@ -223,7 +237,6 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
        switch (budget_ci->budget.dev->pci->subsystem_device) {
        case 0x100c:
        case 0x100f:
-       case 0x1010:
        case 0x1011:
        case 0x1012:
        case 0x1017:
@@ -236,6 +249,16 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
                else
                        budget_ci->ir.rc5_device = rc5_device;
                break;
+       case 0x1010:
+               /* for the Technotrend 1500 bundled remote */
+               ir_input_init(input_dev, &budget_ci->ir.state,
+                             IR_TYPE_RC5, ir_codes_tt_1500);
+
+               if (rc5_device < 0)
+                       budget_ci->ir.rc5_device = IR_DEVICE_ANY;
+               else
+                       budget_ci->ir.rc5_device = rc5_device;
+               break;
        default:
                /* unknown remote */
                ir_input_init(input_dev, &budget_ci->ir.state,
@@ -869,6 +892,17 @@ static struct tda1004x_config philips_tdm1316l_config = {
        .request_firmware = philips_tdm1316l_request_firmware,
 };
 
+static struct tda1004x_config philips_tdm1316l_config_invert = {
+
+       .demod_address = 0x8,
+       .invert = 1,
+       .invert_oclk = 0,
+       .xtal_freq = TDA10046_XTAL_4M,
+       .agc_config = TDA10046_AGC_DEFAULT,
+       .if_freq = TDA10046_FREQ_3617,
+       .request_firmware = philips_tdm1316l_request_firmware,
+};
+
 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;
@@ -1092,9 +1126,8 @@ static void frontend_init(struct budget_ci *budget_ci)
 
        case 0x1012:            // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
                budget_ci->tuner_pll_address = 0x60;
-               philips_tdm1316l_config.invert = 1;
                budget_ci->budget.dvb_frontend =
-                       dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+                       dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &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;
index bd6e7ba..78c98b0 100644 (file)
@@ -20,8 +20,6 @@
  *
  */
 
-#include <linux/mutex.h>
-
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -35,6 +33,8 @@
 #include <linux/init.h>
 #include <linux/input.h>
 
+#include <linux/mutex.h>
+
 #include "dmxdev.h"
 #include "dvb_demux.h"
 #include "dvb_filter.h"
index 19d45cc..9f1adda 100644 (file)
@@ -180,136 +180,163 @@ static int az_setfreq(struct az_device *dev, unsigned long frequency)
        return 0;
 }
 
-static int az_do_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, void *arg)
+static int vidioc_querycap (struct file *file, void  *priv,
+                                       struct v4l2_capability *v)
+{
+       strlcpy(v->driver, "radio-aztech", sizeof (v->driver));
+       strlcpy(v->card, "Aztech Radio", sizeof (v->card));
+       sprintf(v->bus_info,"ISA");
+       v->version = RADIO_VERSION;
+       v->capabilities = V4L2_CAP_TUNER;
+       return 0;
+}
+
+static int vidioc_g_tuner (struct file *file, void *priv,
+                               struct v4l2_tuner *v)
 {
        struct video_device *dev = video_devdata(file);
        struct az_device *az = dev->priv;
 
-       switch(cmd)
-       {
-               case VIDIOC_QUERYCAP:
-               {
-                       struct v4l2_capability *v = arg;
-                       memset(v,0,sizeof(*v));
-                       strlcpy(v->driver, "radio-aztech", sizeof (v->driver));
-                       strlcpy(v->card, "Aztech Radio", sizeof (v->card));
-                       sprintf(v->bus_info,"ISA");
-                       v->version = RADIO_VERSION;
-                       v->capabilities = V4L2_CAP_TUNER;
+       if (v->index > 0)
+               return -EINVAL;
 
-                       return 0;
-               }
-               case VIDIOC_G_TUNER:
-               {
-                       struct v4l2_tuner *v = arg;
-
-                       if (v->index > 0)
-                               return -EINVAL;
-
-                       memset(v,0,sizeof(*v));
-                       strcpy(v->name, "FM");
-                       v->type = V4L2_TUNER_RADIO;
-
-                       v->rangelow=(87*16000);
-                       v->rangehigh=(108*16000);
-                       v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
-                       v->capability=V4L2_TUNER_CAP_LOW;
-                       if(az_getstereo(az))
-                               v->audmode = V4L2_TUNER_MODE_STEREO;
-                       else
-                               v->audmode = V4L2_TUNER_MODE_MONO;
-                       v->signal=0xFFFF*az_getsigstr(az);
+       strcpy(v->name, "FM");
+       v->type = V4L2_TUNER_RADIO;
 
-                       return 0;
-               }
-               case VIDIOC_S_TUNER:
-               {
-                       struct v4l2_tuner *v = arg;
+       v->rangelow=(87*16000);
+       v->rangehigh=(108*16000);
+       v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+       v->capability=V4L2_TUNER_CAP_LOW;
+       if(az_getstereo(az))
+               v->audmode = V4L2_TUNER_MODE_STEREO;
+       else
+               v->audmode = V4L2_TUNER_MODE_MONO;
+       v->signal=0xFFFF*az_getsigstr(az);
 
-                       if (v->index > 0)
-                               return -EINVAL;
+       return 0;
+}
 
-                       return 0;
-               }
-               case VIDIOC_S_FREQUENCY:
-               {
-                       struct v4l2_frequency *f = arg;
 
-                       az->curfreq = f->frequency;
-                       az_setfreq(az, az->curfreq);
-                       return 0;
-               }
-               case VIDIOC_G_FREQUENCY:
-               {
-                       struct v4l2_frequency *f = arg;
+static int vidioc_s_tuner (struct file *file, void *priv,
+                               struct v4l2_tuner *v)
+{
+       if (v->index > 0)
+               return -EINVAL;
 
-                       f->type = V4L2_TUNER_RADIO;
-                       f->frequency = az->curfreq;
+       return 0;
+}
 
-                       return 0;
-               }
+static int vidioc_g_audio (struct file *file, void *priv,
+                          struct v4l2_audio *a)
+{
+       if (a->index > 1)
+               return -EINVAL;
 
-               case VIDIOC_QUERYCTRL:
-               {
-                       struct v4l2_queryctrl *qc = arg;
-                       int i;
-
-                       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-                               if (qc->id && qc->id == radio_qctrl[i].id) {
-                                       memcpy(qc, &(radio_qctrl[i]),
-                                                               sizeof(*qc));
-                                       return (0);
-                               }
-                       }
-                       return -EINVAL;
-               }
-               case VIDIOC_G_CTRL:
-               {
-                       struct v4l2_control *ctrl= arg;
-
-                       switch (ctrl->id) {
-                               case V4L2_CID_AUDIO_MUTE:
-                                       if (az->curvol==0)
-                                               ctrl->value=1;
-                                       else
-                                               ctrl->value=0;
-                                       return (0);
-                               case V4L2_CID_AUDIO_VOLUME:
-                                       ctrl->value=az->curvol * 6554;
-                                       return (0);
-                       }
-                       return -EINVAL;
-               }
-               case VIDIOC_S_CTRL:
-               {
-                       struct v4l2_control *ctrl= arg;
-
-                       switch (ctrl->id) {
-                               case V4L2_CID_AUDIO_MUTE:
-                                       if (ctrl->value) {
-                                               az_setvol(az,0);
-                                       } else {
-                                               az_setvol(az,az->curvol);
-                                       }
-                                       return (0);
-                               case V4L2_CID_AUDIO_VOLUME:
-                                       az_setvol(az,ctrl->value);
-                                       return (0);
-                       }
-                       return -EINVAL;
+       strcpy(a->name, "Radio");
+       a->capability = V4L2_AUDCAP_STEREO;
+       return 0;
+}
+
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+       *i = 0;
+       return 0;
+}
+
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+       if (i != 0)
+               return -EINVAL;
+       return 0;
+}
+
+
+static int vidioc_s_audio (struct file *file, void *priv,
+                          struct v4l2_audio *a)
+{
+       if (a->index != 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int vidioc_s_frequency (struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct video_device *dev = video_devdata(file);
+       struct az_device *az = dev->priv;
+
+       az->curfreq = f->frequency;
+       az_setfreq(az, az->curfreq);
+       return 0;
+}
+
+static int vidioc_g_frequency (struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct video_device *dev = video_devdata(file);
+       struct az_device *az = dev->priv;
+
+       f->type = V4L2_TUNER_RADIO;
+       f->frequency = az->curfreq;
+
+       return 0;
+}
+
+static int vidioc_queryctrl (struct file *file, void *priv,
+                           struct v4l2_queryctrl *qc)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+               if (qc->id && qc->id == radio_qctrl[i].id) {
+                       memcpy(qc, &(radio_qctrl[i]),
+                                               sizeof(*qc));
+                       return (0);
                }
+       }
+       return -EINVAL;
+}
+
+static int vidioc_g_ctrl (struct file *file, void *priv,
+                           struct v4l2_control *ctrl)
+{
+       struct video_device *dev = video_devdata(file);
+       struct az_device *az = dev->priv;
 
-               default:
-                       return v4l_compat_translate_ioctl(inode,file,cmd,arg,
-                                                         az_do_ioctl);
+       switch (ctrl->id) {
+               case V4L2_CID_AUDIO_MUTE:
+                       if (az->curvol==0)
+                               ctrl->value=1;
+                       else
+                               ctrl->value=0;
+                       return (0);
+               case V4L2_CID_AUDIO_VOLUME:
+                       ctrl->value=az->curvol * 6554;
+                       return (0);
        }
+       return -EINVAL;
 }
 
-static int az_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, az_do_ioctl);
+       struct video_device *dev = video_devdata(file);
+       struct az_device *az = dev->priv;
+
+       switch (ctrl->id) {
+               case V4L2_CID_AUDIO_MUTE:
+                       if (ctrl->value) {
+                               az_setvol(az,0);
+                       } else {
+                               az_setvol(az,az->curvol);
+                       }
+                       return (0);
+               case V4L2_CID_AUDIO_VOLUME:
+                       az_setvol(az,ctrl->value);
+                       return (0);
+       }
+       return -EINVAL;
 }
 
 static struct az_device aztech_unit;
@@ -318,20 +345,35 @@ static const struct file_operations aztech_fops = {
        .owner          = THIS_MODULE,
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
-       .ioctl          = az_ioctl,
+       .ioctl          = video_ioctl2,
        .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
 
 static struct video_device aztech_radio=
 {
-       .owner          = THIS_MODULE,
-       .name           = "Aztech radio",
-       .type           = VID_TYPE_TUNER,
-       .hardware       = 0,
-       .fops           = &aztech_fops,
+       .owner              = THIS_MODULE,
+       .name               = "Aztech radio",
+       .type               = VID_TYPE_TUNER,
+       .hardware           = 0,
+       .fops               = &aztech_fops,
+       .vidioc_querycap    = vidioc_querycap,
+       .vidioc_g_tuner     = vidioc_g_tuner,
+       .vidioc_s_tuner     = vidioc_s_tuner,
+       .vidioc_g_audio     = vidioc_g_audio,
+       .vidioc_s_audio     = vidioc_s_audio,
+       .vidioc_g_input     = vidioc_g_input,
+       .vidioc_s_input     = vidioc_s_input,
+       .vidioc_g_frequency = vidioc_g_frequency,
+       .vidioc_s_frequency = vidioc_s_frequency,
+       .vidioc_queryctrl   = vidioc_queryctrl,
+       .vidioc_g_ctrl      = vidioc_g_ctrl,
+       .vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
+module_param_named(debug,aztech_radio.debug, int, 0644);
+MODULE_PARM_DESC(debug,"activates debug info");
+
 static int __init aztech_init(void)
 {
        if(io==-1)
index 05e5aa7..74976cb 100644 (file)
@@ -89,14 +89,6 @@ static struct v4l2_queryctrl radio_qctrl[] = {
 #define GEMTEK_PCI_RANGE_HIGH (108*16000)
 #endif
 
-#ifndef TRUE
-#define TRUE (1)
-#endif
-
-#ifndef FALSE
-#define FALSE (0)
-#endif
-
 struct gemtek_pci_card {
        struct video_device *videodev;
 
@@ -146,12 +138,12 @@ static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
 
 static inline void gemtek_pci_nil( u32 port, u8 *last_byte )
 {
-       __gemtek_pci_cmd( 0x00, port, last_byte, FALSE );
+       __gemtek_pci_cmd( 0x00, port, last_byte, false );
 }
 
 static inline void gemtek_pci_cmd( u16 cmd, u32 port, u8 *last_byte )
 {
-       __gemtek_pci_cmd( cmd, port, last_byte, TRUE );
+       __gemtek_pci_cmd( cmd, port, last_byte, true );
 }
 
 static void gemtek_pci_setfrequency( struct gemtek_pci_card *card, unsigned long frequency )
@@ -184,14 +176,14 @@ static void gemtek_pci_setfrequency( struct gemtek_pci_card *card, unsigned long
 static inline void gemtek_pci_mute( struct gemtek_pci_card *card )
 {
        outb( 0x1f, card->iobase );
-       card->mute = TRUE;
+       card->mute = true;
 }
 
 static inline void gemtek_pci_unmute( struct gemtek_pci_card *card )
 {
        if ( card->mute ) {
                gemtek_pci_setfrequency( card, card->current_frequency );
-               card->mute = FALSE;
+               card->mute = false;
        }
 }
 
@@ -259,7 +251,7 @@ static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file,
 
                        gemtek_pci_setfrequency( card, f->frequency );
                        card->current_frequency = f->frequency;
-                       card->mute = FALSE;
+                       card->mute = false;
                        return 0;
                }
                case VIDIOC_QUERYCTRL:
index 6beeb74..8e184cf 100644 (file)
@@ -27,7 +27,9 @@
  * BUGS:
  *   - card unmutes if you change frequency
  *
- * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
+ * (c) 2006, 2007 by Mauro Carvalho Chehab <mchehab@infradead.org>:
+ *     - Conversion to V4L2 API
+ *      - Uses video_ioctl2 for parsing and to add debug support
  */
 
 
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 
-#define DRIVER_VERSION "0.76"
+#define DRIVER_VERSION "0.77"
 
 #include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
-#define RADIO_VERSION KERNEL_VERSION(0,7,6)
+#define RADIO_VERSION KERNEL_VERSION(0,7,7)
+
+static struct video_device maxiradio_radio;
+
+#define dprintk(num, fmt, arg...)                                          \
+       do {                                                               \
+               if (maxiradio_radio.debug >= num)                          \
+                       printk(KERN_DEBUG "%s: " fmt,                      \
+                               maxiradio_radio.name, ## arg); } while (0)
 
 static struct v4l2_queryctrl radio_qctrl[] = {
        {
@@ -81,30 +91,21 @@ module_param(radio_nr, int, 0);
 #define FREQ_IF         171200 /* 10.7*16000   */
 #define FREQ_STEP       200    /* 12.5*16      */
 
-#define FREQ2BITS(x)   ((( (unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1))\
-                       /(FREQ_STEP<<2))<<2) /* (x==fmhz*16*1000) -> bits */
+/* (x==fmhz*16*1000) -> bits */
+#define FREQ2BITS(x)   ((( (unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1)) \
+                       /(FREQ_STEP<<2))<<2)
 
 #define BITS2FREQ(x)   ((x) * FREQ_STEP - FREQ_IF)
 
 
-static int radio_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg);
-
 static const struct file_operations maxiradio_fops = {
        .owner          = THIS_MODULE,
        .open           = video_exclusive_open,
        .release        = video_exclusive_release,
-       .ioctl          = radio_ioctl,
+       .ioctl          = video_ioctl2,
        .compat_ioctl   = v4l_compat_ioctl32,
        .llseek         = no_llseek,
 };
-static struct video_device maxiradio_radio =
-{
-       .owner          = THIS_MODULE,
-       .name           = "Maxi Radio FM2000 radio",
-       .type           = VID_TYPE_TUNER,
-       .fops           = &maxiradio_fops,
-};
 
 static struct radio_device
 {
@@ -116,12 +117,14 @@ static struct radio_device
        unsigned long freq;
 
        struct mutex lock;
-} radio_unit = {0, 0, 0, 0, };
-
+} radio_unit = {
+       .muted =1,
+       .freq = FREQ_LO,
+};
 
 static void outbit(unsigned long bit, __u16 io)
 {
-       if(bit != 0)
+       if (bit != 0)
                {
                        outb(  power|wren|data     ,io); udelay(4);
                        outb(  power|wren|data|clk ,io); udelay(4);
@@ -137,14 +140,20 @@ static void outbit(unsigned long bit, __u16 io)
 
 static void turn_power(__u16 io, int p)
 {
-       if(p != 0) outb(power, io); else outb(0,io);
+       if (p != 0) {
+               dprintk(1, "Radio powered on\n");
+               outb(power, io);
+       } else {
+               dprintk(1, "Radio powered off\n");
+               outb(0,io);
+       }
 }
 
-
-static void set_freq(__u16 io, __u32 data)
+static void set_freq(__u16 io, __u32 freq)
 {
        unsigned long int si;
        int bl;
+       int data = FREQ2BITS(freq);
 
        /* TEA5757 shift register bits (see pdf) */
 
@@ -163,161 +172,225 @@ static void set_freq(__u16 io, __u32 data)
        outbit(0,io); // 16  search level
 
        si = 0x8000;
-       for(bl = 1; bl <= 16 ; bl++) { outbit(data & si,io); si >>=1; }
+       for (bl = 1; bl <= 16 ; bl++) {
+               outbit(data & si,io);
+               si >>=1;
+       }
 
-       outb(power,io);
+       dprintk(1, "Radio freq set to %d.%02d MHz\n",
+                               freq / 16000,
+                               freq % 16000 * 100 / 16000);
+
+       turn_power(io, 1);
 }
 
 static int get_stereo(__u16 io)
 {
-       outb(power,io); udelay(4);
+       outb(power,io);
+       udelay(4);
+
        return !(inb(io) & mo_st);
 }
 
 static int get_tune(__u16 io)
 {
-       outb(power+clk,io); udelay(4);
+       outb(power+clk,io);
+       udelay(4);
+
        return !(inb(io) & mo_st);
 }
 
 
-static inline int radio_function(struct inode *inode, struct file *file,
-                                unsigned int cmd, void *arg)
+static int vidioc_querycap (struct file *file, void  *priv,
+                           struct v4l2_capability *v)
+{
+       strlcpy(v->driver, "radio-maxiradio", sizeof (v->driver));
+       strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof (v->card));
+       sprintf(v->bus_info,"ISA");
+       v->version = RADIO_VERSION;
+       v->capabilities = V4L2_CAP_TUNER;
+
+       return 0;
+}
+
+static int vidioc_g_tuner (struct file *file, void *priv,
+                          struct v4l2_tuner *v)
 {
        struct video_device *dev = video_devdata(file);
        struct radio_device *card=dev->priv;
 
-       switch(cmd) {
-               case VIDIOC_QUERYCAP:
-               {
-                       struct v4l2_capability *v = arg;
-                       memset(v,0,sizeof(*v));
-                       strlcpy(v->driver, "radio-maxiradio", sizeof (v->driver));
-                       strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof (v->card));
-                       sprintf(v->bus_info,"ISA");
-                       v->version = RADIO_VERSION;
-                       v->capabilities = V4L2_CAP_TUNER;
+       if (v->index > 0)
+               return -EINVAL;
 
-                       return 0;
-               }
-               case VIDIOC_G_TUNER:
-               {
-                       struct v4l2_tuner *v = arg;
+       memset(v,0,sizeof(*v));
+       strcpy(v->name, "FM");
+       v->type = V4L2_TUNER_RADIO;
 
-                       if (v->index > 0)
-                               return -EINVAL;
+       v->rangelow=FREQ_LO;
+       v->rangehigh=FREQ_HI;
+       v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+       v->capability=V4L2_TUNER_CAP_LOW;
+       if(get_stereo(card->io))
+               v->audmode = V4L2_TUNER_MODE_STEREO;
+       else
+               v->audmode = V4L2_TUNER_MODE_MONO;
+       v->signal=0xffff*get_tune(card->io);
 
-                       memset(v,0,sizeof(*v));
-                       strcpy(v->name, "FM");
-                       v->type = V4L2_TUNER_RADIO;
+       return 0;
+}
 
-                       v->rangelow=FREQ_LO;
-                       v->rangehigh=FREQ_HI;
-                       v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
-                       v->capability=V4L2_TUNER_CAP_LOW;
-                       if(get_stereo(card->io))
-                               v->audmode = V4L2_TUNER_MODE_STEREO;
-                       else
-                               v->audmode = V4L2_TUNER_MODE_MONO;
-                       v->signal=0xffff*get_tune(card->io);
+static int vidioc_s_tuner (struct file *file, void *priv,
+                          struct v4l2_tuner *v)
+{
+       if (v->index > 0)
+               return -EINVAL;
 
-                       return 0;
-               }
-               case VIDIOC_S_TUNER:
-               {
-                       struct v4l2_tuner *v = arg;
+       return 0;
+}
 
-                       if (v->index > 0)
-                               return -EINVAL;
+static int vidioc_g_audio (struct file *file, void *priv,
+                          struct v4l2_audio *a)
+{
+       if (a->index > 1)
+               return -EINVAL;
 
-                       return 0;
-               }
-               case VIDIOC_S_FREQUENCY:
-               {
-                       struct v4l2_frequency *f = arg;
+       strcpy(a->name, "FM");
+       a->capability = V4L2_AUDCAP_STEREO;
+       return 0;
+}
 
-                       if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
-                               return -EINVAL;
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+       *i = 0;
 
-                       card->freq = f->frequency;
-                       set_freq(card->io, FREQ2BITS(card->freq));
-                       msleep(125);
-                       return 0;
-               }
-               case VIDIOC_G_FREQUENCY:
-               {
-                       struct v4l2_frequency *f = arg;
+       return 0;
+}
 
-                       f->type = V4L2_TUNER_RADIO;
-                       f->frequency = card->freq;
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+       if (i != 0)
+               return -EINVAL;
 
-                       return 0;
-               }
-               case VIDIOC_QUERYCTRL:
-               {
-                       struct v4l2_queryctrl *qc = arg;
-                       int i;
-
-                       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-                               if (qc->id && qc->id == radio_qctrl[i].id) {
-                                       memcpy(qc, &(radio_qctrl[i]),
-                                                               sizeof(*qc));
-                                       return (0);
-                               }
-                       }
-                       return -EINVAL;
-               }
-               case VIDIOC_G_CTRL:
-               {
-                       struct v4l2_control *ctrl= arg;
-
-                       switch (ctrl->id) {
-                               case V4L2_CID_AUDIO_MUTE:
-                                       ctrl->value=card->muted;
-                                       return (0);
-                       }
-                       return -EINVAL;
-               }
-               case VIDIOC_S_CTRL:
-               {
-                       struct v4l2_control *ctrl= arg;
-
-                       switch (ctrl->id) {
-                               case V4L2_CID_AUDIO_MUTE:
-                                       card->muted = ctrl->value;
-                                       if(card->muted)
-                                               turn_power(card->io, 0);
-                                       else
-                                               set_freq(card->io, FREQ2BITS(card->freq));
-                                       return 0;
-                       }
-                       return -EINVAL;
-               }
+       return 0;
+}
+
+
+static int vidioc_s_audio (struct file *file, void *priv,
+                          struct v4l2_audio *a)
+{
+       if (a->index != 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int vidioc_s_frequency (struct file *file, void *priv,
+                              struct v4l2_frequency *f)
+{
+       struct video_device *dev = video_devdata(file);
+       struct radio_device *card=dev->priv;
 
-               default:
-                       return v4l_compat_translate_ioctl(inode,file,cmd,arg,
-                                                         radio_function);
+       if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) {
+               dprintk(1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n",
+                                       f->frequency / 16000,
+                                       f->frequency % 16000 * 100 / 16000,
+                                       FREQ_LO / 16000, FREQ_HI / 16000);
 
+               return -EINVAL;
        }
+
+       card->freq = f->frequency;
+       set_freq(card->io, card->freq);
+       msleep(125);
+
+       return 0;
 }
 
-static int radio_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
+static int vidioc_g_frequency (struct file *file, void *priv,
+                              struct v4l2_frequency *f)
 {
        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);
-       return ret;
+       f->type = V4L2_TUNER_RADIO;
+       f->frequency = card->freq;
+
+       dprintk(4, "radio freq is %d.%02d MHz",
+                               f->frequency / 16000,
+                               f->frequency % 16000 * 100 / 16000);
+
+       return 0;
 }
 
-MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
-MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
-MODULE_LICENSE("GPL");
+static int vidioc_queryctrl (struct file *file, void *priv,
+                            struct v4l2_queryctrl *qc)
+{
+       int i;
 
+       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+               if (qc->id && qc->id == radio_qctrl[i].id) {
+                       memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
+                       return (0);
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int vidioc_g_ctrl (struct file *file, void *priv,
+                           struct v4l2_control *ctrl)
+{
+       struct video_device *dev = video_devdata(file);
+       struct radio_device *card=dev->priv;
+
+       switch (ctrl->id) {
+               case V4L2_CID_AUDIO_MUTE:
+                       ctrl->value=card->muted;
+                       return (0);
+       }
+
+       return -EINVAL;
+}
+
+static int vidioc_s_ctrl (struct file *file, void *priv,
+                         struct v4l2_control *ctrl)
+{
+       struct video_device *dev = video_devdata(file);
+       struct radio_device *card=dev->priv;
+
+       switch (ctrl->id) {
+               case V4L2_CID_AUDIO_MUTE:
+                       card->muted = ctrl->value;
+                       if(card->muted)
+                               turn_power(card->io, 0);
+                       else
+                               set_freq(card->io, card->freq);
+                       return 0;
+       }
+
+       return -EINVAL;
+}
+
+static struct video_device maxiradio_radio =
+{
+       .owner              = THIS_MODULE,
+       .name               = "Maxi Radio FM2000 radio",
+       .type               = VID_TYPE_TUNER,
+       .fops               = &maxiradio_fops,
+
+       .vidioc_querycap    = vidioc_querycap,
+       .vidioc_g_tuner     = vidioc_g_tuner,
+       .vidioc_s_tuner     = vidioc_s_tuner,
+       .vidioc_g_audio     = vidioc_g_audio,
+       .vidioc_s_audio     = vidioc_s_audio,
+       .vidioc_g_input     = vidioc_g_input,
+       .vidioc_s_input     = vidioc_s_input,
+       .vidioc_g_frequency = vidioc_g_frequency,
+       .vidioc_s_frequency = vidioc_s_frequency,
+       .vidioc_queryctrl   = vidioc_queryctrl,
+       .vidioc_g_ctrl      = vidioc_g_ctrl,
+       .vidioc_s_ctrl      = vidioc_s_ctrl,
+};
 
 static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
@@ -334,7 +407,7 @@ static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_d
        mutex_init(&radio_unit.lock);
        maxiradio_radio.priv = &radio_unit;
 
-       if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
+       if (video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
                printk("radio-maxiradio: can't register device!");
                goto err_out_free_region;
        }
@@ -389,3 +462,10 @@ static void __exit maxiradio_radio_exit(void)
 
 module_init(maxiradio_radio_init);
 module_exit(maxiradio_radio_exit);
+
+MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
+MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
+MODULE_LICENSE("GPL");
+
+module_param_named(debug,maxiradio_radio.debug, int, 0644);
+MODULE_PARM_DESC(debug,"activates debug info");
index 57357db..7a61051 100644 (file)
@@ -342,7 +342,7 @@ endmenu # encoder / decoder chips
 
 config VIDEO_VIVI
        tristate "Virtual Video Driver"
-       depends on VIDEO_V4L2 && !SPARC32 && !SPARC64
+       depends on VIDEO_V4L2 && !SPARC32 && !SPARC64 && PCI
        select VIDEO_BUF
        default n
        ---help---
index 9b1f3f0..44ccaed 100644 (file)
@@ -113,4 +113,3 @@ obj-$(CONFIG_USB_QUICKCAM_MESSENGER)        += usbvideo/
 obj-$(CONFIG_VIDEO_VIVI) += vivi.o
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-extra-cflags-$(CONFIG_VIDEO_V4L1_COMPAT) += -DCONFIG_VIDEO_V4L1_COMPAT
index 21ebe8f..6addc42 100644 (file)
@@ -307,6 +307,7 @@ static struct CARD {
        { 0x07711461, BTTV_BOARD_AVDVBT_771,    "AVermedia AverTV DVB-T 771" },
        { 0x07611461, BTTV_BOARD_AVDVBT_761,    "AverMedia AverTV DVB-T 761" },
        { 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE,    "DViCO FusionHDTV DVB-T Lite" },
+       { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE,    "Ultraview DVB-T Lite" },
        { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,    "DViCO FusionHDTV 5 Lite" },
        { 0x00261822, BTTV_BOARD_TWINHAN_DST,   "DNTV Live! Mini "},
 
@@ -578,14 +579,9 @@ struct tvcard bttv_tvcards[] = {
                .svhs           = 2,
                .gpiomask       = 0x01fe00,
                .muxsel         = { 2, 3, 1, 1 },
-       #if 0
-               /* old */
-               .gpiomux        = { 0x01c000, 0, 0x018000, 0x014000, 0x002000 },
-       #else
                /* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */
                .gpiomux        = { 0x001e00, 0, 0x018000, 0x014000 },
                .gpiomute       = 0x002000,
-       #endif
                .needs_tvaudio  = 1,
                .pll            = PLL_28,
                .tuner_type     = -1,
@@ -894,15 +890,10 @@ struct tvcard bttv_tvcards[] = {
                .tuner          = 0,
                .svhs           = 2,
                .muxsel         = { 2, 3, 1, 1, 0 }, /* TV, CVid, SVid, CVid over SVid connector */
-       #if 0
-               .gpiomask       = 0xc33000,
-               .gpiomux        = { 0x422000,0x1000,0x0000,0x620000,0x800000 },
-       #else
                /* Alexander Varakin <avarakin@hotmail.com> [stereo version] */
                .gpiomask       = 0xb33000,
                .gpiomux        = { 0x122000,0x1000,0x0000,0x620000 },
                .gpiomute       = 0x800000,
-       #endif
                /* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
                        gpio23 -- hef4052:nEnable (0x800000)
                        gpio12 -- hef4052:A1
@@ -1937,11 +1928,6 @@ struct tvcard bttv_tvcards[] = {
                .video_inputs   = 4,
                .audio_inputs   = 1,
                .tuner          = -1,
-       #if 0 /* TODO ... */
-               .svhs           = OSPREY540_SVID_ANALOG,
-               .muxsel         = {       [OSPREY540_COMP_ANALOG] = 2,
-                                       [OSPREY540_SVID_ANALOG] = 3, },
-       #endif
                .pll            = PLL_28,
                .tuner_type     = -1,
                .tuner_addr     = ADDR_UNSET,
@@ -1949,10 +1935,6 @@ struct tvcard bttv_tvcards[] = {
                .no_msp34xx     = 1,
                .no_tda9875     = 1,
                .no_tda7432     = 1,
-       #if 0 /* TODO ... */
-               .muxsel_hook    = osprey_540_muxsel,
-               .picture_hook   = osprey_540_set_picture,
-       #endif
        },
 
                /* ---- card 0x5C ---------------------------------- */
@@ -2627,9 +2609,6 @@ struct tvcard bttv_tvcards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .has_radio      = 0,
-       #if 0
-               .has_remote     = 1,
-       #endif
        },
        [BTTV_BOARD_SUPER_TV] = {
                /* Rick C <cryptdragoon@gmail.com> */
index 41fd09d..5720b77 100644 (file)
@@ -9,6 +9,10 @@
     some v4l2 code lines are taken from Justin's bttv2 driver which is
     (c) 2000 Justin Schoeman <justin@suntiger.ee.up.ac.za>
 
+    Cropping and overscan support
+    Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
+    Sponsored by OPQ Systems AB
+
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
@@ -64,6 +68,7 @@ static unsigned int radio[BTTV_MAX];
 static unsigned int irq_debug;
 static unsigned int gbuffers = 8;
 static unsigned int gbufsize = 0x208000;
+static unsigned int reset_crop = 1;
 
 static int video_nr = -1;
 static int radio_nr = -1;
@@ -103,6 +108,7 @@ module_param(radio_nr,          int, 0444);
 module_param(vbi_nr,            int, 0444);
 module_param(gbuffers,          int, 0444);
 module_param(gbufsize,          int, 0444);
+module_param(reset_crop,        int, 0444);
 
 module_param(v4l2,              int, 0644);
 module_param(bigendian,         int, 0644);
@@ -129,6 +135,8 @@ MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
 MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
 MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8");
 MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
+MODULE_PARM_DESC(reset_crop,"reset cropping parameters at open(), default "
+                "is 1 (yes) for compatibility with older applications");
 MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");
 MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");
 MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
@@ -192,6 +200,33 @@ static u8 SRAM_Table[][60] =
        }
 };
 
+/* minhdelayx1 first video pixel we can capture on a line and
+   hdelayx1    start of active video, both relative to rising edge of
+               /HRESET pulse (0H) in 1 / fCLKx1.
+   swidth      width of active video and
+   totalwidth  total line width, both in 1 / fCLKx1.
+   sqwidth     total line width in square pixels.
+   vdelay      start of active video in 2 * field lines relative to
+               trailing edge of /VRESET pulse (VDELAY register).
+   sheight     height of active video in 2 * field lines.
+   videostart0 ITU-R frame line number of the line corresponding
+               to vdelay in the first field. */
+#define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth,     \
+               vdelay, sheight, videostart0)                            \
+       .cropcap.bounds.left = minhdelayx1,                              \
+       /* * 2 because vertically we count field lines times two, */     \
+       /* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */           \
+       .cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \
+       /* 4 is a safety margin at the end of the line. */               \
+       .cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4,        \
+       .cropcap.bounds.height = (sheight) + (vdelay) - MIN_VDELAY,      \
+       .cropcap.defrect.left = hdelayx1,                                \
+       .cropcap.defrect.top = (videostart0) * 2,                        \
+       .cropcap.defrect.width = swidth,                                 \
+       .cropcap.defrect.height = sheight,                               \
+       .cropcap.pixelaspect.numerator = totalwidth,                     \
+       .cropcap.pixelaspect.denominator = sqwidth,
+
 const struct bttv_tvnorm bttv_tvnorms[] = {
        /* PAL-BDGHI */
        /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
@@ -210,11 +245,26 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                .hdelayx1       = 186,
                .hactivex1      = 924,
                .vdelay         = 0x20,
-               .vbipack        = 255,
+               .vbipack        = 255, /* min (2048 / 4, 0x1ff) & 0xff */
                .sram           = 0,
                /* ITU-R frame line number of the first VBI line
-                  we can capture, of the first and second field. */
-               .vbistart       = { 7,320 },
+                  we can capture, of the first and second field.
+                  The last line is determined by cropcap.bounds. */
+               .vbistart       = { 7, 320 },
+               CROPCAP(/* minhdelayx1 */ 68,
+                       /* hdelayx1 */ 186,
+                       /* Should be (768 * 1135 + 944 / 2) / 944.
+                          cropcap.defrect is used for image width
+                          checks, so we keep the old value 924. */
+                       /* swidth */ 924,
+                       /* totalwidth */ 1135,
+                       /* sqwidth */ 944,
+                       /* vdelay */ 0x20,
+                       /* sheight */ 576,
+                       /* videostart0 */ 23)
+               /* bt878 (and bt848?) can capture another
+                  line below active video. */
+               .cropcap.bounds.height = (576 + 2) + 0x20 - 2,
        },{
                .v4l2_id        = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
                .name           = "NTSC",
@@ -229,9 +279,18 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                .hdelayx1       = 128,
                .hactivex1      = 910,
                .vdelay         = 0x1a,
-               .vbipack        = 144,
+               .vbipack        = 144, /* min (1600 / 4, 0x1ff) & 0xff */
                .sram           = 1,
                .vbistart       = { 10, 273 },
+               CROPCAP(/* minhdelayx1 */ 68,
+                       /* hdelayx1 */ 128,
+                       /* Should be (640 * 910 + 780 / 2) / 780? */
+                       /* swidth */ 768,
+                       /* totalwidth */ 910,
+                       /* sqwidth */ 780,
+                       /* vdelay */ 0x1a,
+                       /* sheight */ 480,
+                       /* videostart0 */ 23)
        },{
                .v4l2_id        = V4L2_STD_SECAM,
                .name           = "SECAM",
@@ -249,6 +308,14 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                .vbipack        = 255,
                .sram           = 0, /* like PAL, correct? */
                .vbistart       = { 7, 320 },
+               CROPCAP(/* minhdelayx1 */ 68,
+                       /* hdelayx1 */ 186,
+                       /* swidth */ 924,
+                       /* totalwidth */ 1135,
+                       /* sqwidth */ 944,
+                       /* vdelay */ 0x20,
+                       /* sheight */ 576,
+                       /* videostart0 */ 23)
        },{
                .v4l2_id        = V4L2_STD_PAL_Nc,
                .name           = "PAL-Nc",
@@ -266,6 +333,14 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                .vbipack        = 144,
                .sram           = -1,
                .vbistart       = { 7, 320 },
+               CROPCAP(/* minhdelayx1 */ 68,
+                       /* hdelayx1 */ 130,
+                       /* swidth */ (640 * 910 + 780 / 2) / 780,
+                       /* totalwidth */ 910,
+                       /* sqwidth */ 780,
+                       /* vdelay */ 0x1a,
+                       /* sheight */ 576,
+                       /* videostart0 */ 23)
        },{
                .v4l2_id        = V4L2_STD_PAL_M,
                .name           = "PAL-M",
@@ -283,6 +358,14 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                .vbipack        = 144,
                .sram           = -1,
                .vbistart       = { 10, 273 },
+               CROPCAP(/* minhdelayx1 */ 68,
+                       /* hdelayx1 */ 135,
+                       /* swidth */ (640 * 910 + 780 / 2) / 780,
+                       /* totalwidth */ 910,
+                       /* sqwidth */ 780,
+                       /* vdelay */ 0x1a,
+                       /* sheight */ 480,
+                       /* videostart0 */ 23)
        },{
                .v4l2_id        = V4L2_STD_PAL_N,
                .name           = "PAL-N",
@@ -299,7 +382,15 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                .vdelay         = 0x20,
                .vbipack        = 144,
                .sram           = -1,
-               .vbistart       = { 7, 320},
+               .vbistart       = { 7, 320 },
+               CROPCAP(/* minhdelayx1 */ 68,
+                       /* hdelayx1 */ 186,
+                       /* swidth */ (768 * 1135 + 944 / 2) / 944,
+                       /* totalwidth */ 1135,
+                       /* sqwidth */ 944,
+                       /* vdelay */ 0x20,
+                       /* sheight */ 576,
+                       /* videostart0 */ 23)
        },{
                .v4l2_id        = V4L2_STD_NTSC_M_JP,
                .name           = "NTSC-JP",
@@ -316,7 +407,15 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                .vdelay         = 0x16,
                .vbipack        = 144,
                .sram           = -1,
-               .vbistart       = {10, 273},
+               .vbistart       = { 10, 273 },
+               CROPCAP(/* minhdelayx1 */ 68,
+                       /* hdelayx1 */ 135,
+                       /* swidth */ (640 * 910 + 780 / 2) / 780,
+                       /* totalwidth */ 910,
+                       /* sqwidth */ 780,
+                       /* vdelay */ 0x16,
+                       /* sheight */ 480,
+                       /* videostart0 */ 23)
        },{
                /* that one hopefully works with the strange timing
                 * which video recorders produce when playing a NTSC
@@ -338,6 +437,14 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                .vtotal         = 524,
                .sram           = -1,
                .vbistart       = { 10, 273 },
+               CROPCAP(/* minhdelayx1 */ 68,
+                       /* hdelayx1 */ 186,
+                       /* swidth */ 924,
+                       /* totalwidth */ 1135,
+                       /* sqwidth */ 944,
+                       /* vdelay */ 0x1a,
+                       /* sheight */ 480,
+                       /* videostart0 */ 23)
        }
 };
 static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
@@ -678,25 +785,89 @@ static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
 /* ----------------------------------------------------------------------- */
 /* resource management                                                     */
 
+/*
+   RESOURCE_    allocated by                freed by
+
+   VIDEO_READ   bttv_read 1)                bttv_read 2)
+
+   VIDEO_STREAM VIDIOC_STREAMON             VIDIOC_STREAMOFF
+                VIDIOC_QBUF 1)              bttv_release
+                VIDIOCMCAPTURE 1)
+
+   OVERLAY      VIDIOCCAPTURE on            VIDIOCCAPTURE off
+                VIDIOC_OVERLAY on           VIDIOC_OVERLAY off
+                3)                          bttv_release
+
+   VBI          VIDIOC_STREAMON             VIDIOC_STREAMOFF
+                VIDIOC_QBUF 1)              bttv_release
+                bttv_read, bttv_poll 1) 4)
+
+   1) The resource must be allocated when we enter buffer prepare functions
+      and remain allocated while buffers are in the DMA queue.
+   2) This is a single frame read.
+   3) VIDIOC_S_FBUF and VIDIOC_S_FMT (OVERLAY) still work when
+      RESOURCE_OVERLAY is allocated.
+   4) This is a continuous read, implies VIDIOC_STREAMON.
+
+   Note this driver permits video input and standard changes regardless if
+   resources are allocated.
+*/
+
+#define VBI_RESOURCES (RESOURCE_VBI)
+#define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \
+                        RESOURCE_VIDEO_STREAM | \
+                        RESOURCE_OVERLAY)
+
 static
 int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
 {
+       int xbits; /* mutual exclusive resources */
+
        if (fh->resources & bit)
                /* have it already allocated */
                return 1;
 
+       xbits = bit;
+       if (bit & (RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM))
+               xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM;
+
        /* is it free? */
-       mutex_lock(&btv->reslock);
-       if (btv->resources & bit) {
+       mutex_lock(&btv->lock);
+       if (btv->resources & xbits) {
                /* no, someone else uses it */
-               mutex_unlock(&btv->reslock);
-               return 0;
+               goto fail;
+       }
+
+       if ((bit & VIDEO_RESOURCES)
+           && 0 == (btv->resources & VIDEO_RESOURCES)) {
+               /* Do crop - use current, don't - use default parameters. */
+               __s32 top = btv->crop[!!fh->do_crop].rect.top;
+
+               if (btv->vbi_end > top)
+                       goto fail;
+
+               /* We cannot capture the same line as video and VBI data.
+                  Claim scan lines crop[].rect.top to bottom. */
+               btv->crop_start = top;
+       } else if (bit & VBI_RESOURCES) {
+               __s32 end = fh->vbi_fmt.end;
+
+               if (end > btv->crop_start)
+                       goto fail;
+
+               /* Claim scan lines above fh->vbi_fmt.end. */
+               btv->vbi_end = end;
        }
+
        /* it's free, grab it */
        fh->resources  |= bit;
        btv->resources |= bit;
-       mutex_unlock(&btv->reslock);
+       mutex_unlock(&btv->lock);
        return 1;
+
+ fail:
+       mutex_unlock(&btv->lock);
+       return 0;
 }
 
 static
@@ -711,6 +882,35 @@ int locked_btres(struct bttv *btv, int bit)
        return (btv->resources & bit);
 }
 
+/* Call with btv->lock down. */
+static void
+disclaim_vbi_lines(struct bttv *btv)
+{
+       btv->vbi_end = 0;
+}
+
+/* Call with btv->lock down. */
+static void
+disclaim_video_lines(struct bttv *btv)
+{
+       const struct bttv_tvnorm *tvnorm;
+       u8 crop;
+
+       tvnorm = &bttv_tvnorms[btv->tvnorm];
+       btv->crop_start = tvnorm->cropcap.bounds.top
+               + tvnorm->cropcap.bounds.height;
+
+       /* VBI capturing ends at VDELAY, start of video capturing, no
+          matter how many lines the VBI RISC program expects. When video
+          capturing is off, it shall no longer "preempt" VBI capturing,
+          so we set VDELAY to maximum. */
+       crop = btread(BT848_E_CROP) | 0xc0;
+       btwrite(crop, BT848_E_CROP);
+       btwrite(0xfe, BT848_E_VDELAY_LO);
+       btwrite(crop, BT848_O_CROP);
+       btwrite(0xfe, BT848_O_VDELAY_LO);
+}
+
 static
 void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
 {
@@ -718,10 +918,19 @@ void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
                /* trying to free ressources not allocated by us ... */
                printk("bttv: BUG! (btres)\n");
        }
-       mutex_lock(&btv->reslock);
+       mutex_lock(&btv->lock);
        fh->resources  &= ~bits;
        btv->resources &= ~bits;
-       mutex_unlock(&btv->reslock);
+
+       bits = btv->resources;
+
+       if (0 == (bits & VIDEO_RESOURCES))
+               disclaim_video_lines(btv);
+
+       if (0 == (bits & VBI_RESOURCES))
+               disclaim_vbi_lines(btv);
+
+       mutex_unlock(&btv->lock);
 }
 
 /* ----------------------------------------------------------------------- */
@@ -1030,6 +1239,36 @@ i2c_vidiocschan(struct bttv *btv)
                bttv_tda9880_setnorm(btv,btv->tvnorm);
 }
 
+static void
+bttv_crop_calc_limits(struct bttv_crop *c)
+{
+       /* Scale factor min. 1:1, max. 16:1. Min. image size
+          48 x 32. Scaled width must be a multiple of 4. */
+
+       if (1) {
+               /* For bug compatibility with VIDIOCGCAP and image
+                  size checks in earlier driver versions. */
+               c->min_scaled_width = 48;
+               c->min_scaled_height = 32;
+       } else {
+               c->min_scaled_width =
+                       (max(48, c->rect.width >> 4) + 3) & ~3;
+               c->min_scaled_height =
+                       max(32, c->rect.height >> 4);
+       }
+
+       c->max_scaled_width  = c->rect.width & ~3;
+       c->max_scaled_height = c->rect.height;
+}
+
+static void
+bttv_crop_reset(struct bttv_crop *c, int norm)
+{
+       c->rect = bttv_tvnorms[norm].cropcap.defrect;
+       bttv_crop_calc_limits(c);
+}
+
+/* Call with btv->lock down. */
 static int
 set_tvnorm(struct bttv *btv, unsigned int norm)
 {
@@ -1038,9 +1277,24 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
        if (norm < 0 || norm >= BTTV_TVNORMS)
                return -EINVAL;
 
-       btv->tvnorm = norm;
        tvnorm = &bttv_tvnorms[norm];
 
+       if (btv->tvnorm < 0 ||
+           btv->tvnorm >= BTTV_TVNORMS ||
+           0 != memcmp(&bttv_tvnorms[btv->tvnorm].cropcap,
+                       &tvnorm->cropcap,
+                       sizeof (tvnorm->cropcap))) {
+               bttv_crop_reset(&btv->crop[0], norm);
+               btv->crop[1] = btv->crop[0]; /* current = default */
+
+               if (0 == (btv->resources & VIDEO_RESOURCES)) {
+                       btv->crop_start = tvnorm->cropcap.bounds.top
+                               + tvnorm->cropcap.bounds.height;
+               }
+       }
+
+       btv->tvnorm = norm;
+
        btwrite(tvnorm->adelay, BT848_ADELAY);
        btwrite(tvnorm->bdelay, BT848_BDELAY);
        btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
@@ -1057,6 +1311,7 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
        return 0;
 }
 
+/* Call with btv->lock down. */
 static void
 set_input(struct bttv *btv, unsigned int input)
 {
@@ -1459,13 +1714,13 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
        btv->loop_irq |= 1;
        bttv_set_dma(btv, 0x03);
        spin_unlock_irqrestore(&btv->s_lock,flags);
-       if (NULL == new)
-               free_btres(btv,fh,RESOURCE_OVERLAY);
        if (NULL != old) {
                dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
                bttv_dma_free(&fh->cap,btv, old);
                kfree(old);
        }
+       if (NULL == new)
+               free_btres(btv,fh,RESOURCE_OVERLAY);
        dprintk("switch_overlay: done\n");
        return retval;
 }
@@ -1479,7 +1734,10 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
                               unsigned int width, unsigned int height,
                               enum v4l2_field field)
 {
+       struct bttv_fh *fh = q->priv_data;
        int redo_dma_risc = 0;
+       struct bttv_crop c;
+       int norm;
        int rc;
 
        /* check settings */
@@ -1491,12 +1749,52 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
                if (width*height > buf->vb.bsize)
                        return -EINVAL;
                buf->vb.size = buf->vb.bsize;
+
+               /* Make sure tvnorm and vbi_end remain consistent
+                  until we're done. */
+               mutex_lock(&btv->lock);
+
+               norm = btv->tvnorm;
+
+               /* In this mode capturing always starts at defrect.top
+                  (default VDELAY), ignoring cropping parameters. */
+               if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) {
+                       mutex_unlock(&btv->lock);
+                       return -EINVAL;
+               }
+
+               mutex_unlock(&btv->lock);
+
+               c.rect = bttv_tvnorms[norm].cropcap.defrect;
        } else {
-               if (width  < 48 ||
-                   height < 32 ||
-                   width  > bttv_tvnorms[btv->tvnorm].swidth ||
-                   height > bttv_tvnorms[btv->tvnorm].sheight)
+               mutex_lock(&btv->lock);
+
+               norm = btv->tvnorm;
+               c = btv->crop[!!fh->do_crop];
+
+               mutex_unlock(&btv->lock);
+
+               if (width < c.min_scaled_width ||
+                   width > c.max_scaled_width ||
+                   height < c.min_scaled_height)
                        return -EINVAL;
+
+               switch (field) {
+               case V4L2_FIELD_TOP:
+               case V4L2_FIELD_BOTTOM:
+               case V4L2_FIELD_ALTERNATE:
+                       /* btv->crop counts frame lines. Max. scale
+                          factor is 16:1 for frames, 8:1 for fields. */
+                       if (height * 2 > c.max_scaled_height)
+                               return -EINVAL;
+                       break;
+
+               default:
+                       if (height > c.max_scaled_height)
+                               return -EINVAL;
+                       break;
+               }
+
                buf->vb.size = (width * height * fmt->depth) >> 3;
                if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
                        return -EINVAL;
@@ -1505,12 +1803,17 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
        /* alloc + fill struct bttv_buffer (if changed) */
        if (buf->vb.width != width || buf->vb.height != height ||
            buf->vb.field != field ||
-           buf->tvnorm != btv->tvnorm || buf->fmt != fmt) {
+           buf->tvnorm != norm || buf->fmt != fmt ||
+           buf->crop.top != c.rect.top ||
+           buf->crop.left != c.rect.left ||
+           buf->crop.width != c.rect.width ||
+           buf->crop.height != c.rect.height) {
                buf->vb.width  = width;
                buf->vb.height = height;
                buf->vb.field  = field;
-               buf->tvnorm    = btv->tvnorm;
+               buf->tvnorm    = norm;
                buf->fmt       = fmt;
+               buf->crop      = c.rect;
                redo_dma_risc = 1;
        }
 
@@ -1577,7 +1880,7 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
        struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
        struct bttv_fh *fh = q->priv_data;
 
-       bttv_dma_free(&fh->cap,fh->btv,buf);
+       bttv_dma_free(q,fh->btv,buf);
 }
 
 static struct videobuf_queue_ops bttv_video_qops = {
@@ -1939,11 +2242,179 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
        return 0;
 }
 
-static int verify_window(const struct bttv_tvnorm *tvn,
-                        struct v4l2_window *win, int fixup)
+/* Given cropping boundaries b and the scaled width and height of a
+   single field or frame, which must not exceed hardware limits, this
+   function adjusts the cropping parameters c. */
+static void
+bttv_crop_adjust       (struct bttv_crop *             c,
+                        const struct v4l2_rect *       b,
+                        __s32                          width,
+                        __s32                          height,
+                        enum v4l2_field                field)
+{
+       __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field);
+       __s32 max_left;
+       __s32 max_top;
+
+       if (width < c->min_scaled_width) {
+               /* Max. hor. scale factor 16:1. */
+               c->rect.width = width * 16;
+       } else if (width > c->max_scaled_width) {
+               /* Min. hor. scale factor 1:1. */
+               c->rect.width = width;
+
+               max_left = b->left + b->width - width;
+               max_left = min(max_left, (__s32) MAX_HDELAY);
+               if (c->rect.left > max_left)
+                       c->rect.left = max_left;
+       }
+
+       if (height < c->min_scaled_height) {
+               /* Max. vert. scale factor 16:1, single fields 8:1. */
+               c->rect.height = height * 16;
+       } else if (frame_height > c->max_scaled_height) {
+               /* Min. vert. scale factor 1:1.
+                  Top and height count field lines times two. */
+               c->rect.height = (frame_height + 1) & ~1;
+
+               max_top = b->top + b->height - c->rect.height;
+               if (c->rect.top > max_top)
+                       c->rect.top = max_top;
+       }
+
+       bttv_crop_calc_limits(c);
+}
+
+/* Returns an error if scaling to a frame or single field with the given
+   width and height is not possible with the current cropping parameters
+   and width aligned according to width_mask. If adjust_size is TRUE the
+   function may adjust the width and/or height instead, rounding width
+   to (width + width_bias) & width_mask. If adjust_crop is TRUE it may
+   also adjust the current cropping parameters to get closer to the
+   desired image size. */
+static int
+limit_scaled_size       (struct bttv_fh *               fh,
+                        __s32 *                        width,
+                        __s32 *                        height,
+                        enum v4l2_field                field,
+                        unsigned int                   width_mask,
+                        unsigned int                   width_bias,
+                        int                            adjust_size,
+                        int                            adjust_crop)
+{
+       struct bttv *btv = fh->btv;
+       const struct v4l2_rect *b;
+       struct bttv_crop *c;
+       __s32 min_width;
+       __s32 min_height;
+       __s32 max_width;
+       __s32 max_height;
+       int rc;
+
+       BUG_ON((int) width_mask >= 0 ||
+              width_bias >= (unsigned int) -width_mask);
+
+       /* Make sure tvnorm, vbi_end and the current cropping parameters
+          remain consistent until we're done. */
+       mutex_lock(&btv->lock);
+
+       b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
+
+       /* Do crop - use current, don't - use default parameters. */
+       c = &btv->crop[!!fh->do_crop];
+
+       if (fh->do_crop
+           && adjust_size
+           && adjust_crop
+           && !locked_btres(btv, VIDEO_RESOURCES)) {
+               min_width = 48;
+               min_height = 32;
+
+               /* We cannot scale up. When the scaled image is larger
+                  than crop.rect we adjust the crop.rect as required
+                  by the V4L2 spec, hence cropcap.bounds are our limit. */
+               max_width = min(b->width, (__s32) MAX_HACTIVE);
+               max_height = b->height;
+
+               /* We cannot capture the same line as video and VBI data.
+                  Note btv->vbi_end is really a minimum, see
+                  bttv_vbi_try_fmt(). */
+               if (btv->vbi_end > b->top) {
+                       max_height -= btv->vbi_end - b->top;
+                       rc = -EBUSY;
+                       if (min_height > max_height)
+                               goto fail;
+               }
+       } else {
+               rc = -EBUSY;
+               if (btv->vbi_end > c->rect.top)
+                       goto fail;
+
+               min_width  = c->min_scaled_width;
+               min_height = c->min_scaled_height;
+               max_width  = c->max_scaled_width;
+               max_height = c->max_scaled_height;
+
+               adjust_crop = 0;
+       }
+
+       min_width = (min_width - width_mask - 1) & width_mask;
+       max_width = max_width & width_mask;
+
+       /* Max. scale factor is 16:1 for frames, 8:1 for fields. */
+       min_height = min_height;
+       /* Min. scale factor is 1:1. */
+       max_height >>= !V4L2_FIELD_HAS_BOTH(field);
+
+       if (adjust_size) {
+               *width = clamp(*width, min_width, max_width);
+               *height = clamp(*height, min_height, max_height);
+
+               /* Round after clamping to avoid overflow. */
+               *width = (*width + width_bias) & width_mask;
+
+               if (adjust_crop) {
+                       bttv_crop_adjust(c, b, *width, *height, field);
+
+                       if (btv->vbi_end > c->rect.top) {
+                               /* Move the crop window out of the way. */
+                               c->rect.top = btv->vbi_end;
+                       }
+               }
+       } else {
+               rc = -EINVAL;
+               if (*width  < min_width ||
+                   *height < min_height ||
+                   *width  > max_width ||
+                   *height > max_height ||
+                   0 != (*width & ~width_mask))
+                       goto fail;
+       }
+
+       rc = 0; /* success */
+
+ fail:
+       mutex_unlock(&btv->lock);
+
+       return rc;
+}
+
+/* Returns an error if the given overlay window dimensions are not
+   possible with the current cropping parameters. If adjust_size is
+   TRUE the function may adjust the window width and/or height
+   instead, however it always rounds the horizontal position and
+   width as btcx_align() does. If adjust_crop is TRUE the function
+   may also adjust the current cropping parameters to get closer
+   to the desired window size. */
+static int
+verify_window          (struct bttv_fh *               fh,
+                        struct v4l2_window *           win,
+                        int                            adjust_size,
+                        int                            adjust_crop)
 {
        enum v4l2_field field;
-       int maxw, maxh;
+       unsigned int width_mask;
+       int rc;
 
        if (win->w.width  < 48 || win->w.height < 32)
                return -EINVAL;
@@ -1951,32 +2422,52 @@ static int verify_window(const struct bttv_tvnorm *tvn,
                return -EINVAL;
 
        field = win->field;
-       maxw  = tvn->swidth;
-       maxh  = tvn->sheight;
 
        if (V4L2_FIELD_ANY == field) {
-               field = (win->w.height > maxh/2)
+               __s32 height2;
+
+               height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1;
+               field = (win->w.height > height2)
                        ? V4L2_FIELD_INTERLACED
                        : V4L2_FIELD_TOP;
        }
        switch (field) {
        case V4L2_FIELD_TOP:
        case V4L2_FIELD_BOTTOM:
-               maxh = maxh / 2;
-               break;
        case V4L2_FIELD_INTERLACED:
                break;
        default:
                return -EINVAL;
        }
 
-       if (!fixup && (win->w.width > maxw || win->w.height > maxh))
+       /* 4-byte alignment. */
+       if (NULL == fh->ovfmt)
                return -EINVAL;
+       width_mask = ~0;
+       switch (fh->ovfmt->depth) {
+       case 8:
+       case 24:
+               width_mask = ~3;
+               break;
+       case 16:
+               width_mask = ~1;
+               break;
+       case 32:
+               break;
+       default:
+               BUG();
+       }
+
+       win->w.width -= win->w.left & ~width_mask;
+       win->w.left = (win->w.left - width_mask - 1) & width_mask;
+
+       rc = limit_scaled_size(fh, &win->w.width, &win->w.height,
+                              field, width_mask,
+                              /* width_bias: round down */ 0,
+                              adjust_size, adjust_crop);
+       if (0 != rc)
+               return rc;
 
-       if (win->w.width > maxw)
-               win->w.width = maxw;
-       if (win->w.height > maxh)
-               win->w.height = maxh;
        win->field = field;
        return 0;
 }
@@ -1991,7 +2482,9 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
                return -EINVAL;
        if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
                return -EINVAL;
-       retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup);
+       retval = verify_window(fh, win,
+                              /* adjust_size */ fixup,
+                              /* adjust_crop */ fixup);
        if (0 != retval)
                return retval;
 
@@ -2048,6 +2541,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
                struct bttv_buffer *new;
 
                new = videobuf_alloc(sizeof(*new));
+               new->crop = btv->crop[!!fh->do_crop].rect;
                bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
                retval = bttv_switch_overlay(btv,fh,new);
        }
@@ -2080,7 +2574,7 @@ static int bttv_resource(struct bttv_fh *fh)
 
        switch (fh->type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               res = RESOURCE_VIDEO;
+               res = RESOURCE_VIDEO_STREAM;
                break;
        case V4L2_BUF_TYPE_VBI_CAPTURE:
                res = RESOURCE_VBI;
@@ -2138,7 +2632,7 @@ static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
                f->fmt.win.field = fh->ov.field;
                return 0;
        case V4L2_BUF_TYPE_VBI_CAPTURE:
-               bttv_vbi_get_fmt(fh,f);
+               bttv_vbi_get_fmt(fh, &f->fmt.vbi);
                return 0;
        default:
                return -EINVAL;
@@ -2146,35 +2640,35 @@ static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
 }
 
 static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
-                       struct v4l2_format *f)
+                       struct v4l2_format *f, int adjust_crop)
 {
        switch (f->type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
        {
                const struct bttv_format *fmt;
                enum v4l2_field field;
-               unsigned int maxw,maxh;
+               __s32 width, height;
+               int rc;
 
                fmt = format_by_fourcc(f->fmt.pix.pixelformat);
                if (NULL == fmt)
                        return -EINVAL;
 
-               /* fixup format */
-               maxw  = bttv_tvnorms[btv->tvnorm].swidth;
-               maxh  = bttv_tvnorms[btv->tvnorm].sheight;
                field = f->fmt.pix.field;
-               if (V4L2_FIELD_ANY == field)
-                       field = (f->fmt.pix.height > maxh/2)
+               if (V4L2_FIELD_ANY == field) {
+                       __s32 height2;
+
+                       height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
+                       field = (f->fmt.pix.height > height2)
                                ? V4L2_FIELD_INTERLACED
                                : V4L2_FIELD_BOTTOM;
+               }
                if (V4L2_FIELD_SEQ_BT == field)
                        field = V4L2_FIELD_SEQ_TB;
                switch (field) {
                case V4L2_FIELD_TOP:
                case V4L2_FIELD_BOTTOM:
                case V4L2_FIELD_ALTERNATE:
-                       maxh = maxh/2;
-                       break;
                case V4L2_FIELD_INTERLACED:
                        break;
                case V4L2_FIELD_SEQ_TB:
@@ -2185,28 +2679,29 @@ static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
                        return -EINVAL;
                }
 
+               width = f->fmt.pix.width;
+               height = f->fmt.pix.height;
+
+               rc = limit_scaled_size(fh, &width, &height, field,
+                                      /* width_mask: 4 pixels */ ~3,
+                                      /* width_bias: nearest */ 2,
+                                      /* adjust_size */ 1,
+                                      adjust_crop);
+               if (0 != rc)
+                       return rc;
+
                /* update data for the application */
                f->fmt.pix.field = field;
-               if (f->fmt.pix.width  < 48)
-                       f->fmt.pix.width  = 48;
-               if (f->fmt.pix.height < 32)
-                       f->fmt.pix.height = 32;
-               if (f->fmt.pix.width  > maxw)
-                       f->fmt.pix.width = maxw;
-               if (f->fmt.pix.height > maxh)
-                       f->fmt.pix.height = maxh;
-               pix_format_set_size (&f->fmt.pix, fmt,
-                                    f->fmt.pix.width & ~3,
-                                    f->fmt.pix.height);
+               pix_format_set_size(&f->fmt.pix, fmt, width, height);
 
                return 0;
        }
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-               return verify_window(&bttv_tvnorms[btv->tvnorm],
-                                    &f->fmt.win, 1);
+               return verify_window(fh, &f->fmt.win,
+                                    /* adjust_size */ 1,
+                                    /* adjust_crop */ 0);
        case V4L2_BUF_TYPE_VBI_CAPTURE:
-               bttv_vbi_try_fmt(fh,f);
-               return 0;
+               return bttv_vbi_try_fmt(fh, &f->fmt.vbi);
        default:
                return -EINVAL;
        }
@@ -2225,7 +2720,7 @@ static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
                retval = bttv_switch_type(fh,f->type);
                if (0 != retval)
                        return retval;
-               retval = bttv_try_fmt(fh,btv,f);
+               retval = bttv_try_fmt(fh,btv,f, /* adjust_crop */ 1);
                if (0 != retval)
                        return retval;
                fmt = format_by_fourcc(f->fmt.pix.pixelformat);
@@ -2254,12 +2749,7 @@ static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
                retval = bttv_switch_type(fh,f->type);
                if (0 != retval)
                        return retval;
-               if (locked_btres(fh->btv, RESOURCE_VBI))
-                       return -EBUSY;
-               bttv_vbi_try_fmt(fh,f);
-               bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
-               bttv_vbi_get_fmt(fh,f);
-               return 0;
+               return bttv_vbi_set_fmt(fh, &f->fmt.vbi);
        default:
                return -EINVAL;
        }
@@ -2517,6 +3007,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                if (*on) {
                        fh->ov.tvnorm = btv->tvnorm;
                        new = videobuf_alloc(sizeof(*new));
+                       new->crop = btv->crop[!!fh->do_crop].rect;
                        bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
                } else {
                        new = NULL;
@@ -2551,10 +3042,16 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                struct video_mmap *vm = arg;
                struct bttv_buffer *buf;
                enum v4l2_field field;
+               __s32 height2;
+               int res;
 
                if (vm->frame >= VIDEO_MAX_FRAME)
                        return -EINVAL;
 
+               res = bttv_resource(fh);
+               if (!check_alloc_btres(btv, fh, res))
+                       return -EBUSY;
+
                mutex_lock(&fh->cap.lock);
                retval = -EINVAL;
                buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
@@ -2566,7 +3063,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                    buf->vb.state == STATE_ACTIVE)
                        goto fh_unlock_and_return;
 
-               field = (vm->height > bttv_tvnorms[btv->tvnorm].sheight/2)
+               height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
+               field = (vm->height > height2)
                        ? V4L2_FIELD_INTERLACED
                        : V4L2_FIELD_BOTTOM;
                retval = bttv_prepare_buffer(&fh->cap,btv,buf,
@@ -2613,54 +3111,17 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
        }
 
        case VIDIOCGVBIFMT:
-       {
-               struct vbi_format *fmt = (void *) arg;
-               struct v4l2_format fmt2;
-
                if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
                        retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
                        if (0 != retval)
                                return retval;
                }
-               bttv_vbi_get_fmt(fh, &fmt2);
-
-               memset(fmt,0,sizeof(*fmt));
-               fmt->sampling_rate    = fmt2.fmt.vbi.sampling_rate;
-               fmt->samples_per_line = fmt2.fmt.vbi.samples_per_line;
-               fmt->sample_format    = VIDEO_PALETTE_RAW;
-               fmt->start[0]         = fmt2.fmt.vbi.start[0];
-               fmt->count[0]         = fmt2.fmt.vbi.count[0];
-               fmt->start[1]         = fmt2.fmt.vbi.start[1];
-               fmt->count[1]         = fmt2.fmt.vbi.count[1];
-               if (fmt2.fmt.vbi.flags & V4L2_VBI_UNSYNC)
-                       fmt->flags   |= VBI_UNSYNC;
-               if (fmt2.fmt.vbi.flags & V4L2_VBI_INTERLACED)
-                       fmt->flags   |= VBI_INTERLACED;
-               return 0;
-       }
-       case VIDIOCSVBIFMT:
-       {
-               struct vbi_format *fmt = (void *) arg;
-               struct v4l2_format fmt2;
 
-               retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
-               if (0 != retval)
-                       return retval;
-               bttv_vbi_get_fmt(fh, &fmt2);
-
-               if (fmt->sampling_rate    != fmt2.fmt.vbi.sampling_rate     ||
-                   fmt->samples_per_line != fmt2.fmt.vbi.samples_per_line  ||
-                   fmt->sample_format    != VIDEO_PALETTE_RAW              ||
-                   fmt->start[0]         != fmt2.fmt.vbi.start[0]          ||
-                   fmt->start[1]         != fmt2.fmt.vbi.start[1]          ||
-                   fmt->count[0]         != fmt->count[1]                  ||
-                   fmt->count[0]         <  1                              ||
-                   fmt->count[0]         >  32 /* VBI_MAXLINES */)
-                       return -EINVAL;
+               /* fall through */
 
-               bttv_vbi_setlines(fh,btv,fmt->count[0]);
-               return 0;
-       }
+       case VIDIOCSVBIFMT:
+               return v4l_compat_translate_ioctl(inode, file, cmd,
+                                                 arg, bttv_do_ioctl);
 
        case BTTV_VERSION:
        case VIDIOCGFREQ:
@@ -2753,7 +3214,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_TRY_FMT:
        {
                struct v4l2_format *f = arg;
-               return bttv_try_fmt(fh,btv,f);
+               return bttv_try_fmt(fh,btv,f, /* adjust_crop */ 0);
        }
        case VIDIOC_G_FMT:
        {
@@ -2792,16 +3253,23 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
                        return -EINVAL;
 
-               mutex_lock(&fh->cap.lock);
                retval = -EINVAL;
                if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
-                       if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth)
-                               goto fh_unlock_and_return;
-                       if (fb->fmt.height > bttv_tvnorms[btv->tvnorm].sheight)
-                               goto fh_unlock_and_return;
+                       __s32 width = fb->fmt.width;
+                       __s32 height = fb->fmt.height;
+
+                       retval = limit_scaled_size(fh, &width, &height,
+                                                  V4L2_FIELD_INTERLACED,
+                                                  /* width_mask */ ~3,
+                                                  /* width_bias */ 2,
+                                                  /* adjust_size */ 0,
+                                                  /* adjust_crop */ 0);
+                       if (0 != retval)
+                               return retval;
                }
 
                /* ok, accept it */
+               mutex_lock(&fh->cap.lock);
                btv->fbuf.base       = fb->base;
                btv->fbuf.fmt.width  = fb->fmt.width;
                btv->fbuf.fmt.height = fb->fmt.height;
@@ -2828,6 +3296,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                                struct bttv_buffer *new;
 
                                new = videobuf_alloc(sizeof(*new));
+                               new->crop = btv->crop[!!fh->do_crop].rect;
                                bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
                                retval = bttv_switch_overlay(btv,fh,new);
                        }
@@ -2843,7 +3312,13 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                return videobuf_querybuf(bttv_queue(fh),arg);
 
        case VIDIOC_QBUF:
+       {
+               int res = bttv_resource(fh);
+
+               if (!check_alloc_btres(btv, fh, res))
+                       return -EBUSY;
                return videobuf_qbuf(bttv_queue(fh),arg);
+       }
 
        case VIDIOC_DQBUF:
                return videobuf_dqbuf(bttv_queue(fh),arg,
@@ -2942,6 +3417,122 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
        }
 
+       case VIDIOC_CROPCAP:
+       {
+               struct v4l2_cropcap *cap = arg;
+               enum v4l2_buf_type type;
+
+               type = cap->type;
+
+               if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+                   type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+                       return -EINVAL;
+
+               *cap = bttv_tvnorms[btv->tvnorm].cropcap;
+               cap->type = type;
+
+               return 0;
+       }
+       case VIDIOC_G_CROP:
+       {
+               struct v4l2_crop * crop = arg;
+
+               if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+                   crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+                       return -EINVAL;
+
+               /* No fh->do_crop = 1; because btv->crop[1] may be
+                  inconsistent with fh->width or fh->height and apps
+                  do not expect a change here. */
+
+               crop->c = btv->crop[!!fh->do_crop].rect;
+
+               return 0;
+       }
+       case VIDIOC_S_CROP:
+       {
+               struct v4l2_crop *crop = arg;
+               const struct v4l2_rect *b;
+               struct bttv_crop c;
+               __s32 b_left;
+               __s32 b_top;
+               __s32 b_right;
+               __s32 b_bottom;
+
+               if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+                   crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+                       return -EINVAL;
+
+               retval = v4l2_prio_check(&btv->prio,&fh->prio);
+               if (0 != retval)
+                       return retval;
+
+               /* Make sure tvnorm, vbi_end and the current cropping
+                  parameters remain consistent until we're done. Note
+                  read() may change vbi_end in check_alloc_btres(). */
+               mutex_lock(&btv->lock);
+
+               retval = -EBUSY;
+
+               if (locked_btres(fh->btv, VIDEO_RESOURCES))
+                       goto btv_unlock_and_return;
+
+               b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
+
+               b_left = b->left;
+               b_right = b_left + b->width;
+               b_bottom = b->top + b->height;
+
+               b_top = max(b->top, btv->vbi_end);
+               if (b_top + 32 >= b_bottom)
+                       goto btv_unlock_and_return;
+
+               /* Min. scaled size 48 x 32. */
+               c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
+               c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
+
+               c.rect.width = clamp(crop->c.width,
+                                    48, b_right - c.rect.left);
+
+               c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
+               /* Top and height must be a multiple of two. */
+               c.rect.top = (c.rect.top + 1) & ~1;
+
+               c.rect.height = clamp(crop->c.height,
+                                     32, b_bottom - c.rect.top);
+               c.rect.height = (c.rect.height + 1) & ~1;
+
+               bttv_crop_calc_limits(&c);
+
+               btv->crop[1] = c;
+
+               mutex_unlock(&btv->lock);
+
+               fh->do_crop = 1;
+
+               mutex_lock(&fh->cap.lock);
+
+               if (fh->width < c.min_scaled_width) {
+                       fh->width = c.min_scaled_width;
+                       btv->init.width = c.min_scaled_width;
+               } else if (fh->width > c.max_scaled_width) {
+                       fh->width = c.max_scaled_width;
+                       btv->init.width = c.max_scaled_width;
+               }
+
+               if (fh->height < c.min_scaled_height) {
+                       fh->height = c.min_scaled_height;
+                       btv->init.height = c.min_scaled_height;
+               } else if (fh->height > c.max_scaled_height) {
+                       fh->height = c.max_scaled_height;
+                       btv->init.height = c.max_scaled_height;
+               }
+
+               mutex_unlock(&fh->cap.lock);
+
+               return 0;
+       }
+
        case VIDIOC_ENUMSTD:
        case VIDIOC_G_STD:
        case VIDIOC_S_STD:
@@ -2963,6 +3554,10 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
  fh_unlock_and_return:
        mutex_unlock(&fh->cap.lock);
        return retval;
+
+ btv_unlock_and_return:
+       mutex_unlock(&btv->lock);
+       return retval;
 }
 
 static int bttv_ioctl(struct inode *inode, struct file *file,
@@ -2972,8 +3567,26 @@ static int bttv_ioctl(struct inode *inode, struct file *file,
 
        switch (cmd) {
        case BTTV_VBISIZE:
+       {
+               const struct bttv_tvnorm *tvnorm;
+
+               tvnorm = fh->vbi_fmt.tvnorm;
+
+               if (fh->vbi_fmt.fmt.start[0] != tvnorm->vbistart[0] ||
+                   fh->vbi_fmt.fmt.start[1] != tvnorm->vbistart[1] ||
+                   fh->vbi_fmt.fmt.count[0] != fh->vbi_fmt.fmt.count[1]) {
+                       /* BTTV_VBISIZE cannot express these parameters,
+                          however open() resets the paramters to defaults
+                          and apps shouldn't call BTTV_VBISIZE after
+                          VIDIOC_S_FMT. */
+                       return -EINVAL;
+               }
+
                bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
-               return fh->lines * 2 * 2048;
+               return (fh->vbi_fmt.fmt.count[0] * 2
+                       * fh->vbi_fmt.fmt.samples_per_line);
+       }
+
        default:
                return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
        }
@@ -2992,10 +3605,14 @@ static ssize_t bttv_read(struct file *file, char __user *data,
 
        switch (fh->type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if (locked_btres(fh->btv,RESOURCE_VIDEO))
+               if (!check_alloc_btres(fh->btv, fh, RESOURCE_VIDEO_READ)) {
+                       /* VIDEO_READ in use by another fh,
+                          or VIDEO_STREAM by any fh. */
                        return -EBUSY;
+               }
                retval = videobuf_read_one(&fh->cap, data, count, ppos,
                                           file->f_flags & O_NONBLOCK);
+               free_btres(fh->btv, fh, RESOURCE_VIDEO_READ);
                break;
        case V4L2_BUF_TYPE_VBI_CAPTURE:
                if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
@@ -3021,7 +3638,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
                return videobuf_poll_stream(file, &fh->vbi, wait);
        }
 
-       if (check_btres(fh,RESOURCE_VIDEO)) {
+       if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
                /* streaming capture */
                if (list_empty(&fh->cap.stream))
                        return POLLERR;
@@ -3031,7 +3648,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
                mutex_lock(&fh->cap.lock);
                if (NULL == fh->cap.read_buf) {
                        /* need to capture a new frame */
-                       if (locked_btres(fh->btv,RESOURCE_VIDEO)) {
+                       if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM)) {
                                mutex_unlock(&fh->cap.lock);
                                return POLLERR;
                        }
@@ -3117,8 +3734,23 @@ static int bttv_open(struct inode *inode, struct file *file)
        i2c_vidiocschan(btv);
 
        btv->users++;
-       if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
-               bttv_vbi_setlines(fh,btv,16);
+
+       /* The V4L2 spec requires one global set of cropping parameters
+          which only change on request. These are stored in btv->crop[1].
+          However for compatibility with V4L apps and cropping unaware
+          V4L2 apps we now reset the cropping parameters as seen through
+          this fh, which is to say VIDIOC_G_CROP and scaling limit checks
+          will use btv->crop[0], the default cropping parameters for the
+          current video standard, and VIDIOC_S_FMT will not implicitely
+          change the cropping parameters until VIDIOC_S_CROP has been
+          called. */
+       fh->do_crop = !reset_crop; /* module parameter */
+
+       /* Likewise there should be one global set of VBI capture
+          parameters, but for compatibility with V4L apps and earlier
+          driver versions each fh has its own parameters. */
+       bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
+
        bttv_field_count(btv);
        return 0;
 }
@@ -3133,14 +3765,17 @@ static int bttv_release(struct inode *inode, struct file *file)
                bttv_switch_overlay(btv,fh,NULL);
 
        /* stop video capture */
-       if (check_btres(fh, RESOURCE_VIDEO)) {
+       if (check_btres(fh, RESOURCE_VIDEO_STREAM)) {
                videobuf_streamoff(&fh->cap);
-               free_btres(btv,fh,RESOURCE_VIDEO);
+               free_btres(btv,fh,RESOURCE_VIDEO_STREAM);
        }
        if (fh->cap.read_buf) {
                buffer_release(&fh->cap,fh->cap.read_buf);
                kfree(fh->cap.read_buf);
        }
+       if (check_btres(fh, RESOURCE_VIDEO_READ)) {
+               free_btres(btv, fh, RESOURCE_VIDEO_READ);
+       }
 
        /* stop vbi capture */
        if (check_btres(fh, RESOURCE_VBI)) {
@@ -3997,7 +4632,6 @@ static int __devinit bttv_probe(struct pci_dev *dev,
 
        /* initialize structs / fill in defaults */
        mutex_init(&btv->lock);
-       mutex_init(&btv->reslock);
        spin_lock_init(&btv->s_lock);
        spin_lock_init(&btv->gpio_lock);
        init_waitqueue_head(&btv->gpioq);
@@ -4095,7 +4729,6 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        btv->init.fmt         = format_by_palette(VIDEO_PALETTE_RGB24);
        btv->init.width       = 320;
        btv->init.height      = 240;
-       btv->init.lines       = 16;
        btv->input = 0;
 
        /* initialize hardware */
@@ -4130,6 +4763,10 @@ static int __devinit bttv_probe(struct pci_dev *dev,
                bt848_sat(btv,32768);
                audio_mute(btv, 1);
                set_input(btv,0);
+               bttv_crop_reset(&btv->crop[0], btv->tvnorm);
+               btv->crop[1] = btv->crop[0]; /* current = default */
+               disclaim_vbi_lines(btv);
+               disclaim_video_lines(btv);
        }
 
        /* add subdevices */
index cbc012f..6f74c80 100644 (file)
@@ -36,13 +36,18 @@ module_param(repeat_delay, int, 0644);
 static int repeat_period = 33;
 module_param(repeat_period, int, 0644);
 
+static int ir_rc5_remote_gap = 885;
+module_param(ir_rc5_remote_gap, int, 0644);
+static int ir_rc5_key_timeout = 200;
+module_param(ir_rc5_key_timeout, int, 0644);
+
 #define DEVNAME "bttv-input"
 
 /* ---------------------------------------------------------------------- */
 
 static void ir_handle_key(struct bttv *btv)
 {
-       struct bttv_ir *ir = btv->remote;
+       struct card_ir *ir = btv->remote;
        u32 gpio,data;
 
        /* read gpio value */
@@ -72,7 +77,7 @@ static void ir_handle_key(struct bttv *btv)
 
 void bttv_input_irq(struct bttv *btv)
 {
-       struct bttv_ir *ir = btv->remote;
+       struct card_ir *ir = btv->remote;
 
        if (!ir->polling)
                ir_handle_key(btv);
@@ -81,65 +86,21 @@ void bttv_input_irq(struct bttv *btv)
 static void bttv_input_timer(unsigned long data)
 {
        struct bttv *btv = (struct bttv*)data;
-       struct bttv_ir *ir = btv->remote;
-       unsigned long timeout;
+       struct card_ir *ir = btv->remote;
 
        ir_handle_key(btv);
-       timeout = jiffies + (ir->polling * HZ / 1000);
-       mod_timer(&ir->timer, timeout);
+       mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
 }
 
 /* ---------------------------------------------------------------*/
 
-static int rc5_remote_gap = 885;
-module_param(rc5_remote_gap, int, 0644);
-static int rc5_key_timeout = 200;
-module_param(rc5_key_timeout, int, 0644);
-
-#define RC5_START(x)   (((x)>>12)&3)
-#define RC5_TOGGLE(x)  (((x)>>11)&1)
-#define RC5_ADDR(x)    (((x)>>6)&31)
-#define RC5_INSTR(x)   ((x)&63)
-
-/* decode raw bit pattern to RC5 code */
-static u32 rc5_decode(unsigned int code)
-{
-       unsigned int org_code = code;
-       unsigned int pair;
-       unsigned int rc5 = 0;
-       int i;
-
-       code = (code << 1) | 1;
-       for (i = 0; i < 14; ++i) {
-               pair = code & 0x3;
-               code >>= 2;
-
-               rc5 <<= 1;
-               switch (pair) {
-               case 0:
-               case 2:
-                       break;
-               case 1:
-                       rc5 |= 1;
-                       break;
-               case 3:
-                       dprintk(KERN_WARNING "bad code: %x\n", org_code);
-                       return 0;
-               }
-       }
-       dprintk(KERN_WARNING "code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
-               "instr=%x\n", rc5, org_code, RC5_START(rc5),
-               RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
-       return rc5;
-}
-
 static int bttv_rc5_irq(struct bttv *btv)
 {
-       struct bttv_ir *ir = btv->remote;
+       struct card_ir *ir = btv->remote;
        struct timeval tv;
        u32 gpio;
        u32 gap;
-       unsigned long current_jiffies, timeout;
+       unsigned long current_jiffies;
 
        /* read gpio port */
        gpio = bttv_gpio_read(&btv->c);
@@ -165,8 +126,8 @@ static int bttv_rc5_irq(struct bttv *btv)
                /* only if in the code (otherwise spurious IRQ or timer
                   late) */
                if (ir->last_bit < 28) {
-                       ir->last_bit = (gap - rc5_remote_gap / 2) /
-                           rc5_remote_gap;
+                       ir->last_bit = (gap - ir_rc5_remote_gap / 2) /
+                           ir_rc5_remote_gap;
                        ir->code |= 1 << ir->last_bit;
                }
                /* starting new code */
@@ -176,8 +137,8 @@ static int bttv_rc5_irq(struct bttv *btv)
                ir->base_time = tv;
                ir->last_bit = 0;
 
-               timeout = current_jiffies + (500 + 30 * HZ) / 1000;
-               mod_timer(&ir->timer_end, timeout);
+               mod_timer(&ir->timer_end,
+                         current_jiffies + msecs_to_jiffies(30));
        }
 
        /* toggle GPIO pin 4 to reset the irq */
@@ -186,96 +147,28 @@ static int bttv_rc5_irq(struct bttv *btv)
        return 1;
 }
 
-
-static void bttv_rc5_timer_end(unsigned long data)
-{
-       struct bttv_ir *ir = (struct bttv_ir *)data;
-       struct timeval tv;
-       unsigned long current_jiffies, timeout;
-       u32 gap;
-
-       /* get time */
-       current_jiffies = jiffies;
-       do_gettimeofday(&tv);
-
-       /* avoid overflow with gap >1s */
-       if (tv.tv_sec - ir->base_time.tv_sec > 1) {
-               gap = 200000;
-       } else {
-               gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
-                   tv.tv_usec - ir->base_time.tv_usec;
-       }
-
-       /* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */
-       if (gap < 28000) {
-               dprintk(KERN_WARNING "spurious timer_end\n");
-               return;
-       }
-
-       ir->active = 0;
-       if (ir->last_bit < 20) {
-               /* ignore spurious codes (caused by light/other remotes) */
-               dprintk(KERN_WARNING "short code: %x\n", ir->code);
-       } else {
-               u32 rc5 = rc5_decode(ir->code);
-
-               /* two start bits? */
-               if (RC5_START(rc5) != 3) {
-                       dprintk(KERN_WARNING "rc5 start bits invalid: %u\n", RC5_START(rc5));
-
-                       /* right address? */
-               } else if (RC5_ADDR(rc5) == 0x0) {
-                       u32 toggle = RC5_TOGGLE(rc5);
-                       u32 instr = RC5_INSTR(rc5);
-
-                       /* Good code, decide if repeat/repress */
-                       if (toggle != RC5_TOGGLE(ir->last_rc5) ||
-                           instr != RC5_INSTR(ir->last_rc5)) {
-                               dprintk(KERN_WARNING "instruction %x, toggle %x\n", instr,
-                                       toggle);
-                               ir_input_nokey(ir->dev, &ir->ir);
-                               ir_input_keydown(ir->dev, &ir->ir, instr,
-                                                instr);
-                       }
-
-                       /* Set/reset key-up timer */
-                       timeout = current_jiffies + (500 + rc5_key_timeout
-                                                    * HZ) / 1000;
-                       mod_timer(&ir->timer_keyup, timeout);
-
-                       /* Save code for repeat test */
-                       ir->last_rc5 = rc5;
-               }
-       }
-}
-
-static void bttv_rc5_timer_keyup(unsigned long data)
-{
-       struct bttv_ir *ir = (struct bttv_ir *)data;
-
-       dprintk(KERN_DEBUG "key released\n");
-       ir_input_nokey(ir->dev, &ir->ir);
-}
-
 /* ---------------------------------------------------------------------- */
 
-static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir)
+static void bttv_ir_start(struct bttv *btv, struct card_ir *ir)
 {
        if (ir->polling) {
-               init_timer(&ir->timer);
-               ir->timer.function = bttv_input_timer;
-               ir->timer.data     = (unsigned long)btv;
+               setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv);
                ir->timer.expires  = jiffies + HZ;
                add_timer(&ir->timer);
        } else if (ir->rc5_gpio) {
                /* set timer_end for code completion */
                init_timer(&ir->timer_end);
-               ir->timer_end.function = bttv_rc5_timer_end;
+               ir->timer_end.function = ir_rc5_timer_end;
                ir->timer_end.data = (unsigned long)ir;
 
                init_timer(&ir->timer_keyup);
-               ir->timer_keyup.function = bttv_rc5_timer_keyup;
+               ir->timer_keyup.function = ir_rc5_timer_keyup;
                ir->timer_keyup.data = (unsigned long)ir;
+               ir->shift_by = 1;
+               ir->start = 3;
+               ir->addr = 0x0;
+               ir->rc5_key_timeout = ir_rc5_key_timeout;
+               ir->rc5_remote_gap = ir_rc5_remote_gap;
        }
 }
 
@@ -299,7 +192,7 @@ static void bttv_ir_stop(struct bttv *btv)
 
 int bttv_input_init(struct bttv *btv)
 {
-       struct bttv_ir *ir;
+       struct card_ir *ir;
        IR_KEYTAB_TYPE *ir_codes = NULL;
        struct input_dev *input_dev;
        int ir_type = IR_TYPE_OTHER;
index afcfe71..e7104d9 100644 (file)
@@ -43,7 +43,8 @@ int
 bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
                 struct scatterlist *sglist,
                 unsigned int offset, unsigned int bpl,
-                unsigned int padding, unsigned int lines)
+                unsigned int padding, unsigned int skip_lines,
+                unsigned int store_lines)
 {
        u32 instructions,line,todo;
        struct scatterlist *sg;
@@ -54,9 +55,11 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
           one write per scan line + sync + jump (all 2 dwords).  padding
           can cause next bpl to start close to a page border.  First DMA
           region may be smaller than PAGE_SIZE */
-       instructions  = 1 + ((bpl + padding) * lines) / PAGE_SIZE + lines;
-       instructions += 2;
-       if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0)
+       instructions  = skip_lines * 4;
+       instructions += (1 + ((bpl + padding) * store_lines)
+                        / PAGE_SIZE + store_lines) * 8;
+       instructions += 2 * 8;
+       if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions)) < 0)
                return rc;
 
        /* sync instruction */
@@ -64,11 +67,16 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
        *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
        *(rp++) = cpu_to_le32(0);
 
+       while (skip_lines-- > 0) {
+               *(rp++) = cpu_to_le32(BT848_RISC_SKIP | BT848_RISC_SOL |
+                                     BT848_RISC_EOL | bpl);
+       }
+
        /* scan lines */
        sg = sglist;
-       for (line = 0; line < lines; line++) {
+       for (line = 0; line < store_lines; line++) {
                if ((btv->opt_vcr_hack) &&
-                   (line >= (lines - VCR_HACK_LINES)))
+                   (line >= (store_lines - VCR_HACK_LINES)))
                        continue;
                while (offset && offset >= sg_dma_len(sg)) {
                        offset -= sg_dma_len(sg);
@@ -130,7 +138,8 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
        /* estimate risc mem: worst case is one write per page border +
           one write per scan line (5 dwords)
           plus sync + jump (2 dwords) */
-       instructions  = (ybpl * ylines * 2) / PAGE_SIZE + ylines;
+       instructions  = ((3 + (ybpl + ypadding) * ylines * 2)
+                        / PAGE_SIZE) + ylines;
        instructions += 2;
        if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0)
                return rc;
@@ -317,10 +326,10 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
 /* ---------------------------------------------------------- */
 
 static void
-bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
-             int width, int height, int interleaved, int norm)
+bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo,
+                 int width, int height, int interleaved,
+                 const struct bttv_tvnorm *tvnorm)
 {
-       const struct bttv_tvnorm *tvnorm = &bttv_tvnorms[norm];
        u32 xsf, sr;
        int vdelay;
 
@@ -361,6 +370,62 @@ bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
 }
 
 static void
+bttv_calc_geo          (struct bttv *                  btv,
+                        struct bttv_geometry *         geo,
+                        unsigned int                   width,
+                        unsigned int                   height,
+                        int                            both_fields,
+                        const struct bttv_tvnorm *     tvnorm,
+                        const struct v4l2_rect *       crop)
+{
+       unsigned int c_width;
+       unsigned int c_height;
+       u32 sr;
+
+       if ((crop->left == tvnorm->cropcap.defrect.left
+            && crop->top == tvnorm->cropcap.defrect.top
+            && crop->width == tvnorm->cropcap.defrect.width
+            && crop->height == tvnorm->cropcap.defrect.height
+            && width <= tvnorm->swidth /* see PAL-Nc et al */)
+           || bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
+               bttv_calc_geo_old(btv, geo, width, height,
+                                 both_fields, tvnorm);
+               return;
+       }
+
+       /* For bug compatibility the image size checks permit scale
+          factors > 16. See bttv_crop_calc_limits(). */
+       c_width = min((unsigned int) crop->width, width * 16);
+       c_height = min((unsigned int) crop->height, height * 16);
+
+       geo->width = width;
+       geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096;
+       /* Even to store Cb first, odd for Cr. */
+       geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1;
+
+       geo->sheight = c_height;
+       geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY;
+       sr = c_height >> !both_fields;
+       sr = (sr * 512U + (height >> 1)) / height - 512;
+       geo->vscale = (0x10000UL - sr) & 0x1fff;
+       geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0;
+       geo->vtotal = tvnorm->vtotal;
+
+       geo->crop = (((geo->width   >> 8) & 0x03) |
+                    ((geo->hdelay  >> 6) & 0x0c) |
+                    ((geo->sheight >> 4) & 0x30) |
+                    ((geo->vdelay  >> 2) & 0xc0));
+
+       if (btv->opt_combfilter) {
+               geo->vtc  = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
+               geo->comb = (width < 769) ? 1 : 0;
+       } else {
+               geo->vtc  = 0;
+               geo->comb = 0;
+       }
+}
+
+static void
 bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
 {
        int off = odd ? 0x80 : 0x00;
@@ -522,16 +587,51 @@ int
 bttv_buffer_activate_vbi(struct bttv *btv,
                         struct bttv_buffer *vbi)
 {
-       /* vbi capture */
+       struct btcx_riscmem *top;
+       struct btcx_riscmem *bottom;
+       int top_irq_flags;
+       int bottom_irq_flags;
+
+       top = NULL;
+       bottom = NULL;
+       top_irq_flags = 0;
+       bottom_irq_flags = 0;
+
        if (vbi) {
+               unsigned int crop, vdelay;
+
                vbi->vb.state = STATE_ACTIVE;
                list_del(&vbi->vb.queue);
-               bttv_risc_hook(btv, RISC_SLOT_O_VBI, &vbi->top,    0);
-               bttv_risc_hook(btv, RISC_SLOT_E_VBI, &vbi->bottom, 4);
-       } else {
-               bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0);
-               bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0);
+
+               /* VDELAY is start of video, end of VBI capturing. */
+               crop = btread(BT848_E_CROP);
+               vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2);
+
+               if (vbi->geo.vdelay > vdelay) {
+                       vdelay = vbi->geo.vdelay & 0xfe;
+                       crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0);
+
+                       btwrite(vdelay, BT848_E_VDELAY_LO);
+                       btwrite(crop,   BT848_E_CROP);
+                       btwrite(vdelay, BT848_O_VDELAY_LO);
+                       btwrite(crop,   BT848_O_CROP);
+               }
+
+               if (vbi->vbi_count[0] > 0) {
+                       top = &vbi->top;
+                       top_irq_flags = 4;
+               }
+
+               if (vbi->vbi_count[1] > 0) {
+                       top_irq_flags = 0;
+                       bottom = &vbi->bottom;
+                       bottom_irq_flags = 4;
+               }
        }
+
+       bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags);
+       bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags);
+
        return 0;
 }
 
@@ -611,28 +711,31 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
                int bpf = bpl * (buf->vb.height >> 1);
 
                bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
-                             V4L2_FIELD_HAS_BOTH(buf->vb.field),buf->tvnorm);
+                             V4L2_FIELD_HAS_BOTH(buf->vb.field),
+                             tvnorm,&buf->crop);
 
                switch (buf->vb.field) {
                case V4L2_FIELD_TOP:
                        bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
-                                        0,bpl,0,buf->vb.height);
+                                        /* offset */ 0,bpl,
+                                        /* padding */ 0,/* skip_lines */ 0,
+                                        buf->vb.height);
                        break;
                case V4L2_FIELD_BOTTOM:
                        bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
-                                        0,bpl,0,buf->vb.height);
+                                        0,bpl,0,0,buf->vb.height);
                        break;
                case V4L2_FIELD_INTERLACED:
                        bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
-                                        0,bpl,bpl,buf->vb.height >> 1);
+                                        0,bpl,bpl,0,buf->vb.height >> 1);
                        bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
-                                        bpl,bpl,bpl,buf->vb.height >> 1);
+                                        bpl,bpl,bpl,0,buf->vb.height >> 1);
                        break;
                case V4L2_FIELD_SEQ_TB:
                        bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
-                                        0,bpl,0,buf->vb.height >> 1);
+                                        0,bpl,0,0,buf->vb.height >> 1);
                        bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
-                                        bpf,bpl,0,buf->vb.height >> 1);
+                                        bpf,bpl,0,0,buf->vb.height >> 1);
                        break;
                default:
                        BUG();
@@ -662,7 +765,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
                switch (buf->vb.field) {
                case V4L2_FIELD_TOP:
                        bttv_calc_geo(btv,&buf->geo,buf->vb.width,
-                                     buf->vb.height,0,buf->tvnorm);
+                                     buf->vb.height,/* both_fields */ 0,
+                                     tvnorm,&buf->crop);
                        bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist,
                                         0,buf->vb.width,0,buf->vb.height,
                                         uoffset,voffset,buf->fmt->hshift,
@@ -670,7 +774,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
                        break;
                case V4L2_FIELD_BOTTOM:
                        bttv_calc_geo(btv,&buf->geo,buf->vb.width,
-                                     buf->vb.height,0,buf->tvnorm);
+                                     buf->vb.height,0,
+                                     tvnorm,&buf->crop);
                        bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist,
                                         0,buf->vb.width,0,buf->vb.height,
                                         uoffset,voffset,buf->fmt->hshift,
@@ -678,7 +783,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
                        break;
                case V4L2_FIELD_INTERLACED:
                        bttv_calc_geo(btv,&buf->geo,buf->vb.width,
-                                     buf->vb.height,1,buf->tvnorm);
+                                     buf->vb.height,1,
+                                     tvnorm,&buf->crop);
                        lines    = buf->vb.height >> 1;
                        ypadding = buf->vb.width;
                        cpadding = buf->vb.width >> buf->fmt->hshift;
@@ -700,7 +806,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
                        break;
                case V4L2_FIELD_SEQ_TB:
                        bttv_calc_geo(btv,&buf->geo,buf->vb.width,
-                                     buf->vb.height,1,buf->tvnorm);
+                                     buf->vb.height,1,
+                                     tvnorm,&buf->crop);
                        lines    = buf->vb.height >> 1;
                        ypadding = buf->vb.width;
                        cpadding = buf->vb.width >> buf->fmt->hshift;
@@ -731,11 +838,12 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
                /* build risc code */
                buf->vb.field = V4L2_FIELD_SEQ_TB;
                bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
-                             1,buf->tvnorm);
+                             1,tvnorm,&buf->crop);
                bttv_risc_packed(btv, &buf->top,  buf->vb.dma.sglist,
-                                0, RAW_BPL, 0, RAW_LINES);
+                                /* offset */ 0, RAW_BPL, /* padding */ 0,
+                                /* skip_lines */ 0, RAW_LINES);
                bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
-                                buf->vb.size/2 , RAW_BPL, 0, RAW_LINES);
+                                buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
        }
 
        /* copy format info */
@@ -761,7 +869,8 @@ bttv_overlay_risc(struct bttv *btv,
 
        /* calculate geometry */
        bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
-                     V4L2_FIELD_HAS_BOTH(ov->field), ov->tvnorm);
+                     V4L2_FIELD_HAS_BOTH(ov->field),
+                     &bttv_tvnorms[ov->tvnorm],&buf->crop);
 
        /* build risc code */
        switch (ov->field) {
index 6fc6b02..93e35de 100644 (file)
@@ -5,6 +5,9 @@
 
     (c) 2002 Gerd Knorr <kraxel@bytesex.org>
 
+    Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
+    Sponsored by OPQ Systems AB
+
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
    to be about 244.  */
 #define VBI_OFFSET 244
 
+/* 2048 for compatibility with earlier driver versions. The driver
+   really stores 1024 + tvnorm->vbipack * 4 samples per line in the
+   buffer. Note tvnorm->vbipack is <= 0xFF (limit of VBIPACK_LO + HI
+   is 0x1FF DWORDs) and VBI read()s store a frame counter in the last
+   four bytes of the VBI image. */
+#define VBI_BPL 2048
+
+/* Compatibility. */
 #define VBI_DEFLINES 16
-#define VBI_MAXLINES 32
 
 static unsigned int vbibufs = 4;
 static unsigned int vbi_debug = 0;
@@ -58,21 +68,12 @@ MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)");
 #define dprintk(fmt, arg...)   if (vbi_debug) \
        printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->c.nr , ## arg)
 
+#define IMAGE_SIZE(fmt) \
+       (((fmt)->count[0] + (fmt)->count[1]) * (fmt)->samples_per_line)
+
 /* ----------------------------------------------------------------------- */
 /* vbi risc code + mm                                                      */
 
-static int
-vbi_buffer_risc(struct bttv *btv, struct bttv_buffer *buf, int lines)
-{
-       int bpl = 2048;
-
-       bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
-                        0, bpl-4, 4, lines);
-       bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
-                        lines * bpl, bpl-4, 4, lines);
-       return 0;
-}
-
 static int vbi_buffer_setup(struct videobuf_queue *q,
                            unsigned int *count, unsigned int *size)
 {
@@ -81,8 +82,16 @@ static int vbi_buffer_setup(struct videobuf_queue *q,
 
        if (0 == *count)
                *count = vbibufs;
-       *size = fh->lines * 2 * 2048;
-       dprintk("setup: lines=%d\n",fh->lines);
+
+       *size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
+
+       dprintk("setup: samples=%u start=%d,%d count=%u,%u\n",
+               fh->vbi_fmt.fmt.samples_per_line,
+               fh->vbi_fmt.fmt.start[0],
+               fh->vbi_fmt.fmt.start[1],
+               fh->vbi_fmt.fmt.count[0],
+               fh->vbi_fmt.fmt.count[1]);
+
        return 0;
 }
 
@@ -93,18 +102,93 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
        struct bttv_fh *fh = q->priv_data;
        struct bttv *btv = fh->btv;
        struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
+       const struct bttv_tvnorm *tvnorm;
+       unsigned int skip_lines0, skip_lines1, min_vdelay;
+       int redo_dma_risc;
        int rc;
 
-       buf->vb.size = fh->lines * 2 * 2048;
+       buf->vb.size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
        if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
                return -EINVAL;
 
+       tvnorm = fh->vbi_fmt.tvnorm;
+
+       /* There's no VBI_VDELAY register, RISC must skip the lines
+          we don't want. With default parameters we skip zero lines
+          as earlier driver versions did. The driver permits video
+          standard changes while capturing, so we use vbi_fmt.tvnorm
+          instead of btv->tvnorm to skip zero lines after video
+          standard changes as well. */
+
+       skip_lines0 = 0;
+       skip_lines1 = 0;
+
+       if (fh->vbi_fmt.fmt.count[0] > 0)
+               skip_lines0 = max(0, (fh->vbi_fmt.fmt.start[0]
+                                     - tvnorm->vbistart[0]));
+       if (fh->vbi_fmt.fmt.count[1] > 0)
+               skip_lines1 = max(0, (fh->vbi_fmt.fmt.start[1]
+                                     - tvnorm->vbistart[1]));
+
+       redo_dma_risc = 0;
+
+       if (buf->vbi_skip[0] != skip_lines0 ||
+           buf->vbi_skip[1] != skip_lines1 ||
+           buf->vbi_count[0] != fh->vbi_fmt.fmt.count[0] ||
+           buf->vbi_count[1] != fh->vbi_fmt.fmt.count[1]) {
+               buf->vbi_skip[0] = skip_lines0;
+               buf->vbi_skip[1] = skip_lines1;
+               buf->vbi_count[0] = fh->vbi_fmt.fmt.count[0];
+               buf->vbi_count[1] = fh->vbi_fmt.fmt.count[1];
+               redo_dma_risc = 1;
+       }
+
        if (STATE_NEEDS_INIT == buf->vb.state) {
+               redo_dma_risc = 1;
                if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
                        goto fail;
-               if (0 != (rc = vbi_buffer_risc(btv,buf,fh->lines)))
-                       goto fail;
        }
+
+       if (redo_dma_risc) {
+               unsigned int bpl, padding, offset;
+
+               bpl = 2044; /* max. vbipack */
+               padding = VBI_BPL - bpl;
+
+               if (fh->vbi_fmt.fmt.count[0] > 0) {
+                       rc = bttv_risc_packed(btv, &buf->top,
+                                             buf->vb.dma.sglist,
+                                             /* offset */ 0, bpl,
+                                             padding, skip_lines0,
+                                             fh->vbi_fmt.fmt.count[0]);
+                       if (0 != rc)
+                               goto fail;
+               }
+
+               if (fh->vbi_fmt.fmt.count[1] > 0) {
+                       offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL;
+
+                       rc = bttv_risc_packed(btv, &buf->bottom,
+                                             buf->vb.dma.sglist,
+                                             offset, bpl,
+                                             padding, skip_lines1,
+                                             fh->vbi_fmt.fmt.count[1]);
+                       if (0 != rc)
+                               goto fail;
+               }
+       }
+
+       /* VBI capturing ends at VDELAY, start of video capturing,
+          no matter where the RISC program ends. VDELAY minimum is 2,
+          bounds.top is the corresponding first field line number
+          times two. VDELAY counts half field lines. */
+       min_vdelay = MIN_VDELAY;
+       if (fh->vbi_fmt.end >= tvnorm->cropcap.bounds.top)
+               min_vdelay += fh->vbi_fmt.end - tvnorm->cropcap.bounds.top;
+
+       /* For bttv_buffer_activate_vbi(). */
+       buf->geo.vdelay = min_vdelay;
+
        buf->vb.state = STATE_PREPARED;
        buf->vb.field = field;
        dprintk("buf prepare %p: top=%p bottom=%p field=%s\n",
@@ -140,7 +224,7 @@ static void vbi_buffer_release(struct videobuf_queue *q, struct videobuf_buffer
        struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
 
        dprintk("free %p\n",vb);
-       bttv_dma_free(&fh->cap,fh->btv,buf);
+       bttv_dma_free(q,fh->btv,buf);
 }
 
 struct videobuf_queue_ops bttv_vbi_qops = {
@@ -152,69 +236,215 @@ struct videobuf_queue_ops bttv_vbi_qops = {
 
 /* ----------------------------------------------------------------------- */
 
-void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines)
+static int
+try_fmt                        (struct v4l2_vbi_format *       f,
+                        const struct bttv_tvnorm *     tvnorm,
+                        __s32                          crop_start)
 {
-       int vdelay;
-
-       if (lines < 1)
-               lines = 1;
-       if (lines > VBI_MAXLINES)
-               lines = VBI_MAXLINES;
-       fh->lines = lines;
-
-       vdelay = btread(BT848_E_VDELAY_LO);
-       if (vdelay < lines*2) {
-               vdelay = lines*2;
-               btwrite(vdelay,BT848_E_VDELAY_LO);
-               btwrite(vdelay,BT848_O_VDELAY_LO);
+       __s32 min_start, max_start, max_end, f2_offset;
+       unsigned int i;
+
+       /* For compatibility with earlier driver versions we must pretend
+          the VBI and video capture window may overlap. In reality RISC
+          magic aborts VBI capturing at the first line of video capturing,
+          leaving the rest of the buffer unchanged, usually all zero.
+          VBI capturing must always start before video capturing. >> 1
+          because cropping counts field lines times two. */
+       min_start = tvnorm->vbistart[0];
+       max_start = (crop_start >> 1) - 1;
+       max_end = (tvnorm->cropcap.bounds.top
+                  + tvnorm->cropcap.bounds.height) >> 1;
+
+       if (min_start > max_start)
+               return -EBUSY;
+
+       BUG_ON(max_start >= max_end);
+
+       f->sampling_rate    = tvnorm->Fsc;
+       f->samples_per_line = VBI_BPL;
+       f->sample_format    = V4L2_PIX_FMT_GREY;
+       f->offset           = VBI_OFFSET;
+
+       f2_offset = tvnorm->vbistart[1] - tvnorm->vbistart[0];
+
+       for (i = 0; i < 2; ++i) {
+               if (0 == f->count[i]) {
+                       /* No data from this field. We leave f->start[i]
+                          alone because VIDIOCSVBIFMT is w/o and EINVALs
+                          when a driver does not support exactly the
+                          requested parameters. */
+               } else {
+                       s64 start, count;
+
+                       start = clamp(f->start[i], min_start, max_start);
+                       /* s64 to prevent overflow. */
+                       count = (s64) f->start[i] + f->count[i] - start;
+                       f->start[i] = start;
+                       f->count[i] = clamp(count, (s64) 1,
+                                           max_end - start);
+               }
+
+               min_start += f2_offset;
+               max_start += f2_offset;
+               max_end += f2_offset;
        }
+
+       if (0 == (f->count[0] | f->count[1])) {
+               /* As in earlier driver versions. */
+               f->start[0] = tvnorm->vbistart[0];
+               f->start[1] = tvnorm->vbistart[1];
+               f->count[0] = 1;
+               f->count[1] = 1;
+       }
+
+       f->flags = 0;
+
+       f->reserved[0] = 0;
+       f->reserved[1] = 0;
+
+       return 0;
 }
 
-void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f)
+int
+bttv_vbi_try_fmt       (struct bttv_fh *               fh,
+                        struct v4l2_vbi_format *       f)
 {
+       struct bttv *btv = fh->btv;
        const struct bttv_tvnorm *tvnorm;
-       s64 count0,count1,count;
+       __s32 crop_start;
 
-       tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
-       f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
-       f->fmt.vbi.sampling_rate    = tvnorm->Fsc;
-       f->fmt.vbi.samples_per_line = 2048;
-       f->fmt.vbi.sample_format    = V4L2_PIX_FMT_GREY;
-       f->fmt.vbi.offset           = VBI_OFFSET;
-       f->fmt.vbi.flags            = 0;
-
-       /* s64 to prevent overflow. */
-       count0 = (s64) f->fmt.vbi.start[0] + f->fmt.vbi.count[0]
-               - tvnorm->vbistart[0];
-       count1 = (s64) f->fmt.vbi.start[1] + f->fmt.vbi.count[1]
-               - tvnorm->vbistart[1];
-       count  = clamp (max (count0, count1), (s64) 1, (s64) VBI_MAXLINES);
-
-       f->fmt.vbi.start[0] = tvnorm->vbistart[0];
-       f->fmt.vbi.start[1] = tvnorm->vbistart[1];
-       f->fmt.vbi.count[0] = count;
-       f->fmt.vbi.count[1] = count;
-
-       f->fmt.vbi.reserved[0] = 0;
-       f->fmt.vbi.reserved[1] = 0;
+       mutex_lock(&btv->lock);
+
+       tvnorm = &bttv_tvnorms[btv->tvnorm];
+       crop_start = btv->crop_start;
+
+       mutex_unlock(&btv->lock);
+
+       return try_fmt(f, tvnorm, crop_start);
 }
 
-void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f)
+int
+bttv_vbi_set_fmt       (struct bttv_fh *               fh,
+                        struct v4l2_vbi_format *       f)
 {
+       struct bttv *btv = fh->btv;
        const struct bttv_tvnorm *tvnorm;
+       __s32 start1, end;
+       int rc;
+
+       mutex_lock(&btv->lock);
+
+       rc = -EBUSY;
+       if (fh->resources & RESOURCE_VBI)
+               goto fail;
+
+       tvnorm = &bttv_tvnorms[btv->tvnorm];
+
+       rc = try_fmt(f, tvnorm, btv->crop_start);
+       if (0 != rc)
+               goto fail;
+
+       start1 = f->start[1] - tvnorm->vbistart[1] + tvnorm->vbistart[0];
+
+       /* First possible line of video capturing. Should be
+          max(f->start[0] + f->count[0], start1 + f->count[1]) * 2
+          when capturing both fields. But for compatibility we must
+          pretend the VBI and video capture window may overlap,
+          so end = start + 1, the lowest possible value, times two
+          because vbi_fmt.end counts field lines times two. */
+       end = max(f->start[0], start1) * 2 + 2;
+
+       mutex_lock(&fh->vbi.lock);
+
+       fh->vbi_fmt.fmt    = *f;
+       fh->vbi_fmt.tvnorm = tvnorm;
+       fh->vbi_fmt.end    = end;
+
+       mutex_unlock(&fh->vbi.lock);
+
+       rc = 0;
+
+ fail:
+       mutex_unlock(&btv->lock);
+
+       return rc;
+}
+
+void
+bttv_vbi_get_fmt       (struct bttv_fh *               fh,
+                        struct v4l2_vbi_format *       f)
+{
+       const struct bttv_tvnorm *tvnorm;
+
+       *f = fh->vbi_fmt.fmt;
 
        tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
-       memset(f,0,sizeof(*f));
-       f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
-       f->fmt.vbi.sampling_rate    = tvnorm->Fsc;
-       f->fmt.vbi.samples_per_line = 2048;
-       f->fmt.vbi.sample_format    = V4L2_PIX_FMT_GREY;
-       f->fmt.vbi.offset           = VBI_OFFSET;
-       f->fmt.vbi.start[0]         = tvnorm->vbistart[0];
-       f->fmt.vbi.start[1]         = tvnorm->vbistart[1];
-       f->fmt.vbi.count[0]         = fh->lines;
-       f->fmt.vbi.count[1]         = fh->lines;
-       f->fmt.vbi.flags            = 0;
+
+       if (tvnorm != fh->vbi_fmt.tvnorm) {
+               __s32 max_end;
+               unsigned int i;
+
+               /* As in vbi_buffer_prepare() this imitates the
+                  behaviour of earlier driver versions after video
+                  standard changes, with default parameters anyway. */
+
+               max_end = (tvnorm->cropcap.bounds.top
+                          + tvnorm->cropcap.bounds.height) >> 1;
+
+               f->sampling_rate = tvnorm->Fsc;
+
+               for (i = 0; i < 2; ++i) {
+                       __s32 new_start;
+
+                       new_start = f->start[i]
+                               + tvnorm->vbistart[i]
+                               - fh->vbi_fmt.tvnorm->vbistart[i];
+
+                       f->start[i] = min(new_start, max_end - 1);
+                       f->count[i] = min((__s32) f->count[i],
+                                         max_end - f->start[i]);
+
+                       max_end += tvnorm->vbistart[1]
+                               - tvnorm->vbistart[0];
+               }
+       }
+}
+
+void
+bttv_vbi_fmt_reset     (struct bttv_vbi_fmt *          f,
+                        int                            norm)
+{
+       const struct bttv_tvnorm *tvnorm;
+       unsigned int real_samples_per_line;
+       unsigned int real_count;
+
+       tvnorm = &bttv_tvnorms[norm];
+
+       f->fmt.sampling_rate    = tvnorm->Fsc;
+       f->fmt.samples_per_line = VBI_BPL;
+       f->fmt.sample_format    = V4L2_PIX_FMT_GREY;
+       f->fmt.offset           = VBI_OFFSET;
+       f->fmt.start[0]         = tvnorm->vbistart[0];
+       f->fmt.start[1]         = tvnorm->vbistart[1];
+       f->fmt.count[0]         = VBI_DEFLINES;
+       f->fmt.count[1]         = VBI_DEFLINES;
+       f->fmt.flags            = 0;
+       f->fmt.reserved[0]      = 0;
+       f->fmt.reserved[1]      = 0;
+
+       /* For compatibility the buffer size must be 2 * VBI_DEFLINES *
+          VBI_BPL regardless of the current video standard. */
+       real_samples_per_line   = 1024 + tvnorm->vbipack * 4;
+       real_count              = ((tvnorm->cropcap.defrect.top >> 1)
+                                  - tvnorm->vbistart[0]);
+
+       BUG_ON(real_samples_per_line > VBI_BPL);
+       BUG_ON(real_count > VBI_DEFLINES);
+
+       f->tvnorm               = tvnorm;
+
+       /* See bttv_vbi_fmt_set(). */
+       f->end                  = tvnorm->vbistart[0] * 2 + 2;
 }
 
 /* ----------------------------------------------------------------------- */
index f9c9e3c..5491acb 100644 (file)
@@ -197,33 +197,6 @@ struct bttv_core {
 struct bttv;
 
 
-struct bttv_ir {
-       struct input_dev        *dev;
-       struct ir_input_state   ir;
-       char                    name[32];
-       char                    phys[32];
-
-       /* Usual gpio signalling */
-
-       u32                     mask_keycode;
-       u32                     mask_keydown;
-       u32                     mask_keyup;
-       u32                     polling;
-       u32                     last_gpio;
-       struct work_struct      work;
-       struct timer_list       timer;
-
-       /* RC5 gpio */
-       u32 rc5_gpio;
-       struct timer_list timer_end;    /* timer_end for code completion */
-       struct timer_list timer_keyup;  /* timer_end for key release */
-       u32 last_rc5;                   /* last good rc5 code */
-       u32 last_bit;                   /* last raw bit seen */
-       u32 code;                       /* raw code under construction */
-       struct timeval base_time;       /* time of last seen code */
-       int active;                     /* building raw code */
-};
-
 struct tvcard
 {
        char *name;
index 311c4c5..ad79b8d 100644 (file)
@@ -26,7 +26,7 @@
 #define _BTTVP_H_
 
 #include <linux/version.h>
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,16)
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,17)
 
 #include <linux/types.h>
 #include <linux/wait.h>
 #define RISC_SLOT_LOOP        14
 
 #define RESOURCE_OVERLAY       1
-#define RESOURCE_VIDEO         2
+#define RESOURCE_VIDEO_STREAM  2
 #define RESOURCE_VBI           4
+#define RESOURCE_VIDEO_READ    8
 
 #define RAW_LINES            640
 #define RAW_BPL             1024
 
 #define UNSET (-1U)
 
+/* Min. value in VDELAY register. */
+#define MIN_VDELAY 2
+/* Even to get Cb first, odd for Cr. */
+#define MAX_HDELAY (0x3FF & -2)
+/* Limits scaled width, which must be a multiple of 4. */
+#define MAX_HACTIVE (0x3FF & -4)
+
 #define clamp(x, low, high) min (max (low, x), high)
 
 /* ---------------------------------------------------------- */
@@ -92,8 +100,13 @@ struct bttv_tvnorm {
        u16   vtotal;
        int   sram;
        /* ITU-R frame line number of the first VBI line we can
-          capture, of the first and second field. */
+          capture, of the first and second field. The last possible line
+          is determined by cropcap.bounds. */
        u16   vbistart[2];
+       /* Horizontally this counts fCLKx1 samples following the leading
+          edge of the horizontal sync pulse, vertically ITU-R frame line
+          numbers of the first field times two (2, 4, 6, ... 524 or 624). */
+       struct v4l2_cropcap cropcap;
 };
 extern const struct bttv_tvnorm bttv_tvnorms[];
 
@@ -128,6 +141,9 @@ struct bttv_buffer {
        struct bttv_geometry       geo;
        struct btcx_riscmem        top;
        struct btcx_riscmem        bottom;
+       struct v4l2_rect           crop;
+       unsigned int               vbi_skip[2];
+       unsigned int               vbi_count[2];
 };
 
 struct bttv_buffer_set {
@@ -146,6 +162,34 @@ struct bttv_overlay {
        int                    setup_ok;
 };
 
+struct bttv_vbi_fmt {
+       struct v4l2_vbi_format fmt;
+
+       /* fmt.start[] and count[] refer to this video standard. */
+       const struct bttv_tvnorm *tvnorm;
+
+       /* Earliest possible start of video capturing with this
+          v4l2_vbi_format, in struct bttv_crop.rect units. */
+       __s32                  end;
+};
+
+/* bttv-vbi.c */
+void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, int norm);
+
+struct bttv_crop {
+       /* A cropping rectangle in struct bttv_tvnorm.cropcap units. */
+       struct v4l2_rect       rect;
+
+       /* Scaled image size limits with this crop rect. Divide
+          max_height, but not min_height, by two when capturing
+          single fields. See also bttv_crop_reset() and
+          bttv_crop_adjust() in bttv-driver.c. */
+       __s32                  min_scaled_width;
+       __s32                  min_scaled_height;
+       __s32                  max_scaled_width;
+       __s32                  max_scaled_height;
+};
+
 struct bttv_fh {
        struct bttv              *btv;
        int resources;
@@ -160,13 +204,19 @@ struct bttv_fh {
        int                      width;
        int                      height;
 
-       /* current settings */
+       /* video overlay */
        const struct bttv_format *ovfmt;
        struct bttv_overlay      ov;
 
-       /* video overlay */
+       /* Application called VIDIOC_S_CROP. */
+       int                      do_crop;
+
+       /* vbi capture */
        struct videobuf_queue    vbi;
-       int                      lines;
+       /* Current VBI capture window as seen through this fh (cannot
+          be global for compatibility with earlier drivers). Protected
+          by struct bttv.lock and struct bttv_fh.vbi.lock. */
+       struct bttv_vbi_fmt      vbi_fmt;
 };
 
 /* ---------------------------------------------------------- */
@@ -176,7 +226,8 @@ struct bttv_fh {
 int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
                     struct scatterlist *sglist,
                     unsigned int offset, unsigned int bpl,
-                    unsigned int pitch, unsigned int lines);
+                    unsigned int pitch, unsigned int skip_lines,
+                    unsigned int store_lines);
 
 /* control dma register + risc main loop */
 void bttv_set_dma(struct bttv *btv, int override);
@@ -202,9 +253,9 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
 /* ---------------------------------------------------------- */
 /* bttv-vbi.c                                                 */
 
-void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f);
-void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f);
-void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines);
+int bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
+void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
+int bttv_vbi_set_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
 
 extern struct videobuf_queue_ops bttv_vbi_qops;
 
@@ -233,7 +284,6 @@ extern int fini_bttv_i2c(struct bttv *btv);
 #define d2printk if (bttv_debug >= 2) printk
 
 #define BTTV_MAX_FBUF   0x208000
-#define VBIBUF_SIZE     (2048*VBI_MAXLINES*2)
 #define BTTV_TIMEOUT    (HZ/2) /* 0.5 seconds */
 #define BTTV_FREE_IDLE  (HZ)   /* one second */
 
@@ -308,13 +358,12 @@ struct bttv {
 
        /* infrared remote */
        int has_remote;
-       struct bttv_ir *remote;
+       struct card_ir *remote;
 
        /* locking */
        spinlock_t s_lock;
        struct mutex lock;
        int resources;
-       struct mutex reslock;
 #ifdef VIDIOC_G_PRIORITY
        struct v4l2_prio_state prio;
 #endif
@@ -384,6 +433,21 @@ struct bttv {
 
        unsigned int users;
        struct bttv_fh init;
+
+       /* Default (0) and current (1) video capturing and overlay
+          cropping parameters in bttv_tvnorm.cropcap units. Protected
+          by bttv.lock. */
+       struct bttv_crop crop[2];
+
+       /* Earliest possible start of video capturing in
+          bttv_tvnorm.cropcap line units. Set by check_alloc_btres()
+          and free_btres(). Protected by bttv.lock. */
+       __s32                   vbi_end;
+
+       /* Latest possible end of VBI capturing (= crop[x].rect.top when
+          VIDEO_RESOURCES are locked). Set by check_alloc_btres()
+          and free_btres(). Protected by bttv.lock. */
+       __s32                   crop_start;
 };
 
 /* our devices */
index 4dae892..682dc7c 100644 (file)
@@ -1195,7 +1195,7 @@ static int cafe_vidioc_reqbufs(struct file *filp, void *priv,
                struct v4l2_requestbuffers *req)
 {
        struct cafe_camera *cam = filp->private_data;
-       int ret;
+       int ret = 0;  /* Silence warning */
 
        /*
         * Make sure it's something we can do.  User pointers could be
index 7e8d5ef..78c9699 100644 (file)
@@ -1350,13 +1350,13 @@ out:
 
 static void create_proc_cpia_cam(struct cam_data *cam)
 {
-       char name[7];
+       char name[5 + 1 + 10 + 1];
        struct proc_dir_entry *ent;
 
        if (!cpia_proc_root || !cam)
                return;
 
-       sprintf(name, "video%d", cam->vdev.minor);
+       snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
 
        ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
        if (!ent)
@@ -1376,12 +1376,12 @@ static void create_proc_cpia_cam(struct cam_data *cam)
 
 static void destroy_proc_cpia_cam(struct cam_data *cam)
 {
-       char name[7];
+       char name[5 + 1 + 10 + 1];
 
        if (!cam || !cam->proc_entry)
                return;
 
-       sprintf(name, "video%d", cam->vdev.minor);
+       snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
        remove_proc_entry(name, cpia_proc_root);
        cam->proc_entry = NULL;
 }
@@ -3153,8 +3153,7 @@ static int reset_camera(struct cam_data *cam)
 
 static void put_cam(struct cpia_camera_ops* ops)
 {
-       if (ops->owner)
-               module_put(ops->owner);
+       module_put(ops->owner);
 }
 
 /* ------------------------- V4L interface --------------------- */
index 2f5ca71..d60cd5e 100644 (file)
@@ -56,7 +56,6 @@ const u32 cx2341x_mpeg_ctrls[] = {
        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,
@@ -118,9 +117,6 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
        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;
@@ -231,9 +227,6 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
        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 &&
@@ -679,7 +672,6 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
        .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,
@@ -783,10 +775,6 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
                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;
@@ -888,11 +876,10 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
                printk(", Peak %d", p->video_bitrate_peak);
        }
        printk("\n");
-       printk(KERN_INFO "%s: Video:  GOP Size %d, %d B-Frames, %sGOP Closure, %s3:2 Pulldown\n",
+       printk(KERN_INFO "%s: Video:  GOP Size %d, %d B-Frames, %sGOP Closure\n",
                prefix,
                p->video_gop_size, p->video_b_frames,
-               p->video_gop_closure ? "" : "No ",
-               p->video_pulldown ? "" : "No ");
+               p->video_gop_closure ? "" : "No ");
        if (p->video_temporal_decimation) {
                printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
                        prefix, p->video_temporal_decimation);
index 7bb7589..cc535ca 100644 (file)
@@ -628,17 +628,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        /* ioctls to allow direct access to the
         * cx25840 registers for testing */
-       case VIDIOC_INT_G_REGISTER:
-       {
-               struct v4l2_register *reg = arg;
-
-               if (reg->i2c_id != I2C_DRIVERID_CX25840)
-                       return -EINVAL;
-               reg->val = cx25840_read(client, reg->reg & 0x0fff);
-               break;
-       }
-
-       case VIDIOC_INT_S_REGISTER:
+       case VIDIOC_DBG_G_REGISTER:
+       case VIDIOC_DBG_S_REGISTER:
        {
                struct v4l2_register *reg = arg;
 
@@ -646,7 +637,10 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                        return -EINVAL;
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
+               if (cmd == VIDIOC_DBG_G_REGISTER)
+                       reg->val = cx25840_read(client, reg->reg & 0x0fff);
+               else
+                       cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
                break;
        }
 #endif
@@ -893,9 +887,11 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
                return 0;
        }
 
+       /* Note: revision '(device_id & 0x0f) == 2' was never built. The
+          marking skips from 0x1 == 22 to 0x3 == 23. */
        v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
                    (device_id & 0xfff0) >> 4,
-                   (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3,
+                   (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : (device_id & 0x0f),
                    address << 1, adapter->name);
 
        i2c_set_clientdata(client, state);
index 639c3b6..532cee3 100644 (file)
@@ -12,8 +12,3 @@ obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o
 EXTRA_CFLAGS += -Idrivers/media/video
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
-
-extra-cflags-$(CONFIG_VIDEO_BUF_DVB) += -DHAVE_VIDEO_BUF_DVB=1
-extra-cflags-$(CONFIG_VIDEO_CX88_VP3054)+= -DHAVE_VP3054_I2C=1
-
-EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
index 9a7a299..a1be1e2 100644 (file)
@@ -6,6 +6,9 @@
  *    (c) 2004 Jelle Foks <jelle@foks.8m.com>
  *    (c) 2004 Gerd Knorr <kraxel@bytesex.org>
  *
+ *    (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *        - video_ioctl2 conversion
+ *
  *  Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -520,7 +523,7 @@ static void blackbird_codec_settings(struct cx8802_dev *dev)
 
        dev->params.width = dev->width;
        dev->params.height = dev->height;
-       dev->params.is_50hz = (dev->core->tvnorm->id & V4L2_STD_625_50) != 0;
+       dev->params.is_50hz = (dev->core->tvnorm & V4L2_STD_625_50) != 0;
 
        cx2341x_update(dev, blackbird_mbox_func, NULL, &dev->params);
 }
@@ -710,8 +713,13 @@ static int blackbird_queryctrl(struct cx8802_dev *dev, struct v4l2_queryctrl *qc
        return 0;
 }
 
-static int blackbird_querymenu(struct cx8802_dev *dev, struct v4l2_querymenu *qmenu)
+/* ------------------------------------------------------------------ */
+/* IOCTL Handlers                                                     */
+
+static int vidioc_querymenu (struct file *file, void *priv,
+                               struct v4l2_querymenu *qmenu)
 {
+       struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
        struct v4l2_queryctrl qctrl;
 
        qctrl.id = qmenu->id;
@@ -719,221 +727,347 @@ static int blackbird_querymenu(struct cx8802_dev *dev, struct v4l2_querymenu *qm
        return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
 }
 
-/* ------------------------------------------------------------------ */
+static int vidioc_querycap (struct file *file, void  *priv,
+                                       struct v4l2_capability *cap)
+{
+       struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
+       struct cx88_core  *core = dev->core;
 
-static int mpeg_do_ioctl(struct inode *inode, struct file *file,
-                        unsigned int cmd, void *arg)
+       strcpy(cap->driver, "cx88_blackbird");
+       strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card));
+       sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
+       cap->version = CX88_VERSION_CODE;
+       cap->capabilities =
+               V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_READWRITE     |
+               V4L2_CAP_STREAMING;
+       if (UNSET != core->tuner_type)
+               cap->capabilities |= V4L2_CAP_TUNER;
+       return 0;
+}
+
+static int vidioc_enum_fmt_cap (struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
 {
-       struct cx8802_fh  *fh  = file->private_data;
-       struct cx8802_dev *dev = fh->dev;
+       if (f->index != 0)
+               return -EINVAL;
+
+       strlcpy(f->description, "MPEG", sizeof(f->description));
+       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       f->pixelformat = V4L2_PIX_FMT_MPEG;
+       return 0;
+}
+
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct cx8802_fh  *fh   = priv;
+       struct cx8802_dev *dev  = fh->dev;
+
+       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */
+       f->fmt.pix.colorspace   = 0;
+       f->fmt.pix.width        = dev->width;
+       f->fmt.pix.height       = dev->height;
+       f->fmt.pix.field        = fh->mpegq.field;
+       dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+               dev->width, dev->height, fh->mpegq.field );
+       return 0;
+}
+
+static int vidioc_try_fmt_cap (struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct cx8802_fh  *fh   = priv;
+       struct cx8802_dev *dev  = fh->dev;
+
+       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
+       f->fmt.pix.colorspace   = 0;
+       dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+               dev->width, dev->height, fh->mpegq.field );
+       return 0;
+}
+
+static int vidioc_s_fmt_cap (struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct cx8802_fh  *fh   = priv;
+       struct cx8802_dev *dev  = fh->dev;
        struct cx88_core  *core = dev->core;
 
-       if (debug > 1)
-               v4l_print_ioctl(core->name,cmd);
-
-       switch (cmd) {
-
-       /* --- capabilities ------------------------------------------ */
-       case VIDIOC_QUERYCAP:
-       {
-               struct v4l2_capability *cap = arg;
-
-               memset(cap,0,sizeof(*cap));
-               strcpy(cap->driver, "cx88_blackbird");
-               strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card));
-               sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
-               cap->version = CX88_VERSION_CODE;
-               cap->capabilities =
-                       V4L2_CAP_VIDEO_CAPTURE |
-                       V4L2_CAP_READWRITE     |
-                       V4L2_CAP_STREAMING     |
-                       0;
-               if (UNSET != core->tuner_type)
-                       cap->capabilities |= V4L2_CAP_TUNER;
+       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
+       f->fmt.pix.colorspace   = 0;
+       dev->width              = f->fmt.pix.width;
+       dev->height             = f->fmt.pix.height;
+       fh->mpegq.field         = f->fmt.pix.field;
+       cx88_set_scale(core, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
+       blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
+                               f->fmt.pix.height, f->fmt.pix.width);
+       dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+               f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field );
+       return 0;
+}
 
-               return 0;
-       }
+static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
+{
+       struct cx8802_fh  *fh   = priv;
+       return (videobuf_reqbufs(&fh->mpegq, p));
+}
 
-       /* --- capture ioctls ---------------------------------------- */
-       case VIDIOC_ENUM_FMT:
-       {
-               struct v4l2_fmtdesc *f = arg;
-               int index;
-
-               index = f->index;
-               if (index != 0)
-                       return -EINVAL;
-
-               memset(f,0,sizeof(*f));
-               f->index = index;
-               strlcpy(f->description, "MPEG", sizeof(f->description));
-               f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               f->pixelformat = V4L2_PIX_FMT_MPEG;
-               return 0;
-       }
-       case VIDIOC_G_FMT:
-       {
-               struct v4l2_format *f = arg;
-
-               memset(f,0,sizeof(*f));
-               f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
-               f->fmt.pix.bytesperline = 0;
-               f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */
-               f->fmt.pix.colorspace   = 0;
-               f->fmt.pix.width        = dev->width;
-               f->fmt.pix.height       = dev->height;
-               f->fmt.pix.field        = fh->mpegq.field;
-               dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
-                       dev->width, dev->height, fh->mpegq.field );
-               return 0;
-       }
-       case VIDIOC_TRY_FMT:
-       {
-               struct v4l2_format *f = arg;
-
-               f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
-               f->fmt.pix.bytesperline = 0;
-               f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
-               f->fmt.pix.colorspace   = 0;
-               dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
-                       dev->width, dev->height, fh->mpegq.field );
-               return 0;
-       }
-       case VIDIOC_S_FMT:
-       {
-               struct v4l2_format *f = arg;
-
-               f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
-               f->fmt.pix.bytesperline = 0;
-               f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
-               f->fmt.pix.colorspace   = 0;
-               dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
-                       f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field );
-               return 0;
-       }
+static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct cx8802_fh  *fh   = priv;
+       return (videobuf_querybuf(&fh->mpegq, p));
+}
 
-       /* --- streaming capture ------------------------------------- */
-       case VIDIOC_REQBUFS:
-               return videobuf_reqbufs(&fh->mpegq, arg);
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct cx8802_fh  *fh   = priv;
+       return (videobuf_qbuf(&fh->mpegq, p));
+}
 
-       case VIDIOC_QUERYBUF:
-               return videobuf_querybuf(&fh->mpegq, arg);
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct cx8802_fh  *fh   = priv;
+       return (videobuf_dqbuf(&fh->mpegq, p,
+                               file->f_flags & O_NONBLOCK));
+}
 
-       case VIDIOC_QBUF:
-               return videobuf_qbuf(&fh->mpegq, arg);
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct cx8802_fh  *fh   = priv;
+       return videobuf_streamon(&fh->mpegq);
+}
 
-       case VIDIOC_DQBUF:
-               return videobuf_dqbuf(&fh->mpegq, arg,
-                                     file->f_flags & O_NONBLOCK);
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct cx8802_fh  *fh   = priv;
+       return videobuf_streamoff(&fh->mpegq);
+}
 
-       case VIDIOC_STREAMON:
-               return videobuf_streamon(&fh->mpegq);
+static int vidioc_g_mpegcomp (struct file *file, void *fh,
+                             struct v4l2_mpeg_compression *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_STREAMOFF:
-               return videobuf_streamoff(&fh->mpegq);
+static int vidioc_s_mpegcomp (struct file *file, void *fh,
+                             struct v4l2_mpeg_compression *f)
+{
+       printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
+                               "Replace with VIDIOC_S_EXT_CTRLS!");
+       return 0;
+}
 
-       /* --- mpeg compression -------------------------------------- */
-       case VIDIOC_G_MPEGCOMP:
-       {
-               struct v4l2_mpeg_compression *f = arg;
+static int vidioc_g_ext_ctrls (struct file *file, void *priv,
+                              struct v4l2_ext_controls *f)
+{
+       struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
 
-               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_ext_controls *f = arg;
+       if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+               return -EINVAL;
+       return cx2341x_ext_ctrls(&dev->params, f, VIDIOC_G_EXT_CTRLS);
+}
 
-               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;
+static int vidioc_s_ext_ctrls (struct file *file, void *priv,
+                              struct v4l2_ext_controls *f)
+{
+       struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
+       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, VIDIOC_S_EXT_CTRLS);
+       if (!err) {
+               err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p);
+               dev->params = p;
        }
-       case VIDIOC_LOG_STATUS:
-       {
-               char name[32 + 2];
-
-               snprintf(name, sizeof(name), "%s/2", core->name);
-               printk("%s/2: ============  START LOG STATUS  ============\n",
-                      core->name);
-               cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, NULL);
-               cx2341x_log_status(&dev->params, name);
-               printk("%s/2: =============  END LOG STATUS  =============\n",
-                      core->name);
+       return err;
+}
+
+static int vidioc_try_ext_ctrls (struct file *file, void *priv,
+                              struct v4l2_ext_controls *f)
+{
+       struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
+       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, VIDIOC_TRY_EXT_CTRLS);
+
+       return err;
+}
+
+static int vidioc_s_frequency (struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct cx8802_fh  *fh   = priv;
+       struct cx8802_dev *dev  = fh->dev;
+       struct cx88_core  *core = dev->core;
+
+       blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+                               BLACKBIRD_END_NOW,
+                               BLACKBIRD_MPEG_CAPTURE,
+                               BLACKBIRD_RAW_BITS_NONE);
+       cx88_set_freq (core,f);
+       blackbird_initialize_codec(dev);
+       cx88_set_scale(dev->core, dev->width, dev->height,
+                       fh->mpegq.field);
+       return 0;
+}
+
+static int vidioc_log_status (struct file *file, void *priv)
+{
+       struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
+       struct cx88_core  *core = dev->core;
+       char name[32 + 2];
+
+       snprintf(name, sizeof(name), "%s/2", core->name);
+       printk("%s/2: ============  START LOG STATUS  ============\n",
+               core->name);
+       cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, NULL);
+       cx2341x_log_status(&dev->params, name);
+       printk("%s/2: =============  END LOG STATUS  =============\n",
+               core->name);
+       return 0;
+}
+
+static int vidioc_queryctrl (struct file *file, void *priv,
+                               struct v4l2_queryctrl *qctrl)
+{
+       struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
+
+       if (blackbird_queryctrl(dev, qctrl) == 0)
                return 0;
-       }
-       case VIDIOC_QUERYMENU:
-               return blackbird_querymenu(dev, arg);
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *c = arg;
 
-               if (blackbird_queryctrl(dev, c) == 0)
-                       return 0;
-               return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl);
-       }
+       qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+       if (unlikely(qctrl->id == 0))
+               return -EINVAL;
+       return cx8800_ctrl_query(qctrl);
+}
 
-       default:
-               return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook);
-       }
+static int vidioc_enum_input (struct file *file, void *priv,
+                               struct v4l2_input *i)
+{
+       struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
+       return cx88_enum_input (core,i);
+}
+
+static int vidioc_g_ctrl (struct file *file, void *priv,
+                               struct v4l2_control *ctl)
+{
+       struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
+       return
+               cx88_get_control(core,ctl);
+}
+
+static int vidioc_s_ctrl (struct file *file, void *priv,
+                               struct v4l2_control *ctl)
+{
+       struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
+       return
+               cx88_set_control(core,ctl);
+}
+
+static int vidioc_g_frequency (struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct cx8802_fh  *fh   = priv;
+       struct cx88_core  *core = fh->dev->core;
+
+       if (unlikely(UNSET == core->tuner_type))
+               return -EINVAL;
+
+       f->type = V4L2_TUNER_ANALOG_TV;
+       f->frequency = core->freq;
+       cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
+
+       return 0;
+}
+
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+{
+       struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
+
+       *i = core->input;
+       return 0;
+}
+
+static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+{
+       struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
+
+       if (i >= 4)
+               return -EINVAL;
+
+       mutex_lock(&core->lock);
+       cx88_newstation(core);
+       cx88_video_mux(core,i);
+       mutex_unlock(&core->lock);
        return 0;
 }
 
-int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
-                       unsigned int cmd, void *arg);
-unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
+static int vidioc_g_tuner (struct file *file, void *priv,
+                               struct v4l2_tuner *t)
+{
+       struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
+       u32 reg;
+
+       if (unlikely(UNSET == core->tuner_type))
+               return -EINVAL;
+
+       strcpy(t->name, "Television");
+       t->type       = V4L2_TUNER_ANALOG_TV;
+       t->capability = V4L2_TUNER_CAP_NORM;
+       t->rangehigh  = 0xffffffffUL;
+
+       cx88_get_stereo(core ,t);
+       reg = cx_read(MO_DEVICE_STATUS);
+       t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
+       return 0;
+}
 
-static unsigned int mpeg_translate_ioctl(unsigned int cmd)
+static int vidioc_s_tuner (struct file *file, void *priv,
+                               struct v4l2_tuner *t)
 {
-       return cmd;
+       struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
+
+       if (UNSET == core->tuner_type)
+               return -EINVAL;
+       if (0 != t->index)
+               return -EINVAL;
+
+       cx88_set_stereo(core, t->audmode, 1);
+       return 0;
 }
 
-static int mpeg_ioctl(struct inode *inode, struct file *file,
-                       unsigned int cmd, unsigned long arg)
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
 {
-       cmd = cx88_ioctl_translator( cmd );
-       return video_usercopy(inode, file, cmd, arg, cx88_ioctl_hook);
+       struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
+
+       mutex_lock(&core->lock);
+       cx88_set_tvnorm(core,*id);
+       mutex_unlock(&core->lock);
+       return 0;
 }
 
+/* FIXME: cx88_ioctl_hook not implemented */
+
 static int mpeg_open(struct inode *inode, struct file *file)
 {
        int minor = iminor(inode);
@@ -1059,17 +1193,47 @@ static const struct file_operations mpeg_fops =
        .read          = mpeg_read,
        .poll          = mpeg_poll,
        .mmap          = mpeg_mmap,
-       .ioctl         = mpeg_ioctl,
+       .ioctl         = video_ioctl2,
        .llseek        = no_llseek,
 };
 
 static struct video_device cx8802_mpeg_template =
 {
-       .name          = "cx8802",
-       .type          = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES|VID_TYPE_MPEG_ENCODER,
-       .hardware      = 0,
-       .fops          = &mpeg_fops,
-       .minor         = -1,
+       .name                 = "cx8802",
+       .type                 = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES|VID_TYPE_MPEG_ENCODER,
+       .fops                 = &mpeg_fops,
+       .minor                = -1,
+       .vidioc_querymenu     = vidioc_querymenu,
+       .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_streamon      = vidioc_streamon,
+       .vidioc_streamoff     = vidioc_streamoff,
+       .vidioc_g_mpegcomp    = vidioc_g_mpegcomp,
+       .vidioc_s_mpegcomp    = vidioc_s_mpegcomp,
+       .vidioc_g_ext_ctrls   = vidioc_g_ext_ctrls,
+       .vidioc_s_ext_ctrls   = vidioc_s_ext_ctrls,
+       .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
+       .vidioc_s_frequency   = vidioc_s_frequency,
+       .vidioc_log_status    = vidioc_log_status,
+       .vidioc_queryctrl     = vidioc_queryctrl,
+       .vidioc_enum_input    = vidioc_enum_input,
+       .vidioc_g_ctrl        = vidioc_g_ctrl,
+       .vidioc_s_ctrl        = vidioc_s_ctrl,
+       .vidioc_g_frequency   = vidioc_g_frequency,
+       .vidioc_g_input       = vidioc_g_input,
+       .vidioc_s_input       = vidioc_s_input,
+       .vidioc_g_tuner       = vidioc_g_tuner,
+       .vidioc_s_tuner       = vidioc_s_tuner,
+       .vidioc_s_std         = vidioc_s_std,
+       .tvnorms              = CX88_NORMS,
+       .current_norm         = V4L2_STD_NTSC_M,
 };
 
 /* ------------------------------------------------------------------ */
@@ -1164,7 +1328,9 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
        cx2341x_fill_defaults(&dev->params);
        dev->params.port = CX2341X_PORT_STREAMING;
 
-       if (core->tvnorm->id & V4L2_STD_525_60) {
+       cx8802_mpeg_template.current_norm = core->tvnorm;
+
+       if (core->tvnorm & V4L2_STD_525_60) {
                dev->height = 480;
        } else {
                dev->height = 576;
@@ -1178,6 +1344,11 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
        blackbird_register_video(dev);
 
        /* initial device configuration: needed ? */
+       mutex_lock(&dev->core->lock);
+//     init_controls(core);
+       cx88_set_tvnorm(core,core->tvnorm);
+       cx88_video_mux(core,0);
+       mutex_unlock(&dev->core->lock);
 
        return 0;
 
@@ -1212,8 +1383,6 @@ static int blackbird_init(void)
        printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
               SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
 #endif
-       cx88_ioctl_hook = mpeg_do_ioctl;
-       cx88_ioctl_translator = mpeg_translate_ioctl;
        return cx8802_register_driver(&cx8802_blackbird_driver);
 }
 
@@ -1225,8 +1394,8 @@ static void blackbird_fini(void)
 module_init(blackbird_init);
 module_exit(blackbird_fini);
 
-EXPORT_SYMBOL(cx88_ioctl_hook);
-EXPORT_SYMBOL(cx88_ioctl_translator);
+module_param_named(video_debug,cx8802_mpeg_template.debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages [video]");
 
 /* ----------------------------------------------------------- */
 /*
index 434b78a..65e9d80 100644 (file)
@@ -764,6 +764,12 @@ struct cx88_board cx88_boards[] = {
                .input          = {{
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 2,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
                }},
                .mpeg           = CX88_MPEG_DVB,
        },
index 1899736..d86813b 100644 (file)
@@ -5,6 +5,11 @@
  *
  * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
  *
+ * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *     - Multituner support
+ *     - video_ioctl2 conversion
+ *     - PAL/M fixes
+ *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
@@ -631,30 +636,30 @@ int cx88_reset(struct cx88_core *core)
 
 /* ------------------------------------------------------------------ */
 
-static unsigned int inline norm_swidth(struct cx88_tvnorm *norm)
+static unsigned int inline norm_swidth(v4l2_std_id norm)
 {
-       return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
+       return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
 }
 
-static unsigned int inline norm_hdelay(struct cx88_tvnorm *norm)
+static unsigned int inline norm_hdelay(v4l2_std_id norm)
 {
-       return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186;
+       return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186;
 }
 
-static unsigned int inline norm_vdelay(struct cx88_tvnorm *norm)
+static unsigned int inline norm_vdelay(v4l2_std_id norm)
 {
-       return (norm->id & V4L2_STD_625_50) ? 0x24 : 0x18;
+       return (norm & V4L2_STD_625_50) ? 0x24 : 0x18;
 }
 
-static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
+static unsigned int inline norm_fsc8(v4l2_std_id norm)
 {
-       if (norm->id & V4L2_STD_PAL_M)
+       if (norm & V4L2_STD_PAL_M)
                return 28604892;      // 3.575611 MHz
 
-       if (norm->id & (V4L2_STD_PAL_Nc))
+       if (norm & (V4L2_STD_PAL_Nc))
                return 28656448;      // 3.582056 MHz
 
-       if (norm->id & V4L2_STD_NTSC) // All NTSC/M and variants
+       if (norm & V4L2_STD_NTSC) // All NTSC/M and variants
                return 28636360;      // 3.57954545 MHz +/- 10 Hz
 
        /* SECAM have also different sub carrier for chroma,
@@ -666,20 +671,20 @@ static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
        return 35468950;      // 4.43361875 MHz +/- 5 Hz
 }
 
-static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
+static unsigned int inline norm_htotal(v4l2_std_id norm)
 {
 
        unsigned int fsc4=norm_fsc8(norm)/2;
 
        /* returns 4*FSC / vtotal / frames per seconds */
-       return (norm->id & V4L2_STD_625_50) ?
+       return (norm & V4L2_STD_625_50) ?
                                ((fsc4+312)/625+12)/25 :
                                ((fsc4+262)/525*1001+15000)/30000;
 }
 
-static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
+static unsigned int inline norm_vbipack(v4l2_std_id norm)
 {
-       return (norm->id & V4L2_STD_625_50) ? 511 : 400;
+       return (norm & V4L2_STD_625_50) ? 511 : 400;
 }
 
 int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
@@ -692,7 +697,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig
        dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
                V4L2_FIELD_HAS_TOP(field)    ? "T" : "",
                V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
-               core->tvnorm->name);
+               v4l2_norm_to_name(core->tvnorm));
        if (!V4L2_FIELD_HAS_BOTH(field))
                height *= 2;
 
@@ -729,7 +734,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig
        // setup filters
        value = 0;
        value |= (1 << 19);        // CFILT (default)
-       if (core->tvnorm->id & V4L2_STD_SECAM) {
+       if (core->tvnorm & V4L2_STD_SECAM) {
                value |= (1 << 15);
                value |= (1 << 16);
        }
@@ -826,36 +831,36 @@ int cx88_stop_audio_dma(struct cx88_core *core)
 
 static int set_tvaudio(struct cx88_core *core)
 {
-       struct cx88_tvnorm *norm = core->tvnorm;
+       v4l2_std_id norm = core->tvnorm;
 
        if (CX88_VMUX_TELEVISION != INPUT(core->input)->type)
                return 0;
 
-       if (V4L2_STD_PAL_BG & norm->id) {
+       if (V4L2_STD_PAL_BG & norm) {
                core->tvaudio = WW_BG;
 
-       } else if (V4L2_STD_PAL_DK & norm->id) {
+       } else if (V4L2_STD_PAL_DK & norm) {
                core->tvaudio = WW_DK;
 
-       } else if (V4L2_STD_PAL_I & norm->id) {
+       } else if (V4L2_STD_PAL_I & norm) {
                core->tvaudio = WW_I;
 
-       } else if (V4L2_STD_SECAM_L & norm->id) {
+       } else if (V4L2_STD_SECAM_L & norm) {
                core->tvaudio = WW_L;
 
-       } else if (V4L2_STD_SECAM_DK & norm->id) {
+       } else if (V4L2_STD_SECAM_DK & norm) {
                core->tvaudio = WW_DK;
 
-       } else if ((V4L2_STD_NTSC_M & norm->id) ||
-                  (V4L2_STD_PAL_M  & norm->id)) {
+       } else if ((V4L2_STD_NTSC_M & norm) ||
+                  (V4L2_STD_PAL_M  & norm)) {
                core->tvaudio = WW_BTSC;
 
-       } else if (V4L2_STD_NTSC_M_JP & norm->id) {
+       } else if (V4L2_STD_NTSC_M_JP & norm) {
                core->tvaudio = WW_EIAJ;
 
        } else {
                printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
-                      core->name, norm->name);
+                      core->name, v4l2_norm_to_name(core->tvnorm));
                core->tvaudio = 0;
                return 0;
        }
@@ -874,7 +879,7 @@ static int set_tvaudio(struct cx88_core *core)
 
 
 
-int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
+int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
 {
        u32 fsc8;
        u32 adc_clock;
@@ -882,6 +887,7 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
        u32 step_db,step_dr;
        u64 tmp64;
        u32 bdelay,agcdelay,htotal;
+       u32 cxiformat, cxoformat;
 
        core->tvnorm = norm;
        fsc8       = norm_fsc8(norm);
@@ -890,23 +896,51 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
        step_db    = fsc8;
        step_dr    = fsc8;
 
-       if (norm->id & V4L2_STD_SECAM) {
+       if (norm & V4L2_STD_NTSC_M_JP) {
+               cxiformat = VideoFormatNTSCJapan;
+               cxoformat = 0x181f0008;
+       } else if (norm & V4L2_STD_NTSC_443) {
+               cxiformat = VideoFormatNTSC443;
+               cxoformat = 0x181f0008;
+       } else if (norm & V4L2_STD_PAL_M) {
+               cxiformat = VideoFormatPALM;
+               cxoformat = 0x1c1f0008;
+       } else if (norm & V4L2_STD_PAL_N) {
+               cxiformat = VideoFormatPALN;
+               cxoformat = 0x1c1f0008;
+       } else if (norm & V4L2_STD_PAL_Nc) {
+               cxiformat = VideoFormatPALNC;
+               cxoformat = 0x1c1f0008;
+       } else if (norm & V4L2_STD_PAL_60) {
+               cxiformat = VideoFormatPAL60;
+               cxoformat = 0x181f0008;
+       } else if (norm & V4L2_STD_NTSC) {
+               cxiformat = VideoFormatNTSC;
+               cxoformat = 0x181f0008;
+       } else if (norm & V4L2_STD_SECAM) {
                step_db = 4250000 * 8;
                step_dr = 4406250 * 8;
+
+               cxiformat = VideoFormatSECAM;
+               cxoformat = 0x181f0008;
+       } else { /* PAL */
+               cxiformat = VideoFormatPAL;
+               cxoformat = 0x181f0008;
        }
 
        dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",
-               norm->name, fsc8, adc_clock, vdec_clock, step_db, step_dr);
+               v4l2_norm_to_name(core->tvnorm), fsc8, adc_clock, vdec_clock,
+               step_db, step_dr);
        set_pll(core,2,vdec_clock);
 
        dprintk(1,"set_tvnorm: MO_INPUT_FORMAT  0x%08x [old=0x%08x]\n",
-               norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
-       cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat);
+               cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
+       cx_andor(MO_INPUT_FORMAT, 0xf, cxiformat);
 
        // FIXME: as-is from DScaler
        dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
-               norm->cxoformat, cx_read(MO_OUTPUT_FORMAT));
-       cx_write(MO_OUTPUT_FORMAT, norm->cxoformat);
+               cxoformat, cx_read(MO_OUTPUT_FORMAT));
+       cx_write(MO_OUTPUT_FORMAT, cxoformat);
 
        // MO_SCONV_REG = adc clock / video dec clock * 2^17
        tmp64  = adc_clock * (u64)(1 << 17);
@@ -955,7 +989,7 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
        set_tvaudio(core);
 
        // tell i2c chips
-       cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id);
+       cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm);
 
        // done
        return 0;
index 8b20335..4f55602 100644 (file)
@@ -35,7 +35,7 @@
 
 #include "mt352.h"
 #include "mt352_priv.h"
-#ifdef HAVE_VP3054_I2C
+#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
 # include "cx88-vp3054-i2c.h"
 #endif
 #include "zl10353.h"
@@ -200,7 +200,7 @@ static struct mt352_config dvico_fusionhdtv_dual = {
        .demod_init    = dvico_dual_demod_init,
 };
 
-#ifdef HAVE_VP3054_I2C
+#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
 static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
 {
        static u8 clock_config []  = { 0x89, 0x38, 0x38 };
@@ -543,7 +543,7 @@ static int dvb_register(struct cx8802_dev *dev)
                }
                break;
        case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
-#ifdef HAVE_VP3054_I2C
+#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
                dev->core->pll_addr = 0x61;
                dev->core->pll_desc = &dvb_pll_fmd1216me;
                dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
@@ -793,7 +793,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
        if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB))
                goto fail_core;
 
-#ifdef HAVE_VP3054_I2C
+#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
        err = vp3054_i2c_probe(dev);
        if (0 != err)
                goto fail_core;
@@ -822,7 +822,7 @@ static int cx8802_dvb_remove(struct cx8802_driver *drv)
        /* dvb */
        videobuf_dvb_unregister(&dev->dvb);
 
-#ifdef HAVE_VP3054_I2C
+#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
        vp3054_i2c_remove(dev);
 #endif
 
index 88af23a..9830d5c 100644 (file)
@@ -145,6 +145,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
        if (0 != core->i2c_rc)
                return;
 
+#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
        if ( (core->dvbdev) && (core->dvbdev->dvb.frontend) ) {
                if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
                        core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
@@ -154,6 +155,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
                if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
                        core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
        } else
+#endif
                i2c_clients_command(&core->i2c_adap, cmd, arg);
 }
 
index 063df03..97ef421 100644 (file)
@@ -797,55 +797,6 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
        Add some code here later.
 */
 
-# if 0
-       t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
-           V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
-       t->rxsubchans = V4L2_TUNER_SUB_MONO;
-       t->audmode = V4L2_TUNER_MODE_MONO;
-
-       switch (core->tvaudio) {
-       case WW_BTSC:
-               t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP;
-               t->rxsubchans = V4L2_TUNER_SUB_STEREO;
-               if (1 == pilot) {
-                       /* SAP */
-                       t->rxsubchans |= V4L2_TUNER_SUB_SAP;
-               }
-               break;
-       case WW_A2_BG:
-       case WW_A2_DK:
-       case WW_A2_M:
-               if (1 == pilot) {
-                       /* stereo */
-                       t->rxsubchans =
-                           V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-                       if (0 == mode)
-                               t->audmode = V4L2_TUNER_MODE_STEREO;
-               }
-               if (2 == pilot) {
-                       /* dual language -- FIXME */
-                       t->rxsubchans =
-                           V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
-                       t->audmode = V4L2_TUNER_MODE_LANG1;
-               }
-               break;
-       case WW_NICAM_BGDKL:
-               if (0 == mode) {
-                       t->audmode = V4L2_TUNER_MODE_STEREO;
-                       t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
-               }
-               break;
-       case WW_SYSTEM_L_AM:
-               if (0x0 == mode && !(cx_read(AUD_INIT) & 0x04)) {
-                       t->audmode = V4L2_TUNER_MODE_STEREO;
-                       t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
-               }
-               break;
-       default:
-               /* nothing */
-               break;
-       }
-# endif
        return;
 }
 
index aa2a697..86c1cf8 100644 (file)
@@ -21,9 +21,11 @@ MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]");
 
 /* ------------------------------------------------------------------ */
 
-void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f)
+int cx8800_vbi_fmt (struct file *file, void *priv,
+                                       struct v4l2_format *f)
 {
-       memset(&f->fmt.vbi,0,sizeof(f->fmt.vbi));
+       struct cx8800_fh  *fh   = priv;
+       struct cx8800_dev *dev  = fh->dev;
 
        f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
        f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
@@ -31,18 +33,19 @@ void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f)
        f->fmt.vbi.count[0] = VBI_LINE_COUNT;
        f->fmt.vbi.count[1] = VBI_LINE_COUNT;
 
-       if (dev->core->tvnorm->id & V4L2_STD_525_60) {
+       if (dev->core->tvnorm & V4L2_STD_525_60) {
                /* ntsc */
                f->fmt.vbi.sampling_rate = 28636363;
                f->fmt.vbi.start[0] = 10;
                f->fmt.vbi.start[1] = 273;
 
-       } else if (dev->core->tvnorm->id & V4L2_STD_625_50) {
+       } else if (dev->core->tvnorm & V4L2_STD_625_50) {
                /* pal */
                f->fmt.vbi.sampling_rate = 35468950;
                f->fmt.vbi.start[0] = 7 -1;
                f->fmt.vbi.start[1] = 319 -1;
        }
+       return 0;
 }
 
 static int cx8800_start_vbi_dma(struct cx8800_dev    *dev,
index c86a7e0..a97be1b 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  *
  * device driver for Conexant 2388x based TV cards
@@ -5,6 +6,11 @@
  *
  * (c) 2003-04 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
  *
+ * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *     - Multituner support
+ *     - video_ioctl2 conversion
+ *     - PAL/M fixes
+ *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
@@ -80,65 +86,6 @@ static LIST_HEAD(cx8800_devlist);
 /* ------------------------------------------------------------------- */
 /* static data                                                         */
 
-static struct cx88_tvnorm tvnorms[] = {
-       {
-               .name      = "NTSC-M",
-               .id        = V4L2_STD_NTSC_M,
-               .cxiformat = VideoFormatNTSC,
-               .cxoformat = 0x181f0008,
-       },{
-               .name      = "NTSC-JP",
-               .id        = V4L2_STD_NTSC_M_JP,
-               .cxiformat = VideoFormatNTSCJapan,
-               .cxoformat = 0x181f0008,
-       },{
-               .name      = "PAL-BG",
-               .id        = V4L2_STD_PAL_BG,
-               .cxiformat = VideoFormatPAL,
-               .cxoformat = 0x181f0008,
-       },{
-               .name      = "PAL-DK",
-               .id        = V4L2_STD_PAL_DK,
-               .cxiformat = VideoFormatPAL,
-               .cxoformat = 0x181f0008,
-       },{
-               .name      = "PAL-I",
-               .id        = V4L2_STD_PAL_I,
-               .cxiformat = VideoFormatPAL,
-               .cxoformat = 0x181f0008,
-       },{
-               .name      = "PAL-M",
-               .id        = V4L2_STD_PAL_M,
-               .cxiformat = VideoFormatPALM,
-               .cxoformat = 0x1c1f0008,
-       },{
-               .name      = "PAL-N",
-               .id        = V4L2_STD_PAL_N,
-               .cxiformat = VideoFormatPALN,
-               .cxoformat = 0x1c1f0008,
-       },{
-               .name      = "PAL-Nc",
-               .id        = V4L2_STD_PAL_Nc,
-               .cxiformat = VideoFormatPALNC,
-               .cxoformat = 0x1c1f0008,
-       },{
-               .name      = "PAL-60",
-               .id        = V4L2_STD_PAL_60,
-               .cxiformat = VideoFormatPAL60,
-               .cxoformat = 0x181f0008,
-       },{
-               .name      = "SECAM-L",
-               .id        = V4L2_STD_SECAM_L,
-               .cxiformat = VideoFormatSECAM,
-               .cxoformat = 0x181f0008,
-       },{
-               .name      = "SECAM-DK",
-               .id        = V4L2_STD_SECAM_DK,
-               .cxiformat = VideoFormatSECAM,
-               .cxoformat = 0x181f0008,
-       }
-};
-
 static struct cx8800_fmt formats[] = {
        {
                .name     = "8 bpp, gray",
@@ -364,14 +311,6 @@ int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl)
 }
 EXPORT_SYMBOL(cx8800_ctrl_query);
 
-static int cx88_queryctrl(struct v4l2_queryctrl *qctrl)
-{
-       qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
-       if (qctrl->id == 0)
-               return -EINVAL;
-       return cx8800_ctrl_query(qctrl);
-}
-
 /* ------------------------------------------------------------------- */
 /* resource management                                                 */
 
@@ -424,8 +363,7 @@ void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits)
 
 /* ------------------------------------------------------------------ */
 
-/* static int video_mux(struct cx8800_dev *dev, unsigned int input) */
-static int video_mux(struct cx88_core *core, unsigned int input)
+int cx88_video_mux(struct cx88_core *core, unsigned int input)
 {
        /* struct cx88_core *core = dev->core; */
 
@@ -464,6 +402,7 @@ static int video_mux(struct cx88_core *core, unsigned int input)
        }
        return 0;
 }
+EXPORT_SYMBOL(cx88_video_mux);
 
 /* ------------------------------------------------------------------ */
 
@@ -944,19 +883,18 @@ video_mmap(struct file *file, struct vm_area_struct * vma)
 }
 
 /* ------------------------------------------------------------------ */
+/* VIDEO CTRL IOCTLS                                                  */
 
-/* static int get_control(struct cx8800_dev *dev, struct v4l2_control *ctl) */
-static int get_control(struct cx88_core *core, struct v4l2_control *ctl)
+int cx88_get_control (struct cx88_core  *core, struct v4l2_control *ctl)
 {
-       /* struct cx88_core *core = dev->core; */
-       struct cx88_ctrl *c = NULL;
+       struct cx88_ctrl  *c    = NULL;
        u32 value;
        int i;
 
        for (i = 0; i < CX8800_CTLS; i++)
                if (cx8800_ctls[i].v.id == ctl->id)
                        c = &cx8800_ctls[i];
-       if (NULL == c)
+       if (unlikely(NULL == c))
                return -EINVAL;
 
        value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg);
@@ -977,20 +915,20 @@ static int get_control(struct cx88_core *core, struct v4l2_control *ctl)
                                value,c->mask, c->sreg ? " [shadowed]" : "");
        return 0;
 }
+EXPORT_SYMBOL(cx88_get_control);
 
-/* static int set_control(struct cx8800_dev *dev, struct v4l2_control *ctl) */
-static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
+int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
 {
-       /* struct cx88_core *core = dev->core; */
        struct cx88_ctrl *c = NULL;
        u32 value,mask;
        int i;
+
        for (i = 0; i < CX8800_CTLS; i++) {
                if (cx8800_ctls[i].v.id == ctl->id) {
                        c = &cx8800_ctls[i];
                }
        }
-       if (NULL == c)
+       if (unlikely(NULL == c))
                return -EINVAL;
 
        if (ctl->value < c->v.minimum)
@@ -1010,7 +948,7 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
 
                value = ((ctl->value - c->off) << c->shift) & c->mask;
 
-               if (core->tvnorm->id & V4L2_STD_SECAM) {
+               if (core->tvnorm & V4L2_STD_SECAM) {
                        /* For SECAM, both U and V sat should be equal */
                        value=value<<8|value;
                } else {
@@ -1033,6 +971,7 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
        }
        return 0;
 }
+EXPORT_SYMBOL(cx88_set_control);
 
 static void init_controls(struct cx88_core *core)
 {
@@ -1042,648 +981,531 @@ static void init_controls(struct cx88_core *core)
        for (i = 0; i < CX8800_CTLS; i++) {
                ctrl.id=cx8800_ctls[i].v.id;
                ctrl.value=cx8800_ctls[i].v.default_value;
-               set_control(core, &ctrl);
+
+               cx88_set_control(core, &ctrl);
        }
 }
 
 /* ------------------------------------------------------------------ */
+/* VIDEO IOCTLS                                                       */
 
-static int cx8800_g_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh,
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct cx8800_fh  *fh   = priv;
+
+       f->fmt.pix.width        = fh->width;
+       f->fmt.pix.height       = fh->height;
+       f->fmt.pix.field        = fh->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)
 {
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               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->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;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               cx8800_vbi_fmt(dev, f);
-               return 0;
+       struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
+       struct cx8800_fmt *fmt;
+       enum v4l2_field   field;
+       unsigned int      maxw, maxh;
+
+       fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       if (NULL == fmt)
+               return -EINVAL;
+
+       field = f->fmt.pix.field;
+       maxw  = norm_maxw(core->tvnorm);
+       maxh  = norm_maxh(core->tvnorm);
+
+       if (V4L2_FIELD_ANY == field) {
+               field = (f->fmt.pix.height > maxh/2)
+                       ? V4L2_FIELD_INTERLACED
+                       : V4L2_FIELD_BOTTOM;
+       }
+
+       switch (field) {
+       case V4L2_FIELD_TOP:
+       case V4L2_FIELD_BOTTOM:
+               maxh = maxh / 2;
+               break;
+       case V4L2_FIELD_INTERLACED:
+               break;
        default:
                return -EINVAL;
        }
+
+       f->fmt.pix.field = field;
+       if (f->fmt.pix.height < 32)
+               f->fmt.pix.height = 32;
+       if (f->fmt.pix.height > maxh)
+               f->fmt.pix.height = maxh;
+       if (f->fmt.pix.width < 48)
+               f->fmt.pix.width = 48;
+       if (f->fmt.pix.width > maxw)
+               f->fmt.pix.width = maxw;
+       f->fmt.pix.width &= ~0x03;
+       f->fmt.pix.bytesperline =
+               (f->fmt.pix.width * fmt->depth) >> 3;
+       f->fmt.pix.sizeimage =
+               f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+       return 0;
 }
 
-static int cx8800_try_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh,
-                         struct v4l2_format *f)
+static int vidioc_s_fmt_cap (struct file *file, void *priv,
+                                       struct v4l2_format *f)
 {
-       struct cx88_core *core = dev->core;
+       struct cx8800_fh  *fh   = priv;
+       int err = vidioc_try_fmt_cap (file,priv,f);
 
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-       {
-               struct cx8800_fmt *fmt;
-               enum v4l2_field field;
-               unsigned int maxw, maxh;
-
-               fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-               if (NULL == fmt)
-                       return -EINVAL;
-
-               field = f->fmt.pix.field;
-               maxw  = norm_maxw(core->tvnorm);
-               maxh  = norm_maxh(core->tvnorm);
-
-               if (V4L2_FIELD_ANY == field) {
-                       field = (f->fmt.pix.height > maxh/2)
-                               ? V4L2_FIELD_INTERLACED
-                               : V4L2_FIELD_BOTTOM;
-               }
+       if (0 != err)
+               return err;
+       fh->fmt        = format_by_fourcc(f->fmt.pix.pixelformat);
+       fh->width      = f->fmt.pix.width;
+       fh->height     = f->fmt.pix.height;
+       fh->vidq.field = f->fmt.pix.field;
+       return 0;
+}
 
-               switch (field) {
-               case V4L2_FIELD_TOP:
-               case V4L2_FIELD_BOTTOM:
-                       maxh = maxh / 2;
-                       break;
-               case V4L2_FIELD_INTERLACED:
-                       break;
-               default:
-                       return -EINVAL;
-               }
+static int vidioc_querycap (struct file *file, void  *priv,
+                                       struct v4l2_capability *cap)
+{
+       struct cx8800_dev *dev  = ((struct cx8800_fh *)priv)->dev;
+       struct cx88_core  *core = dev->core;
 
-               f->fmt.pix.field = field;
-               if (f->fmt.pix.height < 32)
-                       f->fmt.pix.height = 32;
-               if (f->fmt.pix.height > maxh)
-                       f->fmt.pix.height = maxh;
-               if (f->fmt.pix.width < 48)
-                       f->fmt.pix.width = 48;
-               if (f->fmt.pix.width > maxw)
-                       f->fmt.pix.width = maxw;
-               f->fmt.pix.width &= ~0x03;
-               f->fmt.pix.bytesperline =
-                       (f->fmt.pix.width * fmt->depth) >> 3;
-               f->fmt.pix.sizeimage =
-                       f->fmt.pix.height * f->fmt.pix.bytesperline;
+       strcpy(cap->driver, "cx8800");
+       strlcpy(cap->card, cx88_boards[core->board].name,
+               sizeof(cap->card));
+       sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
+       cap->version = CX88_VERSION_CODE;
+       cap->capabilities =
+               V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_READWRITE     |
+               V4L2_CAP_STREAMING     |
+               V4L2_CAP_VBI_CAPTURE;
+       if (UNSET != core->tuner_type)
+               cap->capabilities |= V4L2_CAP_TUNER;
+       return 0;
+}
 
-               return 0;
-       }
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               cx8800_vbi_fmt(dev, f);
-               return 0;
-       default:
+static int vidioc_enum_fmt_cap (struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       if (unlikely(f->index >= ARRAY_SIZE(formats)))
                return -EINVAL;
-       }
+
+       strlcpy(f->description,formats[f->index].name,sizeof(f->description));
+       f->pixelformat = formats[f->index].fourcc;
+
+       return 0;
 }
 
-static int cx8800_s_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh,
-                       struct v4l2_format *f)
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
 {
+       struct cx8800_fh           *fh   = priv;
+       struct videobuf_queue      *q;
+       struct v4l2_requestbuffers req;
+       unsigned int i;
        int err;
 
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               err = cx8800_try_fmt(dev,fh,f);
-               if (0 != err)
-                       return err;
+       q = get_queue(fh);
+       memset(&req,0,sizeof(req));
+       req.type   = q->type;
+       req.count  = 8;
+       req.memory = V4L2_MEMORY_MMAP;
+       err = videobuf_reqbufs(q,&req);
+       if (err < 0)
+               return err;
 
-               fh->fmt        = format_by_fourcc(f->fmt.pix.pixelformat);
-               fh->width      = f->fmt.pix.width;
-               fh->height     = f->fmt.pix.height;
-               fh->vidq.field = f->fmt.pix.field;
-               return 0;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               cx8800_vbi_fmt(dev, f);
-               return 0;
-       default:
-               return -EINVAL;
+       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;
        }
+       return 0;
 }
+#endif
 
-/*
- * This function is _not_ called directly, but from
- * video_generic_ioctl (and maybe others).  userspace
- * copying is done already, arg is a kernel pointer.
- */
-static int video_do_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, void *arg)
+static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
+{
+       struct cx8800_fh  *fh   = priv;
+       return (videobuf_reqbufs(get_queue(fh), p));
+}
+
+static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct cx8800_fh  *fh   = priv;
+       return (videobuf_querybuf(get_queue(fh), p));
+}
+
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct cx8800_fh  *fh   = priv;
+       return (videobuf_qbuf(get_queue(fh), p));
+}
+
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct cx8800_fh  *fh   = priv;
+       return (videobuf_dqbuf(get_queue(fh), p,
+                               file->f_flags & O_NONBLOCK));
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 {
-       struct cx8800_fh  *fh   = file->private_data;
+       struct cx8800_fh  *fh   = priv;
        struct cx8800_dev *dev  = fh->dev;
-       struct cx88_core  *core = dev->core;
-       int err;
 
-       if (video_debug > 1)
-               v4l_print_ioctl(core->name,cmd);
-       switch (cmd) {
+       if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
+               return -EINVAL;
+       if (unlikely(i != fh->type))
+               return -EINVAL;
 
-       /* --- capabilities ------------------------------------------ */
-       case VIDIOC_QUERYCAP:
-       {
-               struct v4l2_capability *cap = arg;
-
-               memset(cap,0,sizeof(*cap));
-               strcpy(cap->driver, "cx8800");
-               strlcpy(cap->card, cx88_boards[core->board].name,
-                       sizeof(cap->card));
-               sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
-               cap->version = CX88_VERSION_CODE;
-               cap->capabilities =
-                       V4L2_CAP_VIDEO_CAPTURE |
-                       V4L2_CAP_READWRITE     |
-                       V4L2_CAP_STREAMING     |
-                       V4L2_CAP_VBI_CAPTURE   |
-                       0;
-               if (UNSET != core->tuner_type)
-                       cap->capabilities |= V4L2_CAP_TUNER;
-               return 0;
-       }
+       if (unlikely(!res_get(dev,fh,get_ressource(fh))))
+               return -EBUSY;
+       return videobuf_streamon(get_queue(fh));
+}
 
-       /* --- 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;
-               switch (type) {
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                       if (index >= ARRAY_SIZE(formats))
-                               return -EINVAL;
-                       memset(f,0,sizeof(*f));
-                       f->index = index;
-                       f->type  = type;
-                       strlcpy(f->description,formats[index].name,sizeof(f->description));
-                       f->pixelformat = formats[index].fourcc;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               return 0;
-       }
-       case VIDIOC_G_FMT:
-       {
-               struct v4l2_format *f = arg;
-               return cx8800_g_fmt(dev,fh,f);
-       }
-       case VIDIOC_S_FMT:
-       {
-               struct v4l2_format *f = arg;
-               return cx8800_s_fmt(dev,fh,f);
-       }
-       case VIDIOC_TRY_FMT:
-       {
-               struct v4l2_format *f = arg;
-               return cx8800_try_fmt(dev,fh,f);
-       }
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       /* --- streaming capture ------------------------------------- */
-       case VIDIOCGMBUF:
-       {
-               struct video_mbuf *mbuf = arg;
-               struct videobuf_queue *q;
-               struct v4l2_requestbuffers req;
-               unsigned int i;
-
-               q = get_queue(fh);
-               memset(&req,0,sizeof(req));
-               req.type   = q->type;
-               req.count  = 8;
-               req.memory = V4L2_MEMORY_MMAP;
-               err = videobuf_reqbufs(q,&req);
-               if (err < 0)
-                       return err;
-               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;
-               }
-               return 0;
-       }
-#endif
-       case VIDIOC_REQBUFS:
-               return videobuf_reqbufs(get_queue(fh), arg);
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct cx8800_fh  *fh   = priv;
+       struct cx8800_dev *dev  = fh->dev;
+       int               err, res;
 
-       case VIDIOC_QUERYBUF:
-               return videobuf_querybuf(get_queue(fh), arg);
+       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (i != fh->type)
+               return -EINVAL;
 
-       case VIDIOC_QBUF:
-               return videobuf_qbuf(get_queue(fh), arg);
+       res = get_ressource(fh);
+       err = videobuf_streamoff(get_queue(fh));
+       if (err < 0)
+               return err;
+       res_free(dev,fh,res);
+       return 0;
+}
 
-       case VIDIOC_DQBUF:
-               return videobuf_dqbuf(get_queue(fh), arg,
-                                       file->f_flags & O_NONBLOCK);
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *tvnorms)
+{
+       struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
 
-       case VIDIOC_STREAMON:
-       {
-               int res = get_ressource(fh);
+       mutex_lock(&core->lock);
+       cx88_set_tvnorm(core,*tvnorms);
+       mutex_unlock(&core->lock);
 
-               if (!res_get(dev,fh,res))
-                       return -EBUSY;
-               return videobuf_streamon(get_queue(fh));
-       }
-       case VIDIOC_STREAMOFF:
-       {
-               int res = get_ressource(fh);
+       return 0;
+}
 
-               err = videobuf_streamoff(get_queue(fh));
-               if (err < 0)
-                       return err;
-               res_free(dev,fh,res);
-               return 0;
-       }
-       default:
-               return cx88_do_ioctl( inode, file, fh->radio, core, cmd, arg, video_do_ioctl );
-       }
+/* only one input in this sample driver */
+int cx88_enum_input (struct cx88_core  *core,struct v4l2_input *i)
+{
+       static const char *iname[] = {
+               [ CX88_VMUX_COMPOSITE1 ] = "Composite1",
+               [ CX88_VMUX_COMPOSITE2 ] = "Composite2",
+               [ CX88_VMUX_COMPOSITE3 ] = "Composite3",
+               [ CX88_VMUX_COMPOSITE4 ] = "Composite4",
+               [ CX88_VMUX_SVIDEO     ] = "S-Video",
+               [ CX88_VMUX_TELEVISION ] = "Television",
+               [ CX88_VMUX_CABLE      ] = "Cable TV",
+               [ CX88_VMUX_DVB        ] = "DVB",
+               [ CX88_VMUX_DEBUG      ] = "for debug only",
+       };
+       unsigned int n;
+
+       n = i->index;
+       if (n >= 4)
+               return -EINVAL;
+       if (0 == INPUT(n)->type)
+               return -EINVAL;
+       memset(i,0,sizeof(*i));
+       i->index = n;
+       i->type  = V4L2_INPUT_TYPE_CAMERA;
+       strcpy(i->name,iname[INPUT(n)->type]);
+       if ((CX88_VMUX_TELEVISION == INPUT(n)->type) ||
+               (CX88_VMUX_CABLE      == INPUT(n)->type))
+               i->type = V4L2_INPUT_TYPE_TUNER;
+               i->std = CX88_NORMS;
        return 0;
 }
+EXPORT_SYMBOL(cx88_enum_input);
 
-int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
-                 struct cx88_core *core, unsigned int cmd, void *arg, v4l2_kioctl driver_ioctl)
+static int vidioc_enum_input (struct file *file, void *priv,
+                               struct v4l2_input *i)
 {
-       int err;
+       struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
+       return cx88_enum_input (core,i);
+}
 
-       if (video_debug) {
-              if (video_debug > 1) {
-                      if (_IOC_DIR(cmd) & _IOC_WRITE)
-                              v4l_printk_ioctl_arg("cx88(w)",cmd, arg);
-                      else if (!_IOC_DIR(cmd) & _IOC_READ) {
-                              v4l_print_ioctl("cx88", cmd);
-                      }
-              } else
-                      v4l_print_ioctl(core->name,cmd);
-
-       }
-
-       switch (cmd) {
-       /* ---------- tv norms ---------- */
-       case VIDIOC_ENUMSTD:
-       {
-               struct v4l2_standard *e = arg;
-               unsigned int i;
-
-               i = e->index;
-               if (i >= ARRAY_SIZE(tvnorms))
-                       return -EINVAL;
-               err = v4l2_video_std_construct(e, tvnorms[e->index].id,
-                                              tvnorms[e->index].name);
-               e->index = i;
-               if (err < 0)
-                       return err;
-               return 0;
-       }
-       case VIDIOC_G_STD:
-       {
-               v4l2_std_id *id = arg;
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+{
+       struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
 
-               *id = core->tvnorm->id;
-               return 0;
-       }
-       case VIDIOC_S_STD:
-       {
-               v4l2_std_id *id = arg;
-               unsigned int i;
+       *i = core->input;
+       return 0;
+}
 
-               for(i = 0; i < ARRAY_SIZE(tvnorms); i++)
-                       if (*id & tvnorms[i].id)
-                               break;
-               if (i == ARRAY_SIZE(tvnorms))
-                       return -EINVAL;
+static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+{
+       struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
 
-               mutex_lock(&core->lock);
-               cx88_set_tvnorm(core,&tvnorms[i]);
-               mutex_unlock(&core->lock);
-               return 0;
-       }
+       if (i >= 4)
+               return -EINVAL;
 
-       /* ------ input switching ---------- */
-       case VIDIOC_ENUMINPUT:
-       {
-               static const char *iname[] = {
-                       [ CX88_VMUX_COMPOSITE1 ] = "Composite1",
-                       [ CX88_VMUX_COMPOSITE2 ] = "Composite2",
-                       [ CX88_VMUX_COMPOSITE3 ] = "Composite3",
-                       [ CX88_VMUX_COMPOSITE4 ] = "Composite4",
-                       [ CX88_VMUX_SVIDEO     ] = "S-Video",
-                       [ CX88_VMUX_TELEVISION ] = "Television",
-                       [ CX88_VMUX_CABLE      ] = "Cable TV",
-                       [ CX88_VMUX_DVB        ] = "DVB",
-                       [ CX88_VMUX_DEBUG      ] = "for debug only",
-               };
-               struct v4l2_input *i = arg;
-               unsigned int n;
-
-               n = i->index;
-               if (n >= 4)
-                       return -EINVAL;
-               if (0 == INPUT(n)->type)
-                       return -EINVAL;
-               memset(i,0,sizeof(*i));
-               i->index = n;
-               i->type  = V4L2_INPUT_TYPE_CAMERA;
-               strcpy(i->name,iname[INPUT(n)->type]);
-               if ((CX88_VMUX_TELEVISION == INPUT(n)->type) ||
-                   (CX88_VMUX_CABLE      == INPUT(n)->type))
-                       i->type = V4L2_INPUT_TYPE_TUNER;
-               for (n = 0; n < ARRAY_SIZE(tvnorms); n++)
-                       i->std |= tvnorms[n].id;
-               return 0;
-       }
-       case VIDIOC_G_INPUT:
-       {
-               unsigned int *i = arg;
+       mutex_lock(&core->lock);
+       cx88_newstation(core);
+       cx88_video_mux(core,i);
+       mutex_unlock(&core->lock);
+       return 0;
+}
 
-               *i = core->input;
-               return 0;
-       }
-       case VIDIOC_S_INPUT:
-       {
-               unsigned int *i = arg;
 
-               if (*i >= 4)
-                       return -EINVAL;
-               mutex_lock(&core->lock);
-               cx88_newstation(core);
-               video_mux(core,*i);
-               mutex_unlock(&core->lock);
-               return 0;
-       }
 
+static int vidioc_queryctrl (struct file *file, void *priv,
+                               struct v4l2_queryctrl *qctrl)
+{
+       qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+       if (unlikely(qctrl->id == 0))
+               return -EINVAL;
+       return cx8800_ctrl_query(qctrl);
+}
 
+static int vidioc_g_ctrl (struct file *file, void *priv,
+                               struct v4l2_control *ctl)
+{
+       struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
+       return
+               cx88_get_control(core,ctl);
+}
 
-       /* --- controls ---------------------------------------------- */
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *c = arg;
+static int vidioc_s_ctrl (struct file *file, void *priv,
+                               struct v4l2_control *ctl)
+{
+       struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
+       return
+               cx88_set_control(core,ctl);
+}
 
-               return cx88_queryctrl(c);
-       }
-       case VIDIOC_G_CTRL:
-               return get_control(core,arg);
-       case VIDIOC_S_CTRL:
-               return set_control(core,arg);
+static int vidioc_g_tuner (struct file *file, void *priv,
+                               struct v4l2_tuner *t)
+{
+       struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
+       u32 reg;
 
-       /* --- tuner ioctls ------------------------------------------ */
-       case VIDIOC_G_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
-               u32 reg;
-
-               if (UNSET == core->tuner_type)
-                       return -EINVAL;
-               if (0 != t->index)
-                       return -EINVAL;
-
-               memset(t,0,sizeof(*t));
-               strcpy(t->name, "Television");
-               t->type       = V4L2_TUNER_ANALOG_TV;
-               t->capability = V4L2_TUNER_CAP_NORM;
-               t->rangehigh  = 0xffffffffUL;
-
-               cx88_get_stereo(core ,t);
-               reg = cx_read(MO_DEVICE_STATUS);
-               t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
-               return 0;
-       }
-       case VIDIOC_S_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
+       if (unlikely(UNSET == core->tuner_type))
+               return -EINVAL;
+       if (0 != t->index)
+               return -EINVAL;
 
-               if (UNSET == core->tuner_type)
-                       return -EINVAL;
-               if (0 != t->index)
-                       return -EINVAL;
-               cx88_set_stereo(core, t->audmode, 1);
-               return 0;
-       }
-       case VIDIOC_G_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
+       strcpy(t->name, "Television");
+       t->type       = V4L2_TUNER_ANALOG_TV;
+       t->capability = V4L2_TUNER_CAP_NORM;
+       t->rangehigh  = 0xffffffffUL;
 
-               memset(f,0,sizeof(*f));
+       cx88_get_stereo(core ,t);
+       reg = cx_read(MO_DEVICE_STATUS);
+       t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
+       return 0;
+}
 
-               if (UNSET == core->tuner_type)
-                       return -EINVAL;
+static int vidioc_s_tuner (struct file *file, void *priv,
+                               struct v4l2_tuner *t)
+{
+       struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
 
-               /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
-               f->type = radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-               f->frequency = core->freq;
+       if (UNSET == core->tuner_type)
+               return -EINVAL;
+       if (0 != t->index)
+               return -EINVAL;
 
-               cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
+       cx88_set_stereo(core, t->audmode, 1);
+       return 0;
+}
 
-               return 0;
-       }
-       case VIDIOC_S_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
-
-               if (UNSET == core->tuner_type)
-                       return -EINVAL;
-               if (f->tuner != 0)
-                       return -EINVAL;
-               if (0 == radio && f->type != V4L2_TUNER_ANALOG_TV)
-                       return -EINVAL;
-               if (1 == radio && f->type != V4L2_TUNER_RADIO)
-                       return -EINVAL;
-               mutex_lock(&core->lock);
-               core->freq = f->frequency;
-               cx88_newstation(core);
-               cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f);
-
-               /* When changing channels it is required to reset TVAUDIO */
-               msleep (10);
-               cx88_set_tvaudio(core);
+static int vidioc_g_frequency (struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct cx8800_fh  *fh   = priv;
+       struct cx88_core  *core = fh->dev->core;
 
-               mutex_unlock(&core->lock);
-               return 0;
-       }
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       /* ioctls to allow direct acces to the cx2388x registers */
-       case VIDIOC_INT_G_REGISTER:
-       {
-               struct v4l2_register *reg = arg;
+       if (unlikely(UNSET == core->tuner_type))
+               return -EINVAL;
 
-               if (reg->i2c_id != 0)
-                       return -EINVAL;
-               /* cx2388x has a 24-bit register space */
-               reg->val = cx_read(reg->reg&0xffffff);
-               return 0;
-       }
-       case VIDIOC_INT_S_REGISTER:
-       {
-               struct v4l2_register *reg = arg;
+       /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
+       f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+       f->frequency = core->freq;
 
-               if (reg->i2c_id != 0)
-                       return -EINVAL;
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               cx_write(reg->reg&0xffffff, reg->val);
-               return 0;
-       }
-#endif
+       cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
 
-       default:
-               return v4l_compat_translate_ioctl(inode,file,cmd,arg,
-                                                 driver_ioctl);
-       }
        return 0;
 }
 
-static int video_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
+int cx88_set_freq (struct cx88_core  *core,
+                               struct v4l2_frequency *f)
 {
-       int retval;
+       if (unlikely(UNSET == core->tuner_type))
+               return -EINVAL;
+       if (unlikely(f->tuner != 0))
+               return -EINVAL;
 
-       retval=video_usercopy(inode, file, cmd, arg, video_do_ioctl);
+       mutex_lock(&core->lock);
+       core->freq = f->frequency;
+       cx88_newstation(core);
+       cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f);
+
+       /* When changing channels it is required to reset TVAUDIO */
+       msleep (10);
+       cx88_set_tvaudio(core);
 
-       if (video_debug > 1) {
-              if (retval < 0) {
-                      v4l_print_ioctl("cx88(err)", cmd);
-                      printk(KERN_DEBUG "cx88(err): errcode=%d\n",retval);
-              } else if (_IOC_DIR(cmd) & _IOC_READ)
-                      v4l_printk_ioctl_arg("cx88(r)",cmd, (void *)arg);
-       }
+       mutex_unlock(&core->lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(cx88_set_freq);
+
+static int vidioc_s_frequency (struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct cx8800_fh  *fh   = priv;
+       struct cx88_core  *core = fh->dev->core;
 
-       return retval;
+       if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
+               return -EINVAL;
+       if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
+               return -EINVAL;
+
+       return
+               cx88_set_freq (core,f);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register (struct file *file, void *fh,
+                               struct v4l2_register *reg)
+{
+       struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core;
+
+       if (reg->i2c_id != 0)
+               return -EINVAL;
+       /* cx2388x has a 24-bit register space */
+       reg->val = cx_read(reg->reg&0xffffff);
+       return 0;
 }
 
+static int vidioc_s_register (struct file *file, void *fh,
+                               struct v4l2_register *reg)
+{
+       struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core;
+
+       if (reg->i2c_id != 0)
+               return -EINVAL;
+       cx_write(reg->reg&0xffffff, reg->val);
+       return 0;
+}
+#endif
+
+/* ----------------------------------------------------------- */
+/* RADIO ESPECIFIC IOCTLS                                      */
 /* ----------------------------------------------------------- */
 
-static int radio_do_ioctl(struct inode *inode, struct file *file,
-                       unsigned int cmd, void *arg)
+static int radio_querycap (struct file *file, void  *priv,
+                                       struct v4l2_capability *cap)
 {
-       struct cx8800_fh *fh    = file->private_data;
-       struct cx8800_dev *dev  = fh->dev;
+       struct cx8800_dev *dev  = ((struct cx8800_fh *)priv)->dev;
        struct cx88_core  *core = dev->core;
 
-       if (video_debug > 1)
-               v4l_print_ioctl(core->name,cmd);
-
-       switch (cmd) {
-       case VIDIOC_QUERYCAP:
-       {
-               struct v4l2_capability *cap = arg;
-
-               memset(cap,0,sizeof(*cap));
-               strcpy(cap->driver, "cx8800");
-               strlcpy(cap->card, cx88_boards[core->board].name,
-                       sizeof(cap->card));
-               sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
-               cap->version = CX88_VERSION_CODE;
-               cap->capabilities = V4L2_CAP_TUNER;
-               return 0;
-       }
-       case VIDIOC_G_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
+       strcpy(cap->driver, "cx8800");
+       strlcpy(cap->card, cx88_boards[core->board].name,
+               sizeof(cap->card));
+       sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
+       cap->version = CX88_VERSION_CODE;
+       cap->capabilities = V4L2_CAP_TUNER;
+       return 0;
+}
 
-               if (t->index > 0)
-                       return -EINVAL;
+static int radio_g_tuner (struct file *file, void *priv,
+                               struct v4l2_tuner *t)
+{
+       struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
 
-               memset(t,0,sizeof(*t));
-               strcpy(t->name, "Radio");
-               t->type = V4L2_TUNER_RADIO;
+       if (unlikely(t->index > 0))
+               return -EINVAL;
 
-               cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t);
-               return 0;
-       }
-       case VIDIOC_ENUMINPUT:
-       {
-               struct v4l2_input *i = arg;
+       strcpy(t->name, "Radio");
+       t->type = V4L2_TUNER_RADIO;
 
-               if (i->index != 0)
-                       return -EINVAL;
-               strcpy(i->name,"Radio");
-               i->type = V4L2_INPUT_TYPE_TUNER;
-               return 0;
-       }
-       case VIDIOC_G_INPUT:
-       {
-               int *i = arg;
-               *i = 0;
-               return 0;
-       }
-       case VIDIOC_G_AUDIO:
-       {
-               struct v4l2_audio *a = arg;
+       cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t);
+       return 0;
+}
 
-               memset(a,0,sizeof(*a));
-               strcpy(a->name,"Radio");
-               return 0;
-       }
-       case VIDIOC_G_STD:
-       {
-               v4l2_std_id *id = arg;
-               *id = 0;
-               return 0;
-       }
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       case VIDIOCSTUNER:
-       {
-               struct video_tuner *v = arg;
+static int radio_enum_input (struct file *file, void *priv,
+                               struct v4l2_input *i)
+{
+       if (i->index != 0)
+               return -EINVAL;
+       strcpy(i->name,"Radio");
+       i->type = V4L2_INPUT_TYPE_TUNER;
 
-               if (v->tuner) /* Only tuner 0 */
-                       return -EINVAL;
+       return 0;
+}
 
-               cx88_call_i2c_clients(core,VIDIOCSTUNER,v);
-               return 0;
-       }
-#endif
-       case VIDIOC_S_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
+static int radio_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
+{
+       if (unlikely(a->index))
+               return -EINVAL;
 
-               if (0 != t->index)
-                       return -EINVAL;
+       memset(a,0,sizeof(*a));
+       strcpy(a->name,"Radio");
+       return 0;
+}
 
-               cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t);
+/* FIXME: Should add a standard for radio */
 
-               return 0;
-       }
+static int radio_s_tuner (struct file *file, void *priv,
+                               struct v4l2_tuner *t)
+{
+       struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
 
-       case VIDIOC_S_AUDIO:
-       case VIDIOC_S_INPUT:
-       case VIDIOC_S_STD:
-               return 0;
+       if (0 != t->index)
+               return -EINVAL;
 
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *c = arg;
-               int i;
-
-               if (c->id <  V4L2_CID_BASE ||
-                   c->id >= V4L2_CID_LASTP1)
-                       return -EINVAL;
-               if (c->id == V4L2_CID_AUDIO_MUTE) {
-                       for (i = 0; i < CX8800_CTLS; i++)
-                               if (cx8800_ctls[i].v.id == c->id)
-                                       break;
-                       *c = cx8800_ctls[i].v;
-               } else
-                       *c = no_ctl;
-               return 0;
-       }
+       cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t);
 
+       return 0;
+}
 
-       case VIDIOC_G_CTRL:
-       case VIDIOC_S_CTRL:
-       case VIDIOC_G_FREQUENCY:
-       case VIDIOC_S_FREQUENCY:
-               return video_do_ioctl(inode,file,cmd,arg);
+static int radio_s_audio (struct file *file, void *fh,
+                         struct v4l2_audio *a)
+{
+       return 0;
+}
 
-       default:
-               return v4l_compat_translate_ioctl(inode,file,cmd,arg,
-                                                 radio_do_ioctl);
-       }
+static int radio_s_input (struct file *file, void *fh, unsigned int i)
+{
        return 0;
-};
+}
 
-static int radio_ioctl(struct inode *inode, struct file *file,
-                       unsigned int cmd, unsigned long arg)
+static int radio_queryctrl (struct file *file, void *priv,
+                           struct v4l2_queryctrl *c)
 {
-       return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
-};
+       int i;
+
+       if (c->id <  V4L2_CID_BASE ||
+               c->id >= V4L2_CID_LASTP1)
+               return -EINVAL;
+       if (c->id == V4L2_CID_AUDIO_MUTE) {
+               for (i = 0; i < CX8800_CTLS; i++)
+                       if (cx8800_ctls[i].v.id == c->id)
+                               break;
+               *c = cx8800_ctls[i].v;
+       } else
+               *c = no_ctl;
+       return 0;
+}
 
 /* ----------------------------------------------------------- */
 
@@ -1816,27 +1638,52 @@ static const struct file_operations video_fops =
        .read          = video_read,
        .poll          = video_poll,
        .mmap          = video_mmap,
-       .ioctl         = video_ioctl,
+       .ioctl         = video_ioctl2,
        .compat_ioctl  = v4l_compat_ioctl32,
        .llseek        = no_llseek,
 };
 
+static struct video_device cx8800_vbi_template;
 static struct video_device cx8800_video_template =
 {
-       .name          = "cx8800-video",
-       .type          = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES,
-       .hardware      = 0,
-       .fops          = &video_fops,
-       .minor         = -1,
-};
-
-static struct video_device cx8800_vbi_template =
-{
-       .name          = "cx8800-vbi",
-       .type          = VID_TYPE_TELETEXT|VID_TYPE_TUNER,
-       .hardware      = 0,
-       .fops          = &video_fops,
-       .minor         = -1,
+       .name                 = "cx8800-video",
+       .type                 = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES,
+       .fops                 = &video_fops,
+       .minor                = -1,
+       .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_g_fmt_vbi     = cx8800_vbi_fmt,
+       .vidioc_try_fmt_vbi   = cx8800_vbi_fmt,
+       .vidioc_s_fmt_vbi     = cx8800_vbi_fmt,
+       .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 CONFIG_VIDEO_V4L1_COMPAT
+       .vidiocgmbuf          = vidiocgmbuf,
+#endif
+       .vidioc_g_tuner       = vidioc_g_tuner,
+       .vidioc_s_tuner       = vidioc_s_tuner,
+       .vidioc_g_frequency   = vidioc_g_frequency,
+       .vidioc_s_frequency   = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register    = vidioc_g_register,
+       .vidioc_s_register    = vidioc_s_register,
+#endif
+       .tvnorms              = CX88_NORMS,
+       .current_norm         = V4L2_STD_NTSC_M,
 };
 
 static const struct file_operations radio_fops =
@@ -1844,18 +1691,30 @@ static const struct file_operations radio_fops =
        .owner         = THIS_MODULE,
        .open          = video_open,
        .release       = video_release,
-       .ioctl         = radio_ioctl,
+       .ioctl         = video_ioctl2,
        .compat_ioctl  = v4l_compat_ioctl32,
        .llseek        = no_llseek,
 };
 
 static struct video_device cx8800_radio_template =
 {
-       .name          = "cx8800-radio",
-       .type          = VID_TYPE_TUNER,
-       .hardware      = 0,
-       .fops          = &radio_fops,
-       .minor         = -1,
+       .name                 = "cx8800-radio",
+       .type                 = VID_TYPE_TUNER,
+       .hardware             = 0,
+       .fops                 = &radio_fops,
+       .minor                = -1,
+       .vidioc_querycap      = radio_querycap,
+       .vidioc_g_tuner       = radio_g_tuner,
+       .vidioc_enum_input    = radio_enum_input,
+       .vidioc_g_audio       = radio_g_audio,
+       .vidioc_s_tuner       = radio_s_tuner,
+       .vidioc_s_audio       = radio_s_audio,
+       .vidioc_s_input       = radio_s_input,
+       .vidioc_queryctrl     = radio_queryctrl,
+       .vidioc_g_ctrl        = vidioc_g_ctrl,
+       .vidioc_s_ctrl        = vidioc_s_ctrl,
+       .vidioc_g_frequency   = vidioc_g_frequency,
+       .vidioc_s_frequency   = vidioc_s_frequency,
 };
 
 /* ----------------------------------------------------------- */
@@ -1890,6 +1749,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
 {
        struct cx8800_dev *dev;
        struct cx88_core *core;
+
        int err;
 
        dev = kzalloc(sizeof(*dev),GFP_KERNEL);
@@ -1924,9 +1784,15 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
                goto fail_core;
        }
 
+       /* Initialize VBI template */
+       memcpy( &cx8800_vbi_template, &cx8800_video_template,
+               sizeof(cx8800_vbi_template) );
+       strcpy(cx8800_vbi_template.name,"cx8800-vbi");
+       cx8800_vbi_template.type = VID_TYPE_TELETEXT|VID_TYPE_TUNER;
+
        /* initialize driver struct */
        spin_lock_init(&dev->slock);
-       core->tvnorm = tvnorms;
+       core->tvnorm = cx8800_video_template.current_norm;
 
        /* init video dma queues */
        INIT_LIST_HEAD(&dev->vidq.active);
@@ -2007,9 +1873,9 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
 
        /* initial device configuration */
        mutex_lock(&core->lock);
-       cx88_set_tvnorm(core,tvnorms);
+       cx88_set_tvnorm(core,core->tvnorm);
        init_controls(core);
-       video_mux(core,0);
+       cx88_video_mux(core,0);
        mutex_unlock(&core->lock);
 
        /* start tvaudio thread */
@@ -2178,8 +2044,6 @@ static void cx8800_fini(void)
 module_init(cx8800_init);
 module_exit(cx8800_fini);
 
-EXPORT_SYMBOL(cx88_do_ioctl);
-
 /* ----------------------------------------------------------- */
 /*
  * Local variables:
index a9575ad..d2ecfba 100644 (file)
@@ -31,7 +31,9 @@
 #include <media/video-buf.h>
 #include <media/cx2341x.h>
 #include <media/audiochip.h>
+#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
 #include <media/video-buf-dvb.h>
+#endif
 
 #include "btcx-risc.h"
 #include "cx88-reg.h"
 /* ----------------------------------------------------------- */
 /* defines and enums                                           */
 
+/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
+#define CX88_NORMS (\
+       V4L2_STD_NTSC_M|  V4L2_STD_NTSC_M_JP|  V4L2_STD_NTSC_443 | \
+       V4L2_STD_PAL_BG|  V4L2_STD_PAL_DK   |  V4L2_STD_PAL_I    | \
+       V4L2_STD_PAL_M |  V4L2_STD_PAL_N    |  V4L2_STD_PAL_Nc   | \
+       V4L2_STD_PAL_60|  V4L2_STD_SECAM_L  |  V4L2_STD_SECAM_DK )
+
 #define FORMAT_FLAGS_PACKED       0x01
 #define FORMAT_FLAGS_PLANAR       0x02
 
@@ -82,22 +91,15 @@ enum cx8802_board_access {
 /* ----------------------------------------------------------- */
 /* tv norms                                                    */
 
-struct cx88_tvnorm {
-       char                   *name;
-       v4l2_std_id            id;
-       u32                    cxiformat;
-       u32                    cxoformat;
-};
-
-static unsigned int inline norm_maxw(struct cx88_tvnorm *norm)
+static unsigned int inline norm_maxw(v4l2_std_id norm)
 {
-       return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
+       return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
 }
 
 
-static unsigned int inline norm_maxh(struct cx88_tvnorm *norm)
+static unsigned int inline norm_maxh(v4l2_std_id norm)
 {
-       return (norm->id & V4L2_STD_625_50) ? 576 : 480;
+       return (norm & V4L2_STD_625_50) ? 576 : 480;
 }
 
 /* ----------------------------------------------------------- */
@@ -313,13 +315,15 @@ struct cx88_core {
        unsigned int               tuner_formats;
 
        /* config info -- dvb */
+#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
        struct dvb_pll_desc        *pll_desc;
        unsigned int               pll_addr;
        int                        (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
+#endif
 
        /* state info */
        struct task_struct         *kthread;
-       struct cx88_tvnorm         *tvnorm;
+       v4l2_std_id                tvnorm;
        u32                        tvaudio;
        u32                        audiomode_manual;
        u32                        audiomode_current;
@@ -460,12 +464,14 @@ struct cx8802_dev {
        int                        width;
        int                        height;
 
+#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
        /* for dvb only */
        struct videobuf_dvb        dvb;
        void*                      fe_handle;
        int                        (*fe_release)(void *handle);
 
        void                       *card_priv;
+#endif
        /* for switching modulation types */
        unsigned char              ts_gen_cntrl;
 
@@ -536,7 +542,7 @@ extern void cx88_sram_channel_dump(struct cx88_core *core,
 
 extern int cx88_set_scale(struct cx88_core *core, unsigned int width,
                          unsigned int height, enum v4l2_field field);
-extern int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm);
+extern int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm);
 
 extern struct video_device *cx88_vdev_init(struct cx88_core *core,
                                           struct pci_dev *pci,
@@ -553,7 +559,10 @@ extern int cx88_stop_audio_dma(struct cx88_core *core);
 /* ----------------------------------------------------------- */
 /* cx88-vbi.c                                                  */
 
-void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f);
+/* Can be used as g_vbi_fmt, try_vbi_fmt and s_vbi_fmt */
+int cx8800_vbi_fmt (struct file *file, void *priv,
+                                       struct v4l2_format *f);
+
 /*
 int cx8800_start_vbi_dma(struct cx8800_dev    *dev,
                         struct cx88_dmaqueue *q,
@@ -633,19 +642,14 @@ int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state);
 int cx8802_resume_common(struct pci_dev *pci_dev);
 
 /* ----------------------------------------------------------- */
-/* cx88-video.c                                                */
-extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
-                               struct cx88_core *core, unsigned int cmd,
-                               void *arg, v4l2_kioctl driver_ioctl);
+/* cx88-video.c*/
 extern const u32 cx88_user_ctrls[];
 extern int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl);
-
-/* ----------------------------------------------------------- */
-/* cx88-blackbird.c                                            */
-/* used by cx88-ivtv ioctl emulation layer                     */
-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);
+int cx88_enum_input (struct cx88_core  *core,struct v4l2_input *i);
+int cx88_set_freq (struct cx88_core  *core,struct v4l2_frequency *f);
+int cx88_get_control(struct cx88_core *core, struct v4l2_control *ctl);
+int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl);
+int cx88_video_mux(struct cx88_core *core, unsigned int input);
 
 /*
  * Local variables:
index 2e5ca40..262f98e 100644 (file)
@@ -171,10 +171,7 @@ struct et61x251_device {
 struct et61x251_device*
 et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id)
 {
-       if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
-               return cam;
-
-       return NULL;
+       return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
 }
 
 
index 49792ae..a652551 100644 (file)
@@ -1,7 +1,7 @@
 /***************************************************************************
  * V4L2 driver for ET61X[12]51 PC Camera Controllers                       *
  *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
  * it under the terms of the GNU General Public License as published by    *
@@ -48,8 +48,8 @@
 #define ET61X251_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
 #define ET61X251_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
 #define ET61X251_MODULE_LICENSE "GPL"
-#define ET61X251_MODULE_VERSION "1:1.02"
-#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 2)
+#define ET61X251_MODULE_VERSION "1:1.04"
+#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 4)
 
 /*****************************************************************************/
 
@@ -85,7 +85,7 @@ MODULE_PARM_DESC(force_munmap,
                 "\ndetected camera."
                 "\n 0 = do not force memory unmapping"
                 "\n 1 = force memory unmapping (save memory)"
-                "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
+                "\nDefault value is "__MODULE_STRING(ET61X251_FORCE_MUNMAP)"."
                 "\n");
 
 static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] =
@@ -133,7 +133,8 @@ et61x251_request_buffers(struct et61x251_device* cam, u32 count,
 
        cam->nbuffers = count;
        while (cam->nbuffers > 0) {
-               if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
+               if ((buff = vmalloc_32_user(cam->nbuffers *
+                                           PAGE_ALIGN(imagesize))))
                        break;
                cam->nbuffers--;
        }
@@ -543,10 +544,11 @@ static int et61x251_start_transfer(struct et61x251_device* cam)
 {
        struct usb_device *udev = cam->usbdev;
        struct urb* urb;
-       const unsigned int wMaxPacketSize[] = {0, 256, 384, 512, 640, 768, 832,
-                                              864, 896, 920, 956, 980, 1000,
-                                              1022};
-       const unsigned int psz = wMaxPacketSize[ET61X251_ALTERNATE_SETTING];
+       struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
+                                                  usb_ifnum_to_if(udev, 0),
+                                                  ET61X251_ALTERNATE_SETTING);
+       const unsigned int psz = le16_to_cpu(altsetting->
+                                            endpoint[0].desc.wMaxPacketSize);
        s8 i, j;
        int err = 0;
 
@@ -976,29 +978,31 @@ static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
 static int et61x251_create_sysfs(struct et61x251_device* cam)
 {
        struct video_device *v4ldev = cam->v4ldev;
-       int rc;
+       int err = 0;
+
+       if ((err = video_device_create_file(v4ldev, &class_device_attr_reg)))
+               goto err_out;
+       if ((err = video_device_create_file(v4ldev, &class_device_attr_val)))
+               goto err_reg;
 
-       rc = video_device_create_file(v4ldev, &class_device_attr_reg);
-       if (rc) goto err;
-       rc = video_device_create_file(v4ldev, &class_device_attr_val);
-       if (rc) goto err_reg;
        if (cam->sensor.sysfs_ops) {
-               rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
-               if (rc) goto err_val;
-               rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val);
-               if (rc) goto err_i2c_reg;
+               if ((err = video_device_create_file(v4ldev,
+                                                 &class_device_attr_i2c_reg)))
+                       goto err_val;
+               if ((err = video_device_create_file(v4ldev,
+                                                 &class_device_attr_i2c_val)))
+                       goto err_i2c_reg;
        }
 
-       return 0;
-
 err_i2c_reg:
+       if (cam->sensor.sysfs_ops)
        video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
 err_val:
        video_device_remove_file(v4ldev, &class_device_attr_val);
 err_reg:
        video_device_remove_file(v4ldev, &class_device_attr_reg);
-err:
-       return rc;
+err_out:
+       return err;
 }
 #endif /* CONFIG_VIDEO_ADV_DEBUG */
 
@@ -1767,10 +1771,10 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
        rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
        rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
 
-       if (rect->width < 4)
-               rect->width = 4;
-       if (rect->height < 4)
-               rect->height = 4;
+       if (rect->width < 16)
+               rect->width = 16;
+       if (rect->height < 16)
+               rect->height = 16;
        if (rect->width > bounds->width)
                rect->width = bounds->width;
        if (rect->height > bounds->height)
@@ -1784,8 +1788,8 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
        if (rect->top + rect->height > bounds->top + bounds->height)
                rect->top = bounds->top+bounds->height - rect->height;
 
-       rect->width &= ~3L;
-       rect->height &= ~3L;
+       rect->width &= ~15L;
+       rect->height &= ~15L;
 
        if (ET61X251_PRESERVE_IMGSCALE) {
                /* Calculate the actual scaling factor */
@@ -1846,6 +1850,35 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
 
 
 static int
+et61x251_vidioc_enum_framesizes(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_frmsizeenum frmsize;
+
+       if (copy_from_user(&frmsize, arg, sizeof(frmsize)))
+               return -EFAULT;
+
+       if (frmsize.index != 0)
+               return -EINVAL;
+
+       if (frmsize.pixel_format != V4L2_PIX_FMT_ET61X251 &&
+           frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8)
+               return -EINVAL;
+
+       frmsize.type = V4L2_FRMSIZE_TYPE_STEPWISE;
+       frmsize.stepwise.min_width = frmsize.stepwise.step_width = 16;
+       frmsize.stepwise.min_height = frmsize.stepwise.step_height = 16;
+       frmsize.stepwise.max_width = cam->sensor.cropcap.bounds.width;
+       frmsize.stepwise.max_height = cam->sensor.cropcap.bounds.height;
+       memset(&frmsize.reserved, 0, sizeof(frmsize.reserved));
+
+       if (copy_to_user(arg, &frmsize, sizeof(frmsize)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
 et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg)
 {
        struct v4l2_fmtdesc fmtd;
@@ -1853,6 +1886,9 @@ et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg)
        if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
                return -EFAULT;
 
+       if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
        if (fmtd.index == 0) {
                strcpy(fmtd.description, "bayer rgb");
                fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
@@ -1934,17 +1970,17 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
        rect.width = scale * pix->width;
        rect.height = scale * pix->height;
 
-       if (rect.width < 4)
-               rect.width = 4;
-       if (rect.height < 4)
-               rect.height = 4;
+       if (rect.width < 16)
+               rect.width = 16;
+       if (rect.height < 16)
+               rect.height = 16;
        if (rect.width > bounds->left + bounds->width - rect.left)
                rect.width = bounds->left + bounds->width - rect.left;
        if (rect.height > bounds->top + bounds->height - rect.top)
                rect.height = bounds->top + bounds->height - rect.top;
 
-       rect.width &= ~3L;
-       rect.height &= ~3L;
+       rect.width &= ~15L;
+       rect.height &= ~15L;
 
        { /* adjust the scaling factor */
                u32 a, b;
@@ -2378,6 +2414,9 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
        case VIDIOC_S_FMT:
                return et61x251_vidioc_try_s_fmt(cam, cmd, arg);
 
+       case VIDIOC_ENUM_FRAMESIZES:
+               return et61x251_vidioc_enum_framesizes(cam, arg);
+
        case VIDIOC_G_JPEGCOMP:
                return et61x251_vidioc_g_jpegcomp(cam, arg);
 
@@ -2413,6 +2452,7 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
        case VIDIOC_QUERYSTD:
        case VIDIOC_ENUMSTD:
        case VIDIOC_QUERYMENU:
+       case VIDIOC_ENUM_FRAMEINTERVALS:
                return -EINVAL;
 
        default:
@@ -2459,6 +2499,7 @@ static const struct file_operations et61x251_fops = {
        .open =    et61x251_open,
        .release = et61x251_release,
        .ioctl =   et61x251_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
        .read =    et61x251_read,
        .poll =    et61x251_poll,
        .mmap =    et61x251_mmap,
@@ -2497,7 +2538,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        mutex_init(&cam->dev_mutex);
 
        DBG(2, "ET61X[12]51 PC Camera Controller detected "
-              "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
+              "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
 
        for  (i = 0; et61x251_sensor_table[i]; i++) {
                err = et61x251_sensor_table[i](cam);
@@ -2550,9 +2591,14 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        err = et61x251_create_sysfs(cam);
-       if (err)
-               goto fail2;
-       DBG(2, "Optional device control through 'sysfs' interface ready");
+       if (!err)
+               DBG(2, "Optional device control through 'sysfs' "
+                      "interface ready");
+       else
+               DBG(2, "Failed to create 'sysfs' interface for optional "
+                      "device controlling. Error #%d", err);
+#else
+       DBG(2, "Optional device control through 'sysfs' interface disabled");
 #endif
 
        usb_set_intfdata(intf, cam);
@@ -2561,13 +2607,6 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 
        return 0;
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-fail2:
-       video_nr[dev_nr] = -1;
-       dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
-       mutex_unlock(&cam->dev_mutex);
-       video_unregister_device(cam->v4ldev);
-#endif
 fail:
        if (cam) {
                kfree(cam->control_buffer);
index 65edd08..5fadb5d 100644 (file)
@@ -1,7 +1,7 @@
 /***************************************************************************
  * API for image sensors connected to ET61X[12]51 PC Camera Controllers    *
  *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
  * it under the terms of the GNU General Public License as published by    *
@@ -82,7 +82,7 @@ enum et61x251_i2c_rsta {
        ET61X251_I2C_RSTA_REPEAT = 0x01, /* repeat start */
 };
 
-#define ET61X251_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
+#define ET61X251_MAX_CTRLS (V4L2_CID_LASTP1-V4L2_CID_BASE+10)
 
 struct et61x251_sensor {
        char name[32];
index a7d65b8..b066434 100644 (file)
@@ -2,7 +2,7 @@
  * Plug-in for TAS5130D1B image sensor connected to the ET61X[12]51        *
  * PC Camera Controllers                                                   *
  *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
  * it under the terms of the GNU General Public License as published by    *
index 122496f..379645e 100644 (file)
@@ -31,7 +31,6 @@ struct pvr2_msp3400_handler {
        struct pvr2_hdw *hdw;
        struct pvr2_i2c_client *client;
        struct pvr2_i2c_handler i2c_handler;
-       struct pvr2_audio_stat astat;
        unsigned long stale_mask;
 };
 
@@ -44,13 +43,6 @@ static void set_stereo(struct pvr2_msp3400_handler *ctxt)
 
        pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo");
 
-       if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
-               struct v4l2_tuner vt;
-               memset(&vt,0,sizeof(vt));
-               vt.audmode = hdw->audiomode_val;
-               pvr2_i2c_client_cmd(ctxt->client,VIDIOC_S_TUNER,&vt);
-       }
-
        route.input = MSP_INPUT_DEFAULT;
        route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
        switch (hdw->input_val) {
@@ -78,8 +70,7 @@ static void set_stereo(struct pvr2_msp3400_handler *ctxt)
 static int check_stereo(struct pvr2_msp3400_handler *ctxt)
 {
        struct pvr2_hdw *hdw = ctxt->hdw;
-       return (hdw->input_dirty ||
-               hdw->audiomode_dirty);
+       return hdw->input_dirty;
 }
 
 
@@ -99,8 +90,7 @@ static int msp3400_check(struct pvr2_msp3400_handler *ctxt)
        unsigned long msk;
        unsigned int idx;
 
-       for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]);
-            idx++) {
+       for (idx = 0; idx < ARRAY_SIZE(msp3400_ops); idx++) {
                msk = 1 << idx;
                if (ctxt->stale_mask & msk) continue;
                if (msp3400_ops[idx].check(ctxt)) {
@@ -116,8 +106,7 @@ static void msp3400_update(struct pvr2_msp3400_handler *ctxt)
        unsigned long msk;
        unsigned int idx;
 
-       for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]);
-            idx++) {
+       for (idx = 0; idx < ARRAY_SIZE(msp3400_ops); idx++) {
                msk = 1 << idx;
                if (!(ctxt->stale_mask & msk)) continue;
                ctxt->stale_mask &= ~msk;
@@ -126,27 +115,9 @@ static void msp3400_update(struct pvr2_msp3400_handler *ctxt)
 }
 
 
-/* This reads back the current signal type */
-static int get_audio_status(struct pvr2_msp3400_handler *ctxt)
-{
-       struct v4l2_tuner vt;
-       int stat;
-
-       memset(&vt,0,sizeof(vt));
-       stat = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
-       if (stat < 0) return stat;
-
-       ctxt->hdw->flag_stereo = (vt.audmode & V4L2_TUNER_MODE_STEREO) != 0;
-       ctxt->hdw->flag_bilingual =
-               (vt.audmode & V4L2_TUNER_MODE_LANG2) != 0;
-       return 0;
-}
-
-
 static void pvr2_msp3400_detach(struct pvr2_msp3400_handler *ctxt)
 {
        ctxt->client->handler = NULL;
-       ctxt->hdw->audio_stat = NULL;
        kfree(ctxt);
 }
 
@@ -169,24 +140,17 @@ static const struct pvr2_i2c_handler_functions msp3400_funcs = {
 int pvr2_i2c_msp3400_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
 {
        struct pvr2_msp3400_handler *ctxt;
-       if (hdw->audio_stat) return 0;
        if (cp->handler) return 0;
 
-       ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+       ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
        if (!ctxt) return 0;
-       memset(ctxt,0,sizeof(*ctxt));
 
        ctxt->i2c_handler.func_data = ctxt;
        ctxt->i2c_handler.func_table = &msp3400_funcs;
        ctxt->client = cp;
        ctxt->hdw = hdw;
-       ctxt->astat.ctxt = ctxt;
-       ctxt->astat.status = (int (*)(void *))get_audio_status;
-       ctxt->astat.detach = (void (*)(void *))pvr2_msp3400_detach;
-       ctxt->stale_mask = (1 << (sizeof(msp3400_ops)/
-                                 sizeof(msp3400_ops[0]))) - 1;
+       ctxt->stale_mask = (1 << ARRAY_SIZE(msp3400_ops)) - 1;
        cp->handler = &ctxt->i2c_handler;
-       hdw->audio_stat = &ctxt->astat;
        pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x msp3400 V4L2 handler set up",
                   cp->client->addr);
        return !0;
index cf12974..6bbed88 100644 (file)
@@ -83,9 +83,8 @@ struct pvr2_context *pvr2_context_create(
        void (*setup_func)(struct pvr2_context *))
 {
        struct pvr2_context *mp = NULL;
-       mp = kmalloc(sizeof(*mp),GFP_KERNEL);
+       mp = kzalloc(sizeof(*mp),GFP_KERNEL);
        if (!mp) goto done;
-       memset(mp,0,sizeof(*mp));
        pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_main id=%p",mp);
        mp->setup_func = setup_func;
        mutex_init(&mp->mutex);
index c77de85..f569b00 100644 (file)
 #include <linux/mutex.h>
 
 
+static int pvr2_ctrl_range_check(struct pvr2_ctrl *cptr,int val)
+{
+       if (cptr->info->check_value) {
+               if (!cptr->info->check_value(cptr,val)) return -ERANGE;
+       } else {
+               int lim;
+               lim = cptr->info->def.type_int.min_value;
+               if (cptr->info->get_min_value) {
+                       cptr->info->get_min_value(cptr,&lim);
+               }
+               if (val < lim) return -ERANGE;
+               lim = cptr->info->def.type_int.max_value;
+               if (cptr->info->get_max_value) {
+                       cptr->info->get_max_value(cptr,&lim);
+               }
+               if (val > lim) return -ERANGE;
+       }
+       return 0;
+}
+
+
 /* Set the given control. */
 int pvr2_ctrl_set_value(struct pvr2_ctrl *cptr,int val)
 {
@@ -43,17 +64,8 @@ int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val)
                        if (cptr->info->type == pvr2_ctl_bitmask) {
                                mask &= cptr->info->def.type_bitmask.valid_bits;
                        } else if (cptr->info->type == pvr2_ctl_int) {
-                               int lim;
-                               lim = cptr->info->def.type_int.min_value;
-                               if (cptr->info->get_min_value) {
-                                       cptr->info->get_min_value(cptr,&lim);
-                               }
-                               if (val < lim) break;
-                               lim = cptr->info->def.type_int.max_value;
-                               if (cptr->info->get_max_value) {
-                                       cptr->info->get_max_value(cptr,&lim);
-                               }
-                               if (val > lim) break;
+                               ret = pvr2_ctrl_range_check(cptr,val);
+                               if (ret < 0) break;
                        } else if (cptr->info->type == pvr2_ctl_enum) {
                                if (val >= cptr->info->def.type_enum.count) {
                                        break;
@@ -498,16 +510,13 @@ int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
        LOCK_TAKE(cptr->hdw->big_lock); do {
                if (cptr->info->type == pvr2_ctl_int) {
                        ret = parse_token(ptr,len,valptr,NULL,0);
-                       if ((ret >= 0) &&
-                           ((*valptr < cptr->info->def.type_int.min_value) ||
-                            (*valptr > cptr->info->def.type_int.max_value))) {
-                               ret = -ERANGE;
+                       if (ret >= 0) {
+                               ret = pvr2_ctrl_range_check(cptr,*valptr);
                        }
                        if (maskptr) *maskptr = ~0;
                } else if (cptr->info->type == pvr2_ctl_bool) {
-                       ret = parse_token(
-                               ptr,len,valptr,boolNames,
-                               sizeof(boolNames)/sizeof(boolNames[0]));
+                       ret = parse_token(ptr,len,valptr,boolNames,
+                                         ARRAY_SIZE(boolNames));
                        if (ret == 1) {
                                *valptr = *valptr ? !0 : 0;
                        } else if (ret == 0) {
index 8df969c..e8a9252 100644 (file)
@@ -63,6 +63,7 @@ static void set_input(struct pvr2_v4l_cx2584x *ctxt)
                vid_input = CX25840_COMPOSITE7;
                aud_input = CX25840_AUDIO8;
                break;
+       case PVR2_CVAL_INPUT_RADIO: // Treat same as composite
        case PVR2_CVAL_INPUT_COMPOSITE:
                vid_input = CX25840_COMPOSITE3;
                aud_input = CX25840_AUDIO_SERIAL;
@@ -71,7 +72,6 @@ static void set_input(struct pvr2_v4l_cx2584x *ctxt)
                vid_input = CX25840_SVIDEO1;
                aud_input = CX25840_AUDIO_SERIAL;
                break;
-       case PVR2_CVAL_INPUT_RADIO:
        default:
                // Just set it to be composite input for now...
                vid_input = CX25840_COMPOSITE3;
@@ -150,8 +150,7 @@ static int decoder_check(struct pvr2_v4l_cx2584x *ctxt)
        unsigned long msk;
        unsigned int idx;
 
-       for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
-            idx++) {
+       for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
                msk = 1 << idx;
                if (ctxt->stale_mask & msk) continue;
                if (decoder_ops[idx].check(ctxt)) {
@@ -167,8 +166,7 @@ static void decoder_update(struct pvr2_v4l_cx2584x *ctxt)
        unsigned long msk;
        unsigned int idx;
 
-       for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
-            idx++) {
+       for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
                msk = 1 << idx;
                if (!(ctxt->stale_mask & msk)) continue;
                ctxt->stale_mask &= ~msk;
@@ -199,18 +197,6 @@ static int decoder_detect(struct pvr2_i2c_client *cp)
 }
 
 
-static int decoder_is_tuned(struct pvr2_v4l_cx2584x *ctxt)
-{
-       struct v4l2_tuner vt;
-       int ret;
-
-       memset(&vt,0,sizeof(vt));
-       ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
-       if (ret < 0) return -EINVAL;
-       return vt.signal ? 1 : 0;
-}
-
-
 static unsigned int decoder_describe(struct pvr2_v4l_cx2584x *ctxt,
                                     char *buf,unsigned int cnt)
 {
@@ -243,21 +229,18 @@ int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
        if (cp->handler) return 0;
        if (!decoder_detect(cp)) return 0;
 
-       ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+       ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
        if (!ctxt) return 0;
-       memset(ctxt,0,sizeof(*ctxt));
 
        ctxt->handler.func_data = ctxt;
        ctxt->handler.func_table = &hfuncs;
        ctxt->ctrl.ctxt = ctxt;
        ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
        ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
-       ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned;
        ctxt->ctrl.force_reset = (void (*)(void*))decoder_reset;
        ctxt->client = cp;
        ctxt->hdw = hdw;
-       ctxt->stale_mask = (1 << (sizeof(decoder_ops)/
-                                 sizeof(decoder_ops[0]))) - 1;
+       ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
        hdw->decoder_ctrl = &ctxt->ctrl;
        cp->handler = &ctxt->handler;
        {
index f985f00..e9da9bb 100644 (file)
@@ -152,7 +152,7 @@ static unsigned long debugifc_find_mask(const char *buf,unsigned int count)
 {
        struct debugifc_mask_item *mip;
        unsigned int idx;
-       for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
+       for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
                mip = mask_items + idx;
                if (debugifc_match_keyword(buf,count,mip->name)) {
                        return mip->msk;
@@ -169,7 +169,7 @@ static int debugifc_print_mask(char *buf,unsigned int sz,
        unsigned int idx;
        int bcnt = 0;
        int ccnt;
-       for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
+       for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
                mip = mask_items + idx;
                if (!(mip->msk & msk)) continue;
                ccnt = scnprintf(buf,sz,"%s%c%s",
index 6cff8e7..45cbca0 100644 (file)
@@ -102,9 +102,8 @@ static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw)
                }
                msg[1].len = pcnt;
                msg[1].buf = eeprom+tcnt;
-               if ((ret = i2c_transfer(
-                            &hdw->i2c_adap,
-                            msg,sizeof(msg)/sizeof(msg[0]))) != 2) {
+               if ((ret = i2c_transfer(&hdw->i2c_adap,
+                                       msg,ARRAY_SIZE(msg))) != 2) {
                        pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                                   "eeprom fetch set offs err=%d",ret);
                        kfree(eeprom);
index c94f97b..5786faf 100644 (file)
@@ -26,6 +26,7 @@
 #include "pvrusb2-encoder.h"
 #include "pvrusb2-hdw-internal.h"
 #include "pvrusb2-debug.h"
+#include "pvrusb2-fx2-cmd.h"
 
 
 
 #define IVTV_MBOX_DRIVER_DONE 0x00000002
 #define IVTV_MBOX_DRIVER_BUSY 0x00000001
 
+#define MBOX_BASE 0x44
+
 
 static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
+                                   unsigned int offs,
                                    const u32 *data, unsigned int dlen)
 {
-       unsigned int idx;
+       unsigned int idx,addr;
+       unsigned int bAddr;
        int ret;
-       unsigned int offs = 0;
        unsigned int chunkCnt;
 
        /*
 
        Format: First byte must be 0x01.  Remaining 32 bit words are
-       spread out into chunks of 7 bytes each, little-endian ordered,
-       offset at zero within each 2 blank bytes following and a
-       single byte that is 0x44 plus the offset of the word.  Repeat
-       request for additional words, with offset adjusted
-       accordingly.
+       spread out into chunks of 7 bytes each, with the first 4 bytes
+       being the data word (little endian), and the next 3 bytes
+       being the address where that data word is to be written (big
+       endian).  Repeat request for additional words, with offset
+       adjusted accordingly.
 
        */
        while (dlen) {
                chunkCnt = 8;
                if (chunkCnt > dlen) chunkCnt = dlen;
                memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
-               hdw->cmd_buffer[0] = 0x01;
+               bAddr = 0;
+               hdw->cmd_buffer[bAddr++] = FX2CMD_MEM_WRITE_DWORD;
                for (idx = 0; idx < chunkCnt; idx++) {
-                       hdw->cmd_buffer[1+(idx*7)+6] = 0x44 + idx + offs;
-                       PVR2_DECOMPOSE_LE(hdw->cmd_buffer, 1+(idx*7),
-                                         data[idx]);
+                       addr = idx + offs;
+                       hdw->cmd_buffer[bAddr+6] = (addr & 0xffu);
+                       hdw->cmd_buffer[bAddr+5] = ((addr>>8) & 0xffu);
+                       hdw->cmd_buffer[bAddr+4] = ((addr>>16) & 0xffu);
+                       PVR2_DECOMPOSE_LE(hdw->cmd_buffer, bAddr,data[idx]);
+                       bAddr += 7;
                }
                ret = pvr2_send_request(hdw,
                                        hdw->cmd_buffer,1+(chunkCnt*7),
@@ -76,33 +84,42 @@ static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
 }
 
 
-static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,int statusFl,
+static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,
+                                  unsigned int offs,
                                   u32 *data, unsigned int dlen)
 {
        unsigned int idx;
        int ret;
-       unsigned int offs = 0;
        unsigned int chunkCnt;
 
        /*
 
        Format: First byte must be 0x02 (status check) or 0x28 (read
        back block of 32 bit words).  Next 6 bytes must be zero,
-       followed by a single byte of 0x44+offset for portion to be
-       read.  Returned data is packed set of 32 bits words that were
-       read.
+       followed by a single byte of MBOX_BASE+offset for portion to
+       be read.  Returned data is packed set of 32 bits words that
+       were read.
 
        */
 
        while (dlen) {
                chunkCnt = 16;
                if (chunkCnt > dlen) chunkCnt = dlen;
-               memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
-               hdw->cmd_buffer[0] = statusFl ? 0x02 : 0x28;
-               hdw->cmd_buffer[7] = 0x44 + offs;
+               if (chunkCnt < 16) chunkCnt = 1;
+               hdw->cmd_buffer[0] =
+                       ((chunkCnt == 1) ?
+                        FX2CMD_MEM_READ_DWORD : FX2CMD_MEM_READ_64BYTES);
+               hdw->cmd_buffer[1] = 0;
+               hdw->cmd_buffer[2] = 0;
+               hdw->cmd_buffer[3] = 0;
+               hdw->cmd_buffer[4] = 0;
+               hdw->cmd_buffer[5] = ((offs>>16) & 0xffu);
+               hdw->cmd_buffer[6] = ((offs>>8) & 0xffu);
+               hdw->cmd_buffer[7] = (offs & 0xffu);
                ret = pvr2_send_request(hdw,
                                        hdw->cmd_buffer,8,
-                                       hdw->cmd_buffer,chunkCnt * 4);
+                                       hdw->cmd_buffer,
+                                       (chunkCnt == 1 ? 4 : 16 * 4));
                if (ret) return ret;
 
                for (idx = 0; idx < chunkCnt; idx++) {
@@ -129,6 +146,8 @@ static int pvr2_encoder_cmd(void *ctxt,
                            u32 *argp)
 {
        unsigned int poll_count;
+       unsigned int try_count = 0;
+       int retry_flag;
        int ret = 0;
        unsigned int idx;
        /* These sizes look to be limited by the FX2 firmware implementation */
@@ -140,14 +159,15 @@ static int pvr2_encoder_cmd(void *ctxt,
        /*
 
        The encoder seems to speak entirely using blocks 32 bit words.
-       In ivtv driver terms, this is a mailbox which we populate with
-       data and watch what the hardware does with it.  The first word
-       is a set of flags used to control the transaction, the second
-       word is the command to execute, the third byte is zero (ivtv
-       driver suggests that this is some kind of return value), and
-       the fourth byte is a specified timeout (windows driver always
-       uses 0x00060000 except for one case when it is zero).  All
-       successive words are the argument words for the command.
+       In ivtv driver terms, this is a mailbox at MBOX_BASE which we
+       populate with data and watch what the hardware does with it.
+       The first word is a set of flags used to control the
+       transaction, the second word is the command to execute, the
+       third byte is zero (ivtv driver suggests that this is some
+       kind of return value), and the fourth byte is a specified
+       timeout (windows driver always uses 0x00060000 except for one
+       case when it is zero).  All successive words are the argument
+       words for the command.
 
        First, write out the entire set of words, with the first word
        being zero.
@@ -156,44 +176,42 @@ static int pvr2_encoder_cmd(void *ctxt,
        IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which
        probably means "go").
 
-       Next, read back 16 words as status.  Check the first word,
+       Next, read back the return count words.  Check the first word,
        which should have IVTV_MBOX_FIRMWARE_DONE set.  If however
        that bit is not set, then the command isn't done so repeat the
-       read.
-
-       Next, read back 32 words and compare with the original
-       arugments.  Hopefully they will match.
+       read until it is set.
 
        Finally, write out just the first word again, but set it to
        0x0 this time (which probably means "idle").
 
        */
 
-       if (arg_cnt_send > (sizeof(wrData)/sizeof(wrData[0]))-4) {
+       if (arg_cnt_send > (ARRAY_SIZE(wrData) - 4)) {
                pvr2_trace(
                        PVR2_TRACE_ERROR_LEGS,
                        "Failed to write cx23416 command"
                        " - too many input arguments"
-                       " (was given %u limit %u)",
-                       arg_cnt_send,
-                       (unsigned int)(sizeof(wrData)/sizeof(wrData[0])) - 4);
+                       " (was given %u limit %lu)",
+                       arg_cnt_send, (long unsigned) ARRAY_SIZE(wrData) - 4);
                return -EINVAL;
        }
 
-       if (arg_cnt_recv > (sizeof(rdData)/sizeof(rdData[0]))-4) {
+       if (arg_cnt_recv > (ARRAY_SIZE(rdData) - 4)) {
                pvr2_trace(
                        PVR2_TRACE_ERROR_LEGS,
                        "Failed to write cx23416 command"
                        " - too many return arguments"
-                       " (was given %u limit %u)",
-                       arg_cnt_recv,
-                       (unsigned int)(sizeof(rdData)/sizeof(rdData[0])) - 4);
+                       " (was given %u limit %lu)",
+                       arg_cnt_recv, (long unsigned) ARRAY_SIZE(rdData) - 4);
                return -EINVAL;
        }
 
 
        LOCK_TAKE(hdw->ctl_lock); do {
 
+               retry_flag = 0;
+               try_count++;
+               ret = 0;
                wrData[0] = 0;
                wrData[1] = cmd;
                wrData[2] = 0;
@@ -201,59 +219,74 @@ static int pvr2_encoder_cmd(void *ctxt,
                for (idx = 0; idx < arg_cnt_send; idx++) {
                        wrData[idx+4] = argp[idx];
                }
-               for (; idx < (sizeof(wrData)/sizeof(wrData[0]))-4; idx++) {
+               for (; idx < ARRAY_SIZE(wrData) - 4; idx++) {
                        wrData[idx+4] = 0;
                }
 
-               ret = pvr2_encoder_write_words(hdw,wrData,idx);
+               ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,idx);
                if (ret) break;
                wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY;
-               ret = pvr2_encoder_write_words(hdw,wrData,1);
+               ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,1);
                if (ret) break;
                poll_count = 0;
                while (1) {
-                       if (poll_count < 10000000) poll_count++;
-                       ret = pvr2_encoder_read_words(hdw,!0,rdData,1);
-                       if (ret) break;
+                       poll_count++;
+                       ret = pvr2_encoder_read_words(hdw,MBOX_BASE,rdData,
+                                                     arg_cnt_recv+4);
+                       if (ret) {
+                               break;
+                       }
                        if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) {
                                break;
                        }
-                       if (poll_count == 100) {
+                       if (rdData[0] && (poll_count < 1000)) continue;
+                       if (!rdData[0]) {
+                               retry_flag = !0;
                                pvr2_trace(
                                        PVR2_TRACE_ERROR_LEGS,
-                                       "***WARNING*** device's encoder"
-                                       " appears to be stuck"
-                                       " (status=0%08x)",rdData[0]);
+                                       "Encoder timed out waiting for us"
+                                       "; arranging to retry");
+                       } else {
                                pvr2_trace(
                                        PVR2_TRACE_ERROR_LEGS,
-                                       "Encoder command: 0x%02x",cmd);
-                               for (idx = 4; idx < arg_cnt_send; idx++) {
-                                       pvr2_trace(
-                                               PVR2_TRACE_ERROR_LEGS,
-                                               "Encoder arg%d: 0x%08x",
-                                               idx-3,wrData[idx]);
-                               }
+                                       "***WARNING*** device's encoder"
+                                       " appears to be stuck"
+                                       " (status=0x%08x)",rdData[0]);
+                       }
+                       pvr2_trace(
+                               PVR2_TRACE_ERROR_LEGS,
+                               "Encoder command: 0x%02x",cmd);
+                       for (idx = 4; idx < arg_cnt_send; idx++) {
                                pvr2_trace(
                                        PVR2_TRACE_ERROR_LEGS,
-                                       "Giving up waiting."
-                                       "  It is likely that"
-                                       " this is a bad idea...");
-                               ret = -EBUSY;
-                               break;
+                                       "Encoder arg%d: 0x%08x",
+                                       idx-3,wrData[idx]);
                        }
+                       ret = -EBUSY;
+                       break;
+               }
+               if (retry_flag) {
+                       if (try_count < 20) continue;
+                       pvr2_trace(
+                               PVR2_TRACE_ERROR_LEGS,
+                               "Too many retries...");
+                       ret = -EBUSY;
+               }
+               if (ret) {
+                       pvr2_trace(
+                               PVR2_TRACE_ERROR_LEGS,
+                               "Giving up on command."
+                               "  It is likely that"
+                               " this is a bad idea...");
+                       break;
                }
-               if (ret) break;
                wrData[0] = 0x7;
-               ret = pvr2_encoder_read_words(
-                       hdw,0,rdData,
-                       sizeof(rdData)/sizeof(rdData[0]));
-               if (ret) break;
                for (idx = 0; idx < arg_cnt_recv; idx++) {
                        argp[idx] = rdData[idx+4];
                }
 
                wrData[0] = 0x0;
-               ret = pvr2_encoder_write_words(hdw,wrData,1);
+               ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,1);
                if (ret) break;
 
        } while(0); LOCK_GIVE(hdw->ctl_lock);
@@ -269,13 +302,13 @@ static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
        unsigned int idx;
        u32 data[12];
 
-       if (args > sizeof(data)/sizeof(data[0])) {
+       if (args > ARRAY_SIZE(data)) {
                pvr2_trace(
                        PVR2_TRACE_ERROR_LEGS,
                        "Failed to write cx23416 command"
                        " - too many arguments"
-                       " (was given %u limit %u)",
-                       args,(unsigned int)(sizeof(data)/sizeof(data[0])));
+                       " (was given %u limit %lu)",
+                       args, (long unsigned) ARRAY_SIZE(data));
                return -EINVAL;
        }
 
@@ -288,6 +321,73 @@ static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
        return pvr2_encoder_cmd(hdw,cmd,args,0,data);
 }
 
+
+/* This implements some extra setup for the encoder that seems to be
+   specific to the PVR USB2 hardware. */
+int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
+{
+       int ret = 0;
+       int encMisc3Arg = 0;
+
+#if 0
+       /* This inexplicable bit happens in the Hauppage windows
+          driver (for both 24xxx and 29xxx devices).  However I
+          currently see no difference in behavior with or without
+          this stuff.  Leave this here as a note of its existence,
+          but don't use it. */
+       LOCK_TAKE(hdw->ctl_lock); do {
+               u32 dat[1];
+               dat[0] = 0x80000640;
+               pvr2_encoder_write_words(hdw,0x01fe,dat,1);
+               pvr2_encoder_write_words(hdw,0x023e,dat,1);
+       } while(0); LOCK_GIVE(hdw->ctl_lock);
+#endif
+
+       /* Mike Isely <isely@pobox.com> 26-Jan-2006 The windows driver
+          sends the following list of ENC_MISC commands (for both
+          24xxx and 29xxx devices).  Meanings are not entirely clear,
+          however without the ENC_MISC(3,1) command then we risk
+          random perpetual video corruption whenever the video input
+          breaks up for a moment (like when switching channels). */
+
+
+#if 0
+       /* This ENC_MISC(5,0) command seems to hurt 29xxx sync
+          performance on channel changes, but is not a problem on
+          24xxx devices. */
+       ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 5,0,0,0);
+#endif
+
+       /* This ENC_MISC(3,encMisc3Arg) command is critical - without
+          it there will eventually be video corruption.  Also, the
+          29xxx case is strange - the Windows driver is passing 1
+          regardless of device type but if we have 1 for 29xxx device
+          the video turns sluggish.  */
+       switch (hdw->hdw_type) {
+       case PVR2_HDW_TYPE_24XXX: encMisc3Arg = 1; break;
+       case PVR2_HDW_TYPE_29XXX: encMisc3Arg = 0; break;
+       default: break;
+       }
+       ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3,
+                                encMisc3Arg,0,0);
+
+       ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 8,0,0,0);
+
+#if 0
+       /* This ENC_MISC(4,1) command is poisonous, so it is commented
+          out.  But I'm leaving it here anyway to document its
+          existence in the Windows driver.  The effect of this
+          command is that apps displaying the stream become sluggish
+          with stuttering video. */
+       ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 4,1,0,0);
+#endif
+
+       ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 0,3,0,0);
+       ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4,15,0,0,0);
+
+       return ret;
+}
+
 int pvr2_encoder_configure(struct pvr2_hdw *hdw)
 {
        int ret;
@@ -302,6 +402,8 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
 
        ret = 0;
 
+       ret |= pvr2_encoder_prep_config(hdw);
+
        if (!ret) ret = pvr2_encoder_vcmd(
                hdw,CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,
                0xf0, 0xf0);
@@ -360,15 +462,22 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw)
        pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000481);
        pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
 
-       if (hdw->config == pvr2_config_vbi) {
+       pvr2_encoder_vcmd(hdw,CX2341X_ENC_MUTE_VIDEO,1,
+                         hdw->input_val == PVR2_CVAL_INPUT_RADIO ? 1 : 0);
+
+       switch (hdw->config) {
+       case pvr2_config_vbi:
                status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
                                           0x01,0x14);
-       } else if (hdw->config == pvr2_config_mpeg) {
+               break;
+       case pvr2_config_mpeg:
                status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
                                           0,0x13);
-       } else {
+               break;
+       default: /* Unhandled cases for now */
                status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
                                           0,0x13);
+               break;
        }
        if (!status) {
                hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
@@ -383,15 +492,19 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw)
        /* mask all interrupts */
        pvr2_write_register(hdw, 0x0048, 0xffffffff);
 
-       if (hdw->config == pvr2_config_vbi) {
+       switch (hdw->config) {
+       case pvr2_config_vbi:
                status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
                                           0x01,0x01,0x14);
-       } else if (hdw->config == pvr2_config_mpeg) {
+               break;
+       case pvr2_config_mpeg:
                status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
                                           0x01,0,0x13);
-       } else {
+               break;
+       default: /* Unhandled cases for now */
                status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
                                           0x01,0,0x13);
+               break;
        }
 
        /* change some GPIO data */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h b/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
new file mode 100644 (file)
index 0000000..ffbc6d0
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2007 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You 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 _PVRUSB2_FX2_CMD_H_
+#define _PVRUSB2_FX2_CMD_H_
+
+#define FX2CMD_MEM_WRITE_DWORD  0x01
+#define FX2CMD_MEM_READ_DWORD   0x02
+
+#define FX2CMD_MEM_READ_64BYTES 0x28
+
+#define FX2CMD_REG_WRITE        0x04
+#define FX2CMD_REG_READ         0x05
+#define FX2CMD_MEMSEL           0x06
+
+#define FX2CMD_I2C_WRITE        0x08
+#define FX2CMD_I2C_READ         0x09
+
+#define FX2CMD_GET_USB_SPEED    0x0b
+
+#define FX2CMD_STREAMING_ON     0x36
+#define FX2CMD_STREAMING_OFF    0x37
+
+#define FX2CMD_FWPOST1          0x52
+
+#define FX2CMD_POWER_OFF        0xdc
+#define FX2CMD_POWER_ON         0xde
+
+#define FX2CMD_DEEP_RESET       0xdd
+
+#define FX2CMD_GET_EEPROM_ADDR  0xeb
+#define FX2CMD_GET_IR_CODE      0xec
+
+#endif /* _PVRUSB2_FX2_CMD_H_ */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
index 34b08fb..16bd741 100644 (file)
@@ -60,6 +60,7 @@ struct pvr2_decoder;
 
 typedef int (*pvr2_ctlf_is_dirty)(struct pvr2_ctrl *);
 typedef void (*pvr2_ctlf_clear_dirty)(struct pvr2_ctrl *);
+typedef int (*pvr2_ctlf_check_value)(struct pvr2_ctrl *,int);
 typedef int (*pvr2_ctlf_get_value)(struct pvr2_ctrl *,int *);
 typedef int (*pvr2_ctlf_set_value)(struct pvr2_ctrl *,int msk,int val);
 typedef int (*pvr2_ctlf_val_to_sym)(struct pvr2_ctrl *,int msk,int val,
@@ -83,6 +84,7 @@ struct pvr2_ctl_info {
        pvr2_ctlf_get_value get_min_value;  /* Get minimum allowed value */
        pvr2_ctlf_get_value get_max_value;  /* Get maximum allowed value */
        pvr2_ctlf_set_value set_value;      /* Set its value */
+       pvr2_ctlf_check_value check_value;  /* Check that value is valid */
        pvr2_ctlf_val_to_sym val_to_sym;    /* Custom convert value->symbol */
        pvr2_ctlf_sym_to_val sym_to_val;    /* Custom convert symbol->value */
        pvr2_ctlf_is_dirty is_dirty;        /* Return true if dirty */
@@ -135,17 +137,10 @@ struct pvr2_ctrl {
 };
 
 
-struct pvr2_audio_stat {
-       void *ctxt;
-       void (*detach)(void *);
-       int (*status)(void *);
-};
-
 struct pvr2_decoder_ctrl {
        void *ctxt;
        void (*detach)(void *);
        void (*enable)(void *,int);
-       int (*tuned)(void *);
        void (*force_reset)(void *);
 };
 
@@ -212,7 +207,6 @@ struct pvr2_hdw {
        /* Frequency table */
        unsigned int freqTable[FREQTABLE_SIZE];
        unsigned int freqProgSlot;
-       unsigned int freqSlot;
 
        /* Stuff for handling low level control interaction with device */
        struct mutex ctl_lock_mutex;
@@ -258,9 +252,17 @@ struct pvr2_hdw {
        /* Tuner / frequency control stuff */
        unsigned int tuner_type;
        int tuner_updated;
-       unsigned int freqVal;
+       unsigned int freqValTelevision;  /* Current freq for tv mode */
+       unsigned int freqValRadio;       /* Current freq for radio mode */
+       unsigned int freqSlotTelevision; /* Current slot for tv mode */
+       unsigned int freqSlotRadio;      /* Current slot for radio mode */
+       unsigned int freqSelector;       /* 0=radio 1=television */
        int freqDirty;
 
+       /* Current tuner info - this information is polled from the I2C bus */
+       struct v4l2_tuner tuner_signal_info;
+       int tuner_signal_stale;
+
        /* Video standard handling */
        v4l2_std_id std_mask_eeprom; // Hardware supported selections
        v4l2_std_id std_mask_avail;  // Which standards we may select from
@@ -281,20 +283,17 @@ struct pvr2_hdw {
        int unit_number;             /* ID for driver instance */
        unsigned long serial_number; /* ID for hardware itself */
 
-       /* Minor number used by v4l logic (yes, this is a hack, as there should
-          be no v4l junk here).  Probably a better way to do this. */
-       int v4l_minor_number;
+       /* Minor numbers used by v4l logic (yes, this is a hack, as there
+          should be no v4l junk here).  Probably a better way to do this. */
+       int v4l_minor_number_video;
+       int v4l_minor_number_vbi;
+       int v4l_minor_number_radio;
 
        /* Location of eeprom or a negative number if none */
        int eeprom_addr;
 
        enum pvr2_config config;
 
-       /* Information about what audio signal we're hearing */
-       int flag_stereo;
-       int flag_bilingual;
-       struct pvr2_audio_stat *audio_stat;
-
        /* Control state needed for cx2341x module */
        struct cx2341x_mpeg_params enc_cur_state;
        struct cx2341x_mpeg_params enc_ctl_state;
@@ -327,6 +326,9 @@ struct pvr2_hdw {
        unsigned int control_cnt;
 };
 
+/* This function gets the current frequency */
+unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *);
+
 #endif /* __PVRUSB2_HDW_INTERNAL_H */
 
 /*
index d200496..a1ca0f5 100644 (file)
 #include "pvrusb2-hdw-internal.h"
 #include "pvrusb2-encoder.h"
 #include "pvrusb2-debug.h"
+#include "pvrusb2-fx2-cmd.h"
+
+#define TV_MIN_FREQ     55250000L
+#define TV_MAX_FREQ    850000000L
 
 struct usb_device_id pvr2_device_table[] = {
        [PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) },
@@ -71,12 +75,10 @@ static const char *pvr2_client_29xxx[] = {
 
 static struct pvr2_string_table pvr2_client_lists[] = {
        [PVR2_HDW_TYPE_29XXX] = {
-               pvr2_client_29xxx,
-               sizeof(pvr2_client_29xxx)/sizeof(pvr2_client_29xxx[0]),
+               pvr2_client_29xxx, ARRAY_SIZE(pvr2_client_29xxx)
        },
        [PVR2_HDW_TYPE_24XXX] = {
-               pvr2_client_24xxx,
-               sizeof(pvr2_client_24xxx)/sizeof(pvr2_client_24xxx[0]),
+               pvr2_client_24xxx, ARRAY_SIZE(pvr2_client_24xxx)
        },
 };
 
@@ -160,9 +162,6 @@ static const struct pvr2_mpeg_ids mpeg_ids[] = {
                .strid = "video_gop_closure",
                .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
        },{
-               .strid = "video_pulldown",
-               .id = V4L2_CID_MPEG_VIDEO_PULLDOWN,
-       },{
                .strid = "video_bitrate_mode",
                .id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
        },{
@@ -212,7 +211,7 @@ static const struct pvr2_mpeg_ids mpeg_ids[] = {
                .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
        }
 };
-#define MPEGDEF_COUNT (sizeof(mpeg_ids)/sizeof(mpeg_ids[0]))
+#define MPEGDEF_COUNT ARRAY_SIZE(mpeg_ids)
 
 
 static const char *control_values_srate[] = {
@@ -255,10 +254,10 @@ static const char *control_values_subsystem[] = {
        [PVR2_SUBSYS_B_ENC_RUN] = "enc_run",
 };
 
+static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
 static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
 static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw);
 static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw);
-static unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw);
 static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
 static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
 static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw);
@@ -272,8 +271,6 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
                                unsigned int timeout,int probe_fl,
                                void *write_data,unsigned int write_len,
                                void *read_data,unsigned int read_len);
-static int pvr2_write_u16(struct pvr2_hdw *hdw, u16 data, int res);
-static int pvr2_write_u8(struct pvr2_hdw *hdw, u8 data, int res);
 
 static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
 {
@@ -289,8 +286,21 @@ static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
 static int ctrl_channelfreq_set(struct pvr2_ctrl *cptr,int m,int v)
 {
        struct pvr2_hdw *hdw = cptr->hdw;
-       if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) {
-               hdw->freqTable[hdw->freqProgSlot-1] = v;
+       unsigned int slotId = hdw->freqProgSlot;
+       if ((slotId > 0) && (slotId <= FREQTABLE_SIZE)) {
+               hdw->freqTable[slotId-1] = v;
+               /* Handle side effects correctly - if we're tuned to this
+                  slot, then forgot the slot id relation since the stored
+                  frequency has been changed. */
+               if (hdw->freqSelector) {
+                       if (hdw->freqSlotRadio == slotId) {
+                               hdw->freqSlotRadio = 0;
+                       }
+               } else {
+                       if (hdw->freqSlotTelevision == slotId) {
+                               hdw->freqSlotTelevision = 0;
+                       }
+               }
        }
        return 0;
 }
@@ -312,28 +322,32 @@ static int ctrl_channelprog_set(struct pvr2_ctrl *cptr,int m,int v)
 
 static int ctrl_channel_get(struct pvr2_ctrl *cptr,int *vp)
 {
-       *vp = cptr->hdw->freqSlot;
+       struct pvr2_hdw *hdw = cptr->hdw;
+       *vp = hdw->freqSelector ? hdw->freqSlotRadio : hdw->freqSlotTelevision;
        return 0;
 }
 
-static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int v)
+static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int slotId)
 {
        unsigned freq = 0;
        struct pvr2_hdw *hdw = cptr->hdw;
-       hdw->freqSlot = v;
-       if ((hdw->freqSlot > 0) && (hdw->freqSlot <= FREQTABLE_SIZE)) {
-               freq = hdw->freqTable[hdw->freqSlot-1];
-       }
-       if (freq && (freq != hdw->freqVal)) {
-               hdw->freqVal = freq;
-               hdw->freqDirty = !0;
+       if ((slotId < 0) || (slotId > FREQTABLE_SIZE)) return 0;
+       if (slotId > 0) {
+               freq = hdw->freqTable[slotId-1];
+               if (!freq) return 0;
+               pvr2_hdw_set_cur_freq(hdw,freq);
+       }
+       if (hdw->freqSelector) {
+               hdw->freqSlotRadio = slotId;
+       } else {
+               hdw->freqSlotTelevision = slotId;
        }
        return 0;
 }
 
 static int ctrl_freq_get(struct pvr2_ctrl *cptr,int *vp)
 {
-       *vp = cptr->hdw->freqVal;
+       *vp = pvr2_hdw_get_cur_freq(cptr->hdw);
        return 0;
 }
 
@@ -349,10 +363,7 @@ static void ctrl_freq_clear_dirty(struct pvr2_ctrl *cptr)
 
 static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v)
 {
-       struct pvr2_hdw *hdw = cptr->hdw;
-       hdw->freqVal = v;
-       hdw->freqDirty = !0;
-       hdw->freqSlot = 0;
+       pvr2_hdw_set_cur_freq(cptr->hdw,v);
        return 0;
 }
 
@@ -378,6 +389,89 @@ static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp)
        return 0;
 }
 
+static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp)
+{
+       *vp = cptr->hdw->input_val;
+       return 0;
+}
+
+static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v)
+{
+       struct pvr2_hdw *hdw = cptr->hdw;
+
+       if (hdw->input_val != v) {
+               hdw->input_val = v;
+               hdw->input_dirty = !0;
+       }
+
+       /* Handle side effects - if we switch to a mode that needs the RF
+          tuner, then select the right frequency choice as well and mark
+          it dirty. */
+       if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+               hdw->freqSelector = 0;
+               hdw->freqDirty = !0;
+       } else if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
+               hdw->freqSelector = 1;
+               hdw->freqDirty = !0;
+       }
+       return 0;
+}
+
+static int ctrl_isdirty_input(struct pvr2_ctrl *cptr)
+{
+       return cptr->hdw->input_dirty != 0;
+}
+
+static void ctrl_cleardirty_input(struct pvr2_ctrl *cptr)
+{
+       cptr->hdw->input_dirty = 0;
+}
+
+
+static int ctrl_freq_max_get(struct pvr2_ctrl *cptr, int *vp)
+{
+       unsigned long fv;
+       struct pvr2_hdw *hdw = cptr->hdw;
+       if (hdw->tuner_signal_stale) {
+               pvr2_i2c_core_status_poll(hdw);
+       }
+       fv = hdw->tuner_signal_info.rangehigh;
+       if (!fv) {
+               /* Safety fallback */
+               *vp = TV_MAX_FREQ;
+               return 0;
+       }
+       if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+               fv = (fv * 125) / 2;
+       } else {
+               fv = fv * 62500;
+       }
+       *vp = fv;
+       return 0;
+}
+
+static int ctrl_freq_min_get(struct pvr2_ctrl *cptr, int *vp)
+{
+       unsigned long fv;
+       struct pvr2_hdw *hdw = cptr->hdw;
+       if (hdw->tuner_signal_stale) {
+               pvr2_i2c_core_status_poll(hdw);
+       }
+       fv = hdw->tuner_signal_info.rangelow;
+       if (!fv) {
+               /* Safety fallback */
+               *vp = TV_MIN_FREQ;
+               return 0;
+       }
+       if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+               fv = (fv * 125) / 2;
+       } else {
+               fv = fv * 62500;
+       }
+       *vp = fv;
+       return 0;
+}
+
 static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr)
 {
        return cptr->hdw->enc_stale != 0;
@@ -534,8 +628,32 @@ static void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr)
 
 static int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp)
 {
-       *vp = ((pvr2_hdw_get_signal_status_internal(cptr->hdw) &
-               PVR2_SIGNAL_OK) ? 1 : 0);
+       struct pvr2_hdw *hdw = cptr->hdw;
+       pvr2_i2c_core_status_poll(hdw);
+       *vp = hdw->tuner_signal_info.signal;
+       return 0;
+}
+
+static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       int val = 0;
+       unsigned int subchan;
+       struct pvr2_hdw *hdw = cptr->hdw;
+       pvr2_i2c_core_status_poll(hdw);
+       subchan = hdw->tuner_signal_info.rxsubchans;
+       if (subchan & V4L2_TUNER_SUB_MONO) {
+               val |= (1 << V4L2_TUNER_MODE_MONO);
+       }
+       if (subchan & V4L2_TUNER_SUB_STEREO) {
+               val |= (1 << V4L2_TUNER_MODE_STEREO);
+       }
+       if (subchan & V4L2_TUNER_SUB_LANG1) {
+               val |= (1 << V4L2_TUNER_MODE_LANG1);
+       }
+       if (subchan & V4L2_TUNER_SUB_LANG2) {
+               val |= (1 << V4L2_TUNER_MODE_LANG2);
+       }
+       *vp = val;
        return 0;
 }
 
@@ -604,7 +722,7 @@ static void ctrl_stdenumcur_clear_dirty(struct pvr2_ctrl *cptr)
 
 #define DEFENUM(tab) \
        .type = pvr2_ctl_enum, \
-       .def.type_enum.count = (sizeof(tab)/sizeof((tab)[0])), \
+       .def.type_enum.count = ARRAY_SIZE(tab), \
        .def.type_enum.value_names = tab
 
 #define DEFBOOL \
@@ -641,15 +759,11 @@ VCREATE_FUNCS(balance)
 VCREATE_FUNCS(bass)
 VCREATE_FUNCS(treble)
 VCREATE_FUNCS(mute)
-VCREATE_FUNCS(input)
 VCREATE_FUNCS(audiomode)
 VCREATE_FUNCS(res_hor)
 VCREATE_FUNCS(res_ver)
 VCREATE_FUNCS(srate)
 
-#define MIN_FREQ 55250000L
-#define MAX_FREQ 850000000L
-
 /* Table definition of all controls which can be manipulated */
 static const struct pvr2_ctl_info control_defs[] = {
        {
@@ -684,7 +798,7 @@ static const struct pvr2_ctl_info control_defs[] = {
                .v4l_id = V4L2_CID_AUDIO_VOLUME,
                .desc = "Volume",
                .name = "volume",
-               .default_value = 65535,
+               .default_value = 62000,
                DEFREF(volume),
                DEFINT(0,65535),
        },{
@@ -758,12 +872,16 @@ static const struct pvr2_ctl_info control_defs[] = {
                .desc = "Tuner Frequency (Hz)",
                .name = "frequency",
                .internal_id = PVR2_CID_FREQUENCY,
-               .default_value = 175250000L,
+               .default_value = 0,
                .set_value = ctrl_freq_set,
                .get_value = ctrl_freq_get,
                .is_dirty = ctrl_freq_is_dirty,
                .clear_dirty = ctrl_freq_clear_dirty,
-               DEFINT(MIN_FREQ,MAX_FREQ),
+               DEFINT(0,0),
+               /* Hook in check for input value (tv/radio) and adjust
+                  max/min values accordingly */
+               .get_max_value = ctrl_freq_max_get,
+               .get_min_value = ctrl_freq_min_get,
        },{
                .desc = "Channel",
                .name = "channel",
@@ -775,7 +893,11 @@ static const struct pvr2_ctl_info control_defs[] = {
                .name = "freq_table_value",
                .set_value = ctrl_channelfreq_set,
                .get_value = ctrl_channelfreq_get,
-               DEFINT(MIN_FREQ,MAX_FREQ),
+               DEFINT(0,0),
+               /* Hook in check for input value (tv/radio) and adjust
+                  max/min values accordingly */
+               .get_max_value = ctrl_freq_max_get,
+               .get_min_value = ctrl_freq_min_get,
        },{
                .desc = "Channel Program ID",
                .name = "freq_table_channel",
@@ -796,7 +918,20 @@ static const struct pvr2_ctl_info control_defs[] = {
                .desc = "Signal Present",
                .name = "signal_present",
                .get_value = ctrl_signal_get,
-               DEFBOOL,
+               DEFINT(0,65535),
+       },{
+               .desc = "Audio Modes Present",
+               .name = "audio_modes_present",
+               .get_value = ctrl_audio_modes_present_get,
+               /* For this type we "borrow" the V4L2_TUNER_MODE enum from
+                  v4l.  Nothing outside of this module cares about this,
+                  but I reuse it in order to also reuse the
+                  control_values_audiomode string table. */
+               DEFMASK(((1 << V4L2_TUNER_MODE_MONO)|
+                        (1 << V4L2_TUNER_MODE_STEREO)|
+                        (1 << V4L2_TUNER_MODE_LANG1)|
+                        (1 << V4L2_TUNER_MODE_LANG2)),
+                       control_values_audiomode),
        },{
                .desc = "Video Standards Available Mask",
                .name = "video_standard_mask_available",
@@ -846,7 +981,7 @@ static const struct pvr2_ctl_info control_defs[] = {
        }
 };
 
-#define CTRLDEF_COUNT (sizeof(control_defs)/sizeof(control_defs[0]))
+#define CTRLDEF_COUNT ARRAY_SIZE(control_defs)
 
 
 const char *pvr2_config_get_name(enum pvr2_config cfg)
@@ -855,7 +990,8 @@ const char *pvr2_config_get_name(enum pvr2_config cfg)
        case pvr2_config_empty: return "empty";
        case pvr2_config_mpeg: return "mpeg";
        case pvr2_config_vbi: return "vbi";
-       case pvr2_config_radio: return "radio";
+       case pvr2_config_pcm: return "pcm";
+       case pvr2_config_rawvideo: return "raw video";
        }
        return "<unknown>";
 }
@@ -872,6 +1008,40 @@ unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw)
        return hdw->serial_number;
 }
 
+unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw)
+{
+       return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio;
+}
+
+/* Set the currently tuned frequency and account for all possible
+   driver-core side effects of this action. */
+void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val)
+{
+       if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+               if (hdw->freqSelector) {
+                       /* Swing over to radio frequency selection */
+                       hdw->freqSelector = 0;
+                       hdw->freqDirty = !0;
+               }
+               if (hdw->freqValRadio != val) {
+                       hdw->freqValRadio = val;
+                       hdw->freqSlotRadio = 0;
+                       hdw->freqDirty = !0;
+               }
+       } else {
+               if (!(hdw->freqSelector)) {
+                       /* Swing over to television frequency selection */
+                       hdw->freqSelector = 1;
+                       hdw->freqDirty = !0;
+               }
+               if (hdw->freqValTelevision != val) {
+                       hdw->freqValTelevision = val;
+                       hdw->freqSlotTelevision = 0;
+                       hdw->freqDirty = !0;
+               }
+       }
+}
+
 int pvr2_hdw_get_unit_number(struct pvr2_hdw *hdw)
 {
        return hdw->unit_number;
@@ -960,12 +1130,10 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
        };
        static const struct pvr2_string_table fw_file_defs[] = {
                [PVR2_HDW_TYPE_29XXX] = {
-                       fw_files_29xxx,
-                       sizeof(fw_files_29xxx)/sizeof(fw_files_29xxx[0]),
+                       fw_files_29xxx, ARRAY_SIZE(fw_files_29xxx)
                },
                [PVR2_HDW_TYPE_24XXX] = {
-                       fw_files_24xxx,
-                       sizeof(fw_files_24xxx)/sizeof(fw_files_24xxx[0]),
+                       fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx)
                },
        };
        hdw->fw1_state = FW1_STATE_FAILED; // default result
@@ -1041,7 +1209,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
 {
        const struct firmware *fw_entry = NULL;
        void  *fw_ptr;
-       unsigned int pipe, fw_len, fw_done;
+       unsigned int pipe, fw_len, fw_done, bcnt, icnt;
        int actual_length;
        int ret = 0;
        int fwidx;
@@ -1052,8 +1220,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
        trace_firmware("pvr2_upload_firmware2");
 
        ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder",
-                                  sizeof(fw_files)/sizeof(fw_files[0]),
-                                  fw_files);
+                                  ARRAY_SIZE(fw_files), fw_files);
        if (ret < 0) return ret;
        fwidx = ret;
        ret = 0;
@@ -1079,8 +1246,13 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
        ret |= pvr2_write_register(hdw, 0xaa04, 0x00057810); /*unknown*/
        ret |= pvr2_write_register(hdw, 0xaa10, 0x00148500); /*unknown*/
        ret |= pvr2_write_register(hdw, 0xaa18, 0x00840000); /*unknown*/
-       ret |= pvr2_write_u8(hdw, 0x52, 0);
-       ret |= pvr2_write_u16(hdw, 0x0600, 0);
+       LOCK_TAKE(hdw->ctl_lock); do {
+               hdw->cmd_buffer[0] = FX2CMD_FWPOST1;
+               ret |= pvr2_send_request(hdw,hdw->cmd_buffer,1,0,0);
+               hdw->cmd_buffer[0] = FX2CMD_MEMSEL;
+               hdw->cmd_buffer[1] = 0;
+               ret |= pvr2_send_request(hdw,hdw->cmd_buffer,2,0,0);
+       } while (0); LOCK_GIVE(hdw->ctl_lock);
 
        if (ret) {
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
@@ -1093,11 +1265,11 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
 
        fw_len = fw_entry->size;
 
-       if (fw_len % FIRMWARE_CHUNK_SIZE) {
+       if (fw_len % sizeof(u32)) {
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                           "size of %s firmware"
-                          " must be a multiple of 8192B",
-                          fw_files[fwidx]);
+                          " must be a multiple of %u bytes",
+                          fw_files[fwidx],sizeof(u32));
                release_firmware(fw_entry);
                return -1;
        }
@@ -1112,18 +1284,21 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
 
        pipe = usb_sndbulkpipe(hdw->usb_dev, PVR2_FIRMWARE_ENDPOINT);
 
-       for (fw_done = 0 ; (fw_done < fw_len) && !ret ;
-            fw_done += FIRMWARE_CHUNK_SIZE ) {
-               int i;
-               memcpy(fw_ptr, fw_entry->data + fw_done, FIRMWARE_CHUNK_SIZE);
-               /* Usbsnoop log  shows that we must swap bytes... */
-               for (i = 0; i < FIRMWARE_CHUNK_SIZE/4 ; i++)
-                       ((u32 *)fw_ptr)[i] = ___swab32(((u32 *)fw_ptr)[i]);
-
-               ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,
-                                   FIRMWARE_CHUNK_SIZE,
+       fw_done = 0;
+       for (fw_done = 0; fw_done < fw_len;) {
+               bcnt = fw_len - fw_done;
+               if (bcnt > FIRMWARE_CHUNK_SIZE) bcnt = FIRMWARE_CHUNK_SIZE;
+               memcpy(fw_ptr, fw_entry->data + fw_done, bcnt);
+               /* Usbsnoop log shows that we must swap bytes... */
+               for (icnt = 0; icnt < bcnt/4 ; icnt++)
+                       ((u32 *)fw_ptr)[icnt] =
+                               ___swab32(((u32 *)fw_ptr)[icnt]);
+
+               ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,bcnt,
                                    &actual_length, HZ);
-               ret |= (actual_length != FIRMWARE_CHUNK_SIZE);
+               ret |= (actual_length != bcnt);
+               if (ret) break;
+               fw_done += bcnt;
        }
 
        trace_firmware("upload of %s : %i / %i ",
@@ -1142,7 +1317,11 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
 
        ret |= pvr2_write_register(hdw, 0x9054, 0xffffffff); /*reset hw blocks*/
        ret |= pvr2_write_register(hdw, 0x9058, 0xffffffe8); /*VPU ctrl*/
-       ret |= pvr2_write_u16(hdw, 0x0600, 0);
+       LOCK_TAKE(hdw->ctl_lock); do {
+               hdw->cmd_buffer[0] = FX2CMD_MEMSEL;
+               hdw->cmd_buffer[1] = 0;
+               ret |= pvr2_send_request(hdw,hdw->cmd_buffer,2,0,0);
+       } while (0); LOCK_GIVE(hdw->ctl_lock);
 
        if (ret) {
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
@@ -1479,7 +1658,7 @@ static int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw)
           firmware needs be loaded. */
        int result;
        LOCK_TAKE(hdw->ctl_lock); do {
-               hdw->cmd_buffer[0] = 0xeb;
+               hdw->cmd_buffer[0] = FX2CMD_GET_EEPROM_ADDR;
                result = pvr2_send_request_ex(hdw,HZ*1,!0,
                                           hdw->cmd_buffer,1,
                                           hdw->cmd_buffer,1);
@@ -1611,6 +1790,16 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
                cptr->info->set_value(cptr,~0,cptr->info->default_value);
        }
 
+       /* Set up special default values for the television and radio
+          frequencies here.  It's not really important what these defaults
+          are, but I set them to something usable in the Chicago area just
+          to make driver testing a little easier. */
+
+       /* US Broadcast channel 7 (175.25 MHz) */
+       hdw->freqValTelevision = 175250000L;
+       /* 104.3 MHz, a usable FM station for my area */
+       hdw->freqValRadio = 104300000L;
+
        // Do not use pvr2_reset_ctl_endpoints() here.  It is not
        // thread-safe against the normal pvr2_send_request() mechanism.
        // (We should make it thread safe).
@@ -1750,26 +1939,24 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
        struct pvr2_ctl_info *ciptr;
 
        hdw_type = devid - pvr2_device_table;
-       if (hdw_type >=
-           sizeof(pvr2_device_names)/sizeof(pvr2_device_names[0])) {
+       if (hdw_type >= ARRAY_SIZE(pvr2_device_names)) {
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                           "Bogus device type of %u reported",hdw_type);
                return NULL;
        }
 
-       hdw = kmalloc(sizeof(*hdw),GFP_KERNEL);
+       hdw = kzalloc(sizeof(*hdw),GFP_KERNEL);
        pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"",
                   hdw,pvr2_device_names[hdw_type]);
        if (!hdw) goto fail;
-       memset(hdw,0,sizeof(*hdw));
+       hdw->tuner_signal_stale = !0;
        cx2341x_fill_defaults(&hdw->enc_ctl_state);
 
        hdw->control_cnt = CTRLDEF_COUNT;
        hdw->control_cnt += MPEGDEF_COUNT;
-       hdw->controls = kmalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
+       hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
                                GFP_KERNEL);
        if (!hdw->controls) goto fail;
-       memset(hdw->controls,0,sizeof(struct pvr2_ctrl) * hdw->control_cnt);
        hdw->hdw_type = hdw_type;
        for (idx = 0; idx < hdw->control_cnt; idx++) {
                cptr = hdw->controls + idx;
@@ -1783,11 +1970,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
                cptr->info = control_defs+idx;
        }
        /* Define and configure additional controls from cx2341x module. */
-       hdw->mpeg_ctrl_info = kmalloc(
+       hdw->mpeg_ctrl_info = kzalloc(
                sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL);
        if (!hdw->mpeg_ctrl_info) goto fail;
-       memset(hdw->mpeg_ctrl_info,0,
-              sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT);
        for (idx = 0; idx < MPEGDEF_COUNT; idx++) {
                cptr = hdw->controls + idx + CTRLDEF_COUNT;
                ciptr = &(hdw->mpeg_ctrl_info[idx].info);
@@ -1872,7 +2057,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
 
        hdw->eeprom_addr = -1;
        hdw->unit_number = -1;
-       hdw->v4l_minor_number = -1;
+       hdw->v4l_minor_number_video = -1;
+       hdw->v4l_minor_number_vbi = -1;
+       hdw->v4l_minor_number_radio = -1;
        hdw->ctl_write_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
        if (!hdw->ctl_write_buffer) goto fail;
        hdw->ctl_read_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
@@ -1929,10 +2116,10 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
        if (hdw) {
                usb_free_urb(hdw->ctl_read_urb);
                usb_free_urb(hdw->ctl_write_urb);
-               if (hdw->ctl_read_buffer) kfree(hdw->ctl_read_buffer);
-               if (hdw->ctl_write_buffer) kfree(hdw->ctl_write_buffer);
-               if (hdw->controls) kfree(hdw->controls);
-               if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info);
+               kfree(hdw->ctl_read_buffer);
+               kfree(hdw->ctl_write_buffer);
+               kfree(hdw->controls);
+               kfree(hdw->mpeg_ctrl_info);
                kfree(hdw);
        }
        return NULL;
@@ -1982,9 +2169,6 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
                pvr2_stream_destroy(hdw->vid_stream);
                hdw->vid_stream = NULL;
        }
-       if (hdw->audio_stat) {
-               hdw->audio_stat->detach(hdw->audio_stat->ctxt);
-       }
        if (hdw->decoder_ctrl) {
                hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt);
        }
@@ -1997,10 +2181,10 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
                        unit_pointers[hdw->unit_number] = NULL;
                }
        } while (0); up(&pvr2_unit_sem);
-       if (hdw->controls) kfree(hdw->controls);
-       if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info);
-       if (hdw->std_defs) kfree(hdw->std_defs);
-       if (hdw->std_enum_names) kfree(hdw->std_enum_names);
+       kfree(hdw->controls);
+       kfree(hdw->mpeg_ctrl_info);
+       kfree(hdw->std_defs);
+       kfree(hdw->std_enum_names);
        kfree(hdw);
 }
 
@@ -2210,10 +2394,9 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
                cptr = hdw->controls + idx;
                if (cptr->info->is_dirty == 0) continue;
                if (!cptr->info->is_dirty(cptr)) continue;
-               if (!commit_flag) {
-                       commit_flag = !0;
-               }
+               commit_flag = !0;
 
+               if (!(pvrusb2_debug & PVR2_TRACE_CTL)) continue;
                bcnt = scnprintf(buf,sizeof(buf),"\"%s\" <-- ",
                                 cptr->info->name);
                value = 0;
@@ -2263,6 +2446,13 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
                stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
        }
 
+       if (hdw->input_dirty) {
+               /* pk: If input changes to or from radio, then the encoder
+                  needs to be restarted (for ENC_MUTE_VIDEO to work) */
+               stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
+       }
+
+
        if (hdw->srate_dirty) {
                /* Write new sample rate into control structure since
                 * the master copy is stale.  We must track srate
@@ -2343,39 +2533,11 @@ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
 }
 
 
-/* Return bit mask indicating signal status */
-static unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw)
-{
-       unsigned int msk = 0;
-       switch (hdw->input_val) {
-       case PVR2_CVAL_INPUT_TV:
-       case PVR2_CVAL_INPUT_RADIO:
-               if (hdw->decoder_ctrl &&
-                   hdw->decoder_ctrl->tuned(hdw->decoder_ctrl->ctxt)) {
-                       msk |= PVR2_SIGNAL_OK;
-                       if (hdw->audio_stat &&
-                           hdw->audio_stat->status(hdw->audio_stat->ctxt)) {
-                               if (hdw->flag_stereo) {
-                                       msk |= PVR2_SIGNAL_STEREO;
-                               }
-                               if (hdw->flag_bilingual) {
-                                       msk |= PVR2_SIGNAL_SAP;
-                               }
-                       }
-               }
-               break;
-       default:
-               msk |= PVR2_SIGNAL_OK | PVR2_SIGNAL_STEREO;
-       }
-       return msk;
-}
-
-
 int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
 {
        int result;
        LOCK_TAKE(hdw->ctl_lock); do {
-               hdw->cmd_buffer[0] = 0x0b;
+               hdw->cmd_buffer[0] = FX2CMD_GET_USB_SPEED;
                result = pvr2_send_request(hdw,
                                           hdw->cmd_buffer,1,
                                           hdw->cmd_buffer,1);
@@ -2386,14 +2548,25 @@ int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
 }
 
 
-/* Return bit mask indicating signal status */
-unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *hdw)
+/* Execute poll of tuner status */
+void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *hdw)
 {
-       unsigned int msk = 0;
        LOCK_TAKE(hdw->big_lock); do {
-               msk = pvr2_hdw_get_signal_status_internal(hdw);
+               pvr2_i2c_core_status_poll(hdw);
        } while (0); LOCK_GIVE(hdw->big_lock);
-       return msk;
+}
+
+
+/* Return information about the tuner */
+int pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp)
+{
+       LOCK_TAKE(hdw->big_lock); do {
+               if (hdw->tuner_signal_stale) {
+                       pvr2_i2c_core_status_poll(hdw);
+               }
+               memcpy(vtp,&hdw->tuner_signal_info,sizeof(struct v4l2_tuner));
+       } while (0); LOCK_GIVE(hdw->big_lock);
+       return 0;
 }
 
 
@@ -2442,14 +2615,12 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag)
                pvr2_trace(PVR2_TRACE_FIRMWARE,
                           "Preparing to suck out CPU firmware");
                hdw->fw_size = 0x2000;
-               hdw->fw_buffer = kmalloc(hdw->fw_size,GFP_KERNEL);
+               hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL);
                if (!hdw->fw_buffer) {
                        hdw->fw_size = 0;
                        break;
                }
 
-               memset(hdw->fw_buffer,0,hdw->fw_size);
-
                /* We have to hold the CPU during firmware upload. */
                pvr2_hdw_cpureset_assert(hdw,1);
 
@@ -2513,16 +2684,28 @@ int pvr2_hdw_cpufw_get(struct pvr2_hdw *hdw,unsigned int offs,
 }
 
 
-int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *hdw)
+int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *hdw,
+                                 enum pvr2_v4l_type index)
 {
-       return hdw->v4l_minor_number;
+       switch (index) {
+       case pvr2_v4l_type_video: return hdw->v4l_minor_number_video;
+       case pvr2_v4l_type_vbi: return hdw->v4l_minor_number_vbi;
+       case pvr2_v4l_type_radio: return hdw->v4l_minor_number_radio;
+       default: return -1;
+       }
 }
 
 
-/* Store the v4l minor device number */
-void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw,int v)
+/* Store a v4l minor device number */
+void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw,
+                                    enum pvr2_v4l_type index,int v)
 {
-       hdw->v4l_minor_number = v;
+       switch (index) {
+       case pvr2_v4l_type_video: hdw->v4l_minor_number_video = v;
+       case pvr2_v4l_type_vbi: hdw->v4l_minor_number_vbi = v;
+       case pvr2_v4l_type_radio: hdw->v4l_minor_number_radio = v;
+       default: break;
+       }
 }
 
 
@@ -2804,7 +2987,7 @@ int pvr2_write_register(struct pvr2_hdw *hdw, u16 reg, u32 data)
 
        LOCK_TAKE(hdw->ctl_lock);
 
-       hdw->cmd_buffer[0] = 0x04;  /* write register prefix */
+       hdw->cmd_buffer[0] = FX2CMD_REG_WRITE;  /* write register prefix */
        PVR2_DECOMPOSE_LE(hdw->cmd_buffer,1,data);
        hdw->cmd_buffer[5] = 0;
        hdw->cmd_buffer[6] = (reg >> 8) & 0xff;
@@ -2825,7 +3008,7 @@ static int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data)
 
        LOCK_TAKE(hdw->ctl_lock);
 
-       hdw->cmd_buffer[0] = 0x05;  /* read register prefix */
+       hdw->cmd_buffer[0] = FX2CMD_REG_READ;  /* read register prefix */
        hdw->cmd_buffer[1] = 0;
        hdw->cmd_buffer[2] = 0;
        hdw->cmd_buffer[3] = 0;
@@ -2843,39 +3026,6 @@ static int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data)
 }
 
 
-static int pvr2_write_u16(struct pvr2_hdw *hdw, u16 data, int res)
-{
-       int ret;
-
-       LOCK_TAKE(hdw->ctl_lock);
-
-       hdw->cmd_buffer[0] = (data >> 8) & 0xff;
-       hdw->cmd_buffer[1] = data & 0xff;
-
-       ret = pvr2_send_request(hdw, hdw->cmd_buffer, 2, hdw->cmd_buffer, res);
-
-       LOCK_GIVE(hdw->ctl_lock);
-
-       return ret;
-}
-
-
-static int pvr2_write_u8(struct pvr2_hdw *hdw, u8 data, int res)
-{
-       int ret;
-
-       LOCK_TAKE(hdw->ctl_lock);
-
-       hdw->cmd_buffer[0] = data;
-
-       ret = pvr2_send_request(hdw, hdw->cmd_buffer, 1, hdw->cmd_buffer, res);
-
-       LOCK_GIVE(hdw->ctl_lock);
-
-       return ret;
-}
-
-
 static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw)
 {
        if (!hdw->flag_ok) return;
@@ -2949,7 +3099,7 @@ int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw)
        LOCK_TAKE(hdw->ctl_lock); do {
                pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset");
                hdw->flag_ok = !0;
-               hdw->cmd_buffer[0] = 0xdd;
+               hdw->cmd_buffer[0] = FX2CMD_DEEP_RESET;
                status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
        } while (0); LOCK_GIVE(hdw->ctl_lock);
        return status;
@@ -2961,7 +3111,7 @@ int pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw)
        int status;
        LOCK_TAKE(hdw->ctl_lock); do {
                pvr2_trace(PVR2_TRACE_INIT,"Requesting powerup");
-               hdw->cmd_buffer[0] = 0xde;
+               hdw->cmd_buffer[0] = FX2CMD_POWER_ON;
                status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
        } while (0); LOCK_GIVE(hdw->ctl_lock);
        return status;
@@ -2994,7 +3144,8 @@ static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
 {
        int status;
        LOCK_TAKE(hdw->ctl_lock); do {
-               hdw->cmd_buffer[0] = (runFl ? 0x36 : 0x37);
+               hdw->cmd_buffer[0] =
+                       (runFl ? FX2CMD_STREAMING_ON : FX2CMD_STREAMING_OFF);
                status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
        } while (0); LOCK_GIVE(hdw->ctl_lock);
        if (!status) {
@@ -3093,7 +3244,7 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
 {
        int result;
        LOCK_TAKE(hdw->ctl_lock); do {
-               hdw->cmd_buffer[0] = 0xeb;
+               hdw->cmd_buffer[0] = FX2CMD_GET_EEPROM_ADDR;
                result = pvr2_send_request(hdw,
                                           hdw->cmd_buffer,1,
                                           hdw->cmd_buffer,1);
@@ -3105,7 +3256,7 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
 
 
 int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
-                            u32 chip_id,unsigned long reg_id,
+                            u32 chip_id, u64 reg_id,
                             int setFl,u32 *val_ptr)
 {
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -3115,6 +3266,8 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
        int stat = 0;
        int okFl = 0;
 
+       if (!capable(CAP_SYS_ADMIN)) return -EPERM;
+
        req.i2c_id = chip_id;
        req.reg = reg_id;
        if (setFl) req.val = *val_ptr;
@@ -3123,8 +3276,8 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
                        cp = list_entry(item,struct pvr2_i2c_client,list);
                        if (cp->client->driver->id != chip_id) continue;
                        stat = pvr2_i2c_client_cmd(
-                               cp,(setFl ? VIDIOC_INT_S_REGISTER :
-                                   VIDIOC_INT_G_REGISTER),&req);
+                               cp,(setFl ? VIDIOC_DBG_S_REGISTER :
+                                   VIDIOC_DBG_G_REGISTER),&req);
                        if (!setFl) *val_ptr = req.val;
                        okFl = !0;
                        break;
index 29979bb..566a8ef 100644 (file)
 #define PVR2_CVAL_INPUT_COMPOSITE 2
 #define PVR2_CVAL_INPUT_RADIO 3
 
-/* Values that pvr2_hdw_get_signal_status() returns */
-#define PVR2_SIGNAL_OK     0x0001
-#define PVR2_SIGNAL_STEREO 0x0002
-#define PVR2_SIGNAL_SAP    0x0004
-
-
 /* Subsystem definitions - these are various pieces that can be
    independently stopped / started.  Usually you don't want to mess with
    this directly (let the driver handle things itself), but it is useful
        PVR2_SUBSYS_RUN_ALL )
 
 enum pvr2_config {
-       pvr2_config_empty,
-       pvr2_config_mpeg,
-       pvr2_config_vbi,
-       pvr2_config_radio,
+       pvr2_config_empty,    /* No configuration */
+       pvr2_config_mpeg,     /* Encoded / compressed video */
+       pvr2_config_vbi,      /* Standard vbi info */
+       pvr2_config_pcm,      /* Audio raw pcm stream */
+       pvr2_config_rawvideo, /* Video raw frames */
+};
+
+enum pvr2_v4l_type {
+       pvr2_v4l_type_video,
+       pvr2_v4l_type_vbi,
+       pvr2_v4l_type_radio,
 };
 
 const char *pvr2_config_get_name(enum pvr2_config);
@@ -148,8 +149,11 @@ int pvr2_hdw_commit_ctl(struct pvr2_hdw *);
 /* Return name for this driver instance */
 const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *);
 
-/* Return PVR2_SIGNAL_XXXX bit mask indicating signal status */
-unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *);
+/* Mark tuner status stale so that it will be re-fetched */
+void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *);
+
+/* Return information about the tuner */
+int pvr2_hdw_get_tuner_status(struct pvr2_hdw *,struct v4l2_tuner *);
 
 /* Query device and see if it thinks it is on a high-speed USB link */
 int pvr2_hdw_is_hsm(struct pvr2_hdw *);
@@ -205,11 +209,12 @@ int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *);
 int pvr2_hdw_cpufw_get(struct pvr2_hdw *,unsigned int offs,
                       char *buf,unsigned int cnt);
 
-/* Retrieve previously stored v4l minor device number */
-int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *);
+/* Retrieve previously stored v4l minor device number */
+int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *,enum pvr2_v4l_type index);
 
-/* Store the v4l minor device number */
-void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,int);
+/* Store a v4l minor device number */
+void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,
+                                    enum pvr2_v4l_type index,int);
 
 /* Direct read/write access to chip's registers:
    chip_id - unique id of chip (e.g. I2C_DRIVERD_xxxx)
@@ -217,7 +222,7 @@ void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,int);
    setFl   - true to set the register, false to read it
    val_ptr - storage location for source / result. */
 int pvr2_hdw_register_access(struct pvr2_hdw *,
-                            u32 chip_id,unsigned long reg_id,
+                            u32 chip_id,u64 reg_id,
                             int setFl,u32 *val_ptr);
 
 /* The following entry points are all lower level things you normally don't
index 0512166..4977376 100644 (file)
 #define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
 
 #define OP_STANDARD 0
-#define OP_BCSH 1
-#define OP_VOLUME 2
-#define OP_FREQ 3
-#define OP_AUDIORATE 4
-#define OP_SIZE 5
-#define OP_LOG 6
+#define OP_AUDIOMODE 1
+#define OP_BCSH 2
+#define OP_VOLUME 3
+#define OP_FREQ 4
+#define OP_AUDIORATE 5
+#define OP_SIZE 6
+#define OP_LOG 7
 
 static const struct pvr2_i2c_op * const ops[] = {
        [OP_STANDARD] = &pvr2_i2c_op_v4l2_standard,
+       [OP_AUDIOMODE] = &pvr2_i2c_op_v4l2_audiomode,
        [OP_BCSH] = &pvr2_i2c_op_v4l2_bcsh,
        [OP_VOLUME] = &pvr2_i2c_op_v4l2_volume,
        [OP_FREQ] = &pvr2_i2c_op_v4l2_frequency,
@@ -54,11 +56,13 @@ void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
        int id;
        id = cp->client->driver->id;
        cp->ctl_mask = ((1 << OP_STANDARD) |
+                       (1 << OP_AUDIOMODE) |
                        (1 << OP_BCSH) |
                        (1 << OP_VOLUME) |
                        (1 << OP_FREQ) |
                        (1 << OP_SIZE) |
                        (1 << OP_LOG));
+       cp->status_poll = pvr2_v4l2_cmd_status_poll;
 
        if (id == I2C_DRIVERID_MSP3400) {
                if (pvr2_i2c_msp3400_setup(hdw,cp)) {
index 05ea17a..c650e02 100644 (file)
 #include "pvrusb2-hdw-internal.h"
 #include "pvrusb2-debug.h"
 #include <linux/videodev2.h>
-
+#include <media/v4l2-common.h>
 
 static void set_standard(struct pvr2_hdw *hdw)
 {
-       v4l2_std_id vs;
-       vs = hdw->std_mask_cur;
-       pvr2_trace(PVR2_TRACE_CHIPS,
-                  "i2c v4l2 set_standard(0x%llx)",(long long unsigned)vs);
-
-       pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_standard");
+
+       if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+               pvr2_i2c_core_cmd(hdw,AUDC_SET_RADIO,NULL);
+       } else {
+               v4l2_std_id vs;
+               vs = hdw->std_mask_cur;
+               pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
+       }
+       hdw->tuner_signal_stale = !0;
 }
 
 
 static int check_standard(struct pvr2_hdw *hdw)
 {
-       return hdw->std_dirty != 0;
+       return (hdw->input_dirty != 0) || (hdw->std_dirty != 0);
 }
 
 
@@ -136,16 +140,53 @@ const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume = {
 };
 
 
+static void set_audiomode(struct pvr2_hdw *hdw)
+{
+       struct v4l2_tuner vt;
+       memset(&vt,0,sizeof(vt));
+       vt.audmode = hdw->audiomode_val;
+       pvr2_i2c_core_cmd(hdw,VIDIOC_S_TUNER,&vt);
+}
+
+
+static int check_audiomode(struct pvr2_hdw *hdw)
+{
+       return (hdw->input_dirty ||
+               hdw->audiomode_dirty);
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode = {
+       .check = check_audiomode,
+       .update = set_audiomode,
+       .name = "v4l2_audiomode",
+};
+
+
 static void set_frequency(struct pvr2_hdw *hdw)
 {
        unsigned long fv;
        struct v4l2_frequency freq;
-       fv = hdw->freqVal;
+       fv = pvr2_hdw_get_cur_freq(hdw);
        pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_freq(%lu)",fv);
+       if (hdw->tuner_signal_stale) {
+               pvr2_i2c_core_status_poll(hdw);
+       }
        memset(&freq,0,sizeof(freq));
-       freq.frequency = fv / 62500;
+       if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+               // ((fv * 1000) / 62500)
+               freq.frequency = (fv * 2) / 125;
+       } else {
+               freq.frequency = fv / 62500;
+       }
+       /* tuner-core currently doesn't seem to care about this, but
+          let's set it anyway for completeness. */
+       if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+               freq.type = V4L2_TUNER_RADIO;
+       } else {
+               freq.type = V4L2_TUNER_ANALOG_TV;
+       }
        freq.tuner = 0;
-       freq.type = V4L2_TUNER_ANALOG_TV;
        pvr2_i2c_core_cmd(hdw,VIDIOC_S_FREQUENCY,&freq);
 }
 
@@ -221,6 +262,12 @@ void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *cp,int fl)
 }
 
 
+void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *cp)
+{
+       pvr2_i2c_client_cmd(cp,VIDIOC_G_TUNER,&cp->hdw->tuner_signal_info);
+}
+
+
 /*
   Stuff for Emacs to see, in order to encourage consistent editing style:
   *** Local Variables: ***
index ecabddb..c838df6 100644 (file)
 #include "pvrusb2-i2c-core.h"
 
 extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_radio;
 extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh;
 extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume;
 extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency;
 extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode;
 extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log;
 
 void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *,int);
+void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *);
 
 #endif /* __PVRUSB2_CMD_V4L2_H */
 
index 62a7cfc..58fc3c7 100644 (file)
@@ -22,6 +22,7 @@
 #include "pvrusb2-i2c-core.h"
 #include "pvrusb2-hdw-internal.h"
 #include "pvrusb2-debug.h"
+#include "pvrusb2-fx2-cmd.h"
 
 #define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
 
@@ -66,7 +67,7 @@ static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
        memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
 
        /* Set up command buffer for an I2C write */
-       hdw->cmd_buffer[0] = 0x08;      /* write prefix */
+       hdw->cmd_buffer[0] = FX2CMD_I2C_WRITE;      /* write prefix */
        hdw->cmd_buffer[1] = i2c_addr;  /* i2c addr of chip */
        hdw->cmd_buffer[2] = length;    /* length of what follows */
        if (length) memcpy(hdw->cmd_buffer + 3, data, length);
@@ -128,7 +129,7 @@ static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */
        memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
 
        /* Set up command buffer for an I2C write followed by a read */
-       hdw->cmd_buffer[0] = 0x09;  /* read prefix */
+       hdw->cmd_buffer[0] = FX2CMD_I2C_READ;  /* read prefix */
        hdw->cmd_buffer[1] = dlen;  /* arg length */
        hdw->cmd_buffer[2] = rlen;  /* answer length. Device will send one
                                       more byte (status). */
@@ -221,7 +222,7 @@ static int i2c_24xxx_ir(struct pvr2_hdw *hdw,
 
        /* Issue a command to the FX2 to read the IR receiver. */
        LOCK_TAKE(hdw->ctl_lock); do {
-               hdw->cmd_buffer[0] = 0xec;
+               hdw->cmd_buffer[0] = FX2CMD_GET_IR_CODE;
                stat = pvr2_send_request(hdw,
                                         hdw->cmd_buffer,1,
                                         hdw->cmd_buffer,4);
@@ -590,6 +591,33 @@ static int handler_check(struct pvr2_i2c_client *cp)
 
 #define BUFSIZE 500
 
+
+void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw)
+{
+       struct list_head *item;
+       struct pvr2_i2c_client *cp;
+       mutex_lock(&hdw->i2c_list_lock); do {
+               struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
+               memset(vtp,0,sizeof(*vtp));
+               list_for_each(item,&hdw->i2c_clients) {
+                       cp = list_entry(item,struct pvr2_i2c_client,list);
+                       if (!cp->detected_flag) continue;
+                       if (!cp->status_poll) continue;
+                       cp->status_poll(cp);
+               }
+               hdw->tuner_signal_stale = 0;
+               pvr2_trace(PVR2_TRACE_CHIPS,"i2c status poll"
+                          " type=%u strength=%u audio=0x%x cap=0x%x"
+                          " low=%u hi=%u",
+                          vtp->type,
+                          vtp->signal,vtp->rxsubchans,vtp->capability,
+                          vtp->rangelow,vtp->rangehigh);
+       } while (0); mutex_unlock(&hdw->i2c_list_lock);
+}
+
+
+/* Issue various I2C operations to bring chip-level drivers into sync with
+   state stored in this driver. */
 void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
 {
        unsigned long msk;
@@ -870,12 +898,12 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client)
        struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
        struct pvr2_i2c_client *cp;
        int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL);
-       cp = kmalloc(sizeof(*cp),GFP_KERNEL);
+       cp = kzalloc(sizeof(*cp),GFP_KERNEL);
        trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]",
                  client->name,
                  client->addr,cp);
        if (!cp) return -ENOMEM;
-       memset(cp,0,sizeof(*cp));
+       cp->hdw = hdw;
        INIT_LIST_HEAD(&cp->list);
        cp->client = client;
        mutex_lock(&hdw->i2c_list_lock); do {
@@ -948,8 +976,7 @@ static void do_i2c_scan(struct pvr2_hdw *hdw)
        printk("%s: i2c scan beginning\n",hdw->name);
        for (i = 0; i < 128; i++) {
                msg[0].addr = i;
-               rc = i2c_transfer(&hdw->i2c_adap,msg,
-                                 sizeof(msg)/sizeof(msg[0]));
+               rc = i2c_transfer(&hdw->i2c_adap,msg, ARRAY_SIZE(msg));
                if (rc != 1) continue;
                printk("%s: i2c scan: found device @ 0x%x\n",hdw->name,i);
        }
index 6d7e252..bd0807b 100644 (file)
@@ -35,10 +35,12 @@ struct pvr2_i2c_client {
        struct i2c_client *client;
        struct pvr2_i2c_handler *handler;
        struct list_head list;
+       struct pvr2_hdw *hdw;
        int detected_flag;
        int recv_enable;
        unsigned long pend_mask;
        unsigned long ctl_mask;
+       void (*status_poll)(struct pvr2_i2c_client *);
 };
 
 struct pvr2_i2c_handler {
@@ -67,6 +69,7 @@ int pvr2_i2c_core_cmd(struct pvr2_hdw *,unsigned int cmd,void *arg);
 
 int pvr2_i2c_core_check_stale(struct pvr2_hdw *);
 void pvr2_i2c_core_sync(struct pvr2_hdw *);
+void pvr2_i2c_core_status_poll(struct pvr2_hdw *);
 unsigned int pvr2_i2c_report(struct pvr2_hdw *,char *buf,unsigned int maxlen);
 #define PVR2_I2C_DETAIL_DEBUG   0x0001
 #define PVR2_I2C_DETAIL_HANDLER 0x0002
index 57fb320..ce3c898 100644 (file)
@@ -474,9 +474,8 @@ static void buffer_complete(struct urb *urb)
 struct pvr2_stream *pvr2_stream_create(void)
 {
        struct pvr2_stream *sp;
-       sp = kmalloc(sizeof(*sp),GFP_KERNEL);
+       sp = kzalloc(sizeof(*sp),GFP_KERNEL);
        if (!sp) return sp;
-       memset(sp,0,sizeof(*sp));
        pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_create: sp=%p",sp);
        pvr2_stream_init(sp);
        return sp;
index b71f9a9..f782418 100644 (file)
@@ -87,10 +87,9 @@ static void pvr2_ioread_done(struct pvr2_ioread *cp)
 struct pvr2_ioread *pvr2_ioread_create(void)
 {
        struct pvr2_ioread *cp;
-       cp = kmalloc(sizeof(*cp),GFP_KERNEL);
+       cp = kzalloc(sizeof(*cp),GFP_KERNEL);
        if (!cp) return NULL;
        pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_create id=%p",cp);
-       memset(cp,0,sizeof(*cp));
        if (pvr2_ioread_init(cp) < 0) {
                kfree(cp);
                return NULL;
index c089255..81de26b 100644 (file)
@@ -141,10 +141,8 @@ int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
                        cnt = 0;
                        while ((cnt < bufSize) && (bufPtr[cnt] != '-')) cnt++;
                        if (cnt >= bufSize) return 0; // No more characters
-                       sp = find_std_name(
-                               std_groups,
-                               sizeof(std_groups)/sizeof(std_groups[0]),
-                               bufPtr,cnt);
+                       sp = find_std_name(std_groups, ARRAY_SIZE(std_groups),
+                                          bufPtr,cnt);
                        if (!sp) return 0; // Illegal color system name
                        cnt++;
                        bufPtr += cnt;
@@ -163,8 +161,7 @@ int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
                        if (ch == '/') break;
                        cnt++;
                }
-               sp = find_std_name(std_items,
-                                  sizeof(std_items)/sizeof(std_items[0]),
+               sp = find_std_name(std_items, ARRAY_SIZE(std_items),
                                   bufPtr,cnt);
                if (!sp) return 0; // Illegal modulation system ID
                t = sp->id & cmsk;
@@ -189,14 +186,10 @@ unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize,
        unsigned int c1,c2;
        cfl = 0;
        c1 = 0;
-       for (idx1 = 0;
-            idx1 < sizeof(std_groups)/sizeof(std_groups[0]);
-            idx1++) {
+       for (idx1 = 0; idx1 < ARRAY_SIZE(std_groups); idx1++) {
                gp = std_groups + idx1;
                gfl = 0;
-               for (idx2 = 0;
-                    idx2 < sizeof(std_items)/sizeof(std_items[0]);
-                    idx2++) {
+               for (idx2 = 0; idx2 < ARRAY_SIZE(std_items); idx2++) {
                        ip = std_items + idx2;
                        if (!(gp->id & ip->id & id)) continue;
                        if (!gfl) {
@@ -279,7 +272,7 @@ static struct v4l2_standard generic_standards[] = {
        }
 };
 
-#define generic_standards_cnt (sizeof(generic_standards)/sizeof(generic_standards[0]))
+#define generic_standards_cnt ARRAY_SIZE(generic_standards)
 
 static struct v4l2_standard *match_std(v4l2_std_id id)
 {
@@ -348,7 +341,7 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
                fmsk |= idmsk;
        }
 
-       for (idx2 = 0; idx2 < sizeof(std_mixes)/sizeof(std_mixes[0]); idx2++) {
+       for (idx2 = 0; idx2 < ARRAY_SIZE(std_mixes); idx2++) {
                if ((id & std_mixes[idx2]) == std_mixes[idx2]) std_cnt++;
        }
 
@@ -366,16 +359,15 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
                   std_cnt);
        if (!std_cnt) return NULL; // paranoia
 
-       stddefs = kmalloc(sizeof(struct v4l2_standard) * std_cnt,
+       stddefs = kzalloc(sizeof(struct v4l2_standard) * std_cnt,
                          GFP_KERNEL);
-       memset(stddefs,0,sizeof(struct v4l2_standard) * std_cnt);
        for (idx = 0; idx < std_cnt; idx++) stddefs[idx].index = idx;
 
        idx = 0;
 
        /* Enumerate potential special cases */
-       for (idx2 = 0; ((idx2 < sizeof(std_mixes)/sizeof(std_mixes[0])) &&
-                       (idx < std_cnt)); idx2++) {
+       for (idx2 = 0; (idx2 < ARRAY_SIZE(std_mixes)) && (idx < std_cnt);
+            idx2++) {
                if (!(id & std_mixes[idx2])) continue;
                if (pvr2_std_fill(stddefs+idx,std_mixes[idx2])) idx++;
        }
index c294f46..91396fd 100644 (file)
@@ -40,8 +40,10 @@ struct pvr2_sysfs {
        struct pvr2_sysfs_ctl_item *item_first;
        struct pvr2_sysfs_ctl_item *item_last;
        struct class_device_attribute attr_v4l_minor_number;
+       struct class_device_attribute attr_v4l_radio_minor_number;
        struct class_device_attribute attr_unit_number;
        int v4l_minor_number_created_ok;
+       int v4l_radio_minor_number_created_ok;
        int unit_number_created_ok;
 };
 
@@ -491,7 +493,7 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
        unsigned int cnt,acnt;
        int ret;
 
-       if ((ctl_id < 0) || (ctl_id >= (sizeof(funcs)/sizeof(funcs[0])))) {
+       if ((ctl_id < 0) || (ctl_id >= ARRAY_SIZE(funcs))) {
                return;
        }
 
@@ -499,9 +501,8 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
        cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id);
        if (!cptr) return;
 
-       cip = kmalloc(sizeof(*cip),GFP_KERNEL);
+       cip = kzalloc(sizeof(*cip),GFP_KERNEL);
        if (!cip) return;
-       memset(cip,0,sizeof(*cip));
        pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip);
 
        cip->cptr = cptr;
@@ -611,9 +612,8 @@ static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
        struct pvr2_sysfs_debugifc *dip;
        int ret;
 
-       dip = kmalloc(sizeof(*dip),GFP_KERNEL);
+       dip = kzalloc(sizeof(*dip),GFP_KERNEL);
        if (!dip) return;
-       memset(dip,0,sizeof(*dip));
        dip->attr_debugcmd.attr.owner = THIS_MODULE;
        dip->attr_debugcmd.attr.name = "debugcmd";
        dip->attr_debugcmd.attr.mode = S_IRUGO|S_IWUSR|S_IWGRP;
@@ -709,6 +709,10 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp)
                class_device_remove_file(sfp->class_dev,
                                         &sfp->attr_v4l_minor_number);
        }
+       if (sfp->v4l_radio_minor_number_created_ok) {
+               class_device_remove_file(sfp->class_dev,
+                                        &sfp->attr_v4l_radio_minor_number);
+       }
        if (sfp->unit_number_created_ok) {
                class_device_remove_file(sfp->class_dev,
                                         &sfp->attr_unit_number);
@@ -726,7 +730,20 @@ static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf)
        sfp = (struct pvr2_sysfs *)class_dev->class_data;
        if (!sfp) return -EINVAL;
        return scnprintf(buf,PAGE_SIZE,"%d\n",
-                        pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw));
+                        pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
+                                                      pvr2_v4l_type_video));
+}
+
+
+static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev,
+                                          char *buf)
+{
+       struct pvr2_sysfs *sfp;
+       sfp = (struct pvr2_sysfs *)class_dev->class_data;
+       if (!sfp) return -EINVAL;
+       return scnprintf(buf,PAGE_SIZE,"%d\n",
+                        pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
+                                                      pvr2_v4l_type_radio));
 }
 
 
@@ -749,9 +766,8 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
 
        usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw);
        if (!usb_dev) return;
-       class_dev = kmalloc(sizeof(*class_dev),GFP_KERNEL);
+       class_dev = kzalloc(sizeof(*class_dev),GFP_KERNEL);
        if (!class_dev) return;
-       memset(class_dev,0,sizeof(*class_dev));
 
        pvr2_sysfs_trace("Creating class_dev id=%p",class_dev);
 
@@ -793,6 +809,20 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
                sfp->v4l_minor_number_created_ok = !0;
        }
 
+       sfp->attr_v4l_radio_minor_number.attr.owner = THIS_MODULE;
+       sfp->attr_v4l_radio_minor_number.attr.name = "v4l_radio_minor_number";
+       sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO;
+       sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show;
+       sfp->attr_v4l_radio_minor_number.store = NULL;
+       ret = class_device_create_file(sfp->class_dev,
+                                      &sfp->attr_v4l_radio_minor_number);
+       if (ret < 0) {
+               printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+                      __FUNCTION__, ret);
+       } else {
+               sfp->v4l_radio_minor_number_created_ok = !0;
+       }
+
        sfp->attr_unit_number.attr.owner = THIS_MODULE;
        sfp->attr_unit_number.attr.name = "unit_number";
        sfp->attr_unit_number.attr.mode = S_IRUGO;
@@ -829,9 +859,8 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp,
                                     struct pvr2_sysfs_class *class_ptr)
 {
        struct pvr2_sysfs *sfp;
-       sfp = kmalloc(sizeof(*sfp),GFP_KERNEL);
+       sfp = kzalloc(sizeof(*sfp),GFP_KERNEL);
        if (!sfp) return sfp;
-       memset(sfp,0,sizeof(*sfp));
        pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_sysfs id=%p",sfp);
        pvr2_channel_init(&sfp->channel,mp);
        sfp->channel.check_func = pvr2_sysfs_internal_check;
@@ -852,9 +881,8 @@ static int pvr2_sysfs_hotplug(struct class_device *cd,char **envp,
 struct pvr2_sysfs_class *pvr2_sysfs_class_create(void)
 {
        struct pvr2_sysfs_class *clp;
-       clp = kmalloc(sizeof(*clp),GFP_KERNEL);
+       clp = kzalloc(sizeof(*clp),GFP_KERNEL);
        if (!clp) return clp;
-       memset(clp,0,sizeof(*clp));
        pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp);
        clp->class.name = "pvrusb2";
        clp->class.class_release = pvr2_sysfs_class_release;
index bb17db3..05e65ce 100644 (file)
@@ -93,9 +93,8 @@ int pvr2_i2c_tuner_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
        struct pvr2_tuner_handler *ctxt;
        if (cp->handler) return 0;
 
-       ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+       ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
        if (!ctxt) return 0;
-       memset(ctxt,0,sizeof(*ctxt));
 
        ctxt->i2c_handler.func_data = ctxt;
        ctxt->i2c_handler.func_table = &tuner_funcs;
index 6cf1708..4fe4136 100644 (file)
@@ -40,7 +40,10 @@ struct pvr2_v4l2_dev {
        struct video_device devbase; /* MUST be first! */
        struct pvr2_v4l2 *v4lp;
        struct pvr2_context_stream *stream;
-       enum pvr2_config config;
+       /* Information about this device: */
+       enum pvr2_config config; /* Expected stream format */
+       int v4l_type; /* V4L defined type for this device node */
+       enum pvr2_v4l_type minor_type; /* pvr2-understood minor device type */
 };
 
 struct pvr2_v4l2_fh {
@@ -54,6 +57,7 @@ struct pvr2_v4l2_fh {
        struct pvr2_v4l2_fh *vprev;
        wait_queue_head_t wait_data;
        int fw_mode_flag;
+       int prev_input_val;
 };
 
 struct pvr2_v4l2 {
@@ -63,13 +67,22 @@ struct pvr2_v4l2 {
 
        struct v4l2_prio_state prio;
 
-       /* streams */
-       struct pvr2_v4l2_dev *vdev;
+       /* streams - Note that these must be separately, individually,
+        * allocated pointers.  This is because the v4l core is going to
+        * manage their deletion - separately, individually...  */
+       struct pvr2_v4l2_dev *dev_video;
+       struct pvr2_v4l2_dev *dev_radio;
 };
 
 static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
 module_param_array(video_nr, int, NULL, 0444);
-MODULE_PARM_DESC(video_nr, "Offset for device's minor");
+MODULE_PARM_DESC(video_nr, "Offset for device's video dev minor");
+static int radio_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Offset for device's radio dev minor");
+static int vbi_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
+module_param_array(vbi_nr, int, NULL, 0444);
+MODULE_PARM_DESC(vbi_nr, "Offset for device's vbi dev minor");
 
 static struct v4l2_capability pvr_capability ={
        .driver         = "pvrusb2",
@@ -77,30 +90,11 @@ static struct v4l2_capability pvr_capability ={
        .bus_info       = "usb",
        .version        = KERNEL_VERSION(0,8,0),
        .capabilities   = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
-                          V4L2_CAP_TUNER | V4L2_CAP_AUDIO |
+                          V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
                           V4L2_CAP_READWRITE),
        .reserved       = {0,0,0,0}
 };
 
-static struct v4l2_tuner pvr_v4l2_tuners[]= {
-       {
-               .index      = 0,
-               .name       = "TV Tuner",
-               .type           = V4L2_TUNER_ANALOG_TV,
-               .capability     = (V4L2_TUNER_CAP_NORM |
-                                  V4L2_TUNER_CAP_STEREO |
-                                  V4L2_TUNER_CAP_LANG1 |
-                                  V4L2_TUNER_CAP_LANG2),
-               .rangelow   = 0,
-               .rangehigh  = 0,
-               .rxsubchans     = V4L2_TUNER_SUB_STEREO,
-               .audmode        = V4L2_TUNER_MODE_STEREO,
-               .signal         = 0,
-               .afc            = 0,
-               .reserved       = {0,0,0,0}
-       }
-};
-
 static struct v4l2_fmtdesc pvr_fmtdesc [] = {
        {
                .index          = 0,
@@ -154,6 +148,18 @@ static struct v4l2_format pvr_format [] = {
        }
 };
 
+
+static const char *get_v4l_name(int v4l_type)
+{
+       switch (v4l_type) {
+       case VFL_TYPE_GRABBER: return "video";
+       case VFL_TYPE_RADIO: return "radio";
+       case VFL_TYPE_VBI: return "vbi";
+       default: return "?";
+       }
+}
+
+
 /*
  * pvr_ioctl()
  *
@@ -315,13 +321,39 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
 
        case VIDIOC_ENUMAUDIO:
        {
+               /* pkt: FIXME: We are returning one "fake" input here
+                  which could very well be called "whatever_we_like".
+                  This is for apps that want to see an audio input
+                  just to feel comfortable, as well as to test if
+                  it can do stereo or sth. There is actually no guarantee
+                  that the actual audio input cannot change behind the app's
+                  back, but most applications should not mind that either.
+
+                  Hopefully, mplayer people will work with us on this (this
+                  whole mess is to support mplayer pvr://), or Hans will come
+                  up with a more standard way to say "we have inputs but we
+                  don 't want you to change them independent of video" which
+                  will sort this mess.
+                */
+               struct v4l2_audio *vin = arg;
                ret = -EINVAL;
+               if (vin->index > 0) break;
+               strncpy(vin->name, "PVRUSB2 Audio",14);
+               vin->capability = V4L2_AUDCAP_STEREO;
+               ret = 0;
+               break;
                break;
        }
 
        case VIDIOC_G_AUDIO:
        {
-               ret = -EINVAL;
+               /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */
+               struct v4l2_audio *vin = arg;
+               memset(vin,0,sizeof(*vin));
+               vin->index = 0;
+               strncpy(vin->name, "PVRUSB2 Audio",14);
+               vin->capability = V4L2_AUDCAP_STEREO;
+               ret = 0;
                break;
        }
 
@@ -333,34 +365,11 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_G_TUNER:
        {
                struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
-               unsigned int status_mask;
-               int val;
-               if (vt->index !=0) break;
 
-               status_mask = pvr2_hdw_get_signal_status(hdw);
+               if (vt->index != 0) break; /* Only answer for the 1st tuner */
 
-               memcpy(vt, &pvr_v4l2_tuners[vt->index],
-                      sizeof(struct v4l2_tuner));
-
-               vt->signal = 0;
-               if (status_mask & PVR2_SIGNAL_OK) {
-                       if (status_mask & PVR2_SIGNAL_STEREO) {
-                               vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
-                       } else {
-                               vt->rxsubchans = V4L2_TUNER_SUB_MONO;
-                       }
-                       if (status_mask & PVR2_SIGNAL_SAP) {
-                               vt->rxsubchans |= (V4L2_TUNER_SUB_LANG1 |
-                                                  V4L2_TUNER_SUB_LANG2);
-                       }
-                       vt->signal = 65535;
-               }
-
-               val = 0;
-               ret = pvr2_ctrl_get_value(
-                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
-                       &val);
-               vt->audmode = val;
+               pvr2_hdw_execute_tuner_poll(hdw);
+               ret = pvr2_hdw_get_tuner_status(hdw,vt);
                break;
        }
 
@@ -374,14 +383,40 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
                ret = pvr2_ctrl_set_value(
                        pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
                        vt->audmode);
+               break;
        }
 
        case VIDIOC_S_FREQUENCY:
        {
                const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
+               unsigned long fv;
+               struct v4l2_tuner vt;
+               int cur_input;
+               struct pvr2_ctrl *ctrlp;
+               ret = pvr2_hdw_get_tuner_status(hdw,&vt);
+               if (ret != 0) break;
+               ctrlp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+               ret = pvr2_ctrl_get_value(ctrlp,&cur_input);
+               if (ret != 0) break;
+               if (vf->type == V4L2_TUNER_RADIO) {
+                       if (cur_input != PVR2_CVAL_INPUT_RADIO) {
+                               pvr2_ctrl_set_value(ctrlp,
+                                                   PVR2_CVAL_INPUT_RADIO);
+                       }
+               } else {
+                       if (cur_input == PVR2_CVAL_INPUT_RADIO) {
+                               pvr2_ctrl_set_value(ctrlp,
+                                                   PVR2_CVAL_INPUT_TV);
+                       }
+               }
+               fv = vf->frequency;
+               if (vt.capability & V4L2_TUNER_CAP_LOW) {
+                       fv = (fv * 125) / 2;
+               } else {
+                       fv = fv * 62500;
+               }
                ret = pvr2_ctrl_set_value(
-                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
-                       vf->frequency * 62500);
+                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),fv);
                break;
        }
 
@@ -389,10 +424,27 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
        {
                struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
                int val = 0;
+               int cur_input;
+               struct v4l2_tuner vt;
+               ret = pvr2_hdw_get_tuner_status(hdw,&vt);
+               if (ret != 0) break;
                ret = pvr2_ctrl_get_value(
                        pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
                        &val);
-               val /= 62500;
+               if (ret != 0) break;
+               pvr2_ctrl_get_value(
+                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
+                       &cur_input);
+               if (cur_input == PVR2_CVAL_INPUT_RADIO) {
+                       vf->type = V4L2_TUNER_RADIO;
+               } else {
+                       vf->type = V4L2_TUNER_ANALOG_TV;
+               }
+               if (vt.capability & V4L2_TUNER_CAP_LOW) {
+                       val = (val * 2) / 125;
+               } else {
+                       val /= 62500;
+               }
                vf->frequency = val;
                break;
        }
@@ -449,7 +501,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
                ret = 0;
                switch(vf->type) {
                case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
-                       int lmin,lmax;
+                       int lmin,lmax,ldef;
                        struct pvr2_ctrl *hcp,*vcp;
                        int h = vf->fmt.pix.height;
                        int w = vf->fmt.pix.width;
@@ -458,14 +510,20 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
 
                        lmin = pvr2_ctrl_get_min(hcp);
                        lmax = pvr2_ctrl_get_max(hcp);
-                       if (w < lmin) {
+                       ldef = pvr2_ctrl_get_def(hcp);
+                       if (w == -1) {
+                               w = ldef;
+                       } else if (w < lmin) {
                                w = lmin;
                        } else if (w > lmax) {
                                w = lmax;
                        }
                        lmin = pvr2_ctrl_get_min(vcp);
                        lmax = pvr2_ctrl_get_max(vcp);
-                       if (h < lmin) {
+                       ldef = pvr2_ctrl_get_def(vcp);
+                       if (h == -1) {
+                               h = ldef;
+                       } else if (h < lmin) {
                                h = lmin;
                        } else if (h > lmax) {
                                h = lmax;
@@ -494,6 +552,13 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
 
        case VIDIOC_STREAMON:
        {
+               if (!fh->dev_info->stream) {
+                       /* No stream defined for this node.  This means
+                          that we're not currently allowed to stream from
+                          this node. */
+                       ret = -EPERM;
+                       break;
+               }
                ret = pvr2_hdw_set_stream_type(hdw,dev_info->config);
                if (ret < 0) return ret;
                ret = pvr2_hdw_set_streaming(hdw,!0);
@@ -502,6 +567,13 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
 
        case VIDIOC_STREAMOFF:
        {
+               if (!fh->dev_info->stream) {
+                       /* No stream defined for this node.  This means
+                          that we're not currently allowed to stream from
+                          this node. */
+                       ret = -EPERM;
+                       break;
+               }
                ret = pvr2_hdw_set_streaming(hdw,0);
                break;
        }
@@ -599,6 +671,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
                struct v4l2_ext_control *ctrl;
                unsigned int idx;
                int val;
+               ret = 0;
                for (idx = 0; idx < ctls->count; idx++) {
                        ctrl = ctls->controls + idx;
                        ret = pvr2_ctrl_get_value(
@@ -621,6 +694,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
                        (struct v4l2_ext_controls *)arg;
                struct v4l2_ext_control *ctrl;
                unsigned int idx;
+               ret = 0;
                for (idx = 0; idx < ctls->count; idx++) {
                        ctrl = ctls->controls + idx;
                        ret = pvr2_ctrl_set_value(
@@ -643,6 +717,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
                unsigned int idx;
                /* For the moment just validate that the requested control
                   actually exists. */
+               ret = 0;
                for (idx = 0; idx < ctls->count; idx++) {
                        ctrl = ctls->controls + idx;
                        pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id);
@@ -662,16 +737,16 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
                break;
        }
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-       case VIDIOC_INT_G_REGISTER:
-       case VIDIOC_INT_S_REGISTER:
+       case VIDIOC_DBG_S_REGISTER:
+       case VIDIOC_DBG_G_REGISTER:
        {
                u32 val;
                struct v4l2_register *req = (struct v4l2_register *)arg;
-               if (cmd == VIDIOC_INT_S_REGISTER) val = req->val;
+               if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val;
                ret = pvr2_hdw_register_access(
                        hdw,req->i2c_id,req->reg,
-                       cmd == VIDIOC_INT_S_REGISTER,&val);
-               if (cmd == VIDIOC_INT_G_REGISTER) req->val = val;
+                       cmd == VIDIOC_DBG_S_REGISTER,&val);
+               if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val;
                break;
        }
 #endif
@@ -707,8 +782,12 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
 
 static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
 {
-       printk(KERN_INFO "pvrusb2: unregistering device video%d [%s]\n",
-              dip->devbase.minor,pvr2_config_get_name(dip->config));
+       int minor_id = dip->devbase.minor;
+       struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw;
+       enum pvr2_config cfg = dip->config;
+       int v4l_type = dip->v4l_type;
+
+       pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1);
 
        /* Paranoia */
        dip->v4lp = NULL;
@@ -717,13 +796,24 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
        /* Actual deallocation happens later when all internal references
           are gone. */
        video_unregister_device(&dip->devbase);
+
+       printk(KERN_INFO "pvrusb2: unregistered device %s%u [%s]\n",
+              get_v4l_name(v4l_type),minor_id & 0x1f,
+              pvr2_config_get_name(cfg));
+
 }
 
 
 static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
 {
-       pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,-1);
-       pvr2_v4l2_dev_destroy(vp->vdev);
+       if (vp->dev_video) {
+               pvr2_v4l2_dev_destroy(vp->dev_video);
+               vp->dev_video = 0;
+       }
+       if (vp->dev_radio) {
+               pvr2_v4l2_dev_destroy(vp->dev_radio);
+               vp->dev_radio = 0;
+       }
 
        pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
        pvr2_channel_done(&vp->channel);
@@ -766,23 +856,37 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file)
        struct pvr2_v4l2_fh *fhp = file->private_data;
        struct pvr2_v4l2 *vp = fhp->vhead;
        struct pvr2_context *mp = fhp->vhead->channel.mc_head;
+       struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw;
 
        pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release");
 
        if (fhp->rhp) {
                struct pvr2_stream *sp;
-               struct pvr2_hdw *hdw;
-               hdw = fhp->channel.mc_head->hdw;
                pvr2_hdw_set_streaming(hdw,0);
                sp = pvr2_ioread_get_stream(fhp->rhp);
                if (sp) pvr2_stream_set_callback(sp,NULL,NULL);
                pvr2_ioread_destroy(fhp->rhp);
                fhp->rhp = NULL;
        }
+
        v4l2_prio_close(&vp->prio, &fhp->prio);
        file->private_data = NULL;
 
        pvr2_context_enter(mp); do {
+               /* Restore the previous input selection, if it makes sense
+                  to do so. */
+               if (fhp->dev_info->v4l_type == VFL_TYPE_RADIO) {
+                       struct pvr2_ctrl *cp;
+                       int pval;
+                       cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+                       pvr2_ctrl_get_value(cp,&pval);
+                       /* Only restore if we're still selecting the radio */
+                       if (pval == PVR2_CVAL_INPUT_RADIO) {
+                               pvr2_ctrl_set_value(cp,fhp->prev_input_val);
+                               pvr2_hdw_commit_ctl(hdw);
+                       }
+               }
+
                if (fhp->vnext) {
                        fhp->vnext->vprev = fhp->vprev;
                } else {
@@ -828,11 +932,10 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
                return -EIO;
        }
 
-       fhp = kmalloc(sizeof(*fhp),GFP_KERNEL);
+       fhp = kzalloc(sizeof(*fhp),GFP_KERNEL);
        if (!fhp) {
                return -ENOMEM;
        }
-       memset(fhp,0,sizeof(*fhp));
 
        init_waitqueue_head(&fhp->wait_data);
        fhp->dev_info = dip;
@@ -840,6 +943,7 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
        pvr2_context_enter(vp->channel.mc_head); do {
                pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
                pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
+
                fhp->vnext = NULL;
                fhp->vprev = vp->vlast;
                if (vp->vlast) {
@@ -849,6 +953,18 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
                }
                vp->vlast = fhp;
                fhp->vhead = vp;
+
+               /* Opening the /dev/radioX device implies a mode switch.
+                  So execute that here.  Note that you can get the
+                  IDENTICAL effect merely by opening the normal video
+                  device and setting the input appropriately. */
+               if (dip->v4l_type == VFL_TYPE_RADIO) {
+                       struct pvr2_ctrl *cp;
+                       cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+                       pvr2_ctrl_get_value(cp,&fhp->prev_input_val);
+                       pvr2_ctrl_set_value(cp,PVR2_CVAL_INPUT_RADIO);
+                       pvr2_hdw_commit_ctl(hdw);
+               }
        } while (0); pvr2_context_exit(vp->channel.mc_head);
 
        fhp->file = file;
@@ -873,6 +989,12 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh)
        struct pvr2_hdw *hdw;
        if (fh->rhp) return 0;
 
+       if (!fh->dev_info->stream) {
+               /* No stream defined for this node.  This means that we're
+                  not currently allowed to stream from this node. */
+               return -EPERM;
+       }
+
        /* First read() attempt.  Try to claim the stream and start
           it... */
        if ((ret = pvr2_channel_claim_stream(&fh->channel,
@@ -1012,25 +1134,37 @@ static struct video_device vdev_template = {
 
 static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
                               struct pvr2_v4l2 *vp,
-                              enum pvr2_config cfg)
+                              int v4l_type)
 {
        int mindevnum;
        int unit_number;
-       int v4l_type;
+       int *nr_ptr = 0;
        dip->v4lp = vp;
-       dip->config = cfg;
 
 
-       switch (cfg) {
-       case pvr2_config_mpeg:
-               v4l_type = VFL_TYPE_GRABBER;
+       dip->v4l_type = v4l_type;
+       switch (v4l_type) {
+       case VFL_TYPE_GRABBER:
                dip->stream = &vp->channel.mc_head->video_stream;
+               dip->config = pvr2_config_mpeg;
+               dip->minor_type = pvr2_v4l_type_video;
+               nr_ptr = video_nr;
+               if (!dip->stream) {
+                       err("Failed to set up pvrusb2 v4l video dev"
+                           " due to missing stream instance");
+                       return;
+               }
                break;
-       case pvr2_config_vbi:
-               v4l_type = VFL_TYPE_VBI;
+       case VFL_TYPE_VBI:
+               dip->config = pvr2_config_vbi;
+               dip->minor_type = pvr2_v4l_type_vbi;
+               nr_ptr = vbi_nr;
                break;
-       case pvr2_config_radio:
-               v4l_type = VFL_TYPE_RADIO;
+       case VFL_TYPE_RADIO:
+               dip->stream = &vp->channel.mc_head->video_stream;
+               dip->config = pvr2_config_mpeg;
+               dip->minor_type = pvr2_v4l_type_radio;
+               nr_ptr = radio_nr;
                break;
        default:
                /* Bail out (this should be impossible) */
@@ -1039,30 +1173,27 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
                return;
        }
 
-       if (!dip->stream) {
-               err("Failed to set up pvrusb2 v4l dev"
-                   " due to missing stream instance");
-               return;
-       }
-
        memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template));
        dip->devbase.release = pvr2_video_device_release;
 
        mindevnum = -1;
        unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);
-       if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
-               mindevnum = video_nr[unit_number];
+       if (nr_ptr && (unit_number >= 0) && (unit_number < PVR_NUM)) {
+               mindevnum = nr_ptr[unit_number];
        }
-       if ((video_register_device(&dip->devbase, v4l_type, mindevnum) < 0) &&
-           (video_register_device(&dip->devbase, v4l_type, -1) < 0)) {
-               err("Failed to register pvrusb2 v4l video device");
-       } else {
-               printk(KERN_INFO "pvrusb2: registered device video%d [%s]\n",
-                      dip->devbase.minor,pvr2_config_get_name(dip->config));
+       if ((video_register_device(&dip->devbase,
+                                  dip->v4l_type, mindevnum) < 0) &&
+           (video_register_device(&dip->devbase,
+                                  dip->v4l_type, -1) < 0)) {
+               err("Failed to register pvrusb2 v4l device");
        }
 
+       printk(KERN_INFO "pvrusb2: registered device %s%u [%s]\n",
+              get_v4l_name(dip->v4l_type),dip->devbase.minor & 0x1f,
+              pvr2_config_get_name(dip->config));
+
        pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
-                                       dip->devbase.minor);
+                                       dip->minor_type,dip->devbase.minor);
 }
 
 
@@ -1070,22 +1201,24 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
 {
        struct pvr2_v4l2 *vp;
 
-       vp = kmalloc(sizeof(*vp),GFP_KERNEL);
+       vp = kzalloc(sizeof(*vp),GFP_KERNEL);
        if (!vp) return vp;
-       memset(vp,0,sizeof(*vp));
-       vp->vdev = kmalloc(sizeof(*vp->vdev),GFP_KERNEL);
-       if (!vp->vdev) {
+       vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
+       vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
+       if (!(vp->dev_video && vp->dev_radio)) {
+               kfree(vp->dev_video);
+               kfree(vp->dev_radio);
                kfree(vp);
                return NULL;
        }
-       memset(vp->vdev,0,sizeof(*vp->vdev));
        pvr2_channel_init(&vp->channel,mnp);
        pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
 
        vp->channel.check_func = pvr2_v4l2_internal_check;
 
        /* register streams */
-       pvr2_v4l2_dev_init(vp->vdev,vp,pvr2_config_mpeg);
+       pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER);
+       pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO);
 
        return vp;
 }
index 2a82646..61efa6f 100644 (file)
@@ -66,7 +66,9 @@ static void set_input(struct pvr2_v4l_decoder *ctxt)
                route.input = SAA7115_SVIDEO2;
                break;
        case PVR2_CVAL_INPUT_RADIO:
-               // ????? No idea yet what to do here
+               // In radio mode, we mute the video, but point at one
+               // spot just to stay consistent
+               route.input = SAA7115_COMPOSITE5;
        default:
                return;
        }
@@ -137,8 +139,7 @@ static int decoder_check(struct pvr2_v4l_decoder *ctxt)
        unsigned long msk;
        unsigned int idx;
 
-       for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
-            idx++) {
+       for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
                msk = 1 << idx;
                if (ctxt->stale_mask & msk) continue;
                if (decoder_ops[idx].check(ctxt)) {
@@ -154,8 +155,7 @@ static void decoder_update(struct pvr2_v4l_decoder *ctxt)
        unsigned long msk;
        unsigned int idx;
 
-       for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
-            idx++) {
+       for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
                msk = 1 << idx;
                if (!(ctxt->stale_mask & msk)) continue;
                ctxt->stale_mask &= ~msk;
@@ -183,18 +183,6 @@ static void decoder_enable(struct pvr2_v4l_decoder *ctxt,int fl)
 }
 
 
-static int decoder_is_tuned(struct pvr2_v4l_decoder *ctxt)
-{
-       struct v4l2_tuner vt;
-       int ret;
-
-       memset(&vt,0,sizeof(vt));
-       ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
-       if (ret < 0) return -EINVAL;
-       return vt.signal ? 1 : 0;
-}
-
-
 static unsigned int decoder_describe(struct pvr2_v4l_decoder *ctxt,char *buf,unsigned int cnt)
 {
        return scnprintf(buf,cnt,"handler: pvrusb2-video-v4l");
@@ -218,20 +206,17 @@ int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw,
        if (cp->handler) return 0;
        if (!decoder_detect(cp)) return 0;
 
-       ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+       ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
        if (!ctxt) return 0;
-       memset(ctxt,0,sizeof(*ctxt));
 
        ctxt->handler.func_data = ctxt;
        ctxt->handler.func_table = &hfuncs;
        ctxt->ctrl.ctxt = ctxt;
        ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
        ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
-       ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned;
        ctxt->client = cp;
        ctxt->hdw = hdw;
-       ctxt->stale_mask = (1 << (sizeof(decoder_ops)/
-                                 sizeof(decoder_ops[0]))) - 1;
+       ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
        hdw->decoder_ctrl = &ctxt->ctrl;
        cp->handler = &ctxt->handler;
        pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up",
index 7794c34..66b4d36 100644 (file)
@@ -50,15 +50,21 @@ static void set_input(struct pvr2_v4l_wm8775 *ctxt)
 {
        struct v4l2_routing route;
        struct pvr2_hdw *hdw = ctxt->hdw;
-       int msk = 0;
 
        memset(&route,0,sizeof(route));
 
-       pvr2_trace(PVR2_TRACE_CHIPS,"i2c wm8775 set_input(val=%d msk=0x%x)",
-                  hdw->input_val,msk);
+       switch(hdw->input_val) {
+       case PVR2_CVAL_INPUT_RADIO:
+               route.input = 1;
+               break;
+       default:
+               /* All other cases just use the second input */
+               route.input = 2;
+               break;
+       }
+       pvr2_trace(PVR2_TRACE_CHIPS,"i2c wm8775 set_input(val=%d route=0x%x)",
+                  hdw->input_val,route.input);
 
-       // Always point to input #1 no matter what
-       route.input = 2;
        pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
 }
 
@@ -99,8 +105,7 @@ static int wm8775_check(struct pvr2_v4l_wm8775 *ctxt)
        unsigned long msk;
        unsigned int idx;
 
-       for (idx = 0; idx < sizeof(wm8775_ops)/sizeof(wm8775_ops[0]);
-            idx++) {
+       for (idx = 0; idx < ARRAY_SIZE(wm8775_ops); idx++) {
                msk = 1 << idx;
                if (ctxt->stale_mask & msk) continue;
                if (wm8775_ops[idx].check(ctxt)) {
@@ -116,8 +121,7 @@ static void wm8775_update(struct pvr2_v4l_wm8775 *ctxt)
        unsigned long msk;
        unsigned int idx;
 
-       for (idx = 0; idx < sizeof(wm8775_ops)/sizeof(wm8775_ops[0]);
-            idx++) {
+       for (idx = 0; idx < ARRAY_SIZE(wm8775_ops); idx++) {
                msk = 1 << idx;
                if (!(ctxt->stale_mask & msk)) continue;
                ctxt->stale_mask &= ~msk;
@@ -140,16 +144,14 @@ int pvr2_i2c_wm8775_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
 
        if (cp->handler) return 0;
 
-       ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+       ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
        if (!ctxt) return 0;
-       memset(ctxt,0,sizeof(*ctxt));
 
        ctxt->handler.func_data = ctxt;
        ctxt->handler.func_table = &hfuncs;
        ctxt->client = cp;
        ctxt->hdw = hdw;
-       ctxt->stale_mask = (1 << (sizeof(wm8775_ops)/
-                                 sizeof(wm8775_ops[0]))) - 1;
+       ctxt->stale_mask = (1 << ARRAY_SIZE(wm8775_ops)) - 1;
        cp->handler = &ctxt->handler;
        pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x wm8775 V4L2 handler set up",
                   cp->client->addr);
index 9db2260..f5c8ec2 100644 (file)
@@ -2,11 +2,3 @@ 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 9825fd3..27ed769 100644 (file)
@@ -128,7 +128,7 @@ static int default_size = PSZ_QCIF;
 static int default_fps = 10;
 static int default_fbufs = 3;   /* Default number of frame buffers */
        int pwc_mbufs = 2;      /* Default number of mmap() buffers */
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
        int pwc_trace = PWC_DEBUG_LEVEL;
 #endif
 static int power_save = 0;
@@ -1051,7 +1051,7 @@ static void pwc_remove_sysfs_files(struct video_device *vdev)
        video_device_remove_file(vdev, &class_device_attr_button);
 }
 
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
 static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
 {
        switch(sensor_type) {
@@ -1835,7 +1835,7 @@ module_param(size, charp, 0444);
 module_param(fps, int, 0444);
 module_param(fbufs, int, 0444);
 module_param(mbufs, int, 0444);
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
 module_param_named(trace, pwc_trace, int, 0644);
 #endif
 module_param(power_save, int, 0444);
@@ -1908,7 +1908,7 @@ static int __init usb_pwc_init(void)
                default_fbufs = fbufs;
                PWC_DEBUG_MODULE("Number of frame buffers set to %d.\n", default_fbufs);
        }
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
        if (pwc_trace >= 0) {
                PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
        }
index b7eb3ce..d5e6bc8 100644 (file)
@@ -350,7 +350,7 @@ int pwc_video_do_ioctl(struct inode *inode, struct file *file,
        if (pdev == NULL)
                return -EFAULT;
 
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
        if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace)
                v4l_printk_ioctl(cmd);
 #endif
index 7e9c423..e778a2b 100644 (file)
 #include "pwc-uncompress.h"
 #include <media/pwc-ioctl.h>
 
-/* Turn some debugging options on/off */
-#ifndef CONFIG_PWC_DEBUG
-#define CONFIG_PWC_DEBUG 1
-#endif
-
 /* Version block */
 #define PWC_MAJOR      10
 #define PWC_MINOR      0
@@ -76,7 +71,7 @@
 #define PWC_DEBUG_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args)
 
 
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
 
 #define PWC_DEBUG_LEVEL        (PWC_DEBUG_LEVEL_MODULE)
 
@@ -270,7 +265,7 @@ extern "C" {
 #endif
 
 /* Global variables */
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
 extern int pwc_trace;
 #endif
 extern int pwc_mbufs;
index 76f5f5d..e20aa36 100644 (file)
@@ -111,7 +111,7 @@ static int saa5246a_attach(struct i2c_adapter *adap, int addr, int kind)
        for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++)
        {
                memset(t->pgbuf[pgbuf], ' ', sizeof(t->pgbuf[0]));
-               t->is_searching[pgbuf] = FALSE;
+               t->is_searching[pgbuf] = false;
        }
        vd->priv=t;
 
@@ -198,7 +198,7 @@ static int i2c_senddata(struct saa5246a_device *t, ...)
 
 /* Get count number of bytes from I²C-device at address adr, store them in buf.
  * Start & stop handshaking is done by this routine, ack will be sent after the
- * last byte to inhibit further sending of data. If uaccess is TRUE, data is
+ * last byte to inhibit further sending of data. If uaccess is 'true', data is
  * written to user-space with put_user. Returns -1 if I²C-device didn't send
  * acknowledge, 0 otherwise
  */
@@ -338,7 +338,7 @@ static int saa5246a_request_page(struct saa5246a_device *t,
                return -EIO;
        }
 
-       t->is_searching[req->pgbuf] = TRUE;
+       t->is_searching[req->pgbuf] = true;
        return 0;
 }
 
@@ -452,7 +452,7 @@ static inline int saa5246a_get_status(struct saa5246a_device *t,
                }
        }
        if (!info->hamming && !info->notfound)
-               t->is_searching[dau_no] = FALSE;
+               t->is_searching[dau_no] = false;
        return 0;
 }
 
@@ -564,7 +564,7 @@ static inline int saa5246a_stop_dau(struct saa5246a_device *t,
        {
                return -EIO;
        }
-       t->is_searching[dau_no] = FALSE;
+       t->is_searching[dau_no] = false;
        return 0;
 }
 
index 7b91112..64394c0 100644 (file)
 #define POS_HEADER_START 7
 #define POS_HEADER_END 31
 
-/* Returns TRUE if the part of the videotext page described with req contains
+/* Returns 'true' if the part of the videotext page described with req contains
    (at least parts of) the time field */
 #define REQ_CONTAINS_TIME(p_req) \
        ((p_req)->start <= POS_TIME_END && \
         (p_req)->end   >= POS_TIME_START)
 
-/* Returns TRUE if the part of the videotext page described with req contains
+/* Returns 'true' if the part of the videotext page described with req contains
    (at least parts of) the page header */
 #define REQ_CONTAINS_HEADER(p_req) \
        ((p_req)->start <= POS_HEADER_END && \
         (p_req)->end   >= POS_HEADER_START)
 
-#ifndef FALSE
-#define FALSE 0
-#define TRUE 1
-#endif
-
 /*****************************************************************************/
 /* Mode register numbers of the SAA5246A                                    */
 /*****************************************************************************/
index 3e84737..f2a2f34 100644 (file)
@@ -124,11 +124,6 @@ struct saa5249_device
 
 /* General defines and debugging support */
 
-#ifndef FALSE
-#define FALSE 0
-#define TRUE 1
-#endif
-
 #define RESCHED do { cond_resched(); } while(0)
 
 static struct video_device saa_template;       /* Declared near bottom */
@@ -183,9 +178,9 @@ static int saa5249_attach(struct i2c_adapter *adap, int addr, int kind)
                memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
                memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
                t->vdau[pgbuf].expire = 0;
-               t->vdau[pgbuf].clrfound = TRUE;
-               t->vdau[pgbuf].stopped = TRUE;
-               t->is_searching[pgbuf] = FALSE;
+               t->vdau[pgbuf].clrfound = true;
+               t->vdau[pgbuf].stopped = true;
+               t->is_searching[pgbuf] = false;
        }
        vd->priv=t;
 
@@ -298,7 +293,7 @@ static int i2c_senddata(struct saa5249_device *t, ...)
 
 /* Get count number of bytes from I²C-device at address adr, store them in buf. Start & stop
  * handshaking is done by this routine, ack will be sent after the last byte to inhibit further
- * sending of data. If uaccess is TRUE, data is written to user-space with put_user.
+ * sending of data. If uaccess is 'true', data is written to user-space with put_user.
  * Returns -1 if I²C-device didn't send acknowledge, 0 otherwise
  */
 
@@ -317,7 +312,7 @@ static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf)
 static int do_saa5249_ioctl(struct inode *inode, struct file *file,
                            unsigned int cmd, void *arg)
 {
-       static int virtual_mode = FALSE;
+       static int virtual_mode = false;
        struct video_device *vd = video_devdata(file);
        struct saa5249_device *t=vd->priv;
 
@@ -340,7 +335,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
                        if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
                                return -EINVAL;
                        memset(t->vdau[req->pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
-                       t->vdau[req->pgbuf].clrfound = TRUE;
+                       t->vdau[req->pgbuf].clrfound = true;
                        return 0;
                }
 
@@ -350,7 +345,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
 
                        if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
                                return -EINVAL;
-                       t->vdau[req->pgbuf].clrfound = TRUE;
+                       t->vdau[req->pgbuf].clrfound = true;
                        return 0;
                }
 
@@ -376,9 +371,9 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
                        t->vdau[req->pgbuf].sregs[4] = (req->pagemask & HR_UNIT ? 0x10 : 0) | (req->hour & 0xf);
                        t->vdau[req->pgbuf].sregs[5] = (req->pagemask & MIN_TEN ? 0x10 : 0) | (req->minute / 0x10);
                        t->vdau[req->pgbuf].sregs[6] = (req->pagemask & MIN_UNIT ? 0x10 : 0) | (req->minute & 0xf);
-                       t->vdau[req->pgbuf].stopped = FALSE;
-                       t->vdau[req->pgbuf].clrfound = TRUE;
-                       t->is_searching[req->pgbuf] = TRUE;
+                       t->vdau[req->pgbuf].stopped = false;
+                       t->vdau[req->pgbuf].clrfound = true;
+                       t->is_searching[req->pgbuf] = true;
                        return 0;
                }
 
@@ -430,7 +425,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
                                                        i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 23 * 40))
                                                        return -EIO;
                                        }
-                                       t->vdau[req->pgbuf].clrfound = FALSE;
+                                       t->vdau[req->pgbuf].clrfound = false;
                                        memcpy(t->vdau[req->pgbuf].laststat, infobits, sizeof(infobits));
                                }
                                else
@@ -474,7 +469,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
                                return -EFAULT;
                        if (!info.hamming && !info.notfound)
                        {
-                               t->is_searching[req->pgbuf] = FALSE;
+                               t->is_searching[req->pgbuf] = false;
                        }
                        return 0;
                }
@@ -530,8 +525,8 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
 
                        if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
                                return -EINVAL;
-                       t->vdau[req->pgbuf].stopped = TRUE;
-                       t->is_searching[req->pgbuf] = FALSE;
+                       t->vdau[req->pgbuf].stopped = true;
+                       t->is_searching[req->pgbuf] = false;
                        return 0;
                }
 
@@ -660,11 +655,11 @@ static int saa5249_open(struct inode *inode, struct file *file)
                memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
                memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
                t->vdau[pgbuf].expire = 0;
-               t->vdau[pgbuf].clrfound = TRUE;
-               t->vdau[pgbuf].stopped = TRUE;
-               t->is_searching[pgbuf] = FALSE;
+               t->vdau[pgbuf].clrfound = true;
+               t->vdau[pgbuf].stopped = true;
+               t->is_searching[pgbuf] = false;
        }
-       t->virtual_mode=FALSE;
+       t->virtual_mode = false;
        return 0;
 
  fail:
index c2374ed..c4f066d 100644 (file)
@@ -71,6 +71,7 @@ I2C_CLIENT_INSMOD;
 struct saa711x_state {
        v4l2_std_id std;
        int input;
+       int output;
        int enable;
        int radio;
        int bright;
@@ -1301,7 +1302,7 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
                struct v4l2_routing *route = arg;
 
                route->input = state->input;
-               route->output = 0;
+               route->output = state->output;
                break;
        }
 
@@ -1309,7 +1310,7 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
        {
                struct v4l2_routing *route = arg;
 
-               v4l_dbg(1, debug, client, "decoder set input %d\n", route->input);
+               v4l_dbg(1, debug, client, "decoder set input %d output %d\n", route->input, route->output);
                /* saa7113 does not have these inputs */
                if (state->ident == V4L2_IDENT_SAA7113 &&
                    (route->input == SAA7115_COMPOSITE4 ||
@@ -1318,10 +1319,12 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
                }
                if (route->input > SAA7115_SVIDEO3)
                        return -EINVAL;
-               if (state->input == route->input)
+               if (route->output > SAA7115_IPORT_ON)
+                       return -EINVAL;
+               if (state->input == route->input && state->output == route->output)
                        break;
-               v4l_dbg(1, debug, client, "now setting %s input\n",
-                       (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite");
+               v4l_dbg(1, debug, client, "now setting %s input %s output\n",
+                       (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite", (route->output == SAA7115_IPORT_ON) ? "iport on" : "iport off");
                state->input = route->input;
 
                /* select mode */
@@ -1333,6 +1336,14 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
                saa711x_write(client, R_09_LUMA_CNTL,
                              (saa711x_read(client, R_09_LUMA_CNTL) & 0x7f) |
                               (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
+
+               state->output = route->output;
+               if (state->ident == V4L2_IDENT_SAA7114 ||
+                       state->ident == V4L2_IDENT_SAA7115) {
+                       saa711x_write(client, R_83_X_PORT_I_O_ENA_AND_OUT_CLK,
+                             (saa711x_read(client, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) |
+                              (state->output & 0x01));
+               }
                break;
        }
 
@@ -1377,6 +1388,9 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
        {
                struct v4l2_sliced_vbi_data *data = arg;
 
+               /* Note: the internal field ID is inverted for NTSC,
+                  so data->field 0 maps to the saa7115 even field,
+                  whereas for PAL it maps to the saa7115 odd field. */
                switch (data->id) {
                case V4L2_SLICED_WSS_625:
                        if (saa711x_read(client, 0x6b) & 0xc0)
@@ -1387,17 +1401,17 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
                case V4L2_SLICED_CAPTION_525:
                        if (data->field == 0) {
                                /* CC */
-                               if (saa711x_read(client, 0x66) & 0xc0)
+                               if (saa711x_read(client, 0x66) & 0x30)
                                        return -EIO;
-                               data->data[0] = saa711x_read(client, 0x67);
-                               data->data[1] = saa711x_read(client, 0x68);
+                               data->data[0] = saa711x_read(client, 0x69);
+                               data->data[1] = saa711x_read(client, 0x6a);
                                return 0;
                        }
                        /* XDS */
-                       if (saa711x_read(client, 0x66) & 0x30)
+                       if (saa711x_read(client, 0x66) & 0xc0)
                                return -EIO;
-                       data->data[0] = saa711x_read(client, 0x69);
-                       data->data[1] = saa711x_read(client, 0x6a);
+                       data->data[0] = saa711x_read(client, 0x67);
+                       data->data[1] = saa711x_read(client, 0x68);
                        return 0;
                default:
                        return -EINVAL;
@@ -1406,17 +1420,8 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
        }
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-       case VIDIOC_INT_G_REGISTER:
-       {
-               struct v4l2_register *reg = arg;
-
-               if (reg->i2c_id != I2C_DRIVERID_SAA711X)
-                       return -EINVAL;
-               reg->val = saa711x_read(client, reg->reg & 0xff);
-               break;
-       }
-
-       case VIDIOC_INT_S_REGISTER:
+       case VIDIOC_DBG_G_REGISTER:
+       case VIDIOC_DBG_S_REGISTER:
        {
                struct v4l2_register *reg = arg;
 
@@ -1424,7 +1429,10 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
                        return -EINVAL;
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
+               if (cmd == VIDIOC_DBG_G_REGISTER)
+                       reg->val = saa711x_read(client, reg->reg & 0xff);
+               else
+                       saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
                break;
        }
 #endif
@@ -1492,6 +1500,7 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
                return -ENOMEM;
        }
        state->input = -1;
+       state->output = SAA7115_IPORT_ON;
        state->enable = 1;
        state->radio = 0;
        state->bright = 128;
@@ -1550,7 +1559,7 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
 
 static int saa711x_probe(struct i2c_adapter *adapter)
 {
-       if (adapter->class & I2C_CLASS_TV_ANALOG)
+       if (adapter->class & I2C_CLASS_TV_ANALOG || adapter->class & I2C_CLASS_TV_DIGITAL)
                return i2c_probe(adapter, &addr_data, &saa711x_attach);
        return 0;
 }
index ad401bd..bd9c4f3 100644 (file)
@@ -614,17 +614,8 @@ static int saa7127_command(struct i2c_client *client,
                break;
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-       case VIDIOC_INT_G_REGISTER:
-       {
-               struct v4l2_register *reg = arg;
-
-               if (reg->i2c_id != I2C_DRIVERID_SAA7127)
-                       return -EINVAL;
-               reg->val = saa7127_read(client, reg->reg & 0xff);
-               break;
-       }
-
-       case VIDIOC_INT_S_REGISTER:
+       case VIDIOC_DBG_G_REGISTER:
+       case VIDIOC_DBG_S_REGISTER:
        {
                struct v4l2_register *reg = arg;
 
@@ -632,7 +623,10 @@ static int saa7127_command(struct i2c_client *client,
                        return -EINVAL;
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               saa7127_write(client, reg->reg & 0xff, reg->val & 0xff);
+               if (cmd == VIDIOC_DBG_G_REGISTER)
+                       reg->val = saa7127_read(client, reg->reg & 0xff);
+               else
+                       saa7127_write(client, reg->reg & 0xff, reg->val & 0xff);
                break;
        }
 #endif
index 89a1565..c85c8a8 100644 (file)
@@ -14,7 +14,3 @@ obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
 EXTRA_CFLAGS += -Idrivers/media/video
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
-
-extra-cflags-$(CONFIG_VIDEO_BUF_DVB) += -DHAVE_VIDEO_BUF_DVB=1
-
-EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
index ae984bb..89f3210 100644 (file)
@@ -2469,6 +2469,11 @@ struct saa7134_board saa7134_boards[] = {
                        .amux = LINE2,
                        .gpio = 0x0200000,
                },{
+                       .name = name_comp2,
+                       .vmux = 0,
+                       .amux = LINE2,
+                       .gpio = 0x0200000,
+               },{
                        .name = name_svideo,
                        .vmux = 8,
                        .amux = LINE2,
@@ -3183,6 +3188,107 @@ struct saa7134_board saa7134_boards[] = {
                        .amux   = LINE1,
                }},
        },
+       [SAA7134_BOARD_ENCORE_ENLTV] = {
+       /* Steven Walter <stevenrwalter@gmail.com>
+          Juan Pablo Sormani <sorman@gmail.com> */
+               .name           = "Encore ENLTV",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_TNF_5335MF,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = 3,
+                       .tv   = 1,
+               },{
+                       .name = name_tv_mono,
+                       .vmux = 7,
+                       .amux = 4,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = 2,
+               },{
+                       .name = name_svideo,
+                       .vmux = 0,
+                       .amux = 2,
+               }},
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+/*                     .gpio = 0x00300001,*/
+                       .gpio = 0x20000,
+
+               },
+               .mute = {
+                       .name = name_mute,
+                       .amux = 0,
+               },
+       },
+       [SAA7134_BOARD_ENCORE_ENLTV_FM] = {
+  /*   Juan Pablo Sormani <sorman@gmail.com> */
+               .name           = "Encore ENLTV-FM",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_PHILIPS_ATSC,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = 3,
+                       .tv   = 1,
+               },{
+                       .name = name_tv_mono,
+                       .vmux = 7,
+                       .amux = 4,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = 2,
+               },{
+                       .name = name_svideo,
+                       .vmux = 0,
+                       .amux = 2,
+               }},
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+                       .gpio = 0x20000,
+
+               },
+               .mute = {
+                       .name = name_mute,
+                       .amux = 0,
+               },
+       },
+       [SAA7134_BOARD_CINERGY_HT_PCI] = {
+               .name           = "Terratec Cinergy HT PCI",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .inputs = {{
+                       .name   = name_tv,
+                       .vmux   = 1,
+                       .amux   = TV,
+                       .tv     = 1,
+               },{
+                       .name   = name_comp1,
+                       .vmux   = 0,
+                       .amux   = LINE1,
+               },{
+                       .name   = name_svideo,
+                       .vmux   = 6,
+                       .amux   = LINE1,
+               }},
+       },
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -3822,6 +3928,36 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subdevice    = 0x1172,
                .driver_data  = SAA7134_BOARD_CINERGY_HT_PCMCIA,
        },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+               .subvendor    = PCI_VENDOR_ID_PHILIPS,
+               .subdevice    = 0x2342,
+               .driver_data  = SAA7134_BOARD_ENCORE_ENLTV,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+               .subvendor    = 0x1131,
+               .subdevice    = 0x2341,
+               .driver_data  = SAA7134_BOARD_ENCORE_ENLTV,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+               .subvendor    = 0x3016,
+               .subdevice    = 0x2344,
+               .driver_data  = SAA7134_BOARD_ENCORE_ENLTV,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+               .subvendor    = 0x1131,
+               .subdevice    = 0x230f,
+               .driver_data  = SAA7134_BOARD_ENCORE_ENLTV_FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x153b,
+               .subdevice    = 0x1175,
+               .driver_data  = SAA7134_BOARD_CINERGY_HT_PCI,
+       },{
                /* --- boards without eeprom + subsystem ID --- */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -3926,9 +4062,12 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_KWORLD_TERMINATOR:
        case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
        case SAA7134_BOARD_FLYDVBT_LR301:
+       case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
        case SAA7134_BOARD_FLYDVBTDUO:
        case SAA7134_BOARD_PROTEUS_2309:
        case SAA7134_BOARD_AVERMEDIA_A16AR:
+       case SAA7134_BOARD_ENCORE_ENLTV:
+       case SAA7134_BOARD_ENCORE_ENLTV_FM:
                dev->has_remote = SAA7134_REMOTE_GPIO;
                break;
        case SAA7134_BOARD_FLYDVBS_LR300:
@@ -4150,6 +4289,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
                }
                break;
        case SAA7134_BOARD_CINERGY_HT_PCMCIA:
+       case SAA7134_BOARD_CINERGY_HT_PCI:
                /* make the tda10046 find its eeprom */
                {
                u8 data[] = { 0x3c, 0x33, 0x60};
index c33f6a6..e3059fd 100644 (file)
@@ -1426,6 +1426,18 @@ static int dvb_init(struct saa7134_dev *dev)
 
                }
                break;
+       case SAA7134_BOARD_CINERGY_HT_PCI:
+               dev->dvb.frontend = dvb_attach(tda10046_attach,
+                                              &cinergy_ht_config,
+                                              &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
+                       dev->dvb.frontend->ops.tuner_ops.init = cinergy_ht_tuner_init;
+                       dev->dvb.frontend->ops.tuner_ops.sleep = cinergy_ht_tuner_sleep;
+                       dev->dvb.frontend->ops.tuner_ops.set_params = md8800_dvbt_pll_set;
+
+               }
+               break;
        default:
                printk("%s: Huh? unknown DVB card?\n",dev->name);
                break;
index 6f9fe86..cce8da6 100644 (file)
@@ -120,9 +120,9 @@ static inline int i2c_is_error(enum i2c_status status)
        case ARB_LOST:
        case SEQ_ERR:
        case ST_ERR:
-               return TRUE;
+               return true;
        default:
-               return FALSE;
+               return false;
        }
 }
 
@@ -131,9 +131,9 @@ static inline int i2c_is_idle(enum i2c_status status)
        switch (status) {
        case IDLE:
        case DONE_STOP:
-               return TRUE;
+               return true;
        default:
-               return FALSE;
+               return false;
        }
 }
 
@@ -141,9 +141,9 @@ static inline int i2c_is_busy(enum i2c_status status)
 {
        switch (status) {
        case BUSY:
-               return TRUE;
+               return true;
        default:
-               return FALSE;
+               return false;
        }
 }
 
@@ -159,8 +159,8 @@ static int i2c_is_busy_wait(struct saa7134_dev *dev)
                saa_wait(I2C_WAIT_DELAY);
        }
        if (I2C_WAIT_RETRY == count)
-               return FALSE;
-       return TRUE;
+               return false;
+       return true;
 }
 
 static int i2c_reset(struct saa7134_dev *dev)
@@ -171,7 +171,7 @@ static int i2c_reset(struct saa7134_dev *dev)
        d2printk(KERN_DEBUG "%s: i2c reset\n",dev->name);
        status = i2c_get_status(dev);
        if (!i2c_is_error(status))
-               return TRUE;
+               return true;
        i2c_set_status(dev,status);
 
        for (count = 0; count < I2C_WAIT_RETRY; count++) {
@@ -181,13 +181,13 @@ static int i2c_reset(struct saa7134_dev *dev)
                udelay(I2C_WAIT_DELAY);
        }
        if (I2C_WAIT_RETRY == count)
-               return FALSE;
+               return false;
 
        if (!i2c_is_idle(status))
-               return FALSE;
+               return false;
 
        i2c_set_attr(dev,NOP);
-       return TRUE;
+       return true;
 }
 
 static inline int i2c_send_byte(struct saa7134_dev *dev,
index e425268..46c583f 100644 (file)
@@ -40,16 +40,24 @@ 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)");
 
+static int ir_rc5_remote_gap = 885;
+module_param(ir_rc5_remote_gap, int, 0644);
+static int ir_rc5_key_timeout = 115;
+module_param(ir_rc5_key_timeout, int, 0644);
+
 #define dprintk(fmt, arg...)   if (ir_debug) \
        printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
 #define i2cdprintk(fmt, arg...)    if (ir_debug) \
        printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
 
+/** rc5 functions */
+static int saa7134_rc5_irq(struct saa7134_dev *dev);
+
 /* -------------------- GPIO generic keycode builder -------------------- */
 
 static int build_key(struct saa7134_dev *dev)
 {
-       struct saa7134_ir *ir = dev->remote;
+       struct card_ir *ir = dev->remote;
        u32 gpio, data;
 
        /* rising SAA7134_GPIO_GPRESCAN reads the status */
@@ -134,16 +142,19 @@ static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 
 void saa7134_input_irq(struct saa7134_dev *dev)
 {
-       struct saa7134_ir *ir = dev->remote;
+       struct card_ir *ir = dev->remote;
 
-       if (!ir->polling)
+       if (!ir->polling && !ir->rc5_gpio) {
                build_key(dev);
+       } else if (ir->rc5_gpio) {
+               saa7134_rc5_irq(dev);
+       }
 }
 
 static void saa7134_input_timer(unsigned long data)
 {
        struct saa7134_dev *dev = (struct saa7134_dev*)data;
-       struct saa7134_ir *ir = dev->remote;
+       struct card_ir *ir = dev->remote;
        unsigned long timeout;
 
        build_key(dev);
@@ -151,7 +162,7 @@ static void saa7134_input_timer(unsigned long data)
        mod_timer(&ir->timer, timeout);
 }
 
-static void saa7134_ir_start(struct saa7134_dev *dev, struct saa7134_ir *ir)
+static void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
 {
        if (ir->polling) {
                init_timer(&ir->timer);
@@ -159,6 +170,19 @@ static void saa7134_ir_start(struct saa7134_dev *dev, struct saa7134_ir *ir)
                ir->timer.data     = (unsigned long)dev;
                ir->timer.expires  = jiffies + HZ;
                add_timer(&ir->timer);
+       } else if (ir->rc5_gpio) {
+               /* set timer_end for code completion */
+               init_timer(&ir->timer_end);
+               ir->timer_end.function = ir_rc5_timer_end;
+               ir->timer_end.data = (unsigned long)ir;
+               init_timer(&ir->timer_keyup);
+               ir->timer_keyup.function = ir_rc5_timer_keyup;
+               ir->timer_keyup.data = (unsigned long)ir;
+               ir->shift_by = 2;
+               ir->start = 0x2;
+               ir->addr = 0x17;
+               ir->rc5_key_timeout = ir_rc5_key_timeout;
+               ir->rc5_remote_gap = ir_rc5_remote_gap;
        }
 }
 
@@ -170,13 +194,14 @@ static void saa7134_ir_stop(struct saa7134_dev *dev)
 
 int saa7134_input_init1(struct saa7134_dev *dev)
 {
-       struct saa7134_ir *ir;
+       struct card_ir *ir;
        struct input_dev *input_dev;
        IR_KEYTAB_TYPE *ir_codes = NULL;
        u32 mask_keycode = 0;
        u32 mask_keydown = 0;
        u32 mask_keyup   = 0;
        int polling      = 0;
+       int rc5_gpio     = 0;
        int ir_type      = IR_TYPE_OTHER;
        int err;
 
@@ -295,6 +320,18 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                mask_keycode = 0x0001F00;
                mask_keydown = 0x0040000;
                break;
+       case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+               ir_codes     = ir_codes_asus_pc39;
+               mask_keydown = 0x0040000;
+               rc5_gpio = 1;
+               break;
+       case SAA7134_BOARD_ENCORE_ENLTV:
+       case SAA7134_BOARD_ENCORE_ENLTV_FM:
+               ir_codes     = ir_codes_encore_enltv;
+               mask_keycode = 0x00007f;
+               mask_keyup   = 0x040000;
+               polling      = 50; // ms
+               break;
        }
        if (NULL == ir_codes) {
                printk("%s: Oops: IR config error [card=%d]\n",
@@ -316,6 +353,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        ir->mask_keydown = mask_keydown;
        ir->mask_keyup   = mask_keyup;
        ir->polling      = polling;
+       ir->rc5_gpio     = rc5_gpio;
 
        /* init input device */
        snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
@@ -402,6 +440,49 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
        }
 
 }
+
+static int saa7134_rc5_irq(struct saa7134_dev *dev)
+{
+       struct card_ir *ir = dev->remote;
+       struct timeval tv;
+       u32 gap;
+       unsigned long current_jiffies, timeout;
+
+       /* get time of bit */
+       current_jiffies = jiffies;
+       do_gettimeofday(&tv);
+
+       /* avoid overflow with gap >1s */
+       if (tv.tv_sec - ir->base_time.tv_sec > 1) {
+               gap = 200000;
+       } else {
+               gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+                   tv.tv_usec - ir->base_time.tv_usec;
+       }
+
+       /* active code => add bit */
+       if (ir->active) {
+               /* only if in the code (otherwise spurious IRQ or timer
+                  late) */
+               if (ir->last_bit < 28) {
+                       ir->last_bit = (gap - ir_rc5_remote_gap / 2) /
+                           ir_rc5_remote_gap;
+                       ir->code |= 1 << ir->last_bit;
+               }
+               /* starting new code */
+       } else {
+               ir->active = 1;
+               ir->code = 0;
+               ir->base_time = tv;
+               ir->last_bit = 0;
+
+               timeout = current_jiffies + (500 + 30 * HZ) / 1000;
+               mod_timer(&ir->timer_end, timeout);
+       }
+
+       return 1;
+}
+
 /* ----------------------------------------------------------------------
  * Local variables:
  * c-basic-offset: 8
index 88cd129..b3e3957 100644 (file)
 #include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
+#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
 #include <media/video-buf-dvb.h>
-
-#ifndef TRUE
-# define TRUE (1==1)
-#endif
-#ifndef FALSE
-# define FALSE (1==0)
 #endif
+
 #define UNSET (-1U)
 
 /* ----------------------------------------------------------- */
@@ -232,6 +228,9 @@ struct saa7134_format {
 #define SAA7134_BOARD_VIDEOMATE_DVBT_200A  103
 #define SAA7134_BOARD_HAUPPAUGE_HVR1110    104
 #define SAA7134_BOARD_CINERGY_HT_PCMCIA    105
+#define SAA7134_BOARD_ENCORE_ENLTV         106
+#define SAA7134_BOARD_ENCORE_ENLTV_FM      107
+#define SAA7134_BOARD_CINERGY_HT_PCI       108
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -411,20 +410,6 @@ struct saa7134_dmasound {
        struct snd_pcm_substream   *substream;
 };
 
-/* IR input */
-struct saa7134_ir {
-       struct input_dev           *dev;
-       struct ir_input_state      ir;
-       char                       name[32];
-       char                       phys[32];
-       u32                        mask_keycode;
-       u32                        mask_keydown;
-       u32                        mask_keyup;
-       int                        polling;
-       u32                        last_gpio;
-       struct timer_list          timer;
-};
-
 /* ts/mpeg status */
 struct saa7134_ts {
        /* TS capture */
@@ -463,7 +448,7 @@ struct saa7134_dev {
 
        /* infrared remote */
        int                        has_remote;
-       struct saa7134_ir          *remote;
+       struct card_ir             *remote;
 
        /* pci i/o */
        char                       name[32];
@@ -543,9 +528,11 @@ struct saa7134_dev {
        struct work_struct         empress_workqueue;
        int                        empress_started;
 
+#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
        /* SAA7134_MPEG_DVB only */
        struct videobuf_dvb        dvb;
        int (*original_demod_sleep)(struct dvb_frontend* fe);
+#endif
 };
 
 /* ----------------------------------------------------------- */
@@ -698,6 +685,7 @@ void saa7134_input_fini(struct saa7134_dev *dev);
 void saa7134_input_irq(struct saa7134_dev *dev);
 void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir);
 
+
 /*
  * Local variables:
  * c-basic-offset: 8
index cf552e6..1a7ccb6 100644 (file)
@@ -1,9 +1,9 @@
 config USB_SN9C102
-       tristate "USB SN9C10x PC Camera Controller support"
+       tristate "USB SN9C1xx PC Camera Controller support"
        depends on USB && VIDEO_V4L1
        ---help---
          Say Y here if you want support for cameras based on SONiX SN9C101,
-         SN9C102 or SN9C103 PC Camera Controllers.
+         SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers.
 
          See <file:Documentation/video4linux/sn9c102.txt> for more info.
 
index 536ad30..30e3dfe 100644 (file)
@@ -1,5 +1,5 @@
 sn9c102-objs    := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \
-                  sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bca.o \
+                  sn9c102_ov7630.o sn9c102_ov7660.o sn9c102_pas106b.o \
                   sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \
                   sn9c102_tas5130d1b.o
 
index 2c6ff39..5428f34 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- * V4L2 driver for SN9C10x PC Camera Controllers                           *
+ * V4L2 driver for SN9C1xx PC Camera Controllers                           *
  *                                                                         *
  * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
 #include <linux/string.h>
 #include <linux/stddef.h>
 
+#include "sn9c102_config.h"
 #include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
 
-/*****************************************************************************/
-
-#define SN9C102_DEBUG
-#define SN9C102_DEBUG_LEVEL       2
-#define SN9C102_MAX_DEVICES       64
-#define SN9C102_PRESERVE_IMGSCALE 0
-#define SN9C102_FORCE_MUNMAP      0
-#define SN9C102_MAX_FRAMES        32
-#define SN9C102_URBS              2
-#define SN9C102_ISO_PACKETS       7
-#define SN9C102_ALTERNATE_SETTING 8
-#define SN9C102_URB_TIMEOUT       msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
-#define SN9C102_CTRL_TIMEOUT      300
-#define SN9C102_FRAME_TIMEOUT     2
-
-/*****************************************************************************/
-
-enum sn9c102_bridge {
-       BRIDGE_SN9C101 = 0x01,
-       BRIDGE_SN9C102 = 0x02,
-       BRIDGE_SN9C103 = 0x04,
-};
-
-SN9C102_ID_TABLE
-SN9C102_SENSOR_TABLE
 
 enum sn9c102_frame_state {
        F_UNUSED,
@@ -99,13 +76,11 @@ enum sn9c102_stream_state {
        STREAM_ON,
 };
 
-typedef char sn9c103_sof_header_t[18];
-typedef char sn9c102_sof_header_t[12];
-typedef char sn9c102_eof_header_t[4];
+typedef char sn9c102_sof_header_t[62];
 
 struct sn9c102_sysfs_attr {
        u8 reg, i2c_reg;
-       sn9c103_sof_header_t frame_header;
+       sn9c102_sof_header_t frame_header;
 };
 
 struct sn9c102_module_param {
@@ -137,8 +112,8 @@ struct sn9c102_device {
        struct v4l2_jpegcompression compression;
 
        struct sn9c102_sysfs_attr sysfs;
-       sn9c103_sof_header_t sof_header;
-       u16 reg[63];
+       sn9c102_sof_header_t sof_header;
+       u16 reg[384];
 
        struct sn9c102_module_param module_param;
 
@@ -155,10 +130,7 @@ struct sn9c102_device {
 struct sn9c102_device*
 sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id)
 {
-       if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
-               return cam;
-
-       return NULL;
+       return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
 }
 
 
@@ -169,6 +141,19 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
        memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor));
 }
 
+
+enum sn9c102_bridge
+sn9c102_get_bridge(struct sn9c102_device* cam)
+{
+       return cam->bridge;
+}
+
+
+struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam)
+{
+       return &cam->sensor;
+}
+
 /*****************************************************************************/
 
 #undef DBG
diff --git a/drivers/media/video/sn9c102/sn9c102_config.h b/drivers/media/video/sn9c102/sn9c102_config.h
new file mode 100644 (file)
index 0000000..0f4e037
--- /dev/null
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * Global parameters for the V4L2 driver for SN9C1xx PC Camera Controllers *
+ *                                                                         *
+ * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _SN9C102_CONFIG_H_
+#define _SN9C102_CONFIG_H_
+
+#include <linux/types.h>
+#include <linux/jiffies.h>
+
+#define SN9C102_DEBUG
+#define SN9C102_DEBUG_LEVEL       2
+#define SN9C102_MAX_DEVICES       64
+#define SN9C102_PRESERVE_IMGSCALE 0
+#define SN9C102_FORCE_MUNMAP      0
+#define SN9C102_MAX_FRAMES        32
+#define SN9C102_URBS              2
+#define SN9C102_ISO_PACKETS       7
+#define SN9C102_ALTERNATE_SETTING 8
+#define SN9C102_URB_TIMEOUT       msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
+#define SN9C102_CTRL_TIMEOUT      300
+#define SN9C102_FRAME_TIMEOUT     0
+
+/*****************************************************************************/
+
+static const u8 SN9C102_Y_QTABLE0[64] = {
+        8,   5,   5,   8,  12,  20,  25,  30,
+        6,   6,   7,   9,  13,  29,  30,  27,
+        7,   6,   8,  12,  20,  28,  34,  28,
+        7,   8,  11,  14,  25,  43,  40,  31,
+        9,  11,  18,  28,  34,  54,  51,  38,
+       12,  17,  27,  32,  40,  52,  56,  46,
+       24,  32,  39,  43,  51,  60,  60,  50,
+       36,  46,  47,  49,  56,  50,  51,  49
+};
+
+static const u8 SN9C102_UV_QTABLE0[64] = {
+        8,   9,  12,  23,  49,  49,  49,  49,
+        9,  10,  13,  33,  49,  49,  49,  49,
+       12,  13,  28,  49,  49,  49,  49,  49,
+       23,  33,  49,  49,  49,  49,  49,  49,
+       49,  49,  49,  49,  49,  49,  49,  49,
+       49,  49,  49,  49,  49,  49,  49,  49,
+       49,  49,  49,  49,  49,  49,  49,  49,
+       49,  49,  49,  49,  49,  49,  49,  49
+};
+
+static const u8 SN9C102_Y_QTABLE1[64] = {
+       16,  11,  10,  16,  24,  40,  51,  61,
+       12,  12,  14,  19,  26,  58,  60,  55,
+       14,  13,  16,  24,  40,  57,  69,  56,
+       14,  17,  22,  29,  51,  87,  80,  62,
+       18,  22,  37,  56,  68, 109, 103,  77,
+       24,  35,  55,  64,  81, 104, 113,  92,
+       49,  64,  78,  87, 103, 121, 120, 101,
+       72,  92,  95,  98, 112, 100, 103,  99
+};
+
+static const u8 SN9C102_UV_QTABLE1[64] = {
+       17,  18,  24,  47,  99,  99,  99,  99,
+       18,  21,  26,  66,  99,  99,  99,  99,
+       24,  26,  56,  99,  99,  99,  99,  99,
+       47,  66,  99,  99,  99,  99,  99,  99,
+       99,  99,  99,  99,  99,  99,  99,  99,
+       99,  99,  99,  99,  99,  99,  99,  99,
+       99,  99,  99,  99,  99,  99,  99,  99,
+       99,  99,  99,  99,  99,  99,  99,  99
+};
+
+#endif /* _SN9C102_CONFIG_H_ */
index 04d4c8f..d0e2b40 100644 (file)
@@ -1,7 +1,7 @@
 /***************************************************************************
- * V4L2 driver for SN9C10x PC Camera Controllers                           *
+ * V4L2 driver for SN9C1xx PC Camera Controllers                           *
  *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
  * it under the terms of the GNU General Public License as published by    *
 
 /*****************************************************************************/
 
-#define SN9C102_MODULE_NAME     "V4L2 driver for SN9C10x PC Camera Controllers"
+#define SN9C102_MODULE_NAME     "V4L2 driver for SN9C1xx PC Camera Controllers"
 #define SN9C102_MODULE_AUTHOR   "(C) 2004-2006 Luca Risolia"
 #define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
 #define SN9C102_MODULE_LICENSE  "GPL"
-#define SN9C102_MODULE_VERSION  "1:1.27"
-#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 27)
+#define SN9C102_MODULE_VERSION  "1:1.34"
+#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 34)
 
 /*****************************************************************************/
 
@@ -91,7 +91,8 @@ static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] =
                                       SN9C102_FRAME_TIMEOUT};
 module_param_array(frame_timeout, uint, NULL, 0644);
 MODULE_PARM_DESC(frame_timeout,
-                "\n<n[,...]> Timeout for a video frame in seconds."
+                "\n<0|n[,...]> Timeout for a video frame in seconds before"
+                "\nreturning an I/O error; 0 for infinity."
                 "\nThis parameter is specific for each detected camera."
                 "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
                 "\n");
@@ -113,32 +114,13 @@ MODULE_PARM_DESC(debug,
 
 /*****************************************************************************/
 
-static sn9c102_sof_header_t sn9c102_sof_header[] = {
-       {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00},
-       {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01},
-};
-
-static sn9c103_sof_header_t sn9c103_sof_header[] = {
-       {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x20},
-};
-
-static sn9c102_eof_header_t sn9c102_eof_header[] = {
-       {0x00, 0x00, 0x00, 0x00},
-       {0x40, 0x00, 0x00, 0x00},
-       {0x80, 0x00, 0x00, 0x00},
-       {0xc0, 0x00, 0x00, 0x00},
-};
-
-/*****************************************************************************/
-
 static u32
 sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
                        enum sn9c102_io_method io)
 {
        struct v4l2_pix_format* p = &(cam->sensor.pix_format);
        struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
-       const size_t imagesize = cam->module_param.force_munmap ||
-                                io == IO_READ ?
+       size_t imagesize = cam->module_param.force_munmap || io == IO_READ ?
                                 (p->width * p->height * p->priv) / 8 :
                                 (r->width * r->height * p->priv) / 8;
        void* buff = NULL;
@@ -147,9 +129,13 @@ sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
        if (count > SN9C102_MAX_FRAMES)
                count = SN9C102_MAX_FRAMES;
 
+       if (cam->bridge == BRIDGE_SN9C105 || cam->bridge == BRIDGE_SN9C120)
+               imagesize += 589 + 2; /* length of JPEG header + EOI marker */
+
        cam->nbuffers = count;
        while (cam->nbuffers > 0) {
-               if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
+               if ((buff = vmalloc_32_user(cam->nbuffers *
+                                           PAGE_ALIGN(imagesize))))
                        break;
                cam->nbuffers--;
        }
@@ -322,9 +308,21 @@ static int
 sn9c102_i2c_detect_read_error(struct sn9c102_device* cam,
                              struct sn9c102_sensor* sensor)
 {
-       int r;
+       int r , err = 0;
+
        r = sn9c102_read_reg(cam, 0x08);
-       return (r < 0 || (r >= 0 && !(r & 0x08))) ? -EIO : 0;
+       if (r < 0)
+               err += r;
+
+       if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) {
+               if (!(r & 0x08))
+                       err += -1;
+       } else {
+               if (r & 0x08)
+                       err += -1;
+       }
+
+       return err ? -EIO : 0;
 }
 
 
@@ -415,7 +413,7 @@ sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
        data[4] = data3;
        data[5] = data4;
        data[6] = data5;
-       data[7] = 0x14;
+       data[7] = 0x17;
        res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
                              0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
        if (res < 0)
@@ -467,31 +465,35 @@ int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
 
 /*****************************************************************************/
 
-static void*
-sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
+static size_t sn9c102_sof_length(struct sn9c102_device* cam)
 {
-       size_t soflen = 0, i;
-       u8 j, n = 0;
-
        switch (cam->bridge) {
        case BRIDGE_SN9C101:
        case BRIDGE_SN9C102:
-               soflen = sizeof(sn9c102_sof_header_t);
-               n = sizeof(sn9c102_sof_header) / soflen;
-               break;
+               return 12;
        case BRIDGE_SN9C103:
-               soflen = sizeof(sn9c103_sof_header_t);
-               n = sizeof(sn9c103_sof_header) / soflen;
+               return 18;
+       case BRIDGE_SN9C105:
+       case BRIDGE_SN9C120:
+               return 62;
        }
 
+       return 0;
+}
+
+
+static void*
+sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
+{
+       char sof_header[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
+       size_t soflen = 0, i;
+
+       soflen = sn9c102_sof_length(cam);
+
        for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
-               for (j = 0; j < n; j++)
-                       /* The invariable part of the header is 6 bytes long */
-                       if ((cam->bridge != BRIDGE_SN9C103 &&
-                           !memcmp(mem + i, sn9c102_sof_header[j], 6)) ||
-                           (cam->bridge == BRIDGE_SN9C103 &&
-                           !memcmp(mem + i, sn9c103_sof_header[j], 6))) {
-                               memcpy(cam->sof_header, mem + i, soflen);
+               if (!memcmp(mem + i, sof_header, sizeof(sof_header))) {
+                       memcpy(cam->sof_header, mem + i,
+                              sizeof(sn9c102_sof_header_t));
                                /* Skip the header */
                                return mem + i + soflen;
                        }
@@ -503,21 +505,123 @@ sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
 static void*
 sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
 {
-       size_t eoflen = sizeof(sn9c102_eof_header_t), i;
-       unsigned j, n = sizeof(sn9c102_eof_header) / eoflen;
+       char eof_header[4][4] = {
+               {0x00, 0x00, 0x00, 0x00},
+               {0x40, 0x00, 0x00, 0x00},
+               {0x80, 0x00, 0x00, 0x00},
+               {0xc0, 0x00, 0x00, 0x00},
+       };
+       size_t i, j;
 
-       if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+       if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X ||
+           cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
                return NULL; /* EOF header does not exist in compressed data */
 
-       for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++)
-               for (j = 0; j < n; j++)
-                       if (!memcmp(mem + i, sn9c102_eof_header[j], eoflen))
+       for (i = 0; (len >= 4) && (i <= len - 4); i++)
+               for (j = 0; j < ARRAY_SIZE(eof_header); j++)
+                       if (!memcmp(mem + i, eof_header[j], 4))
                                return mem + i;
 
        return NULL;
 }
 
 
+static void
+sn9c102_write_jpegheader(struct sn9c102_device* cam, struct sn9c102_frame_t* f)
+{
+       static u8 jpeg_header[589] = {
+               0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x06, 0x04, 0x05,
+               0x06, 0x05, 0x04, 0x06, 0x06, 0x05, 0x06, 0x07, 0x07, 0x06,
+               0x08, 0x0a, 0x10, 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x14, 0x0e,
+               0x0f, 0x0c, 0x10, 0x17, 0x14, 0x18, 0x18, 0x17, 0x14, 0x16,
+               0x16, 0x1a, 0x1d, 0x25, 0x1f, 0x1a, 0x1b, 0x23, 0x1c, 0x16,
+               0x16, 0x20, 0x2c, 0x20, 0x23, 0x26, 0x27, 0x29, 0x2a, 0x29,
+               0x19, 0x1f, 0x2d, 0x30, 0x2d, 0x28, 0x30, 0x25, 0x28, 0x29,
+               0x28, 0x01, 0x07, 0x07, 0x07, 0x0a, 0x08, 0x0a, 0x13, 0x0a,
+               0x0a, 0x13, 0x28, 0x1a, 0x16, 0x1a, 0x28, 0x28, 0x28, 0x28,
+               0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+               0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+               0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+               0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+               0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0xff, 0xc4, 0x01, 0xa2,
+               0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
+               0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01,
+               0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+               0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
+               0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00,
+               0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
+               0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04,
+               0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61,
+               0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23,
+               0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62,
+               0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
+               0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38,
+               0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
+               0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
+               0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76,
+               0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
+               0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+               0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
+               0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2,
+               0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3,
+               0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3,
+               0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
+               0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x11, 0x00, 0x02,
+               0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04,
+               0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
+               0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+               0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1,
+               0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1,
+               0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19,
+               0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+               0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
+               0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
+               0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76,
+               0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+               0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+               0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
+               0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
+               0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+               0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3,
+               0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
+               0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xc0, 0x00, 0x11,
+               0x08, 0x01, 0xe0, 0x02, 0x80, 0x03, 0x01, 0x21, 0x00, 0x02,
+               0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda, 0x00, 0x0c, 0x03,
+               0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
+       };
+       u8 *pos = f->bufmem;
+
+       memcpy(pos, jpeg_header, sizeof(jpeg_header));
+       *(pos + 6) = 0x00;
+       *(pos + 7 + 64) = 0x01;
+       if (cam->compression.quality == 0) {
+               memcpy(pos + 7, SN9C102_Y_QTABLE0, 64);
+               memcpy(pos + 8 + 64, SN9C102_UV_QTABLE0, 64);
+       } else if (cam->compression.quality == 1) {
+               memcpy(pos + 7, SN9C102_Y_QTABLE1, 64);
+               memcpy(pos + 8 + 64, SN9C102_UV_QTABLE1, 64);
+       }
+       *(pos + 564) = cam->sensor.pix_format.width & 0xFF;
+       *(pos + 563) = (cam->sensor.pix_format.width >> 8) & 0xFF;
+       *(pos + 562) = cam->sensor.pix_format.height & 0xFF;
+       *(pos + 561) = (cam->sensor.pix_format.height >> 8) & 0xFF;
+       *(pos + 567) = 0x21;
+
+       f->buf.bytesused += sizeof(jpeg_header);
+}
+
+
+static void
+sn9c102_write_eoimarker(struct sn9c102_device* cam, struct sn9c102_frame_t* f)
+{
+       static const u8 eoi_marker[2] = {0xff, 0xd9};
+
+       memcpy(f->bufmem + f->buf.bytesused, eoi_marker, sizeof(eoi_marker));
+       f->buf.bytesused += sizeof(eoi_marker);
+}
+
+
 static void sn9c102_urb_complete(struct urb *urb)
 {
        struct sn9c102_device* cam = urb->context;
@@ -535,7 +639,7 @@ static void sn9c102_urb_complete(struct urb *urb)
                cam->stream = STREAM_OFF;
                if ((*f))
                        (*f)->state = F_QUEUED;
-               DBG(3, "Stream interrupted");
+               DBG(3, "Stream interrupted by application");
                wake_up(&cam->wait_stream);
        }
 
@@ -557,10 +661,9 @@ static void sn9c102_urb_complete(struct urb *urb)
        imagesize = (cam->sensor.pix_format.width *
                     cam->sensor.pix_format.height *
                     cam->sensor.pix_format.priv) / 8;
-
-       soflen = (cam->bridge) == BRIDGE_SN9C103 ?
-                                 sizeof(sn9c103_sof_header_t) :
-                                 sizeof(sn9c102_sof_header_t);
+       if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
+               imagesize += 589; /* length of jpeg header */
+       soflen = sn9c102_sof_length(cam);
 
        for (i = 0; i < urb->number_of_packets; i++) {
                unsigned int img, len, status;
@@ -610,12 +713,21 @@ end_of_frame:
                                (*f)->buf.bytesused += img;
 
                                if ((*f)->buf.bytesused == imagesize ||
-                                   (cam->sensor.pix_format.pixelformat ==
-                                               V4L2_PIX_FMT_SN9C10X && eof)) {
+                                   ((cam->sensor.pix_format.pixelformat ==
+                                     V4L2_PIX_FMT_SN9C10X ||
+                                     cam->sensor.pix_format.pixelformat ==
+                                     V4L2_PIX_FMT_JPEG) && eof)) {
                                        u32 b;
+
+                                       if (cam->sensor.pix_format.pixelformat
+                                           == V4L2_PIX_FMT_JPEG)
+                                               sn9c102_write_eoimarker(cam,
+                                                                       (*f));
+
                                        b = (*f)->buf.bytesused;
                                        (*f)->state = F_DONE;
                                        (*f)->buf.sequence= ++cam->frame_count;
+
                                        spin_lock(&cam->queue_lock);
                                        list_move_tail(&(*f)->frame,
                                                       &cam->outqueue);
@@ -627,8 +739,10 @@ end_of_frame:
                                        else
                                                (*f) = NULL;
                                        spin_unlock(&cam->queue_lock);
+
                                        memcpy(cam->sysfs.frame_header,
                                               cam->sof_header, soflen);
+
                                        DBG(3, "Video frame captured: %lu "
                                               "bytes", (unsigned long)(b));
 
@@ -661,6 +775,9 @@ start_of_frame:
                        (*f)->buf.bytesused = 0;
                        len -= (sof - pos);
                        pos = sof;
+                       if (cam->sensor.pix_format.pixelformat ==
+                           V4L2_PIX_FMT_JPEG)
+                               sn9c102_write_jpegheader(cam, (*f));
                        DBG(3, "SOF detected: new video frame");
                        if (len)
                                goto redo;
@@ -671,7 +788,9 @@ start_of_frame:
                                goto end_of_frame; /* (1) */
                        else {
                                if (cam->sensor.pix_format.pixelformat ==
-                                   V4L2_PIX_FMT_SN9C10X) {
+                                   V4L2_PIX_FMT_SN9C10X ||
+                                   cam->sensor.pix_format.pixelformat ==
+                                   V4L2_PIX_FMT_JPEG) {
                                        eof = sof - soflen;
                                        goto end_of_frame;
                                } else {
@@ -701,13 +820,11 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
 {
        struct usb_device *udev = cam->usbdev;
        struct urb* urb;
-       const unsigned int sn9c102_wMaxPacketSize[] = {0, 128, 256, 384, 512,
-                                                      680, 800, 900, 1023};
-       const unsigned int sn9c103_wMaxPacketSize[] = {0, 128, 256, 384, 512,
-                                                      680, 800, 900, 1003};
-       const unsigned int psz = (cam->bridge == BRIDGE_SN9C103) ?
-                           sn9c103_wMaxPacketSize[SN9C102_ALTERNATE_SETTING] :
-                           sn9c102_wMaxPacketSize[SN9C102_ALTERNATE_SETTING];
+       struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
+                                                   usb_ifnum_to_if(udev, 0),
+                                                   SN9C102_ALTERNATE_SETTING);
+       const unsigned int psz = le16_to_cpu(altsetting->
+                                            endpoint[0].desc.wMaxPacketSize);
        s8 i, j;
        int err = 0;
 
@@ -775,7 +892,7 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
        return 0;
 
 free_urbs:
-       for (i = 0; i < SN9C102_URBS; i++)
+       for (i = 0; (i < SN9C102_URBS) && cam->urb[i]; i++)
                usb_free_urb(cam->urb[i]);
 
 free_buffers:
@@ -834,29 +951,29 @@ static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
 /*****************************************************************************/
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count)
+static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count)
 {
-       char str[5];
+       char str[7];
        char* endp;
        unsigned long val;
 
-       if (len < 4) {
+       if (len < 6) {
                strncpy(str, buff, len);
                str[len+1] = '\0';
        } else {
                strncpy(str, buff, 4);
-               str[4] = '\0';
+               str[6] = '\0';
        }
 
        val = simple_strtoul(str, &endp, 0);
 
        *count = 0;
-       if (val <= 0xff)
+       if (val <= 0xffff)
                *count = (ssize_t)(endp - str);
        if ((*count) && (len == *count+1) && (buff[*count] == '\n'))
                *count += 1;
 
-       return (u8)val;
+       return (u16)val;
 }
 
 /*
@@ -873,7 +990,8 @@ static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf)
        if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
-       cam = video_get_drvdata(to_video_device(cd));
+       cam = video_get_drvdata(container_of(cd, struct video_device,
+                                            class_dev));
        if (!cam) {
                mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
@@ -891,27 +1009,28 @@ static ssize_t
 sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
 {
        struct sn9c102_device* cam;
-       u8 index;
+       u16 index;
        ssize_t count;
 
        if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
-       cam = video_get_drvdata(to_video_device(cd));
+       cam = video_get_drvdata(container_of(cd, struct video_device,
+                                            class_dev));
        if (!cam) {
                mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
-       index = sn9c102_strtou8(buf, len, &count);
-       if (index > 0x1f || !count) {
+       index = sn9c102_strtou16(buf, len, &count);
+       if (index >= ARRAY_SIZE(cam->reg) || !count) {
                mutex_unlock(&sn9c102_sysfs_lock);
                return -EINVAL;
        }
 
        cam->sysfs.reg = index;
 
-       DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg);
+       DBG(2, "Moved SN9C1XX register index to 0x%02X", cam->sysfs.reg);
        DBG(3, "Written bytes: %zd", count);
 
        mutex_unlock(&sn9c102_sysfs_lock);
@@ -929,7 +1048,8 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
        if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
-       cam = video_get_drvdata(to_video_device(cd));
+       cam = video_get_drvdata(container_of(cd, struct video_device,
+                                            class_dev));
        if (!cam) {
                mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
@@ -954,20 +1074,21 @@ static ssize_t
 sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
 {
        struct sn9c102_device* cam;
-       u8 value;
+       u16 value;
        ssize_t count;
        int err;
 
        if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
-       cam = video_get_drvdata(to_video_device(cd));
+       cam = video_get_drvdata(container_of(cd, struct video_device,
+                                            class_dev));
        if (!cam) {
                mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
-       value = sn9c102_strtou8(buf, len, &count);
+       value = sn9c102_strtou16(buf, len, &count);
        if (!count) {
                mutex_unlock(&sn9c102_sysfs_lock);
                return -EINVAL;
@@ -979,7 +1100,7 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
                return -EIO;
        }
 
-       DBG(2, "Written SN9C10X reg. 0x%02X, val. 0x%02X",
+       DBG(2, "Written SN9C1XX reg. 0x%02X, val. 0x%02X",
            cam->sysfs.reg, value);
        DBG(3, "Written bytes: %zd", count);
 
@@ -997,7 +1118,8 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
        if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
-       cam = video_get_drvdata(to_video_device(cd));
+       cam = video_get_drvdata(container_of(cd, struct video_device,
+                                            class_dev));
        if (!cam) {
                mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
@@ -1017,19 +1139,20 @@ static ssize_t
 sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
 {
        struct sn9c102_device* cam;
-       u8 index;
+       u16 index;
        ssize_t count;
 
        if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
-       cam = video_get_drvdata(to_video_device(cd));
+       cam = video_get_drvdata(container_of(cd, struct video_device,
+                                            class_dev));
        if (!cam) {
                mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
-       index = sn9c102_strtou8(buf, len, &count);
+       index = sn9c102_strtou16(buf, len, &count);
        if (!count) {
                mutex_unlock(&sn9c102_sysfs_lock);
                return -EINVAL;
@@ -1055,7 +1178,8 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
        if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
-       cam = video_get_drvdata(to_video_device(cd));
+       cam = video_get_drvdata(container_of(cd, struct video_device,
+                                            class_dev));
        if (!cam) {
                mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
@@ -1085,14 +1209,15 @@ static ssize_t
 sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
 {
        struct sn9c102_device* cam;
-       u8 value;
+       u16 value;
        ssize_t count;
        int err;
 
        if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
-       cam = video_get_drvdata(to_video_device(cd));
+       cam = video_get_drvdata(container_of(cd, struct video_device,
+                                            class_dev));
        if (!cam) {
                mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
@@ -1103,7 +1228,7 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
                return -ENOSYS;
        }
 
-       value = sn9c102_strtou8(buf, len, &count);
+       value = sn9c102_strtou16(buf, len, &count);
        if (!count) {
                mutex_unlock(&sn9c102_sysfs_lock);
                return -EINVAL;
@@ -1131,13 +1256,14 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
        struct sn9c102_device* cam;
        enum sn9c102_bridge bridge;
        ssize_t res = 0;
-       u8 value;
+       u16 value;
        ssize_t count;
 
        if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
-       cam = video_get_drvdata(to_video_device(cd));
+       cam = video_get_drvdata(container_of(cd, struct video_device,
+                                            class_dev));
        if (!cam) {
                mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
@@ -1147,7 +1273,7 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
 
        mutex_unlock(&sn9c102_sysfs_lock);
 
-       value = sn9c102_strtou8(buf, len, &count);
+       value = sn9c102_strtou16(buf, len, &count);
        if (!count)
                return -EINVAL;
 
@@ -1160,9 +1286,11 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
                        res = sn9c102_store_val(cd, buf, len);
                break;
        case BRIDGE_SN9C103:
+       case BRIDGE_SN9C105:
+       case BRIDGE_SN9C120:
                if (value > 0x7f)
                        return -EINVAL;
-               if ((res = sn9c102_store_reg(cd, "0x04", 4)) >= 0)
+               if ((res = sn9c102_store_reg(cd, "0x07", 4)) >= 0)
                        res = sn9c102_store_val(cd, buf, len);
                break;
        }
@@ -1175,10 +1303,10 @@ static ssize_t
 sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len)
 {
        ssize_t res = 0;
-       u8 value;
+       u16 value;
        ssize_t count;
 
-       value = sn9c102_strtou8(buf, len, &count);
+       value = sn9c102_strtou16(buf, len, &count);
        if (!count || value > 0x7f)
                return -EINVAL;
 
@@ -1193,10 +1321,10 @@ static ssize_t
 sn9c102_store_red(struct class_device* cd, const char* buf, size_t len)
 {
        ssize_t res = 0;
-       u8 value;
+       u16 value;
        ssize_t count;
 
-       value = sn9c102_strtou8(buf, len, &count);
+       value = sn9c102_strtou16(buf, len, &count);
        if (!count || value > 0x7f)
                return -EINVAL;
 
@@ -1212,7 +1340,8 @@ static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf)
        struct sn9c102_device* cam;
        ssize_t count;
 
-       cam = video_get_drvdata(to_video_device(cd));
+       cam = video_get_drvdata(container_of(cd, struct video_device,
+                                            class_dev));
        if (!cam)
                return -ENODEV;
 
@@ -1243,30 +1372,36 @@ static CLASS_DEVICE_ATTR(frame_header, S_IRUGO,
 static int sn9c102_create_sysfs(struct sn9c102_device* cam)
 {
        struct video_device *v4ldev = cam->v4ldev;
-       int rc;
+       int err = 0;
 
-       rc = video_device_create_file(v4ldev, &class_device_attr_reg);
-       if (rc) goto err;
-       rc = video_device_create_file(v4ldev, &class_device_attr_val);
-       if (rc) goto err_reg;
-       rc = video_device_create_file(v4ldev, &class_device_attr_frame_header);
-       if (rc) goto err_val;
+       if ((err = video_device_create_file(v4ldev, &class_device_attr_reg)))
+               goto err_out;
+       if ((err = video_device_create_file(v4ldev, &class_device_attr_val)))
+               goto err_reg;
+       if ((err = video_device_create_file(v4ldev,
+                                           &class_device_attr_frame_header)))
+               goto err_val;
 
        if (cam->sensor.sysfs_ops) {
-               rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
-               if (rc) goto err_frhead;
-               rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val);
-               if (rc) goto err_i2c_reg;
+               if ((err = video_device_create_file(v4ldev,
+                                                 &class_device_attr_i2c_reg)))
+                       goto err_frame_header;
+               if ((err = video_device_create_file(v4ldev,
+                                                 &class_device_attr_i2c_val)))
+                       goto err_i2c_reg;
        }
 
        if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) {
-               rc = video_device_create_file(v4ldev, &class_device_attr_green);
-               if (rc) goto err_i2c_val;
-       } else if (cam->bridge == BRIDGE_SN9C103) {
-               rc = video_device_create_file(v4ldev, &class_device_attr_blue);
-               if (rc) goto err_i2c_val;
-               rc = video_device_create_file(v4ldev, &class_device_attr_red);
-               if (rc) goto err_blue;
+               if ((err = video_device_create_file(v4ldev,
+                                                   &class_device_attr_green)))
+                       goto err_i2c_val;
+       } else {
+               if ((err = video_device_create_file(v4ldev,
+                                                   &class_device_attr_blue)))
+                       goto err_i2c_val;
+               if ((err = video_device_create_file(v4ldev,
+                                                   &class_device_attr_red)))
+                       goto err_blue;
        }
 
        return 0;
@@ -1279,14 +1414,14 @@ err_i2c_val:
 err_i2c_reg:
        if (cam->sensor.sysfs_ops)
                video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
-err_frhead:
+err_frame_header:
        video_device_remove_file(v4ldev, &class_device_attr_frame_header);
 err_val:
        video_device_remove_file(v4ldev, &class_device_attr_val);
 err_reg:
        video_device_remove_file(v4ldev, &class_device_attr_reg);
-err:
-       return rc;
+err_out:
+       return err;
 }
 #endif /* CONFIG_VIDEO_ADV_DEBUG */
 
@@ -1297,10 +1432,36 @@ sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix)
 {
        int err = 0;
 
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, 0x18);
-       else
-               err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, 0x18);
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X ||
+           pix->pixelformat == V4L2_PIX_FMT_JPEG) {
+               switch (cam->bridge) {
+               case BRIDGE_SN9C101:
+               case BRIDGE_SN9C102:
+               case BRIDGE_SN9C103:
+                       err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80,
+                                                0x18);
+                       break;
+               case BRIDGE_SN9C105:
+               case BRIDGE_SN9C120:
+                       err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f,
+                                                0x18);
+                       break;
+               }
+       } else {
+               switch (cam->bridge) {
+               case BRIDGE_SN9C101:
+               case BRIDGE_SN9C102:
+               case BRIDGE_SN9C103:
+                       err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f,
+                                                0x18);
+                       break;
+               case BRIDGE_SN9C105:
+               case BRIDGE_SN9C120:
+                       err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80,
+                                                0x18);
+                       break;
+               }
+       }
 
        return err ? -EIO : 0;
 }
@@ -1310,12 +1471,46 @@ static int
 sn9c102_set_compression(struct sn9c102_device* cam,
                        struct v4l2_jpegcompression* compression)
 {
-       int err = 0;
+       int i, err = 0;
 
+       switch (cam->bridge) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
+       case BRIDGE_SN9C103:
        if (compression->quality == 0)
-               err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, 0x17);
+                       err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01,
+                                                0x17);
        else if (compression->quality == 1)
-               err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, 0x17);
+                       err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe,
+                                                0x17);
+               break;
+       case BRIDGE_SN9C105:
+       case BRIDGE_SN9C120:
+               if (compression->quality == 0) {
+                       for (i = 0; i <= 63; i++) {
+                               err += sn9c102_write_reg(cam,
+                                                        SN9C102_Y_QTABLE0[i],
+                                                        0x100 + i);
+                               err += sn9c102_write_reg(cam,
+                                                        SN9C102_UV_QTABLE0[i],
+                                                        0x140 + i);
+                       }
+                       err += sn9c102_write_reg(cam, cam->reg[0x18] & 0xbf,
+                                                0x18);
+               } else if (compression->quality == 1) {
+                       for (i = 0; i <= 63; i++) {
+                               err += sn9c102_write_reg(cam,
+                                                        SN9C102_Y_QTABLE1[i],
+                                                        0x100 + i);
+                               err += sn9c102_write_reg(cam,
+                                                        SN9C102_UV_QTABLE1[i],
+                                                        0x140 + i);
+                       }
+                       err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x40,
+                                                0x18);
+               }
+               break;
+       }
 
        return err ? -EIO : 0;
 }
@@ -1399,7 +1594,16 @@ static int sn9c102_init(struct sn9c102_device* cam)
        }
 
        if (!(cam->state & DEV_INITIALIZED))
-               cam->compression.quality =  cam->reg[0x17] & 0x01 ? 0 : 1;
+               if (cam->bridge == BRIDGE_SN9C101 ||
+                   cam->bridge == BRIDGE_SN9C102 ||
+                   cam->bridge == BRIDGE_SN9C103) {
+                       cam->compression.quality =  cam->reg[0x17] & 0x01 ?
+                                                   0 : 1;
+               } else {
+                       cam->compression.quality =  cam->reg[0x18] & 0x40 ?
+                                                   0 : 1;
+                       err += sn9c102_set_compression(cam, &cam->compression);
+               }
        else
                err += sn9c102_set_compression(cam, &cam->compression);
        err += sn9c102_set_pix_format(cam, &s->pix_format);
@@ -1408,7 +1612,8 @@ static int sn9c102_init(struct sn9c102_device* cam)
        if (err)
                return err;
 
-       if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+       if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X ||
+           s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
                DBG(3, "Compressed video format is active, quality %d",
                    cam->compression.quality);
        else
@@ -1490,6 +1695,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
 
        if (cam->users) {
                DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+               DBG(3, "Simultaneous opens are not supported");
                if ((filp->f_flags & O_NONBLOCK) ||
                    (filp->f_flags & O_NDELAY)) {
                        err = -EWOULDBLOCK;
@@ -1628,6 +1834,17 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
                        mutex_unlock(&cam->fileop_mutex);
                        return -EAGAIN;
                }
+               if (!cam->module_param.frame_timeout) {
+                       err = wait_event_interruptible
+                             ( cam->wait_frame,
+                               (!list_empty(&cam->outqueue)) ||
+                               (cam->state & DEV_DISCONNECTED) ||
+                               (cam->state & DEV_MISCONFIGURED) );
+                       if (err) {
+                               mutex_unlock(&cam->fileop_mutex);
+                               return err;
+                       }
+               } else {
                timeout = wait_event_interruptible_timeout
                          ( cam->wait_frame,
                            (!list_empty(&cam->outqueue)) ||
@@ -1638,12 +1855,18 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
                if (timeout < 0) {
                        mutex_unlock(&cam->fileop_mutex);
                        return timeout;
+                       } else if (timeout == 0 &&
+                                  !(cam->state & DEV_DISCONNECTED)) {
+                               DBG(1, "Video frame timeout elapsed");
+                               mutex_unlock(&cam->fileop_mutex);
+                               return -EIO;
+                       }
                }
                if (cam->state & DEV_DISCONNECTED) {
                        mutex_unlock(&cam->fileop_mutex);
                        return -ENODEV;
                }
-               if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
+               if (cam->state & DEV_MISCONFIGURED) {
                        mutex_unlock(&cam->fileop_mutex);
                        return -EIO;
                }
@@ -1940,6 +2163,9 @@ exit:
        if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
                return -EFAULT;
 
+       PDBGG("VIDIOC_G_CTRL: id %lu, value %lu",
+             (unsigned long)ctrl.id, (unsigned long)ctrl.value);
+
        return err;
 }
 
@@ -2127,6 +2353,45 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
 
 
 static int
+sn9c102_vidioc_enum_framesizes(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_frmsizeenum frmsize;
+
+       if (copy_from_user(&frmsize, arg, sizeof(frmsize)))
+               return -EFAULT;
+
+       if (frmsize.index != 0)
+               return -EINVAL;
+
+       switch (cam->bridge) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
+       case BRIDGE_SN9C103:
+               if (frmsize.pixel_format != V4L2_PIX_FMT_SN9C10X &&
+                   frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8)
+                       return -EINVAL;
+       case BRIDGE_SN9C105:
+       case BRIDGE_SN9C120:
+               if (frmsize.pixel_format != V4L2_PIX_FMT_JPEG &&
+                   frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8)
+                       return -EINVAL;
+       }
+
+       frmsize.type = V4L2_FRMSIZE_TYPE_STEPWISE;
+       frmsize.stepwise.min_width = frmsize.stepwise.step_width = 16;
+       frmsize.stepwise.min_height = frmsize.stepwise.step_height = 16;
+       frmsize.stepwise.max_width = cam->sensor.cropcap.bounds.width;
+       frmsize.stepwise.max_height = cam->sensor.cropcap.bounds.height;
+       memset(&frmsize.reserved, 0, sizeof(frmsize.reserved));
+
+       if (copy_to_user(arg, &frmsize, sizeof(frmsize)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
 sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
 {
        struct v4l2_fmtdesc fmtd;
@@ -2134,12 +2399,26 @@ sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
        if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
                return -EFAULT;
 
+       if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
        if (fmtd.index == 0) {
                strcpy(fmtd.description, "bayer rgb");
                fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
        } else if (fmtd.index == 1) {
+               switch (cam->bridge) {
+               case BRIDGE_SN9C101:
+               case BRIDGE_SN9C102:
+               case BRIDGE_SN9C103:
                strcpy(fmtd.description, "compressed");
                fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
+                       break;
+               case BRIDGE_SN9C105:
+               case BRIDGE_SN9C120:
+                       strcpy(fmtd.description, "JPEG");
+                       fmtd.pixelformat = V4L2_PIX_FMT_JPEG;
+                       break;
+               }
                fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
        } else
                return -EINVAL;
@@ -2166,7 +2445,8 @@ sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
        if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X)
+       pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X ||
+                             pfmt->pixelformat==V4L2_PIX_FMT_JPEG)
                             ? 0 : (pfmt->width * pfmt->priv) / 8;
        pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
        pfmt->field = V4L2_FIELD_NONE;
@@ -2237,12 +2517,25 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
        pix->width = rect.width / scale;
        pix->height = rect.height / scale;
 
+       switch (cam->bridge) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
+       case BRIDGE_SN9C103:
        if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
            pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
                pix->pixelformat = pfmt->pixelformat;
+               break;
+       case BRIDGE_SN9C105:
+       case BRIDGE_SN9C120:
+               if (pix->pixelformat != V4L2_PIX_FMT_JPEG &&
+                   pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
+                       pix->pixelformat = pfmt->pixelformat;
+               break;
+       }
        pix->priv = pfmt->priv; /* bpp */
        pix->colorspace = pfmt->colorspace;
-       pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+       pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X ||
+                            pix->pixelformat == V4L2_PIX_FMT_JPEG)
                            ? 0 : (pix->width * pix->priv) / 8;
        pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
        pix->field = V4L2_FIELD_NONE;
@@ -2315,8 +2608,7 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
 static int
 sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg)
 {
-       if (copy_to_user(arg, &cam->compression,
-                        sizeof(cam->compression)))
+       if (copy_to_user(arg, &cam->compression, sizeof(cam->compression)))
                return -EFAULT;
 
        return 0;
@@ -2471,6 +2763,7 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
        struct sn9c102_frame_t *f;
        unsigned long lock_flags;
        long timeout;
+       int err = 0;
 
        if (copy_from_user(&b, arg, sizeof(b)))
                return -EFAULT;
@@ -2483,6 +2776,15 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
                        return -EINVAL;
                if (filp->f_flags & O_NONBLOCK)
                        return -EAGAIN;
+               if (!cam->module_param.frame_timeout) {
+                       err = wait_event_interruptible
+                             ( cam->wait_frame,
+                               (!list_empty(&cam->outqueue)) ||
+                               (cam->state & DEV_DISCONNECTED) ||
+                               (cam->state & DEV_MISCONFIGURED) );
+                       if (err)
+                               return err;
+               } else {
                timeout = wait_event_interruptible_timeout
                          ( cam->wait_frame,
                            (!list_empty(&cam->outqueue)) ||
@@ -2492,9 +2794,15 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
                            1000 * msecs_to_jiffies(1) );
                if (timeout < 0)
                        return timeout;
+                       else if (timeout == 0 &&
+                                !(cam->state & DEV_DISCONNECTED)) {
+                               DBG(1, "Video frame timeout elapsed");
+                               return -EIO;
+                       }
+               }
                if (cam->state & DEV_DISCONNECTED)
                        return -ENODEV;
-               if (!timeout || (cam->state & DEV_MISCONFIGURED))
+               if (cam->state & DEV_MISCONFIGURED)
                        return -EIO;
        }
 
@@ -2612,6 +2920,70 @@ sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg)
 }
 
 
+static int
+sn9c102_vidioc_enumaudio(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_audio audio;
+
+       if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
+               return -EINVAL;
+
+       if (copy_from_user(&audio, arg, sizeof(audio)))
+               return -EFAULT;
+
+       if (audio.index != 0)
+               return -EINVAL;
+
+       strcpy(audio.name, "Microphone");
+       audio.capability = 0;
+       audio.mode = 0;
+
+       if (copy_to_user(arg, &audio, sizeof(audio)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_g_audio(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_audio audio;
+
+       if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
+               return -EINVAL;
+
+       if (copy_from_user(&audio, arg, sizeof(audio)))
+               return -EFAULT;
+
+       memset(&audio, 0, sizeof(audio));
+       strcpy(audio.name, "Microphone");
+
+       if (copy_to_user(arg, &audio, sizeof(audio)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_s_audio(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_audio audio;
+
+       if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
+               return -EINVAL;
+
+       if (copy_from_user(&audio, arg, sizeof(audio)))
+               return -EFAULT;
+
+       if (audio.index != 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+
 static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
                              unsigned int cmd, void __user * arg)
 {
@@ -2649,6 +3021,9 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
        case VIDIOC_S_CROP:
                return sn9c102_vidioc_s_crop(cam, arg);
 
+       case VIDIOC_ENUM_FRAMESIZES:
+               return sn9c102_vidioc_enum_framesizes(cam, arg);
+
        case VIDIOC_ENUM_FMT:
                return sn9c102_vidioc_enum_fmt(cam, arg);
 
@@ -2689,11 +3064,21 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
        case VIDIOC_S_PARM:
                return sn9c102_vidioc_s_parm(cam, arg);
 
+       case VIDIOC_ENUMAUDIO:
+               return sn9c102_vidioc_enumaudio(cam, arg);
+
+       case VIDIOC_G_AUDIO:
+               return sn9c102_vidioc_g_audio(cam, arg);
+
+       case VIDIOC_S_AUDIO:
+               return sn9c102_vidioc_s_audio(cam, arg);
+
        case VIDIOC_G_STD:
        case VIDIOC_S_STD:
        case VIDIOC_QUERYSTD:
        case VIDIOC_ENUMSTD:
        case VIDIOC_QUERYMENU:
+       case VIDIOC_ENUM_FRAMEINTERVALS:
                return -EINVAL;
 
        default:
@@ -2741,6 +3126,7 @@ static const struct file_operations sn9c102_fops = {
        .open =    sn9c102_open,
        .release = sn9c102_release,
        .ioctl =   sn9c102_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
        .read =    sn9c102_read,
        .poll =    sn9c102_poll,
        .mmap =    sn9c102_mmap,
@@ -2765,7 +3151,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        cam->usbdev = udev;
 
        if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
-               DBG(1, "kmalloc() failed");
+               DBG(1, "kzalloc() failed");
                err = -ENOMEM;
                goto fail;
        }
@@ -2779,24 +3165,31 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        mutex_init(&cam->dev_mutex);
 
        r = sn9c102_read_reg(cam, 0x00);
-       if (r < 0 || r != 0x10) {
-               DBG(1, "Sorry, this is not a SN9C10x based camera "
-                      "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
+       if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) {
+               DBG(1, "Sorry, this is not a SN9C1xx based camera "
+                      "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
                err = -ENODEV;
                goto fail;
        }
 
-       cam->bridge = (id->idProduct & 0xffc0) == 0x6080 ?
-                     BRIDGE_SN9C103 : BRIDGE_SN9C102;
+       cam->bridge = id->driver_info;
        switch (cam->bridge) {
        case BRIDGE_SN9C101:
        case BRIDGE_SN9C102:
                DBG(2, "SN9C10[12] PC Camera Controller detected "
-                      "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
+                      "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
                break;
        case BRIDGE_SN9C103:
                DBG(2, "SN9C103 PC Camera Controller detected "
-                      "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
+                      "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+               break;
+       case BRIDGE_SN9C105:
+               DBG(2, "SN9C105 PC Camera Controller detected "
+                      "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+               break;
+       case BRIDGE_SN9C120:
+               DBG(2, "SN9C120 PC Camera Controller detected "
+                      "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
                break;
        }
 
@@ -2816,12 +3209,18 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                goto fail;
        }
 
+       if (!(cam->bridge & cam->sensor.supported_bridge)) {
+               DBG(1, "Bridge not supported");
+               err = -ENODEV;
+               goto fail;
+       }
+
        if (sn9c102_init(cam)) {
                DBG(1, "Initialization failed. I will retry on open().");
                cam->state |= DEV_MISCONFIGURED;
        }
 
-       strcpy(cam->v4ldev->name, "SN9C10x PC Camera");
+       strcpy(cam->v4ldev->name, "SN9C1xx PC Camera");
        cam->v4ldev->owner = THIS_MODULE;
        cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
        cam->v4ldev->hardware = 0;
@@ -2838,7 +3237,10 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                DBG(1, "V4L2 device registration failed");
                if (err == -ENFILE && video_nr[dev_nr] == -1)
                        DBG(1, "Free /dev/videoX node not found");
-               goto fail2;
+               video_nr[dev_nr] = -1;
+               dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
+               mutex_unlock(&cam->dev_mutex);
+               goto fail;
        }
 
        DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
@@ -2850,9 +3252,14 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        err = sn9c102_create_sysfs(cam);
-       if (err)
-               goto fail3;
-       DBG(2, "Optional device control through 'sysfs' interface ready");
+       if (!err)
+               DBG(2, "Optional device control through 'sysfs' "
+                      "interface ready");
+       else
+               DBG(2, "Failed to create optional 'sysfs' interface for "
+                      "device controlling. Error #%d", err);
+#else
+       DBG(2, "Optional device control through 'sysfs' interface disabled");
 #endif
 
        usb_set_intfdata(intf, cam);
@@ -2861,14 +3268,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 
        return 0;
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-fail3:
-       video_unregister_device(cam->v4ldev);
-#endif
-fail2:
-       video_nr[dev_nr] = -1;
-       dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
-       mutex_unlock(&cam->dev_mutex);
 fail:
        if (cam) {
                kfree(cam->control_buffer);
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
new file mode 100644 (file)
index 0000000..3a682ec
--- /dev/null
@@ -0,0 +1,142 @@
+/***************************************************************************
+ * Table of device identifiers of the SN9C1xx PC Camera Controllers        *
+ *                                                                         *
+ * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _SN9C102_DEVTABLE_H_
+#define _SN9C102_DEVTABLE_H_
+
+#include <linux/usb.h>
+
+struct sn9c102_device;
+
+/*
+   Each SN9C1xx camera has proper PID/VID identifiers.
+   SN9C103, SN9C105, SN9C120 support multiple interfaces, but we only have to
+   handle the video class interface.
+*/
+#define SN9C102_USB_DEVICE(vend, prod, bridge)                                \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |                           \
+                      USB_DEVICE_ID_MATCH_INT_CLASS,                         \
+       .idVendor = (vend),                                                   \
+       .idProduct = (prod),                                                  \
+       .bInterfaceClass = 0xff,                                              \
+       .driver_info = (bridge)
+
+static const struct usb_device_id sn9c102_id_table[] = {
+       /* SN9C101 and SN9C102 */
+       { SN9C102_USB_DEVICE(0x0c45, 0x6001, BRIDGE_SN9C102), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x6028, BRIDGE_SN9C102), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x603f, BRIDGE_SN9C102), },
+       /* SN9C103 */
+       { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60ba, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60bb, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), },
+       /* SN9C105 */
+       { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), },
+       { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), },
+       /* SN9C120 */
+       { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
+       { SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), },
+       { }
+};
+
+/*
+   Probing functions: on success, you must attach the sensor to the camera
+   by calling sn9c102_attach_sensor().
+   To enable the I2C communication, you might need to perform a really basic
+   initialization of the SN9C1XX chip.
+   Functions must return 0 on success, the appropriate error otherwise.
+*/
+extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
+extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
+extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
+extern int sn9c102_probe_ov7660(struct sn9c102_device* cam);
+extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
+extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
+extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
+extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
+
+/*
+   Add the above entries to this table. Be sure to add the entry in the right
+   place, since, on failure, the next probing routine is called according to
+   the order of the list below, from top to bottom.
+*/
+static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {
+       &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */
+       &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */
+       &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */
+       &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */
+       &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */
+       &sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */
+       &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */
+       &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */
+       NULL,
+};
+
+#endif /* _SN9C102_DEVTABLE_H_ */
index c4117bf..7ae368f 100644 (file)
@@ -1,8 +1,8 @@
 /***************************************************************************
- * Plug-in for HV7131D image sensor connected to the SN9C10x PC Camera     *
+ * Plug-in for HV7131D image sensor connected to the SN9C1xx PC Camera     *
  * Controllers                                                             *
  *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
  * it under the terms of the GNU General Public License as published by    *
@@ -124,7 +124,7 @@ static int hv7131d_set_ctrl(struct sn9c102_device* cam,
 static int hv7131d_set_crop(struct sn9c102_device* cam,
                            const struct v4l2_rect* rect)
 {
-       struct sn9c102_sensor* s = &hv7131d;
+       struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
        int err = 0;
        u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2,
           v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
@@ -153,6 +153,7 @@ static int hv7131d_set_pix_format(struct sn9c102_device* cam,
 static struct sn9c102_sensor hv7131d = {
        .name = "HV7131D",
        .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
        .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
        .frequency = SN9C102_I2C_100KHZ,
        .interface = SN9C102_I2C_2WIRES,
index 4169ea4..a33d1bc 100644 (file)
@@ -1,8 +1,8 @@
 /***************************************************************************
- * Plug-in for MI-0343 image sensor connected to the SN9C10x PC Camera     *
+ * Plug-in for MI-0343 image sensor connected to the SN9C1xx PC Camera     *
  * Controllers                                                             *
  *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
  * it under the terms of the GNU General Public License as published by    *
@@ -201,7 +201,7 @@ static int mi0343_set_ctrl(struct sn9c102_device* cam,
 static int mi0343_set_crop(struct sn9c102_device* cam,
                            const struct v4l2_rect* rect)
 {
-       struct sn9c102_sensor* s = &mi0343;
+       struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
        int err = 0;
        u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0,
           v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
@@ -237,6 +237,7 @@ static int mi0343_set_pix_format(struct sn9c102_device* cam,
 static struct sn9c102_sensor mi0343 = {
        .name = "MI-0343",
        .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
        .frequency = SN9C102_I2C_100KHZ,
        .interface = SN9C102_I2C_2WIRES,
        .i2c_slave_id = 0x5d,
index 3da0420..7df09ff 100644 (file)
@@ -1,8 +1,8 @@
 /***************************************************************************
- * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera      *
+ * Plug-in for OV7630 image sensor connected to the SN9C1xx PC Camera      *
  * Controllers                                                             *
  *                                                                         *
- * Copyright (C) 2005-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
  * it under the terms of the GNU General Public License as published by    *
@@ -29,13 +29,17 @@ static int ov7630_init(struct sn9c102_device* cam)
 {
        int err = 0;
 
+       switch (sn9c102_get_bridge(cam)) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
        err += sn9c102_write_reg(cam, 0x00, 0x14);
        err += sn9c102_write_reg(cam, 0x60, 0x17);
        err += sn9c102_write_reg(cam, 0x0f, 0x18);
        err += sn9c102_write_reg(cam, 0x50, 0x19);
 
-       err += sn9c102_i2c_write(cam, 0x12, 0x80);
-       err += sn9c102_i2c_write(cam, 0x11, 0x01);
+               err += sn9c102_i2c_write(cam, 0x12, 0x8d);
+               err += sn9c102_i2c_write(cam, 0x12, 0x0d);
+               err += sn9c102_i2c_write(cam, 0x11, 0x00);
        err += sn9c102_i2c_write(cam, 0x15, 0x34);
        err += sn9c102_i2c_write(cam, 0x16, 0x03);
        err += sn9c102_i2c_write(cam, 0x17, 0x1c);
@@ -43,14 +47,72 @@ static int ov7630_init(struct sn9c102_device* cam)
        err += sn9c102_i2c_write(cam, 0x19, 0x06);
        err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
        err += sn9c102_i2c_write(cam, 0x1b, 0x04);
-       err += sn9c102_i2c_write(cam, 0x20, 0xf6);
+               err += sn9c102_i2c_write(cam, 0x20, 0x44);
+               err += sn9c102_i2c_write(cam, 0x23, 0xee);
+               err += sn9c102_i2c_write(cam, 0x26, 0xa0);
+               err += sn9c102_i2c_write(cam, 0x27, 0x9a);
+               err += sn9c102_i2c_write(cam, 0x28, 0x20);
+               err += sn9c102_i2c_write(cam, 0x29, 0x30);
+               err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
+               err += sn9c102_i2c_write(cam, 0x30, 0x24);
+               err += sn9c102_i2c_write(cam, 0x32, 0x86);
+               err += sn9c102_i2c_write(cam, 0x60, 0xa9);
+               err += sn9c102_i2c_write(cam, 0x61, 0x42);
+               err += sn9c102_i2c_write(cam, 0x65, 0x00);
+               err += sn9c102_i2c_write(cam, 0x69, 0x38);
+               err += sn9c102_i2c_write(cam, 0x6f, 0x88);
+               err += sn9c102_i2c_write(cam, 0x70, 0x0b);
+               err += sn9c102_i2c_write(cam, 0x71, 0x00);
+               err += sn9c102_i2c_write(cam, 0x74, 0x21);
+               err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
+               break;
+       case BRIDGE_SN9C103:
+               err += sn9c102_write_reg(cam, 0x00, 0x02);
+               err += sn9c102_write_reg(cam, 0x00, 0x03);
+               err += sn9c102_write_reg(cam, 0x1a, 0x04);
+               err += sn9c102_write_reg(cam, 0x20, 0x05);
+               err += sn9c102_write_reg(cam, 0x20, 0x06);
+               err += sn9c102_write_reg(cam, 0x20, 0x07);
+               err += sn9c102_write_reg(cam, 0x03, 0x10);
+               err += sn9c102_write_reg(cam, 0x0a, 0x14);
+               err += sn9c102_write_reg(cam, 0x60, 0x17);
+               err += sn9c102_write_reg(cam, 0x0f, 0x18);
+               err += sn9c102_write_reg(cam, 0x50, 0x19);
+               err += sn9c102_write_reg(cam, 0x1d, 0x1a);
+               err += sn9c102_write_reg(cam, 0x10, 0x1b);
+               err += sn9c102_write_reg(cam, 0x02, 0x1c);
+               err += sn9c102_write_reg(cam, 0x03, 0x1d);
+               err += sn9c102_write_reg(cam, 0x0f, 0x1e);
+               err += sn9c102_write_reg(cam, 0x0c, 0x1f);
+               err += sn9c102_write_reg(cam, 0x00, 0x20);
+               err += sn9c102_write_reg(cam, 0x10, 0x21);
+               err += sn9c102_write_reg(cam, 0x20, 0x22);
+               err += sn9c102_write_reg(cam, 0x30, 0x23);
+               err += sn9c102_write_reg(cam, 0x40, 0x24);
+               err += sn9c102_write_reg(cam, 0x50, 0x25);
+               err += sn9c102_write_reg(cam, 0x60, 0x26);
+               err += sn9c102_write_reg(cam, 0x70, 0x27);
+               err += sn9c102_write_reg(cam, 0x80, 0x28);
+               err += sn9c102_write_reg(cam, 0x90, 0x29);
+               err += sn9c102_write_reg(cam, 0xa0, 0x2a);
+               err += sn9c102_write_reg(cam, 0xb0, 0x2b);
+               err += sn9c102_write_reg(cam, 0xc0, 0x2c);
+               err += sn9c102_write_reg(cam, 0xd0, 0x2d);
+               err += sn9c102_write_reg(cam, 0xe0, 0x2e);
+               err += sn9c102_write_reg(cam, 0xf0, 0x2f);
+               err += sn9c102_write_reg(cam, 0xff, 0x30);
+
+               err += sn9c102_i2c_write(cam, 0x12, 0x8d);
+               err += sn9c102_i2c_write(cam, 0x12, 0x0d);
+               err += sn9c102_i2c_write(cam, 0x15, 0x34);
+               err += sn9c102_i2c_write(cam, 0x11, 0x01);
+               err += sn9c102_i2c_write(cam, 0x1b, 0x04);
+               err += sn9c102_i2c_write(cam, 0x20, 0x44);
        err += sn9c102_i2c_write(cam, 0x23, 0xee);
        err += sn9c102_i2c_write(cam, 0x26, 0xa0);
        err += sn9c102_i2c_write(cam, 0x27, 0x9a);
-       err += sn9c102_i2c_write(cam, 0x28, 0xa0);
+               err += sn9c102_i2c_write(cam, 0x28, 0x20);
        err += sn9c102_i2c_write(cam, 0x29, 0x30);
-       err += sn9c102_i2c_write(cam, 0x2a, 0xa0);
-       err += sn9c102_i2c_write(cam, 0x2b, 0x1f);
        err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
        err += sn9c102_i2c_write(cam, 0x30, 0x24);
        err += sn9c102_i2c_write(cam, 0x32, 0x86);
@@ -63,45 +125,97 @@ static int ov7630_init(struct sn9c102_device* cam)
        err += sn9c102_i2c_write(cam, 0x71, 0x00);
        err += sn9c102_i2c_write(cam, 0x74, 0x21);
        err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
+               break;
+       default:
+               break;
+       }
 
        return err;
 }
 
 
-static int ov7630_set_ctrl(struct sn9c102_device* cam,
-                          const struct v4l2_control* ctrl)
+static int ov7630_get_ctrl(struct sn9c102_device* cam,
+                          struct v4l2_control* ctrl)
 {
        int err = 0;
 
        switch (ctrl->id) {
        case V4L2_CID_EXPOSURE:
-               err += sn9c102_i2c_write(cam, 0x10, ctrl->value >> 2);
-               err += sn9c102_i2c_write(cam, 0x76, ctrl->value & 0x03);
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
+                       return -EIO;
                break;
        case V4L2_CID_RED_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x02, ctrl->value);
+               ctrl->value = sn9c102_pread_reg(cam, 0x07);
                break;
        case V4L2_CID_BLUE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x01, ctrl->value);
+               ctrl->value = sn9c102_pread_reg(cam, 0x06);
+               break;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               ctrl->value = sn9c102_pread_reg(cam, 0x05);
                break;
        case V4L2_CID_GAIN:
-               err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x3f;
+               break;
+       case V4L2_CID_DO_WHITE_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x3f;
+               break;
+       case V4L2_CID_WHITENESS:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0d)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x3f;
+               break;
+       case V4L2_CID_AUTOGAIN:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x01;
+               break;
+       case V4L2_CID_VFLIP:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x75)) < 0)
+                       return -EIO;
+               ctrl->value = (ctrl->value & 0x80) ? 1 : 0;
+               break;
+       case SN9C102_V4L2_CID_GAMMA:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x14)) < 0)
+                       return -EIO;
+               ctrl->value = (ctrl->value & 0x02) ? 1 : 0;
+               break;
+       case SN9C102_V4L2_CID_BAND_FILTER:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x2d)) < 0)
+                       return -EIO;
+               ctrl->value = (ctrl->value & 0x02) ? 1 : 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err ? -EIO : 0;
+}
+
+
+static int ov7630_set_ctrl(struct sn9c102_device* cam,
+                          const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
                break;
-       case V4L2_CID_CONTRAST:
-               err += ctrl->value ? sn9c102_i2c_write(cam, 0x05,
-                                                      (ctrl->value-1) | 0x20)
-                                  : sn9c102_i2c_write(cam, 0x05, 0x00);
+       case V4L2_CID_RED_BALANCE:
+               err += sn9c102_write_reg(cam, ctrl->value, 0x07);
                break;
-       case V4L2_CID_BRIGHTNESS:
-               err += sn9c102_i2c_write(cam, 0x06, ctrl->value);
+       case V4L2_CID_BLUE_BALANCE:
+               err += sn9c102_write_reg(cam, ctrl->value, 0x06);
                break;
-       case V4L2_CID_SATURATION:
-               err += sn9c102_i2c_write(cam, 0x03, ctrl->value << 4);
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               err += sn9c102_write_reg(cam, ctrl->value, 0x05);
                break;
-       case V4L2_CID_HUE:
-               err += ctrl->value ? sn9c102_i2c_write(cam, 0x04,
-                                                      (ctrl->value-1) | 0x20)
-                                  : sn9c102_i2c_write(cam, 0x04, 0x00);
+       case V4L2_CID_GAIN:
+               err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
                break;
        case V4L2_CID_DO_WHITE_BALANCE:
                err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
@@ -109,23 +223,15 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
        case V4L2_CID_WHITENESS:
                err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
                break;
-       case V4L2_CID_AUTO_WHITE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x78);
-               break;
        case V4L2_CID_AUTOGAIN:
-               err += sn9c102_i2c_write(cam, 0x13, ctrl->value);
+               err += sn9c102_i2c_write(cam, 0x13, ctrl->value |
+                                                   (ctrl->value << 1));
                break;
        case V4L2_CID_VFLIP:
                err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7));
                break;
-       case V4L2_CID_BLACK_LEVEL:
-               err += sn9c102_i2c_write(cam, 0x25, ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_BRIGHT_LEVEL:
-               err += sn9c102_i2c_write(cam, 0x24, ctrl->value);
-               break;
        case SN9C102_V4L2_CID_GAMMA:
-               err += sn9c102_i2c_write(cam, 0x14, (ctrl->value << 2) | 0x80);
+               err += sn9c102_i2c_write(cam, 0x14, ctrl->value << 2);
                break;
        case SN9C102_V4L2_CID_BAND_FILTER:
                err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2);
@@ -141,10 +247,12 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
 static int ov7630_set_crop(struct sn9c102_device* cam,
                           const struct v4l2_rect* rect)
 {
-       struct sn9c102_sensor* s = &ov7630;
+       struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
        int err = 0;
-       u8 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
+          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
 
+       err += sn9c102_write_reg(cam, h_start, 0x12);
        err += sn9c102_write_reg(cam, v_start, 0x13);
 
        return err;
@@ -168,7 +276,8 @@ static int ov7630_set_pix_format(struct sn9c102_device* cam,
 static struct sn9c102_sensor ov7630 = {
        .name = "OV7630",
        .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-       .sysfs_ops = SN9C102_I2C_WRITE,
+       .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
+       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
        .frequency = SN9C102_I2C_100KHZ,
        .interface = SN9C102_I2C_2WIRES,
        .i2c_slave_id = 0x21,
@@ -185,73 +294,23 @@ static struct sn9c102_sensor ov7630 = {
                        .flags = 0,
                },
                {
-                       .id = V4L2_CID_HUE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "hue",
-                       .minimum = 0x00,
-                       .maximum = 0x1f+1,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_SATURATION,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "saturation",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x08,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_CONTRAST,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "contrast",
-                       .minimum = 0x00,
-                       .maximum = 0x1f+1,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
                        .id = V4L2_CID_EXPOSURE,
                        .type = V4L2_CTRL_TYPE_INTEGER,
                        .name = "exposure",
-                       .minimum = 0x000,
-                       .maximum = 0x3ff,
-                       .step = 0x001,
-                       .default_value = 0x83<<2,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_RED_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "red balance",
-                       .minimum = 0x00,
-                       .maximum = 0xff,
-                       .step = 0x01,
-                       .default_value = 0x3a,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_BLUE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "blue balance",
                        .minimum = 0x00,
                        .maximum = 0xff,
                        .step = 0x01,
-                       .default_value = 0x77,
+                       .default_value = 0x60,
                        .flags = 0,
                },
                {
-                       .id = V4L2_CID_BRIGHTNESS,
+                       .id = V4L2_CID_WHITENESS,
                        .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "brightness",
+                       .name = "white balance background: red",
                        .minimum = 0x00,
-                       .maximum = 0xff,
+                       .maximum = 0x3f,
                        .step = 0x01,
-                       .default_value = 0xa0,
+                       .default_value = 0x20,
                        .flags = 0,
                },
                {
@@ -265,31 +324,31 @@ static struct sn9c102_sensor ov7630 = {
                        .flags = 0,
                },
                {
-                       .id = V4L2_CID_WHITENESS,
+                       .id = V4L2_CID_RED_BALANCE,
                        .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "white balance background: red",
+                       .name = "red balance",
                        .minimum = 0x00,
-                       .maximum = 0x3f,
+                       .maximum = 0x7f,
                        .step = 0x01,
                        .default_value = 0x20,
                        .flags = 0,
                },
                {
-                       .id = V4L2_CID_AUTO_WHITE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name = "auto white balance",
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "blue balance",
                        .minimum = 0x00,
-                       .maximum = 0x01,
+                       .maximum = 0x7f,
                        .step = 0x01,
-                       .default_value = 0x01,
+                       .default_value = 0x20,
                        .flags = 0,
                },
                {
                        .id = V4L2_CID_AUTOGAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "gain & exposure mode",
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "auto adjust",
                        .minimum = 0x00,
-                       .maximum = 0x03,
+                       .maximum = 0x01,
                        .step = 0x01,
                        .default_value = 0x00,
                        .flags = 0,
@@ -305,23 +364,13 @@ static struct sn9c102_sensor ov7630 = {
                        .flags = 0,
                },
                {
-                       .id = V4L2_CID_BLACK_LEVEL,
+                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
                        .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "black pixel ratio",
-                       .minimum = 0x01,
-                       .maximum = 0x9a,
-                       .step = 0x01,
-                       .default_value = 0x8a,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_BRIGHT_LEVEL,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "bright pixel ratio",
-                       .minimum = 0x01,
-                       .maximum = 0x9a,
+                       .name = "green balance",
+                       .minimum = 0x00,
+                       .maximum = 0x7f,
                        .step = 0x01,
-                       .default_value = 0x10,
+                       .default_value = 0x20,
                        .flags = 0,
                },
                {
@@ -345,6 +394,7 @@ static struct sn9c102_sensor ov7630 = {
                        .flags = 0,
                },
        },
+       .get_ctrl = &ov7630_get_ctrl,
        .set_ctrl = &ov7630_set_ctrl,
        .cropcap = {
                .bounds = {
@@ -364,7 +414,7 @@ static struct sn9c102_sensor ov7630 = {
        .pix_format = {
                .width = 640,
                .height = 480,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .pixelformat = V4L2_PIX_FMT_SN9C10X,
                .priv = 8,
        },
        .set_pix_format = &ov7630_set_pix_format
@@ -373,28 +423,36 @@ static struct sn9c102_sensor ov7630 = {
 
 int sn9c102_probe_ov7630(struct sn9c102_device* cam)
 {
-       const struct usb_device_id ov7630_id_table[] = {
-               { USB_DEVICE(0x0c45, 0x602c), },
-               { USB_DEVICE(0x0c45, 0x602d), },
-               { USB_DEVICE(0x0c45, 0x608f), },
-               { USB_DEVICE(0x0c45, 0x60b0), },
-               { }
-       };
-       int err = 0;
-
-       if (!sn9c102_match_id(cam, ov7630_id_table))
-               return -ENODEV;
+       int pid, ver, err = 0;
 
+       switch (sn9c102_get_bridge(cam)) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
        err += sn9c102_write_reg(cam, 0x01, 0x01);
        err += sn9c102_write_reg(cam, 0x00, 0x01);
        err += sn9c102_write_reg(cam, 0x28, 0x17);
-       if (err)
-               return -EIO;
+               break;
+       case BRIDGE_SN9C103: /* do _not_ change anything! */
+               err += sn9c102_write_reg(cam, 0x09, 0x01);
+               err += sn9c102_write_reg(cam, 0x42, 0x01);
+               err += sn9c102_write_reg(cam, 0x28, 0x17);
+               err += sn9c102_write_reg(cam, 0x44, 0x02);
+               pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a);
+               if (err || pid < 0) { /* try a different initialization */
+                       err = sn9c102_write_reg(cam, 0x01, 0x01);
+                       err += sn9c102_write_reg(cam, 0x00, 0x01);
+               }
+               break;
+       default:
+               break;
+       }
 
-       err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0);
-       if (err)
+       pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a);
+       ver = sn9c102_i2c_try_read(cam, &ov7630, 0x0b);
+       if (err || pid < 0 || ver < 0)
+               return -EIO;
+       if (pid != 0x76 || ver != 0x31)
                return -ENODEV;
-
        sn9c102_attach_sensor(cam, &ov7630);
 
        return 0;
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7660.c b/drivers/media/video/sn9c102/sn9c102_ov7660.c
new file mode 100644 (file)
index 0000000..d670c24
--- /dev/null
@@ -0,0 +1,592 @@
+/***************************************************************************
+ * Plug-in for OV7660 image sensor connected to the SN9C1xx PC Camera      *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor ov7660;
+
+
+static int ov7660_init(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x40, 0x02);
+       err += sn9c102_write_reg(cam, 0x00, 0x03);
+       err += sn9c102_write_reg(cam, 0x1a, 0x04);
+       err += sn9c102_write_reg(cam, 0x03, 0x10);
+       err += sn9c102_write_reg(cam, 0x08, 0x14);
+       err += sn9c102_write_reg(cam, 0x20, 0x17);
+       err += sn9c102_write_reg(cam, 0x8b, 0x18);
+       err += sn9c102_write_reg(cam, 0x00, 0x19);
+       err += sn9c102_write_reg(cam, 0x1d, 0x1a);
+       err += sn9c102_write_reg(cam, 0x10, 0x1b);
+       err += sn9c102_write_reg(cam, 0x02, 0x1c);
+       err += sn9c102_write_reg(cam, 0x03, 0x1d);
+       err += sn9c102_write_reg(cam, 0x0f, 0x1e);
+       err += sn9c102_write_reg(cam, 0x0c, 0x1f);
+       err += sn9c102_write_reg(cam, 0x00, 0x20);
+       err += sn9c102_write_reg(cam, 0x29, 0x21);
+       err += sn9c102_write_reg(cam, 0x40, 0x22);
+       err += sn9c102_write_reg(cam, 0x54, 0x23);
+       err += sn9c102_write_reg(cam, 0x66, 0x24);
+       err += sn9c102_write_reg(cam, 0x76, 0x25);
+       err += sn9c102_write_reg(cam, 0x85, 0x26);
+       err += sn9c102_write_reg(cam, 0x94, 0x27);
+       err += sn9c102_write_reg(cam, 0xa1, 0x28);
+       err += sn9c102_write_reg(cam, 0xae, 0x29);
+       err += sn9c102_write_reg(cam, 0xbb, 0x2a);
+       err += sn9c102_write_reg(cam, 0xc7, 0x2b);
+       err += sn9c102_write_reg(cam, 0xd3, 0x2c);
+       err += sn9c102_write_reg(cam, 0xde, 0x2d);
+       err += sn9c102_write_reg(cam, 0xea, 0x2e);
+       err += sn9c102_write_reg(cam, 0xf4, 0x2f);
+       err += sn9c102_write_reg(cam, 0xff, 0x30);
+       err += sn9c102_write_reg(cam, 0x00, 0x3F);
+       err += sn9c102_write_reg(cam, 0xC7, 0x40);
+       err += sn9c102_write_reg(cam, 0x01, 0x41);
+       err += sn9c102_write_reg(cam, 0x44, 0x42);
+       err += sn9c102_write_reg(cam, 0x00, 0x43);
+       err += sn9c102_write_reg(cam, 0x44, 0x44);
+       err += sn9c102_write_reg(cam, 0x00, 0x45);
+       err += sn9c102_write_reg(cam, 0x44, 0x46);
+       err += sn9c102_write_reg(cam, 0x00, 0x47);
+       err += sn9c102_write_reg(cam, 0xC7, 0x48);
+       err += sn9c102_write_reg(cam, 0x01, 0x49);
+       err += sn9c102_write_reg(cam, 0xC7, 0x4A);
+       err += sn9c102_write_reg(cam, 0x01, 0x4B);
+       err += sn9c102_write_reg(cam, 0xC7, 0x4C);
+       err += sn9c102_write_reg(cam, 0x01, 0x4D);
+       err += sn9c102_write_reg(cam, 0x44, 0x4E);
+       err += sn9c102_write_reg(cam, 0x00, 0x4F);
+       err += sn9c102_write_reg(cam, 0x44, 0x50);
+       err += sn9c102_write_reg(cam, 0x00, 0x51);
+       err += sn9c102_write_reg(cam, 0x44, 0x52);
+       err += sn9c102_write_reg(cam, 0x00, 0x53);
+       err += sn9c102_write_reg(cam, 0xC7, 0x54);
+       err += sn9c102_write_reg(cam, 0x01, 0x55);
+       err += sn9c102_write_reg(cam, 0xC7, 0x56);
+       err += sn9c102_write_reg(cam, 0x01, 0x57);
+       err += sn9c102_write_reg(cam, 0xC7, 0x58);
+       err += sn9c102_write_reg(cam, 0x01, 0x59);
+       err += sn9c102_write_reg(cam, 0x44, 0x5A);
+       err += sn9c102_write_reg(cam, 0x00, 0x5B);
+       err += sn9c102_write_reg(cam, 0x44, 0x5C);
+       err += sn9c102_write_reg(cam, 0x00, 0x5D);
+       err += sn9c102_write_reg(cam, 0x44, 0x5E);
+       err += sn9c102_write_reg(cam, 0x00, 0x5F);
+       err += sn9c102_write_reg(cam, 0xC7, 0x60);
+       err += sn9c102_write_reg(cam, 0x01, 0x61);
+       err += sn9c102_write_reg(cam, 0xC7, 0x62);
+       err += sn9c102_write_reg(cam, 0x01, 0x63);
+       err += sn9c102_write_reg(cam, 0xC7, 0x64);
+       err += sn9c102_write_reg(cam, 0x01, 0x65);
+       err += sn9c102_write_reg(cam, 0x44, 0x66);
+       err += sn9c102_write_reg(cam, 0x00, 0x67);
+       err += sn9c102_write_reg(cam, 0x44, 0x68);
+       err += sn9c102_write_reg(cam, 0x00, 0x69);
+       err += sn9c102_write_reg(cam, 0x44, 0x6A);
+       err += sn9c102_write_reg(cam, 0x00, 0x6B);
+       err += sn9c102_write_reg(cam, 0xC7, 0x6C);
+       err += sn9c102_write_reg(cam, 0x01, 0x6D);
+       err += sn9c102_write_reg(cam, 0xC7, 0x6E);
+       err += sn9c102_write_reg(cam, 0x01, 0x6F);
+       err += sn9c102_write_reg(cam, 0xC7, 0x70);
+       err += sn9c102_write_reg(cam, 0x01, 0x71);
+       err += sn9c102_write_reg(cam, 0x44, 0x72);
+       err += sn9c102_write_reg(cam, 0x00, 0x73);
+       err += sn9c102_write_reg(cam, 0x44, 0x74);
+       err += sn9c102_write_reg(cam, 0x00, 0x75);
+       err += sn9c102_write_reg(cam, 0x44, 0x76);
+       err += sn9c102_write_reg(cam, 0x00, 0x77);
+       err += sn9c102_write_reg(cam, 0xC7, 0x78);
+       err += sn9c102_write_reg(cam, 0x01, 0x79);
+       err += sn9c102_write_reg(cam, 0xC7, 0x7A);
+       err += sn9c102_write_reg(cam, 0x01, 0x7B);
+       err += sn9c102_write_reg(cam, 0xC7, 0x7C);
+       err += sn9c102_write_reg(cam, 0x01, 0x7D);
+       err += sn9c102_write_reg(cam, 0x44, 0x7E);
+       err += sn9c102_write_reg(cam, 0x00, 0x7F);
+       err += sn9c102_write_reg(cam, 0x14, 0x84);
+       err += sn9c102_write_reg(cam, 0x00, 0x85);
+       err += sn9c102_write_reg(cam, 0x27, 0x86);
+       err += sn9c102_write_reg(cam, 0x00, 0x87);
+       err += sn9c102_write_reg(cam, 0x07, 0x88);
+       err += sn9c102_write_reg(cam, 0x00, 0x89);
+       err += sn9c102_write_reg(cam, 0xEC, 0x8A);
+       err += sn9c102_write_reg(cam, 0x0f, 0x8B);
+       err += sn9c102_write_reg(cam, 0xD8, 0x8C);
+       err += sn9c102_write_reg(cam, 0x0f, 0x8D);
+       err += sn9c102_write_reg(cam, 0x3D, 0x8E);
+       err += sn9c102_write_reg(cam, 0x00, 0x8F);
+       err += sn9c102_write_reg(cam, 0x3D, 0x90);
+       err += sn9c102_write_reg(cam, 0x00, 0x91);
+       err += sn9c102_write_reg(cam, 0xCD, 0x92);
+       err += sn9c102_write_reg(cam, 0x0f, 0x93);
+       err += sn9c102_write_reg(cam, 0xf7, 0x94);
+       err += sn9c102_write_reg(cam, 0x0f, 0x95);
+       err += sn9c102_write_reg(cam, 0x0C, 0x96);
+       err += sn9c102_write_reg(cam, 0x00, 0x97);
+       err += sn9c102_write_reg(cam, 0x00, 0x98);
+       err += sn9c102_write_reg(cam, 0x66, 0x99);
+       err += sn9c102_write_reg(cam, 0x05, 0x9A);
+       err += sn9c102_write_reg(cam, 0x00, 0x9B);
+       err += sn9c102_write_reg(cam, 0x04, 0x9C);
+       err += sn9c102_write_reg(cam, 0x00, 0x9D);
+       err += sn9c102_write_reg(cam, 0x08, 0x9E);
+       err += sn9c102_write_reg(cam, 0x00, 0x9F);
+       err += sn9c102_write_reg(cam, 0x2D, 0xC0);
+       err += sn9c102_write_reg(cam, 0x2D, 0xC1);
+       err += sn9c102_write_reg(cam, 0x3A, 0xC2);
+       err += sn9c102_write_reg(cam, 0x05, 0xC3);
+       err += sn9c102_write_reg(cam, 0x04, 0xC4);
+       err += sn9c102_write_reg(cam, 0x3F, 0xC5);
+       err += sn9c102_write_reg(cam, 0x00, 0xC6);
+       err += sn9c102_write_reg(cam, 0x00, 0xC7);
+       err += sn9c102_write_reg(cam, 0x50, 0xC8);
+       err += sn9c102_write_reg(cam, 0x3C, 0xC9);
+       err += sn9c102_write_reg(cam, 0x28, 0xCA);
+       err += sn9c102_write_reg(cam, 0xD8, 0xCB);
+       err += sn9c102_write_reg(cam, 0x14, 0xCC);
+       err += sn9c102_write_reg(cam, 0xEC, 0xCD);
+       err += sn9c102_write_reg(cam, 0x32, 0xCE);
+       err += sn9c102_write_reg(cam, 0xDD, 0xCF);
+       err += sn9c102_write_reg(cam, 0x32, 0xD0);
+       err += sn9c102_write_reg(cam, 0xDD, 0xD1);
+       err += sn9c102_write_reg(cam, 0x6A, 0xD2);
+       err += sn9c102_write_reg(cam, 0x50, 0xD3);
+       err += sn9c102_write_reg(cam, 0x00, 0xD4);
+       err += sn9c102_write_reg(cam, 0x00, 0xD5);
+       err += sn9c102_write_reg(cam, 0x00, 0xD6);
+
+       err += sn9c102_i2c_write(cam, 0x12, 0x80);
+       err += sn9c102_i2c_write(cam, 0x11, 0x09);
+       err += sn9c102_i2c_write(cam, 0x00, 0x0A);
+       err += sn9c102_i2c_write(cam, 0x01, 0x78);
+       err += sn9c102_i2c_write(cam, 0x02, 0x90);
+       err += sn9c102_i2c_write(cam, 0x03, 0x00);
+       err += sn9c102_i2c_write(cam, 0x04, 0x00);
+       err += sn9c102_i2c_write(cam, 0x05, 0x08);
+       err += sn9c102_i2c_write(cam, 0x06, 0x0B);
+       err += sn9c102_i2c_write(cam, 0x07, 0x00);
+       err += sn9c102_i2c_write(cam, 0x08, 0x1C);
+       err += sn9c102_i2c_write(cam, 0x09, 0x01);
+       err += sn9c102_i2c_write(cam, 0x0A, 0x76);
+       err += sn9c102_i2c_write(cam, 0x0B, 0x60);
+       err += sn9c102_i2c_write(cam, 0x0C, 0x00);
+       err += sn9c102_i2c_write(cam, 0x0D, 0x08);
+       err += sn9c102_i2c_write(cam, 0x0E, 0x04);
+       err += sn9c102_i2c_write(cam, 0x0F, 0x6F);
+       err += sn9c102_i2c_write(cam, 0x10, 0x20);
+       err += sn9c102_i2c_write(cam, 0x11, 0x03);
+       err += sn9c102_i2c_write(cam, 0x12, 0x05);
+       err += sn9c102_i2c_write(cam, 0x13, 0xF8);
+       err += sn9c102_i2c_write(cam, 0x14, 0x2C);
+       err += sn9c102_i2c_write(cam, 0x15, 0x00);
+       err += sn9c102_i2c_write(cam, 0x16, 0x02);
+       err += sn9c102_i2c_write(cam, 0x17, 0x10);
+       err += sn9c102_i2c_write(cam, 0x18, 0x60);
+       err += sn9c102_i2c_write(cam, 0x19, 0x02);
+       err += sn9c102_i2c_write(cam, 0x1A, 0x7B);
+       err += sn9c102_i2c_write(cam, 0x1B, 0x02);
+       err += sn9c102_i2c_write(cam, 0x1C, 0x7F);
+       err += sn9c102_i2c_write(cam, 0x1D, 0xA2);
+       err += sn9c102_i2c_write(cam, 0x1E, 0x01);
+       err += sn9c102_i2c_write(cam, 0x1F, 0x0E);
+       err += sn9c102_i2c_write(cam, 0x20, 0x05);
+       err += sn9c102_i2c_write(cam, 0x21, 0x05);
+       err += sn9c102_i2c_write(cam, 0x22, 0x05);
+       err += sn9c102_i2c_write(cam, 0x23, 0x05);
+       err += sn9c102_i2c_write(cam, 0x24, 0x68);
+       err += sn9c102_i2c_write(cam, 0x25, 0x58);
+       err += sn9c102_i2c_write(cam, 0x26, 0xD4);
+       err += sn9c102_i2c_write(cam, 0x27, 0x80);
+       err += sn9c102_i2c_write(cam, 0x28, 0x80);
+       err += sn9c102_i2c_write(cam, 0x29, 0x30);
+       err += sn9c102_i2c_write(cam, 0x2A, 0x00);
+       err += sn9c102_i2c_write(cam, 0x2B, 0x00);
+       err += sn9c102_i2c_write(cam, 0x2C, 0x80);
+       err += sn9c102_i2c_write(cam, 0x2D, 0x00);
+       err += sn9c102_i2c_write(cam, 0x2E, 0x00);
+       err += sn9c102_i2c_write(cam, 0x2F, 0x0E);
+       err += sn9c102_i2c_write(cam, 0x30, 0x08);
+       err += sn9c102_i2c_write(cam, 0x31, 0x30);
+       err += sn9c102_i2c_write(cam, 0x32, 0xB4);
+       err += sn9c102_i2c_write(cam, 0x33, 0x00);
+       err += sn9c102_i2c_write(cam, 0x34, 0x07);
+       err += sn9c102_i2c_write(cam, 0x35, 0x84);
+       err += sn9c102_i2c_write(cam, 0x36, 0x00);
+       err += sn9c102_i2c_write(cam, 0x37, 0x0C);
+       err += sn9c102_i2c_write(cam, 0x38, 0x02);
+       err += sn9c102_i2c_write(cam, 0x39, 0x43);
+       err += sn9c102_i2c_write(cam, 0x3A, 0x00);
+       err += sn9c102_i2c_write(cam, 0x3B, 0x02);
+       err += sn9c102_i2c_write(cam, 0x3C, 0x6C);
+       err += sn9c102_i2c_write(cam, 0x3D, 0x99);
+       err += sn9c102_i2c_write(cam, 0x3E, 0x0E);
+       err += sn9c102_i2c_write(cam, 0x3F, 0x41);
+       err += sn9c102_i2c_write(cam, 0x40, 0xC1);
+       err += sn9c102_i2c_write(cam, 0x41, 0x22);
+       err += sn9c102_i2c_write(cam, 0x42, 0x08);
+       err += sn9c102_i2c_write(cam, 0x43, 0xF0);
+       err += sn9c102_i2c_write(cam, 0x44, 0x10);
+       err += sn9c102_i2c_write(cam, 0x45, 0x78);
+       err += sn9c102_i2c_write(cam, 0x46, 0xA8);
+       err += sn9c102_i2c_write(cam, 0x47, 0x60);
+       err += sn9c102_i2c_write(cam, 0x48, 0x80);
+       err += sn9c102_i2c_write(cam, 0x49, 0x00);
+       err += sn9c102_i2c_write(cam, 0x4A, 0x00);
+       err += sn9c102_i2c_write(cam, 0x4B, 0x00);
+       err += sn9c102_i2c_write(cam, 0x4C, 0x00);
+       err += sn9c102_i2c_write(cam, 0x4D, 0x00);
+       err += sn9c102_i2c_write(cam, 0x4E, 0x00);
+       err += sn9c102_i2c_write(cam, 0x4F, 0x46);
+       err += sn9c102_i2c_write(cam, 0x50, 0x36);
+       err += sn9c102_i2c_write(cam, 0x51, 0x0F);
+       err += sn9c102_i2c_write(cam, 0x52, 0x17);
+       err += sn9c102_i2c_write(cam, 0x53, 0x7F);
+       err += sn9c102_i2c_write(cam, 0x54, 0x96);
+       err += sn9c102_i2c_write(cam, 0x55, 0x40);
+       err += sn9c102_i2c_write(cam, 0x56, 0x40);
+       err += sn9c102_i2c_write(cam, 0x57, 0x40);
+       err += sn9c102_i2c_write(cam, 0x58, 0x0F);
+       err += sn9c102_i2c_write(cam, 0x59, 0xBA);
+       err += sn9c102_i2c_write(cam, 0x5A, 0x9A);
+       err += sn9c102_i2c_write(cam, 0x5B, 0x22);
+       err += sn9c102_i2c_write(cam, 0x5C, 0xB9);
+       err += sn9c102_i2c_write(cam, 0x5D, 0x9B);
+       err += sn9c102_i2c_write(cam, 0x5E, 0x10);
+       err += sn9c102_i2c_write(cam, 0x5F, 0xF0);
+       err += sn9c102_i2c_write(cam, 0x60, 0x05);
+       err += sn9c102_i2c_write(cam, 0x61, 0x60);
+       err += sn9c102_i2c_write(cam, 0x62, 0x00);
+       err += sn9c102_i2c_write(cam, 0x63, 0x00);
+       err += sn9c102_i2c_write(cam, 0x64, 0x50);
+       err += sn9c102_i2c_write(cam, 0x65, 0x30);
+       err += sn9c102_i2c_write(cam, 0x66, 0x00);
+       err += sn9c102_i2c_write(cam, 0x67, 0x80);
+       err += sn9c102_i2c_write(cam, 0x68, 0x7A);
+       err += sn9c102_i2c_write(cam, 0x69, 0x90);
+       err += sn9c102_i2c_write(cam, 0x6A, 0x80);
+       err += sn9c102_i2c_write(cam, 0x6B, 0x0A);
+       err += sn9c102_i2c_write(cam, 0x6C, 0x30);
+       err += sn9c102_i2c_write(cam, 0x6D, 0x48);
+       err += sn9c102_i2c_write(cam, 0x6E, 0x80);
+       err += sn9c102_i2c_write(cam, 0x6F, 0x74);
+       err += sn9c102_i2c_write(cam, 0x70, 0x64);
+       err += sn9c102_i2c_write(cam, 0x71, 0x60);
+       err += sn9c102_i2c_write(cam, 0x72, 0x5C);
+       err += sn9c102_i2c_write(cam, 0x73, 0x58);
+       err += sn9c102_i2c_write(cam, 0x74, 0x54);
+       err += sn9c102_i2c_write(cam, 0x75, 0x4C);
+       err += sn9c102_i2c_write(cam, 0x76, 0x40);
+       err += sn9c102_i2c_write(cam, 0x77, 0x38);
+       err += sn9c102_i2c_write(cam, 0x78, 0x34);
+       err += sn9c102_i2c_write(cam, 0x79, 0x30);
+       err += sn9c102_i2c_write(cam, 0x7A, 0x2F);
+       err += sn9c102_i2c_write(cam, 0x7B, 0x2B);
+       err += sn9c102_i2c_write(cam, 0x7C, 0x03);
+       err += sn9c102_i2c_write(cam, 0x7D, 0x07);
+       err += sn9c102_i2c_write(cam, 0x7E, 0x17);
+       err += sn9c102_i2c_write(cam, 0x7F, 0x34);
+       err += sn9c102_i2c_write(cam, 0x80, 0x41);
+       err += sn9c102_i2c_write(cam, 0x81, 0x4D);
+       err += sn9c102_i2c_write(cam, 0x82, 0x58);
+       err += sn9c102_i2c_write(cam, 0x83, 0x63);
+       err += sn9c102_i2c_write(cam, 0x84, 0x6E);
+       err += sn9c102_i2c_write(cam, 0x85, 0x77);
+       err += sn9c102_i2c_write(cam, 0x86, 0x87);
+       err += sn9c102_i2c_write(cam, 0x87, 0x95);
+       err += sn9c102_i2c_write(cam, 0x88, 0xAF);
+       err += sn9c102_i2c_write(cam, 0x89, 0xC7);
+       err += sn9c102_i2c_write(cam, 0x8A, 0xDF);
+       err += sn9c102_i2c_write(cam, 0x8B, 0x99);
+       err += sn9c102_i2c_write(cam, 0x8C, 0x99);
+       err += sn9c102_i2c_write(cam, 0x8D, 0xCF);
+       err += sn9c102_i2c_write(cam, 0x8E, 0x20);
+       err += sn9c102_i2c_write(cam, 0x8F, 0x26);
+       err += sn9c102_i2c_write(cam, 0x90, 0x10);
+       err += sn9c102_i2c_write(cam, 0x91, 0x0C);
+       err += sn9c102_i2c_write(cam, 0x92, 0x25);
+       err += sn9c102_i2c_write(cam, 0x93, 0x00);
+       err += sn9c102_i2c_write(cam, 0x94, 0x50);
+       err += sn9c102_i2c_write(cam, 0x95, 0x50);
+       err += sn9c102_i2c_write(cam, 0x96, 0x00);
+       err += sn9c102_i2c_write(cam, 0x97, 0x01);
+       err += sn9c102_i2c_write(cam, 0x98, 0x10);
+       err += sn9c102_i2c_write(cam, 0x99, 0x40);
+       err += sn9c102_i2c_write(cam, 0x9A, 0x40);
+       err += sn9c102_i2c_write(cam, 0x9B, 0x20);
+       err += sn9c102_i2c_write(cam, 0x9C, 0x00);
+       err += sn9c102_i2c_write(cam, 0x9D, 0x99);
+       err += sn9c102_i2c_write(cam, 0x9E, 0x7F);
+       err += sn9c102_i2c_write(cam, 0x9F, 0x00);
+       err += sn9c102_i2c_write(cam, 0xA0, 0x00);
+       err += sn9c102_i2c_write(cam, 0xA1, 0x00);
+
+       return err;
+}
+
+
+static int ov7660_get_ctrl(struct sn9c102_device* cam,
+                          struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
+                       return -EIO;
+               break;
+       case V4L2_CID_DO_WHITE_BALANCE:
+               ctrl->value = sn9c102_pread_reg(cam, 0x02);
+               ctrl->value = (ctrl->value & 0x04) ? 1 : 0;
+               break;
+       case V4L2_CID_RED_BALANCE:
+               ctrl->value = sn9c102_pread_reg(cam, 0x05);
+               ctrl->value &= 0x7f;
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               ctrl->value = sn9c102_pread_reg(cam, 0x06);
+               ctrl->value &= 0x7f;
+               break;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               ctrl->value = sn9c102_pread_reg(cam, 0x07);
+               ctrl->value &= 0x7f;
+               break;
+       case V4L2_CID_GAIN:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x7f;
+               break;
+       case V4L2_CID_AUTOGAIN:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x01;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err ? -EIO : 0;
+}
+
+
+static int ov7660_set_ctrl(struct sn9c102_device* cam,
+                          const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
+               break;
+       case V4L2_CID_DO_WHITE_BALANCE:
+               err += sn9c102_write_reg(cam, 0x43 | (ctrl->value << 2), 0x02);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               err += sn9c102_write_reg(cam, ctrl->value, 0x05);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               err += sn9c102_write_reg(cam, ctrl->value, 0x06);
+               break;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               err += sn9c102_write_reg(cam, ctrl->value, 0x07);
+               break;
+       case V4L2_CID_GAIN:
+               err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
+               break;
+       case V4L2_CID_AUTOGAIN:
+               err += sn9c102_i2c_write(cam, 0x13, 0xf0 | ctrl->value |
+                                                   (ctrl->value << 1));
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err ? -EIO : 0;
+}
+
+
+static int ov7660_set_crop(struct sn9c102_device* cam,
+                          const struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+       int err = 0;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
+          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+
+       err += sn9c102_write_reg(cam, h_start, 0x12);
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       return err;
+}
+
+
+static int ov7660_set_pix_format(struct sn9c102_device* cam,
+                                const struct v4l2_pix_format* pix)
+{
+       int r0, err = 0;
+
+       r0 = sn9c102_pread_reg(cam, 0x01);
+
+       if (pix->pixelformat == V4L2_PIX_FMT_JPEG) {
+               err += sn9c102_write_reg(cam, r0 | 0x40, 0x01);
+               err += sn9c102_write_reg(cam, 0xa2, 0x17);
+               err += sn9c102_i2c_write(cam, 0x11, 0x00);
+       } else {
+               err += sn9c102_write_reg(cam, r0 | 0x40, 0x01);
+               err += sn9c102_write_reg(cam, 0xa2, 0x17);
+               err += sn9c102_i2c_write(cam, 0x11, 0x0d);
+       }
+
+       return err;
+}
+
+
+static struct sn9c102_sensor ov7660 = {
+       .name = "OV7660",
+       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120,
+       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
+       .frequency = SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_2WIRES,
+       .i2c_slave_id = 0x21,
+       .init = &ov7660_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0x7f,
+                       .step = 0x01,
+                       .default_value = 0x0a,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x00,
+                       .maximum = 0xff,
+                       .step = 0x01,
+                       .default_value = 0x50,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_DO_WHITE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "night mode",
+                       .minimum = 0x00,
+                       .maximum = 0x01,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_RED_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "red balance",
+                       .minimum = 0x00,
+                       .maximum = 0x7f,
+                       .step = 0x01,
+                       .default_value = 0x1f,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "blue balance",
+                       .minimum = 0x00,
+                       .maximum = 0x7f,
+                       .step = 0x01,
+                       .default_value = 0x1e,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_AUTOGAIN,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "auto adjust",
+                       .minimum = 0x00,
+                       .maximum = 0x01,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "green balance",
+                       .minimum = 0x00,
+                       .maximum = 0x7f,
+                       .step = 0x01,
+                       .default_value = 0x20,
+                       .flags = 0,
+               },
+       },
+       .get_ctrl = &ov7660_get_ctrl,
+       .set_ctrl = &ov7660_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .set_crop = &ov7660_set_crop,
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_JPEG,
+               .priv = 8,
+       },
+       .set_pix_format = &ov7660_set_pix_format
+};
+
+
+int sn9c102_probe_ov7660(struct sn9c102_device* cam)
+{
+       int pid, ver, err = 0;
+
+       err += sn9c102_write_reg(cam, 0x01, 0xf1);
+       err += sn9c102_write_reg(cam, 0x00, 0xf1);
+       err += sn9c102_write_reg(cam, 0x01, 0x01);
+       err += sn9c102_write_reg(cam, 0x00, 0x01);
+       err += sn9c102_write_reg(cam, 0x28, 0x17);
+
+       pid = sn9c102_i2c_try_read(cam, &ov7660, 0x0a);
+       ver = sn9c102_i2c_try_read(cam, &ov7660, 0x0b);
+       if (err || pid < 0 || ver < 0)
+               return -EIO;
+       if (pid != 0x76 || ver != 0x60)
+               return -ENODEV;
+       sn9c102_attach_sensor(cam, &ov7660);
+
+       return 0;
+}
index 9915944..8d79a5f 100644 (file)
@@ -1,8 +1,8 @@
 /***************************************************************************
- * Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera     *
+ * Plug-in for PAS106B image sensor connected to the SN9C1xx PC Camera     *
  * Controllers                                                             *
  *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
  * it under the terms of the GNU General Public License as published by    *
@@ -143,7 +143,7 @@ static int pas106b_set_ctrl(struct sn9c102_device* cam,
 static int pas106b_set_crop(struct sn9c102_device* cam,
                            const struct v4l2_rect* rect)
 {
-       struct sn9c102_sensor* s = &pas106b;
+       struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
        int err = 0;
        u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
           v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
@@ -172,6 +172,7 @@ static int pas106b_set_pix_format(struct sn9c102_device* cam,
 static struct sn9c102_sensor pas106b = {
        .name = "PAS106B",
        .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
        .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
        .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
        .interface = SN9C102_I2C_2WIRES,
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bca.c b/drivers/media/video/sn9c102/sn9c102_pas202bca.c
deleted file mode 100644 (file)
index c8f1ae2..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/***************************************************************************
- * Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera   *
- * Controllers                                                             *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/delay.h>
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor pas202bca;
-
-
-static int pas202bca_init(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, 0x00, 0x10);
-       err += sn9c102_write_reg(cam, 0x00, 0x11);
-       err += sn9c102_write_reg(cam, 0x00, 0x14);
-       err += sn9c102_write_reg(cam, 0x20, 0x17);
-       err += sn9c102_write_reg(cam, 0x30, 0x19);
-       err += sn9c102_write_reg(cam, 0x09, 0x18);
-
-       err += sn9c102_i2c_write(cam, 0x02, 0x14);
-       err += sn9c102_i2c_write(cam, 0x03, 0x40);
-       err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
-       err += sn9c102_i2c_write(cam, 0x0e, 0x01);
-       err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
-       err += sn9c102_i2c_write(cam, 0x10, 0x08);
-       err += sn9c102_i2c_write(cam, 0x13, 0x63);
-       err += sn9c102_i2c_write(cam, 0x15, 0x70);
-       err += sn9c102_i2c_write(cam, 0x11, 0x01);
-
-       msleep(400);
-
-       return err;
-}
-
-
-static int pas202bca_set_pix_format(struct sn9c102_device* cam,
-                                   const struct v4l2_pix_format* pix)
-{
-       int err = 0;
-
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, 0x24, 0x17);
-       else
-               err += sn9c102_write_reg(cam, 0x20, 0x17);
-
-       return err;
-}
-
-
-static int pas202bca_set_ctrl(struct sn9c102_device* cam,
-                             const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
-               err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
-               break;
-       case V4L2_CID_RED_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
-               break;
-       case V4L2_CID_GAIN:
-               err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
-               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
-               break;
-       default:
-               return -EINVAL;
-       }
-       err += sn9c102_i2c_write(cam, 0x11, 0x01);
-
-       return err ? -EIO : 0;
-}
-
-
-static int pas202bca_set_crop(struct sn9c102_device* cam,
-                             const struct v4l2_rect* rect)
-{
-       struct sn9c102_sensor* s = &pas202bca;
-       int err = 0;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3,
-          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
-
-       err += sn9c102_write_reg(cam, h_start, 0x12);
-       err += sn9c102_write_reg(cam, v_start, 0x13);
-
-       return err;
-}
-
-
-static struct sn9c102_sensor pas202bca = {
-       .name = "PAS202BCA",
-       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
-       .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
-       .interface = SN9C102_I2C_2WIRES,
-       .i2c_slave_id = 0x40,
-       .init = &pas202bca_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x01e5,
-                       .maximum = 0x3fff,
-                       .step = 0x0001,
-                       .default_value = 0x01e5,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = 0x1f,
-                       .step = 0x01,
-                       .default_value = 0x0c,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_RED_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "red balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x01,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_BLUE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "blue balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x05,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "green balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "DAC magnitude",
-                       .minimum = 0x00,
-                       .maximum = 0xff,
-                       .step = 0x01,
-                       .default_value = 0x04,
-                       .flags = 0,
-               },
-       },
-       .set_ctrl = &pas202bca_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-       },
-       .set_crop = &pas202bca_set_crop,
-       .pix_format = {
-               .width = 640,
-               .height = 480,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
-               .priv = 8,
-       },
-       .set_pix_format = &pas202bca_set_pix_format
-};
-
-
-int sn9c102_probe_pas202bca(struct sn9c102_device* cam)
-{
-       const struct usb_device_id pas202bca_id_table[] = {
-               { USB_DEVICE(0x0c45, 0x60af), },
-               { }
-       };
-       int err = 0;
-
-       if (!sn9c102_match_id(cam,pas202bca_id_table))
-               return -ENODEV;
-
-       err += sn9c102_write_reg(cam, 0x01, 0x01);
-       err += sn9c102_write_reg(cam, 0x40, 0x01);
-       err += sn9c102_write_reg(cam, 0x28, 0x17);
-       if (err)
-               return -EIO;
-
-       if (sn9c102_i2c_try_write(cam, &pas202bca, 0x10, 0)) /* try to write */
-               return -ENODEV;
-
-       sn9c102_attach_sensor(cam, &pas202bca);
-
-       return 0;
-}
index e3c1178..7894f01 100644 (file)
@@ -1,13 +1,13 @@
 /***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the SN9C10x PC Camera   *
+ * Plug-in for PAS202BCB image sensor connected to the SN9C1xx PC Camera   *
  * Controllers                                                             *
  *                                                                         *
  * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio                  *
  *                       <medaglia@undl.org.br>                            *
  *                       http://cadu.homelinux.com:8080/                   *
  *                                                                         *
- * DAC Magnitude, exposure and green gain controls added by                *
- * Luca Risolia <luca.risolia@studio.unibo.it>                             *
+ * Support for SN9C103, DAC Magnitude, exposure and green gain controls    *
+ * added by Luca Risolia <luca.risolia@studio.unibo.it>                    *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
  * it under the terms of the GNU General Public License as published by    *
@@ -35,12 +35,54 @@ static int pas202bcb_init(struct sn9c102_device* cam)
 {
        int err = 0;
 
+       switch (sn9c102_get_bridge(cam)) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
        err += sn9c102_write_reg(cam, 0x00, 0x10);
        err += sn9c102_write_reg(cam, 0x00, 0x11);
        err += sn9c102_write_reg(cam, 0x00, 0x14);
        err += sn9c102_write_reg(cam, 0x20, 0x17);
        err += sn9c102_write_reg(cam, 0x30, 0x19);
        err += sn9c102_write_reg(cam, 0x09, 0x18);
+               break;
+       case BRIDGE_SN9C103:
+               err += sn9c102_write_reg(cam, 0x00, 0x02);
+               err += sn9c102_write_reg(cam, 0x00, 0x03);
+               err += sn9c102_write_reg(cam, 0x1a, 0x04);
+               err += sn9c102_write_reg(cam, 0x20, 0x05);
+               err += sn9c102_write_reg(cam, 0x20, 0x06);
+               err += sn9c102_write_reg(cam, 0x20, 0x07);
+               err += sn9c102_write_reg(cam, 0x00, 0x10);
+               err += sn9c102_write_reg(cam, 0x00, 0x11);
+               err += sn9c102_write_reg(cam, 0x00, 0x14);
+               err += sn9c102_write_reg(cam, 0x20, 0x17);
+               err += sn9c102_write_reg(cam, 0x30, 0x19);
+               err += sn9c102_write_reg(cam, 0x09, 0x18);
+               err += sn9c102_write_reg(cam, 0x02, 0x1c);
+               err += sn9c102_write_reg(cam, 0x03, 0x1d);
+               err += sn9c102_write_reg(cam, 0x0f, 0x1e);
+               err += sn9c102_write_reg(cam, 0x0c, 0x1f);
+               err += sn9c102_write_reg(cam, 0x00, 0x20);
+               err += sn9c102_write_reg(cam, 0x10, 0x21);
+               err += sn9c102_write_reg(cam, 0x20, 0x22);
+               err += sn9c102_write_reg(cam, 0x30, 0x23);
+               err += sn9c102_write_reg(cam, 0x40, 0x24);
+               err += sn9c102_write_reg(cam, 0x50, 0x25);
+               err += sn9c102_write_reg(cam, 0x60, 0x26);
+               err += sn9c102_write_reg(cam, 0x70, 0x27);
+               err += sn9c102_write_reg(cam, 0x80, 0x28);
+               err += sn9c102_write_reg(cam, 0x90, 0x29);
+               err += sn9c102_write_reg(cam, 0xa0, 0x2a);
+               err += sn9c102_write_reg(cam, 0xb0, 0x2b);
+               err += sn9c102_write_reg(cam, 0xc0, 0x2c);
+               err += sn9c102_write_reg(cam, 0xd0, 0x2d);
+               err += sn9c102_write_reg(cam, 0xe0, 0x2e);
+               err += sn9c102_write_reg(cam, 0xf0, 0x2f);
+               err += sn9c102_write_reg(cam, 0xff, 0x30);
+               break;
+       default:
+               break;
+       }
 
        err += sn9c102_i2c_write(cam, 0x02, 0x14);
        err += sn9c102_i2c_write(cam, 0x03, 0x40);
@@ -107,7 +149,7 @@ static int pas202bcb_set_pix_format(struct sn9c102_device* cam,
        int err = 0;
 
        if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, 0x24, 0x17);
+               err += sn9c102_write_reg(cam, 0x28, 0x17);
        else
                err += sn9c102_write_reg(cam, 0x20, 0x17);
 
@@ -152,11 +194,23 @@ static int pas202bcb_set_ctrl(struct sn9c102_device* cam,
 static int pas202bcb_set_crop(struct sn9c102_device* cam,
                              const struct v4l2_rect* rect)
 {
-       struct sn9c102_sensor* s = &pas202bcb;
+       struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
        int err = 0;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
+       u8 h_start = 0,
           v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
 
+       switch (sn9c102_get_bridge(cam)) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
+               h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4;
+               break;
+       case BRIDGE_SN9C103:
+               h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3;
+               break;
+       default:
+               break;
+       }
+
        err += sn9c102_write_reg(cam, h_start, 0x12);
        err += sn9c102_write_reg(cam, v_start, 0x13);
 
@@ -166,8 +220,8 @@ static int pas202bcb_set_crop(struct sn9c102_device* cam,
 
 static struct sn9c102_sensor pas202bcb = {
        .name = "PAS202BCB",
-       .maintainer = "Carlos Eduardo Medaglia Dyonisio "
-                     "<medaglia@undl.org.br>",
+       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
        .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
        .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
        .interface = SN9C102_I2C_2WIRES,
@@ -191,7 +245,7 @@ static struct sn9c102_sensor pas202bcb = {
                        .minimum = 0x00,
                        .maximum = 0x1f,
                        .step = 0x01,
-                       .default_value = 0x0c,
+                       .default_value = 0x0b,
                        .flags = 0,
                },
                {
@@ -201,7 +255,7 @@ static struct sn9c102_sensor pas202bcb = {
                        .minimum = 0x00,
                        .maximum = 0x0f,
                        .step = 0x01,
-                       .default_value = 0x01,
+                       .default_value = 0x00,
                        .flags = 0,
                },
                {
@@ -271,16 +325,27 @@ int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
         *  Minimal initialization to enable the I2C communication
         *  NOTE: do NOT change the values!
         */
-       err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */
-       err += sn9c102_write_reg(cam, 0x40, 0x01); /* sensor power on */
-       err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */
-       if (err)
-               return -EIO;
+       switch (sn9c102_get_bridge(cam)) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
+               err += sn9c102_write_reg(cam, 0x01, 0x01); /* power down */
+               err += sn9c102_write_reg(cam, 0x40, 0x01); /* power on */
+               err += sn9c102_write_reg(cam, 0x28, 0x17); /* clock 24 MHz */
+               break;
+       case BRIDGE_SN9C103: /* do _not_ change anything! */
+               err += sn9c102_write_reg(cam, 0x09, 0x01);
+               err += sn9c102_write_reg(cam, 0x44, 0x01);
+               err += sn9c102_write_reg(cam, 0x44, 0x02);
+               err += sn9c102_write_reg(cam, 0x29, 0x17);
+               break;
+       default:
+               break;
+       }
 
        r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00);
        r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01);
 
-       if (r0 < 0 || r1 < 0)
+       if (err || r0 < 0 || r1 < 0)
                return -EIO;
 
        pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
index 2a874ee..05f2942 100644 (file)
@@ -1,7 +1,7 @@
 /***************************************************************************
- * API for image sensors connected to the SN9C10x PC Camera Controllers    *
+ * API for image sensors connected to the SN9C1xx PC Camera Controllers    *
  *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
  * it under the terms of the GNU General Public License as published by    *
@@ -36,14 +36,13 @@ struct sn9c102_sensor;
 /*
    OVERVIEW.
    This is a small interface that allows you to add support for any CCD/CMOS
-   image sensors connected to the SN9C10X bridges. The entire API is documented
+   image sensors connected to the SN9C1XX bridges. The entire API is documented
    below. In the most general case, to support a sensor there are three steps
    you have to follow:
    1) define the main "sn9c102_sensor" structure by setting the basic fields;
    2) write a probing function to be called by the core module when the USB
       camera is recognized, then add both the USB ids and the name of that
-      function to the two corresponding tables SENSOR_TABLE and ID_TABLE (see
-      below);
+      function to the two corresponding tables in sn9c102_devtable.h;
    3) implement the methods that you want/need (and fill the rest of the main
       structure accordingly).
    "sn9c102_pas106b.c" is an example of all this stuff. Remember that you do
@@ -54,42 +53,21 @@ struct sn9c102_sensor;
 
 /*****************************************************************************/
 
-/*
-   Probing functions: on success, you must attach the sensor to the camera
-   by calling sn9c102_attach_sensor() provided below.
-   To enable the I2C communication, you might need to perform a really basic
-   initialization of the SN9C10X chip by using the write function declared
-   ahead.
-   Functions must return 0 on success, the appropriate error otherwise.
-*/
-extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
-extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
-extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
-extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
-extern int sn9c102_probe_pas202bca(struct sn9c102_device* cam);
-extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
-extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
-extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
-
-/*
-   Add the above entries to this table. Be sure to add the entry in the right
-   place, since, on failure, the next probing routine is called according to
-   the order of the list below, from top to bottom.
-*/
-#define SN9C102_SENSOR_TABLE                                                  \
-static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {              \
-       &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */     \
-       &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */    \
-       &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */  \
-       &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */    \
-       &sn9c102_probe_pas202bca, /* detection mostly based on USB pid/vid */ \
-       &sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */    \
-       &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */       \
-       &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */       \
-       NULL,                                                                 \
+enum sn9c102_bridge {
+       BRIDGE_SN9C101 = 0x01,
+       BRIDGE_SN9C102 = 0x02,
+       BRIDGE_SN9C103 = 0x04,
+       BRIDGE_SN9C105 = 0x08,
+       BRIDGE_SN9C120 = 0x10,
 };
 
-/* Device identification */
+/* Return the bridge name */
+enum sn9c102_bridge sn9c102_get_bridge(struct sn9c102_device* cam);
+
+/* Return a pointer the sensor struct attached to the camera */
+struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam);
+
+/* Identify a device */
 extern struct sn9c102_device*
 sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id);
 
@@ -99,68 +77,8 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
                      struct sn9c102_sensor* sensor);
 
 /*
-   Each SN9C10x camera has proper PID/VID identifiers.
-   SN9C103 supports multiple interfaces, but we only handle the video class
-   interface.
-*/
-#define SN9C102_USB_DEVICE(vend, prod, intclass)                              \
-       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |                           \
-                      USB_DEVICE_ID_MATCH_INT_CLASS,                         \
-       .idVendor = (vend),                                                   \
-       .idProduct = (prod),                                                  \
-       .bInterfaceClass = (intclass)
-
-#define SN9C102_ID_TABLE                                                      \
-static const struct usb_device_id sn9c102_id_table[] = {                      \
-       { USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */                     \
-       { USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */                     \
-       { USB_DEVICE(0x0c45, 0x6007), },                                      \
-       { USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */                        \
-       { USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */                        \
-       { USB_DEVICE(0x0c45, 0x6024), },                                      \
-       { USB_DEVICE(0x0c45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */      \
-       { USB_DEVICE(0x0c45, 0x6028), }, /* PAS202BCB */                      \
-       { USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */                        \
-       { USB_DEVICE(0x0c45, 0x602a), }, /* HV7131D */                        \
-       { USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */                        \
-       { USB_DEVICE(0x0c45, 0x602c), }, /* OV7630 */                         \
-       { USB_DEVICE(0x0c45, 0x602d), },                                      \
-       { USB_DEVICE(0x0c45, 0x602e), }, /* OV7630 */                         \
-       { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */                          \
-       { SN9C102_USB_DEVICE(0x0c45, 0x6080, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x6082, 0xff), }, /* MI0343 & MI0360 */  \
-       { SN9C102_USB_DEVICE(0x0c45, 0x6083, 0xff), }, /* HV7131[D|E1] */     \
-       { SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131/R */         \
-       { SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */         \
-       { SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */           \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60a2, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60a3, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60a8, 0xff), }, /* PAS106B */          \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60aa, 0xff), }, /* TAS5130D1B */       \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60ab, 0xff), }, /* TAS5110C1B */       \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60ac, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60ae, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60af, 0xff), }, /* PAS202BCB */        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60b0, 0xff), }, /* OV7630 (?) */       \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60b2, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60b3, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60b8, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60ba, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60bb, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60bc, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60be, 0xff), },                        \
-       { }                                                                   \
-};
-
-/*****************************************************************************/
-
-/*
    Read/write routines: they always return -1 on error, 0 or the read value
-   otherwise. NOTE that a real read operation is not supported by the SN9C10X
+   otherwise. NOTE that a real read operation is not supported by the SN9C1XX
    chip for some of its registers. To work around this problem, a pseudo-read
    call is provided instead: it returns the last successfully written value
    on the register (0 if it has never been written), the usual -1 on error.
@@ -176,7 +94,7 @@ extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*,
    These must be used if and only if the sensor doesn't implement the standard
    I2C protocol. There are a number of good reasons why you must use the
    single-byte versions of these functions: do not abuse. The first function
-   writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C10X
+   writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C1XX
    chip. The second one programs the registers 0x09 and 0x10 with data0 and
    data1, and places the n bytes read from the sensor register table in the
    buffer pointed by 'buffer'. Both the functions return -1 on error; the write
@@ -200,16 +118,6 @@ extern int sn9c102_write_regs(struct sn9c102_device*, u8* buff, u16 index);
 extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index);
 extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index);
 
-/*
-   NOTE: there are no exported debugging functions. To uniform the output you
-   must use the dev_info()/dev_warn()/dev_err() macros defined in device.h,
-   already included here, the argument being the struct device '&usbdev->dev'
-   of the sensor structure. Do NOT use these macros before the sensor is
-   attached or the kernel will crash! However, you should not need to notify
-   the user about common errors or other messages, since this is done by the
-   master module.
-*/
-
 /*****************************************************************************/
 
 enum sn9c102_i2c_sysfs_ops {
@@ -227,17 +135,19 @@ enum sn9c102_i2c_interface {
        SN9C102_I2C_3WIRES,
 };
 
-#define SN9C102_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
+#define SN9C102_MAX_CTRLS (V4L2_CID_LASTP1-V4L2_CID_BASE+10)
 
 struct sn9c102_sensor {
        char name[32], /* sensor name */
             maintainer[64]; /* name of the mantainer <email> */
 
+       enum sn9c102_bridge supported_bridge; /* supported SN9C1xx bridges */
+
        /* Supported operations through the 'sysfs' interface */
        enum sn9c102_i2c_sysfs_ops sysfs_ops;
 
        /*
-          These sensor capabilities must be provided if the SN9C10X controller
+          These sensor capabilities must be provided if the SN9C1XX controller
           needs to communicate through the sensor serial interface by using
           at least one of the i2c functions available.
        */
@@ -260,7 +170,7 @@ struct sn9c102_sensor {
        /*
           This function will be called after the sensor has been attached.
           It should be used to initialize the sensor only, but may also
-          configure part of the SN9C10X chip if necessary. You don't need to
+          configure part of the SN9C1XX chip if necessary. You don't need to
           setup picture settings like brightness, contrast, etc.. here, if
           the corrisponding controls are implemented (see below), since
           they are adjusted in the core driver by calling the set_ctrl()
@@ -300,7 +210,7 @@ struct sn9c102_sensor {
           It is not always true that the largest achievable active window can
           cover the whole array of pixels. The V4L2 API defines another
           area called "source rectangle", which, in turn, is a subrectangle of
-          the active window. The SN9C10X chip is always programmed to read the
+          the active window. The SN9C1XX chip is always programmed to read the
           source rectangle.
           The bounds of both the active window and the source rectangle are
           specified in the cropcap substructures 'bounds' and 'defrect'.
@@ -326,13 +236,13 @@ struct sn9c102_sensor {
                        const struct v4l2_rect* rect);
        /*
           To be called on VIDIOC_C_SETCROP. The core module always calls a
-          default routine which configures the appropriate SN9C10X regs (also
+          default routine which configures the appropriate SN9C1XX regs (also
           scaling), but you may need to override/adjust specific stuff.
           'rect' contains width and height values that are multiple of 16: in
           case you override the default function, you always have to program
           the chip to match those values; on error return the corresponding
           error code without rolling back.
-          NOTE: in case, you must program the SN9C10X chip to get rid of
+          NOTE: in case, you must program the SN9C1XX chip to get rid of
                 blank pixels or blank lines at the _start_ of each line or
                 frame after each HSYNC or VSYNC, so that the image starts with
                 real RGB data (see regs 0x12, 0x13) (having set H_SIZE and,
@@ -344,16 +254,16 @@ struct sn9c102_sensor {
        /*
           What you have to define here are: 1) initial 'width' and 'height' of
           the target rectangle 2) the initial 'pixelformat', which can be
-          either V4L2_PIX_FMT_SN9C10X (for compressed video) or
-          V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate the
-          number of bits per pixel for uncompressed video, 8 or 9 (despite the
-          current value of 'pixelformat').
+          either V4L2_PIX_FMT_SN9C10X, V4L2_PIX_FMT_JPEG (for ompressed video)
+          or V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate
+          the number of bits per pixel for uncompressed video, 8 or 9 (despite
+          the current value of 'pixelformat').
           NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4
                   of cropcap.defrect.width and cropcap.defrect.height. I
                   suggest 1/1.
           NOTE 2: The initial compression quality is defined by the first bit
                   of reg 0x17 during the initialization of the image sensor.
-          NOTE 3: as said above, you have to program the SN9C10X chip to get
+          NOTE 3: as said above, you have to program the SN9C1XX chip to get
                   rid of any blank pixels, so that the output of the sensor
                   matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR).
        */
@@ -378,12 +288,12 @@ struct sn9c102_sensor {
 /*****************************************************************************/
 
 /* Private ioctl's for control settings supported by some image sensors */
-#define SN9C102_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE
-#define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1
-#define SN9C102_V4L2_CID_RESET_LEVEL V4L2_CID_PRIVATE_BASE + 2
-#define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE V4L2_CID_PRIVATE_BASE + 3
-#define SN9C102_V4L2_CID_GAMMA V4L2_CID_PRIVATE_BASE + 4
-#define SN9C102_V4L2_CID_BAND_FILTER V4L2_CID_PRIVATE_BASE + 5
-#define SN9C102_V4L2_CID_BRIGHT_LEVEL V4L2_CID_PRIVATE_BASE + 6
+#define SN9C102_V4L2_CID_DAC_MAGNITUDE (V4L2_CID_PRIVATE_BASE + 0)
+#define SN9C102_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 1)
+#define SN9C102_V4L2_CID_RESET_LEVEL (V4L2_CID_PRIVATE_BASE + 2)
+#define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE (V4L2_CID_PRIVATE_BASE + 3)
+#define SN9C102_V4L2_CID_GAMMA (V4L2_CID_PRIVATE_BASE + 4)
+#define SN9C102_V4L2_CID_BAND_FILTER (V4L2_CID_PRIVATE_BASE + 5)
+#define SN9C102_V4L2_CID_BRIGHT_LEVEL (V4L2_CID_PRIVATE_BASE + 6)
 
 #endif /* _SN9C102_SENSOR_H_ */
index 294eb02..90023ad 100644 (file)
@@ -1,8 +1,8 @@
 /***************************************************************************
- * Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera  *
+ * Plug-in for TAS5110C1B image sensor connected to the SN9C1xx PC Camera  *
  * Controllers                                                             *
  *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
  * it under the terms of the GNU General Public License as published by    *
@@ -64,7 +64,7 @@ static int tas5110c1b_set_ctrl(struct sn9c102_device* cam,
 static int tas5110c1b_set_crop(struct sn9c102_device* cam,
                               const struct v4l2_rect* rect)
 {
-       struct sn9c102_sensor* s = &tas5110c1b;
+       struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
        int err = 0;
        u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69,
           v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9;
@@ -98,6 +98,7 @@ static int tas5110c1b_set_pix_format(struct sn9c102_device* cam,
 static struct sn9c102_sensor tas5110c1b = {
        .name = "TAS5110C1B",
        .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
        .sysfs_ops = SN9C102_I2C_WRITE,
        .frequency = SN9C102_I2C_100KHZ,
        .interface = SN9C102_I2C_3WIRES,
@@ -145,6 +146,7 @@ int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
        const struct usb_device_id tas5110c1b_id_table[] = {
                { USB_DEVICE(0x0c45, 0x6001), },
                { USB_DEVICE(0x0c45, 0x6005), },
+               { USB_DEVICE(0x0c45, 0x6007), },
                { USB_DEVICE(0x0c45, 0x60ab), },
                { }
        };
index 9ecb090..cb1b318 100644 (file)
@@ -1,8 +1,8 @@
 /***************************************************************************
- * Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera  *
+ * Plug-in for TAS5130D1B image sensor connected to the SN9C1xx PC Camera  *
  * Controllers                                                             *
  *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
  * it under the terms of the GNU General Public License as published by    *
@@ -65,7 +65,7 @@ static int tas5130d1b_set_ctrl(struct sn9c102_device* cam,
 static int tas5130d1b_set_crop(struct sn9c102_device* cam,
                               const struct v4l2_rect* rect)
 {
-       struct sn9c102_sensor* s = &tas5130d1b;
+       struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
        u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104,
           v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12;
        int err = 0;
@@ -99,6 +99,7 @@ static int tas5130d1b_set_pix_format(struct sn9c102_device* cam,
 static struct sn9c102_sensor tas5130d1b = {
        .name = "TAS5130D1B",
        .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
        .sysfs_ops = SN9C102_I2C_WRITE,
        .frequency = SN9C102_I2C_100KHZ,
        .interface = SN9C102_I2C_3WIRES,
@@ -154,6 +155,7 @@ static struct sn9c102_sensor tas5130d1b = {
 int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
 {
        const struct usb_device_id tas5130d1b_id_table[] = {
+               { USB_DEVICE(0x0c45, 0x6024), },
                { USB_DEVICE(0x0c45, 0x6025), },
                { USB_DEVICE(0x0c45, 0x60aa), },
                { }
index 7ea9132..3ae5a9c 100644 (file)
@@ -212,8 +212,7 @@ static int tvmixer_release(struct inode *inode, struct file *file)
                return -ENODEV;
        }
 
-       if (client->adapter->owner)
-               module_put(client->adapter->owner);
+       module_put(client->adapter->owner);
        return 0;
 }
 
index bc0a4fc..886b5df 100644 (file)
@@ -950,17 +950,8 @@ static int tvp5150_command(struct i2c_client *c,
        }
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-       case VIDIOC_INT_G_REGISTER:
-       {
-               struct v4l2_register *reg = arg;
-
-               if (reg->i2c_id != I2C_DRIVERID_TVP5150)
-                       return -EINVAL;
-               reg->val = tvp5150_read(c, reg->reg & 0xff);
-               break;
-       }
-
-       case VIDIOC_INT_S_REGISTER:
+       case VIDIOC_DBG_G_REGISTER:
+       case VIDIOC_DBG_S_REGISTER:
        {
                struct v4l2_register *reg = arg;
 
@@ -968,7 +959,10 @@ static int tvp5150_command(struct i2c_client *c,
                        return -EINVAL;
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               tvp5150_write(c, reg->reg & 0xff, reg->val & 0xff);
+               if (cmd == VIDIOC_DBG_G_REGISTER)
+                       reg->val = tvp5150_read(c, reg->reg & 0xff);
+               else
+                       tvp5150_write(c, reg->reg & 0xff, reg->val & 0xff);
                break;
        }
 #endif
index fc52201..b3b5fd5 100644 (file)
@@ -162,27 +162,19 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *
                break;
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-       case VIDIOC_INT_G_REGISTER:
+       case VIDIOC_DBG_G_REGISTER:
+       case VIDIOC_DBG_S_REGISTER:
        {
                struct v4l2_register *reg = arg;
 
                if (reg->i2c_id != I2C_DRIVERID_UPD64031A)
                        return -EINVAL;
-               reg->val = upd64031a_read(client, reg->reg & 0xff);
-               break;
-       }
-
-       case VIDIOC_INT_S_REGISTER:
-       {
-               struct v4l2_register *reg = arg;
-               u8 addr = reg->reg & 0xff;
-               u8 val = reg->val & 0xff;
-
-               if (reg->i2c_id != I2C_DRIVERID_UPD64031A)
-                       return -EINVAL;
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               upd64031a_write(client, addr, val);
+               if (cmd == VIDIOC_DBG_G_REGISTER)
+                       reg->val = upd64031a_read(client, reg->reg & 0xff);
+               else
+                       upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff);
                break;
        }
 #endif
index c3a7ffe..8852903 100644 (file)
@@ -139,27 +139,19 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a
                break;
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-       case VIDIOC_INT_G_REGISTER:
+       case VIDIOC_DBG_G_REGISTER:
+       case VIDIOC_DBG_S_REGISTER:
        {
                struct v4l2_register *reg = arg;
 
                if (reg->i2c_id != I2C_DRIVERID_UPD64083)
                        return -EINVAL;
-               reg->val = upd64083_read(client, reg->reg & 0xff);
-               break;
-       }
-
-       case VIDIOC_INT_S_REGISTER:
-       {
-               struct v4l2_register *reg = arg;
-               u8 addr = reg->reg & 0xff;
-               u8 val = reg->val & 0xff;
-
-               if (reg->i2c_id != I2C_DRIVERID_UPD64083)
-                       return -EINVAL;
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               upd64083_write(client, addr, val);
+               if (cmd == VIDIOC_DBG_G_REGISTER)
+                       reg->val = upd64083_read(client, reg->reg & 0xff);
+               else
+                       upd64083_write(client, reg->reg & 0xff, reg->val & 0xff);
                break;
        }
 #endif
index fc24ef0..c43a5d8 100644 (file)
@@ -1,6 +1,6 @@
 config VIDEO_USBVISION
        tristate "USB video devices based on Nogatech NT1003/1004/1005"
-       depends on I2C && VIDEO_V4L2
+       depends on I2C && VIDEO_V4L2 && USB
        select VIDEO_TUNER
        select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
        ---help---
index 901f664..f2154dc 100644 (file)
@@ -138,7 +138,7 @@ static void *usbvision_rvmalloc(unsigned long size)
        return mem;
 }
 
-void usbvision_rvfree(void *mem, unsigned long size)
+static void usbvision_rvfree(void *mem, unsigned long size)
 {
        unsigned long adr;
 
@@ -1852,28 +1852,33 @@ int usbvision_set_output(struct usb_usbvision *usbvision, int width,
 
 /*
  * usbvision_frames_alloc
- * allocate the maximum frames this driver can manage
+ * allocate the required frames
  */
-int usbvision_frames_alloc(struct usb_usbvision *usbvision)
+int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames)
 {
        int i;
 
-       /* Allocate memory for the frame buffers */
-       usbvision->max_frame_size = MAX_FRAME_SIZE;
-       usbvision->fbuf_size = USBVISION_NUMFRAMES * usbvision->max_frame_size;
-       usbvision->fbuf = usbvision_rvmalloc(usbvision->fbuf_size);
+       /*needs to be page aligned cause the buffers can be mapped individually! */
+       usbvision->max_frame_size =  PAGE_ALIGN(usbvision->curwidth *
+                                               usbvision->curheight *
+                                               usbvision->palette.bytes_per_pixel);
 
-       if(usbvision->fbuf == NULL) {
-               err("%s: unable to allocate %d bytes for fbuf ",
-                   __FUNCTION__, usbvision->fbuf_size);
-               return -ENOMEM;
+       /* Try to do my best to allocate the frames the user want in the remaining memory */
+       usbvision->num_frames = number_of_frames;
+       while (usbvision->num_frames > 0) {
+               usbvision->fbuf_size = usbvision->num_frames * usbvision->max_frame_size;
+               if((usbvision->fbuf = usbvision_rvmalloc(usbvision->fbuf_size))) {
+                       break;
+               }
+               usbvision->num_frames--;
        }
+
        spin_lock_init(&usbvision->queue_lock);
        init_waitqueue_head(&usbvision->wait_frame);
        init_waitqueue_head(&usbvision->wait_stream);
 
        /* Allocate all buffers */
-       for (i = 0; i < USBVISION_NUMFRAMES; i++) {
+       for (i = 0; i < usbvision->num_frames; i++) {
                usbvision->frame[i].index = i;
                usbvision->frame[i].grabstate = FrameState_Unused;
                usbvision->frame[i].data = usbvision->fbuf +
@@ -1887,7 +1892,8 @@ int usbvision_frames_alloc(struct usb_usbvision *usbvision)
                usbvision->frame[i].height = usbvision->curheight;
                usbvision->frame[i].bytes_read = 0;
        }
-       return 0;
+       PDEBUG(DBG_FUNC, "allocated %d frames (%d bytes per frame)",usbvision->num_frames,usbvision->max_frame_size);
+       return usbvision->num_frames;
 }
 
 /*
@@ -1897,9 +1903,13 @@ int usbvision_frames_alloc(struct usb_usbvision *usbvision)
 void usbvision_frames_free(struct usb_usbvision *usbvision)
 {
        /* Have to free all that memory */
+       PDEBUG(DBG_FUNC, "free %d frames",usbvision->num_frames);
+
        if (usbvision->fbuf != NULL) {
                usbvision_rvfree(usbvision->fbuf, usbvision->fbuf_size);
                usbvision->fbuf = NULL;
+
+               usbvision->num_frames = 0;
        }
 }
 /*
@@ -2351,6 +2361,32 @@ int usbvision_setup(struct usb_usbvision *usbvision,int format)
        return USBVISION_IS_OPERATIONAL(usbvision);
 }
 
+int usbvision_set_alternate(struct usb_usbvision *dev)
+{
+       int errCode, prev_alt = dev->ifaceAlt;
+       int i;
+
+       dev->ifaceAlt=0;
+       for(i=0;i< dev->num_alt; i++)
+               if(dev->alt_max_pkt_size[i]>dev->alt_max_pkt_size[dev->ifaceAlt])
+                       dev->ifaceAlt=i;
+
+       if (dev->ifaceAlt != prev_alt) {
+               dev->isocPacketSize = dev->alt_max_pkt_size[dev->ifaceAlt];
+               PDEBUG(DBG_FUNC,"setting alternate %d with wMaxPacketSize=%u", dev->ifaceAlt,dev->isocPacketSize);
+               errCode = usb_set_interface(dev->dev, dev->iface, dev->ifaceAlt);
+               if (errCode < 0) {
+                       err ("cannot change alternate number to %d (error=%i)",
+                                                       dev->ifaceAlt, errCode);
+                       return errCode;
+               }
+       }
+
+       PDEBUG(DBG_ISOC, "ISO Packet Length:%d", dev->isocPacketSize);
+
+       return 0;
+}
+
 /*
  * usbvision_init_isoc()
  *
@@ -2368,15 +2404,13 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
        scratch_reset(usbvision);
 
        /* Alternate interface 1 is is the biggest frame size */
-       errCode = usb_set_interface(dev, usbvision->iface, usbvision->ifaceAltActive);
+       errCode = usbvision_set_alternate(usbvision);
        if (errCode < 0) {
                usbvision->last_error = errCode;
                return -EBUSY;
        }
 
        regValue = (16 - usbvision_read_reg(usbvision, USBVISION_ALTER_REG)) & 0x0F;
-       usbvision->isocPacketSize = (regValue == 0) ? 0 : (regValue * 64) - 1;
-       PDEBUG(DBG_ISOC, "ISO Packet Length:%d", usbvision->isocPacketSize);
 
        usbvision->usb_bandwidth = regValue >> 1;
        PDEBUG(DBG_ISOC, "USB Bandwidth Usage: %dMbit/Sec", usbvision->usb_bandwidth);
@@ -2462,8 +2496,9 @@ void usbvision_stop_isoc(struct usb_usbvision *usbvision)
        if (!usbvision->remove_pending) {
 
                /* Set packet size to 0 */
+               usbvision->ifaceAlt=0;
                errCode = usb_set_interface(usbvision->dev, usbvision->iface,
-                                     usbvision->ifaceAltInactive);
+                                           usbvision->ifaceAlt);
                if (errCode < 0) {
                        err("%s: usb_set_interface() failed: error %d", __FUNCTION__, errCode);
                        usbvision->last_error = errCode;
@@ -2490,6 +2525,7 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
        RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs);
        usbvision->ctl_input = channel;
          route.input = SAA7115_COMPOSITE1;
+         route.output = 0;
          call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
          call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->ctl_input);
 
index af33653..ae5f425 100644 (file)
@@ -230,7 +230,7 @@ static ssize_t show_hue(struct class_device *cd, char *buf)
        ctrl.value = 0;
        if(usbvision->user)
                call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
-       return sprintf(buf, "%d\n", ctrl.value >> 8);
+       return sprintf(buf, "%d\n", ctrl.value);
 }
 static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
 
@@ -243,7 +243,7 @@ static ssize_t show_contrast(struct class_device *cd, char *buf)
        ctrl.value = 0;
        if(usbvision->user)
                call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
-       return sprintf(buf, "%d\n", ctrl.value >> 8);
+       return sprintf(buf, "%d\n", ctrl.value);
 }
 static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
 
@@ -256,7 +256,7 @@ static ssize_t show_brightness(struct class_device *cd, char *buf)
        ctrl.value = 0;
        if(usbvision->user)
                call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
-       return sprintf(buf, "%d\n", ctrl.value >> 8);
+       return sprintf(buf, "%d\n", ctrl.value);
 }
 static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
 
@@ -269,7 +269,7 @@ static ssize_t show_saturation(struct class_device *cd, char *buf)
        ctrl.value = 0;
        if(usbvision->user)
                call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
-       return sprintf(buf, "%d\n", ctrl.value >> 8);
+       return sprintf(buf, "%d\n", ctrl.value);
 }
 static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
 
@@ -391,19 +391,14 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
        if (usbvision->user)
                errCode = -EBUSY;
        else {
-               /* Allocate memory for the frame buffers */
-               errCode = usbvision_frames_alloc(usbvision);
-               if(!errCode) {
-                       /* Allocate memory for the scratch ring buffer */
-                       errCode = usbvision_scratch_alloc(usbvision);
-                       if ((!errCode) && (isocMode==ISOC_MODE_COMPRESS)) {
-                               /* Allocate intermediate decompression buffers only if needed */
-                               errCode = usbvision_decompress_alloc(usbvision);
-                       }
+               /* Allocate memory for the scratch ring buffer */
+               errCode = usbvision_scratch_alloc(usbvision);
+               if (isocMode==ISOC_MODE_COMPRESS) {
+                       /* Allocate intermediate decompression buffers only if needed */
+                       errCode = usbvision_decompress_alloc(usbvision);
                }
                if (errCode) {
                        /* Deallocate all buffers if trouble */
-                       usbvision_frames_free(usbvision);
                        usbvision_scratch_free(usbvision);
                        usbvision_decompress_free(usbvision);
                }
@@ -476,6 +471,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
 
        usbvision_decompress_free(usbvision);
        usbvision_frames_free(usbvision);
+       usbvision_empty_framequeues(usbvision);
        usbvision_scratch_free(usbvision);
 
        usbvision->user--;
@@ -489,7 +485,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
        up(&usbvision->lock);
 
        if (usbvision->remove_pending) {
-               info("%s: Final disconnect", __FUNCTION__);
+               printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__);
                usbvision_release(usbvision);
        }
 
@@ -519,27 +515,8 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
                /* ioctls to allow direct acces to the NT100x registers */
-               case VIDIOC_INT_G_REGISTER:
-               {
-                       struct v4l2_register *reg = arg;
-                       int errCode;
-
-                       if (reg->i2c_id != 0)
-                               return -EINVAL;
-                       /* NT100x has a 8-bit register space */
-                       errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
-                       if (errCode < 0) {
-                               err("%s: VIDIOC_INT_G_REGISTER failed: error %d", __FUNCTION__, errCode);
-                       }
-                       else {
-                               reg->val=(unsigned char)errCode;
-                               PDEBUG(DBG_IOCTL, "VIDIOC_INT_G_REGISTER reg=0x%02X, value=0x%02X",
-                                                       (unsigned int)reg->reg, reg->val);
-                               errCode = 0; // No error
-                       }
-                       return errCode;
-               }
-               case VIDIOC_INT_S_REGISTER:
+               case VIDIOC_DBG_G_REGISTER:
+               case VIDIOC_DBG_S_REGISTER:
                {
                        struct v4l2_register *reg = arg;
                        int errCode;
@@ -548,15 +525,22 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
                                return -EINVAL;
                        if (!capable(CAP_SYS_ADMIN))
                                return -EPERM;
-                       errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
+                       /* NT100x has a 8-bit register space */
+                       if (cmd == VIDIOC_DBG_G_REGISTER)
+                               errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
+                       else
+                               errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
                        if (errCode < 0) {
-                               err("%s: VIDIOC_INT_S_REGISTER failed: error %d", __FUNCTION__, errCode);
-                       }
-                       else {
-                               PDEBUG(DBG_IOCTL, "VIDIOC_INT_S_REGISTER reg=0x%02X, value=0x%02X",
-                                                       (unsigned int)reg->reg, reg->val);
-                               errCode = 0;
+                               err("%s: VIDIOC_DBG_%c_REGISTER failed: error %d", __FUNCTION__,
+                                   cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S', errCode);
+                               return errCode;
                        }
+                       if (cmd == VIDIOC_DBG_S_REGISTER)
+                               reg->val = (u8)errCode;
+
+                       PDEBUG(DBG_IOCTL, "VIDIOC_DBG_%c_REGISTER reg=0x%02X, value=0x%02X",
+                              cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S',
+                              (unsigned int)reg->reg, reg->val);
                        return 0;
                }
 #endif
@@ -792,8 +776,8 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
                case VIDIOC_G_CTRL:
                {
                        struct v4l2_control *ctrl = arg;
-                       PDEBUG(DBG_IOCTL,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
                        call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
+                       PDEBUG(DBG_IOCTL,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
                        return 0;
                }
                case VIDIOC_S_CTRL:
@@ -821,7 +805,9 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
                                    return ret;
                        }
 
+                       usbvision_frames_free(usbvision);
                        usbvision_empty_framequeues(usbvision);
+                       vr->count = usbvision_frames_alloc(usbvision,vr->count);
 
                        usbvision->curFrame = NULL;
 
@@ -838,7 +824,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
                        if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
                                return -EINVAL;
                        }
-                       if(vb->index>=USBVISION_NUMFRAMES)  {
+                       if(vb->index>=usbvision->num_frames)  {
                                return -EINVAL;
                        }
                        // Updating the corresponding frame state
@@ -852,7 +838,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
                                vb->flags |= V4L2_BUF_FLAG_MAPPED;
                        vb->memory = V4L2_MEMORY_MMAP;
 
-                       vb->m.offset = vb->index*usbvision->max_frame_size;
+                       vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size);
 
                        vb->memory = V4L2_MEMORY_MMAP;
                        vb->field = V4L2_FIELD_NONE;
@@ -871,7 +857,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
                        if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
                                return -EINVAL;
                        }
-                       if(vb->index>=USBVISION_NUMFRAMES)  {
+                       if(vb->index>=usbvision->num_frames)  {
                                return -EINVAL;
                        }
 
@@ -1041,6 +1027,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
                                                if ((ret = usbvision_stream_interrupt(usbvision)))
                                                        return ret;
                                        }
+                                       usbvision_frames_free(usbvision);
                                        usbvision_empty_framequeues(usbvision);
 
                                        usbvision->curFrame = NULL;
@@ -1087,12 +1074,24 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
        if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL))
                return -EFAULT;
 
-       /* no stream is running, make it running ! */
-       usbvision->streaming = Stream_On;
-       call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
+       /* This entry point is compatible with the mmap routines so that a user can do either
+          VIDIOC_QBUF/VIDIOC_DQBUF to get frames or call read on the device. */
+       if(!usbvision->num_frames) {
+               /* First, allocate some frames to work with if this has not been done with
+                VIDIOC_REQBUF */
+               usbvision_frames_free(usbvision);
+               usbvision_empty_framequeues(usbvision);
+               usbvision_frames_alloc(usbvision,USBVISION_NUMFRAMES);
+       }
+
+       if(usbvision->streaming != Stream_On) {
+               /* no stream is running, make it running ! */
+               usbvision->streaming = Stream_On;
+               call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
+       }
 
-       /* First, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */
-       for(i=0;i<USBVISION_NUMFRAMES;i++) {
+       /* Then, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */
+       for(i=0;i<usbvision->num_frames;i++) {
                frame = &usbvision->frame[i];
                if(frame->grabstate == FrameState_Unused) {
                        /* Mark it as ready and enqueue frame */
@@ -1169,6 +1168,8 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
        struct video_device *dev = video_devdata(file);
        struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
 
+       PDEBUG(DBG_MMAP, "mmap");
+
        down(&usbvision->lock);
 
        if (!USBVISION_IS_OPERATIONAL(usbvision)) {
@@ -1177,16 +1178,16 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
        }
 
        if (!(vma->vm_flags & VM_WRITE) ||
-           size != PAGE_ALIGN(usbvision->curwidth*usbvision->curheight*usbvision->palette.bytes_per_pixel)) {
+           size != PAGE_ALIGN(usbvision->max_frame_size)) {
                up(&usbvision->lock);
                return -EINVAL;
        }
 
-       for (i = 0; i < USBVISION_NUMFRAMES; i++) {
-               if (((usbvision->max_frame_size*i) >> PAGE_SHIFT) == vma->vm_pgoff)
+       for (i = 0; i < usbvision->num_frames; i++) {
+               if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) == vma->vm_pgoff)
                        break;
        }
-       if (i == USBVISION_NUMFRAMES) {
+       if (i == usbvision->num_frames) {
                PDEBUG(DBG_MMAP, "mmap: user supplied mapping address is out of range");
                up(&usbvision->lock);
                return -EINVAL;
@@ -1242,6 +1243,13 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
                        }
                }
 
+               /* Alternate interface 1 is is the biggest frame size */
+               errCode = usbvision_set_alternate(usbvision);
+               if (errCode < 0) {
+                       usbvision->last_error = errCode;
+                       return -EBUSY;
+               }
+
                // If so far no errors then we shall start the radio
                usbvision->radio = 1;
                call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type);
@@ -1273,6 +1281,11 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
 
        down(&usbvision->lock);
 
+       /* Set packet size to 0 */
+       usbvision->ifaceAlt=0;
+       errCode = usb_set_interface(usbvision->dev, usbvision->iface,
+                                   usbvision->ifaceAlt);
+
        usbvision_audio_off(usbvision);
        usbvision->radio=0;
        usbvision->user--;
@@ -1285,7 +1298,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
        up(&usbvision->lock);
 
        if (usbvision->remove_pending) {
-               info("%s: Final disconnect", __FUNCTION__);
+               printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__);
                usbvision_release(usbvision);
        }
 
@@ -1611,7 +1624,7 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
        if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr)<0) {
                goto err_exit;
        }
-       info("USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]", usbvision->nr,usbvision->vdev->minor & 0x1f);
+       printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n", usbvision->nr,usbvision->vdev->minor & 0x1f);
 
        // Radio Device:
        if (usbvision_device_data[usbvision->DevModel].Radio) {
@@ -1623,7 +1636,7 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
                if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr)<0) {
                        goto err_exit;
                }
-               info("USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]", usbvision->nr, usbvision->rdev->minor & 0x1f);
+               printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n", usbvision->nr, usbvision->rdev->minor & 0x1f);
        }
        // vbi Device:
        if (usbvision_device_data[usbvision->DevModel].vbi) {
@@ -1634,7 +1647,7 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
                if (video_register_device(usbvision->vbi, VFL_TYPE_VBI, vbi_nr)<0) {
                        goto err_exit;
                }
-               info("USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)", usbvision->nr,usbvision->vbi->minor & 0x1f);
+               printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n", usbvision->nr,usbvision->vbi->minor & 0x1f);
        }
        // all done
        return 0;
@@ -1764,15 +1777,17 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision)
  */
 static int __devinit usbvision_probe(struct usb_interface *intf, const struct usb_device_id *devid)
 {
-       struct usb_device *dev = interface_to_usbdev(intf);
+       struct usb_device *dev = usb_get_dev(interface_to_usbdev(intf));
+       struct usb_interface *uif;
        __u8 ifnum = intf->altsetting->desc.bInterfaceNumber;
        const struct usb_host_interface *interface;
        struct usb_usbvision *usbvision = NULL;
        const struct usb_endpoint_descriptor *endpoint;
-       int model;
+       int model,i;
 
        PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u",
                                        dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
+
        /* Is it an USBVISION video dev? */
        model = 0;
        for(model = 0; usbvision_device_data[model].idVendor; model++) {
@@ -1783,7 +1798,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us
                        continue;
                }
 
-               info("%s: %s found", __FUNCTION__, usbvision_device_data[model].ModelString);
+               printk(KERN_INFO "%s: %s found\n", __FUNCTION__, usbvision_device_data[model].ModelString);
                break;
        }
 
@@ -1799,7 +1814,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us
        endpoint = &interface->endpoint[1].desc;
        if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC) {
                err("%s: interface %d. has non-ISO endpoint!", __FUNCTION__, ifnum);
-               err("%s: Endpoint attribures %d", __FUNCTION__, endpoint->bmAttributes);
+               err("%s: Endpoint attributes %d", __FUNCTION__, endpoint->bmAttributes);
                return -ENODEV;
        }
        if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
@@ -1826,6 +1841,28 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us
 
        down(&usbvision->lock);
 
+       /* compute alternate max packet sizes */
+       uif = dev->actconfig->interface[0];
+
+       usbvision->num_alt=uif->num_altsetting;
+       PDEBUG(DBG_PROBE, "Alternate settings: %i",usbvision->num_alt);
+       usbvision->alt_max_pkt_size = kmalloc(32*
+                                             usbvision->num_alt,GFP_KERNEL);
+       if (usbvision->alt_max_pkt_size == NULL) {
+               err("usbvision: out of memory!\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < usbvision->num_alt ; i++) {
+               u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc.
+                                     wMaxPacketSize);
+               usbvision->alt_max_pkt_size[i] =
+                       (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+               PDEBUG(DBG_PROBE, "Alternate setting %i, max size= %i",i,
+                      usbvision->alt_max_pkt_size[i]);
+       }
+
+
        usbvision->nr = usbvision_nr++;
 
        usbvision->have_tuner = usbvision_device_data[model].Tuner;
@@ -1838,8 +1875,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us
        usbvision->DevModel = model;
        usbvision->remove_pending = 0;
        usbvision->iface = ifnum;
-       usbvision->ifaceAltInactive = 0;
-       usbvision->ifaceAltActive = 1;
+       usbvision->ifaceAlt = 0;
        usbvision->video_endp = endpoint->bEndpointAddress;
        usbvision->isocPacketSize = 0;
        usbvision->usb_bandwidth = 0;
@@ -1895,7 +1931,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
        up(&usbvision->lock);
 
        if (usbvision->user) {
-               info("%s: In use, disconnect pending", __FUNCTION__);
+               printk(KERN_INFO "%s: In use, disconnect pending\n", __FUNCTION__);
                wake_up_interruptible(&usbvision->wait_frame);
                wake_up_interruptible(&usbvision->wait_stream);
        }
@@ -2061,7 +2097,7 @@ static int __init usbvision_init(void)
        errCode = usb_register(&usbvision_driver);
 
        if (errCode == 0) {
-               info(DRIVER_DESC " : " USBVISION_VERSION_STRING);
+               printk(KERN_INFO DRIVER_DESC " : " USBVISION_VERSION_STRING "\n");
                PDEBUG(DBG_PROBE, "success");
        }
        return errCode;
index e2bcaba..ad6afd3 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <linux/list.h>
 #include <linux/usb.h>
+#include <linux/i2c.h>
 #include <media/v4l2-common.h>
 #include <media/tuner.h>
 #include <linux/videodev2.h>
@@ -396,8 +397,11 @@ struct usb_usbvision {
 
        /* Device structure */
        struct usb_device *dev;
+       /* usb transfer */
+       int num_alt;            /* Number of alternative settings */
+       unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
        unsigned char iface;                                            /* Video interface number */
-       unsigned char ifaceAltActive, ifaceAltInactive;                 /* Alt settings */
+       unsigned char ifaceAlt;                 /* Alt settings */
        unsigned char Vin_Reg2_Preset;
        struct semaphore lock;
        struct timer_list powerOffTimer;
@@ -421,6 +425,7 @@ struct usb_usbvision {
        wait_queue_head_t wait_stream;                                  /* Processes waiting */
        struct usbvision_frame *curFrame;                               // pointer to current frame, set by usbvision_find_header
        struct usbvision_frame frame[USBVISION_NUMFRAMES];              // frame buffer
+       int num_frames;                                                 // number of frames allocated
        struct usbvision_sbuf sbuf[USBVISION_NUMSBUF];                  // S buffering
        volatile int remove_pending;                                    /* If set then about to exit */
 
@@ -486,12 +491,11 @@ int usbvision_init_i2c(struct usb_usbvision *usbvision);
 void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,void *arg);
 
 /* defined in usbvision-core.c                                      */
-void usbvision_rvfree(void *mem, unsigned long size);
 int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg);
 int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg,
                        unsigned char value);
 
-int usbvision_frames_alloc(struct usb_usbvision *usbvision);
+int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames);
 void usbvision_frames_free(struct usb_usbvision *usbvision);
 int usbvision_scratch_alloc(struct usb_usbvision *usbvision);
 void usbvision_scratch_free(struct usb_usbvision *usbvision);
@@ -502,6 +506,7 @@ int usbvision_setup(struct usb_usbvision *usbvision,int format);
 int usbvision_init_isoc(struct usb_usbvision *usbvision);
 int usbvision_restart_isoc(struct usb_usbvision *usbvision);
 void usbvision_stop_isoc(struct usb_usbvision *usbvision);
+int usbvision_set_alternate(struct usb_usbvision *dev);
 
 int usbvision_set_audio(struct usb_usbvision *usbvision, int AudioChannel);
 int usbvision_audio_off(struct usb_usbvision *usbvision);
index 8a13e59..d2c1ae0 100644 (file)
@@ -11,7 +11,7 @@
  *     as published by the Free Software Foundation; either version
  *     2 of the License, or (at your option) any later version.
  *
- * Author:     Bill Dirks <bdirks@pacbell.net>
+ * Author:     Bill Dirks <bill@thedirks.org>
  *             et al.
  *
  */
index b8ee37d..ddfd80c 100644 (file)
@@ -12,7 +12,7 @@
  *     as published by the Free Software Foundation; either version
  *     2 of the License, or (at your option) any later version.
  *
- * Author:     Bill Dirks <bdirks@pacbell.net>
+ * Author:     Bill Dirks <bill@thedirks.org>
  *             based on code by Alan Cox, <alan@cymru.net>
  *
  */
@@ -271,11 +271,6 @@ char *v4l2_type_names[] = {
        [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT]  = "slicec-vbi-out",
 };
 
-static char *v4l2_memory_names[] = {
-       [V4L2_MEMORY_MMAP]    = "mmap",
-       [V4L2_MEMORY_USERPTR] = "userptr",
-       [V4L2_MEMORY_OVERLAY] = "overlay",
-};
 
 #define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown"
 
@@ -400,9 +395,10 @@ static const char *v4l2_int_ioctls[] = {
        [_IOC_NR(TUNER_SET_STANDBY)]           = "TUNER_SET_STANDBY",
        [_IOC_NR(TDA9887_SET_CONFIG)]          = "TDA9887_SET_CONFIG",
 
+       [_IOC_NR(VIDIOC_DBG_S_REGISTER)]       = "VIDIOC_DBG_S_REGISTER",
+       [_IOC_NR(VIDIOC_DBG_G_REGISTER)]       = "VIDIOC_DBG_G_REGISTER",
+
        [_IOC_NR(VIDIOC_INT_S_TUNER_MODE)]     = "VIDIOC_INT_S_TUNER_MODE",
-       [_IOC_NR(VIDIOC_INT_S_REGISTER)]       = "VIDIOC_INT_S_REGISTER",
-       [_IOC_NR(VIDIOC_INT_G_REGISTER)]       = "VIDIOC_INT_G_REGISTER",
        [_IOC_NR(VIDIOC_INT_RESET)]            = "VIDIOC_INT_RESET",
        [_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ",
        [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)]  = "VIDIOC_INT_DECODE_VBI_LINE",
@@ -419,14 +415,6 @@ static const char *v4l2_int_ioctls[] = {
 };
 #define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
 
-static void v4l_print_pix_fmt (char *s, struct v4l2_pix_format *fmt)
-{
-       printk ("%s: width=%d, height=%d, format=%d, field=%s, "
-               "bytesperline=%d sizeimage=%d, colorspace=%d\n", s,
-               fmt->width,fmt->height,fmt->pixelformat,
-               prt_names(fmt->field,v4l2_field_names),
-               fmt->bytesperline,fmt->sizeimage,fmt->colorspace);
-};
 
 /* Common ioctl debug function. This function can be used by
    external ioctl messages as well as internal V4L ioctl */
@@ -466,576 +454,6 @@ void v4l_printk_ioctl(unsigned int cmd)
        }
 }
 
-/* Common ioctl debug function. This function can be used by
-   external ioctl messages as well as internal V4L ioctl and its
-   arguments */
-void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
-{
-       printk(s);
-       printk(": ");
-       v4l_printk_ioctl(cmd);
-       switch (cmd) {
-       case VIDIOC_INT_G_CHIP_IDENT:
-       {
-               enum v4l2_chip_ident  *p=arg;
-               printk ("%s: chip ident=%d\n", s, *p);
-               break;
-       }
-       case VIDIOC_G_PRIORITY:
-       case VIDIOC_S_PRIORITY:
-       {
-               enum v4l2_priority *p=arg;
-               printk ("%s: priority=%d\n", s, *p);
-               break;
-       }
-       case VIDIOC_INT_S_TUNER_MODE:
-       {
-               enum v4l2_tuner_type *p=arg;
-               printk ("%s: tuner type=%d\n", s, *p);
-               break;
-       }
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       case DECODER_SET_VBI_BYPASS:
-       case DECODER_ENABLE_OUTPUT:
-       case DECODER_GET_STATUS:
-       case DECODER_SET_OUTPUT:
-       case DECODER_SET_INPUT:
-       case DECODER_SET_GPIO:
-       case DECODER_SET_NORM:
-       case VIDIOCCAPTURE:
-       case VIDIOCSYNC:
-       case VIDIOCSWRITEMODE:
-#endif
-       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:
-       case VIDIOC_STREAMON:
-       case VIDIOC_G_INPUT:
-       case VIDIOC_OVERLAY:
-       case VIDIOC_S_INPUT:
-       {
-               int *p=arg;
-               printk ("%s: value=%d\n", s, *p);
-               break;
-       }
-       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;
-
-               printk ("%s: index=%d, name=%s, capability=%d, mode=%d\n",
-                       s,p->index, p->name,p->capability, p->mode);
-               break;
-       }
-       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,
-                               p->index, p->name, p->capability,p->mode);
-               break;
-       }
-       case VIDIOC_QBUF:
-       case VIDIOC_DQBUF:
-       case VIDIOC_QUERYBUF:
-       {
-               struct v4l2_buffer *p=arg;
-               struct v4l2_timecode *tc=&p->timecode;
-               printk ("%s: %02ld:%02d:%02d.%08ld index=%d, type=%s, "
-                       "bytesused=%d, flags=0x%08x, "
-                       "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx\n",
-                               s,
-                               (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),
-                               p->bytesused,p->flags,
-                               p->field,p->sequence,
-                               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%08x\n",
-                               s,tc->hours,tc->minutes,tc->seconds,
-                               tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
-               break;
-       }
-       case VIDIOC_QUERYCAP:
-       {
-               struct v4l2_capability *p=arg;
-               printk ("%s: driver=%s, card=%s, bus=%s, version=0x%08x, "
-                       "capabilities=0x%08x\n", s,
-                               p->driver,p->card,p->bus_info,
-                               p->version,
-                               p->capabilities);
-               break;
-       }
-       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:
-       {
-               struct v4l2_crop *p=arg;
-               /*FIXME: Should also show rect structs */
-               printk ("%s: type=%d\n", s, p->type);
-               break;
-       }
-       case VIDIOC_CROPCAP:
-#ifdef __OLD_VIDIOC_
-       case VIDIOC_CROPCAP_OLD:
-#endif
-       {
-               struct v4l2_cropcap *p=arg;
-               /*FIXME: Should also show rect structs */
-               printk ("%s: type=%d\n", s, p->type);
-               break;
-       }
-       case VIDIOC_INT_DECODE_VBI_LINE:
-       {
-               struct v4l2_decode_vbi_line *p=arg;
-               printk ("%s: is_second_field=%d, ptr=0x%08lx, line=%d, "
-                       "type=%d\n", s,
-                               p->is_second_field,(unsigned long)p->p,p->line,p->type);
-               break;
-       }
-       case VIDIOC_ENUM_FMT:
-       {
-               struct v4l2_fmtdesc *p=arg;
-               printk ("%s: index=%d, type=%d, flags=%d, description=%s,"
-                       " pixelformat=%d\n", s,
-                               p->index, p->type, p->flags,p->description,
-                               p->pixelformat);
-
-               break;
-       }
-       case VIDIOC_G_FMT:
-       case VIDIOC_S_FMT:
-       case VIDIOC_TRY_FMT:
-       {
-               struct v4l2_format *p=arg;
-               printk ("%s: type=%s\n", s,
-                               prt_names(p->type,v4l2_type_names));
-               switch (p->type) {
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                       v4l_print_pix_fmt (s, &p->fmt.pix);
-                       break;
-               default:
-                       break;
-               }
-       }
-       case VIDIOC_G_FBUF:
-       case VIDIOC_S_FBUF:
-       {
-               struct v4l2_framebuffer *p=arg;
-               printk ("%s: capability=%d, flags=%d, base=0x%08lx\n", s,
-                               p->capability,p->flags, (unsigned long)p->base);
-               v4l_print_pix_fmt (s, &p->fmt);
-               break;
-       }
-       case VIDIOC_G_FREQUENCY:
-       case VIDIOC_S_FREQUENCY:
-       {
-               struct v4l2_frequency *p=arg;
-               printk ("%s: tuner=%d, type=%d, frequency=%d\n", s,
-                               p->tuner,p->type,p->frequency);
-               break;
-       }
-       case VIDIOC_ENUMINPUT:
-       {
-               struct v4l2_input *p=arg;
-               printk ("%s: index=%d, name=%s, type=%d, audioset=%d, "
-                       "tuner=%d, std=%Ld, status=%d\n", s,
-                               p->index,p->name,p->type,p->audioset,
-                               p->tuner,
-                               (unsigned long long)p->std,
-                               p->status);
-               break;
-       }
-       case VIDIOC_G_JPEGCOMP:
-       case VIDIOC_S_JPEGCOMP:
-       {
-               struct v4l2_jpegcompression *p=arg;
-               printk ("%s: quality=%d, APPn=%d, APP_len=%d, COM_len=%d,"
-                       " jpeg_markers=%d\n", s,
-                               p->quality,p->APPn,p->APP_len,
-                               p->COM_len,p->jpeg_markers);
-               break;
-       }
-       case VIDIOC_G_MODULATOR:
-       case VIDIOC_S_MODULATOR:
-       {
-               struct v4l2_modulator *p=arg;
-               printk ("%s: index=%d, name=%s, capability=%d, rangelow=%d,"
-                       " rangehigh=%d, txsubchans=%d\n", s,
-                               p->index, p->name,p->capability,p->rangelow,
-                               p->rangehigh,p->txsubchans);
-               break;
-       }
-       case VIDIOC_G_MPEGCOMP:
-       case VIDIOC_S_MPEGCOMP:
-       {
-               struct v4l2_mpeg_compression *p=arg;
-               /*FIXME: Several fields not shown */
-               printk ("%s: 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", s,
-                               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_ENUMOUTPUT:
-       {
-               struct v4l2_output *p=arg;
-               printk ("%s: index=%d, name=%s,type=%d, audioset=%d, "
-                       "modulator=%d, std=%Ld\n",
-                               s,p->index,p->name,p->type,p->audioset,
-                               p->modulator,
-                               (unsigned long long)p->std);
-               break;
-       }
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *p=arg;
-               printk ("%s: id=%d, type=%d, name=%s, min/max=%d/%d,"
-                       " step=%d, default=%d, flags=0x%08x\n", s,
-                               p->id,p->type,p->name,p->minimum,p->maximum,
-                               p->step,p->default_value,p->flags);
-               break;
-       }
-       case VIDIOC_QUERYMENU:
-       {
-               struct v4l2_querymenu *p=arg;
-               printk ("%s: id=%d, index=%d, name=%s\n", s,
-                               p->id,p->index,p->name);
-               break;
-       }
-       case VIDIOC_INT_G_REGISTER:
-       case VIDIOC_INT_S_REGISTER:
-       {
-               struct v4l2_register *p=arg;
-               printk ("%s: i2c_id=%d, reg=%lu, val=%d\n", s,
-                               p->i2c_id,p->reg,p->val);
-
-               break;
-       }
-       case VIDIOC_REQBUFS:
-       {
-               struct v4l2_requestbuffers *p=arg;
-               printk ("%s: count=%d, type=%s, memory=%s\n", s,
-                               p->count,
-                               prt_names(p->type,v4l2_type_names),
-                               prt_names(p->memory,v4l2_memory_names));
-               break;
-       }
-       case VIDIOC_INT_S_AUDIO_ROUTING:
-       case VIDIOC_INT_S_VIDEO_ROUTING:
-       case VIDIOC_INT_G_AUDIO_ROUTING:
-       case VIDIOC_INT_G_VIDEO_ROUTING:
-       {
-               struct v4l2_routing  *p=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;
-               printk ("%s: service_set=%d\n", s,
-                               p->service_set);
-               break;
-       }
-       case VIDIOC_INT_S_VBI_DATA:
-       case VIDIOC_INT_G_VBI_DATA:
-       {
-               struct v4l2_sliced_vbi_data  *p=arg;
-               printk ("%s: id=%d, field=%d, line=%d\n", s,
-                               p->id, p->field, p->line);
-               break;
-       }
-       case VIDIOC_ENUMSTD:
-       {
-               struct v4l2_standard *p=arg;
-               printk ("%s: index=%d, id=%Ld, name=%s, fps=%d/%d, "
-                       "framelines=%d\n", s, p->index,
-                               (unsigned long long)p->id, p->name,
-                               p->frameperiod.numerator,
-                               p->frameperiod.denominator,
-                               p->framelines);
-
-               break;
-       }
-       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);
-
-               break;
-       }
-       case VIDIOC_G_TUNER:
-       case VIDIOC_S_TUNER:
-       {
-               struct v4l2_tuner *p=arg;
-               printk ("%s: index=%d, name=%s, type=%d, capability=%d, "
-                       "rangelow=%d, rangehigh=%d, signal=%d, afc=%d, "
-                       "rxsubchans=%d, audmode=%d\n", s,
-                               p->index, p->name, p->type,
-                               p->capability, p->rangelow,p->rangehigh,
-                               p->rxsubchans, p->audmode, p->signal,
-                               p->afc);
-               break;
-       }
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       case VIDIOCGVBIFMT:
-       case VIDIOCSVBIFMT:
-       {
-               struct vbi_format *p=arg;
-               printk ("%s: sampling_rate=%d, samples_per_line=%d, "
-                       "sample_format=%d, start=%d/%d, count=%d/%d, flags=%d\n", s,
-                               p->sampling_rate,p->samples_per_line,
-                               p->sample_format,p->start[0],p->start[1],
-                               p->count[0],p->count[1],p->flags);
-               break;
-       }
-       case VIDIOCGAUDIO:
-       case VIDIOCSAUDIO:
-       {
-               struct video_audio *p=arg;
-               printk ("%s: audio=%d, volume=%d, bass=%d, treble=%d, "
-                       "flags=%d, name=%s, mode=%d, balance=%d, step=%d\n",
-                               s,p->audio,p->volume,p->bass, p->treble,
-                               p->flags,p->name,p->mode,p->balance,p->step);
-               break;
-       }
-       case VIDIOCGFBUF:
-       case VIDIOCSFBUF:
-       {
-               struct video_buffer *p=arg;
-               printk ("%s: base=%08lx, height=%d, width=%d, depth=%d, "
-                       "bytesperline=%d\n", s,
-                               (unsigned long) p->base, p->height, p->width,
-                               p->depth,p->bytesperline);
-               break;
-       }
-       case VIDIOCGCAP:
-       {
-               struct video_capability *p=arg;
-               printk ("%s: name=%s, type=%d, channels=%d, audios=%d, "
-                       "maxwidth=%d, maxheight=%d, minwidth=%d, minheight=%d\n",
-                               s,p->name,p->type,p->channels,p->audios,
-                               p->maxwidth,p->maxheight,p->minwidth,
-                               p->minheight);
-
-               break;
-       }
-       case VIDIOCGCAPTURE:
-       case VIDIOCSCAPTURE:
-       {
-               struct video_capture *p=arg;
-               printk ("%s: x=%d, y=%d, width=%d, height=%d, decimation=%d,"
-                       " flags=%d\n", s,
-                               p->x, p->y,p->width, p->height,
-                               p->decimation,p->flags);
-               break;
-       }
-       case VIDIOCGCHAN:
-       case VIDIOCSCHAN:
-       {
-               struct video_channel *p=arg;
-               printk ("%s: channel=%d, name=%s, tuners=%d, flags=%d, "
-                       "type=%d, norm=%d\n", s,
-                               p->channel,p->name,p->tuners,
-                               p->flags,p->type,p->norm);
-
-               break;
-       }
-       case VIDIOCSMICROCODE:
-       {
-               struct video_code *p=arg;
-               printk ("%s: loadwhat=%s, datasize=%d\n", s,
-                               p->loadwhat,p->datasize);
-               break;
-       }
-       case DECODER_GET_CAPABILITIES:
-       {
-               struct video_decoder_capability *p=arg;
-               printk ("%s: flags=%d, inputs=%d, outputs=%d\n", s,
-                               p->flags,p->inputs,p->outputs);
-               break;
-       }
-       case DECODER_INIT:
-       {
-               struct video_decoder_init *p=arg;
-               printk ("%s: len=%c\n", s, p->len);
-               break;
-       }
-       case VIDIOCGPLAYINFO:
-       {
-               struct video_info *p=arg;
-               printk ("%s: frame_count=%d, h_size=%d, v_size=%d, "
-                       "smpte_timecode=%d, picture_type=%d, "
-                       "temporal_reference=%d, user_data=%s\n", s,
-                               p->frame_count, p->h_size,
-                               p->v_size, p->smpte_timecode,
-                               p->picture_type, p->temporal_reference,
-                               p->user_data);
-               break;
-       }
-       case VIDIOCKEY:
-       {
-               struct video_key *p=arg;
-               printk ("%s: key=%s, flags=%d\n", s,
-                               p->key, p->flags);
-               break;
-       }
-       case VIDIOCGMBUF:
-       {
-               struct video_mbuf *p=arg;
-               printk ("%s: size=%d, frames=%d, offsets=0x%08lx\n", s,
-                               p->size,
-                               p->frames,
-                               (unsigned long)p->offsets);
-               break;
-       }
-       case VIDIOCMCAPTURE:
-       {
-               struct video_mmap *p=arg;
-               printk ("%s: frame=%d, height=%d, width=%d, format=%d\n", s,
-                               p->frame,
-                               p->height, p->width,
-                               p->format);
-               break;
-       }
-       case VIDIOCGPICT:
-       case VIDIOCSPICT:
-       case DECODER_SET_PICTURE:
-       {
-               struct video_picture *p=arg;
-
-               printk ("%s: brightness=%d, hue=%d, colour=%d, contrast=%d,"
-                       " whiteness=%d, depth=%d, palette=%d\n", s,
-                               p->brightness, p->hue, p->colour,
-                               p->contrast, p->whiteness, p->depth,
-                               p->palette);
-               break;
-       }
-       case VIDIOCSPLAYMODE:
-       {
-               struct video_play_mode *p=arg;
-               printk ("%s: mode=%d, p1=%d, p2=%d\n", s,
-                               p->mode,p->p1,p->p2);
-               break;
-       }
-       case VIDIOCGTUNER:
-       case VIDIOCSTUNER:
-       {
-               struct video_tuner *p=arg;
-               printk ("%s: tuner=%d, name=%s, rangelow=%ld, rangehigh=%ld, "
-                       "flags=%d, mode=%d, signal=%d\n", s,
-                               p->tuner, p->name,p->rangelow, p->rangehigh,
-                               p->flags,p->mode, p->signal);
-               break;
-       }
-       case VIDIOCGUNIT:
-       {
-               struct video_unit *p=arg;
-               printk ("%s: video=%d, vbi=%d, radio=%d, audio=%d, "
-                       "teletext=%d\n", s,
-                               p->video,p->vbi,p->radio,p->audio,p->teletext);
-               break;
-       }
-       case VIDIOCGWIN:
-       case VIDIOCSWIN:
-       {
-               struct video_window *p=arg;
-               printk ("%s: x=%d, y=%d, width=%d, height=%d, chromakey=%d,"
-                       " flags=%d, clipcount=%d\n", s,
-                               p->x, p->y,p->width, p->height,
-                               p->chromakey,p->flags,
-                               p->clipcount);
-               break;
-       }
-       case VIDIOCGFREQ:
-       case VIDIOCSFREQ:
-       {
-               unsigned long *p=arg;
-               printk ("%s: value=%lu\n", s, *p);
-               break;
-       }
-#endif
-       case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-       case VIDIOC_INT_I2S_CLOCK_FREQ:
-       case VIDIOC_INT_S_STANDBY:
-       case VIDIOC_INT_RESET:
-       {
-               u32 *p=arg;
-
-               printk ("%s: value=%d\n", s, *p);
-               break;
-       }
-       case VIDIOC_G_STD:
-       case VIDIOC_S_STD:
-       case VIDIOC_QUERYSTD:
-       {
-               v4l2_std_id *p=arg;
-
-               printk ("%s: value=%Lu\n", s, (unsigned long long)*p);
-               break;
-       }
-       }
-}
 
 /* ----------------------------------------------------------------- */
 
@@ -1544,7 +962,6 @@ EXPORT_SYMBOL(v4l2_prio_check);
 EXPORT_SYMBOL(v4l2_field_names);
 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);
index 6504a58..459786f 100644 (file)
@@ -148,6 +148,8 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
        dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n",
                data,size,dma->nr_pages);
 
+       dma->varea = (void *) data;
+
        down_read(&current->mm->mmap_sem);
        err = get_user_pages(current,current->mm,
                             data & PAGE_MASK, dma->nr_pages,
@@ -285,6 +287,7 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma)
 
        vfree(dma->vmalloc);
        dma->vmalloc = NULL;
+       dma->varea = NULL;
 
        if (dma->bus_addr) {
                dma->bus_addr = 0;
index a786c1f..dc9b1ef 100644 (file)
@@ -1453,6 +1453,26 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                ret=vfd->vidioc_log_status(file, fh);
                break;
        }
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       case VIDIOC_DBG_G_REGISTER:
+       {
+               struct v4l2_register *p=arg;
+               if (!capable(CAP_SYS_ADMIN))
+                       ret=-EPERM;
+               else if (vfd->vidioc_g_register)
+                       ret=vfd->vidioc_g_register(file, fh, p);
+               break;
+       }
+       case VIDIOC_DBG_S_REGISTER:
+       {
+               struct v4l2_register *p=arg;
+               if (!capable(CAP_SYS_ADMIN))
+                       ret=-EPERM;
+               else if (vfd->vidioc_s_register)
+                       ret=vfd->vidioc_s_register(file, fh, p);
+               break;
+       }
+#endif
        } /* switch */
 
        if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
index cfb6b1f..f7e1d19 100644 (file)
@@ -145,7 +145,9 @@ struct vivi_buffer {
 
        struct vivi_fmt        *fmt;
 
+#ifdef CONFIG_VIVI_SCATTER
        struct sg_to_addr      *to_addr;
+#endif
 };
 
 struct vivi_dmaqueue {
@@ -230,6 +232,7 @@ static u8 bars[8][3] = {
 #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
 #define TSTAMP_MIN_X 64
 
+#ifdef CONFIG_VIVI_SCATTER
 static void prep_to_addr(struct sg_to_addr to_addr[],
                         struct videobuf_buffer *vb)
 {
@@ -262,14 +265,24 @@ static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
 
        return (p1);
 }
+#endif
 
+#ifdef CONFIG_VIVI_SCATTER
 static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
                     int hmax, int line, char *timestr)
+#else
+static void gen_line(char *basep,int inipos,int wmax,
+                    int hmax, int line, char *timestr)
+#endif
 {
-       int  w,i,j,pos=inipos,pgpos,oldpg,y;
-       char *p,*s,*basep;
-       struct page *pg;
+       int  w,i,j,pos=inipos,y;
+       char *p,*s;
        u8   chr,r,g,b,color;
+#ifdef CONFIG_VIVI_SCATTER
+       int pgpos,oldpg;
+       char *basep;
+       struct page *pg;
+
        unsigned long flags;
        spinlock_t spinlock;
 
@@ -280,6 +293,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
        pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT);
        spin_lock_irqsave(&spinlock,flags);
        basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset;
+#endif
 
        /* We will just duplicate the second pixel at the packet */
        wmax/=2;
@@ -291,6 +305,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
                b=bars[w*7/wmax][2];
 
                for (color=0;color<4;color++) {
+#ifdef CONFIG_VIVI_SCATTER
                        pgpos=get_addr_pos(pos,pages,to_addr);
                        if (pgpos!=oldpg) {
                                pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT);
@@ -299,6 +314,9 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
                                oldpg=pgpos;
                        }
                        p=basep+pos-to_addr[pgpos].pos;
+#else
+                       p=basep+pos;
+#endif
 
                        switch (color) {
                                case 0:
@@ -343,6 +361,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
 
                                pos=inipos+j*2;
                                for (color=0;color<4;color++) {
+#ifdef CONFIG_VIVI_SCATTER
                                        pgpos=get_addr_pos(pos,pages,to_addr);
                                        if (pgpos!=oldpg) {
                                                pg=pfn_to_page(sg_dma_address(
@@ -356,6 +375,9 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
                                                oldpg=pgpos;
                                        }
                                        p=basep+pos-to_addr[pgpos].pos;
+#else
+                                       p=basep+pos;
+#endif
 
                                        y=TO_Y(r,g,b);
 
@@ -380,19 +402,27 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
 
 
 end:
+#ifdef CONFIG_VIVI_SCATTER
        kunmap_atomic(basep, KM_BOUNCE_READ);
        spin_unlock_irqrestore(&spinlock,flags);
-
+#else
+       return;
+#endif
 }
 static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
 {
        int h,pos=0;
        int hmax  = buf->vb.height;
        int wmax  = buf->vb.width;
-       struct videobuf_buffer *vb=&buf->vb;
-       struct sg_to_addr *to_addr=buf->to_addr;
        struct timeval ts;
+#ifdef CONFIG_VIVI_SCATTER
+       struct sg_to_addr *to_addr=buf->to_addr;
+       struct videobuf_buffer *vb=&buf->vb;
+#else
+       char *tmpbuf;
+#endif
 
+#ifdef CONFIG_VIVI_SCATTER
        /* Test if DMA mapping is ready */
        if (!sg_dma_address(&vb->dma.sglist[0]))
                return;
@@ -401,9 +431,28 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
 
        /* Check if there is enough memory */
        BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2);
+#else
+       if (buf->vb.dma.varea) {
+               tmpbuf=kmalloc (wmax*2, GFP_KERNEL);
+       } else {
+               tmpbuf=buf->vb.dma.vmalloc;
+       }
+
+#endif
 
        for (h=0;h<hmax;h++) {
+#ifdef CONFIG_VIVI_SCATTER
                gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr);
+#else
+               if (buf->vb.dma.varea) {
+                       gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr);
+                       /* FIXME: replacing to __copy_to_user */
+                       if (copy_to_user(buf->vb.dma.varea+pos,tmpbuf,wmax*2)!=0)
+                               dprintk(2,"vivifill copy_to_user failed.\n");
+               } else {
+                       gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr);
+               }
+#endif
                pos += wmax*2;
        }
 
@@ -429,7 +478,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
                        dev->h,dev->m,dev->s,(dev->us+500)/1000);
 
        dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr,
-                       (unsigned long)buf->vb.dma.vmalloc,pos);
+                       (unsigned long)buf->vb.dma.varea,pos);
 
        /* Advice that buffer was filled */
        buf->vb.state = STATE_DONE;
@@ -471,11 +520,12 @@ static void vivi_thread_tick(struct vivi_dmaqueue  *dma_q)
 
                /* Fill buffer */
                vivi_fillbuff(dev,buf);
-       }
-       if (list_empty(&dma_q->active)) {
-               del_timer(&dma_q->timeout);
-       } else {
-               mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+
+               if (list_empty(&dma_q->active)) {
+                       del_timer(&dma_q->timeout);
+               } else {
+                       mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+               }
        }
        if (bc != 1)
                dprintk(1,"%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
@@ -522,6 +572,8 @@ static int vivi_thread(void *data)
 
        dprintk(1,"thread started\n");
 
+       mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+
        for (;;) {
                vivi_sleep(dma_q);
 
@@ -538,7 +590,6 @@ static int vivi_start_thread(struct vivi_dmaqueue  *dma_q)
        dma_q->ini_jiffies=jiffies;
 
        dprintk(1,"%s\n",__FUNCTION__);
-       init_waitqueue_head(&dma_q->wq);
 
        dma_q->kthread = kthread_run(vivi_thread, dma_q, "vivi");
 
@@ -546,6 +597,9 @@ static int vivi_start_thread(struct vivi_dmaqueue  *dma_q)
                printk(KERN_ERR "vivi: kernel_thread() failed\n");
                return PTR_ERR(dma_q->kthread);
        }
+       /* Wakes thread */
+       wake_up_interruptible(&dma_q->wq);
+
        dprintk(1,"returning from %s\n",__FUNCTION__);
        return 0;
 }
@@ -663,9 +717,11 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
        if (in_interrupt())
                BUG();
 
+#ifdef CONFIG_VIVI_SCATTER
        /*FIXME: Maybe a spinlock is required here */
        kfree(buf->to_addr);
        buf->to_addr=NULL;
+#endif
 
        videobuf_waiton(&buf->vb,0,0);
        videobuf_dma_unmap(vq, &buf->vb.dma);
@@ -711,11 +767,12 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
 
        buf->vb.state = STATE_PREPARED;
 
+#ifdef CONFIG_VIVI_SCATTER
        if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) {
                rc=-ENOMEM;
                goto fail;
        }
-
+#endif
        return 0;
 
 fail:
@@ -780,6 +837,7 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb
        free_buffer(vq,buf);
 }
 
+#ifdef CONFIG_VIVI_SCATTER
 static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents,
                       int direction)
 {
@@ -812,6 +870,7 @@ static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages,
 //     flush_write_buffers();
        return 0;
 }
+#endif
 
 static struct videobuf_queue_ops vivi_video_qops = {
        .buf_setup      = buffer_setup,
@@ -820,9 +879,9 @@ static struct videobuf_queue_ops vivi_video_qops = {
        .buf_release    = buffer_release,
 
        /* Non-pci handling routines */
-       .vb_map_sg      = vivi_map_sg,
-       .vb_dma_sync_sg = vivi_dma_sync_sg,
-       .vb_unmap_sg    = vivi_unmap_sg,
+//     .vb_map_sg      = vivi_map_sg,
+//     .vb_dma_sync_sg = vivi_dma_sync_sg,
+//     .vb_unmap_sg    = vivi_unmap_sg,
 };
 
 /* ------------------------------------------------------------------
@@ -1200,11 +1259,19 @@ static int vivi_open(struct inode *inode, struct file *file)
        sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
                        dev->h,dev->m,dev->s,(dev->us+500)/1000);
 
+#ifdef CONFIG_VIVI_SCATTER
+       videobuf_queue_init(&fh->vb_vidq,VIDEOBUF_DMA_SCATTER, &vivi_video_qops,
+                       NULL, NULL,
+                       fh->type,
+                       V4L2_FIELD_INTERLACED,
+                       sizeof(struct vivi_buffer),fh);
+#else
        videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops,
                        NULL, NULL,
                        fh->type,
                        V4L2_FIELD_INTERLACED,
                        sizeof(struct vivi_buffer),fh);
+#endif
 
        return 0;
 }
@@ -1352,6 +1419,7 @@ static int __init vivi_init(void)
        /* init video dma queues */
        INIT_LIST_HEAD(&dev->vidq.active);
        INIT_LIST_HEAD(&dev->vidq.queued);
+       init_waitqueue_head(&dev->vidq.wq);
 
        /* initialize locks */
        init_MUTEX(&dev->lock);
index b9c93b8..710f12e 100644 (file)
@@ -1,7 +1,7 @@
 /***************************************************************************
- * V4L2 driver for ZC0301 Image Processor and Control Chip                 *
+ * V4L2 driver for ZC0301[P] Image Processor and Control Chip              *
  *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
  * it under the terms of the GNU General Public License as published by    *
index 8da7f15..f112055 100644 (file)
@@ -1,7 +1,7 @@
 /***************************************************************************
  * Video4Linux2 driver for ZC0301[P] Image Processor and Control Chip      *
  *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * Informations about the chip internals needed to enable the I2C protocol *
  * have been taken from the documentation of the ZC030x Video4Linux1       *
@@ -52,8 +52,8 @@
 #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.05"
-#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 5)
+#define ZC0301_MODULE_VERSION "1:1.07"
+#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 7)
 
 /*****************************************************************************/
 
@@ -89,7 +89,7 @@ MODULE_PARM_DESC(force_munmap,
                 "\ndetected camera."
                 "\n 0 = do not force memory unmapping"
                 "\n 1 = force memory unmapping (save memory)"
-                "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
+                "\nDefault value is "__MODULE_STRING(ZC0301_FORCE_MUNMAP)"."
                 "\n");
 
 static unsigned int frame_timeout[] = {[0 ... ZC0301_MAX_DEVICES-1] =
@@ -136,7 +136,8 @@ zc0301_request_buffers(struct zc0301_device* cam, u32 count,
 
        cam->nbuffers = count;
        while (cam->nbuffers > 0) {
-               if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
+               if ((buff = vmalloc_32_user(cam->nbuffers *
+                                           PAGE_ALIGN(imagesize))))
                        break;
                cam->nbuffers--;
        }
@@ -430,7 +431,8 @@ static int zc0301_start_transfer(struct zc0301_device* cam)
        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;
+       const unsigned int psz = le16_to_cpu(altsetting->
+                                            endpoint[0].desc.wMaxPacketSize);
        struct urb* urb;
        s8 i, j;
        int err = 0;
@@ -489,7 +491,7 @@ static int zc0301_start_transfer(struct zc0301_device* cam)
        return 0;
 
 free_urbs:
-       for (i = 0; i < ZC0301_URBS; i++)
+       for (i = 0; (i < ZC0301_URBS) && cam->urb[i]; i++)
                usb_free_urb(cam->urb[i]);
 
 free_buffers:
@@ -1288,6 +1290,35 @@ zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
 
 
 static int
+zc0301_vidioc_enum_framesizes(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_frmsizeenum frmsize;
+
+       if (copy_from_user(&frmsize, arg, sizeof(frmsize)))
+               return -EFAULT;
+
+       if (frmsize.index != 0 && frmsize.index != 1)
+               return -EINVAL;
+
+       if (frmsize.pixel_format != V4L2_PIX_FMT_JPEG)
+               return -EINVAL;
+
+       frmsize.type = V4L2_FRMSIZE_TYPE_DISCRETE;
+
+       if (frmsize.index == 1) {
+               frmsize.discrete.width = cam->sensor.cropcap.defrect.width;
+               frmsize.discrete.height = cam->sensor.cropcap.defrect.height;
+       }
+       memset(&frmsize.reserved, 0, sizeof(frmsize.reserved));
+
+       if (copy_to_user(arg, &frmsize, sizeof(frmsize)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
 zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg)
 {
        struct v4l2_fmtdesc fmtd;
@@ -1295,6 +1326,9 @@ zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg)
        if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
                return -EFAULT;
 
+       if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
        if (fmtd.index == 0) {
                strcpy(fmtd.description, "JPEG");
                fmtd.pixelformat = V4L2_PIX_FMT_JPEG;
@@ -1795,6 +1829,9 @@ static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
        case VIDIOC_S_FMT:
                return zc0301_vidioc_try_s_fmt(cam, cmd, arg);
 
+       case VIDIOC_ENUM_FRAMESIZES:
+               return zc0301_vidioc_enum_framesizes(cam, arg);
+
        case VIDIOC_G_JPEGCOMP:
                return zc0301_vidioc_g_jpegcomp(cam, arg);
 
@@ -1830,6 +1867,7 @@ static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
        case VIDIOC_QUERYSTD:
        case VIDIOC_ENUMSTD:
        case VIDIOC_QUERYMENU:
+       case VIDIOC_ENUM_FRAMEINTERVALS:
                return -EINVAL;
 
        default:
@@ -1876,6 +1914,7 @@ static const struct file_operations zc0301_fops = {
        .open =    zc0301_open,
        .release = zc0301_release,
        .ioctl =   zc0301_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
        .read =    zc0301_read,
        .poll =    zc0301_poll,
        .mmap =    zc0301_mmap,
@@ -1913,7 +1952,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        mutex_init(&cam->dev_mutex);
 
        DBG(2, "ZC0301[P] Image Processor and Control Chip detected "
-              "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
+              "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
 
        for  (i = 0; zc0301_sensor_table[i]; i++) {
                err = zc0301_sensor_table[i](cam);
index ecfd39a..3efb92a 100644 (file)
@@ -1,8 +1,8 @@
 /***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the ZC0301[P] Image     *
+ * Plug-in for PAS202BCB image sensor connected to the ZC0301 Image        *
  * Processor and Control Chip                                              *
  *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
  * driver maintained by Michel Xhaard <mxhaard@magic.fr>                   *
index ed8542e..5784b1d 100644 (file)
@@ -1,8 +1,8 @@
 /***************************************************************************
- * Plug-in for PB-0330 image sensor connected to the ZC0301[P] Image       *
+ * Plug-in for PB-0330 image sensor connected to the ZC0301P Image         *
  * Processor and Control Chip                                              *
  *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
  * driver maintained by Michel Xhaard <mxhaard@magic.fr>                   *
index 3daf049..44e82cf 100644 (file)
@@ -1,8 +1,8 @@
 /***************************************************************************
- * API for image sensors connected to the ZC0301 Image Processor and       *
+ * API for image sensors connected to the ZC0301[P] Image Processor and    *
  * Control Chip                                                            *
  *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
  * it under the terms of the GNU General Public License as published by    *
@@ -70,7 +70,7 @@ static const struct usb_device_id zc0301_id_table[] =  {                      \
        { 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, 0x700c, 0xff), }, /* TAS5130 */           \
        { ZC0301_USB_DEVICE(0x0458, 0x700f, 0xff), }, /* TAS5130 */           \
        { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
        { ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */           \
@@ -93,9 +93,9 @@ extern int zc0301_i2c_read(struct zc0301_device*, u16 address, u8 length);
 
 /*****************************************************************************/
 
-#define ZC0301_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
-#define ZC0301_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE
-#define ZC0301_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1
+#define ZC0301_MAX_CTRLS (V4L2_CID_LASTP1 - V4L2_CID_BASE + 10)
+#define ZC0301_V4L2_CID_DAC_MAGNITUDE (V4L2_CID_PRIVATE_BASE + 0)
+#define ZC0301_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 1)
 
 struct zc0301_sensor {
        char name[32];
index fc3c885..ab6e985 100644 (file)
@@ -2,6 +2,20 @@
 # Multifunction miscellaneous devices
 #
 
+menu "Multifunction device drivers"
+
+config MFD_SM501
+       tristate "Support for Silicon Motion SM501"
+        ---help---
+         This is the core driver for the Silicon Motion SM501 multimedia
+         companion chip. This device is a multifunction device which may
+         provide numerous interfaces including USB host controller USB gadget,
+         Asyncronous Serial ports, Audio functions and a dual display video
+         interface. The device may be connected by PCI or local bus with
+         varying functions enabled.
+
+endmenu
+
 menu "Multimedia Capabilities Port drivers"
        depends on ARCH_SA1100
 
index adb29b5..5143209 100644 (file)
@@ -2,6 +2,8 @@
 # Makefile for multifunction miscellaneous devices
 #
 
+obj-$(CONFIG_MFD_SM501)                += sm501.o
+
 obj-$(CONFIG_MCP)              += mcp-core.o
 obj-$(CONFIG_MCP_SA11X0)       += mcp-sa11x0.o
 obj-$(CONFIG_MCP_UCB1200)      += ucb1x00-core.o
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
new file mode 100644 (file)
index 0000000..c707c8e
--- /dev/null
@@ -0,0 +1,1148 @@
+/* linux/drivers/mfd/sm501.c
+ *
+ * Copyright (C) 2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     Vincent Sanders <vince@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.
+ *
+ * SM501 MFD driver
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+
+#include <linux/sm501.h>
+#include <linux/sm501-regs.h>
+
+#include <asm/io.h>
+
+struct sm501_device {
+       struct list_head                list;
+       struct platform_device          pdev;
+};
+
+struct sm501_devdata {
+       spinlock_t                       reg_lock;
+       struct mutex                     clock_lock;
+       struct list_head                 devices;
+
+       struct device                   *dev;
+       struct resource                 *io_res;
+       struct resource                 *mem_res;
+       struct resource                 *regs_claim;
+       struct sm501_platdata           *platdata;
+
+       int                              unit_power[20];
+       unsigned int                     pdev_id;
+       unsigned int                     irq;
+       void __iomem                    *regs;
+};
+
+#define MHZ (1000 * 1000)
+
+#ifdef DEBUG
+static const unsigned int misc_div[] = {
+       [0]             = 1,
+       [1]             = 2,
+       [2]             = 4,
+       [3]             = 8,
+       [4]             = 16,
+       [5]             = 32,
+       [6]             = 64,
+       [7]             = 128,
+       [8]             = 3,
+       [9]             = 6,
+       [10]            = 12,
+       [11]            = 24,
+       [12]            = 48,
+       [13]            = 96,
+       [14]            = 192,
+       [15]            = 384,
+};
+
+static const unsigned int px_div[] = {
+       [0]             = 1,
+       [1]             = 2,
+       [2]             = 4,
+       [3]             = 8,
+       [4]             = 16,
+       [5]             = 32,
+       [6]             = 64,
+       [7]             = 128,
+       [8]             = 3,
+       [9]             = 6,
+       [10]            = 12,
+       [11]            = 24,
+       [12]            = 48,
+       [13]            = 96,
+       [14]            = 192,
+       [15]            = 384,
+       [16]            = 5,
+       [17]            = 10,
+       [18]            = 20,
+       [19]            = 40,
+       [20]            = 80,
+       [21]            = 160,
+       [22]            = 320,
+       [23]            = 604,
+};
+
+static unsigned long decode_div(unsigned long pll2, unsigned long val,
+                               unsigned int lshft, unsigned int selbit,
+                               unsigned long mask, const unsigned int *dtab)
+{
+       if (val & selbit)
+               pll2 = 288 * MHZ;
+
+       return pll2 / dtab[(val >> lshft) & mask];
+}
+
+#define fmt_freq(x) ((x) / MHZ), ((x) % MHZ), (x)
+
+/* sm501_dump_clk
+ *
+ * Print out the current clock configuration for the device
+*/
+
+static void sm501_dump_clk(struct sm501_devdata *sm)
+{
+       unsigned long misct = readl(sm->regs + SM501_MISC_TIMING);
+       unsigned long pm0 = readl(sm->regs + SM501_POWER_MODE_0_CLOCK);
+       unsigned long pm1 = readl(sm->regs + SM501_POWER_MODE_1_CLOCK);
+       unsigned long pmc = readl(sm->regs + SM501_POWER_MODE_CONTROL);
+       unsigned long sdclk0, sdclk1;
+       unsigned long pll2 = 0;
+
+       switch (misct & 0x30) {
+       case 0x00:
+               pll2 = 336 * MHZ;
+               break;
+       case 0x10:
+               pll2 = 288 * MHZ;
+               break;
+       case 0x20:
+               pll2 = 240 * MHZ;
+               break;
+       case 0x30:
+               pll2 = 192 * MHZ;
+               break;
+       }
+
+       sdclk0 = (misct & (1<<12)) ? pll2 : 288 * MHZ;
+       sdclk0 /= misc_div[((misct >> 8) & 0xf)];
+
+       sdclk1 = (misct & (1<<20)) ? pll2 : 288 * MHZ;
+       sdclk1 /= misc_div[((misct >> 16) & 0xf)];
+
+       dev_dbg(sm->dev, "MISCT=%08lx, PM0=%08lx, PM1=%08lx\n",
+               misct, pm0, pm1);
+
+       dev_dbg(sm->dev, "PLL2 = %ld.%ld MHz (%ld), SDCLK0=%08lx, SDCLK1=%08lx\n",
+               fmt_freq(pll2), sdclk0, sdclk1);
+
+       dev_dbg(sm->dev, "SDRAM: PM0=%ld, PM1=%ld\n", sdclk0, sdclk1);
+
+       dev_dbg(sm->dev, "PM0[%c]: "
+                "P2 %ld.%ld MHz (%ld), V2 %ld.%ld (%ld), "
+x               "M %ld.%ld (%ld), MX1 %ld.%ld (%ld)\n",
+                (pmc & 3 ) == 0 ? '*' : '-',
+                fmt_freq(decode_div(pll2, pm0, 24, 1<<29, 31, px_div)),
+                fmt_freq(decode_div(pll2, pm0, 16, 1<<20, 15, misc_div)),
+                fmt_freq(decode_div(pll2, pm0, 8,  1<<12, 15, misc_div)),
+                fmt_freq(decode_div(pll2, pm0, 0,  1<<4,  15, misc_div)));
+
+       dev_dbg(sm->dev, "PM1[%c]: "
+               "P2 %ld.%ld MHz (%ld), V2 %ld.%ld (%ld), "
+               "M %ld.%ld (%ld), MX1 %ld.%ld (%ld)\n",
+               (pmc & 3 ) == 1 ? '*' : '-',
+               fmt_freq(decode_div(pll2, pm1, 24, 1<<29, 31, px_div)),
+               fmt_freq(decode_div(pll2, pm1, 16, 1<<20, 15, misc_div)),
+               fmt_freq(decode_div(pll2, pm1, 8,  1<<12, 15, misc_div)),
+               fmt_freq(decode_div(pll2, pm1, 0,  1<<4,  15, misc_div)));
+}
+#else
+static void sm501_dump_clk(struct sm501_devdata *sm)
+{
+}
+#endif
+
+/* sm501_sync_regs
+ *
+ * ensure the
+*/
+
+static void sm501_sync_regs(struct sm501_devdata *sm)
+{
+       readl(sm->regs);
+}
+
+/* sm501_misc_control
+ *
+ * alters the misceleneous control parameters
+*/
+
+int sm501_misc_control(struct device *dev,
+                      unsigned long set, unsigned long clear)
+{
+       struct sm501_devdata *sm = dev_get_drvdata(dev);
+       unsigned long misc;
+       unsigned long save;
+       unsigned long to;
+
+       spin_lock_irqsave(&sm->reg_lock, save);
+
+       misc = readl(sm->regs + SM501_MISC_CONTROL);
+       to = (misc & ~clear) | set;
+
+       if (to != misc) {
+               writel(to, sm->regs + SM501_MISC_CONTROL);
+               sm501_sync_regs(sm);
+
+               dev_dbg(sm->dev, "MISC_CONTROL %08lx\n", misc);
+       }
+
+       spin_unlock_irqrestore(&sm->reg_lock, save);
+       return to;
+}
+
+EXPORT_SYMBOL_GPL(sm501_misc_control);
+
+/* sm501_modify_reg
+ *
+ * Modify a register in the SM501 which may be shared with other
+ * drivers.
+*/
+
+unsigned long sm501_modify_reg(struct device *dev,
+                              unsigned long reg,
+                              unsigned long set,
+                              unsigned long clear)
+{
+       struct sm501_devdata *sm = dev_get_drvdata(dev);
+       unsigned long data;
+       unsigned long save;
+
+       spin_lock_irqsave(&sm->reg_lock, save);
+
+       data = readl(sm->regs + reg);
+       data |= set;
+       data &= ~clear;
+
+       writel(data, sm->regs + reg);
+       sm501_sync_regs(sm);
+
+       spin_unlock_irqrestore(&sm->reg_lock, save);
+
+       return data;
+}
+
+EXPORT_SYMBOL_GPL(sm501_modify_reg);
+
+unsigned long sm501_gpio_get(struct device *dev,
+                            unsigned long gpio)
+{
+       struct sm501_devdata *sm = dev_get_drvdata(dev);
+       unsigned long result;
+       unsigned long reg;
+
+       reg = (gpio > 32) ? SM501_GPIO_DATA_HIGH : SM501_GPIO_DATA_LOW;
+       result = readl(sm->regs + reg);
+
+       result >>= (gpio & 31);
+       return result & 1UL;
+}
+
+EXPORT_SYMBOL_GPL(sm501_gpio_get);
+
+void sm501_gpio_set(struct device *dev,
+                   unsigned long gpio,
+                   unsigned int to,
+                   unsigned int dir)
+{
+       struct sm501_devdata *sm = dev_get_drvdata(dev);
+
+       unsigned long bit = 1 << (gpio & 31);
+       unsigned long base;
+       unsigned long save;
+       unsigned long val;
+
+       base = (gpio > 32) ? SM501_GPIO_DATA_HIGH : SM501_GPIO_DATA_LOW;
+       base += SM501_GPIO;
+
+       spin_lock_irqsave(&sm->reg_lock, save);
+
+       val = readl(sm->regs + base) & ~bit;
+       if (to)
+               val |= bit;
+       writel(val, sm->regs + base);
+
+       val = readl(sm->regs + SM501_GPIO_DDR_LOW) & ~bit;
+       if (dir)
+               val |= bit;
+
+       writel(val, sm->regs + SM501_GPIO_DDR_LOW);
+       sm501_sync_regs(sm);
+
+       spin_unlock_irqrestore(&sm->reg_lock, save);
+
+}
+
+EXPORT_SYMBOL_GPL(sm501_gpio_set);
+
+
+/* sm501_unit_power
+ *
+ * alters the power active gate to set specific units on or off
+ */
+
+int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
+{
+       struct sm501_devdata *sm = dev_get_drvdata(dev);
+       unsigned long mode;
+       unsigned long gate;
+       unsigned long clock;
+
+       mutex_lock(&sm->clock_lock);
+
+       mode = readl(sm->regs + SM501_POWER_MODE_CONTROL);
+       gate = readl(sm->regs + SM501_CURRENT_GATE);
+       clock = readl(sm->regs + SM501_CURRENT_CLOCK);
+
+       mode &= 3;              /* get current power mode */
+
+       if (unit > ARRAY_SIZE(sm->unit_power)) {
+               dev_err(dev, "%s: bad unit %d\n", __FUNCTION__, unit);
+               goto already;
+       }
+
+       dev_dbg(sm->dev, "%s: unit %d, cur %d, to %d\n", __FUNCTION__, unit,
+               sm->unit_power[unit], to);
+
+       if (to == 0 && sm->unit_power[unit] == 0) {
+               dev_err(sm->dev, "unit %d is already shutdown\n", unit);
+               goto already;
+       }
+
+       sm->unit_power[unit] += to ? 1 : -1;
+       to = sm->unit_power[unit] ? 1 : 0;
+
+       if (to) {
+               if (gate & (1 << unit))
+                       goto already;
+               gate |= (1 << unit);
+       } else {
+               if (!(gate & (1 << unit)))
+                       goto already;
+               gate &= ~(1 << unit);
+       }
+
+       switch (mode) {
+       case 1:
+               writel(gate, sm->regs + SM501_POWER_MODE_0_GATE);
+               writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK);
+               mode = 0;
+               break;
+       case 2:
+       case 0:
+               writel(gate, sm->regs + SM501_POWER_MODE_1_GATE);
+               writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK);
+               mode = 1;
+               break;
+
+       default:
+               return -1;
+       }
+
+       writel(mode, sm->regs + SM501_POWER_MODE_CONTROL);
+       sm501_sync_regs(sm);
+
+       dev_dbg(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n",
+               gate, clock, mode);
+
+       msleep(16);
+
+ already:
+       mutex_unlock(&sm->clock_lock);
+       return gate;
+}
+
+EXPORT_SYMBOL_GPL(sm501_unit_power);
+
+
+/* Perform a rounded division. */
+static long sm501fb_round_div(long num, long denom)
+{
+        /* n / d + 1 / 2 = (2n + d) / 2d */
+        return (2 * num + denom) / (2 * denom);
+}
+
+/* clock value structure. */
+struct sm501_clock {
+       unsigned long mclk;
+       int divider;
+       int shift;
+};
+
+/* sm501_select_clock
+ *
+ * selects nearest discrete clock frequency the SM501 can achive
+ *   the maximum divisor is 3 or 5
+ */
+static unsigned long sm501_select_clock(unsigned long freq,
+                                       struct sm501_clock *clock,
+                                       int max_div)
+{
+       unsigned long mclk;
+       int divider;
+       int shift;
+       long diff;
+       long best_diff = 999999999;
+
+       /* Try 288MHz and 336MHz clocks. */
+       for (mclk = 288000000; mclk <= 336000000; mclk += 48000000) {
+               /* try dividers 1 and 3 for CRT and for panel,
+                  try divider 5 for panel only.*/
+
+               for (divider = 1; divider <= max_div; divider += 2) {
+                       /* try all 8 shift values.*/
+                       for (shift = 0; shift < 8; shift++) {
+                               /* Calculate difference to requested clock */
+                               diff = sm501fb_round_div(mclk, divider << shift) - freq;
+                               if (diff < 0)
+                                       diff = -diff;
+
+                               /* If it is less than the current, use it */
+                               if (diff < best_diff) {
+                                       best_diff = diff;
+
+                                       clock->mclk = mclk;
+                                       clock->divider = divider;
+                                       clock->shift = shift;
+                               }
+                       }
+               }
+       }
+
+       /* Return best clock. */
+       return clock->mclk / (clock->divider << clock->shift);
+}
+
+/* sm501_set_clock
+ *
+ * set one of the four clock sources to the closest available frequency to
+ *  the one specified
+*/
+
+unsigned long sm501_set_clock(struct device *dev,
+                             int clksrc,
+                             unsigned long req_freq)
+{
+       struct sm501_devdata *sm = dev_get_drvdata(dev);
+       unsigned long mode = readl(sm->regs + SM501_POWER_MODE_CONTROL);
+       unsigned long gate = readl(sm->regs + SM501_CURRENT_GATE);
+       unsigned long clock = readl(sm->regs + SM501_CURRENT_CLOCK);
+       unsigned char reg;
+       unsigned long sm501_freq; /* the actual frequency acheived */
+
+       struct sm501_clock to;
+
+       /* find achivable discrete frequency and setup register value
+        * accordingly, V2XCLK, MCLK and M1XCLK are the same P2XCLK
+        * has an extra bit for the divider */
+
+       switch (clksrc) {
+       case SM501_CLOCK_P2XCLK:
+               /* This clock is divided in half so to achive the
+                * requested frequency the value must be multiplied by
+                * 2. This clock also has an additional pre divisor */
+
+               sm501_freq = (sm501_select_clock(2 * req_freq, &to, 5) / 2);
+               reg=to.shift & 0x07;/* bottom 3 bits are shift */
+               if (to.divider == 3)
+                       reg |= 0x08; /* /3 divider required */
+               else if (to.divider == 5)
+                       reg |= 0x10; /* /5 divider required */
+               if (to.mclk != 288000000)
+                       reg |= 0x20; /* which mclk pll is source */
+               break;
+
+       case SM501_CLOCK_V2XCLK:
+               /* This clock is divided in half so to achive the
+                * requested frequency the value must be multiplied by 2. */
+
+               sm501_freq = (sm501_select_clock(2 * req_freq, &to, 3) / 2);
+               reg=to.shift & 0x07;    /* bottom 3 bits are shift */
+               if (to.divider == 3)
+                       reg |= 0x08;    /* /3 divider required */
+               if (to.mclk != 288000000)
+                       reg |= 0x10;    /* which mclk pll is source */
+               break;
+
+       case SM501_CLOCK_MCLK:
+       case SM501_CLOCK_M1XCLK:
+               /* These clocks are the same and not further divided */
+
+               sm501_freq = sm501_select_clock( req_freq, &to, 3);
+               reg=to.shift & 0x07;    /* bottom 3 bits are shift */
+               if (to.divider == 3)
+                       reg |= 0x08;    /* /3 divider required */
+               if (to.mclk != 288000000)
+                       reg |= 0x10;    /* which mclk pll is source */
+               break;
+
+       default:
+               return 0; /* this is bad */
+       }
+
+       mutex_lock(&sm->clock_lock);
+
+       mode = readl(sm->regs + SM501_POWER_MODE_CONTROL);
+       gate = readl(sm->regs + SM501_CURRENT_GATE);
+       clock = readl(sm->regs + SM501_CURRENT_CLOCK);
+
+       clock = clock & ~(0xFF << clksrc);
+       clock |= reg<<clksrc;
+
+       mode &= 3;      /* find current mode */
+
+       switch (mode) {
+       case 1:
+               writel(gate, sm->regs + SM501_POWER_MODE_0_GATE);
+               writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK);
+               mode = 0;
+               break;
+       case 2:
+       case 0:
+               writel(gate, sm->regs + SM501_POWER_MODE_1_GATE);
+               writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK);
+               mode = 1;
+               break;
+
+       default:
+               mutex_unlock(&sm->clock_lock);
+               return -1;
+       }
+
+       writel(mode, sm->regs + SM501_POWER_MODE_CONTROL);
+       sm501_sync_regs(sm);
+
+       dev_info(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n",
+                gate, clock, mode);
+
+       msleep(16);
+       mutex_unlock(&sm->clock_lock);
+
+       sm501_dump_clk(sm);
+
+       return sm501_freq;
+}
+
+EXPORT_SYMBOL_GPL(sm501_set_clock);
+
+/* sm501_find_clock
+ *
+ * finds the closest available frequency for a given clock
+*/
+
+unsigned long sm501_find_clock(int clksrc,
+                              unsigned long req_freq)
+{
+       unsigned long sm501_freq; /* the frequency achiveable by the 501 */
+       struct sm501_clock to;
+
+       switch (clksrc) {
+       case SM501_CLOCK_P2XCLK:
+               sm501_freq = (sm501_select_clock(2 * req_freq, &to, 5) / 2);
+               break;
+
+       case SM501_CLOCK_V2XCLK:
+               sm501_freq = (sm501_select_clock(2 * req_freq, &to, 3) / 2);
+               break;
+
+       case SM501_CLOCK_MCLK:
+       case SM501_CLOCK_M1XCLK:
+               sm501_freq = sm501_select_clock(req_freq, &to, 3);
+               break;
+
+       default:
+               sm501_freq = 0;         /* error */
+       }
+
+       return sm501_freq;
+}
+
+EXPORT_SYMBOL_GPL(sm501_find_clock);
+
+static struct sm501_device *to_sm_device(struct platform_device *pdev)
+{
+       return container_of(pdev, struct sm501_device, pdev);
+}
+
+/* sm501_device_release
+ *
+ * A release function for the platform devices we create to allow us to
+ * free any items we allocated
+*/
+
+static void sm501_device_release(struct device *dev)
+{
+       kfree(to_sm_device(to_platform_device(dev)));
+}
+
+/* sm501_create_subdev
+ *
+ * Create a skeleton platform device with resources for passing to a
+ * sub-driver
+*/
+
+static struct platform_device *
+sm501_create_subdev(struct sm501_devdata *sm,
+                   char *name, unsigned int res_count)
+{
+       struct sm501_device *smdev;
+
+       smdev = kzalloc(sizeof(struct sm501_device) +
+                       sizeof(struct resource) * res_count, GFP_KERNEL);
+       if (!smdev)
+               return NULL;
+
+       smdev->pdev.dev.release = sm501_device_release;
+
+       smdev->pdev.name = name;
+       smdev->pdev.id = sm->pdev_id;
+       smdev->pdev.resource = (struct resource *)(smdev+1);
+       smdev->pdev.num_resources = res_count;
+
+       smdev->pdev.dev.parent = sm->dev;
+
+       return &smdev->pdev;
+}
+
+/* sm501_register_device
+ *
+ * Register a platform device created with sm501_create_subdev()
+*/
+
+static int sm501_register_device(struct sm501_devdata *sm,
+                                struct platform_device *pdev)
+{
+       struct sm501_device *smdev = to_sm_device(pdev);
+       int ptr;
+       int ret;
+
+       for (ptr = 0; ptr < pdev->num_resources; ptr++) {
+               printk("%s[%d] flags %08lx: %08llx..%08llx\n",
+                      pdev->name, ptr,
+                      pdev->resource[ptr].flags,
+                      (unsigned long long)pdev->resource[ptr].start,
+                      (unsigned long long)pdev->resource[ptr].end);
+       }
+
+       ret = platform_device_register(pdev);
+
+       if (ret >= 0) {
+               dev_dbg(sm->dev, "registered %s\n", pdev->name);
+               list_add_tail(&smdev->list, &sm->devices);
+       } else
+               dev_err(sm->dev, "error registering %s (%d)\n",
+                       pdev->name, ret);
+
+       return ret;
+}
+
+/* sm501_create_subio
+ *
+ * Fill in an IO resource for a sub device
+*/
+
+static void sm501_create_subio(struct sm501_devdata *sm,
+                              struct resource *res,
+                              resource_size_t offs,
+                              resource_size_t size)
+{
+       res->flags = IORESOURCE_MEM;
+       res->parent = sm->io_res;
+       res->start = sm->io_res->start + offs;
+       res->end = res->start + size - 1;
+}
+
+/* sm501_create_mem
+ *
+ * Fill in an MEM resource for a sub device
+*/
+
+static void sm501_create_mem(struct sm501_devdata *sm,
+                            struct resource *res,
+                            resource_size_t *offs,
+                            resource_size_t size)
+{
+       *offs -= size;          /* adjust memory size */
+
+       res->flags = IORESOURCE_MEM;
+       res->parent = sm->mem_res;
+       res->start = sm->mem_res->start + *offs;
+       res->end = res->start + size - 1;
+}
+
+/* sm501_create_irq
+ *
+ * Fill in an IRQ resource for a sub device
+*/
+
+static void sm501_create_irq(struct sm501_devdata *sm,
+                            struct resource *res)
+{
+       res->flags = IORESOURCE_IRQ;
+       res->parent = NULL;
+       res->start = res->end = sm->irq;
+}
+
+static int sm501_register_usbhost(struct sm501_devdata *sm,
+                                 resource_size_t *mem_avail)
+{
+       struct platform_device *pdev;
+
+       pdev = sm501_create_subdev(sm, "sm501-usb", 3);
+       if (!pdev)
+               return -ENOMEM;
+
+       sm501_create_subio(sm, &pdev->resource[0], 0x40000, 0x20000);
+       sm501_create_mem(sm, &pdev->resource[1], mem_avail, 256*1024);
+       sm501_create_irq(sm, &pdev->resource[2]);
+
+       return sm501_register_device(sm, pdev);
+}
+
+static int sm501_register_display(struct sm501_devdata *sm,
+                                 resource_size_t *mem_avail)
+{
+       struct platform_device *pdev;
+
+       pdev = sm501_create_subdev(sm, "sm501-fb", 4);
+       if (!pdev)
+               return -ENOMEM;
+
+       sm501_create_subio(sm, &pdev->resource[0], 0x80000, 0x10000);
+       sm501_create_subio(sm, &pdev->resource[1], 0x100000, 0x50000);
+       sm501_create_mem(sm, &pdev->resource[2], mem_avail, *mem_avail);
+       sm501_create_irq(sm, &pdev->resource[3]);
+
+       return sm501_register_device(sm, pdev);
+}
+
+/* sm501_dbg_regs
+ *
+ * Debug attribute to attach to parent device to show core registers
+*/
+
+static ssize_t sm501_dbg_regs(struct device *dev,
+                             struct device_attribute *attr, char *buff)
+{
+       struct sm501_devdata *sm = dev_get_drvdata(dev) ;
+       unsigned int reg;
+       char *ptr = buff;
+       int ret;
+
+       for (reg = 0x00; reg < 0x70; reg += 4) {
+               ret = sprintf(ptr, "%08x = %08x\n",
+                             reg, readl(sm->regs + reg));
+               ptr += ret;
+       }
+
+       return ptr - buff;
+}
+
+
+static DEVICE_ATTR(dbg_regs, 0666, sm501_dbg_regs, NULL);
+
+/* sm501_init_reg
+ *
+ * Helper function for the init code to setup a register
+*/
+
+static inline void sm501_init_reg(struct sm501_devdata *sm,
+                                 unsigned long reg,
+                                 struct sm501_reg_init *r)
+{
+       unsigned long tmp;
+
+       tmp = readl(sm->regs + reg);
+       tmp |= r->set;
+       tmp &= ~r->mask;
+       writel(tmp, sm->regs + reg);
+}
+
+/* sm501_init_regs
+ *
+ * Setup core register values
+*/
+
+static void sm501_init_regs(struct sm501_devdata *sm,
+                           struct sm501_initdata *init)
+{
+       sm501_misc_control(sm->dev,
+                          init->misc_control.set,
+                          init->misc_control.mask);
+
+       sm501_init_reg(sm, SM501_MISC_TIMING, &init->misc_timing);
+       sm501_init_reg(sm, SM501_GPIO31_0_CONTROL, &init->gpio_low);
+       sm501_init_reg(sm, SM501_GPIO63_32_CONTROL, &init->gpio_high);
+
+       if (init->mclk) {
+               dev_info(sm->dev, "setting MCLK to %ld\n", init->mclk);
+               sm501_set_clock(sm->dev, SM501_CLOCK_MCLK, init->mclk);
+       }
+
+       if (init->m1xclk) {
+               dev_info(sm->dev, "setting M1XCLK to %ld\n", init->m1xclk);
+               sm501_set_clock(sm->dev, SM501_CLOCK_M1XCLK, init->m1xclk);
+       }
+}
+
+static unsigned int sm501_mem_local[] = {
+       [0]     = 4*1024*1024,
+       [1]     = 8*1024*1024,
+       [2]     = 16*1024*1024,
+       [3]     = 32*1024*1024,
+       [4]     = 64*1024*1024,
+       [5]     = 2*1024*1024,
+};
+
+/* sm501_init_dev
+ *
+ * Common init code for an SM501
+*/
+
+static int sm501_init_dev(struct sm501_devdata *sm)
+{
+       resource_size_t mem_avail;
+       unsigned long dramctrl;
+       int ret;
+
+       mutex_init(&sm->clock_lock);
+       spin_lock_init(&sm->reg_lock);
+
+       INIT_LIST_HEAD(&sm->devices);
+
+       dramctrl = readl(sm->regs + SM501_DRAM_CONTROL);
+
+       mem_avail = sm501_mem_local[(dramctrl >> 13) & 0x7];
+
+       dev_info(sm->dev, "SM501 At %p: Version %08x, %ld Mb, IRQ %d\n",
+                sm->regs, readl(sm->regs + SM501_DEVICEID),
+                (unsigned long)mem_avail >> 20, sm->irq);
+
+       dev_info(sm->dev, "CurrentGate      %08x\n", readl(sm->regs+0x38));
+       dev_info(sm->dev, "CurrentClock     %08x\n", readl(sm->regs+0x3c));
+       dev_info(sm->dev, "PowerModeControl %08x\n", readl(sm->regs+0x54));
+
+       ret = device_create_file(sm->dev, &dev_attr_dbg_regs);
+       if (ret)
+               dev_err(sm->dev, "failed to create debug regs file\n");
+
+       sm501_dump_clk(sm);
+
+       /* check to see if we have some device initialisation */
+
+       if (sm->platdata) {
+               struct sm501_platdata *pdata = sm->platdata;
+
+               if (pdata->init) {
+                       sm501_init_regs(sm, sm->platdata->init);
+
+                       if (pdata->init->devices & SM501_USE_USB_HOST)
+                               sm501_register_usbhost(sm, &mem_avail);
+               }
+       }
+
+       /* always create a framebuffer */
+       sm501_register_display(sm, &mem_avail);
+
+       return 0;
+}
+
+static int sm501_plat_probe(struct platform_device *dev)
+{
+       struct sm501_devdata *sm;
+       int err;
+
+       sm = kzalloc(sizeof(struct sm501_devdata), GFP_KERNEL);
+       if (sm == NULL) {
+               dev_err(&dev->dev, "no memory for device data\n");
+               err = -ENOMEM;
+               goto err1;
+       }
+
+       sm->dev = &dev->dev;
+       sm->pdev_id = dev->id;
+       sm->irq = platform_get_irq(dev, 0);
+       sm->io_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
+       sm->mem_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       sm->platdata = dev->dev.platform_data;
+
+       if (sm->irq < 0) {
+               dev_err(&dev->dev, "failed to get irq resource\n");
+               err = sm->irq;
+               goto err_res;
+       }
+
+       if (sm->io_res == NULL || sm->mem_res == NULL) {
+               dev_err(&dev->dev, "failed to get IO resource\n");
+               err = -ENOENT;
+               goto err_res;
+       }
+
+       sm->regs_claim = request_mem_region(sm->io_res->start,
+                                           0x100, "sm501");
+
+       if (sm->regs_claim == NULL) {
+               dev_err(&dev->dev, "cannot claim registers\n");
+               err= -EBUSY;
+               goto err_res;
+       }
+
+       platform_set_drvdata(dev, sm);
+
+       sm->regs = ioremap(sm->io_res->start,
+                          (sm->io_res->end - sm->io_res->start) - 1);
+
+       if (sm->regs == NULL) {
+               dev_err(&dev->dev, "cannot remap registers\n");
+               err = -EIO;
+               goto err_claim;
+       }
+
+       return sm501_init_dev(sm);
+
+ err_claim:
+       release_resource(sm->regs_claim);
+       kfree(sm->regs_claim);
+ err_res:
+       kfree(sm);
+ err1:
+       return err;
+
+}
+
+/* Initialisation data for PCI devices */
+
+static struct sm501_initdata sm501_pci_initdata = {
+       .gpio_high      = {
+               .set    = 0x3F000000,           /* 24bit panel */
+               .mask   = 0x0,
+       },
+       .misc_timing    = {
+               .set    = 0x010100,             /* SDRAM timing */
+               .mask   = 0x1F1F00,
+       },
+       .misc_control   = {
+               .set    = SM501_MISC_PNL_24BIT,
+               .mask   = 0,
+       },
+
+       .devices        = SM501_USE_ALL,
+       .mclk           = 100 * MHZ,
+       .m1xclk         = 160 * MHZ,
+};
+
+static struct sm501_platdata_fbsub sm501_pdata_fbsub = {
+       .flags          = (SM501FB_FLAG_USE_INIT_MODE |
+                          SM501FB_FLAG_USE_HWCURSOR |
+                          SM501FB_FLAG_USE_HWACCEL |
+                          SM501FB_FLAG_DISABLE_AT_EXIT),
+};
+
+static struct sm501_platdata_fb sm501_fb_pdata = {
+       .fb_route       = SM501_FB_OWN,
+       .fb_crt         = &sm501_pdata_fbsub,
+       .fb_pnl         = &sm501_pdata_fbsub,
+};
+
+static struct sm501_platdata sm501_pci_platdata = {
+       .init           = &sm501_pci_initdata,
+       .fb             = &sm501_fb_pdata,
+};
+
+static int sm501_pci_probe(struct pci_dev *dev,
+                          const struct pci_device_id *id)
+{
+       struct sm501_devdata *sm;
+       int err;
+
+       sm = kzalloc(sizeof(struct sm501_devdata), GFP_KERNEL);
+       if (sm == NULL) {
+               dev_err(&dev->dev, "no memory for device data\n");
+               err = -ENOMEM;
+               goto err1;
+       }
+
+       /* set a default set of platform data */
+       dev->dev.platform_data = sm->platdata = &sm501_pci_platdata;
+
+       /* set a hopefully unique id for our child platform devices */
+       sm->pdev_id = 32 + dev->devfn;
+
+       pci_set_drvdata(dev, sm);
+
+       err = pci_enable_device(dev);
+       if (err) {
+               dev_err(&dev->dev, "cannot enable device\n");
+               goto err2;
+       }
+
+       sm->dev = &dev->dev;
+       sm->irq = dev->irq;
+
+#ifdef __BIG_ENDIAN
+       /* if the system is big-endian, we most probably have a
+        * translation in the IO layer making the PCI bus little endian
+        * so make the framebuffer swapped pixels */
+
+       sm501_fb_pdata.flags |= SM501_FBPD_SWAP_FB_ENDIAN;
+#endif
+
+       /* check our resources */
+
+       if (!(pci_resource_flags(dev, 0) & IORESOURCE_MEM)) {
+               dev_err(&dev->dev, "region #0 is not memory?\n");
+               err = -EINVAL;
+               goto err3;
+       }
+
+       if (!(pci_resource_flags(dev, 1) & IORESOURCE_MEM)) {
+               dev_err(&dev->dev, "region #1 is not memory?\n");
+               err = -EINVAL;
+               goto err3;
+       }
+
+       /* make our resources ready for sharing */
+
+       sm->io_res = &dev->resource[1];
+       sm->mem_res = &dev->resource[0];
+
+       sm->regs_claim = request_mem_region(sm->io_res->start,
+                                           0x100, "sm501");
+       if (sm->regs_claim == NULL) {
+               dev_err(&dev->dev, "cannot claim registers\n");
+               err= -EBUSY;
+               goto err3;
+       }
+
+       sm->regs = ioremap(pci_resource_start(dev, 1),
+                          pci_resource_len(dev, 1));
+
+       if (sm->regs == NULL) {
+               dev_err(&dev->dev, "cannot remap registers\n");
+               err = -EIO;
+               goto err4;
+       }
+
+       sm501_init_dev(sm);
+       return 0;
+
+ err4:
+       release_resource(sm->regs_claim);
+       kfree(sm->regs_claim);
+ err3:
+       pci_disable_device(dev);
+ err2:
+       pci_set_drvdata(dev, NULL);
+       kfree(sm);
+ err1:
+       return err;
+}
+
+static void sm501_remove_sub(struct sm501_devdata *sm,
+                            struct sm501_device *smdev)
+{
+       list_del(&smdev->list);
+       platform_device_unregister(&smdev->pdev);
+}
+
+static void sm501_dev_remove(struct sm501_devdata *sm)
+{
+       struct sm501_device *smdev, *tmp;
+
+       list_for_each_entry_safe(smdev, tmp, &sm->devices, list)
+               sm501_remove_sub(sm, smdev);
+
+       device_remove_file(sm->dev, &dev_attr_dbg_regs);
+}
+
+static void sm501_pci_remove(struct pci_dev *dev)
+{
+       struct sm501_devdata *sm = pci_get_drvdata(dev);
+
+       sm501_dev_remove(sm);
+       iounmap(sm->regs);
+
+       release_resource(sm->regs_claim);
+       kfree(sm->regs_claim);
+
+       pci_set_drvdata(dev, NULL);
+       pci_disable_device(dev);
+}
+
+static int sm501_plat_remove(struct platform_device *dev)
+{
+       struct sm501_devdata *sm = platform_get_drvdata(dev);
+
+       sm501_dev_remove(sm);
+       iounmap(sm->regs);
+
+       release_resource(sm->regs_claim);
+       kfree(sm->regs_claim);
+
+       return 0;
+}
+
+static struct pci_device_id sm501_pci_tbl[] = {
+       { 0x126f, 0x0501, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, sm501_pci_tbl);
+
+static struct pci_driver sm501_pci_drv = {
+       .name           = "sm501",
+       .id_table       = sm501_pci_tbl,
+       .probe          = sm501_pci_probe,
+       .remove         = sm501_pci_remove,
+};
+
+static struct platform_driver sm501_plat_drv = {
+       .driver         = {
+               .name   = "sm501",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = sm501_plat_probe,
+       .remove         = sm501_plat_remove,
+};
+
+static int __init sm501_base_init(void)
+{
+       platform_driver_register(&sm501_plat_drv);
+       return pci_register_driver(&sm501_pci_drv);
+}
+
+static void __exit sm501_base_exit(void)
+{
+       platform_driver_unregister(&sm501_plat_drv);
+       pci_unregister_driver(&sm501_pci_drv);
+}
+
+module_init(sm501_base_init);
+module_exit(sm501_base_exit);
+
+MODULE_DESCRIPTION("SM501 Core Driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, Vincent Sanders");
+MODULE_LICENSE("GPL v2");
index 9d5c083..38ac679 100644 (file)
@@ -430,10 +430,10 @@ config HPLANCE
 
 config LASI_82596
        tristate "Lasi ethernet"
-       depends on NET_ETHERNET && PARISC && GSC_LASI
+       depends on NET_ETHERNET && GSC
        help
-         Say Y here to support the on-board Intel 82596 ethernet controller
-         built into Hewlett-Packard PA-RISC machines.
+         Say Y here to support the builtin Intel 82596 ethernet controller
+         found in Hewlett-Packard PA-RISC machines with 10Mbit ethernet.
 
 config MIPS_JAZZ_SONIC
        tristate "MIPS JAZZ onboard SONIC Ethernet support"
index a710237..98215fd 100644 (file)
@@ -1417,6 +1417,10 @@ e1000_open(struct net_device *netdev)
        if ((err = e1000_setup_all_rx_resources(adapter)))
                goto err_setup_rx;
 
+       err = e1000_request_irq(adapter);
+       if (err)
+               goto err_req_irq;
+
        e1000_power_up_phy(adapter);
 
        if ((err = e1000_up(adapter)))
@@ -1427,10 +1431,6 @@ e1000_open(struct net_device *netdev)
                e1000_update_mng_vlan(adapter);
        }
 
-       err = e1000_request_irq(adapter);
-       if (err)
-               goto err_req_irq;
-
        /* If AMT is enabled, let the firmware know that the network
         * interface is now open */
        if (adapter->hw.mac_type == e1000_82573 &&
@@ -1439,10 +1439,10 @@ e1000_open(struct net_device *netdev)
 
        return E1000_SUCCESS;
 
-err_req_irq:
-       e1000_down(adapter);
 err_up:
        e1000_power_down_phy(adapter);
+       e1000_free_irq(adapter);
+err_req_irq:
        e1000_free_all_rx_resources(adapter);
 err_setup_rx:
        e1000_free_all_tx_resources(adapter);
index ea392f2..452863d 100644 (file)
@@ -384,7 +384,7 @@ struct i596_private {
        struct device *dev;
 };
 
-static char init_setup[] =
+static const char init_setup[] =
 {
        0x8E,                   /* length, prefetch on */
        0xC8,                   /* fifo to 8, monitor off */
@@ -683,7 +683,7 @@ static int init_i596_mem(struct net_device *dev)
        enable_irq(dev->irq);   /* enable IRQs from LAN */
 
        DEB(DEB_INIT, printk("%s: queuing CmdConfigure\n", dev->name));
-       memcpy(lp->cf_cmd.i596_config, init_setup, 14);
+       memcpy(lp->cf_cmd.i596_config, init_setup, sizeof(init_setup));
        lp->cf_cmd.cmd.command = CmdConfigure;
        CHECK_WBACK(lp, &(lp->cf_cmd), sizeof(struct cf_cmd));
        i596_add_cmd(dev, &lp->cf_cmd.cmd);
@@ -1156,32 +1156,12 @@ static int __devinit i82596_probe(struct net_device *dev,
        dma_addr_t dma_addr;
 
        /* This lot is ensure things have been cache line aligned. */
-       if (sizeof(struct i596_rfd) != 32) {
-           printk("82596: sizeof(struct i596_rfd) = %d\n",
-                           (int)sizeof(struct i596_rfd));
-           return -ENODEV;
-       }
-       if ((sizeof(struct i596_rbd) % 32) != 0) {
-           printk("82596: sizeof(struct i596_rbd) = %d\n",
-                           (int)sizeof(struct i596_rbd));
-           return -ENODEV;
-       }
-       if ((sizeof(struct tx_cmd) % 32) != 0) {
-           printk("82596: sizeof(struct tx_cmd) = %d\n",
-                           (int)sizeof(struct tx_cmd));
-           return -ENODEV;
-       }
-       if (sizeof(struct i596_tbd) != 32) {
-           printk("82596: sizeof(struct i596_tbd) = %d\n",
-                           (int)sizeof(struct i596_tbd));
-           return -ENODEV;
-       }
+       BUILD_BUG_ON(sizeof(struct i596_rfd) != 32);
+       BUILD_BUG_ON(sizeof(struct i596_rbd) &  31);
+       BUILD_BUG_ON(sizeof(struct tx_cmd)   &  31);
+       BUILD_BUG_ON(sizeof(struct i596_tbd) != 32);
 #ifndef __LP64__
-       if (sizeof(struct i596_private) > 4096) {
-           printk("82596: sizeof(struct i596_private) = %d\n",
-                           (int)sizeof(struct i596_private));
-           return -ENODEV;
-       }
+       BUILD_BUG_ON(sizeof(struct i596_private) > 4096);
 #endif
 
        if (!dev->base_addr || !dev->irq)
index 81a1c2e..26c6ac4 100644 (file)
@@ -64,8 +64,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.73"
-#define DRV_MODULE_RELDATE     "February 12, 2007"
+#define DRV_MODULE_VERSION     "3.74"
+#define DRV_MODULE_RELDATE     "February 20, 2007"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -3993,7 +3993,10 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb)
        /* Estimate the number of fragments in the worst case */
        if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->gso_segs * 3))) {
                netif_stop_queue(tp->dev);
-               return NETDEV_TX_BUSY;
+               if (tg3_tx_avail(tp) <= (skb_shinfo(skb)->gso_segs * 3))
+                       return NETDEV_TX_BUSY;
+
+               netif_wake_queue(tp->dev);
        }
 
        segs = skb_gso_segment(skb, tp->dev->features & ~NETIF_F_TSO);
@@ -4061,7 +4064,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
 
                hdr_len = ip_tcp_len + tcp_opt_len;
                if (unlikely((ETH_HLEN + hdr_len) > 80) &&
-                            (tp->tg3_flags2 & TG3_FLG2_HW_TSO_1_BUG))
+                            (tp->tg3_flags2 & TG3_FLG2_TSO_BUG))
                        return (tg3_tso_bug(tp, skb));
 
                base_flags |= (TXD_FLAG_CPU_PRE_DMA |
@@ -8137,7 +8140,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
            (ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
            (ering->tx_pending > TG3_TX_RING_SIZE - 1) ||
            (ering->tx_pending <= MAX_SKB_FRAGS) ||
-           ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_1_BUG) &&
+           ((tp->tg3_flags2 & TG3_FLG2_TSO_BUG) &&
             (ering->tx_pending <= (MAX_SKB_FRAGS * 3))))
                return -EINVAL;
 
@@ -10557,12 +10560,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                        tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2;
                        tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
                } else {
-                       tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1 |
-                                         TG3_FLG2_HW_TSO_1_BUG;
+                       tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1 | TG3_FLG2_TSO_BUG;
                        if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
                                ASIC_REV_5750 &&
                            tp->pci_chip_rev_id >= CHIPREV_ID_5750_C2)
-                               tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_1_BUG;
+                               tp->tg3_flags2 &= ~TG3_FLG2_TSO_BUG;
                }
        }
 
@@ -11867,7 +11869,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
            (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0) {
                tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE;
        } else {
-               tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
+               tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE | TG3_FLG2_TSO_BUG;
        }
 
        /* TSO is on by default on chips that support hardware TSO.
index 45d477e..086892d 100644 (file)
@@ -2227,7 +2227,7 @@ struct tg3 {
 #define TG3_FLAG_INIT_COMPLETE         0x80000000
        u32                             tg3_flags2;
 #define TG3_FLG2_RESTART_TIMER         0x00000001
-#define TG3_FLG2_HW_TSO_1_BUG          0x00000002
+#define TG3_FLG2_TSO_BUG               0x00000002
 #define TG3_FLG2_NO_ETH_WIRE_SPEED     0x00000004
 #define TG3_FLG2_IS_5788               0x00000008
 #define TG3_FLG2_MAX_RXPEND_64         0x00000010
index 07dc2b6..9bb4db5 100644 (file)
 ** the Free Software Foundation; either version 2 of the License, or
 ** (at your option) any later version.
 **
-** This Driver currently only supports the console (port 0) on the MUX.
-** Additional work will be needed on this driver to enable the full
-** functionality of the MUX.
-**
 */
 
 #include <linux/types.h>
@@ -67,7 +63,7 @@ static int hppb_probe(struct parisc_device *dev)
                }
                card = card->next;
        }
-        printk(KERN_INFO "Found GeckoBoa at 0x%lx\n", dev->hpa.start);
+        printk(KERN_INFO "Found GeckoBoa at 0x%x\n", dev->hpa.start);
 
        card->hpa = dev->hpa.start;
        card->mmio_region.name = "HP-PB Bus";
@@ -78,16 +74,18 @@ static int hppb_probe(struct parisc_device *dev)
 
        status = ccio_request_resource(dev, &card->mmio_region);
        if(status < 0) {
-               printk(KERN_ERR "%s: failed to claim HP-PB bus space (%08lx, %08lx)\n",
+               printk(KERN_ERR "%s: failed to claim HP-PB bus space (%08x, %08x)\n",
                        __FILE__, card->mmio_region.start, card->mmio_region.end);
        }
 
         return 0;
 }
 
-
 static struct parisc_device_id hppb_tbl[] = {
-        { HPHW_BCPORT, HVERSION_REV_ANY_ID, 0x500, 0xc }, 
+        { HPHW_BCPORT, HVERSION_REV_ANY_ID, 0x500, 0xc }, /* E25 and K */
+        { HPHW_BCPORT, 0x0, 0x501, 0xc }, /* E35 */
+        { HPHW_BCPORT, 0x0, 0x502, 0xc }, /* E45 */
+        { HPHW_BCPORT, 0x0, 0x503, 0xc }, /* E55 */
         { 0, }
 };
 
index 41e7ec2..6e05e30 100644 (file)
@@ -132,7 +132,7 @@ struct iosapic_irt {
 struct vector_info {
        struct iosapic_info *iosapic;   /* I/O SAPIC this vector is on */
        struct irt_entry *irte;         /* IRT entry */
-       u32     *eoi_addr;              /* precalculate EOI reg address */
+       u32 __iomem *eoi_addr;          /* precalculate EOI reg address */
        u32     eoi_data;               /* IA64: ?       PA: swapped txn_data */
        int     txn_irq;                /* virtual IRQ number for processor */
        ulong   txn_addr;               /* IA64: id_eid  PA: partial HPA */
index ba67699..21c4c29 100644 (file)
@@ -168,7 +168,8 @@ lba_dump_res(struct resource *r, int d)
 
        printk(KERN_DEBUG "(%p)", r->parent);
        for (i = d; i ; --i) printk(" ");
-       printk(KERN_DEBUG "%p [%lx,%lx]/%lx\n", r, r->start, r->end, r->flags);
+       printk(KERN_DEBUG "%p [%lx,%lx]/%lx\n", r,
+               (long)r->start, (long)r->end, r->flags);
        lba_dump_res(r->child, d+2);
        lba_dump_res(r->sibling, d);
 }
@@ -647,7 +648,7 @@ truncate_pat_collision(struct resource *root, struct resource *new)
        printk(KERN_WARNING "LBA: Truncating lmmio_space [%lx/%lx] "
                                        "to [%lx,%lx]\n",
                        start, end,
-                       new->start, new->end );
+                       (long)new->start, (long)new->end );
 
        return 0;       /* truncation successful */
 }
@@ -715,8 +716,8 @@ lba_fixup_bus(struct pci_bus *bus)
 
                                printk("FAILED: lba_fixup_bus() request for "
                                                "elmmio_space [%lx/%lx]\n",
-                                               ldev->hba.elmmio_space.start,
-                                               ldev->hba.elmmio_space.end);
+                                               (long)ldev->hba.elmmio_space.start,
+                                               (long)ldev->hba.elmmio_space.end);
 
                                /* lba_dump_res(&iomem_resource, 2); */
                                /* BUG(); */
@@ -738,15 +739,15 @@ lba_fixup_bus(struct pci_bus *bus)
                                        &(ldev->hba.lmmio_space))) {
 
                        printk(KERN_WARNING "LBA: lmmio_space [%lx/%lx] duplicate!\n",
-                                       ldev->hba.lmmio_space.start,
-                                       ldev->hba.lmmio_space.end);
+                                       (long)ldev->hba.lmmio_space.start,
+                                       (long)ldev->hba.lmmio_space.end);
                } else {
                        err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space));
                        if (err < 0) {
                                printk(KERN_ERR "FAILED: lba_fixup_bus() request for "
                                        "lmmio_space [%lx/%lx]\n",
-                                       ldev->hba.lmmio_space.start,
-                                       ldev->hba.lmmio_space.end);
+                                       (long)ldev->hba.lmmio_space.start,
+                                       (long)ldev->hba.lmmio_space.end);
                        } else
                                bus->resource[i++] = &(ldev->hba.lmmio_space);
                }
@@ -758,8 +759,8 @@ lba_fixup_bus(struct pci_bus *bus)
                        if (err < 0) {
                                printk("FAILED: lba_fixup_bus() request for "
                                        "gmmio_space [%lx/%lx]\n",
-                                       ldev->hba.gmmio_space.start,
-                                       ldev->hba.gmmio_space.end);
+                                       (long)ldev->hba.gmmio_space.start,
+                                       (long)ldev->hba.gmmio_space.end);
                                lba_dump_res(&iomem_resource, 2);
                                BUG();
                        }
@@ -980,7 +981,7 @@ LBA_PORT_IN(32, 0)
 #define LBA_PORT_OUT(size, mask) \
 static void lba_pat_out##size (struct pci_hba_data *l, u16 addr, u##size val) \
 { \
-       void *where = (void *) PIOP_TO_GMMIO(LBA_DEV(l), addr); \
+       void __iomem *where = PIOP_TO_GMMIO(LBA_DEV(l), addr); \
        DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, l, addr, val); \
        WRITE_REG##size(val, where); \
        /* flush the I/O down to the elroy at least */ \
@@ -1063,16 +1064,16 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
                        /* used to fix up pre-initialized MEM BARs */
                        if (!lba_dev->hba.lmmio_space.start) {
                                sprintf(lba_dev->hba.lmmio_name,
-                                               "PCI%02lx LMMIO",
-                                               lba_dev->hba.bus_num.start);
+                                               "PCI%02x LMMIO",
+                                               (int)lba_dev->hba.bus_num.start);
                                lba_dev->hba.lmmio_space_offset = p->start -
                                        io->start;
                                r = &lba_dev->hba.lmmio_space;
                                r->name = lba_dev->hba.lmmio_name;
                        } else if (!lba_dev->hba.elmmio_space.start) {
                                sprintf(lba_dev->hba.elmmio_name,
-                                               "PCI%02lx ELMMIO",
-                                               lba_dev->hba.bus_num.start);
+                                               "PCI%02x ELMMIO",
+                                               (int)lba_dev->hba.bus_num.start);
                                r = &lba_dev->hba.elmmio_space;
                                r->name = lba_dev->hba.elmmio_name;
                        } else {
@@ -1089,8 +1090,8 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
 
                case PAT_GMMIO:
                        /* MMIO space > 4GB phys addr; for 64-bit BAR */
-                       sprintf(lba_dev->hba.gmmio_name, "PCI%02lx GMMIO",
-                                       lba_dev->hba.bus_num.start);
+                       sprintf(lba_dev->hba.gmmio_name, "PCI%02x GMMIO",
+                                       (int)lba_dev->hba.bus_num.start);
                        r = &lba_dev->hba.gmmio_space;
                        r->name  = lba_dev->hba.gmmio_name;
                        r->start  = p->start;
@@ -1112,8 +1113,8 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
                        */
                        lba_dev->iop_base = ioremap_nocache(p->start, 64 * 1024 * 1024);
 
-                       sprintf(lba_dev->hba.io_name, "PCI%02lx Ports",
-                                       lba_dev->hba.bus_num.start);
+                       sprintf(lba_dev->hba.io_name, "PCI%02x Ports",
+                                       (int)lba_dev->hba.bus_num.start);
                        r = &lba_dev->hba.io_space;
                        r->name  = lba_dev->hba.io_name;
                        r->start  = HBA_PORT_BASE(lba_dev->hba.hba_num);
@@ -1166,8 +1167,8 @@ lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
        ** Legacy boxes but it's nice to see in /proc/iomem.
        */
        r = &(lba_dev->hba.lmmio_space);
-       sprintf(lba_dev->hba.lmmio_name, "PCI%02lx LMMIO",
-                                       lba_dev->hba.bus_num.start);
+       sprintf(lba_dev->hba.lmmio_name, "PCI%02x LMMIO",
+                                       (int)lba_dev->hba.bus_num.start);
        r->name  = lba_dev->hba.lmmio_name;
 
 #if 1
@@ -1275,8 +1276,8 @@ lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
        ** an existing (but unused portion of) distributed range.
        */
        r = &(lba_dev->hba.elmmio_space);
-       sprintf(lba_dev->hba.elmmio_name, "PCI%02lx ELMMIO",
-                                       lba_dev->hba.bus_num.start);
+       sprintf(lba_dev->hba.elmmio_name, "PCI%02x ELMMIO",
+                                       (int)lba_dev->hba.bus_num.start);
        r->name  = lba_dev->hba.elmmio_name;
 
 #if 1
@@ -1297,8 +1298,8 @@ lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
 #endif
 
        r = &(lba_dev->hba.io_space);
-       sprintf(lba_dev->hba.io_name, "PCI%02lx Ports",
-                                       lba_dev->hba.bus_num.start);
+       sprintf(lba_dev->hba.io_name, "PCI%02x Ports",
+                                       (int)lba_dev->hba.bus_num.start);
        r->name  = lba_dev->hba.io_name;
        r->flags = IORESOURCE_IO;
        r->start = READ_REG32(lba_dev->hba.base_addr + LBA_IOS_BASE) & ~1L;
@@ -1406,13 +1407,20 @@ lba_hw_init(struct lba_device *d)
        return 0;
 }
 
-
+/*
+ * Unfortunately, when firmware numbers busses, it doesn't take into account
+ * Cardbus bridges.  So we have to renumber the busses to suit ourselves.
+ * Elroy/Mercury don't actually know what bus number they're attached to;
+ * we use bus 0 to indicate the directly attached bus and any other bus
+ * number will be taken care of by the PCI-PCI bridge.
+ */
+static unsigned int lba_next_bus = 0;
 
 /*
-** Determine if lba should claim this chip (return 0) or not (return 1).
-** If so, initialize the chip and tell other partners in crime they
-** have work to do.
-*/
+ * Determine if lba should claim this chip (return 0) or not (return 1).
+ * If so, initialize the chip and tell other partners in crime they
+ * have work to do.
+ */
 static int __init
 lba_driver_probe(struct parisc_device *dev)
 {
@@ -1440,7 +1448,7 @@ lba_driver_probe(struct parisc_device *dev)
                }
 
                printk(KERN_INFO "Elroy version %s (0x%x) found at 0x%lx\n",
-                      version, func_class & 0xf, dev->hpa.start);
+                      version, func_class & 0xf, (long)dev->hpa.start);
 
                if (func_class < 2) {
                        printk(KERN_WARNING "Can't support LBA older than "
@@ -1470,17 +1478,16 @@ lba_driver_probe(struct parisc_device *dev)
                  */ 
                printk(KERN_INFO "%s version TR%d.%d (0x%x) found at 0x%lx\n",
                       IS_MERCURY(dev) ? "Mercury" : "Quicksilver", major,
-                      minor, func_class, dev->hpa.start);
+                      minor, func_class, (long)dev->hpa.start);
 
                cfg_ops = &mercury_cfg_ops;
        } else {
-               printk(KERN_ERR "Unknown LBA found at 0x%lx\n", dev->hpa.start);
+               printk(KERN_ERR "Unknown LBA found at 0x%lx\n",
+                       (long)dev->hpa.start);
                return -ENODEV;
        }
 
-       /*
-       ** Tell I/O SAPIC driver we have a IRQ handler/region.
-       */
+       /* Tell I/O SAPIC driver we have a IRQ handler/region. */
        tmp_obj = iosapic_register(dev->hpa.start + LBA_IOSAPIC_BASE);
 
        /* NOTE: PCI devices (e.g. 103c:1005 graphics card) which don't
@@ -1529,16 +1536,17 @@ lba_driver_probe(struct parisc_device *dev)
                lba_legacy_resources(dev, lba_dev);
        }
 
-       /* 
-       ** Tell PCI support another PCI bus was found.
-       ** Walks PCI bus for us too.
-       */
+       if (lba_dev->hba.bus_num.start < lba_next_bus)
+               lba_dev->hba.bus_num.start = lba_next_bus;
+
        dev->dev.platform_data = lba_dev;
        lba_bus = lba_dev->hba.hba_bus =
                pci_scan_bus_parented(&dev->dev, lba_dev->hba.bus_num.start,
                                cfg_ops, NULL);
-       if (lba_bus)
+       if (lba_bus) {
+               lba_next_bus = lba_bus->subordinate + 1;
                pci_bus_add_devices(lba_bus);
+       }
 
        /* This is in lieu of calling pci_assign_unassigned_resources() */
        if (is_pdc_pat()) {
index 9a731c1..d190c05 100644 (file)
@@ -66,8 +66,8 @@ static char lcd_text_default[32]  __read_mostly;
 
 
 static struct workqueue_struct *led_wq;
-static void led_work_func(void *);
-static DECLARE_WORK(led_task, led_work_func, NULL);
+static void led_work_func(struct work_struct *);
+static DECLARE_DELAYED_WORK(led_task, led_work_func);
 
 #if 0
 #define DPRINTK(x)     printk x
@@ -136,7 +136,7 @@ static int start_task(void)
 
        /* Create the work queue and queue the LED task */
        led_wq = create_singlethread_workqueue("led_wq");       
-       queue_work(led_wq, &led_task);
+       queue_delayed_work(led_wq, &led_task, 0);
 
        return 0;
 }
@@ -441,7 +441,7 @@ static __inline__ int led_get_diskio_activity(void)
 
 #define LED_UPDATE_INTERVAL (1 + (HZ*19/1000))
 
-static void led_work_func (void *unused)
+static void led_work_func (struct work_struct *unused)
 {
        static unsigned long last_jiffies;
        static unsigned long count_HZ; /* counter in range 0..HZ */
@@ -588,7 +588,7 @@ int __init register_led_driver(int model, unsigned long cmd_reg, unsigned long d
 
        /* Ensure the work is queued */
        if (led_wq) {
-               queue_work(led_wq, &led_task);
+               queue_delayed_work(led_wq, &led_task, 0);
        }
 
        return 0;
@@ -629,7 +629,7 @@ void __init register_led_regions(void)
    ** avoid a race condition while writing the CMD/DATA register pair.
    **
  */
-int lcd_print( char *str )
+int lcd_print( const char *str )
 {
        int i;
 
@@ -658,7 +658,7 @@ int lcd_print( char *str )
        
        /* re-queue the work */
        if (led_wq) {
-               queue_work(led_wq, &led_task);
+               queue_delayed_work(led_wq, &led_task, 0);
        }
 
        return lcd_info.lcd_width;
index 97e9dc0..6dedbde 100644 (file)
@@ -2,7 +2,7 @@
  * linux/drivers/parisc/power.c
  * HP PARISC soft power switch support driver
  *
- * Copyright (c) 2001-2005 Helge Deller <deller@gmx.de>
+ * Copyright (c) 2001-2007 Helge Deller <deller@gmx.de>
  * All rights reserved.
  *
  *
@@ -29,7 +29,6 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  *
  *
- * 
  *  HINT:
  *  Support of the soft power switch button may be enabled or disabled at
  *  runtime through the "/proc/sys/kernel/power" procfs entry.
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/string.h>
 #include <linux/notifier.h>
 #include <linux/reboot.h>
 #include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
+#include <linux/kthread.h>
 
 #include <asm/pdc.h>
 #include <asm/io.h>
 #include <asm/led.h>
-#include <asm/uaccess.h>
 
+#define DRIVER_NAME  "powersw"
+#define KTHREAD_NAME "kpowerswd"
 
-#ifdef DEBUG
-# define DPRINTK(x...) printk(x)
-#else
-# define DPRINTK(x...)
-#endif
-
-
-/* filename in /proc which can be used to enable/disable the power switch */
-#define SYSCTL_FILENAME                "sys/kernel/power"
+/* how often should the power button be polled ? */
+#define POWERSWITCH_POLL_PER_SEC 2
 
+/* how long does the power button needs to be down until we react ? */
+#define POWERSWITCH_DOWN_SEC 2
 
+/* assembly code to access special registers */
+/* taken from PCXL ERS page 82 */
 #define DIAG_CODE(code)                (0x14000000 + ((code)<<5))
 
-/* this will go to processor.h or any other place... */
-/* taken from PCXL ERS page 82 */
 #define MFCPU_X(rDiagReg, t_ch, t_th, code) \
        (DIAG_CODE(code) + ((rDiagReg)<<21) + ((t_ch)<<16) + ((t_th)<<0) )
        
 #define __getDIAG(dr) ( {                      \
         register unsigned long __res asm("r28");\
         __asm__ __volatile__ (                 \
-               ".word %1\n nop\n" : "=&r" (__res) : "i" (MFCPU_T(dr,28)) \
+               ".word %1" : "=&r" (__res) : "i" (MFCPU_T(dr,28) ) \
        );                                      \
        __res;                                  \
 } )
 
-
-static void deferred_poweroff(void *dummy)
-{
-       if (kill_cad_pid(SIGINT, 1)) {
-               /* just in case killing init process failed */
-               machine_power_off();
-       }
-}
-
-/*
- * This function gets called from interrupt context.
- * As it's called within an interrupt, it wouldn't sync if we don't
- * use schedule_work().
- */
-
-static DECLARE_WORK(poweroff_work, deferred_poweroff, NULL);
-
-static void poweroff(void)
-{
-       static int powering_off __read_mostly;
-
-       if (powering_off)
-               return;
-
-       powering_off++;
-       schedule_work(&poweroff_work);
-}
-
-
-/* local time-counter for shutdown */
+/* local shutdown counter */
 static int shutdown_timer __read_mostly;
 
 /* check, give feedback and start shutdown after one second */
 static void process_shutdown(void)
 {
        if (shutdown_timer == 0)
-               DPRINTK(KERN_INFO "Shutdown requested...\n");
+               printk(KERN_ALERT KTHREAD_NAME ": Shutdown requested...\n");
 
        shutdown_timer++;
        
        /* wait until the button was pressed for 1 second */
-       if (shutdown_timer == HZ) {
-#if defined (DEBUG) || defined(CONFIG_CHASSIS_LCD_LED)
-               static char msg[] = "Shutting down...";
-#endif
-               DPRINTK(KERN_INFO "%s\n", msg);
+       if (shutdown_timer == (POWERSWITCH_DOWN_SEC*POWERSWITCH_POLL_PER_SEC)) {
+               static const char msg[] = "Shutting down...";
+               printk(KERN_INFO KTHREAD_NAME ": %s\n", msg);
                lcd_print(msg);
-               poweroff();
+
+               /* send kill signal */
+               if (kill_cad_pid(SIGINT, 1)) {
+                       /* just in case killing init process failed */
+                       if (pm_power_off)
+                               pm_power_off();
+               }
        }
 }
 
 
-/* main power switch tasklet struct (scheduled from time.c) */
-DECLARE_TASKLET_DISABLED(power_tasklet, NULL, 0);
+/* main power switch task struct */
+static struct task_struct *power_task;
+
+/* filename in /proc which can be used to enable/disable the power switch */
+#define SYSCTL_FILENAME        "sys/kernel/power"
 
 /* soft power switch enabled/disabled */
 int pwrsw_enabled __read_mostly = 1;
 
-/*
- * On gecko style machines (e.g. 712/xx and 715/xx) 
- * the power switch status is stored in Bit 0 ("the highest bit")
- * of CPU diagnose register 25.
- * 
- */
-static void gecko_tasklet_func(unsigned long unused)
+/* main kernel thread worker. It polls the button state */
+static int kpowerswd(void *param)
 {
-       if (unlikely(!pwrsw_enabled))
-               return;
-
-       if (__getDIAG(25) & 0x80000000) {
-               /* power switch button not pressed or released again */
-               /* Warning: Some machines do never reset this DIAG flag! */
-               shutdown_timer = 0;
-       } else {
-               process_shutdown();
-       }
-}
-
+       __set_current_state(TASK_RUNNING);
+
+       do {
+               int button_not_pressed;
+               unsigned long soft_power_reg = (unsigned long) param;
+
+               schedule_timeout_interruptible(pwrsw_enabled ? HZ : HZ/POWERSWITCH_POLL_PER_SEC);
+               __set_current_state(TASK_RUNNING);
+
+               if (unlikely(!pwrsw_enabled))
+                       continue;
+
+               if (soft_power_reg) {
+                       /*
+                        * Non-Gecko-style machines:
+                        * Check the power switch status which is read from the
+                        * real I/O location at soft_power_reg.
+                        * Bit 31 ("the lowest bit) is the status of the power switch.
+                        * This bit is "1" if the button is NOT pressed.
+                        */
+                       button_not_pressed = (gsc_readl(soft_power_reg) & 0x1);
+               } else {
+                       /*
+                        * On gecko style machines (e.g. 712/xx and 715/xx) 
+                        * the power switch status is stored in Bit 0 ("the highest bit")
+                        * of CPU diagnose register 25.
+                        * Warning: Some machines never reset the DIAG flag, even if
+                        * the button has been released again.
+                        */
+                       button_not_pressed = (__getDIAG(25) & 0x80000000);
+               }
+
+               if (likely(button_not_pressed)) {
+                       if (unlikely(shutdown_timer && /* avoid writing if not necessary */
+                               shutdown_timer < (POWERSWITCH_DOWN_SEC*POWERSWITCH_POLL_PER_SEC))) {
+                               shutdown_timer = 0;
+                               printk(KERN_INFO KTHREAD_NAME ": Shutdown request aborted.\n");
+                       }
+               } else
+                       process_shutdown();
+
+
+       } while (!kthread_should_stop());
 
-
-/*
- * Check the power switch status which is read from the
- * real I/O location at soft_power_reg.
- * Bit 31 ("the lowest bit) is the status of the power switch.
- */
-
-static void polling_tasklet_func(unsigned long soft_power_reg)
-{
-        unsigned long current_status;
-       
-       if (unlikely(!pwrsw_enabled))
-               return;
-
-       current_status = gsc_readl(soft_power_reg);
-       if (current_status & 0x1) {
-               /* power switch button not pressed */
-               shutdown_timer = 0;
-       } else {
-               process_shutdown();
-       }
+       return 0;
 }
 
 
@@ -220,7 +197,7 @@ static struct notifier_block parisc_panic_block = {
 static int __init power_init(void)
 {
        unsigned long ret;
-       unsigned long soft_power_reg = 0;
+       unsigned long soft_power_reg;
 
 #if 0
        request_irq( IRQ_FROM_REGION(CPU_IRQ_REGION)+2, &powerfail_interrupt,
@@ -235,44 +212,44 @@ static int __init power_init(void)
                soft_power_reg = -1UL;
        
        switch (soft_power_reg) {
-       case 0:         printk(KERN_INFO "Gecko-style soft power switch enabled.\n");
-                       power_tasklet.func = gecko_tasklet_func;
+       case 0:         printk(KERN_INFO DRIVER_NAME ": Gecko-style soft power switch enabled.\n");
                        break;
                        
-       case -1UL:      printk(KERN_INFO "Soft power switch support not available.\n");
+       case -1UL:      printk(KERN_INFO DRIVER_NAME ": Soft power switch support not available.\n");
                        return -ENODEV;
        
-       default:        printk(KERN_INFO "Soft power switch enabled, polling @ 0x%08lx.\n",
+       default:        printk(KERN_INFO DRIVER_NAME ": Soft power switch at 0x%08lx enabled.\n",
                                soft_power_reg);
-                       power_tasklet.data = soft_power_reg;
-                       power_tasklet.func = polling_tasklet_func;
+       }
+
+       power_task = kthread_run(kpowerswd, (void*)soft_power_reg, KTHREAD_NAME);
+       if (IS_ERR(power_task)) {
+               printk(KERN_ERR DRIVER_NAME ": thread creation failed.  Driver not loaded.\n");
+               pdc_soft_power_button(0);
+               return -EIO;
        }
 
        /* Register a call for panic conditions. */
        atomic_notifier_chain_register(&panic_notifier_list,
                        &parisc_panic_block);
 
-       tasklet_enable(&power_tasklet);
-
        return 0;
 }
 
 static void __exit power_exit(void)
 {
-       if (!power_tasklet.func)
-               return;
+       kthread_stop(power_task);
 
-       tasklet_disable(&power_tasklet);
        atomic_notifier_chain_unregister(&panic_notifier_list,
                        &parisc_panic_block);
-       power_tasklet.func = NULL;
+
        pdc_soft_power_button(0);
 }
 
-module_init(power_init);
+arch_initcall(power_init);
 module_exit(power_exit);
 
 
-MODULE_AUTHOR("Helge Deller");
+MODULE_AUTHOR("Helge Deller <deller@gmx.de>");
 MODULE_DESCRIPTION("Soft power switch driver");
 MODULE_LICENSE("Dual BSD/GPL");
index 76a29da..322957a 100644 (file)
@@ -109,7 +109,7 @@ static unsigned long piranha_bad_128k = 0;
 
 #ifdef SBA_AGP_SUPPORT
 static int sba_reserve_agpgart = 1;
-module_param(sba_reserve_agpgart, int, 1);
+module_param(sba_reserve_agpgart, int, 0444);
 MODULE_PARM_DESC(sba_reserve_agpgart, "Reserve half of IO pdir as AGPGART");
 #endif
 
@@ -846,7 +846,7 @@ static void *sba_alloc_consistent(struct device *hwdev, size_t size,
        if (!hwdev) {
                /* only support PCI */
                *dma_handle = 0;
-               return 0;
+               return NULL;
        }
 
         ret = (void *) __get_free_pages(gfp, get_order(size));
index b61c17b..3de2623 100644 (file)
@@ -1546,7 +1546,7 @@ static void __devinit detect_and_report_smsc (void)
 }
 #endif /* CONFIG_PARPORT_PC_SUPERIO */
 
-static int __devinit get_superio_dma (struct parport *p)
+static int get_superio_dma (struct parport *p)
 {
        int i=0;
        while( (superios[i].io != p->base) && (i<NR_SUPERIOS))
@@ -2106,7 +2106,7 @@ static int parport_irq_probe(struct parport *pb)
 /* --- DMA detection -------------------------------------- */
 
 /* Only if chipset conforms to ECP ISA Interface Standard */
-static int __devinit programmable_dma_support (struct parport *p)
+static int programmable_dma_support (struct parport *p)
 {
        unsigned char oecr = inb (ECONTROL (p));
        int dma;
@@ -2123,7 +2123,7 @@ static int __devinit programmable_dma_support (struct parport *p)
        return dma;
 }
 
-static int __devinit parport_dma_probe (struct parport *p)
+static int parport_dma_probe (struct parport *p)
 {
        const struct parport_pc_private *priv = p->private_data;
        if (priv->ecr)
index caca0dc..f2e810f 100644 (file)
@@ -907,7 +907,7 @@ static int __init init_hs(void)
 
        for (i=0; i<HS_MAX_SOCKETS; i++) {
                unsigned int ret;
-               hs_sockets[i].socket.dev.dev = &hd64465_device.dev;             
+               hs_sockets[i].socket.dev.parent = &hd64465_device.dev;
                hs_sockets[i].number = i;
                ret = pcmcia_register_socket(&hs_sockets[i].socket);
                if (ret && i)
index e4a9410..91da15b 100644 (file)
@@ -760,7 +760,7 @@ static int __init init_m32r_pcc(void)
        /* Set up interrupt handler(s) */
 
        for (i = 0 ; i < pcc_sockets ; i++) {
-               socket[i].socket.dev.dev = &pcc_device.dev;
+               socket[i].socket.dev.parent = &pcc_device.dev;
                socket[i].socket.ops = &pcc_operations;
                socket[i].socket.resource_ops = &pccard_nonstatic_ops;
                socket[i].socket.owner = THIS_MODULE;
index d059c91..9721ed7 100644 (file)
@@ -1321,7 +1321,7 @@ static int __init m8xx_init(void)
                socket[i].socket.ops = &m8xx_services;
                socket[i].socket.resource_ops = &pccard_iodyn_ops;
                socket[i].socket.cb_dev = NULL;
-               socket[i].socket.dev.dev = &m8xx_device.dev;
+               socket[i].socket.dev.parent = &m8xx_device.dev;
        }
 
        for (i = 0; i < PCMCIA_SOCKETS_NO; i++)
index 76f7cbc..d77f751 100644 (file)
@@ -291,7 +291,7 @@ static int __devinit omap_cf_probe(struct device *dev)
                omap_cf_present() ? "present" : "(not present)");
 
        cf->socket.owner = THIS_MODULE;
-       cf->socket.dev.dev = dev;
+       cf->socket.dev.parent = dev;
        cf->socket.ops = &omap_cf_ops;
        cf->socket.resource_ops = &pccard_static_ops;
        cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
index 81dfc2c..ce22262 100644 (file)
@@ -232,7 +232,7 @@ static struct resource *iodyn_find_io_region(unsigned long base, int num,
                unsigned long align, struct pcmcia_socket *s)
 {
        struct resource *res = make_resource(0, num, IORESOURCE_IO,
-                                            s->dev.class_id);
+                                            s->dev.bus_id);
        struct pcmcia_align_data data;
        unsigned long min = base;
        int ret;
index 206e26c..eee2f1c 100644 (file)
@@ -596,7 +596,7 @@ static int __devinit vrc4171_add_sockets(void)
                }
 
                sprintf(socket->name, "NEC VRC4171 Card Slot %1c", 'A' + slot);
-               socket->pcmcia_socket.dev.dev = &vrc4171_card_device.dev;
+               socket->pcmcia_socket.dev.parent = &vrc4171_card_device.dev;
                socket->pcmcia_socket.ops = &vrc4171_pccard_operations;
                socket->pcmcia_socket.owner = THIS_MODULE;
 
index 4bbca50..deef296 100644 (file)
@@ -101,7 +101,7 @@ comment "RTC drivers"
 
 config RTC_DRV_CMOS
        tristate "PC-style 'CMOS' real time clock"
-       depends on RTC_CLASS && (X86_PC || ALPHA || ARM26 || ARM \
+       depends on RTC_CLASS && (X86 || ALPHA || ARM26 || ARM \
                || M32R || ATARI || POWERPC)
        help
          Say "yes" here to get direct support for the real time clock
index a724ab4..ac0e68e 100644 (file)
@@ -164,6 +164,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
        tm.tm_min = alrm->time.tm_min;
        tm.tm_sec = alrm->time.tm_sec;
 
+       at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM);
        at91_sys_write(AT91_RTC_TIMALR,
                  BIN2BCD(tm.tm_sec) << 0
                | BIN2BCD(tm.tm_min) << 8
@@ -174,6 +175,9 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
                | BIN2BCD(tm.tm_mday) << 24
                | AT91_RTC_DATEEN | AT91_RTC_MTHEN);
 
+       if (alrm->enabled)
+               at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM);
+
        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);
@@ -303,6 +307,12 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
                return ret;
        }
 
+       /* cpu init code should really have flagged this device as
+        * being wake-capable; if it didn't, do that here.
+        */
+       if (!device_can_wakeup(&pdev->dev))
+               device_init_wakeup(&pdev->dev, 1);
+
        rtc = rtc_device_register(pdev->name, &pdev->dev,
                                &at91_rtc_ops, THIS_MODULE);
        if (IS_ERR(rtc)) {
@@ -310,7 +320,6 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
                return PTR_ERR(rtc);
        }
        platform_set_drvdata(pdev, rtc);
-       device_init_wakeup(&pdev->dev, 1);
 
        printk(KERN_INFO "AT91 Real Time Clock driver.\n");
        return 0;
@@ -319,7 +328,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
 /*
  * Disable and remove the RTC driver
  */
-static int __devexit at91_rtc_remove(struct platform_device *pdev)
+static int __exit at91_rtc_remove(struct platform_device *pdev)
 {
        struct rtc_device *rtc = platform_get_drvdata(pdev);
 
@@ -331,7 +340,6 @@ static int __devexit at91_rtc_remove(struct platform_device *pdev)
 
        rtc_device_unregister(rtc);
        platform_set_drvdata(pdev, NULL);
-       device_init_wakeup(&pdev->dev, 0);
 
        return 0;
 }
@@ -404,8 +412,7 @@ static int at91_rtc_resume(struct platform_device *pdev)
 #endif
 
 static struct platform_driver at91_rtc_driver = {
-       .probe          = at91_rtc_probe,
-       .remove         = at91_rtc_remove,
+       .remove         = __exit_p(at91_rtc_remove),
        .suspend        = at91_rtc_suspend,
        .resume         = at91_rtc_resume,
        .driver         = {
@@ -416,7 +423,7 @@ static struct platform_driver at91_rtc_driver = {
 
 static int __init at91_rtc_init(void)
 {
-       return platform_driver_register(&at91_rtc_driver);
+       return platform_driver_probe(&at91_rtc_driver, at91_rtc_probe);
 }
 
 static void __exit at91_rtc_exit(void)
index 9c8ead4..677bae8 100644 (file)
@@ -263,8 +263,12 @@ static int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm)
 
 static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
+       u32     rtsr;
+
        memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time));
-       alrm->pending = RTSR & RTSR_AL ? 1 : 0;
+       rtsr = RTSR;
+       alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0;
+       alrm->pending = (rtsr & RTSR_AL) ? 1 : 0;
        return 0;
 }
 
@@ -275,12 +279,10 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        spin_lock_irq(&sa1100_rtc_lock);
        ret = rtc_update_alarm(&alrm->time);
        if (ret == 0) {
-               memcpy(&rtc_alarm, &alrm->time, sizeof(struct rtc_time));
-
                if (alrm->enabled)
-                       enable_irq_wake(IRQ_RTCAlrm);
+                       RTSR |= RTSR_ALE;
                else
-                       disable_irq_wake(IRQ_RTCAlrm);
+                       RTSR &= ~RTSR_ALE;
        }
        spin_unlock_irq(&sa1100_rtc_lock);
 
index ffa9282..baa8fe6 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/atomic.h>
 #include <asm/ptrace.h>
 #include <asm/sigp.h>
+#include <asm/smp.h>
 
 #include "sclp.h"
 
index b3a56dc..9cb129a 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/irq_regs.h>
 #include <asm/setup.h>
 #include <asm/reset.h>
+#include <asm/ipl.h>
 #include "airq.h"
 #include "cio.h"
 #include "css.h"
@@ -1047,7 +1048,7 @@ void reipl_ccw_dev(struct ccw_dev_id *devid)
        do_reipl_asm(*((__u32*)&schid));
 }
 
-extern struct schib ipl_schib;
+static struct schib __initdata ipl_schib;
 
 /*
  * ipl_save_parameters gets called very early. It is not allowed to access
index 3a81529..35a7316 100644 (file)
@@ -46,13 +46,6 @@ config SUN_VIDEOPIX
          based on the Phillips SAA9051, can handle NTSC and PAL/SECAM and
          SVIDEO signals.
 
-config SUN_AURORA
-       tristate "Aurora Multiboard 1600se (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && BROKEN
-       help
-         The Aurora Multiboard is a multi-port high-speed serial controller.
-         If you have one of these, say Y.
-
 config TADPOLE_TS102_UCTRL
        tristate "Tadpole TS102 Microcontroller support (EXPERIMENTAL)"
        depends on EXPERIMENTAL && SPARC32
index 3a5ea1d..7ab060e 100644 (file)
@@ -19,7 +19,6 @@ obj-$(CONFIG_SUN_OPENPROMIO)          += openprom.o
 obj-$(CONFIG_SUN_MOSTEK_RTC)           += rtc.o
 obj-$(CONFIG_SUN_BPP)                  += bpp.o
 obj-$(CONFIG_SUN_VIDEOPIX)             += vfc.o
-obj-$(CONFIG_SUN_AURORA)               += aurora.o
 obj-$(CONFIG_TADPOLE_TS102_UCTRL)      += uctrl.o
 obj-$(CONFIG_SUN_JSFLASH)              += jsflash.o
 obj-$(CONFIG_BBC_I2C)                  += bbc.o
diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c
deleted file mode 100644 (file)
index a54b4ac..0000000
+++ /dev/null
@@ -1,2364 +0,0 @@
-/*     $Id: aurora.c,v 1.19 2002/01/08 16:00:16 davem Exp $
- *     linux/drivers/sbus/char/aurora.c -- Aurora multiport driver
- *
- *     Copyright (c) 1999 by Oliver Aldulea (oli at bv dot ro)
- *
- *     This code is based on the RISCom/8 multiport serial driver written
- *     by Dmitry Gorodchanin (pgmdsg@ibi.com), based on the Linux serial
- *     driver, written by Linus Torvalds, Theodore T'so and others.
- *     The Aurora multiport programming info was obtained mainly from the
- *     Cirrus Logic CD180 documentation (available on the web), and by
- *     doing heavy tests on the board. Many thanks to Eddie C. Dost for the
- *     help on the sbus interface.
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the 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.
- *
- *     Revision 1.0
- *
- *     This is the first public release.
- *
- *     Most of the information you need is in the aurora.h file. Please
- *     read that file before reading this one.
- *
- *     Several parts of the code do not have comments yet.
- * 
- * n.b.  The board can support 115.2 bit rates, but only on a few
- * ports. The total badwidth of one chip (ports 0-7 or 8-15) is equal
- * to OSC_FREQ div 16. In case of my board, each chip can take 6
- * channels of 115.2 kbaud.  This information is not well-tested.
- * 
- * Fixed to use tty_get_baud_rate().
- *   Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
- */
-
-#include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#ifdef AURORA_INT_DEBUG
-#include <linux/timer.h>
-#endif
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/oplib.h>
-#include <asm/system.h>
-#include <asm/kdebug.h>
-#include <asm/sbus.h>
-#include <asm/uaccess.h>
-
-#include "aurora.h"
-#include "cd180.h"
-
-unsigned char irqs[4] = {
-       0, 0, 0, 0
-};
-
-#ifdef AURORA_INT_DEBUG
-int irqhit=0;
-#endif
-
-static struct tty_driver *aurora_driver;
-static struct Aurora_board aurora_board[AURORA_NBOARD] = {
-       {0,},
-};
-
-static struct Aurora_port aurora_port[AURORA_TNPORTS] =  {
-       { 0, },
-};
-
-/* no longer used. static struct Aurora_board * IRQ_to_board[16] = { NULL, } ;*/
-static unsigned char * tmp_buf = NULL;
-
-DECLARE_TASK_QUEUE(tq_aurora);
-
-static inline int aurora_paranoia_check(struct Aurora_port const * port,
-                                   char *name, const char *routine)
-{
-#ifdef AURORA_PARANOIA_CHECK
-       static const char *badmagic =
-               KERN_DEBUG "aurora: Warning: bad aurora port magic number for device %s in %s\n";
-       static const char *badinfo =
-               KERN_DEBUG "aurora: Warning: null aurora port for device %s in %s\n";
-
-       if (!port) {
-               printk(badinfo, name, routine);
-               return 1;
-       }
-       if (port->magic != AURORA_MAGIC) {
-               printk(badmagic, name, routine);
-               return 1;
-       }
-#endif
-       return 0;
-}
-
-/*
- * 
- *  Service functions for aurora driver.
- * 
- */
-
-/* Get board number from pointer */
-static inline int board_No (struct Aurora_board const * bp)
-{
-       return bp - aurora_board;
-}
-
-/* Get port number from pointer */
-static inline int port_No (struct Aurora_port const * port)
-{
-       return AURORA_PORT(port - aurora_port); 
-}
-
-/* Get pointer to board from pointer to port */
-static inline struct Aurora_board * port_Board(struct Aurora_port const * port)
-{
-       return &aurora_board[AURORA_BOARD(port - aurora_port)];
-}
-
-/* Wait for Channel Command Register ready */
-static inline void aurora_wait_CCR(struct aurora_reg128 * r)
-{
-       unsigned long delay;
-
-#ifdef AURORA_DEBUG
-printk("aurora_wait_CCR\n");
-#endif
-       /* FIXME: need something more descriptive than 100000 :) */
-       for (delay = 100000; delay; delay--) 
-               if (!sbus_readb(&r->r[CD180_CCR]))
-                       return;
-       printk(KERN_DEBUG "aurora: Timeout waiting for CCR.\n");
-}
-
-/*
- *  aurora probe functions.
- */
-
-/* Must be called with enabled interrupts */
-static inline void aurora_long_delay(unsigned long delay)
-{
-       unsigned long i;
-
-#ifdef AURORA_DEBUG
-       printk("aurora_long_delay: start\n");
-#endif
-       for (i = jiffies + delay; time_before(jiffies, i); ) ;
-#ifdef AURORA_DEBUG
-       printk("aurora_long_delay: end\n");
-#endif
-}
-
-/* Reset and setup CD180 chip */
-static int aurora_init_CD180(struct Aurora_board * bp, int chip)
-{
-       unsigned long flags;
-       int id;
-       
-#ifdef AURORA_DEBUG
-       printk("aurora_init_CD180: start %d:%d\n",
-              board_No(bp), chip);
-#endif
-       save_flags(flags); cli();
-       sbus_writeb(0, &bp->r[chip]->r[CD180_CAR]);
-       sbus_writeb(0, &bp->r[chip]->r[CD180_GSVR]);
-
-       /* Wait for CCR ready        */
-       aurora_wait_CCR(bp->r[chip]);
-
-       /* Reset CD180 chip          */
-       sbus_writeb(CCR_HARDRESET, &bp->r[chip]->r[CD180_CCR]);
-       udelay(1);
-       sti();
-       id=1000;
-       while((--id) &&
-             (sbus_readb(&bp->r[chip]->r[CD180_GSVR])!=0xff))udelay(100);
-       if(!id) {
-               printk(KERN_ERR "aurora%d: Chip %d failed init.\n",
-                      board_No(bp), chip);
-               restore_flags(flags);
-               return(-1);
-       }
-       cli();
-       sbus_writeb((board_No(bp)<<5)|((chip+1)<<3),
-                   &bp->r[chip]->r[CD180_GSVR]); /* Set ID for this chip      */
-       sbus_writeb(0x80|bp->ACK_MINT,
-                   &bp->r[chip]->r[CD180_MSMR]); /* Prio for modem intr       */
-       sbus_writeb(0x80|bp->ACK_TINT,
-                   &bp->r[chip]->r[CD180_TSMR]); /* Prio for transmitter intr */
-       sbus_writeb(0x80|bp->ACK_RINT,
-                   &bp->r[chip]->r[CD180_RSMR]); /* Prio for receiver intr    */
-       /* Setting up prescaler. We need 4 tick per 1 ms */
-       sbus_writeb((bp->oscfreq/(1000000/AURORA_TPS)) >> 8,
-                   &bp->r[chip]->r[CD180_PPRH]);
-       sbus_writeb((bp->oscfreq/(1000000/AURORA_TPS)) & 0xff,
-                   &bp->r[chip]->r[CD180_PPRL]);
-
-       sbus_writeb(SRCR_AUTOPRI|SRCR_GLOBPRI,
-                   &bp->r[chip]->r[CD180_SRCR]);
-
-       id = sbus_readb(&bp->r[chip]->r[CD180_GFRCR]);
-       printk(KERN_INFO "aurora%d: Chip %d id %02x: ",
-              board_No(bp), chip,id);
-       if(sbus_readb(&bp->r[chip]->r[CD180_SRCR]) & 128) {
-               switch (id) {
-                       case 0x82:printk("CL-CD1864 rev A\n");break;
-                       case 0x83:printk("CL-CD1865 rev A\n");break;
-                       case 0x84:printk("CL-CD1865 rev B\n");break;
-                       case 0x85:printk("CL-CD1865 rev C\n");break;
-                       default:printk("Unknown.\n");
-               };
-       } else {
-               switch (id) {
-                       case 0x81:printk("CL-CD180 rev B\n");break;
-                       case 0x82:printk("CL-CD180 rev C\n");break;
-                       default:printk("Unknown.\n");
-               };
-       }
-       restore_flags(flags);
-#ifdef AURORA_DEBUG
-       printk("aurora_init_CD180: end\n");
-#endif
-       return 0;
-}
-
-static int valid_irq(unsigned char irq)
-{
-int i;
-for(i=0;i<TYPE_1_IRQS;i++)
-       if (type_1_irq[i]==irq) return 1;
-return 0;
-}
-
-static irqreturn_t aurora_interrupt(int irq, void * dev_id);
-
-/* Main probing routine, also sets irq. */
-static int aurora_probe(void)
-{
-       struct sbus_bus *sbus;
-       struct sbus_dev *sdev;
-       int grrr;
-       char buf[30];
-       int bn = 0;
-       struct Aurora_board *bp;
-
-       for_each_sbus(sbus) {
-               for_each_sbusdev(sdev, sbus) {
-/*                     printk("Try: %x %s\n",sdev,sdev->prom_name);*/
-                       if (!strcmp(sdev->prom_name, "sio16")) {
-#ifdef AURORA_DEBUG
-                               printk(KERN_INFO "aurora: sio16 at %p\n",sdev);
-#endif
-                               if((sdev->reg_addrs[0].reg_size!=1) &&
-                                  (sdev->reg_addrs[1].reg_size!=128) &&
-                                  (sdev->reg_addrs[2].reg_size!=128) &&
-                                  (sdev->reg_addrs[3].reg_size!=4)) {
-                                       printk(KERN_ERR "aurora%d: registers' sizes "
-                                              "do not match.\n", bn);
-                                       break;
-                               }
-                               bp = &aurora_board[bn];
-                               bp->r0 = (struct aurora_reg1 *)
-                                       sbus_ioremap(&sdev->resource[0], 0,
-                                                    sdev->reg_addrs[0].reg_size,
-                                                    "sio16");
-                               if (bp->r0 == NULL) {
-                                       printk(KERN_ERR "aurora%d: can't map "
-                                              "reg_addrs[0]\n", bn);
-                                       break;
-                               }
-#ifdef AURORA_DEBUG
-                               printk("Map reg 0: %p\n", bp->r0);
-#endif
-                               bp->r[0] = (struct aurora_reg128 *)
-                                       sbus_ioremap(&sdev->resource[1], 0,
-                                                    sdev->reg_addrs[1].reg_size,
-                                                    "sio16");
-                               if (bp->r[0] == NULL) {
-                                       printk(KERN_ERR "aurora%d: can't map "
-                                              "reg_addrs[1]\n", bn);
-                                       break;
-                               }
-#ifdef AURORA_DEBUG
-                               printk("Map reg 1: %p\n", bp->r[0]);
-#endif
-                               bp->r[1] = (struct aurora_reg128 *)
-                                       sbus_ioremap(&sdev->resource[2], 0,
-                                                    sdev->reg_addrs[2].reg_size,
-                                                    "sio16");
-                               if (bp->r[1] == NULL) {
-                                       printk(KERN_ERR "aurora%d: can't map "
-                                              "reg_addrs[2]\n", bn);
-                                       break;
-                               }
-#ifdef AURORA_DEBUG
-                               printk("Map reg 2: %p\n", bp->r[1]);
-#endif
-                               bp->r3 = (struct aurora_reg4 *)
-                                       sbus_ioremap(&sdev->resource[3], 0,
-                                                    sdev->reg_addrs[3].reg_size,
-                                                    "sio16");
-                               if (bp->r3 == NULL) {
-                                       printk(KERN_ERR "aurora%d: can't map "
-                                              "reg_addrs[3]\n", bn);
-                                       break;
-                               }
-#ifdef AURORA_DEBUG
-                               printk("Map reg 3: %p\n", bp->r3);
-#endif
-                               /* Variables setup */
-                               bp->flags = 0;
-#ifdef AURORA_DEBUG
-                               grrr=prom_getint(sdev->prom_node,"intr");
-                               printk("intr pri %d\n", grrr);
-#endif
-                               if ((bp->irq=irqs[bn]) && valid_irq(bp->irq) &&
-                                   !request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) {
-                                       free_irq(bp->irq|0x30, bp);
-                               } else
-                               if ((bp->irq=prom_getint(sdev->prom_node, "bintr")) && valid_irq(bp->irq) &&
-                                   !request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) {
-                                       free_irq(bp->irq|0x30, bp);
-                               } else
-                               if ((bp->irq=prom_getint(sdev->prom_node, "intr")) && valid_irq(bp->irq) &&
-                                   !request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) {
-                                       free_irq(bp->irq|0x30, bp);
-                               } else
-                               for(grrr=0;grrr<TYPE_1_IRQS;grrr++) {
-                                       if ((bp->irq=type_1_irq[grrr])&&!request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) {
-                                               free_irq(bp->irq|0x30, bp);
-                                               break;
-                                       } else {
-                                       printk(KERN_ERR "aurora%d: Could not get an irq for this board !!!\n",bn);
-                                       bp->flags=0xff;
-                                       }
-                               }
-                               if(bp->flags==0xff)break;
-                               printk(KERN_INFO "aurora%d: irq %d\n",bn,bp->irq&0x0f);
-                               buf[0]=0;
-                               grrr=prom_getproperty(sdev->prom_node,"dtr_rts",buf,sizeof(buf));
-                               if(!strcmp(buf,"swapped")){
-                                       printk(KERN_INFO "aurora%d: Swapped DTR and RTS\n",bn);
-                                       bp->DTR=MSVR_RTS;
-                                       bp->RTS=MSVR_DTR;
-                                       bp->MSVDTR=CD180_MSVRTS;
-                                       bp->MSVRTS=CD180_MSVDTR;
-                                       bp->flags|=AURORA_BOARD_DTR_FLOW_OK;
-                                       }else{
-                                       #ifdef AURORA_FORCE_DTR_FLOW
-                                       printk(KERN_INFO "aurora%d: Forcing swapped DTR-RTS\n",bn);
-                                       bp->DTR=MSVR_RTS;
-                                       bp->RTS=MSVR_DTR;
-                                       bp->MSVDTR=CD180_MSVRTS;
-                                       bp->MSVRTS=CD180_MSVDTR;
-                                       bp->flags|=AURORA_BOARD_DTR_FLOW_OK;
-                                       #else
-                                       printk(KERN_INFO "aurora%d: Normal DTR and RTS\n",bn);
-                                       bp->DTR=MSVR_DTR;
-                                       bp->RTS=MSVR_RTS;
-                                       bp->MSVDTR=CD180_MSVDTR;
-                                       bp->MSVRTS=CD180_MSVRTS;
-                                       #endif
-                               }
-                               bp->oscfreq=prom_getint(sdev->prom_node,"clk")*100;
-                               printk(KERN_INFO "aurora%d: Oscillator: %d Hz\n",bn,bp->oscfreq);
-                               grrr=prom_getproperty(sdev->prom_node,"chip",buf,sizeof(buf));
-                               printk(KERN_INFO "aurora%d: Chips: %s\n",bn,buf);
-                               grrr=prom_getproperty(sdev->prom_node,"manu",buf,sizeof(buf));
-                               printk(KERN_INFO "aurora%d: Manufacturer: %s\n",bn,buf);
-                               grrr=prom_getproperty(sdev->prom_node,"model",buf,sizeof(buf));
-                               printk(KERN_INFO "aurora%d: Model: %s\n",bn,buf);
-                               grrr=prom_getproperty(sdev->prom_node,"rev",buf,sizeof(buf));
-                               printk(KERN_INFO "aurora%d: Revision: %s\n",bn,buf);
-                               grrr=prom_getproperty(sdev->prom_node,"mode",buf,sizeof(buf));
-                               printk(KERN_INFO "aurora%d: Mode: %s\n",bn,buf);
-                               #ifdef MODULE
-                               bp->count=0;
-                               #endif
-                               bp->flags = AURORA_BOARD_PRESENT;
-                               /* hardware ack */
-                               bp->ACK_MINT=1;
-                               bp->ACK_TINT=2;
-                               bp->ACK_RINT=3;
-                               bn++;
-                       }
-               }
-       }
-       return bn;
-}
-
-static void aurora_release_io_range(struct Aurora_board *bp)
-{
-       sbus_iounmap((unsigned long)bp->r0, 1);
-       sbus_iounmap((unsigned long)bp->r[0], 128);
-       sbus_iounmap((unsigned long)bp->r[1], 128);
-       sbus_iounmap((unsigned long)bp->r3, 4);
-}
-
-static inline void aurora_mark_event(struct Aurora_port * port, int event)
-{
-#ifdef AURORA_DEBUG
-       printk("aurora_mark_event: start\n");
-#endif
-       set_bit(event, &port->event);
-       queue_task(&port->tqueue, &tq_aurora);
-       mark_bh(AURORA_BH);
-#ifdef AURORA_DEBUG
-       printk("aurora_mark_event: end\n");
-#endif
-}
-
-static __inline__ struct Aurora_port * aurora_get_port(struct Aurora_board const * bp,
-                                                      int chip,
-                                                      unsigned char const *what)
-{
-       unsigned char channel;
-       struct Aurora_port * port;
-
-       channel = ((chip << 3) |
-                  ((sbus_readb(&bp->r[chip]->r[CD180_GSCR]) & GSCR_CHAN) >> GSCR_CHAN_OFF));
-       port = &aurora_port[board_No(bp) * AURORA_NPORT * AURORA_NCD180 + channel];
-       if (port->flags & ASYNC_INITIALIZED)
-               return port;
-
-       printk(KERN_DEBUG "aurora%d: %s interrupt from invalid port %d\n",
-              board_No(bp), what, channel);
-       return NULL;
-}
-
-static void aurora_receive_exc(struct Aurora_board const * bp, int chip)
-{
-       struct Aurora_port *port;
-       struct tty_struct *tty;
-       unsigned char status;
-       unsigned char ch;
-       
-       if (!(port = aurora_get_port(bp, chip, "Receive_x")))
-               return;
-
-       tty = port->tty;
-       if (tty->flip.count >= TTY_FLIPBUF_SIZE)  {
-#ifdef AURORA_INTNORM
-               printk("aurora%d: port %d: Working around flip buffer overflow.\n",
-                      board_No(bp), port_No(port));
-#endif
-               return;
-       }
-       
-#ifdef AURORA_REPORT_OVERRUN   
-       status = sbus_readb(&bp->r[chip]->r[CD180_RCSR]);
-       if (status & RCSR_OE)  {
-               port->overrun++;
-#if 1
-               printk("aurora%d: port %d: Overrun. Total %ld overruns.\n",
-                      board_No(bp), port_No(port), port->overrun);
-#endif         
-       }
-       status &= port->mark_mask;
-#else  
-       status = sbus_readb(&bp->r[chip]->r[CD180_RCSR]) & port->mark_mask;
-#endif 
-       ch = sbus_readb(&bp->r[chip]->r[CD180_RDR]);
-       if (!status)
-               return;
-
-       if (status & RCSR_TOUT)  {
-/*             printk("aurora%d: port %d: Receiver timeout. Hardware problems ?\n",
-                      board_No(bp), port_No(port));*/
-               return;
-               
-       } else if (status & RCSR_BREAK)  {
-               printk(KERN_DEBUG "aurora%d: port %d: Handling break...\n",
-                      board_No(bp), port_No(port));
-               *tty->flip.flag_buf_ptr++ = TTY_BREAK;
-               if (port->flags & ASYNC_SAK)
-                       do_SAK(tty);
-               
-       } else if (status & RCSR_PE) 
-               *tty->flip.flag_buf_ptr++ = TTY_PARITY;
-       
-       else if (status & RCSR_FE) 
-               *tty->flip.flag_buf_ptr++ = TTY_FRAME;
-       
-        else if (status & RCSR_OE)
-               *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
-       
-       else
-               *tty->flip.flag_buf_ptr++ = 0;
-       
-       *tty->flip.char_buf_ptr++ = ch;
-       tty->flip.count++;
-       queue_task(&tty->flip.tqueue, &tq_timer);
-}
-
-static void aurora_receive(struct Aurora_board const * bp, int chip)
-{
-       struct Aurora_port *port;
-       struct tty_struct *tty;
-       unsigned char count,cnt;
-
-       if (!(port = aurora_get_port(bp, chip, "Receive")))
-               return;
-       
-       tty = port->tty;
-       
-       count = sbus_readb(&bp->r[chip]->r[CD180_RDCR]);
-
-#ifdef AURORA_REPORT_FIFO
-       port->hits[count > 8 ? 9 : count]++;
-#endif
-
-       while (count--)  {
-               if (tty->flip.count >= TTY_FLIPBUF_SIZE)  {
-#ifdef AURORA_INTNORM
-                       printk("aurora%d: port %d: Working around flip buffer overflow.\n",
-                              board_No(bp), port_No(port));
-#endif
-                       break;
-               }
-               cnt = sbus_readb(&bp->r[chip]->r[CD180_RDR]);
-               *tty->flip.char_buf_ptr++ = cnt;
-               *tty->flip.flag_buf_ptr++ = 0;
-               tty->flip.count++;
-       }
-       queue_task(&tty->flip.tqueue, &tq_timer);
-}
-
-static void aurora_transmit(struct Aurora_board const * bp, int chip)
-{
-       struct Aurora_port *port;
-       struct tty_struct *tty;
-       unsigned char count;
-       
-       if (!(port = aurora_get_port(bp, chip, "Transmit")))
-               return;
-               
-       tty = port->tty;
-       
-       if (port->SRER & SRER_TXEMPTY)  {
-               /* FIFO drained */
-               sbus_writeb(port_No(port) & 7,
-                           &bp->r[chip]->r[CD180_CAR]);
-               udelay(1);
-               port->SRER &= ~SRER_TXEMPTY;
-               sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
-               return;
-       }
-       
-       if ((port->xmit_cnt <= 0 && !port->break_length)
-           || tty->stopped || tty->hw_stopped)  {
-               sbus_writeb(port_No(port) & 7,
-                           &bp->r[chip]->r[CD180_CAR]);
-               udelay(1);
-               port->SRER &= ~SRER_TXRDY;
-               sbus_writeb(port->SRER,
-                           &bp->r[chip]->r[CD180_SRER]);
-               return;
-       }
-       
-       if (port->break_length)  {
-               if (port->break_length > 0)  {
-                       if (port->COR2 & COR2_ETC)  {
-                               sbus_writeb(CD180_C_ESC,
-                                           &bp->r[chip]->r[CD180_TDR]);
-                               sbus_writeb(CD180_C_SBRK,
-                                           &bp->r[chip]->r[CD180_TDR]);
-                               port->COR2 &= ~COR2_ETC;
-                       }
-                       count = min(port->break_length, 0xff);
-                       sbus_writeb(CD180_C_ESC,
-                                   &bp->r[chip]->r[CD180_TDR]);
-                       sbus_writeb(CD180_C_DELAY,
-                                   &bp->r[chip]->r[CD180_TDR]);
-                       sbus_writeb(count,
-                                   &bp->r[chip]->r[CD180_TDR]);
-                       if (!(port->break_length -= count))
-                               port->break_length--;
-               } else  {
-                       sbus_writeb(CD180_C_ESC,
-                                   &bp->r[chip]->r[CD180_TDR]);
-                       sbus_writeb(CD180_C_EBRK,
-                                   &bp->r[chip]->r[CD180_TDR]);
-                       sbus_writeb(port->COR2,
-                                   &bp->r[chip]->r[CD180_COR2]);
-                       aurora_wait_CCR(bp->r[chip]);
-                       sbus_writeb(CCR_CORCHG2,
-                                   &bp->r[chip]->r[CD180_CCR]);
-                       port->break_length = 0;
-               }
-               return;
-       }
-       
-       count = CD180_NFIFO;
-       do {
-               u8 byte = port->xmit_buf[port->xmit_tail++];
-
-               sbus_writeb(byte, &bp->r[chip]->r[CD180_TDR]);
-               port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE-1);
-               if (--port->xmit_cnt <= 0)
-                       break;
-       } while (--count > 0);
-       
-       if (port->xmit_cnt <= 0)  {
-               sbus_writeb(port_No(port) & 7,
-                           &bp->r[chip]->r[CD180_CAR]);
-               udelay(1);
-               port->SRER &= ~SRER_TXRDY;
-               sbus_writeb(port->SRER,
-                           &bp->r[chip]->r[CD180_SRER]);
-       }
-       if (port->xmit_cnt <= port->wakeup_chars)
-               aurora_mark_event(port, RS_EVENT_WRITE_WAKEUP);
-}
-
-static void aurora_check_modem(struct Aurora_board const * bp, int chip)
-{
-       struct Aurora_port *port;
-       struct tty_struct *tty;
-       unsigned char mcr;
-       
-       if (!(port = aurora_get_port(bp, chip, "Modem")))
-               return;
-               
-       tty = port->tty;
-       
-       mcr = sbus_readb(&bp->r[chip]->r[CD180_MCR]);
-       if (mcr & MCR_CDCHG)  {
-               if (sbus_readb(&bp->r[chip]->r[CD180_MSVR]) & MSVR_CD) 
-                       wake_up_interruptible(&port->open_wait);
-               else
-                       schedule_task(&port->tqueue_hangup);
-       }
-       
-/* We don't have such things yet. My aurora board has DTR and RTS swapped, but that doesn't count in this driver. Let's hope
- * Aurora didn't made any boards with CTS or DSR broken...
- */
-/* #ifdef AURORA_BRAIN_DAMAGED_CTS
-       if (mcr & MCR_CTSCHG)  {
-               if (aurora_in(bp, CD180_MSVR) & MSVR_CTS)  {
-                       tty->hw_stopped = 0;
-                       port->SRER |= SRER_TXRDY;
-                       if (port->xmit_cnt <= port->wakeup_chars)
-                               aurora_mark_event(port, RS_EVENT_WRITE_WAKEUP);
-               } else  {
-                       tty->hw_stopped = 1;
-                       port->SRER &= ~SRER_TXRDY;
-               }
-               sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
-       }
-       if (mcr & MCR_DSRCHG)  {
-               if (aurora_in(bp, CD180_MSVR) & MSVR_DSR)  {
-                       tty->hw_stopped = 0;
-                       port->SRER |= SRER_TXRDY;
-                       if (port->xmit_cnt <= port->wakeup_chars)
-                               aurora_mark_event(port, RS_EVENT_WRITE_WAKEUP);
-               } else  {
-                       tty->hw_stopped = 1;
-                       port->SRER &= ~SRER_TXRDY;
-               }
-               sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
-       }
-#endif AURORA_BRAIN_DAMAGED_CTS */
-       
-       /* Clear change bits */
-       sbus_writeb(0, &bp->r[chip]->r[CD180_MCR]);
-}
-
-/* The main interrupt processing routine */
-static irqreturn_t aurora_interrupt(int irq, void * dev_id)
-{
-       unsigned char status;
-       unsigned char ack,chip/*,chip_id*/;
-       struct Aurora_board * bp = (struct Aurora_board *) dev_id;
-       unsigned long loop = 0;
-
-#ifdef AURORA_INT_DEBUG
-       printk("IRQ%d %d\n",irq,++irqhit);
-#ifdef AURORA_FLOODPRO
-       if (irqhit>=AURORA_FLOODPRO)
-               sbus_writeb(8, &bp->r0->r);
-#endif
-#endif
-       
-/* old bp = IRQ_to_board[irq&0x0f];*/
-       
-       if (!bp || !(bp->flags & AURORA_BOARD_ACTIVE))
-               return IRQ_NONE;
-
-/*     The while() below takes care of this.
-       status = sbus_readb(&bp->r[0]->r[CD180_SRSR]);
-#ifdef AURORA_INT_DEBUG
-       printk("mumu: %02x\n", status);
-#endif
-       if (!(status&SRSR_ANYINT))
-               return IRQ_NONE; * Nobody has anything to say, so exit *
-*/
-       while ((loop++ < 48) &&
-              (status = sbus_readb(&bp->r[0]->r[CD180_SRSR]) & SRSR_ANYINT)){
-#ifdef AURORA_INT_DEBUG
-               printk("SRSR: %02x\n", status);
-#endif
-               if (status & SRSR_REXT) {
-                       ack = sbus_readb(&bp->r3->r[bp->ACK_RINT]);
-#ifdef AURORA_INT_DEBUG
-                       printk("R-ACK %02x\n", ack);
-#endif
-                       if ((ack >> 5) == board_No(bp)) {
-                               if ((chip=((ack>>3)&3)-1) < AURORA_NCD180) {
-                                       if ((ack&GSVR_ITMASK)==GSVR_IT_RGD) {
-                                               aurora_receive(bp,chip);
-                                               sbus_writeb(0,
-                                                        &bp->r[chip]->r[CD180_EOSRR]);
-                                       } else if ((ack & GSVR_ITMASK) == GSVR_IT_REXC) {
-                                               aurora_receive_exc(bp,chip);
-                                               sbus_writeb(0,
-                                                        &bp->r[chip]->r[CD180_EOSRR]);
-                                       }
-                               }
-                       }
-               } else if (status & SRSR_TEXT) {
-                       ack = sbus_readb(&bp->r3->r[bp->ACK_TINT]);
-#ifdef AURORA_INT_DEBUG
-                       printk("T-ACK %02x\n", ack);
-#endif
-                       if ((ack >> 5) == board_No(bp)) {
-                               if ((chip=((ack>>3)&3)-1) < AURORA_NCD180) {
-                                       if ((ack&GSVR_ITMASK)==GSVR_IT_TX) {
-                                               aurora_transmit(bp,chip);
-                                               sbus_writeb(0,
-                                                        &bp->r[chip]->r[CD180_EOSRR]);
-                                       }
-                               }
-                       }
-               } else if (status & SRSR_MEXT) {
-                       ack = sbus_readb(&bp->r3->r[bp->ACK_MINT]);
-#ifdef AURORA_INT_DEBUG
-                       printk("M-ACK %02x\n", ack);
-#endif
-                       if ((ack >> 5) == board_No(bp)) {
-                               if ((chip = ((ack>>3)&3)-1) < AURORA_NCD180) {
-                                       if ((ack&GSVR_ITMASK)==GSVR_IT_MDM) {
-                                               aurora_check_modem(bp,chip);
-                                               sbus_writeb(0,
-                                                        &bp->r[chip]->r[CD180_EOSRR]);
-                                       }
-                               }
-                       }
-               }
-       }
-/* I guess this faster code can be used with CD1865, using AUROPRI and GLOBPRI. */
-#if 0
-       while ((loop++ < 48)&&(status=bp->r[0]->r[CD180_SRSR]&SRSR_ANYINT)){
-#ifdef AURORA_INT_DEBUG
-               printk("SRSR: %02x\n",status);
-#endif
-               ack = sbus_readb(&bp->r3->r[0]);
-#ifdef AURORA_INT_DEBUG
-               printk("ACK: %02x\n",ack);
-#endif
-               if ((ack>>5)==board_No(bp)) {
-                       if ((chip=((ack>>3)&3)-1) < AURORA_NCD180) {
-                               ack&=GSVR_ITMASK;
-                               if (ack==GSVR_IT_RGD) {
-                                       aurora_receive(bp,chip);
-                                       sbus_writeb(0,
-                                                   &bp->r[chip]->r[CD180_EOSRR]);
-                               } else if (ack==GSVR_IT_REXC) {
-                                       aurora_receive_exc(bp,chip);
-                                       sbus_writeb(0,
-                                                   &bp->r[chip]->r[CD180_EOSRR]);
-                               } else if (ack==GSVR_IT_TX) {
-                                       aurora_transmit(bp,chip);
-                                       sbus_writeb(0,
-                                                   &bp->r[chip]->r[CD180_EOSRR]);
-                               } else if (ack==GSVR_IT_MDM) {
-                                       aurora_check_modem(bp,chip);
-                                       sbus_writeb(0,
-                                                   &bp->r[chip]->r[CD180_EOSRR]);
-                               }
-                       }
-               }
-       }
-#endif
-
-/* This is the old handling routine, used in riscom8 for only one CD180. I keep it here for reference. */
-#if 0
-       for(chip=0;chip<AURORA_NCD180;chip++){
-               chip_id=(board_No(bp)<<5)|((chip+1)<<3);
-               loop=0;
-               while ((loop++ < 1) &&
-                      ((status = sbus_readb(&bp->r[chip]->r[CD180_SRSR])) &
-                       (SRSR_TEXT | SRSR_MEXT | SRSR_REXT))) {
-
-                       if (status & SRSR_REXT) {
-                               ack = sbus_readb(&bp->r3->r[bp->ACK_RINT]);
-                               if (ack == (chip_id | GSVR_IT_RGD)) {
-#ifdef AURORA_INTMSG
-                                       printk("RX ACK\n");
-#endif
-                                       aurora_receive(bp,chip);
-                               } else if (ack == (chip_id | GSVR_IT_REXC)) {
-#ifdef AURORA_INTMSG
-                                       printk("RXC ACK\n");
-#endif
-                                       aurora_receive_exc(bp,chip);
-                               } else {
-#ifdef AURORA_INTNORM
-                                       printk("aurora%d-%d: Bad receive ack 0x%02x.\n",
-                                              board_No(bp), chip, ack);
-#endif
-                               }
-                       } else if (status & SRSR_TEXT) {
-                               ack = sbus_readb(&bp->r3->r[bp->ACK_TINT]);
-                               if (ack == (chip_id | GSVR_IT_TX)){
-#ifdef AURORA_INTMSG
-                                       printk("TX ACK\n");
-#endif
-                                       aurora_transmit(bp,chip);
-                               } else {
-#ifdef AURORA_INTNORM
-                                       printk("aurora%d-%d: Bad transmit ack 0x%02x.\n",
-                                              board_No(bp), chip, ack);
-#endif
-                               }
-                       } else  if (status & SRSR_MEXT)  {
-                               ack = sbus_readb(&bp->r3->r[bp->ACK_MINT]);
-                               if (ack == (chip_id | GSVR_IT_MDM)){
-#ifdef AURORA_INTMSG
-                                       printk("MDM ACK\n");
-#endif
-                                       aurora_check_modem(bp,chip);
-                               } else {
-#ifdef AURORA_INTNORM
-                                       printk("aurora%d-%d: Bad modem ack 0x%02x.\n",
-                                              board_No(bp), chip, ack);
-#endif
-                               }
-                       }
-                       sbus_writeb(0, &bp->r[chip]->r[CD180_EOSRR]);
-               }
-       }
-#endif
-
-       return IRQ_HANDLED;
-}
-
-#ifdef AURORA_INT_DEBUG
-static void aurora_timer (unsigned long ignored);
-
-static DEFINE_TIMER(aurora_poll_timer, aurora_timer, 0, 0);
-
-static void
-aurora_timer (unsigned long ignored)
-{
-       unsigned long flags;
-       int i;
-
-       save_flags(flags); cli();
-
-       printk("SRSR: %02x,%02x - ",
-              sbus_readb(&aurora_board[0].r[0]->r[CD180_SRSR]),
-              sbus_readb(&aurora_board[0].r[1]->r[CD180_SRSR]));
-       for (i = 0; i < 4; i++) {
-               udelay(1);
-               printk("%02x ",
-                      sbus_readb(&aurora_board[0].r3->r[i]));
-       }
-       printk("\n");
-
-       aurora_poll_timer.expires = jiffies + 300;
-       add_timer (&aurora_poll_timer);
-
-       restore_flags(flags);
-}
-#endif
-
-/*
- *  Routines for open & close processing.
- */
-
-/* Called with disabled interrupts */
-static int aurora_setup_board(struct Aurora_board * bp)
-{
-       int error;
-       
-#ifdef AURORA_ALLIRQ
-       int i;
-       for (i = 0; i < AURORA_ALLIRQ; i++) {
-               error = request_irq(allirq[i]|0x30, aurora_interrupt, IRQF_SHARED,
-                                   "sio16", bp);
-               if (error)
-                       printk(KERN_ERR "IRQ%d request error %d\n",
-                              allirq[i], error);
-       }
-#else
-       error = request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED,
-                           "sio16", bp);
-       if (error) {
-               printk(KERN_ERR "IRQ request error %d\n", error);
-               return error;
-       }
-#endif
-       /* Board reset */
-       sbus_writeb(0, &bp->r0->r);
-       udelay(1);
-       if (bp->flags & AURORA_BOARD_TYPE_2) {
-               /* unknown yet */
-       } else {
-               sbus_writeb((AURORA_CFG_ENABLE_IO | AURORA_CFG_ENABLE_IRQ |
-                            (((bp->irq)&0x0f)>>2)),
-                           &bp->r0->r);
-       }
-       udelay(10000);
-
-       if (aurora_init_CD180(bp,0))error=1;error=0;
-       if (aurora_init_CD180(bp,1))error++;
-       if (error == AURORA_NCD180) {
-               printk(KERN_ERR "Both chips failed initialisation.\n");
-               return -EIO;
-       }
-
-#ifdef AURORA_INT_DEBUG
-       aurora_poll_timer.expires= jiffies + 1;
-       add_timer(&aurora_poll_timer);
-#endif
-#ifdef AURORA_DEBUG
-       printk("aurora_setup_board: end\n");
-#endif
-       return 0;
-}
-
-/* Called with disabled interrupts */
-static void aurora_shutdown_board(struct Aurora_board *bp)
-{
-       int i;
-
-#ifdef AURORA_DEBUG
-       printk("aurora_shutdown_board: start\n");
-#endif
-
-#ifdef AURORA_INT_DEBUG
-       del_timer(&aurora_poll_timer);
-#endif
-
-#ifdef AURORA_ALLIRQ
-       for(i=0;i<AURORA_ALLIRQ;i++){
-               free_irq(allirq[i]|0x30, bp);
-/*             IRQ_to_board[allirq[i]&0xf] = NULL;*/
-       }
-#else
-       free_irq(bp->irq|0x30, bp);
-/*     IRQ_to_board[bp->irq&0xf] = NULL;*/
-#endif 
-       /* Drop all DTR's */
-       for(i=0;i<16;i++){
-               sbus_writeb(i & 7, &bp->r[i>>3]->r[CD180_CAR]);
-               udelay(1);
-               sbus_writeb(0, &bp->r[i>>3]->r[CD180_MSVR]);
-               udelay(1);
-       }
-       /* Board shutdown */
-       sbus_writeb(0, &bp->r0->r);
-
-#ifdef AURORA_DEBUG
-       printk("aurora_shutdown_board: end\n");
-#endif
-}
-
-/* Setting up port characteristics. 
- * Must be called with disabled interrupts
- */
-static void aurora_change_speed(struct Aurora_board *bp, struct Aurora_port *port)
-{
-       struct tty_struct *tty;
-       unsigned long baud;
-       long tmp;
-       unsigned char cor1 = 0, cor3 = 0;
-       unsigned char mcor1 = 0, mcor2 = 0,chip;
-       
-#ifdef AURORA_DEBUG
-       printk("aurora_change_speed: start\n");
-#endif
-       if (!(tty = port->tty) || !tty->termios)
-               return;
-               
-       chip = AURORA_CD180(port_No(port));
-
-       port->SRER  = 0;
-       port->COR2 = 0;
-       port->MSVR = MSVR_RTS|MSVR_DTR;
-       
-       baud = tty_get_baud_rate(tty);
-       
-       /* Select port on the board */
-       sbus_writeb(port_No(port) & 7,
-                   &bp->r[chip]->r[CD180_CAR]);
-       udelay(1);
-       
-       if (!baud)  {
-               /* Drop DTR & exit */
-               port->MSVR &= ~(bp->DTR|bp->RTS);
-               sbus_writeb(port->MSVR,
-                           &bp->r[chip]->r[CD180_MSVR]);
-               return;
-       } else  {
-               /* Set DTR on */
-               port->MSVR |= bp->DTR;
-               sbus_writeb(port->MSVR,
-                           &bp->r[chip]->r[CD180_MSVR]);
-       }
-       
-       /* Now we must calculate some speed dependent things. */
-       
-       /* Set baud rate for port. */
-       tmp = (((bp->oscfreq + baud/2) / baud +
-               CD180_TPC/2) / CD180_TPC);
-
-/*     tmp = (bp->oscfreq/7)/baud;
-       if((tmp%10)>4)tmp=tmp/10+1;else tmp=tmp/10;*/
-/*     printk("Prescaler period: %d\n",tmp);*/
-
-       sbus_writeb((tmp >> 8) & 0xff,
-                   &bp->r[chip]->r[CD180_RBPRH]);
-       sbus_writeb((tmp >> 8) & 0xff,
-                   &bp->r[chip]->r[CD180_TBPRH]);
-       sbus_writeb(tmp & 0xff, &bp->r[chip]->r[CD180_RBPRL]);
-       sbus_writeb(tmp & 0xff, &bp->r[chip]->r[CD180_TBPRL]);
-       
-       baud = (baud + 5) / 10;   /* Estimated CPS */
-       
-       /* Two timer ticks seems enough to wakeup something like SLIP driver */
-       tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO;           
-       port->wakeup_chars = (tmp < 0) ? 0 : ((tmp >= SERIAL_XMIT_SIZE) ?
-                                             SERIAL_XMIT_SIZE - 1 : tmp);
-       
-       /* Receiver timeout will be transmission time for 1.5 chars */
-       tmp = (AURORA_TPS + AURORA_TPS/2 + baud/2) / baud;
-       tmp = (tmp > 0xff) ? 0xff : tmp;
-       sbus_writeb(tmp, &bp->r[chip]->r[CD180_RTPR]);
-       
-       switch (C_CSIZE(tty))  {
-        case CS5:
-               cor1 |= COR1_5BITS;
-               break;
-        case CS6:
-               cor1 |= COR1_6BITS;
-               break;
-        case CS7:
-               cor1 |= COR1_7BITS;
-               break;
-        case CS8:
-               cor1 |= COR1_8BITS;
-               break;
-       }
-       
-       if (C_CSTOPB(tty)) 
-               cor1 |= COR1_2SB;
-       
-       cor1 |= COR1_IGNORE;
-       if (C_PARENB(tty))  {
-               cor1 |= COR1_NORMPAR;
-               if (C_PARODD(tty)) 
-                       cor1 |= COR1_ODDP;
-               if (I_INPCK(tty)) 
-                       cor1 &= ~COR1_IGNORE;
-       }
-       /* Set marking of some errors */
-       port->mark_mask = RCSR_OE | RCSR_TOUT;
-       if (I_INPCK(tty)) 
-               port->mark_mask |= RCSR_FE | RCSR_PE;
-       if (I_BRKINT(tty) || I_PARMRK(tty)) 
-               port->mark_mask |= RCSR_BREAK;
-       if (I_IGNPAR(tty)) 
-               port->mark_mask &= ~(RCSR_FE | RCSR_PE);
-       if (I_IGNBRK(tty))  {
-               port->mark_mask &= ~RCSR_BREAK;
-               if (I_IGNPAR(tty)) 
-                       /* Real raw mode. Ignore all */
-                       port->mark_mask &= ~RCSR_OE;
-       }
-       /* Enable Hardware Flow Control */
-       if (C_CRTSCTS(tty))  {
-/*#ifdef AURORA_BRAIN_DAMAGED_CTS
-               port->SRER |= SRER_DSR | SRER_CTS;
-               mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD;
-               mcor2 |= MCOR2_DSROD | MCOR2_CTSOD;
-               tty->hw_stopped = !(aurora_in(bp, CD180_MSVR) & (MSVR_CTS|MSVR_DSR));
-#else*/
-               port->COR2 |= COR2_CTSAE;
-/*#endif*/
-               if (bp->flags&AURORA_BOARD_DTR_FLOW_OK) {
-                       mcor1 |= AURORA_RXTH;
-               }
-       }
-       /* Enable Software Flow Control. FIXME: I'm not sure about this */
-       /* Some people reported that it works, but I still doubt */
-       if (I_IXON(tty))  {
-               port->COR2 |= COR2_TXIBE;
-               cor3 |= (COR3_FCT | COR3_SCDE);
-               if (I_IXANY(tty))
-                       port->COR2 |= COR2_IXM;
-               sbus_writeb(START_CHAR(tty),
-                           &bp->r[chip]->r[CD180_SCHR1]);
-               sbus_writeb(STOP_CHAR(tty),
-                           &bp->r[chip]->r[CD180_SCHR2]);
-               sbus_writeb(START_CHAR(tty),
-                           &bp->r[chip]->r[CD180_SCHR3]);
-               sbus_writeb(STOP_CHAR(tty),
-                           &bp->r[chip]->r[CD180_SCHR4]);
-       }
-       if (!C_CLOCAL(tty))  {
-               /* Enable CD check */
-               port->SRER |= SRER_CD;
-               mcor1 |= MCOR1_CDZD;
-               mcor2 |= MCOR2_CDOD;
-       }
-       
-       if (C_CREAD(tty)) 
-               /* Enable receiver */
-               port->SRER |= SRER_RXD;
-       
-       /* Set input FIFO size (1-8 bytes) */
-       cor3 |= AURORA_RXFIFO; 
-       /* Setting up CD180 channel registers */
-       sbus_writeb(cor1, &bp->r[chip]->r[CD180_COR1]);
-       sbus_writeb(port->COR2, &bp->r[chip]->r[CD180_COR2]);
-       sbus_writeb(cor3, &bp->r[chip]->r[CD180_COR3]);
-       /* Make CD180 know about registers change */
-       aurora_wait_CCR(bp->r[chip]);
-       sbus_writeb(CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3,
-                   &bp->r[chip]->r[CD180_CCR]);
-       /* Setting up modem option registers */
-       sbus_writeb(mcor1, &bp->r[chip]->r[CD180_MCOR1]);
-       sbus_writeb(mcor2, &bp->r[chip]->r[CD180_MCOR2]);
-       /* Enable CD180 transmitter & receiver */
-       aurora_wait_CCR(bp->r[chip]);
-       sbus_writeb(CCR_TXEN | CCR_RXEN, &bp->r[chip]->r[CD180_CCR]);
-       /* Enable interrupts */
-       sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
-       /* And finally set RTS on */
-       sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]);
-#ifdef AURORA_DEBUG
-       printk("aurora_change_speed: end\n");
-#endif
-}
-
-/* Must be called with interrupts enabled */
-static int aurora_setup_port(struct Aurora_board *bp, struct Aurora_port *port)
-{
-       unsigned long flags;
-       
-#ifdef AURORA_DEBUG
-       printk("aurora_setup_port: start %d\n",port_No(port));
-#endif
-       if (port->flags & ASYNC_INITIALIZED)
-               return 0;
-               
-       if (!port->xmit_buf) {
-               /* We may sleep in get_zeroed_page() */
-               unsigned long tmp;
-               
-               if (!(tmp = get_zeroed_page(GFP_KERNEL)))
-                       return -ENOMEM;
-                   
-               if (port->xmit_buf) {
-                       free_page(tmp);
-                       return -ERESTARTSYS;
-               }
-               port->xmit_buf = (unsigned char *) tmp;
-       }
-               
-       save_flags(flags); cli();
-               
-       if (port->tty) 
-               clear_bit(TTY_IO_ERROR, &port->tty->flags);
-               
-#ifdef MODULE
-       if ((port->count == 1) && ((++bp->count) == 1))
-                       bp->flags |= AURORA_BOARD_ACTIVE;
-#endif
-
-       port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
-       aurora_change_speed(bp, port);
-       port->flags |= ASYNC_INITIALIZED;
-               
-       restore_flags(flags);
-#ifdef AURORA_DEBUG
-       printk("aurora_setup_port: end\n");
-#endif
-       return 0;
-}
-
-/* Must be called with interrupts disabled */
-static void aurora_shutdown_port(struct Aurora_board *bp, struct Aurora_port *port)
-{
-       struct tty_struct *tty;
-       unsigned char chip;
-
-#ifdef AURORA_DEBUG
-       printk("aurora_shutdown_port: start\n");
-#endif
-       if (!(port->flags & ASYNC_INITIALIZED)) 
-               return;
-       
-       chip = AURORA_CD180(port_No(port));
-       
-#ifdef AURORA_REPORT_OVERRUN
-       printk("aurora%d: port %d: Total %ld overruns were detected.\n",
-              board_No(bp), port_No(port), port->overrun);
-#endif 
-#ifdef AURORA_REPORT_FIFO
-       {
-               int i;
-               
-               printk("aurora%d: port %d: FIFO hits [ ",
-                      board_No(bp), port_No(port));
-               for (i = 0; i < 10; i++)  {
-                       printk("%ld ", port->hits[i]);
-               }
-               printk("].\n");
-       }
-#endif 
-       if (port->xmit_buf)  {
-               free_page((unsigned long) port->xmit_buf);
-               port->xmit_buf = NULL;
-       }
-
-       if (!(tty = port->tty) || C_HUPCL(tty))  {
-               /* Drop DTR */
-               port->MSVR &= ~(bp->DTR|bp->RTS);
-               sbus_writeb(port->MSVR,
-                           &bp->r[chip]->r[CD180_MSVR]);
-       }
-       
-        /* Select port */
-       sbus_writeb(port_No(port) & 7,
-                   &bp->r[chip]->r[CD180_CAR]);
-       udelay(1);
-
-       /* Reset port */
-       aurora_wait_CCR(bp->r[chip]);
-       sbus_writeb(CCR_SOFTRESET, &bp->r[chip]->r[CD180_CCR]);
-
-       /* Disable all interrupts from this port */
-       port->SRER = 0;
-       sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
-       
-       if (tty)  
-               set_bit(TTY_IO_ERROR, &tty->flags);
-       port->flags &= ~ASYNC_INITIALIZED;
-
-#ifdef MODULE
-       if (--bp->count < 0)  {
-               printk(KERN_DEBUG "aurora%d: aurora_shutdown_port: "
-                      "bad board count: %d\n",
-                      board_No(bp), bp->count);
-               bp->count = 0;
-       }
-       
-       if (!bp->count)
-               bp->flags &= ~AURORA_BOARD_ACTIVE;
-#endif
-
-#ifdef AURORA_DEBUG
-       printk("aurora_shutdown_port: end\n");
-#endif
-}
-
-       
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
-                          struct Aurora_port *port)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       struct Aurora_board *bp = port_Board(port);
-       int    retval;
-       int    do_clocal = 0;
-       int    CD;
-       unsigned char chip;
-       
-#ifdef AURORA_DEBUG
-       printk("block_til_ready: start\n");
-#endif
-       chip = AURORA_CD180(port_No(port));
-
-       /* If the device is in the middle of being closed, then block
-        * until it's done, and then try again.
-        */
-       if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
-               interruptible_sleep_on(&port->close_wait);
-               if (port->flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               else
-                       return -ERESTARTSYS;
-       }
-
-       /* If non-blocking mode is set, or the port is not enabled,
-        * then make the check up front and then exit.
-        */
-       if ((filp->f_flags & O_NONBLOCK) ||
-           (tty->flags & (1 << TTY_IO_ERROR))) {
-               port->flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (C_CLOCAL(tty))  
-               do_clocal = 1;
-
-       /* Block waiting for the carrier detect and the line to become
-        * free (i.e., not in use by the callout).  While we are in
-        * this loop, info->count is dropped by one, so that
-        * rs_close() knows when to free things.  We restore it upon
-        * exit, either normal or abnormal.
-        */
-       retval = 0;
-       add_wait_queue(&port->open_wait, &wait);
-       cli();
-       if (!tty_hung_up_p(filp))
-               port->count--;
-       sti();
-       port->blocked_open++;
-       while (1) {
-               cli();
-               sbus_writeb(port_No(port) & 7,
-                           &bp->r[chip]->r[CD180_CAR]);
-               udelay(1);
-               CD = sbus_readb(&bp->r[chip]->r[CD180_MSVR]) & MSVR_CD;
-               port->MSVR=bp->RTS;
-
-               /* auto drops DTR */
-               sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]);
-               sti();
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (tty_hung_up_p(filp) ||
-                   !(port->flags & ASYNC_INITIALIZED)) {
-                       if (port->flags & ASYNC_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;  
-                       break;
-               }
-               if (!(port->flags & ASYNC_CLOSING) &&
-                   (do_clocal || CD))
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               schedule();
-       }
-       current->state = TASK_RUNNING;
-       remove_wait_queue(&port->open_wait, &wait);
-       if (!tty_hung_up_p(filp))
-               port->count++;
-       port->blocked_open--;
-       if (retval)
-               return retval;
-       
-       port->flags |= ASYNC_NORMAL_ACTIVE;
-#ifdef AURORA_DEBUG
-       printk("block_til_ready: end\n");
-#endif
-       return 0;
-}      
-
-static int aurora_open(struct tty_struct * tty, struct file * filp)
-{
-       int board;
-       int error;
-       struct Aurora_port * port;
-       struct Aurora_board * bp;
-       unsigned long flags;
-       
-#ifdef AURORA_DEBUG
-       printk("aurora_open: start\n");
-#endif
-       
-       board = AURORA_BOARD(tty->index);
-       if (board > AURORA_NBOARD ||
-           !(aurora_board[board].flags & AURORA_BOARD_PRESENT)) {
-#ifdef AURORA_DEBUG
-               printk("aurora_open: error board %d present %d\n",
-                      board, aurora_board[board].flags & AURORA_BOARD_PRESENT);
-#endif
-               return -ENODEV;
-       }
-       
-       bp = &aurora_board[board];
-       port = aurora_port + board * AURORA_NPORT * AURORA_NCD180 + AURORA_PORT(tty->index);
-       if ((aurora_paranoia_check(port, tty->name, "aurora_open")) {
-#ifdef AURORA_DEBUG
-               printk("aurora_open: error paranoia check\n");
-#endif
-               return -ENODEV;
-       }
-       
-       port->count++;
-       tty->driver_data = port;
-       port->tty = tty;
-       
-       if ((error = aurora_setup_port(bp, port))) {
-#ifdef AURORA_DEBUG
-               printk("aurora_open: error aurora_setup_port ret %d\n",error);
-#endif
-               return error;
-       }
-
-       if ((error = block_til_ready(tty, filp, port))) {
-#ifdef AURORA_DEBUG
-               printk("aurora_open: error block_til_ready ret %d\n",error);
-#endif
-               return error;
-       }
-       
-#ifdef AURORA_DEBUG
-       printk("aurora_open: end\n");
-#endif
-       return 0;
-}
-
-static void aurora_close(struct tty_struct * tty, struct file * filp)
-{
-       struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-       struct Aurora_board *bp;
-       unsigned long flags;
-       unsigned long timeout;
-       unsigned char chip;
-       
-#ifdef AURORA_DEBUG
-       printk("aurora_close: start\n");
-#endif
-       
-       if (!port || (aurora_paranoia_check(port, tty->name, "close"))
-               return;
-       
-       chip = AURORA_CD180(port_No(port));
-
-       save_flags(flags); cli();
-       if (tty_hung_up_p(filp))  {
-               restore_flags(flags);
-               return;
-       }
-       
-       bp = port_Board(port);
-       if ((tty->count == 1) && (port->count != 1))  {
-               printk(KERN_DEBUG "aurora%d: aurora_close: bad port count; "
-                      "tty->count is 1, port count is %d\n",
-                      board_No(bp), port->count);
-               port->count = 1;
-       }
-       if (--port->count < 0)  {
-               printk(KERN_DEBUG "aurora%d: aurora_close: bad port "
-                      "count for tty%d: %d\n",
-                      board_No(bp), port_No(port), port->count);
-               port->count = 0;
-       }
-       if (port->count)  {
-               restore_flags(flags);
-               return;
-       }
-       port->flags |= ASYNC_CLOSING;
-
-       /* Now we wait for the transmit buffer to clear; and we notify 
-        * the line discipline to only process XON/XOFF characters.
-        */
-       tty->closing = 1;
-       if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE){
-#ifdef AURORA_DEBUG
-               printk("aurora_close: waiting to flush...\n");
-#endif
-               tty_wait_until_sent(tty, port->closing_wait);
-       }
-
-       /* At this point we stop accepting input.  To do this, we
-        * disable the receive line status interrupts, and tell the
-        * interrupt driver to stop checking the data ready bit in the
-        * line status register.
-        */
-       port->SRER &= ~SRER_RXD;
-       if (port->flags & ASYNC_INITIALIZED) {
-               port->SRER &= ~SRER_TXRDY;
-               port->SRER |= SRER_TXEMPTY;
-               sbus_writeb(port_No(port) & 7,
-                           &bp->r[chip]->r[CD180_CAR]);
-               udelay(1);
-               sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
-               /*
-                * Before we drop DTR, make sure the UART transmitter
-                * has completely drained; this is especially
-                * important if there is a transmit FIFO!
-                */
-               timeout = jiffies+HZ;
-               while(port->SRER & SRER_TXEMPTY)  {
-                       msleep_interruptible(jiffies_to_msecs(port->timeout));
-                       if (time_after(jiffies, timeout))
-                               break;
-               }
-       }
-#ifdef AURORA_DEBUG
-       printk("aurora_close: shutdown_port\n");
-#endif
-       aurora_shutdown_port(bp, port);
-       if (tty->driver->flush_buffer)
-               tty->driver->flush_buffer(tty);
-       tty_ldisc_flush(tty);
-       tty->closing = 0;
-       port->event = 0;
-       port->tty = 0;
-       if (port->blocked_open) {
-               if (port->close_delay) {
-                       msleep_interruptible(jiffies_to_msecs(port->close_delay));
-               }
-               wake_up_interruptible(&port->open_wait);
-       }
-       port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-       wake_up_interruptible(&port->close_wait);
-       restore_flags(flags);
-#ifdef AURORA_DEBUG
-       printk("aurora_close: end\n");
-#endif
-}
-
-static int aurora_write(struct tty_struct * tty, 
-                       const unsigned char *buf, int count)
-{
-       struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-       struct Aurora_board *bp;
-       int c, total = 0;
-       unsigned long flags;
-       unsigned char chip;
-
-#ifdef AURORA_DEBUG
-       printk("aurora_write: start %d\n",count);
-#endif
-       if ((aurora_paranoia_check(port, tty->name, "aurora_write"))
-               return 0;
-               
-       chip = AURORA_CD180(port_No(port));
-       
-       bp = port_Board(port);
-
-       if (!tty || !port->xmit_buf || !tmp_buf)
-               return 0;
-
-       save_flags(flags);
-       while (1) {
-               cli();
-               c = min(count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
-                                  SERIAL_XMIT_SIZE - port->xmit_head));
-               if (c <= 0) {
-                       restore_flags(flags);
-                       break;
-               }
-               memcpy(port->xmit_buf + port->xmit_head, buf, c);
-               port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
-               port->xmit_cnt += c;
-               restore_flags(flags);
-
-               buf += c;
-               count -= c;
-               total += c;
-       }
-
-       cli();
-       if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
-           !(port->SRER & SRER_TXRDY)) {
-               port->SRER |= SRER_TXRDY;
-               sbus_writeb(port_No(port) & 7,
-                           &bp->r[chip]->r[CD180_CAR]);
-               udelay(1);
-               sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
-       }
-       restore_flags(flags);
-#ifdef AURORA_DEBUG
-       printk("aurora_write: end %d\n",total);
-#endif
-       return total;
-}
-
-static void aurora_put_char(struct tty_struct * tty, unsigned char ch)
-{
-       struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-       unsigned long flags;
-
-#ifdef AURORA_DEBUG
-       printk("aurora_put_char: start %c\n",ch);
-#endif
-       if ((aurora_paranoia_check(port, tty->name, "aurora_put_char"))
-               return;
-
-       if (!tty || !port->xmit_buf)
-               return;
-
-       save_flags(flags); cli();
-       
-       if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
-               restore_flags(flags);
-               return;
-       }
-
-       port->xmit_buf[port->xmit_head++] = ch;
-       port->xmit_head &= SERIAL_XMIT_SIZE - 1;
-       port->xmit_cnt++;
-       restore_flags(flags);
-#ifdef AURORA_DEBUG
-       printk("aurora_put_char: end\n");
-#endif
-}
-
-static void aurora_flush_chars(struct tty_struct * tty)
-{
-       struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-       unsigned long flags;
-       unsigned char chip;
-
-/*#ifdef AURORA_DEBUG
-       printk("aurora_flush_chars: start\n");
-#endif*/
-       if ((aurora_paranoia_check(port, tty->name, "aurora_flush_chars"))
-               return;
-               
-       chip = AURORA_CD180(port_No(port));
-       
-       if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
-           !port->xmit_buf)
-               return;
-
-       save_flags(flags); cli();
-       port->SRER |= SRER_TXRDY;
-       sbus_writeb(port_No(port) & 7,
-                   &port_Board(port)->r[chip]->r[CD180_CAR]);
-       udelay(1);
-       sbus_writeb(port->SRER,
-                   &port_Board(port)->r[chip]->r[CD180_SRER]);
-       restore_flags(flags);
-/*#ifdef AURORA_DEBUG
-       printk("aurora_flush_chars: end\n");
-#endif*/
-}
-
-static int aurora_write_room(struct tty_struct * tty)
-{
-       struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-       int     ret;
-
-#ifdef AURORA_DEBUG
-       printk("aurora_write_room: start\n");
-#endif
-       if ((aurora_paranoia_check(port, tty->name, "aurora_write_room"))
-               return 0;
-
-       ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
-       if (ret < 0)
-               ret = 0;
-#ifdef AURORA_DEBUG
-       printk("aurora_write_room: end\n");
-#endif
-       return ret;
-}
-
-static int aurora_chars_in_buffer(struct tty_struct *tty)
-{
-       struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-                               
-       if ((aurora_paranoia_check(port, tty->name, "aurora_chars_in_buffer"))
-               return 0;
-       
-       return port->xmit_cnt;
-}
-
-static void aurora_flush_buffer(struct tty_struct *tty)
-{
-       struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-       unsigned long flags;
-
-#ifdef AURORA_DEBUG
-       printk("aurora_flush_buffer: start\n");
-#endif
-       if ((aurora_paranoia_check(port, tty->name, "aurora_flush_buffer"))
-               return;
-
-       save_flags(flags); cli();
-       port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
-       restore_flags(flags);
-       
-       tty_wakeup(tty);
-#ifdef AURORA_DEBUG
-       printk("aurora_flush_buffer: end\n");
-#endif
-}
-
-static int aurora_tiocmget(struct tty_struct *tty, struct file *file)
-{
-       struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-       struct Aurora_board * bp;
-       unsigned char status,chip;
-       unsigned int result;
-       unsigned long flags;
-
-#ifdef AURORA_DEBUG
-       printk("aurora_get_modem_info: start\n");
-#endif
-       if ((aurora_paranoia_check(port, tty->name, __FUNCTION__))
-               return -ENODEV;
-
-       chip = AURORA_CD180(port_No(port));
-
-       bp = port_Board(port);
-
-       save_flags(flags); cli();
-
-       sbus_writeb(port_No(port) & 7, &bp->r[chip]->r[CD180_CAR]);
-       udelay(1);
-
-       status = sbus_readb(&bp->r[chip]->r[CD180_MSVR]);
-       result = 0/*bp->r[chip]->r[AURORA_RI] & (1u << port_No(port)) ? 0 : TIOCM_RNG*/;
-
-       restore_flags(flags);
-
-       result |= ((status & bp->RTS) ? TIOCM_RTS : 0)
-               | ((status & bp->DTR) ? TIOCM_DTR : 0)
-               | ((status & MSVR_CD)  ? TIOCM_CAR : 0)
-               | ((status & MSVR_DSR) ? TIOCM_DSR : 0)
-               | ((status & MSVR_CTS) ? TIOCM_CTS : 0);
-
-#ifdef AURORA_DEBUG
-       printk("aurora_get_modem_info: end\n");
-#endif
-       return result;
-}
-
-static int aurora_tiocmset(struct tty_struct *tty, struct file *file,
-                          unsigned int set, unsigned int clear)
-{
-       struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-       unsigned int arg;
-       unsigned long flags;
-       struct Aurora_board *bp = port_Board(port);
-       unsigned char chip;
-
-#ifdef AURORA_DEBUG
-       printk("aurora_set_modem_info: start\n");
-#endif
-       if ((aurora_paranoia_check(port, tty->name, __FUNCTION__))
-               return -ENODEV;
-
-       chip = AURORA_CD180(port_No(port));
-
-       save_flags(flags); cli();
-       if (set & TIOCM_RTS)
-               port->MSVR |= bp->RTS;
-       if (set & TIOCM_DTR)
-               port->MSVR |= bp->DTR;
-       if (clear & TIOCM_RTS)
-               port->MSVR &= ~bp->RTS;
-       if (clear & TIOCM_DTR)
-               port->MSVR &= ~bp->DTR;
-
-       sbus_writeb(port_No(port) & 7, &bp->r[chip]->r[CD180_CAR]);
-       udelay(1);
-
-       sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]);
-
-       restore_flags(flags);
-#ifdef AURORA_DEBUG
-       printk("aurora_set_modem_info: end\n");
-#endif
-       return 0;
-}
-
-static void aurora_send_break(struct Aurora_port * port, unsigned long length)
-{
-       struct Aurora_board *bp = port_Board(port);
-       unsigned long flags;
-       unsigned char chip;
-       
-#ifdef AURORA_DEBUG
-       printk("aurora_send_break: start\n");
-#endif
-       chip = AURORA_CD180(port_No(port));
-       
-       save_flags(flags); cli();
-
-       port->break_length = AURORA_TPS / HZ * length;
-       port->COR2 |= COR2_ETC;
-       port->SRER  |= SRER_TXRDY;
-       sbus_writeb(port_No(port) & 7, &bp->r[chip]->r[CD180_CAR]);
-       udelay(1);
-
-       sbus_writeb(port->COR2, &bp->r[chip]->r[CD180_COR2]);
-       sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
-       aurora_wait_CCR(bp->r[chip]);
-
-       sbus_writeb(CCR_CORCHG2, &bp->r[chip]->r[CD180_CCR]);
-       aurora_wait_CCR(bp->r[chip]);
-
-       restore_flags(flags);
-#ifdef AURORA_DEBUG
-       printk("aurora_send_break: end\n");
-#endif
-}
-
-static int aurora_set_serial_info(struct Aurora_port * port,
-                                 struct serial_struct * newinfo)
-{
-       struct serial_struct tmp;
-       struct Aurora_board *bp = port_Board(port);
-       int change_speed;
-       unsigned long flags;
-
-#ifdef AURORA_DEBUG
-       printk("aurora_set_serial_info: start\n");
-#endif
-       if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
-               return -EFAULT;
-#if 0  
-       if ((tmp.irq != bp->irq) ||
-           (tmp.port != bp->base) ||
-           (tmp.type != PORT_CIRRUS) ||
-           (tmp.baud_base != (bp->oscfreq + CD180_TPC/2) / CD180_TPC) ||
-           (tmp.custom_divisor != 0) ||
-           (tmp.xmit_fifo_size != CD180_NFIFO) ||
-           (tmp.flags & ~AURORA_LEGAL_FLAGS))
-               return -EINVAL;
-#endif 
-       
-       change_speed = ((port->flags & ASYNC_SPD_MASK) !=
-                       (tmp.flags & ASYNC_SPD_MASK));
-       
-       if (!capable(CAP_SYS_ADMIN)) {
-               if ((tmp.close_delay != port->close_delay) ||
-                   (tmp.closing_wait != port->closing_wait) ||
-                   ((tmp.flags & ~ASYNC_USR_MASK) !=
-                    (port->flags & ~ASYNC_USR_MASK)))  
-                       return -EPERM;
-               port->flags = ((port->flags & ~ASYNC_USR_MASK) |
-                              (tmp.flags & ASYNC_USR_MASK));
-       } else  {
-               port->flags = ((port->flags & ~ASYNC_FLAGS) |
-                              (tmp.flags & ASYNC_FLAGS));
-               port->close_delay = tmp.close_delay;
-               port->closing_wait = tmp.closing_wait;
-       }
-       if (change_speed)  {
-               save_flags(flags); cli();
-               aurora_change_speed(bp, port);
-               restore_flags(flags);
-       }
-#ifdef AURORA_DEBUG
-       printk("aurora_set_serial_info: end\n");
-#endif
-       return 0;
-}
-
-extern int aurora_get_serial_info(struct Aurora_port * port,
-                                 struct serial_struct * retinfo)
-{
-       struct serial_struct tmp;
-       struct Aurora_board *bp = port_Board(port);
-       
-#ifdef AURORA_DEBUG
-       printk("aurora_get_serial_info: start\n");
-#endif
-       if (!access_ok(VERIFY_WRITE, (void *) retinfo, sizeof(tmp)))
-               return -EFAULT;
-       
-       memset(&tmp, 0, sizeof(tmp));
-       tmp.type = PORT_CIRRUS;
-       tmp.line = port - aurora_port;
-       tmp.port = 0;
-       tmp.irq  = bp->irq;
-       tmp.flags = port->flags;
-       tmp.baud_base = (bp->oscfreq + CD180_TPC/2) / CD180_TPC;
-       tmp.close_delay = port->close_delay * HZ/100;
-       tmp.closing_wait = port->closing_wait * HZ/100;
-       tmp.xmit_fifo_size = CD180_NFIFO;
-       copy_to_user(retinfo, &tmp, sizeof(tmp));
-#ifdef AURORA_DEBUG
-printk("aurora_get_serial_info: end\n");
-#endif
-       return 0;
-}
-
-static int aurora_ioctl(struct tty_struct * tty, struct file * filp, 
-                   unsigned int cmd, unsigned long arg)
-                   
-{
-       struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-       int retval;
-
-#ifdef AURORA_DEBUG
-       printk("aurora_ioctl: start\n");
-#endif
-       if ((aurora_paranoia_check(port, tty->name, "aurora_ioctl"))
-               return -ENODEV;
-       
-       switch (cmd) {
-       case TCSBRK:    /* SVID version: non-zero arg --> no break */
-               retval = tty_check_change(tty);
-               if (retval)
-                       return retval;
-               tty_wait_until_sent(tty, 0);
-               if (!arg)
-                       aurora_send_break(port, HZ/4);  /* 1/4 second */
-               return 0;
-       case TCSBRKP:   /* support for POSIX tcsendbreak() */
-               retval = tty_check_change(tty);
-               if (retval)
-                       return retval;
-               tty_wait_until_sent(tty, 0);
-               aurora_send_break(port, arg ? arg*(HZ/10) : HZ/4);
-               return 0;
-       case TIOCGSOFTCAR:
-               return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg);
-       case TIOCSSOFTCAR:
-               if (get_user(arg,(unsigned long *)arg))
-                       return -EFAULT;
-               tty->termios->c_cflag =
-                       ((tty->termios->c_cflag & ~CLOCAL) |
-                        (arg ? CLOCAL : 0));
-               return 0;
-       case TIOCGSERIAL:       
-               return aurora_get_serial_info(port, (struct serial_struct *) arg);
-       case TIOCSSERIAL:       
-               return aurora_set_serial_info(port, (struct serial_struct *) arg);
-       default:
-               return -ENOIOCTLCMD;
-       };
-#ifdef AURORA_DEBUG
-       printk("aurora_ioctl: end\n");
-#endif
-       return 0;
-}
-
-static void aurora_throttle(struct tty_struct * tty)
-{
-       struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-       struct Aurora_board *bp;
-       unsigned long flags;
-       unsigned char chip;
-
-#ifdef AURORA_DEBUG
-       printk("aurora_throttle: start\n");
-#endif
-       if ((aurora_paranoia_check(port, tty->name, "aurora_throttle"))
-               return;
-       
-       bp = port_Board(port);
-       chip = AURORA_CD180(port_No(port));
-       
-       save_flags(flags); cli();
-       port->MSVR &= ~bp->RTS;
-       sbus_writeb(port_No(port) & 7, &bp->r[chip]->r[CD180_CAR]);
-       udelay(1);
-       if (I_IXOFF(tty))  {
-               aurora_wait_CCR(bp->r[chip]);
-               sbus_writeb(CCR_SSCH2, &bp->r[chip]->r[CD180_CCR]);
-               aurora_wait_CCR(bp->r[chip]);
-       }
-       sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]);
-       restore_flags(flags);
-#ifdef AURORA_DEBUG
-       printk("aurora_throttle: end\n");
-#endif
-}
-
-static void aurora_unthrottle(struct tty_struct * tty)
-{
-       struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-       struct Aurora_board *bp;
-       unsigned long flags;
-       unsigned char chip;
-
-#ifdef AURORA_DEBUG
-       printk("aurora_unthrottle: start\n");
-#endif
-       if ((aurora_paranoia_check(port, tty->name, "aurora_unthrottle"))
-               return;
-       
-       bp = port_Board(port);
-       
-       chip = AURORA_CD180(port_No(port));
-       
-       save_flags(flags); cli();
-       port->MSVR |= bp->RTS;
-       sbus_writeb(port_No(port) & 7,
-                   &bp->r[chip]->r[CD180_CAR]);
-       udelay(1);
-       if (I_IXOFF(tty))  {
-               aurora_wait_CCR(bp->r[chip]);
-               sbus_writeb(CCR_SSCH1,
-                           &bp->r[chip]->r[CD180_CCR]);
-               aurora_wait_CCR(bp->r[chip]);
-       }
-       sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]);
-       restore_flags(flags);
-#ifdef AURORA_DEBUG
-       printk("aurora_unthrottle: end\n");
-#endif
-}
-
-static void aurora_stop(struct tty_struct * tty)
-{
-       struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-       struct Aurora_board *bp;
-       unsigned long flags;
-       unsigned char chip;
-
-#ifdef AURORA_DEBUG
-       printk("aurora_stop: start\n");
-#endif
-       if ((aurora_paranoia_check(port, tty->name, "aurora_stop"))
-               return;
-       
-       bp = port_Board(port);
-       
-       chip = AURORA_CD180(port_No(port));
-       
-       save_flags(flags); cli();
-       port->SRER &= ~SRER_TXRDY;
-       sbus_writeb(port_No(port) & 7,
-                   &bp->r[chip]->r[CD180_CAR]);
-       udelay(1);
-       sbus_writeb(port->SRER,
-                   &bp->r[chip]->r[CD180_SRER]);
-       restore_flags(flags);
-#ifdef AURORA_DEBUG
-       printk("aurora_stop: end\n");
-#endif
-}
-
-static void aurora_start(struct tty_struct * tty)
-{
-       struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-       struct Aurora_board *bp;
-       unsigned long flags;
-       unsigned char chip;
-
-#ifdef AURORA_DEBUG
-       printk("aurora_start: start\n");
-#endif
-       if ((aurora_paranoia_check(port, tty->name, "aurora_start"))
-               return;
-       
-       bp = port_Board(port);
-       
-       chip = AURORA_CD180(port_No(port));
-       
-       save_flags(flags); cli();
-       if (port->xmit_cnt && port->xmit_buf && !(port->SRER & SRER_TXRDY))  {
-               port->SRER |= SRER_TXRDY;
-               sbus_writeb(port_No(port) & 7,
-                           &bp->r[chip]->r[CD180_CAR]);
-               udelay(1);
-               sbus_writeb(port->SRER,
-                           &bp->r[chip]->r[CD180_SRER]);
-       }
-       restore_flags(flags);
-#ifdef AURORA_DEBUG
-       printk("aurora_start: end\n");
-#endif
-}
-
-/*
- * This routine is called from the scheduler tqueue when the interrupt
- * routine has signalled that a hangup has occurred.  The path of
- * hangup processing is:
- *
- *     serial interrupt routine -> (scheduler tqueue) ->
- *     do_aurora_hangup() -> tty->hangup() -> aurora_hangup()
- * 
- */
-static void do_aurora_hangup(void *private_)
-{
-       struct Aurora_port      *port = (struct Aurora_port *) private_;
-       struct tty_struct       *tty;
-
-#ifdef AURORA_DEBUG
-       printk("do_aurora_hangup: start\n");
-#endif
-       tty = port->tty;
-       if (tty != NULL) {
-               tty_hangup(tty);        /* FIXME: module removal race - AKPM */
-#ifdef AURORA_DEBUG
-               printk("do_aurora_hangup: end\n");
-#endif
-       }
-}
-
-static void aurora_hangup(struct tty_struct * tty)
-{
-       struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-       struct Aurora_board *bp;
-                               
-#ifdef AURORA_DEBUG
-       printk("aurora_hangup: start\n");
-#endif
-       if ((aurora_paranoia_check(port, tty->name, "aurora_hangup"))
-               return;
-       
-       bp = port_Board(port);
-       
-       aurora_shutdown_port(bp, port);
-       port->event = 0;
-       port->count = 0;
-       port->flags &= ~ASYNC_NORMAL_ACTIVE;
-       port->tty = 0;
-       wake_up_interruptible(&port->open_wait);
-#ifdef AURORA_DEBUG
-       printk("aurora_hangup: end\n");
-#endif
-}
-
-static void aurora_set_termios(struct tty_struct * tty, struct termios * old_termios)
-{
-       struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-       unsigned long flags;
-
-#ifdef AURORA_DEBUG
-       printk("aurora_set_termios: start\n");
-#endif
-       if ((aurora_paranoia_check(port, tty->name, "aurora_set_termios"))
-               return;
-       
-       if (tty->termios->c_cflag == old_termios->c_cflag &&
-           tty->termios->c_iflag == old_termios->c_iflag)
-               return;
-
-       save_flags(flags); cli();
-       aurora_change_speed(port_Board(port), port);
-       restore_flags(flags);
-
-       if ((old_termios->c_cflag & CRTSCTS) &&
-           !(tty->termios->c_cflag & CRTSCTS)) {
-               tty->hw_stopped = 0;
-               aurora_start(tty);
-       }
-#ifdef AURORA_DEBUG
-       printk("aurora_set_termios: end\n");
-#endif
-}
-
-static void do_aurora_bh(void)
-{
-        run_task_queue(&tq_aurora);
-}
-
-static void do_softint(void *private_)
-{
-       struct Aurora_port      *port = (struct Aurora_port *) private_;
-       struct tty_struct       *tty;
-
-#ifdef AURORA_DEBUG
-       printk("do_softint: start\n");
-#endif
-       tty = port->tty;
-       if (tty == NULL)
-               return;
-
-       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
-               tty_wakeup(tty);
-       }
-#ifdef AURORA_DEBUG
-       printk("do_softint: end\n");
-#endif
-}
-
-static const struct tty_operations aurora_ops = {
-       .open  = aurora_open,
-       .close = aurora_close,
-       .write = aurora_write,
-       .put_char = aurora_put_char,
-       .flush_chars = aurora_flush_chars,
-       .write_room = aurora_write_room,
-       .chars_in_buffer = aurora_chars_in_buffer,
-       .flush_buffer = aurora_flush_buffer,
-       .ioctl = aurora_ioctl,
-       .throttle = aurora_throttle,
-       .unthrottle = aurora_unthrottle,
-       .set_termios = aurora_set_termios,
-       .stop = aurora_stop,
-       .start = aurora_start,
-       .hangup = aurora_hangup,
-       .tiocmget = aurora_tiocmget,
-       .tiocmset = aurora_tiocmset,
-};
-
-static int aurora_init_drivers(void)
-{
-       int error;
-       int i;
-
-#ifdef AURORA_DEBUG
-       printk("aurora_init_drivers: start\n");
-#endif
-       tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
-       if (tmp_buf == NULL) {
-               printk(KERN_ERR "aurora: Couldn't get free page.\n");
-               return 1;
-       }
-       init_bh(AURORA_BH, do_aurora_bh);
-       aurora_driver = alloc_tty_driver(AURORA_INPORTS);
-       if (!aurora_driver) {
-               printk(KERN_ERR "aurora: Couldn't allocate tty driver.\n");
-               free_page((unsigned long) tmp_buf);
-               return 1;
-       }
-       aurora_driver->owner = THIS_MODULE;
-       aurora_driver->name = "ttyA";
-       aurora_driver->major = AURORA_MAJOR;
-       aurora_driver->type = TTY_DRIVER_TYPE_SERIAL;
-       aurora_driver->subtype = SERIAL_TYPE_NORMAL;
-       aurora_driver->init_termios = tty_std_termios;
-       aurora_driver->init_termios.c_cflag =
-               B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-       aurora_driver->flags = TTY_DRIVER_REAL_RAW;
-       tty_set_operations(aurora_driver, &aurora_ops);
-       error = tty_register_driver(aurora_driver);
-       if (error) {
-               put_tty_driver(aurora_driver);
-               free_page((unsigned long) tmp_buf);
-               printk(KERN_ERR "aurora: Couldn't register aurora driver, error = %d\n",
-                      error);
-               return 1;
-       }
-       
-       memset(aurora_port, 0, sizeof(aurora_port));
-       for (i = 0; i < AURORA_TNPORTS; i++)  {
-               aurora_port[i].magic = AURORA_MAGIC;
-               aurora_port[i].tqueue.routine = do_softint;
-               aurora_port[i].tqueue.data = &aurora_port[i];
-               aurora_port[i].tqueue_hangup.routine = do_aurora_hangup;
-               aurora_port[i].tqueue_hangup.data = &aurora_port[i];
-               aurora_port[i].close_delay = 50 * HZ/100;
-               aurora_port[i].closing_wait = 3000 * HZ/100;
-               init_waitqueue_head(&aurora_port[i].open_wait);
-               init_waitqueue_head(&aurora_port[i].close_wait);
-       }
-#ifdef AURORA_DEBUG
-       printk("aurora_init_drivers: end\n");
-#endif
-       return 0;
-}
-
-static void aurora_release_drivers(void)
-{
-#ifdef AURORA_DEBUG
-       printk("aurora_release_drivers: start\n");
-#endif
-       free_page((unsigned long)tmp_buf);
-       tty_unregister_driver(aurora_driver);
-       put_tty_driver(aurora_driver);
-#ifdef AURORA_DEBUG
-       printk("aurora_release_drivers: end\n");
-#endif
-}
-
-/*
- * Called at boot time.
- *
- * You can specify IO base for up to RC_NBOARD cards,
- * using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt.
- * Note that there will be no probing at default
- * addresses in this case.
- *
- */
-void __init aurora_setup(char *str, int *ints)
-{
-       int i;
-
-       for(i=0;(i<ints[0])&&(i<4);i++) {
-               if (ints[i+1]) irqs[i]=ints[i+1];
-               }
-}
-
-static int __init aurora_real_init(void)
-{
-       int found;
-       int i;
-
-       printk(KERN_INFO "aurora: Driver starting.\n");
-       if(aurora_init_drivers())
-               return -EIO;
-       found = aurora_probe();
-       if(!found) {
-               aurora_release_drivers();
-               printk(KERN_INFO "aurora: No Aurora Multiport boards detected.\n");
-               return -EIO;
-       } else {
-               printk(KERN_INFO "aurora: %d boards found.\n", found);
-       }
-       for (i = 0; i < found; i++) {
-               int ret = aurora_setup_board(&aurora_board[i]);
-
-               if (ret) {
-#ifdef AURORA_DEBUG
-                       printk(KERN_ERR "aurora_init: error aurora_setup_board ret %d\n",
-                              ret);
-#endif
-                       return ret;
-               }
-       }
-       return 0;
-}
-
-int irq  = 0;
-int irq1 = 0;
-int irq2 = 0;
-int irq3 = 0;
-module_param(irq , int, 0);
-module_param(irq1, int, 0);
-module_param(irq2, int, 0);
-module_param(irq3, int, 0);
-
-static int __init aurora_init(void) 
-{
-       if (irq ) irqs[0]=irq ;
-       if (irq1) irqs[1]=irq1;
-       if (irq2) irqs[2]=irq2;
-       if (irq3) irqs[3]=irq3;
-       return aurora_real_init();
-}
-       
-static void __exit aurora_cleanup(void)
-{
-       int i;
-       
-#ifdef AURORA_DEBUG
-printk("cleanup_module: aurora_release_drivers\n");
-#endif
-
-       aurora_release_drivers();
-       for (i = 0; i < AURORA_NBOARD; i++)
-               if (aurora_board[i].flags & AURORA_BOARD_PRESENT) {
-                       aurora_shutdown_board(&aurora_board[i]);
-                       aurora_release_io_range(&aurora_board[i]);
-               }
-}
-
-module_init(aurora_init);
-module_exit(aurora_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/drivers/sbus/char/aurora.h b/drivers/sbus/char/aurora.h
deleted file mode 100644 (file)
index b8b5476..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-/*     $Id: aurora.h,v 1.6 2001/06/05 12:23:38 davem Exp $
- *     linux/drivers/sbus/char/aurora.h -- Aurora multiport driver
- *
- *     Copyright (c) 1999 by Oliver Aldulea (oli@bv.ro)
- *
- *     This code is based on the RISCom/8 multiport serial driver written
- *     by Dmitry Gorodchanin (pgmdsg@ibi.com), based on the Linux serial
- *     driver, written by Linus Torvalds, Theodore T'so and others.
- *     The Aurora multiport programming info was obtained mainly from the
- *     Cirrus Logic CD180 documentation (available on the web), and by
- *     doing heavy tests on the board. Many thanks to Eddie C. Dost for the
- *     help on the sbus interface.
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the 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.
- *
- *     Revision 1.0
- *
- *     This is the first public release.
- *
- *     This version needs a lot of feedback. This is the version that works
- *     with _my_ board. My board is model 1600se, revision '@(#)1600se.fth
- *     1.2 3/28/95 1'. The driver might work with your board, but I do not
- *     guarantee it. If you have _any_ type of board, I need to know if the
- *     driver works or not, I need to know exactly your board parameters
- *     (get them with 'cd /proc/openprom/iommu/sbus/sio16/; ls *; cat *')
- *     Also, I need your board revision code, which is written on the board.
- *     Send me the output of my driver too (it outputs through klogd).
- *
- *     If the driver does not work, you can try enabling the debug options
- *     to see what's wrong or what should be done.
- *
- *     I'm sorry about the alignment of the code. It was written in a
- *     128x48 environment.
- *
- *     I must say that I do not like Aurora Technologies' policy. I asked
- *     them to help me do this driver faster, but they ended by something
- *     like "don't call us, we'll call you", and I never heard anything
- *     from them. They told me "knowing the way the board works, I don't
- *     doubt you and others on the net will make the driver."
- *     The truth about this board is that it has nothing intelligent on it.
- *     If you want to say to somebody what kind of board you have, say that
- *     it uses Cirrus Logic processors (CD180). The power of the board is
- *     in those two chips. The rest of the board is the interface to the
- *     sbus and to the peripherals. Still, they did something smart: they
- *     reversed DTR and RTS to make on-board automatic hardware flow
- *     control usable.
- *     Thanks to Aurora Technologies for wasting my time, nerves and money.
- */
-
-#ifndef __LINUX_AURORA_H
-#define __LINUX_AURORA_H
-
-#include <linux/serial.h>
-#include <linux/serialP.h>
-
-#ifdef __KERNEL__
-
-/* This is the number of boards to support. I've only tested this driver with
- * one board, so it might not work.
- */
-#define AURORA_NBOARD 1
-
-/* Useful ? Yes. But you can safely comment the warnings if they annoy you
- * (let me say that again: the warnings in the code, not this define). 
- */
-#define AURORA_PARANOIA_CHECK
-
-/* Well, after many lost nights, I found that the IRQ for this board is
- * selected from four built-in values by writing some bits in the
- * configuration register. This causes a little problem to occur: which
- * IRQ to select ? Which one is the best for the user ? Well, I finally
- * decided for the following algorithm: if the "bintr" value is not acceptable
- * (not within type_1_irq[], then test the "intr" value, if that fails too,
- * try each value from type_1_irq until succeded. Hope it's ok.
- * You can safely reorder the irq's.
- */
-#define TYPE_1_IRQS 4
-unsigned char type_1_irq[TYPE_1_IRQS] = {
-       3, 5, 9, 13
-};
-/* I know something about another method of interrupt setting, but not enough.
- * Also, this is for another type of board, so I first have to learn how to
- * detect it.
-#define TYPE_2_IRQS 3
-unsigned char type_2_irq[TYPE_2_IRQS] = {
-       0, 0, 0 ** could anyone find these for me ? (see AURORA_ALLIRQ below) **
-       };
-unsigned char type_2_mask[TYPE_2_IRQS] = {
-       32, 64, 128
-       };
-*/
-
-/* The following section should only be modified by those who know what
- * they're doing (or don't, but want to help with some feedback). Modifying
- * anything raises a _big_ probability for your system to hang, but the
- * sacrifice worths. (I sacrificed my ext2fs many, many times...)
- */
-
-/* This one tries to dump to console the name of almost every function called,
- * and many other debugging info.
- */
-#undef AURORA_DEBUG
-
-/* These are the most dangerous and useful defines. They do printk() during
- * the interrupt processing routine(s), so if you manage to get "flooded" by
- * irq's, start thinking about the "Power off/on" button...
- */
-#undef AURORA_INTNORM  /* This one enables the "normal" messages, but some
-                        * of them cause flood, so I preffered putting
-                        * them under a define */
-#undef AURORA_INT_DEBUG /* This one is really bad. */
-
-/* Here's something helpful: after n irq's, the board will be disabled. This
- * prevents irq flooding during debug (no need to think about power
- * off/on anymore...)
- */
-#define AURORA_FLOODPRO        10
-
-/* This one helps finding which irq the board calls, in case of a strange/
- * unsupported board. AURORA_INT_DEBUG should be enabled, because I don't
- * think /proc/interrupts or any command will be available in case of an irq
- * flood... "allirq" is the list of all free irq's.
- */
-/*
-#define AURORA_ALLIRQ 6
-int allirq[AURORA_ALLIRQ]={
-       2,3,5,7,9,13
-       };
-*/
-
-/* These must not be modified. These values are assumed during the code for
- * performance optimisations.
- */
-#define AURORA_NCD180 2 /* two chips per board */
-#define AURORA_NPORT 8  /* 8 ports per chip */
-
-/* several utilities */
-#define AURORA_BOARD(line)     (((line) >> 4) & 0x01)
-#define AURORA_CD180(line)     (((line) >> 3) & 0x01)
-#define AURORA_PORT(line)      ((line) & 15)
-
-#define AURORA_TNPORTS (AURORA_NBOARD*AURORA_NCD180*AURORA_NPORT)
-
-/* Ticks per sec. Used for setting receiver timeout and break length */
-#define AURORA_TPS             4000
-
-#define AURORA_MAGIC   0x0A18
-
-/* Yeah, after heavy testing I decided it must be 6.
- * Sure, You can change it if needed.
- */
-#define AURORA_RXFIFO          6       /* Max. receiver FIFO size (1-8) */
-
-#define AURORA_RXTH            7
-
-struct aurora_reg1 {
-       __volatile__ unsigned char r;
-};
-
-struct aurora_reg128 {
-       __volatile__ unsigned char r[128];
-};
-       
-struct aurora_reg4 {
-       __volatile__ unsigned char r[4];
-};
-
-struct Aurora_board {
-       unsigned long           flags;
-       struct aurora_reg1      * r0;   /* This is the board configuration
-                                        * register (write-only). */
-       struct aurora_reg128    * r[2]; /* These are the registers for the
-                                        * two chips. */
-       struct aurora_reg4      * r3;   /* These are used for hardware-based
-                                        * acknowledge. Software-based ack is
-                                        * not supported by CD180. */
-       unsigned int            oscfreq; /* The on-board oscillator
-                                         * frequency, in Hz. */
-       unsigned char           irq;
-#ifdef MODULE
-       signed char             count;  /* counts the use of the board */
-#endif
-       /* Values for the dtr_rts swapped mode. */
-       unsigned char           DTR;
-       unsigned char           RTS;
-       unsigned char           MSVDTR;
-       unsigned char           MSVRTS;
-       /* Values for hardware acknowledge. */
-       unsigned char           ACK_MINT, ACK_TINT, ACK_RINT;
-};
-
-/* Board configuration register */
-#define AURORA_CFG_ENABLE_IO   8
-#define AURORA_CFG_ENABLE_IRQ  4
-
-/* Board flags */
-#define AURORA_BOARD_PRESENT           0x00000001
-#define AURORA_BOARD_ACTIVE            0x00000002
-#define AURORA_BOARD_TYPE_2            0x00000004      /* don't know how to
-                                                        * detect this yet */
-#define AURORA_BOARD_DTR_FLOW_OK       0x00000008
-
-/* The story goes like this: Cirrus programmed the CD-180 chip to do automatic
- * hardware flow control, and do it using CTS and DTR. CTS is ok, but, if you
- * have a modem and the chip drops DTR, then the modem will drop the carrier
- * (ain't that cute...). Luckily, the guys at Aurora decided to swap DTR and
- * RTS, which makes the flow control usable. I hope that all the boards made
- * by Aurora have these two signals swapped. If your's doesn't but you have a
- * breakout box, you can try to reverse them yourself, then set the following
- * flag.
- */
-#undef AURORA_FORCE_DTR_FLOW
-
-/* In fact, a few more words have to be said about hardware flow control.
- * This driver handles "output" flow control through the on-board facility
- * CTS Auto Enable. For the "input" flow control there are two cases when
- * the flow should be controlled. The first case is when the kernel is so
- * busy that it cannot process IRQ's in time; this flow control can only be
- * activated by the on-board chip, and if the board has RTS and DTR swapped,
- * this facility is usable. The second case is when the application is so
- * busy that it cannot receive bytes from the kernel, and this flow must be
- * activated by software. This second case is not yet implemented in this
- * driver. Unfortunately, I estimate that the second case is the one that
- * occurs the most.
- */
-
-
-struct Aurora_port {
-       int                     magic;
-       int                     baud_base;
-       int                     flags;
-       struct tty_struct       * tty;
-       int                     count;
-       int                     blocked_open;
-       long                    event;
-       int                     timeout;
-       int                     close_delay;
-       unsigned char           * xmit_buf;
-       int                     custom_divisor;
-       int                     xmit_head;
-       int                     xmit_tail;
-       int                     xmit_cnt;
-       wait_queue_head_t       open_wait;
-       wait_queue_head_t       close_wait;
-       struct tq_struct        tqueue;
-       struct tq_struct        tqueue_hangup;
-       short                   wakeup_chars;
-       short                   break_length;
-       unsigned short          closing_wait;
-       unsigned char           mark_mask;
-       unsigned char           SRER;
-       unsigned char           MSVR;
-       unsigned char           COR2;
-#ifdef AURORA_REPORT_OVERRUN
-       unsigned long           overrun;
-#endif 
-#ifdef AURORA_REPORT_FIFO
-       unsigned long           hits[10];
-#endif
-};
-
-#endif
-#endif /*__LINUX_AURORA_H*/
-
index 22631f8..8410587 100644 (file)
@@ -187,19 +187,20 @@ static int wait_for_pin(struct bbc_i2c_bus *bp, u8 *status)
        bp->waiting = 1;
        add_wait_queue(&bp->wq, &wait);
        while (limit-- > 0) {
-               u8 val;
-
-               set_current_state(TASK_INTERRUPTIBLE);
-               *status = val = readb(bp->i2c_control_regs + 0);
-               if ((val & I2C_PCF_PIN) == 0) {
+               unsigned long val;
+
+               val = wait_event_interruptible_timeout(
+                               bp->wq,
+                               (((*status = readb(bp->i2c_control_regs + 0))
+                                 & I2C_PCF_PIN) == 0),
+                               msecs_to_jiffies(250));
+               if (val > 0) {
                        ret = 0;
                        break;
                }
-               msleep_interruptible(250);
        }
        remove_wait_queue(&bp->wq, &wait);
        bp->waiting = 0;
-       current->state = TASK_RUNNING;
 
        return ret;
 }
@@ -340,7 +341,7 @@ static irqreturn_t bbc_i2c_interrupt(int irq, void *dev_id)
         */
        if (bp->waiting &&
            !(readb(bp->i2c_control_regs + 0x0) & I2C_PCF_PIN))
-               wake_up(&bp->wq);
+               wake_up_interruptible(&bp->wq);
 
        return IRQ_HANDLED;
 }
diff --git a/drivers/sbus/char/cd180.h b/drivers/sbus/char/cd180.h
deleted file mode 100644 (file)
index 445b86c..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-
-/* Definitions for Cirrus Logic CL-CD180 8-port async mux chip */
-#define CD180_NCH       8       /* Total number of channels                */
-#define CD180_TPC       16      /* Ticks per character                     */
-#define CD180_NFIFO    8       /* TX FIFO size                            */
-
-/* Global registers */
-#define CD180_GFRCR    0x6b    /* Global Firmware Revision Code Register  */
-#define CD180_SRCR     0x66    /* Service Request Configuration Register  */
-#define CD180_PPRH     0x70    /* Prescaler Period Register High          */
-#define CD180_PPRL     0x71    /* Prescaler Period Register Low           */
-#define CD180_MSMR     0x61    /* Modem Service Match Register            */
-#define CD180_TSMR     0x62    /* Transmit Service Match Register         */
-#define CD180_RSMR     0x63    /* Receive Service Match Register          */
-#define CD180_GSVR     0x40    /* Global Service Vector Register          */
-#define CD180_SRSR     0x65    /* Service Request Status Register         */
-#define CD180_GSCR     0x41    /* Global Service Channel Register         */
-#define CD180_CAR      0x64    /* Channel Access Register                 */
-
-/* Indexed registers */
-#define CD180_RDCR     0x07    /* Receive Data Count Register             */
-#define CD180_RDR      0x78    /* Receiver Data Register                  */
-#define CD180_RCSR     0x7a    /* Receiver Character Status Register      */
-#define CD180_TDR      0x7b    /* Transmit Data Register                  */
-#define CD180_EOSRR    0x7f    /* End of Service Request Register         */
-
-/* Channel Registers */
-#define CD180_SRER      0x02    /* Service Request Enable Register         */
-#define CD180_CCR       0x01    /* Channel Command Register                */
-#define CD180_COR1      0x03    /* Channel Option Register 1               */
-#define CD180_COR2      0x04    /* Channel Option Register 2               */
-#define CD180_COR3      0x05    /* Channel Option Register 3               */
-#define CD180_CCSR      0x06    /* Channel Control Status Register         */
-#define CD180_RTPR      0x18    /* Receive Timeout Period Register         */
-#define CD180_RBPRH     0x31    /* Receive Bit Rate Period Register High  */
-#define CD180_RBPRL     0x32    /* Receive Bit Rate Period Register Low   */
-#define CD180_TBPRH     0x39    /* Transmit Bit Rate Period Register High */
-#define CD180_TBPRL     0x3a    /* Transmit Bit Rate Period Register Low  */
-#define CD180_SCHR1     0x09    /* Special Character Register 1            */
-#define CD180_SCHR2     0x0a    /* Special Character Register 2            */
-#define CD180_SCHR3     0x0b    /* Special Character Register 3            */
-#define CD180_SCHR4     0x0c    /* Special Character Register 4            */
-#define CD180_MCR       0x12    /* Modem Change Register                   */
-#define CD180_MCOR1     0x10    /* Modem Change Option 1 Register          */
-#define CD180_MCOR2     0x11    /* Modem Change Option 2 Register          */
-#define CD180_MSVR      0x28    /* Modem Signal Value Register             */
-#define CD180_MSVRTS    0x29    /* Modem Signal Value RTS                  */
-#define CD180_MSVDTR    0x2a    /* Modem Signal Value DTR                  */
-
-/* Global Interrupt Vector Register (R/W) */
-
-#define GSVR_ITMASK     0x07     /* Interrupt type mask                     */
-#define  GSVR_IT_MDM     0x01    /* Modem Signal Change Interrupt           */
-#define  GSVR_IT_TX      0x02    /* Transmit Data Interrupt                 */
-#define  GSVR_IT_RGD     0x03    /* Receive Good Data Interrupt             */
-#define  GSVR_IT_REXC    0x07    /* Receive Exception Interrupt             */
-
-
-/* Global Interrupt Channel Register (R/W) */
-#define GSCR_CHAN       0x1c    /* Channel Number Mask                     */
-#define GSCR_CHAN_OFF   2       /* Channel Number Offset                   */
-
-
-/* Channel Address Register (R/W) */
-
-#define CAR_CHAN        0x07    /* Channel Number Mask                     */
-
-
-/* Receive Character Status Register (R/O) */
-
-#define RCSR_TOUT       0x80    /* Rx Timeout                              */
-#define RCSR_SCDET      0x70    /* Special Character Detected Mask         */
-#define  RCSR_NO_SC      0x00   /* No Special Characters Detected          */
-#define  RCSR_SC_1       0x10   /* Special Char 1 (or 1 & 3) Detected      */
-#define  RCSR_SC_2       0x20   /* Special Char 2 (or 2 & 4) Detected      */
-#define  RCSR_SC_3       0x30   /* Special Char 3 Detected                 */
-#define  RCSR_SC_4       0x40   /* Special Char 4 Detected                 */
-#define RCSR_BREAK      0x08    /* Break has been detected                 */
-#define RCSR_PE         0x04    /* Parity Error                            */
-#define RCSR_FE         0x02    /* Frame Error                             */
-#define RCSR_OE         0x01    /* Overrun Error                           */
-
-
-/* Channel Command Register (R/W) (commands in groups can be OR-ed) */
-
-#define CCR_HARDRESET   0x81    /* Reset the chip                          */
-
-#define CCR_SOFTRESET   0x80    /* Soft Channel Reset                      */
-
-#define CCR_CORCHG1     0x42    /* Channel Option Register 1 Changed       */
-#define CCR_CORCHG2     0x44    /* Channel Option Register 2 Changed       */
-#define CCR_CORCHG3     0x48    /* Channel Option Register 3 Changed       */
-
-#define CCR_SSCH1       0x21    /* Send Special Character 1                */
-
-#define CCR_SSCH2       0x22    /* Send Special Character 2                */
-
-#define CCR_SSCH3       0x23    /* Send Special Character 3                */
-
-#define CCR_SSCH4       0x24    /* Send Special Character 4                */
-
-#define CCR_TXEN        0x18    /* Enable Transmitter                      */
-#define CCR_RXEN        0x12    /* Enable Receiver                         */
-
-#define CCR_TXDIS       0x14    /* Disable Transmitter                     */
-#define CCR_RXDIS       0x11    /* Disable Receiver                        */
-
-
-/* Service Request Enable Register (R/W) */
-
-#define SRER_DSR         0x80    /* Enable interrupt on DSR change          */
-#define SRER_CD          0x40    /* Enable interrupt on CD change           */
-#define SRER_CTS         0x20    /* Enable interrupt on CTS change          */
-#define SRER_RXD         0x10    /* Enable interrupt on Receive Data        */
-#define SRER_RXSC        0x08    /* Enable interrupt on Receive Spec. Char  */
-#define SRER_TXRDY       0x04    /* Enable interrupt on TX FIFO empty       */
-#define SRER_TXEMPTY     0x02    /* Enable interrupt on TX completely empty */
-#define SRER_RET         0x01    /* Enable interrupt on RX Exc. Timeout     */
-
-
-/* Channel Option Register 1 (R/W) */
-
-#define COR1_ODDP       0x80    /* Odd Parity                              */
-#define COR1_PARMODE    0x60    /* Parity Mode mask                        */
-#define  COR1_NOPAR      0x00   /* No Parity                               */
-#define  COR1_FORCEPAR   0x20   /* Force Parity                            */
-#define  COR1_NORMPAR    0x40   /* Normal Parity                           */
-#define COR1_IGNORE     0x10    /* Ignore Parity on RX                     */
-#define COR1_STOPBITS   0x0c    /* Number of Stop Bits                     */
-#define  COR1_1SB        0x00   /* 1 Stop Bit                              */
-#define  COR1_15SB       0x04   /* 1.5 Stop Bits                           */
-#define  COR1_2SB        0x08   /* 2 Stop Bits                             */
-#define COR1_CHARLEN    0x03    /* Character Length                        */
-#define  COR1_5BITS      0x00   /* 5 bits                                  */
-#define  COR1_6BITS      0x01   /* 6 bits                                  */
-#define  COR1_7BITS      0x02   /* 7 bits                                  */
-#define  COR1_8BITS      0x03   /* 8 bits                                  */
-
-
-/* Channel Option Register 2 (R/W) */
-
-#define COR2_IXM        0x80    /* Implied XON mode                        */
-#define COR2_TXIBE      0x40    /* Enable In-Band (XON/XOFF) Flow Control  */
-#define COR2_ETC        0x20    /* Embedded Tx Commands Enable             */
-#define COR2_LLM        0x10    /* Local Loopback Mode                     */
-#define COR2_RLM        0x08    /* Remote Loopback Mode                    */
-#define COR2_RTSAO      0x04    /* RTS Automatic Output Enable             */
-#define COR2_CTSAE      0x02    /* CTS Automatic Enable                    */
-#define COR2_DSRAE      0x01    /* DSR Automatic Enable                    */
-
-
-/* Channel Option Register 3 (R/W) */
-
-#define COR3_XONCH      0x80    /* XON is a pair of characters (1 & 3)     */
-#define COR3_XOFFCH     0x40    /* XOFF is a pair of characters (2 & 4)    */
-#define COR3_FCT        0x20    /* Flow-Control Transparency Mode          */
-#define COR3_SCDE       0x10    /* Special Character Detection Enable      */
-#define COR3_RXTH       0x0f    /* RX FIFO Threshold value (1-8)           */
-
-
-/* Channel Control Status Register (R/O) */
-
-#define CCSR_RXEN       0x80    /* Receiver Enabled                        */
-#define CCSR_RXFLOFF    0x40    /* Receive Flow Off (XOFF was sent)        */
-#define CCSR_RXFLON     0x20    /* Receive Flow On (XON was sent)          */
-#define CCSR_TXEN       0x08    /* Transmitter Enabled                     */
-#define CCSR_TXFLOFF    0x04    /* Transmit Flow Off (got XOFF)            */
-#define CCSR_TXFLON     0x02    /* Transmit Flow On (got XON)              */
-
-
-/* Modem Change Option Register 1 (R/W) */
-
-#define MCOR1_DSRZD     0x80    /* Detect 0->1 transition of DSR           */
-#define MCOR1_CDZD      0x40    /* Detect 0->1 transition of CD            */
-#define MCOR1_CTSZD     0x20    /* Detect 0->1 transition of CTS           */
-#define MCOR1_DTRTH     0x0f    /* Auto DTR flow control Threshold (1-8)   */
-#define  MCOR1_NODTRFC   0x0     /* Automatic DTR flow control disabled     */
-
-
-/* Modem Change Option Register 2 (R/W) */
-
-#define MCOR2_DSROD     0x80    /* Detect 1->0 transition of DSR           */
-#define MCOR2_CDOD      0x40    /* Detect 1->0 transition of CD            */
-#define MCOR2_CTSOD     0x20    /* Detect 1->0 transition of CTS           */
-
-
-/* Modem Change Register (R/W) */
-
-#define MCR_DSRCHG      0x80    /* DSR Changed                             */
-#define MCR_CDCHG       0x40    /* CD Changed                              */
-#define MCR_CTSCHG      0x20    /* CTS Changed                             */
-
-
-/* Modem Signal Value Register (R/W) */
-
-#define MSVR_DSR        0x80    /* Current state of DSR input              */
-#define MSVR_CD         0x40    /* Current state of CD input               */
-#define MSVR_CTS        0x20    /* Current state of CTS input              */
-#define MSVR_DTR        0x02    /* Current state of DTR output             */
-#define MSVR_RTS        0x01    /* Current state of RTS output             */
-
-
-/* Service Request Status Register */
-
-#define SRSR_CMASK     0xC0    /* Current Service Context Mask            */
-#define  SRSR_CNONE    0x00    /* Not in a service context                */
-#define  SRSR_CRX      0x40    /* Rx Context                              */
-#define  SRSR_CTX      0x80    /* Tx Context                              */
-#define  SRSR_CMDM     0xC0    /* Modem Context                           */
-#define SRSR_ANYINT    0x6F    /* Any interrupt flag                      */
-#define SRSR_RINT      0x10    /* Receive Interrupt                       */
-#define SRSR_TINT      0x04    /* Transmit Interrupt                      */
-#define SRSR_MINT      0x01    /* Modem Interrupt                         */
-#define SRSR_REXT      0x20    /* Receive External Interrupt              */
-#define SRSR_TEXT      0x08    /* Transmit External Interrupt             */
-#define SRSR_MEXT      0x02    /* Modem External Interrupt                */
-
-
-/* Service Request Configuration Register */
-
-#define SRCR_PKGTYPE    0x80
-#define SRCR_REGACKEN   0x40
-#define SRCR_DAISYEN    0x20
-#define SRCR_GLOBPRI    0x10
-#define SRCR_UNFAIR     0x08
-#define SRCR_AUTOPRI    0x02
-#define SRCR_PRISEL     0x01
-
-/* Values for register-based Interrupt ACKs */
-#define CD180_ACK_MINT 0x75    /* goes to MSMR                            */
-#define CD180_ACK_TINT 0x76    /* goes to TSMR                            */
-#define CD180_ACK_RINT 0x77    /* goes to RSMR                            */
-
-/* Escape characters */
-
-#define CD180_C_ESC     0x00    /* Escape character                        */
-#define CD180_C_SBRK    0x81    /* Start sending BREAK                     */
-#define CD180_C_DELAY   0x82    /* Delay output                            */
-#define CD180_C_EBRK    0x83    /* Stop sending BREAK                      */
index 45cf5bc..44d2ef9 100644 (file)
@@ -364,6 +364,7 @@ static int __init ts102_uctrl_init(void)
        struct linux_prom_irqs tmp_irq[2];
         unsigned int vaddr[2] = { 0, 0 };
        int tmpnode, uctrlnode = prom_getchild(prom_root_node);
+       int err;
 
        tmpnode = prom_searchsiblings(uctrlnode, "obio");
 
@@ -389,7 +390,12 @@ static int __init ts102_uctrl_init(void)
        if(!driver->irq) 
                driver->irq = tmp_irq[0].pri;
 
-       request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver);
+       err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver);
+       if (err) {
+               printk("%s: unable to register irq %d\n",
+                      __FUNCTION__, driver->irq);
+               return err;
+       }
 
        if (misc_register(&uctrl_dev)) {
                printk("%s: unable to get misc minor %d\n",
index 98ec861..c129a0e 100644 (file)
@@ -1196,7 +1196,7 @@ static void serial8250_enable_ms(struct uart_port *port)
 }
 
 static void
-receive_chars(struct uart_8250_port *up, int *status)
+receive_chars(struct uart_8250_port *up, unsigned int *status)
 {
        struct tty_struct *tty = up->port.info->tty;
        unsigned char ch, lsr = *status;
index ccb8fa1..8321101 100644 (file)
 
 #define MUX_NR 256
 static unsigned int port_cnt __read_mostly;
-static struct uart_port mux_ports[MUX_NR];
+struct mux_port {
+       struct uart_port port;
+       int enabled;
+};
+static struct mux_port mux_ports[MUX_NR];
 
 static struct uart_driver mux_driver = {
        .owner = THIS_MODULE,
@@ -66,7 +70,36 @@ static struct timer_list mux_timer;
 
 #define UART_PUT_CHAR(p, c) __raw_writel((c), (p)->membase + IO_DATA_REG_OFFSET)
 #define UART_GET_FIFO_CNT(p) __raw_readl((p)->membase + IO_DCOUNT_REG_OFFSET)
-#define GET_MUX_PORTS(iodc_data) ((((iodc_data)[4] & 0xf0) >> 4) * 8) + 8
+
+/**
+ * get_mux_port_count - Get the number of available ports on the Mux.
+ * @dev: The parisc device.
+ *
+ * This function is used to determine the number of ports the Mux
+ * supports.  The IODC data reports the number of ports the Mux
+ * can support, but there are cases where not all the Mux ports
+ * are connected.  This function can override the IODC and
+ * return the true port count.
+ */
+static int __init get_mux_port_count(struct parisc_device *dev)
+{
+       int status;
+       u8 iodc_data[32];
+       unsigned long bytecnt;
+
+       /* If this is the built-in Mux for the K-Class (Eole CAP/MUX),
+        * we only need to allocate resources for 1 port since the
+        * other 7 ports are not connected.
+        */
+       if(dev->id.hversion == 0x15)
+               return 1;
+
+       status = pdc_iodc_read(&bytecnt, dev->hpa.start, 0, iodc_data, 32);
+       BUG_ON(status != PDC_OK);
+
+       /* Return the number of ports specified in the iodc data. */
+       return ((((iodc_data)[4] & 0xf0) >> 4) * 8) + 8;
+}
 
 /**
  * mux_tx_empty - Check if the transmitter fifo is empty.
@@ -250,7 +283,7 @@ static void mux_read(struct uart_port *port)
  */
 static int mux_startup(struct uart_port *port)
 {
-       mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
+       mux_ports[port->line].enabled = 1;
        return 0;
 }
 
@@ -262,6 +295,7 @@ static int mux_startup(struct uart_port *port)
  */
 static void mux_shutdown(struct uart_port *port)
 {
+       mux_ports[port->line].enabled = 0;
 }
 
 /**
@@ -319,7 +353,7 @@ static int mux_request_port(struct uart_port *port)
  * @port: Ptr to the uart_port.
  * @type: Bitmask of required configurations.
  *
- * Perform any autoconfiguration steps for the port.  This functino is
+ * Perform any autoconfiguration steps for the port.  This function is
  * called if the UPF_BOOT_AUTOCONF flag is specified for the port.
  * [Note: This is required for now because of a bug in the Serial core.
  *  rmk has already submitted a patch to linus, should be available for
@@ -357,11 +391,11 @@ static void mux_poll(unsigned long unused)
        int i;
 
        for(i = 0; i < port_cnt; ++i) {
-               if(!mux_ports[i].info)
+               if(!mux_ports[i].enabled)
                        continue;
 
-               mux_read(&mux_ports[i]);
-               mux_write(&mux_ports[i]);
+               mux_read(&mux_ports[i].port);
+               mux_write(&mux_ports[i].port);
        }
 
        mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
@@ -371,8 +405,17 @@ static void mux_poll(unsigned long unused)
 #ifdef CONFIG_SERIAL_MUX_CONSOLE
 static void mux_console_write(struct console *co, const char *s, unsigned count)
 {
-        while(count--)
-                pdc_iodc_putc(*s++);
+       /* Wait until the FIFO drains. */
+       while(UART_GET_FIFO_CNT(&mux_ports[0].port))
+               udelay(1);
+
+       while(count--) {
+               if(*s == '\n') {
+                       UART_PUT_CHAR(&mux_ports[0].port, '\r');
+               }
+               UART_PUT_CHAR(&mux_ports[0].port, *s++);
+       }
+
 }
 
 static int mux_console_setup(struct console *co, char *options)
@@ -428,19 +471,14 @@ static struct uart_ops mux_pops = {
  */
 static int __init mux_probe(struct parisc_device *dev)
 {
-       int i, status, ports;
-       u8 iodc_data[32];
-       unsigned long bytecnt;
-       struct uart_port *port;
+       int i, status;
 
-       status = pdc_iodc_read(&bytecnt, dev->hpa.start, 0, iodc_data, 32);
-       if(status != PDC_OK) {
-               printk(KERN_ERR "Serial mux: Unable to read IODC.\n");
-               return 1;
-       }
+       int port_count = get_mux_port_count(dev);
+       printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.6\n", port_count);
 
-       ports = GET_MUX_PORTS(iodc_data);
-       printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.3\n", ports);
+       dev_set_drvdata(&dev->dev, (void *)(long)port_count);
+       request_mem_region(dev->hpa.start + MUX_OFFSET,
+                           port_count * MUX_LINE_OFFSET, "Mux");
 
        if(!port_cnt) {
                mux_driver.cons = MUX_CONSOLE;
@@ -450,13 +488,10 @@ static int __init mux_probe(struct parisc_device *dev)
                        printk(KERN_ERR "Serial mux: Unable to register driver.\n");
                        return 1;
                }
-
-               init_timer(&mux_timer);
-               mux_timer.function = mux_poll;
        }
 
-       for(i = 0; i < ports; ++i, ++port_cnt) {
-               port = &mux_ports[port_cnt];
+       for(i = 0; i < port_count; ++i, ++port_cnt) {
+               struct uart_port *port = &mux_ports[port_cnt].port;
                port->iobase    = 0;
                port->mapbase   = dev->hpa.start + MUX_OFFSET +
                                                (i * MUX_LINE_OFFSET);
@@ -477,27 +512,73 @@ static int __init mux_probe(struct parisc_device *dev)
                 */
                port->timeout   = HZ / 50;
                spin_lock_init(&port->lock);
+
                status = uart_add_one_port(&mux_driver, port);
                BUG_ON(status);
        }
 
-#ifdef CONFIG_SERIAL_MUX_CONSOLE
-        register_console(&mux_console);
-#endif
        return 0;
 }
 
+static int __devexit mux_remove(struct parisc_device *dev)
+{
+       int i, j;
+       int port_count = (long)dev_get_drvdata(&dev->dev);
+
+       /* Find Port 0 for this card in the mux_ports list. */
+       for(i = 0; i < port_cnt; ++i) {
+               if(mux_ports[i].port.mapbase == dev->hpa.start + MUX_OFFSET)
+                       break;
+       }
+       BUG_ON(i + port_count > port_cnt);
+
+       /* Release the resources associated with each port on the device. */
+       for(j = 0; j < port_count; ++j, ++i) {
+               struct uart_port *port = &mux_ports[i].port;
+
+               uart_remove_one_port(&mux_driver, port);
+               if(port->membase)
+                       iounmap(port->membase);
+       }
+
+       release_mem_region(dev->hpa.start + MUX_OFFSET, port_count * MUX_LINE_OFFSET);
+       return 0;
+}
+
+/* Hack.  This idea was taken from the 8250_gsc.c on how to properly order
+ * the serial port detection in the proper order.   The idea is we always
+ * want the builtin mux to be detected before addin mux cards, so we
+ * specifically probe for the builtin mux cards first.
+ *
+ * This table only contains the parisc_device_id of known builtin mux
+ * devices.  All other mux cards will be detected by the generic mux_tbl.
+ */
+static struct parisc_device_id builtin_mux_tbl[] = {
+       { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x15, 0x0000D }, /* All K-class */
+       { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x44, 0x0000D }, /* E35, E45, and E55 */
+       { 0, }
+};
+
 static struct parisc_device_id mux_tbl[] = {
        { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0000D },
        { 0, }
 };
 
+MODULE_DEVICE_TABLE(parisc, builtin_mux_tbl);
 MODULE_DEVICE_TABLE(parisc, mux_tbl);
 
+static struct parisc_driver builtin_serial_mux_driver = {
+       .name =         "builtin_serial_mux",
+       .id_table =     builtin_mux_tbl,
+       .probe =        mux_probe,
+       .remove =       __devexit_p(mux_remove),
+};
+
 static struct parisc_driver serial_mux_driver = {
        .name =         "serial_mux",
        .id_table =     mux_tbl,
        .probe =        mux_probe,
+       .remove =       __devexit_p(mux_remove),
 };
 
 /**
@@ -507,7 +588,21 @@ static struct parisc_driver serial_mux_driver = {
  */
 static int __init mux_init(void)
 {
-       return register_parisc_driver(&serial_mux_driver);
+       register_parisc_driver(&builtin_serial_mux_driver);
+       register_parisc_driver(&serial_mux_driver);
+
+       if(port_cnt > 0) {
+               /* Start the Mux timer */
+               init_timer(&mux_timer);
+               mux_timer.function = mux_poll;
+               mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
+
+#ifdef CONFIG_SERIAL_MUX_CONSOLE
+               register_console(&mux_console);
+#endif
+       }
+
+       return 0;
 }
 
 /**
@@ -517,14 +612,16 @@ static int __init mux_init(void)
  */
 static void __exit mux_exit(void)
 {
-       int i;
-
-       for (i = 0; i < port_cnt; i++) {
-               uart_remove_one_port(&mux_driver, &mux_ports[i]);
-               if (mux_ports[i].membase)
-                       iounmap(mux_ports[i].membase);
+       /* Delete the Mux timer. */
+       if(port_cnt > 0) {
+               del_timer(&mux_timer);
+#ifdef CONFIG_SERIAL_MUX_CONSOLE
+               unregister_console(&mux_console);
+#endif
        }
 
+       unregister_parisc_driver(&builtin_serial_mux_driver);
+       unregister_parisc_driver(&serial_mux_driver);
        uart_unregister_driver(&mux_driver);
 }
 
index f4440d3..509ace7 100644 (file)
@@ -38,6 +38,8 @@
  *             Fix some spin_locks.
  *             Do not call uart_add_one_port for absent ports.
  *     1.07    Use CONFIG_SERIAL_TXX9_NR_UARTS.  Cleanup.
+ *     1.08    Use platform_device.
+ *             Fix and cleanup suspend/resume/initialization codes.
  */
 
 #if defined(CONFIG_SERIAL_TXX9_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
@@ -50,7 +52,7 @@
 #include <linux/console.h>
 #include <linux/sysrq.h>
 #include <linux/delay.h>
-#include <linux/device.h>
+#include <linux/platform_device.h>
 #include <linux/pci.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
@@ -60,7 +62,7 @@
 
 #include <asm/io.h>
 
-static char *serial_version = "1.07";
+static char *serial_version = "1.08";
 static char *serial_name = "TX39/49 Serial driver";
 
 #define PASS_LIMIT     256
@@ -94,12 +96,7 @@ static char *serial_name = "TX39/49 Serial driver";
 
 struct uart_txx9_port {
        struct uart_port        port;
-
-       /*
-        * We provide a per-port pm hook.
-        */
-       void                    (*pm)(struct uart_port *port,
-                                     unsigned int state, unsigned int old);
+       /* No additional info for now */
 };
 
 #define TXX9_REGION_SIZE       0x24
@@ -277,6 +274,31 @@ static void serial_txx9_enable_ms(struct uart_port *port)
        /* TXX9-SIO can not control DTR... */
 }
 
+static void serial_txx9_initialize(struct uart_port *port)
+{
+       struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+       unsigned int tmout = 10000;
+
+       sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST);
+       /* TX4925 BUG WORKAROUND.  Accessing SIOC register
+        * immediately after soft reset causes bus error. */
+       mmiowb();
+       udelay(1);
+       while ((sio_in(up, TXX9_SIFCR) & TXX9_SIFCR_SWRST) && --tmout)
+               udelay(1);
+       /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */
+       sio_set(up, TXX9_SIFCR,
+               TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1);
+       /* initial settings */
+       sio_out(up, TXX9_SILCR,
+               TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT |
+               ((up->port.flags & UPF_TXX9_USE_SCLK) ?
+                TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG));
+       sio_quot_set(up, uart_get_divisor(port, 9600));
+       sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */);
+       sio_out(up, TXX9_SIDICR, 0);
+}
+
 static inline void
 receive_chars(struct uart_txx9_port *up, unsigned int *status)
 {
@@ -657,9 +679,8 @@ static void
 serial_txx9_pm(struct uart_port *port, unsigned int state,
              unsigned int oldstate)
 {
-       struct uart_txx9_port *up = (struct uart_txx9_port *)port;
-       if (up->pm)
-               up->pm(port, state, oldstate);
+       if (state == 0)
+               serial_txx9_initialize(port);
 }
 
 static int serial_txx9_request_resource(struct uart_txx9_port *up)
@@ -732,7 +753,6 @@ static int serial_txx9_request_port(struct uart_port *port)
 static void serial_txx9_config_port(struct uart_port *port, int uflags)
 {
        struct uart_txx9_port *up = (struct uart_txx9_port *)port;
-       unsigned long flags;
        int ret;
 
        /*
@@ -749,30 +769,7 @@ static void serial_txx9_config_port(struct uart_port *port, int uflags)
        if (up->port.line == up->port.cons->index)
                return;
 #endif
-       spin_lock_irqsave(&up->port.lock, flags);
-       /*
-        * Reset the UART.
-        */
-       sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST);
-#ifdef CONFIG_CPU_TX49XX
-       /* TX4925 BUG WORKAROUND.  Accessing SIOC register
-        * immediately after soft reset causes bus error. */
-       iob();
-       udelay(1);
-#endif
-       while (sio_in(up, TXX9_SIFCR) & TXX9_SIFCR_SWRST)
-               ;
-       /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */
-       sio_set(up, TXX9_SIFCR,
-               TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1);
-       /* initial settings */
-       sio_out(up, TXX9_SILCR,
-               TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT |
-               ((up->port.flags & UPF_TXX9_USE_SCLK) ?
-                TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG));
-       sio_quot_set(up, uart_get_divisor(port, 9600));
-       sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */);
-       spin_unlock_irqrestore(&up->port.lock, flags);
+       serial_txx9_initialize(port);
 }
 
 static int
@@ -818,7 +815,8 @@ static struct uart_ops serial_txx9_pops = {
 
 static struct uart_txx9_port serial_txx9_ports[UART_NR];
 
-static void __init serial_txx9_register_ports(struct uart_driver *drv)
+static void __init serial_txx9_register_ports(struct uart_driver *drv,
+                                             struct device *dev)
 {
        int i;
 
@@ -827,6 +825,7 @@ static void __init serial_txx9_register_ports(struct uart_driver *drv)
 
                up->port.line = i;
                up->port.ops = &serial_txx9_pops;
+               up->port.dev = dev;
                if (up->port.iobase || up->port.mapbase)
                        uart_add_one_port(drv, &up->port);
        }
@@ -898,7 +897,7 @@ serial_txx9_console_write(struct console *co, const char *s, unsigned int count)
        sio_out(up, TXX9_SIDICR, ier);
 }
 
-static int serial_txx9_console_setup(struct console *co, char *options)
+static int __init serial_txx9_console_setup(struct console *co, char *options)
 {
        struct uart_port *port;
        struct uart_txx9_port *up;
@@ -919,17 +918,7 @@ static int serial_txx9_console_setup(struct console *co, char *options)
        if (!port->ops)
                return -ENODEV;
 
-       /*
-        *      Disable UART interrupts, set DTR and RTS high
-        *      and set speed.
-        */
-       sio_out(up, TXX9_SIDICR, 0);
-       /* initial settings */
-       sio_out(up, TXX9_SILCR,
-               TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT |
-               ((port->flags & UPF_TXX9_USE_SCLK) ?
-                TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG));
-       sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */);
+       serial_txx9_initialize(&up->port);
 
        if (options)
                uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -981,31 +970,6 @@ int __init early_serial_txx9_setup(struct uart_port *port)
        return 0;
 }
 
-#ifdef ENABLE_SERIAL_TXX9_PCI
-#ifdef CONFIG_PM
-/**
- *     serial_txx9_suspend_port - suspend one serial port
- *     @line:  serial line number
- *
- *     Suspend one serial port.
- */
-static void serial_txx9_suspend_port(int line)
-{
-       uart_suspend_port(&serial_txx9_reg, &serial_txx9_ports[line].port);
-}
-
-/**
- *     serial_txx9_resume_port - resume one serial port
- *     @line:  serial line number
- *
- *     Resume one serial port.
- */
-static void serial_txx9_resume_port(int line)
-{
-       uart_resume_port(&serial_txx9_reg, &serial_txx9_ports[line].port);
-}
-#endif
-
 static DEFINE_MUTEX(serial_txx9_mutex);
 
 /**
@@ -1028,8 +992,18 @@ static int __devinit serial_txx9_register_port(struct uart_port *port)
        mutex_lock(&serial_txx9_mutex);
        for (i = 0; i < UART_NR; i++) {
                uart = &serial_txx9_ports[i];
-               if (!(uart->port.iobase || uart->port.mapbase))
+               if (uart_match_port(&uart->port, port)) {
+                       uart_remove_one_port(&serial_txx9_reg, &uart->port);
                        break;
+               }
+       }
+       if (i == UART_NR) {
+               /* Find unused port */
+               for (i = 0; i < UART_NR; i++) {
+                       uart = &serial_txx9_ports[i];
+                       if (!(uart->port.iobase || uart->port.mapbase))
+                               break;
+               }
        }
        if (i < UART_NR) {
                uart->port.iobase = port->iobase;
@@ -1072,6 +1046,95 @@ static void __devexit serial_txx9_unregister_port(int line)
 }
 
 /*
+ * Register a set of serial devices attached to a platform device.
+ */
+static int __devinit serial_txx9_probe(struct platform_device *dev)
+{
+       struct uart_port *p = dev->dev.platform_data;
+       struct uart_port port;
+       int ret, i;
+
+       memset(&port, 0, sizeof(struct uart_port));
+       for (i = 0; p && p->uartclk != 0; p++, i++) {
+               port.iobase     = p->iobase;
+               port.membase    = p->membase;
+               port.irq        = p->irq;
+               port.uartclk    = p->uartclk;
+               port.iotype     = p->iotype;
+               port.flags      = p->flags;
+               port.mapbase    = p->mapbase;
+               port.dev        = &dev->dev;
+               ret = serial_txx9_register_port(&port);
+               if (ret < 0) {
+                       dev_err(&dev->dev, "unable to register port at index %d "
+                               "(IO%x MEM%lx IRQ%d): %d\n", i,
+                               p->iobase, p->mapbase, p->irq, ret);
+               }
+       }
+       return 0;
+}
+
+/*
+ * Remove serial ports registered against a platform device.
+ */
+static int __devexit serial_txx9_remove(struct platform_device *dev)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_txx9_port *up = &serial_txx9_ports[i];
+
+               if (up->port.dev == &dev->dev)
+                       serial_txx9_unregister_port(i);
+       }
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int serial_txx9_suspend(struct platform_device *dev, pm_message_t state)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_txx9_port *up = &serial_txx9_ports[i];
+
+               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
+                       uart_suspend_port(&serial_txx9_reg, &up->port);
+       }
+
+       return 0;
+}
+
+static int serial_txx9_resume(struct platform_device *dev)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_txx9_port *up = &serial_txx9_ports[i];
+
+               if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
+                       uart_resume_port(&serial_txx9_reg, &up->port);
+       }
+
+       return 0;
+}
+#endif
+
+static struct platform_driver serial_txx9_plat_driver = {
+       .probe          = serial_txx9_probe,
+       .remove         = __devexit_p(serial_txx9_remove),
+#ifdef CONFIG_PM
+       .suspend        = serial_txx9_suspend,
+       .resume         = serial_txx9_resume,
+#endif
+       .driver         = {
+               .name   = "serial_txx9",
+               .owner  = THIS_MODULE,
+       },
+};
+
+#ifdef ENABLE_SERIAL_TXX9_PCI
+/*
  * Probe one serial board.  Unfortunately, there is no rhyme nor reason
  * to the arrangement of serial ports on a PCI card.
  */
@@ -1097,20 +1160,22 @@ pciserial_txx9_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
        line = serial_txx9_register_port(&port);
        if (line < 0) {
                printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), line);
+               pci_disable_device(dev);
+               return line;
        }
-       pci_set_drvdata(dev, (void *)(long)line);
+       pci_set_drvdata(dev, &serial_txx9_ports[line]);
 
        return 0;
 }
 
 static void __devexit pciserial_txx9_remove_one(struct pci_dev *dev)
 {
-       int line = (int)(long)pci_get_drvdata(dev);
+       struct uart_txx9_port *up = pci_get_drvdata(dev);
 
        pci_set_drvdata(dev, NULL);
 
-       if (line) {
-               serial_txx9_unregister_port(line);
+       if (up) {
+               serial_txx9_unregister_port(up->port.line);
                pci_disable_device(dev);
        }
 }
@@ -1118,10 +1183,10 @@ static void __devexit pciserial_txx9_remove_one(struct pci_dev *dev)
 #ifdef CONFIG_PM
 static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state)
 {
-       int line = (int)(long)pci_get_drvdata(dev);
+       struct uart_txx9_port *up = pci_get_drvdata(dev);
 
-       if (line)
-               serial_txx9_suspend_port(line);
+       if (up)
+               uart_suspend_port(&serial_txx9_reg, &up->port);
        pci_save_state(dev);
        pci_set_power_state(dev, pci_choose_state(dev, state));
        return 0;
@@ -1129,15 +1194,12 @@ static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state)
 
 static int pciserial_txx9_resume_one(struct pci_dev *dev)
 {
-       int line = (int)(long)pci_get_drvdata(dev);
+       struct uart_txx9_port *up = pci_get_drvdata(dev);
 
        pci_set_power_state(dev, PCI_D0);
        pci_restore_state(dev);
-
-       if (line) {
-               pci_enable_device(dev);
-               serial_txx9_resume_port(line);
-       }
+       if (up)
+               uart_resume_port(&serial_txx9_reg, &up->port);
        return 0;
 }
 #endif
@@ -1161,6 +1223,8 @@ static struct pci_driver serial_txx9_pci_driver = {
 MODULE_DEVICE_TABLE(pci, serial_txx9_pci_tbl);
 #endif /* ENABLE_SERIAL_TXX9_PCI */
 
+static struct platform_device *serial_txx9_plat_devs;
+
 static int __init serial_txx9_init(void)
 {
        int ret;
@@ -1168,13 +1232,39 @@ static int __init serial_txx9_init(void)
        printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
 
        ret = uart_register_driver(&serial_txx9_reg);
-       if (ret >= 0) {
-               serial_txx9_register_ports(&serial_txx9_reg);
+       if (ret)
+               goto out;
+
+       serial_txx9_plat_devs = platform_device_alloc("serial_txx9", -1);
+       if (!serial_txx9_plat_devs) {
+               ret = -ENOMEM;
+               goto unreg_uart_drv;
+       }
+
+       ret = platform_device_add(serial_txx9_plat_devs);
+       if (ret)
+               goto put_dev;
+
+       serial_txx9_register_ports(&serial_txx9_reg,
+                                  &serial_txx9_plat_devs->dev);
+
+       ret = platform_driver_register(&serial_txx9_plat_driver);
+       if (ret)
+               goto del_dev;
 
 #ifdef ENABLE_SERIAL_TXX9_PCI
-               ret = pci_register_driver(&serial_txx9_pci_driver);
+       ret = pci_register_driver(&serial_txx9_pci_driver);
 #endif
-       }
+       if (ret == 0)
+               goto out;
+
+ del_dev:
+       platform_device_del(serial_txx9_plat_devs);
+ put_dev:
+       platform_device_put(serial_txx9_plat_devs);
+ unreg_uart_drv:
+       uart_unregister_driver(&serial_txx9_reg);
+ out:
        return ret;
 }
 
@@ -1185,6 +1275,8 @@ static void __exit serial_txx9_exit(void)
 #ifdef ENABLE_SERIAL_TXX9_PCI
        pci_unregister_driver(&serial_txx9_pci_driver);
 #endif
+       platform_driver_unregister(&serial_txx9_plat_driver);
+       platform_device_unregister(serial_txx9_plat_devs);
        for (i = 0; i < UART_NR; i++) {
                struct uart_txx9_port *up = &serial_txx9_ports[i];
                if (up->port.iobase || up->port.mapbase)
index c2a9fef..6fa260d 100644 (file)
 #include <asm/arch/board.h>
 #include <asm/arch/gpio.h>
 
+#ifdef CONFIG_ARCH_AT91
+#include <asm/arch/cpu.h>
+#endif
+
 #include "atmel_spi.h"
 
 /*
@@ -491,7 +495,7 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
        return 0;
 }
 
-static void atmel_spi_cleanup(const struct spi_device *spi)
+static void atmel_spi_cleanup(struct spi_device *spi)
 {
        if (spi->controller_state)
                gpio_free((unsigned int)spi->controller_data);
index 366af49..96f62b2 100644 (file)
@@ -459,7 +459,7 @@ static int uwire_setup(struct spi_device *spi)
        return uwire_setup_transfer(spi, NULL);
 }
 
-static void uwire_cleanup(const struct spi_device *spi)
+static void uwire_cleanup(struct spi_device *spi)
 {
        kfree(spi->controller_state);
 }
index 6ccf8a1..51daa21 100644 (file)
@@ -1361,10 +1361,9 @@ err_first_setup:
        return status;
 }
 
-static void cleanup(const struct spi_device *spi)
+static void cleanup(struct spi_device *spi)
 {
-       struct chip_data *chip = spi_get_ctldata((struct spi_device *)spi);
-       kfree(chip);
+       kfree(spi_get_ctldata(spi));
 }
 
 static int init_queue(struct driver_data *drv_data)
index eda53ed..611ac22 100644 (file)
@@ -73,6 +73,19 @@ static u32 s3c2410_spigpio_txrx_mode1(struct spi_device *spi,
        return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
 }
 
+static u32 s3c2410_spigpio_txrx_mode2(struct spi_device *spi,
+                                     unsigned nsecs, u32 word, u8 bits)
+{
+       return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
+}
+
+static u32 s3c2410_spigpio_txrx_mode3(struct spi_device *spi,
+                                     unsigned nsecs, u32 word, u8 bits)
+{
+       return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
+}
+
+
 static void s3c2410_spigpio_chipselect(struct spi_device *dev, int value)
 {
        struct s3c2410_spigpio *sg = spidev_to_sg(dev);
@@ -108,6 +121,8 @@ static int s3c2410_spigpio_probe(struct platform_device *dev)
 
        sp->bitbang.txrx_word[SPI_MODE_0] = s3c2410_spigpio_txrx_mode0;
        sp->bitbang.txrx_word[SPI_MODE_1] = s3c2410_spigpio_txrx_mode1;
+       sp->bitbang.txrx_word[SPI_MODE_2] = s3c2410_spigpio_txrx_mode2;
+       sp->bitbang.txrx_word[SPI_MODE_3] = s3c2410_spigpio_txrx_mode3;
 
        /* set state of spi pins */
        s3c2410_gpio_setpin(sp->info->pin_clk, 0);
index 34e9bac..b607870 100644 (file)
@@ -4,7 +4,7 @@
 
 usbcore-objs   := usb.o hub.o hcd.o urb.o message.o driver.o \
                        config.o file.o buffer.o sysfs.o endpoint.o \
-                       devio.o notify.o generic.o
+                       devio.o notify.o generic.o quirks.o
 
 ifeq ($(CONFIG_PCI),y)
        usbcore-objs    += hcd-pci.o
index 2aded26..9e3e943 100644 (file)
@@ -366,19 +366,8 @@ void usb_driver_release_interface(struct usb_driver *driver,
 EXPORT_SYMBOL(usb_driver_release_interface);
 
 /* returns 0 if no match, 1 if match */
-int usb_match_one_id(struct usb_interface *interface,
-                    const struct usb_device_id *id)
+int usb_match_device(struct usb_device *dev, const struct usb_device_id *id)
 {
-       struct usb_host_interface *intf;
-       struct usb_device *dev;
-
-       /* proc_connectinfo in devio.c may call us with id == NULL. */
-       if (id == NULL)
-               return 0;
-
-       intf = interface->cur_altsetting;
-       dev = interface_to_usbdev(interface);
-
        if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
            id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
                return 0;
@@ -409,6 +398,26 @@ int usb_match_one_id(struct usb_interface *interface,
            (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
                return 0;
 
+       return 1;
+}
+
+/* returns 0 if no match, 1 if match */
+int usb_match_one_id(struct usb_interface *interface,
+                    const struct usb_device_id *id)
+{
+       struct usb_host_interface *intf;
+       struct usb_device *dev;
+
+       /* proc_connectinfo in devio.c may call us with id == NULL. */
+       if (id == NULL)
+               return 0;
+
+       intf = interface->cur_altsetting;
+       dev = interface_to_usbdev(interface);
+
+       if (!usb_match_device(dev, id))
+               return 0;
+
        /* The interface class, subclass, and protocol should never be
         * checked for a match if the device class is Vendor Specific,
         * unless the match record specifies the Vendor ID. */
@@ -954,12 +963,16 @@ static int autosuspend_check(struct usb_device *udev)
        int                     i;
        struct usb_interface    *intf;
 
-       /* For autosuspend, fail fast if anything is in use.
-        * Also fail if any interfaces require remote wakeup but it
-        * isn't available. */
+       /* For autosuspend, fail fast if anything is in use or autosuspend
+        * is disabled.  Also fail if any interfaces require remote wakeup
+        * but it isn't available.
+        */
        udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
        if (udev->pm_usage_cnt > 0)
                return -EBUSY;
+       if (!udev->autosuspend_delay)
+               return -EPERM;
+
        if (udev->actconfig) {
                for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
                        intf = udev->actconfig->interface[i];
@@ -982,7 +995,7 @@ static int autosuspend_check(struct usb_device *udev)
 
 #define autosuspend_check(udev)                0
 
-#endif
+#endif /* CONFIG_USB_SUSPEND */
 
 /**
  * usb_suspend_both - suspend a USB device and its interfaces
@@ -1177,7 +1190,7 @@ static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt)
                        udev->pm_usage_cnt -= inc_usage_cnt;
        } else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0)
                queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
-                               USB_AUTOSUSPEND_DELAY);
+                               udev->autosuspend_delay);
        usb_pm_unlock(udev);
        return status;
 }
@@ -1212,6 +1225,26 @@ void usb_autosuspend_device(struct usb_device *udev)
 }
 
 /**
+ * usb_try_autosuspend_device - attempt an autosuspend of a USB device and its interfaces
+ * @udev: the usb_device to autosuspend
+ *
+ * This routine should be called when a core subsystem thinks @udev may
+ * be ready to autosuspend.
+ *
+ * @udev's usage counter left unchanged.  If it or any of the usage counters
+ * for an active interface is greater than 0, or autosuspend is not allowed
+ * for any other reason, no autosuspend request will be queued.
+ *
+ * This routine can run only in process context.
+ */
+void usb_try_autosuspend_device(struct usb_device *udev)
+{
+       usb_autopm_do_device(udev, 0);
+       // dev_dbg(&udev->dev, "%s: cnt %d\n",
+       //              __FUNCTION__, udev->pm_usage_cnt);
+}
+
+/**
  * usb_autoresume_device - immediately autoresume a USB device and its interfaces
  * @udev: the usb_device to autoresume
  *
@@ -1261,7 +1294,7 @@ static int usb_autopm_do_interface(struct usb_interface *intf,
                                intf->pm_usage_cnt -= inc_usage_cnt;
                } else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0)
                        queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
-                                       USB_AUTOSUSPEND_DELAY);
+                                       udev->autosuspend_delay);
        }
        usb_pm_unlock(udev);
        return status;
index 50c0db1..4140074 100644 (file)
@@ -1287,6 +1287,9 @@ int usb_new_device(struct usb_device *udev)
        if (!try_module_get(THIS_MODULE))
                return -EINVAL;
 
+       /* Determine quirks */
+       usb_detect_quirks(udev);
+
        err = usb_get_configuration(udev);
        if (err < 0) {
                dev_err(&udev->dev, "can't read configurations, error %d\n",
index 74edaea..2f17468 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/timer.h>
 #include <linux/ctype.h>
 #include <linux/device.h>
+#include <linux/usb/quirks.h>
 #include <asm/byteorder.h>
 #include <asm/scatterlist.h>
 
@@ -685,7 +686,10 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid,
 
        /* Try to read the string descriptor by asking for the maximum
         * possible number of bytes */
-       rc = usb_get_string(dev, langid, index, buf, 255);
+       if (dev->quirks & USB_QUIRK_STRING_FETCH_255)
+               rc = -EIO;
+       else
+               rc = usb_get_string(dev, langid, index, buf, 255);
 
        /* If that failed try to read the descriptor length, then
         * ask for just that many bytes */
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
new file mode 100644 (file)
index 0000000..0e5c646
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * USB device quirk handling logic and table
+ *
+ * Copyright (c) 2007 Oliver Neukum
+ * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/usb/quirks.h>
+#include "usb.h"
+
+/* List of quirky USB devices.  Please keep this list ordered by:
+ *     1) Vendor ID
+ *     2) Product ID
+ *     3) Class ID
+ *
+ * as we want specific devices to be overridden first, and only after that, any
+ * class specific quirks.
+ *
+ * Right now the logic aborts if it finds a valid device in the table, we might
+ * want to change that in the future if it turns out that a whole class of
+ * devices is broken...
+ */
+static const struct usb_device_id usb_quirk_list[] = {
+       /* HP 5300/5370C scanner */
+       { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
+
+       /* Elsa MicroLink 56k (V.250) */
+       { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+
+       { }  /* terminating entry must be last */
+};
+
+static void usb_autosuspend_quirk(struct usb_device *udev)
+{
+#ifdef CONFIG_USB_SUSPEND
+       /* disable autosuspend, but allow the user to re-enable it via sysfs */
+       udev->autosuspend_delay = 0;
+#endif
+}
+
+static const struct usb_device_id *find_id(struct usb_device *udev)
+{
+       const struct usb_device_id *id = usb_quirk_list;
+
+       for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
+                       id->driver_info; id++) {
+               if (usb_match_device(udev, id))
+                       return id;
+       }
+       return NULL;
+}
+
+/*
+ * Detect any quirks the device has, and do any housekeeping for it if needed.
+ */
+void usb_detect_quirks(struct usb_device *udev)
+{
+       const struct usb_device_id *id = usb_quirk_list;
+
+       id = find_id(udev);
+       if (id)
+               udev->quirks = (u32)(id->driver_info);
+       if (udev->quirks)
+               dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
+                               udev->quirks);
+
+       /* do any special quirk handling here if needed */
+       if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND)
+               usb_autosuspend_quirk(udev);
+}
index 0edfbaf..311d5df 100644 (file)
@@ -148,6 +148,75 @@ show_maxchild(struct device *dev, struct device_attribute *attr, char *buf)
 }
 static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL);
 
+static ssize_t
+show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct usb_device *udev;
+
+       udev = to_usb_device(dev);
+       return sprintf(buf, "0x%x\n", udev->quirks);
+}
+static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
+
+#ifdef CONFIG_USB_SUSPEND
+
+static ssize_t
+show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct usb_device *udev = to_usb_device(dev);
+
+       return sprintf(buf, "%u\n", udev->autosuspend_delay / HZ);
+}
+
+static ssize_t
+set_autosuspend(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct usb_device *udev = to_usb_device(dev);
+       unsigned value, old;
+
+       if (sscanf(buf, "%u", &value) != 1 || value >= INT_MAX/HZ)
+               return -EINVAL;
+       value *= HZ;
+
+       old = udev->autosuspend_delay;
+       udev->autosuspend_delay = value;
+       if (value > 0 && old == 0)
+               usb_try_autosuspend_device(udev);
+
+       return count;
+}
+
+static DEVICE_ATTR(autosuspend, S_IRUGO | S_IWUSR,
+               show_autosuspend, set_autosuspend);
+
+static char power_group[] = "power";
+
+static int add_power_attributes(struct device *dev)
+{
+       int rc = 0;
+
+       if (is_usb_device(dev))
+               rc = sysfs_add_file_to_group(&dev->kobj,
+                               &dev_attr_autosuspend.attr,
+                               power_group);
+       return rc;
+}
+
+static void remove_power_attributes(struct device *dev)
+{
+       sysfs_remove_file_from_group(&dev->kobj,
+                       &dev_attr_autosuspend.attr,
+                       power_group);
+}
+
+#else
+
+#define add_power_attributes(dev)      0
+#define remove_power_attributes(dev)   do {} while (0)
+
+#endif /* CONFIG_USB_SUSPEND */
+
 /* Descriptor fields */
 #define usb_descriptor_attr_le16(field, format_string)                 \
 static ssize_t                                                         \
@@ -204,6 +273,7 @@ static struct attribute *dev_attrs[] = {
        &dev_attr_devnum.attr,
        &dev_attr_version.attr,
        &dev_attr_maxchild.attr,
+       &dev_attr_quirks.attr,
        NULL,
 };
 static struct attribute_group dev_attr_grp = {
@@ -219,6 +289,10 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
        if (retval)
                return retval;
 
+       retval = add_power_attributes(dev);
+       if (retval)
+               goto error;
+
        if (udev->manufacturer) {
                retval = device_create_file(dev, &dev_attr_manufacturer);
                if (retval)
@@ -239,10 +313,7 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
                goto error;
        return 0;
 error:
-       usb_remove_ep_files(&udev->ep0);
-       device_remove_file(dev, &dev_attr_manufacturer);
-       device_remove_file(dev, &dev_attr_product);
-       device_remove_file(dev, &dev_attr_serial);
+       usb_remove_sysfs_dev_files(udev);
        return retval;
 }
 
@@ -251,14 +322,11 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)
        struct device *dev = &udev->dev;
 
        usb_remove_ep_files(&udev->ep0);
+       device_remove_file(dev, &dev_attr_manufacturer);
+       device_remove_file(dev, &dev_attr_product);
+       device_remove_file(dev, &dev_attr_serial);
+       remove_power_attributes(dev);
        sysfs_remove_group(&dev->kobj, &dev_attr_grp);
-
-       if (udev->manufacturer)
-               device_remove_file(dev, &dev_attr_manufacturer);
-       if (udev->product)
-               device_remove_file(dev, &dev_attr_product);
-       if (udev->serial)
-               device_remove_file(dev, &dev_attr_serial);
 }
 
 /* Interface fields */
@@ -362,33 +430,28 @@ static inline void usb_remove_intf_ep_files(struct usb_interface *intf)
 
 int usb_create_sysfs_intf_files(struct usb_interface *intf)
 {
+       struct device *dev = &intf->dev;
        struct usb_device *udev = interface_to_usbdev(intf);
        struct usb_host_interface *alt = intf->cur_altsetting;
        int retval;
 
-       retval = sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
+       retval = sysfs_create_group(&dev->kobj, &intf_attr_grp);
        if (retval)
-               goto error;
+               return retval;
 
        if (alt->string == NULL)
                alt->string = usb_cache_string(udev, alt->desc.iInterface);
        if (alt->string)
-               retval = device_create_file(&intf->dev, &dev_attr_interface);
+               retval = device_create_file(dev, &dev_attr_interface);
        usb_create_intf_ep_files(intf, udev);
        return 0;
-error:
-       if (alt->string)
-               device_remove_file(&intf->dev, &dev_attr_interface);
-       sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
-       usb_remove_intf_ep_files(intf);
-       return retval;
 }
 
 void usb_remove_sysfs_intf_files(struct usb_interface *intf)
 {
-       usb_remove_intf_ep_files(intf);
-       sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
+       struct device *dev = &intf->dev;
 
-       if (intf->cur_altsetting->string)
-               device_remove_file(&intf->dev, &dev_attr_interface);
+       usb_remove_intf_ep_files(intf);
+       device_remove_file(dev, &dev_attr_interface);
+       sysfs_remove_group(&dev->kobj, &intf_attr_grp);
 }
index 3db721c..54b42ce 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/bitops.h>
 #include <linux/slab.h>
@@ -50,6 +51,16 @@ static int nousb;    /* Disable USB when built into kernel image */
 
 struct workqueue_struct *ksuspend_usb_wq;      /* For autosuspend */
 
+#ifdef CONFIG_USB_SUSPEND
+static int usb_autosuspend_delay = 2;          /* Default delay value,
+                                                * in seconds */
+module_param_named(autosuspend, usb_autosuspend_delay, uint, 0644);
+MODULE_PARM_DESC(autosuspend, "default autosuspend delay");
+
+#else
+#define usb_autosuspend_delay          0
+#endif
+
 
 /**
  * usb_ifnum_to_if - get the interface object with a given interface number
@@ -306,6 +317,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
 #ifdef CONFIG_PM
        mutex_init(&dev->pm_mutex);
        INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
+       dev->autosuspend_delay = usb_autosuspend_delay * HZ;
 #endif
        return dev;
 }
index 17830a8..08b5a04 100644 (file)
@@ -13,6 +13,7 @@ extern void usb_disable_interface (struct usb_device *dev,
                struct usb_interface *intf);
 extern void usb_release_interface_cache(struct kref *ref);
 extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
+extern void usb_detect_quirks(struct usb_device *udev);
 
 extern int usb_get_device_descriptor(struct usb_device *dev,
                unsigned int size);
@@ -21,6 +22,8 @@ extern int usb_set_configuration(struct usb_device *dev, int configuration);
 
 extern void usb_kick_khubd(struct usb_device *dev);
 extern void usb_resume_root_hub(struct usb_device *dev);
+extern int usb_match_device(struct usb_device *dev,
+                           const struct usb_device_id *id);
 
 extern int  usb_hub_init(void);
 extern void usb_hub_cleanup(void);
@@ -62,14 +65,14 @@ static inline void usb_pm_unlock(struct usb_device *udev) {}
 
 #ifdef CONFIG_USB_SUSPEND
 
-#define USB_AUTOSUSPEND_DELAY  (HZ*2)
-
 extern void usb_autosuspend_device(struct usb_device *udev);
+extern void usb_try_autosuspend_device(struct usb_device *udev);
 extern int usb_autoresume_device(struct usb_device *udev);
 
 #else
 
-#define usb_autosuspend_device(udev)   do {} while (0)
+#define usb_autosuspend_device(udev)           do {} while (0)
+#define usb_try_autosuspend_device(udev)       do {} while (0)
 static inline int usb_autoresume_device(struct usb_device *udev)
 {
        return 0;
index 34296e7..188c74a 100644 (file)
@@ -553,6 +553,7 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb)
 {
        struct kiocb_priv       *priv = iocb->private;
        ssize_t                 len, total;
+       void                    *to_copy;
        int                     i;
 
        /* we "retry" to get the right mm context for this: */
@@ -560,10 +561,11 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb)
        /* copy stuff into user buffers */
        total = priv->actual;
        len = 0;
+       to_copy = priv->buf;
        for (i=0; i < priv->nr_segs; i++) {
                ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
 
-               if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
+               if (copy_to_user(priv->iv[i].iov_base, to_copy, this)) {
                        if (len == 0)
                                len = -EFAULT;
                        break;
@@ -571,6 +573,7 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb)
 
                total -= this;
                len += this;
+               to_copy += this;
                if (total == 0)
                        break;
        }
index 5d6c06b..8d24d3d 100644 (file)
@@ -196,7 +196,7 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
                struct uhci_td *td = list_entry(urbp->td_list.next,
                                struct uhci_td, list);
 
-               if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS))
+               if (element != LINK_TO_TD(td))
                        out += sprintf(out, "%*s Element != First TD\n",
                                        space, "");
                i = nurbs = 0;
@@ -220,16 +220,6 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
        return out - buf;
 }
 
-static const char * const qh_names[] = {
-  "skel_unlink_qh", "skel_iso_qh",
-  "skel_int128_qh", "skel_int64_qh",
-  "skel_int32_qh", "skel_int16_qh",
-  "skel_int8_qh", "skel_int4_qh",
-  "skel_int2_qh", "skel_int1_qh",
-  "skel_ls_control_qh", "skel_fs_control_qh",
-  "skel_bulk_qh", "skel_term_qh"
-};
-
 static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
 {
        char *out = buf;
@@ -352,6 +342,12 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
        struct uhci_td *td;
        struct list_head *tmp, *head;
        int nframes, nerrs;
+       __le32 link;
+
+       static const char * const qh_names[] = {
+               "unlink", "iso", "int128", "int64", "int32", "int16",
+               "int8", "int4", "int2", "async", "term"
+       };
 
        out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
        out += sprintf(out, "HC status\n");
@@ -374,7 +370,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
        nframes = 10;
        nerrs = 0;
        for (i = 0; i < UHCI_NUMFRAMES; ++i) {
-               __le32 link, qh_dma;
+               __le32 qh_dma;
 
                j = 0;
                td = uhci->frame_cpu[i];
@@ -393,7 +389,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
                do {
                        td = list_entry(tmp, struct uhci_td, fl_list);
                        tmp = tmp->next;
-                       if (cpu_to_le32(td->dma_handle) != link) {
+                       if (link != LINK_TO_TD(td)) {
                                if (nframes > 0)
                                        out += sprintf(out, "    link does "
                                                "not match list entry!\n");
@@ -430,23 +426,21 @@ check_link:
 
        for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
                int cnt = 0;
+               __le32 fsbr_link = 0;
 
                qh = uhci->skelqh[i];
-               out += sprintf(out, "- %s\n", qh_names[i]); \
+               out += sprintf(out, "- skel_%s_qh\n", qh_names[i]); \
                out += uhci_show_qh(qh, out, len - (out - buf), 4);
 
                /* Last QH is the Terminating QH, it's different */
-               if (i == UHCI_NUM_SKELQH - 1) {
-                       if (qh->link != UHCI_PTR_TERM)
-                               out += sprintf(out, "    bandwidth reclamation on!\n");
-
-                       if (qh_element(qh) != cpu_to_le32(uhci->term_td->dma_handle))
+               if (i == SKEL_TERM) {
+                       if (qh_element(qh) != LINK_TO_TD(uhci->term_td))
                                out += sprintf(out, "    skel_term_qh element is not set to term_td!\n");
-
+                       if (link == LINK_TO_QH(uhci->skel_term_qh))
+                               goto check_qh_link;
                        continue;
                }
 
-               j = (i < 9) ? 9 : i+1;          /* Next skeleton */
                head = &qh->node;
                tmp = head->next;
 
@@ -456,15 +450,26 @@ check_link:
                        if (++cnt <= 10)
                                out += uhci_show_qh(qh, out,
                                                len - (out - buf), 4);
+                       if (!fsbr_link && qh->skel >= SKEL_FSBR)
+                               fsbr_link = LINK_TO_QH(qh);
                }
                if ((cnt -= 10) > 0)
                        out += sprintf(out, "    Skipped %d QHs\n", cnt);
 
-               if (i > 1 && i < UHCI_NUM_SKELQH - 1) {
-                       if (qh->link !=
-                           (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH))
-                               out += sprintf(out, "    last QH not linked to next skeleton!\n");
-               }
+               link = UHCI_PTR_TERM;
+               if (i <= SKEL_ISO)
+                       ;
+               else if (i < SKEL_ASYNC)
+                       link = LINK_TO_QH(uhci->skel_async_qh);
+               else if (!uhci->fsbr_is_on)
+                       ;
+               else if (fsbr_link)
+                       link = fsbr_link;
+               else
+                       link = LINK_TO_QH(uhci->skel_term_qh);
+check_qh_link:
+               if (qh->link != link)
+                       out += sprintf(out, "    last QH not linked to next skeleton!\n");
        }
 
        return out - buf;
index ded4df3..44da433 100644 (file)
@@ -13,7 +13,7 @@
  * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
  *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
  * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
- * (C) Copyright 2004-2006 Alan Stern, stern@rowland.harvard.edu
+ * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu
  *
  * Intel documents this fairly well, and as far as I know there
  * are no royalties or anything like that, but even so there are
@@ -107,16 +107,16 @@ static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
         * interrupt QHs, which will help spread out bandwidth utilization.
         *
         * ffs (Find First bit Set) does exactly what we need:
-        * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[8],
-        * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
+        * 1,3,5,...  => ffs = 0 => use period-2 QH = skelqh[8],
+        * 2,6,10,... => ffs = 1 => use period-4 QH = skelqh[7], etc.
         * ffs >= 7 => not on any high-period queue, so use
-        *      skel_int1_qh = skelqh[9].
+        *      period-1 QH = skelqh[9].
         * Add in UHCI_NUMFRAMES to insure at least one bit is set.
         */
        skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES);
        if (skelnum <= 1)
                skelnum = 9;
-       return UHCI_PTR_QH | cpu_to_le32(uhci->skelqh[skelnum]->dma_handle);
+       return LINK_TO_QH(uhci->skelqh[skelnum]);
 }
 
 #include "uhci-debug.c"
@@ -540,16 +540,18 @@ static void uhci_shutdown(struct pci_dev *pdev)
  *
  * The hardware doesn't really know any difference
  * in the queues, but the order does matter for the
- * protocols higher up. The order is:
+ * protocols higher up.  The order in which the queues
+ * are encountered by the hardware is:
  *
- *  - any isochronous events handled before any
+ *  - All isochronous events are handled before any
  *    of the queues. We don't do that here, because
  *    we'll create the actual TD entries on demand.
- *  - The first queue is the interrupt queue.
- *  - The second queue is the control queue, split into low- and full-speed
- *  - The third queue is bulk queue.
- *  - The fourth queue is the bandwidth reclamation queue, which loops back
- *    to the full-speed control queue.
+ *  - The first queue is the high-period interrupt queue.
+ *  - The second queue is the period-1 interrupt and async
+ *    (low-speed control, full-speed control, then bulk) queue.
+ *  - The third queue is the terminating bandwidth reclamation queue,
+ *    which contains no members, loops back to itself, and is present
+ *    only when FSBR is on and there are no full-speed control or bulk QHs.
  */
 static int uhci_start(struct usb_hcd *hcd)
 {
@@ -626,34 +628,18 @@ static int uhci_start(struct usb_hcd *hcd)
        }
 
        /*
-        * 8 Interrupt queues; link all higher int queues to int1,
-        * then link int1 to control and control to bulk
+        * 8 Interrupt queues; link all higher int queues to int1 = async
         */
-       uhci->skel_int128_qh->link =
-                       uhci->skel_int64_qh->link =
-                       uhci->skel_int32_qh->link =
-                       uhci->skel_int16_qh->link =
-                       uhci->skel_int8_qh->link =
-                       uhci->skel_int4_qh->link =
-                       uhci->skel_int2_qh->link = UHCI_PTR_QH |
-                       cpu_to_le32(uhci->skel_int1_qh->dma_handle);
-
-       uhci->skel_int1_qh->link = UHCI_PTR_QH |
-                       cpu_to_le32(uhci->skel_ls_control_qh->dma_handle);
-       uhci->skel_ls_control_qh->link = UHCI_PTR_QH |
-                       cpu_to_le32(uhci->skel_fs_control_qh->dma_handle);
-       uhci->skel_fs_control_qh->link = UHCI_PTR_QH |
-                       cpu_to_le32(uhci->skel_bulk_qh->dma_handle);
-       uhci->skel_bulk_qh->link = UHCI_PTR_QH |
-                       cpu_to_le32(uhci->skel_term_qh->dma_handle);
+       for (i = SKEL_ISO + 1; i < SKEL_ASYNC; ++i)
+               uhci->skelqh[i]->link = LINK_TO_QH(uhci->skel_async_qh);
+       uhci->skel_async_qh->link = uhci->skel_term_qh->link = UHCI_PTR_TERM;
 
        /* This dummy TD is to work around a bug in Intel PIIX controllers */
        uhci_fill_td(uhci->term_td, 0, uhci_explen(0) |
-               (0x7f << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_IN, 0);
-       uhci->term_td->link = cpu_to_le32(uhci->term_td->dma_handle);
-
-       uhci->skel_term_qh->link = UHCI_PTR_TERM;
-       uhci->skel_term_qh->element = cpu_to_le32(uhci->term_td->dma_handle);
+                       (0x7f << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_IN, 0);
+       uhci->term_td->link = UHCI_PTR_TERM;
+       uhci->skel_async_qh->element = uhci->skel_term_qh->element =
+                       LINK_TO_TD(uhci->term_td);
 
        /*
         * Fill the frame list: make all entries point to the proper
index 74469b5..1b3d234 100644 (file)
@@ -129,11 +129,12 @@ struct uhci_qh {
        __le32 element;                 /* Queue element (TD) pointer */
 
        /* Software fields */
+       dma_addr_t dma_handle;
+
        struct list_head node;          /* Node in the list of QHs */
        struct usb_host_endpoint *hep;  /* Endpoint information */
        struct usb_device *udev;
        struct list_head queue;         /* Queue of urbps for this QH */
-       struct uhci_qh *skel;           /* Skeleton for this QH */
        struct uhci_td *dummy_td;       /* Dummy TD to end the queue */
        struct uhci_td *post_td;        /* Last TD completed */
 
@@ -149,8 +150,7 @@ struct uhci_qh {
 
        int state;                      /* QH_STATE_xxx; see above */
        int type;                       /* Queue type (control, bulk, etc) */
-
-       dma_addr_t dma_handle;
+       int skel;                       /* Skeleton queue number */
 
        unsigned int initial_toggle:1;  /* Endpoint's current toggle value */
        unsigned int needs_fixup:1;     /* Must fix the TD toggle values */
@@ -171,6 +171,8 @@ static inline __le32 qh_element(struct uhci_qh *qh) {
        return element;
 }
 
+#define LINK_TO_QH(qh)         (UHCI_PTR_QH | cpu_to_le32((qh)->dma_handle))
+
 
 /*
  *     Transfer Descriptors
@@ -264,6 +266,8 @@ static inline u32 td_status(struct uhci_td *td) {
        return le32_to_cpu(status);
 }
 
+#define LINK_TO_TD(td)         (cpu_to_le32((td)->dma_handle))
+
 
 /*
  *     Skeleton Queue Headers
@@ -272,12 +276,13 @@ static inline u32 td_status(struct uhci_td *td) {
 /*
  * The UHCI driver uses QHs with Interrupt, Control and Bulk URBs for
  * automatic queuing. To make it easy to insert entries into the schedule,
- * we have a skeleton of QHs for each predefined Interrupt latency,
- * low-speed control, full-speed control, bulk, and terminating QH
- * (see explanation for the terminating QH below).
+ * we have a skeleton of QHs for each predefined Interrupt latency.
+ * Asynchronous QHs (low-speed control, full-speed control, and bulk)
+ * go onto the period-1 interrupt list, since they all get accessed on
+ * every frame.
  *
- * When we want to add a new QH, we add it to the end of the list for the
- * skeleton QH.  For instance, the schedule list can look like this:
+ * When we want to add a new QH, we add it to the list starting from the
+ * appropriate skeleton QH.  For instance, the schedule can look like this:
  *
  * skel int128 QH
  * dev 1 interrupt QH
@@ -285,50 +290,47 @@ static inline u32 td_status(struct uhci_td *td) {
  * skel int64 QH
  * skel int32 QH
  * ...
- * skel int1 QH
- * skel low-speed control QH
- * dev 5 control QH
- * skel full-speed control QH
- * skel bulk QH
+ * skel int1 + async QH
+ * dev 5 low-speed control QH
  * dev 1 bulk QH
  * dev 2 bulk QH
- * skel terminating QH
  *
- * The terminating QH is used for 2 reasons:
- * - To place a terminating TD which is used to workaround a PIIX bug
- *   (see Intel errata for explanation), and
- * - To loop back to the full-speed control queue for full-speed bandwidth
- *   reclamation.
+ * There is a special terminating QH used to keep full-speed bandwidth
+ * reclamation active when no full-speed control or bulk QHs are linked
+ * into the schedule.  It has an inactive TD (to work around a PIIX bug,
+ * see the Intel errata) and it points back to itself.
  *
- * There's a special skeleton QH for Isochronous QHs.  It never appears
- * on the schedule, and Isochronous TDs go on the schedule before the
+ * There's a special skeleton QH for Isochronous QHs which never appears
+ * on the schedule Isochronous TDs go on the schedule before the
  * the skeleton QHs.  The hardware accesses them directly rather than
  * through their QH, which is used only for bookkeeping purposes.
  * While the UHCI spec doesn't forbid the use of QHs for Isochronous,
  * it doesn't use them either.  And the spec says that queues never
  * advance on an error completion status, which makes them totally
  * unsuitable for Isochronous transfers.
+ *
+ * There's also a special skeleton QH used for QHs which are in the process
+ * of unlinking and so may still be in use by the hardware.  It too never
+ * appears on the schedule.
  */
 
-#define UHCI_NUM_SKELQH                14
-#define skel_unlink_qh         skelqh[0]
-#define skel_iso_qh            skelqh[1]
-#define skel_int128_qh         skelqh[2]
-#define skel_int64_qh          skelqh[3]
-#define skel_int32_qh          skelqh[4]
-#define skel_int16_qh          skelqh[5]
-#define skel_int8_qh           skelqh[6]
-#define skel_int4_qh           skelqh[7]
-#define skel_int2_qh           skelqh[8]
-#define skel_int1_qh           skelqh[9]
-#define skel_ls_control_qh     skelqh[10]
-#define skel_fs_control_qh     skelqh[11]
-#define skel_bulk_qh           skelqh[12]
-#define skel_term_qh           skelqh[13]
-
-/* Find the skelqh entry corresponding to an interval exponent */
-#define UHCI_SKEL_INDEX(exponent)      (9 - exponent)
-
+#define UHCI_NUM_SKELQH                11
+#define SKEL_UNLINK            0
+#define skel_unlink_qh         skelqh[SKEL_UNLINK]
+#define SKEL_ISO               1
+#define skel_iso_qh            skelqh[SKEL_ISO]
+       /* int128, int64, ..., int1 = 2, 3, ..., 9 */
+#define SKEL_INDEX(exponent)   (9 - exponent)
+#define SKEL_ASYNC             9
+#define skel_async_qh          skelqh[SKEL_ASYNC]
+#define SKEL_TERM              10
+#define skel_term_qh           skelqh[SKEL_TERM]
+
+/* The following entries refer to sublists of skel_async_qh */
+#define SKEL_LS_CONTROL                20
+#define SKEL_FS_CONTROL                21
+#define SKEL_FSBR              SKEL_FS_CONTROL
+#define SKEL_BULK              22
 
 /*
  *     The UHCI controller and root hub
index 68e66b3..f4ebdb3 100644 (file)
@@ -13,7 +13,7 @@
  * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
  *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
  * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
- * (C) Copyright 2004-2006 Alan Stern, stern@rowland.harvard.edu
+ * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu
  */
 
 
@@ -45,15 +45,43 @@ static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
  */
 static void uhci_fsbr_on(struct uhci_hcd *uhci)
 {
+       struct uhci_qh *fsbr_qh, *lqh, *tqh;
+
        uhci->fsbr_is_on = 1;
-       uhci->skel_term_qh->link = cpu_to_le32(
-                       uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;
+       lqh = list_entry(uhci->skel_async_qh->node.prev,
+                       struct uhci_qh, node);
+
+       /* Find the first FSBR QH.  Linear search through the list is
+        * acceptable because normally FSBR gets turned on as soon as
+        * one QH needs it. */
+       fsbr_qh = NULL;
+       list_for_each_entry_reverse(tqh, &uhci->skel_async_qh->node, node) {
+               if (tqh->skel < SKEL_FSBR)
+                       break;
+               fsbr_qh = tqh;
+       }
+
+       /* No FSBR QH means we must insert the terminating skeleton QH */
+       if (!fsbr_qh) {
+               uhci->skel_term_qh->link = LINK_TO_QH(uhci->skel_term_qh);
+               wmb();
+               lqh->link = uhci->skel_term_qh->link;
+
+       /* Otherwise loop the last QH to the first FSBR QH */
+       } else
+               lqh->link = LINK_TO_QH(fsbr_qh);
 }
 
 static void uhci_fsbr_off(struct uhci_hcd *uhci)
 {
+       struct uhci_qh *lqh;
+
        uhci->fsbr_is_on = 0;
-       uhci->skel_term_qh->link = UHCI_PTR_TERM;
+       lqh = list_entry(uhci->skel_async_qh->node.prev,
+                       struct uhci_qh, node);
+
+       /* End the async list normally and unlink the terminating QH */
+       lqh->link = uhci->skel_term_qh->link = UHCI_PTR_TERM;
 }
 
 static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb)
@@ -158,11 +186,11 @@ static inline void uhci_insert_td_in_frame_list(struct uhci_hcd *uhci,
 
                td->link = ltd->link;
                wmb();
-               ltd->link = cpu_to_le32(td->dma_handle);
+               ltd->link = LINK_TO_TD(td);
        } else {
                td->link = uhci->frame[framenum];
                wmb();
-               uhci->frame[framenum] = cpu_to_le32(td->dma_handle);
+               uhci->frame[framenum] = LINK_TO_TD(td);
                uhci->frame_cpu[framenum] = td;
        }
 }
@@ -184,7 +212,7 @@ static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci,
                        struct uhci_td *ntd;
 
                        ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
-                       uhci->frame[td->frame] = cpu_to_le32(ntd->dma_handle);
+                       uhci->frame[td->frame] = LINK_TO_TD(ntd);
                        uhci->frame_cpu[td->frame] = ntd;
                }
        } else {
@@ -405,12 +433,81 @@ static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first)
 }
 
 /*
- * Put a QH on the schedule in both hardware and software
+ * Link an Isochronous QH into its skeleton's list
  */
-static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+static inline void link_iso(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+       list_add_tail(&qh->node, &uhci->skel_iso_qh->node);
+
+       /* Isochronous QHs aren't linked by the hardware */
+}
+
+/*
+ * Link a high-period interrupt QH into the schedule at the end of its
+ * skeleton's list
+ */
+static void link_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh)
 {
        struct uhci_qh *pqh;
 
+       list_add_tail(&qh->node, &uhci->skelqh[qh->skel]->node);
+
+       pqh = list_entry(qh->node.prev, struct uhci_qh, node);
+       qh->link = pqh->link;
+       wmb();
+       pqh->link = LINK_TO_QH(qh);
+}
+
+/*
+ * Link a period-1 interrupt or async QH into the schedule at the
+ * correct spot in the async skeleton's list, and update the FSBR link
+ */
+static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+       struct uhci_qh *pqh, *lqh;
+       __le32 link_to_new_qh;
+       __le32 *extra_link = &link_to_new_qh;
+
+       /* Find the predecessor QH for our new one and insert it in the list.
+        * The list of QHs is expected to be short, so linear search won't
+        * take too long. */
+       list_for_each_entry_reverse(pqh, &uhci->skel_async_qh->node, node) {
+               if (pqh->skel <= qh->skel)
+                       break;
+       }
+       list_add(&qh->node, &pqh->node);
+       qh->link = pqh->link;
+
+       link_to_new_qh = LINK_TO_QH(qh);
+
+       /* If this is now the first FSBR QH, take special action */
+       if (uhci->fsbr_is_on && pqh->skel < SKEL_FSBR &&
+                       qh->skel >= SKEL_FSBR) {
+               lqh = list_entry(uhci->skel_async_qh->node.prev,
+                               struct uhci_qh, node);
+
+               /* If the new QH is also the last one, we must unlink
+                * the terminating skeleton QH and make the new QH point
+                * back to itself. */
+               if (qh == lqh) {
+                       qh->link = link_to_new_qh;
+                       extra_link = &uhci->skel_term_qh->link;
+
+               /* Otherwise the last QH must point to the new QH */
+               } else
+                       extra_link = &lqh->link;
+       }
+
+       /* Link it into the schedule */
+       wmb();
+       *extra_link = pqh->link = link_to_new_qh;
+}
+
+/*
+ * Put a QH on the schedule in both hardware and software
+ */
+static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
        WARN_ON(list_empty(&qh->queue));
 
        /* Set the element pointer if it isn't set already.
@@ -421,7 +518,7 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
                struct uhci_td *td = list_entry(urbp->td_list.next,
                                struct uhci_td, list);
 
-               qh->element = cpu_to_le32(td->dma_handle);
+               qh->element = LINK_TO_TD(td);
        }
 
        /* Treat the queue as if it has just advanced */
@@ -432,18 +529,64 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
                return;
        qh->state = QH_STATE_ACTIVE;
 
-       /* Move the QH from its old list to the end of the appropriate
+       /* Move the QH from its old list to the correct spot in the appropriate
         * skeleton's list */
        if (qh == uhci->next_qh)
                uhci->next_qh = list_entry(qh->node.next, struct uhci_qh,
                                node);
-       list_move_tail(&qh->node, &qh->skel->node);
+       list_del(&qh->node);
+
+       if (qh->skel == SKEL_ISO)
+               link_iso(uhci, qh);
+       else if (qh->skel < SKEL_ASYNC)
+               link_interrupt(uhci, qh);
+       else
+               link_async(uhci, qh);
+}
+
+/*
+ * Unlink a high-period interrupt QH from the schedule
+ */
+static void unlink_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+       struct uhci_qh *pqh;
 
-       /* Link it into the schedule */
        pqh = list_entry(qh->node.prev, struct uhci_qh, node);
-       qh->link = pqh->link;
-       wmb();
-       pqh->link = UHCI_PTR_QH | cpu_to_le32(qh->dma_handle);
+       pqh->link = qh->link;
+       mb();
+}
+
+/*
+ * Unlink a period-1 interrupt or async QH from the schedule
+ */
+static void unlink_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+       struct uhci_qh *pqh, *lqh;
+       __le32 link_to_next_qh = qh->link;
+
+       pqh = list_entry(qh->node.prev, struct uhci_qh, node);
+
+       /* If this is the first FSBQ QH, take special action */
+       if (uhci->fsbr_is_on && pqh->skel < SKEL_FSBR &&
+                       qh->skel >= SKEL_FSBR) {
+               lqh = list_entry(uhci->skel_async_qh->node.prev,
+                               struct uhci_qh, node);
+
+               /* If this QH is also the last one, we must link in
+                * the terminating skeleton QH. */
+               if (qh == lqh) {
+                       link_to_next_qh = LINK_TO_QH(uhci->skel_term_qh);
+                       uhci->skel_term_qh->link = link_to_next_qh;
+                       wmb();
+                       qh->link = link_to_next_qh;
+
+               /* Otherwise the last QH must point to the new first FSBR QH */
+               } else
+                       lqh->link = link_to_next_qh;
+       }
+
+       pqh->link = link_to_next_qh;
+       mb();
 }
 
 /*
@@ -451,17 +594,18 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
  */
 static void uhci_unlink_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
 {
-       struct uhci_qh *pqh;
-
        if (qh->state == QH_STATE_UNLINKING)
                return;
        WARN_ON(qh->state != QH_STATE_ACTIVE || !qh->udev);
        qh->state = QH_STATE_UNLINKING;
 
        /* Unlink the QH from the schedule and record when we did it */
-       pqh = list_entry(qh->node.prev, struct uhci_qh, node);
-       pqh->link = qh->link;
-       mb();
+       if (qh->skel == SKEL_ISO)
+               ;
+       else if (qh->skel < SKEL_ASYNC)
+               unlink_interrupt(uhci, qh);
+       else
+               unlink_async(uhci, qh);
 
        uhci_get_current_frame_number(uhci);
        qh->unlink_frame = uhci->frame_number;
@@ -697,6 +841,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
        dma_addr_t data = urb->transfer_dma;
        __le32 *plink;
        struct urb_priv *urbp = urb->hcpriv;
+       int skel;
 
        /* The "pipe" thing contains the destination in bits 8--18 */
        destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
@@ -737,7 +882,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
                td = uhci_alloc_td(uhci);
                if (!td)
                        goto nomem;
-               *plink = cpu_to_le32(td->dma_handle);
+               *plink = LINK_TO_TD(td);
 
                /* Alternate Data0/1 (start with Data1) */
                destination ^= TD_TOKEN_TOGGLE;
@@ -757,7 +902,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
        td = uhci_alloc_td(uhci);
        if (!td)
                goto nomem;
-       *plink = cpu_to_le32(td->dma_handle);
+       *plink = LINK_TO_TD(td);
 
        /*
         * It's IN if the pipe is an output pipe or we're not expecting
@@ -784,7 +929,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
        td = uhci_alloc_td(uhci);
        if (!td)
                goto nomem;
-       *plink = cpu_to_le32(td->dma_handle);
+       *plink = LINK_TO_TD(td);
 
        uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
        wmb();
@@ -797,11 +942,13 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
         * isn't in the CONFIGURED state. */
        if (urb->dev->speed == USB_SPEED_LOW ||
                        urb->dev->state != USB_STATE_CONFIGURED)
-               qh->skel = uhci->skel_ls_control_qh;
+               skel = SKEL_LS_CONTROL;
        else {
-               qh->skel = uhci->skel_fs_control_qh;
+               skel = SKEL_FS_CONTROL;
                uhci_add_fsbr(uhci, urb);
        }
+       if (qh->state != QH_STATE_ACTIVE)
+               qh->skel = skel;
 
        urb->actual_length = -8;        /* Account for the SETUP packet */
        return 0;
@@ -860,7 +1007,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
                        td = uhci_alloc_td(uhci);
                        if (!td)
                                goto nomem;
-                       *plink = cpu_to_le32(td->dma_handle);
+                       *plink = LINK_TO_TD(td);
                }
                uhci_add_td_to_urbp(td, urbp);
                uhci_fill_td(td, status,
@@ -888,7 +1035,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
                td = uhci_alloc_td(uhci);
                if (!td)
                        goto nomem;
-               *plink = cpu_to_le32(td->dma_handle);
+               *plink = LINK_TO_TD(td);
 
                uhci_add_td_to_urbp(td, urbp);
                uhci_fill_td(td, status,
@@ -914,7 +1061,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
        td = uhci_alloc_td(uhci);
        if (!td)
                goto nomem;
-       *plink = cpu_to_le32(td->dma_handle);
+       *plink = LINK_TO_TD(td);
 
        uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
        wmb();
@@ -931,7 +1078,7 @@ nomem:
        return -ENOMEM;
 }
 
-static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
+static int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
                struct uhci_qh *qh)
 {
        int ret;
@@ -940,7 +1087,8 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
        if (urb->dev->speed == USB_SPEED_LOW)
                return -EINVAL;
 
-       qh->skel = uhci->skel_bulk_qh;
+       if (qh->state != QH_STATE_ACTIVE)
+               qh->skel = SKEL_BULK;
        ret = uhci_submit_common(uhci, urb, qh);
        if (ret == 0)
                uhci_add_fsbr(uhci, urb);
@@ -968,7 +1116,7 @@ static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
                if (exponent < 0)
                        return -EINVAL;
                qh->period = 1 << exponent;
-               qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)];
+               qh->skel = SKEL_INDEX(exponent);
 
                /* For now, interrupt phase is fixed by the layout
                 * of the QH lists. */
@@ -1005,7 +1153,7 @@ static int uhci_fixup_short_transfer(struct uhci_hcd *uhci,
                 * the queue at the status stage transaction, which is
                 * the last TD. */
                WARN_ON(list_empty(&urbp->td_list));
-               qh->element = cpu_to_le32(td->dma_handle);
+               qh->element = LINK_TO_TD(td);
                tmp = td->list.prev;
                ret = -EINPROGRESS;
 
@@ -1216,7 +1364,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
                qh->iso_status = 0;
        }
 
-       qh->skel = uhci->skel_iso_qh;
+       qh->skel = SKEL_ISO;
        if (!qh->bandwidth_reserved)
                uhci_reserve_bandwidth(uhci, qh);
        return 0;
@@ -1566,8 +1714,7 @@ static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh)
        if (time_after(jiffies, qh->advance_jiffies + QH_WAIT_TIMEOUT)) {
 
                /* Detect the Intel bug and work around it */
-               if (qh->post_td && qh_element(qh) ==
-                               cpu_to_le32(qh->post_td->dma_handle)) {
+               if (qh->post_td && qh_element(qh) == LINK_TO_TD(qh->post_td)) {
                        qh->element = qh->post_td->link;
                        qh->advance_jiffies = jiffies;
                        ret = 1;
index 8505824..3749f4a 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/usb/input.h>
+#include <linux/hid.h>
 
 /*
  * Version Information
@@ -330,7 +331,8 @@ static void usb_kbd_disconnect(struct usb_interface *intf)
 }
 
 static struct usb_device_id usb_kbd_id_table [] = {
-       { USB_INTERFACE_INFO(3, 1, 1) },
+       { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
+               USB_INTERFACE_PROTOCOL_KEYBOARD) },
        { }                                             /* Terminating entry */
 };
 
index 64a33e4..692fd60 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/usb/input.h>
+#include <linux/hid.h>
 
 /*
  * Version Information
@@ -213,7 +214,8 @@ static void usb_mouse_disconnect(struct usb_interface *intf)
 }
 
 static struct usb_device_id usb_mouse_id_table [] = {
-       { USB_INTERFACE_INFO(3, 1, 2) },
+       { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
+               USB_INTERFACE_PROTOCOL_MOUSE) },
        { }     /* Terminating entry */
 };
 
index 4142e36..4f3e9bc 100644 (file)
@@ -163,7 +163,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
        }
 
        id = STYLUS_DEVICE_ID;
-       if (data[1] & 0x10) { /* in prox */
+       if (data[1] & 0x80) { /* in prox */
 
                switch ((data[1] >> 5) & 3) {
 
@@ -196,9 +196,6 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
                                        wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f);
                                break;
                }
-       }
-
-       if (data[1] & 0x90) {
                x = wacom_le16_to_cpu(&data[2]);
                y = wacom_le16_to_cpu(&data[4]);
                wacom_report_abs(wcombo, ABS_X, x);
@@ -210,19 +207,28 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
                        wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x04);
                }
                wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
-       }
-       else
-               wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
-
-       if (data[1] & 0x10)  /* only report prox-in when in area */
                wacom_report_key(wcombo, wacom->tool[0], 1);
-       if (!(data[1] & 0x90))  /* report prox-out when physically out */
+       } else if (!(data[1] & 0x90)) {
+               wacom_report_abs(wcombo, ABS_X, 0);
+               wacom_report_abs(wcombo, ABS_Y, 0);
+               if (wacom->tool[0] == BTN_TOOL_MOUSE) {
+                       wacom_report_key(wcombo, BTN_LEFT, 0);
+                       wacom_report_key(wcombo, BTN_RIGHT, 0);
+                       wacom_report_abs(wcombo, ABS_DISTANCE, 0);
+               } else {
+                       wacom_report_abs(wcombo, ABS_PRESSURE, 0);
+                       wacom_report_key(wcombo, BTN_TOUCH, 0);
+                       wacom_report_key(wcombo, BTN_STYLUS, 0);
+                       wacom_report_key(wcombo, BTN_STYLUS2, 0);
+               }
+               wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
                wacom_report_key(wcombo, wacom->tool[0], 0);
-       wacom_input_sync(wcombo);
+       }
 
        /* send pad data */
        if (wacom->features->type == WACOM_G4) {
-               if ( (wacom->serial[1] & 0xc0) != (data[7] & 0xf8) ) {
+               if (data[7] & 0xf8) {
+                       wacom_input_sync(wcombo); /* sync last event */
                        wacom->id[1] = 1;
                        wacom->serial[1] = (data[7] & 0xf8);
                        wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
@@ -230,10 +236,15 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
                        rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3);
                        wacom_report_rel(wcombo, REL_WHEEL, rw);
                        wacom_report_key(wcombo, BTN_TOOL_FINGER, 0xf0);
+                       wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
                        wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
                } else if (wacom->id[1]) {
+                       wacom_input_sync(wcombo); /* sync last event */
                        wacom->id[1] = 0;
+                       wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
+                       wacom_report_key(wcombo, BTN_4, (data[7] & 0x80));
                        wacom_report_key(wcombo, BTN_TOOL_FINGER, 0);
+                       wacom_report_abs(wcombo, ABS_MISC, 0);
                        wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
                }
        }
@@ -304,28 +315,35 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
                        default: /* Unknown tool */
                                wacom->tool[idx] = BTN_TOOL_PEN;
                }
-               /* only large I3 support Lens Cursor */
-               if(!((wacom->tool[idx] == BTN_TOOL_LENS)
-                                && ((wacom->features->type == INTUOS3)
-                                || (wacom->features->type == INTUOS3S)))) {
-                       wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */
-                       wacom_report_key(wcombo, wacom->tool[idx], 1);
-                       wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
-                       return 2;
-               }
                return 1;
        }
 
        /* Exit report */
        if ((data[1] & 0xfe) == 0x80) {
-               if(!((wacom->tool[idx] == BTN_TOOL_LENS)
-                                && ((wacom->features->type == INTUOS3)
-                                || (wacom->features->type == INTUOS3S)))) {
-                       wacom_report_key(wcombo, wacom->tool[idx], 0);
-                       wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
-                       wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
-                       return 2;
+               wacom_report_abs(wcombo, ABS_X, 0);
+               wacom_report_abs(wcombo, ABS_Y, 0);
+               wacom_report_abs(wcombo, ABS_DISTANCE, 0);
+               if (wacom->tool[idx] >= BTN_TOOL_MOUSE) {
+                       wacom_report_key(wcombo, BTN_LEFT, 0);
+                       wacom_report_key(wcombo, BTN_MIDDLE, 0);
+                       wacom_report_key(wcombo, BTN_RIGHT, 0);
+                       wacom_report_key(wcombo, BTN_SIDE, 0);
+                       wacom_report_key(wcombo, BTN_EXTRA, 0);
+                       wacom_report_abs(wcombo, ABS_THROTTLE, 0);
+                       wacom_report_abs(wcombo, ABS_RZ, 0);
+               } else {
+                       wacom_report_abs(wcombo, ABS_PRESSURE, 0);
+                       wacom_report_abs(wcombo, ABS_TILT_X, 0);
+                       wacom_report_abs(wcombo, ABS_TILT_Y, 0);
+                       wacom_report_key(wcombo, BTN_STYLUS, 0);
+                       wacom_report_key(wcombo, BTN_STYLUS2, 0);
+                       wacom_report_key(wcombo, BTN_TOUCH, 0);
+                       wacom_report_abs(wcombo, ABS_WHEEL, 0);
                }
+               wacom_report_key(wcombo, wacom->tool[idx], 0);
+               wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
+               wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+               return 2;
        }
        return 0;
 }
@@ -394,6 +412,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
                        wacom_report_key(wcombo, wacom->tool[1], 1);
                else
                        wacom_report_key(wcombo, wacom->tool[1], 0);
+               wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
                wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xffffffff);
                 return 1;
        }
@@ -403,6 +422,12 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
        if (result)
                 return result-1;
 
+       /* Only large I3 and I1 & I2 support Lense Cursor */
+       if((wacom->tool[idx] == BTN_TOOL_LENS)
+                       && ((wacom->features->type == INTUOS3)
+                       || (wacom->features->type == INTUOS3S)))
+               return 0;
+
        /* Cintiq doesn't send data when RDY bit isn't set */
        if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
                  return 0;
@@ -554,11 +579,11 @@ static struct wacom_features wacom_features[] = {
        { "Wacom Volito2 4x5",   8,   5104,  3712,  511, 63, GRAPHIRE },
        { "Wacom Volito2 2x3",   8,   3248,  2320,  511, 63, GRAPHIRE },
        { "Wacom PenPartner2",   8,   3250,  2320,  255, 63, GRAPHIRE },
-       { "Wacom Intuos 4x5",   10,  12700, 10600, 1023, 63, INTUOS },
-       { "Wacom Intuos 6x8",   10,  20320, 16240, 1023, 63, INTUOS },
-       { "Wacom Intuos 9x12",  10,  30480, 24060, 1023, 63, INTUOS },
-       { "Wacom Intuos 12x12", 10,  30480, 31680, 1023, 63, INTUOS },
-       { "Wacom Intuos 12x18", 10,  45720, 31680, 1023, 63, INTUOS },
+       { "Wacom Intuos 4x5",   10,  12700, 10600, 1023, 31, INTUOS },
+       { "Wacom Intuos 6x8",   10,  20320, 16240, 1023, 31, INTUOS },
+       { "Wacom Intuos 9x12",  10,  30480, 24060, 1023, 31, INTUOS },
+       { "Wacom Intuos 12x12", 10,  30480, 31680, 1023, 31, INTUOS },
+       { "Wacom Intuos 12x18", 10,  45720, 31680, 1023, 31, INTUOS },
        { "Wacom PL400",         8,   5408,  4056,  255,  0, PL },
        { "Wacom PL500",         8,   6144,  4608,  255,  0, PL },
        { "Wacom PL600",         8,   6126,  4604,  255,  0, PL },
@@ -571,11 +596,11 @@ static struct wacom_features wacom_features[] = {
        { "Wacom DTF521",        8,   6282,  4762,  511,  0, PL },
        { "Wacom DTF720",        8,   6858,  5506,  511,  0, PL },
        { "Wacom Cintiq Partner",8,  20480, 15360,  511,  0, PTU },
-       { "Wacom Intuos2 4x5",   10, 12700, 10600, 1023, 63, INTUOS },
-       { "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 63, INTUOS },
-       { "Wacom Intuos2 9x12",  10, 30480, 24060, 1023, 63, INTUOS },
-       { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 63, INTUOS },
-       { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 63, INTUOS },
+       { "Wacom Intuos2 4x5",   10, 12700, 10600, 1023, 31, INTUOS },
+       { "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 31, INTUOS },
+       { "Wacom Intuos2 9x12",  10, 30480, 24060, 1023, 31, INTUOS },
+       { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 31, INTUOS },
+       { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 31, INTUOS },
        { "Wacom Intuos3 4x5",   10, 25400, 20320, 1023, 63, INTUOS3S },
        { "Wacom Intuos3 6x8",   10, 40640, 30480, 1023, 63, INTUOS3 },
        { "Wacom Intuos3 9x12",  10, 60960, 45720, 1023, 63, INTUOS3 },
@@ -584,7 +609,7 @@ static struct wacom_features wacom_features[] = {
        { "Wacom Intuos3 6x11",  10, 54204, 31750, 1023, 63, INTUOS3 },
        { "Wacom Intuos3 4x6",   10, 31496, 19685, 1023, 63, INTUOS3S },
        { "Wacom Cintiq 21UX",   10, 87200, 65600, 1023, 63, CINTIQ },
-       { "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 63, INTUOS },
+       { "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 31, INTUOS },
        { }
 };
 
index a1d9ce0..a230222 100644 (file)
@@ -12,6 +12,7 @@
 #define STYLUS_DEVICE_ID       0x02
 #define CURSOR_DEVICE_ID       0x06
 #define ERASER_DEVICE_ID       0x0A
+#define PAD_DEVICE_ID          0x0F
 
 enum {
        PENPARTNER = 0,
index 4907e8b..9c7eb61 100644 (file)
@@ -244,6 +244,20 @@ config USB_TRANCEVIBRATOR
          To compile this driver as a module, choose M here: the
          module will be called trancevibrator.
 
+config USB_IOWARRIOR
+       tristate "IO Warrior driver support"
+       depends on USB
+       help
+         Say Y here if you want to support the IO Warrior devices from Code
+         Mercenaries.  This includes support for the following devices:
+               IO Warrior 40
+               IO Warrior 24
+               IO Warrior 56
+               IO Warrior 24 Power Vampire
+
+         To compile this driver as a module, choose M here: the
+         module will be called iowarrior.
+
 config USB_TEST
        tristate "USB testing driver (DEVELOPMENT)"
        depends on USB && USB_DEVICEFS && EXPERIMENTAL
index dac2d5b..b68e6b7 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_USB_EMI26)               += emi26.o
 obj-$(CONFIG_USB_EMI62)                += emi62.o
 obj-$(CONFIG_USB_FTDI_ELAN)    += ftdi-elan.o
 obj-$(CONFIG_USB_IDMOUSE)      += idmouse.o
+obj-$(CONFIG_USB_IOWARRIOR)    += iowarrior.o
 obj-$(CONFIG_USB_LCD)          += usblcd.o
 obj-$(CONFIG_USB_LD)           += ldusb.o
 obj-$(CONFIG_USB_LED)          += usbled.o
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
new file mode 100644 (file)
index 0000000..d69665c
--- /dev/null
@@ -0,0 +1,925 @@
+/*
+ *  Native support for the I/O-Warrior USB devices
+ *
+ *  Copyright (c) 2003-2005  Code Mercenaries GmbH
+ *  written by Christian Lucht <lucht@codemercs.com>
+ *
+ *  based on
+
+ *  usb-skeleton.c by Greg Kroah-Hartman  <greg@kroah.com>
+ *  brlvger.c by Stephane Dalton  <sdalton@videotron.ca>
+ *           and St�hane Doyon   <s.doyon@videotron.ca>
+ *
+ *  Released under the GPLv2.
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/version.h>
+#include <linux/usb/iowarrior.h>
+
+/* Version Information */
+#define DRIVER_VERSION "v0.4.0"
+#define DRIVER_AUTHOR "Christian Lucht <lucht@codemercs.com>"
+#define DRIVER_DESC "USB IO-Warrior driver (Linux 2.6.x)"
+
+#define USB_VENDOR_ID_CODEMERCS                1984
+/* low speed iowarrior */
+#define USB_DEVICE_ID_CODEMERCS_IOW40  0x1500
+#define USB_DEVICE_ID_CODEMERCS_IOW24  0x1501
+#define USB_DEVICE_ID_CODEMERCS_IOWPV1 0x1511
+#define USB_DEVICE_ID_CODEMERCS_IOWPV2 0x1512
+/* full speed iowarrior */
+#define USB_DEVICE_ID_CODEMERCS_IOW56  0x1503
+
+/* Get a minor range for your devices from the usb maintainer */
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+#define IOWARRIOR_MINOR_BASE   0
+#else
+#define IOWARRIOR_MINOR_BASE   208     // SKELETON_MINOR_BASE 192 + 16, not offical yet
+#endif
+
+/* interrupt input queue size */
+#define MAX_INTERRUPT_BUFFER 16
+/*
+   maximum number of urbs that are submitted for writes at the same time,
+   this applies to the IOWarrior56 only!
+   IOWarrior24 and IOWarrior40 use synchronous usb_control_msg calls.
+*/
+#define MAX_WRITES_IN_FLIGHT 4
+
+/* Use our own dbg macro */
+#undef dbg
+#define dbg( format, arg... ) do { if( debug ) printk( KERN_DEBUG __FILE__ ": " format "\n" , ## arg ); } while ( 0 )
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/* Module parameters */
+static int debug = 0;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "debug=1 enables debugging messages");
+
+static struct usb_driver iowarrior_driver;
+
+/*--------------*/
+/*     data     */
+/*--------------*/
+
+/* Structure to hold all of our device specific stuff */
+struct iowarrior {
+       struct mutex mutex;                     /* locks this structure */
+       struct usb_device *udev;                /* save off the usb device pointer */
+       struct usb_interface *interface;        /* the interface for this device */
+       unsigned char minor;                    /* the starting minor number for this device */
+       struct usb_endpoint_descriptor *int_out_endpoint;       /* endpoint for reading (needed for IOW56 only) */
+       struct usb_endpoint_descriptor *int_in_endpoint;        /* endpoint for reading */
+       struct urb *int_in_urb;         /* the urb for reading data */
+       unsigned char *int_in_buffer;   /* buffer for data to be read */
+       unsigned char serial_number;    /* to detect lost packages */
+       unsigned char *read_queue;      /* size is MAX_INTERRUPT_BUFFER * packet size */
+       wait_queue_head_t read_wait;
+       wait_queue_head_t write_wait;   /* wait-queue for writing to the device */
+       atomic_t write_busy;            /* number of write-urbs submitted */
+       atomic_t read_idx;
+       atomic_t intr_idx;
+       spinlock_t intr_idx_lock;       /* protects intr_idx */
+       atomic_t overflow_flag;         /* signals an index 'rollover' */
+       int present;                    /* this is 1 as long as the device is connected */
+       int opened;                     /* this is 1 if the device is currently open */
+       char chip_serial[9];            /* the serial number string of the chip connected */
+       int report_size;                /* number of bytes in a report */
+       u16 product_id;
+};
+
+/*--------------*/
+/*    globals   */
+/*--------------*/
+/* prevent races between open() and disconnect() */
+static DECLARE_MUTEX(disconnect_sem);
+
+/*
+ *  USB spec identifies 5 second timeouts.
+ */
+#define GET_TIMEOUT 5
+#define USB_REQ_GET_REPORT  0x01
+//#if 0
+static int usb_get_report(struct usb_device *dev,
+                         struct usb_host_interface *inter, unsigned char type,
+                         unsigned char id, void *buf, int size)
+{
+       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                              USB_REQ_GET_REPORT,
+                              USB_DIR_IN | USB_TYPE_CLASS |
+                              USB_RECIP_INTERFACE, (type << 8) + id,
+                              inter->desc.bInterfaceNumber, buf, size,
+                              GET_TIMEOUT);
+}
+//#endif
+
+#define USB_REQ_SET_REPORT 0x09
+
+static int usb_set_report(struct usb_interface *intf, unsigned char type,
+                         unsigned char id, void *buf, int size)
+{
+       return usb_control_msg(interface_to_usbdev(intf),
+                              usb_sndctrlpipe(interface_to_usbdev(intf), 0),
+                              USB_REQ_SET_REPORT,
+                              USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                              (type << 8) + id,
+                              intf->cur_altsetting->desc.bInterfaceNumber, buf,
+                              size, 1);
+}
+
+/*---------------------*/
+/* driver registration */
+/*---------------------*/
+/* table of devices that work with this driver */
+static struct usb_device_id iowarrior_ids[] = {
+       {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40)},
+       {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24)},
+       {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOWPV1)},
+       {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOWPV2)},
+       {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW56)},
+       {}                      /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, iowarrior_ids);
+
+/*
+ * USB callback handler for reading data
+ */
+static void iowarrior_callback(struct urb *urb)
+{
+       struct iowarrior *dev = (struct iowarrior *)urb->context;
+       int intr_idx;
+       int read_idx;
+       int aux_idx;
+       int offset;
+       int status;
+
+       switch (urb->status) {
+       case 0:
+               /* success */
+               break;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               return;
+       default:
+               goto exit;
+       }
+
+       spin_lock(&dev->intr_idx_lock);
+       intr_idx = atomic_read(&dev->intr_idx);
+       /* aux_idx become previous intr_idx */
+       aux_idx = (intr_idx == 0) ? (MAX_INTERRUPT_BUFFER - 1) : (intr_idx - 1);
+       read_idx = atomic_read(&dev->read_idx);
+
+       /* queue is not empty and it's interface 0 */
+       if ((intr_idx != read_idx)
+           && (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0)) {
+               /* + 1 for serial number */
+               offset = aux_idx * (dev->report_size + 1);
+               if (!memcmp
+                   (dev->read_queue + offset, urb->transfer_buffer,
+                    dev->report_size)) {
+                       /* equal values on interface 0 will be ignored */
+                       spin_unlock(&dev->intr_idx_lock);
+                       goto exit;
+               }
+       }
+
+       /* aux_idx become next intr_idx */
+       aux_idx = (intr_idx == (MAX_INTERRUPT_BUFFER - 1)) ? 0 : (intr_idx + 1);
+       if (read_idx == aux_idx) {
+               /* queue full, dropping oldest input */
+               read_idx = (++read_idx == MAX_INTERRUPT_BUFFER) ? 0 : read_idx;
+               atomic_set(&dev->read_idx, read_idx);
+               atomic_set(&dev->overflow_flag, 1);
+       }
+
+       /* +1 for serial number */
+       offset = intr_idx * (dev->report_size + 1);
+       memcpy(dev->read_queue + offset, urb->transfer_buffer,
+              dev->report_size);
+       *(dev->read_queue + offset + (dev->report_size)) = dev->serial_number++;
+
+       atomic_set(&dev->intr_idx, aux_idx);
+       spin_unlock(&dev->intr_idx_lock);
+       /* tell the blocking read about the new data */
+       wake_up_interruptible(&dev->read_wait);
+
+exit:
+       status = usb_submit_urb(urb, GFP_ATOMIC);
+       if (status)
+               dev_err(&dev->interface->dev, "%s - usb_submit_urb failed with result %d",
+                       __FUNCTION__, status);
+
+}
+
+/*
+ * USB Callback handler for write-ops
+ */
+static void iowarrior_write_callback(struct urb *urb)
+{
+       struct iowarrior *dev;
+       dev = (struct iowarrior *)urb->context;
+       /* sync/async unlink faults aren't errors */
+       if (urb->status &&
+           !(urb->status == -ENOENT ||
+             urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) {
+               dbg("%s - nonzero write bulk status received: %d",
+                   __func__, urb->status);
+       }
+       /* free up our allocated buffer */
+       usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+                       urb->transfer_buffer, urb->transfer_dma);
+       /* tell a waiting writer the interrupt-out-pipe is available again */
+       atomic_dec(&dev->write_busy);
+       wake_up_interruptible(&dev->write_wait);
+}
+
+/**
+ *     iowarrior_delete
+ */
+static inline void iowarrior_delete(struct iowarrior *dev)
+{
+       dbg("%s - minor %d", __func__, dev->minor);
+       kfree(dev->int_in_buffer);
+       usb_free_urb(dev->int_in_urb);
+       kfree(dev->read_queue);
+       kfree(dev);
+}
+
+/*---------------------*/
+/* fops implementation */
+/*---------------------*/
+
+static int read_index(struct iowarrior *dev)
+{
+       int intr_idx, read_idx;
+
+       read_idx = atomic_read(&dev->read_idx);
+       intr_idx = atomic_read(&dev->intr_idx);
+
+       return (read_idx == intr_idx ? -1 : read_idx);
+}
+
+/**
+ *  iowarrior_read
+ */
+static ssize_t iowarrior_read(struct file *file, char __user *buffer,
+                             size_t count, loff_t *ppos)
+{
+       struct iowarrior *dev;
+       int read_idx;
+       int offset;
+
+       dev = (struct iowarrior *)file->private_data;
+
+       /* verify that the device wasn't unplugged */
+       if (dev == NULL || !dev->present)
+               return -ENODEV;
+
+       dbg("%s - minor %d, count = %zd", __func__, dev->minor, count);
+
+       /* read count must be packet size (+ time stamp) */
+       if ((count != dev->report_size)
+           && (count != (dev->report_size + 1)))
+               return -EINVAL;
+
+       /* repeat until no buffer overrun in callback handler occur */
+       do {
+               atomic_set(&dev->overflow_flag, 0);
+               if ((read_idx = read_index(dev)) == -1) {
+                       /* queue emty */
+                       if (file->f_flags & O_NONBLOCK)
+                               return -EAGAIN;
+                       else {
+                               //next line will return when there is either new data, or the device is unplugged
+                               int r = wait_event_interruptible(dev->read_wait,
+                                                                (!dev->present
+                                                                 || (read_idx =
+                                                                     read_index
+                                                                     (dev)) !=
+                                                                 -1));
+                               if (r) {
+                                       //we were interrupted by a signal
+                                       return -ERESTART;
+                               }
+                               if (!dev->present) {
+                                       //The device was unplugged
+                                       return -ENODEV;
+                               }
+                               if (read_idx == -1) {
+                                       // Can this happen ???
+                                       return 0;
+                               }
+                       }
+               }
+
+               offset = read_idx * (dev->report_size + 1);
+               if (copy_to_user(buffer, dev->read_queue + offset, count)) {
+                       return -EFAULT;
+               }
+       } while (atomic_read(&dev->overflow_flag));
+
+       read_idx = ++read_idx == MAX_INTERRUPT_BUFFER ? 0 : read_idx;
+       atomic_set(&dev->read_idx, read_idx);
+       return count;
+}
+
+/*
+ * iowarrior_write
+ */
+static ssize_t iowarrior_write(struct file *file,
+                              const char __user *user_buffer,
+                              size_t count, loff_t *ppos)
+{
+       struct iowarrior *dev;
+       int retval = 0;
+       char *buf = NULL;       /* for IOW24 and IOW56 we need a buffer */
+       struct urb *int_out_urb = NULL;
+
+       dev = (struct iowarrior *)file->private_data;
+
+       mutex_lock(&dev->mutex);
+       /* verify that the device wasn't unplugged */
+       if (dev == NULL || !dev->present) {
+               retval = -ENODEV;
+               goto exit;
+       }
+       dbg("%s - minor %d, count = %zd", __func__, dev->minor, count);
+       /* if count is 0 we're already done */
+       if (count == 0) {
+               retval = 0;
+               goto exit;
+       }
+       /* We only accept full reports */
+       if (count != dev->report_size) {
+               retval = -EINVAL;
+               goto exit;
+       }
+       switch (dev->product_id) {
+       case USB_DEVICE_ID_CODEMERCS_IOW24:
+       case USB_DEVICE_ID_CODEMERCS_IOWPV1:
+       case USB_DEVICE_ID_CODEMERCS_IOWPV2:
+       case USB_DEVICE_ID_CODEMERCS_IOW40:
+               /* IOW24 and IOW40 use a synchronous call */
+               buf = kmalloc(8, GFP_KERNEL);   /* 8 bytes are enough for both products */
+               if (!buf) {
+                       retval = -ENOMEM;
+                       goto exit;
+               }
+               if (copy_from_user(buf, user_buffer, count)) {
+                       retval = -EFAULT;
+                       kfree(buf);
+                       goto exit;
+               }
+               retval = usb_set_report(dev->interface, 2, 0, buf, count);
+               kfree(buf);
+               goto exit;
+               break;
+       case USB_DEVICE_ID_CODEMERCS_IOW56:
+               /* The IOW56 uses asynchronous IO and more urbs */
+               if (atomic_read(&dev->write_busy) == MAX_WRITES_IN_FLIGHT) {
+                       /* Wait until we are below the limit for submitted urbs */
+                       if (file->f_flags & O_NONBLOCK) {
+                               retval = -EAGAIN;
+                               goto exit;
+                       } else {
+                               retval = wait_event_interruptible(dev->write_wait,
+                                                                 (!dev->present || (atomic_read (&dev-> write_busy) < MAX_WRITES_IN_FLIGHT)));
+                               if (retval) {
+                                       /* we were interrupted by a signal */
+                                       retval = -ERESTART;
+                                       goto exit;
+                               }
+                               if (!dev->present) {
+                                       /* The device was unplugged */
+                                       retval = -ENODEV;
+                                       goto exit;
+                               }
+                               if (!dev->opened) {
+                                       /* We were closed while waiting for an URB */
+                                       retval = -ENODEV;
+                                       goto exit;
+                               }
+                       }
+               }
+               atomic_inc(&dev->write_busy);
+               int_out_urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!int_out_urb) {
+                       retval = -ENOMEM;
+                       dbg("%s Unable to allocate urb ", __func__);
+                       goto error;
+               }
+               buf = usb_buffer_alloc(dev->udev, dev->report_size,
+                                      GFP_KERNEL, &int_out_urb->transfer_dma);
+               if (!buf) {
+                       retval = -ENOMEM;
+                       dbg("%s Unable to allocate buffer ", __func__);
+                       goto error;
+               }
+               usb_fill_int_urb(int_out_urb, dev->udev,
+                                usb_sndintpipe(dev->udev,
+                                               dev->int_out_endpoint->bEndpointAddress),
+                                buf, dev->report_size,
+                                iowarrior_write_callback, dev,
+                                dev->int_out_endpoint->bInterval);
+               int_out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+               if (copy_from_user(buf, user_buffer, count)) {
+                       retval = -EFAULT;
+                       goto error;
+               }
+               retval = usb_submit_urb(int_out_urb, GFP_KERNEL);
+               if (retval) {
+                       dbg("%s submit error %d for urb nr.%d", __func__,
+                           retval, atomic_read(&dev->write_busy));
+                       goto error;
+               }
+               /* submit was ok */
+               retval = count;
+               usb_free_urb(int_out_urb);
+               goto exit;
+               break;
+       default:
+               /* what do we have here ? An unsupported Product-ID ? */
+               dev_err(&dev->interface->dev, "%s - not supported for product=0x%x",
+                       __FUNCTION__, dev->product_id);
+               retval = -EFAULT;
+               goto exit;
+               break;
+       }
+error:
+       usb_buffer_free(dev->udev, dev->report_size, buf,
+                       int_out_urb->transfer_dma);
+       usb_free_urb(int_out_urb);
+       atomic_dec(&dev->write_busy);
+       wake_up_interruptible(&dev->write_wait);
+exit:
+       mutex_unlock(&dev->mutex);
+       return retval;
+}
+
+/**
+ *     iowarrior_ioctl
+ */
+static int iowarrior_ioctl(struct inode *inode, struct file *file,
+                          unsigned int cmd, unsigned long arg)
+{
+       struct iowarrior *dev = NULL;
+       __u8 *buffer;
+       __u8 __user *user_buffer;
+       int retval;
+       int io_res;             /* checks for bytes read/written and copy_to/from_user results */
+
+       dev = (struct iowarrior *)file->private_data;
+       if (dev == NULL) {
+               return -ENODEV;
+       }
+
+       buffer = kzalloc(dev->report_size, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       /* lock this object */
+       mutex_lock(&dev->mutex);
+
+       /* verify that the device wasn't unplugged */
+       if (!dev->present) {
+               mutex_unlock(&dev->mutex);
+               return -ENODEV;
+       }
+
+       dbg("%s - minor %d, cmd 0x%.4x, arg %ld", __func__, dev->minor, cmd,
+           arg);
+
+       retval = 0;
+       io_res = 0;
+       switch (cmd) {
+       case IOW_WRITE:
+               if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24 ||
+                   dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV1 ||
+                   dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV2 ||
+                   dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW40) {
+                       user_buffer = (__u8 __user *)arg;
+                       io_res = copy_from_user(buffer, user_buffer,
+                                               dev->report_size);
+                       if (io_res) {
+                               retval = -EFAULT;
+                       } else {
+                               io_res = usb_set_report(dev->interface, 2, 0,
+                                                       buffer,
+                                                       dev->report_size);
+                               if (io_res < 0)
+                                       retval = io_res;
+                       }
+               } else {
+                       retval = -EINVAL;
+                       dev_err(&dev->interface->dev,
+                               "ioctl 'IOW_WRITE' is not supported for product=0x%x.",
+                               dev->product_id);
+               }
+               break;
+       case IOW_READ:
+               user_buffer = (__u8 __user *)arg;
+               io_res = usb_get_report(dev->udev,
+                                       dev->interface->cur_altsetting, 1, 0,
+                                       buffer, dev->report_size);
+               if (io_res < 0)
+                       retval = io_res;
+               else {
+                       io_res = copy_to_user(user_buffer, buffer, dev->report_size);
+                       if (io_res < 0)
+                               retval = -EFAULT;
+               }
+               break;
+       case IOW_GETINFO:
+               {
+                       /* Report available information for the device */
+                       struct iowarrior_info info;
+                       /* needed for power consumption */
+                       struct usb_config_descriptor *cfg_descriptor = &dev->udev->actconfig->desc;
+
+                       /* directly from the descriptor */
+                       info.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+                       info.product = dev->product_id;
+                       info.revision = le16_to_cpu(dev->udev->descriptor.bcdDevice);
+
+                       /* 0==UNKNOWN, 1==LOW(usb1.1) ,2=FULL(usb1.1), 3=HIGH(usb2.0) */
+                       info.speed = le16_to_cpu(dev->udev->speed);
+                       info.if_num = dev->interface->cur_altsetting->desc.bInterfaceNumber;
+                       info.report_size = dev->report_size;
+
+                       /* serial number string has been read earlier 8 chars or empty string */
+                       memcpy(info.serial, dev->chip_serial,
+                              sizeof(dev->chip_serial));
+                       if (cfg_descriptor == NULL) {
+                               info.power = -1;        /* no information available */
+                       } else {
+                               /* the MaxPower is stored in units of 2mA to make it fit into a byte-value */
+                               info.power = cfg_descriptor->bMaxPower * 2;
+                       }
+                       io_res = copy_to_user((struct iowarrior_info __user *)arg, &info,
+                                        sizeof(struct iowarrior_info));
+                       if (io_res < 0)
+                               retval = -EFAULT;
+                       break;
+               }
+       default:
+               /* return that we did not understand this ioctl call */
+               retval = -ENOTTY;
+               break;
+       }
+
+       /* unlock the device */
+       mutex_unlock(&dev->mutex);
+       return retval;
+}
+
+/**
+ *     iowarrior_open
+ */
+static int iowarrior_open(struct inode *inode, struct file *file)
+{
+       struct iowarrior *dev = NULL;
+       struct usb_interface *interface;
+       int subminor;
+       int retval = 0;
+
+       dbg("%s", __func__);
+
+       subminor = iminor(inode);
+
+       /* prevent disconnects */
+       down(&disconnect_sem);
+
+       interface = usb_find_interface(&iowarrior_driver, subminor);
+       if (!interface) {
+               err("%s - error, can't find device for minor %d", __FUNCTION__,
+                   subminor);
+               retval = -ENODEV;
+               goto out;
+       }
+
+       dev = usb_get_intfdata(interface);
+       if (!dev) {
+               retval = -ENODEV;
+               goto out;
+       }
+
+       /* Only one process can open each device, no sharing. */
+       if (dev->opened) {
+               retval = -EBUSY;
+               goto out;
+       }
+
+       /* setup interrupt handler for receiving values */
+       if ((retval = usb_submit_urb(dev->int_in_urb, GFP_KERNEL)) < 0) {
+               dev_err(&interface->dev, "Error %d while submitting URB\n", retval);
+               retval = -EFAULT;
+               goto out;
+       }
+       /* increment our usage count for the driver */
+       ++dev->opened;
+       /* save our object in the file's private structure */
+       file->private_data = dev;
+       retval = 0;
+
+out:
+       up(&disconnect_sem);
+       return retval;
+}
+
+/**
+ *     iowarrior_release
+ */
+static int iowarrior_release(struct inode *inode, struct file *file)
+{
+       struct iowarrior *dev;
+       int retval = 0;
+
+       dev = (struct iowarrior *)file->private_data;
+       if (dev == NULL) {
+               return -ENODEV;
+       }
+
+       dbg("%s - minor %d", __func__, dev->minor);
+
+       /* lock our device */
+       mutex_lock(&dev->mutex);
+
+       if (dev->opened <= 0) {
+               retval = -ENODEV;       /* close called more than once */
+               mutex_unlock(&dev->mutex);
+       } else {
+               dev->opened = 0;        /* we're closeing now */
+               retval = 0;
+               if (dev->present) {
+                       /*
+                          The device is still connected so we only shutdown
+                          pending read-/write-ops.
+                        */
+                       usb_kill_urb(dev->int_in_urb);
+                       wake_up_interruptible(&dev->read_wait);
+                       wake_up_interruptible(&dev->write_wait);
+                       mutex_unlock(&dev->mutex);
+               } else {
+                       /* The device was unplugged, cleanup resources */
+                       mutex_unlock(&dev->mutex);
+                       iowarrior_delete(dev);
+               }
+       }
+       return retval;
+}
+
+static unsigned iowarrior_poll(struct file *file, poll_table * wait)
+{
+       struct iowarrior *dev = file->private_data;
+       unsigned int mask = 0;
+
+       if (!dev->present)
+               return POLLERR | POLLHUP;
+
+       poll_wait(file, &dev->read_wait, wait);
+       poll_wait(file, &dev->write_wait, wait);
+
+       if (!dev->present)
+               return POLLERR | POLLHUP;
+
+       if (read_index(dev) != -1)
+               mask |= POLLIN | POLLRDNORM;
+
+       if (atomic_read(&dev->write_busy) < MAX_WRITES_IN_FLIGHT)
+               mask |= POLLOUT | POLLWRNORM;
+       return mask;
+}
+
+/*
+ * File operations needed when we register this driver.
+ * This assumes that this driver NEEDS file operations,
+ * of course, which means that the driver is expected
+ * to have a node in the /dev directory. If the USB
+ * device were for a network interface then the driver
+ * would use "struct net_driver" instead, and a serial
+ * device would use "struct tty_driver".
+ */
+static struct file_operations iowarrior_fops = {
+       .owner = THIS_MODULE,
+       .write = iowarrior_write,
+       .read = iowarrior_read,
+       .ioctl = iowarrior_ioctl,
+       .open = iowarrior_open,
+       .release = iowarrior_release,
+       .poll = iowarrior_poll,
+};
+
+/*
+ * usb class driver info in order to get a minor number from the usb core,
+ * and to have the device registered with devfs and the driver core
+ */
+static struct usb_class_driver iowarrior_class = {
+       .name = "iowarrior%d",
+       .fops = &iowarrior_fops,
+       .minor_base = IOWARRIOR_MINOR_BASE,
+};
+
+/*---------------------------------*/
+/*  probe and disconnect functions */
+/*---------------------------------*/
+/**
+ *     iowarrior_probe
+ *
+ *     Called by the usb core when a new device is connected that it thinks
+ *     this driver might be interested in.
+ */
+static int iowarrior_probe(struct usb_interface *interface,
+                          const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(interface);
+       struct iowarrior *dev = NULL;
+       struct usb_host_interface *iface_desc;
+       struct usb_endpoint_descriptor *endpoint;
+       int i;
+       int retval = -ENOMEM;
+       int idele = 0;
+
+       /* allocate memory for our device state and intialize it */
+       dev = kzalloc(sizeof(struct iowarrior), GFP_KERNEL);
+       if (dev == NULL) {
+               dev_err(&interface->dev, "Out of memory");
+               return retval;
+       }
+
+       mutex_init(&dev->mutex);
+
+       atomic_set(&dev->intr_idx, 0);
+       atomic_set(&dev->read_idx, 0);
+       spin_lock_init(&dev->intr_idx_lock);
+       atomic_set(&dev->overflow_flag, 0);
+       init_waitqueue_head(&dev->read_wait);
+       atomic_set(&dev->write_busy, 0);
+       init_waitqueue_head(&dev->write_wait);
+
+       dev->udev = udev;
+       dev->interface = interface;
+
+       iface_desc = interface->cur_altsetting;
+       dev->product_id = le16_to_cpu(udev->descriptor.idProduct);
+
+       /* set up the endpoint information */
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+               endpoint = &iface_desc->endpoint[i].desc;
+
+               if (usb_endpoint_is_int_in(endpoint))
+                       dev->int_in_endpoint = endpoint;
+               if (usb_endpoint_is_int_out(endpoint))
+                       /* this one will match for the IOWarrior56 only */
+                       dev->int_out_endpoint = endpoint;
+       }
+       /* we have to check the report_size often, so remember it in the endianess suitable for our machine */
+       dev->report_size = le16_to_cpu(dev->int_in_endpoint->wMaxPacketSize);
+       if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) &&
+           (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56))
+               /* IOWarrior56 has wMaxPacketSize different from report size */
+               dev->report_size = 7;
+
+       /* create the urb and buffer for reading */
+       dev->int_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!dev->int_in_urb) {
+               dev_err(&interface->dev, "Couldn't allocate interrupt_in_urb\n");
+               goto error;
+       }
+       dev->int_in_buffer = kmalloc(dev->report_size, GFP_KERNEL);
+       if (!dev->int_in_buffer) {
+               dev_err(&interface->dev, "Couldn't allocate int_in_buffer\n");
+               goto error;
+       }
+       usb_fill_int_urb(dev->int_in_urb, dev->udev,
+                        usb_rcvintpipe(dev->udev,
+                                       dev->int_in_endpoint->bEndpointAddress),
+                        dev->int_in_buffer, dev->report_size,
+                        iowarrior_callback, dev,
+                        dev->int_in_endpoint->bInterval);
+       /* create an internal buffer for interrupt data from the device */
+       dev->read_queue =
+           kmalloc(((dev->report_size + 1) * MAX_INTERRUPT_BUFFER),
+                   GFP_KERNEL);
+       if (!dev->read_queue) {
+               dev_err(&interface->dev, "Couldn't allocate read_queue\n");
+               goto error;
+       }
+       /* Get the serial-number of the chip */
+       memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial));
+       usb_string(udev, udev->descriptor.iSerialNumber, dev->chip_serial,
+                  sizeof(dev->chip_serial));
+       if (strlen(dev->chip_serial) != 8)
+               memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial));
+
+       /* Set the idle timeout to 0, if this is interface 0 */
+       if (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) {
+               idele = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                                       0x0A,
+                                       USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
+                                       0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+               dbg("idele = %d", idele);
+       }
+       /* allow device read and ioctl */
+       dev->present = 1;
+
+       /* we can register the device now, as it is ready */
+       usb_set_intfdata(interface, dev);
+
+       retval = usb_register_dev(interface, &iowarrior_class);
+       if (retval) {
+               /* something prevented us from registering this driver */
+               dev_err(&interface->dev, "Not able to get a minor for this device.\n");
+               usb_set_intfdata(interface, NULL);
+               goto error;
+       }
+
+       dev->minor = interface->minor;
+
+       /* let the user know what node this device is now attached to */
+       dev_info(&interface->dev, "IOWarrior product=0x%x, serial=%s interface=%d "
+                "now attached to iowarrior%d\n", dev->product_id, dev->chip_serial,
+                iface_desc->desc.bInterfaceNumber, dev->minor - IOWARRIOR_MINOR_BASE);
+       return retval;
+
+error:
+       iowarrior_delete(dev);
+       return retval;
+}
+
+/**
+ *     iowarrior_disconnect
+ *
+ *     Called by the usb core when the device is removed from the system.
+ */
+static void iowarrior_disconnect(struct usb_interface *interface)
+{
+       struct iowarrior *dev;
+       int minor;
+
+       /* prevent races with open() */
+       down(&disconnect_sem);
+
+       dev = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
+
+       mutex_lock(&dev->mutex);
+
+       minor = dev->minor;
+
+       /* give back our minor */
+       usb_deregister_dev(interface, &iowarrior_class);
+
+       /* prevent device read, write and ioctl */
+       dev->present = 0;
+
+       mutex_unlock(&dev->mutex);
+
+       if (dev->opened) {
+               /* There is a process that holds a filedescriptor to the device ,
+                  so we only shutdown read-/write-ops going on.
+                  Deleting the device is postponed until close() was called.
+                */
+               usb_kill_urb(dev->int_in_urb);
+               wake_up_interruptible(&dev->read_wait);
+               wake_up_interruptible(&dev->write_wait);
+       } else {
+               /* no process is using the device, cleanup now */
+               iowarrior_delete(dev);
+       }
+       up(&disconnect_sem);
+
+       dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n",
+                minor - IOWARRIOR_MINOR_BASE);
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver iowarrior_driver = {
+       .name = "iowarrior",
+       .probe = iowarrior_probe,
+       .disconnect = iowarrior_disconnect,
+       .id_table = iowarrior_ids,
+};
+
+static int __init iowarrior_init(void)
+{
+       return usb_register(&iowarrior_driver);
+}
+
+static void __exit iowarrior_exit(void)
+{
+       usb_deregister(&iowarrior_driver);
+}
+
+module_init(iowarrior_init);
+module_exit(iowarrior_exit);
index c01dfe6..b2bedd9 100644 (file)
@@ -1165,7 +1165,7 @@ err_dev:
        return rc;
 }
 
-void __exit mon_bin_exit(void)
+void mon_bin_exit(void)
 {
        cdev_del(&mon_bin_cdev);
        unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
index d38a127..494ee3b 100644 (file)
@@ -520,7 +520,7 @@ int __init mon_text_init(void)
        return 0;
 }
 
-void __exit mon_text_exit(void)
+void mon_text_exit(void)
 {
        debugfs_remove(mon_dir);
 }
index 4f949ce..efdfd89 100644 (file)
@@ -57,9 +57,9 @@ void mon_text_del(struct mon_bus *mbus);
 // void mon_bin_add(struct mon_bus *);
 
 int __init mon_text_init(void);
-void __exit mon_text_exit(void);
+void mon_text_exit(void);
 int __init mon_bin_init(void);
-void __exit mon_bin_exit(void);
+void mon_bin_exit(void);
 
 /*
  * DMA interface.
index 0f3d7db..3de564b 100644 (file)
@@ -186,6 +186,15 @@ config USB_NET_CDCETHER
          IEEE 802 "local assignment" bit is set in the address, a "usbX"
          name is used instead.
 
+config USB_NET_DM9601
+       tristate "Davicom DM9601 based USB 1.1 10/100 ethernet devices"
+       depends on USB_USBNET
+       select CRC32
+       select USB_USBNET_MII
+       help
+         This option adds support for Davicom DM9601 based USB 1.1
+         10/100 Ethernet adapters.
+
 config USB_NET_GL620A
        tristate "GeneSys GL620USB-A based cables"
        depends on USB_USBNET
index 7b51964..595a539 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_USB_PEGASUS)       += pegasus.o
 obj-$(CONFIG_USB_RTL8150)      += rtl8150.o
 obj-$(CONFIG_USB_NET_AX8817X)  += asix.o
 obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
+obj-$(CONFIG_USB_NET_DM9601)   += dm9601.o
 obj-$(CONFIG_USB_NET_GL620A)   += gl620a.o
 obj-$(CONFIG_USB_NET_NET1080)  += net1080.o
 obj-$(CONFIG_USB_NET_PLUSB)    += plusb.o
index 7ef2e4b..5808ea0 100644 (file)
@@ -1395,9 +1395,9 @@ static const struct usb_device_id products [] = {
        USB_DEVICE (0x07b8, 0x420a),
        .driver_info =  (unsigned long) &hawking_uf200_info,
 }, {
-        // Billionton Systems, USB2AR
-        USB_DEVICE (0x08dd, 0x90ff),
-        .driver_info =  (unsigned long) &ax8817x_info,
+       // Billionton Systems, USB2AR
+       USB_DEVICE (0x08dd, 0x90ff),
+       .driver_info =  (unsigned long) &ax8817x_info,
 }, {
        // ATEN UC210T
        USB_DEVICE (0x0557, 0x2009),
@@ -1423,9 +1423,13 @@ static const struct usb_device_id        products [] = {
        USB_DEVICE (0x1631, 0x6200),
        .driver_info = (unsigned long) &ax8817x_info,
 }, {
+       // JVC MP-PRX1 Port Replicator
+       USB_DEVICE (0x04f1, 0x3008),
+       .driver_info = (unsigned long) &ax8817x_info,
+}, {
        // ASIX AX88772 10/100
-        USB_DEVICE (0x0b95, 0x7720),
-        .driver_info = (unsigned long) &ax88772_info,
+       USB_DEVICE (0x0b95, 0x7720),
+       .driver_info = (unsigned long) &ax88772_info,
 }, {
        // ASIX AX88178 10/100/1000
        USB_DEVICE (0x0b95, 0x1780),
diff --git a/drivers/usb/net/dm9601.c b/drivers/usb/net/dm9601.c
new file mode 100644 (file)
index 0000000..4a932e1
--- /dev/null
@@ -0,0 +1,606 @@
+/*
+ * Davicom DM9601 USB 1.1 10/100Mbps ethernet devices
+ *
+ * Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+//#define DEBUG
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+
+#include "usbnet.h"
+
+/* datasheet:
+ http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-P01-930914.pdf
+*/
+
+/* control requests */
+#define DM_READ_REGS   0x00
+#define DM_WRITE_REGS  0x01
+#define DM_READ_MEMS   0x02
+#define DM_WRITE_REG   0x03
+#define DM_WRITE_MEMS  0x05
+#define DM_WRITE_MEM   0x07
+
+/* registers */
+#define DM_NET_CTRL    0x00
+#define DM_RX_CTRL     0x05
+#define DM_SHARED_CTRL 0x0b
+#define DM_SHARED_ADDR 0x0c
+#define DM_SHARED_DATA 0x0d    /* low + high */
+#define DM_PHY_ADDR    0x10    /* 6 bytes */
+#define DM_MCAST_ADDR  0x16    /* 8 bytes */
+#define DM_GPR_CTRL    0x1e
+#define DM_GPR_DATA    0x1f
+
+#define DM_MAX_MCAST   64
+#define DM_MCAST_SIZE  8
+#define DM_EEPROM_LEN  256
+#define DM_TX_OVERHEAD 2       /* 2 byte header */
+#define DM_RX_OVERHEAD 7       /* 3 byte header + 4 byte crc tail */
+#define DM_TIMEOUT     1000
+
+
+static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+       devdbg(dev, "dm_read() reg=0x%02x length=%d", reg, length);
+       return usb_control_msg(dev->udev,
+                              usb_rcvctrlpipe(dev->udev, 0),
+                              DM_READ_REGS,
+                              USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                              0, reg, data, length, USB_CTRL_SET_TIMEOUT);
+}
+
+static int dm_read_reg(struct usbnet *dev, u8 reg, u8 *value)
+{
+       return dm_read(dev, reg, 1, value);
+}
+
+static int dm_write(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+       devdbg(dev, "dm_write() reg=0x%02x, length=%d", reg, length);
+       return usb_control_msg(dev->udev,
+                              usb_sndctrlpipe(dev->udev, 0),
+                              DM_WRITE_REGS,
+                              USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE,
+                              0, reg, data, length, USB_CTRL_SET_TIMEOUT);
+}
+
+static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value)
+{
+       devdbg(dev, "dm_write_reg() reg=0x%02x, value=0x%02x", reg, value);
+       return usb_control_msg(dev->udev,
+                              usb_sndctrlpipe(dev->udev, 0),
+                              DM_WRITE_REG,
+                              USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE,
+                              value, reg, 0, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+static void dm_write_async_callback(struct urb *urb)
+{
+       struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
+
+       if (urb->status < 0)
+               printk(KERN_DEBUG "dm_write_async_callback() failed with %d",
+                      urb->status);
+
+       kfree(req);
+       usb_free_urb(urb);
+}
+
+static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+       struct usb_ctrlrequest *req;
+       struct urb *urb;
+       int status;
+
+       devdbg(dev, "dm_write_async() reg=0x%02x length=%d", reg, length);
+
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!urb) {
+               deverr(dev, "Error allocating URB in dm_write_async!");
+               return;
+       }
+
+       req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
+       if (!req) {
+               deverr(dev, "Failed to allocate memory for control request");
+               usb_free_urb(urb);
+               return;
+       }
+
+       req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+       req->bRequest = DM_WRITE_REGS;
+       req->wValue = 0;
+       req->wIndex = cpu_to_le16(reg);
+       req->wLength = cpu_to_le16(length);
+
+       usb_fill_control_urb(urb, dev->udev,
+                            usb_sndctrlpipe(dev->udev, 0),
+                            (void *)req, data, length,
+                            dm_write_async_callback, req);
+
+       status = usb_submit_urb(urb, GFP_ATOMIC);
+       if (status < 0) {
+               deverr(dev, "Error submitting the control message: status=%d",
+                      status);
+               kfree(req);
+               usb_free_urb(urb);
+       }
+}
+
+static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
+{
+       struct usb_ctrlrequest *req;
+       struct urb *urb;
+       int status;
+
+       devdbg(dev, "dm_write_reg_async() reg=0x%02x value=0x%02x",
+              reg, value);
+
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!urb) {
+               deverr(dev, "Error allocating URB in dm_write_async!");
+               return;
+       }
+
+       req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
+       if (!req) {
+               deverr(dev, "Failed to allocate memory for control request");
+               usb_free_urb(urb);
+               return;
+       }
+
+       req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+       req->bRequest = DM_WRITE_REG;
+       req->wValue = cpu_to_le16(value);
+       req->wIndex = cpu_to_le16(reg);
+       req->wLength = 0;
+
+       usb_fill_control_urb(urb, dev->udev,
+                            usb_sndctrlpipe(dev->udev, 0),
+                            (void *)req, 0, 0, dm_write_async_callback, req);
+
+       status = usb_submit_urb(urb, GFP_ATOMIC);
+       if (status < 0) {
+               deverr(dev, "Error submitting the control message: status=%d",
+                      status);
+               kfree(req);
+               usb_free_urb(urb);
+       }
+}
+
+static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, u16 *value)
+{
+       int ret, i;
+
+       mutex_lock(&dev->phy_mutex);
+
+       dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg);
+       dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0xc : 0x4);
+
+       for (i = 0; i < DM_TIMEOUT; i++) {
+               u8 tmp;
+
+               udelay(1);
+               ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
+               if (ret < 0)
+                       goto out;
+
+               /* ready */
+               if ((tmp & 1) == 0)
+                       break;
+       }
+
+       if (i == DM_TIMEOUT) {
+               deverr(dev, "%s read timed out!", phy ? "phy" : "eeprom");
+               ret = -EIO;
+               goto out;
+       }
+
+       dm_write_reg(dev, DM_SHARED_CTRL, 0x0);
+       ret = dm_read(dev, DM_SHARED_DATA, 2, value);
+
+       devdbg(dev, "read shared %d 0x%02x returned 0x%04x, %d",
+              phy, reg, *value, ret);
+
+ out:
+       mutex_unlock(&dev->phy_mutex);
+       return ret;
+}
+
+static int dm_write_shared_word(struct usbnet *dev, int phy, u8 reg, u16 value)
+{
+       int ret, i;
+
+       mutex_lock(&dev->phy_mutex);
+
+       ret = dm_write(dev, DM_SHARED_DATA, 2, &value);
+       if (ret < 0)
+               goto out;
+
+       dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg);
+       dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x1c : 0x14);
+
+       for (i = 0; i < DM_TIMEOUT; i++) {
+               u8 tmp;
+
+               udelay(1);
+               ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
+               if (ret < 0)
+                       goto out;
+
+               /* ready */
+               if ((tmp & 1) == 0)
+                       break;
+       }
+
+       if (i == DM_TIMEOUT) {
+               deverr(dev, "%s write timed out!", phy ? "phy" : "eeprom");
+               ret = -EIO;
+               goto out;
+       }
+
+       dm_write_reg(dev, DM_SHARED_CTRL, 0x0);
+
+out:
+       mutex_unlock(&dev->phy_mutex);
+       return ret;
+}
+
+static int dm_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
+{
+       return dm_read_shared_word(dev, 0, offset, value);
+}
+
+
+
+static int dm9601_get_eeprom_len(struct net_device *dev)
+{
+       return DM_EEPROM_LEN;
+}
+
+static int dm9601_get_eeprom(struct net_device *net,
+                            struct ethtool_eeprom *eeprom, u8 * data)
+{
+       struct usbnet *dev = netdev_priv(net);
+       u16 *ebuf = (u16 *) data;
+       int i;
+
+       /* access is 16bit */
+       if ((eeprom->offset % 2) || (eeprom->len % 2))
+               return -EINVAL;
+
+       for (i = 0; i < eeprom->len / 2; i++) {
+               if (dm_read_eeprom_word(dev, eeprom->offset / 2 + i,
+                                       &ebuf[i]) < 0)
+                       return -EINVAL;
+       }
+       return 0;
+}
+
+static int dm9601_mdio_read(struct net_device *netdev, int phy_id, int loc)
+{
+       struct usbnet *dev = netdev_priv(netdev);
+
+       u16 res;
+
+       if (phy_id) {
+               devdbg(dev, "Only internal phy supported");
+               return 0;
+       }
+
+       dm_read_shared_word(dev, 1, loc, &res);
+
+       devdbg(dev,
+              "dm9601_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x",
+              phy_id, loc, le16_to_cpu(res));
+
+       return le16_to_cpu(res);
+}
+
+static void dm9601_mdio_write(struct net_device *netdev, int phy_id, int loc,
+                             int val)
+{
+       struct usbnet *dev = netdev_priv(netdev);
+       u16 res = cpu_to_le16(val);
+
+       if (phy_id) {
+               devdbg(dev, "Only internal phy supported");
+               return;
+       }
+
+       devdbg(dev,"dm9601_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x",
+              phy_id, loc, val);
+
+       dm_write_shared_word(dev, 1, loc, res);
+}
+
+static void dm9601_get_drvinfo(struct net_device *net,
+                              struct ethtool_drvinfo *info)
+{
+       /* Inherit standard device info */
+       usbnet_get_drvinfo(net, info);
+       info->eedump_len = DM_EEPROM_LEN;
+}
+
+static u32 dm9601_get_link(struct net_device *net)
+{
+       struct usbnet *dev = netdev_priv(net);
+
+       return mii_link_ok(&dev->mii);
+}
+
+static int dm9601_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+       struct usbnet *dev = netdev_priv(net);
+
+       return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+static struct ethtool_ops dm9601_ethtool_ops = {
+       .get_drvinfo    = dm9601_get_drvinfo,
+       .get_link       = dm9601_get_link,
+       .get_msglevel   = usbnet_get_msglevel,
+       .set_msglevel   = usbnet_set_msglevel,
+       .get_eeprom_len = dm9601_get_eeprom_len,
+       .get_eeprom     = dm9601_get_eeprom,
+       .get_settings   = usbnet_get_settings,
+       .set_settings   = usbnet_set_settings,
+       .nway_reset     = usbnet_nway_reset,
+};
+
+static void dm9601_set_multicast(struct net_device *net)
+{
+       struct usbnet *dev = netdev_priv(net);
+       /* We use the 20 byte dev->data for our 8 byte filter buffer
+        * to avoid allocating memory that is tricky to free later */
+       u8 *hashes = (u8 *) & dev->data;
+       u8 rx_ctl = 0x01;
+
+       memset(hashes, 0x00, DM_MCAST_SIZE);
+       hashes[DM_MCAST_SIZE - 1] |= 0x80;      /* broadcast address */
+
+       if (net->flags & IFF_PROMISC) {
+               rx_ctl |= 0x02;
+       } else if (net->flags & IFF_ALLMULTI || net->mc_count > DM_MAX_MCAST) {
+               rx_ctl |= 0x04;
+       } else if (net->mc_count) {
+               struct dev_mc_list *mc_list = net->mc_list;
+               int i;
+
+               for (i = 0; i < net->mc_count; i++) {
+                       u32 crc = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26;
+                       hashes[crc >> 3] |= 1 << (crc & 0x7);
+               }
+       }
+
+       dm_write_async(dev, DM_MCAST_ADDR, DM_MCAST_SIZE, hashes);
+       dm_write_reg_async(dev, DM_RX_CTRL, rx_ctl);
+}
+
+static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+       int ret;
+
+       ret = usbnet_get_endpoints(dev, intf);
+       if (ret)
+               goto out;
+
+       dev->net->do_ioctl = dm9601_ioctl;
+       dev->net->set_multicast_list = dm9601_set_multicast;
+       dev->net->ethtool_ops = &dm9601_ethtool_ops;
+       dev->net->hard_header_len += DM_TX_OVERHEAD;
+       dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
+       dev->rx_urb_size = dev->net->mtu + DM_RX_OVERHEAD;
+
+       dev->mii.dev = dev->net;
+       dev->mii.mdio_read = dm9601_mdio_read;
+       dev->mii.mdio_write = dm9601_mdio_write;
+       dev->mii.phy_id_mask = 0x1f;
+       dev->mii.reg_num_mask = 0x1f;
+
+       /* reset */
+       ret = dm_write_reg(dev, DM_NET_CTRL, 1);
+       udelay(20);
+
+       /* read MAC */
+       ret = dm_read(dev, DM_PHY_ADDR, ETH_ALEN, dev->net->dev_addr);
+       if (ret < 0) {
+               printk(KERN_ERR "Error reading MAC address\n");
+               ret = -ENODEV;
+               goto out;
+       }
+
+
+       /* power up phy */
+       dm_write_reg(dev, DM_GPR_CTRL, 1);
+       dm_write_reg(dev, DM_GPR_DATA, 0);
+
+       /* receive broadcast packets */
+       dm9601_set_multicast(dev->net);
+
+       dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+       dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+                         ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+       mii_nway_restart(&dev->mii);
+
+out:
+       return ret;
+}
+
+static int dm9601_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+       u8 status;
+       int len;
+
+       /* format:
+          b0: rx status
+          b1: packet length (incl crc) low
+          b2: packet length (incl crc) high
+          b3..n-4: packet data
+          bn-3..bn: ethernet crc
+        */
+
+       if (unlikely(skb->len < DM_RX_OVERHEAD)) {
+               dev_err(&dev->udev->dev, "unexpected tiny rx frame\n");
+               return 0;
+       }
+
+       status = skb->data[0];
+       len = (skb->data[1] | (skb->data[2] << 8)) - 4;
+
+       if (unlikely(status & 0xbf)) {
+               if (status & 0x01) dev->stats.rx_fifo_errors++;
+               if (status & 0x02) dev->stats.rx_crc_errors++;
+               if (status & 0x04) dev->stats.rx_frame_errors++;
+               if (status & 0x20) dev->stats.rx_missed_errors++;
+               if (status & 0x90) dev->stats.rx_length_errors++;
+               return 0;
+       }
+
+       skb_pull(skb, 3);
+       skb_trim(skb, len);
+
+       return 1;
+}
+
+static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
+                                      gfp_t flags)
+{
+       int len;
+
+       /* format:
+          b0: packet length low
+          b1: packet length high
+          b3..n: packet data
+       */
+
+       if (skb_headroom(skb) < DM_TX_OVERHEAD) {
+               struct sk_buff *skb2;
+
+               skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, 0, flags);
+               dev_kfree_skb_any(skb);
+               skb = skb2;
+               if (!skb)
+                       return NULL;
+       }
+
+       __skb_push(skb, DM_TX_OVERHEAD);
+
+       len = skb->len;
+       /* usbnet adds padding if length is a multiple of packet size
+          if so, adjust length value in header */
+       if ((len % dev->maxpacket) == 0)
+               len++;
+
+       skb->data[0] = len;
+       skb->data[1] = len >> 8;
+
+       return skb;
+}
+
+static void dm9601_status(struct usbnet *dev, struct urb *urb)
+{
+       int link;
+       u8 *buf;
+
+       /* format:
+          b0: net status
+          b1: tx status 1
+          b2: tx status 2
+          b3: rx status
+          b4: rx overflow
+          b5: rx count
+          b6: tx count
+          b7: gpr
+       */
+
+       if (urb->actual_length < 8)
+               return;
+
+       buf = urb->transfer_buffer;
+
+       link = !!(buf[0] & 0x40);
+       if (netif_carrier_ok(dev->net) != link) {
+               if (link) {
+                       netif_carrier_on(dev->net);
+                       usbnet_defer_kevent (dev, EVENT_LINK_RESET);
+               }
+               else
+                       netif_carrier_off(dev->net);
+               devdbg(dev, "Link Status is: %d", link);
+       }
+}
+
+static int dm9601_link_reset(struct usbnet *dev)
+{
+       struct ethtool_cmd ecmd;
+
+       mii_check_media(&dev->mii, 1, 1);
+       mii_ethtool_gset(&dev->mii, &ecmd);
+
+       devdbg(dev, "link_reset() speed: %d duplex: %d",
+              ecmd.speed, ecmd.duplex);
+
+       return 0;
+}
+
+static const struct driver_info dm9601_info = {
+       .description    = "Davicom DM9601 USB Ethernet",
+       .flags          = FLAG_ETHER,
+       .bind           = dm9601_bind,
+       .rx_fixup       = dm9601_rx_fixup,
+       .tx_fixup       = dm9601_tx_fixup,
+       .status         = dm9601_status,
+       .link_reset     = dm9601_link_reset,
+       .reset          = dm9601_link_reset,
+};
+
+static const struct usb_device_id products[] = {
+       {
+        USB_DEVICE(0x0a46, 0x9601),    /* Davicom USB-100 */
+        .driver_info = (unsigned long)&dm9601_info,
+        },
+       {},                     // END
+};
+
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver dm9601_driver = {
+       .name = "dm9601",
+       .id_table = products,
+       .probe = usbnet_probe,
+       .disconnect = usbnet_disconnect,
+       .suspend = usbnet_suspend,
+       .resume = usbnet_resume,
+};
+
+static int __init dm9601_init(void)
+{
+       return usb_register(&dm9601_driver);
+}
+
+static void __exit dm9601_exit(void)
+{
+       usb_deregister(&dm9601_driver);
+}
+
+module_init(dm9601_init);
+module_exit(dm9601_exit);
+
+MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
+MODULE_DESCRIPTION("Davicom DM9601 USB 1.1 ethernet devices");
+MODULE_LICENSE("GPL");
index 4695952..c525b42 100644 (file)
@@ -513,6 +513,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) },
        { USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) },
+       { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
        { },                                    /* Optional parameter entry */
        { }                                     /* Terminating entry */
 };
index 7eff1c0..1bdda93 100644 (file)
 #define FTDI_TACTRIX_OPENPORT_13S_PID  0xCC49  /* OpenPort 1.3 Subaru */
 #define FTDI_TACTRIX_OPENPORT_13U_PID  0xCC4A  /* OpenPort 1.3 Universal */
 
+/*
+ * Telldus Technologies
+ */
+#define TELLDUS_VID                    0x1781  /* Vendor ID */
+#define TELLDUS_TELLSTICK_PID          0x0C30  /* RF control dongle 433 MHz using FT232RL */
+
 /* Commands */
 #define FTDI_SIO_RESET                 0 /* Reset the port */
 #define FTDI_SIO_MODEM_CTRL    1 /* Set the modem control register */
index 9963a8b..db92a7f 100644 (file)
@@ -67,50 +67,95 @@ static int  option_tiocmset(struct usb_serial_port *port, struct file *file,
 static int  option_send_setup(struct usb_serial_port *port);
 
 /* Vendor and product IDs */
-#define OPTION_VENDOR_ID                0x0AF0
-#define HUAWEI_VENDOR_ID                0x12D1
-#define NOVATELWIRELESS_VENDOR_ID       0x1410
-#define ANYDATA_VENDOR_ID               0x16d5
-
-#define OPTION_PRODUCT_OLD              0x5000
-#define OPTION_PRODUCT_FUSION           0x6000
-#define OPTION_PRODUCT_FUSION2          0x6300
-#define OPTION_PRODUCT_COBRA            0x6500
-#define OPTION_PRODUCT_COBRA2           0x6600
-#define OPTION_PRODUCT_GTMAX36          0x6701
-#define HUAWEI_PRODUCT_E600             0x1001
-#define HUAWEI_PRODUCT_E220             0x1003
-#define NOVATELWIRELESS_PRODUCT_U740    0x1400
-#define ANYDATA_PRODUCT_ID              0x6501
+#define OPTION_VENDOR_ID                       0x0AF0
+#define OPTION_PRODUCT_COLT                    0x5000
+#define OPTION_PRODUCT_RICOLA                  0x6000
+#define OPTION_PRODUCT_RICOLA_LIGHT            0x6100
+#define OPTION_PRODUCT_RICOLA_QUAD             0x6200
+#define OPTION_PRODUCT_RICOLA_QUAD_LIGHT       0x6300
+#define OPTION_PRODUCT_RICOLA_NDIS             0x6050
+#define OPTION_PRODUCT_RICOLA_NDIS_LIGHT       0x6150
+#define OPTION_PRODUCT_RICOLA_NDIS_QUAD                0x6250
+#define OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT  0x6350
+#define OPTION_PRODUCT_COBRA                   0x6500
+#define OPTION_PRODUCT_COBRA_BUS               0x6501
+#define OPTION_PRODUCT_VIPER                   0x6600
+#define OPTION_PRODUCT_VIPER_BUS               0x6601
+#define OPTION_PRODUCT_GT_MAX_READY            0x6701
+#define OPTION_PRODUCT_GT_MAX                  0x6711
+#define OPTION_PRODUCT_FUJI_MODEM_LIGHT                0x6721
+#define OPTION_PRODUCT_FUJI_MODEM_GT           0x6741
+#define OPTION_PRODUCT_FUJI_MODEM_EX           0x6761
+#define OPTION_PRODUCT_FUJI_NETWORK_LIGHT      0x6731
+#define OPTION_PRODUCT_FUJI_NETWORK_GT         0x6751
+#define OPTION_PRODUCT_FUJI_NETWORK_EX         0x6771
+#define OPTION_PRODUCT_KOI_MODEM               0x6800
+#define OPTION_PRODUCT_KOI_NETWORK             0x6811
+#define OPTION_PRODUCT_SCORPION_MODEM          0x6901
+#define OPTION_PRODUCT_SCORPION_NETWORK                0x6911
+#define OPTION_PRODUCT_ETNA_MODEM              0x7001
+#define OPTION_PRODUCT_ETNA_NETWORK            0x7011
+#define OPTION_PRODUCT_ETNA_MODEM_LITE         0x7021
+#define OPTION_PRODUCT_ETNA_MODEM_GT           0x7041
+#define OPTION_PRODUCT_ETNA_MODEM_EX           0x7061
+#define OPTION_PRODUCT_ETNA_NETWORK_LITE       0x7031
+#define OPTION_PRODUCT_ETNA_NETWORK_GT         0x7051
+#define OPTION_PRODUCT_ETNA_NETWORK_EX         0x7071
+#define OPTION_PRODUCT_ETNA_KOI_MODEM          0x7100
+#define OPTION_PRODUCT_ETNA_KOI_NETWORK                0x7111
+
+#define HUAWEI_VENDOR_ID                       0x12D1
+#define HUAWEI_PRODUCT_E600                    0x1001
+#define HUAWEI_PRODUCT_E220                    0x1003
+
+#define NOVATELWIRELESS_VENDOR_ID              0x1410
+#define NOVATELWIRELESS_PRODUCT_U740           0x1400
+
+#define ANYDATA_VENDOR_ID                      0x16d5
+#define ANYDATA_PRODUCT_ID                     0x6501
 
 static struct usb_device_id option_ids[] = {
-       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
-       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
-       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD_LIGHT) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_LIGHT) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT) },
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
-       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
-       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA_BUS) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER_BUS) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GT_MAX_READY) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GT_MAX) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_LIGHT) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_GT) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_EX) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_LIGHT) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_GT) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_EX) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_KOI_MODEM) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_KOI_NETWORK) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_SCORPION_MODEM) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_SCORPION_NETWORK) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_LITE) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_GT) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_EX) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_LITE) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_GT) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_EX) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_MODEM) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_NETWORK) },
        { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
        { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
        { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
        { } /* Terminating entry */
 };
-
-static struct usb_device_id option_ids1[] = {
-       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
-       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
-       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
-       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
-       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
-       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) },
-       { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
-       { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
-       { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
-       { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
-       { } /* Terminating entry */
-};
-
 MODULE_DEVICE_TABLE(usb, option_ids);
 
 static struct usb_driver option_driver = {
@@ -132,7 +177,7 @@ static struct usb_serial_driver option_1port_device = {
        },
        .description       = "GSM modem (1-port)",
        .usb_driver        = &option_driver,
-       .id_table          = option_ids1,
+       .id_table          = option_ids,
        .num_interrupt_in  = NUM_DONT_CARE,
        .num_bulk_in       = NUM_DONT_CARE,
        .num_bulk_out      = NUM_DONT_CARE,
index f8bc43c..c1536d7 100644 (file)
@@ -1573,6 +1573,24 @@ config FB_S3C2410_DEBUG
          Turn on debugging messages. Note that you can set/unset at run time
          through sysfs
 
+config FB_SM501
+       tristate "Silicon Motion SM501 framebuffer support"
+       depends on FB && MFD_SM501
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       ---help---
+         Frame buffer driver for the CRT and LCD controllers in the Silicon
+         Motion SM501.
+
+         This driver is also available as a module ( = code which can be
+         inserted and removed from the running kernel whenever you want). The
+         module will be called sm501fb. If you want to compile it as a module,
+         say M here and read <file:Documentation/modules.txt>.
+
+         If unsure, say N.
+
+
 config FB_PNX4008_DUM
        tristate "Display Update Module support on Philips PNX4008 board"
        depends on FB && ARCH_PNX4008
index 1b79a6f..760305c 100644 (file)
@@ -98,6 +98,7 @@ obj-$(CONFIG_FB_PNX4008_DUM)    += pnx4008/
 obj-$(CONFIG_FB_PNX4008_DUM_RGB)  += pnx4008/
 obj-$(CONFIG_FB_IBM_GXT4500)     += gxt4500.o
 obj-$(CONFIG_FB_PS3)             += ps3fb.o
+obj-$(CONFIG_FB_SM501)            += sm501fb.o
 
 # Platform or fallback drivers go here
 obj-$(CONFIG_FB_VESA)             += vesafb.o
index ab1b8fe..7e76019 100644 (file)
@@ -142,7 +142,7 @@ static int hsync2     __devinitdata;
 static int vsync1     __devinitdata;
 static int vsync2     __devinitdata;
 static int xres       __devinitdata;
-static int yres       __devinitdata;
+static int yres;
 static int vyres      __devinitdata;
 static int sync       __devinitdata;
 static int extvga     __devinitdata;
index 3162c37..98919a6 100644 (file)
@@ -1134,11 +1134,11 @@ static int  __init s3fb_setup(char *options)
                if (!*opt)
                        continue;
 #ifdef CONFIG_MTRR
-               else if (!strcmp(opt, "mtrr:"))
+               else if (!strncmp(opt, "mtrr:", 5))
                        mtrr = simple_strtoul(opt + 5, NULL, 0);
 #endif
-               else if (!strcmp(opt, "fasttext:"))
-                       mtrr = simple_strtoul(opt + 9, NULL, 0);
+               else if (!strncmp(opt, "fasttext:", 9))
+                       fasttext = simple_strtoul(opt + 9, NULL, 0);
                else
                        mode = opt;
        }
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
new file mode 100644 (file)
index 0000000..02b290c
--- /dev/null
@@ -0,0 +1,1786 @@
+/* linux/drivers/video/sm501fb.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ *     Vincent Sanders <vince@simtec.co.uk>
+ *     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.
+ *
+ * Framebuffer driver for the Silicon Motion SM501
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/div64.h>
+
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+#include <linux/sm501.h>
+#include <linux/sm501-regs.h>
+
+#define NR_PALETTE     256
+
+enum sm501_controller {
+       HEAD_CRT        = 0,
+       HEAD_PANEL      = 1,
+};
+
+/* SM501 memory adress */
+struct sm501_mem {
+       unsigned long    size;
+       unsigned long    sm_addr;
+       void __iomem    *k_addr;
+};
+
+/* private data that is shared between all frambuffers* */
+struct sm501fb_info {
+       struct device           *dev;
+       struct fb_info          *fb[2];         /* fb info for both heads */
+       struct resource         *fbmem_res;     /* framebuffer resource */
+       struct resource         *regs_res;      /* registers resource */
+       struct sm501_platdata_fb *pdata;        /* our platform data */
+
+       int                      irq;
+       int                      swap_endian;   /* set to swap rgb=>bgr */
+       void __iomem            *regs;          /* remapped registers */
+       void __iomem            *fbmem;         /* remapped framebuffer */
+       size_t                   fbmem_len;     /* length of remapped region */
+};
+
+/* per-framebuffer private data */
+struct sm501fb_par {
+       u32                      pseudo_palette[16];
+
+       enum sm501_controller    head;
+       struct sm501_mem         cursor;
+       struct sm501_mem         screen;
+       struct fb_ops            ops;
+
+       void                    *store_fb;
+       void                    *store_cursor;
+       void __iomem            *cursor_regs;
+       struct sm501fb_info     *info;
+};
+
+/* Helper functions */
+
+static inline int h_total(struct fb_var_screeninfo *var)
+{
+       return var->xres + var->left_margin +
+               var->right_margin + var->hsync_len;
+}
+
+static inline int v_total(struct fb_var_screeninfo *var)
+{
+       return var->yres + var->upper_margin +
+               var->lower_margin + var->vsync_len;
+}
+
+/* sm501fb_sync_regs()
+ *
+ * This call is mainly for PCI bus systems where we need to
+ * ensure that any writes to the bus are completed before the
+ * next phase, or after completing a function.
+*/
+
+static inline void sm501fb_sync_regs(struct sm501fb_info *info)
+{
+       readl(info->regs);
+}
+
+/* sm501_alloc_mem
+ *
+ * This is an attempt to lay out memory for the two framebuffers and
+ * everything else
+ *
+ * |fbmem_res->start                                          fbmem_res->end|
+ * |                                                                         |
+ * |fb[0].fix.smem_start    |         |fb[1].fix.smem_start    |     2K      |
+ * |-> fb[0].fix.smem_len <-| spare   |-> fb[1].fix.smem_len <-|-> cursors <-|
+ *
+ * The "spare" space is for the 2d engine data
+ * the fixed is space for the cursors (2x1Kbyte)
+ *
+ * we need to allocate memory for the 2D acceleration engine
+ * command list and the data for the engine to deal with.
+ *
+ * - all allocations must be 128bit aligned
+ * - cursors are 64x64x2 bits (1Kbyte)
+ *
+ */
+
+#define SM501_MEMF_CURSOR              (1)
+#define SM501_MEMF_PANEL               (2)
+#define SM501_MEMF_CRT                 (4)
+#define SM501_MEMF_ACCEL               (8)
+
+int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
+                   unsigned int why, size_t size)
+{
+       unsigned int ptr = 0;
+
+       switch (why) {
+       case SM501_MEMF_CURSOR:
+               ptr = inf->fbmem_len - size;
+               inf->fbmem_len = ptr;
+               break;
+
+       case SM501_MEMF_PANEL:
+               ptr = inf->fbmem_len - size;
+               if (ptr < inf->fb[0]->fix.smem_len)
+                       return -ENOMEM;
+
+               break;
+
+       case SM501_MEMF_CRT:
+               ptr = 0;
+               break;
+
+       case SM501_MEMF_ACCEL:
+               ptr = inf->fb[0]->fix.smem_len;
+
+               if ((ptr + size) >
+                   (inf->fb[1]->fix.smem_start - inf->fbmem_res->start))
+                       return -ENOMEM;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       mem->size    = size;
+       mem->sm_addr = ptr;
+       mem->k_addr  = inf->fbmem + ptr;
+
+       dev_dbg(inf->dev, "%s: result %08lx, %p - %u, %zd\n",
+               __func__, mem->sm_addr, mem->k_addr, why, size);
+
+       return 0;
+}
+
+/* sm501fb_ps_to_hz
+ *
+ * Converts a period in picoseconds to Hz.
+ *
+ * Note, we try to keep this in Hz to minimise rounding with
+ * the limited PLL settings on the SM501.
+*/
+
+static unsigned long sm501fb_ps_to_hz(unsigned long psvalue)
+{
+       unsigned long long numerator=1000000000000ULL;
+
+       /* 10^12 / picosecond period gives frequency in Hz */
+       do_div(numerator, psvalue);
+       return (unsigned long)numerator;
+}
+
+/* sm501fb_hz_to_ps is identical to the oposite transform */
+
+#define sm501fb_hz_to_ps(x) sm501fb_ps_to_hz(x)
+
+/* sm501fb_setup_gamma
+ *
+ * Programs a linear 1.0 gamma ramp in case the gamma
+ * correction is enabled without programming anything else.
+*/
+
+static void sm501fb_setup_gamma(struct sm501fb_info *fbi,
+                               unsigned long palette)
+{
+       unsigned long value = 0;
+       int offset;
+
+       /* set gamma values */
+       for (offset = 0; offset < 256 * 4; offset += 4) {
+               writel(value, fbi->regs + palette + offset);
+               value += 0x010101;      /* Advance RGB by 1,1,1.*/
+       }
+}
+
+/* sm501fb_check_var
+ *
+ * check common variables for both panel and crt
+*/
+
+static int sm501fb_check_var(struct fb_var_screeninfo *var,
+                            struct fb_info *info)
+{
+       struct sm501fb_par  *par = info->par;
+       struct sm501fb_info *sm  = par->info;
+       unsigned long tmp;
+
+       /* check we can fit these values into the registers */
+
+       if (var->hsync_len > 255 || var->vsync_len > 255)
+               return -EINVAL;
+
+       if ((var->xres + var->right_margin) >= 4096)
+               return -EINVAL;
+
+       if ((var->yres + var->lower_margin) > 2048)
+               return -EINVAL;
+
+       /* hard limits of device */
+
+       if (h_total(var) > 4096 || v_total(var) > 2048)
+               return -EINVAL;
+
+       /* check our line length is going to be 128 bit aligned */
+
+       tmp = (var->xres * var->bits_per_pixel) / 8;
+       if ((tmp & 15) != 0)
+               return -EINVAL;
+
+       /* check the virtual size */
+
+       if (var->xres_virtual > 4096 || var->yres_virtual > 2048)
+               return -EINVAL;
+
+       /* can cope with 8,16 or 32bpp */
+
+       if (var->bits_per_pixel <= 8)
+               var->bits_per_pixel = 8;
+       else if (var->bits_per_pixel <= 16)
+               var->bits_per_pixel = 16;
+       else if (var->bits_per_pixel == 24)
+               var->bits_per_pixel = 32;
+
+       /* set r/g/b positions and validate bpp */
+       switch(var->bits_per_pixel) {
+       case 8:
+               var->red.length         = var->bits_per_pixel;
+               var->red.offset         = 0;
+               var->green.length       = var->bits_per_pixel;
+               var->green.offset       = 0;
+               var->blue.length        = var->bits_per_pixel;
+               var->blue.offset        = 0;
+               var->transp.length      = 0;
+
+               break;
+
+       case 16:
+               if (sm->pdata->flags & SM501_FBPD_SWAP_FB_ENDIAN) {
+                       var->red.offset         = 11;
+                       var->green.offset       = 5;
+                       var->blue.offset        = 0;
+               } else {
+                       var->blue.offset        = 11;
+                       var->green.offset       = 5;
+                       var->red.offset         = 0;
+               }
+
+               var->red.length         = 5;
+               var->green.length       = 6;
+               var->blue.length        = 5;
+               var->transp.length      = 0;
+               break;
+
+       case 32:
+               if (sm->pdata->flags & SM501_FBPD_SWAP_FB_ENDIAN) {
+                       var->transp.offset      = 0;
+                       var->red.offset         = 8;
+                       var->green.offset       = 16;
+                       var->blue.offset        = 24;
+               } else {
+                       var->transp.offset      = 24;
+                       var->red.offset         = 16;
+                       var->green.offset       = 8;
+                       var->blue.offset        = 0;
+               }
+
+               var->red.length         = 8;
+               var->green.length       = 8;
+               var->blue.length        = 8;
+               var->transp.length      = 0;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * sm501fb_check_var_crt():
+ *
+ * check the parameters for the CRT head, and either bring them
+ * back into range, or return -EINVAL.
+*/
+
+static int sm501fb_check_var_crt(struct fb_var_screeninfo *var,
+                                struct fb_info *info)
+{
+       return sm501fb_check_var(var, info);
+}
+
+/* sm501fb_check_var_pnl():
+ *
+ * check the parameters for the CRT head, and either bring them
+ * back into range, or return -EINVAL.
+*/
+
+static int sm501fb_check_var_pnl(struct fb_var_screeninfo *var,
+                                struct fb_info *info)
+{
+       return sm501fb_check_var(var, info);
+}
+
+/* sm501fb_set_par_common
+ *
+ * set common registers for framebuffers
+*/
+
+static int sm501fb_set_par_common(struct fb_info *info,
+                                 struct fb_var_screeninfo *var)
+{
+       struct sm501fb_par  *par = info->par;
+       struct sm501fb_info *fbi = par->info;
+       unsigned long pixclock;      /* pixelclock in Hz */
+       unsigned long sm501pixclock; /* pixelclock the 501 can achive in Hz */
+       unsigned int mem_type;
+       unsigned int clock_type;
+       unsigned int head_addr;
+
+       dev_dbg(fbi->dev, "%s: %dx%d, bpp = %d, virtual %dx%d\n",
+               __func__, var->xres, var->yres, var->bits_per_pixel,
+               var->xres_virtual, var->yres_virtual);
+
+       switch (par->head) {
+       case HEAD_CRT:
+               mem_type = SM501_MEMF_CRT;
+               clock_type = SM501_CLOCK_V2XCLK;
+               head_addr = SM501_DC_CRT_FB_ADDR;
+               break;
+
+       case HEAD_PANEL:
+               mem_type = SM501_MEMF_PANEL;
+               clock_type = SM501_CLOCK_P2XCLK;
+               head_addr = SM501_DC_PANEL_FB_ADDR;
+               break;
+
+       default:
+               mem_type = 0;           /* stop compiler warnings */
+               head_addr = 0;
+               clock_type = 0;
+       }
+
+       switch (var->bits_per_pixel) {
+       case 8:
+               info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+               break;
+
+       case 16:
+               info->fix.visual = FB_VISUAL_DIRECTCOLOR;
+               break;
+
+       case 32:
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
+               break;
+       }
+
+       /* allocate fb memory within 501 */
+       info->fix.line_length = (var->xres_virtual * var->bits_per_pixel)/8;
+       info->fix.smem_len    = info->fix.line_length * var->yres_virtual;
+
+       dev_dbg(fbi->dev, "%s: line length = %u\n", __func__,
+               info->fix.line_length);
+
+       if (sm501_alloc_mem(fbi, &par->screen, mem_type,
+                           info->fix.smem_len)) {
+               dev_err(fbi->dev, "no memory available\n");
+               return -ENOMEM;
+       }
+
+       info->fix.smem_start = fbi->fbmem_res->start + par->screen.sm_addr;
+
+       info->screen_base = fbi->fbmem + par->screen.sm_addr;
+       info->screen_size = info->fix.smem_len;
+
+       /* set start of framebuffer to the screen */
+
+       writel(par->screen.sm_addr | SM501_ADDR_FLIP, fbi->regs + head_addr);
+
+       /* program CRT clock  */
+
+       pixclock = sm501fb_ps_to_hz(var->pixclock);
+
+       sm501pixclock = sm501_set_clock(fbi->dev->parent, clock_type,
+                                       pixclock);
+
+       /* update fb layer with actual clock used */
+       var->pixclock = sm501fb_hz_to_ps(sm501pixclock);
+
+       dev_dbg(fbi->dev, "%s: pixclock(ps) = %u, pixclock(Hz)  = %lu, "
+              "sm501pixclock = %lu,  error = %ld%%\n",
+              __func__, var->pixclock, pixclock, sm501pixclock,
+              ((pixclock - sm501pixclock)*100)/pixclock);
+
+       return 0;
+}
+
+/* sm501fb_set_par_geometry
+ *
+ * set the geometry registers for specified framebuffer.
+*/
+
+static void sm501fb_set_par_geometry(struct fb_info *info,
+                                    struct fb_var_screeninfo *var)
+{
+       struct sm501fb_par  *par = info->par;
+       struct sm501fb_info *fbi = par->info;
+       void __iomem *base = fbi->regs;
+       unsigned long reg;
+
+       if (par->head == HEAD_CRT)
+               base += SM501_DC_CRT_H_TOT;
+       else
+               base += SM501_DC_PANEL_H_TOT;
+
+       /* set framebuffer width and display width */
+
+       reg = info->fix.line_length;
+       reg |= ((var->xres * var->bits_per_pixel)/8) << 16;
+
+       writel(reg, fbi->regs + (par->head == HEAD_CRT ?
+                   SM501_DC_CRT_FB_OFFSET :  SM501_DC_PANEL_FB_OFFSET));
+
+       /* program horizontal total */
+
+       reg  = (h_total(var) - 1) << 16;
+       reg |= (var->xres - 1);
+
+       writel(reg, base + SM501_OFF_DC_H_TOT);
+
+       /* program horizontal sync */
+
+       reg  = var->hsync_len << 16;
+       reg |= var->xres + var->right_margin - 1;
+
+       writel(reg, base + SM501_OFF_DC_H_SYNC);
+
+       /* program vertical total */
+
+       reg  = (v_total(var) - 1) << 16;
+       reg |= (var->yres - 1);
+
+       writel(reg, base + SM501_OFF_DC_V_TOT);
+
+       /* program vertical sync */
+       reg  = var->vsync_len << 16;
+       reg |= var->yres + var->lower_margin - 1;
+
+       writel(reg, base + SM501_OFF_DC_V_SYNC);
+}
+
+/* sm501fb_pan_crt
+ *
+ * pan the CRT display output within an virtual framebuffer
+*/
+
+static int sm501fb_pan_crt(struct fb_var_screeninfo *var,
+                          struct fb_info *info)
+{
+       struct sm501fb_par  *par = info->par;
+       struct sm501fb_info *fbi = par->info;
+       unsigned int bytes_pixel = var->bits_per_pixel / 8;
+       unsigned long reg;
+       unsigned long xoffs;
+
+       xoffs = var->xoffset * bytes_pixel;
+
+       reg = readl(fbi->regs + SM501_DC_CRT_CONTROL);
+
+       reg &= ~SM501_DC_CRT_CONTROL_PIXEL_MASK;
+       reg |= ((xoffs & 15) / bytes_pixel) << 4;
+       writel(reg, fbi->regs + SM501_DC_CRT_CONTROL);
+
+       reg = (par->screen.sm_addr + xoffs +
+              var->yoffset * info->fix.line_length);
+       writel(reg | SM501_ADDR_FLIP, fbi->regs + SM501_DC_CRT_FB_ADDR);
+
+       sm501fb_sync_regs(fbi);
+       return 0;
+}
+
+/* sm501fb_pan_pnl
+ *
+ * pan the panel display output within an virtual framebuffer
+*/
+
+static int sm501fb_pan_pnl(struct fb_var_screeninfo *var,
+                          struct fb_info *info)
+{
+       struct sm501fb_par  *par = info->par;
+       struct sm501fb_info *fbi = par->info;
+       unsigned long reg;
+
+       reg = var->xoffset | (var->xres_virtual << 16);
+       writel(reg, fbi->regs + SM501_DC_PANEL_FB_WIDTH);
+
+       reg = var->yoffset | (var->yres_virtual << 16);
+       writel(reg, fbi->regs + SM501_DC_PANEL_FB_HEIGHT);
+
+       sm501fb_sync_regs(fbi);
+       return 0;
+}
+
+/* sm501fb_set_par_crt
+ *
+ * Set the CRT video mode from the fb_info structure
+*/
+
+static int sm501fb_set_par_crt(struct fb_info *info)
+{
+       struct sm501fb_par  *par = info->par;
+       struct sm501fb_info *fbi = par->info;
+       struct fb_var_screeninfo *var = &info->var;
+       unsigned long control;       /* control register */
+       int ret;
+
+       /* activate new configuration */
+
+       dev_dbg(fbi->dev, "%s(%p)\n", __func__, info);
+
+       /* enable CRT DAC - note 0 is on!*/
+       sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER);
+
+       control = readl(fbi->regs + SM501_DC_CRT_CONTROL);
+
+       control &= (SM501_DC_CRT_CONTROL_PIXEL_MASK |
+                   SM501_DC_CRT_CONTROL_GAMMA |
+                   SM501_DC_CRT_CONTROL_BLANK |
+                   SM501_DC_CRT_CONTROL_SEL |
+                   SM501_DC_CRT_CONTROL_CP |
+                   SM501_DC_CRT_CONTROL_TVP);
+
+       /* set the sync polarities before we check data source  */
+
+       if ((var->sync & FB_SYNC_HOR_HIGH_ACT) == 0)
+               control |= SM501_DC_CRT_CONTROL_HSP;
+
+       if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0)
+               control |= SM501_DC_CRT_CONTROL_VSP;
+
+       if ((control & SM501_DC_CRT_CONTROL_SEL) == 0) {
+               /* the head is displaying panel data... */
+
+               sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0);
+               goto out_update;
+       }
+
+       ret = sm501fb_set_par_common(info, var);
+       if (ret) {
+               dev_err(fbi->dev, "failed to set common parameters\n");
+               return ret;
+       }
+
+       sm501fb_pan_crt(var, info);
+       sm501fb_set_par_geometry(info, var);
+
+       control |= SM501_FIFO_3;        /* fill if >3 free slots */
+
+       switch(var->bits_per_pixel) {
+       case 8:
+               control |= SM501_DC_CRT_CONTROL_8BPP;
+               break;
+
+       case 16:
+               control |= SM501_DC_CRT_CONTROL_16BPP;
+               break;
+
+       case 32:
+               control |= SM501_DC_CRT_CONTROL_32BPP;
+               sm501fb_setup_gamma(fbi, SM501_DC_CRT_PALETTE);
+               break;
+
+       default:
+               BUG();
+       }
+
+       control |= SM501_DC_CRT_CONTROL_SEL;    /* CRT displays CRT data */
+       control |= SM501_DC_CRT_CONTROL_TE;     /* enable CRT timing */
+       control |= SM501_DC_CRT_CONTROL_ENABLE; /* enable CRT plane */
+
+ out_update:
+       dev_dbg(fbi->dev, "new control is %08lx\n", control);
+
+       writel(control, fbi->regs + SM501_DC_CRT_CONTROL);
+       sm501fb_sync_regs(fbi);
+
+       return 0;
+}
+
+static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
+{
+       unsigned long control;
+       void __iomem *ctrl_reg = fbi->regs + SM501_DC_PANEL_CONTROL;
+
+       control = readl(ctrl_reg);
+
+       if (to && (control & SM501_DC_PANEL_CONTROL_VDD) == 0) {
+               /* enable panel power */
+
+               control |= SM501_DC_PANEL_CONTROL_VDD;  /* FPVDDEN */
+               writel(control, ctrl_reg);
+               sm501fb_sync_regs(fbi);
+               mdelay(10);
+
+               control |= SM501_DC_PANEL_CONTROL_DATA; /* DATA */
+               writel(control, ctrl_reg);
+               sm501fb_sync_regs(fbi);
+               mdelay(10);
+
+               control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */
+               writel(control, ctrl_reg);
+               sm501fb_sync_regs(fbi);
+               mdelay(10);
+
+               control |= SM501_DC_PANEL_CONTROL_FPEN;
+               writel(control, ctrl_reg);
+
+       } else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) {
+               /* disable panel power */
+
+               control &= ~SM501_DC_PANEL_CONTROL_FPEN;
+               writel(control, ctrl_reg);
+               sm501fb_sync_regs(fbi);
+               mdelay(10);
+
+               control &= ~SM501_DC_PANEL_CONTROL_BIAS;
+               writel(control, ctrl_reg);
+               sm501fb_sync_regs(fbi);
+               mdelay(10);
+
+               control &= ~SM501_DC_PANEL_CONTROL_DATA;
+               writel(control, ctrl_reg);
+               sm501fb_sync_regs(fbi);
+               mdelay(10);
+
+               control &= ~SM501_DC_PANEL_CONTROL_VDD;
+               writel(control, ctrl_reg);
+               sm501fb_sync_regs(fbi);
+               mdelay(10);
+       }
+
+       sm501fb_sync_regs(fbi);
+}
+
+/* sm501fb_set_par_pnl
+ *
+ * Set the panel video mode from the fb_info structure
+*/
+
+static int sm501fb_set_par_pnl(struct fb_info *info)
+{
+       struct sm501fb_par  *par = info->par;
+       struct sm501fb_info *fbi = par->info;
+       struct fb_var_screeninfo *var = &info->var;
+       unsigned long control;
+       unsigned long reg;
+       int ret;
+
+       dev_dbg(fbi->dev, "%s(%p)\n", __func__, info);
+
+       /* activate this new configuration */
+
+       ret = sm501fb_set_par_common(info, var);
+       if (ret)
+               return ret;
+
+       sm501fb_pan_pnl(var, info);
+       sm501fb_set_par_geometry(info, var);
+
+       /* update control register */
+
+       control = readl(fbi->regs + SM501_DC_PANEL_CONTROL);
+       control &= (SM501_DC_PANEL_CONTROL_GAMMA |
+                   SM501_DC_PANEL_CONTROL_VDD  |
+                   SM501_DC_PANEL_CONTROL_DATA |
+                   SM501_DC_PANEL_CONTROL_BIAS |
+                   SM501_DC_PANEL_CONTROL_FPEN |
+                   SM501_DC_PANEL_CONTROL_CP |
+                   SM501_DC_PANEL_CONTROL_CK |
+                   SM501_DC_PANEL_CONTROL_HP |
+                   SM501_DC_PANEL_CONTROL_VP |
+                   SM501_DC_PANEL_CONTROL_HPD |
+                   SM501_DC_PANEL_CONTROL_VPD);
+
+       control |= SM501_FIFO_3;        /* fill if >3 free slots */
+
+       switch(var->bits_per_pixel) {
+       case 8:
+               control |= SM501_DC_PANEL_CONTROL_8BPP;
+               break;
+
+       case 16:
+               control |= SM501_DC_PANEL_CONTROL_16BPP;
+               break;
+
+       case 32:
+               control |= SM501_DC_PANEL_CONTROL_32BPP;
+               sm501fb_setup_gamma(fbi, SM501_DC_PANEL_PALETTE);
+               break;
+
+       default:
+               BUG();
+       }
+
+       writel(0x0, fbi->regs + SM501_DC_PANEL_PANNING_CONTROL);
+
+       /* panel plane top left and bottom right location */
+
+       writel(0x00, fbi->regs + SM501_DC_PANEL_TL_LOC);
+
+       reg  = var->xres - 1;
+       reg |= (var->yres - 1) << 16;
+
+       writel(reg, fbi->regs + SM501_DC_PANEL_BR_LOC);
+
+       /* program panel control register */
+
+       control |= SM501_DC_PANEL_CONTROL_TE;   /* enable PANEL timing */
+       control |= SM501_DC_PANEL_CONTROL_EN;   /* enable PANEL gfx plane */
+
+       if ((var->sync & FB_SYNC_HOR_HIGH_ACT) == 0)
+               control |= SM501_DC_PANEL_CONTROL_HSP;
+
+       if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0)
+               control |= SM501_DC_PANEL_CONTROL_VSP;
+
+       writel(control, fbi->regs + SM501_DC_PANEL_CONTROL);
+       sm501fb_sync_regs(fbi);
+
+       /* power the panel up */
+       sm501fb_panel_power(fbi, 1);
+       return 0;
+}
+
+
+/* chan_to_field
+ *
+ * convert a colour value into a field position
+ *
+ * from pxafb.c
+*/
+
+static inline unsigned int chan_to_field(unsigned int chan,
+                                        struct fb_bitfield *bf)
+{
+       chan &= 0xffff;
+       chan >>= 16 - bf->length;
+       return chan << bf->offset;
+}
+
+/* sm501fb_setcolreg
+ *
+ * set the colour mapping for modes that support palettised data
+*/
+
+static int sm501fb_setcolreg(unsigned regno,
+                            unsigned red, unsigned green, unsigned blue,
+                            unsigned transp, struct fb_info *info)
+{
+       struct sm501fb_par  *par = info->par;
+       struct sm501fb_info *fbi = par->info;
+       void __iomem *base = fbi->regs;
+       unsigned int val;
+
+       if (par->head == HEAD_CRT)
+               base += SM501_DC_CRT_PALETTE;
+       else
+               base += SM501_DC_PANEL_PALETTE;
+
+       switch (info->fix.visual) {
+       case FB_VISUAL_TRUECOLOR:
+               /* true-colour, use pseuo-palette */
+
+               if (regno < 16) {
+                       u32 *pal = par->pseudo_palette;
+
+                       val  = chan_to_field(red,   &info->var.red);
+                       val |= chan_to_field(green, &info->var.green);
+                       val |= chan_to_field(blue,  &info->var.blue);
+
+                       pal[regno] = val;
+               }
+               break;
+
+       case FB_VISUAL_PSEUDOCOLOR:
+               if (regno < 256) {
+                       val = (red >> 8) << 16;
+                       val |= (green >> 8) << 8;
+                       val |= blue >> 8;
+
+                       writel(val, base + (regno * 4));
+               }
+
+               break;
+
+       default:
+               return 1;   /* unknown type */
+       }
+
+       return 0;
+}
+
+/* sm501fb_blank_pnl
+ *
+ * Blank or un-blank the panel interface
+*/
+
+static int sm501fb_blank_pnl(int blank_mode, struct fb_info *info)
+{
+       struct sm501fb_par  *par = info->par;
+       struct sm501fb_info *fbi = par->info;
+
+       dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info);
+
+       switch (blank_mode) {
+       case FB_BLANK_POWERDOWN:
+               sm501fb_panel_power(fbi, 0);
+               break;
+
+       case FB_BLANK_UNBLANK:
+               sm501fb_panel_power(fbi, 1);
+               break;
+
+       case FB_BLANK_NORMAL:
+       case FB_BLANK_VSYNC_SUSPEND:
+       case FB_BLANK_HSYNC_SUSPEND:
+       default:
+               return 1;
+       }
+
+       return 0;
+}
+
+/* sm501fb_blank_crt
+ *
+ * Blank or un-blank the crt interface
+*/
+
+static int sm501fb_blank_crt(int blank_mode, struct fb_info *info)
+{
+       struct sm501fb_par  *par = info->par;
+       struct sm501fb_info *fbi = par->info;
+       unsigned long ctrl;
+
+       dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info);
+
+       ctrl = readl(fbi->regs + SM501_DC_CRT_CONTROL);
+
+       switch (blank_mode) {
+       case FB_BLANK_POWERDOWN:
+               ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE;
+               sm501_misc_control(fbi->dev->parent, SM501_MISC_DAC_POWER, 0);
+
+       case FB_BLANK_NORMAL:
+               ctrl |= SM501_DC_CRT_CONTROL_BLANK;
+               break;
+
+       case FB_BLANK_UNBLANK:
+               ctrl &= ~SM501_DC_CRT_CONTROL_BLANK;
+               ctrl |=  SM501_DC_CRT_CONTROL_ENABLE;
+               sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER);
+               break;
+
+       case FB_BLANK_VSYNC_SUSPEND:
+       case FB_BLANK_HSYNC_SUSPEND:
+       default:
+               return 1;
+
+       }
+
+       writel(ctrl, fbi->regs + SM501_DC_CRT_CONTROL);
+       sm501fb_sync_regs(fbi);
+
+       return 0;
+}
+
+/* sm501fb_cursor
+ *
+ * set or change the hardware cursor parameters
+*/
+
+int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+       struct sm501fb_par  *par = info->par;
+       struct sm501fb_info *fbi = par->info;
+       void __iomem *base = fbi->regs;
+       unsigned long hwc_addr;
+       unsigned long fg, bg;
+
+       dev_dbg(fbi->dev, "%s(%p,%p)\n", __func__, info, cursor);
+
+       if (par->head == HEAD_CRT)
+               base += SM501_DC_CRT_HWC_BASE;
+       else
+               base += SM501_DC_PANEL_HWC_BASE;
+
+       /* check not being asked to exceed capabilities */
+
+       if (cursor->image.width > 64)
+               return -EINVAL;
+
+       if (cursor->image.height > 64)
+               return -EINVAL;
+
+       if (cursor->image.depth > 1)
+               return -EINVAL;
+
+       hwc_addr = readl(base + SM501_OFF_HWC_ADDR);
+
+       if (cursor->enable)
+               writel(hwc_addr | SM501_HWC_EN, base + SM501_OFF_HWC_ADDR);
+       else
+               writel(hwc_addr & ~SM501_HWC_EN, base + SM501_OFF_HWC_ADDR);
+
+       /* set data */
+       if (cursor->set & FB_CUR_SETPOS) {
+               unsigned int x = cursor->image.dx;
+               unsigned int y = cursor->image.dy;
+
+               if (x >= 2048 || y >= 2048 )
+                       return -EINVAL;
+
+               dev_dbg(fbi->dev, "set position %d,%d\n", x, y);
+
+               //y += cursor->image.height;
+
+               writel(x | (y << 16), base + SM501_OFF_HWC_LOC);
+       }
+
+       if (cursor->set & FB_CUR_SETCMAP) {
+               unsigned int bg_col = cursor->image.bg_color;
+               unsigned int fg_col = cursor->image.fg_color;
+
+               dev_dbg(fbi->dev, "%s: update cmap (%08x,%08x)\n",
+                       __func__, bg_col, fg_col);
+
+               bg = ((info->cmap.red[bg_col] & 0xF8) << 8) |
+                       ((info->cmap.green[bg_col] & 0xFC) << 3) |
+                       ((info->cmap.blue[bg_col] & 0xF8) >> 3);
+
+               fg = ((info->cmap.red[fg_col] & 0xF8) << 8) |
+                       ((info->cmap.green[fg_col] & 0xFC) << 3) |
+                       ((info->cmap.blue[fg_col] & 0xF8) >> 3);
+
+               dev_dbg(fbi->dev, "fgcol %08x, bgcol %08x\n", fg, bg);
+
+               writel(bg, base + SM501_OFF_HWC_COLOR_1_2);
+               writel(fg, base + SM501_OFF_HWC_COLOR_3);
+       }
+
+       if (cursor->set & FB_CUR_SETSIZE ||
+           cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE)) {
+               /* SM501 cursor is a two bpp 64x64 bitmap this routine
+                * clears it to transparent then combines the cursor
+                * shape plane with the colour plane to set the
+                * cursor */
+               int x, y;
+               const unsigned char *pcol = cursor->image.data;
+               const unsigned char *pmsk = cursor->mask;
+               void __iomem   *dst = par->cursor.k_addr;
+               unsigned char  dcol = 0;
+               unsigned char  dmsk = 0;
+               unsigned int   op;
+
+               dev_dbg(fbi->dev, "%s: setting shape (%d,%d)\n",
+                       __func__, cursor->image.width, cursor->image.height);
+
+               for (op = 0; op < (64*64*2)/8; op+=4)
+                       writel(0x0, dst + op);
+
+               for (y = 0; y < cursor->image.height; y++) {
+                       for (x = 0; x < cursor->image.width; x++) {
+                               if ((x % 8) == 0) {
+                                       dcol = *pcol++;
+                                       dmsk = *pmsk++;
+                               } else {
+                                       dcol >>= 1;
+                                       dmsk >>= 1;
+                               }
+
+                               if (dmsk & 1) {
+                                       op = (dcol & 1) ? 1 : 3;
+                                       op <<= ((x % 4) * 2);
+
+                                       op |= readb(dst + (x / 4));
+                                       writeb(op, dst + (x / 4));
+                               }
+                       }
+                       dst += (64*2)/8;
+               }
+       }
+
+       sm501fb_sync_regs(fbi); /* ensure cursor data flushed */
+       return 0;
+}
+
+/* sm501fb_crtsrc_show
+ *
+ * device attribute code to show where the crt output is sourced from
+*/
+
+static ssize_t sm501fb_crtsrc_show(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       struct sm501fb_info *info = dev_get_drvdata(dev);
+       unsigned long ctrl;
+
+       ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
+       ctrl &= SM501_DC_CRT_CONTROL_SEL;
+
+       return snprintf(buf, PAGE_SIZE, "%s\n", ctrl ? "crt" : "panel");
+}
+
+/* sm501fb_crtsrc_show
+ *
+ * device attribute code to set where the crt output is sourced from
+*/
+
+static ssize_t sm501fb_crtsrc_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t len)
+{
+       struct sm501fb_info *info = dev_get_drvdata(dev);
+       enum sm501_controller head;
+       unsigned long ctrl;
+
+       if (len < 1)
+               return -EINVAL;
+
+       if (strnicmp(buf, "crt", sizeof("crt")) == 0)
+               head = HEAD_CRT;
+       else if (strnicmp(buf, "panel", sizeof("panel")) == 0)
+               head = HEAD_PANEL;
+       else
+               return -EINVAL;
+
+       dev_info(dev, "setting crt source to head %d\n", head);
+
+       ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
+
+       if (head == HEAD_CRT) {
+               ctrl |= SM501_DC_CRT_CONTROL_SEL;
+               ctrl |= SM501_DC_CRT_CONTROL_ENABLE;
+               ctrl |= SM501_DC_CRT_CONTROL_TE;
+       } else {
+               ctrl &= ~SM501_DC_CRT_CONTROL_SEL;
+               ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE;
+               ctrl &= ~SM501_DC_CRT_CONTROL_TE;
+       }
+
+       writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
+       sm501fb_sync_regs(info);
+
+       return (head == HEAD_CRT) ? 3 : 5;
+}
+
+/* Prepare the device_attr for registration with sysfs later */
+static DEVICE_ATTR(crt_src, 0666, sm501fb_crtsrc_show, sm501fb_crtsrc_store);
+
+/* sm501fb_show_regs
+ *
+ * show the primary sm501 registers
+*/
+static int sm501fb_show_regs(struct sm501fb_info *info, char *ptr,
+                            unsigned int start, unsigned int len)
+{
+       void __iomem *mem = info->regs;
+       char *buf = ptr;
+       unsigned int reg;
+
+       for (reg = start; reg < (len + start); reg += 4)
+               ptr += sprintf(ptr, "%08x = %08x\n", reg, readl(mem + reg));
+
+       return ptr - buf;
+}
+
+/* sm501fb_debug_show_crt
+ *
+ * show the crt control and cursor registers
+*/
+
+static ssize_t sm501fb_debug_show_crt(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct sm501fb_info *info = dev_get_drvdata(dev);
+       char *ptr = buf;
+
+       ptr += sm501fb_show_regs(info, ptr, SM501_DC_CRT_CONTROL, 0x40);
+       ptr += sm501fb_show_regs(info, ptr, SM501_DC_CRT_HWC_BASE, 0x10);
+
+       return ptr - buf;
+}
+
+static DEVICE_ATTR(fbregs_crt, 0444, sm501fb_debug_show_crt, NULL);
+
+/* sm501fb_debug_show_pnl
+ *
+ * show the panel control and cursor registers
+*/
+
+static ssize_t sm501fb_debug_show_pnl(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct sm501fb_info *info = dev_get_drvdata(dev);
+       char *ptr = buf;
+
+       ptr += sm501fb_show_regs(info, ptr, 0x0, 0x40);
+       ptr += sm501fb_show_regs(info, ptr, SM501_DC_PANEL_HWC_BASE, 0x10);
+
+       return ptr - buf;
+}
+
+static DEVICE_ATTR(fbregs_pnl, 0444, sm501fb_debug_show_pnl, NULL);
+
+/* framebuffer ops */
+
+static struct fb_ops sm501fb_ops_crt = {
+       .owner          = THIS_MODULE,
+       .fb_check_var   = sm501fb_check_var_crt,
+       .fb_set_par     = sm501fb_set_par_crt,
+       .fb_blank       = sm501fb_blank_crt,
+       .fb_setcolreg   = sm501fb_setcolreg,
+       .fb_pan_display = sm501fb_pan_crt,
+       .fb_cursor      = sm501fb_cursor,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+};
+
+static struct fb_ops sm501fb_ops_pnl = {
+       .owner          = THIS_MODULE,
+       .fb_check_var   = sm501fb_check_var_pnl,
+       .fb_set_par     = sm501fb_set_par_pnl,
+       .fb_pan_display = sm501fb_pan_pnl,
+       .fb_blank       = sm501fb_blank_pnl,
+       .fb_setcolreg   = sm501fb_setcolreg,
+       .fb_cursor      = sm501fb_cursor,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+};
+
+/* sm501fb_info_alloc
+ *
+ * creates and initialises an sm501fb_info structure
+*/
+
+static struct sm501fb_info *sm501fb_info_alloc(struct fb_info *fbinfo_crt,
+                                              struct fb_info *fbinfo_pnl)
+{
+       struct sm501fb_info *info;
+       struct sm501fb_par  *par;
+
+       info = kzalloc(sizeof(struct sm501fb_info), GFP_KERNEL);
+       if (info) {
+               /* set the references back */
+
+               par = fbinfo_crt->par;
+               par->info = info;
+               par->head = HEAD_CRT;
+               fbinfo_crt->pseudo_palette = &par->pseudo_palette;
+
+               par = fbinfo_pnl->par;
+               par->info = info;
+               par->head = HEAD_PANEL;
+               fbinfo_pnl->pseudo_palette = &par->pseudo_palette;
+
+               /* store the two fbs into our info */
+               info->fb[HEAD_CRT] = fbinfo_crt;
+               info->fb[HEAD_PANEL] = fbinfo_pnl;
+       }
+
+       return info;
+}
+
+/* sm501_init_cursor
+ *
+ * initialise hw cursor parameters
+*/
+
+int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base)
+{
+       struct sm501fb_par *par = fbi->par;
+       struct sm501fb_info *info = par->info;
+       int ret;
+
+       par->cursor_regs = info->regs + reg_base;
+
+       ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024);
+       if (ret < 0)
+               return ret;
+
+       /* initialise the colour registers */
+
+       writel(par->cursor.sm_addr, par->cursor_regs + SM501_OFF_HWC_ADDR);
+
+       writel(0x00, par->cursor_regs + SM501_OFF_HWC_LOC);
+       writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_1_2);
+       writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_3);
+       sm501fb_sync_regs(info);
+
+       return 0;
+}
+
+/* sm501fb_info_start
+ *
+ * fills the par structure claiming resources and remapping etc.
+*/
+
+static int sm501fb_start(struct sm501fb_info *info,
+                        struct platform_device *pdev)
+{
+       struct resource *res;
+       struct device *dev;
+       int ret;
+
+       info->dev = dev = &pdev->dev;
+       platform_set_drvdata(pdev, info);
+
+       info->irq = ret = platform_get_irq(pdev, 0);
+       if (ret < 0) {
+               /* we currently do not use the IRQ */
+               dev_warn(dev, "no irq for device\n");
+       }
+
+       /* allocate, reserve and remap resources for registers */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(dev, "no resource definition for registers\n");
+               ret = -ENOENT;
+               goto err_release;
+       }
+
+       info->regs_res = request_mem_region(res->start,
+                                           res->end - res->start,
+                                           pdev->name);
+
+       if (info->regs_res == NULL) {
+               dev_err(dev, "cannot claim registers\n");
+               ret = -ENXIO;
+               goto err_release;
+       }
+
+       info->regs = ioremap(res->start, (res->end - res->start)+1);
+       if (info->regs == NULL) {
+               dev_err(dev, "cannot remap registers\n");
+               ret = -ENXIO;
+               goto err_regs_res;
+       }
+
+       /* allocate, reserve resources for framebuffer */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+       if (res == NULL) {
+               dev_err(dev, "no memory resource defined\n");
+               ret = -ENXIO;
+               goto err_regs_map;
+       }
+
+       info->fbmem_res = request_mem_region(res->start,
+                                            (res->end - res->start)+1,
+                                            pdev->name);
+       if (info->fbmem_res == NULL) {
+               dev_err(dev, "cannot claim framebuffer\n");
+               ret = -ENXIO;
+               goto err_regs_map;
+       }
+
+       info->fbmem = ioremap(res->start, (res->end - res->start)+1);
+       if (info->fbmem == NULL) {
+               dev_err(dev, "cannot remap framebuffer\n");
+               goto err_mem_res;
+       }
+
+       info->fbmem_len = (res->end - res->start)+1;
+
+       /* enable display controller */
+       sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1);
+
+       /* setup cursors */
+
+       sm501_init_cursor(info->fb[HEAD_CRT], SM501_DC_CRT_HWC_ADDR);
+       sm501_init_cursor(info->fb[HEAD_PANEL], SM501_DC_PANEL_HWC_ADDR);
+
+       return 0; /* everything is setup */
+
+ err_mem_res:
+       release_resource(info->fbmem_res);
+       kfree(info->fbmem_res);
+
+ err_regs_map:
+       iounmap(info->regs);
+
+ err_regs_res:
+       release_resource(info->regs_res);
+       kfree(info->regs_res);
+
+ err_release:
+       return ret;
+}
+
+static void sm501fb_stop(struct sm501fb_info *info)
+{
+       /* disable display controller */
+       sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0);
+
+       iounmap(info->fbmem);
+       release_resource(info->fbmem_res);
+       kfree(info->fbmem_res);
+
+       iounmap(info->regs);
+       release_resource(info->regs_res);
+       kfree(info->regs_res);
+}
+
+static void sm501fb_info_release(struct sm501fb_info *info)
+{
+       kfree(info);
+}
+
+static int sm501fb_init_fb(struct fb_info *fb,
+                          enum sm501_controller head,
+                          const char *fbname)
+{
+       struct sm501_platdata_fbsub *pd;
+       struct sm501fb_par *par = fb->par;
+       struct sm501fb_info *info = par->info;
+       unsigned long ctrl;
+       unsigned int enable;
+       int ret;
+
+       switch (head) {
+       case HEAD_CRT:
+               pd = info->pdata->fb_crt;
+               ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
+               enable = (ctrl & SM501_DC_CRT_CONTROL_ENABLE) ? 1 : 0;
+
+               /* ensure we set the correct source register */
+               if (info->pdata->fb_route != SM501_FB_CRT_PANEL) {
+                       ctrl |= SM501_DC_CRT_CONTROL_SEL;
+                       writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
+               }
+
+               break;
+
+       case HEAD_PANEL:
+               pd = info->pdata->fb_pnl;
+               ctrl = readl(info->regs + SM501_DC_PANEL_CONTROL);
+               enable = (ctrl & SM501_DC_PANEL_CONTROL_EN) ? 1 : 0;
+               break;
+
+       default:
+               pd = NULL;              /* stop compiler warnings */
+               ctrl = 0;
+               enable = 0;
+               BUG();
+       }
+
+       dev_info(info->dev, "fb %s %sabled at start\n",
+                fbname, enable ? "en" : "dis");
+
+       /* check to see if our routing allows this */
+
+       if (head == HEAD_CRT && info->pdata->fb_route == SM501_FB_CRT_PANEL) {
+               ctrl &= ~SM501_DC_CRT_CONTROL_SEL;
+               writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
+               enable = 0;
+       }
+
+       strlcpy(fb->fix.id, fbname, sizeof(fb->fix.id));
+
+       memcpy(&par->ops,
+              (head == HEAD_CRT) ? &sm501fb_ops_crt : &sm501fb_ops_pnl,
+              sizeof(struct fb_ops));
+
+       /* update ops dependant on what we've been passed */
+
+       if ((pd->flags & SM501FB_FLAG_USE_HWCURSOR) == 0)
+               par->ops.fb_cursor = NULL;
+
+       fb->fbops = &par->ops;
+       fb->flags = FBINFO_FLAG_DEFAULT |
+               FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
+
+       /* fixed data */
+
+       fb->fix.type            = FB_TYPE_PACKED_PIXELS;
+       fb->fix.type_aux        = 0;
+       fb->fix.xpanstep        = 1;
+       fb->fix.ypanstep        = 1;
+       fb->fix.ywrapstep       = 0;
+       fb->fix.accel           = FB_ACCEL_NONE;
+
+       /* screenmode */
+
+       fb->var.nonstd          = 0;
+       fb->var.activate        = FB_ACTIVATE_NOW;
+       fb->var.accel_flags     = 0;
+       fb->var.vmode           = FB_VMODE_NONINTERLACED;
+       fb->var.bits_per_pixel  = 16;
+
+       if (enable && (pd->flags & SM501FB_FLAG_USE_INIT_MODE) && 0) {
+               /* TODO read the mode from the current display */
+
+       } else {
+               if (pd->def_mode) {
+                       dev_info(info->dev, "using supplied mode\n");
+                       fb_videomode_to_var(&fb->var, pd->def_mode);
+
+                       fb->var.bits_per_pixel = pd->def_bpp ? pd->def_bpp : 8;
+                       fb->var.xres_virtual = fb->var.xres;
+                       fb->var.yres_virtual = fb->var.yres;
+               } else {
+                       ret = fb_find_mode(&fb->var, fb,
+                                          NULL, NULL, 0, NULL, 8);
+
+                       if (ret == 0 || ret == 4) {
+                               dev_err(info->dev,
+                                       "failed to get initial mode\n");
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       /* initialise and set the palette */
+       fb_alloc_cmap(&fb->cmap, NR_PALETTE, 0);
+       fb_set_cmap(&fb->cmap, fb);
+
+       ret = (fb->fbops->fb_check_var)(&fb->var, fb);
+       if (ret)
+               dev_err(info->dev, "check_var() failed on initial setup?\n");
+
+       /* ensure we've activated our new configuration */
+       (fb->fbops->fb_set_par)(fb);
+
+       return 0;
+}
+
+/* default platform data if none is supplied (ie, PCI device) */
+
+static struct sm501_platdata_fbsub sm501fb_pdata_crt = {
+       .flags          = (SM501FB_FLAG_USE_INIT_MODE |
+                          SM501FB_FLAG_USE_HWCURSOR |
+                          SM501FB_FLAG_USE_HWACCEL |
+                          SM501FB_FLAG_DISABLE_AT_EXIT),
+
+};
+
+static struct sm501_platdata_fbsub sm501fb_pdata_pnl = {
+       .flags          = (SM501FB_FLAG_USE_INIT_MODE |
+                          SM501FB_FLAG_USE_HWCURSOR |
+                          SM501FB_FLAG_USE_HWACCEL |
+                          SM501FB_FLAG_DISABLE_AT_EXIT),
+};
+
+static struct sm501_platdata_fb sm501fb_def_pdata = {
+       .fb_route               = SM501_FB_OWN,
+       .fb_crt                 = &sm501fb_pdata_crt,
+       .fb_pnl                 = &sm501fb_pdata_pnl,
+};
+
+static char driver_name_crt[] = "sm501fb-crt";
+static char driver_name_pnl[] = "sm501fb-panel";
+
+static int __init sm501fb_probe(struct platform_device *pdev)
+{
+       struct sm501fb_info *info;
+       struct device       *dev = &pdev->dev;
+       struct fb_info      *fbinfo_crt;
+       struct fb_info      *fbinfo_pnl;
+       int                  ret;
+
+       /* allocate our framebuffers */
+
+       fbinfo_crt = framebuffer_alloc(sizeof(struct sm501fb_par), dev);
+       if (fbinfo_crt == NULL) {
+               dev_err(dev, "cannot allocate crt framebuffer\n");
+               return -ENOMEM;
+       }
+
+       fbinfo_pnl = framebuffer_alloc(sizeof(struct sm501fb_par), dev);
+       if (fbinfo_pnl == NULL) {
+               dev_err(dev, "cannot allocate panel framebuffer\n");
+               ret = -ENOMEM;
+               goto fbinfo_crt_alloc_fail;
+       }
+
+       info = sm501fb_info_alloc(fbinfo_crt, fbinfo_pnl);
+       if (info == NULL) {
+               dev_err(dev, "cannot allocate par\n");
+               ret = -ENOMEM;
+               goto sm501fb_alloc_fail;
+       }
+
+       if (dev->parent->platform_data) {
+               struct sm501_platdata *pd = dev->parent->platform_data;
+               info->pdata = pd->fb;
+       }
+
+       if (info->pdata == NULL) {
+               dev_info(dev, "using default configuration data\n");
+               info->pdata = &sm501fb_def_pdata;
+       }
+
+       /* start the framebuffers */
+
+       ret = sm501fb_start(info, pdev);
+       if (ret) {
+               dev_err(dev, "cannot initialise SM501\n");
+               goto sm501fb_start_fail;
+       }
+
+       /* CRT framebuffer setup */
+
+       ret = sm501fb_init_fb(fbinfo_crt, HEAD_CRT, driver_name_crt);
+       if (ret) {
+               dev_err(dev, "cannot initialise CRT fb\n");
+               goto sm501fb_start_fail;
+       }
+
+       /* Panel framebuffer setup */
+
+       ret = sm501fb_init_fb(fbinfo_pnl, HEAD_PANEL, driver_name_pnl);
+       if (ret) {
+               dev_err(dev, "cannot initialise Panel fb\n");
+               goto sm501fb_start_fail;
+       }
+
+       /* register framebuffers */
+
+       ret = register_framebuffer(fbinfo_crt);
+       if (ret < 0) {
+               dev_err(dev, "failed to register CRT fb (%d)\n", ret);
+               goto register_crt_fail;
+       }
+
+       ret = register_framebuffer(fbinfo_pnl);
+       if (ret < 0) {
+               dev_err(dev, "failed to register panel fb (%d)\n", ret);
+               goto register_pnl_fail;
+       }
+
+       dev_info(dev, "fb%d: %s frame buffer device\n",
+                fbinfo_crt->node, fbinfo_crt->fix.id);
+
+       dev_info(dev, "fb%d: %s frame buffer device\n",
+              fbinfo_pnl->node, fbinfo_pnl->fix.id);
+
+       /* create device files */
+
+       ret = device_create_file(dev, &dev_attr_crt_src);
+       if (ret)
+               goto crtsrc_fail;
+
+       ret = device_create_file(dev, &dev_attr_fbregs_pnl);
+       if (ret)
+               goto fbregs_pnl_fail;
+
+       ret = device_create_file(dev, &dev_attr_fbregs_crt);
+       if (ret)
+               goto fbregs_crt_fail;
+
+       /* we registered, return ok */
+       return 0;
+
+ fbregs_crt_fail:
+       device_remove_file(dev, &dev_attr_fbregs_pnl);
+
+ fbregs_pnl_fail:
+       device_remove_file(dev, &dev_attr_crt_src);
+
+ crtsrc_fail:
+       unregister_framebuffer(fbinfo_pnl);
+
+ register_pnl_fail:
+       unregister_framebuffer(fbinfo_crt);
+
+ register_crt_fail:
+       sm501fb_stop(info);
+
+ sm501fb_start_fail:
+       sm501fb_info_release(info);
+
+ sm501fb_alloc_fail:
+       framebuffer_release(fbinfo_pnl);
+
+ fbinfo_crt_alloc_fail:
+       framebuffer_release(fbinfo_crt);
+
+       return ret;
+}
+
+
+/*
+ *  Cleanup
+ */
+static int sm501fb_remove(struct platform_device *pdev)
+{
+       struct sm501fb_info *info = platform_get_drvdata(pdev);
+       struct fb_info     *fbinfo_crt = info->fb[0];
+       struct fb_info     *fbinfo_pnl = info->fb[1];
+
+       device_remove_file(&pdev->dev, &dev_attr_fbregs_crt);
+       device_remove_file(&pdev->dev, &dev_attr_fbregs_pnl);
+       device_remove_file(&pdev->dev, &dev_attr_crt_src);
+
+       unregister_framebuffer(fbinfo_crt);
+       unregister_framebuffer(fbinfo_pnl);
+
+       sm501fb_stop(info);
+       sm501fb_info_release(info);
+
+       framebuffer_release(fbinfo_pnl);
+       framebuffer_release(fbinfo_crt);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int sm501fb_suspend_fb(struct sm501fb_info *info,
+                             enum sm501_controller head)
+{
+       struct fb_info *fbi = info->fb[head];
+       struct sm501fb_par *par = fbi->par;
+
+       if (par->screen.size == 0)
+               return 0;
+
+       /* backup copies in case chip is powered down over suspend */
+
+       par->store_fb = vmalloc(par->screen.size);
+       if (par->store_fb == NULL) {
+               dev_err(info->dev, "no memory to store screen\n");
+               return -ENOMEM;
+       }
+
+       par->store_cursor = vmalloc(par->cursor.size);
+       if (par->store_cursor == NULL) {
+               dev_err(info->dev, "no memory to store cursor\n");
+               goto err_nocursor;
+       }
+
+       memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size);
+       memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size);
+
+       /* blank the relevant interface to ensure unit power minimised */
+       (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi);
+
+       return 0;
+
+ err_nocursor:
+       vfree(par->store_fb);
+
+       return -ENOMEM;
+
+}
+
+static void sm501fb_resume_fb(struct sm501fb_info *info,
+                             enum sm501_controller head)
+{
+       struct fb_info *fbi = info->fb[head];
+       struct sm501fb_par *par = fbi->par;
+
+       if (par->screen.size == 0)
+               return;
+
+       /* re-activate the configuration */
+
+       (par->ops.fb_set_par)(fbi);
+
+       /* restore the data */
+
+       memcpy_toio(par->screen.k_addr, par->store_fb, par->screen.size);
+       memcpy_toio(par->cursor.k_addr, par->store_cursor, par->cursor.size);
+
+       vfree(par->store_fb);
+       vfree(par->store_cursor);
+}
+
+
+/* suspend and resume support */
+
+static int sm501fb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct sm501fb_info *info = platform_get_drvdata(pdev);
+
+       sm501fb_suspend_fb(info, HEAD_CRT);
+       sm501fb_suspend_fb(info, HEAD_PANEL);
+
+       /* turn off the clocks, in case the device is not powered down */
+       sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0);
+
+       return 0;
+}
+
+static int sm501fb_resume(struct platform_device *pdev)
+{
+       struct sm501fb_info *info = platform_get_drvdata(pdev);
+
+       sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 1);
+
+       sm501fb_resume_fb(info, HEAD_CRT);
+       sm501fb_resume_fb(info, HEAD_PANEL);
+
+       return 0;
+}
+
+#else
+#define sm501fb_suspend NULL
+#define sm501fb_resume  NULL
+#endif
+
+static struct platform_driver sm501fb_driver = {
+       .probe          = sm501fb_probe,
+       .remove         = sm501fb_remove,
+       .suspend        = sm501fb_suspend,
+       .resume         = sm501fb_resume,
+       .driver         = {
+               .name   = "sm501-fb",
+               .owner  = THIS_MODULE,
+       },
+};
+
+int __devinit sm501fb_init(void)
+{
+       return platform_driver_register(&sm501fb_driver);
+}
+
+static void __exit sm501fb_cleanup(void)
+{
+       platform_driver_unregister(&sm501fb_driver);
+}
+
+module_init(sm501fb_init);
+module_exit(sm501fb_cleanup);
+
+MODULE_AUTHOR("Ben Dooks, Vincent Sanders");
+MODULE_DESCRIPTION("SM501 Framebuffer driver");
+MODULE_LICENSE("GPL v2");
index 7db2d28..232c694 100644 (file)
@@ -171,6 +171,7 @@ extern unsigned long                 affs_parent_ino(struct inode *dir);
 extern struct inode            *affs_new_inode(struct inode *dir);
 extern int                      affs_notify_change(struct dentry *dentry, struct iattr *attr);
 extern void                     affs_put_inode(struct inode *inode);
+extern void                     affs_drop_inode(struct inode *inode);
 extern void                     affs_delete_inode(struct inode *inode);
 extern void                     affs_clear_inode(struct inode *inode);
 extern void                     affs_read_inode(struct inode *inode);
index fce6848..c5b9d73 100644 (file)
@@ -243,12 +243,17 @@ affs_put_inode(struct inode *inode)
 {
        pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
        affs_free_prealloc(inode);
-       if (atomic_read(&inode->i_count) == 1) {
-               mutex_lock(&inode->i_mutex);
-               if (inode->i_size != AFFS_I(inode)->mmu_private)
-                       affs_truncate(inode);
-               mutex_unlock(&inode->i_mutex);
-       }
+}
+
+void
+affs_drop_inode(struct inode *inode)
+{
+       mutex_lock(&inode->i_mutex);
+       if (inode->i_size != AFFS_I(inode)->mmu_private)
+               affs_truncate(inode);
+       mutex_unlock(&inode->i_mutex);
+
+       generic_drop_inode(inode);
 }
 
 void
index a324045..c3986a1 100644 (file)
@@ -118,6 +118,7 @@ static const struct super_operations affs_sops = {
        .read_inode     = affs_read_inode,
        .write_inode    = affs_write_inode,
        .put_inode      = affs_put_inode,
+       .drop_inode     = affs_drop_inode,
        .delete_inode   = affs_delete_inode,
        .clear_inode    = affs_clear_inode,
        .put_super      = affs_put_super,
index 6b4cec3..d85f42f 100644 (file)
@@ -52,6 +52,8 @@ struct autofs_info {
 
        int             flags;
 
+       struct list_head rehash;
+
        struct autofs_sb_info *sbi;
        unsigned long last_used;
        atomic_t count;
@@ -110,6 +112,8 @@ struct autofs_sb_info {
        struct mutex wq_mutex;
        spinlock_t fs_lock;
        struct autofs_wait_queue *queues; /* Wait queue pointer */
+       spinlock_t rehash_lock;
+       struct list_head rehash_list;
 };
 
 static inline struct autofs_sb_info *autofs4_sbi(struct super_block *sb)
index 5e458e0..26063dc 100644 (file)
@@ -48,6 +48,8 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
        ino->dentry = NULL;
        ino->size = 0;
 
+       INIT_LIST_HEAD(&ino->rehash);
+
        ino->last_used = jiffies;
        atomic_set(&ino->count, 0);
 
@@ -158,14 +160,13 @@ void autofs4_kill_sb(struct super_block *sb)
        if (!sbi)
                goto out_kill_sb;
 
-       sb->s_fs_info = NULL;
-
-       if ( !sbi->catatonic )
+       if (!sbi->catatonic)
                autofs4_catatonic_mode(sbi); /* Free wait queues, close pipe */
 
        /* Clean up and release dangling references */
        autofs4_force_release(sbi);
 
+       sb->s_fs_info = NULL;
        kfree(sbi);
 
 out_kill_sb:
@@ -336,6 +337,8 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
        mutex_init(&sbi->wq_mutex);
        spin_lock_init(&sbi->fs_lock);
        sbi->queues = NULL;
+       spin_lock_init(&sbi->rehash_lock);
+       INIT_LIST_HEAD(&sbi->rehash_list);
        s->s_blocksize = 1024;
        s->s_blocksize_bits = 10;
        s->s_magic = AUTOFS_SUPER_MAGIC;
index 47fee96..b463104 100644 (file)
@@ -263,7 +263,7 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags)
                 */
                status = d_invalidate(dentry);
                if (status != -EBUSY)
-                       return -ENOENT;
+                       return -EAGAIN;
        }
 
        DPRINTK("dentry=%p %.*s ino=%p",
@@ -413,7 +413,16 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)
                 */
                status = try_to_fill_dentry(dentry, flags);
                if (status == 0)
-                               return 1;
+                       return 1;
+
+               /*
+                * A status of EAGAIN here means that the dentry has gone
+                * away while waiting for an expire to complete. If we are
+                * racing with expire lookup will wait for it so this must
+                * be a revalidate and we need to send it to lookup.
+                */
+               if (status == -EAGAIN)
+                       return 0;
 
                return status;
        }
@@ -459,9 +468,18 @@ void autofs4_dentry_release(struct dentry *de)
        de->d_fsdata = NULL;
 
        if (inf) {
+               struct autofs_sb_info *sbi = autofs4_sbi(de->d_sb);
+
                inf->dentry = NULL;
                inf->inode = NULL;
 
+               if (sbi) {
+                       spin_lock(&sbi->rehash_lock);
+                       if (!list_empty(&inf->rehash))
+                               list_del(&inf->rehash);
+                       spin_unlock(&sbi->rehash_lock);
+               }
+
                autofs4_free_ino(inf);
        }
 }
@@ -478,10 +496,80 @@ static struct dentry_operations autofs4_dentry_operations = {
        .d_release      = autofs4_dentry_release,
 };
 
+static struct dentry *autofs4_lookup_unhashed(struct autofs_sb_info *sbi, struct dentry *parent, struct qstr *name)
+{
+       unsigned int len = name->len;
+       unsigned int hash = name->hash;
+       const unsigned char *str = name->name;
+       struct list_head *p, *head;
+
+       spin_lock(&dcache_lock);
+       spin_lock(&sbi->rehash_lock);
+       head = &sbi->rehash_list;
+       list_for_each(p, head) {
+               struct autofs_info *ino;
+               struct dentry *dentry;
+               struct qstr *qstr;
+
+               ino = list_entry(p, struct autofs_info, rehash);
+               dentry = ino->dentry;
+
+               spin_lock(&dentry->d_lock);
+
+               /* Bad luck, we've already been dentry_iput */
+               if (!dentry->d_inode)
+                       goto next;
+
+               qstr = &dentry->d_name;
+
+               if (dentry->d_name.hash != hash)
+                       goto next;
+               if (dentry->d_parent != parent)
+                       goto next;
+
+               if (qstr->len != len)
+                       goto next;
+               if (memcmp(qstr->name, str, len))
+                       goto next;
+
+               if (d_unhashed(dentry)) {
+                       struct autofs_info *ino = autofs4_dentry_ino(dentry);
+                       struct inode *inode = dentry->d_inode;
+
+                       list_del_init(&ino->rehash);
+                       dget(dentry);
+                       /*
+                        * Make the rehashed dentry negative so the VFS
+                        * behaves as it should.
+                        */
+                       if (inode) {
+                               dentry->d_inode = NULL;
+                               list_del_init(&dentry->d_alias);
+                               spin_unlock(&dentry->d_lock);
+                               spin_unlock(&sbi->rehash_lock);
+                               spin_unlock(&dcache_lock);
+                               iput(inode);
+                               return dentry;
+                       }
+                       spin_unlock(&dentry->d_lock);
+                       spin_unlock(&sbi->rehash_lock);
+                       spin_unlock(&dcache_lock);
+                       return dentry;
+               }
+next:
+               spin_unlock(&dentry->d_lock);
+       }
+       spin_unlock(&sbi->rehash_lock);
+       spin_unlock(&dcache_lock);
+
+       return NULL;
+}
+
 /* Lookups in the root directory */
 static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 {
        struct autofs_sb_info *sbi;
+       struct dentry *unhashed;
        int oz_mode;
 
        DPRINTK("name = %.*s",
@@ -497,25 +585,46 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
        DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d",
                 current->pid, process_group(current), sbi->catatonic, oz_mode);
 
-       /*
-        * Mark the dentry incomplete, but add it. This is needed so
-        * that the VFS layer knows about the dentry, and we can count
-        * on catching any lookups through the revalidate.
-        *
-        * Let all the hard work be done by the revalidate function that
-        * needs to be able to do this anyway..
-        *
-        * We need to do this before we release the directory semaphore.
-        */
-       dentry->d_op = &autofs4_root_dentry_operations;
+       unhashed = autofs4_lookup_unhashed(sbi, dentry->d_parent, &dentry->d_name);
+       if (!unhashed) {
+               /*
+                * Mark the dentry incomplete, but add it. This is needed so
+                * that the VFS layer knows about the dentry, and we can count
+                * on catching any lookups through the revalidate.
+                *
+                * Let all the hard work be done by the revalidate function that
+                * needs to be able to do this anyway..
+                *
+                * We need to do this before we release the directory semaphore.
+                */
+               dentry->d_op = &autofs4_root_dentry_operations;
+
+               dentry->d_fsdata = NULL;
+               d_add(dentry, NULL);
+       } else {
+               struct autofs_info *ino = autofs4_dentry_ino(unhashed);
+               DPRINTK("rehash %p with %p", dentry, unhashed);
+               /*
+                * If we are racing with expire the request might not
+                * be quite complete but the directory has been removed
+                * so it must have been successful, so just wait for it.
+                */
+               if (ino && (ino->flags & AUTOFS_INF_EXPIRING)) {
+                       DPRINTK("wait for incomplete expire %p name=%.*s",
+                               unhashed, unhashed->d_name.len,
+                               unhashed->d_name.name);
+                       autofs4_wait(sbi, unhashed, NFY_NONE);
+                       DPRINTK("request completed");
+               }
+               d_rehash(unhashed);
+               dentry = unhashed;
+       }
 
        if (!oz_mode) {
                spin_lock(&dentry->d_lock);
                dentry->d_flags |= DCACHE_AUTOFS_PENDING;
                spin_unlock(&dentry->d_lock);
        }
-       dentry->d_fsdata = NULL;
-       d_add(dentry, NULL);
 
        if (dentry->d_op && dentry->d_op->d_revalidate) {
                mutex_unlock(&dir->i_mutex);
@@ -534,6 +643,8 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
                        if (sigismember (sigset, SIGKILL) ||
                            sigismember (sigset, SIGQUIT) ||
                            sigismember (sigset, SIGINT)) {
+                           if (unhashed)
+                               dput(unhashed);
                            return ERR_PTR(-ERESTARTNOINTR);
                        }
                }
@@ -544,12 +655,33 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
 
        /*
         * If this dentry is unhashed, then we shouldn't honour this
-        * lookup even if the dentry is positive.  Returning ENOENT here
-        * doesn't do the right thing for all system calls, but it should
-        * be OK for the operations we permit from an autofs.
+        * lookup.  Returning ENOENT here doesn't do the right thing
+        * for all system calls, but it should be OK for the operations
+        * we permit from an autofs.
         */
-       if (dentry->d_inode && d_unhashed(dentry))
-               return ERR_PTR(-ENOENT);
+       if (dentry->d_inode && d_unhashed(dentry)) {
+               /*
+                * A user space application can (and has done in the past)
+                * remove and re-create this directory during the callback.
+                * This can leave us with an unhashed dentry, but a
+                * successful mount!  So we need to perform another
+                * cached lookup in case the dentry now exists.
+                */
+               struct dentry *parent = dentry->d_parent;
+               struct dentry *new = d_lookup(parent, &dentry->d_name);
+               if (new != NULL)
+                       dentry = new;
+               else
+                       dentry = ERR_PTR(-ENOENT);
+
+               if (unhashed)
+                       dput(unhashed);
+
+               return dentry;
+       }
+
+       if (unhashed)
+               return dentry;
 
        return NULL;
 }
@@ -611,9 +743,10 @@ static int autofs4_dir_symlink(struct inode *dir,
  * Normal filesystems would do a "d_delete()" to tell the VFS dcache
  * that the file no longer exists. However, doing that means that the
  * VFS layer can turn the dentry into a negative dentry.  We don't want
- * this, because since the unlink is probably the result of an expire.
- * We simply d_drop it, which allows the dentry lookup to remount it
- * if necessary.
+ * this, because the unlink is probably the result of an expire.
+ * We simply d_drop it and add it to a rehash candidates list in the
+ * super block, which allows the dentry lookup to reuse it retaining
+ * the flags, such as expire in progress, in case we're racing with expire.
  *
  * If a process is blocked on the dentry waiting for the expire to finish,
  * it will invalidate the dentry and try to mount with a new one.
@@ -642,7 +775,14 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
 
        dir->i_mtime = CURRENT_TIME;
 
-       d_drop(dentry);
+       spin_lock(&dcache_lock);
+       spin_lock(&sbi->rehash_lock);
+       list_add(&ino->rehash, &sbi->rehash_list);
+       spin_unlock(&sbi->rehash_lock);
+       spin_lock(&dentry->d_lock);
+       __d_drop(dentry);
+       spin_unlock(&dentry->d_lock);
+       spin_unlock(&dcache_lock);
 
        return 0;
 }
@@ -653,6 +793,9 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
        struct autofs_info *ino = autofs4_dentry_ino(dentry);
        struct autofs_info *p_ino;
        
+       DPRINTK("dentry %p, removing %.*s",
+               dentry, dentry->d_name.len, dentry->d_name.name);
+
        if (!autofs4_oz_mode(sbi))
                return -EACCES;
 
@@ -661,6 +804,9 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
                spin_unlock(&dcache_lock);
                return -ENOTEMPTY;
        }
+       spin_lock(&sbi->rehash_lock);
+       list_add(&ino->rehash, &sbi->rehash_list);
+       spin_unlock(&sbi->rehash_lock);
        spin_lock(&dentry->d_lock);
        __d_drop(dentry);
        spin_unlock(&dentry->d_lock);
index 1e4a539..0d041a9 100644 (file)
@@ -84,7 +84,11 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
                                 struct autofs_wait_queue *wq,
                                 int type)
 {
-       union autofs_packet_union pkt;
+       union {
+               struct autofs_packet_hdr hdr;
+               union autofs_packet_union v4_pkt;
+               union autofs_v5_packet_union v5_pkt;
+       } pkt;
        size_t pktsz;
 
        DPRINTK("wait id = 0x%08lx, name = %.*s, type=%d",
@@ -98,7 +102,7 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
        /* Kernel protocol v4 missing and expire packets */
        case autofs_ptype_missing:
        {
-               struct autofs_packet_missing *mp = &pkt.missing;
+               struct autofs_packet_missing *mp = &pkt.v4_pkt.missing;
 
                pktsz = sizeof(*mp);
 
@@ -110,7 +114,7 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
        }
        case autofs_ptype_expire_multi:
        {
-               struct autofs_packet_expire_multi *ep = &pkt.expire_multi;
+               struct autofs_packet_expire_multi *ep = &pkt.v4_pkt.expire_multi;
 
                pktsz = sizeof(*ep);
 
@@ -129,7 +133,7 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
        case autofs_ptype_missing_direct:
        case autofs_ptype_expire_direct:
        {
-               struct autofs_v5_packet *packet = &pkt.v5_packet;
+               struct autofs_v5_packet *packet = &pkt.v5_pkt.v5_packet;
 
                pktsz = sizeof(*packet);
 
index 0c59b70..575076c 100644 (file)
@@ -1101,6 +1101,13 @@ static int __blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags,
                        int for_part);
 static int __blkdev_put(struct block_device *bdev, int for_part);
 
+/*
+ * bd_mutex locking:
+ *
+ *  mutex_lock(part->bd_mutex)
+ *    mutex_lock_nested(whole->bd_mutex, 1)
+ */
+
 static int do_open(struct block_device *bdev, struct file *file, int for_part)
 {
        struct module *owner = NULL;
index f99c509..e8504b6 100644 (file)
@@ -1743,7 +1743,6 @@ recover:
        SetPageError(page);
        BUG_ON(PageWriteback(page));
        set_page_writeback(page);
-       unlock_page(page);
        do {
                struct buffer_head *next = bh->b_this_page;
                if (buffer_async_write(bh)) {
@@ -1753,6 +1752,7 @@ recover:
                }
                bh = next;
        } while (bh != head);
+       unlock_page(page);
        goto done;
 }
 
@@ -2248,7 +2248,6 @@ int nobh_prepare_write(struct page *page, unsigned from, unsigned to,
        int i;
        int ret = 0;
        int is_mapped_to_disk = 1;
-       int dirtied_it = 0;
 
        if (PageMappedToDisk(page))
                return 0;
@@ -2285,14 +2284,10 @@ int nobh_prepare_write(struct page *page, unsigned from, unsigned to,
                        continue;
                if (buffer_new(&map_bh) || !buffer_mapped(&map_bh)) {
                        kaddr = kmap_atomic(page, KM_USER0);
-                       if (block_start < from) {
+                       if (block_start < from)
                                memset(kaddr+block_start, 0, from-block_start);
-                               dirtied_it = 1;
-                       }
-                       if (block_end > to) {
+                       if (block_end > to)
                                memset(kaddr + to, 0, block_end - to);
-                               dirtied_it = 1;
-                       }
                        flush_dcache_page(page);
                        kunmap_atomic(kaddr, KM_USER0);
                        continue;
@@ -2347,17 +2342,6 @@ int nobh_prepare_write(struct page *page, unsigned from, unsigned to,
 
        if (is_mapped_to_disk)
                SetPageMappedToDisk(page);
-       SetPageUptodate(page);
-
-       /*
-        * Setting the page dirty here isn't necessary for the prepare_write
-        * function - commit_write will do that.  But if/when this function is
-        * used within the pagefault handler to ensure that all mmapped pages
-        * have backing space in the filesystem, we will need to dirty the page
-        * if its contents were altered.
-        */
-       if (dirtied_it)
-               set_page_dirty(page);
 
        return 0;
 
@@ -2387,6 +2371,7 @@ int nobh_commit_write(struct file *file, struct page *page,
        struct inode *inode = page->mapping->host;
        loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
 
+       SetPageUptodate(page);
        set_page_dirty(page);
        if (pos > inode->i_size) {
                i_size_write(inode, pos);
index e6194e2..78ced72 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/init.h>
 #include <linux/fs.h>
+#include <linux/kdev_t.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 
@@ -108,12 +109,7 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
        /* temporary */
        if (major == 0) {
                for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {
-                       /*
-                        * Disallow the LANANA-assigned LOCAL/EXPERIMENTAL
-                        * majors
-                        */
-                       if ((60 <= i && i <= 63) || (120 <= i && i <= 127) ||
-                                       (240 <= i && i <= 254))
+                       if (is_lanana_major(i))
                                continue;
                        if (chrdevs[i] == NULL)
                                break;
index e8287c4..bc2c0ac 100644 (file)
@@ -91,8 +91,9 @@ cifs_read_super(struct super_block *sb, void *data,
        struct inode *inode;
        struct cifs_sb_info *cifs_sb;
        int rc = 0;
-
-       sb->s_flags |= MS_NODIRATIME; /* and probably even noatime */
+       
+       /* BB should we make this contingent on mount parm? */
+       sb->s_flags |= MS_NODIRATIME | MS_NOATIME;
        sb->s_fs_info = kzalloc(sizeof(struct cifs_sb_info),GFP_KERNEL);
        cifs_sb = CIFS_SB(sb);
        if(cifs_sb == NULL)
@@ -258,7 +259,10 @@ cifs_alloc_inode(struct super_block *sb)
        cifs_inode->clientCanCacheRead = FALSE;
        cifs_inode->clientCanCacheAll = FALSE;
        cifs_inode->vfs_inode.i_blkbits = 14;  /* 2**14 = CIFS_MAX_MSGSIZE */
-       cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME;
+       
+       /* Can not set i_flags here - they get immediately overwritten
+          to zero by the VFS */
+/*     cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME;*/
        INIT_LIST_HEAD(&cifs_inode->openFileList);
        return &cifs_inode->vfs_inode;
 }
@@ -283,6 +287,7 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
 
        if (cifs_sb) {
                if (cifs_sb->tcon) {
+/* BB add prepath to mount options displayed */
                        seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName);
                        if (cifs_sb->tcon->ses) {
                                if (cifs_sb->tcon->ses->userName)
index 7d95054..2498d64 100644 (file)
 #define BAD_PROT 0xFFFF
 
 /* SMB command codes */
-/* Some commands have minimal (wct=0,bcc=0), or uninteresting, responses
- (ie which include no useful data other than the SMB error code itself).
- Knowing this helps avoid response buffer allocations and copy in some cases */
+/*
+ * Some commands have minimal (wct=0,bcc=0), or uninteresting, responses
+ * (ie which include no useful data other than the SMB error code itself).
+ * Knowing this helps avoid response buffer allocations and copy in some cases
+ */
 #define SMB_COM_CREATE_DIRECTORY      0x00 /* trivial response */
 #define SMB_COM_DELETE_DIRECTORY      0x01 /* trivial response */
 #define SMB_COM_CLOSE                 0x04 /* triv req/rsp, timestamp ignored */
index 07ff935..a1265c9 100644 (file)
@@ -1014,8 +1014,9 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
        /* since the write may have blocked check these pointers again */
        if (file->f_path.dentry) {
                if (file->f_path.dentry->d_inode) {
-                       file->f_path.dentry->d_inode->i_ctime =
-                       file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;
+/*BB We could make this contingent on superblock ATIME flag too */
+/*                     file->f_path.dentry->d_inode->i_ctime =
+                       file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/
                        if (total_written > 0) {
                                if (*poffset > file->f_path.dentry->d_inode->i_size)
                                        i_size_write(file->f_path.dentry->d_inode,
index 3f5bc83..37c6ce8 100644 (file)
@@ -90,6 +90,9 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                                (*pinode)->i_ino =
                                        (unsigned long)findData.UniqueId;
                        } /* note ino incremented to unique num in new_inode */
+                       if(sb->s_flags & MS_NOATIME)
+                               (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
+                               
                        insert_inode_hash(*pinode);
                }
 
@@ -421,6 +424,8 @@ int cifs_get_inode_info(struct inode **pinode,
                                } else /* do we need cast or hash to ino? */
                                        (*pinode)->i_ino = inode_num;
                        } /* else ino incremented to unique num in new_inode*/
+                       if(sb->s_flags & MS_NOATIME)
+                               (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
                        insert_inode_hash(*pinode);
                }
                inode = *pinode;
@@ -1359,7 +1364,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                and this check ensures that we are not being called from
                sys_utimes in which case we ought to fail the call back to
                the user when the server rejects the call */
-               if((rc) && (attrs->ia_valid &&
+               if((rc) && (attrs->ia_valid &
                         (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
                        rc = 0;
        }
index 8e25996..6baea85 100644 (file)
@@ -77,7 +77,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
                cifsInode = CIFS_I(old_file->d_inode);
                if(rc == 0) {
                        old_file->d_inode->i_nlink++;
-                       old_file->d_inode->i_ctime = CURRENT_TIME;
+/* BB should we make this contingent on superblock flag NOATIME? */
+/*                     old_file->d_inode->i_ctime = CURRENT_TIME;*/
                        /* parent dir timestamps will update from srv
                        within a second, would it really be worth it
                        to set the parent dir cifs inode time to zero
index c6220bd..c444798 100644 (file)
@@ -83,6 +83,8 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
                                return rc;
                        rc = 1;
                }
+               if(file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
+                       (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;
        } else {
                tmp_dentry = d_alloc(file->f_path.dentry, qstring);
                if(tmp_dentry == NULL) {
@@ -98,6 +100,8 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
                        tmp_dentry->d_op = &cifs_dentry_ops;
                if(*ptmp_inode == NULL)
                        return rc;
+               if(file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
+                       (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;                       
                rc = 2;
        }
 
index b1981d0..baf71dd 100644 (file)
@@ -29,7 +29,7 @@
  * The file system contains group descriptors which are located after the
  * super block.  Each descriptor contains the number of the bitmap block and
  * the free blocks count in the block.  The descriptors are loaded in memory
- * when a file system is mounted (see ext2_read_super).
+ * when a file system is mounted (see ext2_fill_super).
  */
 
 
index 2216174..ca8aee6 100644 (file)
@@ -32,7 +32,7 @@
  * The file system contains group descriptors which are located after the
  * super block.  Each descriptor contains the number of the bitmap block and
  * the free blocks count in the block.  The descriptors are loaded in memory
- * when a file system is mounted (see ext3_read_super).
+ * when a file system is mounted (see ext3_fill_super).
  */
 
 
index c4dd110..8a23483 100644 (file)
@@ -50,7 +50,7 @@ void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
  * The file system contains group descriptors which are located after the
  * super block.  Each descriptor contains the number of the bitmap block and
  * the free blocks count in the block.  The descriptors are loaded in memory
- * when a file system is mounted (see ext4_read_super).
+ * when a file system is mounted (see ext4_fill_super).
  */
 
 
index 7610735..9bfe607 100644 (file)
@@ -173,10 +173,12 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
                 *
                 * But we must fill the remaining area or hole by nul for
                 * updating ->mmu_private.
+                *
+                * Return 0, and fallback to normal buffered write.
                 */
                loff_t size = offset + iov_length(iov, nr_segs);
                if (MSDOS_I(inode)->mmu_private < size)
-                       return -EINVAL;
+                       return 0;
        }
 
        /*
index 6988a10..03893ac 100644 (file)
@@ -1919,7 +1919,8 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
         * header ?
         */
        if (tlck->type & tlckTRUNCATE) {
-               pxd_t pxd;      /* truncated extent of xad */
+               /* This odd declaration suppresses a bogus gcc warning */
+               pxd_t pxd = pxd;        /* truncated extent of xad */
                int twm;
 
                /*
index 7d48704..cf79196 100644 (file)
@@ -335,17 +335,18 @@ int simple_prepare_write(struct file *file, struct page *page,
                        flush_dcache_page(page);
                        kunmap_atomic(kaddr, KM_USER0);
                }
-               SetPageUptodate(page);
        }
        return 0;
 }
 
 int simple_commit_write(struct file *file, struct page *page,
-                       unsigned offset, unsigned to)
+                       unsigned from, unsigned to)
 {
        struct inode *inode = page->mapping->host;
        loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
 
+       if (!PageUptodate(page))
+               SetPageUptodate(page);
        /*
         * No need to use i_size_read() here, the i_size
         * cannot change under us because we hold the i_mutex.
index 4f5745a..01f7769 100644 (file)
@@ -581,7 +581,7 @@ out_no_task:
 
 #ifndef mem_write
 /* This is a security hazard */
-static ssize_t mem_write(struct file * file, const char buf,
+static ssize_t mem_write(struct file * file, const char __user *buf,
                         size_t count, loff_t *ppos)
 {
        int copied;
index 98b0910..8d4d839 100644 (file)
@@ -502,6 +502,30 @@ int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
 
 
 /**
+ * sysfs_add_file_to_group - add an attribute file to a pre-existing group.
+ * @kobj: object we're acting for.
+ * @attr: attribute descriptor.
+ * @group: group name.
+ */
+int sysfs_add_file_to_group(struct kobject *kobj,
+               const struct attribute *attr, const char *group)
+{
+       struct dentry *dir;
+       int error;
+
+       dir = lookup_one_len(group, kobj->dentry, strlen(group));
+       if (IS_ERR(dir))
+               error = PTR_ERR(dir);
+       else {
+               error = sysfs_add_file(dir, attr, SYSFS_KOBJ_ATTR);
+               dput(dir);
+       }
+       return error;
+}
+EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
+
+
+/**
  * sysfs_update_file - update the modified timestamp on an object attribute.
  * @kobj: object we're acting for.
  * @attr: attribute descriptor.
@@ -586,6 +610,26 @@ void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
 }
 
 
+/**
+ * sysfs_remove_file_from_group - remove an attribute file from a group.
+ * @kobj: object we're acting for.
+ * @attr: attribute descriptor.
+ * @group: group name.
+ */
+void sysfs_remove_file_from_group(struct kobject *kobj,
+               const struct attribute *attr, const char *group)
+{
+       struct dentry *dir;
+
+       dir = lookup_one_len(group, kobj->dentry, strlen(group));
+       if (!IS_ERR(dir)) {
+               sysfs_hash_and_remove(dir, attr->name);
+               dput(dir);
+       }
+}
+EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group);
+
+
 EXPORT_SYMBOL_GPL(sysfs_create_file);
 EXPORT_SYMBOL_GPL(sysfs_remove_file);
 EXPORT_SYMBOL_GPL(sysfs_update_file);
index d976b00..a77c57e 100644 (file)
@@ -1,3 +1,14 @@
+struct sysfs_dirent {
+       atomic_t                s_count;
+       struct list_head        s_sibling;
+       struct list_head        s_children;
+       void                    * s_element;
+       int                     s_type;
+       umode_t                 s_mode;
+       struct dentry           * s_dentry;
+       struct iattr            * s_iattr;
+       atomic_t                s_event;
+};
 
 extern struct vfsmount * sysfs_mount;
 extern struct kmem_cache *sysfs_dir_cachep;
index 1a4103c..2f2c40d 100644 (file)
@@ -900,7 +900,7 @@ static struct quotactl_ops xfs_quotactl_operations = {
        .set_xquota             = xfs_fs_setxquota,
 };
 
-STATIC struct file_system_type xfs_fs_type = {
+static struct file_system_type xfs_fs_type = {
        .owner                  = THIS_MODULE,
        .name                   = "xfs",
        .get_sb                 = xfs_fs_get_sb,
index e67c238..3d348a3 100644 (file)
 #define __ASM_ARCH_PXA_GPIO_H
 
 #include <asm/arch/pxa-regs.h>
-#include <asm/arch/irqs.h>
-#include <asm/arch/hardware.h>
-
-#include <asm/errno.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
 
 static inline int gpio_request(unsigned gpio, const char *label)
 {
@@ -42,26 +40,36 @@ static inline void gpio_free(unsigned gpio)
 
 static inline int gpio_direction_input(unsigned gpio)
 {
-       if (gpio > PXA_LAST_GPIO)
-               return -EINVAL;
-       pxa_gpio_mode(gpio | GPIO_IN);
+       return pxa_gpio_mode(gpio | GPIO_IN);
 }
 
 static inline int gpio_direction_output(unsigned gpio)
 {
-       if (gpio > PXA_LAST_GPIO)
-               return -EINVAL;
-       pxa_gpio_mode(gpio | GPIO_OUT);
+       return pxa_gpio_mode(gpio | GPIO_OUT);
 }
 
-/* REVISIT these macros are correct, but suffer code explosion
- * for non-constant parameters.  Provide out-line versions too.
- */
-#define gpio_get_value(gpio) \
-       (GPLR(gpio) & GPIO_bit(gpio))
+static inline int __gpio_get_value(unsigned gpio)
+{
+       return GPLR(gpio) & GPIO_bit(gpio);
+}
+
+#define gpio_get_value(gpio)                   \
+       (__builtin_constant_p(gpio) ?           \
+        __gpio_get_value(gpio) :               \
+        pxa_gpio_get_value(gpio))
+
+static inline void __gpio_set_value(unsigned gpio, int value)
+{
+       if (value)
+               GPSR(gpio) = GPIO_bit(gpio);
+       else
+               GPCR(gpio) = GPIO_bit(gpio);
+}
 
-#define gpio_set_value(gpio,value) \
-       ((value) ? (GPSR(gpio) = GPIO_bit(gpio)):(GPCR(gpio) = GPIO_bit(gpio)))
+#define gpio_set_value(gpio,value)             \
+       (__builtin_constant_p(gpio) ?           \
+        __gpio_set_value(gpio, value) :        \
+        pxa_gpio_set_value(gpio, value))
 
 #include <asm-generic/gpio.h>                  /* cansleep wrappers */
 
index 3e70bd9..e2bdc2f 100644 (file)
 /*
  * Handy routine to set GPIO alternate functions
  */
-extern void pxa_gpio_mode( int gpio_mode );
+extern int pxa_gpio_mode( int gpio_mode );
+
+/*
+ * Return GPIO level, nonzero means high, zero is low
+ */
+extern int pxa_gpio_get_value(unsigned gpio);
+
+/*
+ * Set output GPIO level
+ */
+extern void pxa_gpio_set_value(unsigned gpio, int value);
 
 /*
  * Routine to enable or disable CKEN
index 67b8b9a..d47ae45 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * linux/include/asm-arm/arch-pxa/gpio.h
+ * linux/include/asm-arm/arch-s3c2410/gpio.h
  *
- * S3C2400 GPIO wrappers for arch-neutral GPIO calls
+ * S3C2410 GPIO wrappers for arch-neutral GPIO calls
  *
  * Written by Philipp Zabel <philipp.zabel@gmail.com>
  *
  *
  */
 
-#ifndef __ASM_ARCH_PXA_GPIO_H
-#define __ASM_ARCH_PXA_GPIO_H
+#ifndef __ASM_ARCH_S3C2410_GPIO_H
+#define __ASM_ARCH_S3C2410_GPIO_H
 
-#include <asm/arch/pxa-regs.h>
-#include <asm/arch/irqs.h>
-#include <asm/arch/hardware.h>
-
-#include <asm/errno.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/arch/regs-gpio.h>
 
 static inline int gpio_request(unsigned gpio, const char *label)
 {
@@ -57,8 +55,11 @@ static inline int gpio_direction_output(unsigned gpio)
 
 #include <asm-generic/gpio.h>                  /* cansleep wrappers */
 
-/* FIXME or maybe s3c2400_gpio_getirq() ... */
+#ifdef CONFIG_CPU_S3C2400
+#define gpio_to_irq(gpio)              s3c2400_gpio_getirq(gpio)
+#else
 #define gpio_to_irq(gpio)              s3c2410_gpio_getirq(gpio)
+#endif
 
 /* FIXME implement irq_to_gpio() */
 
index a331fe3..da7575b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/include/asm-arm/arch-pxa/gpio.h
+ * linux/include/asm-arm/arch-sa1100/gpio.h
  *
  * SA1100 GPIO wrappers for arch-neutral GPIO calls
  *
 #ifndef __ASM_ARCH_SA1100_GPIO_H
 #define __ASM_ARCH_SA1100_GPIO_H
 
-#include <asm/arch/SA-1100.h>
-#include <asm/arch/irqs.h>
-#include <asm/arch/hardware.h>
-
-#include <asm/errno.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
 
 static inline int gpio_request(unsigned gpio, const char *label)
 {
@@ -40,26 +37,23 @@ static inline void gpio_free(unsigned gpio)
        return;
 }
 
-static inline int gpio_direction_input(unsigned gpio)
+extern int gpio_direction_input(unsigned gpio);
+extern int gpio_direction_output(unsigned gpio);
+
+
+static inline int gpio_get_value(unsigned gpio)
 {
-       if (gpio > GPIO_MAX)
-               return -EINVAL;
-       GPDR = (GPDR_In << gpio) 0
+       return GPLR & GPIO_GPIO(gpio);
 }
 
-static inline int gpio_direction_output(unsigned gpio)
+static inline void gpio_set_value(unsigned gpio, int value)
 {
-       if (gpio > GPIO_MAX)
-               return -EINVAL;
-       GPDR = (GPDR_Out << gpio) 0
+       if (value)
+               GPSR = GPIO_GPIO(gpio);
+       else
+               GPCR = GPIO_GPIO(gpio);
 }
 
-#define gpio_get_value(gpio) \
-       (GPLR & GPIO_GPIO(gpio))
-
-#define gpio_set_value(gpio,value) \
-       ((value) ? (GPSR = GPIO_GPIO(gpio)) : (GPCR(gpio) = GPIO_GPIO(gpio)))
-
 #include <asm-generic/gpio.h>                  /* cansleep wrappers */
 
 static inline unsigned gpio_to_irq(unsigned gpio)
diff --git a/include/asm-i386/idle.h b/include/asm-i386/idle.h
deleted file mode 100644 (file)
index 87ab939..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef _ASM_I386_IDLE_H
-#define _ASM_I386_IDLE_H 1
-
-#define IDLE_START 1
-#define IDLE_END 2
-
-struct notifier_block;
-void idle_notifier_register(struct notifier_block *n);
-void idle_notifier_unregister(struct notifier_block *n);
-
-void exit_idle(void);
-void enter_idle(void);
-
-#endif
index edfbe46..11bf899 100644 (file)
@@ -257,14 +257,6 @@ static inline void __mwait(unsigned long eax, unsigned long ecx)
                : :"a" (eax), "c" (ecx));
 }
 
-static inline void __sti_mwait(unsigned long eax, unsigned long ecx)
-{
-       /* "mwait %eax,%ecx;" */
-       asm volatile(
-               "sti; .byte 0x0f,0x01,0xc9;"
-               : :"a" (eax), "c" (ecx));
-}
-
 extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx);
 
 /* from system description table in BIOS.  Mostly for MCA use, but
index 8a1f2b6..1906938 100644 (file)
@@ -21,6 +21,7 @@
 #define FPC_EIR                70
 #define DSP_BASE       71              /* 3 more hi / lo register pairs */
 #define DSP_CONTROL    77
+#define ACX            78
 
 /*
  * This struct defines the way the registers are stored on the stack during a
@@ -39,6 +40,9 @@ struct pt_regs {
        unsigned long cp0_status;
        unsigned long hi;
        unsigned long lo;
+#ifdef CONFIG_CPU_HAS_SMARTMIPS
+       unsigned long acx;
+#endif
        unsigned long cp0_badvaddr;
        unsigned long cp0_cause;
        unsigned long cp0_epc;
index 9729474..9ce0607 100644 (file)
@@ -23,7 +23,7 @@ struct sigcontext {
        unsigned long long      sc_pc;
        unsigned long long      sc_regs[32];
        unsigned long long      sc_fpregs[32];
-       unsigned int            sc_ownedfp;     /* Unused */
+       unsigned int            sc_acx;         /* Was sc_ownedfp */
        unsigned int            sc_fpc_csr;
        unsigned int            sc_fpc_eir;     /* Unused */
        unsigned int            sc_used_math;
@@ -79,7 +79,7 @@ struct sigcontext32 {
        __u64           sc_pc;
        __u64           sc_regs[32];
        __u64           sc_fpregs[32];
-       __u32           sc_ownedfp;     /* Unused */
+       __u32           sc_acx;         /* Only MIPS32; was sc_ownedfp */
        __u32           sc_fpc_csr;
        __u32           sc_fpc_eir;     /* Unused */
        __u32           sc_used_math;
index 1fae5dc..7afa1fd 100644 (file)
                .endm
 
                .macro  SAVE_TEMP
+#ifdef CONFIG_CPU_HAS_SMARTMIPS
+               mflhxu  v1
+               LONG_S  v1, PT_LO(sp)
+               mflhxu  v1
+               LONG_S  v1, PT_HI(sp)
+               mflhxu  v1
+               LONG_S  v1, PT_ACX(sp)
+#else
                mfhi    v1
+               LONG_S  v1, PT_HI(sp)
+               mflo    v1
+               LONG_S  v1, PT_LO(sp)
+#endif
 #ifdef CONFIG_32BIT
                LONG_S  $8, PT_R8(sp)
                LONG_S  $9, PT_R9(sp)
 #endif
-               LONG_S  v1, PT_HI(sp)
-               mflo    v1
                LONG_S  $10, PT_R10(sp)
                LONG_S  $11, PT_R11(sp)
-               LONG_S  v1,  PT_LO(sp)
                LONG_S  $12, PT_R12(sp)
                LONG_S  $13, PT_R13(sp)
                LONG_S  $14, PT_R14(sp)
                .endm
 
                .macro  RESTORE_TEMP
+#ifdef CONFIG_CPU_HAS_SMARTMIPS
+               LONG_L  $24, PT_ACX(sp)
+               mtlhx   $24
+               LONG_L  $24, PT_HI(sp)
+               mtlhx   $24
                LONG_L  $24, PT_LO(sp)
+               mtlhx   $24
+#else
+               LONG_L  $24, PT_LO(sp)
+               mtlo    $24
+               LONG_L  $24, PT_HI(sp)
+               mthi    $24
+#endif
 #ifdef CONFIG_32BIT
                LONG_L  $8, PT_R8(sp)
                LONG_L  $9, PT_R9(sp)
 #endif
-               mtlo    $24
-               LONG_L  $24, PT_HI(sp)
                LONG_L  $10, PT_R10(sp)
                LONG_L  $11, PT_R11(sp)
-               mthi    $24
                LONG_L  $12, PT_R12(sp)
                LONG_L  $13, PT_R13(sp)
                LONG_L  $14, PT_R14(sp)
index 5a1e0e8..5587f00 100644 (file)
 #define STREGM std,ma
 #define SHRREG shrd
 #define SHLREG shld
+#define ADDIB   addib,*
+#define CMPB    cmpb,*
+#define ANDCM   andcm,*
 #define RP_OFFSET      16
 #define FRAME_SIZE     128
 #define CALLEE_REG_FRAME_SIZE  144
+#define ASM_ULONG_INSN .dword
 #else  /* CONFIG_64BIT */
 #define LDREG  ldw
 #define STREG  stw
 #define STREGM stwm
 #define SHRREG shr
 #define SHLREG shlw
+#define ADDIB   addib,
+#define CMPB    cmpb,
+#define ANDCM   andcm
 #define RP_OFFSET      20
 #define FRAME_SIZE     64
 #define CALLEE_REG_FRAME_SIZE  128
+#define ASM_ULONG_INSN .word
 #endif
 
 #define CALLEE_SAVE_FRAME_SIZE (CALLEE_REG_FRAME_SIZE + CALLEE_FLOAT_FRAME_SIZE)
@@ -65,7 +73,7 @@
 
 #ifdef __ASSEMBLY__
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 /* the 64-bit pa gnu assembler unfortunately defaults to .level 1.1 or 2.0 so
  * work around that for now... */
        .level 2.0w
        .endm
 
        .macro loadgp
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        ldil            L%__gp, %r27
        ldo             R%__gp(%r27), %r27
 #else
        fldd,mb -8(%r30),   %fr12
        .endm
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        .macro  callee_save
        std,ma    %r3,   CALLEE_REG_FRAME_SIZE(%r30)
        mfctl     %cr27, %r3
        ldd,mb  -CALLEE_REG_FRAME_SIZE(%r30),    %r3
        .endm
 
-#else /* ! __LP64__ */
+#else /* ! CONFIG_64BIT */
 
        .macro  callee_save
        stw,ma   %r3,   CALLEE_REG_FRAME_SIZE(%r30)
        mtctl   %r3, %cr27
        ldw,mb  -CALLEE_REG_FRAME_SIZE(%r30),   %r3
        .endm
-#endif /* ! __LP64__ */
+#endif /* ! CONFIG_64BIT */
 
        .macro  save_specials   regs
 
        mtctl    %r0,   %cr18
        SAVE_CR  (%cr18, PT_IAOQ1(\regs))
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        /* cr11 (sar) is a funny one.  5 bits on PA1.1 and 6 bit on PA2.0
         * For PA2.0 mtsar or mtctl always write 6 bits, but mfctl only
         * reads 5 bits.  Use mfctl,w to read all six bits.  Otherwise
index 48bf9b8..7d57d34 100644 (file)
@@ -58,7 +58,7 @@ extern void __xchg_called_with_bad_pointer(void);
 /* __xchg32/64 defined in arch/parisc/lib/bitops.c */
 extern unsigned long __xchg8(char, char *);
 extern unsigned long __xchg32(int, int *);
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 extern unsigned long __xchg64(unsigned long, unsigned long *);
 #endif
 
@@ -67,7 +67,7 @@ static __inline__ unsigned long
 __xchg(unsigned long x, __volatile__ void * ptr, int size)
 {
        switch(size) {
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        case 8: return __xchg64(x,(unsigned long *) ptr);
 #endif
        case 4: return __xchg32((int) x, (int *) ptr);
@@ -81,7 +81,7 @@ __xchg(unsigned long x, __volatile__ void * ptr, int size)
 /*
 ** REVISIT - Abandoned use of LDCW in xchg() for now:
 ** o need to test sizeof(*ptr) to avoid clearing adjacent bytes
-** o and while we are at it, could __LP64__ code use LDCD too?
+** o and while we are at it, could CONFIG_64BIT code use LDCD too?
 **
 **     if (__builtin_constant_p(x) && (x == NULL))
 **             if (((unsigned long)p & 0xf) == 0)
@@ -105,7 +105,7 @@ static __inline__ unsigned long
 __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size)
 {
        switch(size) {
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        case 8: return __cmpxchg_u64((unsigned long *)ptr, old, new_);
 #endif
        case 4: return __cmpxchg_u32((unsigned int *)ptr, (unsigned int) old, (unsigned int) new_);
@@ -218,7 +218,7 @@ static __inline__ int atomic_read(const atomic_t *v)
 #define smp_mb__before_atomic_inc()    smp_mb()
 #define smp_mb__after_atomic_inc()     smp_mb()
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 
 typedef struct { volatile s64 counter; } atomic64_t;
 
@@ -270,7 +270,7 @@ atomic64_read(const atomic64_t *v)
 #define atomic64_dec_and_test(v)       (atomic64_dec_return(v) == 0)
 #define atomic64_sub_and_test(i,v)     (atomic64_sub_return((i),(v)) == 0)
 
-#endif /* __LP64__ */
+#endif /* CONFIG_64BIT */
 
 #include <asm-generic/atomic.h>
 
index 9005619..015cb0d 100644 (file)
@@ -60,31 +60,37 @@ static __inline__ void change_bit(int nr, volatile unsigned long * addr)
 static __inline__ int test_and_set_bit(int nr, volatile unsigned long * addr)
 {
        unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr);
-       unsigned long oldbit;
+       unsigned long old;
        unsigned long flags;
+       int set;
 
        addr += (nr >> SHIFT_PER_LONG);
        _atomic_spin_lock_irqsave(addr, flags);
-       oldbit = *addr;
-       *addr = oldbit | mask;
+       old = *addr;
+       set = (old & mask) ? 1 : 0;
+       if (!set)
+               *addr = old | mask;
        _atomic_spin_unlock_irqrestore(addr, flags);
 
-       return (oldbit & mask) ? 1 : 0;
+       return set;
 }
 
 static __inline__ int test_and_clear_bit(int nr, volatile unsigned long * addr)
 {
        unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr);
-       unsigned long oldbit;
+       unsigned long old;
        unsigned long flags;
+       int set;
 
        addr += (nr >> SHIFT_PER_LONG);
        _atomic_spin_lock_irqsave(addr, flags);
-       oldbit = *addr;
-       *addr = oldbit & ~mask;
+       old = *addr;
+       set = (old & mask) ? 1 : 0;
+       if (set)
+               *addr = old & ~mask;
        _atomic_spin_unlock_irqrestore(addr, flags);
 
-       return (oldbit & mask) ? 1 : 0;
+       return set;
 }
 
 static __inline__ int test_and_change_bit(int nr, volatile unsigned long * addr)
@@ -130,7 +136,7 @@ static __inline__ unsigned long __ffs(unsigned long x)
        unsigned long ret;
 
        __asm__(
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
                " ldi       63,%1\n"
                " extrd,u,*<>  %0,63,32,%%r0\n"
                " extrd,u,*TR  %0,31,32,%0\n"   /* move top 32-bits down */
index 695588d..83ba510 100644 (file)
@@ -1,14 +1,92 @@
 #ifndef _PARISC_BUG_H
 #define _PARISC_BUG_H
 
+/*
+ * Tell the user there is some problem.
+ * The offending file and line are encoded in the __bug_table section.
+ */
+
 #ifdef CONFIG_BUG
 #define HAVE_ARCH_BUG
-#define BUG() do { \
-       printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
-       dump_stack(); \
-       panic("BUG!"); \
-} while (0)
+#define HAVE_ARCH_WARN_ON
+
+/* the break instruction is used as BUG() marker.  */
+#define        PARISC_BUG_BREAK_ASM    "break 0x1f, 0x1fff"
+#define        PARISC_BUG_BREAK_INSN   0x03ffe01f  /* PARISC_BUG_BREAK_ASM */
+
+#if defined(CONFIG_64BIT)
+#define ASM_WORD_INSN          ".dword\t"
+#else
+#define ASM_WORD_INSN          ".word\t"
+#endif
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+#define BUG()                                                          \
+       do {                                                            \
+               asm volatile("\n"                                       \
+                            "1:\t" PARISC_BUG_BREAK_ASM "\n"           \
+                            "\t.pushsection __bug_table,\"a\"\n"       \
+                            "2:\t" ASM_WORD_INSN "1b, %c0\n"           \
+                            "\t.short %c1, %c2\n"                      \
+                            "\t.org 2b+%c3\n"                          \
+                            "\t.popsection"                            \
+                            : : "i" (__FILE__), "i" (__LINE__),        \
+                            "i" (0), "i" (sizeof(struct bug_entry)) ); \
+               for(;;) ;                                               \
+       } while(0)
+
+#else
+#define BUG()                                                          \
+       do {                                                            \
+               asm volatile(PARISC_BUG_BREAK_ASM : : );                \
+               for(;;) ;                                               \
+       } while(0)
+#endif
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+#define __WARN()                                                       \
+       do {                                                            \
+               asm volatile("\n"                                       \
+                            "1:\t" PARISC_BUG_BREAK_ASM "\n"           \
+                            "\t.pushsection __bug_table,\"a\"\n"       \
+                            "2:\t" ASM_WORD_INSN "1b, %c0\n"           \
+                            "\t.short %c1, %c2\n"                      \
+                            "\t.org 2b+%c3\n"                          \
+                            "\t.popsection"                            \
+                            : : "i" (__FILE__), "i" (__LINE__),        \
+                            "i" (BUGFLAG_WARNING),                     \
+                            "i" (sizeof(struct bug_entry)) );          \
+       } while(0)
+#else
+#define __WARN()                                                       \
+       do {                                                            \
+               asm volatile("\n"                                       \
+                            "1:\t" PARISC_BUG_BREAK_ASM "\n"           \
+                            "\t.pushsection __bug_table,\"a\"\n"       \
+                            "2:\t" ASM_WORD_INSN "1b\n"                \
+                            "\t.short %c0\n"                           \
+                            "\t.org 2b+%c1\n"                          \
+                            "\t.popsection"                            \
+                            : : "i" (BUGFLAG_WARNING),                 \
+                            "i" (sizeof(struct bug_entry)) );          \
+       } while(0)
+#endif
+
+
+#define WARN_ON(x) ({                                          \
+       typeof(x) __ret_warn_on = (x);                          \
+       if (__builtin_constant_p(__ret_warn_on)) {              \
+               if (__ret_warn_on)                              \
+                       __WARN();                               \
+       } else {                                                \
+               if (unlikely(__ret_warn_on))                    \
+                       __WARN();                               \
+       }                                                       \
+       unlikely(__ret_warn_on);                                \
+})
+
 #endif
 
 #include <asm-generic/bug.h>
 #endif
+
index 7d22fa2..32c2cca 100644 (file)
 
 #define __read_mostly __attribute__((__section__(".data.read_mostly")))
 
-extern void flush_data_cache_local(void *);  /* flushes local data-cache only */
-extern void flush_instruction_cache_local(void *); /* flushes local code-cache only */
-#ifdef CONFIG_SMP
-extern void flush_data_cache(void); /* flushes data-cache only (all processors) */
-extern void flush_instruction_cache(void); /* flushes i-cache only (all processors) */
-#else
-#define flush_data_cache() flush_data_cache_local(NULL)
-#define flush_instruction_cache() flush_instruction_cache_local(NULL)
-#endif
-
-extern void parisc_cache_init(void);   /* initializes cache-flushing */
-extern void flush_all_caches(void);     /* flush everything (tlb & cache) */
-extern int get_cache_info(char *);
-extern void flush_user_icache_range_asm(unsigned long, unsigned long);
-extern void flush_kernel_icache_range_asm(unsigned long, unsigned long);
-extern void flush_user_dcache_range_asm(unsigned long, unsigned long);
-extern void flush_kernel_dcache_range_asm(unsigned long, unsigned long);
-extern void flush_kernel_dcache_page_asm(void *);
-extern void flush_kernel_icache_page(void *);
-extern void disable_sr_hashing(void);   /* turns off space register hashing */
-extern void disable_sr_hashing_asm(int); /* low level support for above */
-extern void free_sid(unsigned long);
+void parisc_cache_init(void);  /* initializes cache-flushing */
+void disable_sr_hashing_asm(int); /* low level support for above */
+void disable_sr_hashing(void);   /* turns off space register hashing */
+void free_sid(unsigned long);
 unsigned long alloc_sid(void);
-extern void flush_user_dcache_page(unsigned long);
-extern void flush_user_icache_page(unsigned long);
 
 struct seq_file;
 extern void show_cache_info(struct seq_file *m);
@@ -63,6 +43,7 @@ extern int split_tlb;
 extern int dcache_stride;
 extern int icache_stride;
 extern struct pdc_cache_info cache_info;
+void parisc_setup_cache_timing(void);
 
 #define pdtlb(addr)         asm volatile("pdtlb 0(%%sr1,%0)" : : "r" (addr));
 #define pitlb(addr)         asm volatile("pitlb 0(%%sr1,%0)" : : "r" (addr));
index a799dd8..2f1e1b0 100644 (file)
@@ -2,60 +2,46 @@
 #define _PARISC_CACHEFLUSH_H
 
 #include <linux/mm.h>
-#include <asm/cache.h> /* for flush_user_dcache_range_asm() proto */
 
 /* The usual comment is "Caches aren't brain-dead on the <architecture>".
  * Unfortunately, that doesn't apply to PA-RISC. */
 
-/* Cache flush operations */
-
+/* Internal implementation */
+void flush_data_cache_local(void *);  /* flushes local data-cache only */
+void flush_instruction_cache_local(void *); /* flushes local code-cache only */
 #ifdef CONFIG_SMP
-#define flush_cache_mm(mm) flush_cache_all()
+void flush_data_cache(void); /* flushes data-cache only (all processors) */
+void flush_instruction_cache(void); /* flushes i-cache only (all processors) */
 #else
-#define flush_cache_mm(mm) flush_cache_all_local()
+#define flush_data_cache() flush_data_cache_local(NULL)
+#define flush_instruction_cache() flush_instruction_cache_local(NULL)
 #endif
 
 #define flush_cache_dup_mm(mm) flush_cache_mm(mm)
 
-#define flush_kernel_dcache_range(start,size) \
-       flush_kernel_dcache_range_asm((start), (start)+(size));
+void flush_user_icache_range_asm(unsigned long, unsigned long);
+void flush_kernel_icache_range_asm(unsigned long, unsigned long);
+void flush_user_dcache_range_asm(unsigned long, unsigned long);
+void flush_kernel_dcache_range_asm(unsigned long, unsigned long);
+void flush_kernel_dcache_page_asm(void *);
+void flush_kernel_icache_page(void *);
+void flush_user_dcache_page(unsigned long);
+void flush_user_icache_page(unsigned long);
+void flush_user_dcache_range(unsigned long, unsigned long);
+void flush_user_icache_range(unsigned long, unsigned long);
 
-extern void flush_cache_all_local(void);
+/* Cache flush operations */
 
-static inline void cacheflush_h_tmp_function(void *dummy)
-{
-       flush_cache_all_local();
-}
+void flush_cache_all_local(void);
+void flush_cache_all(void);
+void flush_cache_mm(struct mm_struct *mm);
 
-static inline void flush_cache_all(void)
-{
-       on_each_cpu(cacheflush_h_tmp_function, NULL, 1, 1);
-}
+#define flush_kernel_dcache_range(start,size) \
+       flush_kernel_dcache_range_asm((start), (start)+(size));
 
 #define flush_cache_vmap(start, end)           flush_cache_all()
 #define flush_cache_vunmap(start, end)         flush_cache_all()
 
-extern int parisc_cache_flush_threshold;
-void parisc_setup_cache_timing(void);
-
-static inline void
-flush_user_dcache_range(unsigned long start, unsigned long end)
-{
-       if ((end - start) < parisc_cache_flush_threshold)
-               flush_user_dcache_range_asm(start,end);
-       else
-               flush_data_cache();
-}
-
-static inline void
-flush_user_icache_range(unsigned long start, unsigned long end)
-{
-       if ((end - start) < parisc_cache_flush_threshold)
-               flush_user_icache_range_asm(start,end);
-       else
-               flush_instruction_cache();
-}
-
 extern void flush_dcache_page(struct page *page);
 
 #define flush_dcache_mmap_lock(mapping) \
@@ -63,9 +49,15 @@ extern void flush_dcache_page(struct page *page);
 #define flush_dcache_mmap_unlock(mapping) \
        write_unlock_irq(&(mapping)->tree_lock)
 
-#define flush_icache_page(vma,page)    do { flush_kernel_dcache_page(page); flush_kernel_icache_page(page_address(page)); } while (0)
+#define flush_icache_page(vma,page)    do {            \
+       flush_kernel_dcache_page(page);                 \
+       flush_kernel_icache_page(page_address(page));   \
+} while (0)
 
-#define flush_icache_range(s,e)                do { flush_kernel_dcache_range_asm(s,e); flush_kernel_icache_range_asm(s,e); } while (0)
+#define flush_icache_range(s,e)                do {            \
+       flush_kernel_dcache_range_asm(s,e);             \
+       flush_kernel_icache_range_asm(s,e);             \
+} while (0)
 
 #define copy_to_user_page(vma, page, vaddr, dst, src, len) \
 do { \
@@ -80,118 +72,17 @@ do { \
        memcpy(dst, src, len); \
 } while (0)
 
-static inline void flush_cache_range(struct vm_area_struct *vma,
-               unsigned long start, unsigned long end)
-{
-       int sr3;
-
-       if (!vma->vm_mm->context) {
-               BUG();
-               return;
-       }
-
-       sr3 = mfsp(3);
-       if (vma->vm_mm->context == sr3) {
-               flush_user_dcache_range(start,end);
-               flush_user_icache_range(start,end);
-       } else {
-               flush_cache_all();
-       }
-}
-
-/* Simple function to work out if we have an existing address translation
- * for a user space vma. */
-static inline int translation_exists(struct vm_area_struct *vma,
-                               unsigned long addr, unsigned long pfn)
-{
-       pgd_t *pgd = pgd_offset(vma->vm_mm, addr);
-       pmd_t *pmd;
-       pte_t pte;
-
-       if(pgd_none(*pgd))
-               return 0;
-
-       pmd = pmd_offset(pgd, addr);
-       if(pmd_none(*pmd) || pmd_bad(*pmd))
-               return 0;
-
-       /* We cannot take the pte lock here: flush_cache_page is usually
-        * called with pte lock already held.  Whereas flush_dcache_page
-        * takes flush_dcache_mmap_lock, which is lower in the hierarchy:
-        * the vma itself is secure, but the pte might come or go racily.
-        */
-       pte = *pte_offset_map(pmd, addr);
-       /* But pte_unmap() does nothing on this architecture */
-
-       /* Filter out coincidental file entries and swap entries */
-       if (!(pte_val(pte) & (_PAGE_FLUSH|_PAGE_PRESENT)))
-               return 0;
-
-       return pte_pfn(pte) == pfn;
-}
-
-/* Private function to flush a page from the cache of a non-current
- * process.  cr25 contains the Page Directory of the current user
- * process; we're going to hijack both it and the user space %sr3 to
- * temporarily make the non-current process current.  We have to do
- * this because cache flushing may cause a non-access tlb miss which
- * the handlers have to fill in from the pgd of the non-current
- * process. */
-static inline void
-flush_user_cache_page_non_current(struct vm_area_struct *vma,
-                                 unsigned long vmaddr)
-{
-       /* save the current process space and pgd */
-       unsigned long space = mfsp(3), pgd = mfctl(25);
-
-       /* we don't mind taking interrups since they may not
-        * do anything with user space, but we can't
-        * be preempted here */
-       preempt_disable();
-
-       /* make us current */
-       mtctl(__pa(vma->vm_mm->pgd), 25);
-       mtsp(vma->vm_mm->context, 3);
-
-       flush_user_dcache_page(vmaddr);
-       if(vma->vm_flags & VM_EXEC)
-               flush_user_icache_page(vmaddr);
-
-       /* put the old current process back */
-       mtsp(space, 3);
-       mtctl(pgd, 25);
-       preempt_enable();
-}
-
-static inline void
-__flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr)
-{
-       if (likely(vma->vm_mm->context == mfsp(3))) {
-               flush_user_dcache_page(vmaddr);
-               if (vma->vm_flags & VM_EXEC)
-                       flush_user_icache_page(vmaddr);
-       } else {
-               flush_user_cache_page_non_current(vma, vmaddr);
-       }
-}
-
-static inline void
-flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long pfn)
-{
-       BUG_ON(!vma->vm_mm->context);
-
-       if (likely(translation_exists(vma, vmaddr, pfn)))
-               __flush_cache_page(vma, vmaddr);
-
-}
+void flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long pfn);
+void flush_cache_range(struct vm_area_struct *vma,
+               unsigned long start, unsigned long end);
 
+#define ARCH_HAS_FLUSH_ANON_PAGE
 static inline void
 flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr)
 {
        if (PageAnon(page))
                flush_user_dcache_page(vmaddr);
 }
-#define ARCH_HAS_FLUSH_ANON_PAGE
 
 #define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
 void flush_kernel_dcache_page_addr(void *addr);
index 66f0b40..c6c0e9f 100644 (file)
@@ -236,7 +236,7 @@ int ccio_allocate_resource(const struct parisc_device *dev,
                unsigned long min, unsigned long max, unsigned long align);
 #else /* !CONFIG_IOMMU_CCIO */
 #define ccio_get_iommu(dev) NULL
-#define ccio_request_resource(dev, res) request_resource(&iomem_resource, res)
+#define ccio_request_resource(dev, res) insert_resource(&iomem_resource, res)
 #define ccio_allocate_resource(dev, res, size, min, max, align) \
                allocate_resource(&iomem_resource, res, size, min, max, \
                                align, NULL, NULL)
index adea65f..f628ac7 100644 (file)
@@ -220,7 +220,7 @@ typedef struct elf64_fdesc {
  * macros, and then it includes fs/binfmt_elf.c to provide an alternate
  * elf binary handler for 32 bit binaries (on the 64 bit kernel).
  */
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 #define ELF_CLASS       ELFCLASS64
 #else
 #define ELF_CLASS      ELFCLASS32
index 106d3f7..76d880d 100644 (file)
@@ -1,19 +1,13 @@
 #ifndef _PARISC_HARDWARE_H
 #define _PARISC_HARDWARE_H
 
+#include <linux/mod_devicetable.h>
 #include <asm/pdc.h>
 
-struct parisc_device_id {
-       unsigned char   hw_type;        /* 5 bits used */
-       unsigned char   hversion_rev;   /* 4 bits */
-       unsigned short  hversion;       /* 12 bits */
-       unsigned int    sversion;       /* 20 bits */
-};
-
-#define HWTYPE_ANY_ID  0xff
-#define HVERSION_REV_ANY_ID    0xff
-#define HVERSION_ANY_ID        0xffff
-#define SVERSION_ANY_ID        0xffffffffU
+#define HWTYPE_ANY_ID          PA_HWTYPE_ANY_ID
+#define HVERSION_ANY_ID                PA_HVERSION_ANY_ID
+#define HVERSION_REV_ANY_ID    PA_HVERSION_REV_ANY_ID
+#define SVERSION_ANY_ID                PA_SVERSION_ANY_ID
 
 struct hp_hardware {
        unsigned short  hw_type:5;      /* HPHW_xxx */
index ca46e7c..c0fed91 100644 (file)
@@ -67,7 +67,7 @@ static inline unsigned long long gsc_readq(unsigned long addr)
 {
        unsigned long long ret;
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        __asm__ __volatile__(
        "       ldda    0(%1),%0\n"
        :  "=r" (ret) : "r" (addr) );
@@ -108,7 +108,7 @@ static inline void gsc_writel(unsigned int val, unsigned long addr)
 
 static inline void gsc_writeq(unsigned long long val, unsigned long addr)
 {
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        __asm__ __volatile__(
        "       stda    %0,0(%1)\n"
        : :  "r" (val), "r" (addr) );
index efadfd5..c3405ab 100644 (file)
@@ -31,7 +31,7 @@ void __init register_led_regions(void);
 
 #ifdef CONFIG_CHASSIS_LCD_LED
 /* writes a string to the LCD display (if possible on this h/w) */
-int lcd_print(char *str);
+int lcd_print(const char *str);
 #else
 #define lcd_print(str)
 #endif
index 291c2d0..7a09d91 100644 (file)
@@ -1,6 +1,28 @@
-#ifndef __ASM_LINKAGE_H
-#define __ASM_LINKAGE_H
+#ifndef __ASM_PARISC_LINKAGE_H
+#define __ASM_PARISC_LINKAGE_H
 
-/* Nothing to see here... */
+#ifndef __ALIGN
+#define __ALIGN         .align 4
+#define __ALIGN_STR     ".align 4"
+#endif
+
+/*
+ * In parisc assembly a semicolon marks a comment while a
+ * exclamation mark is used to seperate independend lines.
+ */
+#define ENTRY(name) \
+       .export name !\
+       ALIGN !\
+name:
 
+#ifdef CONFIG_64BIT
+#define ENDPROC(name) \
+       END(name)
+#else
+#define ENDPROC(name) \
+       .type name, @function !\
+       END(name)
 #endif
+
+
+#endif  /* __ASM_PARISC_LINKAGE_H */
index c878136..9608d2c 100644 (file)
@@ -35,7 +35,7 @@ extern struct node_map_data node_data[];
 #define PFNNID_MAP_MAX  512     /* support 512GB */
 extern unsigned char pfnnid_map[PFNNID_MAP_MAX];
 
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
 #define pfn_is_io(pfn) ((pfn & (0xf0000000UL >> PAGE_SHIFT)) == (0xf0000000UL >> PAGE_SHIFT))
 #else
 /* io can be 0xf0f0f0f0f0xxxxxx or 0xfffffffff0000000 */
index 00f0688..c2cb49e 100644 (file)
@@ -3,7 +3,7 @@
 /*
  * This file contains the parisc architecture specific module code.
  */
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 #define Elf_Shdr Elf64_Shdr
 #define Elf_Sym Elf64_Sym
 #define Elf_Ehdr Elf64_Ehdr
index 14ffc27..fe88f26 100644 (file)
 
 struct msqid64_ds {
        struct ipc64_perm msg_perm;
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
        unsigned int   __pad1;
 #endif
        __kernel_time_t msg_stime;      /* last msgsnd time */
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
        unsigned int   __pad2;
 #endif
        __kernel_time_t msg_rtime;      /* last msgrcv time */
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
        unsigned int   __pad3;
 #endif
        __kernel_time_t msg_ctime;      /* last change time */
index 3567208..f6bba4c 100644 (file)
@@ -105,7 +105,7 @@ extern int npmem_ranges;
 /* WARNING: The definitions below must match exactly to sizeof(pte_t)
  * etc
  */
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 #define BITS_PER_PTE_ENTRY     3
 #define BITS_PER_PMD_ENTRY     2
 #define BITS_PER_PGD_ENTRY     2
@@ -127,7 +127,11 @@ extern int npmem_ranges;
 /* This governs the relationship between virtual and physical addresses.
  * If you alter it, make sure to take care of our various fixed mapping
  * segments in fixmap.h */
-#define __PAGE_OFFSET           (0x10000000)
+#ifdef CONFIG_64BIT
+#define __PAGE_OFFSET  (0x40000000)    /* 1GB */
+#else
+#define __PAGE_OFFSET  (0x10000000)    /* 256MB */
+#endif
 
 #define PAGE_OFFSET            ((unsigned long)__PAGE_OFFSET)
 
index e12624d..7aa13f2 100644 (file)
@@ -15,7 +15,7 @@ struct parisc_device {
        unsigned int    num_addrs;      /* some devices have additional address ranges. */
        unsigned long   *addr;          /* which will be stored here */
  
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        /* parms for pdc_pat_cell_module() call */
        unsigned long   pcell_loc;      /* Physical Cell location */
        unsigned long   mod_index;      /* PAT specific - Misc Module info */
index 423c2b8..876fd81 100644 (file)
@@ -341,7 +341,7 @@ struct pdc_model {          /* for PDC_MODEL */
 
 struct pdc_cache_cf {          /* for PDC_CACHE  (I/D-caches) */
     unsigned long
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
                cc_padW:32,
 #endif
                cc_alias: 4,    /* alias boundaries for virtual addresses   */
@@ -357,7 +357,7 @@ struct pdc_cache_cf {               /* for PDC_CACHE  (I/D-caches) */
 
 struct pdc_tlb_cf {            /* for PDC_CACHE (I/D-TLB's) */
     unsigned long tc_pad0:12,  /* reserved */
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
                tc_padW:32,
 #endif
                tc_sh   : 2,    /* 0 = separate I/D-TLB, else shared I/D-TLB */
@@ -445,7 +445,7 @@ struct pdc_btlb_info {      /* PDC_BLOCK_TLB, return of PDC_BTLB_INFO */
 
 #endif /* !CONFIG_PA20 */
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 struct pdc_memory_table_raddr { /* PDC_MEM/PDC_MEM_TABLE (return info) */
        unsigned long entries_returned;
        unsigned long entries_total;
@@ -456,7 +456,7 @@ struct pdc_memory_table {       /* PDC_MEM/PDC_MEM_TABLE (arguments) */
        unsigned int  pages;
        unsigned int  reserved;
 };
-#endif /* __LP64__ */
+#endif /* CONFIG_64BIT */
 
 struct pdc_system_map_mod_info { /* PDC_SYSTEM_MAP/FIND_MODULE */
        unsigned long mod_addr;
@@ -752,7 +752,7 @@ int pdc_get_initiator(struct hardware_path *, struct pdc_initiator *);
 int pdc_tod_read(struct pdc_tod *tod);
 int pdc_tod_set(unsigned long sec, unsigned long usec);
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr,
                struct pdc_memory_table *tbl, unsigned long entries);
 #endif
index b4b34c0..47539f1 100644 (file)
@@ -250,7 +250,7 @@ struct pdc_pat_pd_addr_map_entry {
 #define PAT_GET_ENTITY(value)  (((value) >> 56) & 0xffUL)
 #define PAT_GET_DVI(value)     (((value) >> 48) & 0xffUL)
 #define PAT_GET_IOC(value)     (((value) >> 40) & 0xffUL)
-#define PAT_GET_MOD_PAGES(value)(((value) & 0xffffffUL)
+#define PAT_GET_MOD_PAGES(value) ((value) & 0xffffffUL)
 
 
 /*
@@ -303,35 +303,6 @@ extern int pdc_pat_io_pci_cfg_write(unsigned long pci_addr, int pci_size, u32 va
 */
 extern int pdc_pat;     /* arch/parisc/kernel/inventory.c */
 
-/********************************************************************
-* PDC_PAT_CELL[Return Cell Module] memaddr[0] conf_base_addr
-* ----------------------------------------------------------
-* Bit  0 to 51 - conf_base_addr
-* Bit 52 to 62 - reserved
-* Bit       63 - endianess bit
-********************************************************************/
-#define PAT_GET_CBA(value) ((value) & 0xfffffffffffff000UL)
-
-/********************************************************************
-* PDC_PAT_CELL[Return Cell Module] memaddr[1] mod_info
-* ----------------------------------------------------
-* Bit  0 to  7 - entity type
-*    0 = central agent,            1 = processor,
-*    2 = memory controller,        3 = system bus adapter,
-*    4 = local bus adapter,        5 = processor bus converter,
-*    6 = crossbar fabric connect,  7 = fabric interconnect,
-*    8 to 254 reserved,            255 = unknown.
-* Bit  8 to 15 - DVI
-* Bit 16 to 23 - IOC functions
-* Bit 24 to 39 - reserved
-* Bit 40 to 63 - mod_pages
-*    number of 4K pages a module occupies starting at conf_base_addr
-********************************************************************/
-#define PAT_GET_ENTITY(value)  (((value) >> 56) & 0xffUL)
-#define PAT_GET_DVI(value)     (((value) >> 48) & 0xffUL)
-#define PAT_GET_IOC(value)     (((value) >> 40) & 0xffUL)
-#define PAT_GET_MOD_PAGES(value)(((value) & 0xffffffUL)
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* ! __PARISC_PATPDC_H */
index 3122fad..1af1a41 100644 (file)
@@ -14,7 +14,7 @@
  * Here (for 64 bit kernels) we implement a Hybrid L2/L3 scheme: we
  * allocate the first pmd adjacent to the pgd.  This means that we can
  * subtract a constant offset to get to it.  The pmd and pgd sizes are
- * arranged so that a single pmd covers 4GB (giving a full LP64
+ * arranged so that a single pmd covers 4GB (giving a full 64-bit
  * process access to 8TB) so our lookups are effectively L2 for the
  * first 4GB of the kernel (i.e. for all ILP32 processes and all the
  * kernel for machines with under 4GB of memory) */
@@ -26,7 +26,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 
        if (likely(pgd != NULL)) {
                memset(pgd, 0, PAGE_SIZE<<PGD_ALLOC_ORDER);
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
                actual_pgd += PTRS_PER_PGD;
                /* Populate first pmd with allocated memory.  We mark it
                 * with PxD_FLAG_ATTACHED as a signal to the system that this
@@ -45,7 +45,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 
 static inline void pgd_free(pgd_t *pgd)
 {
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        pgd -= PTRS_PER_PGD;
 #endif
        free_pages((unsigned long)pgd, PGD_ALLOC_ORDER);
@@ -72,7 +72,7 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
 
 static inline void pmd_free(pmd_t *pmd)
 {
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        if(pmd_flag(*pmd) & PxD_FLAG_ATTACHED)
                /* This is the permanent pmd attached to the pgd;
                 * cannot free it */
@@ -99,7 +99,7 @@ static inline void pmd_free(pmd_t *pmd)
 static inline void
 pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
 {
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
        /* preserve the gateway marker if this is the beginning of
         * the permanent pmd */
        if(pmd_flag(*pmd) & PxD_FLAG_ATTACHED)
index c0b61e0..d7e1b10 100644 (file)
@@ -10,7 +10,6 @@
  * we simulate an x86-style page table for the linux mm code
  */
 
-#include <linux/spinlock.h>
 #include <linux/mm.h>          /* for vm_area_struct */
 #include <asm/processor.h>
 #include <asm/cache.h>
index 9b19970..b634e3c 100644 (file)
@@ -20,7 +20,7 @@ typedef int                   __kernel_timer_t;
 typedef int                    __kernel_clockid_t;
 typedef int                    __kernel_daddr_t;
 /* Note these change from narrow to wide kernels */
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 typedef unsigned long          __kernel_size_t;
 typedef long                   __kernel_ssize_t;
 typedef long                   __kernel_ptrdiff_t;
index fd7866d..d2f3967 100644 (file)
@@ -9,13 +9,10 @@
 #define __ASM_PARISC_PROCESSOR_H
 
 #ifndef __ASSEMBLY__
-#include <asm/prefetch.h>      /* lockdep.h needs <linux/prefetch.h> */
-
 #include <linux/threads.h>
-#include <linux/spinlock_types.h>
 
+#include <asm/prefetch.h>
 #include <asm/hardware.h>
-#include <asm/page.h>
 #include <asm/pdc.h>
 #include <asm/ptrace.h>
 #include <asm/types.h>
@@ -41,7 +38,7 @@
 #define DEFAULT_TASK_SIZE32    (0xFFF00000UL)
 #define DEFAULT_MAP_BASE32     (0x40000000UL)
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 #define DEFAULT_TASK_SIZE       (MAX_ADDRESS-0xf000000)
 #define DEFAULT_MAP_BASE        (0x200000000UL)
 #else
@@ -87,7 +84,6 @@ struct cpuinfo_parisc {
        unsigned long hpa;          /* Host Physical address */
        unsigned long txn_addr;     /* MMIO addr of EIR or id_eid */
 #ifdef CONFIG_SMP
-       spinlock_t lock;            /* synchronization for ipi's */
        unsigned long pending_ipi;  /* bitmap of type ipi_message_type */
        unsigned long ipi_count;    /* number ipi Interrupts */
 #endif
@@ -277,7 +273,7 @@ on downward growing arches, it looks like this:
  * it in here from the current->personality
  */
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 #define USER_WIDE_MODE (!test_thread_flag(TIF_32BIT))
 #else
 #define USER_WIDE_MODE 0
index 1083368..1e59ffd 100644 (file)
 
 struct semid64_ds {
        struct ipc64_perm sem_perm;             /* permissions .. see ipc.h */
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
        unsigned int    __pad1;
 #endif
        __kernel_time_t sem_otime;              /* last semop time */
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
        unsigned int    __pad2;
 #endif
        __kernel_time_t sem_ctime;              /* last change time */
index 623b6c0..0a3eada 100644 (file)
 
 struct shmid64_ds {
        struct ipc64_perm       shm_perm;       /* operation perms */
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
        unsigned int            __pad1;
 #endif
        __kernel_time_t         shm_atime;      /* last attach time */
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
        unsigned int            __pad2;
 #endif
        __kernel_time_t         shm_dtime;      /* last detach time */
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
        unsigned int            __pad3;
 #endif
        __kernel_time_t         shm_ctime;      /* last change time */
-#ifndef __LP64__
+#ifndef CONFIG_64BIT
        unsigned int            __pad4;
 #endif
        size_t                  shm_segsz;      /* size of segment (bytes) */
@@ -36,7 +36,7 @@ struct shmid64_ds {
        unsigned int            __unused2;
 };
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 /* The 'unsigned int' (formerly 'unsigned long') data types below will
  * ensure that a 32-bit app calling shmctl(*,IPC_INFO,*) will work on
  * a wide kernel, but if some of these values are meant to contain pointers
index 98a82fa..c203563 100644 (file)
 struct siginfo;
 
 /* Type of a signal handler.  */
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 /* function pointers on 64-bit parisc are pointers to little structs and the
  * compiler doesn't support code which changes or tests the address of
  * the function in the little struct.  This is really ugly -PB
index d4c0e26..306f495 100644 (file)
@@ -41,14 +41,6 @@ extern void smp_send_all_nop(void);
  
 #define PROC_CHANGE_PENALTY    15              /* Schedule penalty */
 
-#undef ENTRY_SYS_CPUS
-#ifdef ENTRY_SYS_CPUS
-#define STATE_RENDEZVOUS                       0
-#define STATE_STOPPED                          1 
-#define STATE_RUNNING                          2
-#define STATE_HALTED                           3
-#endif
-
 extern unsigned long cpu_present_mask;
 
 #define raw_smp_processor_id() (current_thread_info()->cpu)
index d6b479b..3f72f47 100644 (file)
@@ -1,10 +1,6 @@
 #ifndef __ASM_SPINLOCK_TYPES_H
 #define __ASM_SPINLOCK_TYPES_H
 
-#ifndef __LINUX_SPINLOCK_TYPES_H
-# error "please don't include this file directly"
-#endif
-
 typedef struct {
 #ifdef CONFIG_PA20
        volatile unsigned int slock;
index a52d8f9..1d2b813 100644 (file)
@@ -30,11 +30,11 @@ struct statfs {
 struct statfs64 {
        long f_type;
        long f_bsize;
-       u64 f_blocks;
-       u64 f_bfree;
-       u64 f_bavail;
-       u64 f_files;
-       u64 f_ffree;
+       __u64 f_blocks;
+       __u64 f_bfree;
+       __u64 f_bavail;
+       __u64 f_files;
+       __u64 f_ffree;
        __kernel_fsid_t f_fsid;
        long f_namelen;
        long f_frsize;
index 74f037a..7e9afa7 100644 (file)
@@ -34,7 +34,7 @@ struct pa_psw {
        unsigned int i:1;
 };
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 #define pa_psw(task) ((struct pa_psw *) ((char *) (task) + TASK_PT_PSW + 4))
 #else
 #define pa_psw(task) ((struct pa_psw *) ((char *) (task) + TASK_PT_PSW))
index f2f83b0..949314c 100644 (file)
@@ -62,6 +62,7 @@ struct thread_info {
 #define TIF_POLLING_NRFLAG     4       /* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_32BIT               5       /* 32 bit binary */
 #define TIF_MEMDIE             6
+#define TIF_RESTORE_SIGMASK    7       /* restore saved signal mask */
 
 #define _TIF_SYSCALL_TRACE     (1 << TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME     (1 << TIF_NOTIFY_RESUME)
@@ -69,9 +70,10 @@ struct thread_info {
 #define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)
 #define _TIF_POLLING_NRFLAG    (1 << TIF_POLLING_NRFLAG)
 #define _TIF_32BIT             (1 << TIF_32BIT)
+#define _TIF_RESTORE_SIGMASK   (1 << TIF_RESTORE_SIGMASK)
 
 #define _TIF_USER_WORK_MASK     (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \
-                                 _TIF_NEED_RESCHED)
+                                 _TIF_NEED_RESCHED | _TIF_RESTORE_SIGMASK)
 
 #endif /* __KERNEL__ */
 
index f662e83..3313da9 100644 (file)
@@ -73,33 +73,11 @@ static inline void flush_tlb_page(struct vm_area_struct *vma,
        purge_tlb_end();
 }
 
-static inline void flush_tlb_range(struct vm_area_struct *vma,
-       unsigned long start, unsigned long end)
-{
-       unsigned long npages;
+void __flush_tlb_range(unsigned long sid,
+       unsigned long start, unsigned long end);
 
-       npages = ((end - (start & PAGE_MASK)) + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
-       if (npages >= 512)  /* 2MB of space: arbitrary, should be tuned */
-               flush_tlb_all();
-       else {
-               mtsp(vma->vm_mm->context,1);
-               purge_tlb_start();
-               if (split_tlb) {
-                       while (npages--) {
-                               pdtlb(start);
-                               pitlb(start);
-                               start += PAGE_SIZE;
-                       }
-               } else {
-                       while (npages--) {
-                               pdtlb(start);
-                               start += PAGE_SIZE;
-                       }
-               }
-               purge_tlb_end();
-       }
-}
+#define flush_tlb_range(vma,start,end) __flush_tlb_range((vma)->vm_mm->context,start,end)
 
-#define flush_tlb_kernel_range(start, end) flush_tlb_all()
+#define flush_tlb_kernel_range(start, end) __flush_tlb_range(0,start,end)
 
 #endif
index 34fdce3..d4aa330 100644 (file)
@@ -31,7 +31,7 @@ typedef unsigned long long __u64;
  */
 #ifdef __KERNEL__
 
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
 #define BITS_PER_LONG 64
 #define SHIFT_PER_LONG 6
 #else
index d973e8b..4878b95 100644 (file)
@@ -4,7 +4,6 @@
 /*
  * User space memory access functions
  */
-#include <linux/sched.h>
 #include <asm/page.h>
 #include <asm/system.h>
 #include <asm/cache.h>
@@ -43,16 +42,18 @@ static inline long access_ok(int type, const void __user * addr,
 #define put_user __put_user
 #define get_user __get_user
 
-#if BITS_PER_LONG == 32
+#if !defined(CONFIG_64BIT)
 #define LDD_KERNEL(ptr)                __get_kernel_bad();
 #define LDD_USER(ptr)          __get_user_bad();
 #define STD_KERNEL(x, ptr)     __put_kernel_asm64(x,ptr)
 #define STD_USER(x, ptr)       __put_user_asm64(x,ptr)
+#define ASM_WORD_INSN          ".word\t"
 #else
-#define LDD_KERNEL(ptr) __get_kernel_asm("ldd",ptr)
-#define LDD_USER(ptr) __get_user_asm("ldd",ptr)
-#define STD_KERNEL(x, ptr) __put_kernel_asm("std",x,ptr)
-#define STD_USER(x, ptr) __put_user_asm("std",x,ptr)
+#define LDD_KERNEL(ptr)                __get_kernel_asm("ldd",ptr)
+#define LDD_USER(ptr)          __get_user_asm("ldd",ptr)
+#define STD_KERNEL(x, ptr)     __put_kernel_asm("std",x,ptr)
+#define STD_USER(x, ptr)       __put_user_asm("std",x,ptr)
+#define ASM_WORD_INSN          ".dword\t"
 #endif
 
 /*
@@ -66,6 +67,11 @@ struct exception_table_entry {
        long fixup;          /* fixup routine */
 };
 
+#define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr )\
+       ".section __ex_table,\"aw\"\n"                     \
+       ASM_WORD_INSN #fault_addr ", " #except_addr "\n\t" \
+       ".previous\n"
+
 /*
  * The page fault handler stores, in a per-cpu area, the following information
  * if a fixup routine is available.
@@ -104,43 +110,19 @@ struct exception_data {
        __gu_err;                                       \
 })
 
-#ifdef __LP64__
-#define __get_kernel_asm(ldx,ptr)                       \
-       __asm__("\n1:\t" ldx "\t0(%2),%0\n"             \
-               "\t.section __ex_table,\"aw\"\n"        \
-               "\t.dword\t1b,fixup_get_user_skip_1\n"  \
-               "\t.previous"                           \
-               : "=r"(__gu_val), "=r"(__gu_err)        \
-               : "r"(ptr), "1"(__gu_err)               \
-               : "r1");
-
-#define __get_user_asm(ldx,ptr)                         \
-       __asm__("\n1:\t" ldx "\t0(%%sr3,%2),%0\n"       \
-               "\t.section __ex_table,\"aw\"\n"        \
-               "\t.dword\t1b,fixup_get_user_skip_1\n"  \
-               "\t.previous"                           \
-               : "=r"(__gu_val), "=r"(__gu_err)        \
-               : "r"(ptr), "1"(__gu_err)               \
-               : "r1");
-#else
 #define __get_kernel_asm(ldx,ptr)                       \
-       __asm__("\n1:\t" ldx "\t0(%2),%0\n"             \
-               "\t.section __ex_table,\"aw\"\n"        \
-               "\t.word\t1b,fixup_get_user_skip_1\n"   \
-               "\t.previous"                           \
+       __asm__("\n1:\t" ldx "\t0(%2),%0\n\t"           \
+               ASM_EXCEPTIONTABLE_ENTRY(1b, fixup_get_user_skip_1)\
                : "=r"(__gu_val), "=r"(__gu_err)        \
                : "r"(ptr), "1"(__gu_err)               \
                : "r1");
 
 #define __get_user_asm(ldx,ptr)                         \
-       __asm__("\n1:\t" ldx "\t0(%%sr3,%2),%0\n"       \
-               "\t.section __ex_table,\"aw\"\n"        \
-                "\t.word\t1b,fixup_get_user_skip_1\n"  \
-                "\t.previous"                          \
+       __asm__("\n1:\t" ldx "\t0(%%sr3,%2),%0\n\t"     \
+               ASM_EXCEPTIONTABLE_ENTRY(1b,fixup_get_user_skip_1)\
                : "=r"(__gu_val), "=r"(__gu_err)        \
                : "r"(ptr), "1"(__gu_err)               \
                : "r1");
-#endif /* !__LP64__ */
 
 #define __put_user(x,ptr)                                       \
 ({                                                             \
@@ -179,80 +161,54 @@ struct exception_data {
  * r8/r9 are already listed as err/val.
  */
 
-#ifdef __LP64__
 #define __put_kernel_asm(stx,x,ptr)                         \
        __asm__ __volatile__ (                              \
-               "\n1:\t" stx "\t%2,0(%1)\n"                 \
-               "\t.section __ex_table,\"aw\"\n"            \
-               "\t.dword\t1b,fixup_put_user_skip_1\n"      \
-               "\t.previous"                               \
+               "\n1:\t" stx "\t%2,0(%1)\n\t"               \
+               ASM_EXCEPTIONTABLE_ENTRY(1b,fixup_put_user_skip_1)\
                : "=r"(__pu_err)                            \
                : "r"(ptr), "r"(x), "0"(__pu_err)           \
                : "r1")
 
 #define __put_user_asm(stx,x,ptr)                           \
        __asm__ __volatile__ (                              \
-               "\n1:\t" stx "\t%2,0(%%sr3,%1)\n"           \
-               "\t.section __ex_table,\"aw\"\n"            \
-                "\t.dword\t1b,fixup_put_user_skip_1\n"     \
-                "\t.previous"                              \
-               : "=r"(__pu_err)                            \
-               : "r"(ptr), "r"(x), "0"(__pu_err)           \
-               : "r1")
-#else
-#define __put_kernel_asm(stx,x,ptr)                         \
-       __asm__ __volatile__ (                              \
-               "\n1:\t" stx "\t%2,0(%1)\n"                 \
-               "\t.section __ex_table,\"aw\"\n"            \
-                "\t.word\t1b,fixup_put_user_skip_1\n"      \
-                "\t.previous"                              \
+               "\n1:\t" stx "\t%2,0(%%sr3,%1)\n\t"         \
+               ASM_EXCEPTIONTABLE_ENTRY(1b,fixup_put_user_skip_1)\
                : "=r"(__pu_err)                            \
                : "r"(ptr), "r"(x), "0"(__pu_err)           \
                : "r1")
 
-#define __put_user_asm(stx,x,ptr)                           \
-       __asm__ __volatile__ (                              \
-               "\n1:\t" stx "\t%2,0(%%sr3,%1)\n"           \
-               "\t.section __ex_table,\"aw\"\n"            \
-                "\t.word\t1b,fixup_put_user_skip_1\n"      \
-                "\t.previous"                              \
-               : "=r"(__pu_err)                            \
-               : "r"(ptr), "r"(x), "0"(__pu_err)           \
-               : "r1")
 
-#define __put_kernel_asm64(__val,ptr) do {                         \
-       u64 __val64 = (u64)(__val);                                 \
-       u32 hi = (__val64) >> 32;                                           \
-       u32 lo = (__val64) & 0xffffffff;                                    \
+#if !defined(CONFIG_64BIT)
+
+#define __put_kernel_asm64(__val,ptr) do {                 \
+       u64 __val64 = (u64)(__val);                         \
+       u32 hi = (__val64) >> 32;                           \
+       u32 lo = (__val64) & 0xffffffff;                    \
        __asm__ __volatile__ (                              \
-               "\n1:\tstw %2,0(%1)\n"                      \
-               "\n2:\tstw %3,4(%1)\n"                      \
-               "\t.section __ex_table,\"aw\"\n"            \
-                "\t.word\t1b,fixup_put_user_skip_2\n"      \
-                "\t.word\t2b,fixup_put_user_skip_1\n"      \
-                "\t.previous"                              \
+               "\n1:\tstw %2,0(%1)"                        \
+               "\n2:\tstw %3,4(%1)\n\t"                    \
+               ASM_EXCEPTIONTABLE_ENTRY(1b,fixup_put_user_skip_2)\
+               ASM_EXCEPTIONTABLE_ENTRY(2b,fixup_put_user_skip_1)\
                : "=r"(__pu_err)                            \
                : "r"(ptr), "r"(hi), "r"(lo), "0"(__pu_err) \
                : "r1");                                    \
 } while (0)
 
-#define __put_user_asm64(__val,ptr) do {                           \
-       u64 __val64 = (u64)__val;                                   \
-       u32 hi = (__val64) >> 32;                                           \
-       u32 lo = (__val64) & 0xffffffff;                                    \
+#define __put_user_asm64(__val,ptr) do {                   \
+       u64 __val64 = (u64)(__val);                         \
+       u32 hi = (__val64) >> 32;                           \
+       u32 lo = (__val64) & 0xffffffff;                    \
        __asm__ __volatile__ (                              \
-               "\n1:\tstw %2,0(%%sr3,%1)\n"                \
-               "\n2:\tstw %3,4(%%sr3,%1)\n"                \
-               "\t.section __ex_table,\"aw\"\n"            \
-                "\t.word\t1b,fixup_get_user_skip_2\n"      \
-                "\t.word\t2b,fixup_get_user_skip_1\n"      \
-                "\t.previous"                              \
+               "\n1:\tstw %2,0(%%sr3,%1)"                  \
+               "\n2:\tstw %3,4(%%sr3,%1)\n\t"              \
+               ASM_EXCEPTIONTABLE_ENTRY(1b,fixup_put_user_skip_2)\
+               ASM_EXCEPTIONTABLE_ENTRY(2b,fixup_put_user_skip_1)\
                : "=r"(__pu_err)                            \
                : "r"(ptr), "r"(hi), "r"(lo), "0"(__pu_err) \
                : "r1");                                    \
 } while (0)
 
-#endif /* !__LP64__ */
+#endif /* !defined(CONFIG_64BIT) */
 
 
 /*
index 53b0f5d..2f7c408 100644 (file)
 #define __NR_mknodat           (__NR_Linux + 277)
 #define __NR_fchownat          (__NR_Linux + 278)
 #define __NR_futimesat         (__NR_Linux + 279)
-#define __NR_newfstatat                (__NR_Linux + 280)
+#define __NR_fstatat64         (__NR_Linux + 280)
 #define __NR_unlinkat          (__NR_Linux + 281)
 #define __NR_renameat          (__NR_Linux + 282)
 #define __NR_linkat            (__NR_Linux + 283)
 #define __NR_splice            (__NR_Linux + 291)
 #define __NR_sync_file_range   (__NR_Linux + 292)
 #define __NR_tee               (__NR_Linux + 293)
+#define __NR_vmsplice          (__NR_Linux + 294)
+#define __NR_move_pages                (__NR_Linux + 295)
+#define __NR_getcpu            (__NR_Linux + 296)
+#define __NR_epoll_pwait       (__NR_Linux + 297)
+#define __NR_statfs64          (__NR_Linux + 298)
+#define __NR_fstatfs64         (__NR_Linux + 299)
 
-#define __NR_Linux_syscalls     294
+#define __NR_Linux_syscalls     (__NR_fstatfs64 + 1)
 
 #define HPUX_GATEWAY_ADDR       0xC0000004
 #define LINUX_GATEWAY_ADDR      0x100
@@ -951,6 +957,8 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)       \
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
 
 #endif /* __ASSEMBLY__ */
 
index af20c74..c17bdbf 100644 (file)
@@ -215,6 +215,8 @@ static __inline__ void atomic64_set_mask(unsigned long mask, atomic64_t * v)
               __CSG_LOOP(v, mask, "ogr");
 }
 
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+
 static __inline__ long long atomic64_cmpxchg(atomic64_t *v,
                                             long long old, long long new)
 {
diff --git a/include/asm-s390/ipl.h b/include/asm-s390/ipl.h
new file mode 100644 (file)
index 0000000..5650d3d
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * s390 (re)ipl support
+ *
+ * Copyright IBM Corp. 2007
+ */
+
+#ifndef _ASM_S390_IPL_H
+#define _ASM_S390_IPL_H
+
+#include <asm/types.h>
+
+#define IPL_PARMBLOCK_ORIGIN   0x2000
+
+#define IPL_PARM_BLK_FCP_LEN (sizeof(struct ipl_list_hdr) + \
+                             sizeof(struct ipl_block_fcp))
+
+#define IPL_PARM_BLK_CCW_LEN (sizeof(struct ipl_list_hdr) + \
+                             sizeof(struct ipl_block_ccw))
+
+#define IPL_MAX_SUPPORTED_VERSION (0)
+
+#define IPL_PARMBLOCK_START    ((struct ipl_parameter_block *) \
+                                IPL_PARMBLOCK_ORIGIN)
+#define IPL_PARMBLOCK_SIZE     (IPL_PARMBLOCK_START->hdr.len)
+
+struct ipl_list_hdr {
+       u32 len;
+       u8  reserved1[3];
+       u8  version;
+       u32 blk0_len;
+       u8  pbt;
+       u8  flags;
+       u16 reserved2;
+} __attribute__((packed));
+
+struct ipl_block_fcp {
+       u8  reserved1[313-1];
+       u8  opt;
+       u8  reserved2[3];
+       u16 reserved3;
+       u16 devno;
+       u8  reserved4[4];
+       u64 wwpn;
+       u64 lun;
+       u32 bootprog;
+       u8  reserved5[12];
+       u64 br_lba;
+       u32 scp_data_len;
+       u8  reserved6[260];
+       u8  scp_data[];
+} __attribute__((packed));
+
+struct ipl_block_ccw {
+       u8  load_param[8];
+       u8  reserved1[84];
+       u8  reserved2[2];
+       u16 devno;
+       u8  vm_flags;
+       u8  reserved3[3];
+       u32 vm_parm_len;
+} __attribute__((packed));
+
+struct ipl_parameter_block {
+       struct ipl_list_hdr hdr;
+       union {
+               struct ipl_block_fcp fcp;
+               struct ipl_block_ccw ccw;
+       } ipl_info;
+} __attribute__((packed));
+
+/*
+ * IPL validity flags and parameters as detected in head.S
+ */
+extern u32 ipl_flags;
+extern u16 ipl_devno;
+
+extern void do_reipl(void);
+extern void ipl_save_parameters(void);
+
+enum {
+       IPL_DEVNO_VALID         = 1,
+       IPL_PARMBLOCK_VALID     = 2,
+       IPL_NSS_VALID           = 4,
+};
+
+/*
+ * DIAG 308 support
+ */
+enum diag308_subcode  {
+       DIAG308_REL_HSA = 2,
+       DIAG308_IPL     = 3,
+       DIAG308_DUMP    = 4,
+       DIAG308_SET     = 5,
+       DIAG308_STORE   = 6,
+};
+
+enum diag308_ipl_type {
+       DIAG308_IPL_TYPE_FCP    = 0,
+       DIAG308_IPL_TYPE_CCW    = 2,
+};
+
+enum diag308_opt {
+       DIAG308_IPL_OPT_IPL     = 0x10,
+       DIAG308_IPL_OPT_DUMP    = 0x20,
+};
+
+enum diag308_rc {
+       DIAG308_RC_OK   = 1,
+};
+
+extern int diag308(unsigned long subcode, void *addr);
+
+#endif /* _ASM_S390_IPL_H */
index 86745a1..c11c530 100644 (file)
@@ -1,58 +1 @@
-#ifndef _ASM_LOCAL_H
-#define _ASM_LOCAL_H
-
-#include <linux/percpu.h>
-#include <asm/atomic.h>
-
-#ifndef __s390x__
-
-typedef atomic_t local_t;
-
-#define LOCAL_INIT(i)  ATOMIC_INIT(i)
-#define local_read(v)  atomic_read(v)
-#define local_set(v,i) atomic_set(v,i)
-
-#define local_inc(v)   atomic_inc(v)
-#define local_dec(v)   atomic_dec(v)
-#define local_add(i, v)        atomic_add(i, v)
-#define local_sub(i, v)        atomic_sub(i, v)
-
-#else
-
-typedef atomic64_t local_t;
-
-#define LOCAL_INIT(i)  ATOMIC64_INIT(i)
-#define local_read(v)  atomic64_read(v)
-#define local_set(v,i) atomic64_set(v,i)
-
-#define local_inc(v)   atomic64_inc(v)
-#define local_dec(v)   atomic64_dec(v)
-#define local_add(i, v)        atomic64_add(i, v)
-#define local_sub(i, v)        atomic64_sub(i, v)
-
-#endif
-
-#define __local_inc(v)         ((v)->counter++)
-#define __local_dec(v)         ((v)->counter--)
-#define __local_add(i,v)       ((v)->counter+=(i))
-#define __local_sub(i,v)       ((v)->counter-=(i))
-
-/*
- * Use these for per-cpu local_t variables: on some archs they are
- * much more efficient than these naive implementations.  Note they take
- * a variable, not an address.
- */
-#define cpu_local_read(v)      local_read(&__get_cpu_var(v))
-#define cpu_local_set(v, i)    local_set(&__get_cpu_var(v), (i))
-
-#define cpu_local_inc(v)       local_inc(&__get_cpu_var(v))
-#define cpu_local_dec(v)       local_dec(&__get_cpu_var(v))
-#define cpu_local_add(i, v)    local_add((i), &__get_cpu_var(v))
-#define cpu_local_sub(i, v)    local_sub((i), &__get_cpu_var(v))
-
-#define __cpu_local_inc(v)     __local_inc(&__get_cpu_var(v))
-#define __cpu_local_dec(v)     __local_dec(&__get_cpu_var(v))
-#define __cpu_local_add(i, v)  __local_add((i), &__get_cpu_var(v))
-#define __cpu_local_sub(i, v)  __local_sub((i), &__get_cpu_var(v))
-
-#endif /* _ASM_LOCAL_H */
+#include <asm-generic/local.h>
index 4c1b739..33b80ce 100644 (file)
@@ -36,6 +36,11 @@ typedef struct
         unsigned int unused  : 16;
 } __attribute__ ((packed)) cpuid_t;
 
+static inline void get_cpu_id(cpuid_t *ptr)
+{
+       asm volatile("stidp 0(%1)" : "=m" (*ptr) : "a" (ptr));
+}
+
 struct cpuinfo_S390
 {
         cpuid_t  cpu_id;
index 1c5a2c4..fbd9116 100644 (file)
@@ -3,6 +3,6 @@
 
 #include <asm-generic/sections.h>
 
-extern char _eshared[];
+extern char _eshared[], _ehead[];
 
 #endif
index 3388bb5..44c7aee 100644 (file)
@@ -16,7 +16,6 @@
 
 #define PARMAREA               0x10400
 #define MEMORY_CHUNKS          16      /* max 0x7fff */
-#define IPL_PARMBLOCK_ORIGIN   0x2000
 
 #ifndef __ASSEMBLY__
 
@@ -97,82 +96,9 @@ extern char vmpoff_cmd[];
 #define SET_CONSOLE_3215       do { console_mode = 2; } while (0)
 #define SET_CONSOLE_3270       do { console_mode = 3; } while (0)
 
-struct ipl_list_hdr {
-       u32 len;
-       u8  reserved1[3];
-       u8  version;
-       u32 blk0_len;
-       u8  pbt;
-       u8  flags;
-       u16 reserved2;
-} __attribute__((packed));
-
-struct ipl_block_fcp {
-       u8  reserved1[313-1];
-       u8  opt;
-       u8  reserved2[3];
-       u16 reserved3;
-       u16 devno;
-       u8  reserved4[4];
-       u64 wwpn;
-       u64 lun;
-       u32 bootprog;
-       u8  reserved5[12];
-       u64 br_lba;
-       u32 scp_data_len;
-       u8  reserved6[260];
-       u8  scp_data[];
-} __attribute__((packed));
-
-struct ipl_block_ccw {
-       u8  load_param[8];
-       u8  reserved1[84];
-       u8  reserved2[2];
-       u16 devno;
-       u8  vm_flags;
-       u8  reserved3[3];
-       u32 vm_parm_len;
-} __attribute__((packed));
-
-struct ipl_parameter_block {
-       struct ipl_list_hdr hdr;
-       union {
-               struct ipl_block_fcp fcp;
-               struct ipl_block_ccw ccw;
-       } ipl_info;
-} __attribute__((packed));
-
-#define IPL_PARM_BLK_FCP_LEN (sizeof(struct ipl_list_hdr) + \
-                             sizeof(struct ipl_block_fcp))
-
-#define IPL_PARM_BLK_CCW_LEN (sizeof(struct ipl_list_hdr) + \
-                             sizeof(struct ipl_block_ccw))
-
-#define IPL_MAX_SUPPORTED_VERSION (0)
-
-/*
- * IPL validity flags and parameters as detected in head.S
- */
-extern u32 ipl_flags;
-extern u16 ipl_devno;
-
-extern void do_reipl(void);
-extern void ipl_save_parameters(void);
-
-enum {
-       IPL_DEVNO_VALID = 1,
-       IPL_PARMBLOCK_VALID = 2,
-       IPL_NSS_VALID = 4,
-};
-
 #define NSS_NAME_SIZE  8
-
 extern char kernel_nss_name[];
 
-#define IPL_PARMBLOCK_START    ((struct ipl_parameter_block *) \
-                                IPL_PARMBLOCK_ORIGIN)
-#define IPL_PARMBLOCK_SIZE     (IPL_PARMBLOCK_START->hdr.len)
-
 #else /* __ASSEMBLY__ */
 
 #ifndef __s390x__
index 552df5f..2e4b7a5 100644 (file)
 #define IA32_SYSCALL_VECTOR    0x80
 
 
+/* Reserve the lowest usable priority level 0x20 - 0x2f for triggering
+ * cleanup after irq migration.
+ */
+#define IRQ_MOVE_CLEANUP_VECTOR        FIRST_EXTERNAL_VECTOR
 /*
  * Vectors 0x20-0x2f are used for ISA interrupts.
  */
+#define IRQ0_VECTOR            FIRST_EXTERNAL_VECTOR + 0x10
+#define IRQ1_VECTOR            IRQ0_VECTOR + 1
+#define IRQ2_VECTOR            IRQ0_VECTOR + 2
+#define IRQ3_VECTOR            IRQ0_VECTOR + 3
+#define IRQ4_VECTOR            IRQ0_VECTOR + 4
+#define IRQ5_VECTOR            IRQ0_VECTOR + 5 
+#define IRQ6_VECTOR            IRQ0_VECTOR + 6
+#define IRQ7_VECTOR            IRQ0_VECTOR + 7
+#define IRQ8_VECTOR            IRQ0_VECTOR + 8
+#define IRQ9_VECTOR            IRQ0_VECTOR + 9
+#define IRQ10_VECTOR           IRQ0_VECTOR + 10
+#define IRQ11_VECTOR           IRQ0_VECTOR + 11
+#define IRQ12_VECTOR           IRQ0_VECTOR + 12
+#define IRQ13_VECTOR           IRQ0_VECTOR + 13
+#define IRQ14_VECTOR           IRQ0_VECTOR + 14
+#define IRQ15_VECTOR           IRQ0_VECTOR + 15
 
 /*
  * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
 
 /*
  * First APIC vector available to drivers: (vectors 0x30-0xee)
- * we start at 0x31 to spread out vectors evenly between priority
+ * we start at 0x41 to spread out vectors evenly between priority
  * levels. (0x80 is the syscall vector)
  */
-#define FIRST_DEVICE_VECTOR    0x31
+#define FIRST_DEVICE_VECTOR    (IRQ15_VECTOR + 2)
 #define FIRST_SYSTEM_VECTOR    0xef   /* duplicated in irq.h */
 
 
index 0a6bc52..31a2954 100644 (file)
@@ -59,6 +59,13 @@ struct autofs_packet_expire_multi {
        char name[NAME_MAX+1];
 };
 
+union autofs_packet_union {
+       struct autofs_packet_hdr hdr;
+       struct autofs_packet_missing missing;
+       struct autofs_packet_expire expire;
+       struct autofs_packet_expire_multi expire_multi;
+};
+
 /* autofs v5 common packet struct */
 struct autofs_v5_packet {
        struct autofs_packet_hdr hdr;
@@ -78,12 +85,13 @@ typedef struct autofs_v5_packet autofs_packet_expire_indirect_t;
 typedef struct autofs_v5_packet autofs_packet_missing_direct_t;
 typedef struct autofs_v5_packet autofs_packet_expire_direct_t;
 
-union autofs_packet_union {
+union autofs_v5_packet_union {
        struct autofs_packet_hdr hdr;
-       struct autofs_packet_missing missing;
-       struct autofs_packet_expire expire;
-       struct autofs_packet_expire_multi expire_multi;
        struct autofs_v5_packet v5_packet;
+       autofs_packet_missing_indirect_t missing_indirect;
+       autofs_packet_expire_indirect_t expire_indirect;
+       autofs_packet_missing_direct_t missing_direct;
+       autofs_packet_expire_direct_t expire_direct;
 };
 
 #define AUTOFS_IOC_EXPIRE_MULTI                _IOW(0x93,0x66,int)
index bbbe7b4..f50f04b 100644 (file)
@@ -939,7 +939,7 @@ struct cdrom_device_info {
        int speed;                      /* maximum speed for reading data */
        int capacity;                   /* number of discs in jukebox */
 /* device-related storage */
-       int options             : 30;   /* options flags */
+       unsigned int options    : 30;   /* options flags */
        unsigned mc_flags       : 2;    /* media change buffer flags */
        int use_count;                  /* number of times device opened */
        char name[20];                  /* name of the device type */
index 0bc45e6..1605dd8 100644 (file)
@@ -73,5 +73,10 @@ extern void cfag12864b_disable(void);
  */
 extern unsigned char cfag12864b_isenabled(void);
 
+/*
+ * Is the module inited?
+ */
+extern unsigned char cfag12864b_isinited(void);
+
 #endif /* _CFAG12864B_H_ */
 
index d0e8c8b..23f5514 100644 (file)
@@ -398,11 +398,11 @@ extern cpumask_t cpu_present_map;
 #endif
 
 #ifdef CONFIG_SMP
-int highest_possible_processor_id(void);
+extern int nr_cpu_ids;
 #define any_online_cpu(mask) __any_online_cpu(&(mask))
 int __any_online_cpu(const cpumask_t *mask);
 #else
-#define highest_possible_processor_id()        0
+#define nr_cpu_ids                     1
 #define any_online_cpu(mask)           0
 #endif
 
index d1a3a27..39a3199 100644 (file)
@@ -294,8 +294,6 @@ extern void class_device_initialize(struct class_device *);
 extern int __must_check class_device_add(struct class_device *);
 extern void class_device_del(struct class_device *);
 
-extern int class_device_rename(struct class_device *, char *);
-
 extern struct class_device * class_device_get(struct class_device *);
 extern void class_device_put(struct class_device *);
 
index aa5b3e6..b0a44b8 100644 (file)
@@ -200,17 +200,6 @@ extern int setup_irq(unsigned int irq, struct irqaction *new);
 #endif
 
 #ifdef CONFIG_SMP
-static inline void set_native_irq_info(int irq, cpumask_t mask)
-{
-       irq_desc[irq].affinity = mask;
-}
-#else
-static inline void set_native_irq_info(int irq, cpumask_t mask)
-{
-}
-#endif
-
-#ifdef CONFIG_SMP
 
 #if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
 
index bceea52..4c2c373 100644 (file)
@@ -87,6 +87,7 @@ static inline unsigned sysv_minor(u32 dev)
        return dev & 0x3ffff;
 }
 
+bool is_lanana_major(unsigned int major);
 
 #else /* __KERNEL__ */
 
index cc8e674..10f505c 100644 (file)
 #ifdef CONFIG_KMOD
 /* modprobe exit status on success, -ve on error.  Return value
  * usually useless though. */
-extern void kmod_sysfs_init(void);
 extern int request_module(const char * name, ...) __attribute__ ((format (printf, 1, 2)));
 #else
-static inline void kmod_sysfs_init(void) {};
 static inline int request_module(const char * name, ...) { return -ENOSYS; }
 #endif
 
index 8047d4b..a2c54ac 100644 (file)
@@ -43,4 +43,7 @@ extern void ks0108_address(unsigned char address);
 /* Set the controller's current page (0..7) */
 extern void ks0108_page(unsigned char page);
 
+/* Is the module inited? */
+extern unsigned char ks0108_isinited(void);
+
 #endif /* _KS0108_H_ */
index 9850d51..0e39745 100644 (file)
@@ -78,8 +78,7 @@ struct minix_super_block {
  * V3 minix super-block data on disk
  */
 struct minix3_super_block {
-       __u16 s_ninodes;
-       __u16 s_nzones;
+       __u32 s_ninodes;
        __u16 s_pad0;
        __u16 s_imap_blocks;
        __u16 s_zmap_blocks;
index e0c393c..e96b2de 100644 (file)
@@ -320,4 +320,16 @@ struct eisa_device_id {
 
 #define EISA_DEVICE_MODALIAS_FMT "eisa:s%s"
 
+struct parisc_device_id {
+       __u8    hw_type;        /* 5 bits used */
+       __u8    hversion_rev;   /* 4 bits */
+       __u16   hversion;       /* 12 bits */
+       __u32   sversion;       /* 20 bits */
+};
+
+#define PA_HWTYPE_ANY_ID       0xff
+#define PA_HVERSION_REV_ANY_ID 0xff
+#define PA_HVERSION_ANY_ID     0xffff
+#define PA_SVERSION_ANY_ID     0xffffffff
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
index b1063e9..52c54a5 100644 (file)
@@ -352,7 +352,7 @@ extern nodemask_t node_possible_map;
 #define node_possible(node)    node_isset((node), node_possible_map)
 #define first_online_node      first_node(node_online_map)
 #define next_online_node(nid)  next_node((nid), node_online_map)
-int highest_possible_node_id(void);
+extern int nr_node_ids;
 #else
 #define num_online_nodes()     1
 #define num_possible_nodes()   1
@@ -360,7 +360,7 @@ int highest_possible_node_id(void);
 #define node_possible(node)    ((node) == 0)
 #define first_online_node      0
 #define next_online_node(nid)  (MAX_NUMNODES)
-#define highest_possible_node_id()     0
+#define nr_node_ids            1
 #endif
 
 #define any_online_node(mask)                  \
index 070394e..21db05a 100644 (file)
@@ -120,15 +120,48 @@ typedef int __bitwise suspend_disk_method_t;
 #define        PM_DISK_TESTPROC        ((__force suspend_disk_method_t) 6)
 #define        PM_DISK_MAX             ((__force suspend_disk_method_t) 7)
 
+/**
+ * struct pm_ops - Callbacks for managing platform dependent suspend states.
+ * @valid: Callback to determine whether the given state can be entered.
+ *     If %CONFIG_SOFTWARE_SUSPEND is set then %PM_SUSPEND_DISK is
+ *     always valid and never passed to this call.
+ *     If not assigned, all suspend states are advertised as valid
+ *     in /sys/power/state (but can still be rejected by prepare or enter.)
+ *
+ * @prepare: Prepare the platform for the given suspend state. Can return a
+ *     negative error code if necessary.
+ *
+ * @enter: Enter the given suspend state, must be assigned. Can return a
+ *     negative error code if necessary.
+ *
+ * @finish: Called when the system has left the given state and all devices
+ *     are resumed. The return value is ignored.
+ *
+ * @pm_disk_mode: Set to the disk method that the user should be able to
+ *     configure for suspend-to-disk. Since %PM_DISK_SHUTDOWN,
+ *     %PM_DISK_REBOOT, %PM_DISK_TEST and %PM_DISK_TESTPROC
+ *     are always allowed, currently only %PM_DISK_PLATFORM
+ *     makes sense. If the user then choses %PM_DISK_PLATFORM,
+ *     the @prepare call will be called before suspending to disk
+ *     (if present), the @enter call should be present and will
+ *     be called after all state has been saved and the machine
+ *     is ready to be shut down/suspended/..., and the @finish
+ *     callback is called after state has been restored. All
+ *     these calls are called with %PM_SUSPEND_DISK as the state.
+ */
 struct pm_ops {
-       suspend_disk_method_t pm_disk_mode;
        int (*valid)(suspend_state_t state);
        int (*prepare)(suspend_state_t state);
        int (*enter)(suspend_state_t state);
        int (*finish)(suspend_state_t state);
+       suspend_disk_method_t pm_disk_mode;
 };
 
-extern void pm_set_ops(struct pm_ops *);
+/**
+ * pm_set_ops - set platform dependent power management ops
+ * @pm_ops: The new power management operations to set.
+ */
+extern void pm_set_ops(struct pm_ops *pm_ops);
 extern struct pm_ops *pm_ops;
 extern int pm_suspend(suspend_state_t state);
 
index 5053dc0..6f7c9a4 100644 (file)
@@ -1329,6 +1329,7 @@ extern int kill_pid_info(int sig, struct siginfo *info, struct pid *pid);
 extern int kill_pid_info_as_uid(int, struct siginfo *, struct pid *, uid_t, uid_t, u32);
 extern int kill_pgrp(struct pid *pid, int sig, int priv);
 extern int kill_pid(struct pid *pid, int sig, int priv);
+extern int kill_proc_info(int, struct siginfo *, pid_t);
 extern void do_notify_parent(struct task_struct *, int);
 extern void force_sig(int, struct task_struct *);
 extern void force_sig_specific(int, struct task_struct *);
diff --git a/include/linux/sm501-regs.h b/include/linux/sm501-regs.h
new file mode 100644 (file)
index 0000000..cc9be4a
--- /dev/null
@@ -0,0 +1,357 @@
+/* sm501-regs.h
+ *
+ * Copyright 2006 Simtec Electronics
+ *
+ * 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.
+ *
+ * Silicon Motion SM501 register definitions
+*/
+
+/* System Configuration area */
+/* System config base */
+#define SM501_SYS_CONFIG               (0x000000)
+
+/* config 1 */
+#define SM501_SYSTEM_CONTROL           (0x000000)
+#define SM501_MISC_CONTROL             (0x000004)
+
+#define SM501_MISC_BUS_SH              (0x0)
+#define SM501_MISC_BUS_PCI             (0x1)
+#define SM501_MISC_BUS_XSCALE          (0x2)
+#define SM501_MISC_BUS_NEC             (0x6)
+#define SM501_MISC_BUS_MASK            (0x7)
+
+#define SM501_MISC_VR_62MB             (1<<3)
+#define SM501_MISC_CDR_RESET           (1<<7)
+#define SM501_MISC_USB_LB              (1<<8)
+#define SM501_MISC_USB_SLAVE           (1<<9)
+#define SM501_MISC_BL_1                        (1<<10)
+#define SM501_MISC_MC                  (1<<11)
+#define SM501_MISC_DAC_POWER           (1<<12)
+#define SM501_MISC_IRQ_INVERT          (1<<16)
+#define SM501_MISC_SH                  (1<<17)
+
+#define SM501_MISC_HOLD_EMPTY          (0<<18)
+#define SM501_MISC_HOLD_8              (1<<18)
+#define SM501_MISC_HOLD_16             (2<<18)
+#define SM501_MISC_HOLD_24             (3<<18)
+#define SM501_MISC_HOLD_32             (4<<18)
+#define SM501_MISC_HOLD_MASK           (7<<18)
+
+#define SM501_MISC_FREQ_12             (1<<24)
+#define SM501_MISC_PNL_24BIT           (1<<25)
+#define SM501_MISC_8051_LE             (1<<26)
+
+
+
+#define SM501_GPIO31_0_CONTROL         (0x000008)
+#define SM501_GPIO63_32_CONTROL                (0x00000C)
+#define SM501_DRAM_CONTROL             (0x000010)
+
+/* command list */
+#define SM501_ARBTRTN_CONTROL          (0x000014)
+
+/* command list */
+#define SM501_COMMAND_LIST_STATUS      (0x000024)
+
+/* interrupt debug */
+#define SM501_RAW_IRQ_STATUS           (0x000028)
+#define SM501_RAW_IRQ_CLEAR            (0x000028)
+#define SM501_IRQ_STATUS               (0x00002C)
+#define SM501_IRQ_MASK                 (0x000030)
+#define SM501_DEBUG_CONTROL            (0x000034)
+
+/* power management */
+#define SM501_CURRENT_GATE             (0x000038)
+#define SM501_CURRENT_CLOCK            (0x00003C)
+#define SM501_POWER_MODE_0_GATE                (0x000040)
+#define SM501_POWER_MODE_0_CLOCK       (0x000044)
+#define SM501_POWER_MODE_1_GATE                (0x000048)
+#define SM501_POWER_MODE_1_CLOCK       (0x00004C)
+#define SM501_SLEEP_MODE_GATE          (0x000050)
+#define SM501_POWER_MODE_CONTROL       (0x000054)
+
+/* power gates for units within the 501 */
+#define SM501_GATE_HOST                        (0)
+#define SM501_GATE_MEMORY              (1)
+#define SM501_GATE_DISPLAY             (2)
+#define SM501_GATE_2D_ENGINE           (3)
+#define SM501_GATE_CSC                 (4)
+#define SM501_GATE_ZVPORT              (5)
+#define SM501_GATE_GPIO                        (6)
+#define SM501_GATE_UART0               (7)
+#define SM501_GATE_UART1               (8)
+#define SM501_GATE_SSP                 (10)
+#define SM501_GATE_USB_HOST            (11)
+#define SM501_GATE_USB_GADGET          (12)
+#define SM501_GATE_UCONTROLLER         (17)
+#define SM501_GATE_AC97                        (18)
+
+/* panel clock */
+#define SM501_CLOCK_P2XCLK             (24)
+/* crt clock */
+#define SM501_CLOCK_V2XCLK             (16)
+/* main clock */
+#define SM501_CLOCK_MCLK               (8)
+/* SDRAM controller clock */
+#define SM501_CLOCK_M1XCLK             (0)
+
+/* config 2 */
+#define SM501_PCI_MASTER_BASE          (0x000058)
+#define SM501_ENDIAN_CONTROL           (0x00005C)
+#define SM501_DEVICEID                 (0x000060)
+/* 0x050100A0 */
+
+#define SM501_PLLCLOCK_COUNT           (0x000064)
+#define SM501_MISC_TIMING              (0x000068)
+#define SM501_CURRENT_SDRAM_CLOCK      (0x00006C)
+
+/* GPIO base */
+#define SM501_GPIO                     (0x010000)
+#define SM501_GPIO_DATA_LOW            (0x00)
+#define SM501_GPIO_DATA_HIGH           (0x04)
+#define SM501_GPIO_DDR_LOW             (0x08)
+#define SM501_GPIO_DDR_HIGH            (0x0C)
+#define SM501_GPIO_IRQ_SETUP           (0x10)
+#define SM501_GPIO_IRQ_STATUS          (0x14)
+#define SM501_GPIO_IRQ_RESET           (0x14)
+
+/* I2C controller base */
+#define SM501_I2C                      (0x010040)
+#define SM501_I2C_BYTE_COUNT           (0x00)
+#define SM501_I2C_CONTROL              (0x01)
+#define SM501_I2C_STATUS               (0x02)
+#define SM501_I2C_RESET                        (0x02)
+#define SM501_I2C_SLAVE_ADDRESS                (0x03)
+#define SM501_I2C_DATA                 (0x04)
+
+/* SSP base */
+#define SM501_SSP                      (0x020000)
+
+/* Uart 0 base */
+#define SM501_UART0                    (0x030000)
+
+/* Uart 1 base */
+#define SM501_UART1                    (0x030020)
+
+/* USB host port base */
+#define SM501_USB_HOST                 (0x040000)
+
+/* USB slave/gadget base */
+#define SM501_USB_GADGET               (0x060000)
+
+/* USB slave/gadget data port base */
+#define SM501_USB_GADGET_DATA          (0x070000)
+
+/* Display contoller/video engine base */
+#define SM501_DC                       (0x080000)
+
+/* common defines for the SM501 address registers */
+#define SM501_ADDR_FLIP                        (1<<31)
+#define SM501_ADDR_EXT                 (1<<27)
+#define SM501_ADDR_CS1                 (1<<26)
+#define SM501_ADDR_MASK                        (0x3f << 26)
+
+#define SM501_FIFO_MASK                        (0x3 << 16)
+#define SM501_FIFO_1                   (0x0 << 16)
+#define SM501_FIFO_3                   (0x1 << 16)
+#define SM501_FIFO_7                   (0x2 << 16)
+#define SM501_FIFO_11                  (0x3 << 16)
+
+/* common registers for panel and the crt */
+#define SM501_OFF_DC_H_TOT             (0x000)
+#define SM501_OFF_DC_V_TOT             (0x008)
+#define SM501_OFF_DC_H_SYNC            (0x004)
+#define SM501_OFF_DC_V_SYNC            (0x00C)
+
+#define SM501_DC_PANEL_CONTROL         (0x000)
+
+#define SM501_DC_PANEL_CONTROL_FPEN    (1<<27)
+#define SM501_DC_PANEL_CONTROL_BIAS    (1<<26)
+#define SM501_DC_PANEL_CONTROL_DATA    (1<<25)
+#define SM501_DC_PANEL_CONTROL_VDD     (1<<24)
+#define SM501_DC_PANEL_CONTROL_DP      (1<<23)
+
+#define SM501_DC_PANEL_CONTROL_TFT_888 (0<<21)
+#define SM501_DC_PANEL_CONTROL_TFT_333 (1<<21)
+#define SM501_DC_PANEL_CONTROL_TFT_444 (2<<21)
+
+#define SM501_DC_PANEL_CONTROL_DE      (1<<20)
+
+#define SM501_DC_PANEL_CONTROL_LCD_TFT (0<<18)
+#define SM501_DC_PANEL_CONTROL_LCD_STN8        (1<<18)
+#define SM501_DC_PANEL_CONTROL_LCD_STN12 (2<<18)
+
+#define SM501_DC_PANEL_CONTROL_CP      (1<<14)
+#define SM501_DC_PANEL_CONTROL_VSP     (1<<13)
+#define SM501_DC_PANEL_CONTROL_HSP     (1<<12)
+#define SM501_DC_PANEL_CONTROL_CK      (1<<9)
+#define SM501_DC_PANEL_CONTROL_TE      (1<<8)
+#define SM501_DC_PANEL_CONTROL_VPD     (1<<7)
+#define SM501_DC_PANEL_CONTROL_VP      (1<<6)
+#define SM501_DC_PANEL_CONTROL_HPD     (1<<5)
+#define SM501_DC_PANEL_CONTROL_HP      (1<<4)
+#define SM501_DC_PANEL_CONTROL_GAMMA   (1<<3)
+#define SM501_DC_PANEL_CONTROL_EN      (1<<2)
+
+#define SM501_DC_PANEL_CONTROL_8BPP    (0<<0)
+#define SM501_DC_PANEL_CONTROL_16BPP   (1<<0)
+#define SM501_DC_PANEL_CONTROL_32BPP   (2<<0)
+
+
+#define SM501_DC_PANEL_PANNING_CONTROL (0x004)
+#define SM501_DC_PANEL_COLOR_KEY       (0x008)
+#define SM501_DC_PANEL_FB_ADDR         (0x00C)
+#define SM501_DC_PANEL_FB_OFFSET       (0x010)
+#define SM501_DC_PANEL_FB_WIDTH                (0x014)
+#define SM501_DC_PANEL_FB_HEIGHT       (0x018)
+#define SM501_DC_PANEL_TL_LOC          (0x01C)
+#define SM501_DC_PANEL_BR_LOC          (0x020)
+#define SM501_DC_PANEL_H_TOT           (0x024)
+#define SM501_DC_PANEL_H_SYNC          (0x028)
+#define SM501_DC_PANEL_V_TOT           (0x02C)
+#define SM501_DC_PANEL_V_SYNC          (0x030)
+#define SM501_DC_PANEL_CUR_LINE                (0x034)
+
+#define SM501_DC_VIDEO_CONTROL         (0x040)
+#define SM501_DC_VIDEO_FB0_ADDR                (0x044)
+#define SM501_DC_VIDEO_FB_WIDTH                (0x048)
+#define SM501_DC_VIDEO_FB0_LAST_ADDR   (0x04C)
+#define SM501_DC_VIDEO_TL_LOC          (0x050)
+#define SM501_DC_VIDEO_BR_LOC          (0x054)
+#define SM501_DC_VIDEO_SCALE           (0x058)
+#define SM501_DC_VIDEO_INIT_SCALE      (0x05C)
+#define SM501_DC_VIDEO_YUV_CONSTANTS   (0x060)
+#define SM501_DC_VIDEO_FB1_ADDR                (0x064)
+#define SM501_DC_VIDEO_FB1_LAST_ADDR   (0x068)
+
+#define SM501_DC_VIDEO_ALPHA_CONTROL   (0x080)
+#define SM501_DC_VIDEO_ALPHA_FB_ADDR   (0x084)
+#define SM501_DC_VIDEO_ALPHA_FB_OFFSET (0x088)
+#define SM501_DC_VIDEO_ALPHA_FB_LAST_ADDR      (0x08C)
+#define SM501_DC_VIDEO_ALPHA_TL_LOC    (0x090)
+#define SM501_DC_VIDEO_ALPHA_BR_LOC    (0x094)
+#define SM501_DC_VIDEO_ALPHA_SCALE     (0x098)
+#define SM501_DC_VIDEO_ALPHA_INIT_SCALE        (0x09C)
+#define SM501_DC_VIDEO_ALPHA_CHROMA_KEY        (0x0A0)
+#define SM501_DC_VIDEO_ALPHA_COLOR_LOOKUP      (0x0A4)
+
+#define SM501_DC_PANEL_HWC_BASE                (0x0F0)
+#define SM501_DC_PANEL_HWC_ADDR                (0x0F0)
+#define SM501_DC_PANEL_HWC_LOC         (0x0F4)
+#define SM501_DC_PANEL_HWC_COLOR_1_2   (0x0F8)
+#define SM501_DC_PANEL_HWC_COLOR_3     (0x0FC)
+
+#define SM501_HWC_EN                   (1<<31)
+
+#define SM501_OFF_HWC_ADDR             (0x00)
+#define SM501_OFF_HWC_LOC              (0x04)
+#define SM501_OFF_HWC_COLOR_1_2                (0x08)
+#define SM501_OFF_HWC_COLOR_3          (0x0C)
+
+#define SM501_DC_ALPHA_CONTROL         (0x100)
+#define SM501_DC_ALPHA_FB_ADDR         (0x104)
+#define SM501_DC_ALPHA_FB_OFFSET       (0x108)
+#define SM501_DC_ALPHA_TL_LOC          (0x10C)
+#define SM501_DC_ALPHA_BR_LOC          (0x110)
+#define SM501_DC_ALPHA_CHROMA_KEY      (0x114)
+#define SM501_DC_ALPHA_COLOR_LOOKUP    (0x118)
+
+#define SM501_DC_CRT_CONTROL           (0x200)
+
+#define SM501_DC_CRT_CONTROL_TVP       (1<<15)
+#define SM501_DC_CRT_CONTROL_CP                (1<<14)
+#define SM501_DC_CRT_CONTROL_VSP       (1<<13)
+#define SM501_DC_CRT_CONTROL_HSP       (1<<12)
+#define SM501_DC_CRT_CONTROL_VS                (1<<11)
+#define SM501_DC_CRT_CONTROL_BLANK     (1<<10)
+#define SM501_DC_CRT_CONTROL_SEL       (1<<9)
+#define SM501_DC_CRT_CONTROL_TE                (1<<8)
+#define SM501_DC_CRT_CONTROL_PIXEL_MASK (0xF << 4)
+#define SM501_DC_CRT_CONTROL_GAMMA     (1<<3)
+#define SM501_DC_CRT_CONTROL_ENABLE    (1<<2)
+
+#define SM501_DC_CRT_CONTROL_8BPP      (0<<0)
+#define SM501_DC_CRT_CONTROL_16BPP     (1<<0)
+#define SM501_DC_CRT_CONTROL_32BPP     (2<<0)
+
+#define SM501_DC_CRT_FB_ADDR           (0x204)
+#define SM501_DC_CRT_FB_OFFSET         (0x208)
+#define SM501_DC_CRT_H_TOT             (0x20C)
+#define SM501_DC_CRT_H_SYNC            (0x210)
+#define SM501_DC_CRT_V_TOT             (0x214)
+#define SM501_DC_CRT_V_SYNC            (0x218)
+#define SM501_DC_CRT_SIGNATURE_ANALYZER        (0x21C)
+#define SM501_DC_CRT_CUR_LINE          (0x220)
+#define SM501_DC_CRT_MONITOR_DETECT    (0x224)
+
+#define SM501_DC_CRT_HWC_BASE          (0x230)
+#define SM501_DC_CRT_HWC_ADDR          (0x230)
+#define SM501_DC_CRT_HWC_LOC           (0x234)
+#define SM501_DC_CRT_HWC_COLOR_1_2     (0x238)
+#define SM501_DC_CRT_HWC_COLOR_3       (0x23C)
+
+#define SM501_DC_PANEL_PALETTE         (0x400)
+
+#define SM501_DC_VIDEO_PALETTE         (0x800)
+
+#define SM501_DC_CRT_PALETTE           (0xC00)
+
+/* Zoom Video port base */
+#define SM501_ZVPORT                   (0x090000)
+
+/* AC97/I2S base */
+#define SM501_AC97                     (0x0A0000)
+
+/* 8051 micro controller base */
+#define SM501_UCONTROLLER              (0x0B0000)
+
+/* 8051 micro controller SRAM base */
+#define SM501_UCONTROLLER_SRAM         (0x0C0000)
+
+/* DMA base */
+#define SM501_DMA                      (0x0D0000)
+
+/* 2d engine base */
+#define SM501_2D_ENGINE                        (0x100000)
+#define SM501_2D_SOURCE                        (0x00)
+#define SM501_2D_DESTINATION           (0x04)
+#define SM501_2D_DIMENSION             (0x08)
+#define SM501_2D_CONTROL               (0x0C)
+#define SM501_2D_PITCH                 (0x10)
+#define SM501_2D_FOREGROUND            (0x14)
+#define SM501_2D_BACKGROUND            (0x18)
+#define SM501_2D_STRETCH               (0x1C)
+#define SM501_2D_COLOR_COMPARE         (0x20)
+#define SM501_2D_COLOR_COMPARE_MASK    (0x24)
+#define SM501_2D_MASK                  (0x28)
+#define SM501_2D_CLIP_TL               (0x2C)
+#define SM501_2D_CLIP_BR               (0x30)
+#define SM501_2D_MONO_PATTERN_LOW      (0x34)
+#define SM501_2D_MONO_PATTERN_HIGH     (0x38)
+#define SM501_2D_WINDOW_WIDTH          (0x3C)
+#define SM501_2D_SOURCE_BASE           (0x40)
+#define SM501_2D_DESTINATION_BASE      (0x44)
+#define SM501_2D_ALPHA                 (0x48)
+#define SM501_2D_WRAP                  (0x4C)
+#define SM501_2D_STATUS                        (0x50)
+
+#define SM501_CSC_Y_SOURCE_BASE                (0xC8)
+#define SM501_CSC_CONSTANTS            (0xCC)
+#define SM501_CSC_Y_SOURCE_X           (0xD0)
+#define SM501_CSC_Y_SOURCE_Y           (0xD4)
+#define SM501_CSC_U_SOURCE_BASE                (0xD8)
+#define SM501_CSC_V_SOURCE_BASE                (0xDC)
+#define SM501_CSC_SOURCE_DIMENSION     (0xE0)
+#define SM501_CSC_SOURCE_PITCH         (0xE4)
+#define SM501_CSC_DESTINATION          (0xE8)
+#define SM501_CSC_DESTINATION_DIMENSION        (0xEC)
+#define SM501_CSC_DESTINATION_PITCH    (0xF0)
+#define SM501_CSC_SCALE_FACTOR         (0xF4)
+#define SM501_CSC_DESTINATION_BASE     (0xF8)
+#define SM501_CSC_CONTROL              (0xFC)
+
+/* 2d engine data port base */
+#define SM501_2D_ENGINE_DATA           (0x110000)
diff --git a/include/linux/sm501.h b/include/linux/sm501.h
new file mode 100644 (file)
index 0000000..9e3aaad
--- /dev/null
@@ -0,0 +1,170 @@
+/* include/linux/sm501.h
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     Vincent Sanders <vince@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 as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+*/
+
+extern int sm501_unit_power(struct device *dev,
+                           unsigned int unit, unsigned int to);
+
+extern unsigned long sm501_set_clock(struct device *dev,
+                                    int clksrc, unsigned long freq);
+
+extern unsigned long sm501_find_clock(int clksrc, unsigned long req_freq);
+
+/* sm501_misc_control
+ *
+ * Modify the SM501's MISC_CONTROL register
+*/
+
+extern int sm501_misc_control(struct device *dev,
+                             unsigned long set, unsigned long clear);
+
+/* sm501_modify_reg
+ *
+ * Modify a register in the SM501 which may be shared with other
+ * drivers.
+*/
+
+extern unsigned long sm501_modify_reg(struct device *dev,
+                                     unsigned long reg,
+                                     unsigned long set,
+                                     unsigned long clear);
+
+/* sm501_gpio_set
+ *
+ * set the state of the given GPIO line
+*/
+
+extern void sm501_gpio_set(struct device *dev,
+                          unsigned long gpio,
+                          unsigned int to,
+                          unsigned int dir);
+
+/* sm501_gpio_get
+ *
+ * get the state of the given GPIO line
+*/
+
+extern unsigned long sm501_gpio_get(struct device *dev,
+                                   unsigned long gpio);
+
+
+/* Platform data definitions */
+
+#define SM501FB_FLAG_USE_INIT_MODE     (1<<0)
+#define SM501FB_FLAG_DISABLE_AT_EXIT   (1<<1)
+#define SM501FB_FLAG_USE_HWCURSOR      (1<<2)
+#define SM501FB_FLAG_USE_HWACCEL       (1<<3)
+
+struct sm501_platdata_fbsub {
+       struct fb_videomode     *def_mode;
+       unsigned int             def_bpp;
+       unsigned long            max_mem;
+       unsigned int             flags;
+};
+
+enum sm501_fb_routing {
+       SM501_FB_OWN            = 0,    /* CRT=>CRT, Panel=>Panel */
+       SM501_FB_CRT_PANEL      = 1,    /* Panel=>CRT, Panel=>Panel */
+};
+
+/* sm501_platdata_fb flag field bit definitions */
+
+#define SM501_FBPD_SWAP_FB_ENDIAN      (1<<0)  /* need to endian swap */
+
+/* sm501_platdata_fb
+ *
+ * configuration data for the framebuffer driver
+*/
+
+struct sm501_platdata_fb {
+       enum sm501_fb_routing            fb_route;
+       unsigned int                     flags;
+       struct sm501_platdata_fbsub     *fb_crt;
+       struct sm501_platdata_fbsub     *fb_pnl;
+};
+
+/* gpio i2c */
+
+struct sm501_platdata_gpio_i2c {
+       unsigned int            pin_sda;
+       unsigned int            pin_scl;
+};
+
+/* sm501_initdata
+ *
+ * use for initialising values that may not have been setup
+ * before the driver is loaded.
+*/
+
+struct sm501_reg_init {
+       unsigned long           set;
+       unsigned long           mask;
+};
+
+#define SM501_USE_USB_HOST     (1<<0)
+#define SM501_USE_USB_SLAVE    (1<<1)
+#define SM501_USE_SSP0         (1<<2)
+#define SM501_USE_SSP1         (1<<3)
+#define SM501_USE_UART0                (1<<4)
+#define SM501_USE_UART1                (1<<5)
+#define SM501_USE_FBACCEL      (1<<6)
+#define SM501_USE_AC97         (1<<7)
+#define SM501_USE_I2S          (1<<8)
+
+#define SM501_USE_ALL          (0xffffffff)
+
+struct sm501_initdata {
+       struct sm501_reg_init   gpio_low;
+       struct sm501_reg_init   gpio_high;
+       struct sm501_reg_init   misc_timing;
+       struct sm501_reg_init   misc_control;
+
+       unsigned long           devices;
+       unsigned long           mclk;           /* non-zero to modify */
+       unsigned long           m1xclk;         /* non-zero to modify */
+};
+
+/* sm501_init_gpio
+ *
+ * default gpio settings
+*/
+
+struct sm501_init_gpio {
+       struct sm501_reg_init   gpio_data_low;
+       struct sm501_reg_init   gpio_data_high;
+       struct sm501_reg_init   gpio_ddr_low;
+       struct sm501_reg_init   gpio_ddr_high;
+};
+
+/* sm501_platdata
+ *
+ * This is passed with the platform device to allow the board
+ * to control the behaviour of the SM501 driver(s) which attach
+ * to the device.
+ *
+*/
+
+struct sm501_platdata {
+       struct sm501_initdata           *init;
+       struct sm501_init_gpio          *init_gpiop;
+       struct sm501_platdata_fb        *fb;
+
+       struct sm501_platdata_gpio_i2c  *gpio_i2c;
+       unsigned int                     gpio_i2c_nr;
+};
index de9fc57..3069ecc 100644 (file)
@@ -150,10 +150,10 @@ struct rpc_call_ops {
 #define RPC_TASK_HAS_TIMER     3
 #define RPC_TASK_ACTIVE                4
 
-#define RPC_IS_RUNNING(t)      (test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate))
-#define rpc_set_running(t)     (set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate))
+#define RPC_IS_RUNNING(t)      test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)
+#define rpc_set_running(t)     set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)
 #define rpc_test_and_set_running(t) \
-                               (test_and_set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate))
+                               test_and_set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)
 #define rpc_clear_running(t)   \
        do { \
                smp_mb__before_clear_bit(); \
@@ -161,8 +161,8 @@ struct rpc_call_ops {
                smp_mb__after_clear_bit(); \
        } while (0)
 
-#define RPC_IS_QUEUED(t)       (test_bit(RPC_TASK_QUEUED, &(t)->tk_runstate))
-#define rpc_set_queued(t)      (set_bit(RPC_TASK_QUEUED, &(t)->tk_runstate))
+#define RPC_IS_QUEUED(t)       test_bit(RPC_TASK_QUEUED, &(t)->tk_runstate)
+#define rpc_set_queued(t)      set_bit(RPC_TASK_QUEUED, &(t)->tk_runstate)
 #define rpc_clear_queued(t)    \
        do { \
                smp_mb__before_clear_bit(); \
@@ -179,7 +179,7 @@ struct rpc_call_ops {
                smp_mb__after_clear_bit(); \
        } while (0)
 
-#define RPC_IS_ACTIVATED(t)    (test_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate))
+#define RPC_IS_ACTIVATED(t)    test_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate)
 
 /*
  * Task priorities.
index ec639aa..ceb6cc5 100644 (file)
@@ -108,7 +108,10 @@ extern void migration_entry_wait(struct mm_struct *mm, pmd_t *pmd,
 #else
 
 #define make_migration_entry(page, write) swp_entry(0, 0)
-#define is_migration_entry(swp) 0
+static inline int is_migration_entry(swp_entry_t swp)
+{
+       return 0;
+}
 #define migration_entry_to_page(swp) NULL
 static inline void make_migration_entry_read(swp_entry_t *entryp) { }
 static inline void migration_entry_wait(struct mm_struct *mm, pmd_t *pmd,
index 192de3a..21805b5 100644 (file)
@@ -17,6 +17,7 @@
 struct kobject;
 struct module;
 struct nameidata;
+struct dentry;
 
 struct attribute {
        const char              * name;
@@ -68,18 +69,6 @@ struct sysfs_ops {
        ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
 };
 
-struct sysfs_dirent {
-       atomic_t                s_count;
-       struct list_head        s_sibling;
-       struct list_head        s_children;
-       void                    * s_element;
-       int                     s_type;
-       umode_t                 s_mode;
-       struct dentry           * s_dentry;
-       struct iattr            * s_iattr;
-       atomic_t                s_event;
-};
-
 #define SYSFS_ROOT             0x0001
 #define SYSFS_DIR              0x0002
 #define SYSFS_KOBJ_ATTR        0x0004
@@ -126,6 +115,11 @@ void sysfs_remove_bin_file(struct kobject *kobj, struct bin_attribute *attr);
 int __must_check sysfs_create_group(struct kobject *,
                                        const struct attribute_group *);
 void sysfs_remove_group(struct kobject *, const struct attribute_group *);
+int sysfs_add_file_to_group(struct kobject *kobj,
+               const struct attribute *attr, const char *group);
+void sysfs_remove_file_from_group(struct kobject *kobj,
+               const struct attribute *attr, const char *group);
+
 void sysfs_notify(struct kobject * k, char *dir, char *attr);
 
 
@@ -210,6 +204,18 @@ static inline void sysfs_remove_group(struct kobject * k, const struct attribute
        ;
 }
 
+static inline int sysfs_add_file_to_group(struct kobject *kobj,
+               const struct attribute *attr, const char *group)
+{
+       return 0;
+}
+
+static inline void sysfs_remove_file_from_group(struct kobject *kobj,
+               const struct attribute *attr, const char *group);
+{
+       ;
+}
+
 static inline void sysfs_notify(struct kobject * k, char *dir, char *attr)
 {
 }
index a8e8d1e..87dc75a 100644 (file)
@@ -388,10 +388,14 @@ struct usb_device {
        struct usb_device *children[USB_MAXCHILDREN];
 
        int pm_usage_cnt;               /* usage counter for autosuspend */
+       u32 quirks;                     /* quirks of the whole device */
+
 #ifdef CONFIG_PM
        struct delayed_work autosuspend; /* for delayed autosuspends */
        struct mutex pm_mutex;          /* protects PM operations */
 
+       unsigned autosuspend_delay;     /* in jiffies */
+
        unsigned auto_pm:1;             /* autosuspend/resume in progress */
        unsigned do_remote_wakeup:1;    /* remote wakeup should be enabled */
 #endif
index 245c725..1122a6c 100644 (file)
@@ -1,8 +1,9 @@
 /*
- * This file holds USB constants and structures that are needed for USB
- * device APIs.  These are used by the USB device model, which is defined
- * in chapter 9 of the USB 2.0 specification.  Linux has several APIs in C
- * that need these:
+ * This file holds USB constants and structures that are needed for
+ * USB device APIs.  These are used by the USB device model, which is
+ * defined in chapter 9 of the USB 2.0 specification and in the
+ * Wireless USB 1.0 (spread around).  Linux has several APIs in C that
+ * need these:
  *
  * - the master/host side Linux-USB kernel driver API;
  * - the "usbfs" user space API; and
  *
  * There's also "Wireless USB", using low power short range radios for
  * peripheral interconnection but otherwise building on the USB framework.
+ *
+ * Note all descriptors are declared '__attribute__((packed))' so that:
+ *
+ * [a] they never get padded, either internally (USB spec writers
+ *     probably handled that) or externally;
+ *
+ * [b] so that accessing bigger-than-a-bytes fields will never
+ *     generate bus errors on any platform, even when the location of
+ *     its descriptor inside a bundle isn't "naturally aligned", and
+ *
+ * [c] for consistency, removing all doubt even when it appears to
+ *     someone that the two other points are non-issues for that
+ *     particular descriptor type.
  */
 
 #ifndef __LINUX_USB_CH9_H
diff --git a/include/linux/usb/iowarrior.h b/include/linux/usb/iowarrior.h
new file mode 100644 (file)
index 0000000..cbbe020
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef _IOWARRIOR_H_
+#define _IOWARRIOR_H_
+
+#define CODEMERCS_MAGIC_NUMBER 0xC0    /* like COde Mercenaries */
+
+/* Define the ioctl commands for reading and writing data */
+#define IOW_WRITE      _IOW(CODEMERCS_MAGIC_NUMBER, 1, __u8 *)
+#define IOW_READ       _IOW(CODEMERCS_MAGIC_NUMBER, 2, __u8 *)
+
+/*
+   A struct for available device info which is read
+   with the ioctl IOW_GETINFO.
+   To be compatible with 2.4 userspace which didn't have an easy way to get
+   this information.
+*/
+struct iowarrior_info {
+       __u32 vendor;           /* vendor id : supposed to be USB_VENDOR_ID_CODEMERCS in all cases */
+       __u32 product;          /* product id : depends on type of chip (USB_DEVICE_ID_CODEMERCS_XXXXX) */
+       __u8 serial[9];         /* the serial number of our chip (if a serial-number is not available this is empty string) */
+       __u32 revision;         /* revision number of the chip */
+       __u32 speed;            /* USB-speed of the device (0=UNKNOWN, 1=LOW, 2=FULL 3=HIGH) */
+       __u32 power;            /* power consumption of the device in mA */
+       __u32 if_num;           /* the number of the endpoint */
+       __u32 report_size;      /* size of the data-packets on this interface */
+};
+
+/*
+  Get some device-information (product-id , serial-number etc.)
+  in order to identify a chip.
+*/
+#define IOW_GETINFO _IOR(CODEMERCS_MAGIC_NUMBER, 3, struct iowarrior_info)
+
+#endif  /* _IOWARRIOR_H_ */
diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h
new file mode 100644 (file)
index 0000000..6bac8fa
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+ * This file holds the definitions of quirks found in USB devices.
+ * Only quirks that affect the whole device, not an interface,
+ * belong here.
+ */
+
+/* device must not be autosuspended */
+#define USB_QUIRK_NO_AUTOSUSPEND       0x00000001
+
+/* string descriptors must not be fetched using a 255-byte read */
+#define USB_QUIRK_STRING_FETCH_255     0x00000002
index d94e268..65a165f 100644 (file)
@@ -1,5 +1,45 @@
 /*
- *     Video for Linux Two
+ *  Video for Linux Two header file
+ *
+ *  Copyright (C) 1999-2007 the contributors
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the 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.
+ *
+ *  Alternatively you can redistribute this file under the terms of the
+ *  BSD license as stated below:
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *  3. The names of its contributors may not be used to endorse or promote
+ *     products derived from this software without specific prior written
+ *     permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ *  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  *     Header file for v4l or V4L2 drivers and applications
  * with public API.
@@ -8,8 +48,9 @@
  *
  *     See http://linuxtv.org for more info
  *
- *     Author: Bill Dirks <bdirks@pacbell.net>
+ *     Author: Bill Dirks <bill@thedirks.org>
  *             Justin Schoeman
+ *              Hans Verkuil <hverkuil@xs4all.nl>
  *             et al.
  */
 #ifndef __LINUX_VIDEODEV2_H
@@ -90,11 +131,8 @@ enum v4l2_buf_type {
        V4L2_BUF_TYPE_VIDEO_OVERLAY      = 3,
        V4L2_BUF_TYPE_VBI_CAPTURE        = 4,
        V4L2_BUF_TYPE_VBI_OUTPUT         = 5,
-#if 1
-       /* Experimental Sliced VBI */
        V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6,
        V4L2_BUF_TYPE_SLICED_VBI_OUTPUT  = 7,
-#endif
        V4L2_BUF_TYPE_PRIVATE            = 0x80,
 };
 
@@ -186,10 +224,8 @@ struct v4l2_capability
 #define V4L2_CAP_VIDEO_OVERLAY         0x00000004  /* Can do video overlay */
 #define V4L2_CAP_VBI_CAPTURE           0x00000010  /* Is a raw VBI capture device */
 #define V4L2_CAP_VBI_OUTPUT            0x00000020  /* Is a raw VBI output device */
-#if 1
 #define V4L2_CAP_SLICED_VBI_CAPTURE    0x00000040  /* Is a sliced VBI capture device */
 #define V4L2_CAP_SLICED_VBI_OUTPUT     0x00000080  /* Is a sliced VBI output device */
-#endif
 #define V4L2_CAP_RDS_CAPTURE           0x00000100  /* RDS data capture */
 
 #define V4L2_CAP_TUNER                 0x00010000  /* has a tuner */
@@ -1179,7 +1215,6 @@ struct v4l2_vbi_format
 #define V4L2_VBI_UNSYNC                (1<< 0)
 #define V4L2_VBI_INTERLACED    (1<< 1)
 
-#if 1
 /* Sliced VBI
  *
  *    This implements is a proposal V4L2 API to allow SLICED VBI
@@ -1212,7 +1247,6 @@ struct v4l2_sliced_vbi_format
 #define V4L2_SLICED_VBI_525             (V4L2_SLICED_CAPTION_525)
 #define V4L2_SLICED_VBI_625             (V4L2_SLICED_TELETEXT_B | V4L2_SLICED_VPS | V4L2_SLICED_WSS_625)
 
-
 struct v4l2_sliced_vbi_cap
 {
        __u16   service_set;
@@ -1233,7 +1267,6 @@ struct v4l2_sliced_vbi_data
        __u32   reserved;       /* must be 0 */
        __u8    data[48];
 };
-#endif
 
 /*
  *     A G G R E G A T E   S T R U C T U R E S
@@ -1249,9 +1282,7 @@ struct v4l2_format
                struct v4l2_pix_format          pix;     // V4L2_BUF_TYPE_VIDEO_CAPTURE
                struct v4l2_window              win;     // V4L2_BUF_TYPE_VIDEO_OVERLAY
                struct v4l2_vbi_format          vbi;     // V4L2_BUF_TYPE_VBI_CAPTURE
-#if 1
                struct v4l2_sliced_vbi_format   sliced;  // V4L2_BUF_TYPE_SLICED_VBI_CAPTURE
-#endif
                __u8    raw_data[200];                   // user-defined
        } fmt;
 };
@@ -1271,6 +1302,17 @@ struct v4l2_streamparm
 };
 
 /*
+ *     A D V A N C E D   D E B U G G I N G
+ */
+
+/* VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER */
+struct v4l2_register {
+       __u64 reg;
+       __u32 i2c_id; /* I2C driver ID of the I2C chip, or 0 for the host */
+       __u32 val;
+};
+
+/*
  *     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
  *
  */
@@ -1328,9 +1370,7 @@ struct v4l2_streamparm
 #define VIDIOC_ENUMAUDOUT      _IOWR ('V', 66, struct v4l2_audioout)
 #define VIDIOC_G_PRIORITY       _IOR  ('V', 67, enum v4l2_priority)
 #define VIDIOC_S_PRIORITY       _IOW  ('V', 68, enum v4l2_priority)
-#if 1
 #define VIDIOC_G_SLICED_VBI_CAP _IOWR ('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)
@@ -1339,6 +1379,9 @@ struct v4l2_streamparm
 #define VIDIOC_ENUM_FRAMESIZES _IOWR ('V', 74, struct v4l2_frmsizeenum)
 #define VIDIOC_ENUM_FRAMEINTERVALS     _IOWR ('V', 75, struct v4l2_frmivalenum)
 #endif
+/* only implemented if CONFIG_VIDEO_ADV_DEBUG is defined */
+#define        VIDIOC_DBG_S_REGISTER   _IOW ('d', 100, struct v4l2_register)
+#define        VIDIOC_DBG_G_REGISTER   _IOWR('d', 101, struct v4l2_register)
 
 #ifdef __OLD_VIDIOC_
 /* for compatibility, will go away some day */
index ecad55b..d758a52 100644 (file)
@@ -57,7 +57,6 @@ struct cx2341x_mpeg_params {
        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;
@@ -121,8 +120,6 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix);
 #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 */
@@ -141,7 +138,6 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix);
 #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
index 4bb0ad8..9807a7c 100644 (file)
 #define IR_KEYCODE(tab,code)   (((unsigned)code < IR_KEYTAB_SIZE) \
                                 ? tab[code] : KEY_RESERVED)
 
+#define RC5_START(x)   (((x)>>12)&3)
+#define RC5_TOGGLE(x)  (((x)>>11)&1)
+#define RC5_ADDR(x)    (((x)>>6)&31)
+#define RC5_INSTR(x)   ((x)&63)
+
 struct ir_input_state {
        /* configuration */
        int                ir_type;
@@ -48,6 +53,40 @@ struct ir_input_state {
        int                keypressed;  /* current state */
 };
 
+/* this was saa7134_ir and bttv_ir, moved here for
+ * rc5 decoding. */
+struct card_ir {
+       struct input_dev        *dev;
+       struct ir_input_state   ir;
+       char                    name[32];
+       char                    phys[32];
+
+       /* Usual gpio signalling */
+
+       u32                     mask_keycode;
+       u32                     mask_keydown;
+       u32                     mask_keyup;
+       u32                     polling;
+       u32                     last_gpio;
+       int                     shift_by;
+       int                     start; // What should RC5_START() be
+       int                     addr; // What RC5_ADDR() should be.
+       int                     rc5_key_timeout;
+       int                     rc5_remote_gap;
+       struct work_struct      work;
+       struct timer_list       timer;
+
+       /* RC5 gpio */
+       u32 rc5_gpio;
+       struct timer_list timer_end;    /* timer_end for code completion */
+       struct timer_list timer_keyup;  /* timer_end for key release */
+       u32 last_rc5;                   /* last good rc5 code */
+       u32 last_bit;                   /* last raw bit seen */
+       u32 code;                       /* raw code under construction */
+       struct timeval base_time;       /* time of last seen code */
+       int active;                     /* building raw code */
+};
+
 void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
                   int ir_type, IR_KEYTAB_TYPE *ir_codes);
 void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir);
@@ -58,6 +97,10 @@ int  ir_dump_samples(u32 *samples, int count);
 int  ir_decode_biphase(u32 *samples, int count, int low, int high);
 int  ir_decode_pulsedistance(u32 *samples, int count, int low, int high);
 
+u32 ir_rc5_decode(unsigned int code);
+void ir_rc5_timer_end(unsigned long data);
+void ir_rc5_timer_keyup(unsigned long data);
+
 /* Keymaps to be used by other modules */
 
 extern IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE];
@@ -94,6 +137,9 @@ extern IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_norwood[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_proteus_2309[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE];
 
 #endif
 
index 9f0e228..f677dfb 100644 (file)
@@ -42,5 +42,8 @@
 #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 */
 
+#define SAA7115_IPORT_ON    1
+#define SAA7115_IPORT_OFF   0
+
 #endif
 
index 91b1992..244e440 100644 (file)
@@ -64,9 +64,6 @@
 /* Prints the ioctl in a human-readable format */
 extern void v4l_printk_ioctl(unsigned int cmd);
 
-/* Prints the ioctl and arg in a human-readable format */
-extern void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg);
-
 /* Use this macro for non-I2C drivers. Pass the driver name as the first arg. */
 #define v4l_print_ioctl(name, cmd)              \
        do {                                     \
@@ -99,13 +96,6 @@ u32 v4l2_ctrl_next(const u32 * const *ctrl_classes, u32 id);
 
 /* Internal ioctls */
 
-/* VIDIOC_INT_G_REGISTER and VIDIOC_INT_S_REGISTER */
-struct v4l2_register {
-       u32 i2c_id;             /* I2C driver ID of the I2C chip. 0 for the I2C adapter. */
-       unsigned long reg;
-       u32 val;
-};
-
 /* VIDIOC_INT_DECODE_VBI_LINE */
 struct v4l2_decode_vbi_line {
        u32 is_second_field;    /* Set to 0 for the first (odd) field,
@@ -175,9 +165,7 @@ enum v4l2_chip_ident {
    Replacement of TUNER_SET_STANDBY. */
 #define VIDIOC_INT_S_STANDBY        _IOW('d', 94, u32)
 
-/* only implemented if CONFIG_VIDEO_ADV_DEBUG is defined */
-#define        VIDIOC_INT_S_REGISTER           _IOW ('d', 100, struct v4l2_register)
-#define        VIDIOC_INT_G_REGISTER           _IOWR('d', 101, struct v4l2_register)
+/* 100, 101 used by  VIDIOC_DBG_[SG]_REGISTER */
 
 /* Generic reset command. The argument selects which subsystems to reset.
    Passing 0 will always reset the whole chip. */
index fb96472..aeec569 100644 (file)
@@ -296,6 +296,15 @@ struct video_device
        int (*vidioc_log_status)       (struct file *file, void *fh);
 
 
+       /* Debugging ioctls */
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       int (*vidioc_g_register)       (struct file *file, void *fh,
+                                       struct v4l2_register *reg);
+       int (*vidioc_s_register)       (struct file *file, void *fh,
+                                       struct v4l2_register *reg);
+#endif
+
+
 #ifdef OBSOLETE_OWNER /* to be removed soon */
 /* obsolete -- fops->owner is used instead */
 struct module *owner;
index 1115a25..d6f0794 100644 (file)
@@ -78,6 +78,9 @@ struct videobuf_dmabuf {
        /* for kernel buffers */
        void                *vmalloc;
 
+       /* Stores the userspace pointer to vmalloc area */
+       void                *varea;
+
        /* for overlay buffers (pci-pci dma) */
        dma_addr_t          bus_addr;
 
index 1cb0607..89fe534 100644 (file)
@@ -113,4 +113,20 @@ do { if(!(expr)) { \
 #define IAS_IRCOMM_ID 0x2343
 #define IAS_IRLPT_ID  0x9876
 
+struct net_device;
+struct packet_type;
+
+extern void irda_proc_register(void);
+extern void irda_proc_unregister(void);
+
+extern int irda_sysctl_register(void);
+extern void irda_sysctl_unregister(void);
+
+extern int irsock_init(void);
+extern void irsock_cleanup(void);
+
+extern int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
+                           struct packet_type *ptype,
+                           struct net_device *orig_dev);
+
 #endif /* NET_IRDA_H */
index 1c5f6dc..a92989e 100644 (file)
@@ -387,14 +387,19 @@ static void __init setup_per_cpu_areas(void)
 /* Called by boot processor to activate the rest. */
 static void __init smp_init(void)
 {
-       unsigned int i;
+       unsigned int cpu;
+       unsigned highest = 0;
+
+       for_each_cpu_mask(cpu, cpu_possible_map)
+               highest = cpu;
+       nr_cpu_ids = highest + 1;
 
        /* FIXME: This should be done in userspace --RR */
-       for_each_present_cpu(i) {
+       for_each_present_cpu(cpu) {
                if (num_online_cpus() >= max_cpus)
                        break;
-               if (!cpu_online(i))
-                       cpu_up(i);
+               if (!cpu_online(cpu))
+                       cpu_up(cpu);
        }
 
        /* Any cleanup work */
index 5bb617f..eb57e22 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
 #include <linux/seq_file.h>
 #include <linux/mutex.h>
 #include <linux/nsproxy.h>
+#include <linux/mount.h>
 
 #include <asm/uaccess.h>
 
 #include "util.h"
 
+struct shm_file_data {
+       int id;
+       struct ipc_namespace *ns;
+       struct file *file;
+       const struct vm_operations_struct *vm_ops;
+};
+
+#define shm_file_data(file) (*((struct shm_file_data **)&(file)->private_data))
+
 static const struct file_operations shm_file_operations;
 static struct vm_operations_struct shm_vm_ops;
 
@@ -60,8 +70,8 @@ static struct ipc_ids init_shm_ids;
 
 static int newseg (struct ipc_namespace *ns, key_t key,
                int shmflg, size_t size);
-static void shm_open (struct vm_area_struct *shmd);
-static void shm_close (struct vm_area_struct *shmd);
+static void shm_open(struct vm_area_struct *vma);
+static void shm_close(struct vm_area_struct *vma);
 static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp);
 #ifdef CONFIG_PROC_FS
 static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
@@ -150,11 +160,14 @@ static inline int shm_addid(struct ipc_namespace *ns, struct shmid_kernel *shp)
 
 
 
-static inline void shm_inc(struct ipc_namespace *ns, int id)
+/* This is called by fork, once for every shm attach. */
+static void shm_open(struct vm_area_struct *vma)
 {
+       struct file *file = vma->vm_file;
+       struct shm_file_data *sfd = shm_file_data(file);
        struct shmid_kernel *shp;
 
-       shp = shm_lock(ns, id);
+       shp = shm_lock(sfd->ns, sfd->id);
        BUG_ON(!shp);
        shp->shm_atim = get_seconds();
        shp->shm_lprid = current->tgid;
@@ -162,15 +175,6 @@ static inline void shm_inc(struct ipc_namespace *ns, int id)
        shm_unlock(shp);
 }
 
-#define shm_file_ns(file) (*((struct ipc_namespace **)&(file)->private_data))
-
-/* This is called by fork, once for every shm attach. */
-static void shm_open(struct vm_area_struct *shmd)
-{
-       shm_inc(shm_file_ns(shmd->vm_file),
-                       shmd->vm_file->f_path.dentry->d_inode->i_ino);
-}
-
 /*
  * shm_destroy - free the struct shmid_kernel
  *
@@ -195,23 +199,21 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
 }
 
 /*
- * remove the attach descriptor shmd.
+ * remove the attach descriptor vma.
  * free memory for segment if it is marked destroyed.
  * The descriptor has already been removed from the current->mm->mmap list
  * and will later be kfree()d.
  */
-static void shm_close (struct vm_area_struct *shmd)
+static void shm_close(struct vm_area_struct *vma)
 {
-       struct file * file = shmd->vm_file;
-       int id = file->f_path.dentry->d_inode->i_ino;
+       struct file * file = vma->vm_file;
+       struct shm_file_data *sfd = shm_file_data(file);
        struct shmid_kernel *shp;
-       struct ipc_namespace *ns;
-
-       ns = shm_file_ns(file);
+       struct ipc_namespace *ns = sfd->ns;
 
        mutex_lock(&shm_ids(ns).mutex);
        /* remove from the list of attaches of the shm segment */
-       shp = shm_lock(ns, id);
+       shp = shm_lock(ns, sfd->id);
        BUG_ON(!shp);
        shp->shm_lprid = current->tgid;
        shp->shm_dtim = get_seconds();
@@ -224,46 +226,91 @@ static void shm_close (struct vm_area_struct *shmd)
        mutex_unlock(&shm_ids(ns).mutex);
 }
 
+struct page *shm_nopage(struct vm_area_struct *vma, unsigned long address,
+                       int *type)
+{
+       struct file *file = vma->vm_file;
+       struct shm_file_data *sfd = shm_file_data(file);
+
+       return sfd->vm_ops->nopage(vma, address, type);
+}
+
+#ifdef CONFIG_NUMA
+int shm_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
+{
+       struct file *file = vma->vm_file;
+       struct shm_file_data *sfd = shm_file_data(file);
+       int err = 0;
+       if (sfd->vm_ops->set_policy)
+               err = sfd->vm_ops->set_policy(vma, new);
+       return err;
+}
+
+struct mempolicy *shm_get_policy(struct vm_area_struct *vma, unsigned long addr)
+{
+       struct file *file = vma->vm_file;
+       struct shm_file_data *sfd = shm_file_data(file);
+       struct mempolicy *pol = NULL;
+
+       if (sfd->vm_ops->get_policy)
+               pol = sfd->vm_ops->get_policy(vma, addr);
+       else
+               pol = vma->vm_policy;
+       return pol;
+}
+#endif
+
 static int shm_mmap(struct file * file, struct vm_area_struct * vma)
 {
+       struct shm_file_data *sfd = shm_file_data(file);
        int ret;
 
-       ret = shmem_mmap(file, vma);
-       if (ret == 0) {
-               vma->vm_ops = &shm_vm_ops;
-               if (!(vma->vm_flags & VM_WRITE))
-                       vma->vm_flags &= ~VM_MAYWRITE;
-               shm_inc(shm_file_ns(file), file->f_path.dentry->d_inode->i_ino);
-       }
+       ret = sfd->file->f_op->mmap(sfd->file, vma);
+       if (ret != 0)
+               return ret;
+       sfd->vm_ops = vma->vm_ops;
+       vma->vm_ops = &shm_vm_ops;
+       shm_open(vma);
 
        return ret;
 }
 
 static int shm_release(struct inode *ino, struct file *file)
 {
-       struct ipc_namespace *ns;
+       struct shm_file_data *sfd = shm_file_data(file);
 
-       ns = shm_file_ns(file);
-       put_ipc_ns(ns);
-       shm_file_ns(file) = NULL;
+       put_ipc_ns(sfd->ns);
+       shm_file_data(file) = NULL;
+       kfree(sfd);
        return 0;
 }
 
+#ifndef CONFIG_MMU
+static unsigned long shm_get_unmapped_area(struct file *file,
+       unsigned long addr, unsigned long len, unsigned long pgoff,
+       unsigned long flags)
+{
+       struct shm_file_data *sfd = shm_file_data(file);
+       return sfd->file->f_op->get_unmapped_area(sfd->file, addr, len, pgoff,
+                                                       flags);
+}
+#else
+#define shm_get_unmapped_area NULL
+#endif
+
 static const struct file_operations shm_file_operations = {
        .mmap           = shm_mmap,
        .release        = shm_release,
-#ifndef CONFIG_MMU
-       .get_unmapped_area = shmem_get_unmapped_area,
-#endif
+       .get_unmapped_area      = shm_get_unmapped_area,
 };
 
 static struct vm_operations_struct shm_vm_ops = {
        .open   = shm_open,     /* callback for a new vm-area open */
        .close  = shm_close,    /* callback for when the vm-area is released */
-       .nopage = shmem_nopage,
-#if defined(CONFIG_NUMA) && defined(CONFIG_SHMEM)
-       .set_policy = shmem_set_policy,
-       .get_policy = shmem_get_policy,
+       .nopage = shm_nopage,
+#if defined(CONFIG_NUMA)
+       .set_policy = shm_set_policy,
+       .get_policy = shm_get_policy,
 #endif
 };
 
@@ -330,13 +377,6 @@ static int newseg (struct ipc_namespace *ns, key_t key, int shmflg, size_t size)
        shp->shm_nattch = 0;
        shp->id = shm_buildid(ns, id, shp->shm_perm.seq);
        shp->shm_file = file;
-       file->f_path.dentry->d_inode->i_ino = shp->id;
-
-       shm_file_ns(file) = get_ipc_ns(ns);
-
-       /* Hugetlb ops would have already been assigned. */
-       if (!(shmflg & SHM_HUGETLB))
-               file->f_op = &shm_file_operations;
 
        ns->shm_tot += numpages;
        shm_unlock(shp);
@@ -607,10 +647,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
                tbuf.shm_ctime  = shp->shm_ctim;
                tbuf.shm_cpid   = shp->shm_cprid;
                tbuf.shm_lpid   = shp->shm_lprid;
-               if (!is_file_hugepages(shp->shm_file))
-                       tbuf.shm_nattch = shp->shm_nattch;
-               else
-                       tbuf.shm_nattch = file_count(shp->shm_file) - 1;
+               tbuf.shm_nattch = shp->shm_nattch;
                shm_unlock(shp);
                if(copy_shmid_to_user (buf, &tbuf, version))
                        err = -EFAULT;
@@ -779,13 +816,16 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
        unsigned long flags;
        unsigned long prot;
        int acc_mode;
-       void *user_addr;
+       unsigned long user_addr;
        struct ipc_namespace *ns;
+       struct shm_file_data *sfd;
+       struct path path;
+       mode_t f_mode;
 
-       if (shmid < 0) {
-               err = -EINVAL;
+       err = -EINVAL;
+       if (shmid < 0)
                goto out;
-       else if ((addr = (ulong)shmaddr)) {
+       else if ((addr = (ulong)shmaddr)) {
                if (addr & (SHMLBA-1)) {
                        if (shmflg & SHM_RND)
                                addr &= ~(SHMLBA-1);       /* round down */
@@ -793,12 +833,12 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
 #ifndef __ARCH_FORCE_SHMLBA
                                if (addr & ~PAGE_MASK)
 #endif
-                                       return -EINVAL;
+                                       goto out;
                }
                flags = MAP_SHARED | MAP_FIXED;
        } else {
                if ((shmflg & SHM_REMAP))
-                       return -EINVAL;
+                       goto out;
 
                flags = MAP_SHARED;
        }
@@ -806,9 +846,11 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
        if (shmflg & SHM_RDONLY) {
                prot = PROT_READ;
                acc_mode = S_IRUGO;
+               f_mode = FMODE_READ;
        } else {
                prot = PROT_READ | PROT_WRITE;
                acc_mode = S_IRUGO | S_IWUGO;
+               f_mode = FMODE_READ | FMODE_WRITE;
        }
        if (shmflg & SHM_EXEC) {
                prot |= PROT_EXEC;
@@ -821,35 +863,50 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
         */
        ns = current->nsproxy->ipc_ns;
        shp = shm_lock(ns, shmid);
-       if(shp == NULL) {
-               err = -EINVAL;
+       if(shp == NULL)
                goto out;
-       }
+
        err = shm_checkid(ns, shp,shmid);
-       if (err) {
-               shm_unlock(shp);
-               goto out;
-       }
-       if (ipcperms(&shp->shm_perm, acc_mode)) {
-               shm_unlock(shp);
-               err = -EACCES;
-               goto out;
-       }
+       if (err)
+               goto out_unlock;
+
+       err = -EACCES;
+       if (ipcperms(&shp->shm_perm, acc_mode))
+               goto out_unlock;
 
        err = security_shm_shmat(shp, shmaddr, shmflg);
-       if (err) {
-               shm_unlock(shp);
-               return err;
-       }
-               
-       file = shp->shm_file;
-       size = i_size_read(file->f_path.dentry->d_inode);
+       if (err)
+               goto out_unlock;
+
+       path.dentry = dget(shp->shm_file->f_path.dentry);
+       path.mnt    = mntget(shp->shm_file->f_path.mnt);
        shp->shm_nattch++;
+       size = i_size_read(path.dentry->d_inode);
        shm_unlock(shp);
 
+       err = -ENOMEM;
+       sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
+       if (!sfd)
+               goto out_put_path;
+
+       err = -ENOMEM;
+       file = get_empty_filp();
+       if (!file)
+               goto out_free;
+
+       file->f_op = &shm_file_operations;
+       file->private_data = sfd;
+       file->f_path = path;
+       file->f_mapping = shp->shm_file->f_mapping;
+       file->f_mode = f_mode;
+       sfd->id = shp->id;
+       sfd->ns = get_ipc_ns(ns);
+       sfd->file = shp->shm_file;
+       sfd->vm_ops = NULL;
+
        down_write(&current->mm->mmap_sem);
        if (addr && !(shmflg & SHM_REMAP)) {
-               user_addr = ERR_PTR(-EINVAL);
+               err = -EINVAL;
                if (find_vma_intersection(current->mm, addr, addr + size))
                        goto invalid;
                /*
@@ -861,11 +918,17 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
                        goto invalid;
        }
                
-       user_addr = (void*) do_mmap (file, addr, size, prot, flags, 0);
-
+       user_addr = do_mmap (file, addr, size, prot, flags, 0);
+       *raddr = user_addr;
+       err = 0;
+       if (IS_ERR_VALUE(user_addr))
+               err = (long)user_addr;
 invalid:
        up_write(&current->mm->mmap_sem);
 
+       fput(file);
+
+out_nattch:
        mutex_lock(&shm_ids(ns).mutex);
        shp = shm_lock(ns, shmid);
        BUG_ON(!shp);
@@ -877,12 +940,19 @@ invalid:
                shm_unlock(shp);
        mutex_unlock(&shm_ids(ns).mutex);
 
-       *raddr = (unsigned long) user_addr;
-       err = 0;
-       if (IS_ERR(user_addr))
-               err = PTR_ERR(user_addr);
 out:
        return err;
+
+out_unlock:
+       shm_unlock(shp);
+       goto out;
+
+out_free:
+       kfree(sfd);
+out_put_path:
+       dput(path.dentry);
+       mntput(path.mnt);
+       goto out_nattch;
 }
 
 asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg)
@@ -944,7 +1014,7 @@ asmlinkage long sys_shmdt(char __user *shmaddr)
                 * a fragment created by mprotect() and/or munmap(), or it
                 * otherwise it starts at this address with no hassles.
                 */
-               if ((vma->vm_ops == &shm_vm_ops || is_vm_hugetlb_page(vma)) &&
+               if ((vma->vm_ops == &shm_vm_ops) &&
                        (vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
 
 
@@ -973,7 +1043,7 @@ asmlinkage long sys_shmdt(char __user *shmaddr)
                next = vma->vm_next;
 
                /* finding a matching vma now does not alter retval */
-               if ((vma->vm_ops == &shm_vm_ops || is_vm_hugetlb_page(vma)) &&
+               if ((vma->vm_ops == &shm_vm_ops) &&
                        (vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff)
 
                        do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
@@ -1004,7 +1074,7 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
                          shp->shm_segsz,
                          shp->shm_cprid,
                          shp->shm_lprid,
-                         is_file_hugepages(shp->shm_file) ? (file_count(shp->shm_file) - 1) : shp->shm_nattch,
+                         shp->shm_nattch,
                          shp->shm_perm.uid,
                          shp->shm_perm.gid,
                          shp->shm_perm.cuid,
index 4baa3bb..77b7acc 100644 (file)
@@ -65,12 +65,11 @@ void move_native_irq(int irq)
        if (likely(!(desc->status & IRQ_MOVE_PENDING)))
                return;
 
-       if (likely(!(desc->status & IRQ_DISABLED)))
-               desc->chip->disable(irq);
+       if (unlikely(desc->status & IRQ_DISABLED))
+               return;
 
+       desc->chip->mask(irq);
        move_masked_irq(irq);
-
-       if (likely(!(desc->status & IRQ_DISABLED)))
-               desc->chip->enable(irq);
+       desc->chip->unmask(irq);
 }
 
index 9f923f8..7962761 100644 (file)
@@ -36,8 +36,6 @@
 #include <linux/resource.h>
 #include <asm/uaccess.h>
 
-extern int delete_module(const char *name, unsigned int flags);
-
 extern int max_threads;
 
 static struct workqueue_struct *khelper_wq;
@@ -48,7 +46,6 @@ static struct workqueue_struct *khelper_wq;
        modprobe_path is set via /proc/sys.
 */
 char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe";
-struct module_kobject kmod_mk;
 
 /**
  * request_module - try to load a kernel module
@@ -78,11 +75,6 @@ int request_module(const char *fmt, ...)
        static atomic_t kmod_concurrent = ATOMIC_INIT(0);
 #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */
        static int kmod_loop_msg;
-       char modalias[16 + MODULE_NAME_LEN] = "MODALIAS=";
-       char *uevent_envp[2] = {
-               modalias,
-               NULL
-       };
 
        va_start(args, fmt);
        ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args);
@@ -90,12 +82,6 @@ int request_module(const char *fmt, ...)
        if (ret >= MODULE_NAME_LEN)
                return -ENAMETOOLONG;
 
-       strcpy(&modalias[strlen("MODALIAS=")], module_name);
-       kobject_uevent_env(&kmod_mk.kobj, KOBJ_CHANGE, uevent_envp);
-
-       if (modprobe_path[0] == '\0')
-               goto out;
-
        /* If modprobe needs a service that is in a module, we get a recursive
         * loop.  Limit the number of running kmod threads to max_threads/2 or
         * MAX_KMOD_CONCURRENT, whichever is the smaller.  A cleaner method
@@ -122,115 +108,9 @@ int request_module(const char *fmt, ...)
 
        ret = call_usermodehelper(modprobe_path, argv, envp, 1);
        atomic_dec(&kmod_concurrent);
-out:
        return ret;
 }
 EXPORT_SYMBOL(request_module);
-
-static ssize_t store_mod_request(struct module_attribute *mattr,
-                                struct module *mod,
-                             const char *buffer, size_t count)
-{
-       char name[MODULE_NAME_LEN];
-       int ret;
-
-       if (count < 1 || count+1 > MODULE_NAME_LEN)
-               return -EINVAL;
-       memcpy(name, buffer, count);
-       name[count] = '\0';
-       if (name[count-1] == '\n')
-               name[count-1] = '\0';
-
-       ret = request_module(name);
-       if (ret < 0)
-               return ret;
-       return count;
-}
-
-static struct module_attribute mod_request = {
-       .attr = { .name = "mod_request", .mode = S_IWUSR, .owner = THIS_MODULE },
-       .store = store_mod_request,
-};
-
-#ifdef CONFIG_MODULE_UNLOAD
-static ssize_t store_mod_unload(struct module_attribute *mattr,
-                           struct module *mod,
-                           const char *buffer, size_t count)
-{
-       char name[MODULE_NAME_LEN];
-       int ret;
-
-       if (count < 1 || count+1 > MODULE_NAME_LEN)
-               return -EINVAL;
-       memcpy(name, buffer, count);
-       name[count] = '\0';
-       if (name[count-1] == '\n')
-               name[count-1] = '\0';
-
-       ret = delete_module(name, O_NONBLOCK);
-       if (ret < 0)
-               return ret;
-       return count;
-}
-
-static struct module_attribute mod_unload = {
-       .attr = { .name = "mod_unload", .mode = S_IWUSR, .owner = THIS_MODULE },
-       .store = store_mod_unload,
-};
-#endif
-
-static ssize_t show_mod_request_helper(struct module_attribute *mattr,
-                                      struct module *mod,
-                                      char *buffer)
-{
-       return sprintf(buffer, "%s\n", modprobe_path);
-}
-
-static ssize_t store_mod_request_helper(struct module_attribute *mattr,
-                                       struct module *mod,
-                                       const char *buffer, size_t count)
-{
-       if (count < 1 || count+1 > KMOD_PATH_LEN)
-               return -EINVAL;
-       memcpy(modprobe_path, buffer, count);
-       modprobe_path[count] = '\0';
-       if (modprobe_path[count-1] == '\n')
-               modprobe_path[count-1] = '\0';
-       return count;
-}
-
-static struct module_attribute mod_request_helper = {
-       .attr = {
-               .name = "mod_request_helper",
-               .mode = S_IWUSR | S_IRUGO,
-               .owner = THIS_MODULE
-       },
-       .show = show_mod_request_helper,
-       .store = store_mod_request_helper,
-};
-
-void __init kmod_sysfs_init(void)
-{
-       int ret;
-
-       kmod_mk.mod = THIS_MODULE;
-       kobj_set_kset_s(&kmod_mk, module_subsys);
-       kobject_set_name(&kmod_mk.kobj, "kmod");
-       kobject_init(&kmod_mk.kobj);
-       ret = kobject_add(&kmod_mk.kobj);
-       if (ret < 0)
-               goto out;
-
-       ret = sysfs_create_file(&kmod_mk.kobj, &mod_request_helper.attr);
-       ret = sysfs_create_file(&kmod_mk.kobj, &mod_request.attr);
-#ifdef CONFIG_MODULE_UNLOAD
-       ret = sysfs_create_file(&kmod_mk.kobj, &mod_unload.attr);
-#endif
-
-       kobject_uevent(&kmod_mk.kobj, KOBJ_ADD);
-out:
-       return;
-}
 #endif /* CONFIG_KMOD */
 
 struct subprocess_info {
index 6fcf8dd..d25a9ad 100644 (file)
@@ -39,6 +39,8 @@
 #include <linux/moduleloader.h>
 #include <linux/kallsyms.h>
 #include <linux/freezer.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
 #include <asm-generic/sections.h>
 #include <asm/cacheflush.h>
 #include <asm/errno.h>
@@ -778,6 +780,12 @@ int __kprobes register_kretprobe(struct kretprobe *rp)
        return -ENOSYS;
 }
 
+static int __kprobes pre_handler_kretprobe(struct kprobe *p,
+                                          struct pt_regs *regs)
+{
+       return 0;
+}
+
 #endif /* ARCH_SUPPORTS_KRETPROBES */
 
 void __kprobes unregister_kretprobe(struct kretprobe *rp)
@@ -815,7 +823,109 @@ static int __init init_kprobes(void)
        return err;
 }
 
-__initcall(init_kprobes);
+#ifdef CONFIG_DEBUG_FS
+static void __kprobes report_probe(struct seq_file *pi, struct kprobe *p,
+               const char *sym, int offset,char *modname)
+{
+       char *kprobe_type;
+
+       if (p->pre_handler == pre_handler_kretprobe)
+               kprobe_type = "r";
+       else if (p->pre_handler == setjmp_pre_handler)
+               kprobe_type = "j";
+       else
+               kprobe_type = "k";
+       if (sym)
+               seq_printf(pi, "%p  %s  %s+0x%x  %s\n", p->addr, kprobe_type,
+                       sym, offset, (modname ? modname : " "));
+       else
+               seq_printf(pi, "%p  %s  %p\n", p->addr, kprobe_type, p->addr);
+}
+
+static void __kprobes *kprobe_seq_start(struct seq_file *f, loff_t *pos)
+{
+       return (*pos < KPROBE_TABLE_SIZE) ? pos : NULL;
+}
+
+static void __kprobes *kprobe_seq_next(struct seq_file *f, void *v, loff_t *pos)
+{
+       (*pos)++;
+       if (*pos >= KPROBE_TABLE_SIZE)
+               return NULL;
+       return pos;
+}
+
+static void __kprobes kprobe_seq_stop(struct seq_file *f, void *v)
+{
+       /* Nothing to do */
+}
+
+static int __kprobes show_kprobe_addr(struct seq_file *pi, void *v)
+{
+       struct hlist_head *head;
+       struct hlist_node *node;
+       struct kprobe *p, *kp;
+       const char *sym = NULL;
+       unsigned int i = *(loff_t *) v;
+       unsigned long size, offset = 0;
+       char *modname, namebuf[128];
+
+       head = &kprobe_table[i];
+       preempt_disable();
+       hlist_for_each_entry_rcu(p, node, head, hlist) {
+               sym = kallsyms_lookup((unsigned long)p->addr, &size,
+                                       &offset, &modname, namebuf);
+               if (p->pre_handler == aggr_pre_handler) {
+                       list_for_each_entry_rcu(kp, &p->list, list)
+                               report_probe(pi, kp, sym, offset, modname);
+               } else
+                       report_probe(pi, p, sym, offset, modname);
+       }
+       preempt_enable();
+       return 0;
+}
+
+static struct seq_operations kprobes_seq_ops = {
+       .start = kprobe_seq_start,
+       .next  = kprobe_seq_next,
+       .stop  = kprobe_seq_stop,
+       .show  = show_kprobe_addr
+};
+
+static int __kprobes kprobes_open(struct inode *inode, struct file *filp)
+{
+       return seq_open(filp, &kprobes_seq_ops);
+}
+
+static struct file_operations debugfs_kprobes_operations = {
+       .open           = kprobes_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+static int __kprobes debugfs_kprobe_init(void)
+{
+       struct dentry *dir, *file;
+
+       dir = debugfs_create_dir("kprobes", NULL);
+       if (!dir)
+               return -ENOMEM;
+
+       file = debugfs_create_file("list", 0444, dir , 0 ,
+                               &debugfs_kprobes_operations);
+       if (!file) {
+               debugfs_remove(dir);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+late_initcall(debugfs_kprobe_init);
+#endif /* CONFIG_DEBUG_FS */
+
+module_init(init_kprobes);
 
 EXPORT_SYMBOL_GPL(register_kprobe);
 EXPORT_SYMBOL_GPL(unregister_kprobe);
@@ -824,4 +934,3 @@ EXPORT_SYMBOL_GPL(unregister_jprobe);
 EXPORT_SYMBOL_GPL(jprobe_return);
 EXPORT_SYMBOL_GPL(register_kretprobe);
 EXPORT_SYMBOL_GPL(unregister_kretprobe);
-
index 592c576..a08a172 100644 (file)
@@ -2228,6 +2228,10 @@ out_calc_hash:
 
        curr->lockdep_depth++;
        check_chain_key(curr);
+#ifdef CONFIG_DEBUG_LOCKDEP
+       if (unlikely(!debug_locks))
+               return 0;
+#endif
        if (unlikely(curr->lockdep_depth >= MAX_LOCK_DEPTH)) {
                debug_locks_off();
                printk("BUG: MAX_LOCK_DEPTH too low!\n");
index 8c25b1a..f77e893 100644 (file)
@@ -653,11 +653,20 @@ static void wait_for_zero_refcount(struct module *mod)
        mutex_lock(&module_mutex);
 }
 
-int delete_module(const char *name, unsigned int flags)
+asmlinkage long
+sys_delete_module(const char __user *name_user, unsigned int flags)
 {
        struct module *mod;
+       char name[MODULE_NAME_LEN];
        int ret, forced = 0;
 
+       if (!capable(CAP_SYS_MODULE))
+               return -EPERM;
+
+       if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0)
+               return -EFAULT;
+       name[MODULE_NAME_LEN-1] = '\0';
+
        if (mutex_lock_interruptible(&module_mutex) != 0)
                return -EINTR;
 
@@ -718,21 +727,6 @@ int delete_module(const char *name, unsigned int flags)
        return ret;
 }
 
-asmlinkage long
-sys_delete_module(const char __user *name_user, unsigned int flags)
-{
-       char name[MODULE_NAME_LEN];
-
-       if (!capable(CAP_SYS_MODULE))
-               return -EPERM;
-
-       if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0)
-               return -EFAULT;
-       name[MODULE_NAME_LEN-1] = '\0';
-
-       return delete_module(name, flags);
-}
-
 static void print_unload_info(struct seq_file *m, struct module *mod)
 {
        struct module_use *use;
@@ -2425,6 +2419,12 @@ void module_remove_driver(struct device_driver *drv)
                        kfree(driver_name);
                }
        }
+       /*
+        * Undo the additional reference we added in module_add_driver()
+        * via kset_find_obj()
+        */
+       if (drv->mod_name)
+               kobject_put(&drv->kobj);
 }
 EXPORT_SYMBOL(module_remove_driver);
 #endif
index 7a75157..e265b13 100644 (file)
@@ -707,7 +707,6 @@ static int __init param_sysfs_init(void)
        }
 
        param_sysfs_builtin();
-       kmod_sysfs_init();
 
        return 0;
 }
index e1c4131..a064dfd 100644 (file)
@@ -167,7 +167,10 @@ static inline int valid_state(suspend_state_t state)
        if (state == PM_SUSPEND_DISK)
                return 1;
 
-       if (pm_ops && pm_ops->valid && !pm_ops->valid(state))
+       /* all other states need lowlevel support and need to be
+        * valid to the lowlevel implementation, no valid callback
+        * implies that all are valid. */
+       if (!pm_ops || (pm_ops->valid && !pm_ops->valid(state)))
                return 0;
        return 1;
 }
index e2a7d4b..3670225 100644 (file)
@@ -1140,7 +1140,8 @@ int kill_pid_info(int sig, struct siginfo *info, struct pid *pid)
        return error;
 }
 
-static int kill_proc_info(int sig, struct siginfo *info, pid_t pid)
+int
+kill_proc_info(int sig, struct siginfo *info, pid_t pid)
 {
        int error;
        rcu_read_lock();
index 4500e34..0986a2b 100644 (file)
@@ -77,6 +77,7 @@ static void tick_periodic(int cpu)
 void tick_handle_periodic(struct clock_event_device *dev)
 {
        int cpu = smp_processor_id();
+       ktime_t next;
 
        tick_periodic(cpu);
 
@@ -86,12 +87,12 @@ void tick_handle_periodic(struct clock_event_device *dev)
         * Setup the next period for devices, which do not have
         * periodic mode:
         */
+       next = ktime_add(dev->next_event, tick_period);
        for (;;) {
-               ktime_t next = ktime_add(dev->next_event, tick_period);
-
                if (!clockevents_program_event(dev, next, ktime_get()))
                        return;
                tick_periodic(cpu);
+               next = ktime_add(next, tick_period);
        }
 }
 
index 512a4a9..51556b9 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/sched.h>
 #include <linux/tick.h>
 
+#include <asm/irq_regs.h>
+
 #include "tick-internal.h"
 
 /*
index 4448f91..3f3e740 100644 (file)
@@ -411,8 +411,6 @@ config LKDTM
 config FAULT_INJECTION
        bool "Fault-injection framework"
        depends on DEBUG_KERNEL
-       depends on STACKTRACE
-       select FRAME_POINTER
        help
          Provide fault-injection framework.
          For more details, see Documentation/fault-injection/.
@@ -440,3 +438,11 @@ config FAULT_INJECTION_DEBUG_FS
        depends on FAULT_INJECTION && SYSFS && DEBUG_FS
        help
          Enable configuration of fault-injection capabilities via debugfs.
+
+config FAULT_INJECTION_STACKTRACE_FILTER
+       bool "stacktrace filter for fault-injection capabilities"
+       depends on FAULT_INJECTION_DEBUG_FS && STACKTRACE_SUPPORT
+       select STACKTRACE
+       select FRAME_POINTER
+       help
+         Provide stacktrace filter for fault-injection capabilities
index 3a67dc5..1ea2c18 100644 (file)
@@ -15,22 +15,8 @@ int __next_cpu(int n, const cpumask_t *srcp)
 }
 EXPORT_SYMBOL(__next_cpu);
 
-/*
- * Find the highest possible smp_processor_id()
- *
- * Note: if we're prepared to assume that cpu_possible_map never changes
- * (reasonable) then this function should cache its return value.
- */
-int highest_possible_processor_id(void)
-{
-       unsigned int cpu;
-       unsigned highest = 0;
-
-       for_each_cpu_mask(cpu, cpu_possible_map)
-               highest = cpu;
-       return highest;
-}
-EXPORT_SYMBOL(highest_possible_processor_id);
+int nr_cpu_ids;
+EXPORT_SYMBOL(nr_cpu_ids);
 
 int __any_online_cpu(const cpumask_t *mask)
 {
index b5a90fc..0fabd12 100644 (file)
@@ -55,7 +55,7 @@ static bool fail_task(struct fault_attr *attr, struct task_struct *task)
 
 #define MAX_STACK_TRACE_DEPTH 32
 
-#if defined(CONFIG_STACKTRACE)
+#ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
 
 static bool fail_stacktrace(struct fault_attr *attr)
 {
@@ -90,17 +90,10 @@ static bool fail_stacktrace(struct fault_attr *attr)
 
 static inline bool fail_stacktrace(struct fault_attr *attr)
 {
-       static bool firsttime = true;
-
-       if (firsttime) {
-               printk(KERN_WARNING
-               "This architecture does not implement save_stack_trace()\n");
-               firsttime = false;
-       }
-       return false;
+       return true;
 }
 
-#endif
+#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
 
 /*
  * This code is stolen from failmalloc-1.0
@@ -217,6 +210,8 @@ void cleanup_fault_attr_dentries(struct fault_attr *attr)
        debugfs_remove(attr->dentries.task_filter_file);
        attr->dentries.task_filter_file = NULL;
 
+#ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
+
        debugfs_remove(attr->dentries.stacktrace_depth_file);
        attr->dentries.stacktrace_depth_file = NULL;
 
@@ -232,6 +227,8 @@ void cleanup_fault_attr_dentries(struct fault_attr *attr)
        debugfs_remove(attr->dentries.reject_end_file);
        attr->dentries.reject_end_file = NULL;
 
+#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
+
        if (attr->dentries.dir)
                WARN_ON(!simple_empty(attr->dentries.dir));
 
@@ -269,6 +266,13 @@ int init_fault_attr_dentries(struct fault_attr *attr, const char *name)
        attr->dentries.task_filter_file = debugfs_create_bool("task-filter",
                                                mode, dir, &attr->task_filter);
 
+       if (!attr->dentries.probability_file || !attr->dentries.interval_file ||
+           !attr->dentries.times_file || !attr->dentries.space_file ||
+           !attr->dentries.verbose_file || !attr->dentries.task_filter_file)
+               goto fail;
+
+#ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
+
        attr->dentries.stacktrace_depth_file =
                debugfs_create_ul_MAX_STACK_TRACE_DEPTH(
                        "stacktrace-depth", mode, dir, &attr->stacktrace_depth);
@@ -285,18 +289,15 @@ int init_fault_attr_dentries(struct fault_attr *attr, const char *name)
        attr->dentries.reject_end_file =
                debugfs_create_ul("reject-end", mode, dir, &attr->reject_end);
 
-
-       if (!attr->dentries.probability_file || !attr->dentries.interval_file
-           || !attr->dentries.times_file || !attr->dentries.space_file
-           || !attr->dentries.verbose_file || !attr->dentries.task_filter_file
-           || !attr->dentries.stacktrace_depth_file
-           || !attr->dentries.require_start_file
-           || !attr->dentries.require_end_file
-           || !attr->dentries.reject_start_file
-           || !attr->dentries.reject_end_file
-           )
+       if (!attr->dentries.stacktrace_depth_file ||
+           !attr->dentries.require_start_file ||
+           !attr->dentries.require_end_file ||
+           !attr->dentries.reject_start_file ||
+           !attr->dentries.reject_end_file)
                goto fail;
 
+#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
+
        return 0;
 fail:
        cleanup_fault_attr_dentries(attr);
index 75ae68c..eb7c2ba 100644 (file)
@@ -148,7 +148,7 @@ unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
                        addr = chunk->start_addr +
                                            ((unsigned long)start_bit << order);
                        while (nbits--)
-                               __set_bit(start_bit++, &chunk->bits);
+                               __set_bit(start_bit++, chunk->bits);
                        spin_unlock_irqrestore(&chunk->lock, flags);
                        read_unlock(&pool->lock);
                        return addr;
@@ -187,7 +187,7 @@ void gen_pool_free(struct gen_pool *pool, unsigned long addr, size_t size)
                        spin_lock_irqsave(&chunk->lock, flags);
                        bit = (addr - chunk->start_addr) >> order;
                        while (nbits--)
-                               __clear_bit(bit++, &chunk->bits);
+                               __clear_bit(bit++, chunk->bits);
                        spin_unlock_irqrestore(&chunk->lock, flags);
                        break;
                }
index 259a706..cf2a538 100644 (file)
@@ -144,7 +144,7 @@ static struct zonelist *bind_zonelist(nodemask_t *nodes)
        max++;                  /* space for zlcache_ptr (see mmzone.h) */
        zl = kmalloc(sizeof(struct zone *) * max, GFP_KERNEL);
        if (!zl)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
        zl->zlcache_ptr = NULL;
        num = 0;
        /* First put in the highest zones from all nodes, then all the next 
@@ -162,6 +162,10 @@ static struct zonelist *bind_zonelist(nodemask_t *nodes)
                        break;
                k--;
        }
+       if (num == 0) {
+               kfree(zl);
+               return ERR_PTR(-EINVAL);
+       }
        zl->zones[num] = NULL;
        return zl;
 }
@@ -193,9 +197,10 @@ static struct mempolicy *mpol_new(int mode, nodemask_t *nodes)
                break;
        case MPOL_BIND:
                policy->v.zonelist = bind_zonelist(nodes);
-               if (policy->v.zonelist == NULL) {
+               if (IS_ERR(policy->v.zonelist)) {
+                       void *error_code = policy->v.zonelist;
                        kmem_cache_free(policy_cache, policy);
-                       return ERR_PTR(-ENOMEM);
+                       return error_code;
                }
                break;
        }
@@ -1667,7 +1672,7 @@ void mpol_rebind_policy(struct mempolicy *pol, const nodemask_t *newmask)
                 * then zonelist_policy() will "FALL THROUGH" to MPOL_DEFAULT.
                 */
 
-               if (zonelist) {
+               if (!IS_ERR(zonelist)) {
                        /* Good - got mem - substitute new zonelist */
                        kfree(pol->v.zonelist);
                        pol->v.zonelist = zonelist;
index d461b23..4173739 100644 (file)
@@ -664,6 +664,26 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order,
        return i;
 }
 
+#if MAX_NUMNODES > 1
+int nr_node_ids __read_mostly;
+EXPORT_SYMBOL(nr_node_ids);
+
+/*
+ * Figure out the number of possible node ids.
+ */
+static void __init setup_nr_node_ids(void)
+{
+       unsigned int node;
+       unsigned int highest = 0;
+
+       for_each_node_mask(node, node_possible_map)
+               highest = node;
+       nr_node_ids = highest + 1;
+}
+#else
+static void __init setup_nr_node_ids(void) {}
+#endif
+
 #ifdef CONFIG_NUMA
 /*
  * Called from the slab reaper to drain pagesets on a particular node that
@@ -2944,6 +2964,7 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn)
                                                early_node_map[i].end_pfn);
 
        /* Initialise every node */
+       setup_nr_node_ids();
        for_each_online_node(nid) {
                pg_data_t *pgdat = NODE_DATA(nid);
                free_area_init_node(nid, pgdat, NULL,
@@ -3370,18 +3391,4 @@ EXPORT_SYMBOL(pfn_to_page);
 EXPORT_SYMBOL(page_to_pfn);
 #endif /* CONFIG_OUT_OF_LINE_PFN_TO_PAGE */
 
-#if MAX_NUMNODES > 1
-/*
- * Find the highest possible node id.
- */
-int highest_possible_node_id(void)
-{
-       unsigned int node;
-       unsigned int highest = 0;
 
-       for_each_node_mask(node, node_possible_map)
-               highest = node;
-       return highest;
-}
-EXPORT_SYMBOL(highest_possible_node_id);
-#endif
index 70784b8..8fdaffa 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1042,7 +1042,7 @@ static void *alternate_node_alloc(struct kmem_cache *, gfp_t);
 static struct array_cache **alloc_alien_cache(int node, int limit)
 {
        struct array_cache **ac_ptr;
-       int memsize = sizeof(void *) * MAX_NUMNODES;
+       int memsize = sizeof(void *) * nr_node_ids;
        int i;
 
        if (limit > 1)
index c6abf2a..98fdfa1 100644 (file)
@@ -1,6 +1,7 @@
 config BT_HIDP
        tristate "HIDP protocol support"
        depends on BT && BT_L2CAP && INPUT
+       select HID
        help
          HIDP (Human Interface Device Protocol) is a transport layer
          for HID reports.  HIDP is required for the Bluetooth Human
index 4b99c5e..4c914df 100644 (file)
@@ -38,6 +38,7 @@
 #include <net/sock.h>
 
 #include <linux/input.h>
+#include <linux/hid.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -50,7 +51,7 @@
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "1.1"
+#define VERSION "1.2"
 
 static DECLARE_RWSEM(hidp_session_sem);
 static LIST_HEAD(hidp_session_list);
@@ -124,15 +125,22 @@ static void __hidp_copy_session(struct hidp_session *session, struct hidp_connin
                else
                        strncpy(ci->name, "HID Boot Device", 128);
        }
+
+       if (session->hid) {
+               ci->vendor  = session->hid->vendor;
+               ci->product = session->hid->product;
+               ci->version = session->hid->version;
+               strncpy(ci->name, session->hid->name, 128);
+       }
 }
 
-static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+static inline int hidp_queue_event(struct hidp_session *session, struct input_dev *dev,
+                                       unsigned int type, unsigned int code, int value)
 {
-       struct hidp_session *session = dev->private;
-       struct sk_buff *skb;
        unsigned char newleds;
+       struct sk_buff *skb;
 
-       BT_DBG("input %p type %d code %d value %d", dev, type, code, value);
+       BT_DBG("session %p type %d code %d value %d", session, type, code, value);
 
        if (type != EV_LED)
                return -1;
@@ -164,6 +172,21 @@ static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned i
        return 0;
 }
 
+static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+       struct hid_device *hid = dev->private;
+       struct hidp_session *session = hid->driver_data;
+
+       return hidp_queue_event(session, dev, type, code, value);
+}
+
+static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+       struct hidp_session *session = dev->private;
+
+       return hidp_queue_event(session, dev, type, code, value);
+}
+
 static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
 {
        struct input_dev *dev = session->input;
@@ -219,6 +242,42 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
        input_sync(dev);
 }
 
+static inline int hidp_queue_report(struct hidp_session *session, unsigned char *data, int size)
+{
+       struct sk_buff *skb;
+
+       BT_DBG("session %p hid %p data %p size %d", session, device, data, size);
+
+       if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) {
+               BT_ERR("Can't allocate memory for new frame");
+               return -ENOMEM;
+       }
+
+       *skb_put(skb, 1) = 0xa2;
+       if (size > 0)
+               memcpy(skb_put(skb, size), data, size);
+
+       skb_queue_tail(&session->intr_transmit, skb);
+
+       hidp_schedule(session);
+
+       return 0;
+}
+
+static int hidp_send_report(struct hidp_session *session, struct hid_report *report)
+{
+       unsigned char buf[32];
+       int rsize;
+
+       rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
+       if (rsize > sizeof(buf))
+               return -EIO;
+
+       hid_output_report(report, buf);
+
+       return hidp_queue_report(session, buf, rsize);
+}
+
 static void hidp_idle_timeout(unsigned long arg)
 {
        struct hidp_session *session = (struct hidp_session *) arg;
@@ -346,6 +405,10 @@ static inline void hidp_process_data(struct hidp_session *session, struct sk_buf
 
                if (session->input)
                        hidp_input_report(session, skb);
+
+               if (session->hid)
+                       hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0);
+
                break;
 
        case HIDP_DATA_RTYPE_OTHER:
@@ -404,8 +467,14 @@ static inline void hidp_recv_intr_frame(struct hidp_session *session, struct sk_
 
        if (hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) {
                hidp_set_timer(session);
+
                if (session->input)
                        hidp_input_report(session, skb);
+
+               if (session->hid) {
+                       hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 1);
+                       BT_DBG("report len %d", skb->len);
+               }
        } else {
                BT_DBG("Unsupported protocol header 0x%02x", hdr);
        }
@@ -471,6 +540,11 @@ static int hidp_session(void *arg)
                product = session->input->id.product;
        }
 
+       if (session->hid) {
+               vendor  = session->hid->vendor;
+               product = session->hid->product;
+       }
+
        daemonize("khidpd_%04x%04x", vendor, product);
        set_user_nice(current, -15);
        current->flags |= PF_NOFREEZE;
@@ -521,6 +595,12 @@ static int hidp_session(void *arg)
                session->input = NULL;
        }
 
+       if (session->hid) {
+               if (session->hid->claimed & HID_CLAIMED_INPUT)
+                       hidinput_disconnect(session->hid);
+               hid_free_device(session->hid);
+       }
+
        up_write(&hidp_session_sem);
 
        kfree(session);
@@ -590,6 +670,56 @@ static inline void hidp_setup_input(struct hidp_session *session, struct hidp_co
        input_register_device(input);
 }
 
+static int hidp_open(struct hid_device *hid)
+{
+       return 0;
+}
+
+static void hidp_close(struct hid_device *hid)
+{
+}
+
+static inline void hidp_setup_hid(struct hidp_session *session, struct hidp_connadd_req *req)
+{
+       struct hid_device *hid = session->hid;
+       struct hid_report *report;
+       bdaddr_t src, dst;
+
+       baswap(&src, &bt_sk(session->ctrl_sock->sk)->src);
+       baswap(&dst, &bt_sk(session->ctrl_sock->sk)->dst);
+
+       hid->driver_data = session;
+
+       hid->country = req->country;
+
+       hid->bus     = BUS_BLUETOOTH;
+       hid->vendor  = req->vendor;
+       hid->product = req->product;
+       hid->version = req->version;
+
+       strncpy(hid->name, req->name, 128);
+       strncpy(hid->phys, batostr(&src), 64);
+       strncpy(hid->uniq, batostr(&dst), 64);
+
+       hid->dev = hidp_get_device(session);
+
+       hid->hid_open  = hidp_open;
+       hid->hid_close = hidp_close;
+
+       hid->hidinput_input_event = hidp_hidinput_event;
+
+       list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
+               hidp_send_report(session, report);
+
+       list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
+               hidp_send_report(session, report);
+
+       if (hidinput_connect(hid) == 0) {
+               hid->claimed |= HID_CLAIMED_INPUT;
+               hid_ff_init(hid);
+       }
+}
+
 int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
 {
        struct hidp_session *session, *s;
@@ -605,10 +735,38 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
        if (!session)
                return -ENOMEM;
 
-       session->input = input_allocate_device();
-       if (!session->input) {
-               kfree(session);
-               return -ENOMEM;
+       BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
+
+       if (req->rd_size > 0) {
+               unsigned char *buf = kmalloc(req->rd_size, GFP_KERNEL);
+
+               if (!buf) {
+                       kfree(session);
+                       return -ENOMEM;
+               }
+
+               if (copy_from_user(buf, req->rd_data, req->rd_size)) {
+                       kfree(buf);
+                       kfree(session);
+                       return -EFAULT;
+               }
+
+               session->hid = hid_parse_report(buf, req->rd_size);
+
+               kfree(buf);
+
+               if (!session->hid) {
+                       kfree(session);
+                       return -EINVAL;
+               }
+       }
+
+       if (!session->hid) {
+               session->input = input_allocate_device();
+               if (!session->input) {
+                       kfree(session);
+                       return -ENOMEM;
+               }
        }
 
        down_write(&hidp_session_sem);
@@ -644,6 +802,9 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
        if (session->input)
                hidp_setup_input(session, req);
 
+       if (session->hid)
+               hidp_setup_hid(session, req);
+
        __hidp_link_session(session);
 
        hidp_set_timer(session);
@@ -677,6 +838,9 @@ unlink:
 failed:
        up_write(&hidp_session_sem);
 
+       if (session->hid)
+               hid_free_device(session->hid);
+
        kfree(session->input);
        kfree(session);
        return err;
index a326601..343fb05 100644 (file)
@@ -145,6 +145,8 @@ struct hidp_session {
 
        struct input_dev *input;
 
+       struct hid_device *hid;
+
        struct timer_list timer;
 
        struct sk_buff_head ctrl_transmit;
index 8b8a6c1..0c18525 100644 (file)
@@ -194,7 +194,7 @@ static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
                if (put_user(ca.ctrl_sock, &uca->ctrl_sock) ||
                                put_user(ca.intr_sock, &uca->intr_sock) ||
                                put_user(ca.parser, &uca->parser) ||
-                               put_user(ca.rd_size, &uca->parser) ||
+                               put_user(ca.rd_size, &uca->rd_size) ||
                                put_user(compat_ptr(ca.rd_data), &uca->rd_data) ||
                                put_user(ca.country, &uca->country) ||
                                put_user(ca.subclass, &uca->subclass) ||
index 8cd82dc..9a7a44f 100644 (file)
@@ -74,6 +74,8 @@ struct rfcomm_dev {
        wait_queue_head_t       wait;
        struct tasklet_struct   wakeup_task;
 
+       struct device           *tty_dev;
+
        atomic_t                wmem_alloc;
 };
 
@@ -261,7 +263,7 @@ out:
                return err;
        }
 
-       tty_register_device(rfcomm_tty_driver, dev->id, rfcomm_get_device(dev));
+       dev->tty_dev = tty_register_device(rfcomm_tty_driver, dev->id, NULL);
 
        return dev->id;
 }
@@ -630,6 +632,9 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
        set_current_state(TASK_RUNNING);
        remove_wait_queue(&dev->wait, &wait);
 
+       if (err == 0)
+               device_move(dev->tty_dev, rfcomm_get_device(dev));
+
        return err;
 }
 
@@ -642,6 +647,8 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
        BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, dev->opened);
 
        if (--dev->opened == 0) {
+               device_move(dev->tty_dev, NULL);
+
                /* Close DLC and dettach TTY */
                rfcomm_dlc_close(dev->dlc, 0);
 
index aff6a77..6845a25 100644 (file)
@@ -77,26 +77,15 @@ static int port_cost(struct net_device *dev)
  * Called from work queue to allow for calling functions that
  * might sleep (such as speed check), and to debounce.
  */
-static void port_carrier_check(struct work_struct *work)
+void br_port_carrier_check(struct net_bridge_port *p)
 {
-       struct net_bridge_port *p;
-       struct net_device *dev;
-       struct net_bridge *br;
-
-       dev = container_of(work, struct net_bridge_port,
-                          carrier_check.work)->dev;
-       work_release(work);
-
-       rtnl_lock();
-       p = dev->br_port;
-       if (!p)
-               goto done;
-       br = p->br;
+       struct net_device *dev = p->dev;
+       struct net_bridge *br = p->br;
 
        if (netif_carrier_ok(dev))
                p->path_cost = port_cost(dev);
 
-       if (br->dev->flags & IFF_UP) {
+       if (netif_running(br->dev)) {
                spin_lock_bh(&br->lock);
                if (netif_carrier_ok(dev)) {
                        if (p->state == BR_STATE_DISABLED)
@@ -107,9 +96,6 @@ static void port_carrier_check(struct work_struct *work)
                }
                spin_unlock_bh(&br->lock);
        }
-done:
-       dev_put(dev);
-       rtnl_unlock();
 }
 
 static void release_nbp(struct kobject *kobj)
@@ -162,9 +148,6 @@ static void del_nbp(struct net_bridge_port *p)
 
        dev_set_promiscuity(dev, -1);
 
-       if (cancel_delayed_work(&p->carrier_check))
-               dev_put(dev);
-
        spin_lock_bh(&br->lock);
        br_stp_disable_port(p);
        spin_unlock_bh(&br->lock);
@@ -282,7 +265,6 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
        p->port_no = index;
        br_init_port(p);
        p->state = BR_STATE_DISABLED;
-       INIT_DELAYED_WORK_NAR(&p->carrier_check, port_carrier_check);
        br_stp_port_timer_init(p);
 
        kobject_init(&p->kobj);
@@ -446,12 +428,10 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
        spin_lock_bh(&br->lock);
        br_stp_recalculate_bridge_id(br);
        br_features_recompute(br);
-       if (schedule_delayed_work(&p->carrier_check, BR_PORT_DEBOUNCE))
-               dev_hold(dev);
-
        spin_unlock_bh(&br->lock);
 
        dev_set_mtu(br->dev, br_min_mtu(br));
+
        kobject_uevent(&p->kobj, KOBJ_ADD);
 
        return 0;
index 3311c4e..37357ed 100644 (file)
@@ -42,51 +42,48 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
 
        br = p->br;
 
-       spin_lock_bh(&br->lock);
        switch (event) {
        case NETDEV_CHANGEMTU:
                dev_set_mtu(br->dev, br_min_mtu(br));
                break;
 
        case NETDEV_CHANGEADDR:
+               spin_lock_bh(&br->lock);
                br_fdb_changeaddr(p, dev->dev_addr);
                br_ifinfo_notify(RTM_NEWLINK, p);
                br_stp_recalculate_bridge_id(br);
+               spin_unlock_bh(&br->lock);
                break;
 
        case NETDEV_CHANGE:
-               if (br->dev->flags & IFF_UP)
-                       if (schedule_delayed_work(&p->carrier_check,
-                                               BR_PORT_DEBOUNCE))
-                               dev_hold(dev);
+               br_port_carrier_check(p);
                break;
 
        case NETDEV_FEAT_CHANGE:
-               if (br->dev->flags & IFF_UP)
+               spin_lock_bh(&br->lock);
+               if (netif_running(br->dev))
                        br_features_recompute(br);
-
-               /* could do recursive feature change notification
-                * but who would care??
-                */
+               spin_unlock_bh(&br->lock);
                break;
 
        case NETDEV_DOWN:
+               spin_lock_bh(&br->lock);
                if (br->dev->flags & IFF_UP)
                        br_stp_disable_port(p);
+               spin_unlock_bh(&br->lock);
                break;
 
        case NETDEV_UP:
+               spin_lock_bh(&br->lock);
                if (netif_carrier_ok(dev) && (br->dev->flags & IFF_UP))
                        br_stp_enable_port(p);
+               spin_unlock_bh(&br->lock);
                break;
 
        case NETDEV_UNREGISTER:
-               spin_unlock_bh(&br->lock);
                br_del_if(br, dev);
-               goto done;
+               break;
        }
-       spin_unlock_bh(&br->lock);
 
- done:
        return NOTIFY_DONE;
 }
index 6a0540e..cc3f1c9 100644 (file)
@@ -16,7 +16,6 @@
 #define _BR_PRIVATE_H
 
 #include <linux/netdevice.h>
-#include <linux/miscdevice.h>
 #include <linux/if_bridge.h>
 
 #define BR_HASH_BITS 8
@@ -27,8 +26,6 @@
 #define BR_PORT_BITS   10
 #define BR_MAX_PORTS   (1<<BR_PORT_BITS)
 
-#define BR_PORT_DEBOUNCE (HZ/10)
-
 #define BR_VERSION     "2.2"
 
 typedef struct bridge_id bridge_id;
@@ -82,7 +79,6 @@ struct net_bridge_port
        struct timer_list               hold_timer;
        struct timer_list               message_age_timer;
        struct kobject                  kobj;
-       struct delayed_work             carrier_check;
        struct rcu_head                 rcu;
 };
 
@@ -173,6 +169,7 @@ extern void br_flood_forward(struct net_bridge *br,
                      int clone);
 
 /* br_if.c */
+extern void br_port_carrier_check(struct net_bridge_port *p);
 extern int br_add_bridge(const char *name);
 extern int br_del_bridge(const char *name);
 extern void br_cleanup_bridges(void);
index 34c4979..ac9984f 100644 (file)
@@ -833,8 +833,7 @@ static int translate_table(char *name, struct ebt_table_info *newinfo)
                /* this will get free'd in do_replace()/ebt_register_table()
                   if an error occurs */
                newinfo->chainstack =
-                       vmalloc((highest_possible_processor_id()+1)
-                                       * sizeof(*(newinfo->chainstack)));
+                       vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
                if (!newinfo->chainstack)
                        return -ENOMEM;
                for_each_possible_cpu(i) {
@@ -947,8 +946,7 @@ static int do_replace(void __user *user, unsigned int len)
        if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
                return -ENOMEM;
 
-       countersize = COUNTER_OFFSET(tmp.nentries) *
-                                       (highest_possible_processor_id()+1);
+       countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
        newinfo = vmalloc(sizeof(*newinfo) + countersize);
        if (!newinfo)
                return -ENOMEM;
@@ -1168,8 +1166,7 @@ int ebt_register_table(struct ebt_table *table)
                return -EINVAL;
        }
 
-       countersize = COUNTER_OFFSET(repl->nentries) *
-                                       (highest_possible_processor_id()+1);
+       countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
        newinfo = vmalloc(sizeof(*newinfo) + countersize);
        ret = -ENOMEM;
        if (!newinfo)
index 91f3a5c..9e8ef50 100644 (file)
@@ -442,7 +442,7 @@ config INET_DIAG
        ---help---
          Support for INET (TCP, DCCP, etc) socket monitoring interface used by
          native Linux tools such as ss. ss is included in iproute2, currently
-         downloadable at <http://developer.osdl.org/dev/iproute2>. 
+         downloadable at <http://linux-net.osdl.org/index.php/Iproute2>.
          
          If unsure, say Y.
 
@@ -550,7 +550,7 @@ config TCP_CONG_SCALABLE
        Scalable TCP is a sender-side only change to TCP which uses a
        MIMD congestion control algorithm which has some nice scaling
        properties, though is known to have fairness issues.
-       See http://www-lce.eng.cam.ac.uk/~ctk21/scalable/
+       See http://www.deneholme.net/tom/scalable/
 
 config TCP_CONG_LP
        tristate "TCP Low Priority"
index 8a0ec10..e10794d 100644 (file)
@@ -1054,12 +1054,14 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
        ASSERT_RTNL();
 
        if (!in_dev) {
-               if (event == NETDEV_REGISTER && dev == &loopback_dev) {
+               if (event == NETDEV_REGISTER) {
                        in_dev = inetdev_init(dev);
                        if (!in_dev)
                                panic("devinet: Failed to create loopback\n");
-                       in_dev->cnf.no_xfrm = 1;
-                       in_dev->cnf.no_policy = 1;
+                       if (dev == &loopback_dev) {
+                               in_dev->cnf.no_xfrm = 1;
+                               in_dev->cnf.no_policy = 1;
+                       }
                }
                goto out;
        }
index 57f4814..c312785 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/module.h>
 #include <linux/mroute.h>
 #include <linux/init.h>
+#include <linux/random.h>
 #include <net/ip.h>
 #include <net/protocol.h>
 #include <linux/skbuff.h>
 
 #define MULTIPATH_MAX_CANDIDATES 40
 
-/* interface to random number generation */
-static unsigned int RANDOM_SEED = 93186752;
-
-static inline unsigned int random(unsigned int ubound)
-{
-       static unsigned int a = 1588635695,
-               q = 2,
-               r = 1117695901;
-
-       RANDOM_SEED = a*(RANDOM_SEED % q) - r*(RANDOM_SEED / q);
-
-       return RANDOM_SEED % ubound;
-}
-
-
 static void random_select_route(const struct flowi *flp,
                                struct rtable *first,
                                struct rtable **rp)
@@ -84,7 +70,7 @@ static void random_select_route(const struct flowi *flp,
        if (candidate_count > 1) {
                unsigned char i = 0;
                unsigned char candidate_no = (unsigned char)
-                       random(candidate_count);
+                       (random32() % candidate_count);
 
                /* find chosen candidate and adjust GC data for all candidates
                 * to ensure they stay in cache
index 2bdbb92..57c5036 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/module.h>
 #include <linux/mroute.h>
 #include <linux/init.h>
+#include <linux/random.h>
 #include <net/ip.h>
 #include <net/protocol.h>
 #include <linux/skbuff.h>
@@ -84,18 +85,6 @@ struct multipath_route {
 /* state: primarily weight per route information */
 static struct multipath_bucket state[MULTIPATH_STATE_SIZE];
 
-/* interface to random number generation */
-static unsigned int RANDOM_SEED = 93186752;
-
-static inline unsigned int random(unsigned int ubound)
-{
-       static unsigned int a = 1588635695,
-               q = 2,
-               r = 1117695901;
-       RANDOM_SEED = a*(RANDOM_SEED % q) - r*(RANDOM_SEED / q);
-       return RANDOM_SEED % ubound;
-}
-
 static unsigned char __multipath_lookup_weight(const struct flowi *fl,
                                               const struct rtable *rt)
 {
@@ -193,7 +182,7 @@ static void wrandom_select_route(const struct flowi *flp,
 
        /* choose a weighted random candidate */
        decision = first;
-       selector = random(power);
+       selector = random32() % power;
        last_power = 0;
 
        /* select candidate, adjust GC data and cleanup local state */
index ac6516c..74c4d10 100644 (file)
@@ -2266,12 +2266,12 @@ void tcp_free_md5sig_pool(void)
 {
        struct tcp_md5sig_pool **pool = NULL;
 
-       spin_lock(&tcp_md5sig_pool_lock);
+       spin_lock_bh(&tcp_md5sig_pool_lock);
        if (--tcp_md5sig_users == 0) {
                pool = tcp_md5sig_pool;
                tcp_md5sig_pool = NULL;
        }
-       spin_unlock(&tcp_md5sig_pool_lock);
+       spin_unlock_bh(&tcp_md5sig_pool_lock);
        if (pool)
                __tcp_free_md5sig_pool(pool);
 }
@@ -2314,36 +2314,36 @@ struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(void)
        int alloc = 0;
 
 retry:
-       spin_lock(&tcp_md5sig_pool_lock);
+       spin_lock_bh(&tcp_md5sig_pool_lock);
        pool = tcp_md5sig_pool;
        if (tcp_md5sig_users++ == 0) {
                alloc = 1;
-               spin_unlock(&tcp_md5sig_pool_lock);
+               spin_unlock_bh(&tcp_md5sig_pool_lock);
        } else if (!pool) {
                tcp_md5sig_users--;
-               spin_unlock(&tcp_md5sig_pool_lock);
+               spin_unlock_bh(&tcp_md5sig_pool_lock);
                cpu_relax();
                goto retry;
        } else
-               spin_unlock(&tcp_md5sig_pool_lock);
+               spin_unlock_bh(&tcp_md5sig_pool_lock);
 
        if (alloc) {
                /* we cannot hold spinlock here because this may sleep. */
                struct tcp_md5sig_pool **p = __tcp_alloc_md5sig_pool();
-               spin_lock(&tcp_md5sig_pool_lock);
+               spin_lock_bh(&tcp_md5sig_pool_lock);
                if (!p) {
                        tcp_md5sig_users--;
-                       spin_unlock(&tcp_md5sig_pool_lock);
+                       spin_unlock_bh(&tcp_md5sig_pool_lock);
                        return NULL;
                }
                pool = tcp_md5sig_pool;
                if (pool) {
                        /* oops, it has already been assigned. */
-                       spin_unlock(&tcp_md5sig_pool_lock);
+                       spin_unlock_bh(&tcp_md5sig_pool_lock);
                        __tcp_free_md5sig_pool(p);
                } else {
                        tcp_md5sig_pool = pool = p;
-                       spin_unlock(&tcp_md5sig_pool_lock);
+                       spin_unlock_bh(&tcp_md5sig_pool_lock);
                }
        }
        return pool;
@@ -2354,11 +2354,11 @@ EXPORT_SYMBOL(tcp_alloc_md5sig_pool);
 struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu)
 {
        struct tcp_md5sig_pool **p;
-       spin_lock(&tcp_md5sig_pool_lock);
+       spin_lock_bh(&tcp_md5sig_pool_lock);
        p = tcp_md5sig_pool;
        if (p)
                tcp_md5sig_users++;
-       spin_unlock(&tcp_md5sig_pool_lock);
+       spin_unlock_bh(&tcp_md5sig_pool_lock);
        return (p ? *per_cpu_ptr(p, cpu) : NULL);
 }
 
index e1cab33..ceb4376 100644 (file)
@@ -111,6 +111,7 @@ static int xfrm4_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
            (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
                goto out;
 
+       iph = skb->nh.iph;
        if (iph->protocol == IPPROTO_IPIP) {
                if (x->props.flags & XFRM_STATE_DECAP_DSCP)
                        ipv4_copy_dscp(iph, skb->h.ipiph);
index fef19c6..5d51a2a 100644 (file)
@@ -291,7 +291,7 @@ static void xfrm4_dst_destroy(struct dst_entry *dst)
 
        if (likely(xdst->u.rt.idev))
                in_dev_put(xdst->u.rt.idev);
-       if (dst->xfrm->props.family == AF_INET && likely(xdst->u.rt.peer))
+       if (dst->xfrm && dst->xfrm->props.family == AF_INET && likely(xdst->u.rt.peer))
                inet_putpeer(xdst->u.rt.peer);
        xfrm_dst_destroy(xdst);
 }
index 8bacda1..d460017 100644 (file)
@@ -32,6 +32,6 @@ obj-$(CONFIG_NETFILTER)       += netfilter/
 obj-$(CONFIG_IPV6_SIT) += sit.o
 obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
 
-obj-y += exthdrs_core.o
+obj-y += addrconf_core.o exthdrs_core.o
 
 obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o
index 569a37d..f6ac65d 100644 (file)
@@ -211,74 +211,6 @@ const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
 #endif
 const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
 
-#define IPV6_ADDR_SCOPE_TYPE(scope)    ((scope) << 16)
-
-static inline unsigned ipv6_addr_scope2type(unsigned scope)
-{
-       switch(scope) {
-       case IPV6_ADDR_SCOPE_NODELOCAL:
-               return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) |
-                       IPV6_ADDR_LOOPBACK);
-       case IPV6_ADDR_SCOPE_LINKLOCAL:
-               return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) |
-                       IPV6_ADDR_LINKLOCAL);
-       case IPV6_ADDR_SCOPE_SITELOCAL:
-               return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) |
-                       IPV6_ADDR_SITELOCAL);
-       }
-       return IPV6_ADDR_SCOPE_TYPE(scope);
-}
-
-int __ipv6_addr_type(const struct in6_addr *addr)
-{
-       __be32 st;
-
-       st = addr->s6_addr32[0];
-
-       /* Consider all addresses with the first three bits different of
-          000 and 111 as unicasts.
-        */
-       if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
-           (st & htonl(0xE0000000)) != htonl(0xE0000000))
-               return (IPV6_ADDR_UNICAST |
-                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
-
-       if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
-               /* multicast */
-               /* addr-select 3.1 */
-               return (IPV6_ADDR_MULTICAST |
-                       ipv6_addr_scope2type(IPV6_ADDR_MC_SCOPE(addr)));
-       }
-
-       if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
-               return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST |
-                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));               /* addr-select 3.1 */
-       if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000))
-               return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST |
-                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL));               /* addr-select 3.1 */
-
-       if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
-               if (addr->s6_addr32[2] == 0) {
-                       if (addr->s6_addr32[3] == 0)
-                               return IPV6_ADDR_ANY;
-
-                       if (addr->s6_addr32[3] == htonl(0x00000001))
-                               return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST |
-                                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));       /* addr-select 3.4 */
-
-                       return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST |
-                               IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.3 */
-               }
-
-               if (addr->s6_addr32[2] == htonl(0x0000ffff))
-                       return (IPV6_ADDR_MAPPED |
-                               IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.3 */
-       }
-
-       return (IPV6_ADDR_RESERVED |
-               IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.4 */
-}
-
 static void addrconf_del_timer(struct inet6_ifaddr *ifp)
 {
        if (del_timer(&ifp->timer))
@@ -1910,6 +1842,7 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
        struct inet6_dev *idev;
        struct net_device *dev;
        int scope;
+       u32 flags = RTF_EXPIRES;
 
        ASSERT_RTNL();
 
@@ -1925,9 +1858,10 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
 
        scope = ipv6_addr_scope(pfx);
 
-       if (valid_lft == INFINITY_LIFE_TIME)
+       if (valid_lft == INFINITY_LIFE_TIME) {
                ifa_flags |= IFA_F_PERMANENT;
-       else if (valid_lft >= 0x7FFFFFFF/HZ)
+               flags = 0;
+       } else if (valid_lft >= 0x7FFFFFFF/HZ)
                valid_lft = 0x7FFFFFFF/HZ;
 
        if (prefered_lft == 0)
@@ -1945,6 +1879,8 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
                ifp->tstamp = jiffies;
                spin_unlock_bh(&ifp->lock);
 
+               addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,
+                                     jiffies_to_clock_t(valid_lft * HZ), flags);
                addrconf_dad_start(ifp, 0);
                in6_ifa_put(ifp);
                addrconf_verify(0);
@@ -2124,6 +2060,7 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr
 
        ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT);
        if (!IS_ERR(ifp)) {
+               addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0);
                addrconf_dad_start(ifp, 0);
                in6_ifa_put(ifp);
        }
@@ -2240,6 +2177,14 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
        int run_pending = 0;
 
        switch(event) {
+       case NETDEV_REGISTER:
+               if (!idev) {
+                       idev = ipv6_add_dev(dev);
+                       if (!idev)
+                               printk(KERN_WARNING "IPv6: add_dev failed for %s\n",
+                                       dev->name);
+               }
+               break;
        case NETDEV_UP:
        case NETDEV_CHANGE:
                if (event == NETDEV_UP) {
@@ -2538,10 +2483,6 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
 
        addrconf_join_solict(dev, &ifp->addr);
 
-       if (ifp->prefix_len != 128 && (ifp->flags&IFA_F_PERMANENT))
-               addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, 0,
-                                       flags);
-
        net_srandom(ifp->addr.s6_addr32[3]);
 
        read_lock_bh(&idev->lock);
@@ -2972,12 +2913,15 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
                             u32 prefered_lft, u32 valid_lft)
 {
+       u32 flags = RTF_EXPIRES;
+
        if (!valid_lft || (prefered_lft > valid_lft))
                return -EINVAL;
 
-       if (valid_lft == INFINITY_LIFE_TIME)
+       if (valid_lft == INFINITY_LIFE_TIME) {
                ifa_flags |= IFA_F_PERMANENT;
-       else if (valid_lft >= 0x7FFFFFFF/HZ)
+               flags = 0;
+       } else if (valid_lft >= 0x7FFFFFFF/HZ)
                valid_lft = 0x7FFFFFFF/HZ;
 
        if (prefered_lft == 0)
@@ -2996,6 +2940,8 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
        if (!(ifp->flags&IFA_F_TENTATIVE))
                ipv6_ifa_notify(0, ifp);
 
+       addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev,
+                             jiffies_to_clock_t(valid_lft * HZ), flags);
        addrconf_verify(0);
 
        return 0;
diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c
new file mode 100644 (file)
index 0000000..faaefb6
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * IPv6 library code, needed by static components when full IPv6 support is
+ * not configured or static.
+ */
+
+#include <net/ipv6.h>
+
+#define IPV6_ADDR_SCOPE_TYPE(scope)    ((scope) << 16)
+
+static inline unsigned ipv6_addr_scope2type(unsigned scope)
+{
+       switch(scope) {
+       case IPV6_ADDR_SCOPE_NODELOCAL:
+               return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) |
+                       IPV6_ADDR_LOOPBACK);
+       case IPV6_ADDR_SCOPE_LINKLOCAL:
+               return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) |
+                       IPV6_ADDR_LINKLOCAL);
+       case IPV6_ADDR_SCOPE_SITELOCAL:
+               return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) |
+                       IPV6_ADDR_SITELOCAL);
+       }
+       return IPV6_ADDR_SCOPE_TYPE(scope);
+}
+
+int __ipv6_addr_type(const struct in6_addr *addr)
+{
+       __be32 st;
+
+       st = addr->s6_addr32[0];
+
+       /* Consider all addresses with the first three bits different of
+          000 and 111 as unicasts.
+        */
+       if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
+           (st & htonl(0xE0000000)) != htonl(0xE0000000))
+               return (IPV6_ADDR_UNICAST |
+                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
+
+       if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
+               /* multicast */
+               /* addr-select 3.1 */
+               return (IPV6_ADDR_MULTICAST |
+                       ipv6_addr_scope2type(IPV6_ADDR_MC_SCOPE(addr)));
+       }
+
+       if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
+               return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST |
+                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));               /* addr-select 3.1 */
+       if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000))
+               return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST |
+                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL));               /* addr-select 3.1 */
+
+       if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
+               if (addr->s6_addr32[2] == 0) {
+                       if (addr->s6_addr32[3] == 0)
+                               return IPV6_ADDR_ANY;
+
+                       if (addr->s6_addr32[3] == htonl(0x00000001))
+                               return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST |
+                                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));       /* addr-select 3.4 */
+
+                       return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST |
+                               IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.3 */
+               }
+
+               if (addr->s6_addr32[2] == htonl(0x0000ffff))
+                       return (IPV6_ADDR_MAPPED |
+                               IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.3 */
+       }
+
+       return (IPV6_ADDR_RESERVED |
+               IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.4 */
+}
+EXPORT_SYMBOL(__ipv6_addr_type);
+
index 3585d8f..5cac14a 100644 (file)
@@ -929,25 +929,28 @@ static void __exit inet6_exit(void)
 {
        /* First of all disallow new sockets creation. */
        sock_unregister(PF_INET6);
+
+       /* Cleanup code parts. */
+       ipv6_packet_cleanup();
+#ifdef CONFIG_IPV6_MIP6
+       mip6_fini();
+#endif
+       addrconf_cleanup();
+       ip6_flowlabel_cleanup();
+       ip6_route_cleanup();
 #ifdef CONFIG_PROC_FS
+
+       /* Cleanup code parts. */
        if6_proc_exit();
        ac6_proc_exit();
        ipv6_misc_proc_exit();
-       udp6_proc_exit();
        udplite6_proc_exit();
+       udp6_proc_exit();
        tcp6_proc_exit();
        raw6_proc_exit();
 #endif
-#ifdef CONFIG_IPV6_MIP6
-       mip6_fini();
-#endif
-       /* Cleanup code parts. */
-       ip6_flowlabel_cleanup();
-       addrconf_cleanup();
-       ip6_route_cleanup();
-       ipv6_packet_cleanup();
-       igmp6_cleanup();
        ipv6_netfilter_fini();
+       igmp6_cleanup();
        ndisc_cleanup();
        icmpv6_cleanup();
 #ifdef CONFIG_SYSCTL
@@ -955,6 +958,7 @@ static void __exit inet6_exit(void)
 #endif
        cleanup_ipv6_mibs();
        proto_unregister(&rawv6_prot);
+       proto_unregister(&udplitev6_prot);
        proto_unregister(&udpv6_prot);
        proto_unregister(&tcpv6_prot);
 }
index 662edb8..08d9442 100644 (file)
@@ -727,11 +727,8 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
        }
        if (mtu < IPV6_MIN_MTU)
                mtu = IPV6_MIN_MTU;
-       if (skb->dst && mtu < dst_mtu(skb->dst)) {
-               struct rt6_info *rt = (struct rt6_info *) skb->dst;
-               rt->rt6i_flags |= RTF_MODIFIED;
-               rt->u.dst.metrics[RTAX_MTU-1] = mtu;
-       }
+       if (skb->dst)
+               skb->dst->ops->update_pmtu(skb->dst, mtu);
        if (skb->len > mtu) {
                icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
                goto tx_err_dst_release;
index 0e8e067..e12e3d4 100644 (file)
@@ -6,7 +6,6 @@
 #include <net/ip6_route.h>
 #include <net/xfrm.h>
 
-EXPORT_SYMBOL(__ipv6_addr_type);
 EXPORT_SYMBOL(icmpv6_send);
 EXPORT_SYMBOL(icmpv6_statistics);
 EXPORT_SYMBOL(icmpv6_err_convert);
index b1133f2..d8a585b 100644 (file)
@@ -189,7 +189,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
                        case AF_INET6:
                                ipv6_addr_copy(&fl_tunnel.fl6_dst, __xfrm6_bundle_addr_remote(xfrm[i], &fl->fl6_dst));
 
-                               ipv6_addr_copy(&fl_tunnel.fl6_src, __xfrm6_bundle_addr_remote(xfrm[i], &fl->fl6_src));
+                               ipv6_addr_copy(&fl_tunnel.fl6_src, __xfrm6_bundle_addr_local(xfrm[i], &fl->fl6_src));
                                break;
                        default:
                                BUG_ON(1);
index 826e6c4..c7fad2c 100644 (file)
 #include <net/irda/irttp.h>            /* irttp_init */
 #include <net/irda/irda_device.h>      /* irda_device_init */
 
-/* irproc.c */
-extern void irda_proc_register(void);
-extern void irda_proc_unregister(void);
-/* irsysctl.c */
-extern int  irda_sysctl_register(void);
-extern void irda_sysctl_unregister(void);
-/* af_irda.c */
-extern int  irsock_init(void);
-extern void irsock_cleanup(void);
-/* irlap_frame.c */
-extern int  irlap_driver_rcv(struct sk_buff *, struct net_device *,
-                            struct packet_type *, struct net_device *);
-
 /*
  * Module parameters
  */
index bf26990..28d47e8 100644 (file)
@@ -227,17 +227,14 @@ struct packet_skb_cb {
 
 #ifdef CONFIG_PACKET_MMAP
 
-static inline char *packet_lookup_frame(struct packet_sock *po, unsigned int position)
+static inline struct tpacket_hdr *packet_lookup_frame(struct packet_sock *po, unsigned int position)
 {
        unsigned int pg_vec_pos, frame_offset;
-       char *frame;
 
        pg_vec_pos = position / po->frames_per_block;
        frame_offset = position % po->frames_per_block;
 
-       frame = po->pg_vec[pg_vec_pos] + (frame_offset * po->frame_size);
-
-       return frame;
+       return (struct tpacket_hdr *)(po->pg_vec[pg_vec_pos] + (frame_offset * po->frame_size));
 }
 #endif
 
@@ -639,7 +636,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
        }
 
        spin_lock(&sk->sk_receive_queue.lock);
-       h = (struct tpacket_hdr *)packet_lookup_frame(po, po->head);
+       h = packet_lookup_frame(po, po->head);
 
        if (h->tp_status)
                goto ring_is_full;
@@ -1473,7 +1470,7 @@ static int packet_notifier(struct notifier_block *this, unsigned long msg, void
 {
        struct sock *sk;
        struct hlist_node *node;
-       struct net_device *dev = (struct net_device*)data;
+       struct net_device *dev = data;
 
        read_lock(&packet_sklist_lock);
        sk_for_each(sk, node, &packet_sklist) {
@@ -1588,7 +1585,7 @@ static unsigned int packet_poll(struct file * file, struct socket *sock,
                unsigned last = po->head ? po->head-1 : po->frame_max;
                struct tpacket_hdr *h;
 
-               h = (struct tpacket_hdr *)packet_lookup_frame(po, last);
+               h = packet_lookup_frame(po, last);
 
                if (h->tp_status)
                        mask |= POLLIN | POLLRDNORM;
index 5c2ddd1..41abfd1 100644 (file)
@@ -396,6 +396,19 @@ void sctp_retransmit_mark(struct sctp_outq *q,
                if (sctp_chunk_abandoned(chunk)) {
                        list_del_init(lchunk);
                        sctp_insert_list(&q->abandoned, lchunk);
+
+                       /* If this chunk has not been previousely acked,
+                        * stop considering it 'outstanding'.  Our peer
+                        * will most likely never see it since it will
+                        * not be retransmitted
+                        */
+                       if (!chunk->tsn_gap_acked) {
+                               chunk->transport->flight_size -=
+                                               sctp_data_size(chunk);
+                               q->outstanding_bytes -= sctp_data_size(chunk);
+                               q->asoc->peer.rwnd += (sctp_data_size(chunk) +
+                                                       sizeof(struct sk_buff));
+                       }
                        continue;
                }
 
@@ -1244,6 +1257,15 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                if (sctp_chunk_abandoned(tchunk)) {
                        /* Move the chunk to abandoned list. */
                        sctp_insert_list(&q->abandoned, lchunk);
+
+                       /* If this chunk has not been acked, stop
+                        * considering it as 'outstanding'.
+                        */
+                       if (!tchunk->tsn_gap_acked) {
+                               tchunk->transport->flight_size -=
+                                               sctp_data_size(tchunk);
+                               q->outstanding_bytes -= sctp_data_size(tchunk);
+                       }
                        continue;
                }
 
@@ -1695,11 +1717,6 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
                 */
                if (TSN_lte(tsn, ctsn)) {
                        list_del_init(lchunk);
-                       if (!chunk->tsn_gap_acked) {
-                               chunk->transport->flight_size -=
-                                       sctp_data_size(chunk);
-                               q->outstanding_bytes -= sctp_data_size(chunk);
-                       }
                        sctp_chunk_free(chunk);
                } else {
                        if (TSN_lte(tsn, asoc->adv_peer_ack_point+1)) {
index b3cad8a..70c39ea 100644 (file)
@@ -4605,12 +4605,12 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep,
         * sent as soon as cwnd allows (normally when a SACK arrives).
         */
 
-       /* NB: Rules E4 and F1 are implicit in R1.  */
-       sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, SCTP_TRANSPORT(transport));
-
        /* Do some failure management (Section 8.2). */
        sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, SCTP_TRANSPORT(transport));
 
+       /* NB: Rules E4 and F1 are implicit in R1.  */
+       sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, SCTP_TRANSPORT(transport));
+
        return SCTP_DISPOSITION_CONSUME;
 }
 
index 4ab1374..8353829 100644 (file)
@@ -115,7 +115,7 @@ fail:
 static int
 svc_pool_map_init_percpu(struct svc_pool_map *m)
 {
-       unsigned int maxpools = highest_possible_processor_id()+1;
+       unsigned int maxpools = nr_cpu_ids;
        unsigned int pidx = 0;
        unsigned int cpu;
        int err;
@@ -143,7 +143,7 @@ svc_pool_map_init_percpu(struct svc_pool_map *m)
 static int
 svc_pool_map_init_pernode(struct svc_pool_map *m)
 {
-       unsigned int maxpools = highest_possible_node_id()+1;
+       unsigned int maxpools = nr_node_ids;
        unsigned int pidx = 0;
        unsigned int node;
        int err;
index 4d928b8..fb43c64 100755 (executable)
@@ -452,7 +452,7 @@ sub output_struct_html(%) {
     my %args = %{$_[0]};
     my ($parameter);
 
-    print "<h2>".$args{'type'}." ".$args{'struct'}."</h2>\n";
+    print "<h2>".$args{'type'}." ".$args{'struct'}. " - " .$args{'purpose'}."</h2>\n";
     print "<b>".$args{'type'}." ".$args{'struct'}."</b> {<br>\n";
     foreach $parameter (@{$args{'parameterlist'}}) {
        if ($parameter =~ /^#/) {
@@ -498,8 +498,8 @@ sub output_function_html(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
     my $count;
-    print "<h2>Function</h2>\n";
 
+    print "<h2>" .$args{'function'}." - ".$args{'purpose'}."</h2>\n";
     print "<i>".$args{'functiontype'}."</i>\n";
     print "<b>".$args{'function'}."</b>\n";
     print "(";
index f61c9cc..b2f73ff 100644 (file)
@@ -452,6 +452,24 @@ static int do_eisa_entry(const char *filename, struct eisa_device_id *eisa,
        return 1;
 }
 
+/* Looks like: parisc:tNhvNrevNsvN */
+static int do_parisc_entry(const char *filename, struct parisc_device_id *id,
+               char *alias)
+{
+       id->hw_type = TO_NATIVE(id->hw_type);
+       id->hversion = TO_NATIVE(id->hversion);
+       id->hversion_rev = TO_NATIVE(id->hversion_rev);
+       id->sversion = TO_NATIVE(id->sversion);
+
+       strcpy(alias, "parisc:");
+       ADD(alias, "t", id->hw_type != PA_HWTYPE_ANY_ID, id->hw_type);
+       ADD(alias, "hv", id->hversion != PA_HVERSION_ANY_ID, id->hversion);
+       ADD(alias, "rev", id->hversion_rev != PA_HVERSION_REV_ANY_ID, id->hversion_rev);
+       ADD(alias, "sv", id->sversion != PA_SVERSION_ANY_ID, id->sversion);
+
+       return 1;
+}
+
 /* Ignore any prefix, eg. v850 prepends _ */
 static inline int sym_is(const char *symbol, const char *name)
 {
@@ -559,6 +577,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
                do_table(symval, sym->st_size,
                         sizeof(struct eisa_device_id), "eisa",
                         do_eisa_entry, mod);
+       else if (sym_is(symname, "__mod_parisc_device_table"))
+               do_table(symval, sym->st_size,
+                        sizeof(struct parisc_device_id), "parisc",
+                        do_parisc_entry, mod);
 }
 
 /* Now add out buffered information to the generated C source */
index 569e684..65bdfdb 100644 (file)
@@ -686,6 +686,30 @@ static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf_Addr addr,
        return NULL;
 }
 
+static inline int is_arm_mapping_symbol(const char *str)
+{
+       return str[0] == '$' && strchr("atd", str[1])
+              && (str[2] == '\0' || str[2] == '.');
+}
+
+/*
+ * If there's no name there, ignore it; likewise, ignore it if it's
+ * one of the magic symbols emitted used by current ARM tools.
+ *
+ * Otherwise if find_symbols_between() returns those symbols, they'll
+ * fail the whitelist tests and cause lots of false alarms ... fixable
+ * only by merging __exit and __init sections into __text, bloating
+ * the kernel (which is especially evil on embedded platforms).
+ */
+static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
+{
+       const char *name = elf->strtab + sym->st_name;
+
+       if (!name || !strlen(name))
+               return 0;
+       return !is_arm_mapping_symbol(name);
+}
+
 /*
  * Find symbols before or equal addr and after addr - in the section sec.
  * If we find two symbols with equal offset prefer one with a valid name.
@@ -714,16 +738,15 @@ static void find_symbols_between(struct elf_info *elf, Elf_Addr addr,
                symsec = secstrings + elf->sechdrs[sym->st_shndx].sh_name;
                if (strcmp(symsec, sec) != 0)
                        continue;
+               if (!is_valid_name(elf, sym))
+                       continue;
                if (sym->st_value <= addr) {
                        if ((addr - sym->st_value) < beforediff) {
                                beforediff = addr - sym->st_value;
                                *before = sym;
                        }
                        else if ((addr - sym->st_value) == beforediff) {
-                               /* equal offset, valid name? */
-                               const char *name = elf->strtab + sym->st_name;
-                               if (name && strlen(name))
-                                       *before = sym;
+                               *before = sym;
                        }
                }
                else
@@ -733,10 +756,7 @@ static void find_symbols_between(struct elf_info *elf, Elf_Addr addr,
                                *after = sym;
                        }
                        else if ((sym->st_value - addr) == afterdiff) {
-                               /* equal offset, valid name? */
-                               const char *name = elf->strtab + sym->st_name;
-                               if (name && strlen(name))
-                                       *after = sym;
+                               *after = sym;
                        }
                }
        }
@@ -941,7 +961,7 @@ static int init_section_ref_ok(const char *name)
                ".opd",   /* see comment [OPD] at exit_section_ref_ok() */
                ".toc1",  /* used by ppc64 */
                ".stab",
-               ".rodata",
+               ".data.rel.ro", /* used by parisc64 */
                ".parainstructions",
                ".text.lock",
                "__bug_table", /* used by powerpc for BUG() */
@@ -964,6 +984,7 @@ static int init_section_ref_ok(const char *name)
                ".eh_frame",
                ".debug",
                ".parainstructions",
+               ".rodata",
                NULL
        };
        /* part of section name */
index b1ac22d..19a385e 100644 (file)
@@ -653,11 +653,11 @@ static int superblock_doinit(struct super_block *sb, void *data)
        sbsec->initialized = 1;
 
        if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) {
-               printk(KERN_INFO "SELinux: initialized (dev %s, type %s), unknown behavior\n",
+               printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
                       sb->s_id, sb->s_type->name);
        }
        else {
-               printk(KERN_INFO "SELinux: initialized (dev %s, type %s), %s\n",
+               printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
                       sb->s_id, sb->s_type->name,
                       labeling_behaviors[sbsec->behavior-1]);
        }
@@ -4434,7 +4434,7 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
 static int selinux_register_security (const char *name, struct security_operations *ops)
 {
        if (secondary_ops != original_ops) {
-               printk(KERN_INFO "%s:  There is already a secondary security "
+               printk(KERN_ERR "%s:  There is already a secondary security "
                       "module registered.\n", __FUNCTION__);
                return -EINVAL;
        }
@@ -4451,7 +4451,7 @@ static int selinux_register_security (const char *name, struct security_operatio
 static int selinux_unregister_security (const char *name, struct security_operations *ops)
 {
        if (ops != secondary_ops) {
-               printk (KERN_INFO "%s:  trying to unregister a security module "
+               printk(KERN_ERR "%s:  trying to unregister a security module "
                        "that is not registered.\n", __FUNCTION__);
                return -EINVAL;
        }
@@ -4889,9 +4889,9 @@ static __init int selinux_init(void)
                panic("SELinux: Unable to register with kernel.\n");
 
        if (selinux_enforcing) {
-               printk(KERN_INFO "SELinux:  Starting in enforcing mode\n");
+               printk(KERN_DEBUG "SELinux:  Starting in enforcing mode\n");
        } else {
-               printk(KERN_INFO "SELinux:  Starting in permissive mode\n");
+               printk(KERN_DEBUG "SELinux:  Starting in permissive mode\n");
        }
 
 #ifdef CONFIG_KEYS
@@ -4907,10 +4907,10 @@ static __init int selinux_init(void)
 
 void selinux_complete_init(void)
 {
-       printk(KERN_INFO "SELinux:  Completing initialization.\n");
+       printk(KERN_DEBUG "SELinux:  Completing initialization.\n");
 
        /* Set up any superblocks initialized prior to the policy load. */
-       printk(KERN_INFO "SELinux:  Setting up existing superblocks.\n");
+       printk(KERN_DEBUG "SELinux:  Setting up existing superblocks.\n");
        spin_lock(&sb_lock);
        spin_lock(&sb_security_lock);
 next_sb:
@@ -4968,9 +4968,9 @@ static int __init selinux_nf_ip_init(void)
 
        if (!selinux_enabled)
                goto out;
-               
-       printk(KERN_INFO "SELinux:  Registering netfilter hooks\n");
-       
+
+       printk(KERN_DEBUG "SELinux:  Registering netfilter hooks\n");
+
        err = nf_register_hook(&selinux_ipv4_op);
        if (err)
                panic("SELinux: nf_register_hook for IPv4: error %d\n", err);
@@ -4992,7 +4992,7 @@ __initcall(selinux_nf_ip_init);
 #ifdef CONFIG_SECURITY_SELINUX_DISABLE
 static void selinux_nf_ip_exit(void)
 {
-       printk(KERN_INFO "SELinux:  Unregistering netfilter hooks\n");
+       printk(KERN_DEBUG "SELinux:  Unregistering netfilter hooks\n");
 
        nf_unregister_hook(&selinux_ipv4_op);
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
index 9142073..3122908 100644 (file)
@@ -277,7 +277,7 @@ void avtab_hash_eval(struct avtab *h, char *tag)
                }
        }
 
-       printk(KERN_INFO "%s:  %d entries and %d/%d buckets used, longest "
+       printk(KERN_DEBUG "%s:  %d entries and %d/%d buckets used, longest "
               "chain length %d\n", tag, h->nel, slots_used, AVTAB_SIZE,
               max_chain_len);
 }
index cd79c63..0ac1021 100644 (file)
@@ -374,7 +374,7 @@ static void symtab_hash_eval(struct symtab *s)
                struct hashtab_info info;
 
                hashtab_stat(h, &info);
-               printk(KERN_INFO "%s:  %d entries and %d/%d buckets used, "
+               printk(KERN_DEBUG "%s:  %d entries and %d/%d buckets used, "
                       "longest chain length %d\n", symtab_name[i], h->nel,
                       info.slots_used, h->size, info.max_chain_len);
        }
@@ -391,14 +391,14 @@ static int policydb_index_others(struct policydb *p)
 {
        int i, rc = 0;
 
-       printk(KERN_INFO "security:  %d users, %d roles, %d types, %d bools",
+       printk(KERN_DEBUG "security:  %d users, %d roles, %d types, %d bools",
               p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim);
        if (selinux_mls_enabled)
                printk(", %d sens, %d cats", p->p_levels.nprim,
                       p->p_cats.nprim);
        printk("\n");
 
-       printk(KERN_INFO "security:  %d classes, %d rules\n",
+       printk(KERN_DEBUG "security:  %d classes, %d rules\n",
               p->p_classes.nprim, p->te_avtab.nel);
 
 #ifdef DEBUG_HASHES
index ca9154d..1e52356 100644 (file)
@@ -609,6 +609,9 @@ int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
        struct context *context;
        int rc = 0;
 
+       *scontext = NULL;
+       *scontext_len  = 0;
+
        if (!ss_initialized) {
                if (sid <= SECINITSID_NUM) {
                        char *scontextp;
index d78f9ff..53a54a7 100644 (file)
@@ -253,7 +253,7 @@ void sidtab_hash_eval(struct sidtab *h, char *tag)
                }
        }
 
-       printk(KERN_INFO "%s:  %d entries and %d/%d buckets used, longest "
+       printk(KERN_DEBUG "%s:  %d entries and %d/%d buckets used, longest "
               "chain length %d\n", tag, h->nel, slots_used, SIDTAB_SIZE,
               max_chain_len);
 }
index cf60333..ff705c6 100644 (file)
@@ -854,7 +854,7 @@ static struct snd_kcontrol_new snd_harmony_controls[] = {
                       HARMONY_GAIN_HE_SHIFT, 1, 0),
 };
 
-static void __init 
+static void __devinit
 snd_harmony_mixer_reset(struct snd_harmony *h)
 {
        harmony_mute(h);
@@ -863,7 +863,7 @@ snd_harmony_mixer_reset(struct snd_harmony *h)
        harmony_unmute(h);
 }
 
-static int __init 
+static int __devinit
 snd_harmony_mixer_init(struct snd_harmony *h)
 {
        struct snd_card *card = h->card;
index c3f3da2..e9b029e 100644 (file)
@@ -804,6 +804,7 @@ static struct {
        {0x1822, 0x0001}, /* Twinhan VisionPlus DVB-T */
        {0x18ac, 0xd500}, /* DVICO FusionHDTV 5 Lite */
        {0x18ac, 0xdb10}, /* DVICO FusionHDTV DVB-T Lite */
+       {0x18ac, 0xdb11}, /* Ultraview DVB-T Lite */
        {0x270f, 0xfc00}, /* Chaintech Digitop DST-1000 DVB-S */
        {0x7063, 0x2000}, /* pcHDTV HD-2000 TV */
 };