Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 9 Sep 2008 19:23:41 +0000 (12:23 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 9 Sep 2008 19:23:41 +0000 (12:23 -0700)
* 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  x86: fix memmap=exactmap boot argument
  x86: disable static NOPLs on 32 bits
  xen: fix 2.6.27-rc5 xen balloon driver warnings

323 files changed:
Documentation/filesystems/Locking
Documentation/laptops/thinkpad-acpi.txt
Documentation/video4linux/CARDLIST.au0828
Documentation/video4linux/gspca.txt
MAINTAINERS
arch/arm/include/asm/byteorder.h
arch/arm/include/asm/io.h
arch/arm/include/asm/mach/map.h
arch/arm/mach-omap1/mcbsp.c
arch/arm/mach-omap2/mcbsp.c
arch/arm/mm/mmu.c
arch/arm/plat-mxc/clock.c
arch/arm/plat-omap/gpio.c
arch/arm/plat-omap/include/mach/mcbsp.h
arch/arm/plat-omap/mcbsp.c
arch/avr32/kernel/asm-offsets.c
arch/avr32/kernel/entry-avr32b.S
arch/avr32/mach-at32ap/pm-at32ap700x.S
arch/ia64/include/asm/sections.h
arch/ia64/kernel/module.c
arch/mips/Kconfig
arch/mips/kernel/setup.c
arch/mips/kernel/traps.c
arch/mips/mm/c-r3k.c
arch/mips/mm/c-r4k.c
arch/mips/mm/c-tx39.c
arch/mips/mm/cache.c
arch/mips/mm/tlbex.c
arch/mips/sgi-ip22/ip22-platform.c
arch/mips/txx9/generic/setup.c
arch/parisc/kernel/module.c
arch/powerpc/Makefile
arch/powerpc/boot/Makefile
arch/powerpc/include/asm/pgtable-ppc64.h
arch/powerpc/include/asm/sections.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/align.c
arch/powerpc/kernel/idle_6xx.S
arch/powerpc/kernel/idle_e500.S
arch/powerpc/kernel/module_64.c
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/platforms/cell/spufs/sched.c
arch/powerpc/platforms/powermac/Makefile
arch/s390/kernel/compat_ptrace.h
arch/s390/kernel/ptrace.c
arch/sh/configs/ap325rxa_defconfig
arch/sh/configs/migor_defconfig
arch/sh/include/asm/uaccess_64.h
arch/sh/kernel/cpu/sh5/entry.S
arch/sh/kernel/entry-common.S
arch/sh/kernel/machine_kexec.c
arch/sh/kernel/ptrace_64.c
arch/sh/kernel/setup.c
arch/sh/kernel/sys_sh.c
arch/sh/mm/consistent.c
arch/sparc64/kernel/smp.c
arch/x86/kernel/hpet.c
arch/x86/kernel/tsc.c
crypto/async_tx/async_tx.c
crypto/camellia.c
drivers/acpi/dispatcher/dsobject.c
drivers/acpi/processor_perflib.c
drivers/acpi/sbshc.c
drivers/acpi/tables.c
drivers/ata/Kconfig
drivers/ata/ahci.c
drivers/ata/libata-sff.c
drivers/ata/pata_marvell.c
drivers/ata/pata_sil680.c
drivers/ata/sata_mv.c
drivers/ata/sata_nv.c
drivers/clocksource/acpi_pm.c
drivers/i2c/busses/i2c-sh_mobile.c
drivers/input/mouse/bcm5974.c
drivers/input/serio/i8042-x86ia64io.h
drivers/media/common/saa7146_video.c
drivers/media/common/tuners/mt2131.c
drivers/media/common/tuners/mt2131.h
drivers/media/common/tuners/mt2131_priv.h
drivers/media/common/tuners/mxl5005s.c
drivers/media/common/tuners/mxl5005s.h
drivers/media/common/tuners/tuner-simple.c
drivers/media/common/tuners/xc5000.c
drivers/media/common/tuners/xc5000.h
drivers/media/common/tuners/xc5000_priv.h
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
drivers/media/dvb/b2c2/flexcop-i2c.c
drivers/media/dvb/bt8xx/dst.c
drivers/media/dvb/dvb-core/dmxdev.c
drivers/media/dvb/dvb-core/dvb_ca_en50221.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-usb/cxusb.c
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/frontends/au8522.c
drivers/media/dvb/frontends/au8522.h
drivers/media/dvb/frontends/cx22702.c
drivers/media/dvb/frontends/cx22702.h
drivers/media/dvb/frontends/cx24123.c
drivers/media/dvb/frontends/cx24123.h
drivers/media/dvb/frontends/s5h1409.c
drivers/media/dvb/frontends/s5h1409.h
drivers/media/dvb/frontends/s5h1411.c
drivers/media/dvb/frontends/s5h1411.h
drivers/media/dvb/frontends/s5h1420.c
drivers/media/dvb/frontends/tda10048.c
drivers/media/dvb/frontends/tda10048.h
drivers/media/dvb/siano/sms-cards.c
drivers/media/dvb/siano/sms-cards.h
drivers/media/dvb/siano/smscoreapi.c
drivers/media/dvb/siano/smscoreapi.h
drivers/media/dvb/siano/smsdvb.c
drivers/media/dvb/siano/smsusb.c
drivers/media/dvb/ttpci/budget-patch.c
drivers/media/dvb/ttpci/budget.c
drivers/media/radio/Makefile
drivers/media/radio/dsbr100.c
drivers/media/radio/miropcm20-radio.c [deleted file]
drivers/media/radio/miropcm20-rds-core.c [deleted file]
drivers/media/radio/miropcm20-rds-core.h [deleted file]
drivers/media/radio/miropcm20-rds.c [deleted file]
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-aztech.c
drivers/media/radio/radio-cadet.c
drivers/media/radio/radio-gemtek-pci.c
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-maestro.c
drivers/media/radio/radio-maxiradio.c
drivers/media/radio/radio-rtrack2.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-si470x.c
drivers/media/radio/radio-terratec.c
drivers/media/radio/radio-trust.c
drivers/media/radio/radio-zoltrix.c
drivers/media/video/Makefile
drivers/media/video/au0828/Kconfig
drivers/media/video/au0828/au0828-cards.c
drivers/media/video/au0828/au0828-cards.h
drivers/media/video/au0828/au0828-core.c
drivers/media/video/au0828/au0828-dvb.c
drivers/media/video/au0828/au0828-i2c.c
drivers/media/video/au0828/au0828-reg.h
drivers/media/video/au0828/au0828.h
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttv-risc.c
drivers/media/video/bt8xx/bttvp.h
drivers/media/video/btcx-risc.c
drivers/media/video/btcx-risc.h
drivers/media/video/bw-qcam.c
drivers/media/video/c-qcam.c
drivers/media/video/cpia.c
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cx18/cx18-av-firmware.c
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-dvb.c
drivers/media/video/cx18/cx18-dvb.h
drivers/media/video/cx18/cx18-irq.c
drivers/media/video/cx18/cx18-queue.c
drivers/media/video/cx18/cx18-queue.h
drivers/media/video/cx23885/cx23885-417.c
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-core.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885-i2c.c
drivers/media/video/cx23885/cx23885-reg.h
drivers/media/video/cx23885/cx23885-vbi.c
drivers/media/video/cx23885/cx23885-video.c
drivers/media/video/cx23885/cx23885.h
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/et61x251/et61x251_core.c
drivers/media/video/gspca/conex.c
drivers/media/video/gspca/etoms.c
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
drivers/media/video/gspca/mars.c
drivers/media/video/gspca/ov519.c
drivers/media/video/gspca/pac207.c
drivers/media/video/gspca/pac7311.c
drivers/media/video/gspca/pac_common.h [new file with mode: 0644]
drivers/media/video/gspca/sonixb.c
drivers/media/video/gspca/sonixj.c
drivers/media/video/gspca/spca500.c
drivers/media/video/gspca/spca501.c
drivers/media/video/gspca/spca505.c
drivers/media/video/gspca/spca506.c
drivers/media/video/gspca/spca508.c
drivers/media/video/gspca/spca561.c
drivers/media/video/gspca/stk014.c
drivers/media/video/gspca/sunplus.c
drivers/media/video/gspca/t613.c
drivers/media/video/gspca/tv8532.c
drivers/media/video/gspca/vc032x.c
drivers/media/video/gspca/zc3xx.c
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-irq.c
drivers/media/video/ivtv/ivtv-queue.h
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/ivtv/ivtv-vbi.c
drivers/media/video/ivtv/ivtv-version.h
drivers/media/video/ks0127.c
drivers/media/video/meye.c
drivers/media/video/mxb.c
drivers/media/video/ov511.c
drivers/media/video/pms.c
drivers/media/video/pwc/pwc-ctrl.c
drivers/media/video/saa7115.c
drivers/media/video/se401.c
drivers/media/video/sn9c102/sn9c102_core.c
drivers/media/video/sn9c102/sn9c102_devtable.h
drivers/media/video/stv680.c
drivers/media/video/usbvideo/ibmcam.c
drivers/media/video/usbvideo/vicam.c
drivers/media/video/v4l2-dev.c
drivers/media/video/v4l2-ioctl.c
drivers/media/video/vivi.c
drivers/media/video/w9966.c
drivers/media/video/zc0301/zc0301_core.c
drivers/media/video/zc0301/zc0301_sensor.h
drivers/misc/fujitsu-laptop.c
drivers/misc/thinkpad_acpi.c
drivers/mmc/card/block.c
drivers/mtd/nand/tmio_nand.c
drivers/net/bnx2x.h
drivers/net/bnx2x_main.c
drivers/net/forcedeth.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/netxen/netxen_nic_main.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/pcmcia/pcnet_cs.c
drivers/net/usb/pegasus.c
drivers/net/wireless/ath9k/main.c
drivers/net/wireless/ath9k/xmit.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-rx.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/pci/setup-bus.c
drivers/pnp/pnpacpi/rsparser.c
drivers/s390/cio/chp.c
drivers/s390/cio/cio.c
drivers/s390/cio/css.c
drivers/s390/cio/device_fsm.c
drivers/usb/host/ohci-omap.c
drivers/usb/serial/console.c
drivers/video/atmel_lcdfb.c
fs/nfs/super.c
fs/proc/array.c
fs/ubifs/budget.c
fs/ubifs/dir.c
fs/ubifs/file.c
fs/ubifs/find.c
fs/ubifs/gc.c
fs/ubifs/misc.h
fs/ubifs/super.c
fs/ubifs/tnc.c
fs/ubifs/ubifs-media.h
fs/ubifs/ubifs.h
include/asm-generic/Kbuild.asm
include/asm-generic/sections.h
include/asm-generic/syscall.h
include/asm-mips/cacheflush.h
include/asm-parisc/sections.h
include/linux/Kbuild
include/linux/clockchips.h
include/linux/cpuset.h
include/linux/list.h
include/linux/res_counter.h
include/linux/sched.h
include/linux/tracehook.h
include/linux/videodev2.h
include/net/inet_timewait_sock.h
kernel/cpuset.c
kernel/exit.c
kernel/sched.c
kernel/sysctl.c
kernel/time/clockevents.c
kernel/time/ntp.c
kernel/time/tick-broadcast.c
kernel/time/tick-common.c
kernel/time/tick-internal.h
kernel/time/tick-oneshot.c
kernel/time/tick-sched.c
lib/Kconfig.debug
lib/debugobjects.c
lib/vsprintf.c
mm/mmap.c
net/bridge/br_ioctl.c
net/bridge/br_sysfs_br.c
net/core/dev.c
net/ipv4/inet_timewait_sock.c
net/ipv4/tcp_ipv4.c
net/ipv6/tcp_ipv6.c
net/mac80211/mlme.c
net/netfilter/nf_conntrack_irc.c
net/netfilter/nf_conntrack_proto_gre.c
net/netfilter/nf_conntrack_sip.c
net/tipc/bcast.c
net/tipc/bcast.h
net/tipc/bearer.c
net/tipc/bearer.h
net/tipc/cluster.c
net/tipc/cluster.h
net/tipc/discover.c
net/tipc/link.c
net/tipc/link.h
net/tipc/name_table.h
net/tipc/net.c
net/tipc/net.h
net/tipc/node.c
net/tipc/node.h
net/tipc/node_subscr.c
net/tipc/node_subscr.h
net/tipc/port.h
net/tipc/zone.c
net/tipc/zone.h
security/selinux/ss/services.c
sound/Kconfig

index 680fb56..8362860 100644 (file)
@@ -144,8 +144,8 @@ prototypes:
        void (*kill_sb) (struct super_block *);
 locking rules:
                may block       BKL
-get_sb         yes             yes
-kill_sb                yes             yes
+get_sb         yes             no
+kill_sb                yes             no
 
 ->get_sb() returns error or 0 with locked superblock attached to the vfsmount
 (exclusive on ->s_umount).
@@ -409,12 +409,12 @@ ioctl:                    yes     (see below)
 unlocked_ioctl:                no      (see below)
 compat_ioctl:          no
 mmap:                  no
-open:                  maybe   (see below)
+open:                  no
 flush:                 no
 release:               no
 fsync:                 no      (see below)
 aio_fsync:             no
-fasync:                        yes     (see below)
+fasync:                        no
 lock:                  yes
 readv:                 no
 writev:                        no
@@ -431,13 +431,6 @@ For many filesystems, it is probably safe to acquire the inode
 semaphore.  Note some filesystems (i.e. remote ones) provide no
 protection for i_size so you will need to use the BKL.
 
-->open() locking is in-transit: big lock partially moved into the methods.
-The only exception is ->open() in the instances of file_operations that never
-end up in ->i_fop/->proc_fops, i.e. ones that belong to character devices
-(chrdev_open() takes lock before replacing ->f_op and calling the secondary
-method. As soon as we fix the handling of module reference counters all
-instances of ->open() will be called without the BKL.
-
 Note: ext2_release() was *the* source of contention on fs-intensive
 loads and dropping BKL on ->release() helps to get rid of that (we still
 grab BKL for cases when we close a file that had been opened r/w, but that
index 02dc748..71f0fe1 100644 (file)
@@ -44,7 +44,7 @@ detailed description):
        - LCD brightness control
        - Volume control
        - Fan control and monitoring: fan speed, fan enable/disable
-       - Experimental: WAN enable and disable
+       - WAN enable and disable
 
 A compatibility table by model and feature is maintained on the web
 site, http://ibm-acpi.sf.net/. I appreciate any success or failure
@@ -1375,18 +1375,13 @@ with EINVAL, try to set pwm1_enable to 1 and pwm1 to at least 128 (255
 would be the safest choice, though).
 
 
-EXPERIMENTAL: WAN
------------------
+WAN
+---
 
 procfs: /proc/acpi/ibm/wan
 sysfs device attribute: wwan_enable (deprecated)
 sysfs rfkill class: switch "tpacpi_wwan_sw"
 
-This feature is marked EXPERIMENTAL because the implementation
-directly accesses hardware registers and may not work as expected. USE
-WITH CAUTION! To use this feature, you need to supply the
-experimental=1 parameter when loading the module.
-
 This feature shows the presence and current state of a W-WAN (Sierra
 Wireless EV-DO) device.
 
index eedc399..aa05e5b 100644 (file)
@@ -3,3 +3,4 @@
   2 -> Hauppauge HVR850                         (au0828)        [2040:7240]
   3 -> DViCO FusionHDTV USB                     (au0828)        [0fe9:d620]
   4 -> Hauppauge HVR950Q rev xxF8               (au0828)        [2040:7201,2040:7211,2040:7281]
+  5 -> Hauppauge Woodbury                       (au0828)        [2040:8200]
index 78a863a..0f03900 100644 (file)
@@ -88,14 +88,14 @@ zc3xx               0471:0325       Philips SPC 200 NC
 zc3xx          0471:0326       Philips SPC 300 NC
 sonixj         0471:0327       Philips SPC 600 NC
 sonixj         0471:0328       Philips SPC 700 NC
-zc3xx          0471:032d       Philips spc210nc
-zc3xx          0471:032e       Philips spc315nc
-sonixj         0471:0330       Philips SPC 710NC
+zc3xx          0471:032d       Philips SPC 210 NC
+zc3xx          0471:032e       Philips SPC 315 NC
+sonixj         0471:0330       Philips SPC 710 NC
 spca501                0497:c001       Smile International
 sunplus                04a5:3003       Benq DC 1300
 sunplus                04a5:3008       Benq DC 1500
-sunplus                04a5:300a       Benq DC3410
-spca500                04a5:300c       Benq DC1016
+sunplus                04a5:300a       Benq DC 3410
+spca500                04a5:300c       Benq DC 1016
 sunplus                04f1:1001       JVC GC A50
 spca561                04fc:0561       Flexcam 100
 sunplus                04fc:500c       Sunplus CA500C
@@ -175,19 +175,21 @@ sunplus           08ca:2060       Aiptek PocketDV5300
 tv8532         0923:010f       ICM532 cams
 mars           093a:050f       Mars-Semi Pc-Camera
 pac207         093a:2460       PAC207 Qtec Webcam 100
-pac207         093a:2463       Philips spc200nc pac207
+pac207         093a:2463       Philips SPC 220 NC
 pac207         093a:2464       Labtec Webcam 1200
 pac207         093a:2468       PAC207
 pac207         093a:2470       Genius GF112
-pac207         093a:2471       PAC207 Genius VideoCam ge111
-pac207         093a:2472       PAC207 Genius VideoCam ge110
+pac207         093a:2471       Genius VideoCam ge111
+pac207         093a:2472       Genius VideoCam ge110
 pac7311                093a:2600       PAC7311 Typhoon
-pac7311                093a:2601       PAC7311 Phillips SPC610NC
+pac7311                093a:2601       Philips SPC 610 NC
 pac7311                093a:2603       PAC7312
-pac7311                093a:2608       PAC7311 Trust WB-3300p
-pac7311                093a:260e       PAC7311 Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350
-pac7311                093a:260f       PAC7311 SnakeCam
+pac7311                093a:2608       Trust WB-3300p
+pac7311                093a:260e       Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350
+pac7311                093a:260f       SnakeCam
 pac7311                093a:2621       PAC731x
+pac7311                093a:2624       PAC7302
+pac7311                093a:2626       Labtec 2200
 zc3xx          0ac8:0302       Z-star Vimicro zc0302
 vc032x         0ac8:0321       Vimicro generic vc0321
 vc032x         0ac8:0323       Vimicro Vc0323
@@ -220,6 +222,7 @@ sonixj              0c45:60c0       Sangha Sn535
 sonixj         0c45:60ec       SN9C105+MO4000
 sonixj         0c45:60fb       Surfer NoName
 sonixj         0c45:60fc       LG-LIC300
+sonixj         0c45:6128       Microdia/Sonix SNP325
 sonixj         0c45:612a       Avant Camera
 sonixj         0c45:612c       Typhoon Rasy Cam 1.3MPix
 sonixj         0c45:6130       Sonix Pccam
@@ -234,7 +237,7 @@ zc3xx               10fd:0128       Typhoon Webshot II USB 300k 0x0128
 spca561                10fd:7e50       FlyCam Usb 100
 zc3xx          10fd:8050       Typhoon Webshot II USB 300k
 spca501                1776:501c       Arowana 300K CMOS Camera
-t613           17a1:0128       T613/TAS5130A
+t613           17a1:0128       TASCORP JPEG Webcam, NGS Cyclops
 vc032x         17ef:4802       Lenovo Vc0323+MI1310_SOC
 pac207         2001:f115       D-Link DSB-C120
 spca500                2899:012c       Toptro Industrial
index ced3c20..186be3b 100644 (file)
@@ -222,8 +222,7 @@ W:  http://code.google.com/p/aceracpi
 S:     Maintained
 
 ACPI
-P:     Andi Kleen
-M:     ak@linux.intel.com
+P:     Len Brown
 M:     lenb@kernel.org
 L:     linux-acpi@vger.kernel.org
 W:     http://www.lesswatts.org/projects/acpi/
@@ -751,11 +750,13 @@ P:        Ville Syrjala
 M:     syrjala@sci.fi
 S:     Maintained
 
-ATL1 ETHERNET DRIVER
+ATLX ETHERNET DRIVERS
 P:     Jay Cliburn
 M:     jcliburn@gmail.com
 P:     Chris Snook
 M:     csnook@redhat.com
+P:     Jie Yang
+M:     jie.yang@atheros.com
 L:     atl1-devel@lists.sourceforge.net
 W:     http://sourceforge.net/projects/atl1
 W:     http://atl1.sourceforge.net
@@ -1594,7 +1595,7 @@ S:        Supported
 EMBEDDED LINUX
 P:     Paul Gortmaker
 M:     paul.gortmaker@windriver.com
-P      David Woodhouse
+P:     David Woodhouse
 M:     dwmw2@infradead.org
 L:     linux-embedded@vger.kernel.org
 S:     Maintained
index d04a7a2..4fbfb22 100644 (file)
 #include <linux/compiler.h>
 #include <asm/types.h>
 
-#ifdef __ARMEB__
-# define __BIG_ENDIAN
-#else
-# define __LITTLE_ENDIAN
-#endif
-
-#define __SWAB_64_THRU_32__
-
-static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
+static inline __attribute_const__ __u32 ___arch__swab32(__u32 x)
 {
        __u32 t;
 
@@ -48,8 +40,19 @@ static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
 
        return x;
 }
-#define __arch_swab32 __arch_swab32
 
-#include <linux/byteorder.h>
+#define __arch__swab32(x) ___arch__swab32(x)
+
+#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
+#  define __BYTEORDER_HAS_U64__
+#  define __SWAB_64_THRU_32__
+#endif
+
+#ifdef __ARMEB__
+#include <linux/byteorder/big_endian.h>
+#else
+#include <linux/byteorder/little_endian.h>
+#endif
 
 #endif
+
index 94a95d7..7193485 100644 (file)
@@ -61,8 +61,9 @@ extern void __raw_readsl(const void __iomem *addr, void *data, int longlen);
 #define MT_DEVICE_NONSHARED    1
 #define MT_DEVICE_CACHED       2
 #define MT_DEVICE_IXP2000      3
+#define MT_DEVICE_WC           4
 /*
- * types 4 onwards can be found in asm/mach/map.h and are undefined
+ * types 5 onwards can be found in asm/mach/map.h and are undefined
  * for ioremap
  */
 
@@ -215,11 +216,13 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
 #define ioremap(cookie,size)           __arm_ioremap(cookie, size, MT_DEVICE)
 #define ioremap_nocache(cookie,size)   __arm_ioremap(cookie, size, MT_DEVICE)
 #define ioremap_cached(cookie,size)    __arm_ioremap(cookie, size, MT_DEVICE_CACHED)
+#define ioremap_wc(cookie,size)                __arm_ioremap(cookie, size, MT_DEVICE_WC)
 #define iounmap(cookie)                        __iounmap(cookie)
 #else
 #define ioremap(cookie,size)           __arch_ioremap((cookie), (size), MT_DEVICE)
 #define ioremap_nocache(cookie,size)   __arch_ioremap((cookie), (size), MT_DEVICE)
 #define ioremap_cached(cookie,size)    __arch_ioremap((cookie), (size), MT_DEVICE_CACHED)
+#define ioremap_wc(cookie,size)                __arch_ioremap((cookie), (size), MT_DEVICE_WC)
 #define iounmap(cookie)                        __arch_iounmap(cookie)
 #endif
 
index 06f583b..9eb936e 100644 (file)
@@ -18,13 +18,13 @@ struct map_desc {
        unsigned int type;
 };
 
-/* types 0-3 are defined in asm/io.h */
-#define MT_CACHECLEAN          4
-#define MT_MINICLEAN           5
-#define MT_LOW_VECTORS         6
-#define MT_HIGH_VECTORS                7
-#define MT_MEMORY              8
-#define MT_ROM                 9
+/* types 0-4 are defined in asm/io.h */
+#define MT_CACHECLEAN          5
+#define MT_MINICLEAN           6
+#define MT_LOW_VECTORS         7
+#define MT_HIGH_VECTORS                8
+#define MT_MEMORY              9
+#define MT_ROM                 10
 
 #define MT_NONSHARED_DEVICE    MT_DEVICE_NONSHARED
 #define MT_IXP2000_DEVICE      MT_DEVICE_IXP2000
index 826010d..2baeaeb 100644 (file)
@@ -159,6 +159,7 @@ static struct omap_mcbsp_ops omap1_mcbsp_ops = {
 #ifdef CONFIG_ARCH_OMAP730
 static struct omap_mcbsp_platform_data omap730_mcbsp_pdata[] = {
        {
+               .phys_base      = OMAP730_MCBSP1_BASE,
                .virt_base      = io_p2v(OMAP730_MCBSP1_BASE),
                .dma_rx_sync    = OMAP_DMA_MCBSP1_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP1_TX,
@@ -167,6 +168,7 @@ static struct omap_mcbsp_platform_data omap730_mcbsp_pdata[] = {
                .ops            = &omap1_mcbsp_ops,
        },
        {
+               .phys_base      = OMAP730_MCBSP2_BASE,
                .virt_base      = io_p2v(OMAP730_MCBSP2_BASE),
                .dma_rx_sync    = OMAP_DMA_MCBSP3_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP3_TX,
@@ -184,6 +186,7 @@ static struct omap_mcbsp_platform_data omap730_mcbsp_pdata[] = {
 #ifdef CONFIG_ARCH_OMAP15XX
 static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = {
        {
+               .phys_base      = OMAP1510_MCBSP1_BASE,
                .virt_base      = OMAP1510_MCBSP1_BASE,
                .dma_rx_sync    = OMAP_DMA_MCBSP1_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP1_TX,
@@ -193,6 +196,7 @@ static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = {
                .clk_name       = "mcbsp_clk",
                },
        {
+               .phys_base      = OMAP1510_MCBSP2_BASE,
                .virt_base      = io_p2v(OMAP1510_MCBSP2_BASE),
                .dma_rx_sync    = OMAP_DMA_MCBSP2_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP2_TX,
@@ -201,6 +205,7 @@ static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = {
                .ops            = &omap1_mcbsp_ops,
        },
        {
+               .phys_base      = OMAP1510_MCBSP3_BASE,
                .virt_base      = OMAP1510_MCBSP3_BASE,
                .dma_rx_sync    = OMAP_DMA_MCBSP3_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP3_TX,
@@ -219,6 +224,7 @@ static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = {
 #ifdef CONFIG_ARCH_OMAP16XX
 static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = {
        {
+               .phys_base      = OMAP1610_MCBSP1_BASE,
                .virt_base      = OMAP1610_MCBSP1_BASE,
                .dma_rx_sync    = OMAP_DMA_MCBSP1_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP1_TX,
@@ -228,6 +234,7 @@ static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = {
                .clk_name       = "mcbsp_clk",
        },
        {
+               .phys_base      = OMAP1610_MCBSP2_BASE,
                .virt_base      = io_p2v(OMAP1610_MCBSP2_BASE),
                .dma_rx_sync    = OMAP_DMA_MCBSP2_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP2_TX,
@@ -236,6 +243,7 @@ static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = {
                .ops            = &omap1_mcbsp_ops,
        },
        {
+               .phys_base      = OMAP1610_MCBSP3_BASE,
                .virt_base      = OMAP1610_MCBSP3_BASE,
                .dma_rx_sync    = OMAP_DMA_MCBSP3_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP3_TX,
index 27eb6e3..b261f1f 100644 (file)
@@ -134,6 +134,7 @@ static struct omap_mcbsp_ops omap2_mcbsp_ops = {
 #ifdef CONFIG_ARCH_OMAP24XX
 static struct omap_mcbsp_platform_data omap24xx_mcbsp_pdata[] = {
        {
+               .phys_base      = OMAP24XX_MCBSP1_BASE,
                .virt_base      = IO_ADDRESS(OMAP24XX_MCBSP1_BASE),
                .dma_rx_sync    = OMAP24XX_DMA_MCBSP1_RX,
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP1_TX,
@@ -143,6 +144,7 @@ static struct omap_mcbsp_platform_data omap24xx_mcbsp_pdata[] = {
                .clk_name       = "mcbsp_clk",
        },
        {
+               .phys_base      = OMAP24XX_MCBSP2_BASE,
                .virt_base      = IO_ADDRESS(OMAP24XX_MCBSP2_BASE),
                .dma_rx_sync    = OMAP24XX_DMA_MCBSP2_RX,
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP2_TX,
@@ -161,6 +163,7 @@ static struct omap_mcbsp_platform_data omap24xx_mcbsp_pdata[] = {
 #ifdef CONFIG_ARCH_OMAP34XX
 static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
        {
+               .phys_base      = OMAP34XX_MCBSP1_BASE,
                .virt_base      = IO_ADDRESS(OMAP34XX_MCBSP1_BASE),
                .dma_rx_sync    = OMAP24XX_DMA_MCBSP1_RX,
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP1_TX,
@@ -170,6 +173,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
                .clk_name       = "mcbsp_clk",
        },
        {
+               .phys_base      = OMAP34XX_MCBSP2_BASE,
                .virt_base      = IO_ADDRESS(OMAP34XX_MCBSP2_BASE),
                .dma_rx_sync    = OMAP24XX_DMA_MCBSP2_RX,
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP2_TX,
index 25d9a11..a713e40 100644 (file)
@@ -211,6 +211,12 @@ static struct mem_type mem_types[] = {
                                  PMD_SECT_TEX(1),
                .domain         = DOMAIN_IO,
        },
+       [MT_DEVICE_WC] = {      /* ioremap_wc */
+               .prot_pte       = PROT_PTE_DEVICE,
+               .prot_l1        = PMD_TYPE_TABLE,
+               .prot_sect      = PROT_SECT_DEVICE,
+               .domain         = DOMAIN_IO,
+       },
        [MT_CACHECLEAN] = {
                .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN,
                .domain    = DOMAIN_KERNEL,
@@ -272,6 +278,20 @@ static void __init build_mem_type_table(void)
                ecc_mask = 0;
        }
 
+       /*
+        * On non-Xscale3 ARMv5-and-older systems, use CB=01
+        * (Uncached/Buffered) for ioremap_wc() mappings.  On XScale3
+        * and ARMv6+, use TEXCB=00100 mappings (Inner/Outer Uncacheable
+        * in xsc3 parlance, Uncached Normal in ARMv6 parlance).
+        */
+       if (cpu_is_xsc3() || cpu_arch >= CPU_ARCH_ARMv6) {
+               mem_types[MT_DEVICE_WC].prot_pte_ext |= PTE_EXT_TEX(1);
+               mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_TEX(1);
+       } else {
+               mem_types[MT_DEVICE_WC].prot_pte |= L_PTE_BUFFERABLE;
+               mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_BUFFERABLE;
+       }
+
        /*
         * ARMv5 and lower, bit 4 must be set for page tables.
         * (was: cache "update-able on write" bit on ARM610)
index 2f86272..0a38f0b 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/proc_fs.h>
 #include <linux/semaphore.h>
 #include <linux/string.h>
-#include <linux/version.h>
 
 #include <mach/clock.h>
 
index 3e76ee2..9e1341e 100644 (file)
@@ -1488,7 +1488,7 @@ static int __init _omap_gpio_init(void)
                bank->chip.set = gpio_set;
                if (bank_is_mpuio(bank)) {
                        bank->chip.label = "mpuio";
-#ifdef CONFIG_ARCH_OMAP1
+#ifdef CONFIG_ARCH_OMAP16XX
                        bank->chip.dev = &omap_mpuio_device.dev;
 #endif
                        bank->chip.base = OMAP_MPUIO(0);
index 6eb44a9..8fdb95e 100644 (file)
@@ -315,6 +315,7 @@ struct omap_mcbsp_ops {
 };
 
 struct omap_mcbsp_platform_data {
+       unsigned long phys_base;
        u32 virt_base;
        u8 dma_rx_sync, dma_tx_sync;
        u16 rx_irq, tx_irq;
@@ -324,6 +325,7 @@ struct omap_mcbsp_platform_data {
 
 struct omap_mcbsp {
        struct device *dev;
+       unsigned long phys_base;
        u32 io_base;
        u8 id;
        u8 free;
index d084405..014d265 100644 (file)
@@ -651,7 +651,7 @@ int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer,
        omap_set_dma_dest_params(mcbsp[id].dma_tx_lch,
                                 src_port,
                                 OMAP_DMA_AMODE_CONSTANT,
-                                mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1,
+                                mcbsp[id].phys_base + OMAP_MCBSP_REG_DXR1,
                                 0, 0);
 
        omap_set_dma_src_params(mcbsp[id].dma_tx_lch,
@@ -712,7 +712,7 @@ int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer,
        omap_set_dma_src_params(mcbsp[id].dma_rx_lch,
                                src_port,
                                OMAP_DMA_AMODE_CONSTANT,
-                               mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1,
+                               mcbsp[id].phys_base + OMAP_MCBSP_REG_DRR1,
                                0, 0);
 
        omap_set_dma_dest_params(mcbsp[id].dma_rx_lch,
@@ -830,6 +830,7 @@ static int __init omap_mcbsp_probe(struct platform_device *pdev)
        mcbsp[id].dma_tx_lch = -1;
        mcbsp[id].dma_rx_lch = -1;
 
+       mcbsp[id].phys_base = pdata->phys_base;
        mcbsp[id].io_base = pdata->virt_base;
        /* Default I/O is IRQ based */
        mcbsp[id].io_type = OMAP_MCBSP_IRQ_IO;
index e4796c6..d6a8193 100644 (file)
@@ -4,6 +4,8 @@
  * to extract and format the required data.
  */
 
+#include <linux/mm.h>
+#include <linux/sched.h>
 #include <linux/thread_info.h>
 #include <linux/kbuild.h>
 
@@ -17,4 +19,8 @@ void foo(void)
        OFFSET(TI_rar_saved, thread_info, rar_saved);
        OFFSET(TI_rsr_saved, thread_info, rsr_saved);
        OFFSET(TI_restart_block, thread_info, restart_block);
+       BLANK();
+       OFFSET(TSK_active_mm, task_struct, active_mm);
+       BLANK();
+       OFFSET(MM_pgd, mm_struct, pgd);
 }
index 2b398ca..33d4937 100644 (file)
@@ -334,9 +334,64 @@ save_full_context_ex:
 
        /* Low-level exception handlers */
 handle_critical:
+       /*
+        * AT32AP700x errata:
+        *
+        * After a Java stack overflow or underflow trap, any CPU
+        * memory access may cause erratic behavior. This will happen
+        * when the four least significant bits of the JOSP system
+        * register contains any value between 9 and 15 (inclusive).
+        *
+        * Possible workarounds:
+        *   - Don't use the Java Extension Module
+        *   - Ensure that the stack overflow and underflow trap
+        *     handlers do not do any memory access or trigger any
+        *     exceptions before the overflow/underflow condition is
+        *     cleared (by incrementing or decrementing the JOSP)
+        *   - Make sure that JOSP does not contain any problematic
+        *     value before doing any exception or interrupt
+        *     processing.
+        *   - Set up a critical exception handler which writes a
+        *     known-to-be-safe value, e.g. 4, to JOSP before doing
+        *     any further processing.
+        *
+        * We'll use the last workaround for now since we cannot
+        * guarantee that user space processes don't use Java mode.
+        * Non-well-behaving userland will be terminated with extreme
+        * prejudice.
+        */
+#ifdef CONFIG_CPU_AT32AP700X
+       /*
+        * There's a chance we can't touch memory, so temporarily
+        * borrow PTBR to save the stack pointer while we fix things
+        * up...
+        */
+       mtsr    SYSREG_PTBR, sp
+       mov     sp, 4
+       mtsr    SYSREG_JOSP, sp
+       mfsr    sp, SYSREG_PTBR
+       sub     pc, -2
+
+       /* Push most of pt_regs on stack. We'll do the rest later */
        sub     sp, 4
-       stmts   --sp, r0-lr
-       rcall   save_full_context_ex
+       pushm   r0-r12
+
+       /* PTBR mirrors current_thread_info()->task->active_mm->pgd */
+       get_thread_info r0
+       ld.w    r1, r0[TI_task]
+       ld.w    r2, r1[TSK_active_mm]
+       ld.w    r3, r2[MM_pgd]
+       mtsr    SYSREG_PTBR, r3
+#else
+       sub     sp, 4
+       pushm   r0-r12
+#endif
+       sub     r0, sp, -(14 * 4)
+       mov     r1, lr
+       mfsr    r2, SYSREG_RAR_EX
+       mfsr    r3, SYSREG_RSR_EX
+       pushm   r0-r3
+
        mfsr    r12, SYSREG_ECR
        mov     r11, sp
        rcall   do_critical_exception
index 5be4de6..17503b0 100644 (file)
@@ -134,7 +134,7 @@ pm_standby:
        mov     r11, SDRAMC_LPR_LPCB_SELF_RFR
        bfins   r10, r11, 0, 2          /* LPCB <- self Refresh */
        sync    0                       /* flush write buffer */
-       st.w    r12[SDRAMC_LPR], r11    /* put SDRAM in self-refresh mode */
+       st.w    r12[SDRAMC_LPR], r10    /* put SDRAM in self-refresh mode */
        ld.w    r11, r12[SDRAMC_LPR]
        unmask_interrupts
        sleep   CPU_SLEEP_FROZEN
index 7286e4a..a7acad2 100644 (file)
@@ -21,5 +21,8 @@ extern char __start_gate_brl_fsys_bubble_down_patchlist[], __end_gate_brl_fsys_b
 extern char __start_unwind[], __end_unwind[];
 extern char __start_ivt_text[], __end_ivt_text[];
 
+#undef dereference_function_descriptor
+void *dereference_function_descriptor(void *);
+
 #endif /* _ASM_IA64_SECTIONS_H */
 
index 29aad34..545626f 100644 (file)
 #include <linux/elf.h>
 #include <linux/moduleloader.h>
 #include <linux/string.h>
+#include <linux/uaccess.h>
 #include <linux/vmalloc.h>
 
 #include <asm/patch.h>
+#include <asm/sections.h>
 #include <asm/unaligned.h>
 
 #define ARCH_MODULE_DEBUG 0
@@ -941,3 +943,13 @@ module_arch_cleanup (struct module *mod)
        if (mod->arch.core_unw_table)
                unw_remove_unwind_table(mod->arch.core_unw_table);
 }
+
+void *dereference_function_descriptor(void *ptr)
+{
+       struct fdesc *desc = ptr;
+       void *p;
+
+       if (!probe_kernel_address(&desc->ip, p))
+               ptr = p;
+       return ptr;
+}
index 4da736e..49896a2 100644 (file)
@@ -1886,6 +1886,15 @@ config STACKTRACE_SUPPORT
 
 source "init/Kconfig"
 
+config PROBE_INITRD_HEADER
+       bool "Probe initrd header created by addinitrd"
+       depends on BLK_DEV_INITRD
+       help
+         Probe initrd header at the last page of kernel image.
+         Say Y here if you are using arch/mips/boot/addinitrd.c to
+         add initrd or initramfs image to the kernel image.
+         Otherwise, say N.
+
 menu "Bus options (PCI, PCMCIA, EISA, ISA, TC)"
 
 config HW_HAS_EISA
index 2aae76b..16f8edf 100644 (file)
@@ -160,30 +160,33 @@ early_param("rd_size", rd_size_early);
 static unsigned long __init init_initrd(void)
 {
        unsigned long end;
-       u32 *initrd_header;
 
        /*
         * Board specific code or command line parser should have
         * already set up initrd_start and initrd_end. In these cases
         * perfom sanity checks and use them if all looks good.
         */
-       if (initrd_start && initrd_end > initrd_start)
-               goto sanitize;
+       if (!initrd_start || initrd_end <= initrd_start) {
+#ifdef CONFIG_PROBE_INITRD_HEADER
+               u32 *initrd_header;
 
-       /*
-        * See if initrd has been added to the kernel image by
-        * arch/mips/boot/addinitrd.c. In that case a header is
-        * prepended to initrd and is made up by 8 bytes. The fisrt
-        * word is a magic number and the second one is the size of
-        * initrd.  Initrd start must be page aligned in any cases.
-        */
-       initrd_header = __va(PAGE_ALIGN(__pa_symbol(&_end) + 8)) - 8;
-       if (initrd_header[0] != 0x494E5244)
+               /*
+                * See if initrd has been added to the kernel image by
+                * arch/mips/boot/addinitrd.c. In that case a header is
+                * prepended to initrd and is made up by 8 bytes. The first
+                * word is a magic number and the second one is the size of
+                * initrd.  Initrd start must be page aligned in any cases.
+                */
+               initrd_header = __va(PAGE_ALIGN(__pa_symbol(&_end) + 8)) - 8;
+               if (initrd_header[0] != 0x494E5244)
+                       goto disable;
+               initrd_start = (unsigned long)(initrd_header + 2);
+               initrd_end = initrd_start + initrd_header[1];
+#else
                goto disable;
-       initrd_start = (unsigned long)(initrd_header + 2);
-       initrd_end = initrd_start + initrd_header[1];
+#endif
+       }
 
-sanitize:
        if (initrd_start & ~PAGE_MASK) {
                pr_err("initrd start must be page aligned\n");
                goto disable;
index 426cced..6bee290 100644 (file)
@@ -373,8 +373,8 @@ void __noreturn die(const char * str, const struct pt_regs * regs)
        do_exit(SIGSEGV);
 }
 
-extern const struct exception_table_entry __start___dbe_table[];
-extern const struct exception_table_entry __stop___dbe_table[];
+extern struct exception_table_entry __start___dbe_table[];
+extern struct exception_table_entry __stop___dbe_table[];
 
 __asm__(
 "      .section        __dbe_table, \"a\"\n"
@@ -1200,7 +1200,7 @@ void *set_except_vector(int n, void *addr)
        if (n == 0 && cpu_has_divec) {
                *(u32 *)(ebase + 0x200) = 0x08000000 |
                                          (0x03ffffff & (handler >> 2));
-               flush_icache_range(ebase + 0x200, ebase + 0x204);
+               local_flush_icache_range(ebase + 0x200, ebase + 0x204);
        }
        return (void *)old_handler;
 }
@@ -1283,7 +1283,8 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs)
                *w = (*w & 0xffff0000) | (((u32)handler >> 16) & 0xffff);
                w = (u32 *)(b + ori_offset);
                *w = (*w & 0xffff0000) | ((u32)handler & 0xffff);
-               flush_icache_range((unsigned long)b, (unsigned long)(b+handler_len));
+               local_flush_icache_range((unsigned long)b,
+                                        (unsigned long)(b+handler_len));
        }
        else {
                /*
@@ -1295,7 +1296,8 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs)
                w = (u32 *)b;
                *w++ = 0x08000000 | (((u32)handler >> 2) & 0x03fffff); /* j handler */
                *w = 0;
-               flush_icache_range((unsigned long)b, (unsigned long)(b+8));
+               local_flush_icache_range((unsigned long)b,
+                                        (unsigned long)(b+8));
        }
 
        return (void *)old_handler;
@@ -1515,7 +1517,7 @@ void __cpuinit per_cpu_trap_init(void)
 void __init set_handler(unsigned long offset, void *addr, unsigned long size)
 {
        memcpy((void *)(ebase + offset), addr, size);
-       flush_icache_range(ebase + offset, ebase + offset + size);
+       local_flush_icache_range(ebase + offset, ebase + offset + size);
 }
 
 static char panic_null_cerr[] __cpuinitdata =
@@ -1680,6 +1682,8 @@ void __init trap_init(void)
        signal32_init();
 #endif
 
-       flush_icache_range(ebase, ebase + 0x400);
+       local_flush_icache_range(ebase, ebase + 0x400);
        flush_tlb_handlers();
+
+       sort_extable(__start___dbe_table, __stop___dbe_table);
 }
index 27a5b46..5500c20 100644 (file)
@@ -320,6 +320,7 @@ void __cpuinit r3k_cache_init(void)
        flush_cache_range = r3k_flush_cache_range;
        flush_cache_page = r3k_flush_cache_page;
        flush_icache_range = r3k_flush_icache_range;
+       local_flush_icache_range = r3k_flush_icache_range;
 
        flush_cache_sigtramp = r3k_flush_cache_sigtramp;
        local_flush_data_cache_page = local_r3k_flush_data_cache_page;
index 71df339..6e99665 100644 (file)
@@ -543,12 +543,8 @@ struct flush_icache_range_args {
        unsigned long end;
 };
 
-static inline void local_r4k_flush_icache_range(void *args)
+static inline void local_r4k_flush_icache_range(unsigned long start, unsigned long end)
 {
-       struct flush_icache_range_args *fir_args = args;
-       unsigned long start = fir_args->start;
-       unsigned long end = fir_args->end;
-
        if (!cpu_has_ic_fills_f_dc) {
                if (end - start >= dcache_size) {
                        r4k_blast_dcache();
@@ -564,6 +560,15 @@ static inline void local_r4k_flush_icache_range(void *args)
                protected_blast_icache_range(start, end);
 }
 
+static inline void local_r4k_flush_icache_range_ipi(void *args)
+{
+       struct flush_icache_range_args *fir_args = args;
+       unsigned long start = fir_args->start;
+       unsigned long end = fir_args->end;
+
+       local_r4k_flush_icache_range(start, end);
+}
+
 static void r4k_flush_icache_range(unsigned long start, unsigned long end)
 {
        struct flush_icache_range_args args;
@@ -571,7 +576,7 @@ static void r4k_flush_icache_range(unsigned long start, unsigned long end)
        args.start = start;
        args.end = end;
 
-       r4k_on_each_cpu(local_r4k_flush_icache_range, &args, 1);
+       r4k_on_each_cpu(local_r4k_flush_icache_range_ipi, &args, 1);
        instruction_hazard();
 }
 
@@ -1375,6 +1380,7 @@ void __cpuinit r4k_cache_init(void)
        local_flush_data_cache_page     = local_r4k_flush_data_cache_page;
        flush_data_cache_page   = r4k_flush_data_cache_page;
        flush_icache_range      = r4k_flush_icache_range;
+       local_flush_icache_range        = local_r4k_flush_icache_range;
 
 #if defined(CONFIG_DMA_NONCOHERENT)
        if (coherentio) {
index a9f7f1f..f7c8f9c 100644 (file)
@@ -362,6 +362,7 @@ void __cpuinit tx39_cache_init(void)
                flush_cache_range       = (void *) tx39h_flush_icache_all;
                flush_cache_page        = (void *) tx39h_flush_icache_all;
                flush_icache_range      = (void *) tx39h_flush_icache_all;
+               local_flush_icache_range = (void *) tx39h_flush_icache_all;
 
                flush_cache_sigtramp    = (void *) tx39h_flush_icache_all;
                local_flush_data_cache_page     = (void *) tx39h_flush_icache_all;
@@ -390,6 +391,7 @@ void __cpuinit tx39_cache_init(void)
                flush_cache_range = tx39_flush_cache_range;
                flush_cache_page = tx39_flush_cache_page;
                flush_icache_range = tx39_flush_icache_range;
+               local_flush_icache_range = tx39_flush_icache_range;
 
                flush_cache_sigtramp = tx39_flush_cache_sigtramp;
                local_flush_data_cache_page = local_tx39_flush_data_cache_page;
index 034e850..1eb7c71 100644 (file)
@@ -29,6 +29,7 @@ void (*flush_cache_range)(struct vm_area_struct *vma, unsigned long start,
 void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page,
        unsigned long pfn);
 void (*flush_icache_range)(unsigned long start, unsigned long end);
+void (*local_flush_icache_range)(unsigned long start, unsigned long end);
 
 void (*__flush_cache_vmap)(void);
 void (*__flush_cache_vunmap)(void);
index 76da73a..979cf91 100644 (file)
@@ -1273,10 +1273,10 @@ void __cpuinit build_tlb_refill_handler(void)
 
 void __cpuinit flush_tlb_handlers(void)
 {
-       flush_icache_range((unsigned long)handle_tlbl,
+       local_flush_icache_range((unsigned long)handle_tlbl,
                           (unsigned long)handle_tlbl + sizeof(handle_tlbl));
-       flush_icache_range((unsigned long)handle_tlbs,
+       local_flush_icache_range((unsigned long)handle_tlbs,
                           (unsigned long)handle_tlbs + sizeof(handle_tlbs));
-       flush_icache_range((unsigned long)handle_tlbm,
+       local_flush_icache_range((unsigned long)handle_tlbm,
                           (unsigned long)handle_tlbm + sizeof(handle_tlbm));
 }
index 6014123..52486c4 100644 (file)
@@ -150,7 +150,7 @@ static int __init sgiseeq_devinit(void)
                return res;
 
        /* Second HPC is missing? */
-       if (!ip22_is_fullhouse() ||
+       if (ip22_is_fullhouse() ||
            get_dbe(tmp, (unsigned int *)&hpc3c1->pbdma[1]))
                return 0;
 
index 0afe94c..fe6bee0 100644 (file)
@@ -53,6 +53,7 @@ txx9_reg_res_init(unsigned int pcode, unsigned long base, unsigned long size)
                txx9_ce_res[i].name = txx9_ce_res_name[i];
        }
 
+       txx9_pcode = pcode;
        sprintf(txx9_pcode_str, "TX%x", pcode);
        if (base) {
                txx9_reg_res.start = base & 0xfffffffffULL;
index fdacdd4..44138c3 100644 (file)
@@ -47,7 +47,9 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/bug.h>
+#include <linux/uaccess.h>
 
+#include <asm/sections.h>
 #include <asm/unwind.h>
 
 #if 0
@@ -860,3 +862,15 @@ void module_arch_cleanup(struct module *mod)
        deregister_unwind_table(mod);
        module_bug_cleanup(mod);
 }
+
+#ifdef CONFIG_64BIT
+void *dereference_function_descriptor(void *ptr)
+{
+       Elf64_Fdesc *desc = ptr;
+       void *p;
+
+       if (!probe_kernel_address(&desc->addr, p))
+               ptr = p;
+       return ptr;
+}
+#endif
index 9155c93..c6be19e 100644 (file)
@@ -116,6 +116,11 @@ ifeq ($(CONFIG_6xx),y)
 KBUILD_CFLAGS          += -mcpu=powerpc
 endif
 
+# Work around a gcc code-gen bug with -fno-omit-frame-pointer.
+ifeq ($(CONFIG_FTRACE),y)
+KBUILD_CFLAGS          += -mno-sched-epilog
+endif
+
 cpu-as-$(CONFIG_4xx)           += -Wa,-m405
 cpu-as-$(CONFIG_6xx)           += -Wa,-maltivec
 cpu-as-$(CONFIG_POWER4)                += -Wa,-maltivec
index 14174aa..717a3bc 100644 (file)
@@ -49,7 +49,7 @@ zlib       := inffast.c inflate.c inftrees.c
 zlibheader := inffast.h inffixed.h inflate.h inftrees.h infutil.h
 zliblinuxheader := zlib.h zconf.h zutil.h
 
-$(addprefix $(obj)/,$(zlib) gunzip_util.o main.o): \
+$(addprefix $(obj)/,$(zlib) cuboot-c2k.o gunzip_util.o main.o prpmc2800.o): \
        $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
 
 src-libfdt := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
index db0b8f3..4597c49 100644 (file)
 #define __S110 PAGE_SHARED_X
 #define __S111 PAGE_SHARED_X
 
-#ifdef CONFIG_HUGETLB_PAGE
-
+#ifdef CONFIG_PPC_MM_SLICES
 #define HAVE_ARCH_UNMAPPED_AREA
 #define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
-
-#endif
+#endif /* CONFIG_PPC_MM_SLICES */
 
 #ifndef __ASSEMBLY__
 
index 916018e..7710e9e 100644 (file)
@@ -16,6 +16,9 @@ static inline int in_kernel_text(unsigned long addr)
        return 0;
 }
 
+#undef dereference_function_descriptor
+void *dereference_function_descriptor(void *);
+
 #endif
 
 #endif /* __KERNEL__ */
index 64f5948..946daea 100644 (file)
@@ -14,12 +14,13 @@ endif
 
 ifdef CONFIG_FTRACE
 # Do not trace early boot code
-CFLAGS_REMOVE_cputable.o = -pg
-CFLAGS_REMOVE_prom_init.o = -pg
+CFLAGS_REMOVE_cputable.o = -pg -mno-sched-epilog
+CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog
+CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog
 
 ifdef CONFIG_DYNAMIC_FTRACE
 # dynamic ftrace setup.
-CFLAGS_REMOVE_ftrace.o = -pg
+CFLAGS_REMOVE_ftrace.o = -pg -mno-sched-epilog
 endif
 
 endif
index 3671297..5af4e9b 100644 (file)
@@ -647,7 +647,7 @@ static int emulate_vsx(unsigned char __user *addr, unsigned int reg,
                       unsigned int flags, unsigned int length)
 {
        char *ptr = (char *) &current->thread.TS_FPR(reg);
-       int ret;
+       int ret = 0;
 
        flush_vsx_to_thread(current);
 
index 019b02d..15c611d 100644 (file)
@@ -158,7 +158,7 @@ _GLOBAL(power_save_ppc32_restore)
        stw     r9,_NIP(r11)            /* make it do a blr */
 
 #ifdef CONFIG_SMP
-       mfspr   r12,SPRN_SPRG3
+       rlwinm  r12,r11,0,0,31-THREAD_SHIFT
        lwz     r11,TI_CPU(r12)         /* get cpu number * 4 */
        slwi    r11,r11,2
 #else
index 0630403..47a1a98 100644 (file)
@@ -84,10 +84,11 @@ _GLOBAL(power_save_ppc32_restore)
        stw     r9,_NIP(r11)            /* make it do a blr */
 
 #ifdef CONFIG_SMP
-       mfspr   r12,SPRN_SPRG3
+       rlwinm  r12,r1,0,0,31-THREAD_SHIFT
        lwz     r11,TI_CPU(r12)         /* get cpu number * 4 */
        slwi    r11,r11,2
 #else
        li      r11,0
 #endif
+
        b       transfer_to_handler_cont
index ee6a298..ad79de2 100644 (file)
@@ -21,8 +21,9 @@
 #include <linux/err.h>
 #include <linux/vmalloc.h>
 #include <linux/bug.h>
+#include <linux/uaccess.h>
 #include <asm/module.h>
-#include <asm/uaccess.h>
+#include <asm/sections.h>
 #include <asm/firmware.h>
 #include <asm/code-patching.h>
 #include <linux/sort.h>
@@ -451,3 +452,13 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
 
        return 0;
 }
+
+void *dereference_function_descriptor(void *ptr)
+{
+       struct ppc64_opd_entry *desc = ptr;
+       void *p;
+
+       if (!probe_kernel_address(&desc->funcaddr, p))
+               ptr = p;
+       return ptr;
+}
index 4a8ce62..9f6c1ca 100644 (file)
@@ -66,11 +66,12 @@ SECTIONS
                __got2_end = .;
 #endif /* CONFIG_PPC32 */
 
-               . = ALIGN(PAGE_SIZE);
-               _etext = .;
-               PROVIDE32 (etext = .);
        } :kernel
 
+       . = ALIGN(PAGE_SIZE);
+       _etext = .;
+       PROVIDE32 (etext = .);
+
        /* Read-only data */
        RODATA
 
index 14be408..8920eea 100644 (file)
@@ -191,12 +191,17 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
                unsigned long hash, hpteg;
                unsigned long vsid = get_kernel_vsid(vaddr, ssize);
                unsigned long va = hpt_va(vaddr, vsid, ssize);
+               unsigned long tprot = prot;
+
+               /* Make kernel text executable */
+               if (in_kernel_text(vaddr))
+                       tprot &= ~HPTE_R_N;
 
                hash = hpt_hash(va, shift, ssize);
                hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
 
                BUG_ON(!ppc_md.hpte_insert);
-               ret = ppc_md.hpte_insert(hpteg, va, paddr, prot,
+               ret = ppc_md.hpte_insert(hpteg, va, paddr, tprot,
                                         HPTE_V_BOLTED, psize, ssize);
 
                if (ret < 0)
@@ -584,7 +589,7 @@ void __init htab_initialize(void)
 {
        unsigned long table;
        unsigned long pteg_count;
-       unsigned long prot, tprot;
+       unsigned long prot;
        unsigned long base = 0, size = 0, limit;
        int i;
 
@@ -660,10 +665,9 @@ void __init htab_initialize(void)
        for (i=0; i < lmb.memory.cnt; i++) {
                base = (unsigned long)__va(lmb.memory.region[i].base);
                size = lmb.memory.region[i].size;
-               tprot = prot | (in_kernel_text(base) ? _PAGE_EXEC : 0);
 
                DBG("creating mapping for region: %lx..%lx (prot: %x)\n",
-                   base, size, tprot);
+                   base, size, prot);
 
 #ifdef CONFIG_U3_DART
                /* Do not map the DART space. Fortunately, it will be aligned
@@ -680,21 +684,21 @@ void __init htab_initialize(void)
                        unsigned long dart_table_end = dart_tablebase + 16 * MB;
                        if (base != dart_tablebase)
                                BUG_ON(htab_bolt_mapping(base, dart_tablebase,
-                                                       __pa(base), tprot,
+                                                       __pa(base), prot,
                                                        mmu_linear_psize,
                                                        mmu_kernel_ssize));
                        if ((base + size) > dart_table_end)
                                BUG_ON(htab_bolt_mapping(dart_tablebase+16*MB,
                                                        base + size,
                                                        __pa(dart_table_end),
-                                                        tprot,
+                                                        prot,
                                                         mmu_linear_psize,
                                                         mmu_kernel_ssize));
                        continue;
                }
 #endif /* CONFIG_U3_DART */
                BUG_ON(htab_bolt_mapping(base, base + size, __pa(base),
-                               tprot, mmu_linear_psize, mmu_kernel_ssize));
+                               prot, mmu_linear_psize, mmu_kernel_ssize));
        }
 
        /*
index 1c1b627..67595bc 100644 (file)
@@ -643,9 +643,10 @@ static struct spu *find_victim(struct spu_context *ctx)
                            !(tmp->flags & SPU_CREATE_NOSCHED) &&
                            (!victim || tmp->prio > victim->prio)) {
                                victim = spu->ctx;
-                               get_spu_context(victim);
                        }
                }
+               if (victim)
+                       get_spu_context(victim);
                mutex_unlock(&cbe_spu_info[node].list_mutex);
 
                if (victim) {
@@ -727,17 +728,33 @@ static void spu_schedule(struct spu *spu, struct spu_context *ctx)
        /* not a candidate for interruptible because it's called either
           from the scheduler thread or from spu_deactivate */
        mutex_lock(&ctx->state_mutex);
-       __spu_schedule(spu, ctx);
+       if (ctx->state == SPU_STATE_SAVED)
+               __spu_schedule(spu, ctx);
        spu_release(ctx);
 }
 
-static void spu_unschedule(struct spu *spu, struct spu_context *ctx)
+/**
+ * spu_unschedule - remove a context from a spu, and possibly release it.
+ * @spu:       The SPU to unschedule from
+ * @ctx:       The context currently scheduled on the SPU
+ * @free_spu   Whether to free the SPU for other contexts
+ *
+ * Unbinds the context @ctx from the SPU @spu. If @free_spu is non-zero, the
+ * SPU is made available for other contexts (ie, may be returned by
+ * spu_get_idle). If this is zero, the caller is expected to schedule another
+ * context to this spu.
+ *
+ * Should be called with ctx->state_mutex held.
+ */
+static void spu_unschedule(struct spu *spu, struct spu_context *ctx,
+               int free_spu)
 {
        int node = spu->node;
 
        mutex_lock(&cbe_spu_info[node].list_mutex);
        cbe_spu_info[node].nr_active--;
-       spu->alloc_state = SPU_FREE;
+       if (free_spu)
+               spu->alloc_state = SPU_FREE;
        spu_unbind_context(spu, ctx);
        ctx->stats.invol_ctx_switch++;
        spu->stats.invol_ctx_switch++;
@@ -837,7 +854,7 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio)
        if (spu) {
                new = grab_runnable_context(max_prio, spu->node);
                if (new || force) {
-                       spu_unschedule(spu, ctx);
+                       spu_unschedule(spu, ctx, new == NULL);
                        if (new) {
                                if (new->flags & SPU_CREATE_NOSCHED)
                                        wake_up(&new->stop_wq);
@@ -910,7 +927,7 @@ static noinline void spusched_tick(struct spu_context *ctx)
 
        new = grab_runnable_context(ctx->prio + 1, spu->node);
        if (new) {
-               spu_unschedule(spu, ctx);
+               spu_unschedule(spu, ctx, 0);
                if (test_bit(SPU_SCHED_SPU_RUN, &ctx->sched_flags))
                        spu_add_to_rq(ctx);
        } else {
index 58ecdd7..be60d64 100644 (file)
@@ -2,7 +2,7 @@ CFLAGS_bootx_init.o             += -fPIC
 
 ifdef CONFIG_FTRACE
 # Do not trace early boot code
-CFLAGS_REMOVE_bootx_init.o = -pg
+CFLAGS_REMOVE_bootx_init.o = -pg -mno-sched-epilog
 endif
 
 obj-y                          += pic.o setup.o time.o feature.o pci.o \
index cde81fa..a2be3a9 100644 (file)
@@ -42,6 +42,7 @@ struct user_regs_struct32
        u32 gprs[NUM_GPRS];
        u32 acrs[NUM_ACRS];
        u32 orig_gpr2;
+       /* nb: there's a 4-byte hole here */
        s390_fp_regs fp_regs;
        /*
         * These per registers are in here so that gdb can modify them
index 2815bfe..c8b0828 100644 (file)
@@ -170,6 +170,13 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr)
                 */
                tmp = (addr_t) task_pt_regs(child)->orig_gpr2;
 
+       } else if (addr < (addr_t) &dummy->regs.fp_regs) {
+               /*
+                * prevent reads of padding hole between
+                * orig_gpr2 and fp_regs on s390.
+                */
+               tmp = 0;
+
        } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
                /* 
                 * floating point regs. are stored in the thread structure
@@ -270,6 +277,13 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data)
                 */
                task_pt_regs(child)->orig_gpr2 = data;
 
+       } else if (addr < (addr_t) &dummy->regs.fp_regs) {
+               /*
+                * prevent writes of padding hole between
+                * orig_gpr2 and fp_regs on s390.
+                */
+               return 0;
+
        } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
                /*
                 * floating point regs. are stored in the thread structure
@@ -428,6 +442,13 @@ static u32 __peek_user_compat(struct task_struct *child, addr_t addr)
                 */
                tmp = *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4);
 
+       } else if (addr < (addr_t) &dummy32->regs.fp_regs) {
+               /*
+                * prevent reads of padding hole between
+                * orig_gpr2 and fp_regs on s390.
+                */
+               tmp = 0;
+
        } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
                /*
                 * floating point regs. are stored in the thread structure 
@@ -514,6 +535,13 @@ static int __poke_user_compat(struct task_struct *child,
                 */
                *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4) = tmp;
 
+       } else if (addr < (addr_t) &dummy32->regs.fp_regs) {
+               /*
+                * prevent writess of padding hole between
+                * orig_gpr2 and fp_regs on s390.
+                */
+               return 0;
+
        } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
                /*
                 * floating point regs. are stored in the thread structure 
index 29926a9..851c870 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.26
-# Wed Jul 30 01:18:59 2008
+# Linux kernel version: 2.6.27-rc4
+# Tue Aug 26 14:21:17 2008
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
@@ -11,6 +11,7 @@ CONFIG_GENERIC_BUG=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_TIME=y
@@ -20,7 +21,6 @@ CONFIG_LOCKDEP_SUPPORT=y
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_ARCH_NO_VIRT_TO_BUS=y
-CONFIG_ARCH_SUPPORTS_AOUT=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
@@ -58,7 +58,6 @@ CONFIG_SYSCTL=y
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 # CONFIG_KALLSYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
@@ -89,6 +88,7 @@ CONFIG_HAVE_OPROFILE=y
 # CONFIG_USE_GENERIC_SMP_HELPERS is not set
 CONFIG_HAVE_CLK=y
 CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
@@ -261,9 +261,10 @@ CONFIG_HZ_250=y
 # CONFIG_HZ_300 is not set
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=250
-# CONFIG_SCHED_HRTICK is not set
+CONFIG_SCHED_HRTICK=y
 # CONFIG_KEXEC is not set
 # CONFIG_CRASH_DUMP is not set
+CONFIG_SECCOMP=y
 # CONFIG_PREEMPT_NONE is not set
 # CONFIG_PREEMPT_VOLUNTARY is not set
 CONFIG_PREEMPT=y
@@ -289,10 +290,6 @@ CONFIG_CMDLINE="console=tty1 console=ttySC5,38400 root=/dev/nfs ip=dhcp"
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-
-#
-# Networking
-#
 CONFIG_NET=y
 
 #
@@ -647,6 +644,7 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
 
 #
 # Multimedia devices
@@ -690,7 +688,10 @@ CONFIG_DUMMY_CONSOLE=y
 # CONFIG_ACCESSIBILITY is not set
 # CONFIG_RTC_CLASS is not set
 # CONFIG_DMADEVICES is not set
-# CONFIG_UIO is not set
+CONFIG_UIO=y
+# CONFIG_UIO_PDRV is not set
+CONFIG_UIO_PDRV_GENIRQ=y
+# CONFIG_UIO_SMX is not set
 
 #
 # File systems
@@ -854,6 +855,7 @@ CONFIG_FRAME_WARN=1024
 # CONFIG_DEBUG_KERNEL is not set
 # CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_DEBUG_MEMORY_INIT is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
 # CONFIG_SAMPLES is not set
 # CONFIG_SH_STANDARD_BIOS is not set
 # CONFIG_EARLY_SCIF_CONSOLE is not set
index c4b3e1d..4f8b197 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.26
-# Wed Jul 30 01:44:41 2008
+# Linux kernel version: 2.6.27-rc4
+# Tue Aug 26 14:18:17 2008
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
@@ -11,6 +11,7 @@ CONFIG_GENERIC_BUG=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_TIME=y
@@ -21,7 +22,6 @@ CONFIG_LOCKDEP_SUPPORT=y
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_ARCH_NO_VIRT_TO_BUS=y
-CONFIG_ARCH_SUPPORTS_AOUT=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
@@ -87,6 +87,7 @@ CONFIG_HAVE_OPROFILE=y
 # CONFIG_USE_GENERIC_SMP_HELPERS is not set
 CONFIG_HAVE_CLK=y
 CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
@@ -270,6 +271,7 @@ CONFIG_HZ=250
 # CONFIG_SCHED_HRTICK is not set
 # CONFIG_KEXEC is not set
 # CONFIG_CRASH_DUMP is not set
+CONFIG_SECCOMP=y
 CONFIG_PREEMPT_NONE=y
 # CONFIG_PREEMPT_VOLUNTARY is not set
 # CONFIG_PREEMPT is not set
@@ -294,10 +296,6 @@ CONFIG_CMDLINE="console=ttySC0,115200 earlyprintk=serial ip=on"
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-
-#
-# Networking
-#
 CONFIG_NET=y
 
 #
@@ -649,6 +647,7 @@ CONFIG_HW_RANDOM=y
 CONFIG_I2C=y
 CONFIG_I2C_BOARDINFO=y
 # CONFIG_I2C_CHARDEV is not set
+CONFIG_I2C_HELPER_AUTO=y
 
 #
 # I2C Hardware Bus support
@@ -709,6 +708,7 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
 
 #
 # Multimedia devices
@@ -755,6 +755,8 @@ CONFIG_USB_ARCH_HAS_HCD=y
 # CONFIG_USB is not set
 # CONFIG_USB_OTG_WHITELIST is not set
 # CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
 
 #
 # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
@@ -842,7 +844,10 @@ CONFIG_RTC_DRV_RS5C372=y
 #
 CONFIG_RTC_DRV_SH=y
 # CONFIG_DMADEVICES is not set
-# CONFIG_UIO is not set
+CONFIG_UIO=y
+# CONFIG_UIO_PDRV is not set
+CONFIG_UIO_PDRV_GENIRQ=y
+# CONFIG_UIO_SMX is not set
 
 #
 # File systems
index 81b3d51..5580fd4 100644 (file)
@@ -76,4 +76,6 @@ extern long __put_user_asm_l(void *, long);
 extern long __put_user_asm_q(void *, long);
 extern void __put_user_unknown(void);
 
+extern long __strnlen_user(const char *__s, long __n);
+
 #endif /* __ASM_SH_UACCESS_64_H */
index 04c7da9..e640c63 100644 (file)
@@ -2,7 +2,7 @@
  * arch/sh/kernel/cpu/sh5/entry.S
  *
  * Copyright (C) 2000, 2001  Paolo Alberelli
- * Copyright (C) 2004 - 2007  Paul Mundt
+ * Copyright (C) 2004 - 2008  Paul Mundt
  * Copyright (C) 2003, 2004  Richard Curnow
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -923,6 +923,8 @@ ret_from_exception:
        blink   tr0, ZERO
 
 resume_kernel:
+       CLI()
+
        pta     restore_all, tr0
 
        getcon  KCR0, r6
@@ -939,19 +941,11 @@ need_resched:
        andi    r7, 0xf0, r7
        bne     r7, ZERO, tr0
 
-       movi    ((PREEMPT_ACTIVE >> 16) & 65535), r8
-       shori   (PREEMPT_ACTIVE & 65535), r8
-       st.l    r6, TI_PRE_COUNT, r8
-
-       STI()
-       movi    schedule, r7
+       movi    preempt_schedule_irq, r7
        ori     r7, 1, r7
        ptabs   r7, tr1
        blink   tr1, LINK
 
-       st.l    r6, TI_PRE_COUNT, ZERO
-       CLI()
-
        pta     need_resched, tr1
        blink   tr1, ZERO
 #endif
index 0bc17de..efbb426 100644 (file)
@@ -92,6 +92,7 @@ ENTRY(ret_from_irq)
        bra     resume_userspace
         nop
 ENTRY(resume_kernel)
+       cli
        mov.l   @(TI_PRE_COUNT,r8), r0  ! current_thread_info->preempt_count
        tst     r0, r0
        bf      noresched
@@ -105,28 +106,9 @@ need_resched:
        and     #0xf0, r0               ! interrupts off (exception path)?
        cmp/eq  #0xf0, r0
        bt      noresched
-
-       mov.l   1f, r0
-       mov.l   r0, @(TI_PRE_COUNT,r8)
-
-#ifdef CONFIG_TRACE_IRQFLAGS
        mov.l   3f, r0
-       jsr     @r0
-        nop
-#endif
-       sti
-       mov.l   2f, r0
-       jsr     @r0
-        nop
-       mov     #0, r0
-       mov.l   r0, @(TI_PRE_COUNT,r8)
-       cli
-#ifdef CONFIG_TRACE_IRQFLAGS
-       mov.l   4f, r0
-       jsr     @r0
+       jsr     @r0                     ! call preempt_schedule_irq
         nop
-#endif
-
        bra     need_resched
         nop
 
@@ -137,10 +119,7 @@ noresched:
        .align 2
 1:     .long   PREEMPT_ACTIVE
 2:     .long   schedule
-#ifdef CONFIG_TRACE_IRQFLAGS
-3:     .long   trace_hardirqs_on
-4:     .long   trace_hardirqs_off
-#endif
+3:     .long   preempt_schedule_irq
 #endif
 
 ENTRY(resume_userspace)
index 4703dff..94df56b 100644 (file)
@@ -102,7 +102,7 @@ void machine_kexec(struct kimage *image)
 
        /* now call it */
        rnk = (relocate_new_kernel_t) reboot_code_buffer;
-       (*rnk)(page_list, reboot_code_buffer, image->start, vbr_reg);
+       (*rnk)(page_list, reboot_code_buffer, P2SEGADDR(image->start), vbr_reg);
 }
 
 void arch_crash_save_vmcoreinfo(void)
index 5922edd..9c64248 100644 (file)
@@ -131,6 +131,8 @@ void user_enable_single_step(struct task_struct *child)
 
 void user_disable_single_step(struct task_struct *child)
 {
+       struct pt_regs *regs = child->thread.uregs;
+
        regs->sr &= ~SR_SSTEP;
 }
 
index a352076..de83205 100644 (file)
@@ -171,6 +171,7 @@ static void __init reserve_crashkernel(void)
                                (unsigned long)(free_mem >> 20));
                crashk_res.start = crash_base;
                crashk_res.end   = crash_base + crash_size - 1;
+               insert_resource(&iomem_resource, &crashk_res);
        }
 }
 #else
@@ -204,11 +205,6 @@ void __init __add_active_range(unsigned int nid, unsigned long start_pfn,
        request_resource(res, &data_resource);
        request_resource(res, &bss_resource);
 
-#ifdef CONFIG_KEXEC
-       if (crashk_res.start != crashk_res.end)
-               request_resource(res, &crashk_res);
-#endif
-
        add_active_range(nid, start_pfn, end_pfn);
 }
 
index 59cd285..9061b86 100644 (file)
@@ -170,7 +170,7 @@ asmlinkage int sys_ipc(uint call, int first, int second,
        version = call >> 16; /* hack for backward compatibility */
        call &= 0xffff;
 
-       if (call <= SEMCTL)
+       if (call <= SEMTIMEDOP)
                switch (call) {
                case SEMOP:
                        return sys_semtimedop(first,
index 895bb3f..64b8f7f 100644 (file)
@@ -101,7 +101,7 @@ static int __init memchunk_setup(char *str)
 }
 __setup("memchunk.", memchunk_setup);
 
-static void memchunk_cmdline_override(char *name, unsigned long *sizep)
+static void __init memchunk_cmdline_override(char *name, unsigned long *sizep)
 {
        char *p = boot_command_line;
        int k = strlen(name);
@@ -118,8 +118,8 @@ static void memchunk_cmdline_override(char *name, unsigned long *sizep)
        }
 }
 
-int platform_resource_setup_memory(struct platform_device *pdev,
-                                  char *name, unsigned long memsize)
+int __init platform_resource_setup_memory(struct platform_device *pdev,
+                                         char *name, unsigned long memsize)
 {
        struct resource *r;
        dma_addr_t dma_handle;
index 743ccad..2be166c 100644 (file)
@@ -80,8 +80,6 @@ void smp_bogo(struct seq_file *m)
                           i, cpu_data(i).clock_tick);
 }
 
-static __cacheline_aligned_in_smp DEFINE_SPINLOCK(call_lock);
-
 extern void setup_sparc64_timer(void);
 
 static volatile unsigned long callin_flag = 0;
@@ -120,9 +118,9 @@ void __cpuinit smp_callin(void)
        while (!cpu_isset(cpuid, smp_commenced_mask))
                rmb();
 
-       spin_lock(&call_lock);
+       ipi_call_lock();
        cpu_set(cpuid, cpu_online_map);
-       spin_unlock(&call_lock);
+       ipi_call_unlock();
 
        /* idle thread is expected to have preempt disabled */
        preempt_disable();
@@ -1305,10 +1303,6 @@ int __cpu_disable(void)
        c->core_id = 0;
        c->proc_id = -1;
 
-       spin_lock(&call_lock);
-       cpu_clear(cpu, cpu_online_map);
-       spin_unlock(&call_lock);
-
        smp_wmb();
 
        /* Make sure no interrupts point to this cpu.  */
@@ -1318,6 +1312,10 @@ int __cpu_disable(void)
        mdelay(1);
        local_irq_disable();
 
+       ipi_call_lock();
+       cpu_clear(cpu, cpu_online_map);
+       ipi_call_unlock();
+
        return 0;
 }
 
index 59fd3b6..73deaff 100644 (file)
@@ -210,8 +210,8 @@ static void hpet_legacy_clockevent_register(void)
        /* Calculate the min / max delta */
        hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
                                                           &hpet_clockevent);
-       hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30,
-                                                          &hpet_clockevent);
+       /* 5 usec minimum reprogramming delta. */
+       hpet_clockevent.min_delta_ns = 5000;
 
        /*
         * Start hpet with the boot cpu mask and make it
@@ -270,15 +270,22 @@ static void hpet_legacy_set_mode(enum clock_event_mode mode,
 }
 
 static int hpet_legacy_next_event(unsigned long delta,
-                          struct clock_event_device *evt)
+                                 struct clock_event_device *evt)
 {
-       unsigned long cnt;
+       u32 cnt;
 
        cnt = hpet_readl(HPET_COUNTER);
-       cnt += delta;
+       cnt += (u32) delta;
        hpet_writel(cnt, HPET_T0_CMP);
 
-       return ((long)(hpet_readl(HPET_COUNTER) - cnt ) > 0) ? -ETIME : 0;
+       /*
+        * We need to read back the CMP register to make sure that
+        * what we wrote hit the chip before we compare it to the
+        * counter.
+        */
+       WARN_ON((u32)hpet_readl(HPET_T0_CMP) != cnt);
+
+       return (s32)((u32)hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0;
 }
 
 /*
index 346cae5..8f98e9d 100644 (file)
@@ -267,8 +267,7 @@ unsigned long native_calibrate_tsc(void)
         */
        if (tsc_pit_min == ULONG_MAX) {
                /* PIT gave no useful value */
-               printk(KERN_WARNING "TSC: PIT calibration failed due to "
-                      "SMI disturbance.\n");
+               printk(KERN_WARNING "TSC: Unable to calibrate against PIT\n");
 
                /* We don't have an alternative source, disable TSC */
                if (!hpet && !pm1 && !pm2) {
index 85eaf7b..e8362c1 100644 (file)
@@ -137,7 +137,8 @@ async_tx_run_dependencies(struct dma_async_tx_descriptor *tx)
                spin_lock_bh(&next->lock);
                next->parent = NULL;
                _next = next->next;
-               next->next = NULL;
+               if (_next && _next->chan == chan)
+                       next->next = NULL;
                spin_unlock_bh(&next->lock);
 
                next->tx_submit(next);
index b1cc4de..493fee7 100644 (file)
@@ -35,8 +35,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/bitops.h>
-#include <asm/unaligned.h>
 
 static const u32 camellia_sp1110[256] = {
        0x70707000,0x82828200,0x2c2c2c00,0xececec00,
@@ -337,6 +335,20 @@ static const u32 camellia_sp4404[256] = {
 /*
  *  macros
  */
+#define GETU32(v, pt) \
+    do { \
+       /* latest breed of gcc is clever enough to use move */ \
+       memcpy(&(v), (pt), 4); \
+       (v) = be32_to_cpu(v); \
+    } while(0)
+
+/* rotation right shift 1byte */
+#define ROR8(x) (((x) >> 8) + ((x) << 24))
+/* rotation left shift 1bit */
+#define ROL1(x) (((x) << 1) + ((x) >> 31))
+/* rotation left shift 1byte */
+#define ROL8(x) (((x) << 8) + ((x) >> 24))
+
 #define ROLDQ(ll, lr, rl, rr, w0, w1, bits)            \
     do {                                               \
        w0 = ll;                                        \
@@ -371,7 +383,7 @@ static const u32 camellia_sp4404[256] = {
           ^ camellia_sp3033[(u8)(il >> 8)]                     \
           ^ camellia_sp4404[(u8)(il     )];                    \
        yl ^= yr;                                               \
-       yr = ror32(yr, 8);                                      \
+       yr = ROR8(yr);                                          \
        yr ^= yl;                                               \
     } while(0)
 
@@ -393,7 +405,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        subL[7] ^= subL[1]; subR[7] ^= subR[1];
        subL[1] ^= subR[1] & ~subR[9];
        dw = subL[1] & subL[9],
-               subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl2) */
+               subR[1] ^= ROL1(dw); /* modified for FLinv(kl2) */
        /* round 8 */
        subL[11] ^= subL[1]; subR[11] ^= subR[1];
        /* round 10 */
@@ -402,7 +414,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        subL[15] ^= subL[1]; subR[15] ^= subR[1];
        subL[1] ^= subR[1] & ~subR[17];
        dw = subL[1] & subL[17],
-               subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl4) */
+               subR[1] ^= ROL1(dw); /* modified for FLinv(kl4) */
        /* round 14 */
        subL[19] ^= subL[1]; subR[19] ^= subR[1];
        /* round 16 */
@@ -418,7 +430,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        } else {
                subL[1] ^= subR[1] & ~subR[25];
                dw = subL[1] & subL[25],
-                       subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl6) */
+                       subR[1] ^= ROL1(dw); /* modified for FLinv(kl6) */
                /* round 20 */
                subL[27] ^= subL[1]; subR[27] ^= subR[1];
                /* round 22 */
@@ -438,7 +450,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
                subL[26] ^= kw4l; subR[26] ^= kw4r;
                kw4l ^= kw4r & ~subR[24];
                dw = kw4l & subL[24],
-                       kw4r ^= rol32(dw, 1); /* modified for FL(kl5) */
+                       kw4r ^= ROL1(dw); /* modified for FL(kl5) */
        }
        /* round 17 */
        subL[22] ^= kw4l; subR[22] ^= kw4r;
@@ -448,7 +460,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        subL[18] ^= kw4l; subR[18] ^= kw4r;
        kw4l ^= kw4r & ~subR[16];
        dw = kw4l & subL[16],
-               kw4r ^= rol32(dw, 1); /* modified for FL(kl3) */
+               kw4r ^= ROL1(dw); /* modified for FL(kl3) */
        /* round 11 */
        subL[14] ^= kw4l; subR[14] ^= kw4r;
        /* round 9 */
@@ -457,7 +469,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        subL[10] ^= kw4l; subR[10] ^= kw4r;
        kw4l ^= kw4r & ~subR[8];
        dw = kw4l & subL[8],
-               kw4r ^= rol32(dw, 1); /* modified for FL(kl1) */
+               kw4r ^= ROL1(dw); /* modified for FL(kl1) */
        /* round 5 */
        subL[6] ^= kw4l; subR[6] ^= kw4r;
        /* round 3 */
@@ -482,7 +494,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        SUBKEY_R(6) = subR[5] ^ subR[7];
        tl = subL[10] ^ (subR[10] & ~subR[8]);
        dw = tl & subL[8],  /* FL(kl1) */
-               tr = subR[10] ^ rol32(dw, 1);
+               tr = subR[10] ^ ROL1(dw);
        SUBKEY_L(7) = subL[6] ^ tl; /* round 6 */
        SUBKEY_R(7) = subR[6] ^ tr;
        SUBKEY_L(8) = subL[8];       /* FL(kl1) */
@@ -491,7 +503,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        SUBKEY_R(9) = subR[9];
        tl = subL[7] ^ (subR[7] & ~subR[9]);
        dw = tl & subL[9],  /* FLinv(kl2) */
-               tr = subR[7] ^ rol32(dw, 1);
+               tr = subR[7] ^ ROL1(dw);
        SUBKEY_L(10) = tl ^ subL[11]; /* round 7 */
        SUBKEY_R(10) = tr ^ subR[11];
        SUBKEY_L(11) = subL[10] ^ subL[12]; /* round 8 */
@@ -504,7 +516,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        SUBKEY_R(14) = subR[13] ^ subR[15];
        tl = subL[18] ^ (subR[18] & ~subR[16]);
        dw = tl & subL[16], /* FL(kl3) */
-               tr = subR[18] ^ rol32(dw, 1);
+               tr = subR[18] ^ ROL1(dw);
        SUBKEY_L(15) = subL[14] ^ tl; /* round 12 */
        SUBKEY_R(15) = subR[14] ^ tr;
        SUBKEY_L(16) = subL[16];     /* FL(kl3) */
@@ -513,7 +525,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        SUBKEY_R(17) = subR[17];
        tl = subL[15] ^ (subR[15] & ~subR[17]);
        dw = tl & subL[17], /* FLinv(kl4) */
-               tr = subR[15] ^ rol32(dw, 1);
+               tr = subR[15] ^ ROL1(dw);
        SUBKEY_L(18) = tl ^ subL[19]; /* round 13 */
        SUBKEY_R(18) = tr ^ subR[19];
        SUBKEY_L(19) = subL[18] ^ subL[20]; /* round 14 */
@@ -532,7 +544,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        } else {
                tl = subL[26] ^ (subR[26] & ~subR[24]);
                dw = tl & subL[24], /* FL(kl5) */
-                       tr = subR[26] ^ rol32(dw, 1);
+                       tr = subR[26] ^ ROL1(dw);
                SUBKEY_L(23) = subL[22] ^ tl; /* round 18 */
                SUBKEY_R(23) = subR[22] ^ tr;
                SUBKEY_L(24) = subL[24];     /* FL(kl5) */
@@ -541,7 +553,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
                SUBKEY_R(25) = subR[25];
                tl = subL[23] ^ (subR[23] & ~subR[25]);
                dw = tl & subL[25], /* FLinv(kl6) */
-                       tr = subR[23] ^ rol32(dw, 1);
+                       tr = subR[23] ^ ROL1(dw);
                SUBKEY_L(26) = tl ^ subL[27]; /* round 19 */
                SUBKEY_R(26) = tr ^ subR[27];
                SUBKEY_L(27) = subL[26] ^ subL[28]; /* round 20 */
@@ -561,17 +573,17 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        /* apply the inverse of the last half of P-function */
        i = 2;
        do {
-               dw = SUBKEY_L(i + 0) ^ SUBKEY_R(i + 0); dw = rol32(dw, 8);/* round 1 */
+               dw = SUBKEY_L(i + 0) ^ SUBKEY_R(i + 0); dw = ROL8(dw);/* round 1 */
                SUBKEY_R(i + 0) = SUBKEY_L(i + 0) ^ dw; SUBKEY_L(i + 0) = dw;
-               dw = SUBKEY_L(i + 1) ^ SUBKEY_R(i + 1); dw = rol32(dw, 8);/* round 2 */
+               dw = SUBKEY_L(i + 1) ^ SUBKEY_R(i + 1); dw = ROL8(dw);/* round 2 */
                SUBKEY_R(i + 1) = SUBKEY_L(i + 1) ^ dw; SUBKEY_L(i + 1) = dw;
-               dw = SUBKEY_L(i + 2) ^ SUBKEY_R(i + 2); dw = rol32(dw, 8);/* round 3 */
+               dw = SUBKEY_L(i + 2) ^ SUBKEY_R(i + 2); dw = ROL8(dw);/* round 3 */
                SUBKEY_R(i + 2) = SUBKEY_L(i + 2) ^ dw; SUBKEY_L(i + 2) = dw;
-               dw = SUBKEY_L(i + 3) ^ SUBKEY_R(i + 3); dw = rol32(dw, 8);/* round 4 */
+               dw = SUBKEY_L(i + 3) ^ SUBKEY_R(i + 3); dw = ROL8(dw);/* round 4 */
                SUBKEY_R(i + 3) = SUBKEY_L(i + 3) ^ dw; SUBKEY_L(i + 3) = dw;
-               dw = SUBKEY_L(i + 4) ^ SUBKEY_R(i + 4); dw = rol32(dw, 9);/* round 5 */
+               dw = SUBKEY_L(i + 4) ^ SUBKEY_R(i + 4); dw = ROL8(dw);/* round 5 */
                SUBKEY_R(i + 4) = SUBKEY_L(i + 4) ^ dw; SUBKEY_L(i + 4) = dw;
-               dw = SUBKEY_L(i + 5) ^ SUBKEY_R(i + 5); dw = rol32(dw, 8);/* round 6 */
+               dw = SUBKEY_L(i + 5) ^ SUBKEY_R(i + 5); dw = ROL8(dw);/* round 6 */
                SUBKEY_R(i + 5) = SUBKEY_L(i + 5) ^ dw; SUBKEY_L(i + 5) = dw;
                i += 8;
        } while (i < max);
@@ -587,10 +599,10 @@ static void camellia_setup128(const unsigned char *key, u32 *subkey)
        /**
         *  k == kll || klr || krl || krr (|| is concatenation)
         */
-       kll = get_unaligned_be32(key);
-       klr = get_unaligned_be32(key + 4);
-       krl = get_unaligned_be32(key + 8);
-       krr = get_unaligned_be32(key + 12);
+       GETU32(kll, key     );
+       GETU32(klr, key +  4);
+       GETU32(krl, key +  8);
+       GETU32(krr, key + 12);
 
        /* generate KL dependent subkeys */
        /* kw1 */
@@ -695,14 +707,14 @@ static void camellia_setup256(const unsigned char *key, u32 *subkey)
         *  key = (kll || klr || krl || krr || krll || krlr || krrl || krrr)
         *  (|| is concatenation)
         */
-       kll = get_unaligned_be32(key);
-       klr = get_unaligned_be32(key + 4);
-       krl = get_unaligned_be32(key + 8);
-       krr = get_unaligned_be32(key + 12);
-       krll = get_unaligned_be32(key + 16);
-       krlr = get_unaligned_be32(key + 20);
-       krrl = get_unaligned_be32(key + 24);
-       krrr = get_unaligned_be32(key + 28);
+       GETU32(kll,  key     );
+       GETU32(klr,  key +  4);
+       GETU32(krl,  key +  8);
+       GETU32(krr,  key + 12);
+       GETU32(krll, key + 16);
+       GETU32(krlr, key + 20);
+       GETU32(krrl, key + 24);
+       GETU32(krrr, key + 28);
 
        /* generate KL dependent subkeys */
        /* kw1 */
@@ -858,13 +870,13 @@ static void camellia_setup192(const unsigned char *key, u32 *subkey)
        t0 &= ll;                                                       \
        t2 |= rr;                                                       \
        rl ^= t2;                                                       \
-       lr ^= rol32(t0, 1);                                             \
+       lr ^= ROL1(t0);                                                 \
        t3 = krl;                                                       \
        t1 = klr;                                                       \
        t3 &= rl;                                                       \
        t1 |= lr;                                                       \
        ll ^= t1;                                                       \
-       rr ^= rol32(t3, 1);                                             \
+       rr ^= ROL1(t3);                                                 \
     } while(0)
 
 #define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir)               \
@@ -880,7 +892,7 @@ static void camellia_setup192(const unsigned char *key, u32 *subkey)
        il ^= kl;                                                       \
        ir ^= il ^ kr;                                                  \
        yl ^= ir;                                                       \
-       yr ^= ror32(il, 8) ^ ir;                                                \
+       yr ^= ROR8(il) ^ ir;                                            \
     } while(0)
 
 /* max = 24: 128bit encrypt, max = 32: 256bit encrypt */
index 1022e38..0f28058 100644 (file)
@@ -496,7 +496,7 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
                        arg = arg->common.next;
                }
 
-               ACPI_ERROR((AE_INFO,
+               ACPI_WARNING((AE_INFO,
                            "Package List length (%X) larger than NumElements count (%X), truncated\n",
                            i, element_count));
        } else if (i < element_count) {
index 80e3209..80c251e 100644 (file)
@@ -71,7 +71,7 @@ static DEFINE_MUTEX(performance_mutex);
  *  1 -> ignore _PPC totally -> forced by user through boot param
  */
 static int ignore_ppc = -1;
-module_param(ignore_ppc, uint, 0644);
+module_param(ignore_ppc, int, 0644);
 MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \
                 "limited by BIOS, this should help");
 
index bcf2c70..a4e3767 100644 (file)
@@ -107,6 +107,13 @@ static int wait_transaction_complete(struct acpi_smb_hc *hc, int timeout)
        if (wait_event_timeout(hc->wait, smb_check_done(hc),
                               msecs_to_jiffies(timeout)))
                return 0;
+       /*
+        * After the timeout happens, OS will try to check the status of SMbus.
+        * If the status is what OS expected, it will be regarded as the bogus
+        * timeout.
+        */
+       if (smb_check_done(hc))
+               return 0;
        else
                return -ETIME;
 }
index c341918..775c97a 100644 (file)
@@ -300,6 +300,8 @@ int __init acpi_table_init(void)
 
 static int __init acpi_parse_apic_instance(char *str)
 {
+       if (!str)
+               return -EINVAL;
 
        acpi_apic_instance = simple_strtoul(str, NULL, 0);
 
index ae84949..11c8c19 100644 (file)
@@ -448,8 +448,10 @@ config PATA_MARVELL
        tristate "Marvell PATA support via legacy mode"
        depends on PCI
        help
-         This option enables limited support for the Marvell 88SE6145 ATA
-         controller.
+         This option enables limited support for the Marvell 88SE61xx ATA
+         controllers. If you wish to use only the SATA ports then select
+         the AHCI driver alone. If you wish to the use the PATA port or
+         both SATA and PATA include this driver.
 
          If unsure, say N.
 
index c729e69..2e1a7cb 100644 (file)
@@ -420,7 +420,7 @@ static const struct ata_port_info ahci_port_info[] = {
        /* board_ahci_mv */
        {
                AHCI_HFLAGS     (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
-                                AHCI_HFLAG_MV_PATA),
+                                AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
                .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
                                  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
                .pio_mask       = 0x1f, /* pio0-4 */
@@ -487,7 +487,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
        { PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
        { PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
+       { PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
        { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
+       { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
 
        /* JMicron 360/1/3/5/6, match class to avoid IDE function */
        { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -610,6 +612,15 @@ module_param(ahci_em_messages, int, 0444);
 MODULE_PARM_DESC(ahci_em_messages,
        "Set AHCI Enclosure Management Message type (0 = disabled, 1 = LED");
 
+#if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE)
+static int marvell_enable;
+#else
+static int marvell_enable = 1;
+#endif
+module_param(marvell_enable, int, 0644);
+MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)");
+
+
 static inline int ahci_nr_ports(u32 cap)
 {
        return (cap & 0x1f) + 1;
@@ -732,6 +743,8 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
                           "MV_AHCI HACK: port_map %x -> %x\n",
                           port_map,
                           port_map & mv);
+               dev_printk(KERN_ERR, &pdev->dev,
+                         "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n");
 
                port_map &= mv;
        }
@@ -2533,6 +2546,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+       /* The AHCI driver can only drive the SATA ports, the PATA driver
+          can drive them all so if both drivers are selected make sure
+          AHCI stays out of the way */
+       if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)
+               return -ENODEV;
+
        /* acquire resources */
        rc = pcim_enable_device(pdev);
        if (rc)
index 304fdc6..2a4c516 100644 (file)
@@ -1315,11 +1315,6 @@ fsm_start:
                break;
 
        case HSM_ST_ERR:
-               /* make sure qc->err_mask is available to
-                * know what's wrong and recover
-                */
-               WARN_ON(!(qc->err_mask & (AC_ERR_DEV | AC_ERR_HSM)));
-
                ap->hsm_task_state = HSM_ST_IDLE;
 
                /* complete taskfile transaction */
index 24a011b..0d87eec 100644 (file)
 #include <linux/ata.h>
 
 #define DRV_NAME       "pata_marvell"
-#define DRV_VERSION    "0.1.4"
+#define DRV_VERSION    "0.1.6"
 
 /**
- *     marvell_pre_reset       -       check for 40/80 pin
- *     @link: link
- *     @deadline: deadline jiffies for the operation
+ *     marvell_pata_active     -       check if PATA is active
+ *     @pdev: PCI device
  *
- *     Perform the PATA port setup we need.
+ *     Returns 1 if the PATA port may be active. We know how to check this
+ *     for the 6145 but not the other devices
  */
 
-static int marvell_pre_reset(struct ata_link *link, unsigned long deadline)
+static int marvell_pata_active(struct pci_dev *pdev)
 {
-       struct ata_port *ap = link->ap;
-       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       int i;
        u32 devices;
        void __iomem *barp;
-       int i;
 
-       /* Check if our port is enabled */
+       /* We don't yet know how to do this for other devices */
+       if (pdev->device != 0x6145)
+               return 1;       
 
        barp = pci_iomap(pdev, 5, 0x10);
        if (barp == NULL)
                return -ENOMEM;
+
        printk("BAR5:");
        for(i = 0; i <= 0x0F; i++)
                printk("%02X:%02X ", i, ioread8(barp + i));
@@ -51,9 +52,27 @@ static int marvell_pre_reset(struct ata_link *link, unsigned long deadline)
        devices = ioread32(barp + 0x0C);
        pci_iounmap(pdev, barp);
 
-       if ((pdev->device == 0x6145) && (ap->port_no == 0) &&
-           (!(devices & 0x10)))        /* PATA enable ? */
-               return -ENOENT;
+       if (devices & 0x10)
+               return 1;
+       return 0;
+}
+
+/**
+ *     marvell_pre_reset       -       check for 40/80 pin
+ *     @link: link
+ *     @deadline: deadline jiffies for the operation
+ *
+ *     Perform the PATA port setup we need.
+ */
+
+static int marvell_pre_reset(struct ata_link *link, unsigned long deadline)
+{
+       struct ata_port *ap = link->ap;
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+       if (pdev->device == 0x6145 && ap->port_no == 0 &&
+               !marvell_pata_active(pdev))     /* PATA enable ? */
+                       return -ENOENT;
 
        return ata_sff_prereset(link, deadline);
 }
@@ -128,6 +147,12 @@ static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *i
        if (pdev->device == 0x6101)
                ppi[1] = &ata_dummy_port_info;
 
+#if defined(CONFIG_AHCI) || defined(CONFIG_AHCI_MODULE)
+       if (!marvell_pata_active(pdev)) {
+               printk(KERN_INFO DRV_NAME ": PATA port not active, deferring to AHCI driver.\n");
+               return -ENODEV;
+       }
+#endif
        return ata_pci_sff_init_one(pdev, ppi, &marvell_sht, NULL);
 }
 
index 720b864..e970b22 100644 (file)
@@ -322,9 +322,6 @@ static int __devinit sil680_init_one(struct pci_dev *pdev,
        /* Try to acquire MMIO resources and fallback to PIO if
         * that fails
         */
-       rc = pcim_enable_device(pdev);
-       if (rc)
-               return rc;
        rc = pcim_iomap_regions(pdev, 1 << SIL680_MMIO_BAR, DRV_NAME);
        if (rc)
                goto use_ioports;
index 13c1d2a..c815f8e 100644 (file)
@@ -667,7 +667,8 @@ static const struct pci_device_id mv_pci_tbl[] = {
        { PCI_VDEVICE(MARVELL, 0x5041), chip_504x },
        { PCI_VDEVICE(MARVELL, 0x5080), chip_5080 },
        { PCI_VDEVICE(MARVELL, 0x5081), chip_508x },
-       /* RocketRAID 1740/174x have different identifiers */
+       /* RocketRAID 1720/174x have different identifiers */
+       { PCI_VDEVICE(TTI, 0x1720), chip_6042 },
        { PCI_VDEVICE(TTI, 0x1740), chip_508x },
        { PCI_VDEVICE(TTI, 0x1742), chip_508x },
 
index 858f706..1e1f3f3 100644 (file)
@@ -309,8 +309,6 @@ static void nv_nf2_freeze(struct ata_port *ap);
 static void nv_nf2_thaw(struct ata_port *ap);
 static void nv_ck804_freeze(struct ata_port *ap);
 static void nv_ck804_thaw(struct ata_port *ap);
-static int nv_hardreset(struct ata_link *link, unsigned int *class,
-                       unsigned long deadline);
 static int nv_adma_slave_config(struct scsi_device *sdev);
 static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc);
 static void nv_adma_qc_prep(struct ata_queued_cmd *qc);
@@ -407,7 +405,7 @@ static struct scsi_host_template nv_swncq_sht = {
 
 static struct ata_port_operations nv_generic_ops = {
        .inherits               = &ata_bmdma_port_ops,
-       .hardreset              = nv_hardreset,
+       .hardreset              = ATA_OP_NULL,
        .scr_read               = nv_scr_read,
        .scr_write              = nv_scr_write,
 };
@@ -1588,21 +1586,6 @@ static void nv_mcp55_thaw(struct ata_port *ap)
        ata_sff_thaw(ap);
 }
 
-static int nv_hardreset(struct ata_link *link, unsigned int *class,
-                       unsigned long deadline)
-{
-       int rc;
-
-       /* SATA hardreset fails to retrieve proper device signature on
-        * some controllers.  Request follow up SRST.  For more info,
-        * see http://bugzilla.kernel.org/show_bug.cgi?id=3352
-        */
-       rc = sata_sff_hardreset(link, class, deadline);
-       if (rc)
-               return rc;
-       return -EAGAIN;
-}
-
 static void nv_adma_error_handler(struct ata_port *ap)
 {
        struct nv_adma_port_priv *pp = ap->private_data;
index 5ca1d80..4eee533 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 
 /*
@@ -151,13 +152,13 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE,
  */
 static int verify_pmtmr_rate(void)
 {
-       u32 value1, value2;
+       cycle_t value1, value2;
        unsigned long count, delta;
 
        mach_prepare_counter();
-       value1 = read_pmtmr();
+       value1 = clocksource_acpi_pm.read();
        mach_countup(&count);
-       value2 = read_pmtmr();
+       value2 = clocksource_acpi_pm.read();
        delta = (value2 - value1) & ACPI_PM_MASK;
 
        /* Check that the PMTMR delta is within 5% of what we expect */
@@ -175,10 +176,13 @@ static int verify_pmtmr_rate(void)
 #define verify_pmtmr_rate() (0)
 #endif
 
+/* Number of monotonicity checks to perform during initialization */
+#define ACPI_PM_MONOTONICITY_CHECKS 10
+
 static int __init init_acpi_pm_clocksource(void)
 {
-       u32 value1, value2;
-       unsigned int i;
+       cycle_t value1, value2;
+       unsigned int i, j, good = 0;
 
        if (!pmtmr_ioport)
                return -ENODEV;
@@ -187,24 +191,32 @@ static int __init init_acpi_pm_clocksource(void)
                                                clocksource_acpi_pm.shift);
 
        /* "verify" this timing source: */
-       value1 = read_pmtmr();
-       for (i = 0; i < 10000; i++) {
-               value2 = read_pmtmr();
-               if (value2 == value1)
-                       continue;
-               if (value2 > value1)
-                       goto pm_good;
-               if ((value2 < value1) && ((value2) < 0xFFF))
-                       goto pm_good;
-               printk(KERN_INFO "PM-Timer had inconsistent results:"
-                       " 0x%#x, 0x%#x - aborting.\n", value1, value2);
-               return -EINVAL;
+       for (j = 0; j < ACPI_PM_MONOTONICITY_CHECKS; j++) {
+               value1 = clocksource_acpi_pm.read();
+               for (i = 0; i < 10000; i++) {
+                       value2 = clocksource_acpi_pm.read();
+                       if (value2 == value1)
+                               continue;
+                       if (value2 > value1)
+                               good++;
+                               break;
+                       if ((value2 < value1) && ((value2) < 0xFFF))
+                               good++;
+                               break;
+                       printk(KERN_INFO "PM-Timer had inconsistent results:"
+                              " 0x%#llx, 0x%#llx - aborting.\n",
+                              value1, value2);
+                       return -EINVAL;
+               }
+               udelay(300 * i);
+       }
+
+       if (good != ACPI_PM_MONOTONICITY_CHECKS) {
+               printk(KERN_INFO "PM-Timer failed consistency check "
+                      " (0x%#llx) - aborting.\n", value1);
+               return -ENODEV;
        }
-       printk(KERN_INFO "PM-Timer had no reasonable result:"
-                       " 0x%#x - aborting.\n", value1);
-       return -ENODEV;
 
-pm_good:
        if (verify_pmtmr_rate() != 0)
                return -ENODEV;
 
index 840e634..640cbb2 100644 (file)
 #include <linux/clk.h>
 #include <linux/io.h>
 
+/* Transmit operation:                                                      */
+/*                                                                          */
+/* 0 byte transmit                                                          */
+/* BUS:     S     A8     ACK   P                                            */
+/* IRQ:       DTE   WAIT                                                    */
+/* ICIC:                                                                    */
+/* ICCR: 0x94 0x90                                                          */
+/* ICDR:      A8                                                            */
+/*                                                                          */
+/* 1 byte transmit                                                          */
+/* BUS:     S     A8     ACK   D8(1)   ACK   P                              */
+/* IRQ:       DTE   WAIT         WAIT                                       */
+/* ICIC:      -DTE                                                          */
+/* ICCR: 0x94       0x90                                                    */
+/* ICDR:      A8    D8(1)                                                   */
+/*                                                                          */
+/* 2 byte transmit                                                          */
+/* BUS:     S     A8     ACK   D8(1)   ACK   D8(2)   ACK   P                */
+/* IRQ:       DTE   WAIT         WAIT          WAIT                         */
+/* ICIC:      -DTE                                                          */
+/* ICCR: 0x94                    0x90                                       */
+/* ICDR:      A8    D8(1)        D8(2)                                      */
+/*                                                                          */
+/* 3 bytes or more, +---------+ gets repeated                               */
+/*                                                                          */
+/*                                                                          */
+/* Receive operation:                                                       */
+/*                                                                          */
+/* 0 byte receive - not supported since slave may hold SDA low              */
+/*                                                                          */
+/* 1 byte receive       [TX] | [RX]                                         */
+/* BUS:     S     A8     ACK | D8(1)   ACK   P                              */
+/* IRQ:       DTE   WAIT     |   WAIT     DTE                               */
+/* ICIC:      -DTE           |   +DTE                                       */
+/* ICCR: 0x94       0x81     |   0xc0                                       */
+/* ICDR:      A8             |            D8(1)                             */
+/*                                                                          */
+/* 2 byte receive        [TX]| [RX]                                         */
+/* BUS:     S     A8     ACK | D8(1)   ACK   D8(2)   ACK   P                */
+/* IRQ:       DTE   WAIT     |   WAIT          WAIT     DTE                 */
+/* ICIC:      -DTE           |                 +DTE                         */
+/* ICCR: 0x94       0x81     |                 0xc0                         */
+/* ICDR:      A8             |                 D8(1)    D8(2)               */
+/*                                                                          */
+/* 3 byte receive       [TX] | [RX]                                         */
+/* BUS:     S     A8     ACK | D8(1)   ACK   D8(2)   ACK   D8(3)   ACK    P */
+/* IRQ:       DTE   WAIT     |   WAIT          WAIT         WAIT      DTE   */
+/* ICIC:      -DTE           |                              +DTE            */
+/* ICCR: 0x94       0x81     |                              0xc0            */
+/* ICDR:      A8             |                 D8(1)        D8(2)     D8(3) */
+/*                                                                          */
+/* 4 bytes or more, this part is repeated    +---------+                    */
+/*                                                                          */
+/*                                                                          */
+/* Interrupt order and BUSY flag                                            */
+/*     ___                                                 _                */
+/* SDA ___\___XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAAAAAAA___/                 */
+/* SCL      \_/1\_/2\_/3\_/4\_/5\_/6\_/7\_/8\___/9\_____/                   */
+/*                                                                          */
+/*        S   D7  D6  D5  D4  D3  D2  D1  D0              P                 */
+/*                                           ___                            */
+/* WAIT IRQ ________________________________/   \___________                */
+/* TACK IRQ ____________________________________/   \_______                */
+/* DTE  IRQ __________________________________________/   \_                */
+/* AL   IRQ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                */
+/*         _______________________________________________                  */
+/* BUSY __/                                               \_                */
+/*                                                                          */
+
 enum sh_mobile_i2c_op {
        OP_START = 0,
-       OP_TX_ONLY,
+       OP_TX_FIRST,
+       OP_TX,
        OP_TX_STOP,
        OP_TX_TO_RX,
-       OP_RX_ONLY,
+       OP_RX,
        OP_RX_STOP,
+       OP_RX_STOP_DATA,
 };
 
 struct sh_mobile_i2c_data {
@@ -127,25 +198,34 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
        spin_lock_irqsave(&pd->lock, flags);
 
        switch (op) {
-       case OP_START:
+       case OP_START: /* issue start and trigger DTE interrupt */
                iowrite8(0x94, ICCR(pd));
                break;
-       case OP_TX_ONLY:
+       case OP_TX_FIRST: /* disable DTE interrupt and write data */
+               iowrite8(ICIC_WAITE | ICIC_ALE | ICIC_TACKE, ICIC(pd));
                iowrite8(data, ICDR(pd));
                break;
-       case OP_TX_STOP:
+       case OP_TX: /* write data */
                iowrite8(data, ICDR(pd));
-               iowrite8(0x90, ICCR(pd));
-               iowrite8(ICIC_ALE | ICIC_TACKE, ICIC(pd));
                break;
-       case OP_TX_TO_RX:
+       case OP_TX_STOP: /* write data and issue a stop afterwards */
                iowrite8(data, ICDR(pd));
+               iowrite8(0x90, ICCR(pd));
+               break;
+       case OP_TX_TO_RX: /* select read mode */
                iowrite8(0x81, ICCR(pd));
                break;
-       case OP_RX_ONLY:
+       case OP_RX: /* just read data */
                ret = ioread8(ICDR(pd));
                break;
-       case OP_RX_STOP:
+       case OP_RX_STOP: /* enable DTE interrupt, issue stop */
+               iowrite8(ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE,
+                        ICIC(pd));
+               iowrite8(0xc0, ICCR(pd));
+               break;
+       case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */
+               iowrite8(ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE,
+                        ICIC(pd));
                ret = ioread8(ICDR(pd));
                iowrite8(0xc0, ICCR(pd));
                break;
@@ -157,58 +237,120 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
        return ret;
 }
 
+static int sh_mobile_i2c_is_first_byte(struct sh_mobile_i2c_data *pd)
+{
+       if (pd->pos == -1)
+               return 1;
+
+       return 0;
+}
+
+static int sh_mobile_i2c_is_last_byte(struct sh_mobile_i2c_data *pd)
+{
+       if (pd->pos == (pd->msg->len - 1))
+               return 1;
+
+       return 0;
+}
+
+static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd,
+                                  unsigned char *buf)
+{
+       switch (pd->pos) {
+       case -1:
+               *buf = (pd->msg->addr & 0x7f) << 1;
+               *buf |= (pd->msg->flags & I2C_M_RD) ? 1 : 0;
+               break;
+       default:
+               *buf = pd->msg->buf[pd->pos];
+       }
+}
+
+static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd)
+{
+       unsigned char data;
+
+       if (pd->pos == pd->msg->len)
+               return 1;
+
+       sh_mobile_i2c_get_data(pd, &data);
+
+       if (sh_mobile_i2c_is_last_byte(pd))
+               i2c_op(pd, OP_TX_STOP, data);
+       else if (sh_mobile_i2c_is_first_byte(pd))
+               i2c_op(pd, OP_TX_FIRST, data);
+       else
+               i2c_op(pd, OP_TX, data);
+
+       pd->pos++;
+       return 0;
+}
+
+static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd)
+{
+       unsigned char data;
+       int real_pos;
+
+       do {
+               if (pd->pos <= -1) {
+                       sh_mobile_i2c_get_data(pd, &data);
+
+                       if (sh_mobile_i2c_is_first_byte(pd))
+                               i2c_op(pd, OP_TX_FIRST, data);
+                       else
+                               i2c_op(pd, OP_TX, data);
+                       break;
+               }
+
+               if (pd->pos == 0) {
+                       i2c_op(pd, OP_TX_TO_RX, 0);
+                       break;
+               }
+
+               real_pos = pd->pos - 2;
+
+               if (pd->pos == pd->msg->len) {
+                       if (real_pos < 0) {
+                               i2c_op(pd, OP_RX_STOP, 0);
+                               break;
+                       }
+                       data = i2c_op(pd, OP_RX_STOP_DATA, 0);
+               } else
+                       data = i2c_op(pd, OP_RX, 0);
+
+               pd->msg->buf[real_pos] = data;
+       } while (0);
+
+       pd->pos++;
+       return pd->pos == (pd->msg->len + 2);
+}
+
 static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
 {
        struct platform_device *dev = dev_id;
        struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev);
-       struct i2c_msg *msg = pd->msg;
-       unsigned char data, sr;
-       int wakeup = 0;
+       unsigned char sr;
+       int wakeup;
 
        sr = ioread8(ICSR(pd));
-       pd->sr |= sr;
+       pd->sr |= sr; /* remember state */
 
        dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr,
-              (msg->flags & I2C_M_RD) ? "read" : "write",
-              pd->pos, msg->len);
+              (pd->msg->flags & I2C_M_RD) ? "read" : "write",
+              pd->pos, pd->msg->len);
 
        if (sr & (ICSR_AL | ICSR_TACK)) {
-               iowrite8(0, ICIC(pd)); /* disable interrupts */
-               wakeup = 1;
-               goto do_wakeup;
-       }
+               /* don't interrupt transaction - continue to issue stop */
+               iowrite8(sr & ~(ICSR_AL | ICSR_TACK), ICSR(pd));
+               wakeup = 0;
+       } else if (pd->msg->flags & I2C_M_RD)
+               wakeup = sh_mobile_i2c_isr_rx(pd);
+       else
+               wakeup = sh_mobile_i2c_isr_tx(pd);
 
-       if (pd->pos == msg->len) {
-               i2c_op(pd, OP_RX_ONLY, 0);
-               wakeup = 1;
-               goto do_wakeup;
-       }
+       if (sr & ICSR_WAIT) /* TODO: add delay here to support slow acks */
+               iowrite8(sr & ~ICSR_WAIT, ICSR(pd));
 
-       if (pd->pos == -1) {
-               data = (msg->addr & 0x7f) << 1;
-               data |= (msg->flags & I2C_M_RD) ? 1 : 0;
-       } else
-               data = msg->buf[pd->pos];
-
-       if ((pd->pos == -1) || !(msg->flags & I2C_M_RD)) {
-               if (msg->flags & I2C_M_RD)
-                       i2c_op(pd, OP_TX_TO_RX, data);
-               else if (pd->pos == (msg->len - 1)) {
-                       i2c_op(pd, OP_TX_STOP, data);
-                       wakeup = 1;
-               } else
-                       i2c_op(pd, OP_TX_ONLY, data);
-       } else {
-               if (pd->pos == (msg->len - 1))
-                       data = i2c_op(pd, OP_RX_STOP, 0);
-               else
-                       data = i2c_op(pd, OP_RX_ONLY, 0);
-
-               msg->buf[pd->pos] = data;
-       }
-       pd->pos++;
-
- do_wakeup:
        if (wakeup) {
                pd->sr |= SW_DONE;
                wake_up(&pd->wait);
@@ -219,6 +361,11 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
 
 static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg)
 {
+       if (usr_msg->len == 0 && (usr_msg->flags & I2C_M_RD)) {
+               dev_err(pd->dev, "Unsupported zero length i2c read\n");
+               return -EIO;
+       }
+
        /* Initialize channel registers */
        iowrite8(ioread8(ICCR(pd)) & ~ICCR_ICE, ICCR(pd));
 
@@ -233,9 +380,8 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg)
        pd->pos = -1;
        pd->sr = 0;
 
-       /* Enable all interrupts except wait */
-       iowrite8(ioread8(ICIC(pd)) | ICIC_ALE | ICIC_TACKE | ICIC_DTEE,
-                ICIC(pd));
+       /* Enable all interrupts to begin with */
+       iowrite8(ICIC_WAITE | ICIC_ALE | ICIC_TACKE | ICIC_DTEE, ICIC(pd));
        return 0;
 }
 
@@ -268,25 +414,18 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
                if (!k)
                        dev_err(pd->dev, "Transfer request timed out\n");
 
-               retry_count = 10;
+               retry_count = 1000;
 again:
                val = ioread8(ICSR(pd));
 
                dev_dbg(pd->dev, "val 0x%02x pd->sr 0x%02x\n", val, pd->sr);
 
-               if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) {
-                       err = -EIO;
-                       break;
-               }
-
                /* the interrupt handler may wake us up before the
                 * transfer is finished, so poll the hardware
                 * until we're done.
                 */
-
-               if (!(!(val & ICSR_BUSY) && (val & ICSR_SCLM) &&
-                     (val & ICSR_SDAM))) {
-                       msleep(1);
+               if (val & ICSR_BUSY) {
+                       udelay(10);
                        if (retry_count--)
                                goto again;
 
@@ -294,6 +433,12 @@ again:
                        dev_err(pd->dev, "Polling timed out\n");
                        break;
                }
+
+               /* handle missing acknowledge and arbitration lost */
+               if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) {
+                       err = -EIO;
+                       break;
+               }
        }
 
        deactivate_ch(pd);
index 2ec921b..18f4d7f 100644 (file)
@@ -63,7 +63,7 @@
 }
 
 /* table of devices that work with this driver */
-static const struct usb_device_id bcm5974_table [] = {
+static const struct usb_device_id bcm5974_table[] = {
        /* MacbookAir1.1 */
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ISO),
@@ -105,7 +105,7 @@ struct tp_header {
 
 /* trackpad finger structure */
 struct tp_finger {
-       __le16 origin;          /* left/right origin? */
+       __le16 origin;          /* zero when switching track finger */
        __le16 abs_x;           /* absolute x coodinate */
        __le16 abs_y;           /* absolute y coodinate */
        __le16 rel_x;           /* relative x coodinate */
@@ -159,6 +159,7 @@ struct bcm5974 {
        struct bt_data *bt_data;        /* button transferred data */
        struct urb *tp_urb;             /* trackpad usb request block */
        struct tp_data *tp_data;        /* trackpad transferred data */
+       int fingers;                    /* number of fingers on trackpad */
 };
 
 /* logical dimensions */
@@ -172,6 +173,10 @@ struct bcm5974 {
 #define SN_WIDTH       100             /* width signal-to-noise ratio */
 #define SN_COORD       250             /* coordinate signal-to-noise ratio */
 
+/* pressure thresholds */
+#define PRESSURE_LOW   (2 * DIM_PRESSURE / SN_PRESSURE)
+#define PRESSURE_HIGH  (3 * PRESSURE_LOW)
+
 /* device constants */
 static const struct bcm5974_config bcm5974_config_table[] = {
        {
@@ -248,6 +253,7 @@ static void setup_events_to_report(struct input_dev *input_dev,
                                0, cfg->y.dim, cfg->y.fuzz, 0);
 
        __set_bit(EV_KEY, input_dev->evbit);
+       __set_bit(BTN_TOUCH, input_dev->keybit);
        __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
        __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
        __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
@@ -273,32 +279,66 @@ static int report_tp_state(struct bcm5974 *dev, int size)
        const struct tp_finger *f = dev->tp_data->finger;
        struct input_dev *input = dev->input;
        const int fingers = (size - 26) / 28;
-       int p = 0, w, x, y, n = 0;
+       int raw_p, raw_w, raw_x, raw_y;
+       int ptest = 0, origin = 0, nmin = 0, nmax = 0;
+       int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0;
 
        if (size < 26 || (size - 26) % 28 != 0)
                return -EIO;
 
+       /* always track the first finger; when detached, start over */
        if (fingers) {
-               p = raw2int(f->force_major);
-               w = raw2int(f->size_major);
-               x = raw2int(f->abs_x);
-               y = raw2int(f->abs_y);
-               n = p > 0 ? fingers : 0;
+               raw_p = raw2int(f->force_major);
+               raw_w = raw2int(f->size_major);
+               raw_x = raw2int(f->abs_x);
+               raw_y = raw2int(f->abs_y);
 
                dprintk(9,
-                       "bcm5974: p: %+05d w: %+05d x: %+05d y: %+05d n: %d\n",
-                       p, w, x, y, n);
+                       "bcm5974: raw: p: %+05d w: %+05d x: %+05d y: %+05d\n",
+                       raw_p, raw_w, raw_x, raw_y);
+
+               ptest = int2bound(&c->p, raw_p);
+               origin = raw2int(f->origin);
+       }
 
-               input_report_abs(input, ABS_TOOL_WIDTH, int2bound(&c->w, w));
-               input_report_abs(input, ABS_X, int2bound(&c->x, x - c->x.devmin));
-               input_report_abs(input, ABS_Y, int2bound(&c->y, c->y.devmax - y));
+       /* while tracking finger still valid, count all fingers */
+       if (ptest > PRESSURE_LOW && origin) {
+               abs_p = ptest;
+               abs_w = int2bound(&c->w, raw_w);
+               abs_x = int2bound(&c->x, raw_x - c->x.devmin);
+               abs_y = int2bound(&c->y, c->y.devmax - raw_y);
+               for (; f != dev->tp_data->finger + fingers; f++) {
+                       ptest = int2bound(&c->p, raw2int(f->force_major));
+                       if (ptest > PRESSURE_LOW)
+                               nmax++;
+                       if (ptest > PRESSURE_HIGH)
+                               nmin++;
+               }
        }
 
-       input_report_abs(input, ABS_PRESSURE, int2bound(&c->p, p));
+       if (dev->fingers < nmin)
+               dev->fingers = nmin;
+       if (dev->fingers > nmax)
+               dev->fingers = nmax;
+
+       input_report_key(input, BTN_TOUCH, dev->fingers > 0);
+       input_report_key(input, BTN_TOOL_FINGER, dev->fingers == 1);
+       input_report_key(input, BTN_TOOL_DOUBLETAP, dev->fingers == 2);
+       input_report_key(input, BTN_TOOL_TRIPLETAP, dev->fingers > 2);
 
-       input_report_key(input, BTN_TOOL_FINGER, n == 1);
-       input_report_key(input, BTN_TOOL_DOUBLETAP, n == 2);
-       input_report_key(input, BTN_TOOL_TRIPLETAP, n > 2);
+       input_report_abs(input, ABS_PRESSURE, abs_p);
+       input_report_abs(input, ABS_TOOL_WIDTH, abs_w);
+
+       if (abs_p) {
+               input_report_abs(input, ABS_X, abs_x);
+               input_report_abs(input, ABS_Y, abs_y);
+
+               dprintk(8,
+                       "bcm5974: abs: p: %+05d w: %+05d x: %+05d y: %+05d "
+                       "nmin: %d nmax: %d n: %d\n",
+                       abs_p, abs_w, abs_x, abs_y, nmin, nmax, dev->fingers);
+
+       }
 
        input_sync(input);
 
index 3282b74..5aafe24 100644 (file)
@@ -305,7 +305,7 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
                .ident = "Lenovo 3000 n100",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "076804U"),
                },
        },
        {
index e8bc7ab..99be9e5 100644 (file)
@@ -1068,7 +1068,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
        {
                v4l2_std_id *id = arg;
                int found = 0;
-               int i, err;
+               int i;
 
                DEB_EE(("VIDIOC_S_STD\n"));
 
@@ -1116,7 +1116,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
        case VIDIOC_OVERLAY:
        {
                int on = *(int *)arg;
-               int err = 0;
 
                DEB_D(("VIDIOC_OVERLAY on:%d\n",on));
                if (on != 0) {
@@ -1192,7 +1191,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
        case VIDIOCGMBUF:
        {
                struct video_mbuf *mbuf = arg;
-               struct videobuf_queue *q;
                int i;
 
                /* fixme: number of capture buffers and sizes for v4l apps */
index e254bcf..e8d3c48 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
  *
- *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2006 Steven Toth <stoth@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
index cd8376f..6632de6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
  *
- *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2006 Steven Toth <stoth@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
index e930759..4e05a67 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
  *
- *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2006 Steven Toth <stoth@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
index 0dc2bef..227642b 100644 (file)
@@ -2,7 +2,7 @@
     MaxLinear MXL5005S VSB/QAM/DVBT tuner driver
 
     Copyright (C) 2008 MaxLinear
-    Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
       Functions:
        mxl5005s_reset()
        mxl5005s_writereg()
@@ -3837,7 +3837,7 @@ static u16 MXL_Hystersis_Test(struct dvb_frontend *fe, int Hystersis)
 /* ----------------------------------------------------------------
  * Begin: Everything after here is new code to adapt the
  * proprietary Realtek driver into a Linux API tuner.
- * Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ * Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
  */
 static int mxl5005s_reset(struct dvb_frontend *fe)
 {
index 396db15..7ac6815 100644 (file)
@@ -2,7 +2,7 @@
     MaxLinear MXL5005S VSB/QAM/DVBT tuner driver
 
     Copyright (C) 2008 MaxLinear
-    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2008 Steven Toth <stoth@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
index 597e47f..aa773a6 100644 (file)
@@ -253,7 +253,7 @@ static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe,
 
 static int simple_config_lookup(struct dvb_frontend *fe,
                                struct tuner_params *t_params,
-                               int *frequency, u8 *config, u8 *cb)
+                               unsigned *frequency, u8 *config, u8 *cb)
 {
        struct tuner_simple_priv *priv = fe->tuner_priv;
        int i;
@@ -587,45 +587,45 @@ static int simple_set_tv_freq(struct dvb_frontend *fe,
        priv->last_div = div;
        if (t_params->has_tda9887) {
                struct v4l2_priv_tun_config tda9887_cfg;
-               int config = 0;
+               int tda_config = 0;
                int is_secam_l = (params->std & (V4L2_STD_SECAM_L |
                                                 V4L2_STD_SECAM_LC)) &&
                        !(params->std & ~(V4L2_STD_SECAM_L |
                                          V4L2_STD_SECAM_LC));
 
                tda9887_cfg.tuner = TUNER_TDA9887;
-               tda9887_cfg.priv  = &config;
+               tda9887_cfg.priv  = &tda_config;
 
                if (params->std == V4L2_STD_SECAM_LC) {
                        if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)
-                               config |= TDA9887_PORT1_ACTIVE;
+                               tda_config |= TDA9887_PORT1_ACTIVE;
                        if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc)
-                               config |= TDA9887_PORT2_ACTIVE;
+                               tda_config |= TDA9887_PORT2_ACTIVE;
                } else {
                        if (t_params->port1_active)
-                               config |= TDA9887_PORT1_ACTIVE;
+                               tda_config |= TDA9887_PORT1_ACTIVE;
                        if (t_params->port2_active)
-                               config |= TDA9887_PORT2_ACTIVE;
+                               tda_config |= TDA9887_PORT2_ACTIVE;
                }
                if (t_params->intercarrier_mode)
-                       config |= TDA9887_INTERCARRIER;
+                       tda_config |= TDA9887_INTERCARRIER;
                if (is_secam_l) {
                        if (i == 0 && t_params->default_top_secam_low)
-                               config |= TDA9887_TOP(t_params->default_top_secam_low);
+                               tda_config |= TDA9887_TOP(t_params->default_top_secam_low);
                        else if (i == 1 && t_params->default_top_secam_mid)
-                               config |= TDA9887_TOP(t_params->default_top_secam_mid);
+                               tda_config |= TDA9887_TOP(t_params->default_top_secam_mid);
                        else if (t_params->default_top_secam_high)
-                               config |= TDA9887_TOP(t_params->default_top_secam_high);
+                               tda_config |= TDA9887_TOP(t_params->default_top_secam_high);
                } else {
                        if (i == 0 && t_params->default_top_low)
-                               config |= TDA9887_TOP(t_params->default_top_low);
+                               tda_config |= TDA9887_TOP(t_params->default_top_low);
                        else if (i == 1 && t_params->default_top_mid)
-                               config |= TDA9887_TOP(t_params->default_top_mid);
+                               tda_config |= TDA9887_TOP(t_params->default_top_mid);
                        else if (t_params->default_top_high)
-                               config |= TDA9887_TOP(t_params->default_top_high);
+                               tda_config |= TDA9887_TOP(t_params->default_top_high);
                }
                if (t_params->default_pll_gating_18)
-                       config |= TDA9887_GATING_18;
+                       tda_config |= TDA9887_GATING_18;
                i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
                                    &tda9887_cfg);
        }
@@ -813,7 +813,8 @@ static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
        static struct tuner_params *t_params;
        u8 config, cb;
        u32 div;
-       int ret, frequency = params->frequency / 62500;
+       int ret;
+       unsigned frequency = params->frequency / 62500;
 
        t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL);
        ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb);
index 5f99de0..dcddfa8 100644 (file)
@@ -2,7 +2,7 @@
  *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
  *
  *  Copyright (c) 2007 Xceive Corporation
- *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2007 Steven Toth <stoth@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
index c910715..5389f74 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
  *
- *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2007 Steven Toth <stoth@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
index a72a988..b2a0074 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
  *
- *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2007 Steven Toth <stoth@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
index f9d0876..4eed783 100644 (file)
@@ -137,7 +137,8 @@ static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, un
                        flexcop_diseqc_send_byte(fe, 0xff);
                else {
                        flexcop_set_tone(fe, SEC_TONE_ON);
-                       udelay(12500);
+                       mdelay(12);
+                       udelay(500);
                        flexcop_set_tone(fe, SEC_TONE_OFF);
                }
                msleep(20);
index 55973ea..43a112e 100644 (file)
@@ -221,12 +221,12 @@ int flexcop_i2c_init(struct flexcop_device *fc)
        fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM;
        fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER;
 
-       strncpy(fc->fc_i2c_adap[0].i2c_adap.name,
-               "B2C2 FlexCop I2C to demod", I2C_NAME_SIZE);
-       strncpy(fc->fc_i2c_adap[1].i2c_adap.name,
-               "B2C2 FlexCop I2C to eeprom", I2C_NAME_SIZE);
-       strncpy(fc->fc_i2c_adap[2].i2c_adap.name,
-               "B2C2 FlexCop I2C to tuner", I2C_NAME_SIZE);
+       strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod",
+               sizeof(fc->fc_i2c_adap[0].i2c_adap.name));
+       strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom",
+               sizeof(fc->fc_i2c_adap[1].i2c_adap.name));
+       strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner",
+               sizeof(fc->fc_i2c_adap[2].i2c_adap.name));
 
        i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]);
        i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]);
index a763756..aa3db57 100644 (file)
@@ -1244,7 +1244,7 @@ static int dst_command(struct dst_state *state, u8 *data, u8 len)
                goto error;
        }
        if (state->type_flags & DST_TYPE_HAS_FW_1)
-               udelay(3000);
+               mdelay(3);
        if (read_dst(state, &reply, GET_ACK)) {
                dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. ");
                if ((dst_error_recovery(state)) < 0) {
@@ -1260,7 +1260,7 @@ static int dst_command(struct dst_state *state, u8 *data, u8 len)
        if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3))
                goto error;
        if (state->type_flags & DST_TYPE_HAS_FW_1)
-               udelay(3000);
+               mdelay(3);
        else
                udelay(2000);
        if (!dst_wait_dst_ready(state, NO_DELAY))
index 1cf9fcb..069d847 100644 (file)
@@ -641,7 +641,6 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
                struct timespec timeout = { 0 };
                struct dmx_pes_filter_params *para = &filter->params.pes;
                dmx_output_t otype;
-               int ret;
                int ts_type;
                enum dmx_ts_pes ts_pes;
                struct dmx_ts_feed **tsfeed = &filter->feed.ts;
index 8e5dd7b..98ee167 100644 (file)
@@ -1032,7 +1032,7 @@ static int dvb_ca_en50221_thread(void *data)
                                        /* we need this extra check for annoying interfaces like the budget-av */
                                        if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
                                            (ca->pub->poll_slot_status)) {
-                                               int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+                                               status = ca->pub->poll_slot_status(ca->pub, slot, 0);
                                                if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
                                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
                                                        dvb_ca_en50221_thread_update_delay(ca);
@@ -1089,7 +1089,7 @@ static int dvb_ca_en50221_thread(void *data)
                                        /* we need this extra check for annoying interfaces like the budget-av */
                                        if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
                                            (ca->pub->poll_slot_status)) {
-                                               int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+                                               status = ca->pub->poll_slot_status(ca->pub, slot, 0);
                                                if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
                                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
                                                        dvb_ca_en50221_thread_update_delay(ca);
index 8cbdb21..3526e3e 100644 (file)
@@ -889,13 +889,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                         * initialization, so parg is 8 bits and does not
                         * include the initialization or start bit
                         */
-                       unsigned long cmd = ((unsigned long) parg) << 1;
+                       unsigned long swcmd = ((unsigned long) parg) << 1;
                        struct timeval nexttime;
                        struct timeval tv[10];
                        int i;
                        u8 last = 1;
                        if (dvb_frontend_debug)
-                               printk("%s switch command: 0x%04lx\n", __func__, cmd);
+                               printk("%s switch command: 0x%04lx\n", __func__, swcmd);
                        do_gettimeofday(&nexttime);
                        if (dvb_frontend_debug)
                                memcpy(&tv[0], &nexttime, sizeof(struct timeval));
@@ -908,12 +908,12 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                        for (i = 0; i < 9; i++) {
                                if (dvb_frontend_debug)
                                        do_gettimeofday(&tv[i + 1]);
-                               if ((cmd & 0x01) != last) {
+                               if ((swcmd & 0x01) != last) {
                                        /* set voltage to (last ? 13V : 18V) */
                                        fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
                                        last = (last) ? 0 : 1;
                                }
-                               cmd = cmd >> 1;
+                               swcmd = swcmd >> 1;
                                if (i != 8)
                                        dvb_frontend_sleep_until(&nexttime, 8000);
                        }
index aaa0b6f..5634002 100644 (file)
@@ -210,7 +210,7 @@ static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff)
        if (d->state == DVB_USB_STATE_INIT &&
            usb_set_interface(d->udev, 0, 0) < 0)
                err("set interface failed");
-       do; while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) &&
+       do {} while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) &&
                   !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) &&
                   !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0);
        if (!ret) {
index 3dd20bf..6c0e5c5 100644 (file)
@@ -1117,7 +1117,8 @@ struct usb_device_id dib0700_usb_id_table[] = {
        { USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_CINERGY_HT_EXPRESS) },
        { USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_CINERGY_T_XXS) },
        { USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) },
-       { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) },
+/* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) },
+       { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) },
        { 0 }           /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -1373,7 +1374,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        }
                },
 
-               .num_device_descs = 3,
+               .num_device_descs = 4,
                .devices = {
                        {   "DiBcom STK7070PD reference design",
                                { &dib0700_usb_id_table[17], NULL },
@@ -1386,6 +1387,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        {   "Hauppauge Nova-TD Stick (52009)",
                                { &dib0700_usb_id_table[35], NULL },
                                { NULL },
+                       },
+                       {   "Hauppauge Nova-TD-500 (84xxx)",
+                               { &dib0700_usb_id_table[36], NULL },
+                               { NULL },
                        }
                }
        }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
index 029b437..03dfb9f 100644 (file)
 #define USB_PID_WINTV_NOVA_T_USB2_WARM                 0x9301
 #define USB_PID_HAUPPAUGE_NOVA_T_500                   0x9941
 #define USB_PID_HAUPPAUGE_NOVA_T_500_2                 0x9950
+#define USB_PID_HAUPPAUGE_NOVA_T_500_3                 0x8400
 #define USB_PID_HAUPPAUGE_NOVA_T_STICK                 0x7050
 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2               0x7060
 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_3               0x7070
index f7b7165..0b82cc2 100644 (file)
@@ -1,7 +1,7 @@
 /*
     Auvitek AU8522 QAM/8VSB demodulator driver
 
-    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2008 Steven Toth <stoth@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
@@ -304,6 +304,43 @@ static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse,
        return ret;
 }
 
+static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq)
+{
+       struct au8522_state *state = fe->demodulator_priv;
+       u8 r0b5, r0b6, r0b7;
+       char *ifmhz;
+
+       switch (if_freq) {
+       case AU8522_IF_3_25MHZ:
+               ifmhz = "3.25";
+               r0b5 = 0x00;
+               r0b6 = 0x3d;
+               r0b7 = 0xa0;
+               break;
+       case AU8522_IF_4MHZ:
+               ifmhz = "4.00";
+               r0b5 = 0x00;
+               r0b6 = 0x4b;
+               r0b7 = 0xd9;
+               break;
+       case AU8522_IF_6MHZ:
+               ifmhz = "6.00";
+               r0b5 = 0xfb;
+               r0b6 = 0x8e;
+               r0b7 = 0x39;
+               break;
+       default:
+               dprintk("%s() IF Frequency not supported\n", __func__);
+               return -EINVAL;
+       }
+       dprintk("%s() %s MHz\n", __func__, ifmhz);
+       au8522_writereg(state, 0x80b5, r0b5);
+       au8522_writereg(state, 0x80b6, r0b6);
+       au8522_writereg(state, 0x80b7, r0b7);
+
+       return 0;
+}
+
 /* VSB Modulation table */
 static struct {
        u16 reg;
@@ -334,9 +371,6 @@ static struct {
        { 0x80af, 0x66 },
        { 0x821b, 0xcc },
        { 0x821d, 0x80 },
-       { 0x80b5, 0xfb },
-       { 0x80b6, 0x8e },
-       { 0x80b7, 0x39 },
        { 0x80a4, 0xe8 },
        { 0x8231, 0x13 },
 };
@@ -350,9 +384,6 @@ static struct {
        { 0x80a4, 0x00 },
        { 0x8081, 0xc4 },
        { 0x80a5, 0x40 },
-       { 0x80b5, 0xfb },
-       { 0x80b6, 0x8e },
-       { 0x80b7, 0x39 },
        { 0x80aa, 0x77 },
        { 0x80ad, 0x77 },
        { 0x80a6, 0x67 },
@@ -438,6 +469,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
                        au8522_writereg(state,
                                VSB_mod_tab[i].reg,
                                VSB_mod_tab[i].data);
+               au8522_set_if(fe, state->config->vsb_if);
                break;
        case QAM_64:
        case QAM_256:
@@ -446,6 +478,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
                        au8522_writereg(state,
                                QAM_mod_tab[i].reg,
                                QAM_mod_tab[i].data);
+               au8522_set_if(fe, state->config->qam_if);
                break;
        default:
                dprintk("%s() Invalid modulation\n", __func__);
index d7affa3..595915a 100644 (file)
@@ -1,7 +1,7 @@
 /*
     Auvitek AU8522 QAM/8VSB demodulator driver
 
-    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2008 Steven Toth <stoth@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
 
 #include <linux/dvb/frontend.h>
 
+enum au8522_if_freq {
+       AU8522_IF_6MHZ = 0,
+       AU8522_IF_4MHZ,
+       AU8522_IF_3_25MHZ,
+};
+
 struct au8522_config {
        /* the demodulator's i2c address */
        u8 demod_address;
@@ -32,6 +38,9 @@ struct au8522_config {
 #define AU8522_TUNERLOCKING 0
 #define AU8522_DEMODLOCKING 1
        u8 status_mode;
+
+       enum au8522_if_freq vsb_if;
+       enum au8522_if_freq qam_if;
 };
 
 #if defined(CONFIG_DVB_AU8522) ||                              \
index cc1db4e..9430e03 100644 (file)
@@ -7,7 +7,7 @@
     Copyright (C) 2001-2002 Convergence Integrated Media GmbH
          Holger Waechtler <holger@convergence.de>
 
-    Copyright (C) 2004 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2004 Steven Toth <stoth@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
index 8af766a..b1e465c 100644 (file)
@@ -7,7 +7,7 @@
     Copyright (C) 2001-2002 Convergence Integrated Media GmbH
          Holger Waechtler <holger@convergence.de>
 
-    Copyright (C) 2004 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2004 Steven Toth <stoth@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
index 7f68d78..7156157 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
  *
- *   Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+ *   Copyright (C) 2005 Steven Toth <stoth@linuxtv.org>
  *
  *   Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc>
  *
@@ -1072,8 +1072,8 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
     if (config->dont_use_pll)
        cx24123_repeater_mode(state, 1, 0);
 
-       strncpy(state->tuner_i2c_adapter.name,
-               "CX24123 tuner I2C bus", I2C_NAME_SIZE);
+       strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus",
+               sizeof(state->tuner_i2c_adapter.name));
        state->tuner_i2c_adapter.class     = I2C_CLASS_TV_DIGITAL,
        state->tuner_i2c_adapter.algo      = &cx24123_tuner_i2c_algo;
        state->tuner_i2c_adapter.algo_data = NULL;
index 81ebc3d..cc6b411 100644 (file)
@@ -1,7 +1,7 @@
 /*
     Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
 
-    Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2005 Steven Toth <stoth@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
index 5ddb2dc..7500a1c 100644 (file)
@@ -1,7 +1,7 @@
 /*
     Samsung S5H1409 VSB/QAM demodulator driver
 
-    Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2006 Steven Toth <stoth@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
@@ -404,6 +404,7 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe,
                break;
        case QAM_64:
        case QAM_256:
+       case QAM_AUTO:
                dprintk("%s() QAM_AUTO (64/256)\n", __func__);
                if (state->if_freq != S5H1409_QAM_IF_FREQ)
                        s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ);
index 59f4335..d1a1d2e 100644 (file)
@@ -1,7 +1,7 @@
 /*
     Samsung S5H1409 VSB/QAM demodulator driver
 
-    Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2006 Steven Toth <stoth@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
index cff360c..2da1a37 100644 (file)
@@ -1,7 +1,7 @@
 /*
     Samsung S5H1411 VSB/QAM demodulator driver
 
-    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2008 Steven Toth <stoth@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
@@ -488,6 +488,7 @@ static int s5h1411_enable_modulation(struct dvb_frontend *fe,
                break;
        case QAM_64:
        case QAM_256:
+       case QAM_AUTO:
                dprintk("%s() QAM_AUTO (64/256)\n", __func__);
                s5h1411_set_if_freq(fe, state->config->qam_if);
                s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x0171);
index 1855f64..7d542bc 100644 (file)
@@ -1,7 +1,7 @@
 /*
     Samsung S5H1411 VSB/QAM demodulator driver
 
-    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2008 Steven Toth <stoth@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
index 720ed9f..747d3fa 100644 (file)
@@ -915,7 +915,8 @@ struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
        state->frontend.demodulator_priv = state;
 
        /* create tuner i2c adapter */
-       strncpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus", I2C_NAME_SIZE);
+       strlcpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus",
+               sizeof(state->tuner_i2c_adapter.name));
        state->tuner_i2c_adapter.class     = I2C_CLASS_TV_DIGITAL,
        state->tuner_i2c_adapter.algo      = &s5h1420_tuner_i2c_algo;
        state->tuner_i2c_adapter.algo_data = NULL;
index 0ab8d86..04e7f1c 100644 (file)
@@ -1,7 +1,7 @@
 /*
     NXP TDA10048HN DVB OFDM demodulator driver
 
-    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2008 Steven Toth <stoth@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
@@ -303,7 +303,7 @@ static int tda10048_firmware_upload(struct dvb_frontend *fe)
 
        if (fw->size != TDA10048_DEFAULT_FIRMWARE_SIZE) {
                printk(KERN_ERR "%s: firmware incorrect size\n", __func__);
-               return -EIO;
+               ret = -EIO;
        } else {
                printk(KERN_INFO "%s: firmware uploading\n", __func__);
 
index 2b5c78e..0457b24 100644 (file)
@@ -1,7 +1,7 @@
 /*
     NXP TDA10048HN DVB OFDM demodulator driver
 
-    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2008 Steven Toth <stoth@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
index e7a8ac0..cc5efb6 100644 (file)
@@ -4,7 +4,7 @@
  *  Copyright (c) 2008 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 version 3 as
+ *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation;
  *
  *  Software distributed under the License is distributed on an "AS IS"
index 83b39bc..c8f3da6 100644 (file)
@@ -4,7 +4,7 @@
  *  Copyright (c) 2008 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 version 3 as
+ *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation;
  *
  *  Software distributed under the License is distributed on an "AS IS"
index c5f45fe..6576fbb 100644 (file)
@@ -8,7 +8,7 @@
  *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 3 as
+ *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation;
  *
  *  Software distributed under the License is distributed on an "AS IS"
index c1f8f1d..8d973f7 100644 (file)
@@ -6,7 +6,7 @@
  *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 3 as
+ *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation;
  *
  *  Software distributed under the License is distributed on an "AS IS"
index 229274a..8d490e1 100644 (file)
@@ -6,7 +6,7 @@
  *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 3 as
+ *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation;
  *
  *  Software distributed under the License is distributed on an "AS IS"
index c10b184..87a3c24 100644 (file)
@@ -6,7 +6,7 @@
  *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 3 as
+ *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation;
  *
  *  Software distributed under the License is distributed on an "AS IS"
index 39bd0a2..aa5ed4e 100644 (file)
@@ -116,7 +116,8 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long
                        DiseqcSendByte(budget, 0xff);
                else {
                        saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
-                       udelay(12500);
+                       mdelay(12);
+                       udelay(500);
                        saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
                }
                msleep(20);
index 2293d80..f006899 100644 (file)
@@ -108,7 +108,8 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long
                        DiseqcSendByte(budget, 0xff);
                else {
                        saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
-                       udelay(12500);
+                       mdelay(12);
+                       udelay(500);
                        saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
                }
                msleep(20);
index a30159f..7ca71ab 100644 (file)
@@ -2,8 +2,6 @@
 # Makefile for the kernel character device drivers.
 #
 
-miropcm20-objs := miropcm20-rds-core.o miropcm20-radio.o
-
 obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o
 obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o
 obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o
@@ -14,8 +12,6 @@ obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o
 obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o
 obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o
 obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o
-obj-$(CONFIG_RADIO_MIROPCM20) += miropcm20.o
-obj-$(CONFIG_RADIO_MIROPCM20_RDS) += miropcm20-rds.o
 obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
 obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
index 1ed88f3..70c65a7 100644 (file)
@@ -493,7 +493,7 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
        radio->usbdev = interface_to_usbdev(intf);
        radio->curfreq = FREQ_MIN*FREQ_MUL;
        video_set_drvdata(radio->videodev, radio);
-       if (video_register_device(radio->videodev, VFL_TYPE_RADIO,radio_nr)) {
+       if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr) < 0) {
                warn("Could not register video device");
                video_device_release(radio->videodev);
                kfree(radio->transfer_buffer);
diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c
deleted file mode 100644 (file)
index 7fd7ee2..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-/* Miro PCM20 radio driver for Linux radio support
- * (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
- * Thanks to Norberto Pellici for the ACI device interface specification
- * The API part is based on the radiotrack driver by M. Kirkwood
- * This driver relies on the aci mixer (drivers/sound/aci.c)
- * Look there for further info...
- */
-
-/* Revision history:
- *
- *   1998        Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
- *   2000-09-05  Robert Siemer <Robert.Siemer@gmx.de>
- *        removed unfinished volume control (maybe adding it later again)
- *        use OSS-mixer; added stereo control
- */
-
-/* What ever you think about the ACI, version 0x07 is not very well!
- * I can't get frequency, 'tuner status', 'tuner flags' or mute/mono
- * conditions...                Robert
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include "oss/aci.h"
-#include "miropcm20-rds-core.h"
-
-static int radio_nr = -1;
-module_param(radio_nr, int, 0);
-
-struct pcm20_device {
-       unsigned long freq;
-       int muted;
-       int stereo;
-};
-
-
-static int pcm20_mute(struct pcm20_device *dev, unsigned char mute)
-{
-       dev->muted = mute;
-       return aci_write_cmd(ACI_SET_TUNERMUTE, mute);
-}
-
-static int pcm20_stereo(struct pcm20_device *dev, unsigned char stereo)
-{
-       dev->stereo = stereo;
-       return aci_write_cmd(ACI_SET_TUNERMONO, !stereo);
-}
-
-static int pcm20_setfreq(struct pcm20_device *dev, unsigned long freq)
-{
-       unsigned char freql;
-       unsigned char freqh;
-
-       dev->freq=freq;
-
-       freq /= 160;
-       if (!(aci_version==0x07 || aci_version>=0xb0))
-               freq /= 10;  /* I don't know exactly which version
-                             * needs this hack */
-       freql = freq & 0xff;
-       freqh = freq >> 8;
-
-       aci_rds_cmd(RDS_RESET, NULL, 0);
-       pcm20_stereo(dev, 1);
-
-       return aci_rw_cmd(ACI_WRITE_TUNE, freql, freqh);
-}
-
-static int pcm20_getflags(struct pcm20_device *dev, __u32 *flags, __u16 *signal)
-{
-       /* okay, check for signal, stereo and rds here... */
-       int i;
-       unsigned char buf;
-
-       if ((i=aci_rw_cmd(ACI_READ_TUNERSTATION, -1, -1))<0)
-               return i;
-       pr_debug("check_sig: 0x%x\n", i);
-       if (i & 0x80) {
-               /* no signal from tuner */
-               *flags=0;
-               *signal=0;
-               return 0;
-       } else
-               *signal=0xffff;
-
-       if ((i=aci_rw_cmd(ACI_READ_TUNERSTEREO, -1, -1))<0)
-               return i;
-       if (i & 0x40) {
-               *flags=0;
-       } else {
-               /* stereo */
-               *flags=VIDEO_TUNER_STEREO_ON;
-               /* I can't see stereo, when forced to mono */
-               dev->stereo=1;
-       }
-
-       if ((i=aci_rds_cmd(RDS_STATUS, &buf, 1))<0)
-               return i;
-       if (buf & 1)
-               /* RDS available */
-               *flags|=VIDEO_TUNER_RDS_ON;
-       else
-               return 0;
-
-       if ((i=aci_rds_cmd(RDS_RXVALUE, &buf, 1))<0)
-               return i;
-       pr_debug("rds-signal: %d\n", buf);
-       if (buf > 15) {
-               printk("miropcm20-radio: RX strengths unexpected high...\n");
-               buf=15;
-       }
-       /* refine signal */
-       if ((*signal=SCALE(15, 0xffff, buf))==0)
-               *signal = 1;
-
-       return 0;
-}
-
-static int pcm20_do_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, void *arg)
-{
-       struct video_device *dev = video_devdata(file);
-       struct pcm20_device *pcm20 = dev->priv;
-       int i;
-
-       switch(cmd)
-       {
-               case VIDIOCGCAP:
-               {
-                       struct video_capability *v = arg;
-                       memset(v,0,sizeof(*v));
-                       v->type=VID_TYPE_TUNER;
-                       strcpy(v->name, "Miro PCM20");
-                       v->channels=1;
-                       v->audios=1;
-                       return 0;
-               }
-               case VIDIOCGTUNER:
-               {
-                       struct video_tuner *v = arg;
-                       if(v->tuner)    /* Only 1 tuner */
-                               return -EINVAL;
-                       v->rangelow=87*16000;
-                       v->rangehigh=108*16000;
-                       pcm20_getflags(pcm20, &v->flags, &v->signal);
-                       v->flags|=VIDEO_TUNER_LOW;
-                       v->mode=VIDEO_MODE_AUTO;
-                       strcpy(v->name, "FM");
-                       return 0;
-               }
-               case VIDIOCSTUNER:
-               {
-                       struct video_tuner *v = arg;
-                       if(v->tuner!=0)
-                               return -EINVAL;
-                       /* Only 1 tuner so no setting needed ! */
-                       return 0;
-               }
-               case VIDIOCGFREQ:
-               {
-                       unsigned long *freq = arg;
-                       *freq = pcm20->freq;
-                       return 0;
-               }
-               case VIDIOCSFREQ:
-               {
-                       unsigned long *freq = arg;
-                       pcm20->freq = *freq;
-                       i=pcm20_setfreq(pcm20, pcm20->freq);
-                       pr_debug("First view (setfreq): 0x%x\n", i);
-                       return i;
-               }
-               case VIDIOCGAUDIO:
-               {
-                       struct video_audio *v = arg;
-                       memset(v,0, sizeof(*v));
-                       v->flags=VIDEO_AUDIO_MUTABLE;
-                       if (pcm20->muted)
-                               v->flags|=VIDEO_AUDIO_MUTE;
-                       v->mode=VIDEO_SOUND_STEREO;
-                       if (pcm20->stereo)
-                               v->mode|=VIDEO_SOUND_MONO;
-                       /* v->step=2048; */
-                       strcpy(v->name, "Radio");
-                       return 0;
-               }
-               case VIDIOCSAUDIO:
-               {
-                       struct video_audio *v = arg;
-                       if(v->audio)
-                               return -EINVAL;
-
-                       pcm20_mute(pcm20, !!(v->flags&VIDEO_AUDIO_MUTE));
-                       if(v->flags&VIDEO_SOUND_MONO)
-                               pcm20_stereo(pcm20, 0);
-                       if(v->flags&VIDEO_SOUND_STEREO)
-                               pcm20_stereo(pcm20, 1);
-
-                       return 0;
-               }
-               default:
-                       return -ENOIOCTLCMD;
-       }
-}
-
-static int pcm20_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       return video_usercopy(inode, file, cmd, arg, pcm20_do_ioctl);
-}
-
-static struct pcm20_device pcm20_unit = {
-       .freq   = 87*16000,
-       .muted  = 1,
-};
-
-static const struct file_operations pcm20_fops = {
-       .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
-       .ioctl          = pcm20_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl   = v4l_compat_ioctl32,
-#endif
-       .llseek         = no_llseek,
-};
-
-static struct video_device pcm20_radio = {
-       .name           = "Miro PCM 20 radio",
-       .fops           = &pcm20_fops,
-       .priv           = &pcm20_unit
-};
-
-static int __init pcm20_init(void)
-{
-       if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO, radio_nr)==-1)
-               goto video_register_device;
-
-       if(attach_aci_rds()<0)
-               goto attach_aci_rds;
-
-       printk(KERN_INFO "Miro PCM20 radio card driver.\n");
-
-       return 0;
-
- attach_aci_rds:
-       video_unregister_device(&pcm20_radio);
- video_register_device:
-       return -EINVAL;
-}
-
-MODULE_AUTHOR("Ruurd Reitsma");
-MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card.");
-MODULE_LICENSE("GPL");
-
-static void __exit pcm20_cleanup(void)
-{
-       unload_aci_rds();
-       video_unregister_device(&pcm20_radio);
-}
-
-module_init(pcm20_init);
-module_exit(pcm20_cleanup);
diff --git a/drivers/media/radio/miropcm20-rds-core.c b/drivers/media/radio/miropcm20-rds-core.c
deleted file mode 100644 (file)
index 9428d8b..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- *  Many thanks to Fred Seidel <seidel@metabox.de>, the
- *  designer of the RDS decoder hardware. With his help
- *  I was able to code this driver.
- *  Thanks also to Norberto Pellicci, Dominic Mounteney
- *  <DMounteney@pinnaclesys.com> and www.teleauskunft.de
- *  for good hints on finding Fred. It was somewhat hard
- *  to locate him here in Germany... [:
- *
- * Revision history:
- *
- *   2000-08-09  Robert Siemer <Robert.Siemer@gmx.de>
- *        RDS support for MiroSound PCM20 radio
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-#include "oss/aci.h"
-#include "miropcm20-rds-core.h"
-
-#define DEBUG 0
-
-static struct mutex aci_rds_mutex;
-
-#define RDS_DATASHIFT          2   /* Bit 2 */
-#define RDS_DATAMASK        (1 << RDS_DATASHIFT)
-#define RDS_BUSYMASK        0x10   /* Bit 4 */
-#define RDS_CLOCKMASK       0x08   /* Bit 3 */
-
-#define RDS_DATA(x)         (((x) >> RDS_DATASHIFT) & 1)
-
-
-#if DEBUG
-static void print_matrix(char array[], unsigned int length)
-{
-       int i, j;
-
-       for (i=0; i<length; i++) {
-               printk(KERN_DEBUG "aci-rds: ");
-               for (j=7; j>=0; j--) {
-                       printk("%d", (array[i] >> j) & 0x1);
-               }
-               if (i%8 == 0)
-                       printk(" byte-border\n");
-               else
-                       printk("\n");
-       }
-}
-#endif /* DEBUG */
-
-static int byte2trans(unsigned char byte, unsigned char sendbuffer[], int size)
-{
-       int i;
-
-       if (size != 8)
-               return -1;
-       for (i = 7; i >= 0; i--)
-               sendbuffer[7-i] = (byte & (1 << i)) ? RDS_DATAMASK : 0;
-       sendbuffer[0] |= RDS_CLOCKMASK;
-
-       return 0;
-}
-
-static int rds_waitread(void)
-{
-       unsigned char byte;
-       int i=2000;
-
-       do {
-               byte=inb(RDS_REGISTER);
-               i--;
-       }
-       while ((byte & RDS_BUSYMASK) && i);
-
-       if (i) {
-               #if DEBUG
-               printk(KERN_DEBUG "rds_waitread()");
-               print_matrix(&byte, 1);
-               #endif
-               return (byte);
-       } else {
-               printk(KERN_WARNING "aci-rds: rds_waitread() timeout...\n");
-               return -1;
-       }
-}
-
-/* don't use any ..._nowait() function if you are not sure what you do... */
-
-static inline void rds_rawwrite_nowait(unsigned char byte)
-{
-       #if DEBUG
-       printk(KERN_DEBUG "rds_rawwrite()");
-       print_matrix(&byte, 1);
-       #endif
-       outb(byte, RDS_REGISTER);
-}
-
-static int rds_rawwrite(unsigned char byte)
-{
-       if (rds_waitread() >= 0) {
-               rds_rawwrite_nowait(byte);
-               return 0;
-       } else
-               return -1;
-}
-
-static int rds_write(unsigned char cmd)
-{
-       unsigned char sendbuffer[8];
-       int i;
-
-       if (byte2trans(cmd, sendbuffer, 8) != 0){
-               return -1;
-       } else {
-               for (i=0; i<8; i++) {
-                       rds_rawwrite(sendbuffer[i]);
-               }
-       }
-       return 0;
-}
-
-static int rds_readcycle_nowait(void)
-{
-       rds_rawwrite_nowait(0);
-       return rds_waitread();
-}
-
-static int rds_readcycle(void)
-{
-       if (rds_rawwrite(0) < 0)
-               return -1;
-       return rds_waitread();
-}
-
-static int rds_read(unsigned char databuffer[], int datasize)
-{
-       #define READSIZE (8*datasize)
-
-       int i,j;
-
-       if (datasize < 1)  /* nothing to read */
-               return 0;
-
-       /* to be able to use rds_readcycle_nowait()
-          I have to waitread() here */
-       if (rds_waitread() < 0)
-               return -1;
-
-       memset(databuffer, 0, datasize);
-
-       for (i=0; i< READSIZE; i++)
-               if((j=rds_readcycle_nowait()) < 0) {
-                       return -1;
-               } else {
-                       databuffer[i/8]|=(RDS_DATA(j) << (7-(i%8)));
-               }
-
-       return 0;
-}
-
-static int rds_ack(void)
-{
-       int i=rds_readcycle();
-
-       if (i < 0)
-               return -1;
-       if (i & RDS_DATAMASK) {
-               return 0;  /* ACK  */
-       } else {
-               printk(KERN_DEBUG "aci-rds: NACK\n");
-               return 1;  /* NACK */
-       }
-}
-
-int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize)
-{
-       int ret;
-
-       if (mutex_lock_interruptible(&aci_rds_mutex))
-               return -EINTR;
-
-       rds_write(cmd);
-
-       /* RDS_RESET doesn't need further processing */
-       if (cmd!=RDS_RESET && (rds_ack() || rds_read(databuffer, datasize)))
-               ret = -1;
-       else
-               ret = 0;
-
-       mutex_unlock(&aci_rds_mutex);
-
-       return ret;
-}
-EXPORT_SYMBOL(aci_rds_cmd);
-
-int __init attach_aci_rds(void)
-{
-       mutex_init(&aci_rds_mutex);
-       return 0;
-}
-
-void __exit unload_aci_rds(void)
-{
-}
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/radio/miropcm20-rds-core.h b/drivers/media/radio/miropcm20-rds-core.h
deleted file mode 100644 (file)
index aeb5761..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef _MIROPCM20_RDS_CORE_H_
-#define _MIROPCM20_RDS_CORE_H_
-
-extern int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize);
-
-#define RDS_STATUS      0x01
-#define RDS_STATIONNAME 0x02
-#define RDS_TEXT        0x03
-#define RDS_ALTFREQ     0x04
-#define RDS_TIMEDATE    0x05
-#define RDS_PI_CODE     0x06
-#define RDS_PTYTATP     0x07
-#define RDS_RESET       0x08
-#define RDS_RXVALUE     0x09
-
-extern void __exit unload_aci_rds(void);
-extern int __init attach_aci_rds(void);
-
-#endif /* _MIROPCM20_RDS_CORE_H_ */
diff --git a/drivers/media/radio/miropcm20-rds.c b/drivers/media/radio/miropcm20-rds.c
deleted file mode 100644 (file)
index 3e840f7..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/* MiroSOUND PCM20 radio rds interface driver
- * (c) 2001 Robert Siemer <Robert.Siemer@gmx.de>
- * Thanks to Fred Seidel. See miropcm20-rds-core.c for further information.
- */
-
-/* Revision history:
- *
- *   2001-04-18  Robert Siemer <Robert.Siemer@gmx.de>
- *        separate file for user interface driver
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/delay.h>
-#include <asm/uaccess.h>
-#include "miropcm20-rds-core.h"
-
-static char * text_buffer;
-static int rds_users;
-
-
-static int rds_f_open(struct inode *in, struct file *fi)
-{
-       if (rds_users)
-               return -EBUSY;
-
-       lock_kernel();
-       rds_users++;
-       if ((text_buffer=kmalloc(66, GFP_KERNEL)) == 0) {
-               rds_users--;
-               printk(KERN_NOTICE "aci-rds: Out of memory by open()...\n");
-               unlock_kernel();
-               return -ENOMEM;
-       }
-
-       unlock_kernel();
-       return 0;
-}
-
-static int rds_f_release(struct inode *in, struct file *fi)
-{
-       kfree(text_buffer);
-
-       rds_users--;
-       return 0;
-}
-
-static void print_matrix(char *ch, char out[])
-{
-       int j;
-
-       for (j=7; j>=0; j--) {
-                out[7-j] = ((*ch >> j) & 0x1) + '0';
-       }
-}
-
-static ssize_t rds_f_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
-{
-//     i = sprintf(text_buffer, "length: %d, offset: %d\n", length, *offset);
-
-       char c;
-       char bits[8];
-
-       msleep(2000);
-       aci_rds_cmd(RDS_STATUS, &c, 1);
-       print_matrix(&c, bits);
-       if (copy_to_user(buffer, bits, 8))
-               return -EFAULT;
-
-/*     if ((c >> 3) & 1) {
-               aci_rds_cmd(RDS_STATIONNAME, text_buffer+1, 8);
-               text_buffer[0]  = ' ' ;
-               text_buffer[9]  = '\n';
-               return copy_to_user(buffer+8, text_buffer, 10) ? -EFAULT: 18;
-       }
-*/
-/*     if ((c >> 6) & 1) {
-               aci_rds_cmd(RDS_PTYTATP, &c, 1);
-               if ( c & 1)
-                       sprintf(text_buffer, " M");
-               else
-                       sprintf(text_buffer, " S");
-               if ((c >> 1) & 1)
-                       sprintf(text_buffer+2, " TA");
-               else
-                       sprintf(text_buffer+2, " --");
-               if ((c >> 7) & 1)
-                       sprintf(text_buffer+5, " TP");
-               else
-                       sprintf(text_buffer+5, " --");
-               sprintf(text_buffer+8, " %2d\n", (c >> 2) & 0x1f);
-               return copy_to_user(buffer+8, text_buffer, 12) ? -EFAULT: 20;
-       }
-*/
-
-       if ((c >> 4) & 1) {
-               aci_rds_cmd(RDS_TEXT, text_buffer, 65);
-               text_buffer[0]  = ' ' ;
-               text_buffer[65] = '\n';
-               return copy_to_user(buffer+8, text_buffer,66) ? -EFAULT : 66+8;
-       } else {
-               put_user('\n', buffer+8);
-               return 9;
-       }
-}
-
-static const struct file_operations rds_fops = {
-       .owner          = THIS_MODULE,
-       .read           = rds_f_read,
-       .open           = rds_f_open,
-       .release        = rds_f_release
-};
-
-static struct miscdevice rds_miscdev = {
-       .minor          = MISC_DYNAMIC_MINOR,
-       .name           = "radiotext",
-       .fops           = &rds_fops,
-};
-
-static int __init miropcm20_rds_init(void)
-{
-       return misc_register(&rds_miscdev);
-}
-
-static void __exit miropcm20_rds_cleanup(void)
-{
-       misc_deregister(&rds_miscdev);
-}
-
-module_init(miropcm20_rds_init);
-module_exit(miropcm20_rds_cleanup);
-MODULE_LICENSE("GPL");
index eba9209..1f064f4 100644 (file)
@@ -426,8 +426,7 @@ static int __init rtrack_init(void)
 
        rtrack_radio.priv=&rtrack_unit;
 
-       if(video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr)==-1)
-       {
+       if (video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
                release_region(io, 2);
                return -EINVAL;
        }
index 3fe5504..628c689 100644 (file)
@@ -394,8 +394,7 @@ static int __init aztech_init(void)
        mutex_init(&lock);
        aztech_radio.priv=&aztech_unit;
 
-       if(video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr)==-1)
-       {
+       if (video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
                release_region(io,2);
                return -EINVAL;
        }
index 6166e72..04c3698 100644 (file)
@@ -682,7 +682,7 @@ static int __init cadet_init(void)
        }
        if (!request_region(io,2,"cadet"))
                goto fail;
-       if(video_register_device(&cadet_radio,VFL_TYPE_RADIO,radio_nr)==-1) {
+       if (video_register_device(&cadet_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
                release_region(io,2);
                goto fail;
        }
index 36e754e..5cd7f03 100644 (file)
@@ -425,7 +425,7 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci
        }
        *devradio = vdev_template;
 
-       if ( video_register_device( devradio, VFL_TYPE_RADIO , nr_radio) == -1 ) {
+       if (video_register_device(devradio, VFL_TYPE_RADIO, nr_radio) < 0) {
                kfree( devradio );
                goto err_video;
        }
index 2b1a622..0a0f956 100644 (file)
@@ -612,8 +612,7 @@ static int __init gemtek_init(void)
 
        gemtek_radio.priv = &gemtek_unit;
 
-       if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO,
-               radio_nr) == -1) {
+       if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
                release_region(io, 1);
                return -EBUSY;
        }
index 0ada1c6..9ef0a76 100644 (file)
@@ -409,8 +409,7 @@ static int __devinit maestro_probe(struct pci_dev *pdev,
        video_set_drvdata(maestro_radio_inst, radio_unit);
        pci_set_drvdata(pdev, maestro_radio_inst);
 
-       retval = video_register_device(maestro_radio_inst, VFL_TYPE_RADIO,
-               radio_nr);
+       retval = video_register_device(maestro_radio_inst, VFL_TYPE_RADIO, radio_nr);
        if (retval) {
                printk(KERN_ERR "can't register video device!\n");
                goto errfr1;
index 43c7549..0cc6fcb 100644 (file)
@@ -156,28 +156,28 @@ static void set_freq(__u16 io, __u32 freq)
 {
        unsigned long int si;
        int bl;
-       int data = FREQ2BITS(freq);
+       int val = FREQ2BITS(freq);
 
        /* TEA5757 shift register bits (see pdf) */
 
-       outbit(0,io); // 24  search
-       outbit(1,io); // 23  search up/down
+       outbit(0, io); /* 24  search */
+       outbit(1, io); /* 23  search up/down */
 
-       outbit(0,io); // 22  stereo/mono
+       outbit(0, io); /* 22  stereo/mono */
 
-       outbit(0,io); // 21  band
-       outbit(0,io); // 20  band (only 00=FM works I think)
+       outbit(0, io); /* 21  band */
+       outbit(0, io); /* 20  band (only 00=FM works I think) */
 
-       outbit(0,io); // 19  port ?
-       outbit(0,io); // 18  port ?
+       outbit(0, io); /* 19  port ? */
+       outbit(0, io); /* 18  port ? */
 
-       outbit(0,io); // 17  search level
-       outbit(0,io); // 16  search level
+       outbit(0, io); /* 17  search level */
+       outbit(0, io); /* 16  search level */
 
        si = 0x8000;
-       for (bl = 1; bl <= 16 ; bl++) {
-               outbit(data & si,io);
-               si >>=1;
+       for (bl = 1; bl <= 16; bl++) {
+               outbit(val & si, io);
+               si >>= 1;
        }
 
        dprintk(1, "Radio freq set to %d.%02d MHz\n",
@@ -410,7 +410,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) < 0) {
                printk("radio-maxiradio: can't register device!");
                goto err_out_free_region;
        }
index e2dde08..6d820e2 100644 (file)
@@ -332,8 +332,7 @@ static int __init rtrack2_init(void)
        rtrack2_radio.priv=&rtrack2_unit;
 
        spin_lock_init(&lock);
-       if(video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
-       {
+       if (video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
                release_region(io, 4);
                return -EINVAL;
        }
index bb5d92f..0d478f5 100644 (file)
@@ -377,7 +377,7 @@ static int __init fmi_init(void)
 
        mutex_init(&lock);
 
-       if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) == -1) {
+       if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
                release_region(io, 2);
                return -EINVAL;
        }
index a4984ff..16c7ef2 100644 (file)
@@ -1694,8 +1694,8 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
        INIT_DELAYED_WORK(&radio->work, si470x_work);
 
        /* register video device */
-       if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
-               retval = -EIO;
+       retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
+       if (retval) {
                printk(KERN_WARNING DRIVER_NAME
                                ": Could not register video device\n");
                goto err_all;
index cefa44f..0876fec 100644 (file)
@@ -405,8 +405,7 @@ static int __init terratec_init(void)
 
        spin_lock_init(&lock);
 
-       if(video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr)==-1)
-       {
+       if (video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
                release_region(io,2);
                return -EINVAL;
        }
index d70172d..1931619 100644 (file)
@@ -378,8 +378,7 @@ static int __init trust_init(void)
                printk(KERN_ERR "trust: port 0x%x already in use\n", io);
                return -EBUSY;
        }
-       if(video_register_device(&trust_radio, VFL_TYPE_RADIO, radio_nr)==-1)
-       {
+       if (video_register_device(&trust_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
                release_region(io, 2);
                return -EINVAL;
        }
index 9f17a33..51d57ed 100644 (file)
@@ -446,8 +446,7 @@ static int __init zoltrix_init(void)
                return -EBUSY;
        }
 
-       if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO, radio_nr) == -1)
-       {
+       if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
                release_region(io, 2);
                return -EINVAL;
        }
index bbc6f8b..ef7c8d3 100644 (file)
@@ -20,6 +20,8 @@ ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
   obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
 endif
 
+obj-$(CONFIG_VIDEO_TUNER) += tuner.o
+
 obj-$(CONFIG_VIDEO_BT848) += bt8xx/
 obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
 obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
@@ -85,8 +87,6 @@ obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
 obj-$(CONFIG_VIDEO_DPC) += dpc7146.o
 obj-$(CONFIG_TUNER_3036) += tuner-3036.o
 
-obj-$(CONFIG_VIDEO_TUNER) += tuner.o
-
 obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
 obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
 obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
index ed9a50f..018f72b 100644 (file)
@@ -7,6 +7,7 @@ config VIDEO_AU0828
        select DVB_AU8522 if !DVB_FE_CUSTOMIZE
        select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
        select MEDIA_TUNER_MXL5007T if !DVB_FE_CUSTOMIZE
+       select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
        ---help---
          This is a video4linux driver for Auvitek's USB device.
 
index 443e590..ed48908 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Auvitek USB bridge
  *
- *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2008 Steven Toth <stoth@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
@@ -38,6 +38,9 @@ struct au0828_board au0828_boards[] = {
        [AU0828_BOARD_DVICO_FUSIONHDTV7] = {
                .name   = "DViCO FusionHDTV USB",
        },
+       [AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
+               .name = "Hauppauge Woodbury",
+       },
 };
 
 /* Tuner callback function for au0828 boards. Currently only needed
@@ -115,6 +118,7 @@ void au0828_card_setup(struct au0828_dev *dev)
        case AU0828_BOARD_HAUPPAUGE_HVR850:
        case AU0828_BOARD_HAUPPAUGE_HVR950Q:
        case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
+       case AU0828_BOARD_HAUPPAUGE_WOODBURY:
                if (dev->i2c_rc == 0)
                        hauppauge_eeprom(dev, eeprom+0xa0);
                break;
@@ -134,6 +138,7 @@ void au0828_gpio_setup(struct au0828_dev *dev)
        case AU0828_BOARD_HAUPPAUGE_HVR850:
        case AU0828_BOARD_HAUPPAUGE_HVR950Q:
        case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
+       case AU0828_BOARD_HAUPPAUGE_WOODBURY:
                /* GPIO's
                 * 4 - CS5340
                 * 5 - AU8522 Demodulator
@@ -205,6 +210,8 @@ struct usb_device_id au0828_usb_id_table [] = {
                .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
        { USB_DEVICE(0x2040, 0x7281),
                .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
+       { USB_DEVICE(0x2040, 0x8200),
+               .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
        { },
 };
 
index c37f5fd..48a1882 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Auvitek USB bridge
  *
- *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2008 Steven Toth <stoth@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
@@ -24,3 +24,4 @@
 #define AU0828_BOARD_HAUPPAUGE_HVR850  2
 #define AU0828_BOARD_DVICO_FUSIONHDTV7 3
 #define AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL     4
+#define AU0828_BOARD_HAUPPAUGE_WOODBURY        5
index 54bfc0f..d856de9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Auvitek USB bridge
  *
- *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2008 Steven Toth <stoth@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
@@ -252,5 +252,5 @@ module_init(au0828_init);
 module_exit(au0828_exit);
 
 MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products");
-MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
+MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
 MODULE_LICENSE("GPL");
index 584a83a..ba94be7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Auvitek USB bridge
  *
- *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2008 Steven Toth <stoth@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
@@ -29,6 +29,7 @@
 #include "au8522.h"
 #include "xc5000.h"
 #include "mxl5007t.h"
+#include "tda18271.h"
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
@@ -38,6 +39,15 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 static struct au8522_config hauppauge_hvr950q_config = {
        .demod_address = 0x8e >> 1,
        .status_mode   = AU8522_DEMODLOCKING,
+       .qam_if        = AU8522_IF_6MHZ,
+       .vsb_if        = AU8522_IF_6MHZ,
+};
+
+static struct au8522_config hauppauge_woodbury_config = {
+       .demod_address = 0x8e >> 1,
+       .status_mode   = AU8522_DEMODLOCKING,
+       .qam_if        = AU8522_IF_4MHZ,
+       .vsb_if        = AU8522_IF_3_25MHZ,
 };
 
 static struct xc5000_config hauppauge_hvr950q_tunerconfig = {
@@ -51,6 +61,10 @@ static struct mxl5007t_config mxl5007t_hvr950q_config = {
        .if_freq_hz = MxL_IF_6_MHZ,
 };
 
+static struct tda18271_config hauppauge_woodbury_tunerconfig = {
+       .gate    = TDA18271_GATE_DIGITAL,
+};
+
 /*-------------------------------------------------------------------*/
 static void urb_completion(struct urb *purb)
 {
@@ -357,6 +371,15 @@ int au0828_dvb_register(struct au0828_dev *dev)
                                   &dev->i2c_adap, 0x60,
                                   &mxl5007t_hvr950q_config);
                break;
+       case AU0828_BOARD_HAUPPAUGE_WOODBURY:
+               dvb->frontend = dvb_attach(au8522_attach,
+                               &hauppauge_woodbury_config,
+                               &dev->i2c_adap);
+               if (dvb->frontend != NULL)
+                       dvb_attach(tda18271_attach, dvb->frontend,
+                                  0x60, &dev->i2c_adap,
+                                  &hauppauge_woodbury_tunerconfig);
+               break;
        default:
                printk(KERN_WARNING "The frontend of your DVB/ATSC card "
                       "isn't supported yet\n");
index 741a493..d618fba 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Auvitek AU0828 USB bridge
  *
- *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2008 Steven Toth <stoth@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
index 3982755..1e87fa0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Auvitek USB bridge
  *
- *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2008 Steven Toth <stoth@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
index 7beb571..4f10ff3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Auvitek AU0828 USB bridge
  *
- *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2008 Steven Toth <stoth@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
index 1c56ae9..6081edc 100644 (file)
@@ -3144,8 +3144,9 @@ static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256])
 
 static void flyvideo_gpio(struct bttv *btv)
 {
-       int gpio,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821;
-       int tuner=UNSET,ttype;
+       int gpio, has_remote, has_radio, is_capture_only;
+       int is_lr90, has_tda9820_tda9821;
+       int tuner_type = UNSET, ttype;
 
        gpio_inout(0xffffff, 0);
        udelay(8);  /* without this we would see the 0x1800 mask */
@@ -3163,20 +3164,26 @@ static void flyvideo_gpio(struct bttv *btv)
         * xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered
         * Note: Some bits are Audio_Mask !
         */
-       ttype=(gpio&0x0f0000)>>16;
-       switch(ttype) {
-       case 0x0: tuner=2; /* NTSC, e.g. TPI8NSR11P */
+       ttype = (gpio & 0x0f0000) >> 16;
+       switch (ttype) {
+       case 0x0:
+               tuner_type = 2;  /* NTSC, e.g. TPI8NSR11P */
                break;
-       case 0x2: tuner=39;/* LG NTSC (newer TAPC series) TAPC-H701P */
+       case 0x2:
+               tuner_type = 39; /* LG NTSC (newer TAPC series) TAPC-H701P */
                break;
-       case 0x4: tuner=5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */
+       case 0x4:
+               tuner_type = 5;  /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */
                break;
-       case 0x6: tuner=37;/* LG PAL (newer TAPC series) TAPC-G702P */
+       case 0x6:
+               tuner_type = 37; /* LG PAL (newer TAPC series) TAPC-G702P */
                break;
-               case 0xC: tuner=3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */
+       case 0xC:
+               tuner_type = 3;  /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */
                break;
        default:
                printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->c.nr);
+               break;
        }
 
        has_remote          =   gpio & 0x800000;
@@ -3189,23 +3196,26 @@ static void flyvideo_gpio(struct bttv *btv)
        /*
         * gpio & 0x001000    output bit for audio routing */
 
-       if(is_capture_only)
-               tuner = TUNER_ABSENT; /* No tuner present */
+       if (is_capture_only)
+               tuner_type = TUNER_ABSENT; /* No tuner present */
 
        printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n",
-              btv->c.nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio);
+               btv->c.nr, has_radio ? "yes" : "no ",
+               has_remote ? "yes" : "no ", tuner_type, gpio);
        printk(KERN_INFO "bttv%d: FlyVideo  LR90=%s tda9821/tda9820=%s capture_only=%s\n",
-               btv->c.nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ",
-               is_capture_only?"yes":"no ");
+               btv->c.nr, is_lr90 ? "yes" : "no ",
+               has_tda9820_tda9821 ? "yes" : "no ",
+               is_capture_only ? "yes" : "no ");
 
-       if (tuner != UNSET) /* only set if known tuner autodetected, else let insmod option through */
-               btv->tuner_type = tuner;
+       if (tuner_type != UNSET) /* only set if known tuner autodetected, else let insmod option through */
+               btv->tuner_type = tuner_type;
        btv->has_radio = has_radio;
 
        /* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80
         * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00
         * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */
-       if(has_tda9820_tda9821) btv->audio_mode_gpio = lt9415_audio;
+       if (has_tda9820_tda9821)
+               btv->audio_mode_gpio = lt9415_audio;
        /* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */
 }
 
@@ -3962,7 +3972,7 @@ static int tuner_1_table[] = {
 
 static void __devinit avermedia_eeprom(struct bttv *btv)
 {
-       int tuner_make,tuner_tv_fm,tuner_format,tuner=0;
+       int tuner_make, tuner_tv_fm, tuner_format, tuner_type = 0;
 
        tuner_make      = (eeprom_data[0x41] & 0x7);
        tuner_tv_fm     = (eeprom_data[0x41] & 0x18) >> 3;
@@ -3970,24 +3980,24 @@ static void __devinit avermedia_eeprom(struct bttv *btv)
        btv->has_remote = (eeprom_data[0x42] & 0x01);
 
        if (tuner_make == 0 || tuner_make == 2)
-               if(tuner_format <=0x0a)
-                       tuner = tuner_0_table[tuner_format];
+               if (tuner_format <= 0x0a)
+                       tuner_type = tuner_0_table[tuner_format];
        if (tuner_make == 1)
-               if(tuner_format <=9)
-                       tuner = tuner_1_table[tuner_format];
+               if (tuner_format <= 9)
+                       tuner_type = tuner_1_table[tuner_format];
 
        if (tuner_make == 4)
-               if(tuner_format == 0x09)
-                       tuner = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */
+               if (tuner_format == 0x09)
+                       tuner_type = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */
 
        printk(KERN_INFO "bttv%d: Avermedia eeprom[0x%02x%02x]: tuner=",
-               btv->c.nr,eeprom_data[0x41],eeprom_data[0x42]);
-       if(tuner) {
-               btv->tuner_type=tuner;
-               printk("%d",tuner);
+               btv->c.nr, eeprom_data[0x41], eeprom_data[0x42]);
+       if (tuner_type) {
+               btv->tuner_type = tuner_type;
+               printk(KERN_CONT "%d", tuner_type);
        } else
-               printk("Unknown type");
-       printk(" radio:%s remote control:%s\n",
+               printk(KERN_CONT "Unknown type");
+       printk(KERN_CONT " radio:%s remote control:%s\n",
               tuner_tv_fm     ? "yes" : "no",
               btv->has_remote ? "yes" : "no");
 }
@@ -4029,7 +4039,8 @@ static void __devinit boot_msp34xx(struct bttv *btv, int pin)
 
        gpio_inout(mask,mask);
        gpio_bits(mask,0);
-       udelay(2500);
+       mdelay(2);
+       udelay(500);
        gpio_bits(mask,mask);
 
        if (bttv_gpio)
index 85bf31a..6ae4cc8 100644 (file)
@@ -96,7 +96,6 @@ static unsigned int irq_iswitch;
 static unsigned int uv_ratio    = 50;
 static unsigned int full_luma_range;
 static unsigned int coring;
-extern int no_overlay;
 
 /* API features (turn on/off stuff for testing) */
 static unsigned int v4l2        = 1;
index 649682a..5b1b8e4 100644 (file)
@@ -244,7 +244,8 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
                  const struct bttv_format *fmt, struct bttv_overlay *ov,
                  int skip_even, int skip_odd)
 {
-       int dwords,rc,line,maxy,start,end,skip,nskips;
+       int dwords, rc, line, maxy, start, end;
+       unsigned skip, nskips;
        struct btcx_skiplist *skips;
        __le32 *rp;
        u32 ri,ra;
index 08ef54a..b4d940b 100644 (file)
@@ -266,6 +266,11 @@ extern struct bus_type bttv_sub_bus_type;
 int bttv_sub_add_device(struct bttv_core *core, char *name);
 int bttv_sub_del_devices(struct bttv_core *core);
 
+/* ---------------------------------------------------------- */
+/* bttv-cards.c                                               */
+
+extern int no_overlay;
+
 /* ---------------------------------------------------------- */
 /* bttv-driver.c                                              */
 
index f42701f..3324ab3 100644 (file)
@@ -184,12 +184,12 @@ btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips)
 }
 
 void
-btcx_calc_skips(int line, int width, unsigned int *maxy,
+btcx_calc_skips(int line, int width, int *maxy,
                struct btcx_skiplist *skips, unsigned int *nskips,
                const struct v4l2_clip *clips, unsigned int nclips)
 {
        unsigned int clip,skip;
-       int end,maxline;
+       int end, maxline;
 
        skip=0;
        maxline = 9999;
index 861bc81..f8bc6e8 100644 (file)
@@ -23,7 +23,7 @@ int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
 int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips,
               unsigned int n, int mask);
 void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips);
-void btcx_calc_skips(int line, int width, unsigned int *maxy,
+void btcx_calc_skips(int line, int width, int *maxy,
                     struct btcx_skiplist *skips, unsigned int *nskips,
                     const struct v4l2_clip *clips, unsigned int nclips);
 
index d3b3268..6e39e25 100644 (file)
@@ -946,8 +946,7 @@ static int init_bwqcam(struct parport *port)
 
        printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name);
 
-       if(video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1)
-       {
+       if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
                parport_unregister_device(qcam->pdev);
                kfree(qcam);
                return -ENODEV;
index fe9379b..7f6c6b4 100644 (file)
@@ -787,8 +787,7 @@ static int init_cqcam(struct parport *port)
 
        parport_release(qcam->pdev);
 
-       if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1)
-       {
+       if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
                printk(KERN_ERR "Unable to register Colour QuickCam on %s\n",
                       qcam->pport->name);
                parport_unregister_device(qcam->pdev);
index dc8cc61..a661800 100644 (file)
@@ -3955,7 +3955,7 @@ struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowleve
        camera->lowlevel_data = lowlevel;
 
        /* register v4l device */
-       if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+       if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
                kfree(camera);
                printk(KERN_DEBUG "video_register_device failed\n");
                return NULL;
index 515c8b5..eb9f15c 100644 (file)
@@ -1024,7 +1024,6 @@ static int ioctl_queryctrl(void *arg,struct camera_data *cam)
                if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
                   cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){
                        // Maximum 15fps
-                       int i;
                        for(i=0; i<c->maximum; ++i) {
                                if(framerate_controls[i].value ==
                                   CPIA2_VP_FRAMERATE_15) {
@@ -1959,8 +1958,7 @@ int cpia2_register_camera(struct camera_data *cam)
        reset_camera_struct_v4l(cam);
 
        /* register v4l device */
-       if (video_register_device
-           (cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+       if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
                ERR("video_register_device failed\n");
                video_device_release(cam->vdev);
                return -ENODEV;
index 834b924..e996a4e 100644 (file)
@@ -32,7 +32,7 @@ int cx18_av_loadfw(struct cx18 *cx)
        u32 v;
        const u8 *ptr;
        int i;
-       int retries = 0;
+       int retries1 = 0;
 
        if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) {
                CX18_ERR("unable to open firmware %s\n", FWFILE);
@@ -41,7 +41,7 @@ int cx18_av_loadfw(struct cx18 *cx)
 
        /* The firmware load often has byte errors, so allow for several
           retries, both at byte level and at the firmware load level. */
-       while (retries < 5) {
+       while (retries1 < 5) {
                cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
                cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6);
 
@@ -57,9 +57,9 @@ int cx18_av_loadfw(struct cx18 *cx)
                for (i = 0; i < size; i++) {
                        u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16);
                        u32 value = 0;
-                       int retries;
+                       int retries2;
 
-                       for (retries = 0; retries < 5; retries++) {
+                       for (retries2 = 0; retries2 < 5; retries2++) {
                                cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
                                udelay(10);
                                value = cx18_av_read4(cx, CXADEC_DL_CTL);
@@ -69,18 +69,18 @@ int cx18_av_loadfw(struct cx18 *cx)
                                   the address.  We can only write the lower
                                   address byte of the address. */
                                if ((value & 0x3F00) != (dl_control & 0x3F00)) {
-                                       retries = 5;
+                                       retries2 = 5;
                                        break;
                                }
                        }
-                       if (retries >= 5)
+                       if (retries2 >= 5)
                                break;
                }
                if (i == size)
                        break;
-               retries++;
+               retries1++;
        }
-       if (retries >= 5) {
+       if (retries1 >= 5) {
                CX18_ERR("unable to load firmware %s\n", FWFILE);
                release_firmware(fw);
                return -EIO;
index 22434aa..bd18afe 100644 (file)
@@ -74,9 +74,9 @@ static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
                                     -1, -1, -1, -1, -1, -1, -1, -1,
                                     -1, -1, -1, -1, -1, -1, -1, -1 };
 
-static int cardtype_c = 1;
-static int tuner_c = 1;
-static int radio_c = 1;
+static unsigned cardtype_c = 1;
+static unsigned tuner_c = 1;
+static unsigned radio_c = 1;
 static char pal[] = "--";
 static char secam[] = "--";
 static char ntsc[] = "-";
index cae3898..1e420a8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  cx18 functions for DVB support
  *
- *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2008 Steven Toth <stoth@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
index d6a6ccd..bf8d8f6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  cx18 functions for DVB support
  *
- *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2008 Steven Toth <stoth@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
index 25114a5..ab21831 100644 (file)
@@ -61,7 +61,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
                CX18_WARN("Ack struct = %d for %s\n",
                        mb->args[2], s->name);
        id = read_enc(off);
-       buf = cx18_queue_find_buf(s, id, read_enc(off + 4));
+       buf = cx18_queue_get_buf_irq(s, id, read_enc(off + 4));
        CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
        if (buf) {
                cx18_buf_sync_for_cpu(s, buf);
index 6990b77..dbe792a 100644 (file)
@@ -78,12 +78,13 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
        return buf;
 }
 
-struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
+struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id,
        u32 bytesused)
 {
        struct cx18 *cx = s->cx;
        struct list_head *p;
 
+       spin_lock(&s->qlock);
        list_for_each(p, &s->q_free.list) {
                struct cx18_buffer *buf =
                        list_entry(p, struct cx18_buffer, list);
@@ -92,114 +93,48 @@ struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
                        continue;
                buf->bytesused = bytesused;
                /* the transport buffers are handled differently,
-                  so there is no need to move them to the full queue */
-               if (s->type == CX18_ENC_STREAM_TYPE_TS)
-                       return buf;
-               s->q_free.buffers--;
-               s->q_free.length -= s->buf_size;
-               s->q_full.buffers++;
-               s->q_full.length += s->buf_size;
-               s->q_full.bytesused += buf->bytesused;
-               list_move_tail(&buf->list, &s->q_full.list);
+                  they are not moved to the full queue */
+               if (s->type != CX18_ENC_STREAM_TYPE_TS) {
+                       s->q_free.buffers--;
+                       s->q_free.length -= s->buf_size;
+                       s->q_full.buffers++;
+                       s->q_full.length += s->buf_size;
+                       s->q_full.bytesused += buf->bytesused;
+                       list_move_tail(&buf->list, &s->q_full.list);
+               }
+               spin_unlock(&s->qlock);
                return buf;
        }
+       spin_unlock(&s->qlock);
        CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name);
        return NULL;
 }
 
-static void cx18_queue_move_buf(struct cx18_stream *s, struct cx18_queue *from,
-               struct cx18_queue *to, int clear, int full)
-{
-       struct cx18_buffer *buf =
-               list_entry(from->list.next, struct cx18_buffer, list);
-
-       list_move_tail(from->list.next, &to->list);
-       from->buffers--;
-       from->length -= s->buf_size;
-       from->bytesused -= buf->bytesused - buf->readpos;
-       /* special handling for q_free */
-       if (clear)
-               buf->bytesused = buf->readpos = buf->b_flags = 0;
-       else if (full) {
-               /* special handling for stolen buffers, assume
-                  all bytes are used. */
-               buf->bytesused = s->buf_size;
-               buf->readpos = buf->b_flags = 0;
-       }
-       to->buffers++;
-       to->length += s->buf_size;
-       to->bytesused += buf->bytesused - buf->readpos;
-}
-
-/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'.
-   If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'.
-   If 'steal' != NULL, then buffers may also taken from that queue if
-   needed.
-
-   The buffer is automatically cleared if it goes to the free queue. It is
-   also cleared if buffers need to be taken from the 'steal' queue and
-   the 'from' queue is the free queue.
-
-   When 'from' is q_free, then needed_bytes is compared to the total
-   available buffer length, otherwise needed_bytes is compared to the
-   bytesused value. For the 'steal' queue the total available buffer
-   length is always used.
-
-   -ENOMEM is returned if the buffers could not be obtained, 0 if all
-   buffers where obtained from the 'from' list and if non-zero then
-   the number of stolen buffers is returned. */
-static int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from,
-                          struct cx18_queue *steal, struct cx18_queue *to,
-                          int needed_bytes)
+/* Move all buffers of a queue to q_free, while flushing the buffers */
+static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q)
 {
        unsigned long flags;
-       int rc = 0;
-       int from_free = from == &s->q_free;
-       int to_free = to == &s->q_free;
-       int bytes_available;
-
-       spin_lock_irqsave(&s->qlock, flags);
-       if (needed_bytes == 0) {
-               from_free = 1;
-               needed_bytes = from->length;
-       }
-
-       bytes_available = from_free ? from->length : from->bytesused;
-       bytes_available += steal ? steal->length : 0;
+       struct cx18_buffer *buf;
 
-       if (bytes_available < needed_bytes) {
-               spin_unlock_irqrestore(&s->qlock, flags);
-               return -ENOMEM;
-       }
-       if (from_free) {
-               u32 old_length = to->length;
+       if (q == &s->q_free)
+               return;
 
-               while (to->length - old_length < needed_bytes) {
-                       if (list_empty(&from->list))
-                               from = steal;
-                       if (from == steal)
-                               rc++;   /* keep track of 'stolen' buffers */
-                       cx18_queue_move_buf(s, from, to, 1, 0);
-               }
-       } else {
-               u32 old_bytesused = to->bytesused;
-
-               while (to->bytesused - old_bytesused < needed_bytes) {
-                       if (list_empty(&from->list))
-                               from = steal;
-                       if (from == steal)
-                               rc++;   /* keep track of 'stolen' buffers */
-                       cx18_queue_move_buf(s, from, to, to_free, rc);
-               }
+       spin_lock_irqsave(&s->qlock, flags);
+       while (!list_empty(&q->list)) {
+               buf = list_entry(q->list.next, struct cx18_buffer, list);
+               list_move_tail(q->list.next, &s->q_free.list);
+               buf->bytesused = buf->readpos = buf->b_flags = 0;
+               s->q_free.buffers++;
+               s->q_free.length += s->buf_size;
        }
+       cx18_queue_init(q);
        spin_unlock_irqrestore(&s->qlock, flags);
-       return rc;
 }
 
 void cx18_flush_queues(struct cx18_stream *s)
 {
-       cx18_queue_move(s, &s->q_io, NULL, &s->q_free, 0);
-       cx18_queue_move(s, &s->q_full, NULL, &s->q_free, 0);
+       cx18_queue_flush(s, &s->q_io);
+       cx18_queue_flush(s, &s->q_full);
 }
 
 int cx18_stream_alloc(struct cx18_stream *s)
@@ -214,10 +149,10 @@ int cx18_stream_alloc(struct cx18_stream *s)
                s->name, s->buffers, s->buf_size,
                s->buffers * s->buf_size / 1024);
 
-       if (((char *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] -
-                               (char *)cx->scb) > SCB_RESERVED_SIZE) {
-               unsigned bufsz = (((char *)cx->scb) + SCB_RESERVED_SIZE -
-                                       ((char *)cx->scb->cpu_mdl));
+       if (((char __iomem *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] -
+                               (char __iomem *)cx->scb) > SCB_RESERVED_SIZE) {
+               unsigned bufsz = (((char __iomem *)cx->scb) + SCB_RESERVED_SIZE -
+                                       ((char __iomem *)cx->scb->cpu_mdl));
 
                CX18_ERR("Too many buffers, cannot fit in SCB area\n");
                CX18_ERR("Max buffers = %zd\n",
index 91423b9..7f93bb1 100644 (file)
@@ -46,7 +46,7 @@ void cx18_queue_init(struct cx18_queue *q);
 void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
        struct cx18_queue *q);
 struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q);
-struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
+struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id,
        u32 bytesused);
 void cx18_flush_queues(struct cx18_stream *s);
 
index 8118091..7b0e8c0 100644 (file)
@@ -4,7 +4,7 @@
  *
  *    (c) 2004 Jelle Foks <jelle@foks.8m.com>
  *    (c) 2004 Gerd Knorr <kraxel@bytesex.org>
- *    (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *    (c) 2008 Steven Toth <stoth@linuxtv.org>
  *      - CX23885/7/8 support
  *
  *  Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
index a19de85..c36d3f6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Conexant CX23885 PCIe bridge
  *
- *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2006 Steven Toth <stoth@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
index 6286a9c..25fb099 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Conexant CX23885 PCIe bridge
  *
- *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2006 Steven Toth <stoth@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
@@ -33,7 +33,7 @@
 #include "cx23885.h"
 
 MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
-MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
+MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
 MODULE_LICENSE("GPL");
 
 static unsigned int debug;
index 0a2e655..291b9d0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Conexant CX23885 PCIe bridge
  *
- *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2006 Steven Toth <stoth@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
index c6bb0a0..f98e476 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Conexant CX23885 PCIe bridge
  *
- *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2006 Steven Toth <stoth@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
index bdd11bc..20b68a2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Conexant CX23885 PCIe bridge
  *
- *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2006 Steven Toth <stoth@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
index e36e3fc..35e61cd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Conexant CX23885 PCIe bridge
  *
- *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2007 Steven Toth <stoth@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
index ad2235d..6047c78 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Conexant CX23885 PCIe bridge
  *
- *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2007 Steven Toth <stoth@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
@@ -41,7 +41,7 @@
 #endif
 
 MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards");
-MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
+MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
 MODULE_LICENSE("GPL");
 
 /* ------------------------------------------------------------------ */
index 00dfdc8..e23d97c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Conexant CX23885 PCIe bridge
  *
- *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2006 Steven Toth <stoth@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
index 209d3bc..4da8cd7 100644 (file)
@@ -13,7 +13,7 @@
  * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca>
  * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>.
  *
- * CX23885 support by Steven Toth <stoth@hauppauge.com>.
+ * CX23885 support by Steven Toth <stoth@linuxtv.org>.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 2d170d1..8db2a05 100644 (file)
@@ -2588,6 +2588,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        cam->v4ldev->fops = &et61x251_fops;
        cam->v4ldev->minor = video_nr[dev_nr];
        cam->v4ldev->release = video_device_release;
+       cam->v4ldev->parent = &udev->dev;
        video_set_drvdata(cam->v4ldev, cam);
 
        init_completion(&cam->probe);
index cd3a3f5..4d9f4cc 100644 (file)
@@ -124,7 +124,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
        struct usb_device *dev = gspca_dev->dev;
 
 #ifdef GSPCA_DEBUG
-       if (len > sizeof gspca_dev->usb_buf) {
+       if (len > USB_BUF_SZ) {
                err("reg_r: buffer overflow");
                return;
        }
@@ -164,7 +164,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
        struct usb_device *dev = gspca_dev->dev;
 
 #ifdef GSPCA_DEBUG
-       if (len > sizeof gspca_dev->usb_buf) {
+       if (len > USB_BUF_SZ) {
                err("reg_w: buffer overflow");
                return;
        }
@@ -731,13 +731,13 @@ static void cx11646_jpeg(struct gspca_dev*gspca_dev)
        reg_w_val(gspca_dev, 0x0000, 0x00);
        /* wait for completion */
        retry = 50;
-       while (retry--) {
+       do {
                reg_r(gspca_dev, 0x0002, 1);
                                                        /* 0x07 until 0x00 */
                if (gspca_dev->usb_buf[0] == 0x00)
                        break;
                reg_w_val(gspca_dev, 0x0053, 0x00);
-       }
+       } while (--retry);
        if (retry == 0)
                PDEBUG(D_ERR, "Damned Errors sending jpeg Table");
        /* send the qtable now */
@@ -826,8 +826,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
        return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
        cx11646_init1(gspca_dev);
        cx11646_initsize(gspca_dev);
@@ -845,10 +845,6 @@ static void sd_start(struct gspca_dev *gspca_dev)
        cx11646_jpeg(gspca_dev);
 }
 
-static void sd_stopN(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_stop0(struct gspca_dev *gspca_dev)
 {
        int retry = 50;
@@ -871,10 +867,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
        reg_w_val(gspca_dev, 0x00fc, 0xe0);
 }
 
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
@@ -998,11 +990,9 @@ static struct sd_desc sd_desc = {
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
-       .stopN = sd_stopN,
        .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
 };
 
@@ -1026,6 +1016,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
index 1dbe92d..4ff0e38 100644 (file)
@@ -81,6 +81,7 @@ static struct ctrl sd_ctrls[] = {
         .set = sd_setcontrast,
         .get = sd_getcontrast,
         },
+#define COLOR_IDX 2
        {
         {
          .id = V4L2_CID_SATURATION,
@@ -234,7 +235,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
        struct usb_device *dev = gspca_dev->dev;
 
 #ifdef GSPCA_DEBUG
-       if (len > sizeof gspca_dev->usb_buf) {
+       if (len > USB_BUF_SZ) {
                err("reg_r: buffer overflow");
                return;
        }
@@ -272,7 +273,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
        struct usb_device *dev = gspca_dev->dev;
 
 #ifdef GSPCA_DEBUG
-       if (len > sizeof gspca_dev->usb_buf) {
+       if (len > USB_BUF_SZ) {
                err("reg_w: buffer overflow");
                return;
        }
@@ -665,6 +666,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        } else {
                cam->cam_mode = vga_mode;
                cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+               gspca_dev->ctrl_dis = (1 << COLOR_IDX);
        }
        sd->brightness = BRIGHTNESS_DEF;
        sd->contrast = CONTRAST_DEF;
@@ -674,8 +676,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
        return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
@@ -709,14 +711,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        et_video(gspca_dev, 0);         /* video off */
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static __u8 Et_getgainG(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -893,21 +887,19 @@ static struct sd_desc sd_desc = {
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
-       .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
        .dq_callback = do_autogain,
 };
 
 /* -- module initialisation -- */
 static __devinitdata struct usb_device_id device_table[] = {
-#ifndef CONFIG_USB_ET61X251
        {USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106},
-#endif
+#if !defined CONFIG_USB_ET61X251 && !defined CONFIG_USB_ET61X251_MODULE
        {USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX},
+#endif
        {}
 };
 
@@ -926,6 +918,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
index 15d302b..7be6928 100644 (file)
@@ -114,7 +114,10 @@ static void fill_frame(struct gspca_dev *gspca_dev,
        cam_pkt_op pkt_scan;
 
        if (urb->status != 0) {
-               PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+#ifdef CONFIG_PM
+               if (!gspca_dev->frozen)
+#endif
+                       PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
                return;         /* disconnection ? */
        }
        pkt_scan = gspca_dev->sd_desc->pkt_scan;
@@ -555,10 +558,12 @@ static void gspca_stream_off(struct gspca_dev *gspca_dev)
        gspca_dev->streaming = 0;
        atomic_set(&gspca_dev->nevent, 0);
        if (gspca_dev->present) {
-               gspca_dev->sd_desc->stopN(gspca_dev);
+               if (gspca_dev->sd_desc->stopN)
+                       gspca_dev->sd_desc->stopN(gspca_dev);
                destroy_urbs(gspca_dev);
                gspca_set_alt0(gspca_dev);
-               gspca_dev->sd_desc->stop0(gspca_dev);
+               if (gspca_dev->sd_desc->stop0)
+                       gspca_dev->sd_desc->stop0(gspca_dev);
                PDEBUG(D_STREAM, "stream off OK");
        }
 }
@@ -767,19 +772,7 @@ static int dev_open(struct inode *inode, struct file *file)
                goto out;
        }
 
-       /* if not done yet, initialize the sensor */
-       if (gspca_dev->users == 0) {
-               if (mutex_lock_interruptible(&gspca_dev->usb_lock)) {
-                       ret = -ERESTARTSYS;
-                       goto out;
-               }
-               ret = gspca_dev->sd_desc->open(gspca_dev);
-               mutex_unlock(&gspca_dev->usb_lock);
-               if (ret != 0) {
-                       PDEBUG(D_ERR|D_CONF, "init device failed %d", ret);
-                       goto out;
-               }
-       } else if (gspca_dev->users > 4) {      /* (arbitrary value) */
+       if (gspca_dev->users > 4) {     /* (arbitrary value) */
                ret = -EBUSY;
                goto out;
        }
@@ -792,6 +785,7 @@ static int dev_open(struct inode *inode, struct file *file)
        else
                gspca_dev->vdev.debug &= ~3;
 #endif
+       ret = 0;
 out:
        mutex_unlock(&gspca_dev->queue_lock);
        if (ret != 0)
@@ -812,11 +806,11 @@ static int dev_close(struct inode *inode, struct file *file)
 
        /* if the file did the capture, free the streaming resources */
        if (gspca_dev->capt_file == file) {
-               mutex_lock(&gspca_dev->usb_lock);
-               if (gspca_dev->streaming)
+               if (gspca_dev->streaming) {
+                       mutex_lock(&gspca_dev->usb_lock);
                        gspca_stream_off(gspca_dev);
-               gspca_dev->sd_desc->close(gspca_dev);
-               mutex_unlock(&gspca_dev->usb_lock);
+                       mutex_unlock(&gspca_dev->usb_lock);
+               }
                frame_free(gspca_dev);
                gspca_dev->capt_file = NULL;
                gspca_dev->memory = GSPCA_MEMORY_NO;
@@ -853,42 +847,44 @@ static int vidioc_querycap(struct file *file, void  *priv,
        return 0;
 }
 
-/* the use of V4L2_CTRL_FLAG_NEXT_CTRL asks for the controls to be sorted */
 static int vidioc_queryctrl(struct file *file, void *priv,
                           struct v4l2_queryctrl *q_ctrl)
 {
        struct gspca_dev *gspca_dev = priv;
-       int i;
+       int i, ix;
        u32 id;
 
+       ix = -1;
        id = q_ctrl->id;
        if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
                id &= V4L2_CTRL_ID_MASK;
                id++;
                for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
-                       if (id >= gspca_dev->sd_desc->ctrls[i].qctrl.id) {
-                               memcpy(q_ctrl,
-                                       &gspca_dev->sd_desc->ctrls[i].qctrl,
-                                       sizeof *q_ctrl);
-                               return 0;
+                       if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id)
+                               continue;
+                       if (ix < 0) {
+                               ix = i;
+                               continue;
                        }
+                       if (gspca_dev->sd_desc->ctrls[i].qctrl.id
+                                   > gspca_dev->sd_desc->ctrls[ix].qctrl.id)
+                               continue;
+                       ix = i;
                }
-               return -EINVAL;
        }
        for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
                if (id == gspca_dev->sd_desc->ctrls[i].qctrl.id) {
-                       memcpy(q_ctrl,
-                               &gspca_dev->sd_desc->ctrls[i].qctrl,
-                               sizeof *q_ctrl);
-                       return 0;
+                       ix = i;
+                       break;
                }
        }
-       if (id >= V4L2_CID_BASE
-           && id <= V4L2_CID_LASTP1) {
+       if (ix < 0)
+               return -EINVAL;
+       memcpy(q_ctrl, &gspca_dev->sd_desc->ctrls[ix].qctrl,
+               sizeof *q_ctrl);
+       if (gspca_dev->ctrl_dis & (1 << ix))
                q_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
-               return 0;
-       }
-       return -EINVAL;
+       return 0;
 }
 
 static int vidioc_s_ctrl(struct file *file, void *priv,
@@ -903,6 +899,8 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
             i++, ctrls++) {
                if (ctrl->id != ctrls->qctrl.id)
                        continue;
+               if (gspca_dev->ctrl_dis & (1 << i))
+                       return -EINVAL;
                if (ctrl->value < ctrls->qctrl.minimum
                    || ctrl->value > ctrls->qctrl.maximum)
                        return -ERANGE;
@@ -929,6 +927,8 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
             i++, ctrls++) {
                if (ctrl->id != ctrls->qctrl.id)
                        continue;
+               if (gspca_dev->ctrl_dis & (1 << i))
+                       return -EINVAL;
                if (mutex_lock_interruptible(&gspca_dev->usb_lock))
                        return -ERESTARTSYS;
                ret = ctrls->get(gspca_dev, &ctrl->value);
@@ -1403,7 +1403,7 @@ static int vidioc_dqbuf(struct file *file, void *priv,
        i = ret;                                /* frame index */
        frame = &gspca_dev->frame[i];
        if (gspca_dev->memory == V4L2_MEMORY_USERPTR) {
-               if (copy_to_user((__u8 *) frame->v4l2_buf.m.userptr,
+               if (copy_to_user((__u8 __user *) frame->v4l2_buf.m.userptr,
                                 frame->data,
                                 frame->v4l2_buf.bytesused)) {
                        PDEBUG(D_ERR|D_STREAM,
@@ -1731,6 +1731,12 @@ int gspca_dev_probe(struct usb_interface *intf,
                err("couldn't kzalloc gspca struct");
                return -EIO;
        }
+       gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL);
+       if (!gspca_dev->usb_buf) {
+               err("out of memory");
+               ret = -EIO;
+               goto out;
+       }
        gspca_dev->dev = dev;
        gspca_dev->iface = interface->bInterfaceNumber;
        gspca_dev->nbalt = intf->num_altsetting;
@@ -1738,8 +1744,11 @@ int gspca_dev_probe(struct usb_interface *intf,
 /*     gspca_dev->users = 0;                   (done by kzalloc) */
        gspca_dev->nbufread = 2;
 
-       /* configure the subdriver */
+       /* configure the subdriver and initialize the USB device */
        ret = gspca_dev->sd_desc->config(gspca_dev, id);
+       if (ret < 0)
+               goto out;
+       ret = gspca_dev->sd_desc->init(gspca_dev);
        if (ret < 0)
                goto out;
        ret = gspca_set_alt0(gspca_dev);
@@ -1771,6 +1780,7 @@ int gspca_dev_probe(struct usb_interface *intf,
        PDEBUG(D_PROBE, "probe ok");
        return 0;
 out:
+       kfree(gspca_dev->usb_buf);
        kfree(gspca_dev);
        return ret;
 }
@@ -1803,11 +1813,42 @@ void gspca_disconnect(struct usb_interface *intf)
 /* We don't want people trying to open up the device */
        video_unregister_device(&gspca_dev->vdev);
 /* Free the memory */
+       kfree(gspca_dev->usb_buf);
        kfree(gspca_dev);
        PDEBUG(D_PROBE, "disconnect complete");
 }
 EXPORT_SYMBOL(gspca_disconnect);
 
+#ifdef CONFIG_PM
+int gspca_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+
+       if (!gspca_dev->streaming)
+               return 0;
+       gspca_dev->frozen = 1;          /* avoid urb error messages */
+       if (gspca_dev->sd_desc->stopN)
+               gspca_dev->sd_desc->stopN(gspca_dev);
+       destroy_urbs(gspca_dev);
+       gspca_set_alt0(gspca_dev);
+       if (gspca_dev->sd_desc->stop0)
+               gspca_dev->sd_desc->stop0(gspca_dev);
+       return 0;
+}
+EXPORT_SYMBOL(gspca_suspend);
+
+int gspca_resume(struct usb_interface *intf)
+{
+       struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+
+       gspca_dev->frozen = 0;
+       gspca_dev->sd_desc->init(gspca_dev);
+       if (gspca_dev->streaming)
+               return gspca_init_transfer(gspca_dev);
+       return 0;
+}
+EXPORT_SYMBOL(gspca_resume);
+#endif
 /* -- cam driver utility functions -- */
 
 /* auto gain and exposure algorithm based on the knee algorithm described here:
index 67e4489..c17625c 100644 (file)
@@ -56,7 +56,6 @@ extern int gspca_debug;
 
 /* device information - set at probe time */
 struct cam {
-       char *dev_name;
        struct v4l2_pix_format *cam_mode;       /* size nmodes */
        char nmodes;
        __u8 epaddr;
@@ -91,15 +90,14 @@ struct sd_desc {
 /* controls */
        const struct ctrl *ctrls;
        int nctrls;
-/* operations */
+/* mandatory operations */
        cam_cf_op config;       /* called on probe */
-       cam_op open;            /* called on open */
+       cam_op init;            /* called on probe and resume */
        cam_v_op start;         /* called on stream on */
-       cam_v_op stopN;         /* called on stream off - main alt */
-       cam_v_op stop0;         /* called on stream off - alt 0 */
-       cam_v_op close;         /* called on close */
        cam_pkt_op pkt_scan;
 /* optional operations */
+       cam_v_op stopN;         /* called on stream off - main alt */
+       cam_v_op stop0;         /* called on stream off - alt 0 */
        cam_v_op dq_callback;   /* called when a frame has been dequeued */
        cam_jpg_op get_jcomp;
        cam_jpg_op set_jcomp;
@@ -127,8 +125,10 @@ struct gspca_dev {
 
        struct cam cam;                         /* device information */
        const struct sd_desc *sd_desc;          /* subdriver description */
+       unsigned ctrl_dis;              /* disabled controls (bit map) */
 
-       __u8 usb_buf[8];                        /* buffer for USB exchanges */
+#define USB_BUF_SZ 64
+       __u8 *usb_buf;                          /* buffer for USB exchanges */
        struct urb *urb[MAX_NURBS];
 
        __u8 *frbuf;                            /* buffer for nframes */
@@ -155,6 +155,9 @@ struct gspca_dev {
        struct mutex queue_lock;        /* ISOC queue protection */
        __u32 sequence;                 /* frame sequence number */
        char streaming;
+#ifdef CONFIG_PM
+       char frozen;                    /* suspend - resume */
+#endif
        char users;                     /* number of opens */
        char present;                   /* device connected */
        char nbufread;                  /* number of buffers for read() */
@@ -174,6 +177,10 @@ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
                                    struct gspca_frame *frame,
                                    const __u8 *data,
                                    int len);
+#ifdef CONFIG_PM
+int gspca_suspend(struct usb_interface *intf, pm_message_t message);
+int gspca_resume(struct usb_interface *intf);
+#endif
 int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum,
        int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee);
 #endif /* GSPCAV2_H */
index 21c4ee5..4d5db47 100644 (file)
@@ -100,22 +100,6 @@ static int reg_w(struct gspca_dev *gspca_dev,
        return rc;
 }
 
-static int reg_w_buf(struct gspca_dev *gspca_dev,
-                       __u16 index, __u8 *buf, int len)
-{
-       int rc;
-
-       rc = usb_control_msg(gspca_dev->dev,
-                        usb_sndbulkpipe(gspca_dev->dev, 4),
-                        0x12,
-                        0xc8,          /* ?? */
-                        0,             /* value */
-                        index, buf, len, 500);
-       if (rc < 0)
-               PDEBUG(D_ERR, "reg write [%02x] error %d", index, rc);
-       return rc;
-}
-
 static void bulk_w(struct gspca_dev *gspca_dev,
                   __u16 *pch,
                   __u16 Address)
@@ -144,8 +128,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
        return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
        return 0;
 }
@@ -175,7 +159,6 @@ static void sd_start(struct gspca_dev *gspca_dev)
        /*
           Initialize the MR97113 chip register
         */
-       data = kmalloc(16, GFP_KERNEL);
        data[0] = 0x00;         /* address */
        data[1] = 0x0c | 0x01;  /* reg 0 */
        data[2] = 0x01;         /* reg 1 */
@@ -195,12 +178,10 @@ static void sd_start(struct gspca_dev *gspca_dev)
        data[10] = 0x5d;        /* reg 9, I2C device address
                                 *      [for PAS5101 (0x40)] [for MI (0x5d)] */
 
-       err_code = reg_w_buf(gspca_dev, data[0], data, 11);
-       kfree(data);
+       err_code = reg_w(gspca_dev, data[0], 11);
        if (err_code < 0)
                return;
 
-       data = gspca_dev->usb_buf;
        data[0] = 0x23;         /* address */
        data[1] = 0x09;         /* reg 35, append frame header */
 
@@ -358,14 +339,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
                PDEBUG(D_ERR, "Camera Stop failed");
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
@@ -411,11 +384,9 @@ static const struct sd_desc sd_desc = {
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
-       .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
 };
 
@@ -439,6 +410,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
index b4f00ec..4df4eec 100644 (file)
@@ -63,11 +63,10 @@ struct sd {
 #define SEN_OV6630 2
 #define SEN_OV7610 3
 #define SEN_OV7620 4
-#define SEN_OV7630 5
-#define SEN_OV7640 6
-#define SEN_OV7670 7
-#define SEN_OV76BE 8
-#define SEN_OV8610 9
+#define SEN_OV7640 5
+#define SEN_OV7670 6
+#define SEN_OV76BE 7
+#define SEN_OV8610 8
 
 };
 
@@ -127,6 +126,7 @@ static struct ctrl sd_ctrls[] = {
            .get = sd_getcolors,
        },
 /* next controls work with ov7670 only */
+#define HFLIP_IDX 3
        {
            {
                .id      = V4L2_CID_HFLIP,
@@ -141,6 +141,7 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_sethflip,
            .get = sd_gethflip,
        },
+#define VFLIP_IDX 4
        {
            {
                .id      = V4L2_CID_VFLIP,
@@ -293,6 +294,541 @@ static struct v4l2_pix_format sif_mode[] = {
 #define OV7670_REG_HAECC7      0xaa    /* Hist AEC/AGC control 7 */
 #define OV7670_REG_BD60MAX     0xab    /* 60hz banding step limit */
 
+struct ov_regvals {
+       __u8 reg;
+       __u8 val;
+};
+struct ov_i2c_regvals {
+       __u8 reg;
+       __u8 val;
+};
+
+static const struct ov_i2c_regvals norm_6x20[] = {
+       { 0x12, 0x80 }, /* reset */
+       { 0x11, 0x01 },
+       { 0x03, 0x60 },
+       { 0x05, 0x7f }, /* For when autoadjust is off */
+       { 0x07, 0xa8 },
+       /* The ratio of 0x0c and 0x0d  controls the white point */
+       { 0x0c, 0x24 },
+       { 0x0d, 0x24 },
+       { 0x0f, 0x15 }, /* COMS */
+       { 0x10, 0x75 }, /* AEC Exposure time */
+       { 0x12, 0x24 }, /* Enable AGC */
+       { 0x14, 0x04 },
+       /* 0x16: 0x06 helps frame stability with moving objects */
+       { 0x16, 0x06 },
+/*     { 0x20, 0x30 },  * Aperture correction enable */
+       { 0x26, 0xb2 }, /* BLC enable */
+       /* 0x28: 0x05 Selects RGB format if RGB on */
+       { 0x28, 0x05 },
+       { 0x2a, 0x04 }, /* Disable framerate adjust */
+/*     { 0x2b, 0xac },  * Framerate; Set 2a[7] first */
+       { 0x2d, 0x99 },
+       { 0x33, 0xa0 }, /* Color Processing Parameter */
+       { 0x34, 0xd2 }, /* Max A/D range */
+       { 0x38, 0x8b },
+       { 0x39, 0x40 },
+
+       { 0x3c, 0x39 }, /* Enable AEC mode changing */
+       { 0x3c, 0x3c }, /* Change AEC mode */
+       { 0x3c, 0x24 }, /* Disable AEC mode changing */
+
+       { 0x3d, 0x80 },
+       /* These next two registers (0x4a, 0x4b) are undocumented.
+        * They control the color balance */
+       { 0x4a, 0x80 },
+       { 0x4b, 0x80 },
+       { 0x4d, 0xd2 }, /* This reduces noise a bit */
+       { 0x4e, 0xc1 },
+       { 0x4f, 0x04 },
+/* Do 50-53 have any effect? */
+/* Toggle 0x12[2] off and on here? */
+};
+
+static const struct ov_i2c_regvals norm_6x30[] = {
+       { 0x12, 0x80 }, /* Reset */
+       { 0x00, 0x1f }, /* Gain */
+       { 0x01, 0x99 }, /* Blue gain */
+       { 0x02, 0x7c }, /* Red gain */
+       { 0x03, 0xc0 }, /* Saturation */
+       { 0x05, 0x0a }, /* Contrast */
+       { 0x06, 0x95 }, /* Brightness */
+       { 0x07, 0x2d }, /* Sharpness */
+       { 0x0c, 0x20 },
+       { 0x0d, 0x20 },
+       { 0x0e, 0x20 },
+       { 0x0f, 0x05 },
+       { 0x10, 0x9a },
+       { 0x11, 0x00 }, /* Pixel clock = fastest */
+       { 0x12, 0x24 }, /* Enable AGC and AWB */
+       { 0x13, 0x21 },
+       { 0x14, 0x80 },
+       { 0x15, 0x01 },
+       { 0x16, 0x03 },
+       { 0x17, 0x38 },
+       { 0x18, 0xea },
+       { 0x19, 0x04 },
+       { 0x1a, 0x93 },
+       { 0x1b, 0x00 },
+       { 0x1e, 0xc4 },
+       { 0x1f, 0x04 },
+       { 0x20, 0x20 },
+       { 0x21, 0x10 },
+       { 0x22, 0x88 },
+       { 0x23, 0xc0 }, /* Crystal circuit power level */
+       { 0x25, 0x9a }, /* Increase AEC black ratio */
+       { 0x26, 0xb2 }, /* BLC enable */
+       { 0x27, 0xa2 },
+       { 0x28, 0x00 },
+       { 0x29, 0x00 },
+       { 0x2a, 0x84 }, /* 60 Hz power */
+       { 0x2b, 0xa8 }, /* 60 Hz power */
+       { 0x2c, 0xa0 },
+       { 0x2d, 0x95 }, /* Enable auto-brightness */
+       { 0x2e, 0x88 },
+       { 0x33, 0x26 },
+       { 0x34, 0x03 },
+       { 0x36, 0x8f },
+       { 0x37, 0x80 },
+       { 0x38, 0x83 },
+       { 0x39, 0x80 },
+       { 0x3a, 0x0f },
+       { 0x3b, 0x3c },
+       { 0x3c, 0x1a },
+       { 0x3d, 0x80 },
+       { 0x3e, 0x80 },
+       { 0x3f, 0x0e },
+       { 0x40, 0x00 }, /* White bal */
+       { 0x41, 0x00 }, /* White bal */
+       { 0x42, 0x80 },
+       { 0x43, 0x3f }, /* White bal */
+       { 0x44, 0x80 },
+       { 0x45, 0x20 },
+       { 0x46, 0x20 },
+       { 0x47, 0x80 },
+       { 0x48, 0x7f },
+       { 0x49, 0x00 },
+       { 0x4a, 0x00 },
+       { 0x4b, 0x80 },
+       { 0x4c, 0xd0 },
+       { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
+       { 0x4e, 0x40 },
+       { 0x4f, 0x07 }, /* UV avg., col. killer: max */
+       { 0x50, 0xff },
+       { 0x54, 0x23 }, /* Max AGC gain: 18dB */
+       { 0x55, 0xff },
+       { 0x56, 0x12 },
+       { 0x57, 0x81 },
+       { 0x58, 0x75 },
+       { 0x59, 0x01 }, /* AGC dark current comp.: +1 */
+       { 0x5a, 0x2c },
+       { 0x5b, 0x0f }, /* AWB chrominance levels */
+       { 0x5c, 0x10 },
+       { 0x3d, 0x80 },
+       { 0x27, 0xa6 },
+       { 0x12, 0x20 }, /* Toggle AWB */
+       { 0x12, 0x24 },
+};
+
+/* Lawrence Glaister <lg@jfm.bc.ca> reports:
+ *
+ * Register 0x0f in the 7610 has the following effects:
+ *
+ * 0x85 (AEC method 1): Best overall, good contrast range
+ * 0x45 (AEC method 2): Very overexposed
+ * 0xa5 (spec sheet default): Ok, but the black level is
+ *     shifted resulting in loss of contrast
+ * 0x05 (old driver setting): very overexposed, too much
+ *     contrast
+ */
+static const struct ov_i2c_regvals norm_7610[] = {
+       { 0x10, 0xff },
+       { 0x16, 0x06 },
+       { 0x28, 0x24 },
+       { 0x2b, 0xac },
+       { 0x12, 0x00 },
+       { 0x38, 0x81 },
+       { 0x28, 0x24 }, /* 0c */
+       { 0x0f, 0x85 }, /* lg's setting */
+       { 0x15, 0x01 },
+       { 0x20, 0x1c },
+       { 0x23, 0x2a },
+       { 0x24, 0x10 },
+       { 0x25, 0x8a },
+       { 0x26, 0xa2 },
+       { 0x27, 0xc2 },
+       { 0x2a, 0x04 },
+       { 0x2c, 0xfe },
+       { 0x2d, 0x93 },
+       { 0x30, 0x71 },
+       { 0x31, 0x60 },
+       { 0x32, 0x26 },
+       { 0x33, 0x20 },
+       { 0x34, 0x48 },
+       { 0x12, 0x24 },
+       { 0x11, 0x01 },
+       { 0x0c, 0x24 },
+       { 0x0d, 0x24 },
+};
+
+static const struct ov_i2c_regvals norm_7620[] = {
+       { 0x00, 0x00 },         /* gain */
+       { 0x01, 0x80 },         /* blue gain */
+       { 0x02, 0x80 },         /* red gain */
+       { 0x03, 0xc0 },         /* OV7670_REG_VREF */
+       { 0x06, 0x60 },
+       { 0x07, 0x00 },
+       { 0x0c, 0x24 },
+       { 0x0c, 0x24 },
+       { 0x0d, 0x24 },
+       { 0x11, 0x01 },
+       { 0x12, 0x24 },
+       { 0x13, 0x01 },
+       { 0x14, 0x84 },
+       { 0x15, 0x01 },
+       { 0x16, 0x03 },
+       { 0x17, 0x2f },
+       { 0x18, 0xcf },
+       { 0x19, 0x06 },
+       { 0x1a, 0xf5 },
+       { 0x1b, 0x00 },
+       { 0x20, 0x18 },
+       { 0x21, 0x80 },
+       { 0x22, 0x80 },
+       { 0x23, 0x00 },
+       { 0x26, 0xa2 },
+       { 0x27, 0xea },
+       { 0x28, 0x20 },
+       { 0x29, 0x00 },
+       { 0x2a, 0x10 },
+       { 0x2b, 0x00 },
+       { 0x2c, 0x88 },
+       { 0x2d, 0x91 },
+       { 0x2e, 0x80 },
+       { 0x2f, 0x44 },
+       { 0x60, 0x27 },
+       { 0x61, 0x02 },
+       { 0x62, 0x5f },
+       { 0x63, 0xd5 },
+       { 0x64, 0x57 },
+       { 0x65, 0x83 },
+       { 0x66, 0x55 },
+       { 0x67, 0x92 },
+       { 0x68, 0xcf },
+       { 0x69, 0x76 },
+       { 0x6a, 0x22 },
+       { 0x6b, 0x00 },
+       { 0x6c, 0x02 },
+       { 0x6d, 0x44 },
+       { 0x6e, 0x80 },
+       { 0x6f, 0x1d },
+       { 0x70, 0x8b },
+       { 0x71, 0x00 },
+       { 0x72, 0x14 },
+       { 0x73, 0x54 },
+       { 0x74, 0x00 },
+       { 0x75, 0x8e },
+       { 0x76, 0x00 },
+       { 0x77, 0xff },
+       { 0x78, 0x80 },
+       { 0x79, 0x80 },
+       { 0x7a, 0x80 },
+       { 0x7b, 0xe2 },
+       { 0x7c, 0x00 },
+};
+
+/* 7640 and 7648. The defaults should be OK for most registers. */
+static const struct ov_i2c_regvals norm_7640[] = {
+       { 0x12, 0x80 },
+       { 0x12, 0x14 },
+};
+
+/* 7670. Defaults taken from OmniVision provided data,
+*  as provided by Jonathan Corbet of OLPC              */
+static const struct ov_i2c_regvals norm_7670[] = {
+       { OV7670_REG_COM7, OV7670_COM7_RESET },
+       { OV7670_REG_TSLB, 0x04 },              /* OV */
+       { OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
+       { OV7670_REG_CLKRC, 0x01 },
+/*
+ * Set the hardware window.  These values from OV don't entirely
+ * make sense - hstop is less than hstart.  But they work...
+ */
+       { OV7670_REG_HSTART, 0x13 },
+       { OV7670_REG_HSTOP, 0x01 },
+       { OV7670_REG_HREF, 0xb6 },
+       { OV7670_REG_VSTART, 0x02 },
+       { OV7670_REG_VSTOP, 0x7a },
+       { OV7670_REG_VREF, 0x0a },
+
+       { OV7670_REG_COM3, 0 },
+       { OV7670_REG_COM14, 0 },
+/* Mystery scaling numbers */
+       { 0x70, 0x3a },
+       { 0x71, 0x35 },
+       { 0x72, 0x11 },
+       { 0x73, 0xf0 },
+       { 0xa2, 0x02 },
+/*     { OV7670_REG_COM10, 0x0 }, */
+
+/* Gamma curve values */
+       { 0x7a, 0x20 },
+       { 0x7b, 0x10 },
+       { 0x7c, 0x1e },
+       { 0x7d, 0x35 },
+       { 0x7e, 0x5a },
+       { 0x7f, 0x69 },
+       { 0x80, 0x76 },
+       { 0x81, 0x80 },
+       { 0x82, 0x88 },
+       { 0x83, 0x8f },
+       { 0x84, 0x96 },
+       { 0x85, 0xa3 },
+       { 0x86, 0xaf },
+       { 0x87, 0xc4 },
+       { 0x88, 0xd7 },
+       { 0x89, 0xe8 },
+
+/* AGC and AEC parameters.  Note we start by disabling those features,
+   then turn them only after tweaking the values. */
+       { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+                        | OV7670_COM8_AECSTEP
+                        | OV7670_COM8_BFILT },
+       { OV7670_REG_GAIN, 0 },
+       { OV7670_REG_AECH, 0 },
+       { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */
+       { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
+       { OV7670_REG_BD50MAX, 0x05 },
+       { OV7670_REG_BD60MAX, 0x07 },
+       { OV7670_REG_AEW, 0x95 },
+       { OV7670_REG_AEB, 0x33 },
+       { OV7670_REG_VPT, 0xe3 },
+       { OV7670_REG_HAECC1, 0x78 },
+       { OV7670_REG_HAECC2, 0x68 },
+       { 0xa1, 0x03 }, /* magic */
+       { OV7670_REG_HAECC3, 0xd8 },
+       { OV7670_REG_HAECC4, 0xd8 },
+       { OV7670_REG_HAECC5, 0xf0 },
+       { OV7670_REG_HAECC6, 0x90 },
+       { OV7670_REG_HAECC7, 0x94 },
+       { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+                       | OV7670_COM8_AECSTEP
+                       | OV7670_COM8_BFILT
+                       | OV7670_COM8_AGC
+                       | OV7670_COM8_AEC },
+
+/* Almost all of these are magic "reserved" values.  */
+       { OV7670_REG_COM5, 0x61 },
+       { OV7670_REG_COM6, 0x4b },
+       { 0x16, 0x02 },
+       { OV7670_REG_MVFP, 0x07 },
+       { 0x21, 0x02 },
+       { 0x22, 0x91 },
+       { 0x29, 0x07 },
+       { 0x33, 0x0b },
+       { 0x35, 0x0b },
+       { 0x37, 0x1d },
+       { 0x38, 0x71 },
+       { 0x39, 0x2a },
+       { OV7670_REG_COM12, 0x78 },
+       { 0x4d, 0x40 },
+       { 0x4e, 0x20 },
+       { OV7670_REG_GFIX, 0 },
+       { 0x6b, 0x4a },
+       { 0x74, 0x10 },
+       { 0x8d, 0x4f },
+       { 0x8e, 0 },
+       { 0x8f, 0 },
+       { 0x90, 0 },
+       { 0x91, 0 },
+       { 0x96, 0 },
+       { 0x9a, 0 },
+       { 0xb0, 0x84 },
+       { 0xb1, 0x0c },
+       { 0xb2, 0x0e },
+       { 0xb3, 0x82 },
+       { 0xb8, 0x0a },
+
+/* More reserved magic, some of which tweaks white balance */
+       { 0x43, 0x0a },
+       { 0x44, 0xf0 },
+       { 0x45, 0x34 },
+       { 0x46, 0x58 },
+       { 0x47, 0x28 },
+       { 0x48, 0x3a },
+       { 0x59, 0x88 },
+       { 0x5a, 0x88 },
+       { 0x5b, 0x44 },
+       { 0x5c, 0x67 },
+       { 0x5d, 0x49 },
+       { 0x5e, 0x0e },
+       { 0x6c, 0x0a },
+       { 0x6d, 0x55 },
+       { 0x6e, 0x11 },
+       { 0x6f, 0x9f },
+                                       /* "9e for advance AWB" */
+       { 0x6a, 0x40 },
+       { OV7670_REG_BLUE, 0x40 },
+       { OV7670_REG_RED, 0x60 },
+       { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+                       | OV7670_COM8_AECSTEP
+                       | OV7670_COM8_BFILT
+                       | OV7670_COM8_AGC
+                       | OV7670_COM8_AEC
+                       | OV7670_COM8_AWB },
+
+/* Matrix coefficients */
+       { 0x4f, 0x80 },
+       { 0x50, 0x80 },
+       { 0x51, 0 },
+       { 0x52, 0x22 },
+       { 0x53, 0x5e },
+       { 0x54, 0x80 },
+       { 0x58, 0x9e },
+
+       { OV7670_REG_COM16, OV7670_COM16_AWBGAIN },
+       { OV7670_REG_EDGE, 0 },
+       { 0x75, 0x05 },
+       { 0x76, 0xe1 },
+       { 0x4c, 0 },
+       { 0x77, 0x01 },
+       { OV7670_REG_COM13, OV7670_COM13_GAMMA
+                         | OV7670_COM13_UVSAT
+                         | 2},         /* was 3 */
+       { 0x4b, 0x09 },
+       { 0xc9, 0x60 },
+       { OV7670_REG_COM16, 0x38 },
+       { 0x56, 0x40 },
+
+       { 0x34, 0x11 },
+       { OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO },
+       { 0xa4, 0x88 },
+       { 0x96, 0 },
+       { 0x97, 0x30 },
+       { 0x98, 0x20 },
+       { 0x99, 0x30 },
+       { 0x9a, 0x84 },
+       { 0x9b, 0x29 },
+       { 0x9c, 0x03 },
+       { 0x9d, 0x4c },
+       { 0x9e, 0x3f },
+       { 0x78, 0x04 },
+
+/* Extra-weird stuff.  Some sort of multiplexor register */
+       { 0x79, 0x01 },
+       { 0xc8, 0xf0 },
+       { 0x79, 0x0f },
+       { 0xc8, 0x00 },
+       { 0x79, 0x10 },
+       { 0xc8, 0x7e },
+       { 0x79, 0x0a },
+       { 0xc8, 0x80 },
+       { 0x79, 0x0b },
+       { 0xc8, 0x01 },
+       { 0x79, 0x0c },
+       { 0xc8, 0x0f },
+       { 0x79, 0x0d },
+       { 0xc8, 0x20 },
+       { 0x79, 0x09 },
+       { 0xc8, 0x80 },
+       { 0x79, 0x02 },
+       { 0xc8, 0xc0 },
+       { 0x79, 0x03 },
+       { 0xc8, 0x40 },
+       { 0x79, 0x05 },
+       { 0xc8, 0x30 },
+       { 0x79, 0x26 },
+};
+
+static const struct ov_i2c_regvals norm_8610[] = {
+       { 0x12, 0x80 },
+       { 0x00, 0x00 },
+       { 0x01, 0x80 },
+       { 0x02, 0x80 },
+       { 0x03, 0xc0 },
+       { 0x04, 0x30 },
+       { 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */
+       { 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */
+       { 0x0a, 0x86 },
+       { 0x0b, 0xb0 },
+       { 0x0c, 0x20 },
+       { 0x0d, 0x20 },
+       { 0x11, 0x01 },
+       { 0x12, 0x25 },
+       { 0x13, 0x01 },
+       { 0x14, 0x04 },
+       { 0x15, 0x01 }, /* Lin and Win think different about UV order */
+       { 0x16, 0x03 },
+       { 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */
+       { 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */
+       { 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */
+       { 0x1a, 0xf5 },
+       { 0x1b, 0x00 },
+       { 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */
+       { 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */
+       { 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */
+       { 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */
+       { 0x26, 0xa2 },
+       { 0x27, 0xea },
+       { 0x28, 0x00 },
+       { 0x29, 0x00 },
+       { 0x2a, 0x80 },
+       { 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */
+       { 0x2c, 0xac },
+       { 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */
+       { 0x2e, 0x80 },
+       { 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */
+       { 0x4c, 0x00 },
+       { 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */
+       { 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */
+       { 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */
+       { 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */
+       { 0x63, 0xff },
+       { 0x64, 0x53 }, /* new windrv 090403 says 0x57,
+                        * maybe thats wrong */
+       { 0x65, 0x00 },
+       { 0x66, 0x55 },
+       { 0x67, 0xb0 },
+       { 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */
+       { 0x69, 0x02 },
+       { 0x6a, 0x22 },
+       { 0x6b, 0x00 },
+       { 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but
+                        * deleting bit7 colors the first images red */
+       { 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */
+       { 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */
+       { 0x6f, 0x01 },
+       { 0x70, 0x8b },
+       { 0x71, 0x00 },
+       { 0x72, 0x14 },
+       { 0x73, 0x54 },
+       { 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */
+       { 0x75, 0x0e },
+       { 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */
+       { 0x77, 0xff },
+       { 0x78, 0x80 },
+       { 0x79, 0x80 },
+       { 0x7a, 0x80 },
+       { 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */
+       { 0x7c, 0x00 },
+       { 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */
+       { 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */
+       { 0x7f, 0xfb },
+       { 0x80, 0x28 },
+       { 0x81, 0x00 },
+       { 0x82, 0x23 },
+       { 0x83, 0x0b },
+       { 0x84, 0x00 },
+       { 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */
+       { 0x86, 0xc9 },
+       { 0x87, 0x00 },
+       { 0x88, 0x00 },
+       { 0x89, 0x01 },
+       { 0x12, 0x20 },
+       { 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */
+};
+
 static unsigned char ov7670_abs_to_sm(unsigned char v)
 {
        if (v > 127)
@@ -537,18 +1073,10 @@ static int ov51x_set_slave_ids(struct sd *sd,
        rc = reg_w(sd, R51x_I2C_W_SID, slave);
        if (rc < 0)
                return rc;
+       sd->primary_i2c_slave = slave;
        return reg_w(sd, R51x_I2C_R_SID, slave + 1);
 }
 
-struct ov_regvals {
-       __u8 reg;
-       __u8 val;
-};
-struct ov_i2c_regvals {
-       __u8 reg;
-       __u8 val;
-};
-
 static int write_regvals(struct sd *sd,
                         const struct ov_regvals *regvals,
                         int n)
@@ -591,101 +1119,9 @@ static int write_i2c_regvals(struct sd *sd,
 static int ov8xx0_configure(struct sd *sd)
 {
        int rc;
-       static const struct ov_i2c_regvals norm_8610[] = {
-               { 0x12, 0x80 },
-               { 0x00, 0x00 },
-               { 0x01, 0x80 },
-               { 0x02, 0x80 },
-               { 0x03, 0xc0 },
-               { 0x04, 0x30 },
-               { 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */
-               { 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */
-               { 0x0a, 0x86 },
-               { 0x0b, 0xb0 },
-               { 0x0c, 0x20 },
-               { 0x0d, 0x20 },
-               { 0x11, 0x01 },
-               { 0x12, 0x25 },
-               { 0x13, 0x01 },
-               { 0x14, 0x04 },
-               { 0x15, 0x01 }, /* Lin and Win think different about UV order */
-               { 0x16, 0x03 },
-               { 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */
-               { 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */
-               { 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */
-               { 0x1a, 0xf5 },
-               { 0x1b, 0x00 },
-               { 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */
-               { 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */
-               { 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */
-               { 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */
-               { 0x26, 0xa2 },
-               { 0x27, 0xea },
-               { 0x28, 0x00 },
-               { 0x29, 0x00 },
-               { 0x2a, 0x80 },
-               { 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */
-               { 0x2c, 0xac },
-               { 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */
-               { 0x2e, 0x80 },
-               { 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */
-               { 0x4c, 0x00 },
-               { 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */
-               { 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */
-               { 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */
-               { 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */
-               { 0x63, 0xff },
-               { 0x64, 0x53 }, /* new windrv 090403 says 0x57,
-                                * maybe thats wrong */
-               { 0x65, 0x00 },
-               { 0x66, 0x55 },
-               { 0x67, 0xb0 },
-               { 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */
-               { 0x69, 0x02 },
-               { 0x6a, 0x22 },
-               { 0x6b, 0x00 },
-               { 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but
-                                  deleting bit7 colors the first images red */
-               { 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */
-               { 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */
-               { 0x6f, 0x01 },
-               { 0x70, 0x8b },
-               { 0x71, 0x00 },
-               { 0x72, 0x14 },
-               { 0x73, 0x54 },
-               { 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */
-               { 0x75, 0x0e },
-               { 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */
-               { 0x77, 0xff },
-               { 0x78, 0x80 },
-               { 0x79, 0x80 },
-               { 0x7a, 0x80 },
-               { 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */
-               { 0x7c, 0x00 },
-               { 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */
-               { 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */
-               { 0x7f, 0xfb },
-               { 0x80, 0x28 },
-               { 0x81, 0x00 },
-               { 0x82, 0x23 },
-               { 0x83, 0x0b },
-               { 0x84, 0x00 },
-               { 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */
-               { 0x86, 0xc9 },
-               { 0x87, 0x00 },
-               { 0x88, 0x00 },
-               { 0x89, 0x01 },
-               { 0x12, 0x20 },
-               { 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */
-       };
 
        PDEBUG(D_PROBE, "starting ov8xx0 configuration");
 
-       if (init_ov_sensor(sd) < 0)
-               PDEBUG(D_ERR|D_PROBE, "Failed to read sensor ID");
-       else
-               PDEBUG(D_PROBE, "OV86x0 initialized");
-
        /* Detect sensor (sub)type */
        rc = i2c_r(sd, OV7610_REG_COM_I);
        if (rc < 0) {
@@ -698,9 +1134,6 @@ static int ov8xx0_configure(struct sd *sd)
                PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3);
                return -1;
        }
-       PDEBUG(D_PROBE, "Writing 8610 registers");
-       if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610)))
-               return -1;
 
        /* Set sensor-specific vars */
 /*     sd->sif = 0;            already done */
@@ -714,252 +1147,6 @@ static int ov7xx0_configure(struct sd *sd)
 {
        int rc, high, low;
 
-       /* Lawrence Glaister <lg@jfm.bc.ca> reports:
-        *
-        * Register 0x0f in the 7610 has the following effects:
-        *
-        * 0x85 (AEC method 1): Best overall, good contrast range
-        * 0x45 (AEC method 2): Very overexposed
-        * 0xa5 (spec sheet default): Ok, but the black level is
-        *      shifted resulting in loss of contrast
-        * 0x05 (old driver setting): very overexposed, too much
-        *      contrast
-        */
-       static const struct ov_i2c_regvals norm_7610[] = {
-               { 0x10, 0xff },
-               { 0x16, 0x06 },
-               { 0x28, 0x24 },
-               { 0x2b, 0xac },
-               { 0x12, 0x00 },
-               { 0x38, 0x81 },
-               { 0x28, 0x24 }, /* 0c */
-               { 0x0f, 0x85 }, /* lg's setting */
-               { 0x15, 0x01 },
-               { 0x20, 0x1c },
-               { 0x23, 0x2a },
-               { 0x24, 0x10 },
-               { 0x25, 0x8a },
-               { 0x26, 0xa2 },
-               { 0x27, 0xc2 },
-               { 0x2a, 0x04 },
-               { 0x2c, 0xfe },
-               { 0x2d, 0x93 },
-               { 0x30, 0x71 },
-               { 0x31, 0x60 },
-               { 0x32, 0x26 },
-               { 0x33, 0x20 },
-               { 0x34, 0x48 },
-               { 0x12, 0x24 },
-               { 0x11, 0x01 },
-               { 0x0c, 0x24 },
-               { 0x0d, 0x24 },
-       };
-
-       static const struct ov_i2c_regvals norm_7620[] = {
-               { 0x00, 0x00 },         /* gain */
-               { 0x01, 0x80 },         /* blue gain */
-               { 0x02, 0x80 },         /* red gain */
-               { 0x03, 0xc0 },         /* OV7670_REG_VREF */
-               { 0x06, 0x60 },
-               { 0x07, 0x00 },
-               { 0x0c, 0x24 },
-               { 0x0c, 0x24 },
-               { 0x0d, 0x24 },
-               { 0x11, 0x01 },
-               { 0x12, 0x24 },
-               { 0x13, 0x01 },
-               { 0x14, 0x84 },
-               { 0x15, 0x01 },
-               { 0x16, 0x03 },
-               { 0x17, 0x2f },
-               { 0x18, 0xcf },
-               { 0x19, 0x06 },
-               { 0x1a, 0xf5 },
-               { 0x1b, 0x00 },
-               { 0x20, 0x18 },
-               { 0x21, 0x80 },
-               { 0x22, 0x80 },
-               { 0x23, 0x00 },
-               { 0x26, 0xa2 },
-               { 0x27, 0xea },
-               { 0x28, 0x20 },
-               { 0x29, 0x00 },
-               { 0x2a, 0x10 },
-               { 0x2b, 0x00 },
-               { 0x2c, 0x88 },
-               { 0x2d, 0x91 },
-               { 0x2e, 0x80 },
-               { 0x2f, 0x44 },
-               { 0x60, 0x27 },
-               { 0x61, 0x02 },
-               { 0x62, 0x5f },
-               { 0x63, 0xd5 },
-               { 0x64, 0x57 },
-               { 0x65, 0x83 },
-               { 0x66, 0x55 },
-               { 0x67, 0x92 },
-               { 0x68, 0xcf },
-               { 0x69, 0x76 },
-               { 0x6a, 0x22 },
-               { 0x6b, 0x00 },
-               { 0x6c, 0x02 },
-               { 0x6d, 0x44 },
-               { 0x6e, 0x80 },
-               { 0x6f, 0x1d },
-               { 0x70, 0x8b },
-               { 0x71, 0x00 },
-               { 0x72, 0x14 },
-               { 0x73, 0x54 },
-               { 0x74, 0x00 },
-               { 0x75, 0x8e },
-               { 0x76, 0x00 },
-               { 0x77, 0xff },
-               { 0x78, 0x80 },
-               { 0x79, 0x80 },
-               { 0x7a, 0x80 },
-               { 0x7b, 0xe2 },
-               { 0x7c, 0x00 },
-       };
-
-       /* 7640 and 7648. The defaults should be OK for most registers. */
-       static const struct ov_i2c_regvals norm_7640[] = {
-               { 0x12, 0x80 },
-               { 0x12, 0x14 },
-       };
-
-       /* 7670. Defaults taken from OmniVision provided data,
-       *  as provided by Jonathan Corbet of OLPC               */
-       static const struct ov_i2c_regvals norm_7670[] = {
-               { OV7670_REG_COM7, OV7670_COM7_RESET },
-               { OV7670_REG_TSLB, 0x04 },              /* OV */
-               { OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
-               { OV7670_REG_CLKRC, 0x01 },
-       /*
-        * Set the hardware window.  These values from OV don't entirely
-        * make sense - hstop is less than hstart.  But they work...
-        */
-               { OV7670_REG_HSTART, 0x13 },    { OV7670_REG_HSTOP, 0x01 },
-               { OV7670_REG_HREF, 0xb6 },      { OV7670_REG_VSTART, 0x02 },
-               { OV7670_REG_VSTOP, 0x7a },     { OV7670_REG_VREF, 0x0a },
-
-               { OV7670_REG_COM3, 0 }, { OV7670_REG_COM14, 0 },
-       /* Mystery scaling numbers */
-               { 0x70, 0x3a },         { 0x71, 0x35 },
-               { 0x72, 0x11 },         { 0x73, 0xf0 },
-               { 0xa2, 0x02 },
-/*             { OV7670_REG_COM10, 0x0 }, */
-
-       /* Gamma curve values */
-               { 0x7a, 0x20 },
-               { 0x7b, 0x10 },
-               { 0x7c, 0x1e },
-               { 0x7d, 0x35 },
-               { 0x7e, 0x5a },         { 0x7f, 0x69 },
-               { 0x80, 0x76 },         { 0x81, 0x80 },
-               { 0x82, 0x88 },         { 0x83, 0x8f },
-               { 0x84, 0x96 },         { 0x85, 0xa3 },
-               { 0x86, 0xaf },         { 0x87, 0xc4 },
-               { 0x88, 0xd7 },         { 0x89, 0xe8 },
-
-       /* AGC and AEC parameters.  Note we start by disabling those features,
-          then turn them only after tweaking the values. */
-               { OV7670_REG_COM8, OV7670_COM8_FASTAEC
-                                | OV7670_COM8_AECSTEP
-                                | OV7670_COM8_BFILT },
-               { OV7670_REG_GAIN, 0 }, { OV7670_REG_AECH, 0 },
-               { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */
-               { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
-               { OV7670_REG_BD50MAX, 0x05 },   { OV7670_REG_BD60MAX, 0x07 },
-               { OV7670_REG_AEW, 0x95 },       { OV7670_REG_AEB, 0x33 },
-               { OV7670_REG_VPT, 0xe3 },       { OV7670_REG_HAECC1, 0x78 },
-               { OV7670_REG_HAECC2, 0x68 },
-               { 0xa1, 0x03 }, /* magic */
-               { OV7670_REG_HAECC3, 0xd8 },    { OV7670_REG_HAECC4, 0xd8 },
-               { OV7670_REG_HAECC5, 0xf0 },    { OV7670_REG_HAECC6, 0x90 },
-               { OV7670_REG_HAECC7, 0x94 },
-               { OV7670_REG_COM8, OV7670_COM8_FASTAEC
-                               | OV7670_COM8_AECSTEP
-                               | OV7670_COM8_BFILT
-                               | OV7670_COM8_AGC
-                               | OV7670_COM8_AEC },
-
-       /* Almost all of these are magic "reserved" values.  */
-               { OV7670_REG_COM5, 0x61 },      { OV7670_REG_COM6, 0x4b },
-               { 0x16, 0x02 },
-               { OV7670_REG_MVFP, 0x07 },
-               { 0x21, 0x02 },         { 0x22, 0x91 },
-               { 0x29, 0x07 },         { 0x33, 0x0b },
-               { 0x35, 0x0b },         { 0x37, 0x1d },
-               { 0x38, 0x71 },         { 0x39, 0x2a },
-               { OV7670_REG_COM12, 0x78 },     { 0x4d, 0x40 },
-               { 0x4e, 0x20 },         { OV7670_REG_GFIX, 0 },
-               { 0x6b, 0x4a },         { 0x74, 0x10 },
-               { 0x8d, 0x4f },         { 0x8e, 0 },
-               { 0x8f, 0 },            { 0x90, 0 },
-               { 0x91, 0 },            { 0x96, 0 },
-               { 0x9a, 0 },            { 0xb0, 0x84 },
-               { 0xb1, 0x0c },         { 0xb2, 0x0e },
-               { 0xb3, 0x82 },         { 0xb8, 0x0a },
-
-       /* More reserved magic, some of which tweaks white balance */
-               { 0x43, 0x0a },         { 0x44, 0xf0 },
-               { 0x45, 0x34 },         { 0x46, 0x58 },
-               { 0x47, 0x28 },         { 0x48, 0x3a },
-               { 0x59, 0x88 },         { 0x5a, 0x88 },
-               { 0x5b, 0x44 },         { 0x5c, 0x67 },
-               { 0x5d, 0x49 },         { 0x5e, 0x0e },
-               { 0x6c, 0x0a },         { 0x6d, 0x55 },
-               { 0x6e, 0x11 },         { 0x6f, 0x9f },
-                                               /* "9e for advance AWB" */
-               { 0x6a, 0x40 },         { OV7670_REG_BLUE, 0x40 },
-               { OV7670_REG_RED, 0x60 },
-               { OV7670_REG_COM8, OV7670_COM8_FASTAEC
-                               | OV7670_COM8_AECSTEP
-                               | OV7670_COM8_BFILT
-                               | OV7670_COM8_AGC
-                               | OV7670_COM8_AEC
-                               | OV7670_COM8_AWB },
-
-       /* Matrix coefficients */
-               { 0x4f, 0x80 },         { 0x50, 0x80 },
-               { 0x51, 0 },            { 0x52, 0x22 },
-               { 0x53, 0x5e },         { 0x54, 0x80 },
-               { 0x58, 0x9e },
-
-               { OV7670_REG_COM16, OV7670_COM16_AWBGAIN },
-               { OV7670_REG_EDGE, 0 },
-               { 0x75, 0x05 },         { 0x76, 0xe1 },
-               { 0x4c, 0 },            { 0x77, 0x01 },
-               { OV7670_REG_COM13, OV7670_COM13_GAMMA
-                                 | OV7670_COM13_UVSAT
-                                 | 2},         /* was 3 */
-               { 0x4b, 0x09 },
-               { 0xc9, 0x60 },         { OV7670_REG_COM16, 0x38 },
-               { 0x56, 0x40 },
-
-               { 0x34, 0x11 },
-               { OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO },
-               { 0xa4, 0x88 },         { 0x96, 0 },
-               { 0x97, 0x30 },         { 0x98, 0x20 },
-               { 0x99, 0x30 },         { 0x9a, 0x84 },
-               { 0x9b, 0x29 },         { 0x9c, 0x03 },
-               { 0x9d, 0x4c },         { 0x9e, 0x3f },
-               { 0x78, 0x04 },
-
-       /* Extra-weird stuff.  Some sort of multiplexor register */
-               { 0x79, 0x01 },         { 0xc8, 0xf0 },
-               { 0x79, 0x0f },         { 0xc8, 0x00 },
-               { 0x79, 0x10 },         { 0xc8, 0x7e },
-               { 0x79, 0x0a },         { 0xc8, 0x80 },
-               { 0x79, 0x0b },         { 0xc8, 0x01 },
-               { 0x79, 0x0c },         { 0xc8, 0x0f },
-               { 0x79, 0x0d },         { 0xc8, 0x20 },
-               { 0x79, 0x09 },         { 0xc8, 0x80 },
-               { 0x79, 0x02 },         { 0xc8, 0xc0 },
-               { 0x79, 0x03 },         { 0xc8, 0x40 },
-               { 0x79, 0x05 },         { 0xc8, 0x30 },
-               { 0x79, 0x26 },
-       };
 
        PDEBUG(D_PROBE, "starting OV7xx0 configuration");
 
@@ -1011,8 +1198,9 @@ static int ov7xx0_configure(struct sd *sd)
                        switch (low) {
                        case 0x30:
                                PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635");
-                               sd->sensor = SEN_OV7630;
-                               break;
+                               PDEBUG(D_ERR,
+                                     "7630 is not supported by this driver");
+                               return -1;
                        case 0x40:
                                PDEBUG(D_PROBE, "Sensor is an OV7645");
                                sd->sensor = SEN_OV7640; /* FIXME */
@@ -1038,32 +1226,6 @@ static int ov7xx0_configure(struct sd *sd)
                return -1;
        }
 
-       switch (sd->sensor) {
-       case SEN_OV7620:
-               PDEBUG(D_PROBE, "Writing 7620 registers");
-               if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620)))
-                       return -1;
-               break;
-       case SEN_OV7630:
-               PDEBUG(D_ERR, "7630 is not supported by this driver version");
-               return -1;
-       case SEN_OV7640:
-               PDEBUG(D_PROBE, "Writing 7640 registers");
-               if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640)))
-                       return -1;
-               break;
-       case SEN_OV7670:
-               PDEBUG(D_PROBE, "Writing 7670 registers");
-               if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670)))
-                       return -1;
-               break;
-       default:
-               PDEBUG(D_PROBE, "Writing 7610 registers");
-               if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610)))
-                       return -1;
-               break;
-       }
-
        /* Set sensor-specific vars */
 /*     sd->sif = 0;            already done */
        return 0;
@@ -1073,141 +1235,7 @@ static int ov7xx0_configure(struct sd *sd)
 static int ov6xx0_configure(struct sd *sd)
 {
        int rc;
-       static const struct ov_i2c_regvals norm_6x20[] = {
-               { 0x12, 0x80 }, /* reset */
-               { 0x11, 0x01 },
-               { 0x03, 0x60 },
-               { 0x05, 0x7f }, /* For when autoadjust is off */
-               { 0x07, 0xa8 },
-               /* The ratio of 0x0c and 0x0d  controls the white point */
-               { 0x0c, 0x24 },
-               { 0x0d, 0x24 },
-               { 0x0f, 0x15 }, /* COMS */
-               { 0x10, 0x75 }, /* AEC Exposure time */
-               { 0x12, 0x24 }, /* Enable AGC */
-               { 0x14, 0x04 },
-               /* 0x16: 0x06 helps frame stability with moving objects */
-               { 0x16, 0x06 },
-/*             { 0x20, 0x30 },  * Aperture correction enable */
-               { 0x26, 0xb2 }, /* BLC enable */
-               /* 0x28: 0x05 Selects RGB format if RGB on */
-               { 0x28, 0x05 },
-               { 0x2a, 0x04 }, /* Disable framerate adjust */
-/*             { 0x2b, 0xac },  * Framerate; Set 2a[7] first */
-               { 0x2d, 0x99 },
-               { 0x33, 0xa0 }, /* Color Processing Parameter */
-               { 0x34, 0xd2 }, /* Max A/D range */
-               { 0x38, 0x8b },
-               { 0x39, 0x40 },
-
-               { 0x3c, 0x39 }, /* Enable AEC mode changing */
-               { 0x3c, 0x3c }, /* Change AEC mode */
-               { 0x3c, 0x24 }, /* Disable AEC mode changing */
-
-               { 0x3d, 0x80 },
-               /* These next two registers (0x4a, 0x4b) are undocumented.
-                * They control the color balance */
-               { 0x4a, 0x80 },
-               { 0x4b, 0x80 },
-               { 0x4d, 0xd2 }, /* This reduces noise a bit */
-               { 0x4e, 0xc1 },
-               { 0x4f, 0x04 },
-/* Do 50-53 have any effect? */
-/* Toggle 0x12[2] off and on here? */
-       };
-
-       static const struct ov_i2c_regvals norm_6x30[] = {
-               { 0x12, 0x80 }, /* Reset */
-               { 0x00, 0x1f }, /* Gain */
-               { 0x01, 0x99 }, /* Blue gain */
-               { 0x02, 0x7c }, /* Red gain */
-               { 0x03, 0xc0 }, /* Saturation */
-               { 0x05, 0x0a }, /* Contrast */
-               { 0x06, 0x95 }, /* Brightness */
-               { 0x07, 0x2d }, /* Sharpness */
-               { 0x0c, 0x20 },
-               { 0x0d, 0x20 },
-               { 0x0e, 0x20 },
-               { 0x0f, 0x05 },
-               { 0x10, 0x9a },
-               { 0x11, 0x00 }, /* Pixel clock = fastest */
-               { 0x12, 0x24 }, /* Enable AGC and AWB */
-               { 0x13, 0x21 },
-               { 0x14, 0x80 },
-               { 0x15, 0x01 },
-               { 0x16, 0x03 },
-               { 0x17, 0x38 },
-               { 0x18, 0xea },
-               { 0x19, 0x04 },
-               { 0x1a, 0x93 },
-               { 0x1b, 0x00 },
-               { 0x1e, 0xc4 },
-               { 0x1f, 0x04 },
-               { 0x20, 0x20 },
-               { 0x21, 0x10 },
-               { 0x22, 0x88 },
-               { 0x23, 0xc0 }, /* Crystal circuit power level */
-               { 0x25, 0x9a }, /* Increase AEC black ratio */
-               { 0x26, 0xb2 }, /* BLC enable */
-               { 0x27, 0xa2 },
-               { 0x28, 0x00 },
-               { 0x29, 0x00 },
-               { 0x2a, 0x84 }, /* 60 Hz power */
-               { 0x2b, 0xa8 }, /* 60 Hz power */
-               { 0x2c, 0xa0 },
-               { 0x2d, 0x95 }, /* Enable auto-brightness */
-               { 0x2e, 0x88 },
-               { 0x33, 0x26 },
-               { 0x34, 0x03 },
-               { 0x36, 0x8f },
-               { 0x37, 0x80 },
-               { 0x38, 0x83 },
-               { 0x39, 0x80 },
-               { 0x3a, 0x0f },
-               { 0x3b, 0x3c },
-               { 0x3c, 0x1a },
-               { 0x3d, 0x80 },
-               { 0x3e, 0x80 },
-               { 0x3f, 0x0e },
-               { 0x40, 0x00 }, /* White bal */
-               { 0x41, 0x00 }, /* White bal */
-               { 0x42, 0x80 },
-               { 0x43, 0x3f }, /* White bal */
-               { 0x44, 0x80 },
-               { 0x45, 0x20 },
-               { 0x46, 0x20 },
-               { 0x47, 0x80 },
-               { 0x48, 0x7f },
-               { 0x49, 0x00 },
-               { 0x4a, 0x00 },
-               { 0x4b, 0x80 },
-               { 0x4c, 0xd0 },
-               { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
-               { 0x4e, 0x40 },
-               { 0x4f, 0x07 }, /* UV avg., col. killer: max */
-               { 0x50, 0xff },
-               { 0x54, 0x23 }, /* Max AGC gain: 18dB */
-               { 0x55, 0xff },
-               { 0x56, 0x12 },
-               { 0x57, 0x81 },
-               { 0x58, 0x75 },
-               { 0x59, 0x01 }, /* AGC dark current comp.: +1 */
-               { 0x5a, 0x2c },
-               { 0x5b, 0x0f }, /* AWB chrominance levels */
-               { 0x5c, 0x10 },
-               { 0x3d, 0x80 },
-               { 0x27, 0xa6 },
-               { 0x12, 0x20 }, /* Toggle AWB */
-               { 0x12, 0x24 },
-       };
-
-       PDEBUG(D_PROBE, "starting sensor configuration");
-
-       if (init_ov_sensor(sd) < 0) {
-               PDEBUG(D_ERR, "Failed to read sensor ID.");
-               return -1;
-       }
-       PDEBUG(D_PROBE, "OV6xx0 sensor detected");
+       PDEBUG(D_PROBE, "starting OV6xx0 configuration");
 
        /* Detect sensor (sub)type */
        rc = i2c_r(sd, OV7610_REG_COM_I);
@@ -1251,15 +1279,6 @@ static int ov6xx0_configure(struct sd *sd)
        /* Set sensor-specific vars */
        sd->sif = 1;
 
-       if (sd->sensor == SEN_OV6620) {
-               PDEBUG(D_PROBE, "Writing 6x20 registers");
-               if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20)))
-                       return -1;
-       } else {
-               PDEBUG(D_PROBE, "Writing 6x30 registers");
-               if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30)))
-                       return -1;
-       }
        return 0;
 }
 
@@ -1298,22 +1317,31 @@ static int sd_config(struct gspca_dev *gspca_dev,
        ov51x_led_control(sd, 0);       /* turn LED off */
 
        /* Test for 76xx */
-       sd->primary_i2c_slave = OV7xx0_SID;
        if (ov51x_set_slave_ids(sd, OV7xx0_SID) < 0)
                goto error;
 
        /* The OV519 must be more aggressive about sensor detection since
         * I2C write will never fail if the sensor is not present. We have
         * to try to initialize the sensor to detect its presence */
-       if (init_ov_sensor(sd) < 0) {
+       if (init_ov_sensor(sd) >= 0) {
+               if (ov7xx0_configure(sd) < 0) {
+                       PDEBUG(D_ERR, "Failed to configure OV7xx0");
+                       goto error;
+               }
+       } else {
+
                /* Test for 6xx0 */
-               sd->primary_i2c_slave = OV6xx0_SID;
                if (ov51x_set_slave_ids(sd, OV6xx0_SID) < 0)
                        goto error;
 
-               if (init_ov_sensor(sd) < 0) {
+               if (init_ov_sensor(sd) >= 0) {
+                       if (ov6xx0_configure(sd) < 0) {
+                               PDEBUG(D_ERR, "Failed to configure OV6xx0");
+                               goto error;
+                       }
+               } else {
+
                        /* Test for 8xx0 */
-                       sd->primary_i2c_slave = OV8xx0_SID;
                        if (ov51x_set_slave_ids(sd, OV8xx0_SID) < 0)
                                goto error;
 
@@ -1321,24 +1349,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
                                PDEBUG(D_ERR,
                                        "Can't determine sensor slave IDs");
                                goto error;
-                       } else {
-                               if (ov8xx0_configure(sd) < 0) {
-                                       PDEBUG(D_ERR,
-                                          "Failed to configure OV8xx0 sensor");
-                                       goto error;
-                               }
                        }
-               } else {
-                       if (ov6xx0_configure(sd) < 0) {
-                               PDEBUG(D_ERR, "Failed to configure OV6xx0");
+                       if (ov8xx0_configure(sd) < 0) {
+                               PDEBUG(D_ERR,
+                                  "Failed to configure OV8xx0 sensor");
                                goto error;
                        }
                }
-       } else {
-               if (ov7xx0_configure(sd) < 0) {
-                       PDEBUG(D_ERR, "Failed to configure OV7xx0");
-                       goto error;
-               }
        }
 
        cam = &gspca_dev->cam;
@@ -1355,15 +1372,53 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->colors = COLOR_DEF;
        sd->hflip = HFLIP_DEF;
        sd->vflip = VFLIP_DEF;
+       if (sd->sensor != SEN_OV7670)
+               gspca_dev->ctrl_dis = (1 << HFLIP_IDX)
+                                       | (1 << VFLIP_IDX);
        return 0;
 error:
        PDEBUG(D_ERR, "OV519 Config failed");
        return -EBUSY;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       /* initialize the sensor */
+       switch (sd->sensor) {
+       case SEN_OV6620:
+               if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20)))
+                       return -EIO;
+               break;
+       case SEN_OV6630:
+               if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30)))
+                       return -EIO;
+               break;
+       default:
+/*     case SEN_OV7610: */
+/*     case SEN_OV76BE: */
+               if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610)))
+                       return -EIO;
+               break;
+       case SEN_OV7620:
+               if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620)))
+                       return -EIO;
+               break;
+       case SEN_OV7640:
+               if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640)))
+                       return -EIO;
+               break;
+       case SEN_OV7670:
+               if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670)))
+                       return -EIO;
+               break;
+       case SEN_OV8610:
+               if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610)))
+                       return -EIO;
+               break;
+       }
        return 0;
 }
 
@@ -1827,14 +1882,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        ov51x_led_control((struct sd *) gspca_dev, 0);
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
@@ -2091,11 +2138,9 @@ static const struct sd_desc sd_desc = {
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
-       .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
 };
 
@@ -2132,6 +2177,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
index 7ef18d5..83b5f74 100644 (file)
@@ -56,12 +56,6 @@ MODULE_LICENSE("GPL");
 #define PAC207_GAIN_KNEE               20
 
 #define PAC207_AUTOGAIN_DEADZONE       30
-/* We calculating the autogain at the end of the transfer of a frame, at this
-   moment a frame with the old settings is being transmitted, and a frame is
-   being captured with the old settings. So if we adjust the autogain we must
-   ignore atleast the 2 next frames for the new settings to come into effect
-   before doing any other adjustments */
-#define PAC207_AUTOGAIN_IGNORE_FRAMES  3
 
 /* specific webcam descriptor */
 struct sd {
@@ -131,7 +125,8 @@ static struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 1,
                .step   = 1,
-               .default_value = 1,
+#define AUTOGAIN_DEF 1
+               .default_value = AUTOGAIN_DEF,
                .flags = 0,
            },
            .set = sd_setautogain,
@@ -181,9 +176,6 @@ static const __u8 pac207_sensor_init[][8] = {
                        /* 48 reg_72 Rate Control end BalSize_4a =0x36 */
 static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 };
 
-static const unsigned char pac207_sof_marker[5] =
-               { 0xff, 0xff, 0x00, 0xff, 0x96 };
-
 static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
        const u8 *buffer, u16 length)
 {
@@ -259,35 +251,32 @@ static int sd_config(struct gspca_dev *gspca_dev,
                return -ENODEV;
        }
 
-       pac207_write_reg(gspca_dev, 0x41, 0x00);
-                               /* Bit_0=Image Format,
-                                * Bit_1=LED,
-                                * Bit_2=Compression test mode enable */
-       pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
-       pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
-
        PDEBUG(D_PROBE,
                "Pixart PAC207BCA Image Processor and Control Chip detected"
                " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
 
        cam = &gspca_dev->cam;
-       cam->dev_name = (char *) id->driver_info;
        cam->epaddr = 0x05;
        cam->cam_mode = sif_mode;
        cam->nmodes = ARRAY_SIZE(sif_mode);
        sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
        sd->exposure = PAC207_EXPOSURE_DEFAULT;
        sd->gain = PAC207_GAIN_DEFAULT;
+       sd->autogain = AUTOGAIN_DEF;
 
        return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
-       struct sd *sd = (struct sd *) gspca_dev;
+       pac207_write_reg(gspca_dev, 0x41, 0x00);
+                               /* Bit_0=Image Format,
+                                * Bit_1=LED,
+                                * Bit_2=Compression test mode enable */
+       pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
+       pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
 
-       sd->autogain = 1;
        return 0;
 }
 
@@ -343,14 +332,8 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
+/* Include pac common sof detection functions */
+#include "pac_common.h"
 
 static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
 {
@@ -365,33 +348,7 @@ static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
        else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
                        100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
                        PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
-               sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
-}
-
-static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
-                                       unsigned char *m, int len)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       int i;
-
-       /* Search for the SOF marker (fixed part) in the header */
-       for (i = 0; i < len; i++) {
-               if (m[i] == pac207_sof_marker[sd->sof_read]) {
-                       sd->sof_read++;
-                       if (sd->sof_read == sizeof(pac207_sof_marker)) {
-                               PDEBUG(D_STREAM,
-                                       "SOF found, bytes to analyze: %u."
-                                       " Frame starts at byte #%u",
-                                       len, i + 1);
-                               sd->sof_read = 0;
-                               return m + i + 1;
-                       }
-               } else {
-                       sd->sof_read = 0;
-               }
-       }
-
-       return NULL;
+               sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
@@ -402,14 +359,14 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        struct sd *sd = (struct sd *) gspca_dev;
        unsigned char *sof;
 
-       sof = pac207_find_sof(gspca_dev, data, len);
+       sof = pac_find_sof(gspca_dev, data, len);
        if (sof) {
                int n;
 
                /* finish decoding current frame */
                n = sof - data;
-               if (n > sizeof pac207_sof_marker)
-                       n -= sizeof pac207_sof_marker;
+               if (n > sizeof pac_sof_marker)
+                       n -= sizeof pac_sof_marker;
                else
                        n = 0;
                frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
@@ -537,7 +494,7 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
                sd->gain = PAC207_GAIN_DEFAULT;
                if (gspca_dev->streaming) {
                        sd->autogain_ignore_frames =
-                               PAC207_AUTOGAIN_IGNORE_FRAMES;
+                               PAC_AUTOGAIN_IGNORE_FRAMES;
                        setexposure(gspca_dev);
                        setgain(gspca_dev);
                }
@@ -560,11 +517,9 @@ static const struct sd_desc sd_desc = {
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
-       .stop0 = sd_stop0,
-       .close = sd_close,
        .dq_callback = pac207_do_auto_gain,
        .pkt_scan = sd_pkt_scan,
 };
@@ -597,6 +552,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
index 815bea6..d4be518 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+/* Some documentation about various registers as determined by trial and error.
+   When the register addresses differ between the 7202 and the 7311 the 2
+   different addresses are written as 7302addr/7311addr, when one of the 2
+   addresses is a - sign that register description is not valid for the
+   matching IC.
+
+   Register page 1:
+
+   Address     Description
+   -/0x08      Unknown compressor related, must always be 8 except when not
+               in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 !
+   -/0x1b      Auto white balance related, bit 0 is AWB enable (inverted)
+               bits 345 seem to toggle per color gains on/off (inverted)
+   0x78                Global control, bit 6 controls the LED (inverted)
+   -/0x80      JPEG compression ratio ? Best not touched
+
+   Register page 3/4:
+
+   Address     Description
+   0x02                Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on
+               the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
+   -/0x0f      Master gain 1-245, low value = high gain
+   0x10/-      Master gain 0-31
+   -/0x10      Another gain 0-15, limited influence (1-2x gain I guess)
+   0x21                Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
+   -/0x27      Seems to toggle various gains on / off, Setting bit 7 seems to
+               completely disable the analog amplification block. Set to 0x68
+               for max gain, 0x14 for minimal gain.
+*/
+
 #define MODULE_NAME "pac7311"
 
 #include "gspca.h"
@@ -31,18 +61,23 @@ MODULE_LICENSE("GPL");
 struct sd {
        struct gspca_dev gspca_dev;             /* !! must be the first item */
 
-       int lum_sum;
-       atomic_t avg_lum;
-       atomic_t do_gain;
-
        unsigned char brightness;
        unsigned char contrast;
        unsigned char colors;
+       unsigned char gain;
+       unsigned char exposure;
        unsigned char autogain;
+       __u8 hflip;
+       __u8 vflip;
+
+       __u8 sensor;
+#define SENSOR_PAC7302 0
+#define SENSOR_PAC7311 1
 
-       char ffseq;
-       signed char ag_cnt;
-#define AG_CNT_START 13
+       u8 sof_read;
+       u8 autogain_ignore_frames;
+
+       atomic_t avg_lum;
 };
 
 /* V4L2 controls supported by the driver */
@@ -54,8 +89,18 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
+/* This control is pac7302 only */
+#define BRIGHTNESS_IDX 0
        {
            {
                .id      = V4L2_CID_BRIGHTNESS,
@@ -71,13 +116,15 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setbrightness,
            .get = sd_getbrightness,
        },
+/* This control is for both the 7302 and the 7311 */
        {
            {
                .id      = V4L2_CID_CONTRAST,
                .type    = V4L2_CTRL_TYPE_INTEGER,
                .name    = "Contrast",
                .minimum = 0,
-               .maximum = 255,
+#define CONTRAST_MAX 255
+               .maximum = CONTRAST_MAX,
                .step    = 1,
 #define CONTRAST_DEF 127
                .default_value = CONTRAST_DEF,
@@ -85,13 +132,16 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setcontrast,
            .get = sd_getcontrast,
        },
+/* This control is pac7302 only */
+#define SATURATION_IDX 2
        {
            {
                .id      = V4L2_CID_SATURATION,
                .type    = V4L2_CTRL_TYPE_INTEGER,
-               .name    = "Color",
+               .name    = "Saturation",
                .minimum = 0,
-               .maximum = 255,
+#define COLOR_MAX 255
+               .maximum = COLOR_MAX,
                .step    = 1,
 #define COLOR_DEF 127
                .default_value = COLOR_DEF,
@@ -99,6 +149,39 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setcolors,
            .get = sd_getcolors,
        },
+/* All controls below are for both the 7302 and the 7311 */
+       {
+           {
+               .id      = V4L2_CID_GAIN,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Gain",
+               .minimum = 0,
+#define GAIN_MAX 255
+               .maximum = GAIN_MAX,
+               .step    = 1,
+#define GAIN_DEF 127
+#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
+               .default_value = GAIN_DEF,
+           },
+           .set = sd_setgain,
+           .get = sd_getgain,
+       },
+       {
+           {
+               .id      = V4L2_CID_EXPOSURE,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Exposure",
+               .minimum = 0,
+#define EXPOSURE_MAX 255
+               .maximum = EXPOSURE_MAX,
+               .step    = 1,
+#define EXPOSURE_DEF  16 /*  32 ms / 30 fps */
+#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
+               .default_value = EXPOSURE_DEF,
+           },
+           .set = sd_setexposure,
+           .get = sd_getexposure,
+       },
        {
            {
                .id      = V4L2_CID_AUTOGAIN,
@@ -113,101 +196,207 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setautogain,
            .get = sd_getautogain,
        },
+       {
+           {
+               .id      = V4L2_CID_HFLIP,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Mirror",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+#define HFLIP_DEF 0
+               .default_value = HFLIP_DEF,
+           },
+           .set = sd_sethflip,
+           .get = sd_gethflip,
+       },
+       {
+           {
+               .id      = V4L2_CID_VFLIP,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Vflip",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+#define VFLIP_DEF 0
+               .default_value = VFLIP_DEF,
+           },
+           .set = sd_setvflip,
+           .get = sd_getvflip,
+       },
 };
 
 static struct v4l2_pix_format vga_mode[] = {
-       {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+       {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
                .bytesperline = 160,
                .sizeimage = 160 * 120 * 3 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 2},
-       {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+       {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240 * 3 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 1},
-       {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+       {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
                .bytesperline = 640,
                .sizeimage = 640 * 480 * 3 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 0},
 };
 
-#define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header)  /* (594) */
-
-static const __u8 pac7311_jpeg_header[] = {
-       0xff, 0xd8,
-       0xff, 0xe0, 0x00, 0x03, 0x20,
-       0xff, 0xc0, 0x00, 0x11, 0x08,
-               0x01, 0xe0,                     /* 12: height */
-               0x02, 0x80,                     /* 14: width */
-               0x03,                           /* 16 */
-                       0x01, 0x21, 0x00,
-                       0x02, 0x11, 0x01,
-                       0x03, 0x11, 0x01,
-       0xff, 0xdb, 0x00, 0x84,
-       0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d,
-       0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16,
-       0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d,
-       0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40,
-       0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f,
-       0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
-       0x78, 0x5c, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, 0x12, 0x18,
-       0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42,
-       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-       0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-       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, 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, 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, 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, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
-       0x11, 0x00, 0x3f, 0x00
+/* pac 7302 */
+static const __u8 init_7302[] = {
+/*     index,value */
+       0xff, 0x01,             /* page 1 */
+       0x78, 0x00,             /* deactivate */
+       0xff, 0x01,
+       0x78, 0x40,             /* led off */
+};
+static const __u8 start_7302[] = {
+/*     index, len, [value]* */
+       0xff, 1,        0x00,           /* page 0 */
+       0x00, 12,       0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
+                       0x00, 0x00, 0x00, 0x00,
+       0x0d, 24,       0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
+                       0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
+                       0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
+       0x26, 2,        0xaa, 0xaa,
+       0x2e, 1,        0x31,
+       0x38, 1,        0x01,
+       0x3a, 3,        0x14, 0xff, 0x5a,
+       0x43, 11,       0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
+                       0x00, 0x54, 0x11,
+       0x55, 1,        0x00,
+       0x62, 4,        0x10, 0x1e, 0x1e, 0x18,
+       0x6b, 1,        0x00,
+       0x6e, 3,        0x08, 0x06, 0x00,
+       0x72, 3,        0x00, 0xff, 0x00,
+       0x7d, 23,       0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
+                       0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
+                       0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
+       0xa2, 10,       0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
+                       0xd2, 0xeb,
+       0xaf, 1,        0x02,
+       0xb5, 2,        0x08, 0x08,
+       0xb8, 2,        0x08, 0x88,
+       0xc4, 4,        0xae, 0x01, 0x04, 0x01,
+       0xcc, 1,        0x00,
+       0xd1, 11,       0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
+                       0xc1, 0xd7, 0xec,
+       0xdc, 1,        0x01,
+       0xff, 1,        0x01,           /* page 1 */
+       0x12, 3,        0x02, 0x00, 0x01,
+       0x3e, 2,        0x00, 0x00,
+       0x76, 5,        0x01, 0x20, 0x40, 0x00, 0xf2,
+       0x7c, 1,        0x00,
+       0x7f, 10,       0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
+                       0x02, 0x00,
+       0x96, 5,        0x01, 0x10, 0x04, 0x01, 0x04,
+       0xc8, 14,       0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
+                       0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
+       0xd8, 1,        0x01,
+       0xdb, 2,        0x00, 0x01,
+       0xde, 7,        0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
+       0xe6, 4,        0x00, 0x00, 0x00, 0x01,
+       0xeb, 1,        0x00,
+       0xff, 1,        0x02,           /* page 2 */
+       0x22, 1,        0x00,
+       0xff, 1,        0x03,           /* page 3 */
+       0x00, 255,                      /* load the page 3 */
+       0x11, 1,        0x01,
+       0xff, 1,        0x02,           /* page 2 */
+       0x13, 1,        0x00,
+       0x22, 4,        0x1f, 0xa4, 0xf0, 0x96,
+       0x27, 2,        0x14, 0x0c,
+       0x2a, 5,        0xc8, 0x00, 0x18, 0x12, 0x22,
+       0x64, 8,        0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
+       0x6e, 1,        0x08,
+       0xff, 1,        0x01,           /* page 1 */
+       0x78, 1,        0x00,
+       0, 0                            /* end of sequence */
+};
+
+/* page 3 - the value 0xaa says skip the index - see reg_w_page() */
+static const __u8 page3_7302[] = {
+       0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
+       0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
+       0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
+       0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
+       0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
+       0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
+       0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
+       0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
+       0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
+       0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
+       0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
+       0x00
+};
+
+/* pac 7311 */
+static const __u8 init_7311[] = {
+       0x78, 0x40,     /* Bit_0=start stream, Bit_6=LED */
+       0x78, 0x40,     /* Bit_0=start stream, Bit_6=LED */
+       0x78, 0x44,     /* Bit_0=start stream, Bit_6=LED */
+       0xff, 0x04,
+       0x27, 0x80,
+       0x28, 0xca,
+       0x29, 0x53,
+       0x2a, 0x0e,
+       0xff, 0x01,
+       0x3e, 0x20,
+};
+
+static const __u8 start_7311[] = {
+/*     index, len, [value]* */
+       0xff, 1,        0x01,           /* page 1 */
+       0x02, 43,       0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
+                       0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
+                       0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
+                       0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00,
+       0x3e, 42,       0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
+                       0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
+                       0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
+                       0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
+                       0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
+                       0xd0, 0xff,
+       0x78, 6,        0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
+       0x7f, 18,       0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
+                       0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
+                       0x18, 0x20,
+       0x96, 3,        0x01, 0x08, 0x04,
+       0xa0, 4,        0x44, 0x44, 0x44, 0x04,
+       0xf0, 13,       0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
+                       0x3f, 0x00, 0x0a, 0x01, 0x00,
+       0xff, 1,        0x04,           /* page 4 */
+       0x00, 254,                      /* load the page 4 */
+       0x11, 1,        0x01,
+       0, 0                            /* end of sequence */
+};
+
+/* page 4 - the value 0xaa says skip the index - see reg_w_page() */
+static const __u8 page4_7311[] = {
+       0xaa, 0xaa, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
+       0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62,
+       0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa,
+       0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x68,
+       0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
+       0x23, 0x28, 0x04, 0x11, 0x00, 0x00
 };
 
 static void reg_w_buf(struct gspca_dev *gspca_dev,
-                 __u16 index,
-                 const char *buffer, __u16 len)
+                 __u8 index,
+                 const char *buffer, int len)
 {
        memcpy(gspca_dev->usb_buf, buffer, len);
        usb_control_msg(gspca_dev->dev,
@@ -219,21 +408,9 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
                        500);
 }
 
-static __u8 reg_r(struct gspca_dev *gspca_dev,
-                            __u16 index)
-{
-       usb_control_msg(gspca_dev->dev,
-                       usb_rcvctrlpipe(gspca_dev->dev, 0),
-                       0,                      /* request */
-                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       0,                      /* value */
-                       index, gspca_dev->usb_buf, 1,
-                       500);
-       return gspca_dev->usb_buf[0];
-}
 
 static void reg_w(struct gspca_dev *gspca_dev,
-                 __u16 index,
+                 __u8 index,
                  __u8 value)
 {
        gspca_dev->usb_buf[0] = value;
@@ -241,10 +418,78 @@ static void reg_w(struct gspca_dev *gspca_dev,
                        usb_sndctrlpipe(gspca_dev->dev, 0),
                        0,                      /* request */
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       value, index, gspca_dev->usb_buf, 1,
+                       0, index, gspca_dev->usb_buf, 1,
                        500);
 }
 
+static void reg_w_seq(struct gspca_dev *gspca_dev,
+               const __u8 *seq, int len)
+{
+       while (--len >= 0) {
+               reg_w(gspca_dev, seq[0], seq[1]);
+               seq += 2;
+       }
+}
+
+/* load the beginning of a page */
+static void reg_w_page(struct gspca_dev *gspca_dev,
+                       const __u8 *page, int len)
+{
+       int index;
+
+       for (index = 0; index < len; index++) {
+               if (page[index] == 0xaa)                /* skip this index */
+                       continue;
+               gspca_dev->usb_buf[0] = page[index];
+               usb_control_msg(gspca_dev->dev,
+                               usb_sndctrlpipe(gspca_dev->dev, 0),
+                               0,                      /* request */
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               0, index, gspca_dev->usb_buf, 1,
+                               500);
+       }
+}
+
+/* output a variable sequence */
+static void reg_w_var(struct gspca_dev *gspca_dev,
+                       const __u8 *seq)
+{
+       int index, len;
+
+       for (;;) {
+               index = *seq++;
+               len = *seq++;
+               switch (len) {
+               case 0:
+                       return;
+               case 254:
+                       reg_w_page(gspca_dev, page4_7311, sizeof page4_7311);
+                       break;
+               case 255:
+                       reg_w_page(gspca_dev, page3_7302, sizeof page3_7302);
+                       break;
+               default:
+                       if (len > 64) {
+                               PDEBUG(D_ERR|D_STREAM,
+                                       "Incorrect variable sequence");
+                               return;
+                       }
+                       while (len > 0) {
+                               if (len < 8) {
+                                       reg_w_buf(gspca_dev, index, seq, len);
+                                       seq += len;
+                                       break;
+                               }
+                               reg_w_buf(gspca_dev, index, seq, 8);
+                               seq += 8;
+                               index += 8;
+                               len -= 8;
+                       }
+               }
+       }
+       /* not reached */
+}
+
 /* this function is called at probe time */
 static int sd_config(struct gspca_dev *gspca_dev,
                        const struct usb_device_id *id)
@@ -252,203 +497,245 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct sd *sd = (struct sd *) gspca_dev;
        struct cam *cam;
 
-       PDEBUG(D_CONF, "Find Sensor PAC7311");
-       reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
-       reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
-       reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
-       reg_w(gspca_dev, 0xff, 0x04);
-       reg_w(gspca_dev, 0x27, 0x80);
-       reg_w(gspca_dev, 0x28, 0xca);
-       reg_w(gspca_dev, 0x29, 0x53);
-       reg_w(gspca_dev, 0x2a, 0x0e);
-       reg_w(gspca_dev, 0xff, 0x01);
-       reg_w(gspca_dev, 0x3e, 0x20);
-
        cam = &gspca_dev->cam;
        cam->epaddr = 0x05;
-       cam->cam_mode = vga_mode;
-       cam->nmodes = ARRAY_SIZE(vga_mode);
+
+       sd->sensor = id->driver_info;
+       if (sd->sensor == SENSOR_PAC7302) {
+               PDEBUG(D_CONF, "Find Sensor PAC7302");
+               cam->cam_mode = &vga_mode[2];   /* only 640x480 */
+               cam->nmodes = 1;
+       } else {
+               PDEBUG(D_CONF, "Find Sensor PAC7311");
+               cam->cam_mode = vga_mode;
+               cam->nmodes = ARRAY_SIZE(vga_mode);
+               gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX)
+                               | (1 << SATURATION_IDX);
+       }
 
        sd->brightness = BRIGHTNESS_DEF;
        sd->contrast = CONTRAST_DEF;
        sd->colors = COLOR_DEF;
+       sd->gain = GAIN_DEF;
+       sd->exposure = EXPOSURE_DEF;
        sd->autogain = AUTOGAIN_DEF;
-       sd->ag_cnt = -1;
+       sd->hflip = HFLIP_DEF;
+       sd->vflip = VFLIP_DEF;
        return 0;
 }
 
-static void setbrightness(struct gspca_dev *gspca_dev)
+/* This function is used by pac7302 only */
+static void setbrightcont(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i, v;
+       static const __u8 max[10] =
+               {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
+                0xd4, 0xec};
+       static const __u8 delta[10] =
+               {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
+                0x11, 0x0b};
+
+       reg_w(gspca_dev, 0xff, 0x00);   /* page 0 */
+       for (i = 0; i < 10; i++) {
+               v = max[i];
+               v += (sd->brightness - BRIGHTNESS_MAX)
+                       * 150 / BRIGHTNESS_MAX;         /* 200 ? */
+               v -= delta[i] * sd->contrast / CONTRAST_MAX;
+               if (v < 0)
+                       v = 0;
+               else if (v > 0xff)
+                       v = 0xff;
+               reg_w(gspca_dev, 0xa2 + i, v);
+       }
+       reg_w(gspca_dev, 0xdc, 0x01);
+}
+
+/* This function is used by pac7311 only */
+static void setcontrast(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int brightness;
 
-/*jfm: inverted?*/
-       brightness = BRIGHTNESS_MAX - sd->brightness;
        reg_w(gspca_dev, 0xff, 0x04);
-/*     reg_w(gspca_dev, 0x0e, 0x00); */
-       reg_w(gspca_dev, 0x0f, brightness);
+       reg_w(gspca_dev, 0x10, sd->contrast >> 4);
        /* load registers to sensor (Bit 0, auto clear) */
        reg_w(gspca_dev, 0x11, 0x01);
-       PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
 }
 
-static void setcontrast(struct gspca_dev *gspca_dev)
+/* This function is used by pac7302 only */
+static void setcolors(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       int i, v;
+       static const int a[9] =
+               {217, -212, 0, -101, 170, -67, -38, -315, 355};
+       static const int b[9] =
+               {19, 106, 0, 19, 106, 1, 19, 106, 1};
 
-       reg_w(gspca_dev, 0xff, 0x01);
-       reg_w(gspca_dev, 0x80, sd->contrast);
-       /* load registers to sensor (Bit 0, auto clear) */
+       reg_w(gspca_dev, 0xff, 0x03);   /* page 3 */
        reg_w(gspca_dev, 0x11, 0x01);
-       PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
+       reg_w(gspca_dev, 0xff, 0x00);   /* page 0 */
+       reg_w(gspca_dev, 0xff, 0x00);   /* page 0 */
+       for (i = 0; i < 9; i++) {
+               v = a[i] * sd->colors / COLOR_MAX + b[i];
+               reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
+               reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
+       }
+       reg_w(gspca_dev, 0xdc, 0x01);
+       PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
 }
 
-static void setcolors(struct gspca_dev *gspca_dev)
+static void setgain(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       reg_w(gspca_dev, 0xff, 0x01);
-       reg_w(gspca_dev, 0x10, sd->colors);
+       if (sd->sensor == SENSOR_PAC7302) {
+               reg_w(gspca_dev, 0xff, 0x03);           /* page 3 */
+               reg_w(gspca_dev, 0x10, sd->gain >> 3);
+       } else {
+               int gain = GAIN_MAX - sd->gain;
+               if (gain < 1)
+                       gain = 1;
+               else if (gain > 245)
+                       gain = 245;
+               reg_w(gspca_dev, 0xff, 0x04);           /* page 4 */
+               reg_w(gspca_dev, 0x0e, 0x00);
+               reg_w(gspca_dev, 0x0f, gain);
+       }
        /* load registers to sensor (Bit 0, auto clear) */
        reg_w(gspca_dev, 0x11, 0x01);
-       PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
 }
 
-static void setautogain(struct gspca_dev *gspca_dev)
+static void setexposure(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       __u8 reg;
+
+       /* register 2 of frame 3/4 contains the clock divider configuring the
+          no fps according to the formula: 60 / reg. sd->exposure is the
+          desired exposure time in ms. */
+       reg = 120 * sd->exposure / 1000;
+       if (reg < 2)
+               reg = 2;
+       else if (reg > 63)
+               reg = 63;
+
+       if (sd->sensor == SENSOR_PAC7302) {
+               /* On the pac7302 reg2 MUST be a multiple of 3, so round it to
+                  the nearest multiple of 3, except when between 6 and 12? */
+               if (reg < 6 || reg > 12)
+                       reg = ((reg + 1) / 3) * 3;
+               reg_w(gspca_dev, 0xff, 0x03);           /* page 3 */
+               reg_w(gspca_dev, 0x02, reg);
+       } else {
+               reg_w(gspca_dev, 0xff, 0x04);           /* page 4 */
+               reg_w(gspca_dev, 0x02, reg);
+               /* Page 1 register 8 must always be 0x08 except when not in
+                  640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
+               reg_w(gspca_dev, 0xff, 0x01);
+               if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
+                               reg <= 3)
+                       reg_w(gspca_dev, 0x08, 0x09);
+               else
+                       reg_w(gspca_dev, 0x08, 0x08);
+       }
+       /* load registers to sensor (Bit 0, auto clear) */
+       reg_w(gspca_dev, 0x11, 0x01);
+}
 
-       if (sd->autogain) {
-               sd->lum_sum = 0;
-               sd->ag_cnt = AG_CNT_START;
+static void sethvflip(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u8 data;
+
+       if (sd->sensor == SENSOR_PAC7302) {
+               reg_w(gspca_dev, 0xff, 0x03);           /* page 3 */
+               data = (sd->hflip ? 0x08 : 0x00)
+                       | (sd->vflip ? 0x04 : 0x00);
        } else {
-               sd->ag_cnt = -1;
+               reg_w(gspca_dev, 0xff, 0x04);           /* page 4 */
+               data = (sd->hflip ? 0x04 : 0x00)
+                       | (sd->vflip ? 0x08 : 0x00);
        }
+       reg_w(gspca_dev, 0x21, data);
+       /* load registers to sensor (Bit 0, auto clear) */
+       reg_w(gspca_dev, 0x11, 0x01);
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
-       reg_w(gspca_dev, 0x78, 0x00);   /* Turn on LED */
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (sd->sensor == SENSOR_PAC7302)
+               reg_w_seq(gspca_dev, init_7302, sizeof init_7302);
+       else
+               reg_w_seq(gspca_dev, init_7311, sizeof init_7311);
+
        return 0;
 }
 
 static void sd_start(struct gspca_dev *gspca_dev)
 {
-       reg_w(gspca_dev, 0xff, 0x01);
-       reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
-       reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
-       reg_w_buf(gspca_dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8);
-       reg_w_buf(gspca_dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8);
-       reg_w_buf(gspca_dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
-       reg_w_buf(gspca_dev, 0x002a, "\x00\x00\x00", 3);
-       reg_w_buf(gspca_dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8);
-       reg_w_buf(gspca_dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8);
-       reg_w_buf(gspca_dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8);
-       reg_w_buf(gspca_dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8);
-       reg_w_buf(gspca_dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8);
-       reg_w_buf(gspca_dev, 0x0066, "\xd0\xff", 2);
-       reg_w_buf(gspca_dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6);
-       reg_w_buf(gspca_dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8);
-       reg_w_buf(gspca_dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8);
-       reg_w_buf(gspca_dev, 0x008f, "\x18\x20", 2);
-       reg_w_buf(gspca_dev, 0x0096, "\x01\x08\x04", 3);
-       reg_w_buf(gspca_dev, 0x00a0, "\x44\x44\x44\x04", 4);
-       reg_w_buf(gspca_dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8);
-       reg_w_buf(gspca_dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5);
+       struct sd *sd = (struct sd *) gspca_dev;
 
-       reg_w(gspca_dev, 0xff, 0x04);
-       reg_w(gspca_dev, 0x02, 0x04);
-       reg_w(gspca_dev, 0x03, 0x54);
-       reg_w(gspca_dev, 0x04, 0x07);
-       reg_w(gspca_dev, 0x05, 0x2b);
-       reg_w(gspca_dev, 0x06, 0x09);
-       reg_w(gspca_dev, 0x07, 0x0f);
-       reg_w(gspca_dev, 0x08, 0x09);
-       reg_w(gspca_dev, 0x09, 0x00);
-       reg_w(gspca_dev, 0x0c, 0x07);
-       reg_w(gspca_dev, 0x0d, 0x00);
-       reg_w(gspca_dev, 0x0e, 0x00);
-       reg_w(gspca_dev, 0x0f, 0x62);
-       reg_w(gspca_dev, 0x10, 0x08);
-       reg_w(gspca_dev, 0x12, 0x07);
-       reg_w(gspca_dev, 0x13, 0x00);
-       reg_w(gspca_dev, 0x14, 0x00);
-       reg_w(gspca_dev, 0x15, 0x00);
-       reg_w(gspca_dev, 0x16, 0x00);
-       reg_w(gspca_dev, 0x17, 0x00);
-       reg_w(gspca_dev, 0x18, 0x00);
-       reg_w(gspca_dev, 0x19, 0x00);
-       reg_w(gspca_dev, 0x1a, 0x00);
-       reg_w(gspca_dev, 0x1b, 0x03);
-       reg_w(gspca_dev, 0x1c, 0xa0);
-       reg_w(gspca_dev, 0x1d, 0x01);
-       reg_w(gspca_dev, 0x1e, 0xf4);
-       reg_w(gspca_dev, 0x21, 0x00);
-       reg_w(gspca_dev, 0x22, 0x08);
-       reg_w(gspca_dev, 0x24, 0x03);
-       reg_w(gspca_dev, 0x26, 0x00);
-       reg_w(gspca_dev, 0x27, 0x01);
-       reg_w(gspca_dev, 0x28, 0xca);
-       reg_w(gspca_dev, 0x29, 0x10);
-       reg_w(gspca_dev, 0x2a, 0x06);
-       reg_w(gspca_dev, 0x2b, 0x78);
-       reg_w(gspca_dev, 0x2c, 0x00);
-       reg_w(gspca_dev, 0x2d, 0x00);
-       reg_w(gspca_dev, 0x2e, 0x00);
-       reg_w(gspca_dev, 0x2f, 0x00);
-       reg_w(gspca_dev, 0x30, 0x23);
-       reg_w(gspca_dev, 0x31, 0x28);
-       reg_w(gspca_dev, 0x32, 0x04);
-       reg_w(gspca_dev, 0x33, 0x11);
-       reg_w(gspca_dev, 0x34, 0x00);
-       reg_w(gspca_dev, 0x35, 0x00);
-       reg_w(gspca_dev, 0x11, 0x01);
-       setcontrast(gspca_dev);
-       setbrightness(gspca_dev);
-       setcolors(gspca_dev);
-       setautogain(gspca_dev);
+       sd->sof_read = 0;
+
+       if (sd->sensor == SENSOR_PAC7302) {
+               reg_w_var(gspca_dev, start_7302);
+               setbrightcont(gspca_dev);
+               setcolors(gspca_dev);
+       } else {
+               reg_w_var(gspca_dev, start_7311);
+               setcontrast(gspca_dev);
+       }
+       setgain(gspca_dev);
+       setexposure(gspca_dev);
+       sethvflip(gspca_dev);
 
        /* set correct resolution */
        switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
-       case 2:                                 /* 160x120 */
-               reg_w(gspca_dev, 0xff, 0x04);
-               reg_w(gspca_dev, 0x02, 0x03);
+       case 2:                                 /* 160x120 pac7311 */
                reg_w(gspca_dev, 0xff, 0x01);
-               reg_w(gspca_dev, 0x08, 0x09);
                reg_w(gspca_dev, 0x17, 0x20);
-               reg_w(gspca_dev, 0x1b, 0x00);
-/*             reg_w(gspca_dev, 0x80, 0x69); */
                reg_w(gspca_dev, 0x87, 0x10);
                break;
-       case 1:                                 /* 320x240 */
-               reg_w(gspca_dev, 0xff, 0x04);
-               reg_w(gspca_dev, 0x02, 0x03);
+       case 1:                                 /* 320x240 pac7311 */
                reg_w(gspca_dev, 0xff, 0x01);
-               reg_w(gspca_dev, 0x08, 0x09);
                reg_w(gspca_dev, 0x17, 0x30);
-/*             reg_w(gspca_dev, 0x80, 0x3f); */
                reg_w(gspca_dev, 0x87, 0x11);
                break;
        case 0:                                 /* 640x480 */
-               reg_w(gspca_dev, 0xff, 0x04);
-               reg_w(gspca_dev, 0x02, 0x03);
+               if (sd->sensor == SENSOR_PAC7302)
+                       break;
                reg_w(gspca_dev, 0xff, 0x01);
-               reg_w(gspca_dev, 0x08, 0x08);
                reg_w(gspca_dev, 0x17, 0x00);
-/*             reg_w(gspca_dev, 0x80, 0x1c); */
                reg_w(gspca_dev, 0x87, 0x12);
                break;
        }
 
+       sd->sof_read = 0;
+       sd->autogain_ignore_frames = 0;
+       atomic_set(&sd->avg_lum, -1);
+
        /* start stream */
        reg_w(gspca_dev, 0xff, 0x01);
-       reg_w(gspca_dev, 0x78, 0x04);
-       reg_w(gspca_dev, 0x78, 0x05);
+       if (sd->sensor == SENSOR_PAC7302)
+               reg_w(gspca_dev, 0x78, 0x01);
+       else
+               reg_w(gspca_dev, 0x78, 0x05);
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (sd->sensor == SENSOR_PAC7302) {
+               reg_w(gspca_dev, 0xff, 0x01);
+               reg_w(gspca_dev, 0x78, 0x00);
+               reg_w(gspca_dev, 0x78, 0x00);
+               return;
+       }
        reg_w(gspca_dev, 0xff, 0x04);
        reg_w(gspca_dev, 0x27, 0x80);
        reg_w(gspca_dev, 0x28, 0xca);
@@ -456,187 +743,147 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        reg_w(gspca_dev, 0x2a, 0x0e);
        reg_w(gspca_dev, 0xff, 0x01);
        reg_w(gspca_dev, 0x3e, 0x20);
-       reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
-       reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
-       reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+       reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
+       reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
+       reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
 }
 
 static void sd_stop0(struct gspca_dev *gspca_dev)
 {
-}
+       struct sd *sd = (struct sd *) gspca_dev;
 
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-       reg_w(gspca_dev, 0xff, 0x04);
-       reg_w(gspca_dev, 0x27, 0x80);
-       reg_w(gspca_dev, 0x28, 0xca);
-       reg_w(gspca_dev, 0x29, 0x53);
-       reg_w(gspca_dev, 0x2a, 0x0e);
-       reg_w(gspca_dev, 0xff, 0x01);
-       reg_w(gspca_dev, 0x3e, 0x20);
-       reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
-       reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
-       reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+       if (sd->sensor == SENSOR_PAC7302) {
+               reg_w(gspca_dev, 0xff, 0x01);
+               reg_w(gspca_dev, 0x78, 0x40);
+       }
 }
 
+/* Include pac common sof detection functions */
+#include "pac_common.h"
+
 static void do_autogain(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int luma;
-       int luma_mean = 128;
-       int luma_delta = 20;
-       __u8 spring = 5;
-       int Gbright;
+       int avg_lum = atomic_read(&sd->avg_lum);
+       int desired_lum, deadzone;
 
-       if (!atomic_read(&sd->do_gain))
+       if (avg_lum == -1)
                return;
-       atomic_set(&sd->do_gain, 0);
-
-       luma = atomic_read(&sd->avg_lum);
-       Gbright = reg_r(gspca_dev, 0x02);
-       PDEBUG(D_FRAM, "luma mean %d", luma);
-       if (luma < luma_mean - luma_delta ||
-           luma > luma_mean + luma_delta) {
-               Gbright += (luma_mean - luma) >> spring;
-               if (Gbright > 0x1a)
-                       Gbright = 0x1a;
-               else if (Gbright < 4)
-                       Gbright = 4;
-               PDEBUG(D_FRAM, "gbright %d", Gbright);
-               reg_w(gspca_dev, 0xff, 0x04);
-               reg_w(gspca_dev, 0x0f, Gbright);
-               /* load registers to sensor (Bit 0, auto clear) */
-               reg_w(gspca_dev, 0x11, 0x01);
+
+       if (sd->sensor == SENSOR_PAC7302) {
+               desired_lum = 270 + sd->brightness * 4;
+               /* Hack hack, with the 7202 the first exposure step is
+                  pretty large, so if we're about to make the first
+                  exposure increase make the deadzone large to avoid
+                  oscilating */
+               if (desired_lum > avg_lum && sd->gain == GAIN_DEF &&
+                               sd->exposure > EXPOSURE_DEF &&
+                               sd->exposure < 42)
+                       deadzone = 90;
+               else
+                       deadzone = 30;
+       } else {
+               desired_lum = 200;
+               deadzone = 20;
        }
+
+       if (sd->autogain_ignore_frames > 0)
+               sd->autogain_ignore_frames--;
+       else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
+                       deadzone, GAIN_KNEE, EXPOSURE_KNEE))
+               sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
 }
 
+static const unsigned char pac7311_jpeg_header1[] = {
+  0xff, 0xd8, 0xff, 0xc0, 0x00, 0x11, 0x08
+};
+
+static const unsigned char pac7311_jpeg_header2[] = {
+  0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda,
+  0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
+};
+
+/* this function is run at interrupt level */
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
                        int len)                        /* iso packet length */
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       unsigned char tmpbuf[4];
-       int i, p, ffseq;
-
-/*     if (len < 5) { */
-       if (len < 6) {
-/*             gspca_dev->last_packet_type = DISCARD_PACKET; */
-               return;
-       }
-
-       ffseq = sd->ffseq;
-
-       for (p = 0; p < len - 6; p++) {
-               if ((data[0 + p] == 0xff)
-                   && (data[1 + p] == 0xff)
-                   && (data[2 + p] == 0x00)
-                   && (data[3 + p] == 0xff)
-                   && (data[4 + p] == 0x96)) {
-
-                       /* start of frame */
-                       if (sd->ag_cnt >= 0 && p > 28) {
-                               sd->lum_sum += data[p - 23];
-                               if (--sd->ag_cnt < 0) {
-                                       sd->ag_cnt = AG_CNT_START;
-                                       atomic_set(&sd->avg_lum,
-                                               sd->lum_sum / AG_CNT_START);
-                                       sd->lum_sum = 0;
-                                       atomic_set(&sd->do_gain, 1);
-                               }
-                       }
+       unsigned char *sof;
+
+       sof = pac_find_sof(gspca_dev, data, len);
+       if (sof) {
+               unsigned char tmpbuf[4];
+               int n, lum_offset, footer_length;
+
+               if (sd->sensor == SENSOR_PAC7302) {
+                 /* 6 bytes after the FF D9 EOF marker a number of lumination
+                    bytes are send corresponding to different parts of the
+                    image, the 14th and 15th byte after the EOF seem to
+                    correspond to the center of the image */
+                 lum_offset = 61 + sizeof pac_sof_marker;
+                 footer_length = 74;
+               } else {
+                 lum_offset = 24 + sizeof pac_sof_marker;
+                 footer_length = 26;
+               }
 
-                       /* copy the end of data to the current frame */
+               /* Finish decoding current frame */
+               n = (sof - data) - (footer_length + sizeof pac_sof_marker);
+               if (n < 0) {
+                       frame->data_end += n;
+                       n = 0;
+               }
+               frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                                       data, n);
+               if (gspca_dev->last_packet_type != DISCARD_PACKET &&
+                               frame->data_end[-2] == 0xff &&
+                               frame->data_end[-1] == 0xd9)
                        frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-                                               data, p);
-
-                       /* put the JPEG header in the new frame */
-                       gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
-                                       (unsigned char *) pac7311_jpeg_header,
-                                       12);
+                                               NULL, 0);
+
+               n = sof - data;
+               len -= n;
+               data = sof;
+
+               /* Get average lumination */
+               if (gspca_dev->last_packet_type == LAST_PACKET &&
+                               n >= lum_offset)
+                       atomic_set(&sd->avg_lum, data[-lum_offset] +
+                                               data[-lum_offset + 1]);
+               else
+                       atomic_set(&sd->avg_lum, -1);
+
+               /* Start the new frame with the jpeg header */
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                       pac7311_jpeg_header1, sizeof(pac7311_jpeg_header1));
+               if (sd->sensor == SENSOR_PAC7302) {
+                       /* The PAC7302 has the image rotated 90 degrees */
+                       tmpbuf[0] = gspca_dev->width >> 8;
+                       tmpbuf[1] = gspca_dev->width & 0xff;
+                       tmpbuf[2] = gspca_dev->height >> 8;
+                       tmpbuf[3] = gspca_dev->height & 0xff;
+               } else {
                        tmpbuf[0] = gspca_dev->height >> 8;
                        tmpbuf[1] = gspca_dev->height & 0xff;
                        tmpbuf[2] = gspca_dev->width >> 8;
                        tmpbuf[3] = gspca_dev->width & 0xff;
-                       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-                                       tmpbuf, 4);
-                       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-                               (unsigned char *) &pac7311_jpeg_header[16],
-                               PAC7311_JPEG_HEADER_SIZE - 16);
-
-                       data += p + 7;
-                       len -= p + 7;
-                       ffseq = 0;
-                       break;
                }
+               gspca_frame_add(gspca_dev, INTER_PACKET, frame, tmpbuf, 4);
+               gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                       pac7311_jpeg_header2, sizeof(pac7311_jpeg_header2));
        }
-
-       /* remove the 'ff ff ff xx' sequences */
-       switch (ffseq) {
-       case 3:
-               data += 1;
-               len -= 1;
-               break;
-       case 2:
-               if (data[0] == 0xff) {
-                       data += 2;
-                       len -= 2;
-                       frame->data_end -= 2;
-               }
-               break;
-       case 1:
-               if (data[0] == 0xff
-                   && data[1] == 0xff) {
-                       data += 3;
-                       len -= 3;
-                       frame->data_end -= 1;
-               }
-               break;
-       }
-       for (i = 0; i < len - 4; i++) {
-               if (data[i] == 0xff
-                   && data[i + 1] == 0xff
-                   && data[i + 2] == 0xff) {
-                       memmove(&data[i], &data[i + 4], len - i - 4);
-                       len -= 4;
-               }
-       }
-       ffseq = 0;
-       if (data[len - 4] == 0xff) {
-               if (data[len - 3] == 0xff
-                   && data[len - 2] == 0xff) {
-                       len -= 4;
-               }
-       } else if (data[len - 3] == 0xff) {
-               if (data[len - 2] == 0xff
-                   && data[len - 1] == 0xff)
-                       ffseq = 3;
-       } else if (data[len - 2] == 0xff) {
-               if (data[len - 1] == 0xff)
-                       ffseq = 2;
-       } else if (data[len - 1] == 0xff)
-               ffseq = 1;
-       sd->ffseq = ffseq;
        gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
-static void getbrightness(struct gspca_dev *gspca_dev)
-{
-/*     sd->brightness = reg_r(gspca_dev, 0x08);
-       return sd->brightness;  */
-/*     PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */
-}
-
-
-
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
        sd->brightness = val;
        if (gspca_dev->streaming)
-               setbrightness(gspca_dev);
+               setbrightcont(gspca_dev);
        return 0;
 }
 
@@ -644,7 +891,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getbrightness(gspca_dev);
        *val = sd->brightness;
        return 0;
 }
@@ -654,8 +900,12 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        sd->contrast = val;
-       if (gspca_dev->streaming)
-               setcontrast(gspca_dev);
+       if (gspca_dev->streaming) {
+               if (sd->sensor == SENSOR_PAC7302)
+                       setbrightcont(gspca_dev);
+               else
+                       setcontrast(gspca_dev);
+       }
        return 0;
 }
 
@@ -663,7 +913,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-/*     getcontrast(gspca_dev); */
        *val = sd->contrast;
        return 0;
 }
@@ -682,18 +931,66 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-/*     getcolors(gspca_dev); */
        *val = sd->colors;
        return 0;
 }
 
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->gain = val;
+       if (gspca_dev->streaming)
+               setgain(gspca_dev);
+       return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->gain;
+       return 0;
+}
+
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->exposure = val;
+       if (gspca_dev->streaming)
+               setexposure(gspca_dev);
+       return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->exposure;
+       return 0;
+}
+
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
        sd->autogain = val;
-       if (gspca_dev->streaming)
-               setautogain(gspca_dev);
+       /* when switching to autogain set defaults to make sure
+          we are on a valid point of the autogain gain /
+          exposure knee graph, and give this change time to
+          take effect before doing autogain. */
+       if (sd->autogain) {
+               sd->exposure = EXPOSURE_DEF;
+               sd->gain = GAIN_DEF;
+               if (gspca_dev->streaming) {
+                       sd->autogain_ignore_frames =
+                               PAC_AUTOGAIN_IGNORE_FRAMES;
+                       setexposure(gspca_dev);
+                       setgain(gspca_dev);
+               }
+       }
+
        return 0;
 }
 
@@ -705,30 +1002,67 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->hflip = val;
+       if (gspca_dev->streaming)
+               sethvflip(gspca_dev);
+       return 0;
+}
+
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->hflip;
+       return 0;
+}
+
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->vflip = val;
+       if (gspca_dev->streaming)
+               sethvflip(gspca_dev);
+       return 0;
+}
+
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->vflip;
+       return 0;
+}
+
 /* sub-driver description */
 static struct sd_desc sd_desc = {
        .name = MODULE_NAME,
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
        .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
        .dq_callback = do_autogain,
 };
 
 /* -- module initialisation -- */
 static __devinitdata struct usb_device_id device_table[] = {
-       {USB_DEVICE(0x093a, 0x2600)},
-       {USB_DEVICE(0x093a, 0x2601)},
-       {USB_DEVICE(0x093a, 0x2603)},
-       {USB_DEVICE(0x093a, 0x2608)},
-       {USB_DEVICE(0x093a, 0x260e)},
-       {USB_DEVICE(0x093a, 0x260f)},
-       {USB_DEVICE(0x093a, 0x2621)},
+       {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
+       {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
+       {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
+       {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
+       {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
+       {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
+       {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
+       {USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302},
+       {USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302},
        {}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
@@ -746,6 +1080,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/pac_common.h b/drivers/media/video/gspca/pac_common.h
new file mode 100644 (file)
index 0000000..34d4b14
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Pixart PAC207BCA / PAC73xx common functions
+ *
+ * Copyright (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+ * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
+ * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (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
+ *
+ */
+
+/* We calculate the autogain at the end of the transfer of a frame, at this
+   moment a frame with the old settings is being transmitted, and a frame is
+   being captured with the old settings. So if we adjust the autogain we must
+   ignore atleast the 2 next frames for the new settings to come into effect
+   before doing any other adjustments */
+#define PAC_AUTOGAIN_IGNORE_FRAMES     3
+
+static const unsigned char pac_sof_marker[5] =
+               { 0xff, 0xff, 0x00, 0xff, 0x96 };
+
+static unsigned char *pac_find_sof(struct gspca_dev *gspca_dev,
+                                       unsigned char *m, int len)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i;
+
+       /* Search for the SOF marker (fixed part) in the header */
+       for (i = 0; i < len; i++) {
+               if (m[i] == pac_sof_marker[sd->sof_read]) {
+                       sd->sof_read++;
+                       if (sd->sof_read == sizeof(pac_sof_marker)) {
+                               PDEBUG(D_FRAM,
+                                       "SOF found, bytes to analyze: %u."
+                                       " Frame starts at byte #%u",
+                                       len, i + 1);
+                               sd->sof_read = 0;
+                               return m + i + 1;
+                       }
+               } else {
+                       sd->sof_read = 0;
+               }
+       }
+
+       return NULL;
+}
index 11210c7..5dd78c6 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+/* Some documentation on known sonixb registers:
+
+Reg    Use
+0x10   high nibble red gain low nibble blue gain
+0x11   low nibble green gain
+0x12   hstart
+0x13   vstart
+0x15   hsize (hsize = register-value * 16)
+0x16   vsize (vsize = register-value * 16)
+0x17   bit 0 toggle compression quality (according to sn9c102 driver)
+0x18   bit 7 enables compression, bit 4-5 set image down scaling:
+       00 scale 1, 01 scale 1/2, 10, scale 1/4
+0x19   high-nibble is sensor clock divider, changes exposure on sensors which
+       use a clock generated by the bridge. Some sensors have their own clock.
+0x1c   auto_exposure area (for avg_lum) startx (startx = register-value * 32)
+0x1d   auto_exposure area (for avg_lum) starty (starty = register-value * 32)
+0x1e   auto_exposure area (for avg_lum) stopx (hsize = (0x1e - 0x1c) * 32)
+0x1f   auto_exposure area (for avg_lum) stopy (vsize = (0x1f - 0x1d) * 32)
+*/
+
 #define MODULE_NAME "sonixb"
 
 #include "gspca.h"
@@ -31,10 +51,8 @@ MODULE_LICENSE("GPL");
 /* specific webcam descriptor */
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
-
-       struct sd_desc sd_desc;         /* our nctrls differ dependend upon the
-                                          sensor, so we use a per cam copy */
        atomic_t avg_lum;
+       int prev_avg_lum;
 
        unsigned char gain;
        unsigned char exposure;
@@ -44,8 +62,12 @@ struct sd {
        unsigned char frames_to_drop;
        unsigned char freq;             /* light freq filter setting */
 
-       unsigned char fr_h_sz;          /* size of frame header */
-       char sensor;                    /* Type of image sensor chip */
+       __u8 bridge;                    /* Type of bridge */
+#define BRIDGE_101 0
+#define BRIDGE_102 0 /* We make no difference between 101 and 102 */
+#define BRIDGE_103 1
+
+       __u8 sensor;                    /* Type of image sensor chip */
 #define SENSOR_HV7131R 0
 #define SENSOR_OV6650 1
 #define SENSOR_OV7630 2
@@ -53,16 +75,35 @@ struct sd {
 #define SENSOR_PAS202 4
 #define SENSOR_TAS5110 5
 #define SENSOR_TAS5130CXX 6
-       char sensor_has_gain;
-       __u8 sensor_addr;
        __u8 reg11;
 };
 
-/* flags used in the device id table */
+typedef const __u8 sensor_init_t[8];
+
+struct sensor_data {
+       const __u8 *bridge_init[2];
+       int bridge_init_size[2];
+       sensor_init_t *sensor_init;
+       int sensor_init_size;
+       sensor_init_t *sensor_bridge_init[2];
+       int sensor_bridge_init_size[2];
+       int flags;
+       unsigned ctrl_dis;
+       __u8 sensor_addr;
+};
+
+/* sensor_data flags */
 #define F_GAIN 0x01            /* has gain */
-#define F_AUTO 0x02            /* has autogain */
-#define F_SIF  0x04            /* sif or vga */
-#define F_H18  0x08            /* long (18 b) or short (12 b) frame header */
+#define F_SIF  0x02            /* sif or vga */
+
+/* priv field of struct v4l2_pix_format flags (do not use low nibble!) */
+#define MODE_RAW 0x10          /* raw bayer mode */
+#define MODE_REDUCED_SIF 0x20  /* vga mode (320x240 / 160x120) on sif cam */
+
+/* ctrl_dis helper macros */
+#define NO_EXPO ((1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX))
+#define NO_FREQ (1 << FREQ_IDX)
+#define NO_BRIGHTNESS (1 << BRIGHTNESS_IDX)
 
 #define COMP2 0x8f
 #define COMP 0xc7              /* 0x87 //0x07 */
@@ -73,6 +114,18 @@ struct sd {
 
 #define SYS_CLK 0x04
 
+#define SENS(bridge_1, bridge_3, sensor, sensor_1, \
+       sensor_3, _flags, _ctrl_dis, _sensor_addr) \
+{ \
+       .bridge_init = { bridge_1, bridge_3 }, \
+       .bridge_init_size = { sizeof(bridge_1), sizeof(bridge_3) }, \
+       .sensor_init = sensor, \
+       .sensor_init_size = sizeof(sensor), \
+       .sensor_bridge_init = { sensor_1, sensor_3,}, \
+       .sensor_bridge_init_size = { sizeof(sensor_1), sizeof(sensor_3)}, \
+       .flags = _flags, .ctrl_dis = _ctrl_dis, .sensor_addr = _sensor_addr \
+}
+
 /* We calculate the autogain at the end of the transfer of a frame, at this
    moment a frame with the old settings is being transmitted, and a frame is
    being captured with the old settings. So if we adjust the autogain we must
@@ -95,6 +148,7 @@ static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
+#define BRIGHTNESS_IDX 0
        {
            {
                .id      = V4L2_CID_BRIGHTNESS,
@@ -109,6 +163,7 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setbrightness,
            .get = sd_getbrightness,
        },
+#define GAIN_IDX 1
        {
            {
                .id      = V4L2_CID_GAIN,
@@ -124,6 +179,7 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setgain,
            .get = sd_getgain,
        },
+#define EXPOSURE_IDX 2
        {
                {
                        .id = V4L2_CID_EXPOSURE,
@@ -140,6 +196,7 @@ static struct ctrl sd_ctrls[] = {
                .set = sd_setexposure,
                .get = sd_getexposure,
        },
+#define AUTOGAIN_IDX 3
        {
                {
                        .id = V4L2_CID_AUTOGAIN,
@@ -155,6 +212,7 @@ static struct ctrl sd_ctrls[] = {
                .set = sd_setautogain,
                .get = sd_getautogain,
        },
+#define FREQ_IDX 4
        {
                {
                        .id      = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -172,31 +230,56 @@ static struct ctrl sd_ctrls[] = {
 };
 
 static struct v4l2_pix_format vga_mode[] = {
+       {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 160,
+               .sizeimage = 160 * 120 * 5 / 4,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 2 | MODE_RAW},
        {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
                .bytesperline = 160,
-               .sizeimage = 160 * 120,
+               .sizeimage = 160 * 120 * 5 / 4,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 2},
        {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
                .bytesperline = 320,
-               .sizeimage = 320 * 240,
+               .sizeimage = 320 * 240 * 5 / 4,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 1},
        {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
                .bytesperline = 640,
-               .sizeimage = 640 * 480,
+               .sizeimage = 640 * 480 * 5 / 4,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 0},
 };
 static struct v4l2_pix_format sif_mode[] = {
+       {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 160,
+               .sizeimage = 160 * 120,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1 | MODE_RAW | MODE_REDUCED_SIF},
+       {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+               .bytesperline = 160,
+               .sizeimage = 160 * 120 * 5 / 4,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1 | MODE_REDUCED_SIF},
+       {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 176,
+               .sizeimage = 176 * 144 * 5 / 4,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1 | MODE_RAW},
        {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
                .bytesperline = 176,
-               .sizeimage = 176 * 144,
+               .sizeimage = 176 * 144 * 5 / 4,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 1},
+       {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 5 / 4,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0 | MODE_REDUCED_SIF},
        {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
                .bytesperline = 352,
-               .sizeimage = 352 * 288,
+               .sizeimage = 352 * 288 * 5 / 4,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 0},
 };
@@ -204,7 +287,7 @@ static struct v4l2_pix_format sif_mode[] = {
 static const __u8 initHv7131[] = {
        0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
        0x00, 0x00,
-       0x00, 0x00, 0x00, 0x03, 0x01, 0x00,     /* shift from 0x02 0x01 0x00 */
+       0x00, 0x00, 0x00, 0x02, 0x01, 0x00,
        0x28, 0x1e, 0x60, 0x8a, 0x20,
        0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
 };
@@ -218,8 +301,8 @@ static const __u8 hv7131_sensor_init[][8] = {
 static const __u8 initOv6650[] = {
        0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
        0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
-       0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
+       0x00, 0x01, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x8b,
+       0x10, 0x1d, 0x10, 0x02, 0x02, 0x09, 0x07
 };
 static const __u8 ov6650_sensor_init[][8] =
 {
@@ -257,15 +340,15 @@ static const __u8 ov6650_sensor_init[][8] =
 static const __u8 initOv7630[] = {
        0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
        0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
-       0x00, 0x02, 0x01, 0x0a,                         /* r11 .. r14 */
+       0x00, 0x01, 0x01, 0x0a,                         /* r11 .. r14 */
        0x28, 0x1e,                     /* H & V sizes     r15 .. r16 */
-       0x68, COMP1, MCK_INIT1,                         /* r17 .. r19 */
+       0x68, COMP2, MCK_INIT1,                         /* r17 .. r19 */
        0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c              /* r1a .. r1f */
 };
 static const __u8 initOv7630_3[] = {
        0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
        0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
-       0x00, 0x01, 0x01, 0x0a,                         /* r11 .. r14 */
+       0x00, 0x02, 0x01, 0x0a,                         /* r11 .. r14 */
        0x28, 0x1e,                     /* H & V sizes     r15 .. r16 */
        0x68, 0x8f, MCK_INIT1,                          /* r17 .. r19 */
        0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00,       /* r1a .. r20 */
@@ -294,47 +377,65 @@ static const __u8 ov7630_sensor_init[][8] = {
        {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
 };
 
+static const __u8 ov7630_sensor_init_3[][8] = {
+       {0xa0, 0x21, 0x13, 0x80, 0x00,  0x00, 0x00, 0x10},
+};
+
 static const __u8 initPas106[] = {
        0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
        0x00, 0x00,
-       0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
-       0x16, 0x12, 0x28, COMP1, MCK_INIT1,
-       0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
+       0x00, 0x00, 0x00, 0x04, 0x01, 0x00,
+       0x16, 0x12, 0x24, COMP1, MCK_INIT1,
+       0x18, 0x10, 0x02, 0x02, 0x09, 0x07
 };
 /* compression 0x86 mckinit1 0x2b */
-static const __u8 pas106_data[][2] = {
-       {0x02, 0x04},           /* Pixel Clock Divider 6 */
-       {0x03, 0x13},           /* Frame Time MSB */
-/*     {0x03, 0x12},            * Frame Time MSB */
-       {0x04, 0x06},           /* Frame Time LSB */
-/*     {0x04, 0x05},            * Frame Time LSB */
-       {0x05, 0x65},           /* Shutter Time Line Offset */
-/*     {0x05, 0x6d},            * Shutter Time Line Offset */
-/*     {0x06, 0xb1},            * Shutter Time Pixel Offset */
-       {0x06, 0xcd},           /* Shutter Time Pixel Offset */
-       {0x07, 0xc1},           /* Black Level Subtract Sign */
-/*     {0x07, 0x00},            * Black Level Subtract Sign */
-       {0x08, 0x06},           /* Black Level Subtract Level */
-       {0x08, 0x06},           /* Black Level Subtract Level */
-/*     {0x08, 0x01},            * Black Level Subtract Level */
-       {0x09, 0x05},           /* Color Gain B Pixel 5 a */
-       {0x0a, 0x04},           /* Color Gain G1 Pixel 1 5 */
-       {0x0b, 0x04},           /* Color Gain G2 Pixel 1 0 5 */
-       {0x0c, 0x05},           /* Color Gain R Pixel 3 1 */
-       {0x0d, 0x00},           /* Color GainH  Pixel */
-       {0x0e, 0x0e},           /* Global Gain */
-       {0x0f, 0x00},           /* Contrast */
-       {0x10, 0x06},           /* H&V synchro polarity */
-       {0x11, 0x06},           /* ?default */
-       {0x12, 0x06},           /* DAC scale */
-       {0x14, 0x02},           /* ?default */
-       {0x13, 0x01},           /* Validate Settings */
+static const __u8 pas106_sensor_init[][8] = {
+       /* Pixel Clock Divider 6 */
+       { 0xa1, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x14 },
+       /* Frame Time MSB (also seen as 0x12) */
+       { 0xa1, 0x40, 0x03, 0x13, 0x00, 0x00, 0x00, 0x14 },
+       /* Frame Time LSB (also seen as 0x05) */
+       { 0xa1, 0x40, 0x04, 0x06, 0x00, 0x00, 0x00, 0x14 },
+       /* Shutter Time Line Offset (also seen as 0x6d) */
+       { 0xa1, 0x40, 0x05, 0x65, 0x00, 0x00, 0x00, 0x14 },
+       /* Shutter Time Pixel Offset (also seen as 0xb1) */
+       { 0xa1, 0x40, 0x06, 0xcd, 0x00, 0x00, 0x00, 0x14 },
+       /* Black Level Subtract Sign (also seen 0x00) */
+       { 0xa1, 0x40, 0x07, 0xc1, 0x00, 0x00, 0x00, 0x14 },
+       /* Black Level Subtract Level (also seen 0x01) */
+       { 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 },
+       { 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 },
+       /* Color Gain B Pixel 5 a */
+       { 0xa1, 0x40, 0x09, 0x05, 0x00, 0x00, 0x00, 0x14 },
+       /* Color Gain G1 Pixel 1 5 */
+       { 0xa1, 0x40, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x14 },
+       /* Color Gain G2 Pixel 1 0 5 */
+       { 0xa1, 0x40, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x14 },
+       /* Color Gain R Pixel 3 1 */
+       { 0xa1, 0x40, 0x0c, 0x05, 0x00, 0x00, 0x00, 0x14 },
+       /* Color GainH  Pixel */
+       { 0xa1, 0x40, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x14 },
+       /* Global Gain */
+       { 0xa1, 0x40, 0x0e, 0x0e, 0x00, 0x00, 0x00, 0x14 },
+       /* Contrast */
+       { 0xa1, 0x40, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x14 },
+       /* H&V synchro polarity */
+       { 0xa1, 0x40, 0x10, 0x06, 0x00, 0x00, 0x00, 0x14 },
+       /* ?default */
+       { 0xa1, 0x40, 0x11, 0x06, 0x00, 0x00, 0x00, 0x14 },
+       /* DAC scale */
+       { 0xa1, 0x40, 0x12, 0x06, 0x00, 0x00, 0x00, 0x14 },
+       /* ?default */
+       { 0xa1, 0x40, 0x14, 0x02, 0x00, 0x00, 0x00, 0x14 },
+       /* Validate Settings */
+       { 0xa1, 0x40, 0x13, 0x01, 0x00, 0x00, 0x00, 0x14 },
 };
+
 static const __u8 initPas202[] = {
        0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
        0x00, 0x00,
-       0x00, 0x00, 0x00, 0x07, 0x03, 0x0a,     /* 6 */
-       0x28, 0x1e, 0x28, 0x89, 0x30,
+       0x00, 0x00, 0x00, 0x06, 0x03, 0x0a,
+       0x28, 0x1e, 0x28, 0x89, 0x20,
        0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
 };
 static const __u8 pas202_sensor_init[][8] = {
@@ -364,7 +465,7 @@ static const __u8 pas202_sensor_init[][8] = {
 static const __u8 initTas5110[] = {
        0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
        0x00, 0x00,
-       0x00, 0x01, 0x00, 0x46, 0x09, 0x0a,     /* shift from 0x45 0x09 0x0a */
+       0x00, 0x01, 0x00, 0x45, 0x09, 0x0a,
        0x16, 0x12, 0x60, 0x86, 0x2b,
        0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
 };
@@ -377,7 +478,7 @@ static const __u8 tas5110_sensor_init[][8] = {
 static const __u8 initTas5130[] = {
        0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
        0x00, 0x00,
-       0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
+       0x00, 0x01, 0x00, 0x68, 0x0c, 0x0a,
        0x28, 0x1e, 0x60, COMP, MCK_INIT,
        0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
 };
@@ -389,6 +490,21 @@ static const __u8 tas5130_sensor_init[][8] = {
        {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
 };
 
+struct sensor_data sensor_data[] = {
+SENS(initHv7131, NULL, hv7131_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, 0),
+SENS(initOv6650, NULL, ov6650_sensor_init, NULL, NULL, F_GAIN|F_SIF, 0, 0x60),
+SENS(initOv7630, initOv7630_3, ov7630_sensor_init, NULL, ov7630_sensor_init_3,
+       F_GAIN, 0, 0x21),
+SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_SIF, NO_EXPO|NO_FREQ,
+       0),
+SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, 0,
+       NO_EXPO|NO_FREQ, 0),
+SENS(initTas5110, NULL, tas5110_sensor_init, NULL, NULL, F_GAIN|F_SIF,
+       NO_BRIGHTNESS|NO_FREQ, 0),
+SENS(initTas5130, NULL, tas5130_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ,
+       0),
+};
+
 /* get one byte in gspca_dev->usb_buf */
 static void reg_r(struct gspca_dev *gspca_dev,
                  __u16 value)
@@ -409,7 +525,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
                  int len)
 {
 #ifdef GSPCA_DEBUG
-       if (len > sizeof gspca_dev->usb_buf) {
+       if (len > USB_BUF_SZ) {
                PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
                return;
        }
@@ -425,26 +541,6 @@ static void reg_w(struct gspca_dev *gspca_dev,
                        500);
 }
 
-static void reg_w_big(struct gspca_dev *gspca_dev,
-                 __u16 value,
-                 const __u8 *buffer,
-                 int len)
-{
-       __u8 *tmpbuf;
-
-       tmpbuf = kmalloc(len, GFP_KERNEL);
-       memcpy(tmpbuf, buffer, len);
-       usb_control_msg(gspca_dev->dev,
-                       usb_sndctrlpipe(gspca_dev->dev, 0),
-                       0x08,                   /* request */
-                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
-                       value,
-                       0,                      /* index */
-                       tmpbuf, len,
-                       500);
-       kfree(tmpbuf);
-}
-
 static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
 {
        int retry = 60;
@@ -487,7 +583,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
                        {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
 
                /* change reg 0x06 */
-               i2cOV[1] = sd->sensor_addr;
+               i2cOV[1] = sensor_data[sd->sensor].sensor_addr;
                i2cOV[3] = sd->brightness;
                if (i2c_w(gspca_dev, i2cOV) < 0)
                        goto err;
@@ -545,9 +641,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
                        goto err;
                break;
            }
-       case SENSOR_TAS5110:
-               /* FIXME figure out howto control brightness on TAS5110 */
-               break;
        }
        return;
 err:
@@ -577,7 +670,7 @@ static void setsensorgain(struct gspca_dev *gspca_dev)
        case SENSOR_OV7630: {
                __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
 
-               i2c[1] = sd->sensor_addr;
+               i2c[1] = sensor_data[sd->sensor].sensor_addr;
                i2c[3] = gain >> 2;
                if (i2c_w(gspca_dev, i2c) < 0)
                        goto err;
@@ -604,7 +697,7 @@ static void setgain(struct gspca_dev *gspca_dev)
        rgb_value = gain;
        reg_w(gspca_dev, 0x11, &rgb_value, 1);
 
-       if (sd->sensor_has_gain)
+       if (sensor_data[sd->sensor].flags & F_GAIN)
                setsensorgain(gspca_dev);
 }
 
@@ -665,6 +758,11 @@ static void setexposure(struct gspca_dev *gspca_dev)
                else if (reg11 > 16)
                        reg11 = 16;
 
+               /* In 640x480, if the reg11 has less than 3, the image is
+                  unstable (not enough bandwidth). */
+               if (gspca_dev->width == 640 && reg11 < 3)
+                       reg11 = 3;
+
                /* frame exposure time in ms = 1000 * reg11 / 30    ->
                reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
                reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
@@ -678,13 +776,8 @@ static void setexposure(struct gspca_dev *gspca_dev)
                else if (reg10 > reg10_max)
                        reg10 = reg10_max;
 
-               /* In 640x480, if the reg11 has less than 3, the image is
-                  unstable (not enough bandwidth). */
-               if (gspca_dev->width == 640 && reg11 < 3)
-                       reg11 = 3;
-
                /* Write reg 10 and reg11 low nibble */
-               i2c[1] = sd->sensor_addr;
+               i2c[1] = sensor_data[sd->sensor].sensor_addr;
                i2c[3] = reg10;
                i2c[4] |= reg11 - 1;
 
@@ -724,7 +817,7 @@ static void setfreq(struct gspca_dev *gspca_dev)
                                        ? 0x4f : 0x8a;
                        break;
                }
-               i2c[1] = sd->sensor_addr;
+               i2c[1] = sensor_data[sd->sensor].sensor_addr;
                if (i2c_w(gspca_dev, i2c) < 0)
                        PDEBUG(D_ERR, "i2c error setfreq");
                break;
@@ -757,30 +850,19 @@ static int sd_config(struct gspca_dev *gspca_dev,
 {
        struct sd *sd = (struct sd *) gspca_dev;
        struct cam *cam;
-       int sif = 0;
 
-       /* nctrls depends upon the sensor, so we use a per cam copy */
-       memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
-       gspca_dev->sd_desc = &sd->sd_desc;
+       reg_r(gspca_dev, 0x00);
+       if (gspca_dev->usb_buf[0] != 0x10)
+               return -ENODEV;
 
        /* copy the webcam info from the device id */
-       sd->sensor = (id->driver_info >> 24) & 0xff;
-       if (id->driver_info & (F_GAIN << 16))
-               sd->sensor_has_gain = 1;
-       if (id->driver_info & (F_AUTO << 16))
-               sd->sd_desc.dq_callback = do_autogain;
-       if (id->driver_info & (F_SIF << 16))
-               sif = 1;
-       if (id->driver_info & (F_H18 << 16))
-               sd->fr_h_sz = 18;               /* size of frame header */
-       else
-               sd->fr_h_sz = 12;
-       sd->sd_desc.nctrls = (id->driver_info >> 8) & 0xff;
-       sd->sensor_addr = id->driver_info & 0xff;
+       sd->sensor = id->driver_info >> 8;
+       sd->bridge = id->driver_info & 0xff;
+       gspca_dev->ctrl_dis = sensor_data[sd->sensor].ctrl_dis;
 
        cam = &gspca_dev->cam;
        cam->epaddr = 0x01;
-       if (!sif) {
+       if (!(sensor_data[sd->sensor].flags & F_SIF)) {
                cam->cam_mode = vga_mode;
                cam->nmodes = ARRAY_SIZE(vga_mode);
        } else {
@@ -790,157 +872,98 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->brightness = BRIGHTNESS_DEF;
        sd->gain = GAIN_DEF;
        sd->exposure = EXPOSURE_DEF;
-       sd->autogain = AUTOGAIN_DEF;
+       if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX))
+               sd->autogain = 0; /* Disable do_autogain callback */
+       else
+               sd->autogain = AUTOGAIN_DEF;
        sd->freq = FREQ_DEF;
 
        return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
-       reg_r(gspca_dev, 0x00);
-       if (gspca_dev->usb_buf[0] != 0x10)
-               return -ENODEV;
-       return 0;
-}
+       const __u8 stop = 0x09; /* Disable stream turn of LED */
 
-static void pas106_i2cinit(struct gspca_dev *gspca_dev)
-{
-       int i;
-       const __u8 *data;
-       __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
-
-       i = ARRAY_SIZE(pas106_data);
-       data = pas106_data[0];
-       while (--i >= 0) {
-               memcpy(&i2c1[2], data, 2);
-                                       /* copy 2 bytes from the template */
-               if (i2c_w(gspca_dev, i2c1) < 0)
-                       PDEBUG(D_ERR, "i2c error pas106");
-               data += 2;
-       }
+       reg_w(gspca_dev, 0x01, &stop, 1);
+
+       return 0;
 }
 
 /* -- start the camera -- */
 static void sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int mode, l = 0x1f;
+       struct cam *cam = &gspca_dev->cam;
+       int mode, l;
        const __u8 *sn9c10x;
-       __u8 reg17_19[3];
-
-       mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+       __u8 reg12_19[8];
+
+       mode = cam->cam_mode[gspca_dev->curr_mode].priv & 0x07;
+       sn9c10x = sensor_data[sd->sensor].bridge_init[sd->bridge];
+       l = sensor_data[sd->sensor].bridge_init_size[sd->bridge];
+       memcpy(reg12_19, &sn9c10x[0x12 - 1], 8);
+       reg12_19[6] = sn9c10x[0x18 - 1] | (mode << 4);
+       /* Special cases where reg 17 and or 19 value depends on mode */
        switch (sd->sensor) {
-       case SENSOR_HV7131R:
-               sn9c10x = initHv7131;
-               reg17_19[0] = 0x60;
-               reg17_19[1] = (mode << 4) | 0x8a;
-               reg17_19[2] = 0x20;
-               break;
-       case SENSOR_OV6650:
-               sn9c10x = initOv6650;
-               reg17_19[0] = 0x68;
-               reg17_19[1] = (mode << 4) | 0x8b;
-               reg17_19[2] = 0x20;
-               break;
-       case SENSOR_OV7630:
-               if (sd->fr_h_sz == 18) { /* SN9C103 */
-                       sn9c10x = initOv7630_3;
-                       l = sizeof initOv7630_3;
-               } else
-                       sn9c10x = initOv7630;
-               reg17_19[0] = 0x68;
-               reg17_19[1] = (mode << 4) | COMP2;
-               reg17_19[2] = MCK_INIT1;
-               break;
-       case SENSOR_PAS106:
-               sn9c10x = initPas106;
-               reg17_19[0] = 0x24;             /* 0x28 */
-               reg17_19[1] = (mode << 4) | COMP1;
-               reg17_19[2] = MCK_INIT1;
-               break;
        case SENSOR_PAS202:
-               sn9c10x = initPas202;
-               reg17_19[0] = mode ? 0x24 : 0x20;
-               reg17_19[1] = (mode << 4) | 0x89;
-               reg17_19[2] = 0x20;
+               reg12_19[5] = mode ? 0x24 : 0x20;
                break;
-       case SENSOR_TAS5110:
-               sn9c10x = initTas5110;
-               reg17_19[0] = 0x60;
-               reg17_19[1] = (mode << 4) | 0x86;
-               reg17_19[2] = 0x2b;             /* 0xf3; */
-               break;
-       default:
-/*     case SENSOR_TAS5130CXX: */
-               sn9c10x = initTas5130;
-               reg17_19[0] = 0x60;
-               reg17_19[1] = (mode << 4) | COMP;
-               reg17_19[2] = mode ? 0x23 : 0x43;
+       case SENSOR_TAS5130CXX:
+               /* probably not mode specific at all most likely the upper
+                  nibble of 0x19 is exposure (clock divider) just as with
+                  the tas5110, we need someone to test this. */
+               reg12_19[7] = mode ? 0x23 : 0x43;
                break;
        }
+       /* Disable compression when the raw bayer format has been selected */
+       if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW)
+               reg12_19[6] &= ~0x80;
+
+       /* Vga mode emulation on SIF sensor? */
+       if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_REDUCED_SIF) {
+               reg12_19[0] += 16; /* 0x12: hstart adjust */
+               reg12_19[1] += 24; /* 0x13: vstart adjust */
+               reg12_19[3] = 320 / 16; /* 0x15: hsize */
+               reg12_19[4] = 240 / 16; /* 0x16: vsize */
+       }
 
        /* reg 0x01 bit 2 video transfert on */
        reg_w(gspca_dev, 0x01, &sn9c10x[0x01 - 1], 1);
        /* reg 0x17 SensorClk enable inv Clk 0x60 */
        reg_w(gspca_dev, 0x17, &sn9c10x[0x17 - 1], 1);
        /* Set the registers from the template */
-       reg_w_big(gspca_dev, 0x01, sn9c10x, l);
-       switch (sd->sensor) {
-       case SENSOR_HV7131R:
-               i2c_w_vector(gspca_dev, hv7131_sensor_init,
-                               sizeof hv7131_sensor_init);
-               break;
-       case SENSOR_OV6650:
-               i2c_w_vector(gspca_dev, ov6650_sensor_init,
-                               sizeof ov6650_sensor_init);
-               break;
-       case SENSOR_OV7630:
-               i2c_w_vector(gspca_dev, ov7630_sensor_init,
-                               sizeof ov7630_sensor_init);
-               if (sd->fr_h_sz == 18) { /* SN9C103 */
-                       const __u8 i2c[] = { 0xa0, 0x21, 0x13, 0x80, 0x00,
-                                               0x00, 0x00, 0x10 };
-                       i2c_w(gspca_dev, i2c);
-               }
-               break;
-       case SENSOR_PAS106:
-               pas106_i2cinit(gspca_dev);
-               break;
-       case SENSOR_PAS202:
-               i2c_w_vector(gspca_dev, pas202_sensor_init,
-                               sizeof pas202_sensor_init);
-               break;
-       case SENSOR_TAS5110:
-               i2c_w_vector(gspca_dev, tas5110_sensor_init,
-                               sizeof tas5110_sensor_init);
-               break;
-       default:
-/*     case SENSOR_TAS5130CXX: */
-               i2c_w_vector(gspca_dev, tas5130_sensor_init,
-                               sizeof tas5130_sensor_init);
-               break;
-       }
+       reg_w(gspca_dev, 0x01, sn9c10x, l);
+
+       /* Init the sensor */
+       i2c_w_vector(gspca_dev, sensor_data[sd->sensor].sensor_init,
+                       sensor_data[sd->sensor].sensor_init_size);
+       if (sensor_data[sd->sensor].sensor_bridge_init[sd->bridge])
+               i2c_w_vector(gspca_dev,
+                       sensor_data[sd->sensor].sensor_bridge_init[sd->bridge],
+                       sensor_data[sd->sensor].sensor_bridge_init_size[
+                               sd->bridge]);
+
        /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
-       reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
+       reg_w(gspca_dev, 0x15, &reg12_19[3], 2);
        /* compression register */
-       reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
+       reg_w(gspca_dev, 0x18, &reg12_19[6], 1);
        /* H_start */
-       reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
+       reg_w(gspca_dev, 0x12, &reg12_19[0], 1);
        /* V_START */
-       reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
+       reg_w(gspca_dev, 0x13, &reg12_19[1], 1);
        /* reset 0x17 SensorClk enable inv Clk 0x60 */
                                /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
-       reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
+       reg_w(gspca_dev, 0x17, &reg12_19[5], 1);
        /*MCKSIZE ->3 */        /*fixme: not ov7630*/
-       reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
+       reg_w(gspca_dev, 0x19, &reg12_19[7], 1);
        /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
        reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
        /* Enable video transfert */
        reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
        /* Compression */
-       reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
+       reg_w(gspca_dev, 0x18, &reg12_19[6], 2);
        msleep(20);
 
        sd->reg11 = -1;
@@ -957,18 +980,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
-       __u8 ByteSend;
-
-       ByteSend = 0x09;        /* 0X00 */
-       reg_w(gspca_dev, 0x01, &ByteSend, 1);
-}
-
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
+       sd_init(gspca_dev);
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
@@ -978,6 +990,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 {
        int i;
        struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam = &gspca_dev->cam;
 
        /* frames start with:
         *      ff ff 00 c4 c4 96       synchro
@@ -998,20 +1011,31 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                            && data[5 + i] == 0x96) {   /* start of frame */
                                int lum = -1;
                                int pkt_type = LAST_PACKET;
+                               int fr_h_sz = (sd->bridge == BRIDGE_103) ?
+                                       18 : 12;
 
-                               if (len - i < sd->fr_h_sz) {
+                               if (len - i < fr_h_sz) {
                                        PDEBUG(D_STREAM, "packet too short to"
                                                " get avg brightness");
-                               } else if (sd->fr_h_sz == 12) {
-                                       lum = data[i + 8] + (data[i + 9] << 8);
-                               } else {
+                               } else if (sd->bridge == BRIDGE_103) {
                                        lum = data[i + 9] +
                                                (data[i + 10] << 8);
+                               } else {
+                                       lum = data[i + 8] + (data[i + 9] << 8);
                                }
-                               if (lum == 0) {
+                               /* When exposure changes midway a frame we
+                                  get a lum of 0 in this case drop 2 frames
+                                  as the frames directly after an exposure
+                                  change have an unstable image. Sometimes lum
+                                  *really* is 0 (cam used in low light with
+                                  low exposure setting), so do not drop frames
+                                  if the previous lum was 0 too. */
+                               if (lum == 0 && sd->prev_avg_lum != 0) {
                                        lum = -1;
                                        sd->frames_to_drop = 2;
-                               }
+                                       sd->prev_avg_lum = 0;
+                               } else
+                                       sd->prev_avg_lum = lum;
                                atomic_set(&sd->avg_lum, lum);
 
                                if (sd->frames_to_drop) {
@@ -1021,14 +1045,25 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 
                                frame = gspca_frame_add(gspca_dev, pkt_type,
                                                        frame, data, 0);
-                               data += i + sd->fr_h_sz;
-                               len -= i + sd->fr_h_sz;
+                               data += i + fr_h_sz;
+                               len -= i + fr_h_sz;
                                gspca_frame_add(gspca_dev, FIRST_PACKET,
                                                frame, data, len);
                                return;
                        }
                }
        }
+
+       if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) {
+               /* In raw mode we sometimes get some garbage after the frame
+                  ignore this */
+               int used = frame->data_end - frame->data;
+               int size = cam->cam_mode[gspca_dev->curr_mode].sizeimage;
+
+               if (used + len > size)
+                       len = size - used;
+       }
+
        gspca_frame_add(gspca_dev, INTER_PACKET,
                        frame, data, len);
 }
@@ -1162,58 +1197,45 @@ static const struct sd_desc sd_desc = {
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
-       .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
        .querymenu = sd_querymenu,
+       .dq_callback = do_autogain,
 };
 
 /* -- module initialisation -- */
-#define SFCI(sensor, flags, nctrls, i2c_addr) \
-       .driver_info = (SENSOR_ ## sensor << 24) \
-                       | ((flags) << 16) \
-                       | ((nctrls) << 8) \
-                       | (i2c_addr)
+#define SB(sensor, bridge) \
+       .driver_info = (SENSOR_ ## sensor << 8) | BRIDGE_ ## bridge
+
+
 static __devinitdata struct usb_device_id device_table[] = {
-#ifndef CONFIG_USB_SN9C102
-       {USB_DEVICE(0x0c45, 0x6001),                    /* SN9C102 */
-                       SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)},
-       {USB_DEVICE(0x0c45, 0x6005),                    /* SN9C101 */
-                       SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)},
-       {USB_DEVICE(0x0c45, 0x6007),                    /* SN9C101 */
-                       SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)},
-       {USB_DEVICE(0x0c45, 0x6009),                    /* SN9C101 */
-                       SFCI(PAS106, F_SIF, 2, 0)},
-       {USB_DEVICE(0x0c45, 0x600d),                    /* SN9C101 */
-                       SFCI(PAS106, F_SIF, 2, 0)},
+       {USB_DEVICE(0x0c45, 0x6001), SB(TAS5110, 102)}, /* TAS5110C1B */
+       {USB_DEVICE(0x0c45, 0x6005), SB(TAS5110, 101)}, /* TAS5110C1B */
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+       {USB_DEVICE(0x0c45, 0x6007), SB(TAS5110, 101)}, /* TAS5110D */
+       {USB_DEVICE(0x0c45, 0x6009), SB(PAS106, 101)},
+       {USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)},
 #endif
-       {USB_DEVICE(0x0c45, 0x6011),            /* SN9C101 - SN9C101G */
-                       SFCI(OV6650, F_GAIN|F_AUTO|F_SIF, 5, 0x60)},
-#ifndef CONFIG_USB_SN9C102
-       {USB_DEVICE(0x0c45, 0x6019),                    /* SN9C101 */
-                       SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)},
-       {USB_DEVICE(0x0c45, 0x6024),                    /* SN9C102 */
-                       SFCI(TAS5130CXX, 0, 2, 0)},
-       {USB_DEVICE(0x0c45, 0x6025),                    /* SN9C102 */
-                       SFCI(TAS5130CXX, 0, 2, 0)},
-       {USB_DEVICE(0x0c45, 0x6028),                    /* SN9C102 */
-                       SFCI(PAS202, 0, 2, 0)},
-       {USB_DEVICE(0x0c45, 0x6029),                    /* SN9C101 */
-                       SFCI(PAS106, F_SIF, 2, 0)},
-       {USB_DEVICE(0x0c45, 0x602c),                    /* SN9C102 */
-                       SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)},
-       {USB_DEVICE(0x0c45, 0x602d),                    /* SN9C102 */
-                       SFCI(HV7131R, 0, 2, 0)},
-       {USB_DEVICE(0x0c45, 0x602e),                    /* SN9C102 */
-                       SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)},
-       {USB_DEVICE(0x0c45, 0x60af),                    /* SN9C103 */
-                       SFCI(PAS202, F_H18, 2, 0)},
-       {USB_DEVICE(0x0c45, 0x60b0),                    /* SN9C103 */
-                       SFCI(OV7630, F_GAIN|F_AUTO|F_H18, 5, 0x21)},
+       {USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)},
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+       {USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)},
+       {USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)},
+       {USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)},
+       {USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)},
+       {USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)},
+       {USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)},
 #endif
+       {USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)},
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+       {USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)},
+#endif
+       {USB_DEVICE(0x0c45, 0x608f), SB(OV7630, 103)},
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+       {USB_DEVICE(0x0c45, 0x60af), SB(PAS202, 103)},
+#endif
+       {USB_DEVICE(0x0c45, 0x60b0), SB(OV7630, 103)},
        {}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
@@ -1231,6 +1253,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
index 245a30e..d75b1d2 100644 (file)
@@ -54,8 +54,10 @@ struct sd {
 #define SENSOR_HV7131R 0
 #define SENSOR_MI0360 1
 #define SENSOR_MO4000 2
-#define SENSOR_OV7648 3
-#define SENSOR_OV7660 4
+#define SENSOR_OM6802 3
+#define SENSOR_OV7630 4
+#define SENSOR_OV7648 5
+#define SENSOR_OV7660 6
        unsigned char i2c_base;
 };
 
@@ -76,7 +78,8 @@ static struct ctrl sd_ctrls[] = {
                .type    = V4L2_CTRL_TYPE_INTEGER,
                .name    = "Brightness",
                .minimum = 0,
-               .maximum = 0xffff,
+#define BRIGHTNESS_MAX 0xffff
+               .maximum = BRIGHTNESS_MAX,
                .step    = 1,
 #define BRIGHTNESS_DEF 0x7fff
                .default_value = BRIGHTNESS_DEF,
@@ -90,7 +93,8 @@ static struct ctrl sd_ctrls[] = {
                .type    = V4L2_CTRL_TYPE_INTEGER,
                .name    = "Contrast",
                .minimum = 0,
-               .maximum = 127,
+#define CONTRAST_MAX 127
+               .maximum = CONTRAST_MAX,
                .step    = 1,
 #define CONTRAST_DEF 63
                .default_value = CONTRAST_DEF,
@@ -104,14 +108,15 @@ static struct ctrl sd_ctrls[] = {
                .type    = V4L2_CTRL_TYPE_INTEGER,
                .name    = "Color",
                .minimum = 0,
-               .maximum = 255,
+               .maximum = 64,
                .step    = 1,
-#define COLOR_DEF 127
+#define COLOR_DEF 32
                .default_value = COLOR_DEF,
            },
            .set = sd_setcolors,
            .get = sd_getcolors,
        },
+#define AUTOGAIN_IDX 3
        {
            {
                .id      = V4L2_CID_AUTOGAIN,
@@ -131,7 +136,7 @@ static struct ctrl sd_ctrls[] = {
 static struct v4l2_pix_format vga_mode[] = {
        {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 160,
-               .sizeimage = 160 * 120 * 3 / 8 + 590,
+               .sizeimage = 160 * 120 * 4 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 2},
        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
@@ -180,6 +185,31 @@ static const __u8 sn_mo4000[] = {
        0x08,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00
 };
 
+static const __u8 sn_om6802[] = {
+/*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
+       0x00,   0x23,   0x72,   0x00,   0x1a,   0x34,   0x27,   0x20,
+/*     reg8    reg9    rega    regb    regc    regd    rege    regf */
+       0x80,   0x34,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,
+/*     reg10   reg11   reg12   reg13   reg14   reg15   reg16   reg17 */
+       0x03,   0x00,   0x51,   0x01,   0x00,   0x28,   0x1e,   0x40,
+/*     reg18   reg19   reg1a   reg1b   reg1c   reg1d   reg1e   reg1f */
+       0x05,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,
+       0x08,   0x22,   0x44,   0x63,   0x7d,   0x92,   0xa3,   0xaf,
+       0xbc,   0xc4,   0xcd,   0xd5,   0xdc,   0xe1,   0xe8,   0xef,
+       0xf7
+};
+
+static const __u8 sn_ov7630[] = {
+/*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
+       0x00,   0x21,   0x40,   0x00,   0x1a,   0x20,   0x1f,   0x20,
+/*     reg8    reg9    rega    regb    regc    regd    rege    regf */
+       0xa1,   0x21,   0x76,   0x21,   0x00,   0x00,   0x00,   0x10,
+/*     reg10   reg11   reg12   reg13   reg14   reg15   reg16   reg17 */
+       0x03,   0x00,   0x04,   0x01,   0x0a,   0x28,   0x1e,   0xc2,
+/*     reg18   reg19   reg1a   reg1b   reg1c   reg1d   reg1e   reg1f */
+       0x0b,   0x00,   0x00,   0x00,   0x00,   0x00
+};
+
 static const __u8 sn_ov7648[] = {
 /*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
        0x00,   0x21,   0x62,   0x00,   0x1a,   0x20,   0x20,   0x20,
@@ -207,31 +237,22 @@ static const __u8 *sn_tb[] = {
        sn_hv7131,
        sn_mi0360,
        sn_mo4000,
+       sn_om6802,
+       sn_ov7630,
        sn_ov7648,
        sn_ov7660
 };
 
-static const __u8 regsn20[] = {
+static const __u8 gamma_def[] = {
        0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99,
        0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
 };
-static const __u8 regsn20_sn9c325[] = {
-       0x0a, 0x3a, 0x56, 0x6c, 0x7e, 0x8d, 0x9a, 0xa4,
-       0xaf, 0xbb, 0xc5, 0xcd, 0xd5, 0xde, 0xe8, 0xed, 0xf5
-};
 
 static const __u8 reg84[] = {
        0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe5, 0x0f,
        0xe4, 0x0f, 0x38, 0x00, 0x3e, 0x00, 0xc3, 0x0f,
-/*     0x00, 0x00, 0x00, 0x00, 0x00 */
-       0xf7, 0x0f, 0x0a, 0x00, 0x00
-};
-static const __u8 reg84_sn9c325[] = {
-       0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe4, 0x0f,
-       0xd3, 0x0f, 0x4b, 0x00, 0x48, 0x00, 0xc0, 0x0f,
-       0xf8, 0x0f, 0x00, 0x00, 0x00
+       0xf7, 0x0f, 0x00, 0x00, 0x00
 };
-
 static const __u8 hv7131r_sensor_init[][8] = {
        {0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
        {0xB1, 0x11, 0x34, 0x17, 0x7F, 0x00, 0x00, 0x10},
@@ -340,6 +361,92 @@ static const __u8 mo4000_sensor_init[][8] = {
        {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
        {}
 };
+static __u8 om6802_sensor_init[][8] = {
+       {0xa0, 0x34, 0x90, 0x05, 0x00, 0x00, 0x00, 0x10},
+       {0xa0, 0x34, 0x49, 0x85, 0x00, 0x00, 0x00, 0x10},
+       {0xa0, 0x34, 0x5a, 0xc0, 0x00, 0x00, 0x00, 0x10},
+       {0xa0, 0x34, 0xdd, 0x18, 0x00, 0x00, 0x00, 0x10},
+/*     {0xa0, 0x34, 0xfb, 0x11, 0x00, 0x00, 0x00, 0x10}, */
+       {0xa0, 0x34, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x10},
+                                       /* white balance & auto-exposure */
+/*     {0xa0, 0x34, 0xf1, 0x02, 0x00, 0x00, 0x00, 0x10},
+                                                        * set color mode */
+/*     {0xa0, 0x34, 0xfe, 0x5b, 0x00, 0x00, 0x00, 0x10},
+                                                * max AGC value in AE */
+/*     {0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10},
+                                                        * preset AGC */
+/*     {0xa0, 0x34, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x10},
+                                                * preset brightness */
+/*     {0xa0, 0x34, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x10},
+                                                        * preset contrast */
+/*     {0xa0, 0x34, 0xe8, 0x31, 0x00, 0x00, 0x00, 0x10},
+                                                        * preset gamma */
+       {0xa0, 0x34, 0xe9, 0x0f, 0x00, 0x00, 0x00, 0x10},
+                                       /* luminance mode (0x4f = AE) */
+       {0xa0, 0x34, 0xe4, 0xff, 0x00, 0x00, 0x00, 0x10},
+                                                       /* preset shutter */
+/*     {0xa0, 0x34, 0xef, 0x00, 0x00, 0x00, 0x00, 0x10},
+                                                        * auto frame rate */
+/*     {0xa0, 0x34, 0xfb, 0xee, 0x00, 0x00, 0x00, 0x10}, */
+
+/*     {0xa0, 0x34, 0x71, 0x84, 0x00, 0x00, 0x00, 0x10}, */
+/*     {0xa0, 0x34, 0x72, 0x05, 0x00, 0x00, 0x00, 0x10}, */
+/*     {0xa0, 0x34, 0x68, 0x80, 0x00, 0x00, 0x00, 0x10}, */
+/*     {0xa0, 0x34, 0x69, 0x01, 0x00, 0x00, 0x00, 0x10}, */
+       {}
+};
+static const __u8 ov7630_sensor_init[][8] = {
+       {0xa1, 0x21, 0x76, 0x01, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10},
+/* win: delay 20ms */
+       {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10},
+/* win: delay 20ms */
+       {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
+/* win: i2c_r from 00 to 80 */
+       {0xd1, 0x21, 0x03, 0x80, 0x10, 0x20, 0x80, 0x10},
+       {0xb1, 0x21, 0x0c, 0x20, 0x20, 0x00, 0x00, 0x10},
+       {0xd1, 0x21, 0x11, 0x00, 0x48, 0xc0, 0x00, 0x10},
+       {0xb1, 0x21, 0x15, 0x80, 0x03, 0x00, 0x00, 0x10},
+       {0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10},
+       {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x21, 0x1f, 0x00, 0x80, 0x80, 0x80, 0x10},
+       {0xd1, 0x21, 0x23, 0xde, 0x10, 0x8a, 0xa0, 0x10},
+       {0xc1, 0x21, 0x27, 0xca, 0xa2, 0x74, 0x00, 0x10},
+       {0xd1, 0x21, 0x2a, 0x88, 0x00, 0x88, 0x01, 0x10},
+       {0xc1, 0x21, 0x2e, 0x80, 0x00, 0x18, 0x00, 0x10},
+       {0xa1, 0x21, 0x21, 0x08, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xb1, 0x21, 0x32, 0xc2, 0x08, 0x00, 0x00, 0x10},
+       {0xb1, 0x21, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x21, 0x60, 0x05, 0x40, 0x12, 0x57, 0x10},
+       {0xa1, 0x21, 0x64, 0x73, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x21, 0x65, 0x00, 0x55, 0x01, 0xac, 0x10},
+       {0xa1, 0x21, 0x69, 0x38, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x21, 0x6f, 0x1f, 0x01, 0x00, 0x10, 0x10},
+       {0xd1, 0x21, 0x73, 0x50, 0x20, 0x02, 0x01, 0x10},
+       {0xd1, 0x21, 0x77, 0xf3, 0x90, 0x98, 0x98, 0x10},
+       {0xc1, 0x21, 0x7b, 0x00, 0x4c, 0xf7, 0x00, 0x10},
+       {0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10},
+       {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10},
+/* */
+       {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
+/*fixme: + 0x12, 0x04*/
+       {0xa1, 0x21, 0x75, 0x82, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xb1, 0x21, 0x01, 0x80, 0x80, 0x00, 0x00, 0x10},
+/* */
+       {0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x2a, 0x88, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x2b, 0x34, 0x00, 0x00, 0x00, 0x10},
+/* */
+       {0xa1, 0x21, 0x10, 0x83, 0x00, 0x00, 0x00, 0x10},
+/*     {0xb1, 0x21, 0x01, 0x88, 0x70, 0x00, 0x00, 0x10}, */
+       {}
+};
 static const __u8 ov7660_sensor_init[][8] = {
        {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
 /*             (delay 20ms) */
@@ -506,10 +613,16 @@ static const __u8 qtable4[] = {
        0x29, 0x29, 0x29, 0x29
 };
 
-/* read <len> bytes (len < sizeof gspca_dev->usb_buf) to gspca_dev->usb_buf */
+/* read <len> bytes to gspca_dev->usb_buf */
 static void reg_r(struct gspca_dev *gspca_dev,
                  __u16 value, int len)
 {
+#ifdef GSPCA_DEBUG
+       if (len > USB_BUF_SZ) {
+               err("reg_r: buffer overflow");
+               return;
+       }
+#endif
        usb_control_msg(gspca_dev->dev,
                        usb_rcvctrlpipe(gspca_dev->dev, 0),
                        0,
@@ -542,29 +655,20 @@ static void reg_w(struct gspca_dev *gspca_dev,
 {
        PDEBUG(D_USBO, "reg_w [%02x] = %02x %02x ..",
                value, buffer[0], buffer[1]);
-       if (len <= sizeof gspca_dev->usb_buf) {
-               memcpy(gspca_dev->usb_buf, buffer, len);
-               usb_control_msg(gspca_dev->dev,
-                               usb_sndctrlpipe(gspca_dev->dev, 0),
-                               0x08,
-                          USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
-                               value, 0,
-                               gspca_dev->usb_buf, len,
-                               500);
-       } else {
-               __u8 *tmpbuf;
-
-               tmpbuf = kmalloc(len, GFP_KERNEL);
-               memcpy(tmpbuf, buffer, len);
-               usb_control_msg(gspca_dev->dev,
-                               usb_sndctrlpipe(gspca_dev->dev, 0),
-                               0x08,
-                          USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
-                               value, 0,
-                               tmpbuf, len,
-                               500);
-               kfree(tmpbuf);
+#ifdef GSPCA_DEBUG
+       if (len > USB_BUF_SZ) {
+               err("reg_w: buffer overflow");
+               return;
        }
+#endif
+       memcpy(gspca_dev->usb_buf, buffer, len);
+       usb_control_msg(gspca_dev->dev,
+                       usb_sndctrlpipe(gspca_dev->dev, 0),
+                       0x08,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+                       value, 0,
+                       gspca_dev->usb_buf, len,
+                       500);
 }
 
 /* I2C write 1 byte */
@@ -665,7 +769,7 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
        static const __u8 regd4[] = {0x60, 0x00, 0x00};
 
        reg_w1(gspca_dev, 0xf1, 0x00);
-       reg_w1(gspca_dev, 0x01, 0x00);          /*jfm was sn9c1xx[1] in v1*/
+       reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
 
        /* configure gpio */
        reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2);
@@ -685,21 +789,41 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
 
        reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
 
-       switch (sd->bridge) {
-       case BRIDGE_SN9C325:
+       switch (sd->sensor) {
+       case SENSOR_OM6802:
+               reg_w1(gspca_dev, 0x02, 0x71);
+               reg_w1(gspca_dev, 0x01, 0x42);
+               reg_w1(gspca_dev, 0x17, 0x64);
+               reg_w1(gspca_dev, 0x01, 0x42);
+               break;
+/*jfm: from win trace */
+       case SENSOR_OV7630:
+               reg_w1(gspca_dev, 0x01, 0x61);
+               reg_w1(gspca_dev, 0x17, 0xe2);
+               reg_w1(gspca_dev, 0x01, 0x60);
+               reg_w1(gspca_dev, 0x01, 0x40);
+               break;
+       case SENSOR_OV7648:
                reg_w1(gspca_dev, 0x01, 0x43);
                reg_w1(gspca_dev, 0x17, 0xae);
                reg_w1(gspca_dev, 0x01, 0x42);
                break;
+/*jfm: from win trace */
+       case SENSOR_OV7660:
+               reg_w1(gspca_dev, 0x01, 0x61);
+               reg_w1(gspca_dev, 0x17, 0x20);
+               reg_w1(gspca_dev, 0x01, 0x60);
+               reg_w1(gspca_dev, 0x01, 0x40);
+               break;
        default:
                reg_w1(gspca_dev, 0x01, 0x43);
                reg_w1(gspca_dev, 0x17, 0x61);
                reg_w1(gspca_dev, 0x01, 0x42);
-       }
-
-       if (sd->sensor == SENSOR_HV7131R) {
-               if (probesensor(gspca_dev) < 0)
-                       return -ENODEV;
+               if (sd->sensor == SENSOR_HV7131R) {
+                       if (probesensor(gspca_dev) < 0)
+                               return -ENODEV;
+               }
+               break;
        }
        return 0;
 }
@@ -737,6 +861,40 @@ static void mo4000_InitSensor(struct gspca_dev *gspca_dev)
        }
 }
 
+static void om6802_InitSensor(struct gspca_dev *gspca_dev)
+{
+       int i = 0;
+
+       while (om6802_sensor_init[i][0]) {
+               i2c_w8(gspca_dev, om6802_sensor_init[i]);
+               i++;
+       }
+}
+
+static void ov7630_InitSensor(struct gspca_dev *gspca_dev)
+{
+       int i = 0;
+
+       i2c_w8(gspca_dev, ov7630_sensor_init[i]);       /* 76 01 */
+       i++;
+       i2c_w8(gspca_dev, ov7630_sensor_init[i]);       /* 12 c8 (RGB+SRST) */
+       i++;
+       msleep(20);
+       i2c_w8(gspca_dev, ov7630_sensor_init[i]);       /* 12 48 */
+       i++;
+       i2c_w8(gspca_dev, ov7630_sensor_init[i]);       /* 12 c8 */
+       i++;
+       msleep(20);
+       i2c_w8(gspca_dev, ov7630_sensor_init[i]);       /* 12 48 */
+       i++;
+/*jfm:win i2c_r from 00 to 80*/
+
+       while (ov7630_sensor_init[i][0]) {
+               i2c_w8(gspca_dev, ov7630_sensor_init[i]);
+               i++;
+       }
+}
+
 static void ov7648_InitSensor(struct gspca_dev *gspca_dev)
 {
        int i = 0;
@@ -783,11 +941,19 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->autogain = AUTOGAIN_DEF;
        sd->ag_cnt = -1;
 
+       switch (sd->sensor) {
+       case SENSOR_OV7630:
+       case SENSOR_OV7648:
+       case SENSOR_OV7660:
+               gspca_dev->ctrl_dis = (1 << AUTOGAIN_IDX);
+               break;
+       }
+
        return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 /*     const __u8 *sn9c1xx; */
@@ -891,16 +1057,53 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev,
                        | ((expoMo10[3] & 0x30) >> 4));
                break;
            }
+       case SENSOR_OM6802: {
+               __u8 gainOm[] =
+                       { 0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10 };
+
+               if (expo > 0x03ff)
+                       expo = 0x03ff;
+                if (expo < 0x0001)
+                       expo = 0x0001;
+               gainOm[3] = expo >> 2;
+               i2c_w8(gspca_dev, gainOm);
+               reg_w1(gspca_dev, 0x96, (expo >> 5) & 0x1f);
+               PDEBUG(D_CONF, "set exposure %d", gainOm[3]);
+               break;
+           }
        }
        return expo;
 }
 
+/* this function is used for sensors o76xx only */
+static void setbrightcont(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       unsigned val;
+       __u8 reg84_full[0x15];
+
+       memset(reg84_full, 0, sizeof reg84_full);
+       val = sd->contrast * 0x20 / CONTRAST_MAX + 0x10;        /* 10..30 */
+       reg84_full[2] = val;
+       reg84_full[0] = (val + 1) / 2;
+       reg84_full[4] = (val + 1) / 5;
+       if (val > BRIGHTNESS_DEF)
+               val = (sd->brightness - BRIGHTNESS_DEF) * 0x20
+                       / BRIGHTNESS_MAX;
+       else
+               val = 0;
+       reg84_full[0x12] = val;                 /* 00..1f */
+       reg_w(gspca_dev, 0x84, reg84_full, sizeof reg84_full);
+}
+
+/* sensor != ov76xx */
 static void setbrightness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        unsigned int expo;
        __u8 k2;
 
+       k2 = sd->brightness >> 10;
        switch (sd->sensor) {
        case SENSOR_HV7131R:
                expo = sd->brightness << 4;
@@ -915,12 +1118,17 @@ static void setbrightness(struct gspca_dev *gspca_dev)
                expo = sd->brightness >> 4;
                sd->exposure = setexposure(gspca_dev, expo);
                break;
+       case SENSOR_OM6802:
+               expo = sd->brightness >> 6;
+               sd->exposure = setexposure(gspca_dev, expo);
+               k2 = sd->brightness >> 11;
+               break;
        }
 
-       k2 = sd->brightness >> 10;
        reg_w1(gspca_dev, 0x96, k2);
 }
 
+/* sensor != ov76xx */
 static void setcontrast(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -937,31 +1145,30 @@ static void setcontrast(struct gspca_dev *gspca_dev)
 static void setcolors(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       __u8 data;
-       int colour;
+       __u8 blue, red;
 
-       colour = sd->colors - 128;
-       if (colour > 0)
-               data = (colour + 32) & 0x7f;    /* blue */
-       else
-               data = (-colour + 32) & 0x7f;   /* red */
-       reg_w1(gspca_dev, 0x05, data);
+       if (sd->colors >= 32) {
+               red = 32 + (sd->colors - 32) / 2;
+               blue = 64 - sd->colors;
+       } else {
+               red = sd->colors;
+               blue = 32 + (32 - sd->colors) / 2;
+       }
+       reg_w1(gspca_dev, 0x05, red);
+/*     reg_w1(gspca_dev, 0x07, 32); */
+       reg_w1(gspca_dev, 0x06, blue);
 }
 
 static void setautogain(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       switch (sd->sensor) {
-       case SENSOR_HV7131R:
-       case SENSOR_MO4000:
-       case SENSOR_MI0360:
-               if (sd->autogain)
-                       sd->ag_cnt = AG_CNT_START;
-               else
-                       sd->ag_cnt = -1;
-               break;
-       }
+       if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX))
+               return;
+       if (sd->autogain)
+               sd->ag_cnt = AG_CNT_START;
+       else
+               sd->ag_cnt = -1;
 }
 
 /* -- start the camera -- */
@@ -975,13 +1182,12 @@ static void sd_start(struct gspca_dev *gspca_dev)
        static const __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
        static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
        static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd };    /* MI0360 */
-       static const __u8 CE_sn9c325[] =
-                       { 0x32, 0xdd, 0x32, 0xdd };     /* OV7648 - SN9C325 */
+       static const __u8 CE_ov76xx[] =
+                       { 0x32, 0xdd, 0x32, 0xdd };     /* OV7630/48 */
 
        sn9c1xx = sn_tb[(int) sd->sensor];
        configure_gpio(gspca_dev, sn9c1xx);
 
-/*     reg_w1(gspca_dev, 0x01, 0x44);          jfm from win trace*/
        reg_w1(gspca_dev, 0x15, sn9c1xx[0x15]);
        reg_w1(gspca_dev, 0x16, sn9c1xx[0x16]);
        reg_w1(gspca_dev, 0x12, sn9c1xx[0x12]);
@@ -994,10 +1200,17 @@ static void sd_start(struct gspca_dev *gspca_dev)
        reg_w1(gspca_dev, 0xc8, 0x50);
        reg_w1(gspca_dev, 0xc9, 0x3c);
        reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]);
-       switch (sd->bridge) {
-       case BRIDGE_SN9C325:
+       switch (sd->sensor) {
+       case SENSOR_OV7630:
+               reg17 = 0xe2;
+               break;
+       case SENSOR_OV7648:
                reg17 = 0xae;
                break;
+/*jfm: from win trace */
+       case SENSOR_OV7660:
+               reg17 = 0xa0;
+               break;
        default:
                reg17 = 0x60;
                break;
@@ -1007,24 +1220,11 @@ static void sd_start(struct gspca_dev *gspca_dev)
        reg_w1(gspca_dev, 0x07, sn9c1xx[7]);
        reg_w1(gspca_dev, 0x06, sn9c1xx[6]);
        reg_w1(gspca_dev, 0x14, sn9c1xx[0x14]);
-       switch (sd->bridge) {
-       case BRIDGE_SN9C325:
-               reg_w(gspca_dev, 0x20, regsn20_sn9c325,
-                               sizeof regsn20_sn9c325);
-               for (i = 0; i < 8; i++)
-                       reg_w(gspca_dev, 0x84, reg84_sn9c325,
-                                       sizeof reg84_sn9c325);
-               reg_w1(gspca_dev, 0x9a, 0x0a);
-               reg_w1(gspca_dev, 0x99, 0x60);
-               break;
-       default:
-               reg_w(gspca_dev, 0x20, regsn20, sizeof regsn20);
-               for (i = 0; i < 8; i++)
-                       reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
+       reg_w(gspca_dev, 0x20, gamma_def, sizeof gamma_def);
+       for (i = 0; i < 8; i++)
+               reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
                reg_w1(gspca_dev, 0x9a, 0x08);
                reg_w1(gspca_dev, 0x99, 0x59);
-               break;
-       }
 
        mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
        if (mode)
@@ -1049,6 +1249,15 @@ static void sd_start(struct gspca_dev *gspca_dev)
 /*                     reg1 = 0x06;     * 640 clk 24Mz (done) */
                }
                break;
+       case SENSOR_OM6802:
+               om6802_InitSensor(gspca_dev);
+               reg17 = 0x64;           /* 640 MCKSIZE */
+               break;
+       case SENSOR_OV7630:
+               ov7630_InitSensor(gspca_dev);
+               reg17 = 0xe2;
+               reg1 = 0x44;
+               break;
        case SENSOR_OV7648:
                ov7648_InitSensor(gspca_dev);
                reg17 = 0xa2;
@@ -1073,9 +1282,10 @@ static void sd_start(struct gspca_dev *gspca_dev)
        }
        reg_w(gspca_dev, 0xc0, C0, 6);
        reg_w(gspca_dev, 0xca, CA, 4);
-       switch (sd->bridge) {
-       case BRIDGE_SN9C325:
-               reg_w(gspca_dev, 0xce, CE_sn9c325, 4);
+       switch (sd->sensor) {
+       case SENSOR_OV7630:
+       case SENSOR_OV7648:
+               reg_w(gspca_dev, 0xce, CE_ov76xx, 4);
                break;
        default:
                reg_w(gspca_dev, 0xce, CE, 4);
@@ -1093,10 +1303,20 @@ static void sd_start(struct gspca_dev *gspca_dev)
        reg_w1(gspca_dev, 0x18, reg18);
 
        reg_w1(gspca_dev, 0x17, reg17);
-       reg_w1(gspca_dev, 0x01, reg1);
-       setbrightness(gspca_dev);
-       setcontrast(gspca_dev);
+       switch (sd->sensor) {
+       case SENSOR_HV7131R:
+       case SENSOR_MI0360:
+       case SENSOR_MO4000:
+       case SENSOR_OM6802:
+               setbrightness(gspca_dev);
+               setcontrast(gspca_dev);
+               break;
+       default:                        /* OV76xx */
+               setbrightcont(gspca_dev);
+               break;
+       }
        setautogain(gspca_dev);
+       reg_w1(gspca_dev, 0x01, reg1);
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -1119,6 +1339,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
                i2c_w8(gspca_dev, stopmi0360);
                data = 0x29;
                break;
+       case SENSOR_OV7630:
        case SENSOR_OV7648:
                data = 0x29;
                break;
@@ -1132,15 +1353,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        reg_w1(gspca_dev, 0x17, sn9c1xx[0x17]);
        reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
        reg_w1(gspca_dev, 0x01, data);
-       reg_w1(gspca_dev, 0xf1, 0x01);
-}
-
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
+       reg_w1(gspca_dev, 0xf1, 0x00);
 }
 
 static void do_autogain(struct gspca_dev *gspca_dev)
@@ -1174,6 +1387,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
                default:
 /*             case SENSOR_MO4000: */
 /*             case SENSOR_MI0360: */
+/*             case SENSOR_OM6802: */
                        expotimes = sd->exposure;
                        expotimes += (luma_mean - delta) >> 6;
                        if (expotimes < 0)
@@ -1229,69 +1443,24 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
-static unsigned int getexposure(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       __u8 hexpo, mexpo, lexpo;
-
-       switch (sd->sensor) {
-       case SENSOR_HV7131R:
-               /* read sensor exposure */
-               i2c_r5(gspca_dev, 0x25);
-               return (gspca_dev->usb_buf[0] << 16)
-                       | (gspca_dev->usb_buf[1] << 8)
-                       | gspca_dev->usb_buf[2];
-       case SENSOR_MI0360:
-               /* read sensor exposure */
-               i2c_r5(gspca_dev, 0x09);
-               return (gspca_dev->usb_buf[0] << 8)
-                       | gspca_dev->usb_buf[1];
-       case SENSOR_MO4000:
-               i2c_r5(gspca_dev, 0x0e);
-               hexpo = 0;              /* gspca_dev->usb_buf[1] & 0x07; */
-               mexpo = 0x40;           /* gspca_dev->usb_buf[2] & 0xff; */
-               lexpo = (gspca_dev->usb_buf[1] & 0x30) >> 4;
-               PDEBUG(D_CONF, "exposure %d",
-                       (hexpo << 10) | (mexpo << 2) | lexpo);
-               return (hexpo << 10) | (mexpo << 2) | lexpo;
-       default:
-/*     case SENSOR_OV7648:             * jfm: is it ok for 7648? */
-/*     case SENSOR_OV7660: */
-               /* read sensor exposure */
-               i2c_r5(gspca_dev, 0x04);
-               hexpo = gspca_dev->usb_buf[3] & 0x2f;
-               lexpo = gspca_dev->usb_buf[0] & 0x02;
-               i2c_r5(gspca_dev, 0x08);
-               mexpo = gspca_dev->usb_buf[2];
-               return (hexpo << 10) | (mexpo << 2) | lexpo;
-       }
-}
-
-static void getbrightness(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       /* hardcoded registers seem not readable */
-       switch (sd->sensor) {
-       case SENSOR_HV7131R:
-               sd->brightness = getexposure(gspca_dev) >> 4;
-               break;
-       case SENSOR_MI0360:
-               sd->brightness = getexposure(gspca_dev) << 4;
-               break;
-       case SENSOR_MO4000:
-               sd->brightness = getexposure(gspca_dev) << 4;
-               break;
-       }
-}
-
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
        sd->brightness = val;
-       if (gspca_dev->streaming)
-               setbrightness(gspca_dev);
+       if (gspca_dev->streaming) {
+               switch (sd->sensor) {
+               case SENSOR_HV7131R:
+               case SENSOR_MI0360:
+               case SENSOR_MO4000:
+               case SENSOR_OM6802:
+                       setbrightness(gspca_dev);
+                       break;
+               default:                        /* OV76xx */
+                       setbrightcont(gspca_dev);
+                       break;
+               }
+       }
        return 0;
 }
 
@@ -1299,7 +1468,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getbrightness(gspca_dev);
        *val = sd->brightness;
        return 0;
 }
@@ -1309,8 +1477,19 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        sd->contrast = val;
-       if (gspca_dev->streaming)
-               setcontrast(gspca_dev);
+       if (gspca_dev->streaming) {
+               switch (sd->sensor) {
+               case SENSOR_HV7131R:
+               case SENSOR_MI0360:
+               case SENSOR_MO4000:
+               case SENSOR_OM6802:
+                       setcontrast(gspca_dev);
+                       break;
+               default:                        /* OV76xx */
+                       setbrightcont(gspca_dev);
+                       break;
+               }
+       }
        return 0;
 }
 
@@ -1364,11 +1543,9 @@ static const struct sd_desc sd_desc = {
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
-       .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
        .dq_callback = do_autogain,
 };
@@ -1379,7 +1556,7 @@ static const struct sd_desc sd_desc = {
                        | (SENSOR_ ## sensor << 8) \
                        | (i2c_addr)
 static const __devinitdata struct usb_device_id device_table[] = {
-#ifndef CONFIG_USB_SN9C102
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
        {USB_DEVICE(0x0458, 0x7025), BSI(SN9C120, MI0360, 0x5d)},
        {USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)},
        {USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)},
@@ -1406,15 +1583,17 @@ static const __devinitdata struct usb_device_id device_table[] = {
 /*     {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */
 /*     {USB_DEVICE(0x0c45, 0x6122), BSI(SN9C110, ICM105C, 0x??)}, */
 /*     {USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */
-       {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C325, OV7648, 0x21)},
-/* bw600.inf:
-       {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C110, OV7648, 0x21)}, */
+       {USB_DEVICE(0x0c45, 0x6128), BSI(SN9C110, OM6802, 0x21)}, /*sn9c325?*/
+/*bw600.inf:*/
+       {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C110, OV7648, 0x21)}, /*sn9c325?*/
        {USB_DEVICE(0x0c45, 0x612c), BSI(SN9C110, MO4000, 0x21)},
-/*     {USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x??)}, */
+       {USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x21)},
 /*     {USB_DEVICE(0x0c45, 0x612f), BSI(SN9C110, ICM105C, 0x??)}, */
-#ifndef CONFIG_USB_SN9C102
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
        {USB_DEVICE(0x0c45, 0x6130), BSI(SN9C120, MI0360, 0x5d)},
+#endif
        {USB_DEVICE(0x0c45, 0x6138), BSI(SN9C120, MO4000, 0x21)},
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
 /*     {USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x??)}, */
        {USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)},
        {USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)},
@@ -1438,6 +1617,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
index 17fe2c2..6e73390 100644 (file)
@@ -645,8 +645,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
        return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
@@ -880,14 +880,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
                gspca_dev->usb_buf[0]);
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
@@ -1051,11 +1043,9 @@ static struct sd_desc sd_desc = {
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
-       .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
 };
 
@@ -1093,6 +1083,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
index 51a3c34..e9eb59b 100644 (file)
@@ -1953,8 +1953,8 @@ error:
        return -EINVAL;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
@@ -2022,11 +2022,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 }
 
 static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
 {
        reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00);
 }
@@ -2120,11 +2115,10 @@ static const struct sd_desc sd_desc = {
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
        .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
 };
 
@@ -2154,6 +2148,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
index eda29d6..f601daf 100644 (file)
@@ -655,8 +655,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
        return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int ret;
@@ -742,11 +742,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 }
 
 static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
 {
        /* This maybe reset or power control */
        reg_write(gspca_dev->dev, 0x03, 0x03, 0x20);
@@ -825,11 +820,10 @@ static const struct sd_desc sd_desc = {
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
        .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
 };
 
@@ -855,6 +849,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
index f622fa7..195dce9 100644 (file)
@@ -313,8 +313,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
        return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
        struct usb_device *dev = gspca_dev->dev;
 
@@ -560,14 +560,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        reg_w(dev, 0x03, 0x00, 0x0003);
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
@@ -740,11 +732,9 @@ static struct sd_desc sd_desc = {
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
-       .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
 };
 
@@ -772,6 +762,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
index 699340c..281ce02 100644 (file)
@@ -1521,8 +1521,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
        return 0;                       /* success */
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
 /*     write_vector(gspca_dev, spca508_open_data); */
        return 0;
@@ -1554,15 +1554,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        reg_write(gspca_dev->dev, 0x8112, 0x20);
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
@@ -1633,11 +1624,9 @@ static const struct sd_desc sd_desc = {
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
-       .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
 };
 
@@ -1667,6 +1656,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
index 1073ac3..cfbc9eb 100644 (file)
@@ -32,69 +32,48 @@ MODULE_LICENSE("GPL");
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
-       unsigned short contrast;
-       __u8 brightness;
+       __u16 contrast;                 /* rev72a only */
+#define CONTRAST_MIN 0x0000
+#define CONTRAST_DEF 0x2000
+#define CONTRAST_MAX 0x3fff
+
+       __u16 exposure;                 /* rev12a only */
+#define EXPOSURE_MIN 1
+#define EXPOSURE_DEF 200
+#define EXPOSURE_MAX (4095 - 900) /* see set_exposure */
+
+       __u8 brightness;                /* rev72a only */
+#define BRIGHTNESS_MIN 0
+#define BRIGHTNESS_DEF 32
+#define BRIGHTNESS_MAX 63
+
+       __u8 white;                     /* rev12a only */
+#define WHITE_MIN 1
+#define WHITE_DEF 0x40
+#define WHITE_MAX 0x7f
+
        __u8 autogain;
+#define AUTOGAIN_MIN 0
+#define AUTOGAIN_DEF 1
+#define AUTOGAIN_MAX 1
+
+       __u8 gain;                      /* rev12a only */
+#define GAIN_MIN 0x0
+#define GAIN_DEF 0x24
+#define GAIN_MAX 0x24
+
+#define EXPO12A_DEF 3
+       __u8 expo12a;           /* expo/gain? for rev 12a */
 
        __u8 chip_revision;
+#define Rev012A 0
+#define Rev072A 1
+
        signed char ag_cnt;
 #define AG_CNT_START 13
 };
 
-/* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-
-static struct ctrl sd_ctrls[] = {
-#define SD_BRIGHTNESS 0
-       {
-        {
-         .id = V4L2_CID_BRIGHTNESS,
-         .type = V4L2_CTRL_TYPE_INTEGER,
-         .name = "Brightness",
-         .minimum = 0,
-         .maximum = 63,
-         .step = 1,
-         .default_value = 32,
-         },
-        .set = sd_setbrightness,
-        .get = sd_getbrightness,
-        },
-#define SD_CONTRAST 1
-       {
-        {
-         .id = V4L2_CID_CONTRAST,
-         .type = V4L2_CTRL_TYPE_INTEGER,
-         .name = "Contrast",
-         .minimum = 0,
-         .maximum = 0x3fff,
-         .step = 1,
-         .default_value = 0x2000,
-         },
-        .set = sd_setcontrast,
-        .get = sd_getcontrast,
-        },
-#define SD_AUTOGAIN 2
-       {
-        {
-         .id = V4L2_CID_AUTOGAIN,
-         .type = V4L2_CTRL_TYPE_BOOLEAN,
-         .name = "Auto Gain",
-         .minimum = 0,
-         .maximum = 1,
-         .step = 1,
-         .default_value = 1,
-         },
-        .set = sd_setautogain,
-        .get = sd_getautogain,
-        },
-};
-
-static struct v4l2_pix_format sif_mode[] = {
+static struct v4l2_pix_format sif_012a_mode[] = {
        {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
                .bytesperline = 160,
                .sizeimage = 160 * 120,
@@ -117,6 +96,29 @@ static struct v4l2_pix_format sif_mode[] = {
                .priv = 0},
 };
 
+static struct v4l2_pix_format sif_072a_mode[] = {
+       {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+               .bytesperline = 160,
+               .sizeimage = 160 * 120,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 3},
+       {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+               .bytesperline = 176,
+               .sizeimage = 176 * 144,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 2},
+       {320, 240, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1},
+       {352, 288, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+               .bytesperline = 352,
+               .sizeimage = 352 * 288,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0},
+};
+
 /*
  * Initialization data
  * I'm not very sure how to split initialization from open data
@@ -143,12 +145,8 @@ static struct v4l2_pix_format sif_mode[] = {
 #define SPCA561_INDEX_I2C_BASE 0x8800
 #define SPCA561_SNAPBIT 0x20
 #define SPCA561_SNAPCTRL 0x40
-enum {
-       Rev072A = 0,
-       Rev012A,
-};
 
-static void reg_w_val(struct usb_device *dev, __u16 index, __u16 value)
+static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value)
 {
        int ret;
 
@@ -198,12 +196,6 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
                        index, gspca_dev->usb_buf, len, 500);
 }
 
-static void i2c_init(struct gspca_dev *gspca_dev, __u8 mode)
-{
-       reg_w_val(gspca_dev->dev, 0x92, 0x8804);
-       reg_w_val(gspca_dev->dev, mode, 0x8802);
-}
-
 static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg)
 {
        int retry = 60;
@@ -212,9 +204,9 @@ static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg)
 
        DataLow = valeur;
        DataHight = valeur >> 8;
-       reg_w_val(gspca_dev->dev, reg, 0x8801);
-       reg_w_val(gspca_dev->dev, DataLow, 0x8805);
-       reg_w_val(gspca_dev->dev, DataHight, 0x8800);
+       reg_w_val(gspca_dev->dev, 0x8801, reg);
+       reg_w_val(gspca_dev->dev, 0x8805, DataLow);
+       reg_w_val(gspca_dev->dev, 0x8800, DataHight);
        while (retry--) {
                reg_r(gspca_dev, 0x8803, 1);
                if (!gspca_dev->usb_buf[0])
@@ -228,14 +220,14 @@ static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
        __u8 value;
        __u8 vallsb;
 
-       reg_w_val(gspca_dev->dev, 0x92, 0x8804);
-       reg_w_val(gspca_dev->dev, reg, 0x8801);
-       reg_w_val(gspca_dev->dev, (mode | 0x01), 0x8802);
-       while (retry--) {
+       reg_w_val(gspca_dev->dev, 0x8804, 0x92);
+       reg_w_val(gspca_dev->dev, 0x8801, reg);
+       reg_w_val(gspca_dev->dev, 0x8802, (mode | 0x01));
+       do {
                reg_r(gspca_dev, 0x8803, 1);
                if (!gspca_dev->usb_buf)
                        break;
-       }
+       } while (--retry);
        if (retry == 0)
                return -1;
        reg_r(gspca_dev, 0x8800, 1);
@@ -438,21 +430,10 @@ static const __u16 spca561_init_data[][2] = {
        {0x0035, 0x8801},       /* 0x14 - set gain general */
        {0x001f, 0x8805},       /* 0x14 */
        {0x0000, 0x8800},
-       {0x0030, 0x8112},
+       {0x000e, 0x8112},       /* white balance - was 30 */
        {}
 };
 
-static void sensor_reset(struct gspca_dev *gspca_dev)
-{
-       reg_w_val(gspca_dev->dev, 0x8631, 0xc8);
-       reg_w_val(gspca_dev->dev, 0x8634, 0xc8);
-       reg_w_val(gspca_dev->dev, 0x8112, 0x00);
-       reg_w_val(gspca_dev->dev, 0x8114, 0x00);
-       reg_w_val(gspca_dev->dev, 0x8118, 0x21);
-       i2c_init(gspca_dev, 0x14);
-       i2c_write(gspca_dev, 1, 0x0d);
-       i2c_write(gspca_dev, 0, 0x0d);
-}
 
 /******************** QC Express etch2 stuff ********************/
 static const __u16 Pb100_1map8300[][2] = {
@@ -462,9 +443,9 @@ static const __u16 Pb100_1map8300[][2] = {
        {0x8303, 0x0125},       /* image area */
        {0x8304, 0x0169},
        {0x8328, 0x000b},
-       {0x833c, 0x0001},
+       {0x833c, 0x0001},               /*fixme: win:07*/
 
-       {0x832f, 0x0419},
+       {0x832f, 0x1904},               /*fixme: was 0419*/
        {0x8307, 0x00aa},
        {0x8301, 0x0003},
        {0x8302, 0x000e},
@@ -478,9 +459,10 @@ static const __u16 Pb100_2map8300[][2] = {
 };
 
 static const __u16 spca561_161rev12A_data1[][2] = {
-       {0x21, 0x8118},
-       {0x01, 0x8114},
-       {0x00, 0x8112},
+       {0x29, 0x8118},         /* white balance - was 21 */
+       {0x08, 0x8114},         /* white balance - was 01 */
+       {0x0e, 0x8112},         /* white balance - was 00 */
+       {0x00, 0x8102},         /* white balance - new */
        {0x92, 0x8804},
        {0x04, 0x8802},         /* windows uses 08 */
        {}
@@ -505,14 +487,16 @@ static const __u16 spca561_161rev12A_data2[][2] = {
        {0xb0, 0x8603},
 
        /* sensor gains */
+       {0x07, 0x8601},         /* white balance - new */
+       {0x07, 0x8602},         /* white balance - new */
        {0x00, 0x8610},         /* *red */
        {0x00, 0x8611},         /* 3f   *green */
        {0x00, 0x8612},         /* green *blue */
        {0x00, 0x8613},         /* blue *green */
-       {0x35, 0x8614},         /* green *red */
-       {0x35, 0x8615},         /* 40   *green */
-       {0x35, 0x8616},         /* 7a   *blue */
-       {0x35, 0x8617},         /* 40   *green */
+       {0x43, 0x8614},         /* green *red - white balance - was 0x35 */
+       {0x40, 0x8615},         /* 40   *green - white balance - was 0x35 */
+       {0x71, 0x8616},         /* 7a   *blue - white balance - was 0x35 */
+       {0x40, 0x8617},         /* 40   *green - white balance - was 0x35 */
 
        {0x0c, 0x8620},         /* 0c */
        {0xc8, 0x8631},         /* c8 */
@@ -527,6 +511,7 @@ static const __u16 spca561_161rev12A_data2[][2] = {
        {0xdf, 0x863c},         /* df */
        {0xf0, 0x8505},
        {0x32, 0x850a},
+/*     {0x99, 0x8700},          * - white balance - new (removed) */
        {}
 };
 
@@ -545,9 +530,10 @@ static void sensor_mapwrite(struct gspca_dev *gspca_dev,
 }
 static void init_161rev12A(struct gspca_dev *gspca_dev)
 {
-       sensor_reset(gspca_dev);
+/*     sensor_reset(gspca_dev);        (not in win) */
        write_vector(gspca_dev, spca561_161rev12A_data1);
        sensor_mapwrite(gspca_dev, Pb100_1map8300);
+/*fixme: should be in sd_start*/
        write_vector(gspca_dev, spca561_161rev12A_data2);
        sensor_mapwrite(gspca_dev, Pb100_2map8300);
 }
@@ -581,35 +567,38 @@ static int sd_config(struct gspca_dev *gspca_dev,
        }
 
        cam = &gspca_dev->cam;
-       cam->dev_name = (char *) id->driver_info;
        cam->epaddr = 0x01;
        gspca_dev->nbalt = 7 + 1;       /* choose alternate 7 first */
-       cam->cam_mode = sif_mode;
-       cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
 
        sd->chip_revision = id->driver_info;
-       sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
-       sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
-       sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+       if (sd->chip_revision == Rev012A) {
+               cam->cam_mode = sif_012a_mode;
+               cam->nmodes = ARRAY_SIZE(sif_012a_mode);
+       } else {
+               cam->cam_mode = sif_072a_mode;
+               cam->nmodes = ARRAY_SIZE(sif_072a_mode);
+       }
+       sd->brightness = BRIGHTNESS_DEF;
+       sd->contrast = CONTRAST_DEF;
+       sd->white = WHITE_DEF;
+       sd->exposure = EXPOSURE_DEF;
+       sd->autogain = AUTOGAIN_DEF;
+       sd->gain = GAIN_DEF;
+       sd->expo12a = EXPO12A_DEF;
        return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init_12a(struct gspca_dev *gspca_dev)
 {
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       switch (sd->chip_revision) {
-       case Rev072A:
-               PDEBUG(D_STREAM, "Chip revision id: 072a");
-               write_vector(gspca_dev, spca561_init_data);
-               break;
-       default:
-/*     case Rev012A: */
-               PDEBUG(D_STREAM, "Chip revision id: 012a");
-               init_161rev12A(gspca_dev);
-               break;
-       }
+       PDEBUG(D_STREAM, "Chip revision: 012a");
+       init_161rev12A(gspca_dev);
+       return 0;
+}
+static int sd_init_72a(struct gspca_dev *gspca_dev)
+{
+       PDEBUG(D_STREAM, "Chip revision: 072a");
+       write_vector(gspca_dev, spca561_init_data);
        return 0;
 }
 
@@ -618,25 +607,20 @@ static void setcontrast(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        struct usb_device *dev = gspca_dev->dev;
        __u8 lowb;
-       int expotimes;
 
        switch (sd->chip_revision) {
        case Rev072A:
                lowb = sd->contrast >> 8;
-               reg_w_val(dev, lowb, 0x8651);
-               reg_w_val(dev, lowb, 0x8652);
-               reg_w_val(dev, lowb, 0x8653);
-               reg_w_val(dev, lowb, 0x8654);
+               reg_w_val(dev, 0x8651, lowb);
+               reg_w_val(dev, 0x8652, lowb);
+               reg_w_val(dev, 0x8653, lowb);
+               reg_w_val(dev, 0x8654, lowb);
                break;
-       case Rev012A: {
-               __u8 Reg8391[] =
-                       { 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00 };
-
-               /* Write camera sensor settings */
-               expotimes = (sd->contrast >> 5) & 0x07ff;
-               Reg8391[0] = expotimes & 0xff;  /* exposure */
-               Reg8391[1] = 0x18 | (expotimes >> 8);
-               Reg8391[2] = sd->brightness;    /* gain */
+       default: {
+/*     case Rev012A: { */
+               static const __u8 Reg8391[] =
+                       { 0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00 };
+
                reg_w_buf(gspca_dev, 0x8391, Reg8391, 8);
                reg_w_buf(gspca_dev, 0x8390, Reg8391, 8);
                break;
@@ -644,93 +628,151 @@ static void setcontrast(struct gspca_dev *gspca_dev)
        }
 }
 
-static void setautogain(struct gspca_dev *gspca_dev)
+/* rev12a only */
+static void setwhite(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       __u16 white;
+       __u8 reg8614, reg8616;
+
+       white = sd->white;
+       /* try to emulate MS-win as possible */
+       reg8616 = 0x90 - white * 5 / 8;
+       reg_w_val(gspca_dev->dev, 0x8616, reg8616);
+       reg8614 = 0x20 + white * 3 / 8;
+       reg_w_val(gspca_dev->dev, 0x8614, reg8614);
+}
 
-       if (sd->chip_revision == Rev072A) {
-               if (sd->autogain)
-                       sd->ag_cnt = AG_CNT_START;
-               else
-                       sd->ag_cnt = -1;
+/* rev 12a only */
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int expo;
+       int clock_divider;
+       __u8 data[2];
+
+       /* Register 0x8309 controls exposure for the spca561,
+          the basic exposure setting goes from 1-2047, where 1 is completely
+          dark and 2047 is very bright. It not only influences exposure but
+          also the framerate (to allow for longer exposure) from 1 - 300 it
+          only raises the exposure time then from 300 - 600 it halves the
+          framerate to be able to further raise the exposure time and for every
+          300 more it halves the framerate again. This allows for a maximum
+          exposure time of circa 0.2 - 0.25 seconds (30 / (2000/3000) fps).
+          Sometimes this is not enough, the 1-2047 uses bits 0-10, bits 11-12
+          configure a divider for the base framerate which us used at the
+          exposure setting of 1-300. These bits configure the base framerate
+          according to the following formula: fps = 60 / (value + 2) */
+       if (sd->exposure < 2048) {
+               expo = sd->exposure;
+               clock_divider = 0;
+       } else {
+               /* Add 900 to make the 0 setting of the second part of the
+                  exposure equal to the 2047 setting of the first part. */
+               expo = (sd->exposure - 2048) + 900;
+               clock_divider = 3;
        }
+       expo |= clock_divider << 11;
+       data[0] = expo;
+       data[1] = expo >> 8;
+       reg_w_buf(gspca_dev, 0x8309, data, 2);
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+/* rev 12a only */
+static void setgain(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       __u8 data[2];
+
+       data[0] = sd->gain;
+       data[1] = 0;
+       reg_w_buf(gspca_dev, 0x8335, data, 2);
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (sd->autogain)
+               sd->ag_cnt = AG_CNT_START;
+       else
+               sd->ag_cnt = -1;
+}
+
+static void sd_start_12a(struct gspca_dev *gspca_dev)
+{
        struct usb_device *dev = gspca_dev->dev;
-       int Clck;
+       int Clck = 0x8a; /* lower 0x8X values lead to fps > 30 */
        __u8 Reg8307[] = { 0xaa, 0x00 };
        int mode;
 
        mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
-       switch (sd->chip_revision) {
-       case Rev072A:
-               switch (mode) {
-               default:
-/*             case 0:
-               case 1: */
-                       Clck = 0x25;
-                       break;
-               case 2:
-                       Clck = 0x22;
-                       break;
-               case 3:
-                       Clck = 0x21;
-                       break;
-               }
-               reg_w_val(dev, 0x8500, mode);   /* mode */
-               reg_w_val(dev, 0x8700, Clck);   /* 0x27 clock */
-               reg_w_val(dev, 0x8112, 0x10 | 0x20);
-               setautogain(gspca_dev);
-               break;
+       if (mode <= 1) {
+               /* Use compression on 320x240 and above */
+               reg_w_val(dev, 0x8500, 0x10 | mode);
+       } else {
+               /* I couldn't get the compression to work below 320x240
+                * Fortunately at these resolutions the bandwidth
+                * is sufficient to push raw frames at ~20fps */
+               reg_w_val(dev, 0x8500, mode);
+       }               /* -- qq@kuku.eu.org */
+       reg_w_buf(gspca_dev, 0x8307, Reg8307, 2);
+       reg_w_val(gspca_dev->dev, 0x8700, Clck);
+                                       /* 0x8f 0x85 0x27 clock */
+       reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
+       reg_w_val(gspca_dev->dev, 0x850b, 0x03);
+       setcontrast(gspca_dev);
+       setwhite(gspca_dev);
+       setautogain(gspca_dev);
+       setexposure(gspca_dev);
+}
+static void sd_start_72a(struct gspca_dev *gspca_dev)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int Clck;
+       int mode;
+
+       mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+       switch (mode) {
        default:
-/*     case Rev012A: */
-               switch (mode) {
-               case 0:
-               case 1:
-                       Clck = 0x8a;
-                       break;
-               case 2:
-                       Clck = 0x85;
-                       break;
-               default:
-                       Clck = 0x83;
-                       break;
-               }
-               if (mode <= 1) {
-                       /* Use compression on 320x240 and above */
-                       reg_w_val(dev, 0x8500, 0x10 | mode);
-               } else {
-                       /* I couldn't get the compression to work below 320x240
-                        * Fortunately at these resolutions the bandwidth
-                        * is sufficient to push raw frames at ~20fps */
-                       reg_w_val(dev, 0x8500, mode);
-               }               /* -- qq@kuku.eu.org */
-               reg_w_buf(gspca_dev, 0x8307, Reg8307, 2);
-               reg_w_val(gspca_dev->dev, 0x8700, Clck);
-                                               /* 0x8f 0x85 0x27 clock */
-               reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
-               reg_w_val(gspca_dev->dev, 0x850b, 0x03);
-               setcontrast(gspca_dev);
+/*     case 0:
+       case 1: */
+               Clck = 0x25;
+               break;
+       case 2:
+               Clck = 0x22;
+               break;
+       case 3:
+               Clck = 0x21;
                break;
        }
+       reg_w_val(dev, 0x8500, mode);   /* mode */
+       reg_w_val(dev, 0x8700, Clck);   /* 0x27 clock */
+       reg_w_val(dev, 0x8112, 0x10 | 0x20);
+       setautogain(gspca_dev);
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
-       reg_w_val(gspca_dev->dev, 0x8112, 0x20);
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (sd->chip_revision == Rev012A) {
+               reg_w_val(gspca_dev->dev, 0x8112, 0x0e);
+       } else {
+               reg_w_val(gspca_dev->dev, 0x8112, 0x20);
+/*             reg_w_val(gspca_dev->dev, 0x8102, 0x00); ?? */
+       }
 }
 
 static void sd_stop0(struct gspca_dev *gspca_dev)
 {
-}
+       struct sd *sd = (struct sd *) gspca_dev;
 
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-       reg_w_val(gspca_dev->dev, 0x8114, 0);
+       if (sd->chip_revision == Rev012A) {
+               reg_w_val(gspca_dev->dev, 0x8118, 0x29);
+               reg_w_val(gspca_dev->dev, 0x8114, 0x08);
+       }
+/*     reg_w_val(gspca_dev->dev, 0x8114, 0); */
 }
 
 static void do_autogain(struct gspca_dev *gspca_dev)
@@ -744,6 +786,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
        __u8 luma_mean = 110;
        __u8 luma_delta = 20;
        __u8 spring = 4;
+       __u8 reg8339[2];
 
        if (sd->ag_cnt < 0)
                return;
@@ -798,13 +841,16 @@ static void do_autogain(struct gspca_dev *gspca_dev)
                }
                break;
        case Rev012A:
-               /* sensor registers is access and memory mapped to 0x8300 */
-               /* readind all 0x83xx block the sensor */
-               /*
-                * The data from the header seem wrong where is the luma
-                * and chroma mean value
-                * at the moment set exposure in contrast set
-                */
+               reg_r(gspca_dev, 0x8330, 2);
+               if (gspca_dev->usb_buf[1] > 0x08) {
+                       reg8339[0] = ++sd->expo12a;
+                       reg8339[1] = 0;
+                       reg_w_buf(gspca_dev, 0x8339, reg8339, 2);
+               } else if (gspca_dev->usb_buf[1] < 0x02) {
+                       reg8339[0] = --sd->expo12a;
+                       reg8339[1] = 0;
+                       reg_w_buf(gspca_dev, 0x8339, reg8339, 2);
+               }
                break;
        }
 }
@@ -814,6 +860,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        __u8 *data,             /* isoc packet */
                        int len)                /* iso packet length */
 {
+       struct sd *sd = (struct sd *) gspca_dev;
+
        switch (data[0]) {
        case 0:         /* start of frame */
                frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
@@ -826,8 +874,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                                        frame, data, len);
                } else {
                        /* raw bayer (with a header, which we skip) */
-                       data += 20;
-                       len -= 20;
+                       if (sd->chip_revision == Rev012A) {
+                               data += 20;
+                               len -= 20;
+                       } else {
+                               data += 16;
+                               len -= 16;
+                       }
                        gspca_frame_add(gspca_dev, FIRST_PACKET,
                                                frame, data, len);
                }
@@ -841,24 +894,17 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
+/* rev 72a only */
 static void setbrightness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        __u8 value;
 
-       switch (sd->chip_revision) {
-       case Rev072A:
-               value = sd->brightness;
-               reg_w_val(gspca_dev->dev, value, 0x8611);
-               reg_w_val(gspca_dev->dev, value, 0x8612);
-               reg_w_val(gspca_dev->dev, value, 0x8613);
-               reg_w_val(gspca_dev->dev, value, 0x8614);
-               break;
-       default:
-/*     case Rev012A: */
-               setcontrast(gspca_dev);
-               break;
-       }
+       value = sd->brightness;
+       reg_w_val(gspca_dev->dev, 0x8611, value);
+       reg_w_val(gspca_dev->dev, 0x8612, value);
+       reg_w_val(gspca_dev->dev, 0x8613, value);
+       reg_w_val(gspca_dev->dev, 0x8614, value);
 }
 
 static void getbrightness(struct gspca_dev *gspca_dev)
@@ -866,52 +912,38 @@ static void getbrightness(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        __u16 tot;
 
-       switch (sd->chip_revision) {
-       case Rev072A:
-               tot = 0;
-               reg_r(gspca_dev, 0x8611, 1);
-               tot += gspca_dev->usb_buf[0];
-               reg_r(gspca_dev, 0x8612, 1);
-               tot += gspca_dev->usb_buf[0];
-               reg_r(gspca_dev, 0x8613, 1);
-               tot += gspca_dev->usb_buf[0];
-               reg_r(gspca_dev, 0x8614, 1);
-               tot += gspca_dev->usb_buf[0];
-               sd->brightness = tot >> 2;
-               break;
-       default:
-/*     case Rev012A: */
-               /* no way to read sensor settings */
-               break;
-       }
+       tot = 0;
+       reg_r(gspca_dev, 0x8611, 1);
+       tot += gspca_dev->usb_buf[0];
+       reg_r(gspca_dev, 0x8612, 1);
+       tot += gspca_dev->usb_buf[0];
+       reg_r(gspca_dev, 0x8613, 1);
+       tot += gspca_dev->usb_buf[0];
+       reg_r(gspca_dev, 0x8614, 1);
+       tot += gspca_dev->usb_buf[0];
+       sd->brightness = tot >> 2;
 }
 
+/* rev72a only */
 static void getcontrast(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        __u16 tot;
 
-       switch (sd->chip_revision) {
-       case Rev072A:
-               tot = 0;
-               reg_r(gspca_dev, 0x8651, 1);
-               tot += gspca_dev->usb_buf[0];
-               reg_r(gspca_dev, 0x8652, 1);
-               tot += gspca_dev->usb_buf[0];
-               reg_r(gspca_dev, 0x8653, 1);
-               tot += gspca_dev->usb_buf[0];
-               reg_r(gspca_dev, 0x8654, 1);
-               tot += gspca_dev->usb_buf[0];
-               sd->contrast = tot << 6;
-               break;
-       default:
-/*     case Rev012A: */
-               /* no way to read sensor settings */
-               break;
-       }
+       tot = 0;
+       reg_r(gspca_dev, 0x8651, 1);
+       tot += gspca_dev->usb_buf[0];
+       reg_r(gspca_dev, 0x8652, 1);
+       tot += gspca_dev->usb_buf[0];
+       reg_r(gspca_dev, 0x8653, 1);
+       tot += gspca_dev->usb_buf[0];
+       reg_r(gspca_dev, 0x8654, 1);
+       tot += gspca_dev->usb_buf[0];
+       sd->contrast = tot << 6;
        PDEBUG(D_CONF, "get contrast %d", sd->contrast);
 }
 
+/* rev 72a only */
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -931,6 +963,7 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
+/* rev 72a only */
 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -968,20 +1001,190 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
+/* rev12a only */
+static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->white = val;
+       if (gspca_dev->streaming)
+               setwhite(gspca_dev);
+       return 0;
+}
+
+static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->white;
+       return 0;
+}
+
+/* rev12a only */
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->exposure = val;
+       if (gspca_dev->streaming)
+               setexposure(gspca_dev);
+       return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->exposure;
+       return 0;
+}
+
+/* rev12a only */
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->gain = val;
+       if (gspca_dev->streaming)
+               setgain(gspca_dev);
+       return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->gain;
+       return 0;
+}
+
+/* control tables */
+static struct ctrl sd_ctrls_12a[] = {
+       {
+           {
+               .id = V4L2_CID_DO_WHITE_BALANCE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "While Balance",
+               .minimum = WHITE_MIN,
+               .maximum = WHITE_MAX,
+               .step = 1,
+               .default_value = WHITE_DEF,
+           },
+           .set = sd_setwhite,
+           .get = sd_getwhite,
+       },
+       {
+           {
+               .id = V4L2_CID_EXPOSURE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Exposure",
+               .minimum = EXPOSURE_MIN,
+               .maximum = EXPOSURE_MAX,
+               .step = 1,
+               .default_value = EXPOSURE_DEF,
+           },
+           .set = sd_setexposure,
+           .get = sd_getexposure,
+       },
+       {
+           {
+               .id = V4L2_CID_AUTOGAIN,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "Auto Gain",
+               .minimum = AUTOGAIN_MIN,
+               .maximum = AUTOGAIN_MAX,
+               .step = 1,
+               .default_value = AUTOGAIN_DEF,
+           },
+           .set = sd_setautogain,
+           .get = sd_getautogain,
+       },
+       {
+           {
+               .id = V4L2_CID_GAIN,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Gain",
+               .minimum = GAIN_MIN,
+               .maximum = GAIN_MAX,
+               .step = 1,
+               .default_value = GAIN_DEF,
+           },
+           .set = sd_setgain,
+           .get = sd_getgain,
+       },
+};
+
+static struct ctrl sd_ctrls_72a[] = {
+       {
+          {
+               .id = V4L2_CID_BRIGHTNESS,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Brightness",
+               .minimum = BRIGHTNESS_MIN,
+               .maximum = BRIGHTNESS_MAX,
+               .step = 1,
+               .default_value = BRIGHTNESS_DEF,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+       {
+           {
+               .id = V4L2_CID_CONTRAST,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Contrast",
+               .minimum = CONTRAST_MIN,
+               .maximum = CONTRAST_MAX,
+               .step = 1,
+               .default_value = CONTRAST_DEF,
+           },
+           .set = sd_setcontrast,
+           .get = sd_getcontrast,
+       },
+       {
+           {
+               .id = V4L2_CID_AUTOGAIN,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "Auto Gain",
+               .minimum = AUTOGAIN_MIN,
+               .maximum = AUTOGAIN_MAX,
+               .step = 1,
+               .default_value = AUTOGAIN_DEF,
+           },
+           .set = sd_setautogain,
+           .get = sd_getautogain,
+       },
+};
+
 /* sub-driver description */
-static const struct sd_desc sd_desc = {
+static const struct sd_desc sd_desc_12a = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls_12a,
+       .nctrls = ARRAY_SIZE(sd_ctrls_12a),
+       .config = sd_config,
+       .init = sd_init_12a,
+       .start = sd_start_12a,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .pkt_scan = sd_pkt_scan,
+/*     .dq_callback = do_autogain,      * fixme */
+};
+static const struct sd_desc sd_desc_72a = {
        .name = MODULE_NAME,
-       .ctrls = sd_ctrls,
-       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .ctrls = sd_ctrls_72a,
+       .nctrls = ARRAY_SIZE(sd_ctrls_72a),
        .config = sd_config,
-       .open = sd_open,
-       .start = sd_start,
+       .init = sd_init_72a,
+       .start = sd_start_72a,
        .stopN = sd_stopN,
        .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
        .dq_callback = do_autogain,
 };
+static const struct sd_desc *sd_desc[2] = {
+       &sd_desc_12a,
+       &sd_desc_72a
+};
 
 /* -- module initialisation -- */
 static const __devinitdata struct usb_device_id device_table[] = {
@@ -1009,7 +1212,9 @@ MODULE_DEVICE_TABLE(usb, device_table);
 static int sd_probe(struct usb_interface *intf,
                    const struct usb_device_id *id)
 {
-       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+       return gspca_dev_probe(intf, id,
+                               sd_desc[id->driver_info],
+                               sizeof(struct sd),
                               THIS_MODULE);
 }
 
@@ -1018,6 +1223,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
index 16219cf..2f2de42 100644 (file)
@@ -306,8 +306,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
        return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
        int ret;
 
@@ -398,14 +398,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        PDEBUG(D_STREAM, "camera stopped");
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
@@ -535,11 +527,9 @@ static const struct sd_desc sd_desc = {
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
-       .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
        .querymenu = sd_querymenu,
 };
@@ -564,6 +554,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
index 54efa48..1cfcc6c 100644 (file)
@@ -449,31 +449,47 @@ static const __u8 qtable_spca504_default[2][64] = {
         0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
 };
 
-static void reg_r(struct usb_device *dev,
-                          __u16 req,
-                          __u16 index,
-                          __u8 *buffer, __u16 length)
+/* read <len> bytes to gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+                 __u16 req,
+                 __u16 index,
+                 __u16 len)
 {
-       usb_control_msg(dev,
-                       usb_rcvctrlpipe(dev, 0),
+#ifdef GSPCA_DEBUG
+       if (len > USB_BUF_SZ) {
+               err("reg_r: buffer overflow");
+               return;
+       }
+#endif
+       usb_control_msg(gspca_dev->dev,
+                       usb_rcvctrlpipe(gspca_dev->dev, 0),
                        req,
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        0,              /* value */
-                       index, buffer, length,
+                       index,
+                       len ? gspca_dev->usb_buf : NULL, len,
                        500);
 }
 
-static void reg_w(struct usb_device *dev,
-                           __u16 req,
-                           __u16 value,
-                           __u16 index,
-                           __u8 *buffer, __u16 length)
+/* write <len> bytes from gspca_dev->usb_buf */
+static void reg_w(struct gspca_dev *gspca_dev,
+                  __u16 req,
+                  __u16 value,
+                  __u16 index,
+                  __u16 len)
 {
-       usb_control_msg(dev,
-                       usb_sndctrlpipe(dev, 0),
+#ifdef GSPCA_DEBUG
+       if (len > USB_BUF_SZ) {
+               err("reg_w: buffer overflow");
+               return;
+       }
+#endif
+       usb_control_msg(gspca_dev->dev,
+                       usb_sndctrlpipe(gspca_dev->dev, 0),
                        req,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       value, index, buffer, length,
+                       value, index,
+                       len ? gspca_dev->usb_buf : NULL, len,
                        500);
 }
 
@@ -634,7 +650,7 @@ static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
        int count = 10;
 
        while (--count > 0) {
-               reg_r(gspca_dev->dev, 0x21, 0, gspca_dev->usb_buf, 1);
+               reg_r(gspca_dev, 0x21, 0, 1);
                if ((gspca_dev->usb_buf[0] & 0x01) == 0)
                        break;
                msleep(10);
@@ -644,15 +660,14 @@ static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
 
 static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
 {
-       struct usb_device *dev = gspca_dev->dev;
        int count = 50;
 
        while (--count > 0) {
-               reg_r(dev, 0x21, 1, gspca_dev->usb_buf, 1);
+               reg_r(gspca_dev, 0x21, 1, 1);
                if (gspca_dev->usb_buf[0] != 0) {
                        gspca_dev->usb_buf[0] = 0;
-                       reg_w(dev, 0x21, 0, 1, gspca_dev->usb_buf, 1);
-                       reg_r(dev, 0x21, 1, gspca_dev->usb_buf, 1);
+                       reg_w(gspca_dev, 0x21, 0, 1, 1);
+                       reg_r(gspca_dev, 0x21, 1, 1);
                        spca504B_PollingDataReady(gspca_dev);
                        break;
                }
@@ -662,16 +677,14 @@ static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
 
 static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
 {
-       struct usb_device *dev = gspca_dev->dev;
        __u8 *data;
 
-       data = kmalloc(64, GFP_KERNEL);
-       reg_r(dev, 0x20, 0, data, 5);
+       data = gspca_dev->usb_buf;
+       reg_r(gspca_dev, 0x20, 0, 5);
        PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
                data[0], data[1], data[2], data[3], data[4]);
-       reg_r(dev, 0x23, 0, data, 64);
-       reg_r(dev, 0x23, 1, data, 64);
-       kfree(data);
+       reg_r(gspca_dev, 0x23, 0, 64);
+       reg_r(gspca_dev, 0x23, 1, 64);
 }
 
 static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
@@ -686,21 +699,21 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
        Type = 0;
        switch (sd->bridge) {
        case BRIDGE_SPCA533:
-               reg_w(dev, 0x31, 0, 0, NULL, 0);
+               reg_w(gspca_dev, 0x31, 0, 0, 0);
                spca504B_WaitCmdStatus(gspca_dev);
                rc = spca504B_PollingDataReady(gspca_dev);
                spca50x_GetFirmware(gspca_dev);
                gspca_dev->usb_buf[0] = 2;                      /* type */
-               reg_w(dev, 0x24, 0, 8, gspca_dev->usb_buf, 1);
-               reg_r(dev, 0x24, 8, gspca_dev->usb_buf, 1);
+               reg_w(gspca_dev, 0x24, 0, 8, 1);
+               reg_r(gspca_dev, 0x24, 8, 1);
 
                gspca_dev->usb_buf[0] = Size;
-               reg_w(dev, 0x25, 0, 4, gspca_dev->usb_buf, 1);
-               reg_r(dev, 0x25, 4, gspca_dev->usb_buf, 1);     /* size */
+               reg_w(gspca_dev, 0x25, 0, 4, 1);
+               reg_r(gspca_dev, 0x25, 4, 1);                   /* size */
                rc = spca504B_PollingDataReady(gspca_dev);
 
                /* Init the cam width height with some values get on init ? */
-               reg_w(dev, 0x31, 0, 4, NULL, 0);
+               reg_w(gspca_dev, 0x31, 0, 4, 0);
                spca504B_WaitCmdStatus(gspca_dev);
                rc = spca504B_PollingDataReady(gspca_dev);
                break;
@@ -708,12 +721,12 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
 /* case BRIDGE_SPCA504B: */
 /* case BRIDGE_SPCA536: */
                gspca_dev->usb_buf[0] = Size;
-               reg_w(dev, 0x25, 0, 4, gspca_dev->usb_buf, 1);
-               reg_r(dev, 0x25, 4, gspca_dev->usb_buf, 1);     /* size */
+               reg_w(gspca_dev, 0x25, 0, 4, 1);
+               reg_r(gspca_dev, 0x25, 4, 1);                   /* size */
                Type = 6;
                gspca_dev->usb_buf[0] = Type;
-               reg_w(dev, 0x27, 0, 0, gspca_dev->usb_buf, 1);
-               reg_r(dev, 0x27, 0, gspca_dev->usb_buf, 1);     /* type */
+               reg_w(gspca_dev, 0x27, 0, 0, 1);
+               reg_r(gspca_dev, 0x27, 0, 1);                   /* type */
                rc = spca504B_PollingDataReady(gspca_dev);
                break;
        case BRIDGE_SPCA504:
@@ -752,18 +765,15 @@ static void spca504_wait_status(struct gspca_dev *gspca_dev)
 
 static void spca504B_setQtable(struct gspca_dev *gspca_dev)
 {
-       struct usb_device *dev = gspca_dev->dev;
-
        gspca_dev->usb_buf[0] = 3;
-       reg_w(dev, 0x26, 0, 0, gspca_dev->usb_buf, 1);
-       reg_r(dev, 0x26, 0, gspca_dev->usb_buf, 1);
+       reg_w(gspca_dev, 0x26, 0, 0, 1);
+       reg_r(gspca_dev, 0x26, 0, 1);
        spca504B_PollingDataReady(gspca_dev);
 }
 
 static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       struct usb_device *dev = gspca_dev->dev;
        int pollreg = 1;
 
        switch (sd->bridge) {
@@ -774,20 +784,20 @@ static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
        default:
 /*     case BRIDGE_SPCA533: */
 /*     case BRIDGE_SPCA504B: */
-               reg_w(dev, 0, 0, 0x21a7, NULL, 0);      /* brightness */
-               reg_w(dev, 0, 0x20, 0x21a8, NULL, 0);   /* contrast */
-               reg_w(dev, 0, 0, 0x21ad, NULL, 0);      /* hue */
-               reg_w(dev, 0, 1, 0x21ac, NULL, 0);      /* sat/hue */
-               reg_w(dev, 0, 0x20, 0x21ae, NULL, 0);   /* saturation */
-               reg_w(dev, 0, 0, 0x21a3, NULL, 0);      /* gamma */
+               reg_w(gspca_dev, 0, 0, 0x21a7, 0);      /* brightness */
+               reg_w(gspca_dev, 0, 0x20, 0x21a8, 0);   /* contrast */
+               reg_w(gspca_dev, 0, 0, 0x21ad, 0);      /* hue */
+               reg_w(gspca_dev, 0, 1, 0x21ac, 0);      /* sat/hue */
+               reg_w(gspca_dev, 0, 0x20, 0x21ae, 0);   /* saturation */
+               reg_w(gspca_dev, 0, 0, 0x21a3, 0);      /* gamma */
                break;
        case BRIDGE_SPCA536:
-               reg_w(dev, 0, 0, 0x20f0, NULL, 0);
-               reg_w(dev, 0, 0x21, 0x20f1, NULL, 0);
-               reg_w(dev, 0, 0x40, 0x20f5, NULL, 0);
-               reg_w(dev, 0, 1, 0x20f4, NULL, 0);
-               reg_w(dev, 0, 0x40, 0x20f6, NULL, 0);
-               reg_w(dev, 0, 0, 0x2089, NULL, 0);
+               reg_w(gspca_dev, 0, 0, 0x20f0, 0);
+               reg_w(gspca_dev, 0, 0x21, 0x20f1, 0);
+               reg_w(gspca_dev, 0, 0x40, 0x20f5, 0);
+               reg_w(gspca_dev, 0, 1, 0x20f4, 0);
+               reg_w(gspca_dev, 0, 0x40, 0x20f6, 0);
+               reg_w(gspca_dev, 0, 0, 0x2089, 0);
                break;
        }
        if (pollreg)
@@ -799,7 +809,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
                        const struct usb_device_id *id)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       struct usb_device *dev = gspca_dev->dev;
        struct cam *cam;
 
        cam = &gspca_dev->cam;
@@ -811,7 +820,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        if (sd->subtype == AiptekMiniPenCam13) {
 /* try to get the firmware as some cam answer 2.0.1.2.2
  * and should be a spca504b then overwrite that setting */
-               reg_r(dev, 0x20, 0, gspca_dev->usb_buf, 1);
+               reg_r(gspca_dev, 0x20, 0, 1);
                switch (gspca_dev->usb_buf[0]) {
                case 1:
                        break;          /* (right bridge/subtype) */
@@ -848,8 +857,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
        return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        struct usb_device *dev = gspca_dev->dev;
@@ -860,12 +869,12 @@ static int sd_open(struct gspca_dev *gspca_dev)
 
        switch (sd->bridge) {
        case BRIDGE_SPCA504B:
-               reg_w(dev, 0x1d, 0, 0, NULL, 0);
-               reg_w(dev, 0, 1, 0x2306, NULL, 0);
-               reg_w(dev, 0, 0, 0x0d04, NULL, 0);
-               reg_w(dev, 0, 0, 0x2000, NULL, 0);
-               reg_w(dev, 0, 0x13, 0x2301, NULL, 0);
-               reg_w(dev, 0, 0, 0x2306, NULL, 0);
+               reg_w(gspca_dev, 0x1d, 0, 0, 0);
+               reg_w(gspca_dev, 0, 1, 0x2306, 0);
+               reg_w(gspca_dev, 0, 0, 0x0d04, 0);
+               reg_w(gspca_dev, 0, 0, 0x2000, 0);
+               reg_w(gspca_dev, 0, 0x13, 0x2301, 0);
+               reg_w(gspca_dev, 0, 0, 0x2306, 0);
                /* fall thru */
        case BRIDGE_SPCA533:
                rc = spca504B_PollingDataReady(gspca_dev);
@@ -873,12 +882,12 @@ static int sd_open(struct gspca_dev *gspca_dev)
                break;
        case BRIDGE_SPCA536:
                spca50x_GetFirmware(gspca_dev);
-               reg_r(dev, 0x00, 0x5002, gspca_dev->usb_buf, 1);
+               reg_r(gspca_dev, 0x00, 0x5002, 1);
                gspca_dev->usb_buf[0] = 0;
-               reg_w(dev, 0x24, 0, 0, gspca_dev->usb_buf, 1);
-               reg_r(dev, 0x24, 0, gspca_dev->usb_buf, 1);
+               reg_w(gspca_dev, 0x24, 0, 0, 1);
+               reg_r(gspca_dev, 0x24, 0, 1);
                rc = spca504B_PollingDataReady(gspca_dev);
-               reg_w(dev, 0x34, 0, 0, NULL, 0);
+               reg_w(gspca_dev, 0x34, 0, 0, 0);
                spca504B_WaitCmdStatus(gspca_dev);
                break;
        case BRIDGE_SPCA504C:   /* pccam600 */
@@ -971,12 +980,12 @@ static void sd_start(struct gspca_dev *gspca_dev)
 /*     case BRIDGE_SPCA536: */
                if (sd->subtype == MegapixV4 ||
                    sd->subtype == LogitechClickSmart820) {
-                       reg_w(dev, 0xf0, 0, 0, NULL, 0);
+                       reg_w(gspca_dev, 0xf0, 0, 0, 0);
                        spca504B_WaitCmdStatus(gspca_dev);
-                       reg_r(dev, 0xf0, 4, NULL, 0);
+                       reg_r(gspca_dev, 0xf0, 4, 0);
                        spca504B_WaitCmdStatus(gspca_dev);
                } else {
-                       reg_w(dev, 0x31, 0, 4, NULL, 0);
+                       reg_w(gspca_dev, 0x31, 0, 4, 0);
                        spca504B_WaitCmdStatus(gspca_dev);
                        rc = spca504B_PollingDataReady(gspca_dev);
                }
@@ -1045,7 +1054,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 /*     case BRIDGE_SPCA533: */
 /*     case BRIDGE_SPCA536: */
 /*     case BRIDGE_SPCA504B: */
-               reg_w(dev, 0x31, 0, 0, NULL, 0);
+               reg_w(gspca_dev, 0x31, 0, 0, 0);
                spca504B_WaitCmdStatus(gspca_dev);
                spca504B_PollingDataReady(gspca_dev);
                break;
@@ -1069,14 +1078,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        }
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
@@ -1369,11 +1370,9 @@ static const struct sd_desc sd_desc = {
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
-       .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
 };
 
@@ -1456,6 +1455,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
index 91b555c..f034c74 100644 (file)
@@ -30,7 +30,7 @@
 
 #define MAX_GAMMA 0x10         /* 0 to 15 */
 
-#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0)
 
 MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
 MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
@@ -233,7 +233,7 @@ static char *effects_control[] = {
 static struct v4l2_pix_format vga_mode_t16[] = {
        {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 160,
-               .sizeimage = 160 * 120 * 3 / 8 + 590,
+               .sizeimage = 160 * 120 * 4 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 4},
        {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
@@ -391,7 +391,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
                                NULL, 0, 500);
                return;
        }
-       if (len <= sizeof gspca_dev->usb_buf) {
+       if (len <= USB_BUF_SZ) {
                memcpy(gspca_dev->usb_buf, buffer, len);
                usb_control_msg(gspca_dev->dev,
                                usb_sndctrlpipe(gspca_dev->dev, 0),
@@ -552,6 +552,13 @@ static int init_default_parameters(struct gspca_dev *gspca_dev)
        return 0;
 }
 
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+       init_default_parameters(gspca_dev);
+       return 0;
+}
+
 static void setbrightness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -893,18 +900,6 @@ static void sd_start(struct gspca_dev *gspca_dev)
        setcolors(gspca_dev);
 }
 
-static void sd_stopN(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
@@ -972,24 +967,14 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
        return -EINVAL;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
-{
-       init_default_parameters(gspca_dev);
-       return 0;
-}
-
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
-       .stopN = sd_stopN,
-       .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
        .querymenu = sd_querymenu,
 };
@@ -1014,6 +999,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
index 1ff8ba2..084af05 100644 (file)
@@ -331,8 +331,8 @@ static void tv_8532_PollReg(struct gspca_dev *gspca_dev)
        }
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
        reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32);
        reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00);
@@ -450,14 +450,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void tv8532_preprocess(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -611,11 +603,9 @@ static const struct sd_desc sd_desc = {
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
-       .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
 };
 
@@ -644,6 +634,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
index f4a5295..bd4c226 100644 (file)
@@ -69,6 +69,7 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setautogain,
            .get = sd_getautogain,
        },
+#define LIGHTFREQ_IDX 1
        {
            {
                .id      = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -87,12 +88,12 @@ static struct ctrl sd_ctrls[] = {
 };
 
 static struct v4l2_pix_format vc0321_mode[] = {
-       {320, 240, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE,
+       {320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240 * 2,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 1},
-       {640, 480, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE,
+       {640, 480, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
                .bytesperline = 640,
                .sizeimage = 640 * 480 * 2,
                .colorspace = V4L2_COLORSPACE_SRGB,
@@ -1463,6 +1464,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->qindex = 7;
        sd->autogain = AUTOGAIN_DEF;
        sd->lightfreq = FREQ_DEF;
+       if (sd->sensor != SENSOR_OV7670)
+               gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX);
 
        if (sd->bridge == BRIDGE_VC0321) {
                reg_r(gspca_dev, 0x8a, 0, 3);
@@ -1474,8 +1477,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
        return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
        return 0;
 }
@@ -1637,19 +1640,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
        reg_w(dev, 0x89, 0xffff, 0xffff);
 }
 
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-/*     struct usb_device *dev = gspca_dev->dev;
-       __u8 buffread;
-
-       reg_w(dev, 0x89, 0xffff, 0xffff);
-       reg_w(dev, 0xa0, 0x01, 0xb301);
-       reg_w(dev, 0xa0, 0x09, 0xb303);
-       reg_w(dev, 0x89, 0xffff, 0xffff);
-*/
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
@@ -1738,11 +1728,10 @@ static const struct sd_desc sd_desc = {
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
        .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
        .querymenu = sd_querymenu,
 };
@@ -1774,6 +1763,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
index bc7d0ee..8d7c27e 100644 (file)
@@ -85,6 +85,7 @@ static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
+#define BRIGHTNESS_IDX 0
 #define SD_BRIGHTNESS 0
        {
            {
@@ -141,6 +142,7 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setautogain,
            .get = sd_getautogain,
        },
+#define LIGHTFREQ_IDX 4
 #define SD_FREQ 4
        {
            {
@@ -6964,8 +6966,13 @@ static int zcxx_probeSensor(struct gspca_dev *gspca_dev)
        case SENSOR_MC501CB:
                return -1;              /* don't probe */
        case SENSOR_TAS5130C_VF0250:
-                               /* may probe but with write in reg 0x0010 */
+                       /* may probe but with no write in reg 0x0010 */
                return -1;              /* don't probe */
+       case SENSOR_PAS106:
+               sensor =  sif_probe(gspca_dev);
+               if (sensor >= 0)
+                       return sensor;
+               break;
        }
        sensor = vga_2wr_probe(gspca_dev);
        if (sensor >= 0) {
@@ -6974,12 +6981,10 @@ static int zcxx_probeSensor(struct gspca_dev *gspca_dev)
                /* next probe is needed for OmniVision ? */
        }
        sensor2 = vga_3wr_probe(gspca_dev);
-       if (sensor2 >= 0) {
-               if (sensor >= 0)
-                       return sensor;
-               return sensor2;
-       }
-       return sif_probe(gspca_dev);
+       if (sensor2 >= 0
+           && sensor >= 0)
+               return sensor;
+       return sensor2;
 }
 
 /* this function is called at probe time */
@@ -7147,13 +7152,27 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value;
        sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value;
 
+       switch (sd->sensor) {
+       case SENSOR_GC0305:
+       case SENSOR_OV7620:
+       case SENSOR_PO2030:
+               gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX);
+               break;
+       case SENSOR_HDCS2020:
+       case SENSOR_HV7131B:
+       case SENSOR_HV7131C:
+       case SENSOR_OV7630C:
+               gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX);
+               break;
+       }
+
        /* switch the led off */
        reg_w(gspca_dev->dev, 0x01, 0x0000);
        return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
        reg_w(gspca_dev->dev, 0x01, 0x0000);
        return 0;
@@ -7314,10 +7333,6 @@ static void sd_start(struct gspca_dev *gspca_dev)
        }
 }
 
-static void sd_stopN(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_stop0(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -7325,11 +7340,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
        send_unknown(gspca_dev->dev, sd->sensor);
 }
 
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,
                        __u8 *data,
@@ -7489,37 +7499,30 @@ static const struct sd_desc sd_desc = {
        .ctrls = sd_ctrls,
        .nctrls = sizeof sd_ctrls / sizeof sd_ctrls[0],
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
-       .stopN = sd_stopN,
        .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
        .querymenu = sd_querymenu,
 };
 
 static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x041e, 0x041e)},
-#ifndef CONFIG_USB_ZC0301
        {USB_DEVICE(0x041e, 0x4017)},
-       {USB_DEVICE(0x041e, 0x401c)},
+       {USB_DEVICE(0x041e, 0x401c), .driver_info = SENSOR_PAS106},
        {USB_DEVICE(0x041e, 0x401e)},
        {USB_DEVICE(0x041e, 0x401f)},
-#endif
+       {USB_DEVICE(0x041e, 0x4022)},
        {USB_DEVICE(0x041e, 0x4029)},
-#ifndef CONFIG_USB_ZC0301
-       {USB_DEVICE(0x041e, 0x4034)},
-       {USB_DEVICE(0x041e, 0x4035)},
+       {USB_DEVICE(0x041e, 0x4034), .driver_info = SENSOR_PAS106},
+       {USB_DEVICE(0x041e, 0x4035), .driver_info = SENSOR_PAS106},
        {USB_DEVICE(0x041e, 0x4036)},
        {USB_DEVICE(0x041e, 0x403a)},
-#endif
        {USB_DEVICE(0x041e, 0x4051), .driver_info = SENSOR_TAS5130C_VF0250},
        {USB_DEVICE(0x041e, 0x4053), .driver_info = SENSOR_TAS5130C_VF0250},
-#ifndef CONFIG_USB_ZC0301
        {USB_DEVICE(0x0458, 0x7007)},
        {USB_DEVICE(0x0458, 0x700c)},
        {USB_DEVICE(0x0458, 0x700f)},
-#endif
        {USB_DEVICE(0x0461, 0x0a00)},
        {USB_DEVICE(0x046d, 0x08a0)},
        {USB_DEVICE(0x046d, 0x08a1)},
@@ -7531,7 +7534,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x046d, 0x08aa)},
        {USB_DEVICE(0x046d, 0x08ac)},
        {USB_DEVICE(0x046d, 0x08ad)},
-#ifndef CONFIG_USB_ZC0301
+#if !defined CONFIG_USB_ZC0301 && !defined CONFIG_USB_ZC0301_MODULE
        {USB_DEVICE(0x046d, 0x08ae)},
 #endif
        {USB_DEVICE(0x046d, 0x08af)},
@@ -7541,27 +7544,25 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x046d, 0x08d8)},
        {USB_DEVICE(0x046d, 0x08da)},
        {USB_DEVICE(0x046d, 0x08dd), .driver_info = SENSOR_MC501CB},
-       {USB_DEVICE(0x0471, 0x0325)},
-       {USB_DEVICE(0x0471, 0x0326)},
-       {USB_DEVICE(0x0471, 0x032d)},
-       {USB_DEVICE(0x0471, 0x032e)},
+       {USB_DEVICE(0x0471, 0x0325), .driver_info = SENSOR_PAS106},
+       {USB_DEVICE(0x0471, 0x0326), .driver_info = SENSOR_PAS106},
+       {USB_DEVICE(0x0471, 0x032d), .driver_info = SENSOR_PAS106},
+       {USB_DEVICE(0x0471, 0x032e), .driver_info = SENSOR_PAS106},
        {USB_DEVICE(0x055f, 0xc005)},
-#ifndef CONFIG_USB_ZC0301
        {USB_DEVICE(0x055f, 0xd003)},
        {USB_DEVICE(0x055f, 0xd004)},
-#endif
        {USB_DEVICE(0x0698, 0x2003)},
+       {USB_DEVICE(0x0ac8, 0x0301), .driver_info = SENSOR_PAS106},
        {USB_DEVICE(0x0ac8, 0x0302)},
-#ifndef CONFIG_USB_ZC0301
        {USB_DEVICE(0x0ac8, 0x301b)},
+#if !defined CONFIG_USB_ZC0301 && !defined CONFIG_USB_ZC0301_MODULE
        {USB_DEVICE(0x0ac8, 0x303b)},
 #endif
        {USB_DEVICE(0x0ac8, 0x305b), .driver_info = SENSOR_TAS5130C_VF0250},
-#ifndef CONFIG_USB_ZC0301
        {USB_DEVICE(0x0ac8, 0x307b)},
        {USB_DEVICE(0x10fd, 0x0128)},
+       {USB_DEVICE(0x10fd, 0x804d)},
        {USB_DEVICE(0x10fd, 0x8050)},
-#endif
        {}                      /* end of entry */
 };
 #undef DVNAME
@@ -7581,6 +7582,10 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 static int __init sd_mod_init(void)
index aea1664..4afc7ea 100644 (file)
@@ -688,7 +688,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
        spin_lock_init(&itv->lock);
        spin_lock_init(&itv->dma_reg_lock);
 
-       itv->irq_work_queues = create_workqueue(itv->name);
+       itv->irq_work_queues = create_singlethread_workqueue(itv->name);
        if (itv->irq_work_queues == NULL) {
                IVTV_ERR("Could not create ivtv workqueue\n");
                return -1;
index ab287b4..2ceb522 100644 (file)
@@ -251,6 +251,7 @@ struct ivtv_mailbox_data {
 #define IVTV_F_I_DEC_PAUSED       20   /* the decoder is paused */
 #define IVTV_F_I_INITED                   21   /* set after first open */
 #define IVTV_F_I_FAILED                   22   /* set if first open failed */
+#define IVTV_F_I_WORK_INITED       23  /* worker thread was initialized */
 
 /* Event notifications */
 #define IVTV_F_I_EV_DEC_STOPPED           28   /* decoder stopped event */
index fba150a..34f3ab8 100644 (file)
@@ -76,6 +76,13 @@ void ivtv_irq_work_handler(struct work_struct *work)
 
        DEFINE_WAIT(wait);
 
+       if (test_and_clear_bit(IVTV_F_I_WORK_INITED, &itv->i_flags)) {
+               struct sched_param param = { .sched_priority = 99 };
+
+               /* This thread must use the FIFO scheduler as it
+                  is realtime sensitive. */
+               sched_setscheduler(current, SCHED_FIFO, &param);
+       }
        if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags))
                ivtv_pio_work_handler(itv);
 
@@ -678,34 +685,14 @@ static void ivtv_irq_enc_start_cap(struct ivtv *itv)
 
 static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
 {
-       struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG];
        u32 data[CX2341X_MBOX_MAX_DATA];
        struct ivtv_stream *s;
 
        IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n");
        s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
 
-       /* If more than two VBI buffers are pending, then
-          clear the old ones and start with this new one.
-          This can happen during transition stages when MPEG capturing is
-          started, but the first interrupts haven't arrived yet. During
-          that period VBI requests can accumulate without being able to
-          DMA the data. Since at most four VBI DMA buffers are available,
-          we just drop the old requests when there are already three
-          requests queued. */
-       if (s->sg_pending_size > 2) {
-               struct ivtv_buffer *buf;
-               list_for_each_entry(buf, &s->q_predma.list, list)
-                       ivtv_buf_sync_for_cpu(s, buf);
-               ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0);
-               s->sg_pending_size = 0;
-       }
-       /* if we can append the data, and the MPEG stream isn't capturing,
-          then start a DMA request for just the VBI data. */
-       if (!stream_enc_dma_append(s, data) &&
-                       !test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) {
+       if (!stream_enc_dma_append(s, data))
                set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
-       }
 }
 
 static void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv)
index 7cfc0c9..476556a 100644 (file)
@@ -23,7 +23,7 @@
 #define IVTV_QUEUE_H
 
 #define IVTV_DMA_UNMAPPED      ((u32) -1)
-#define SLICED_VBI_PIO 1
+#define SLICED_VBI_PIO 0
 
 /* ivtv_buffer utility functions */
 
index 54d2023..730e85d 100644 (file)
@@ -363,7 +363,7 @@ static void ivtv_vbi_setup(struct ivtv *itv)
        /* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */
        data[1] = 1;
        /* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */
-       data[2] = raw ? 4 : 8;
+       data[2] = raw ? 4 : 4 * (itv->vbi.raw_size / itv->vbi.enc_size);
        /* The start/stop codes determine which VBI lines end up in the raw VBI data area.
           The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line
           is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video)
index 71798f0..1ce9deb 100644 (file)
@@ -293,6 +293,7 @@ static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8
        u32 line_size = itv->vbi.sliced_decoder_line_size;
        struct v4l2_decode_vbi_line vbi;
        int i;
+       unsigned lines = 0;
 
        /* find the first valid line */
        for (i = 0; i < size; i++, buf++) {
@@ -313,7 +314,8 @@ static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8
                }
                vbi.p = p + 4;
                itv->video_dec_func(itv, VIDIOC_INT_DECODE_VBI_LINE, &vbi);
-               if (vbi.type) {
+               if (vbi.type && !(lines & (1 << vbi.line))) {
+                       lines |= 1 << vbi.line;
                        itv->vbi.sliced_data[line].id = vbi.type;
                        itv->vbi.sliced_data[line].field = vbi.is_second_field;
                        itv->vbi.sliced_data[line].line = vbi.line;
index 442f43f..8cd753d 100644 (file)
@@ -22,7 +22,7 @@
 
 #define IVTV_DRIVER_NAME "ivtv"
 #define IVTV_DRIVER_VERSION_MAJOR 1
-#define IVTV_DRIVER_VERSION_MINOR 3
+#define IVTV_DRIVER_VERSION_MINOR 4
 #define IVTV_DRIVER_VERSION_PATCHLEVEL 0
 
 #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
index 4895540..2fd4b4a 100644 (file)
@@ -679,26 +679,27 @@ static int ks0127_command(struct i2c_client *client,
 
        case DECODER_ENABLE_OUTPUT:
        {
+               int enable;
 
-               int *iarg = arg;
-               int enable = (*iarg != 0);
-                       if (enable) {
-                               dprintk("ks0127: command "
+               iarg = arg;
+               enable = (*iarg != 0);
+               if (enable) {
+                       dprintk("ks0127: command "
                                        "DECODER_ENABLE_OUTPUT on "
                                        "(%d)\n", enable);
-                               /* All output pins on */
-                               ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30);
-                               /* Obey the OEN pin */
-                               ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00);
-                       } else {
-                               dprintk("ks0127: command "
+                       /* All output pins on */
+                       ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30);
+                       /* Obey the OEN pin */
+                       ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00);
+               } else {
+                       dprintk("ks0127: command "
                                        "DECODER_ENABLE_OUTPUT off "
                                        "(%d)\n", enable);
-                               /* Video output pins off */
-                               ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00);
-                               /* Ignore the OEN pin */
-                               ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80);
-                       }
+                       /* Video output pins off */
+                       ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00);
+                       /* Ignore the OEN pin */
+                       ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80);
+               }
        }
                break;
 
index 7c8ef6a..a9ef780 100644 (file)
@@ -1806,6 +1806,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
        memcpy(meye.video_dev, &meye_template, sizeof(meye_template));
        meye.video_dev->parent = &meye.mchip_dev->dev;
 
+       ret = -EIO;
        if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) {
                printk(KERN_ERR "meye: unable to power on the camera\n");
                printk(KERN_ERR "meye: did you enable the camera in "
@@ -1813,7 +1814,6 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
                goto outsonypienable;
        }
 
-       ret = -EIO;
        if ((ret = pci_enable_device(meye.mchip_dev))) {
                printk(KERN_ERR "meye: pci_enable_device failed\n");
                goto outenabledev;
index f68e91f..8ef578c 100644 (file)
@@ -931,27 +931,29 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
        return 0;
 }
 
-static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
+static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard)
 {
-       struct mxb* mxb = (struct mxb*)dev->ext_priv;
+       struct mxb *mxb = (struct mxb *)dev->ext_priv;
        int zero = 0;
        int one = 1;
 
-       if(V4L2_STD_PAL_I == std->id ) {
+       if (V4L2_STD_PAL_I == standard->id) {
                v4l2_std_id std = V4L2_STD_PAL_I;
+
                DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
                /* set the 7146 gpio register -- I don't know what this does exactly */
                saa7146_write(dev, GPIO_CTRL, 0x00404050);
                /* unset the 7111 gpio register -- I don't know what this does exactly */
-               mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &zero);
+               mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &zero);
                mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
        } else {
                v4l2_std_id std = V4L2_STD_PAL_BG;
+
                DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
                /* set the 7146 gpio register -- I don't know what this does exactly */
                saa7146_write(dev, GPIO_CTRL, 0x00404050);
                /* set the 7111 gpio register -- I don't know what this does exactly */
-               mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &one);
+               mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &one);
                mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
        }
        return 0;
index 9edaca4..3d3c48d 100644 (file)
@@ -626,9 +626,9 @@ ov511_i2c_write_internal(struct usb_ov511 *ov,
                        break;
 
                /* Retry until idle */
-               do
+               do {
                        rc = reg_r(ov, R511_I2C_CTL);
-               while (rc > 0 && ((rc&1) == 0));
+               while (rc > 0 && ((rc&1) == 0));
                if (rc < 0)
                        break;
 
@@ -703,9 +703,9 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
                        return rc;
 
                /* Retry until idle */
-               do
-                        rc = reg_r(ov, R511_I2C_CTL);
-               while (rc > 0 && ((rc&1) == 0));
+               do {
+                       rc = reg_r(ov, R511_I2C_CTL);
+               } while (rc > 0 && ((rc & 1) == 0));
                if (rc < 0)
                        return rc;
 
@@ -729,9 +729,9 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
                        return rc;
 
                /* Retry until idle */
-               do
+               do {
                        rc = reg_r(ov, R511_I2C_CTL);
-               while (rc > 0 && ((rc&1) == 0));
+               while (rc > 0 && ((rc&1) == 0));
                if (rc < 0)
                        return rc;
 
index 00425d7..7c84f79 100644 (file)
@@ -1019,10 +1019,23 @@ static int init_mediavision(void)
  *     Initialization and module stuff
  */
 
+#ifndef MODULE
+static int enable;
+module_param(enable, int, 0);
+#endif
+
 static int __init init_pms_cards(void)
 {
        printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.02\n");
 
+#ifndef MODULE
+       if (!enable) {
+               printk(KERN_INFO "PMS: not enabled, use pms.enable=1 to "
+                                "probe\n");
+               return -ENODEV;
+       }
+#endif
+
        data_port = io_port +1;
 
        if(init_mediavision())
index 1cccd5c..dbc5607 100644 (file)
@@ -1635,15 +1635,15 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 
        case VIDIOCPWCGVIDCMD:
        {
-               ARG_DEF(struct pwc_video_command, cmd);
-
-               ARGR(cmd).type = pdev->type;
-               ARGR(cmd).release = pdev->release;
-               ARGR(cmd).command_len = pdev->cmd_len;
-               memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
-               ARGR(cmd).bandlength = pdev->vbandlength;
-               ARGR(cmd).frame_size = pdev->frame_size;
-               ARG_OUT(cmd)
+               ARG_DEF(struct pwc_video_command, vcmd);
+
+               ARGR(vcmd).type = pdev->type;
+               ARGR(vcmd).release = pdev->release;
+               ARGR(vcmd).command_len = pdev->cmd_len;
+               memcpy(&ARGR(vcmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
+               ARGR(vcmd).bandlength = pdev->vbandlength;
+               ARGR(vcmd).frame_size = pdev->frame_size;
+               ARG_OUT(vcmd)
                break;
        }
        /*
index bcd1c8f..ad733ca 100644 (file)
@@ -1489,10 +1489,9 @@ static int saa7115_probe(struct i2c_client *client,
                 client->addr << 1, client->adapter->name);
 
        state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
-       i2c_set_clientdata(client, state);
-       if (state == NULL) {
+       if (state == NULL)
                return -ENOMEM;
-       }
+       i2c_set_clientdata(client, state);
        state->input = -1;
        state->output = SAA7115_IPORT_ON;
        state->enable = 1;
index f481277..acceed5 100644 (file)
@@ -1397,7 +1397,7 @@ static int se401_probe(struct usb_interface *intf,
        mutex_init(&se401->lock);
        wmb();
 
-       if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+       if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
                kfree(se401);
                err("video_register_device failed");
                return -EIO;
index 2340876..2da6938 100644 (file)
@@ -3312,6 +3312,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        cam->v4ldev->fops = &sn9c102_fops;
        cam->v4ldev->minor = video_nr[dev_nr];
        cam->v4ldev->release = video_device_release;
+       cam->v4ldev->parent = &udev->dev;
 
        init_completion(&cam->probe);
 
index 6ff489b..90a401d 100644 (file)
@@ -40,11 +40,14 @@ struct sn9c102_device;
 
 static const struct usb_device_id sn9c102_id_table[] = {
        /* SN9C101 and SN9C102 */
+#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
        { SN9C102_USB_DEVICE(0x0c45, 0x6001, BRIDGE_SN9C102), },
        { SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), },
+#endif
        { SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), },
        { SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), },
        { SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), },
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, OV6650 */
        { SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), },
        { SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), },
        { SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), },
@@ -53,29 +56,33 @@ static const struct usb_device_id sn9c102_id_table[] = {
        { 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, 0x602d, BRIDGE_SN9C102), }, HV7131R */
        { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), },
        { SN9C102_USB_DEVICE(0x0c45, 0x6030, 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, 0x6083, BRIDGE_SN9C103), }, HY7131D/E */
        { 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, 0x608e, BRIDGE_SN9C103), }, CISVF10 */
+#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
        { SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), },
+#endif
        { 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, 0x60a8, BRIDGE_SN9C103), }, PAS106 */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), }, TAS5130 */
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, TAS5130 */
        { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), },
        { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), },
        { SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), },
+#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
        { SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), },
+#endif
        { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), },
        { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), },
        { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), },
@@ -105,7 +112,7 @@ static const struct usb_device_id sn9c102_id_table[] = {
        { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), },
        { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), },
        { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), },
-       { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), },
+/*     { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */
        { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
        { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
        { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
index 56dc3d6..dce9474 100644 (file)
@@ -1462,7 +1462,7 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id
        mutex_init (&stv680->lock);
        wmb ();
 
-       if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+       if (video_register_device(stv680->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
                PDEBUG (0, "STV(e): video_register_device failed");
                retval = -EIO;
                goto error_vdev;
index 59166b7..cc27efe 100644 (file)
@@ -736,12 +736,12 @@ static enum ParseState ibmcam_model2_320x240_parse_lines(
                 * make black color and quit the horizontal scanning loop.
                 */
                if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) {
-                       const int j = i * V4L_BYTES_PER_PIXEL;
+                       const int offset = i * V4L_BYTES_PER_PIXEL;
 #if USES_IBMCAM_PUTPIXEL
                        /* Refresh 'f' because we don't use it much with PUTPIXEL */
-                       f = frame->data + (v4l_linesize * frame->curline) + j;
+                       f = frame->data + (v4l_linesize * frame->curline) + offset;
 #endif
-                       memset(f, 0, v4l_linesize - j);
+                       memset(f, 0, v4l_linesize - offset);
                        break;
                }
 
index b779245..2eb4582 100644 (file)
@@ -866,7 +866,7 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
        cam->udev = dev;
        cam->bulkEndpoint = bulkEndpoint;
 
-       if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
+       if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) < 0) {
                kfree(cam);
                printk(KERN_WARNING "video_register_device failed\n");
                return -EIO;
index 6f36006..155fdec 100644 (file)
@@ -257,6 +257,9 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
        int ret;
        char *name_base;
 
+       if (vfd == NULL)
+               return -EINVAL;
+
        switch (type) {
        case VFL_TYPE_GRABBER:
                base = MINOR_VFL_TYPE_GRABBER_MIN;
@@ -281,7 +284,7 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
        default:
                printk(KERN_ERR "%s called with unknown type: %d\n",
                       __func__, type);
-               return -1;
+               return -EINVAL;
        }
 
        /* pick a minor number */
index fdfe773..140ef92 100644 (file)
@@ -499,7 +499,7 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd,
                        p->timestamp.tv_sec / 3600,
                        (int)(p->timestamp.tv_sec / 60) % 60,
                        (int)(p->timestamp.tv_sec % 60),
-                       p->timestamp.tv_usec,
+                       (long)p->timestamp.tv_usec,
                        p->index,
                        prt_names(p->type, v4l2_type_names),
                        p->bytesused, p->flags,
@@ -674,7 +674,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
         __video_do_ioctl will be called again, with one or more
         V4L2 ioctls.
         ********************************************************/
-       if (_IOC_TYPE(cmd) == 'v')
+       if (_IOC_TYPE(cmd) == 'v' && _IOC_NR(cmd) < BASE_VIDIOCPRIVATE)
                return v4l_compat_translate_ioctl(inode, file, cmd, arg,
                                                __video_do_ioctl);
 #endif
index 3518af0..8ba8daa 100644 (file)
@@ -1021,13 +1021,13 @@ static int vivi_release(void)
                dev = list_entry(list, struct vivi_dev, vivi_devlist);
 
                if (-1 != dev->vfd->minor) {
-                       video_unregister_device(dev->vfd);
-                       printk(KERN_INFO "%s: /dev/video%d unregistered.\n",
+                       printk(KERN_INFO "%s: unregistering /dev/video%d\n",
                                VIVI_MODULE_NAME, dev->vfd->minor);
+                       video_unregister_device(dev->vfd);
                } else {
-                       video_device_release(dev->vfd);
-                       printk(KERN_INFO "%s: /dev/video%d released.\n",
+                       printk(KERN_INFO "%s: releasing /dev/video%d\n",
                                VIVI_MODULE_NAME, dev->vfd->minor);
+                       video_device_release(dev->vfd);
                }
 
                kfree(dev);
@@ -1104,19 +1104,29 @@ static struct video_device vivi_template = {
        Initialization and module stuff
    ------------------------------------------------------------------*/
 
+/* This routine allocates from 1 to n_devs virtual drivers.
+
+   The real maximum number of virtual drivers will depend on how many drivers
+   will succeed. This is limited to the maximum number of devices that
+   videodev supports. Since there are 64 minors for video grabbers, this is
+   currently the theoretical maximum limit. However, a further limit does
+   exist at videodev that forbids any driver to register more than 32 video
+   grabbers.
+ */
 static int __init vivi_init(void)
 {
        int ret = -ENOMEM, i;
        struct vivi_dev *dev;
        struct video_device *vfd;
 
+       if (n_devs <= 0)
+               n_devs = 1;
+
        for (i = 0; i < n_devs; i++) {
                dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-               if (NULL == dev)
+               if (!dev)
                        break;
 
-               list_add_tail(&dev->vivi_devlist, &vivi_devlist);
-
                /* init video dma queues */
                INIT_LIST_HEAD(&dev->vidq.active);
                init_waitqueue_head(&dev->vidq.wq);
@@ -1126,14 +1136,27 @@ static int __init vivi_init(void)
                mutex_init(&dev->mutex);
 
                vfd = video_device_alloc();
-               if (NULL == vfd)
+               if (!vfd) {
+                       kfree(dev);
                        break;
+               }
 
                *vfd = vivi_template;
 
                ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
-               if (ret < 0)
+               if (ret < 0) {
+                       video_device_release(vfd);
+                       kfree(dev);
+
+                       /* If some registers succeeded, keep driver */
+                       if (i)
+                               ret = 0;
+
                        break;
+               }
+
+               /* Now that everything is fine, let's add it to device list */
+               list_add_tail(&dev->vivi_devlist, &vivi_devlist);
 
                snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
                         vivi_template.name, vfd->minor);
@@ -1149,11 +1172,16 @@ static int __init vivi_init(void)
        if (ret < 0) {
                vivi_release();
                printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
-       } else
+       } else {
                printk(KERN_INFO "Video Technology Magazine Virtual Video "
                        "Capture Board ver %u.%u.%u successfully loaded.\n",
                        (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF,
                        VIVI_VERSION & 0xFF);
+
+               /* n_devs will reflect the actual number of allocated devices */
+               n_devs = i;
+       }
+
        return ret;
 }
 
@@ -1169,10 +1197,10 @@ MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
 MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
 MODULE_LICENSE("Dual BSD/GPL");
 
-module_param(video_nr, int, 0);
+module_param(video_nr, uint, 0444);
 MODULE_PARM_DESC(video_nr, "video iminor start number");
 
-module_param(n_devs, int, 0);
+module_param(n_devs, uint, 0444);
 MODULE_PARM_DESC(n_devs, "number of video devices to create");
 
 module_param_named(debug, vivi_template.debug, int, 0444);
index 9402f40..2ff00bc 100644 (file)
@@ -334,7 +334,7 @@ static int w9966_init(struct w9966_dev* cam, struct parport* port)
        memcpy(&cam->vdev, &w9966_template, sizeof(struct video_device));
        cam->vdev.priv = cam;
 
-       if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1)
+       if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
                return -1;
 
        w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
index 550ce7b..0c32877 100644 (file)
@@ -1988,6 +1988,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        cam->v4ldev->fops = &zc0301_fops;
        cam->v4ldev->minor = video_nr[dev_nr];
        cam->v4ldev->release = video_device_release;
+       cam->v4ldev->parent = &udev->dev;
        video_set_drvdata(cam->v4ldev, cam);
 
        init_completion(&cam->probe);
index 70fe6fc..b0cd49c 100644 (file)
@@ -60,27 +60,8 @@ zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor);
 
 #define ZC0301_ID_TABLE                                                       \
 static const struct usb_device_id zc0301_id_table[] =  {                      \
-       { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), }, /* ICM105 */            \
-       { ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */            \
-       { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131 */            \
-       { ZC0301_USB_DEVICE(0x041e, 0x401f, 0xff), }, /* TAS5130 */           \
-       { ZC0301_USB_DEVICE(0x041e, 0x4022, 0xff), },                         \
-       { ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */            \
-       { ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */            \
-       { ZC0301_USB_DEVICE(0x041e, 0x4036, 0xff), }, /* HV7131 */            \
-       { ZC0301_USB_DEVICE(0x041e, 0x403a, 0xff), }, /* HV7131 */            \
-       { ZC0301_USB_DEVICE(0x0458, 0x7007, 0xff), }, /* TAS5130 */           \
-       { ZC0301_USB_DEVICE(0x0458, 0x700c, 0xff), }, /* TAS5130 */           \
-       { ZC0301_USB_DEVICE(0x0458, 0x700f, 0xff), }, /* TAS5130 */           \
        { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
-       { ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */           \
-       { ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */           \
-       { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), },                         \
-       { ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */    \
        { ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */           \
-       { ZC0301_USB_DEVICE(0x10fd, 0x0128, 0xff), }, /* TAS5130 */           \
-       { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130 */           \
-       { ZC0301_USB_DEVICE(0x10fd, 0x804e, 0xff), }, /* TAS5130 */           \
        { }                                                                   \
 };
 
index 7a1ef6c..3e56203 100644 (file)
@@ -463,6 +463,13 @@ static struct dmi_system_id __initdata fujitsu_dmi_table[] = {
                     DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"),
                     },
         .callback = dmi_check_cb_s6410},
+       {
+        .ident = "FUJITSU LifeBook P8010",
+        .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"),
+                   },
+        .callback = dmi_check_cb_s6410},
        {}
 };
 
index d3eb790..6b93007 100644 (file)
@@ -3086,7 +3086,6 @@ static struct ibm_struct wan_driver_data = {
        .read = wan_read,
        .write = wan_write,
        .exit = wan_exit,
-       .flags.experimental = 1,
 };
 
 /*************************************************************************
index 86dbb36..6986f39 100644 (file)
@@ -103,8 +103,10 @@ static int mmc_blk_open(struct inode *inode, struct file *filp)
                        check_disk_change(inode->i_bdev);
                ret = 0;
 
-               if ((filp->f_mode & FMODE_WRITE) && md->read_only)
+               if ((filp->f_mode & FMODE_WRITE) && md->read_only) {
+                       mmc_blk_put(md);
                        ret = -EROFS;
+               }
        }
 
        return ret;
index cbab654..edb1e32 100644 (file)
@@ -109,7 +109,7 @@ struct tmio_nand {
 
        void __iomem *ccr;
        void __iomem *fcr;
-       unsigned long fcr_phys;
+       unsigned long fcr_base;
 
        unsigned int irq;
 
@@ -316,8 +316,8 @@ static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio)
        tmio_iowrite8(0x81, tmio->ccr + CCR_ICC);
 
        /* (10h)BaseAddress    0x1000 spba.spba2 */
-       tmio_iowrite16(tmio->fcr_phys, tmio->ccr + CCR_BASE);
-       tmio_iowrite16(tmio->fcr_phys >> 16, tmio->ccr + CCR_BASE + 16);
+       tmio_iowrite16(tmio->fcr_base, tmio->ccr + CCR_BASE);
+       tmio_iowrite16(tmio->fcr_base >> 16, tmio->ccr + CCR_BASE + 2);
 
        /* (04h)Command Register I/O spcmd */
        tmio_iowrite8(0x02, tmio->ccr + CCR_COMMAND);
@@ -395,7 +395,7 @@ static int tmio_probe(struct platform_device *dev)
                goto err_iomap_ccr;
        }
 
-       tmio->fcr_phys = (unsigned long)fcr->start;
+       tmio->fcr_base = fcr->start & 0xfffff;
        tmio->fcr = ioremap(fcr->start, fcr->end - fcr->start + 1);
        if (!tmio->fcr) {
                retval = -EIO;
index a14dba1..fd705d1 100644 (file)
@@ -151,6 +151,8 @@ struct sw_rx_page {
 #define PAGES_PER_SGE_SHIFT            0
 #define PAGES_PER_SGE                  (1 << PAGES_PER_SGE_SHIFT)
 
+#define BCM_RX_ETH_PAYLOAD_ALIGN       64
+
 /* SGE ring related macros */
 #define NUM_RX_SGE_PAGES               2
 #define RX_SGE_CNT             (BCM_PAGE_SIZE / sizeof(struct eth_rx_sge))
@@ -750,8 +752,7 @@ struct bnx2x {
 
        u32                     rx_csum;
        u32                     rx_offset;
-       u32                     rx_buf_use_size;        /* useable size */
-       u32                     rx_buf_size;            /* with alignment */
+       u32                     rx_buf_size;
 #define ETH_OVREHEAD                   (ETH_HLEN + 8)  /* 8 for CRC + VLAN */
 #define ETH_MIN_PACKET_SIZE            60
 #define ETH_MAX_PACKET_SIZE            1500
index 82deea0..a8eb3c4 100644 (file)
@@ -59,8 +59,8 @@
 #include "bnx2x.h"
 #include "bnx2x_init.h"
 
-#define DRV_MODULE_VERSION     "1.45.20"
-#define DRV_MODULE_RELDATE     "2008/08/25"
+#define DRV_MODULE_VERSION     "1.45.21"
+#define DRV_MODULE_RELDATE     "2008/09/03"
 #define BNX2X_BC_VER           0x040200
 
 /* Time in jiffies before concluding the transmitter is hung */
@@ -1027,7 +1027,7 @@ static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp,
        if (unlikely(skb == NULL))
                return -ENOMEM;
 
-       mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
+       mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_size,
                                 PCI_DMA_FROMDEVICE);
        if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
                dev_kfree_skb(skb);
@@ -1169,7 +1169,7 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
        /* move empty skb from pool to prod and map it */
        prod_rx_buf->skb = fp->tpa_pool[queue].skb;
        mapping = pci_map_single(bp->pdev, fp->tpa_pool[queue].skb->data,
-                                bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
+                                bp->rx_buf_size, PCI_DMA_FROMDEVICE);
        pci_unmap_addr_set(prod_rx_buf, mapping, mapping);
 
        /* move partial skb from cons to pool (don't unmap yet) */
@@ -1276,7 +1276,7 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
           pool entry status to BNX2X_TPA_STOP even if new skb allocation
           fails. */
        pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping),
-                        bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
+                        bp->rx_buf_size, PCI_DMA_FROMDEVICE);
 
        if (likely(new_skb)) {
                /* fix ip xsum and give it to the stack */
@@ -1520,7 +1520,7 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
                        } else if (bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0) {
                                pci_unmap_single(bp->pdev,
                                        pci_unmap_addr(rx_buf, mapping),
-                                                bp->rx_buf_use_size,
+                                                bp->rx_buf_size,
                                                 PCI_DMA_FROMDEVICE);
                                skb_reserve(skb, pad);
                                skb_put(skb, len);
@@ -4229,7 +4229,7 @@ static inline void bnx2x_free_tpa_pool(struct bnx2x *bp,
                if (fp->tpa_state[i] == BNX2X_TPA_START)
                        pci_unmap_single(bp->pdev,
                                         pci_unmap_addr(rx_buf, mapping),
-                                        bp->rx_buf_use_size,
+                                        bp->rx_buf_size,
                                         PCI_DMA_FROMDEVICE);
 
                dev_kfree_skb(skb);
@@ -4245,15 +4245,14 @@ static void bnx2x_init_rx_rings(struct bnx2x *bp)
        u16 ring_prod, cqe_ring_prod;
        int i, j;
 
-       bp->rx_buf_use_size = bp->dev->mtu;
-       bp->rx_buf_use_size += bp->rx_offset + ETH_OVREHEAD;
-       bp->rx_buf_size = bp->rx_buf_use_size + 64;
+       bp->rx_buf_size = bp->dev->mtu;
+       bp->rx_buf_size += bp->rx_offset + ETH_OVREHEAD +
+               BCM_RX_ETH_PAYLOAD_ALIGN;
 
        if (bp->flags & TPA_ENABLE_FLAG) {
                DP(NETIF_MSG_IFUP,
-                  "rx_buf_use_size %d  rx_buf_size %d  effective_mtu %d\n",
-                  bp->rx_buf_use_size, bp->rx_buf_size,
-                  bp->dev->mtu + ETH_OVREHEAD);
+                  "rx_buf_size %d  effective_mtu %d\n",
+                  bp->rx_buf_size, bp->dev->mtu + ETH_OVREHEAD);
 
                for_each_queue(bp, j) {
                        struct bnx2x_fastpath *fp = &bp->fp[j];
@@ -4462,9 +4461,10 @@ static void bnx2x_init_context(struct bnx2x *bp)
                context->ustorm_st_context.common.status_block_id = sb_id;
                context->ustorm_st_context.common.flags =
                        USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_MC_ALIGNMENT;
-               context->ustorm_st_context.common.mc_alignment_size = 64;
+               context->ustorm_st_context.common.mc_alignment_size =
+                       BCM_RX_ETH_PAYLOAD_ALIGN;
                context->ustorm_st_context.common.bd_buff_size =
-                                               bp->rx_buf_use_size;
+                                               bp->rx_buf_size;
                context->ustorm_st_context.common.bd_page_base_hi =
                                                U64_HI(fp->rx_desc_mapping);
                context->ustorm_st_context.common.bd_page_base_lo =
@@ -4717,7 +4717,7 @@ static void bnx2x_init_internal_func(struct bnx2x *bp)
        }
 
        /* Init CQ ring mapping and aggregation size */
-       max_agg_size = min((u32)(bp->rx_buf_use_size +
+       max_agg_size = min((u32)(bp->rx_buf_size +
                                 8*BCM_PAGE_SIZE*PAGES_PER_SGE),
                           (u32)0xffff);
        for_each_queue(bp, i) {
@@ -5940,7 +5940,7 @@ static void bnx2x_free_rx_skbs(struct bnx2x *bp)
 
                        pci_unmap_single(bp->pdev,
                                         pci_unmap_addr(rx_buf, mapping),
-                                        bp->rx_buf_use_size,
+                                        bp->rx_buf_size,
                                         PCI_DMA_FROMDEVICE);
 
                        rx_buf->skb = NULL;
index 331b86b..0b6ecef 100644 (file)
@@ -5975,10 +5975,12 @@ static void nv_shutdown(struct pci_dev *pdev)
        if (netif_running(dev))
                nv_close(dev);
 
-       pci_enable_wake(pdev, PCI_D3hot, np->wolenabled);
-       pci_enable_wake(pdev, PCI_D3cold, np->wolenabled);
        pci_disable_device(pdev);
-       pci_set_power_state(pdev, PCI_D3hot);
+       if (system_state == SYSTEM_POWER_OFF) {
+               if (pci_enable_wake(pdev, PCI_D3cold, np->wolenabled))
+                       pci_enable_wake(pdev, PCI_D3hot, np->wolenabled);
+               pci_set_power_state(pdev, PCI_D3hot);
+       }
 }
 #else
 #define nv_suspend NULL
index 53f41b6..a417be7 100644 (file)
@@ -2303,6 +2303,12 @@ static int __devinit ixgbe_set_interrupt_capability(struct ixgbe_adapter
        int err = 0;
        int vector, v_budget;
 
+       /*
+        * Set the default interrupt throttle rate.
+        */
+       adapter->rx_eitr = (1000000 / IXGBE_DEFAULT_ITR_RX_USECS);
+       adapter->tx_eitr = (1000000 / IXGBE_DEFAULT_ITR_TX_USECS);
+
        /*
         * It's easy to be greedy for MSI-X vectors, but it really
         * doesn't do us much good if we have a lot more vectors
index 32bb47a..008fd66 100644 (file)
@@ -359,16 +359,6 @@ static void netxen_pcie_strap_init(struct netxen_adapter *adapter)
        int i, pos;
        struct pci_dev *pdev;
 
-       pdev = pci_get_device(0x1166, 0x0140, NULL);
-       if (pdev) {
-               pci_dev_put(pdev);
-               adapter->hw_read_wx(adapter,
-                       NETXEN_PCIE_REG(PCIE_TGT_SPLIT_CHICKEN), &chicken, 4);
-               chicken |= 0x4000;
-               adapter->hw_write_wx(adapter,
-                       NETXEN_PCIE_REG(PCIE_TGT_SPLIT_CHICKEN), &chicken, 4);
-       }
-
        pdev = adapter->pdev;
 
        adapter->hw_read_wx(adapter,
index 3f682d4..52bf11b 100644 (file)
@@ -784,6 +784,7 @@ static struct pcmcia_device_id axnet_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXD", 0x5261440f, 0x436768c5),
        PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEtherII PCC-TXD", 0x5261440f, 0x730df72e),
        PCMCIA_DEVICE_PROD_ID12("Dynalink", "L100C16", 0x55632fd5, 0x66bc2a90),
+       PCMCIA_DEVICE_PROD_ID12("IO DATA", "ETXPCM", 0x547e66dc, 0x233adac2),
        PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V3)", 0x0733cc81, 0x232019a8),
        PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC3-TX", 0x481e0094, 0xf91af609),
        PCMCIA_DEVICE_PROD_ID12("PCMCIA", "100BASE", 0x281f1c5d, 0x7c2add04),
index 2d4c4ad..ebc1ae6 100644 (file)
@@ -1626,6 +1626,7 @@ static struct pcmcia_device_id pcnet_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-TD", 0x5261440f, 0xc49bd73d),
        PCMCIA_DEVICE_PROD_ID12("Corega K.K.", "corega EtherII PCC-TD", 0xd4fdcbd8, 0xc49bd73d),
        PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether PCC-T", 0x5261440f, 0x6705fcaa),
+       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether PCC-TD", 0x5261440f, 0x47d5ca83),
        PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FastEther PCC-TX", 0x5261440f, 0x485e85d9),
        PCMCIA_DEVICE_PROD_ID12("Corega,K.K.", "Ethernet LAN Card", 0x110d26d9, 0x9fd2f0a2),
        PCMCIA_DEVICE_PROD_ID12("corega,K.K.", "Ethernet LAN Card", 0x9791a90e, 0x9fd2f0a2),
@@ -1737,7 +1738,6 @@ static struct pcmcia_device_id pcnet_ids[] = {
        PCMCIA_DEVICE_PROD_ID1("CyQ've 10 Base-T LAN CARD", 0x94faf360),
        PCMCIA_DEVICE_PROD_ID1("EP-210 PCMCIA LAN CARD.", 0x8850b4de),
        PCMCIA_DEVICE_PROD_ID1("ETHER-C16", 0x06a8514f),
-       PCMCIA_DEVICE_PROD_ID1("IC-CARD", 0x60cb09a6),
        PCMCIA_DEVICE_PROD_ID1("NE2000 Compatible", 0x75b8ad5a),
        PCMCIA_DEVICE_PROD_ID2("EN-6200P2", 0xa996d078),
        /* too generic! */
index a84ba48..8c19307 100644 (file)
@@ -117,7 +117,7 @@ static void ctrl_callback(struct urb *urb)
        case -ENOENT:
                break;
        default:
-               if (netif_msg_drv(pegasus))
+               if (netif_msg_drv(pegasus) && printk_ratelimit())
                        dev_dbg(&pegasus->intf->dev, "%s, status %d\n",
                                __FUNCTION__, urb->status);
        }
@@ -166,7 +166,7 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
                set_current_state(TASK_RUNNING);
                if (ret == -ENODEV)
                        netif_device_detach(pegasus->net);
-               if (netif_msg_drv(pegasus))
+               if (netif_msg_drv(pegasus) && printk_ratelimit())
                        dev_err(&pegasus->intf->dev, "%s, status %d\n",
                                        __FUNCTION__, ret);
                goto out;
@@ -275,7 +275,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
        if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
                if (ret == -ENODEV)
                        netif_device_detach(pegasus->net);
-               if (netif_msg_drv(pegasus))
+               if (netif_msg_drv(pegasus) && printk_ratelimit())
                        dev_err(&pegasus->intf->dev, "%s, status %d\n",
                                        __FUNCTION__, ret);
                goto out;
@@ -1209,8 +1209,7 @@ static void pegasus_set_multicast(struct net_device *net)
                pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS;
                if (netif_msg_link(pegasus))
                        pr_info("%s: Promiscuous mode enabled.\n", net->name);
-       } else if (net->mc_count ||
-                  (net->flags & IFF_ALLMULTI)) {
+       } else if (net->mc_count || (net->flags & IFF_ALLMULTI)) {
                pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST;
                pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
                if (netif_msg_link(pegasus))
@@ -1220,6 +1219,8 @@ static void pegasus_set_multicast(struct net_device *net)
                pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
        }
 
+       pegasus->ctrl_urb->status = 0;
+
        pegasus->flags |= ETH_REGS_CHANGE;
        ctrl_callback(pegasus->ctrl_urb);
 }
index 95b3371..c5107f2 100644 (file)
@@ -1067,8 +1067,16 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
                tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
                tx_status->flags &= ~ATH_TX_BAR;
        }
-       if (tx_status->flags)
-               tx_info->status.excessive_retries = 1;
+
+       if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) {
+               if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
+                       /* Frame was not ACKed, but an ACK was expected */
+                       tx_info->status.excessive_retries = 1;
+               }
+       } else {
+               /* Frame was ACKed */
+               tx_info->flags |= IEEE80211_TX_STAT_ACK;
+       }
 
        tx_info->status.retry_count = tx_status->retries;
 
index 157f830..550129f 100644 (file)
@@ -357,9 +357,9 @@ static int ath_tx_prepare(struct ath_softc *sc,
        txctl->flags = ATH9K_TXDESC_CLRDMASK;    /* needed for crypto errors */
 
        if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
-               tx_info->flags |= ATH9K_TXDESC_NOACK;
+               txctl->flags |= ATH9K_TXDESC_NOACK;
        if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
-               tx_info->flags |= ATH9K_TXDESC_RTSENA;
+               txctl->flags |= ATH9K_TXDESC_RTSENA;
 
        /*
         * Setup for rate calculations.
index 754fef5..90a2b6d 100644 (file)
@@ -1153,7 +1153,8 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
            !sta->ht_info.ht_supported)
                return -1;
 
-       if (priv->current_ht_config.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC)
+       if (((sta->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS) >> 2)
+                                               == IWL_MIMO_PS_STATIC)
                return -1;
 
        /* Need both Tx chains/antennas to support MIMO */
index c0b73c4..e01f048 100644 (file)
@@ -181,14 +181,14 @@ static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
 }
 
 /**
- * iwl4965_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
+ * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
  * @priv: staging_rxon is compared to active_rxon
  *
  * If the RXON structure is changing enough to require a new tune,
  * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
  * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
  */
-static int iwl4965_full_rxon_required(struct iwl_priv *priv)
+static int iwl_full_rxon_required(struct iwl_priv *priv)
 {
 
        /* These items are only settable from the full RXON command */
@@ -207,7 +207,6 @@ static int iwl4965_full_rxon_required(struct iwl_priv *priv)
             priv->active_rxon.ofdm_ht_single_stream_basic_rates) ||
            (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates !=
             priv->active_rxon.ofdm_ht_dual_stream_basic_rates) ||
-           (priv->staging_rxon.rx_chain != priv->active_rxon.rx_chain) ||
            (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id))
                return 1;
 
@@ -263,7 +262,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
        /* If we don't need to send a full RXON, we can use
         * iwl4965_rxon_assoc_cmd which is used to reconfigure filter
         * and other flags for the current radio configuration. */
-       if (!iwl4965_full_rxon_required(priv)) {
+       if (!iwl_full_rxon_required(priv)) {
                ret = iwl_send_rxon_assoc(priv);
                if (ret) {
                        IWL_ERROR("Error setting RXON_ASSOC (%d)\n", ret);
@@ -587,8 +586,6 @@ static void iwl4965_ht_conf(struct iwl_priv *priv,
                iwl_conf->supported_chan_width = 0;
        }
 
-       iwl_conf->tx_mimo_ps_mode =
-               (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
        memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);
 
        iwl_conf->control_channel = ht_bss_conf->primary_channel;
@@ -2190,7 +2187,10 @@ static void __iwl4965_down(struct iwl_priv *priv)
        udelay(5);
 
        /* FIXME: apm_ops.suspend(priv) */
-       priv->cfg->ops->lib->apm_ops.reset(priv);
+       if (exit_pending || test_bit(STATUS_IN_SUSPEND, &priv->status))
+               priv->cfg->ops->lib->apm_ops.stop(priv);
+       else
+               priv->cfg->ops->lib->apm_ops.reset(priv);
        priv->cfg->ops->lib->free_shared_mem(priv);
 
  exit:
@@ -3588,7 +3588,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
 
        priv->assoc_id = 0;
        timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
-       priv->timestamp = le64_to_cpu(timestamp) +  (priv->beacon_int * 1000);
+       priv->timestamp = le64_to_cpu(timestamp);
 
        IWL_DEBUG_MAC80211("leave\n");
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -4372,15 +4372,18 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
        iwl_dbgfs_unregister(priv);
        sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
 
+       /* ieee80211_unregister_hw call wil cause iwl4965_mac_stop to
+        * to be called and iwl4965_down since we are removing the device
+        * we need to set STATUS_EXIT_PENDING bit.
+        */
+       set_bit(STATUS_EXIT_PENDING, &priv->status);
        if (priv->mac80211_registered) {
                ieee80211_unregister_hw(priv->hw);
                priv->mac80211_registered = 0;
+       } else {
+               iwl4965_down(priv);
        }
 
-       set_bit(STATUS_EXIT_PENDING, &priv->status);
-
-       iwl4965_down(priv);
-
        /* make sure we flush any pending irq or
         * tasklet for the driver
         */
index c72f725..80f2f84 100644 (file)
@@ -592,12 +592,11 @@ static void iwlcore_free_geos(struct iwl_priv *priv)
        clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
 }
 
-static u8 is_single_rx_stream(struct iwl_priv *priv)
+static bool is_single_rx_stream(struct iwl_priv *priv)
 {
        return !priv->current_ht_config.is_ht ||
               ((priv->current_ht_config.supp_mcs_set[1] == 0) &&
-               (priv->current_ht_config.supp_mcs_set[2] == 0)) ||
-              priv->ps_mode == IWL_MIMO_PS_STATIC;
+               (priv->current_ht_config.supp_mcs_set[2] == 0));
 }
 
 static u8 iwl_is_channel_extension(struct iwl_priv *priv,
@@ -704,33 +703,39 @@ EXPORT_SYMBOL(iwl_set_rxon_ht);
  * MIMO (dual stream) requires at least 2, but works better with 3.
  * This does not determine *which* chains to use, just how many.
  */
-static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv,
-                                       u8 *idle_state, u8 *rx_state)
+static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
 {
-       u8 is_single = is_single_rx_stream(priv);
-       u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1;
+       bool is_single = is_single_rx_stream(priv);
+       bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
 
        /* # of Rx chains to use when expecting MIMO. */
        if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC)))
-               *rx_state = 2;
+               return 2;
        else
-               *rx_state = 3;
+               return 3;
+}
 
+static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
+{
+       int idle_cnt;
+       bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
        /* # Rx chains when idling and maybe trying to save power */
        switch (priv->ps_mode) {
        case IWL_MIMO_PS_STATIC:
        case IWL_MIMO_PS_DYNAMIC:
-               *idle_state = (is_cam) ? 2 : 1;
+               idle_cnt = (is_cam) ? 2 : 1;
                break;
        case IWL_MIMO_PS_NONE:
-               *idle_state = (is_cam) ? *rx_state : 1;
+               idle_cnt = (is_cam) ? active_cnt : 1;
                break;
+       case IWL_MIMO_PS_INVALID:
        default:
-               *idle_state = 1;
+               IWL_ERROR("invalide mimo ps mode %d\n", priv->ps_mode);
+               WARN_ON(1);
+               idle_cnt = -1;
                break;
        }
-
-       return 0;
+       return idle_cnt;
 }
 
 /**
@@ -741,34 +746,44 @@ static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv,
  */
 void iwl_set_rxon_chain(struct iwl_priv *priv)
 {
-       u8 is_single = is_single_rx_stream(priv);
-       u8 idle_state, rx_state;
-
-       priv->staging_rxon.rx_chain = 0;
-       rx_state = idle_state = 3;
+       bool is_single = is_single_rx_stream(priv);
+       bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
+       u8 idle_rx_cnt, active_rx_cnt;
+       u16 rx_chain;
 
        /* Tell uCode which antennas are actually connected.
         * Before first association, we assume all antennas are connected.
         * Just after first association, iwl_chain_noise_calibration()
         *    checks which antennas actually *are* connected. */
-       priv->staging_rxon.rx_chain |=
-                   cpu_to_le16(priv->hw_params.valid_rx_ant <<
-                                                RXON_RX_CHAIN_VALID_POS);
+       rx_chain = priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
 
        /* How many receivers should we use? */
-       iwlcore_get_rx_chain_counter(priv, &idle_state, &rx_state);
-       priv->staging_rxon.rx_chain |=
-               cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS);
-       priv->staging_rxon.rx_chain |=
-               cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS);
-
-       if (!is_single && (rx_state >= 2) &&
-           !test_bit(STATUS_POWER_PMI, &priv->status))
+       active_rx_cnt = iwl_get_active_rx_chain_count(priv);
+       idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt);
+
+       /* correct rx chain count accoridng hw settings */
+       if (priv->hw_params.rx_chains_num < active_rx_cnt)
+               active_rx_cnt = priv->hw_params.rx_chains_num;
+
+       if (priv->hw_params.rx_chains_num < idle_rx_cnt)
+               idle_rx_cnt = priv->hw_params.rx_chains_num;
+
+       rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS;
+       rx_chain |= idle_rx_cnt  << RXON_RX_CHAIN_CNT_POS;
+
+       priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain);
+
+       if (!is_single && (active_rx_cnt >= 2) && is_cam)
                priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
        else
                priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
 
-       IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain);
+       IWL_DEBUG_ASSOC("rx_chain=0x%Xi active=%d idle=%d\n",
+                       priv->staging_rxon.rx_chain,
+                       active_rx_cnt, idle_rx_cnt);
+
+       WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 ||
+               active_rx_cnt < idle_rx_cnt);
 }
 EXPORT_SYMBOL(iwl_set_rxon_chain);
 
index c19db43..cdfb343 100644 (file)
@@ -412,7 +412,6 @@ struct iwl_ht_info {
        /* self configuration data */
        u8 is_ht;
        u8 supported_chan_width;
-       u16 tx_mimo_ps_mode;
        u8 is_green_field;
        u8 sgf;                 /* HT_SHORT_GI_* short guard interval */
        u8 max_amsdu_size;
index f3f6ea4..e81bfc4 100644 (file)
@@ -1173,7 +1173,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
 
        rx_status.antenna = 0;
        rx_status.flag = 0;
-       rx_status.flag |= RX_FLAG_TSFT;
+
+       /* TSF isn't reliable. In order to allow smooth user experience,
+        * this W/A doesn't propagate it to the mac80211 */
+       /*rx_status.flag |= RX_FLAG_TSFT;*/
 
        if ((unlikely(rx_start->cfg_phy_cnt > 20))) {
                IWL_DEBUG_DROP("dsp size out of range [0,20]: %d/n",
index 9bb6adb..6c8ac3a 100644 (file)
@@ -421,7 +421,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
                else
                        scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
 
-               if ((scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) && n_probes)
+               if (n_probes)
                        scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
 
                scan_ch->active_dwell = cpu_to_le16(active_dwell);
index ff879d4..78b1a7a 100644 (file)
@@ -402,12 +402,11 @@ static int iwl_hw_tx_queue_init(struct iwl_priv *priv,
 /**
  * iwl_tx_queue_init - Allocate and initialize one tx/cmd queue
  */
-static int iwl_tx_queue_init(struct iwl_priv *priv,
-                            struct iwl_tx_queue *txq,
+static int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
                             int slots_num, u32 txq_id)
 {
        int i, len;
-       int rc = 0;
+       int ret;
 
        /*
         * Alloc buffer array for commands (Tx or other types of commands).
@@ -428,17 +427,14 @@ static int iwl_tx_queue_init(struct iwl_priv *priv,
 
                txq->cmd[i] = kmalloc(len, GFP_KERNEL);
                if (!txq->cmd[i])
-                       return -ENOMEM;
+                       goto err;
        }
 
        /* Alloc driver data array and TFD circular buffer */
-       rc = iwl_tx_queue_alloc(priv, txq, txq_id);
-       if (rc) {
-               for (i = 0; i < slots_num; i++)
-                       kfree(txq->cmd[i]);
+       ret = iwl_tx_queue_alloc(priv, txq, txq_id);
+       if (ret)
+               goto err;
 
-               return -ENOMEM;
-       }
        txq->need_update = 0;
 
        /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
@@ -452,6 +448,17 @@ static int iwl_tx_queue_init(struct iwl_priv *priv,
        iwl_hw_tx_queue_init(priv, txq);
 
        return 0;
+err:
+       for (i = 0; i < slots_num; i++) {
+               kfree(txq->cmd[i]);
+               txq->cmd[i] = NULL;
+       }
+
+       if (txq_id == IWL_CMD_QUEUE_NUM) {
+               kfree(txq->cmd[slots_num]);
+               txq->cmd[slots_num] = NULL;
+       }
+       return -ENOMEM;
 }
 /**
  * iwl_hw_txq_ctx_free - Free TXQ Context
index 82634a2..1aad599 100644 (file)
@@ -352,11 +352,12 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
                                continue;
                        r_size = r->end - r->start + 1;
                        /* For bridges size != alignment */
-                       align = (i < PCI_BRIDGE_RESOURCES) ? r_size : r->start;
+                       align = resource_alignment(r);
                        order = __ffs(align) - 20;
                        if (order > 11) {
-                               dev_warn(&dev->dev, "BAR %d too large: "
+                               dev_warn(&dev->dev, "BAR %d bad alignment %llx: "
                                       "%#016llx-%#016llx\n", i,
+                                      (unsigned long long)align,
                                       (unsigned long long)r->start,
                                       (unsigned long long)r->end);
                                r->flags = 0;
index d7e9f21..95015cb 100644 (file)
@@ -405,8 +405,6 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
 
        case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
                extended_irq = &res->data.extended_irq;
-               if (extended_irq->producer_consumer == ACPI_PRODUCER)
-                       return AE_OK;
 
                if (extended_irq->interrupt_count == 0)
                        pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
index db00b05..f1216cf 100644 (file)
@@ -423,7 +423,7 @@ int chp_new(struct chp_id chpid)
        ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group);
        if (ret) {
                device_unregister(&chp->dev);
-               goto out_free;
+               goto out;
        }
        mutex_lock(&channel_subsystems[chpid.cssid]->mutex);
        if (channel_subsystems[chpid.cssid]->cm_enabled) {
@@ -432,14 +432,15 @@ int chp_new(struct chp_id chpid)
                        sysfs_remove_group(&chp->dev.kobj, &chp_attr_group);
                        device_unregister(&chp->dev);
                        mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
-                       goto out_free;
+                       goto out;
                }
        }
        channel_subsystems[chpid.cssid]->chps[chpid.id] = chp;
        mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
-       return ret;
+       goto out;
 out_free:
        kfree(chp);
+out:
        return ret;
 }
 
index 33bff8f..5954b90 100644 (file)
@@ -208,8 +208,10 @@ cio_start_key (struct subchannel *sch,     /* subchannel structure */
        case 1:         /* status pending */
        case 2:         /* busy */
                return -EBUSY;
-       default:                /* device/path not operational */
+       case 3:         /* device/path not operational */
                return cio_start_handle_notoper(sch, lpm);
+       default:
+               return ccode;
        }
 }
 
index 51489ef..1261e1a 100644 (file)
@@ -633,6 +633,11 @@ channel_subsystem_release(struct device *dev)
 
        css = to_css(dev);
        mutex_destroy(&css->mutex);
+       if (css->pseudo_subchannel) {
+               /* Implies that it has been generated but never registered. */
+               css_subchannel_release(&css->pseudo_subchannel->dev);
+               css->pseudo_subchannel = NULL;
+       }
        kfree(css);
 }
 
@@ -785,11 +790,15 @@ init_channel_subsystem (void)
                }
                channel_subsystems[i] = css;
                ret = setup_css(i);
-               if (ret)
-                       goto out_free;
+               if (ret) {
+                       kfree(channel_subsystems[i]);
+                       goto out_unregister;
+               }
                ret = device_register(&css->device);
-               if (ret)
-                       goto out_free_all;
+               if (ret) {
+                       put_device(&css->device);
+                       goto out_unregister;
+               }
                if (css_chsc_characteristics.secm) {
                        ret = device_create_file(&css->device,
                                                 &dev_attr_cm_enable);
@@ -802,7 +811,7 @@ init_channel_subsystem (void)
        }
        ret = register_reboot_notifier(&css_reboot_notifier);
        if (ret)
-               goto out_pseudo;
+               goto out_unregister;
        css_init_done = 1;
 
        /* Enable default isc for I/O subchannels. */
@@ -810,18 +819,12 @@ init_channel_subsystem (void)
 
        for_each_subchannel(__init_channel_subsystem, NULL);
        return 0;
-out_pseudo:
-       device_unregister(&channel_subsystems[i]->pseudo_subchannel->dev);
 out_file:
-       device_remove_file(&channel_subsystems[i]->device,
-                          &dev_attr_cm_enable);
+       if (css_chsc_characteristics.secm)
+               device_remove_file(&channel_subsystems[i]->device,
+                                  &dev_attr_cm_enable);
 out_device:
        device_unregister(&channel_subsystems[i]->device);
-out_free_all:
-       kfree(channel_subsystems[i]->pseudo_subchannel->lock);
-       kfree(channel_subsystems[i]->pseudo_subchannel);
-out_free:
-       kfree(channel_subsystems[i]);
 out_unregister:
        while (i > 0) {
                struct channel_subsystem *css;
@@ -829,6 +832,7 @@ out_unregister:
                i--;
                css = channel_subsystems[i];
                device_unregister(&css->pseudo_subchannel->dev);
+               css->pseudo_subchannel = NULL;
                if (css_chsc_characteristics.secm)
                        device_remove_file(&css->device,
                                           &dev_attr_cm_enable);
index 550508d..84cc9ea 100644 (file)
@@ -658,6 +658,13 @@ ccw_device_offline(struct ccw_device *cdev)
 {
        struct subchannel *sch;
 
+       /* Allow ccw_device_offline while disconnected. */
+       if (cdev->private->state == DEV_STATE_DISCONNECTED ||
+           cdev->private->state == DEV_STATE_NOT_OPER) {
+               cdev->private->flags.donotify = 0;
+               ccw_device_done(cdev, DEV_STATE_NOT_OPER);
+               return 0;
+       }
        if (ccw_device_is_orphan(cdev)) {
                ccw_device_done(cdev, DEV_STATE_OFFLINE);
                return 0;
index 1eb64d0..95b3ec8 100644 (file)
@@ -208,7 +208,7 @@ static int ohci_omap_init(struct usb_hcd *hcd)
        if (cpu_is_omap16xx())
                ocpi_enable();
 
-#ifdef CONFIG_ARCH_OMAP_OTG
+#ifdef CONFIG_USB_OTG
        if (need_transceiver) {
                ohci->transceiver = otg_get_transceiver();
                if (ohci->transceiver) {
index 7b74238..e980766 100644 (file)
@@ -161,7 +161,7 @@ static int usb_console_setup(struct console *co, char *options)
                if (serial->type->set_termios) {
                        termios->c_cflag = cflag;
                        tty_termios_encode_baud_rate(termios, baud, baud);
-                       serial->type->set_termios(NULL, port, &dummy);
+                       serial->type->set_termios(tty, port, &dummy);
 
                        port->port.tty = NULL;
                        kfree(termios);
index 9c59259..5a24c64 100644 (file)
@@ -939,7 +939,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
        ret = register_framebuffer(info);
        if (ret < 0) {
                dev_err(dev, "failed to register framebuffer device: %d\n", ret);
-               goto free_cmap;
+               goto reset_drvdata;
        }
 
        /* add selected videomode to modelist */
@@ -955,7 +955,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
 
        return 0;
 
-
+reset_drvdata:
+       dev_set_drvdata(dev, NULL);
 free_cmap:
        fb_dealloc_cmap(&info->cmap);
 unregister_irqs:
@@ -992,10 +993,11 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct fb_info *info = dev_get_drvdata(dev);
-       struct atmel_lcdfb_info *sinfo = info->par;
+       struct atmel_lcdfb_info *sinfo;
 
-       if (!sinfo)
+       if (!info || !info->par)
                return 0;
+       sinfo = info->par;
 
        cancel_work_sync(&sinfo->task);
        exit_backlight(sinfo);
index 9abcd2b..e9b2017 100644 (file)
@@ -1279,6 +1279,12 @@ static int nfs_parse_mount_options(char *raw,
                }
        }
 
+       if (errors > 0) {
+               dfprintk(MOUNT, "NFS: parsing encountered %d error%s\n",
+                               errors, (errors == 1 ? "" : "s"));
+               if (!sloppy)
+                       return 0;
+       }
        return 1;
 
 out_nomem:
index 0d6eb33..71c9be5 100644 (file)
@@ -337,65 +337,6 @@ int proc_pid_status(struct seq_file *m, struct pid_namespace *ns,
        return 0;
 }
 
-/*
- * Use precise platform statistics if available:
- */
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
-static cputime_t task_utime(struct task_struct *p)
-{
-       return p->utime;
-}
-
-static cputime_t task_stime(struct task_struct *p)
-{
-       return p->stime;
-}
-#else
-static cputime_t task_utime(struct task_struct *p)
-{
-       clock_t utime = cputime_to_clock_t(p->utime),
-               total = utime + cputime_to_clock_t(p->stime);
-       u64 temp;
-
-       /*
-        * Use CFS's precise accounting:
-        */
-       temp = (u64)nsec_to_clock_t(p->se.sum_exec_runtime);
-
-       if (total) {
-               temp *= utime;
-               do_div(temp, total);
-       }
-       utime = (clock_t)temp;
-
-       p->prev_utime = max(p->prev_utime, clock_t_to_cputime(utime));
-       return p->prev_utime;
-}
-
-static cputime_t task_stime(struct task_struct *p)
-{
-       clock_t stime;
-
-       /*
-        * Use CFS's precise accounting. (we subtract utime from
-        * the total, to make sure the total observed by userspace
-        * grows monotonically - apps rely on that):
-        */
-       stime = nsec_to_clock_t(p->se.sum_exec_runtime) -
-                       cputime_to_clock_t(task_utime(p));
-
-       if (stime >= 0)
-               p->prev_stime = max(p->prev_stime, clock_t_to_cputime(stime));
-
-       return p->prev_stime;
-}
-#endif
-
-static cputime_t task_gtime(struct task_struct *p)
-{
-       return p->gtime;
-}
-
 static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
                        struct pid *pid, struct task_struct *task, int whole)
 {
index 1540981..73db464 100644 (file)
@@ -302,18 +302,6 @@ long long ubifs_calc_available(const struct ubifs_info *c, int min_idx_lebs)
        int subtract_lebs;
        long long available;
 
-       /*
-        * Force the amount available to the total size reported if the used
-        * space is zero.
-        */
-       if (c->lst.total_used <= UBIFS_INO_NODE_SZ &&
-           c->budg_data_growth + c->budg_dd_growth == 0) {
-               /* Do the same calculation as for c->block_cnt */
-               available = c->main_lebs - 2;
-               available *= c->leb_size - c->dark_wm;
-               return available;
-       }
-
        available = c->main_bytes - c->lst.total_used;
 
        /*
@@ -714,34 +702,106 @@ void ubifs_release_dirty_inode_budget(struct ubifs_info *c,
 }
 
 /**
- * ubifs_budg_get_free_space - return amount of free space.
+ * ubifs_reported_space - calculate reported free space.
+ * @c: the UBIFS file-system description object
+ * @free: amount of free space
+ *
+ * This function calculates amount of free space which will be reported to
+ * user-space. User-space application tend to expect that if the file-system
+ * (e.g., via the 'statfs()' call) reports that it has N bytes available, they
+ * are able to write a file of size N. UBIFS attaches node headers to each data
+ * node and it has to write indexind nodes as well. This introduces additional
+ * overhead, and UBIFS it has to report sligtly less free space to meet the
+ * above expectetion.
+ *
+ * This function assumes free space is made up of uncompressed data nodes and
+ * full index nodes (one per data node, tripled because we always allow enough
+ * space to write the index thrice).
+ *
+ * Note, the calculation is pessimistic, which means that most of the time
+ * UBIFS reports less space than it actually has.
+ */
+long long ubifs_reported_space(const struct ubifs_info *c, uint64_t free)
+{
+       int divisor, factor, f;
+
+       /*
+        * Reported space size is @free * X, where X is UBIFS block size
+        * divided by UBIFS block size + all overhead one data block
+        * introduces. The overhead is the node header + indexing overhead.
+        *
+        * Indexing overhead calculations are based on the following formula:
+        * I = N/(f - 1) + 1, where I - number of indexing nodes, N - number
+        * of data nodes, f - fanout. Because effective UBIFS fanout is twice
+        * as less than maximum fanout, we assume that each data node
+        * introduces 3 * @c->max_idx_node_sz / (@c->fanout/2 - 1) bytes.
+        * Note, the multiplier 3 is because UBIFS reseves thrice as more space
+        * for the index.
+        */
+       f = c->fanout > 3 ? c->fanout >> 1 : 2;
+       factor = UBIFS_BLOCK_SIZE;
+       divisor = UBIFS_MAX_DATA_NODE_SZ;
+       divisor += (c->max_idx_node_sz * 3) / (f - 1);
+       free *= factor;
+       do_div(free, divisor);
+       return free;
+}
+
+/**
+ * ubifs_get_free_space - return amount of free space.
  * @c: UBIFS file-system description object
  *
- * This function returns amount of free space on the file-system.
+ * This function calculates amount of free space to report to user-space.
+ *
+ * Because UBIFS may introduce substantial overhead (the index, node headers,
+ * alighment, wastage at the end of eraseblocks, etc), it cannot report real
+ * amount of free flash space it has (well, because not all dirty space is
+ * reclamable, UBIFS does not actually know the real amount). If UBIFS did so,
+ * it would bread user expectetion about what free space is. Users seem to
+ * accustomed to assume that if the file-system reports N bytes of free space,
+ * they would be able to fit a file of N bytes to the FS. This almost works for
+ * traditional file-systems, because they have way less overhead than UBIFS.
+ * So, to keep users happy, UBIFS tries to take the overhead into account.
  */
-long long ubifs_budg_get_free_space(struct ubifs_info *c)
+long long ubifs_get_free_space(struct ubifs_info *c)
 {
-       int min_idx_lebs, rsvd_idx_lebs;
+       int min_idx_lebs, rsvd_idx_lebs, lebs;
        long long available, outstanding, free;
 
-       /* Do exactly the same calculations as in 'do_budget_space()' */
        spin_lock(&c->space_lock);
        min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       outstanding = c->budg_data_growth + c->budg_dd_growth;
 
-       if (min_idx_lebs > c->lst.idx_lebs)
-               rsvd_idx_lebs = min_idx_lebs - c->lst.idx_lebs;
-       else
-               rsvd_idx_lebs = 0;
-
-       if (rsvd_idx_lebs > c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt
-                               - c->lst.taken_empty_lebs) {
+       /*
+        * Force the amount available to the total size reported if the used
+        * space is zero.
+        */
+       if (c->lst.total_used <= UBIFS_INO_NODE_SZ && !outstanding) {
                spin_unlock(&c->space_lock);
-               return 0;
+               return (long long)c->block_cnt << UBIFS_BLOCK_SHIFT;
        }
 
        available = ubifs_calc_available(c, min_idx_lebs);
-       outstanding = c->budg_data_growth + c->budg_dd_growth;
-       c->min_idx_lebs = min_idx_lebs;
+
+       /*
+        * When reporting free space to user-space, UBIFS guarantees that it is
+        * possible to write a file of free space size. This means that for
+        * empty LEBs we may use more precise calculations than
+        * 'ubifs_calc_available()' is using. Namely, we know that in empty
+        * LEBs we would waste only @c->leb_overhead bytes, not @c->dark_wm.
+        * Thus, amend the available space.
+        *
+        * Note, the calculations below are similar to what we have in
+        * 'do_budget_space()', so refer there for comments.
+        */
+       if (min_idx_lebs > c->lst.idx_lebs)
+               rsvd_idx_lebs = min_idx_lebs - c->lst.idx_lebs;
+       else
+               rsvd_idx_lebs = 0;
+       lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
+              c->lst.taken_empty_lebs;
+       lebs -= rsvd_idx_lebs;
+       available += lebs * (c->dark_wm - c->leb_overhead);
        spin_unlock(&c->space_lock);
 
        if (available > outstanding)
index 5c96f1f..2b267c9 100644 (file)
@@ -587,7 +587,6 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
        if (err) {
                if (err != -ENOSPC)
                        return err;
-               err = 0;
                budgeted = 0;
        }
 
index 4071d1c..3d698e2 100644 (file)
@@ -793,7 +793,7 @@ static int do_truncation(struct ubifs_info *c, struct inode *inode,
        int err;
        struct ubifs_budget_req req;
        loff_t old_size = inode->i_size, new_size = attr->ia_size;
-       int offset = new_size & (UBIFS_BLOCK_SIZE - 1);
+       int offset = new_size & (UBIFS_BLOCK_SIZE - 1), budgeted = 1;
        struct ubifs_inode *ui = ubifs_inode(inode);
 
        dbg_gen("ino %lu, size %lld -> %lld", inode->i_ino, old_size, new_size);
@@ -811,8 +811,15 @@ static int do_truncation(struct ubifs_info *c, struct inode *inode,
        /* A funny way to budget for truncation node */
        req.dirtied_ino_d = UBIFS_TRUN_NODE_SZ;
        err = ubifs_budget_space(c, &req);
-       if (err)
-               return err;
+       if (err) {
+               /*
+                * Treat truncations to zero as deletion and always allow them,
+                * just like we do for '->unlink()'.
+                */
+               if (new_size || err != -ENOSPC)
+                       return err;
+               budgeted = 0;
+       }
 
        err = vmtruncate(inode, new_size);
        if (err)
@@ -869,7 +876,12 @@ static int do_truncation(struct ubifs_info *c, struct inode *inode,
        err = ubifs_jnl_truncate(c, inode, old_size, new_size);
        mutex_unlock(&ui->ui_mutex);
 out_budg:
-       ubifs_release_budget(c, &req);
+       if (budgeted)
+               ubifs_release_budget(c, &req);
+       else {
+               c->nospace = c->nospace_rp = 0;
+               smp_wmb();
+       }
        return err;
 }
 
index adee7b5..e045c8b 100644 (file)
@@ -211,14 +211,8 @@ static const struct ubifs_lprops *scan_for_dirty(struct ubifs_info *c,
  * dirty index heap, and it falls-back to LPT scanning if the heaps are empty
  * or do not have an LEB which satisfies the @min_space criteria.
  *
- * Note:
- *   o LEBs which have less than dead watermark of dirty space are never picked
- *   by this function;
- *
- * Returns zero and the LEB properties of
- * found dirty LEB in case of success, %-ENOSPC if no dirty LEB was found and a
- * negative error code in case of other failures. The returned LEB is marked as
- * "taken".
+ * Note, LEBs which have less than dead watermark of free + dirty space are
+ * never picked by this function.
  *
  * The additional @pick_free argument controls if this function has to return a
  * free or freeable LEB if one is present. For example, GC must to set it to %1,
@@ -231,6 +225,10 @@ static const struct ubifs_lprops *scan_for_dirty(struct ubifs_info *c,
  *
  * In addition @pick_free is set to %2 by the recovery process in order to
  * recover gc_lnum in which case an index LEB must not be returned.
+ *
+ * This function returns zero and the LEB properties of found dirty LEB in case
+ * of success, %-ENOSPC if no dirty LEB was found and a negative error code in
+ * case of other failures. The returned LEB is marked as "taken".
  */
 int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
                         int min_space, int pick_free)
@@ -245,7 +243,7 @@ int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
                int lebs, rsvd_idx_lebs = 0;
 
                spin_lock(&c->space_lock);
-               lebs = c->lst.empty_lebs;
+               lebs = c->lst.empty_lebs + c->idx_gc_cnt;
                lebs += c->freeable_cnt - c->lst.taken_empty_lebs;
 
                /*
@@ -317,7 +315,7 @@ int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
                lp = idx_lp;
 
        if (lp) {
-               ubifs_assert(lp->dirty >= c->dead_wm);
+               ubifs_assert(lp->free + lp->dirty >= c->dead_wm);
                goto found;
        }
 
index d0f3dac..13f1019 100644 (file)
@@ -344,6 +344,12 @@ int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp)
                if (err)
                        goto out;
 
+               /* Allow for races with TNC */
+               c->gced_lnum = lnum;
+               smp_wmb();
+               c->gc_seq += 1;
+               smp_wmb();
+
                if (c->gc_lnum == -1) {
                        c->gc_lnum = lnum;
                        err = LEB_RETAINED;
index 87dabf9..4c12a92 100644 (file)
@@ -283,38 +283,6 @@ static inline void *ubifs_idx_key(const struct ubifs_info *c,
        return (void *)((struct ubifs_branch *)idx->branches)->key;
 }
 
-/**
- * ubifs_reported_space - calculate reported free space.
- * @c: the UBIFS file-system description object
- * @free: amount of free space
- *
- * This function calculates amount of free space which will be reported to
- * user-space. User-space application tend to expect that if the file-system
- * (e.g., via the 'statfs()' call) reports that it has N bytes available, they
- * are able to write a file of size N. UBIFS attaches node headers to each data
- * node and it has to write indexind nodes as well. This introduces additional
- * overhead, and UBIFS it has to report sligtly less free space to meet the
- * above expectetion.
- *
- * This function assumes free space is made up of uncompressed data nodes and
- * full index nodes (one per data node, doubled because we always allow enough
- * space to write the index twice).
- *
- * Note, the calculation is pessimistic, which means that most of the time
- * UBIFS reports less space than it actually has.
- */
-static inline long long ubifs_reported_space(const struct ubifs_info *c,
-                                            uint64_t free)
-{
-       int divisor, factor;
-
-       divisor = UBIFS_MAX_DATA_NODE_SZ + (c->max_idx_node_sz * 3);
-       factor = UBIFS_MAX_DATA_NODE_SZ - UBIFS_DATA_NODE_SZ;
-       do_div(free, divisor);
-
-       return free * factor;
-}
-
 /**
  * ubifs_current_time - round current time to time granularity.
  * @inode: inode
@@ -325,4 +293,21 @@ static inline struct timespec ubifs_current_time(struct inode *inode)
                current_fs_time(inode->i_sb) : CURRENT_TIME_SEC;
 }
 
+/**
+ * ubifs_tnc_lookup - look up a file-system node.
+ * @c: UBIFS file-system description object
+ * @key: node key to lookup
+ * @node: the node is returned here
+ *
+ * This function look up and reads node with key @key. The caller has to make
+ * sure the @node buffer is large enough to fit the node. Returns zero in case
+ * of success, %-ENOENT if the node was not found, and a negative error code in
+ * case of failure.
+ */
+static inline int ubifs_tnc_lookup(struct ubifs_info *c,
+                                  const union ubifs_key *key, void *node)
+{
+       return ubifs_tnc_locate(c, key, node, NULL, NULL);
+}
+
 #endif /* __UBIFS_MISC_H__ */
index f71e6b8..7562464 100644 (file)
@@ -370,8 +370,9 @@ static int ubifs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct ubifs_info *c = dentry->d_sb->s_fs_info;
        unsigned long long free;
+       __le32 *uuid = (__le32 *)c->uuid;
 
-       free = ubifs_budg_get_free_space(c);
+       free = ubifs_get_free_space(c);
        dbg_gen("free space %lld bytes (%lld blocks)",
                free, free >> UBIFS_BLOCK_SHIFT);
 
@@ -386,7 +387,8 @@ static int ubifs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_files = 0;
        buf->f_ffree = 0;
        buf->f_namelen = UBIFS_MAX_NLEN;
-
+       buf->f_fsid.val[0] = le32_to_cpu(uuid[0]) ^ le32_to_cpu(uuid[2]);
+       buf->f_fsid.val[1] = le32_to_cpu(uuid[1]) ^ le32_to_cpu(uuid[3]);
        return 0;
 }
 
@@ -530,6 +532,12 @@ static int init_constants_early(struct ubifs_info *c)
        c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size);
        c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size);
 
+       /*
+        * Calculate how many bytes would be wasted at the end of LEB if it was
+        * fully filled with data nodes of maximum size. This is used in
+        * calculations when reporting free space.
+        */
+       c->leb_overhead = c->leb_size % UBIFS_MAX_DATA_NODE_SZ;
        return 0;
 }
 
@@ -647,13 +655,11 @@ static int init_constants_late(struct ubifs_info *c)
         * internally because it does not make much sense for UBIFS, but it is
         * necessary to report something for the 'statfs()' call.
         *
-        * Subtract the LEB reserved for GC and the LEB which is reserved for
-        * deletions.
-        *
-        * Review 'ubifs_calc_available()' if changing this calculation.
+        * Subtract the LEB reserved for GC, the LEB which is reserved for
+        * deletions, and assume only one journal head is available.
         */
-       tmp64 = c->main_lebs - 2;
-       tmp64 *= (uint64_t)c->leb_size - c->dark_wm;
+       tmp64 = c->main_lebs - 2 - c->jhead_cnt + 1;
+       tmp64 *= (uint64_t)c->leb_size - c->leb_overhead;
        tmp64 = ubifs_reported_space(c, tmp64);
        c->block_cnt = tmp64 >> UBIFS_BLOCK_SHIFT;
 
index e909f4a..7da209a 100644 (file)
@@ -506,7 +506,7 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
                if (keys_cmp(c, key, &node_key) != 0)
                        ret = 0;
        }
-       if (ret == 0)
+       if (ret == 0 && c->replaying)
                dbg_mnt("dangling branch LEB %d:%d len %d, key %s",
                        zbr->lnum, zbr->offs, zbr->len, DBGKEY(key));
        return ret;
@@ -1382,50 +1382,39 @@ static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key,
 }
 
 /**
- * ubifs_tnc_lookup - look up a file-system node.
+ * maybe_leb_gced - determine if a LEB may have been garbage collected.
  * @c: UBIFS file-system description object
- * @key: node key to lookup
- * @node: the node is returned here
+ * @lnum: LEB number
+ * @gc_seq1: garbage collection sequence number
  *
- * This function look up and reads node with key @key. The caller has to make
- * sure the @node buffer is large enough to fit the node. Returns zero in case
- * of success, %-ENOENT if the node was not found, and a negative error code in
- * case of failure.
+ * This function determines if @lnum may have been garbage collected since
+ * sequence number @gc_seq1. If it may have been then %1 is returned, otherwise
+ * %0 is returned.
  */
-int ubifs_tnc_lookup(struct ubifs_info *c, const union ubifs_key *key,
-                    void *node)
+static int maybe_leb_gced(struct ubifs_info *c, int lnum, int gc_seq1)
 {
-       int found, n, err;
-       struct ubifs_znode *znode;
-       struct ubifs_zbranch zbr, *zt;
+       int gc_seq2, gced_lnum;
 
-       mutex_lock(&c->tnc_mutex);
-       found = ubifs_lookup_level0(c, key, &znode, &n);
-       if (!found) {
-               err = -ENOENT;
-               goto out;
-       } else if (found < 0) {
-               err = found;
-               goto out;
-       }
-       zt = &znode->zbranch[n];
-       if (is_hash_key(c, key)) {
-               /*
-                * In this case the leaf node cache gets used, so we pass the
-                * address of the zbranch and keep the mutex locked
-                */
-               err = tnc_read_node_nm(c, zt, node);
-               goto out;
-       }
-       zbr = znode->zbranch[n];
-       mutex_unlock(&c->tnc_mutex);
-
-       err = ubifs_tnc_read_node(c, &zbr, node);
-       return err;
-
-out:
-       mutex_unlock(&c->tnc_mutex);
-       return err;
+       gced_lnum = c->gced_lnum;
+       smp_rmb();
+       gc_seq2 = c->gc_seq;
+       /* Same seq means no GC */
+       if (gc_seq1 == gc_seq2)
+               return 0;
+       /* Different by more than 1 means we don't know */
+       if (gc_seq1 + 1 != gc_seq2)
+               return 1;
+       /*
+        * We have seen the sequence number has increased by 1. Now we need to
+        * be sure we read the right LEB number, so read it again.
+        */
+       smp_rmb();
+       if (gced_lnum != c->gced_lnum)
+               return 1;
+       /* Finally we can check lnum */
+       if (gced_lnum == lnum)
+               return 1;
+       return 0;
 }
 
 /**
@@ -1436,16 +1425,19 @@ out:
  * @lnum: LEB number is returned here
  * @offs: offset is returned here
  *
- * This function is the same as 'ubifs_tnc_lookup()' but it returns the node
- * location also. See 'ubifs_tnc_lookup()'.
+ * This function look up and reads node with key @key. The caller has to make
+ * sure the @node buffer is large enough to fit the node. Returns zero in case
+ * of success, %-ENOENT if the node was not found, and a negative error code in
+ * case of failure. The node location can be returned in @lnum and @offs.
  */
 int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
                     void *node, int *lnum, int *offs)
 {
-       int found, n, err;
+       int found, n, err, safely = 0, gc_seq1;
        struct ubifs_znode *znode;
        struct ubifs_zbranch zbr, *zt;
 
+again:
        mutex_lock(&c->tnc_mutex);
        found = ubifs_lookup_level0(c, key, &znode, &n);
        if (!found) {
@@ -1456,24 +1448,43 @@ int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
                goto out;
        }
        zt = &znode->zbranch[n];
+       if (lnum) {
+               *lnum = zt->lnum;
+               *offs = zt->offs;
+       }
        if (is_hash_key(c, key)) {
                /*
                 * In this case the leaf node cache gets used, so we pass the
                 * address of the zbranch and keep the mutex locked
                 */
-               *lnum = zt->lnum;
-               *offs = zt->offs;
                err = tnc_read_node_nm(c, zt, node);
                goto out;
        }
+       if (safely) {
+               err = ubifs_tnc_read_node(c, zt, node);
+               goto out;
+       }
+       /* Drop the TNC mutex prematurely and race with garbage collection */
        zbr = znode->zbranch[n];
+       gc_seq1 = c->gc_seq;
        mutex_unlock(&c->tnc_mutex);
 
-       *lnum = zbr.lnum;
-       *offs = zbr.offs;
+       if (ubifs_get_wbuf(c, zbr.lnum)) {
+               /* We do not GC journal heads */
+               err = ubifs_tnc_read_node(c, &zbr, node);
+               return err;
+       }
 
-       err = ubifs_tnc_read_node(c, &zbr, node);
-       return err;
+       err = fallible_read_node(c, key, &zbr, node);
+       if (maybe_leb_gced(c, zbr.lnum, gc_seq1)) {
+               /*
+                * The node may have been GC'ed out from under us so try again
+                * while keeping the TNC mutex locked.
+                */
+               safely = 1;
+               goto again;
+       }
+       return 0;
 
 out:
        mutex_unlock(&c->tnc_mutex);
@@ -1498,7 +1509,6 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
 {
        int found, n, err;
        struct ubifs_znode *znode;
-       struct ubifs_zbranch zbr;
 
        dbg_tnc("name '%.*s' key %s", nm->len, nm->name, DBGKEY(key));
        mutex_lock(&c->tnc_mutex);
@@ -1522,11 +1532,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
                goto out_unlock;
        }
 
-       zbr = znode->zbranch[n];
-       mutex_unlock(&c->tnc_mutex);
-
-       err = tnc_read_node_nm(c, &zbr, node);
-       return err;
+       err = tnc_read_node_nm(c, &znode->zbranch[n], node);
 
 out_unlock:
        mutex_unlock(&c->tnc_mutex);
index bd2121f..a9ecbd9 100644 (file)
@@ -87,7 +87,7 @@
 #define UBIFS_SK_LEN 8
 
 /* Minimum index tree fanout */
-#define UBIFS_MIN_FANOUT 2
+#define UBIFS_MIN_FANOUT 3
 
 /* Maximum number of levels in UBIFS indexing B-tree */
 #define UBIFS_MAX_LEVELS 512
index d7f706f..17c620b 100644 (file)
@@ -995,6 +995,9 @@ struct ubifs_mount_opts {
  * @max_idx_node_sz: maximum indexing node aligned on 8-bytes boundary
  * @max_inode_sz: maximum possible inode size in bytes
  * @max_znode_sz: size of znode in bytes
+ *
+ * @leb_overhead: how many bytes are wasted in an LEB when it is filled with
+ *                data nodes of maximum size - used in free space reporting
  * @dead_wm: LEB dead space watermark
  * @dark_wm: LEB dark space watermark
  * @block_cnt: count of 4KiB blocks on the FS
@@ -1028,6 +1031,8 @@ struct ubifs_mount_opts {
  * @sbuf: a buffer of LEB size used by GC and replay for scanning
  * @idx_gc: list of index LEBs that have been garbage collected
  * @idx_gc_cnt: number of elements on the idx_gc list
+ * @gc_seq: incremented for every non-index LEB garbage collected
+ * @gced_lnum: last non-index LEB that was garbage collected
  *
  * @infos_list: links all 'ubifs_info' objects
  * @umount_mutex: serializes shrinker and un-mount
@@ -1224,6 +1229,8 @@ struct ubifs_info {
        int max_idx_node_sz;
        long long max_inode_sz;
        int max_znode_sz;
+
+       int leb_overhead;
        int dead_wm;
        int dark_wm;
        int block_cnt;
@@ -1257,6 +1264,8 @@ struct ubifs_info {
        void *sbuf;
        struct list_head idx_gc;
        int idx_gc_cnt;
+       volatile int gc_seq;
+       volatile int gced_lnum;
 
        struct list_head infos_list;
        struct mutex umount_mutex;
@@ -1434,9 +1443,10 @@ void ubifs_release_ino_dirty(struct ubifs_info *c, struct inode *inode,
                                struct ubifs_budget_req *req);
 void ubifs_cancel_ino_op(struct ubifs_info *c, struct inode *inode,
                         struct ubifs_budget_req *req);
-long long ubifs_budg_get_free_space(struct ubifs_info *c);
+long long ubifs_get_free_space(struct ubifs_info *c);
 int ubifs_calc_min_idx_lebs(struct ubifs_info *c);
 void ubifs_convert_page_budget(struct ubifs_info *c);
+long long ubifs_reported_space(const struct ubifs_info *c, uint64_t free);
 long long ubifs_calc_available(const struct ubifs_info *c, int min_idx_lebs);
 
 /* find.c */
@@ -1451,8 +1461,6 @@ int ubifs_save_dirty_idx_lnums(struct ubifs_info *c);
 /* tnc.c */
 int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
                        struct ubifs_znode **zn, int *n);
-int ubifs_tnc_lookup(struct ubifs_info *c, const union ubifs_key *key,
-                    void *node);
 int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
                        void *node, const struct qstr *nm);
 int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
index 1170dc6..1870d5e 100644 (file)
@@ -1,8 +1,10 @@
-ifneq ($(wildcard $(srctree)/include/asm-$(SRCARCH)/kvm.h),)
+ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/kvm.h \
+                 $(srctree)/include/asm-$(SRCARCH)/kvm.h),)
 header-y  += kvm.h
 endif
 
-ifneq ($(wildcard $(srctree)/include/asm-$(SRCARCH)/a.out.h),)
+ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/a.out.h \
+                 $(srctree)/include/asm-$(SRCARCH)/a.out.h),)
 unifdef-y += a.out.h
 endif
 unifdef-y += auxvec.h
index 8feeae1..79a7ff9 100644 (file)
@@ -14,4 +14,10 @@ extern char __kprobes_text_start[], __kprobes_text_end[];
 extern char __initdata_begin[], __initdata_end[];
 extern char __start_rodata[], __end_rodata[];
 
+/* function descriptor handling (if any).  Override
+ * in asm/sections.h */
+#ifndef dereference_function_descriptor
+#define dereference_function_descriptor(p) (p)
+#endif
+
 #endif /* _ASM_GENERIC_SECTIONS_H_ */
index abcf34c..ea8087b 100644 (file)
@@ -126,7 +126,7 @@ void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
  * @args:      array of argument values to store
  *
  * Changes @n arguments to the system call starting with the @i'th argument.
- * @n'th argument to @val.  Argument @i gets value @args[0], and so on.
+ * Argument @i gets value @args[0], and so on.
  * An arch inline version is probably optimal when @i and @n are constants.
  *
  * It's only valid to call this when @task is stopped for tracing on
index d5c0f2f..03b1d69 100644 (file)
@@ -63,6 +63,7 @@ static inline void flush_icache_page(struct vm_area_struct *vma,
 }
 
 extern void (*flush_icache_range)(unsigned long start, unsigned long end);
+extern void (*local_flush_icache_range)(unsigned long start, unsigned long end);
 
 extern void (*__flush_cache_vmap)(void);
 
index fdd43ec..9d13c35 100644 (file)
@@ -4,4 +4,9 @@
 /* nothing to see, move along */
 #include <asm-generic/sections.h>
 
+#ifdef CONFIG_64BIT
+#undef dereference_function_descriptor
+void *dereference_function_descriptor(void *);
+#endif
+
 #endif
index 5939125..b68ec09 100644 (file)
@@ -167,7 +167,8 @@ unifdef-y += acct.h
 unifdef-y += adb.h
 unifdef-y += adfs_fs.h
 unifdef-y += agpgart.h
-ifneq ($(wildcard $(srctree)/include/asm-$(SRCARCH)/a.out.h),)
+ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/a.out.h \
+                 $(srctree)/include/asm-$(SRCARCH)/a.out.h),)
 unifdef-y += a.out.h
 endif
 unifdef-y += apm_bios.h
@@ -258,7 +259,8 @@ unifdef-y += kd.h
 unifdef-y += kernelcapi.h
 unifdef-y += kernel.h
 unifdef-y += keyboard.h
-ifneq ($(wildcard $(srctree)/include/asm-$(SRCARCH)/kvm.h),)
+ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/kvm.h \
+                 $(srctree)/include/asm-$(SRCARCH)/kvm.h),)
 unifdef-y += kvm.h
 endif
 unifdef-y += llc.h
index c33b0dc..ed3a5d4 100644 (file)
@@ -127,6 +127,8 @@ extern int clockevents_register_notifier(struct notifier_block *nb);
 extern int clockevents_program_event(struct clock_event_device *dev,
                                     ktime_t expires, ktime_t now);
 
+extern void clockevents_handle_noop(struct clock_event_device *dev);
+
 #ifdef CONFIG_GENERIC_CLOCKEVENTS
 extern void clockevents_notify(unsigned long reason, void *arg);
 #else
index e8f450c..2691926 100644 (file)
@@ -160,7 +160,7 @@ static inline int current_cpuset_is_being_rebound(void)
 
 static inline void rebuild_sched_domains(void)
 {
-       partition_sched_domains(0, NULL, NULL);
+       partition_sched_domains(1, NULL, NULL);
 }
 
 #endif /* !CONFIG_CPUSETS */
index db35ef0..969f6e9 100644 (file)
@@ -619,6 +619,19 @@ static inline void hlist_add_after(struct hlist_node *n,
                next->next->pprev  = &next->next;
 }
 
+/*
+ * Move a list from one list head to another. Fixup the pprev
+ * reference of the first entry if it exists.
+ */
+static inline void hlist_move_list(struct hlist_head *old,
+                                  struct hlist_head *new)
+{
+       new->first = old->first;
+       if (new->first)
+               new->first->pprev = &new->first;
+       old->first = NULL;
+}
+
 #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
 
 #define hlist_for_each(pos, head) \
index fdeadd9..271c1c2 100644 (file)
@@ -166,7 +166,7 @@ static inline int res_counter_set_limit(struct res_counter *cnt,
        int ret = -EBUSY;
 
        spin_lock_irqsave(&cnt->lock, flags);
-       if (cnt->usage < limit) {
+       if (cnt->usage <= limit) {
                cnt->limit = limit;
                ret = 0;
        }
index cfb0d87..3d9120c 100644 (file)
@@ -1475,6 +1475,10 @@ static inline void put_task_struct(struct task_struct *t)
                __put_task_struct(t);
 }
 
+extern cputime_t task_utime(struct task_struct *p);
+extern cputime_t task_stime(struct task_struct *p);
+extern cputime_t task_gtime(struct task_struct *p);
+
 /*
  * Per process flags
  */
index b48d819..6186a78 100644 (file)
@@ -272,7 +272,7 @@ static inline void tracehook_finish_clone(struct task_struct *child,
  * tracehook_report_clone_complete().  This must prevent the child from
  * self-reaping if tracehook_report_clone_complete() uses the @child
  * pointer; otherwise it might have died and been released by the time
- * tracehook_report_report_clone_complete() is called.
+ * tracehook_report_clone_complete() is called.
  *
  * Called with no locks held, but the child cannot run until this returns.
  */
index e65a6be..303d93f 100644 (file)
@@ -334,6 +334,8 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_SPCA508  v4l2_fourcc('S', '5', '0', '8') /* YUVY per line */
 #define V4L2_PIX_FMT_SPCA561  v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */
 #define V4L2_PIX_FMT_PAC207   v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */
+#define V4L2_PIX_FMT_PJPG     v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */
+#define V4L2_PIX_FMT_YVYU    v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16  YVU 4:2:2     */
 
 /*
  *     F O R M A T   E N U M E R A T I O N
index 95c660c..9132490 100644 (file)
@@ -208,6 +208,9 @@ extern void inet_twsk_schedule(struct inet_timewait_sock *tw,
 extern void inet_twsk_deschedule(struct inet_timewait_sock *tw,
                                 struct inet_timewait_death_row *twdr);
 
+extern void inet_twsk_purge(struct net *net, struct inet_hashinfo *hashinfo,
+                           struct inet_timewait_death_row *twdr, int family);
+
 static inline
 struct net *twsk_net(const struct inet_timewait_sock *twsk)
 {
index d5ab79c..f227bc1 100644 (file)
@@ -14,6 +14,8 @@
  *  2003-10-22 Updates by Stephen Hemminger.
  *  2004 May-July Rework by Paul Jackson.
  *  2006 Rework by Paul Menage to use generic cgroups
+ *  2008 Rework of the scheduler domains and CPU hotplug handling
+ *       by Max Krasnyansky
  *
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License.  See the file COPYING in the main directory of the Linux
@@ -236,9 +238,11 @@ static struct cpuset top_cpuset = {
 
 static DEFINE_MUTEX(callback_mutex);
 
-/* This is ugly, but preserves the userspace API for existing cpuset
+/*
+ * This is ugly, but preserves the userspace API for existing cpuset
  * users. If someone tries to mount the "cpuset" filesystem, we
- * silently switch it to mount "cgroup" instead */
+ * silently switch it to mount "cgroup" instead
+ */
 static int cpuset_get_sb(struct file_system_type *fs_type,
                         int flags, const char *unused_dev_name,
                         void *data, struct vfsmount *mnt)
@@ -473,10 +477,9 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial)
 }
 
 /*
- * Helper routine for rebuild_sched_domains().
+ * Helper routine for generate_sched_domains().
  * Do cpusets a, b have overlapping cpus_allowed masks?
  */
-
 static int cpusets_overlap(struct cpuset *a, struct cpuset *b)
 {
        return cpus_intersects(a->cpus_allowed, b->cpus_allowed);
@@ -518,26 +521,15 @@ update_domain_attr_tree(struct sched_domain_attr *dattr, struct cpuset *c)
 }
 
 /*
- * rebuild_sched_domains()
- *
- * This routine will be called to rebuild the scheduler's dynamic
- * sched domains:
- * - if the flag 'sched_load_balance' of any cpuset with non-empty
- *   'cpus' changes,
- * - or if the 'cpus' allowed changes in any cpuset which has that
- *   flag enabled,
- * - or if the 'sched_relax_domain_level' of any cpuset which has
- *   that flag enabled and with non-empty 'cpus' changes,
- * - or if any cpuset with non-empty 'cpus' is removed,
- * - or if a cpu gets offlined.
- *
- * This routine builds a partial partition of the systems CPUs
- * (the set of non-overlappping cpumask_t's in the array 'part'
- * below), and passes that partial partition to the kernel/sched.c
- * partition_sched_domains() routine, which will rebuild the
- * schedulers load balancing domains (sched domains) as specified
- * by that partial partition.  A 'partial partition' is a set of
- * non-overlapping subsets whose union is a subset of that set.
+ * generate_sched_domains()
+ *
+ * This function builds a partial partition of the systems CPUs
+ * A 'partial partition' is a set of non-overlapping subsets whose
+ * union is a subset of that set.
+ * The output of this function needs to be passed to kernel/sched.c
+ * partition_sched_domains() routine, which will rebuild the scheduler's
+ * load balancing domains (sched domains) as specified by that partial
+ * partition.
  *
  * See "What is sched_load_balance" in Documentation/cpusets.txt
  * for a background explanation of this.
@@ -547,13 +539,7 @@ update_domain_attr_tree(struct sched_domain_attr *dattr, struct cpuset *c)
  * domains when operating in the severe memory shortage situations
  * that could cause allocation failures below.
  *
- * Call with cgroup_mutex held.  May take callback_mutex during
- * call due to the kfifo_alloc() and kmalloc() calls.  May nest
- * a call to the get_online_cpus()/put_online_cpus() pair.
- * Must not be called holding callback_mutex, because we must not
- * call get_online_cpus() while holding callback_mutex.  Elsewhere
- * the kernel nests callback_mutex inside get_online_cpus() calls.
- * So the reverse nesting would risk an ABBA deadlock.
+ * Must be called with cgroup_lock held.
  *
  * The three key local variables below are:
  *    q  - a linked-list queue of cpuset pointers, used to implement a
@@ -588,10 +574,10 @@ update_domain_attr_tree(struct sched_domain_attr *dattr, struct cpuset *c)
  *     element of the partition (one sched domain) to be passed to
  *     partition_sched_domains().
  */
-
-void rebuild_sched_domains(void)
+static int generate_sched_domains(cpumask_t **domains,
+                       struct sched_domain_attr **attributes)
 {
-       LIST_HEAD(q);           /* queue of cpusets to be scanned*/
+       LIST_HEAD(q);           /* queue of cpusets to be scanned */
        struct cpuset *cp;      /* scans q */
        struct cpuset **csa;    /* array of all cpuset ptrs */
        int csn;                /* how many cpuset ptrs in csa so far */
@@ -601,23 +587,26 @@ void rebuild_sched_domains(void)
        int ndoms;              /* number of sched domains in result */
        int nslot;              /* next empty doms[] cpumask_t slot */
 
-       csa = NULL;
+       ndoms = 0;
        doms = NULL;
        dattr = NULL;
+       csa = NULL;
 
        /* Special case for the 99% of systems with one, full, sched domain */
        if (is_sched_load_balance(&top_cpuset)) {
-               ndoms = 1;
                doms = kmalloc(sizeof(cpumask_t), GFP_KERNEL);
                if (!doms)
-                       goto rebuild;
+                       goto done;
+
                dattr = kmalloc(sizeof(struct sched_domain_attr), GFP_KERNEL);
                if (dattr) {
                        *dattr = SD_ATTR_INIT;
                        update_domain_attr_tree(dattr, &top_cpuset);
                }
                *doms = top_cpuset.cpus_allowed;
-               goto rebuild;
+
+               ndoms = 1;
+               goto done;
        }
 
        csa = kmalloc(number_of_cpusets * sizeof(cp), GFP_KERNEL);
@@ -680,61 +669,141 @@ restart:
                }
        }
 
-       /* Convert <csn, csa> to <ndoms, doms> */
+       /*
+        * Now we know how many domains to create.
+        * Convert <csn, csa> to <ndoms, doms> and populate cpu masks.
+        */
        doms = kmalloc(ndoms * sizeof(cpumask_t), GFP_KERNEL);
-       if (!doms)
-               goto rebuild;
+       if (!doms) {
+               ndoms = 0;
+               goto done;
+       }
+
+       /*
+        * The rest of the code, including the scheduler, can deal with
+        * dattr==NULL case. No need to abort if alloc fails.
+        */
        dattr = kmalloc(ndoms * sizeof(struct sched_domain_attr), GFP_KERNEL);
 
        for (nslot = 0, i = 0; i < csn; i++) {
                struct cpuset *a = csa[i];
+               cpumask_t *dp;
                int apn = a->pn;
 
-               if (apn >= 0) {
-                       cpumask_t *dp = doms + nslot;
-
-                       if (nslot == ndoms) {
-                               static int warnings = 10;
-                               if (warnings) {
-                                       printk(KERN_WARNING
-                                        "rebuild_sched_domains confused:"
-                                         " nslot %d, ndoms %d, csn %d, i %d,"
-                                         " apn %d\n",
-                                         nslot, ndoms, csn, i, apn);
-                                       warnings--;
-                               }
-                               continue;
+               if (apn < 0) {
+                       /* Skip completed partitions */
+                       continue;
+               }
+
+               dp = doms + nslot;
+
+               if (nslot == ndoms) {
+                       static int warnings = 10;
+                       if (warnings) {
+                               printk(KERN_WARNING
+                                "rebuild_sched_domains confused:"
+                                 " nslot %d, ndoms %d, csn %d, i %d,"
+                                 " apn %d\n",
+                                 nslot, ndoms, csn, i, apn);
+                               warnings--;
                        }
+                       continue;
+               }
 
-                       cpus_clear(*dp);
-                       if (dattr)
-                               *(dattr + nslot) = SD_ATTR_INIT;
-                       for (j = i; j < csn; j++) {
-                               struct cpuset *b = csa[j];
-
-                               if (apn == b->pn) {
-                                       cpus_or(*dp, *dp, b->cpus_allowed);
-                                       b->pn = -1;
-                                       if (dattr)
-                                               update_domain_attr_tree(dattr
-                                                                  + nslot, b);
-                               }
+               cpus_clear(*dp);
+               if (dattr)
+                       *(dattr + nslot) = SD_ATTR_INIT;
+               for (j = i; j < csn; j++) {
+                       struct cpuset *b = csa[j];
+
+                       if (apn == b->pn) {
+                               cpus_or(*dp, *dp, b->cpus_allowed);
+                               if (dattr)
+                                       update_domain_attr_tree(dattr + nslot, b);
+
+                               /* Done with this partition */
+                               b->pn = -1;
                        }
-                       nslot++;
                }
+               nslot++;
        }
        BUG_ON(nslot != ndoms);
 
-rebuild:
-       /* Have scheduler rebuild sched domains */
+done:
+       kfree(csa);
+
+       *domains    = doms;
+       *attributes = dattr;
+       return ndoms;
+}
+
+/*
+ * Rebuild scheduler domains.
+ *
+ * Call with neither cgroup_mutex held nor within get_online_cpus().
+ * Takes both cgroup_mutex and get_online_cpus().
+ *
+ * Cannot be directly called from cpuset code handling changes
+ * to the cpuset pseudo-filesystem, because it cannot be called
+ * from code that already holds cgroup_mutex.
+ */
+static void do_rebuild_sched_domains(struct work_struct *unused)
+{
+       struct sched_domain_attr *attr;
+       cpumask_t *doms;
+       int ndoms;
+
        get_online_cpus();
-       partition_sched_domains(ndoms, doms, dattr);
+
+       /* Generate domain masks and attrs */
+       cgroup_lock();
+       ndoms = generate_sched_domains(&doms, &attr);
+       cgroup_unlock();
+
+       /* Have scheduler rebuild the domains */
+       partition_sched_domains(ndoms, doms, attr);
+
        put_online_cpus();
+}
 
-done:
-       kfree(csa);
-       /* Don't kfree(doms) -- partition_sched_domains() does that. */
-       /* Don't kfree(dattr) -- partition_sched_domains() does that. */
+static DECLARE_WORK(rebuild_sched_domains_work, do_rebuild_sched_domains);
+
+/*
+ * Rebuild scheduler domains, asynchronously via workqueue.
+ *
+ * If the flag 'sched_load_balance' of any cpuset with non-empty
+ * 'cpus' changes, or if the 'cpus' allowed changes in any cpuset
+ * which has that flag enabled, or if any cpuset with a non-empty
+ * 'cpus' is removed, then call this routine to rebuild the
+ * scheduler's dynamic sched domains.
+ *
+ * The rebuild_sched_domains() and partition_sched_domains()
+ * routines must nest cgroup_lock() inside get_online_cpus(),
+ * but such cpuset changes as these must nest that locking the
+ * other way, holding cgroup_lock() for much of the code.
+ *
+ * So in order to avoid an ABBA deadlock, the cpuset code handling
+ * these user changes delegates the actual sched domain rebuilding
+ * to a separate workqueue thread, which ends up processing the
+ * above do_rebuild_sched_domains() function.
+ */
+static void async_rebuild_sched_domains(void)
+{
+       schedule_work(&rebuild_sched_domains_work);
+}
+
+/*
+ * Accomplishes the same scheduler domain rebuild as the above
+ * async_rebuild_sched_domains(), however it directly calls the
+ * rebuild routine synchronously rather than calling it via an
+ * asynchronous work thread.
+ *
+ * This can only be called from code that is not holding
+ * cgroup_mutex (not nested in a cgroup_lock() call.)
+ */
+void rebuild_sched_domains(void)
+{
+       do_rebuild_sched_domains(NULL);
 }
 
 /**
@@ -863,7 +932,7 @@ static int update_cpumask(struct cpuset *cs, const char *buf)
                return retval;
 
        if (is_load_balanced)
-               rebuild_sched_domains();
+               async_rebuild_sched_domains();
        return 0;
 }
 
@@ -1090,7 +1159,7 @@ static int update_relax_domain_level(struct cpuset *cs, s64 val)
        if (val != cs->relax_domain_level) {
                cs->relax_domain_level = val;
                if (!cpus_empty(cs->cpus_allowed) && is_sched_load_balance(cs))
-                       rebuild_sched_domains();
+                       async_rebuild_sched_domains();
        }
 
        return 0;
@@ -1131,7 +1200,7 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs,
        mutex_unlock(&callback_mutex);
 
        if (cpus_nonempty && balance_flag_changed)
-               rebuild_sched_domains();
+               async_rebuild_sched_domains();
 
        return 0;
 }
@@ -1492,6 +1561,9 @@ static u64 cpuset_read_u64(struct cgroup *cont, struct cftype *cft)
        default:
                BUG();
        }
+
+       /* Unreachable but makes gcc happy */
+       return 0;
 }
 
 static s64 cpuset_read_s64(struct cgroup *cont, struct cftype *cft)
@@ -1504,6 +1576,9 @@ static s64 cpuset_read_s64(struct cgroup *cont, struct cftype *cft)
        default:
                BUG();
        }
+
+       /* Unrechable but makes gcc happy */
+       return 0;
 }
 
 
@@ -1692,15 +1767,9 @@ static struct cgroup_subsys_state *cpuset_create(
 }
 
 /*
- * Locking note on the strange update_flag() call below:
- *
  * If the cpuset being removed has its flag 'sched_load_balance'
  * enabled, then simulate turning sched_load_balance off, which
- * will call rebuild_sched_domains().  The get_online_cpus()
- * call in rebuild_sched_domains() must not be made while holding
- * callback_mutex.  Elsewhere the kernel nests callback_mutex inside
- * get_online_cpus() calls.  So the reverse nesting would risk an
- * ABBA deadlock.
+ * will call async_rebuild_sched_domains().
  */
 
 static void cpuset_destroy(struct cgroup_subsys *ss, struct cgroup *cont)
@@ -1719,7 +1788,7 @@ static void cpuset_destroy(struct cgroup_subsys *ss, struct cgroup *cont)
 struct cgroup_subsys cpuset_subsys = {
        .name = "cpuset",
        .create = cpuset_create,
-       .destroy  = cpuset_destroy,
+       .destroy = cpuset_destroy,
        .can_attach = cpuset_can_attach,
        .attach = cpuset_attach,
        .populate = cpuset_populate,
@@ -1811,7 +1880,7 @@ static void move_member_tasks_to_cpuset(struct cpuset *from, struct cpuset *to)
 }
 
 /*
- * If common_cpu_mem_hotplug_unplug(), below, unplugs any CPUs
+ * If CPU and/or memory hotplug handlers, below, unplug any CPUs
  * or memory nodes, we need to walk over the cpuset hierarchy,
  * removing that CPU or node from all cpusets.  If this removes the
  * last CPU or node from a cpuset, then move the tasks in the empty
@@ -1902,35 +1971,6 @@ static void scan_for_empty_cpusets(const struct cpuset *root)
        }
 }
 
-/*
- * The cpus_allowed and mems_allowed nodemasks in the top_cpuset track
- * cpu_online_map and node_states[N_HIGH_MEMORY].  Force the top cpuset to
- * track what's online after any CPU or memory node hotplug or unplug event.
- *
- * Since there are two callers of this routine, one for CPU hotplug
- * events and one for memory node hotplug events, we could have coded
- * two separate routines here.  We code it as a single common routine
- * in order to minimize text size.
- */
-
-static void common_cpu_mem_hotplug_unplug(int rebuild_sd)
-{
-       cgroup_lock();
-
-       top_cpuset.cpus_allowed = cpu_online_map;
-       top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
-       scan_for_empty_cpusets(&top_cpuset);
-
-       /*
-        * Scheduler destroys domains on hotplug events.
-        * Rebuild them based on the current settings.
-        */
-       if (rebuild_sd)
-               rebuild_sched_domains();
-
-       cgroup_unlock();
-}
-
 /*
  * The top_cpuset tracks what CPUs and Memory Nodes are online,
  * period.  This is necessary in order to make cpusets transparent
@@ -1939,40 +1979,52 @@ static void common_cpu_mem_hotplug_unplug(int rebuild_sd)
  *
  * This routine ensures that top_cpuset.cpus_allowed tracks
  * cpu_online_map on each CPU hotplug (cpuhp) event.
+ *
+ * Called within get_online_cpus().  Needs to call cgroup_lock()
+ * before calling generate_sched_domains().
  */
-
-static int cpuset_handle_cpuhp(struct notifier_block *unused_nb,
+static int cpuset_track_online_cpus(struct notifier_block *unused_nb,
                                unsigned long phase, void *unused_cpu)
 {
+       struct sched_domain_attr *attr;
+       cpumask_t *doms;
+       int ndoms;
+
        switch (phase) {
-       case CPU_UP_CANCELED:
-       case CPU_UP_CANCELED_FROZEN:
-       case CPU_DOWN_FAILED:
-       case CPU_DOWN_FAILED_FROZEN:
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
-               common_cpu_mem_hotplug_unplug(1);
                break;
+
        default:
                return NOTIFY_DONE;
        }
 
+       cgroup_lock();
+       top_cpuset.cpus_allowed = cpu_online_map;
+       scan_for_empty_cpusets(&top_cpuset);
+       ndoms = generate_sched_domains(&doms, &attr);
+       cgroup_unlock();
+
+       /* Have scheduler rebuild the domains */
+       partition_sched_domains(ndoms, doms, attr);
+
        return NOTIFY_OK;
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
 /*
  * Keep top_cpuset.mems_allowed tracking node_states[N_HIGH_MEMORY].
- * Call this routine anytime after you change
- * node_states[N_HIGH_MEMORY].
- * See also the previous routine cpuset_handle_cpuhp().
+ * Call this routine anytime after node_states[N_HIGH_MEMORY] changes.
+ * See also the previous routine cpuset_track_online_cpus().
  */
-
 void cpuset_track_online_nodes(void)
 {
-       common_cpu_mem_hotplug_unplug(0);
+       cgroup_lock();
+       top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
+       scan_for_empty_cpusets(&top_cpuset);
+       cgroup_unlock();
 }
 #endif
 
@@ -1987,7 +2039,7 @@ void __init cpuset_init_smp(void)
        top_cpuset.cpus_allowed = cpu_online_map;
        top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
 
-       hotcpu_notifier(cpuset_handle_cpuhp, 0);
+       hotcpu_notifier(cpuset_track_online_cpus, 0);
 }
 
 /**
index 25ed2ad..1639564 100644 (file)
@@ -112,9 +112,9 @@ static void __exit_signal(struct task_struct *tsk)
                 * We won't ever get here for the group leader, since it
                 * will have been the last reference on the signal_struct.
                 */
-               sig->utime = cputime_add(sig->utime, tsk->utime);
-               sig->stime = cputime_add(sig->stime, tsk->stime);
-               sig->gtime = cputime_add(sig->gtime, tsk->gtime);
+               sig->utime = cputime_add(sig->utime, task_utime(tsk));
+               sig->stime = cputime_add(sig->stime, task_stime(tsk));
+               sig->gtime = cputime_add(sig->gtime, task_gtime(tsk));
                sig->min_flt += tsk->min_flt;
                sig->maj_flt += tsk->maj_flt;
                sig->nvcsw += tsk->nvcsw;
index 9a1ddb8..cc1f81b 100644 (file)
@@ -4178,6 +4178,65 @@ void account_steal_time(struct task_struct *p, cputime_t steal)
                cpustat->steal = cputime64_add(cpustat->steal, tmp);
 }
 
+/*
+ * Use precise platform statistics if available:
+ */
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+cputime_t task_utime(struct task_struct *p)
+{
+       return p->utime;
+}
+
+cputime_t task_stime(struct task_struct *p)
+{
+       return p->stime;
+}
+#else
+cputime_t task_utime(struct task_struct *p)
+{
+       clock_t utime = cputime_to_clock_t(p->utime),
+               total = utime + cputime_to_clock_t(p->stime);
+       u64 temp;
+
+       /*
+        * Use CFS's precise accounting:
+        */
+       temp = (u64)nsec_to_clock_t(p->se.sum_exec_runtime);
+
+       if (total) {
+               temp *= utime;
+               do_div(temp, total);
+       }
+       utime = (clock_t)temp;
+
+       p->prev_utime = max(p->prev_utime, clock_t_to_cputime(utime));
+       return p->prev_utime;
+}
+
+cputime_t task_stime(struct task_struct *p)
+{
+       clock_t stime;
+
+       /*
+        * Use CFS's precise accounting. (we subtract utime from
+        * the total, to make sure the total observed by userspace
+        * grows monotonically - apps rely on that):
+        */
+       stime = nsec_to_clock_t(p->se.sum_exec_runtime) -
+                       cputime_to_clock_t(task_utime(p));
+
+       if (stime >= 0)
+               p->prev_stime = max(p->prev_stime, clock_t_to_cputime(stime));
+
+       return p->prev_stime;
+}
+#endif
+
+inline cputime_t task_gtime(struct task_struct *p)
+{
+       return p->gtime;
+}
+
 /*
  * This function gets called by the timer code, with HZ frequency.
  * We call it with interrupts disabled.
@@ -7637,24 +7696,27 @@ static int dattrs_equal(struct sched_domain_attr *cur, int idx_cur,
  * and partition_sched_domains() will fallback to the single partition
  * 'fallback_doms', it also forces the domains to be rebuilt.
  *
+ * If doms_new==NULL it will be replaced with cpu_online_map.
+ * ndoms_new==0 is a special case for destroying existing domains.
+ * It will not create the default domain.
+ *
  * Call with hotplug lock held
  */
 void partition_sched_domains(int ndoms_new, cpumask_t *doms_new,
                             struct sched_domain_attr *dattr_new)
 {
-       int i, j;
+       int i, j, n;
 
        mutex_lock(&sched_domains_mutex);
 
        /* always unregister in case we don't destroy any domains */
        unregister_sched_domain_sysctl();
 
-       if (doms_new == NULL)
-               ndoms_new = 0;
+       n = doms_new ? ndoms_new : 0;
 
        /* Destroy deleted domains */
        for (i = 0; i < ndoms_cur; i++) {
-               for (j = 0; j < ndoms_new; j++) {
+               for (j = 0; j < n; j++) {
                        if (cpus_equal(doms_cur[i], doms_new[j])
                            && dattrs_equal(dattr_cur, i, dattr_new, j))
                                goto match1;
@@ -7667,7 +7729,6 @@ match1:
 
        if (doms_new == NULL) {
                ndoms_cur = 0;
-               ndoms_new = 1;
                doms_new = &fallback_doms;
                cpus_andnot(doms_new[0], cpu_online_map, cpu_isolated_map);
                dattr_new = NULL;
@@ -7704,8 +7765,13 @@ match2:
 int arch_reinit_sched_domains(void)
 {
        get_online_cpus();
+
+       /* Destroy domains first to force the rebuild */
+       partition_sched_domains(0, NULL, NULL);
+
        rebuild_sched_domains();
        put_online_cpus();
+
        return 0;
 }
 
@@ -7789,7 +7855,7 @@ static int update_sched_domains(struct notifier_block *nfb,
        case CPU_ONLINE_FROZEN:
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
-               partition_sched_domains(0, NULL, NULL);
+               partition_sched_domains(1, NULL, NULL);
                return NOTIFY_OK;
 
        default:
index fe47133..50ec088 100644 (file)
@@ -159,6 +159,7 @@ static int proc_dointvec_taint(struct ctl_table *table, int write, struct file *
 static struct ctl_table root_table[];
 static struct ctl_table_root sysctl_table_root;
 static struct ctl_table_header root_table_header = {
+       .count = 1,
        .ctl_table = root_table,
        .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list),
        .root = &sysctl_table_root,
index 3d1e3e1..1876b52 100644 (file)
@@ -177,7 +177,7 @@ void clockevents_register_device(struct clock_event_device *dev)
 /*
  * Noop handler when we shut down an event device
  */
-static void clockevents_handle_noop(struct clock_event_device *dev)
+void clockevents_handle_noop(struct clock_event_device *dev)
 {
 }
 
@@ -199,7 +199,6 @@ void clockevents_exchange_device(struct clock_event_device *old,
         * released list and do a notify add later.
         */
        if (old) {
-               old->event_handler = clockevents_handle_noop;
                clockevents_set_mode(old, CLOCK_EVT_MODE_UNUSED);
                list_del(&old->list);
                list_add(&old->list, &clockevents_released);
index 5125ddd..1ad46f3 100644 (file)
@@ -245,7 +245,7 @@ static void sync_cmos_clock(unsigned long dummy)
        if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2)
                fail = update_persistent_clock(now);
 
-       next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec;
+       next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec - (TICK_NSEC / 2);
        if (next.tv_nsec <= 0)
                next.tv_nsec += NSEC_PER_SEC;
 
index 31463d3..2f5a382 100644 (file)
@@ -175,6 +175,8 @@ static void tick_do_periodic_broadcast(void)
  */
 static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
 {
+       ktime_t next;
+
        tick_do_periodic_broadcast();
 
        /*
@@ -185,10 +187,13 @@ static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
 
        /*
         * Setup the next period for devices, which do not have
-        * periodic mode:
+        * periodic mode. We read dev->next_event first and add to it
+        * when the event alrady expired. clockevents_program_event()
+        * sets dev->next_event only when the event is really
+        * programmed to the device.
         */
-       for (;;) {
-               ktime_t next = ktime_add(dev->next_event, tick_period);
+       for (next = dev->next_event; ;) {
+               next = ktime_add(next, tick_period);
 
                if (!clockevents_program_event(dev, next, ktime_get()))
                        return;
@@ -205,7 +210,7 @@ static void tick_do_broadcast_on_off(void *why)
        struct clock_event_device *bc, *dev;
        struct tick_device *td;
        unsigned long flags, *reason = why;
-       int cpu;
+       int cpu, bc_stopped;
 
        spin_lock_irqsave(&tick_broadcast_lock, flags);
 
@@ -223,6 +228,8 @@ static void tick_do_broadcast_on_off(void *why)
        if (!tick_device_is_functional(dev))
                goto out;
 
+       bc_stopped = cpus_empty(tick_broadcast_mask);
+
        switch (*reason) {
        case CLOCK_EVT_NOTIFY_BROADCAST_ON:
        case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
@@ -245,9 +252,10 @@ static void tick_do_broadcast_on_off(void *why)
                break;
        }
 
-       if (cpus_empty(tick_broadcast_mask))
-               clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
-       else {
+       if (cpus_empty(tick_broadcast_mask)) {
+               if (!bc_stopped)
+                       clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
+       } else if (bc_stopped) {
                if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
                        tick_broadcast_start_periodic(bc);
                else
@@ -364,16 +372,8 @@ cpumask_t *tick_get_broadcast_oneshot_mask(void)
 static int tick_broadcast_set_event(ktime_t expires, int force)
 {
        struct clock_event_device *bc = tick_broadcast_device.evtdev;
-       ktime_t now = ktime_get();
-       int res;
-
-       for(;;) {
-               res = clockevents_program_event(bc, expires, now);
-               if (!res || !force)
-                       return res;
-               now = ktime_get();
-               expires = ktime_add(now, ktime_set(0, bc->min_delta_ns));
-       }
+
+       return tick_dev_program_event(bc, expires, force);
 }
 
 int tick_resume_broadcast_oneshot(struct clock_event_device *bc)
@@ -491,14 +491,52 @@ static void tick_broadcast_clear_oneshot(int cpu)
        cpu_clear(cpu, tick_broadcast_oneshot_mask);
 }
 
+static void tick_broadcast_init_next_event(cpumask_t *mask, ktime_t expires)
+{
+       struct tick_device *td;
+       int cpu;
+
+       for_each_cpu_mask_nr(cpu, *mask) {
+               td = &per_cpu(tick_cpu_device, cpu);
+               if (td->evtdev)
+                       td->evtdev->next_event = expires;
+       }
+}
+
 /**
  * tick_broadcast_setup_oneshot - setup the broadcast device
  */
 void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
 {
-       bc->event_handler = tick_handle_oneshot_broadcast;
-       clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
-       bc->next_event.tv64 = KTIME_MAX;
+       /* Set it up only once ! */
+       if (bc->event_handler != tick_handle_oneshot_broadcast) {
+               int was_periodic = bc->mode == CLOCK_EVT_MODE_PERIODIC;
+               int cpu = smp_processor_id();
+               cpumask_t mask;
+
+               bc->event_handler = tick_handle_oneshot_broadcast;
+               clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
+
+               /* Take the do_timer update */
+               tick_do_timer_cpu = cpu;
+
+               /*
+                * We must be careful here. There might be other CPUs
+                * waiting for periodic broadcast. We need to set the
+                * oneshot_mask bits for those and program the
+                * broadcast device to fire.
+                */
+               mask = tick_broadcast_mask;
+               cpu_clear(cpu, mask);
+               cpus_or(tick_broadcast_oneshot_mask,
+                       tick_broadcast_oneshot_mask, mask);
+
+               if (was_periodic && !cpus_empty(mask)) {
+                       tick_broadcast_init_next_event(&mask, tick_next_period);
+                       tick_broadcast_set_event(tick_next_period, 1);
+               } else
+                       bc->next_event.tv64 = KTIME_MAX;
+       }
 }
 
 /*
index 80c4336..c477719 100644 (file)
@@ -161,6 +161,7 @@ static void tick_setup_device(struct tick_device *td,
        } else {
                handler = td->evtdev->event_handler;
                next_event = td->evtdev->next_event;
+               td->evtdev->event_handler = clockevents_handle_noop;
        }
 
        td->evtdev = newdev;
index f13f2b7..0ffc291 100644 (file)
@@ -17,6 +17,8 @@ extern void tick_handle_periodic(struct clock_event_device *dev);
 extern void tick_setup_oneshot(struct clock_event_device *newdev,
                               void (*handler)(struct clock_event_device *),
                               ktime_t nextevt);
+extern int tick_dev_program_event(struct clock_event_device *dev,
+                                 ktime_t expires, int force);
 extern int tick_program_event(ktime_t expires, int force);
 extern void tick_oneshot_notify(void);
 extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *));
index 450c049..2e35501 100644 (file)
 #include "tick-internal.h"
 
 /**
- * tick_program_event
+ * tick_program_event internal worker function
  */
-int tick_program_event(ktime_t expires, int force)
+int tick_dev_program_event(struct clock_event_device *dev, ktime_t expires,
+                          int force)
 {
-       struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
        ktime_t now = ktime_get();
+       int i;
 
-       while (1) {
+       for (i = 0;;) {
                int ret = clockevents_program_event(dev, expires, now);
 
                if (!ret || !force)
                        return ret;
+
+               /*
+                * We tried 2 times to program the device with the given
+                * min_delta_ns. If that's not working then we double it
+                * and emit a warning.
+                */
+               if (++i > 2) {
+                       printk(KERN_WARNING "CE: __tick_program_event of %s is "
+                              "stuck %llx %llx\n", dev->name ? dev->name : "?",
+                              now.tv64, expires.tv64);
+                       printk(KERN_WARNING
+                              "CE: increasing min_delta_ns %ld to %ld nsec\n",
+                              dev->min_delta_ns, dev->min_delta_ns << 1);
+                       WARN_ON(1);
+
+                       /* Double the min. delta and try again */
+                       if (!dev->min_delta_ns)
+                               dev->min_delta_ns = 5000;
+                       else
+                               dev->min_delta_ns <<= 1;
+                       i = 0;
+               }
+
                now = ktime_get();
-               expires = ktime_add(now, ktime_set(0, dev->min_delta_ns));
+               expires = ktime_add_ns(now, dev->min_delta_ns);
        }
 }
 
+/**
+ * tick_program_event
+ */
+int tick_program_event(ktime_t expires, int force)
+{
+       struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
+
+       return tick_dev_program_event(dev, expires, force);
+}
+
 /**
  * tick_resume_onshot - resume oneshot mode
  */
@@ -61,7 +95,7 @@ void tick_setup_oneshot(struct clock_event_device *newdev,
 {
        newdev->event_handler = handler;
        clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT);
-       clockevents_program_event(newdev, next_event, ktime_get());
+       tick_dev_program_event(newdev, next_event, 1);
 }
 
 /**
index 7a46bde..a87b046 100644 (file)
@@ -162,6 +162,8 @@ void tick_nohz_stop_idle(int cpu)
                ts->idle_lastupdate = now;
                ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta);
                ts->idle_active = 0;
+
+               sched_clock_idle_wakeup_event(0);
        }
 }
 
@@ -177,6 +179,7 @@ static ktime_t tick_nohz_start_idle(struct tick_sched *ts)
        }
        ts->idle_entrytime = now;
        ts->idle_active = 1;
+       sched_clock_idle_sleep_event();
        return now;
 }
 
index 8b5a7d3..0b50481 100644 (file)
@@ -394,7 +394,7 @@ config LOCKDEP
        bool
        depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
        select STACKTRACE
-       select FRAME_POINTER if !X86 && !MIPS
+       select FRAME_POINTER if !X86 && !MIPS && !PPC
        select KALLSYMS
        select KALLSYMS_ALL
 
@@ -676,13 +676,13 @@ config FAULT_INJECTION_STACKTRACE_FILTER
        depends on FAULT_INJECTION_DEBUG_FS && STACKTRACE_SUPPORT
        depends on !X86_64
        select STACKTRACE
-       select FRAME_POINTER
+       select FRAME_POINTER if !PPC
        help
          Provide stacktrace filter for fault-injection capabilities
 
 config LATENCYTOP
        bool "Latency measuring infrastructure"
-       select FRAME_POINTER if !MIPS
+       select FRAME_POINTER if !MIPS && !PPC
        select KALLSYMS
        select KALLSYMS_ALL
        select STACKTRACE
index 45a6bde..e3ab374 100644 (file)
@@ -112,6 +112,7 @@ static struct debug_obj *lookup_object(void *addr, struct debug_bucket *b)
 
 /*
  * Allocate a new object. If the pool is empty, switch off the debugger.
+ * Must be called with interrupts disabled.
  */
 static struct debug_obj *
 alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr)
@@ -148,17 +149,18 @@ alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr)
 static void free_object(struct debug_obj *obj)
 {
        unsigned long idx = (unsigned long)(obj - obj_static_pool);
+       unsigned long flags;
 
        if (obj_pool_free < ODEBUG_POOL_SIZE || idx < ODEBUG_POOL_SIZE) {
-               spin_lock(&pool_lock);
+               spin_lock_irqsave(&pool_lock, flags);
                hlist_add_head(&obj->node, &obj_pool);
                obj_pool_free++;
                obj_pool_used--;
-               spin_unlock(&pool_lock);
+               spin_unlock_irqrestore(&pool_lock, flags);
        } else {
-               spin_lock(&pool_lock);
+               spin_lock_irqsave(&pool_lock, flags);
                obj_pool_used--;
-               spin_unlock(&pool_lock);
+               spin_unlock_irqrestore(&pool_lock, flags);
                kmem_cache_free(obj_cache, obj);
        }
 }
@@ -171,6 +173,7 @@ static void debug_objects_oom(void)
 {
        struct debug_bucket *db = obj_hash;
        struct hlist_node *node, *tmp;
+       HLIST_HEAD(freelist);
        struct debug_obj *obj;
        unsigned long flags;
        int i;
@@ -179,11 +182,14 @@ static void debug_objects_oom(void)
 
        for (i = 0; i < ODEBUG_HASH_SIZE; i++, db++) {
                spin_lock_irqsave(&db->lock, flags);
-               hlist_for_each_entry_safe(obj, node, tmp, &db->list, node) {
+               hlist_move_list(&db->list, &freelist);
+               spin_unlock_irqrestore(&db->lock, flags);
+
+               /* Now free them */
+               hlist_for_each_entry_safe(obj, node, tmp, &freelist, node) {
                        hlist_del(&obj->node);
                        free_object(obj);
                }
-               spin_unlock_irqrestore(&db->lock, flags);
        }
 }
 
@@ -498,8 +504,9 @@ void debug_object_free(void *addr, struct debug_obj_descr *descr)
                return;
        default:
                hlist_del(&obj->node);
+               spin_unlock_irqrestore(&db->lock, flags);
                free_object(obj);
-               break;
+               return;
        }
 out_unlock:
        spin_unlock_irqrestore(&db->lock, flags);
@@ -510,6 +517,7 @@ static void __debug_check_no_obj_freed(const void *address, unsigned long size)
 {
        unsigned long flags, oaddr, saddr, eaddr, paddr, chunks;
        struct hlist_node *node, *tmp;
+       HLIST_HEAD(freelist);
        struct debug_obj_descr *descr;
        enum debug_obj_state state;
        struct debug_bucket *db;
@@ -545,11 +553,18 @@ repeat:
                                goto repeat;
                        default:
                                hlist_del(&obj->node);
-                               free_object(obj);
+                               hlist_add_head(&obj->node, &freelist);
                                break;
                        }
                }
                spin_unlock_irqrestore(&db->lock, flags);
+
+               /* Now free them */
+               hlist_for_each_entry_safe(obj, node, tmp, &freelist, node) {
+                       hlist_del(&obj->node);
+                       free_object(obj);
+               }
+
                if (cnt > debug_objects_maxchain)
                        debug_objects_maxchain = cnt;
        }
index d8d1d11..c399bc1 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <asm/page.h>          /* for PAGE_SIZE */
 #include <asm/div64.h>
+#include <asm/sections.h>      /* for dereference_function_descriptor() */
 
 /* Works only for digits and letters, but small and fast */
 #define TOLOWER(x) ((x) | 0x20)
@@ -513,16 +514,6 @@ static char *string(char *buf, char *end, char *s, int field_width, int precisio
        return buf;
 }
 
-static inline void *dereference_function_descriptor(void *ptr)
-{
-#if defined(CONFIG_IA64) || defined(CONFIG_PPC64)
-       void *p;
-       if (!probe_kernel_address(ptr, p))
-               ptr = p;
-#endif
-       return ptr;
-}
-
 static char *symbol_string(char *buf, char *end, void *ptr, int field_width, int precision, int flags)
 {
        unsigned long value = (unsigned long) ptr;
index 339cf5c..e7a5a68 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1030,6 +1030,10 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
        } else {
                switch (flags & MAP_TYPE) {
                case MAP_SHARED:
+                       /*
+                        * Ignore pgoff.
+                        */
+                       pgoff = 0;
                        vm_flags |= VM_SHARED | VM_MAYSHARE;
                        break;
                case MAP_PRIVATE:
index eeee218..5bbf073 100644 (file)
@@ -188,15 +188,21 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
                return 0;
 
        case BRCTL_SET_BRIDGE_HELLO_TIME:
+       {
+               unsigned long t = clock_t_to_jiffies(args[1]);
                if (!capable(CAP_NET_ADMIN))
                        return -EPERM;
 
+               if (t < HZ)
+                       return -EINVAL;
+
                spin_lock_bh(&br->lock);
-               br->bridge_hello_time = clock_t_to_jiffies(args[1]);
+               br->bridge_hello_time = t;
                if (br_is_root_bridge(br))
                        br->hello_time = br->bridge_hello_time;
                spin_unlock_bh(&br->lock);
                return 0;
+       }
 
        case BRCTL_SET_BRIDGE_MAX_AGE:
                if (!capable(CAP_NET_ADMIN))
index 27d6a51..158dee8 100644 (file)
  */
 static ssize_t store_bridge_parm(struct device *d,
                                 const char *buf, size_t len,
-                                void (*set)(struct net_bridge *, unsigned long))
+                                int (*set)(struct net_bridge *, unsigned long))
 {
        struct net_bridge *br = to_bridge(d);
        char *endp;
        unsigned long val;
+       int err;
 
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
@@ -43,9 +44,9 @@ static ssize_t store_bridge_parm(struct device *d,
                return -EINVAL;
 
        spin_lock_bh(&br->lock);
-       (*set)(br, val);
+       err = (*set)(br, val);
        spin_unlock_bh(&br->lock);
-       return len;
+       return err ? err : len;
 }
 
 
@@ -56,12 +57,13 @@ static ssize_t show_forward_delay(struct device *d,
        return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
 }
 
-static void set_forward_delay(struct net_bridge *br, unsigned long val)
+static int set_forward_delay(struct net_bridge *br, unsigned long val)
 {
        unsigned long delay = clock_t_to_jiffies(val);
        br->forward_delay = delay;
        if (br_is_root_bridge(br))
                br->bridge_forward_delay = delay;
+       return 0;
 }
 
 static ssize_t store_forward_delay(struct device *d,
@@ -80,12 +82,17 @@ static ssize_t show_hello_time(struct device *d, struct device_attribute *attr,
                       jiffies_to_clock_t(to_bridge(d)->hello_time));
 }
 
-static void set_hello_time(struct net_bridge *br, unsigned long val)
+static int set_hello_time(struct net_bridge *br, unsigned long val)
 {
        unsigned long t = clock_t_to_jiffies(val);
+
+       if (t < HZ)
+               return -EINVAL;
+
        br->hello_time = t;
        if (br_is_root_bridge(br))
                br->bridge_hello_time = t;
+       return 0;
 }
 
 static ssize_t store_hello_time(struct device *d,
@@ -104,12 +111,13 @@ static ssize_t show_max_age(struct device *d, struct device_attribute *attr,
                       jiffies_to_clock_t(to_bridge(d)->max_age));
 }
 
-static void set_max_age(struct net_bridge *br, unsigned long val)
+static int set_max_age(struct net_bridge *br, unsigned long val)
 {
        unsigned long t = clock_t_to_jiffies(val);
        br->max_age = t;
        if (br_is_root_bridge(br))
                br->bridge_max_age = t;
+       return 0;
 }
 
 static ssize_t store_max_age(struct device *d, struct device_attribute *attr,
@@ -126,9 +134,10 @@ static ssize_t show_ageing_time(struct device *d,
        return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time));
 }
 
-static void set_ageing_time(struct net_bridge *br, unsigned long val)
+static int set_ageing_time(struct net_bridge *br, unsigned long val)
 {
        br->ageing_time = clock_t_to_jiffies(val);
+       return 0;
 }
 
 static ssize_t store_ageing_time(struct device *d,
@@ -180,9 +189,10 @@ static ssize_t show_priority(struct device *d, struct device_attribute *attr,
                       (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]);
 }
 
-static void set_priority(struct net_bridge *br, unsigned long val)
+static int set_priority(struct net_bridge *br, unsigned long val)
 {
        br_stp_set_bridge_priority(br, (u16) val);
+       return 0;
 }
 
 static ssize_t store_priority(struct device *d, struct device_attribute *attr,
index 60c51f7..e719ed2 100644 (file)
@@ -1991,8 +1991,13 @@ static void net_tx_action(struct softirq_action *h)
                                spin_unlock(root_lock);
                        } else {
                                if (!test_bit(__QDISC_STATE_DEACTIVATED,
-                                             &q->state))
+                                             &q->state)) {
                                        __netif_reschedule(q);
+                               } else {
+                                       smp_mb__before_clear_bit();
+                                       clear_bit(__QDISC_STATE_SCHED,
+                                                 &q->state);
+                               }
                        }
                }
        }
index d985bd6..743f011 100644 (file)
@@ -409,3 +409,38 @@ out:
 }
 
 EXPORT_SYMBOL_GPL(inet_twdr_twcal_tick);
+
+void inet_twsk_purge(struct net *net, struct inet_hashinfo *hashinfo,
+                    struct inet_timewait_death_row *twdr, int family)
+{
+       struct inet_timewait_sock *tw;
+       struct sock *sk;
+       struct hlist_node *node;
+       int h;
+
+       local_bh_disable();
+       for (h = 0; h < (hashinfo->ehash_size); h++) {
+               struct inet_ehash_bucket *head =
+                       inet_ehash_bucket(hashinfo, h);
+               rwlock_t *lock = inet_ehash_lockp(hashinfo, h);
+restart:
+               write_lock(lock);
+               sk_for_each(sk, node, &head->twchain) {
+
+                       tw = inet_twsk(sk);
+                       if (!net_eq(twsk_net(tw), net) ||
+                           tw->tw_family != family)
+                               continue;
+
+                       atomic_inc(&tw->tw_refcnt);
+                       write_unlock(lock);
+                       inet_twsk_deschedule(tw, twdr);
+                       inet_twsk_put(tw);
+
+                       goto restart;
+               }
+               write_unlock(lock);
+       }
+       local_bh_enable();
+}
+EXPORT_SYMBOL_GPL(inet_twsk_purge);
index 44c1e93..1b4fee2 100644 (file)
@@ -2376,6 +2376,7 @@ static int __net_init tcp_sk_init(struct net *net)
 static void __net_exit tcp_sk_exit(struct net *net)
 {
        inet_ctl_sock_destroy(net->ipv4.tcp_sock);
+       inet_twsk_purge(net, &tcp_hashinfo, &tcp_death_row, AF_INET);
 }
 
 static struct pernet_operations __net_initdata tcp_sk_ops = {
index 5b90b36..b585c85 100644 (file)
@@ -2148,6 +2148,7 @@ static int tcpv6_net_init(struct net *net)
 static void tcpv6_net_exit(struct net *net)
 {
        inet_ctl_sock_destroy(net->ipv6.tcp_sk);
+       inet_twsk_purge(net, &tcp_hashinfo, &tcp_death_row, AF_INET6);
 }
 
 static struct pernet_operations tcpv6_net_ops = {
index 9bb68c6..902cac1 100644 (file)
@@ -478,21 +478,51 @@ int ieee80211_ht_addt_info_ie_to_ht_bss_info(
 static void ieee80211_sta_send_associnfo(struct net_device *dev,
                                         struct ieee80211_if_sta *ifsta)
 {
+       char *buf;
+       size_t len;
+       int i;
        union iwreq_data wrqu;
 
+       if (!ifsta->assocreq_ies && !ifsta->assocresp_ies)
+               return;
+
+       buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len +
+                               ifsta->assocresp_ies_len), GFP_KERNEL);
+       if (!buf)
+               return;
+
+       len = sprintf(buf, "ASSOCINFO(");
        if (ifsta->assocreq_ies) {
-               memset(&wrqu, 0, sizeof(wrqu));
-               wrqu.data.length = ifsta->assocreq_ies_len;
-               wireless_send_event(dev, IWEVASSOCREQIE, &wrqu,
-                                   ifsta->assocreq_ies);
+               len += sprintf(buf + len, "ReqIEs=");
+               for (i = 0; i < ifsta->assocreq_ies_len; i++) {
+                       len += sprintf(buf + len, "%02x",
+                                      ifsta->assocreq_ies[i]);
+               }
        }
-
        if (ifsta->assocresp_ies) {
-               memset(&wrqu, 0, sizeof(wrqu));
-               wrqu.data.length = ifsta->assocresp_ies_len;
-               wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu,
-                                   ifsta->assocresp_ies);
+               if (ifsta->assocreq_ies)
+                       len += sprintf(buf + len, " ");
+               len += sprintf(buf + len, "RespIEs=");
+               for (i = 0; i < ifsta->assocresp_ies_len; i++) {
+                       len += sprintf(buf + len, "%02x",
+                                      ifsta->assocresp_ies[i]);
+               }
+       }
+       len += sprintf(buf + len, ")");
+
+       if (len > IW_CUSTOM_MAX) {
+               len = sprintf(buf, "ASSOCRESPIE=");
+               for (i = 0; i < ifsta->assocresp_ies_len; i++) {
+                       len += sprintf(buf + len, "%02x",
+                                      ifsta->assocresp_ies[i]);
+               }
        }
+
+       memset(&wrqu, 0, sizeof(wrqu));
+       wrqu.data.length = len;
+       wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
+
+       kfree(buf);
 }
 
 
index 1b1226d..20633fd 100644 (file)
@@ -68,11 +68,21 @@ static const char *const dccprotos[] = {
 static int parse_dcc(char *data, const char *data_end, u_int32_t *ip,
                     u_int16_t *port, char **ad_beg_p, char **ad_end_p)
 {
+       char *tmp;
+
        /* at least 12: "AAAAAAAA P\1\n" */
        while (*data++ != ' ')
                if (data > data_end - 12)
                        return -1;
 
+       /* Make sure we have a newline character within the packet boundaries
+        * because simple_strtoul parses until the first invalid character. */
+       for (tmp = data; tmp <= data_end; tmp++)
+               if (*tmp == '\n')
+                       break;
+       if (tmp > data_end || *tmp != '\n')
+               return -1;
+
        *ad_beg_p = data;
        *ip = simple_strtoul(data, &data, 10);
 
index 654a4f7..9bd0396 100644 (file)
@@ -45,12 +45,12 @@ static LIST_HEAD(gre_keymap_list);
 
 void nf_ct_gre_keymap_flush(void)
 {
-       struct list_head *pos, *n;
+       struct nf_ct_gre_keymap *km, *tmp;
 
        write_lock_bh(&nf_ct_gre_lock);
-       list_for_each_safe(pos, n, &gre_keymap_list) {
-               list_del(pos);
-               kfree(pos);
+       list_for_each_entry_safe(km, tmp, &gre_keymap_list, list) {
+               list_del(&km->list);
+               kfree(km);
        }
        write_unlock_bh(&nf_ct_gre_lock);
 }
@@ -97,10 +97,14 @@ int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir,
        kmp = &help->help.ct_pptp_info.keymap[dir];
        if (*kmp) {
                /* check whether it's a retransmission */
+               read_lock_bh(&nf_ct_gre_lock);
                list_for_each_entry(km, &gre_keymap_list, list) {
-                       if (gre_key_cmpfn(km, t) && km == *kmp)
+                       if (gre_key_cmpfn(km, t) && km == *kmp) {
+                               read_unlock_bh(&nf_ct_gre_lock);
                                return 0;
+                       }
                }
+               read_unlock_bh(&nf_ct_gre_lock);
                pr_debug("trying to override keymap_%s for ct %p\n",
                         dir == IP_CT_DIR_REPLY ? "reply" : "orig", ct);
                return -EEXIST;
index 2f9bbc0..1fa306b 100644 (file)
@@ -1193,7 +1193,6 @@ static const struct sip_handler sip_handlers[] = {
 static int process_sip_response(struct sk_buff *skb,
                                const char **dptr, unsigned int *datalen)
 {
-       static const struct sip_handler *handler;
        enum ip_conntrack_info ctinfo;
        struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
        unsigned int matchoff, matchlen;
@@ -1214,6 +1213,8 @@ static int process_sip_response(struct sk_buff *skb,
        dataoff = matchoff + matchlen + 1;
 
        for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
+               const struct sip_handler *handler;
+
                handler = &sip_handlers[i];
                if (handler->response == NULL)
                        continue;
@@ -1228,13 +1229,14 @@ static int process_sip_response(struct sk_buff *skb,
 static int process_sip_request(struct sk_buff *skb,
                               const char **dptr, unsigned int *datalen)
 {
-       static const struct sip_handler *handler;
        enum ip_conntrack_info ctinfo;
        struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
        unsigned int matchoff, matchlen;
        unsigned int cseq, i;
 
        for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
+               const struct sip_handler *handler;
+
                handler = &sip_handlers[i];
                if (handler->request == NULL)
                        continue;
index b1ff16a..3ddaff4 100644 (file)
@@ -96,8 +96,8 @@ struct bcbearer {
        struct media media;
        struct bcbearer_pair bpairs[MAX_BEARERS];
        struct bcbearer_pair bpairs_temp[TIPC_MAX_LINK_PRI + 1];
-       struct node_map remains;
-       struct node_map remains_new;
+       struct tipc_node_map remains;
+       struct tipc_node_map remains_new;
 };
 
 /**
@@ -110,7 +110,7 @@ struct bcbearer {
 
 struct bclink {
        struct link link;
-       struct node node;
+       struct tipc_node node;
 };
 
 
@@ -149,7 +149,7 @@ static void bcbuf_decr_acks(struct sk_buff *buf)
  * Called with 'node' locked, bc_lock unlocked
  */
 
-static void bclink_set_gap(struct node *n_ptr)
+static void bclink_set_gap(struct tipc_node *n_ptr)
 {
        struct sk_buff *buf = n_ptr->bclink.deferred_head;
 
@@ -202,7 +202,7 @@ static void bclink_retransmit_pkt(u32 after, u32 to)
  * Node is locked, bc_lock unlocked.
  */
 
-void tipc_bclink_acknowledge(struct node *n_ptr, u32 acked)
+void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked)
 {
        struct sk_buff *crs;
        struct sk_buff *next;
@@ -250,7 +250,7 @@ void tipc_bclink_acknowledge(struct node *n_ptr, u32 acked)
  * tipc_net_lock and node lock set
  */
 
-static void bclink_send_ack(struct node *n_ptr)
+static void bclink_send_ack(struct tipc_node *n_ptr)
 {
        struct link *l_ptr = n_ptr->active_links[n_ptr->addr & 1];
 
@@ -264,7 +264,7 @@ static void bclink_send_ack(struct node *n_ptr)
  * tipc_net_lock and node lock set
  */
 
-static void bclink_send_nack(struct node *n_ptr)
+static void bclink_send_nack(struct tipc_node *n_ptr)
 {
        struct sk_buff *buf;
        struct tipc_msg *msg;
@@ -308,7 +308,7 @@ static void bclink_send_nack(struct node *n_ptr)
  * tipc_net_lock and node lock set
  */
 
-void tipc_bclink_check_gap(struct node *n_ptr, u32 last_sent)
+void tipc_bclink_check_gap(struct tipc_node *n_ptr, u32 last_sent)
 {
        if (!n_ptr->bclink.supported ||
            less_eq(last_sent, mod(n_ptr->bclink.last_in)))
@@ -328,7 +328,7 @@ void tipc_bclink_check_gap(struct node *n_ptr, u32 last_sent)
 
 static void tipc_bclink_peek_nack(u32 dest, u32 sender_tag, u32 gap_after, u32 gap_to)
 {
-       struct node *n_ptr = tipc_node_find(dest);
+       struct tipc_node *n_ptr = tipc_node_find(dest);
        u32 my_after, my_to;
 
        if (unlikely(!n_ptr || !tipc_node_is_up(n_ptr)))
@@ -418,7 +418,7 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf)
        static int rx_count = 0;
 #endif
        struct tipc_msg *msg = buf_msg(buf);
-       struct node* node = tipc_node_find(msg_prevnode(msg));
+       struct tipc_node* node = tipc_node_find(msg_prevnode(msg));
        u32 next_in;
        u32 seqno;
        struct sk_buff *deferred;
@@ -538,7 +538,7 @@ u32 tipc_bclink_get_last_sent(void)
        return last_sent;
 }
 
-u32 tipc_bclink_acks_missing(struct node *n_ptr)
+u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr)
 {
        return (n_ptr->bclink.supported &&
                (tipc_bclink_get_last_sent() != n_ptr->bclink.acked));
index a2416fa..5aa024b 100644 (file)
 #define WSIZE 32
 
 /**
- * struct node_map - set of node identifiers
+ * struct tipc_node_map - set of node identifiers
  * @count: # of nodes in set
  * @map: bitmap of node identifiers that are in the set
  */
 
-struct node_map {
+struct tipc_node_map {
        u32 count;
        u32 map[MAX_NODES / WSIZE];
 };
@@ -68,7 +68,7 @@ struct port_list {
 };
 
 
-struct node;
+struct tipc_node;
 
 extern char tipc_bclink_name[];
 
@@ -77,7 +77,7 @@ extern char tipc_bclink_name[];
  * nmap_add - add a node to a node map
  */
 
-static inline void tipc_nmap_add(struct node_map *nm_ptr, u32 node)
+static inline void tipc_nmap_add(struct tipc_node_map *nm_ptr, u32 node)
 {
        int n = tipc_node(node);
        int w = n / WSIZE;
@@ -93,7 +93,7 @@ static inline void tipc_nmap_add(struct node_map *nm_ptr, u32 node)
  * nmap_remove - remove a node from a node map
  */
 
-static inline void tipc_nmap_remove(struct node_map *nm_ptr, u32 node)
+static inline void tipc_nmap_remove(struct tipc_node_map *nm_ptr, u32 node)
 {
        int n = tipc_node(node);
        int w = n / WSIZE;
@@ -109,7 +109,7 @@ static inline void tipc_nmap_remove(struct node_map *nm_ptr, u32 node)
  * nmap_equal - test for equality of node maps
  */
 
-static inline int tipc_nmap_equal(struct node_map *nm_a, struct node_map *nm_b)
+static inline int tipc_nmap_equal(struct tipc_node_map *nm_a, struct tipc_node_map *nm_b)
 {
        return !memcmp(nm_a, nm_b, sizeof(*nm_a));
 }
@@ -121,8 +121,8 @@ static inline int tipc_nmap_equal(struct node_map *nm_a, struct node_map *nm_b)
  * @nm_diff: output node map A-B (i.e. nodes of A that are not in B)
  */
 
-static inline void tipc_nmap_diff(struct node_map *nm_a, struct node_map *nm_b,
-                                 struct node_map *nm_diff)
+static inline void tipc_nmap_diff(struct tipc_node_map *nm_a, struct tipc_node_map *nm_b,
+                                 struct tipc_node_map *nm_diff)
 {
        int stop = sizeof(nm_a->map) / sizeof(u32);
        int w;
@@ -195,12 +195,12 @@ static inline void tipc_port_list_free(struct port_list *pl_ptr)
 
 int  tipc_bclink_init(void);
 void tipc_bclink_stop(void);
-void tipc_bclink_acknowledge(struct node *n_ptr, u32 acked);
+void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked);
 int  tipc_bclink_send_msg(struct sk_buff *buf);
 void tipc_bclink_recv_pkt(struct sk_buff *buf);
 u32  tipc_bclink_get_last_sent(void);
-u32  tipc_bclink_acks_missing(struct node *n_ptr);
-void tipc_bclink_check_gap(struct node *n_ptr, u32 seqno);
+u32  tipc_bclink_acks_missing(struct tipc_node *n_ptr);
+void tipc_bclink_check_gap(struct tipc_node *n_ptr, u32 seqno);
 int  tipc_bclink_stats(char *stats_buf, const u32 buf_size);
 int  tipc_bclink_reset_stats(void);
 int  tipc_bclink_set_queue_limits(u32 limit);
index 6a9aba3..a7a3677 100644 (file)
@@ -599,7 +599,7 @@ int tipc_block_bearer(const char *name)
        spin_lock_bh(&b_ptr->publ.lock);
        b_ptr->publ.blocked = 1;
        list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
-               struct node *n_ptr = l_ptr->owner;
+               struct tipc_node *n_ptr = l_ptr->owner;
 
                spin_lock_bh(&n_ptr->lock);
                tipc_link_reset(l_ptr);
index 6a36b66..ca57348 100644 (file)
@@ -104,7 +104,7 @@ struct bearer {
        u32 continue_count;
        int active;
        char net_plane;
-       struct node_map nodes;
+       struct tipc_node_map nodes;
 };
 
 struct bearer_name {
index 46ee6c5..689fdef 100644 (file)
@@ -48,8 +48,8 @@ static void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf,
                                u32 lower, u32 upper);
 static struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest);
 
-struct node **tipc_local_nodes = NULL;
-struct node_map tipc_cltr_bcast_nodes = {0,{0,}};
+struct tipc_node **tipc_local_nodes = NULL;
+struct tipc_node_map tipc_cltr_bcast_nodes = {0,{0,}};
 u32 tipc_highest_allowed_slave = 0;
 
 struct cluster *tipc_cltr_create(u32 addr)
@@ -115,7 +115,7 @@ void tipc_cltr_delete(struct cluster *c_ptr)
 
 u32 tipc_cltr_next_node(struct cluster *c_ptr, u32 addr)
 {
-       struct node *n_ptr;
+       struct tipc_node *n_ptr;
        u32 n_num = tipc_node(addr) + 1;
 
        if (!c_ptr)
@@ -133,7 +133,7 @@ u32 tipc_cltr_next_node(struct cluster *c_ptr, u32 addr)
        return 0;
 }
 
-void tipc_cltr_attach_node(struct cluster *c_ptr, struct node *n_ptr)
+void tipc_cltr_attach_node(struct cluster *c_ptr, struct tipc_node *n_ptr)
 {
        u32 n_num = tipc_node(n_ptr->addr);
        u32 max_n_num = tipc_max_nodes;
@@ -196,7 +196,7 @@ u32 tipc_cltr_select_router(struct cluster *c_ptr, u32 ref)
  * Uses deterministic and fair algorithm.
  */
 
-struct node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector)
+struct tipc_node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector)
 {
        u32 n_num;
        u32 mask = tipc_max_nodes;
@@ -379,7 +379,7 @@ void tipc_cltr_recv_routing_table(struct sk_buff *buf)
 {
        struct tipc_msg *msg = buf_msg(buf);
        struct cluster *c_ptr;
-       struct node *n_ptr;
+       struct tipc_node *n_ptr;
        unchar *node_table;
        u32 table_size;
        u32 router;
@@ -499,7 +499,7 @@ static void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf,
                         u32 lower, u32 upper)
 {
        struct sk_buff *buf_copy;
-       struct node *n_ptr;
+       struct tipc_node *n_ptr;
        u32 n_num;
        u32 tstop;
 
@@ -534,7 +534,7 @@ void tipc_cltr_broadcast(struct sk_buff *buf)
 {
        struct sk_buff *buf_copy;
        struct cluster *c_ptr;
-       struct node *n_ptr;
+       struct tipc_node *n_ptr;
        u32 n_num;
        u32 tstart;
        u32 tstop;
index 62df074..333efb0 100644 (file)
 struct cluster {
        u32 addr;
        struct _zone *owner;
-       struct node **nodes;
+       struct tipc_node **nodes;
        u32 highest_node;
        u32 highest_slave;
 };
 
 
-extern struct node **tipc_local_nodes;
+extern struct tipc_node **tipc_local_nodes;
 extern u32 tipc_highest_allowed_slave;
-extern struct node_map tipc_cltr_bcast_nodes;
+extern struct tipc_node_map tipc_cltr_bcast_nodes;
 
 void tipc_cltr_remove_as_router(struct cluster *c_ptr, u32 router);
 void tipc_cltr_send_ext_routes(struct cluster *c_ptr, u32 dest);
-struct node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector);
+struct tipc_node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector);
 u32 tipc_cltr_select_router(struct cluster *c_ptr, u32 ref);
 void tipc_cltr_recv_routing_table(struct sk_buff *buf);
 struct cluster *tipc_cltr_create(u32 addr);
 void tipc_cltr_delete(struct cluster *c_ptr);
-void tipc_cltr_attach_node(struct cluster *c_ptr, struct node *n_ptr);
+void tipc_cltr_attach_node(struct cluster *c_ptr, struct tipc_node *n_ptr);
 void tipc_cltr_send_slave_routes(struct cluster *c_ptr, u32 dest);
 void tipc_cltr_broadcast(struct sk_buff *buf);
 int tipc_cltr_init(void);
index 1657f0e..74b7d1e 100644 (file)
@@ -193,7 +193,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr)
                /* Always accept link here */
                struct sk_buff *rbuf;
                struct tipc_media_addr *addr;
-               struct node *n_ptr = tipc_node_find(orig);
+               struct tipc_node *n_ptr = tipc_node_find(orig);
                int link_fully_up;
 
                dbg(" in own cluster\n");
index d60113b..dd4c18b 100644 (file)
@@ -1155,7 +1155,7 @@ int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf)
 int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector)
 {
        struct link *l_ptr;
-       struct node *n_ptr;
+       struct tipc_node *n_ptr;
        int res = -ELINKCONG;
 
        read_lock_bh(&tipc_net_lock);
@@ -1226,7 +1226,7 @@ static int link_send_buf_fast(struct link *l_ptr, struct sk_buff *buf,
 int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode)
 {
        struct link *l_ptr;
-       struct node *n_ptr;
+       struct tipc_node *n_ptr;
        int res;
        u32 selector = msg_origport(buf_msg(buf)) & 1;
        u32 dummy;
@@ -1270,7 +1270,7 @@ int tipc_link_send_sections_fast(struct port *sender,
        struct tipc_msg *hdr = &sender->publ.phdr;
        struct link *l_ptr;
        struct sk_buff *buf;
-       struct node *node;
+       struct tipc_node *node;
        int res;
        u32 selector = msg_origport(hdr) & 1;
 
@@ -1364,7 +1364,7 @@ static int link_send_sections_long(struct port *sender,
                                   u32 destaddr)
 {
        struct link *l_ptr;
-       struct node *node;
+       struct tipc_node *node;
        struct tipc_msg *hdr = &sender->publ.phdr;
        u32 dsz = msg_data_sz(hdr);
        u32 max_pkt,fragm_sz,rest;
@@ -1636,7 +1636,7 @@ void tipc_link_push_queue(struct link *l_ptr)
 
 static void link_reset_all(unsigned long addr)
 {
-       struct node *n_ptr;
+       struct tipc_node *n_ptr;
        char addr_string[16];
        u32 i;
 
@@ -1682,7 +1682,7 @@ static void link_retransmit_failure(struct link *l_ptr, struct sk_buff *buf)
 
                /* Handle failure on broadcast link */
 
-               struct node *n_ptr;
+               struct tipc_node *n_ptr;
                char addr_string[16];
 
                tipc_printf(TIPC_OUTPUT, "Msg seq number: %u,  ", msg_seqno(msg));
@@ -1843,7 +1843,7 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
        read_lock_bh(&tipc_net_lock);
        while (head) {
                struct bearer *b_ptr = (struct bearer *)tb_ptr;
-               struct node *n_ptr;
+               struct tipc_node *n_ptr;
                struct link *l_ptr;
                struct sk_buff *crs;
                struct sk_buff *buf = head;
@@ -2935,7 +2935,7 @@ void tipc_link_set_queue_limits(struct link *l_ptr, u32 window)
  * Returns pointer to link (or 0 if invalid link name).
  */
 
-static struct link *link_find_link(const char *name, struct node **node)
+static struct link *link_find_link(const char *name, struct tipc_node **node)
 {
        struct link_name link_name_parts;
        struct bearer *b_ptr;
@@ -2965,7 +2965,7 @@ struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space
        struct tipc_link_config *args;
        u32 new_value;
        struct link *l_ptr;
-       struct node *node;
+       struct tipc_node *node;
        int res;
 
        if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_CONFIG))
@@ -3043,7 +3043,7 @@ struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_
 {
        char *link_name;
        struct link *l_ptr;
-       struct node *node;
+       struct tipc_node *node;
 
        if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME))
                return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
@@ -3091,7 +3091,7 @@ static int tipc_link_stats(const char *name, char *buf, const u32 buf_size)
 {
        struct print_buf pb;
        struct link *l_ptr;
-       struct node *node;
+       struct tipc_node *node;
        char *status;
        u32 profile_total = 0;
 
@@ -3207,7 +3207,7 @@ int link_control(const char *name, u32 op, u32 val)
        int res = -EINVAL;
        struct link *l_ptr;
        u32 bearer_id;
-       struct node * node;
+       struct tipc_node * node;
        u32 a;
 
        a = link_name2addr(name, &bearer_id);
@@ -3249,7 +3249,7 @@ int link_control(const char *name, u32 op, u32 val)
 
 u32 tipc_link_get_max_pkt(u32 dest, u32 selector)
 {
-       struct node *n_ptr;
+       struct tipc_node *n_ptr;
        struct link *l_ptr;
        u32 res = MAX_PKT_DEFAULT;
 
index 52f3e7c..6a51e38 100644 (file)
@@ -116,7 +116,7 @@ struct link {
        char name[TIPC_MAX_LINK_NAME];
        struct tipc_media_addr media_addr;
        struct timer_list timer;
-       struct node *owner;
+       struct tipc_node *owner;
        struct list_head link_list;
 
        /* Management and link supervision data */
index b9e7cd3..139882d 100644 (file)
@@ -76,7 +76,7 @@ struct publication {
        u32 node;
        u32 ref;
        u32 key;
-       struct node_subscr subscr;
+       struct tipc_node_subscr subscr;
        struct list_head local_list;
        struct list_head pport_list;
        struct publication *node_list_next;
index ec7b04f..7906608 100644 (file)
 DEFINE_RWLOCK(tipc_net_lock);
 struct network tipc_net = { NULL };
 
-struct node *tipc_net_select_remote_node(u32 addr, u32 ref)
+struct tipc_node *tipc_net_select_remote_node(u32 addr, u32 ref)
 {
        return tipc_zone_select_remote_node(tipc_net.zones[tipc_zone(addr)], addr, ref);
 }
index d154ac2..de2b9ad 100644 (file)
@@ -55,7 +55,7 @@ extern rwlock_t tipc_net_lock;
 void tipc_net_remove_as_router(u32 router);
 void tipc_net_send_external_routes(u32 dest);
 void tipc_net_route_msg(struct sk_buff *buf);
-struct node *tipc_net_select_remote_node(u32 addr, u32 ref);
+struct tipc_node *tipc_net_select_remote_node(u32 addr, u32 ref);
 u32 tipc_net_select_router(u32 addr, u32 ref);
 
 int tipc_net_start(u32 addr);
index ee952ad..20d98c5 100644 (file)
 #include "bearer.h"
 #include "name_distr.h"
 
-void node_print(struct print_buf *buf, struct node *n_ptr, char *str);
-static void node_lost_contact(struct node *n_ptr);
-static void node_established_contact(struct node *n_ptr);
+void node_print(struct print_buf *buf, struct tipc_node *n_ptr, char *str);
+static void node_lost_contact(struct tipc_node *n_ptr);
+static void node_established_contact(struct tipc_node *n_ptr);
 
-struct node *tipc_nodes = NULL;        /* sorted list of nodes within cluster */
+struct tipc_node *tipc_nodes = NULL;   /* sorted list of nodes within cluster */
 
 static DEFINE_SPINLOCK(node_create_lock);
 
@@ -66,11 +66,11 @@ u32 tipc_own_tag = 0;
  * but this is a non-trivial change.)
  */
 
-struct node *tipc_node_create(u32 addr)
+struct tipc_node *tipc_node_create(u32 addr)
 {
        struct cluster *c_ptr;
-       struct node *n_ptr;
-       struct node **curr_node;
+       struct tipc_node *n_ptr;
+       struct tipc_node **curr_node;
 
        spin_lock_bh(&node_create_lock);
 
@@ -120,7 +120,7 @@ struct node *tipc_node_create(u32 addr)
        return n_ptr;
 }
 
-void tipc_node_delete(struct node *n_ptr)
+void tipc_node_delete(struct tipc_node *n_ptr)
 {
        if (!n_ptr)
                return;
@@ -146,7 +146,7 @@ void tipc_node_delete(struct node *n_ptr)
  * Link becomes active (alone or shared) or standby, depending on its priority.
  */
 
-void tipc_node_link_up(struct node *n_ptr, struct link *l_ptr)
+void tipc_node_link_up(struct tipc_node *n_ptr, struct link *l_ptr)
 {
        struct link **active = &n_ptr->active_links[0];
 
@@ -180,7 +180,7 @@ void tipc_node_link_up(struct node *n_ptr, struct link *l_ptr)
  * node_select_active_links - select active link
  */
 
-static void node_select_active_links(struct node *n_ptr)
+static void node_select_active_links(struct tipc_node *n_ptr)
 {
        struct link **active = &n_ptr->active_links[0];
        u32 i;
@@ -208,7 +208,7 @@ static void node_select_active_links(struct node *n_ptr)
  * tipc_node_link_down - handle loss of link
  */
 
-void tipc_node_link_down(struct node *n_ptr, struct link *l_ptr)
+void tipc_node_link_down(struct tipc_node *n_ptr, struct link *l_ptr)
 {
        struct link **active;
 
@@ -235,30 +235,30 @@ void tipc_node_link_down(struct node *n_ptr, struct link *l_ptr)
                node_lost_contact(n_ptr);
 }
 
-int tipc_node_has_active_links(struct node *n_ptr)
+int tipc_node_has_active_links(struct tipc_node *n_ptr)
 {
        return (n_ptr &&
                ((n_ptr->active_links[0]) || (n_ptr->active_links[1])));
 }
 
-int tipc_node_has_redundant_links(struct node *n_ptr)
+int tipc_node_has_redundant_links(struct tipc_node *n_ptr)
 {
        return (n_ptr->working_links > 1);
 }
 
-static int tipc_node_has_active_routes(struct node *n_ptr)
+static int tipc_node_has_active_routes(struct tipc_node *n_ptr)
 {
        return (n_ptr && (n_ptr->last_router >= 0));
 }
 
-int tipc_node_is_up(struct node *n_ptr)
+int tipc_node_is_up(struct tipc_node *n_ptr)
 {
        return (tipc_node_has_active_links(n_ptr) || tipc_node_has_active_routes(n_ptr));
 }
 
-struct node *tipc_node_attach_link(struct link *l_ptr)
+struct tipc_node *tipc_node_attach_link(struct link *l_ptr)
 {
-       struct node *n_ptr = tipc_node_find(l_ptr->addr);
+       struct tipc_node *n_ptr = tipc_node_find(l_ptr->addr);
 
        if (!n_ptr)
                n_ptr = tipc_node_create(l_ptr->addr);
@@ -285,7 +285,7 @@ struct node *tipc_node_attach_link(struct link *l_ptr)
        return NULL;
 }
 
-void tipc_node_detach_link(struct node *n_ptr, struct link *l_ptr)
+void tipc_node_detach_link(struct tipc_node *n_ptr, struct link *l_ptr)
 {
        n_ptr->links[l_ptr->b_ptr->identity] = NULL;
        tipc_net.zones[tipc_zone(l_ptr->addr)]->links--;
@@ -338,7 +338,7 @@ void tipc_node_detach_link(struct node *n_ptr, struct link *l_ptr)
  *
  */
 
-static void node_established_contact(struct node *n_ptr)
+static void node_established_contact(struct tipc_node *n_ptr)
 {
        struct cluster *c_ptr;
 
@@ -384,10 +384,10 @@ static void node_established_contact(struct node *n_ptr)
                                  tipc_highest_allowed_slave);
 }
 
-static void node_lost_contact(struct node *n_ptr)
+static void node_lost_contact(struct tipc_node *n_ptr)
 {
        struct cluster *c_ptr;
-       struct node_subscr *ns, *tns;
+       struct tipc_node_subscr *ns, *tns;
        char addr_string[16];
        u32 i;
 
@@ -466,9 +466,9 @@ static void node_lost_contact(struct node *n_ptr)
  * Called by when cluster local lookup has failed.
  */
 
-struct node *tipc_node_select_next_hop(u32 addr, u32 selector)
+struct tipc_node *tipc_node_select_next_hop(u32 addr, u32 selector)
 {
-       struct node *n_ptr;
+       struct tipc_node *n_ptr;
        u32 router_addr;
 
        if (!tipc_addr_domain_valid(addr))
@@ -513,7 +513,7 @@ struct node *tipc_node_select_next_hop(u32 addr, u32 selector)
  * Uses a deterministic and fair algorithm for selecting router node.
  */
 
-u32 tipc_node_select_router(struct node *n_ptr, u32 ref)
+u32 tipc_node_select_router(struct tipc_node *n_ptr, u32 ref)
 {
        u32 ulim;
        u32 mask;
@@ -551,7 +551,7 @@ u32 tipc_node_select_router(struct node *n_ptr, u32 ref)
        return tipc_addr(own_zone(), own_cluster(), r);
 }
 
-void tipc_node_add_router(struct node *n_ptr, u32 router)
+void tipc_node_add_router(struct tipc_node *n_ptr, u32 router)
 {
        u32 r_num = tipc_node(router);
 
@@ -562,7 +562,7 @@ void tipc_node_add_router(struct node *n_ptr, u32 router)
               !n_ptr->routers[n_ptr->last_router]);
 }
 
-void tipc_node_remove_router(struct node *n_ptr, u32 router)
+void tipc_node_remove_router(struct tipc_node *n_ptr, u32 router)
 {
        u32 r_num = tipc_node(router);
 
@@ -580,7 +580,7 @@ void tipc_node_remove_router(struct node *n_ptr, u32 router)
 }
 
 #if 0
-void node_print(struct print_buf *buf, struct node *n_ptr, char *str)
+void node_print(struct print_buf *buf, struct tipc_node *n_ptr, char *str)
 {
        u32 i;
 
@@ -597,7 +597,7 @@ void node_print(struct print_buf *buf, struct node *n_ptr, char *str)
 
 u32 tipc_available_nodes(const u32 domain)
 {
-       struct node *n_ptr;
+       struct tipc_node *n_ptr;
        u32 cnt = 0;
 
        read_lock_bh(&tipc_net_lock);
@@ -615,7 +615,7 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
 {
        u32 domain;
        struct sk_buff *buf;
-       struct node *n_ptr;
+       struct tipc_node *n_ptr;
        struct tipc_node_info node_info;
        u32 payload_size;
 
@@ -667,7 +667,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
 {
        u32 domain;
        struct sk_buff *buf;
-       struct node *n_ptr;
+       struct tipc_node *n_ptr;
        struct tipc_link_info link_info;
        u32 payload_size;
 
index cd18826..6f990da 100644 (file)
@@ -43,7 +43,7 @@
 #include "bearer.h"
 
 /**
- * struct node - TIPC node structure
+ * struct tipc_node - TIPC node structure
  * @addr: network address of node
  * @lock: spinlock governing access to structure
  * @owner: pointer to cluster that node belongs to
  *    @defragm: list of partially reassembled b'cast message fragments from node
  */
 
-struct node {
+struct tipc_node {
        u32 addr;
        spinlock_t lock;
        struct cluster *owner;
-       struct node *next;
+       struct tipc_node *next;
        struct list_head nsub;
        struct link *active_links[2];
        struct link *links[MAX_BEARERS];
@@ -94,26 +94,26 @@ struct node {
        } bclink;
 };
 
-extern struct node *tipc_nodes;
+extern struct tipc_node *tipc_nodes;
 extern u32 tipc_own_tag;
 
-struct node *tipc_node_create(u32 addr);
-void tipc_node_delete(struct node *n_ptr);
-struct node *tipc_node_attach_link(struct link *l_ptr);
-void tipc_node_detach_link(struct node *n_ptr, struct link *l_ptr);
-void tipc_node_link_down(struct node *n_ptr, struct link *l_ptr);
-void tipc_node_link_up(struct node *n_ptr, struct link *l_ptr);
-int tipc_node_has_active_links(struct node *n_ptr);
-int tipc_node_has_redundant_links(struct node *n_ptr);
-u32 tipc_node_select_router(struct node *n_ptr, u32 ref);
-struct node *tipc_node_select_next_hop(u32 addr, u32 selector);
-int tipc_node_is_up(struct node *n_ptr);
-void tipc_node_add_router(struct node *n_ptr, u32 router);
-void tipc_node_remove_router(struct node *n_ptr, u32 router);
+struct tipc_node *tipc_node_create(u32 addr);
+void tipc_node_delete(struct tipc_node *n_ptr);
+struct tipc_node *tipc_node_attach_link(struct link *l_ptr);
+void tipc_node_detach_link(struct tipc_node *n_ptr, struct link *l_ptr);
+void tipc_node_link_down(struct tipc_node *n_ptr, struct link *l_ptr);
+void tipc_node_link_up(struct tipc_node *n_ptr, struct link *l_ptr);
+int tipc_node_has_active_links(struct tipc_node *n_ptr);
+int tipc_node_has_redundant_links(struct tipc_node *n_ptr);
+u32 tipc_node_select_router(struct tipc_node *n_ptr, u32 ref);
+struct tipc_node *tipc_node_select_next_hop(u32 addr, u32 selector);
+int tipc_node_is_up(struct tipc_node *n_ptr);
+void tipc_node_add_router(struct tipc_node *n_ptr, u32 router);
+void tipc_node_remove_router(struct tipc_node *n_ptr, u32 router);
 struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space);
 struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space);
 
-static inline struct node *tipc_node_find(u32 addr)
+static inline struct tipc_node *tipc_node_find(u32 addr)
 {
        if (likely(in_own_cluster(addr)))
                return tipc_local_nodes[tipc_node(addr)];
@@ -126,19 +126,19 @@ static inline struct node *tipc_node_find(u32 addr)
        return NULL;
 }
 
-static inline struct node *tipc_node_select(u32 addr, u32 selector)
+static inline struct tipc_node *tipc_node_select(u32 addr, u32 selector)
 {
        if (likely(in_own_cluster(addr)))
                return tipc_local_nodes[tipc_node(addr)];
        return tipc_node_select_next_hop(addr, selector);
 }
 
-static inline void tipc_node_lock(struct node *n_ptr)
+static inline void tipc_node_lock(struct tipc_node *n_ptr)
 {
        spin_lock_bh(&n_ptr->lock);
 }
 
-static inline void tipc_node_unlock(struct node *n_ptr)
+static inline void tipc_node_unlock(struct tipc_node *n_ptr)
 {
        spin_unlock_bh(&n_ptr->lock);
 }
index 8ecbd0f..19194d4 100644 (file)
@@ -44,7 +44,7 @@
  * tipc_nodesub_subscribe - create "node down" subscription for specified node
  */
 
-void tipc_nodesub_subscribe(struct node_subscr *node_sub, u32 addr,
+void tipc_nodesub_subscribe(struct tipc_node_subscr *node_sub, u32 addr,
                       void *usr_handle, net_ev_handler handle_down)
 {
        if (addr == tipc_own_addr) {
@@ -69,7 +69,7 @@ void tipc_nodesub_subscribe(struct node_subscr *node_sub, u32 addr,
  * tipc_nodesub_unsubscribe - cancel "node down" subscription (if any)
  */
 
-void tipc_nodesub_unsubscribe(struct node_subscr *node_sub)
+void tipc_nodesub_unsubscribe(struct tipc_node_subscr *node_sub)
 {
        if (!node_sub->node)
                return;
index 5f3f585..006ed73 100644 (file)
 typedef void (*net_ev_handler) (void *usr_handle);
 
 /**
- * struct node_subscr - "node down" subscription entry
+ * struct tipc_node_subscr - "node down" subscription entry
  * @node: ptr to node structure of interest (or NULL, if none)
  * @handle_node_down: routine to invoke when node fails
  * @usr_handle: argument to pass to routine when node fails
  * @nodesub_list: adjacent entries in list of subscriptions for the node
  */
 
-struct node_subscr {
-       struct node *node;
+struct tipc_node_subscr {
+       struct tipc_node *node;
        net_ev_handler handle_node_down;
        void *usr_handle;
        struct list_head nodesub_list;
 };
 
-void tipc_nodesub_subscribe(struct node_subscr *node_sub, u32 addr,
+void tipc_nodesub_subscribe(struct tipc_node_subscr *node_sub, u32 addr,
                            void *usr_handle, net_ev_handler handle_down);
-void tipc_nodesub_unsubscribe(struct node_subscr *node_sub);
+void tipc_nodesub_unsubscribe(struct tipc_node_subscr *node_sub);
 
 #endif
index e5f8c16..ff31ee4 100644 (file)
@@ -105,7 +105,7 @@ struct port {
        u32 probing_interval;
        u32 last_in_seqno;
        struct timer_list timer;
-       struct node_subscr subscription;
+       struct tipc_node_subscr subscription;
 };
 
 extern spinlock_t tipc_port_list_lock;
index 3506f85..2c01ba2 100644 (file)
@@ -111,10 +111,10 @@ void tipc_zone_send_external_routes(struct _zone *z_ptr, u32 dest)
        }
 }
 
-struct node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref)
+struct tipc_node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref)
 {
        struct cluster *c_ptr;
-       struct node *n_ptr;
+       struct tipc_node *n_ptr;
        u32 c_num;
 
        if (!z_ptr)
index 6e7a08d..7bdc340 100644 (file)
@@ -54,7 +54,7 @@ struct _zone {
        u32 links;
 };
 
-struct node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref);
+struct tipc_node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref);
 u32 tipc_zone_select_router(struct _zone *z_ptr, u32 addr, u32 ref);
 void tipc_zone_remove_as_router(struct _zone *z_ptr, u32 router);
 void tipc_zone_send_external_routes(struct _zone *z_ptr, u32 dest);
index b52f923..d11a815 100644 (file)
@@ -811,11 +811,12 @@ static int string_to_context_struct(struct policydb *pol,
        /* Check the validity of the new context. */
        if (!policydb_context_isvalid(pol, ctx)) {
                rc = -EINVAL;
-               context_destroy(ctx);
                goto out;
        }
        rc = 0;
 out:
+       if (rc)
+               context_destroy(ctx);
        return rc;
 }
 
@@ -868,8 +869,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
        } else if (rc)
                goto out;
        rc = sidtab_context_to_sid(&sidtab, &context, sid);
-       if (rc)
-               context_destroy(&context);
+       context_destroy(&context);
 out:
        read_unlock(&policy_rwlock);
        kfree(scontext2);
index a37bee0..8ebf512 100644 (file)
@@ -91,6 +91,9 @@ endif # SOUND_PRIME
 
 endif # !M68K
 
+endif # SOUND
+
+# AC97_BUS is used from both sound and ucb1400
 config AC97_BUS
        tristate
        help
@@ -99,4 +102,3 @@ config AC97_BUS
          sound although they're sharing the AC97 bus. Concerned drivers
          should "select" this.
 
-endif # SOUND