diff --git a/.gitignore b/.gitignore index c2fd41347..a23ef2db8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ -linux-*.tar.bz2 -patch-*.bz2 clog +*.xz +*.bz2 *.rpm -kernel-2.6.*/ +*.orig +kernel-[23].*/ diff --git a/ALSA-hda-realtek-Add-quirk-for-Mac-Pro-5-1-machines.patch b/ALSA-hda-realtek-Add-quirk-for-Mac-Pro-5-1-machines.patch new file mode 100644 index 000000000..28579d13b --- /dev/null +++ b/ALSA-hda-realtek-Add-quirk-for-Mac-Pro-5-1-machines.patch @@ -0,0 +1,37 @@ +From a9e1e167d934aa74f48008393ade4f09fc587432 Mon Sep 17 00:00:00 2001 +From: Josh Boyer +Date: Thu, 12 Apr 2012 13:55:36 -0400 +Subject: [PATCH] ALSA: hda/realtek - Add quirk for Mac Pro 5,1 machines + +A user reported that setting model=imac24 used to allow sound to work on their +Mac Pro 5,1 machine. Commit 5671087ffa "Move ALC885 macpro and imac24 models +to auto-parser" removed this model option. All Mac machines are now explicitly +handled with a quirk and the auto-parser. This adds a quirk for the device +found on the Mac Pro 5,1 machines. + +This (partially) fixes https://bugzilla.redhat.com/show_bug.cgi?id=808559 + +[sorted the new entry in the ID number order by tiwai] + +Reported-by: Gabriel Somlo +Signed-off-by: Josh Boyer +Signed-off-by: Takashi Iwai +--- + sound/pci/hda/patch_realtek.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 22c73b7..bd34b51 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -4659,6 +4659,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { + SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO), + SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD), + SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO), ++ SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 5,1", ALC885_FIXUP_MACPRO_GPIO), + + SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD), + SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), +-- +1.7.7.6 + diff --git a/Makefile b/Makefile index 705670ff1..3e9e3a8fa 100644 --- a/Makefile +++ b/Makefile @@ -36,13 +36,11 @@ debug: @perl -pi -e 's/# CONFIG_DEBUG_SLAB is not set/CONFIG_DEBUG_SLAB=y/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_MUTEXES is not set/CONFIG_DEBUG_MUTEXES=y/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_RT_MUTEXES is not set/CONFIG_DEBUG_RT_MUTEXES=y/' config-nodebug - @perl -pi -e 's/# CONFIG_DEBUG_RWSEMS is not set/CONFIG_DEBUG_RWSEMS=y/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_LOCK_ALLOC is not set/CONFIG_DEBUG_LOCK_ALLOC=y/' config-nodebug @perl -pi -e 's/# CONFIG_PROVE_LOCKING is not set/CONFIG_PROVE_LOCKING=y/' config-nodebug @perl -pi -e 's/# CONFIG_PROVE_RCU is not set/CONFIG_PROVE_RCU=y/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_SPINLOCK is not set/CONFIG_DEBUG_SPINLOCK=y/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_VM is not set/CONFIG_DEBUG_VM=y/' config-nodebug - @perl -pi -e 's/# CONFIG_DEBUG_SLEEP_IN_IRQ is not set/CONFIG_DEBUG_SLEEP_IN_IRQ=y/' config-nodebug @perl -pi -e 's/# CONFIG_FAULT_INJECTION is not set/CONFIG_FAULT_INJECTION=y/' config-nodebug @perl -pi -e 's/# CONFIG_FAILSLAB is not set/CONFIG_FAILSLAB=y/' config-nodebug @perl -pi -e 's/# CONFIG_FAIL_PAGE_ALLOC is not set/CONFIG_FAIL_PAGE_ALLOC=y/' config-nodebug @@ -55,6 +53,9 @@ debug: @perl -pi -e 's/# CONFIG_DEBUG_OBJECTS is not set/CONFIG_DEBUG_OBJECTS=y/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_OBJECTS_FREE is not set/CONFIG_DEBUG_OBJECTS_FREE=y/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_OBJECTS_TIMERS is not set/CONFIG_DEBUG_OBJECTS_TIMERS=y/' config-nodebug + @perl -pi -e 's/# CONFIG_DEBUG_OBJECTS_WORK is not set/CONFIG_DEBUG_OBJECTS_WORK=y/' config-nodebug + @perl -pi -e 's/# CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER is not set/CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y/' config-nodebug + @perl -pi -e 's/# CONFIG_DEBUG_OBJECTS_RCU_HEAD is not set/CONFIG_DEBUG_OBJECTS_RCU_HEAD=y/' config-nodebug @perl -pi -e 's/# CONFIG_X86_PTDUMP is not set/CONFIG_X86_PTDUMP=y/' config-nodebug @perl -pi -e 's/# CONFIG_CAN_DEBUG_DEVICES is not set/CONFIG_CAN_DEBUG_DEVICES=y/' config-nodebug @perl -pi -e 's/# CONFIG_MODULE_FORCE_UNLOAD is not set/CONFIG_MODULE_FORCE_UNLOAD=y/' config-nodebug @@ -63,7 +64,6 @@ debug: @perl -pi -e 's/# CONFIG_DMA_API_DEBUG is not set/CONFIG_DMA_API_DEBUG=y/' config-nodebug @perl -pi -e 's/# CONFIG_PM_TEST_SUSPEND is not set/CONFIG_PM_TEST_SUSPEND=y/' config-generic @perl -pi -e 's/# CONFIG_PM_ADVANCED_DEBUG is not set/CONFIG_PM_ADVANCED_DEBUG=y/' config-generic - @perl -pi -e 's/# CONFIG_BOOT_TRACER is not set/CONFIG_BOOT_TRACER=y/' config-generic @perl -pi -e 's/# CONFIG_B43_DEBUG is not set/CONFIG_B43_DEBUG=y/' config-generic @perl -pi -e 's/# CONFIG_B43LEGACY_DEBUG is not set/CONFIG_B43LEGACY_DEBUG=y/' config-generic @perl -pi -e 's/# CONFIG_MMIOTRACE is not set/CONFIG_MMIOTRACE=y/' config-nodebug @@ -74,12 +74,11 @@ debug: @perl -pi -e 's/# CONFIG_EXT4_DEBUG is not set/CONFIG_EXT4_DEBUG=y/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_PERF_USE_VMALLOC is not set/CONFIG_DEBUG_PERF_USE_VMALLOC=y/' config-nodebug @perl -pi -e 's/# CONFIG_JBD2_DEBUG is not set/CONFIG_JBD2_DEBUG=y/' config-nodebug - @perl -pi -e 's/# CONFIG_DEBUG_CFQ_IOSCHED is not set/CONFIG_DEBUG_CFQ_IOSCHED=y/' config-nodebug + @perl -pi -e 's/# CONFIG_DEBUG_BLK_CGROUP is not set/CONFIG_DEBUG_BLK_CGROUP=y/' config-nodebug @perl -pi -e 's/# CONFIG_DRBD_FAULT_INJECTION is not set/CONFIG_DRBD_FAULT_INJECTION=y/' config-nodebug @perl -pi -e 's/# CONFIG_ATH_DEBUG is not set/CONFIG_ATH_DEBUG=y/' config-nodebug @perl -pi -e 's/# CONFIG_CARL9170_DEBUGFS is not set/CONFIG_CARL9170_DEBUGFS=y/' config-nodebug @perl -pi -e 's/# CONFIG_IWLWIFI_DEVICE_TRACING is not set/CONFIG_IWLWIFI_DEVICE_TRACING=y/' config-nodebug - @perl -pi -e 's/# CONFIG_DEBUG_OBJECTS_WORK is not set/CONFIG_DEBUG_OBJECTS_WORK=y/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set/CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y/' config-nodebug @perl -pi -e 's/# CONFIG_DMADEVICES_DEBUG is not set/CONFIG_DMADEVICES_DEBUG=y/' config-nodebug @perl -pi -e 's/# CONFIG_DMADEVICES_VDEBUG is not set/CONFIG_DMADEVICES_VDEBUG=y/' config-nodebug @@ -89,10 +88,9 @@ debug: @perl -pi -e 's/# CONFIG_KDB_KEYBOARD is not set/CONFIG_KDB_KEYBOARD=y/' config-nodebug @perl -pi -e 's/# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set/CONFIG_CPU_NOTIFIER_ERROR_INJECT=m/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_PER_CPU_MAPS is not set/CONFIG_DEBUG_PER_CPU_MAPS=y/' config-nodebug - @perl -pi -e 's/CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y/# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set/' config-nodebug - #@perl -pi -e 's/# CONFIG_PCI_DEFAULT_USE_CRS is not set/CONFIG_PCI_DEFAULT_USE_CRS=y/' config-nodebug - @perl -pi -e 's/# CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER is not set/CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y/' config-nodebug @perl -pi -e 's/# CONFIG_TEST_LIST_SORT is not set/CONFIG_TEST_LIST_SORT=y/' config-nodebug + @perl -pi -e 's/# CONFIG_DEBUG_ATOMIC_SLEEP is not set/CONFIG_DEBUG_ATOMIC_SLEEP=y/' config-nodebug + @perl -pi -e 's/# CONFIG_DETECT_HUNG_TASK is not set/CONFIG_DETECT_HUNG_TASK=y/' config-nodebug @perl -pi -e 's/# CONFIG_DEBUG_SET_MODULE_RONX is not set/CONFIG_DEBUG_SET_MODULE_RONX=y/' config-nodebug @@ -115,13 +113,11 @@ release: @perl -pi -e 's/CONFIG_DEBUG_SLAB=y/# CONFIG_DEBUG_SLAB is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_MUTEXES=y/# CONFIG_DEBUG_MUTEXES is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_RT_MUTEXES=y/# CONFIG_DEBUG_RT_MUTEXES is not set/' config-nodebug - @perl -pi -e 's/CONFIG_DEBUG_RWSEMS=y/# CONFIG_DEBUG_RWSEMS is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_LOCK_ALLOC=y/# CONFIG_DEBUG_LOCK_ALLOC is not set/' config-nodebug @perl -pi -e 's/CONFIG_PROVE_LOCKING=y/# CONFIG_PROVE_LOCKING is not set/' config-nodebug @perl -pi -e 's/CONFIG_PROVE_RCU=y/# CONFIG_PROVE_RCU is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_SPINLOCK=y/# CONFIG_DEBUG_SPINLOCK is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_VM=y/# CONFIG_DEBUG_VM is not set/' config-nodebug - @perl -pi -e 's/CONFIG_DEBUG_SLEEP_IN_IRQ=y/# CONFIG_DEBUG_SLEEP_IN_IRQ is not set/' config-nodebug @perl -pi -e 's/CONFIG_FAULT_INJECTION=y/# CONFIG_FAULT_INJECTION is not set/' config-nodebug @perl -pi -e 's/CONFIG_FAILSLAB=y/# CONFIG_FAILSLAB is not set/' config-nodebug @perl -pi -e 's/CONFIG_FAIL_PAGE_ALLOC=y/# CONFIG_FAIL_PAGE_ALLOC is not set/' config-nodebug @@ -134,15 +130,17 @@ release: @perl -pi -e 's/CONFIG_DEBUG_OBJECTS=y/# CONFIG_DEBUG_OBJECTS is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_OBJECTS_FREE=y/# CONFIG_DEBUG_OBJECTS_FREE is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_OBJECTS_TIMERS=y/# CONFIG_DEBUG_OBJECTS_TIMERS is not set/' config-nodebug + @perl -pi -e 's/CONFIG_DEBUG_OBJECTS_WORK=y/# CONFIG_DEBUG_OBJECTS_WORK is not set/' config-nodebug + @perl -pi -e 's/CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y/# CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER is not set/' config-nodebug + @perl -pi -e 's/CONFIG_DEBUG_OBJECTS_RCU_HEAD=y/# CONFIG_DEBUG_OBJECTS_RCU_HEAD is not set/' config-nodebug @perl -pi -e 's/CONFIG_X86_PTDUMP=y/# CONFIG_X86_PTDUMP is not set/' config-nodebug @perl -pi -e 's/CONFIG_CAN_DEBUG_DEVICES=y/# CONFIG_CAN_DEBUG_DEVICES is not set/' config-nodebug @perl -pi -e 's/CONFIG_MODULE_FORCE_UNLOAD=y/# CONFIG_MODULE_FORCE_UNLOAD is not set/' config-nodebug @perl -pi -e 's/CONFIG_SYSCTL_SYSCALL_CHECK=y/# CONFIG_SYSCTL_SYSCALL_CHECK is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_NOTIFIERS=y/# CONFIG_DEBUG_NOTIFIERS is not set/' config-nodebug @perl -pi -e 's/CONFIG_DMA_API_DEBUG=y/# CONFIG_DMA_API_DEBUG is not set/' config-nodebug - @perl -pi -e 's/CONFIG_PM_TEST_SUSPEND=y/#\ CONFIG_PM_TEST_SUSPEND\ is\ not\ set/' config-generic - @perl -pi -e 's/CONFIG_PM_ADVANCED_DEBUG=y/#\ CONFIG_PM_ADVANCED_DEBUG\ is\ not\ set/' config-generic - @perl -pi -e 's/CONFIG_BOOT_TRACER=y/#\ CONFIG_BOOT_TRACER\ is\ not\ set/' config-generic + @perl -pi -e 's/CONFIG_PM_TEST_SUSPEND=y/# CONFIG_PM_TEST_SUSPEND is not set/' config-generic + @perl -pi -e 's/CONFIG_PM_ADVANCED_DEBUG=y/# CONFIG_PM_ADVANCED_DEBUG is not set/' config-generic @perl -pi -e 's/CONFIG_B43_DEBUG=y/# CONFIG_B43_DEBUG is not set/' config-generic @perl -pi -e 's/CONFIG_B43LEGACY_DEBUG=y/# CONFIG_B43LEGACY_DEBUG is not set/' config-generic @perl -pi -e 's/CONFIG_MMIOTRACE=y/# CONFIG_MMIOTRACE is not set/' config-nodebug @@ -153,12 +151,11 @@ release: @perl -pi -e 's/CONFIG_EXT4_DEBUG=y/# CONFIG_EXT4_DEBUG is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_PERF_USE_VMALLOC=y/# CONFIG_DEBUG_PERF_USE_VMALLOC is not set/' config-nodebug @perl -pi -e 's/CONFIG_JBD2_DEBUG=y/# CONFIG_JBD2_DEBUG is not set/' config-nodebug - @perl -pi -e 's/CONFIG_DEBUG_CFQ_IOSCHED=y/# CONFIG_DEBUG_CFQ_IOSCHED is not set/' config-nodebug + @perl -pi -e 's/CONFIG_DEBUG_BLK_CGROUP=y/# CONFIG_DEBUG_BLK_CGROUP is not set/' config-nodebug @perl -pi -e 's/CONFIG_DRBD_FAULT_INJECTION=y/# CONFIG_DRBD_FAULT_INJECTION is not set/' config-nodebug @perl -pi -e 's/CONFIG_ATH_DEBUG=y/# CONFIG_ATH_DEBUG is not set/' config-nodebug @perl -pi -e 's/CONFIG_CARL9170_DEBUGFS=y/# CONFIG_CARL9170_DEBUGFS is not set/' config-nodebug @perl -pi -e 's/CONFIG_IWLWIFI_DEVICE_TRACING=y/# CONFIG_IWLWIFI_DEVICE_TRACING is not set/' config-nodebug - @perl -pi -e 's/CONFIG_DEBUG_OBJECTS_WORK=y/# CONFIG_DEBUG_OBJECTS_WORK is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y/# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set/' config-nodebug @perl -pi -e 's/CONFIG_DMADEVICES_DEBUG=y/# CONFIG_DMADEVICES_DEBUG is not set/' config-nodebug @perl -pi -e 's/CONFIG_DMADEVICES_VDEBUG=y/# CONFIG_DMADEVICES_VDEBUG is not set/' config-nodebug @@ -168,10 +165,9 @@ release: #@perl -pi -e 's/CONFIG_KGDB_KDB=y/# CONFIG_KGDB_KDB is not set/' config-nodebug #@perl -pi -e 's/CONFIG_KDB_KEYBOARD=y/# CONFIG_KDB_KEYBOARD is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_PER_CPU_MAPS=y/# CONFIG_DEBUG_PER_CPU_MAPS is not set/' config-nodebug - @perl -pi -e 's/# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set/CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y/' config-nodebug - #@perl -pi -e 's/CONFIG_PCI_DEFAULT_USE_CRS=y/# CONFIG_PCI_DEFAULT_USE_CRS is not set/' config-nodebug - @perl -pi -e 's/CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y/# CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER is not set/' config-nodebug @perl -pi -e 's/CONFIG_TEST_LIST_SORT=y/# CONFIG_TEST_LIST_SORT is not set/' config-nodebug + @perl -pi -e 's/CONFIG_DEBUG_ATOMIC_SLEEP=y/# CONFIG_DEBUG_ATOMIC_SLEEP is not set/' config-nodebug + @perl -pi -e 's/CONFIG_DETECT_HUNG_TASK=y/# CONFIG_DETECT_HUNG_TASK is not set/' config-nodebug @perl -pi -e 's/CONFIG_DEBUG_SET_MODULE_RONX=y/# CONFIG_DEBUG_SET_MODULE_RONX is not set/' config-nodebug diff --git a/Makefile.config b/Makefile.config index 53812fa9b..e4e7b7d24 100644 --- a/Makefile.config +++ b/Makefile.config @@ -8,13 +8,18 @@ CONFIGFILES = \ $(CFG)-i686.config $(CFG)-i686-debug.config \ $(CFG)-i686-PAE.config $(CFG)-i686-PAEdebug.config \ $(CFG)-x86_64.config $(CFG)-x86_64-debug.config \ - $(CFG)-s390x.config $(CFG)-arm.config \ + $(CFG)-s390x.config \ + $(CFG)-arm.config $(CFG)-armv5tel.config \ + $(CFG)-armv5tel-kirkwood.config \ + $(CFG)-armv7l-imx.config $(CFG)-armv7l-highbank.config \ + $(CFG)-armv7l-omap.config $(CFG)-armv7l-tegra.config \ + $(CFG)-armv7hl-imx.config $(CFG)-armv7hl-highbank.config \ + $(CFG)-armv7hl-omap.config $(CFG)-armv7hl-tegra.config \ $(CFG)-ppc.config $(CFG)-ppc-smp.config \ $(CFG)-sparc64.config \ - $(CFG)-ppc64.config $(CFG)-ppc64-debug.config \ - $(CFG)-ia64.config + $(CFG)-ppc64.config $(CFG)-ppc64-debug.config -PLATFORMS = x86 x86_64 powerpc powerpc32 powerpc64 s390x ia64 sparc64 +PLATFORMS = x86 x86_64 powerpc powerpc32 powerpc64 s390x sparc64 TEMPFILES = $(addprefix temp-, $(addsuffix -generic, $(PLATFORMS))) configs: $(CONFIGFILES) @@ -32,16 +37,40 @@ temp-generic: config-generic temp-debug-generic: config-generic cat config-generic config-debug > temp-debug-generic -temp-x86-generic: config-x86-generic temp-generic +temp-arm-generic: config-arm-generic temp-generic perl merge.pl $^ > $@ -temp-x86-debug-generic: config-x86-generic temp-debug-generic +temp-armv7l-omap-generic: config-arm-omap-generic temp-arm-generic perl merge.pl $^ > $@ -temp-x86_64-generic: config-x86_64-generic temp-generic +temp-armv7l-tegra: config-arm-tegra temp-arm-generic perl merge.pl $^ > $@ -temp-x86_64-debug-generic: config-x86_64-generic temp-debug-generic +temp-armv5tel-kirkwood: config-arm-kirkwood temp-arm-generic + perl merge.pl $^ > $@ + +temp-armv7l-imx: config-arm-imx temp-arm-generic + perl merge.pl $^ > $@ + +temp-armv7l-highbank: config-arm-highbank temp-arm-generic + perl merge.pl $^ > $@ + +temp-x86-32: config-x86-32-generic config-x86-generic + perl merge.pl $^ > $@ + +temp-x86-32-generic: temp-x86-32 temp-generic + perl merge.pl $^ > $@ + +temp-x86-debug-generic: temp-x86-32 temp-debug-generic + perl merge.pl $^ > $@ + +temp-x86-64: config-x86_64-generic config-x86-generic + perl merge.pl $^ > $@ + +temp-x86_64-generic: temp-x86-64 temp-generic + perl merge.pl $^ > $@ + +temp-x86_64-debug-generic: temp-x86-64 temp-debug-generic perl merge.pl $^ > $@ temp-sparc64-generic: config-sparc64-generic temp-generic @@ -59,16 +88,13 @@ temp-powerpc32-generic: config-powerpc32-generic temp-powerpc-generic temp-s390-generic: config-s390x temp-generic perl merge.pl $^ > $@ -temp-ia64-generic: config-ia64-generic temp-generic - perl merge.pl $^ > $@ - -kernel-$(VERSION)-i686-PAE.config: config-i686-PAE temp-x86-generic +kernel-$(VERSION)-i686-PAE.config: config-i686-PAE temp-x86-32-generic perl merge.pl $^ i386 > $@ kernel-$(VERSION)-i686-PAEdebug.config: config-i686-PAE temp-x86-debug-generic perl merge.pl $^ i386 > $@ -kernel-$(VERSION)-i686.config: /dev/null temp-x86-generic +kernel-$(VERSION)-i686.config: /dev/null temp-x86-32-generic perl merge.pl $^ i386 > $@ kernel-$(VERSION)-i686-debug.config: /dev/null temp-x86-debug-generic @@ -92,7 +118,37 @@ kernel-$(VERSION)-ppc64-debug.config: config-powerpc64 temp-powerpc-debug-generi kernel-$(VERSION)-s390x.config: config-s390x temp-s390-generic perl merge.pl $^ s390 > $@ -kernel-$(VERSION)-arm.config: config-arm temp-generic +kernel-$(VERSION)-arm.config: /dev/null temp-arm-generic + perl merge.pl $^ arm > $@ + +kernel-$(VERSION)-armv5tel.config: /dev/null temp-arm-generic + perl merge.pl $^ arm > $@ + +kernel-$(VERSION)-armv5tel-kirkwood.config: /dev/null temp-armv5tel-kirkwood + perl merge.pl $^ arm > $@ + +kernel-$(VERSION)-armv7l-imx.config: /dev/null temp-armv7l-imx + perl merge.pl $^ arm > $@ + +kernel-$(VERSION)-armv7l-highbank.config: /dev/null temp-armv7l-highbank + perl merge.pl $^ arm > $@ + +kernel-$(VERSION)-armv7l-omap.config: /dev/null temp-armv7l-omap-generic + perl merge.pl $^ arm > $@ + +kernel-$(VERSION)-armv7l-tegra.config: /dev/null temp-armv7l-tegra + perl merge.pl $^ arm > $@ + +kernel-$(VERSION)-armv7hl-imx.config: /dev/null temp-armv7l-imx + perl merge.pl $^ arm > $@ + +kernel-$(VERSION)-armv7hl-highbank.config: /dev/null temp-armv7l-highbank + perl merge.pl $^ arm > $@ + +kernel-$(VERSION)-armv7hl-omap.config: /dev/null temp-armv7l-omap-generic + perl merge.pl $^ arm > $@ + +kernel-$(VERSION)-armv7hl-tegra.config: /dev/null temp-armv7l-tegra perl merge.pl $^ arm > $@ kernel-$(VERSION)-ppc.config: /dev/null temp-powerpc32-generic @@ -100,6 +156,3 @@ kernel-$(VERSION)-ppc.config: /dev/null temp-powerpc32-generic kernel-$(VERSION)-ppc-smp.config: config-powerpc32-smp temp-powerpc32-generic perl merge.pl $^ powerpc > $@ - -kernel-$(VERSION)-ia64.config: /dev/null temp-ia64-generic - perl merge.pl $^ ia64 > $@ diff --git a/NFSv4-Further-reduce-the-footprint-of-the-idmapper.patch b/NFSv4-Further-reduce-the-footprint-of-the-idmapper.patch new file mode 100644 index 000000000..42d1052e2 --- /dev/null +++ b/NFSv4-Further-reduce-the-footprint-of-the-idmapper.patch @@ -0,0 +1,109 @@ +diff -up linux-3.2.noarch/fs/nfs/idmap.c.orig linux-3.2.noarch/fs/nfs/idmap.c +--- linux-3.2.noarch/fs/nfs/idmap.c.orig 2012-03-14 13:08:37.462928792 -0400 ++++ linux-3.2.noarch/fs/nfs/idmap.c 2012-03-14 13:10:17.076030982 -0400 +@@ -365,7 +365,7 @@ struct idmap_hashent { + + struct idmap_hashtable { + __u8 h_type; +- struct idmap_hashent h_entries[IDMAP_HASH_SZ]; ++ struct idmap_hashent *h_entries; + }; + + struct idmap { +@@ -420,20 +420,39 @@ nfs_idmap_new(struct nfs_client *clp) + return 0; + } + ++static void ++idmap_alloc_hashtable(struct idmap_hashtable *h) ++{ ++ if (h->h_entries != NULL) ++ return; ++ h->h_entries = kcalloc(IDMAP_HASH_SZ, ++ sizeof(*h->h_entries), ++ GFP_KERNEL); ++} ++ ++static void ++idmap_free_hashtable(struct idmap_hashtable *h) ++{ ++ int i; ++ ++ if (h->h_entries == NULL) ++ return; ++ for (i = 0; i < IDMAP_HASH_SZ; i++) ++ kfree(h->h_entries[i].ih_name); ++ kfree(h->h_entries); ++} ++ + void + nfs_idmap_delete(struct nfs_client *clp) + { + struct idmap *idmap = clp->cl_idmap; +- int i; + + if (!idmap) + return; + rpc_unlink(idmap->idmap_dentry); + clp->cl_idmap = NULL; +- for (i = 0; i < ARRAY_SIZE(idmap->idmap_user_hash.h_entries); i++) +- kfree(idmap->idmap_user_hash.h_entries[i].ih_name); +- for (i = 0; i < ARRAY_SIZE(idmap->idmap_group_hash.h_entries); i++) +- kfree(idmap->idmap_group_hash.h_entries[i].ih_name); ++ idmap_free_hashtable(&idmap->idmap_user_hash); ++ idmap_free_hashtable(&idmap->idmap_group_hash); + kfree(idmap); + } + +@@ -443,6 +462,8 @@ nfs_idmap_delete(struct nfs_client *clp) + static inline struct idmap_hashent * + idmap_name_hash(struct idmap_hashtable* h, const char *name, size_t len) + { ++ if (h->h_entries == NULL) ++ return NULL; + return &h->h_entries[fnvhash32(name, len) % IDMAP_HASH_SZ]; + } + +@@ -451,6 +472,8 @@ idmap_lookup_name(struct idmap_hashtable + { + struct idmap_hashent *he = idmap_name_hash(h, name, len); + ++ if (he == NULL) ++ return NULL; + if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0) + return NULL; + if (time_after(jiffies, he->ih_expires)) +@@ -461,6 +484,8 @@ idmap_lookup_name(struct idmap_hashtable + static inline struct idmap_hashent * + idmap_id_hash(struct idmap_hashtable* h, __u32 id) + { ++ if (h->h_entries == NULL) ++ return NULL; + return &h->h_entries[fnvhash32(&id, sizeof(id)) % IDMAP_HASH_SZ]; + } + +@@ -468,6 +493,9 @@ static struct idmap_hashent * + idmap_lookup_id(struct idmap_hashtable *h, __u32 id) + { + struct idmap_hashent *he = idmap_id_hash(h, id); ++ ++ if (he == NULL) ++ return NULL; + if (he->ih_id != id || he->ih_namelen == 0) + return NULL; + if (time_after(jiffies, he->ih_expires)) +@@ -483,12 +511,14 @@ idmap_lookup_id(struct idmap_hashtable * + static inline struct idmap_hashent * + idmap_alloc_name(struct idmap_hashtable *h, char *name, size_t len) + { ++ idmap_alloc_hashtable(h); + return idmap_name_hash(h, name, len); + } + + static inline struct idmap_hashent * + idmap_alloc_id(struct idmap_hashtable *h, __u32 id) + { ++ idmap_alloc_hashtable(h); + return idmap_id_hash(h, id); + } + diff --git a/NFSv4-Minor-cleanups-for-nfs4_handle_exception-and-n.patch b/NFSv4-Minor-cleanups-for-nfs4_handle_exception-and-n.patch new file mode 100644 index 000000000..105235126 --- /dev/null +++ b/NFSv4-Minor-cleanups-for-nfs4_handle_exception-and-n.patch @@ -0,0 +1,51 @@ +From 14977489ffdb80d4caf5a184ba41b23b02fbacd9 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Tue, 27 Mar 2012 18:31:25 -0400 +Subject: [PATCH] NFSv4: Minor cleanups for nfs4_handle_exception and + nfs4_async_handle_error + +Signed-off-by: Trond Myklebust +--- + fs/nfs/nfs4proc.c | 10 +++++----- + 1 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c +index 1933e67..f82bde0 100644 +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -270,7 +270,7 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc + case 0: + return 0; + case -NFS4ERR_OPENMODE: +- if (nfs_have_delegation(inode, FMODE_READ)) { ++ if (inode && nfs_have_delegation(inode, FMODE_READ)) { + nfs_inode_return_delegation(inode); + exception->retry = 1; + return 0; +@@ -282,10 +282,9 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc + case -NFS4ERR_DELEG_REVOKED: + case -NFS4ERR_ADMIN_REVOKED: + case -NFS4ERR_BAD_STATEID: +- if (state != NULL) +- nfs_remove_bad_delegation(state->inode); + if (state == NULL) + break; ++ nfs_remove_bad_delegation(state->inode); + nfs4_schedule_stateid_recovery(server, state); + goto wait_on_recovery; + case -NFS4ERR_EXPIRED: +@@ -3825,8 +3824,9 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, + case -NFS4ERR_DELEG_REVOKED: + case -NFS4ERR_ADMIN_REVOKED: + case -NFS4ERR_BAD_STATEID: +- if (state != NULL) +- nfs_remove_bad_delegation(state->inode); ++ if (state == NULL) ++ break; ++ nfs_remove_bad_delegation(state->inode); + case -NFS4ERR_OPENMODE: + if (state == NULL) + break; +-- +1.7.7.6 + diff --git a/NFSv4-Rate-limit-the-state-manager-for-lock-reclaim-.patch b/NFSv4-Rate-limit-the-state-manager-for-lock-reclaim-.patch new file mode 100644 index 000000000..5b7f5e51d --- /dev/null +++ b/NFSv4-Rate-limit-the-state-manager-for-lock-reclaim-.patch @@ -0,0 +1,37 @@ +From 34d91cfbc163c6e2a136a27c96918fc35de06341 Mon Sep 17 00:00:00 2001 +From: William Dauchy +Date: Wed, 14 Mar 2012 12:32:04 +0100 +Subject: [PATCH] NFSv4: Rate limit the state manager for lock reclaim warning + messages + +Adding rate limit on `Lock reclaim failed` messages since it could fill +up system logs +Signed-off-by: William Dauchy +Signed-off-by: Trond Myklebust + +Conflicts: + + fs/nfs/nfs4state.c +--- + fs/nfs/nfs4state.c | 5 +++-- + 1 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c +index bacb271..3676b5c 100644 +--- a/fs/nfs/nfs4state.c ++++ b/fs/nfs/nfs4state.c +@@ -1247,8 +1247,9 @@ restart: + spin_lock(&state->state_lock); + list_for_each_entry(lock, &state->lock_states, ls_locks) { + if (!(lock->ls_flags & NFS_LOCK_INITIALIZED)) +- printk("%s: Lock reclaim failed!\n", +- __func__); ++ pr_warn_ratelimited("NFS: " ++ "%s: Lock reclaim " ++ "failed!\n", __func__); + } + spin_unlock(&state->state_lock); + nfs4_put_open_state(state); +-- +1.7.7.6 + diff --git a/NFSv4-Reduce-the-footprint-of-the-idmapper.patch b/NFSv4-Reduce-the-footprint-of-the-idmapper.patch new file mode 100644 index 000000000..4110ef904 --- /dev/null +++ b/NFSv4-Reduce-the-footprint-of-the-idmapper.patch @@ -0,0 +1,46 @@ +diff -up linux-3.2.noarch/fs/nfs/idmap.c.orig linux-3.2.noarch/fs/nfs/idmap.c +--- linux-3.2.noarch/fs/nfs/idmap.c.orig 2012-02-07 07:12:52.585471833 -0500 ++++ linux-3.2.noarch/fs/nfs/idmap.c 2012-03-14 13:08:37.462928792 -0400 +@@ -360,7 +360,7 @@ struct idmap_hashent { + unsigned long ih_expires; + __u32 ih_id; + size_t ih_namelen; +- char ih_name[IDMAP_NAMESZ]; ++ const char *ih_name; + }; + + struct idmap_hashtable { +@@ -424,11 +424,16 @@ void + nfs_idmap_delete(struct nfs_client *clp) + { + struct idmap *idmap = clp->cl_idmap; ++ int i; + + if (!idmap) + return; + rpc_unlink(idmap->idmap_dentry); + clp->cl_idmap = NULL; ++ for (i = 0; i < ARRAY_SIZE(idmap->idmap_user_hash.h_entries); i++) ++ kfree(idmap->idmap_user_hash.h_entries[i].ih_name); ++ for (i = 0; i < ARRAY_SIZE(idmap->idmap_group_hash.h_entries); i++) ++ kfree(idmap->idmap_group_hash.h_entries[i].ih_name); + kfree(idmap); + } + +@@ -491,9 +496,14 @@ static void + idmap_update_entry(struct idmap_hashent *he, const char *name, + size_t namelen, __u32 id) + { ++ char *str = kmalloc(namelen + 1, GFP_KERNEL); ++ if (str == NULL) ++ return; ++ kfree(he->ih_name); + he->ih_id = id; +- memcpy(he->ih_name, name, namelen); +- he->ih_name[namelen] = '\0'; ++ memcpy(str, name, namelen); ++ str[namelen] = '\0'; ++ he->ih_name = str; + he->ih_namelen = namelen; + he->ih_expires = jiffies + nfs_idmap_cache_timeout; + } diff --git a/Platform-fix-samsung-laptop-DMI-identification-for-N.patch b/Platform-fix-samsung-laptop-DMI-identification-for-N.patch new file mode 100644 index 000000000..c36935d6b --- /dev/null +++ b/Platform-fix-samsung-laptop-DMI-identification-for-N.patch @@ -0,0 +1,44 @@ +From 350268c1de71490d5e803a81e609191034a55560 Mon Sep 17 00:00:00 2001 +From: Thomas Courbon +Date: Wed, 20 Jul 2011 22:57:44 +0200 +Subject: [PATCH] Platform: fix samsung-laptop DMI identification for + N150/N210/220/N230 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some samsung latop of the N150/N2{10,20,30} serie are badly detected by the samsung-laptop platform driver, see bug # 36082. +It appears that N230 identifies itself as N150/N210/N220/N230 whereas the other identify themselves as N150/N210/220. +This patch attemtp fix #36082 allowing correct identification for all the said netbook model. + +Reported-by: Daniel Eklöf +Signed-off-by: Thomas Courbon +Signed-off-by: Matthew Garrett +--- + drivers/platform/x86/samsung-laptop.c | 10 ++++++++++ + 1 files changed, 10 insertions(+), 0 deletions(-) + +diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c +index d347116..1658575 100644 +--- a/drivers/platform/x86/samsung-laptop.c ++++ b/drivers/platform/x86/samsung-laptop.c +@@ -601,6 +601,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { + .callback = dmi_check_cb, + }, + { ++ .ident = "N150/N210/N220", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, ++ "SAMSUNG ELECTRONICS CO., LTD."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"), ++ DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"), ++ }, ++ .callback = dmi_check_cb, ++ }, ++ { + .ident = "N150/N210/N220/N230", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, +-- +1.7.6 + diff --git a/TODO b/TODO index abaefae05..968324422 100644 --- a/TODO +++ b/TODO @@ -1,57 +1,33 @@ # Put stuff likely to go upstream (in decreasing likelyhood) at the top. -# - -* linux-2.6-firewire-git-update.patch - perpetual updates from git trees. * linux-2.6-compile-fixes.patch -* linux-2.6-hotfixes.patch Empty -* linux-2.6-build-nonintconfig.patch -* linux-2.6-debug-nmi-timeout.patch -* linux-2.6-debug-spinlock-taint.patch * linux-2.6-debug-taint-vm.patch * linux-2.6-debug-vm-would-have-oomkilled.patch TODO: Push upstream * linux-2.6-acpi-video-dos.patch * linux-2.6-defaults-acpi-video.patch +* linux-2.6-defaults-aspm.patch Fedora policy decisions Turn into CONFIG_ options and upstream ? -* linux-2.6-crash-driver.patch - Unlikely to go upstream. - https://bugzilla.redhat.com/show_bug.cgi?id=492803 - -* linux-2.6-debug-always-inline-kzalloc.patch - Sent upstream Sep 25 2008 - -* linux-2.6-debug-sizeof-structs.patch - Fedora local debug stuff. - -* linux-2.6-utrace.patch - utrace - -* linux-2.6-defaults-pci_no_msi.patch - Fedora local choices uninteresting to upstream - * linux-2.6-input-kill-stupid-messages.patch * linux-2.6-silence-acpi-blacklist.patch * linux-2.6-silence-fbcon-logo.patch * linux-2.6-silence-noise.patch Fedora local 'hush' patches. (Some will go upstream next time) -* linux-2.6-execshield.patch - Not interesting to upstream. +* linux-2.6-makefile-after_link.patch + Rolandware that is used by the debuginfo generation. + Possibly upstreamable ? -* lirc-2.6.33.patch -* hdpvr-ir-enable.patch - jarod working on upstreaming +* linux-2.6.29-sparc-IOC_TYPECHECK.patch + Responsible: Spot/Dennis. -* linux-2.6-selinux-mprotect-checks.patch -* linux-2.6-sparc-selinux-mprotect-checks.patch - Newer version might go upstream at some point. +* linux-2.6-v4l-dvb-uvcvideo-update.patch + Responsible: Hans. * linux-2.6-serial-460800.patch Probably not upstreamable. @@ -59,3 +35,56 @@ https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=126403 http://lkml.org/lkml/2006/8/2/208 +* linux-2.6-crash-driver.patch + Unlikely to go upstream. + https://bugzilla.redhat.com/show_bug.cgi?id=492803 + +* linux-2.6-32bit-mmap-exec-randomization.patch + One half of the remaining exec-shield diff. + davej bugged Ingo again on Jun 17 2011 about upstreaming. + +* runtime_pm_fixups.patch +* linux-2.6-usb-pci-autosuspend.patch +* linux-2.6-enable-more-pci-autosuspend.patch +* linux-2.6-acpi-debug-infinite-loop.patch +* acpi-ec-add-delay-before-write.patch + Responsible: mjg59 + +* linux-2.6-v4l-dvb-experimental.patch +* linux-2.6-v4l-dvb-fixes.patch +* linux-2.6-v4l-dvb-update.patch + Empty. + +* fix_xen_guest_on_old_EC2.patch + Ugly for upstream. It's a hack to make old HV's work optimally. + Eventually we can drop it, but probably not until fixed HV's + are commonplace. (When?) + Responsible: Justin. + +* linux-2.6-i386-nx-emulation.patch + The ugly segment hack part of exec-shield that Linus hates. + Unlikely to ever go upstream. + +* linux-2.6-e1000-ich9-montevina.patch + Intel hates it. Davej has an SDV that needs it. + Low maintenence, and worth hanging onto until it gets replaced + with something that fails in a different way. + +-------- +currently undocumented: + +add-appleir-usb-driver.patch +die-floppy-die.patch +disable-i8042-check-on-apple-mac.patch +dmar-disable-when-ricoh-multifunction.patch +drm-intel-make-lvds-work.patch +drm-intel-next.patch +drm-nouveau-updates.patch +hda_intel-prealloc-4mb-dmabuffer.patch +linux-2.6.30-no-pcspkr-modalias.patch +linux-2.6-input-kill-stupid-messages.patch +linux-2.6-intel-iommu-igfx.patch +linux-2.6-upstream-reverts.patch +linux-3.0-fix-uts-release.patch +neuter_intel_microcode_load.patch + diff --git a/acpi-ec-add-delay-before-write.patch b/acpi-ec-add-delay-before-write.patch deleted file mode 100644 index f1cb50817..000000000 --- a/acpi-ec-add-delay-before-write.patch +++ /dev/null @@ -1,51 +0,0 @@ -https://bugzilla.kernel.org/show_bug.cgi?id=14733#c41 - -diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c -index 27e0b92..09fbb69 100644 ---- a/drivers/acpi/ec.c -+++ b/drivers/acpi/ec.c -@@ -226,6 +226,7 @@ static int ec_poll(struct acpi_ec *ec) - if (ec_transaction_done(ec)) - return 0; - } else { -+ msleep(1); - if (wait_event_timeout(ec->wait, - ec_transaction_done(ec), - msecs_to_jiffies(1))) -@@ -233,8 +234,8 @@ static int ec_poll(struct acpi_ec *ec) - } - advance_transaction(ec, acpi_ec_read_status(ec)); - } while (time_before(jiffies, delay)); -- if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) -- break; -+// if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) -+// break; - pr_debug(PREFIX "controller reset, restart transaction\n"); - spin_lock_irqsave(&ec->curr_lock, flags); - start_transaction(ec); -@@ -271,15 +272,24 @@ static int ec_check_ibf0(struct acpi_ec *ec) - return (status & ACPI_EC_FLAG_IBF) == 0; - } - -+/* try to clean input buffer with burst_disable transaction */ -+static int acpi_ec_clean_buffer(struct acpi_ec *ec) -+{ -+ struct transaction t = {.command = ACPI_EC_BURST_DISABLE, -+ .wdata = NULL, .rdata = NULL, -+ .wlen = 0, .rlen = 0}; -+ return acpi_ec_transaction_unlocked(ec, &t); -+} -+ - static int ec_wait_ibf0(struct acpi_ec *ec) - { - unsigned long delay = jiffies + msecs_to_jiffies(ec_delay); - /* interrupt wait manually if GPE mode is not active */ - while (time_before(jiffies, delay)) - if (wait_event_timeout(ec->wait, ec_check_ibf0(ec), - msecs_to_jiffies(1))) - return 0; -- return -ETIME; -+ return acpi_ec_clean_buffer(ec); - } - - static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) diff --git a/acpi-sony-nonvs-blacklist.patch b/acpi-sony-nonvs-blacklist.patch new file mode 100644 index 000000000..db500e8bf --- /dev/null +++ b/acpi-sony-nonvs-blacklist.patch @@ -0,0 +1,38 @@ +diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c +index 3ed80b2..17fc718 100644 +--- a/drivers/acpi/sleep.c ++++ b/drivers/acpi/sleep.c +@@ -390,6 +390,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { + }, + { + .callback = init_nvs_nosave, ++ .ident = "Sony Vaio VGN-FW21E", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21E"), ++ }, ++ }, ++ { ++ .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-SR11M", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), +diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c +index 0e46fae..6d9a3ab 100644 +--- a/drivers/acpi/sleep.c ++++ b/drivers/acpi/sleep.c +@@ -398,6 +398,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { + }, + { + .callback = init_nvs_nosave, ++ .ident = "Sony Vaio VPCEB17FX", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB17FX"), ++ }, ++ }, ++ { ++ .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-SR11M", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), diff --git a/acpi_reboot.patch b/acpi_reboot.patch deleted file mode 100644 index a980b31f7..000000000 --- a/acpi_reboot.patch +++ /dev/null @@ -1,102 +0,0 @@ -Improve our reboot handling for compatibility with Windows. Upstream in .38? - -diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c -index c495aa8..c770e66 100644 ---- a/arch/x86/kernel/reboot.c -+++ b/arch/x86/kernel/reboot.c -@@ -34,7 +34,7 @@ EXPORT_SYMBOL(pm_power_off); - - static const struct desc_ptr no_idt = {}; - static int reboot_mode; --enum reboot_type reboot_type = BOOT_KBD; -+enum reboot_type reboot_type = BOOT_ACPI; - int reboot_force; - - #if defined(CONFIG_X86_32) && defined(CONFIG_SMP) -@@ -538,9 +538,23 @@ void __attribute__((weak)) mach_reboot_fixups(void) - { - } - -+/* -+ * Windows does the following on reboot: -+ * 1) If the FADT has the ACPI reboot register flag set, try it -+ * 2) If still alive, write to the keyboard controller -+ * 3) If still alive, write to the ACPI reboot register again -+ * 4) Ig still alive, write to the keyboard controller again -+ * -+ * If the machine is still alive at this stage, it gives up. We default to -+ * following the same pattern, except that if we're still alive after (4) we'll -+ * try to force a triple fault and then cycle between hitting the keyboard -+ * controller and doing that -+ */ - static void native_machine_emergency_restart(void) - { - int i; -+ int attempt = 0; -+ int orig_reboot_type = reboot_type; - - if (reboot_emergency) - emergency_vmx_disable_all(); -@@ -562,6 +576,13 @@ static void native_machine_emergency_restart(void) - outb(0xfe, 0x64); /* pulse reset low */ - udelay(50); - } -+ if (attempt == 0 && orig_reboot_type == BOOT_ACPI) { -+ attempt = 1; -+ reboot_type = BOOT_ACPI; -+ } else { -+ reboot_type = BOOT_TRIPLE; -+ } -+ break; - - case BOOT_TRIPLE: - load_idt(&no_idt); -diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c -index 50cc3be..c6a4e63 100644 ---- a/drivers/acpi/acpica/hwxface.c -+++ b/drivers/acpi/acpica/hwxface.c -@@ -82,12 +82,11 @@ acpi_status acpi_reset(void) - /* - * For I/O space, write directly to the OSL. This bypasses the port - * validation mechanism, which may block a valid write to the reset -- * register. -+ * register. Spec section 4.7.3.6 requires register width to be 8. - */ - status = - acpi_os_write_port((acpi_io_address) reset_reg->address, -- acpi_gbl_FADT.reset_value, -- reset_reg->bit_width); -+ acpi_gbl_FADT.reset_value, 8); - } else { - /* Write the reset value to the reset register */ - -diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c -index 93f9114..a6c77e8b 100644 ---- a/drivers/acpi/reboot.c -+++ b/drivers/acpi/reboot.c -@@ -15,9 +15,15 @@ void acpi_reboot(void) - - rr = &acpi_gbl_FADT.reset_register; - -- /* Is the reset register supported? */ -- if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) || -- rr->bit_width != 8 || rr->bit_offset != 0) -+ /* ACPI reset register was only introduced with v2 of the FADT */ -+ -+ if (acpi_gbl_FADT.header.revision < 2) -+ return; -+ -+ /* Is the reset register supported? The spec says we should be -+ * checking the bit width and bit offset, but Windows ignores -+ * these fields */ -+ if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER)) - return; - - reset_value = acpi_gbl_FADT.reset_value; -@@ -45,6 +51,4 @@ void acpi_reboot(void) - acpi_reset(); - break; - } -- /* Wait ten seconds */ -- acpi_os_stall(10000000); - } diff --git a/add-appleir-usb-driver.patch b/add-appleir-usb-driver.patch deleted file mode 100644 index 61edb8061..000000000 --- a/add-appleir-usb-driver.patch +++ /dev/null @@ -1,702 +0,0 @@ -From e11e9e78799a7641fe0dc5289f35f2604a4b71a3 Mon Sep 17 00:00:00 2001 -From: Bastien Nocera -Date: Sun, 17 Jan 2010 00:40:15 +0000 -Subject: [PATCH] Input: add appleir USB driver - -This driver was originally written by James McKenzie, updated by -Greg Kroah-Hartman, further updated by myself, with suspend support -added. - -More recent versions of the IR receiver are also supported through -a patch by Alex Karpenko. The patch also adds support for the 2nd -and 5th generation of the controller, and the menu key on newer -brushed metal remotes. - -Tested on a MacbookAir1,1 - -Signed-off-by: Bastien Nocera ---- - Documentation/input/appleir.txt | 46 ++++ - drivers/hid/hid-apple.c | 4 - - drivers/hid/hid-core.c | 7 +- - drivers/hid/hid-ids.h | 5 +- - drivers/input/misc/Kconfig | 13 + - drivers/input/misc/Makefile | 1 + - drivers/input/misc/appleir.c | 519 +++++++++++++++++++++++++++++++++++++++ - 7 files changed, 588 insertions(+), 7 deletions(-) - create mode 100644 Documentation/input/appleir.txt - create mode 100644 drivers/input/misc/appleir.c - -diff --git a/Documentation/input/appleir.txt b/Documentation/input/appleir.txt -new file mode 100644 -index 0000000..db637fb ---- /dev/null -+++ b/Documentation/input/appleir.txt -@@ -0,0 +1,46 @@ -+Apple IR receiver Driver (appleir) -+---------------------------------- -+ Copyright (C) 2009 Bastien Nocera -+ -+The appleir driver is a kernel input driver to handle Apple's IR -+receivers (and associated remotes) in the kernel. -+ -+The driver is an input driver which only handles "official" remotes -+as built and sold by Apple. -+ -+Authors -+------- -+ -+James McKenzie (original driver) -+Alex Karpenko (05ac:8242 support) -+Greg Kroah-Hartman (cleanups and original submission) -+Bastien Nocera (further cleanups, brushed metal "enter" -+button support and suspend support) -+ -+Supported hardware -+------------------ -+ -+- All Apple laptops and desktops from 2005 onwards, except: -+ - the unibody Macbook (2009) -+ - Mac Pro (all versions) -+- Apple TV (all revisions prior to September 2010) -+ -+The remote will only support the 6 (old white) or 7 (brushed metal) buttons -+of the remotes as sold by Apple. See the next section if you want to use -+other remotes or want to use lirc with the device instead of the kernel driver. -+ -+Using lirc (native) instead of the kernel driver -+------------------------------------------------ -+ -+First, you will need to disable the kernel driver for the receiver. -+ -+This can be achieved by passing quirks to the usbhid driver. -+The quirk line would be: -+usbhid.quirks=0x05ac:0x8242:0x40000010 -+ -+With 0x05ac being the vendor ID (Apple, you shouldn't need to change this) -+With 0x8242 being the product ID (check the output of lsusb for your hardware) -+And 0x10 being "HID_QUIRK_HIDDEV_FORCE" and 0x40000000 being "HID_QUIRK_NO_IGNORE" -+ -+This should force the creation of a hiddev device for the receiver, and -+make it usable under lirc. -diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c -index bba05d0..0059d5a 100644 ---- a/drivers/hid/hid-apple.c -+++ b/drivers/hid/hid-apple.c -@@ -361,10 +361,6 @@ static void apple_remove(struct hid_device *hdev) - } - - static const struct hid_device_id apple_devices[] = { -- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL), -- .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT }, -- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4), -- .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE), - .driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL }, - -diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c -index baa25ad..abc5bd7 100644 ---- a/drivers/hid/hid-core.c -+++ b/drivers/hid/hid-core.c -@@ -1244,8 +1244,6 @@ static const struct hid_device_id hid_blacklist[] = { - #if defined(CONFIG_HID_ACRUX_FF) || defined(CONFIG_HID_ACRUX_FF_MODULE) - { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) }, - #endif -- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) }, -- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) }, -@@ -1577,6 +1575,11 @@ static const struct hid_device_id hid_ignore_list[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) }, - { HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)}, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)}, - { HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) }, -diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h -index 11af537..360a5ca 100644 ---- a/drivers/hid/hid-ids.h -+++ b/drivers/hid/hid-ids.h -@@ -100,8 +100,11 @@ - #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b - #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a - #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b --#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241 -+#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240 -+#define USB_DEVICE_ID_APPLE_IRCONTROL2 0x1440 -+#define USB_DEVICE_ID_APPLE_IRCONTROL3 0x8241 - #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 -+#define USB_DEVICE_ID_APPLE_IRCONTROL5 0x8243 - - #define USB_VENDOR_ID_ASUS 0x0486 - #define USB_DEVICE_ID_ASUS_T91MT 0x0185 -diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig -index 60de906..2f2f2e7 100644 ---- a/drivers/input/misc/Kconfig -+++ b/drivers/input/misc/Kconfig -@@ -209,6 +209,19 @@ config INPUT_KEYSPAN_REMOTE - To compile this driver as a module, choose M here: the module will - be called keyspan_remote. - -+config INPUT_APPLEIR -+ tristate "Apple infrared receiver (built in)" -+ depends on USB_ARCH_HAS_HCD -+ select USB -+ help -+ Say Y here if you want to use a Apple infrared remote control. All -+ the Apple computers from 2005 onwards include such a port, except -+ the unibody Macbook (2009), and Mac Pros. This receiver is also -+ used in the Apple TV set-top box prior to the 2010 model. -+ -+ To compile this driver as a module, choose M here: the module will -+ be called appleir. -+ - config INPUT_POWERMATE - tristate "Griffin PowerMate and Contour Jog support" - depends on USB_ARCH_HAS_HCD -diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile -index 1fe1f6c..d5ef2b9 100644 ---- a/drivers/input/misc/Makefile -+++ b/drivers/input/misc/Makefile -@@ -13,6 +13,7 @@ obj-$(CONFIG_INPUT_ADXL34X) += adxl34x.o - obj-$(CONFIG_INPUT_ADXL34X_I2C) += adxl34x-i2c.o - obj-$(CONFIG_INPUT_ADXL34X_SPI) += adxl34x-spi.o - obj-$(CONFIG_INPUT_APANEL) += apanel.o -+obj-$(CONFIG_INPUT_APPLEIR) += appleir.o - obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o - obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o - obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o -diff --git a/drivers/input/misc/appleir.c b/drivers/input/misc/appleir.c -new file mode 100644 -index 0000000..3817a3c ---- /dev/null -+++ b/drivers/input/misc/appleir.c -@@ -0,0 +1,519 @@ -+/* -+ * appleir: USB driver for the apple ir device -+ * -+ * Original driver written by James McKenzie -+ * Ported to recent 2.6 kernel versions by Greg Kroah-Hartman -+ * -+ * Copyright (C) 2006 James McKenzie -+ * Copyright (C) 2008 Greg Kroah-Hartman -+ * Copyright (C) 2008 Novell Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the Free -+ * Software Foundation, version 2. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DRIVER_VERSION "v1.2" -+#define DRIVER_AUTHOR "James McKenzie" -+#define DRIVER_DESC "Apple infrared receiver driver" -+#define DRIVER_LICENSE "GPL" -+ -+MODULE_AUTHOR(DRIVER_AUTHOR); -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_LICENSE(DRIVER_LICENSE); -+ -+#define USB_VENDOR_ID_APPLE 0x05ac -+#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240 -+#define USB_DEVICE_ID_APPLE_IRCONTROL2 0x1440 -+#define USB_DEVICE_ID_APPLE_IRCONTROL3 0x8241 -+#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 -+#define USB_DEVICE_ID_APPLE_IRCONTROL5 0x8243 -+ -+#define URB_SIZE 32 -+ -+#define MAX_KEYS 9 -+#define MAX_KEYS_MASK (MAX_KEYS - 1) -+ -+#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) -+ -+static int debug; -+module_param(debug, int, 0644); -+MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); -+ -+/* I have two devices both of which report the following */ -+/* 25 87 ee 83 0a + */ -+/* 25 87 ee 83 0c - */ -+/* 25 87 ee 83 09 << */ -+/* 25 87 ee 83 06 >> */ -+/* 25 87 ee 83 05 >" */ -+/* 25 87 ee 83 03 menu */ -+/* 26 00 00 00 00 for key repeat*/ -+ -+/* Thomas Glanzmann reports the following responses */ -+/* 25 87 ee ca 0b + */ -+/* 25 87 ee ca 0d - */ -+/* 25 87 ee ca 08 << */ -+/* 25 87 ee ca 07 >> */ -+/* 25 87 ee ca 04 >" */ -+/* 25 87 ee ca 02 menu */ -+/* 26 00 00 00 00 for key repeat*/ -+/* He also observes the following event sometimes */ -+/* sent after a key is release, which I interpret */ -+/* as a flat battery message */ -+/* 25 87 e0 ca 06 flat battery */ -+ -+/* Alexandre Karpenko reports the following responses for Device ID 0x8242 */ -+/* 25 87 ee 47 0b + */ -+/* 25 87 ee 47 0d - */ -+/* 25 87 ee 47 08 << */ -+/* 25 87 ee 47 07 >> */ -+/* 25 87 ee 47 04 >" */ -+/* 25 87 ee 47 02 menu */ -+/* 26 87 ee 47 ** for key repeat (** is the code of the key being held) */ -+ -+/* Bastien Nocera's "new" remote */ -+/* 25 87 ee 91 5f followed by -+ * 25 87 ee 91 05 gives you >" -+ * -+ * 25 87 ee 91 5c followed by -+ * 25 87 ee 91 05 gives you the middle button */ -+ -+static const unsigned short appleir_key_table[] = { -+ KEY_RESERVED, -+ KEY_MENU, -+ KEY_PLAYPAUSE, -+ KEY_FORWARD, -+ KEY_BACK, -+ KEY_VOLUMEUP, -+ KEY_VOLUMEDOWN, -+ KEY_ENTER, -+ KEY_RESERVED, -+}; -+ -+struct appleir { -+ struct input_dev *input_dev; -+ unsigned short keymap[ARRAY_SIZE(appleir_key_table)]; -+ u8 *data; -+ dma_addr_t dma_buf; -+ struct usb_device *usbdev; -+ unsigned int flags; -+ struct urb *urb; -+ struct timer_list key_up_timer; -+ int current_key; -+ int prev_key_idx; -+ char phys[32]; -+}; -+ -+static DEFINE_MUTEX(appleir_mutex); -+ -+enum { -+ APPLEIR_OPENED = 0x1, -+ APPLEIR_SUSPENDED = 0x2, -+}; -+ -+static struct usb_device_id appleir_ids[] = { -+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) }, -+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) }, -+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) }, -+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, -+ { USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) }, -+ {} -+}; -+MODULE_DEVICE_TABLE(usb, appleir_ids); -+ -+static void dump_packet(struct appleir *appleir, char *msg, u8 *data, int len) -+{ -+ int i; -+ -+ printk(KERN_ERR "appleir: %s (%d bytes)", msg, len); -+ -+ for (i = 0; i < len; ++i) -+ printk(" %02x", data[i]); -+ printk(" (should be command %d)\n", (data[4] >> 1) & MAX_KEYS_MASK); -+} -+ -+static int get_key(int data) -+{ -+ switch (data) { -+ case 0x02: -+ case 0x03: -+ /* menu */ -+ return 1; -+ case 0x04: -+ case 0x05: -+ /* >" */ -+ return 2; -+ case 0x06: -+ case 0x07: -+ /* >> */ -+ return 3; -+ case 0x08: -+ case 0x09: -+ /* << */ -+ return 4; -+ case 0x0a: -+ case 0x0b: -+ /* + */ -+ return 5; -+ case 0x0c: -+ case 0x0d: -+ /* - */ -+ return 6; -+ case 0x5c: -+ /* Middle button, on newer remotes, -+ * part of a 2 packet-command */ -+ return -7; -+ default: -+ return -1; -+ } -+} -+ -+static void key_up(struct appleir *appleir, int key) -+{ -+ dbginfo(&appleir->input_dev->dev, "key %d up\n", key); -+ input_report_key(appleir->input_dev, key, 0); -+ input_sync(appleir->input_dev); -+} -+ -+static void key_down(struct appleir *appleir, int key) -+{ -+ dbginfo(&appleir->input_dev->dev, "key %d down\n", key); -+ input_report_key(appleir->input_dev, key, 1); -+ input_sync(appleir->input_dev); -+} -+ -+static void battery_flat(struct appleir *appleir) -+{ -+ dev_err(&appleir->input_dev->dev, "possible flat battery?\n"); -+} -+ -+static void key_up_tick(unsigned long data) -+{ -+ struct appleir *appleir = (struct appleir *)data; -+ -+ if (appleir->current_key) { -+ key_up(appleir, appleir->current_key); -+ appleir->current_key = 0; -+ } -+} -+ -+static void new_data(struct appleir *appleir, u8 *data, int len) -+{ -+ static const u8 keydown[] = { 0x25, 0x87, 0xee }; -+ static const u8 keyrepeat[] = { 0x26, }; -+ static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 }; -+ -+ if (debug) -+ dump_packet(appleir, "received", data, len); -+ -+ if (len != 5) -+ return; -+ -+ if (!memcmp(data, keydown, sizeof(keydown))) { -+ int index; -+ -+ /* If we already have a key down, take it up before marking -+ this one down */ -+ if (appleir->current_key) -+ key_up(appleir, appleir->current_key); -+ -+ /* Handle dual packet commands */ -+ if (appleir->prev_key_idx > 0) -+ index = appleir->prev_key_idx; -+ else -+ index = get_key(data[4]); -+ -+ if (index > 0) { -+ appleir->current_key = appleir->keymap[index]; -+ -+ key_down(appleir, appleir->current_key); -+ /* Remote doesn't do key up, either pull them up, in the test -+ above, or here set a timer which pulls them up after 1/8 s */ -+ mod_timer(&appleir->key_up_timer, jiffies + HZ / 8); -+ appleir->prev_key_idx = 0; -+ return; -+ } else if (index == -7) { -+ /* Remember key for next packet */ -+ appleir->prev_key_idx = 0 - index; -+ return; -+ } -+ } -+ -+ appleir->prev_key_idx = 0; -+ -+ if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) { -+ key_down(appleir, appleir->current_key); -+ /* Remote doesn't do key up, either pull them up, in the test -+ above, or here set a timer which pulls them up after 1/8 s */ -+ mod_timer(&appleir->key_up_timer, jiffies + HZ / 8); -+ return; -+ } -+ -+ if (!memcmp(data, flatbattery, sizeof(flatbattery))) { -+ battery_flat(appleir); -+ /* Fall through */ -+ } -+ -+ dump_packet(appleir, "unknown packet", data, len); -+} -+ -+static void appleir_urb(struct urb *urb) -+{ -+ struct appleir *appleir = urb->context; -+ int status = urb->status; -+ int retval; -+ -+ switch (status) { -+ case 0: -+ new_data(appleir, urb->transfer_buffer, urb->actual_length); -+ break; -+ case -ECONNRESET: -+ case -ENOENT: -+ case -ESHUTDOWN: -+ /* This urb is terminated, clean up */ -+ dbginfo(&appleir->input_dev->dev, "%s - urb shutting down with status: %d", __func__, -+ urb->status); -+ return; -+ default: -+ dbginfo(&appleir->input_dev->dev, "%s - nonzero urb status received: %d", __func__, -+ urb->status); -+ } -+ -+ retval = usb_submit_urb(urb, GFP_ATOMIC); -+ if (retval) -+ err("%s - usb_submit_urb failed with result %d", __func__, -+ retval); -+} -+ -+static int appleir_open(struct input_dev *dev) -+{ -+ struct appleir *appleir = input_get_drvdata(dev); -+ struct usb_interface *intf = usb_ifnum_to_if(appleir->usbdev, 0); -+ int r; -+ -+ r = usb_autopm_get_interface(intf); -+ if (r) { -+ dev_err(&intf->dev, -+ "%s(): usb_autopm_get_interface() = %d\n", __func__, r); -+ return r; -+ } -+ -+ mutex_lock(&appleir_mutex); -+ -+ if (usb_submit_urb(appleir->urb, GFP_ATOMIC)) { -+ r = -EIO; -+ goto fail; -+ } -+ -+ appleir->flags |= APPLEIR_OPENED; -+ -+ mutex_unlock(&appleir_mutex); -+ -+ usb_autopm_put_interface(intf); -+ -+ return 0; -+fail: -+ mutex_unlock(&appleir_mutex); -+ usb_autopm_put_interface(intf); -+ return r; -+} -+ -+static void appleir_close(struct input_dev *dev) -+{ -+ struct appleir *appleir = input_get_drvdata(dev); -+ -+ mutex_lock(&appleir_mutex); -+ -+ if (!(appleir->flags & APPLEIR_SUSPENDED)) { -+ usb_kill_urb(appleir->urb); -+ del_timer_sync(&appleir->key_up_timer); -+ } -+ -+ appleir->flags &= ~APPLEIR_OPENED; -+ -+ mutex_unlock(&appleir_mutex); -+} -+ -+static int appleir_probe(struct usb_interface *intf, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *dev = interface_to_usbdev(intf); -+ struct usb_endpoint_descriptor *endpoint; -+ struct appleir *appleir = NULL; -+ struct input_dev *input_dev; -+ int retval = -ENOMEM; -+ int i; -+ -+ appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL); -+ if (!appleir) -+ goto allocfail; -+ -+ appleir->data = usb_alloc_coherent(dev, URB_SIZE, GFP_KERNEL, -+ &appleir->dma_buf); -+ if (!appleir->data) -+ goto usbfail; -+ -+ appleir->urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!appleir->urb) -+ goto urbfail; -+ -+ appleir->usbdev = dev; -+ -+ input_dev = input_allocate_device(); -+ if (!input_dev) -+ goto inputfail; -+ -+ appleir->input_dev = input_dev; -+ -+ usb_make_path(dev, appleir->phys, sizeof(appleir->phys)); -+ strlcpy(appleir->phys, "/input0", sizeof(appleir->phys)); -+ -+ input_dev->name = "Apple Infrared Remote Controller"; -+ input_dev->phys = appleir->phys; -+ usb_to_input_id(dev, &input_dev->id); -+ input_dev->dev.parent = &intf->dev; -+ input_dev->keycode = appleir->keymap; -+ input_dev->keycodesize = sizeof(unsigned short); -+ input_dev->keycodemax = ARRAY_SIZE(appleir->keymap); -+ -+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); -+ -+ memcpy(appleir->keymap, appleir_key_table, sizeof(appleir->keymap)); -+ for (i = 0; i < ARRAY_SIZE(appleir_key_table); i++) -+ set_bit(appleir->keymap[i], input_dev->keybit); -+ clear_bit(KEY_RESERVED, input_dev->keybit); -+ -+ input_set_drvdata(input_dev, appleir); -+ input_dev->open = appleir_open; -+ input_dev->close = appleir_close; -+ -+ endpoint = &intf->cur_altsetting->endpoint[0].desc; -+ -+ usb_fill_int_urb(appleir->urb, dev, -+ usb_rcvintpipe(dev, endpoint->bEndpointAddress), -+ appleir->data, 8, -+ appleir_urb, appleir, endpoint->bInterval); -+ -+ appleir->urb->transfer_dma = appleir->dma_buf; -+ appleir->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -+ -+ setup_timer(&appleir->key_up_timer, -+ key_up_tick, (unsigned long) appleir); -+ -+ retval = input_register_device(appleir->input_dev); -+ if (retval) -+ goto inputfail; -+ -+ usb_set_intfdata(intf, appleir); -+ -+ return 0; -+ -+inputfail: -+ input_free_device(appleir->input_dev); -+ -+urbfail: -+ usb_free_urb(appleir->urb); -+ -+usbfail: -+ usb_free_coherent(dev, URB_SIZE, appleir->data, -+ appleir->dma_buf); -+ -+allocfail: -+ kfree(appleir); -+ -+ return retval; -+} -+ -+static void appleir_disconnect(struct usb_interface *intf) -+{ -+ struct appleir *appleir = usb_get_intfdata(intf); -+ -+ usb_set_intfdata(intf, NULL); -+ input_unregister_device(appleir->input_dev); -+ usb_free_urb(appleir->urb); -+ usb_free_coherent(interface_to_usbdev(intf), URB_SIZE, -+ appleir->data, appleir->dma_buf); -+ kfree(appleir); -+} -+ -+static int appleir_suspend(struct usb_interface *interface, -+ pm_message_t message) -+{ -+ struct appleir *appleir = usb_get_intfdata(interface); -+ -+ mutex_lock(&appleir_mutex); -+ if (appleir->flags & APPLEIR_OPENED) -+ usb_kill_urb(appleir->urb); -+ -+ appleir->flags |= APPLEIR_SUSPENDED; -+ -+ mutex_unlock(&appleir_mutex); -+ -+ return 0; -+} -+ -+static int appleir_resume(struct usb_interface *interface) -+{ -+ struct appleir *appleir; -+ int r = 0; -+ -+ appleir = usb_get_intfdata(interface); -+ -+ mutex_lock(&appleir_mutex); -+ if (appleir->flags & APPLEIR_OPENED) { -+ struct usb_endpoint_descriptor *endpoint; -+ -+ endpoint = &interface->cur_altsetting->endpoint[0].desc; -+ usb_fill_int_urb(appleir->urb, appleir->usbdev, -+ usb_rcvintpipe(appleir->usbdev, endpoint->bEndpointAddress), -+ appleir->data, 8, -+ appleir_urb, appleir, endpoint->bInterval); -+ appleir->urb->transfer_dma = appleir->dma_buf; -+ appleir->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -+ -+ /* And reset the USB device */ -+ if (usb_submit_urb(appleir->urb, GFP_ATOMIC)) -+ r = -EIO; -+ } -+ -+ appleir->flags &= ~APPLEIR_SUSPENDED; -+ -+ mutex_unlock(&appleir_mutex); -+ -+ return r; -+} -+ -+static struct usb_driver appleir_driver = { -+ .name = "appleir", -+ .probe = appleir_probe, -+ .disconnect = appleir_disconnect, -+ .suspend = appleir_suspend, -+ .resume = appleir_resume, -+ .reset_resume = appleir_resume, -+ .id_table = appleir_ids, -+}; -+ -+static int __init appleir_init(void) -+{ -+ return usb_register(&appleir_driver); -+} -+ -+static void __exit appleir_exit(void) -+{ -+ usb_deregister(&appleir_driver); -+} -+ -+module_init(appleir_init); -+module_exit(appleir_exit); --- -1.7.2.2 - diff --git a/add-poll-requested-events.patch b/add-poll-requested-events.patch new file mode 100644 index 000000000..9ab28c1b3 --- /dev/null +++ b/add-poll-requested-events.patch @@ -0,0 +1,393 @@ +commit 626cf236608505d376e4799adb4f7eb00a8594af +Author: Hans Verkuil +Date: Fri Mar 23 15:02:27 2012 -0700 + + poll: add poll_requested_events() and poll_does_not_wait() functions + + In some cases the poll() implementation in a driver has to do different + things depending on the events the caller wants to poll for. An example + is when a driver needs to start a DMA engine if the caller polls for + POLLIN, but doesn't want to do that if POLLIN is not requested but instead + only POLLOUT or POLLPRI is requested. This is something that can happen + in the video4linux subsystem among others. + + Unfortunately, the current epoll/poll/select implementation doesn't + provide that information reliably. The poll_table_struct does have it: it + has a key field with the event mask. But once a poll() call matches one + or more bits of that mask any following poll() calls are passed a NULL + poll_table pointer. + + Also, the eventpoll implementation always left the key field at ~0 instead + of using the requested events mask. + + This was changed in eventpoll.c so the key field now contains the actual + events that should be polled for as set by the caller. + + The solution to the NULL poll_table pointer is to set the qproc field to + NULL in poll_table once poll() matches the events, not the poll_table + pointer itself. That way drivers can obtain the mask through a new + poll_requested_events inline. + + The poll_table_struct can still be NULL since some kernel code calls it + internally (netfs_state_poll() in ./drivers/staging/pohmelfs/netfs.h). In + that case poll_requested_events() returns ~0 (i.e. all events). + + Very rarely drivers might want to know whether poll_wait will actually + wait. If another earlier file descriptor in the set already matched the + events the caller wanted to wait for, then the kernel will return from the + select() call without waiting. This might be useful information in order + to avoid doing expensive work. + + A new helper function poll_does_not_wait() is added that drivers can use + to detect this situation. This is now used in sock_poll_wait() in + include/net/sock.h. This was the only place in the kernel that needed + this information. + + Drivers should no longer access any of the poll_table internals, but use + the poll_requested_events() and poll_does_not_wait() access functions + instead. In order to enforce that the poll_table fields are now prepended + with an underscore and a comment was added warning against using them + directly. + + This required a change in unix_dgram_poll() in unix/af_unix.c which used + the key field to get the requested events. It's been replaced by a call + to poll_requested_events(). + + For qproc it was especially important to change its name since the + behavior of that field changes with this patch since this function pointer + can now be NULL when that wasn't possible in the past. + + Any driver accessing the qproc or key fields directly will now fail to compile. + + Some notes regarding the correctness of this patch: the driver's poll() + function is called with a 'struct poll_table_struct *wait' argument. This + pointer may or may not be NULL, drivers can never rely on it being one or + the other as that depends on whether or not an earlier file descriptor in + the select()'s fdset matched the requested events. + + There are only three things a driver can do with the wait argument: + + 1) obtain the key field: + + events = wait ? wait->key : ~0; + + This will still work although it should be replaced with the new + poll_requested_events() function (which does exactly the same). + This will now even work better, since wait is no longer set to NULL + unnecessarily. + + 2) use the qproc callback. This could be deadly since qproc can now be + NULL. Renaming qproc should prevent this from happening. There are no + kernel drivers that actually access this callback directly, BTW. + + 3) test whether wait == NULL to determine whether poll would return without + waiting. This is no longer sufficient as the correct test is now + wait == NULL || wait->_qproc == NULL. + + However, the worst that can happen here is a slight performance hit in + the case where wait != NULL and wait->_qproc == NULL. In that case the + driver will assume that poll_wait() will actually add the fd to the set + of waiting file descriptors. Of course, poll_wait() will not do that + since it tests for wait->_qproc. This will not break anything, though. + + There is only one place in the whole kernel where this happens + (sock_poll_wait() in include/net/sock.h) and that code will be replaced + by a call to poll_does_not_wait() in the next patch. + + Note that even if wait->_qproc != NULL drivers cannot rely on poll_wait() + actually waiting. The next file descriptor from the set might match the + event mask and thus any possible waits will never happen. + + Signed-off-by: Hans Verkuil + Reviewed-by: Jonathan Corbet + Reviewed-by: Al Viro + Cc: Davide Libenzi + Signed-off-by: Hans de Goede + Cc: Mauro Carvalho Chehab + Cc: David Miller + Cc: Eric Dumazet + Signed-off-by: Andrew Morton + Signed-off-by: Linus Torvalds + +diff --git a/fs/eventpoll.c b/fs/eventpoll.c +index 4d9d3a4..ca30007 100644 +--- a/fs/eventpoll.c ++++ b/fs/eventpoll.c +@@ -699,9 +699,12 @@ static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head, + void *priv) + { + struct epitem *epi, *tmp; ++ poll_table pt; + ++ init_poll_funcptr(&pt, NULL); + list_for_each_entry_safe(epi, tmp, head, rdllink) { +- if (epi->ffd.file->f_op->poll(epi->ffd.file, NULL) & ++ pt._key = epi->event.events; ++ if (epi->ffd.file->f_op->poll(epi->ffd.file, &pt) & + epi->event.events) + return POLLIN | POLLRDNORM; + else { +@@ -1097,6 +1100,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, + /* Initialize the poll table using the queue callback */ + epq.epi = epi; + init_poll_funcptr(&epq.pt, ep_ptable_queue_proc); ++ epq.pt._key = event->events; + + /* + * Attach the item to the poll hooks and get current event bits. +@@ -1191,6 +1195,9 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even + { + int pwake = 0; + unsigned int revents; ++ poll_table pt; ++ ++ init_poll_funcptr(&pt, NULL); + + /* + * Set the new event interest mask before calling f_op->poll(); +@@ -1198,13 +1205,14 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even + * f_op->poll() call and the new event set registering. + */ + epi->event.events = event->events; ++ pt._key = event->events; + epi->event.data = event->data; /* protected by mtx */ + + /* + * Get current event bits. We can safely use the file* here because + * its usage count has been increased by the caller of this function. + */ +- revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL); ++ revents = epi->ffd.file->f_op->poll(epi->ffd.file, &pt); + + /* + * If the item is "hot" and it is not registered inside the ready +@@ -1239,6 +1247,9 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head, + unsigned int revents; + struct epitem *epi; + struct epoll_event __user *uevent; ++ poll_table pt; ++ ++ init_poll_funcptr(&pt, NULL); + + /* + * We can loop without lock because we are passed a task private list. +@@ -1251,7 +1262,8 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head, + + list_del_init(&epi->rdllink); + +- revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL) & ++ pt._key = epi->event.events; ++ revents = epi->ffd.file->f_op->poll(epi->ffd.file, &pt) & + epi->event.events; + + /* +diff --git a/fs/select.c b/fs/select.c +index e782258..ecfd0b1 100644 +--- a/fs/select.c ++++ b/fs/select.c +@@ -223,7 +223,7 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, + get_file(filp); + entry->filp = filp; + entry->wait_address = wait_address; +- entry->key = p->key; ++ entry->key = p->_key; + init_waitqueue_func_entry(&entry->wait, pollwake); + entry->wait.private = pwq; + add_wait_queue(wait_address, &entry->wait); +@@ -386,13 +386,11 @@ get_max: + static inline void wait_key_set(poll_table *wait, unsigned long in, + unsigned long out, unsigned long bit) + { +- if (wait) { +- wait->key = POLLEX_SET; +- if (in & bit) +- wait->key |= POLLIN_SET; +- if (out & bit) +- wait->key |= POLLOUT_SET; +- } ++ wait->_key = POLLEX_SET; ++ if (in & bit) ++ wait->_key |= POLLIN_SET; ++ if (out & bit) ++ wait->_key |= POLLOUT_SET; + } + + int do_select(int n, fd_set_bits *fds, struct timespec *end_time) +@@ -414,7 +412,7 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time) + poll_initwait(&table); + wait = &table.pt; + if (end_time && !end_time->tv_sec && !end_time->tv_nsec) { +- wait = NULL; ++ wait->_qproc = NULL; + timed_out = 1; + } + +@@ -459,17 +457,17 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time) + if ((mask & POLLIN_SET) && (in & bit)) { + res_in |= bit; + retval++; +- wait = NULL; ++ wait->_qproc = NULL; + } + if ((mask & POLLOUT_SET) && (out & bit)) { + res_out |= bit; + retval++; +- wait = NULL; ++ wait->_qproc = NULL; + } + if ((mask & POLLEX_SET) && (ex & bit)) { + res_ex |= bit; + retval++; +- wait = NULL; ++ wait->_qproc = NULL; + } + } + } +@@ -481,7 +479,7 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time) + *rexp = res_ex; + cond_resched(); + } +- wait = NULL; ++ wait->_qproc = NULL; + if (retval || timed_out || signal_pending(current)) + break; + if (table.error) { +@@ -720,7 +718,7 @@ struct poll_list { + * interested in events matching the pollfd->events mask, and the result + * matching that mask is both recorded in pollfd->revents and returned. The + * pwait poll_table will be used by the fd-provided poll handler for waiting, +- * if non-NULL. ++ * if pwait->_qproc is non-NULL. + */ + static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait) + { +@@ -738,9 +736,7 @@ static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait) + if (file != NULL) { + mask = DEFAULT_POLLMASK; + if (file->f_op && file->f_op->poll) { +- if (pwait) +- pwait->key = pollfd->events | +- POLLERR | POLLHUP; ++ pwait->_key = pollfd->events|POLLERR|POLLHUP; + mask = file->f_op->poll(file, pwait); + } + /* Mask out unneeded events. */ +@@ -763,7 +759,7 @@ static int do_poll(unsigned int nfds, struct poll_list *list, + + /* Optimise the no-wait case */ + if (end_time && !end_time->tv_sec && !end_time->tv_nsec) { +- pt = NULL; ++ pt->_qproc = NULL; + timed_out = 1; + } + +@@ -781,22 +777,22 @@ static int do_poll(unsigned int nfds, struct poll_list *list, + for (; pfd != pfd_end; pfd++) { + /* + * Fish for events. If we found one, record it +- * and kill the poll_table, so we don't ++ * and kill poll_table->_qproc, so we don't + * needlessly register any other waiters after + * this. They'll get immediately deregistered + * when we break out and return. + */ + if (do_pollfd(pfd, pt)) { + count++; +- pt = NULL; ++ pt->_qproc = NULL; + } + } + } + /* + * All waiters have already been registered, so don't provide +- * a poll_table to them on the next loop iteration. ++ * a poll_table->_qproc to them on the next loop iteration. + */ +- pt = NULL; ++ pt->_qproc = NULL; + if (!count) { + count = wait->error; + if (signal_pending(current)) +diff --git a/include/linux/poll.h b/include/linux/poll.h +index cf40010..48fe8bc 100644 +--- a/include/linux/poll.h ++++ b/include/linux/poll.h +@@ -32,21 +32,46 @@ struct poll_table_struct; + */ + typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *); + ++/* ++ * Do not touch the structure directly, use the access functions ++ * poll_does_not_wait() and poll_requested_events() instead. ++ */ + typedef struct poll_table_struct { +- poll_queue_proc qproc; +- unsigned long key; ++ poll_queue_proc _qproc; ++ unsigned long _key; + } poll_table; + + static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p) + { +- if (p && wait_address) +- p->qproc(filp, wait_address, p); ++ if (p && p->_qproc && wait_address) ++ p->_qproc(filp, wait_address, p); ++} ++ ++/* ++ * Return true if it is guaranteed that poll will not wait. This is the case ++ * if the poll() of another file descriptor in the set got an event, so there ++ * is no need for waiting. ++ */ ++static inline bool poll_does_not_wait(const poll_table *p) ++{ ++ return p == NULL || p->_qproc == NULL; ++} ++ ++/* ++ * Return the set of events that the application wants to poll for. ++ * This is useful for drivers that need to know whether a DMA transfer has ++ * to be started implicitly on poll(). You typically only want to do that ++ * if the application is actually polling for POLLIN and/or POLLOUT. ++ */ ++static inline unsigned long poll_requested_events(const poll_table *p) ++{ ++ return p ? p->_key : ~0UL; + } + + static inline void init_poll_funcptr(poll_table *pt, poll_queue_proc qproc) + { +- pt->qproc = qproc; +- pt->key = ~0UL; /* all events enabled */ ++ pt->_qproc = qproc; ++ pt->_key = ~0UL; /* all events enabled */ + } + + struct poll_table_entry { +diff --git a/include/net/sock.h b/include/net/sock.h +index 04bc0b3..a6ba1f8 100644 +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -1854,7 +1854,7 @@ static inline bool wq_has_sleeper(struct socket_wq *wq) + static inline void sock_poll_wait(struct file *filp, + wait_queue_head_t *wait_address, poll_table *p) + { +- if (p && wait_address) { ++ if (!poll_does_not_wait(p) && wait_address) { + poll_wait(filp, wait_address, p); + /* + * We need to be sure we are in sync with the +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index eb4277c..d510353 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -2206,7 +2206,7 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock, + } + + /* No write status requested, avoid expensive OUT tests. */ +- if (wait && !(wait->key & (POLLWRBAND | POLLWRNORM | POLLOUT))) ++ if (!(poll_requested_events(wait) & (POLLWRBAND|POLLWRNORM|POLLOUT))) + return mask; + + writable = unix_writable(sk); diff --git a/apple_backlight.patch b/apple_backlight.patch deleted file mode 100644 index c7d5a8191..000000000 --- a/apple_backlight.patch +++ /dev/null @@ -1,688 +0,0 @@ -Various fixes to the Apple backlight driver. Upstream in .38? - -diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig -index e54a337..fb5df46 100644 ---- a/drivers/video/backlight/Kconfig -+++ b/drivers/video/backlight/Kconfig -@@ -236,12 +236,12 @@ config BACKLIGHT_MAX8925 - If you have a LCD backlight connected to the WLED output of MAX8925 - WLED output, say Y here to enable this driver. - --config BACKLIGHT_MBP_NVIDIA -- tristate "MacBook Pro Nvidia Backlight Driver" -+config BACKLIGHT_APPLE -+ tristate "Apple Backlight Driver" - depends on X86 - help -- If you have an Apple Macbook Pro with Nvidia graphics hardware say Y -- to enable a driver for its backlight -+ If you have an Intel-based Apple say Y to enable a driver for its -+ backlight - - config BACKLIGHT_TOSA - tristate "Sharp SL-6000 Backlight Driver" -diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile -index 44c0f81..ebaecc0 100644 ---- a/drivers/video/backlight/Makefile -+++ b/drivers/video/backlight/Makefile -@@ -26,7 +26,7 @@ obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o - obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o - obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o - obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o --obj-$(CONFIG_BACKLIGHT_MBP_NVIDIA) += mbp_nvidia_bl.o -+obj-$(CONFIG_BACKLIGHT_APPLE) += apple_bl.o - obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o - obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o - obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o -diff --git a/drivers/video/backlight/apple_bl.c b/drivers/video/backlight/apple_bl.c -new file mode 100644 -index 0000000..8f808c7 ---- /dev/null -+++ b/drivers/video/backlight/apple_bl.c -@@ -0,0 +1,240 @@ -+/* -+ * Backlight Driver for Intel-based Apples -+ * -+ * Copyright (c) Red Hat -+ * Based on code from Pommed: -+ * Copyright (C) 2006 Nicolas Boichat -+ * Copyright (C) 2006 Felipe Alfaro Solana -+ * Copyright (C) 2007 Julien BLACHE -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * This driver triggers SMIs which cause the firmware to change the -+ * backlight brightness. This is icky in many ways, but it's impractical to -+ * get at the firmware code in order to figure out what it's actually doing. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static struct backlight_device *apple_backlight_device; -+ -+struct hw_data { -+ /* I/O resource to allocate. */ -+ unsigned long iostart; -+ unsigned long iolen; -+ /* Backlight operations structure. */ -+ const struct backlight_ops backlight_ops; -+ void (*set_brightness)(int); -+}; -+ -+static const struct hw_data *hw_data; -+ -+#define DRIVER "apple_backlight: " -+ -+/* Module parameters. */ -+static int debug; -+module_param_named(debug, debug, int, 0644); -+MODULE_PARM_DESC(debug, "Set to one to enable debugging messages."); -+ -+/* -+ * Implementation for machines with Intel chipset. -+ */ -+static void intel_chipset_set_brightness(int intensity) -+{ -+ outb(0x04 | (intensity << 4), 0xb3); -+ outb(0xbf, 0xb2); -+} -+ -+static int intel_chipset_send_intensity(struct backlight_device *bd) -+{ -+ int intensity = bd->props.brightness; -+ -+ if (debug) -+ printk(KERN_DEBUG DRIVER "setting brightness to %d\n", -+ intensity); -+ -+ intel_chipset_set_brightness(intensity); -+ return 0; -+} -+ -+static int intel_chipset_get_intensity(struct backlight_device *bd) -+{ -+ int intensity; -+ -+ outb(0x03, 0xb3); -+ outb(0xbf, 0xb2); -+ intensity = inb(0xb3) >> 4; -+ -+ if (debug) -+ printk(KERN_DEBUG DRIVER "read brightness of %d\n", -+ intensity); -+ -+ return intensity; -+} -+ -+static const struct hw_data intel_chipset_data = { -+ .iostart = 0xb2, -+ .iolen = 2, -+ .backlight_ops = { -+ .options = BL_CORE_SUSPENDRESUME, -+ .get_brightness = intel_chipset_get_intensity, -+ .update_status = intel_chipset_send_intensity, -+ }, -+ .set_brightness = intel_chipset_set_brightness, -+}; -+ -+/* -+ * Implementation for machines with Nvidia chipset. -+ */ -+static void nvidia_chipset_set_brightness(int intensity) -+{ -+ outb(0x04 | (intensity << 4), 0x52f); -+ outb(0xbf, 0x52e); -+} -+ -+static int nvidia_chipset_send_intensity(struct backlight_device *bd) -+{ -+ int intensity = bd->props.brightness; -+ -+ if (debug) -+ printk(KERN_DEBUG DRIVER "setting brightness to %d\n", -+ intensity); -+ -+ nvidia_chipset_set_brightness(intensity); -+ return 0; -+} -+ -+static int nvidia_chipset_get_intensity(struct backlight_device *bd) -+{ -+ int intensity; -+ -+ outb(0x03, 0x52f); -+ outb(0xbf, 0x52e); -+ intensity = inb(0x52f) >> 4; -+ -+ if (debug) -+ printk(KERN_DEBUG DRIVER "read brightness of %d\n", -+ intensity); -+ -+ return intensity; -+} -+ -+static const struct hw_data nvidia_chipset_data = { -+ .iostart = 0x52e, -+ .iolen = 2, -+ .backlight_ops = { -+ .options = BL_CORE_SUSPENDRESUME, -+ .get_brightness = nvidia_chipset_get_intensity, -+ .update_status = nvidia_chipset_send_intensity -+ }, -+ .set_brightness = nvidia_chipset_set_brightness, -+}; -+ -+static int __devinit apple_bl_add(struct acpi_device *dev) -+{ -+ struct backlight_properties props; -+ struct pci_dev *host; -+ int intensity; -+ -+ host = pci_get_bus_and_slot(0, 0); -+ -+ if (!host) { -+ printk(KERN_ERR DRIVER "unable to find PCI host\n"); -+ return -ENODEV; -+ } -+ -+ if (host->vendor == PCI_VENDOR_ID_INTEL) -+ hw_data = &intel_chipset_data; -+ else if (host->vendor == PCI_VENDOR_ID_NVIDIA) -+ hw_data = &nvidia_chipset_data; -+ -+ pci_dev_put(host); -+ -+ if (!hw_data) { -+ printk(KERN_ERR DRIVER "unknown hardware\n"); -+ return -ENODEV; -+ } -+ -+ /* Check that the hardware responds - this may not work under EFI */ -+ -+ intensity = hw_data->backlight_ops.get_brightness(NULL); -+ -+ if (!intensity) { -+ hw_data->set_brightness(1); -+ if (!hw_data->backlight_ops.get_brightness(NULL)) -+ return -ENODEV; -+ -+ hw_data->set_brightness(0); -+ } -+ -+ if (!request_region(hw_data->iostart, hw_data->iolen, -+ "Apple backlight")) -+ return -ENXIO; -+ -+ memset(&props, 0, sizeof(struct backlight_properties)); -+ props.max_brightness = 15; -+ apple_backlight_device = backlight_device_register("apple_backlight", -+ NULL, NULL, &hw_data->backlight_ops, &props); -+ -+ if (IS_ERR(apple_backlight_device)) { -+ release_region(hw_data->iostart, hw_data->iolen); -+ return PTR_ERR(apple_backlight_device); -+ } -+ -+ apple_backlight_device->props.brightness = -+ hw_data->backlight_ops.get_brightness(apple_backlight_device); -+ backlight_update_status(apple_backlight_device); -+ -+ return 0; -+} -+ -+static int __devexit apple_bl_remove(struct acpi_device *dev, int type) -+{ -+ backlight_device_unregister(apple_backlight_device); -+ -+ release_region(hw_data->iostart, hw_data->iolen); -+ hw_data = NULL; -+ return 0; -+} -+ -+static const struct acpi_device_id apple_bl_ids[] = { -+ {"APP0002", 0}, -+ {"", 0}, -+}; -+ -+static struct acpi_driver apple_bl_driver = { -+ .name = "Apple backlight", -+ .ids = apple_bl_ids, -+ .ops = { -+ .add = apple_bl_add, -+ .remove = apple_bl_remove, -+ }, -+}; -+ -+static int __init apple_bl_init(void) -+{ -+ return acpi_bus_register_driver(&apple_bl_driver); -+} -+ -+static void __exit apple_bl_exit(void) -+{ -+ acpi_bus_unregister_driver(&apple_bl_driver); -+} -+ -+module_init(apple_bl_init); -+module_exit(apple_bl_exit); -+ -+MODULE_AUTHOR("Matthew Garrett "); -+MODULE_DESCRIPTION("Apple Backlight Driver"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(acpi, apple_bl_ids); -+MODULE_ALIAS("mbp_nvidia_bl"); -diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c -deleted file mode 100644 -index 1485f73..0000000 ---- a/drivers/video/backlight/mbp_nvidia_bl.c -+++ /dev/null -@@ -1,400 +0,0 @@ --/* -- * Backlight Driver for Nvidia 8600 in Macbook Pro -- * -- * Copyright (c) Red Hat -- * Based on code from Pommed: -- * Copyright (C) 2006 Nicolas Boichat -- * Copyright (C) 2006 Felipe Alfaro Solana -- * Copyright (C) 2007 Julien BLACHE -- * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License version 2 as -- * published by the Free Software Foundation. -- * -- * This driver triggers SMIs which cause the firmware to change the -- * backlight brightness. This is icky in many ways, but it's impractical to -- * get at the firmware code in order to figure out what it's actually doing. -- */ -- --#include --#include --#include --#include --#include --#include --#include --#include -- --static struct backlight_device *mbp_backlight_device; -- --/* Structure to be passed to the DMI_MATCH function. */ --struct dmi_match_data { -- /* I/O resource to allocate. */ -- unsigned long iostart; -- unsigned long iolen; -- /* Backlight operations structure. */ -- const struct backlight_ops backlight_ops; --}; -- --/* Module parameters. */ --static int debug; --module_param_named(debug, debug, int, 0644); --MODULE_PARM_DESC(debug, "Set to one to enable debugging messages."); -- --/* -- * Implementation for MacBooks with Intel chipset. -- */ --static int intel_chipset_send_intensity(struct backlight_device *bd) --{ -- int intensity = bd->props.brightness; -- -- if (debug) -- printk(KERN_DEBUG "mbp_nvidia_bl: setting brightness to %d\n", -- intensity); -- -- outb(0x04 | (intensity << 4), 0xb3); -- outb(0xbf, 0xb2); -- return 0; --} -- --static int intel_chipset_get_intensity(struct backlight_device *bd) --{ -- int intensity; -- -- outb(0x03, 0xb3); -- outb(0xbf, 0xb2); -- intensity = inb(0xb3) >> 4; -- -- if (debug) -- printk(KERN_DEBUG "mbp_nvidia_bl: read brightness of %d\n", -- intensity); -- -- return intensity; --} -- --static const struct dmi_match_data intel_chipset_data = { -- .iostart = 0xb2, -- .iolen = 2, -- .backlight_ops = { -- .options = BL_CORE_SUSPENDRESUME, -- .get_brightness = intel_chipset_get_intensity, -- .update_status = intel_chipset_send_intensity, -- } --}; -- --/* -- * Implementation for MacBooks with Nvidia chipset. -- */ --static int nvidia_chipset_send_intensity(struct backlight_device *bd) --{ -- int intensity = bd->props.brightness; -- -- if (debug) -- printk(KERN_DEBUG "mbp_nvidia_bl: setting brightness to %d\n", -- intensity); -- -- outb(0x04 | (intensity << 4), 0x52f); -- outb(0xbf, 0x52e); -- return 0; --} -- --static int nvidia_chipset_get_intensity(struct backlight_device *bd) --{ -- int intensity; -- -- outb(0x03, 0x52f); -- outb(0xbf, 0x52e); -- intensity = inb(0x52f) >> 4; -- -- if (debug) -- printk(KERN_DEBUG "mbp_nvidia_bl: read brightness of %d\n", -- intensity); -- -- return intensity; --} -- --static const struct dmi_match_data nvidia_chipset_data = { -- .iostart = 0x52e, -- .iolen = 2, -- .backlight_ops = { -- .options = BL_CORE_SUSPENDRESUME, -- .get_brightness = nvidia_chipset_get_intensity, -- .update_status = nvidia_chipset_send_intensity -- } --}; -- --/* -- * DMI matching. -- */ --static /* const */ struct dmi_match_data *driver_data; -- --static int mbp_dmi_match(const struct dmi_system_id *id) --{ -- driver_data = id->driver_data; -- -- printk(KERN_INFO "mbp_nvidia_bl: %s detected\n", id->ident); -- return 1; --} -- --static const struct dmi_system_id __initdata mbp_device_table[] = { -- { -- .callback = mbp_dmi_match, -- .ident = "MacBook 1,1", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"), -- }, -- .driver_data = (void *)&intel_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBook 2,1", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"), -- }, -- .driver_data = (void *)&intel_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBook 3,1", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBook3,1"), -- }, -- .driver_data = (void *)&intel_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBook 4,1", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4,1"), -- }, -- .driver_data = (void *)&intel_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBook 4,2", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4,2"), -- }, -- .driver_data = (void *)&intel_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBookPro 1,1", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"), -- }, -- .driver_data = (void *)&intel_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBookPro 1,2", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,2"), -- }, -- .driver_data = (void *)&intel_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBookPro 2,1", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,1"), -- }, -- .driver_data = (void *)&intel_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBookPro 2,2", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"), -- }, -- .driver_data = (void *)&intel_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBookPro 3,1", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"), -- }, -- .driver_data = (void *)&intel_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBookPro 3,2", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,2"), -- }, -- .driver_data = (void *)&intel_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBookPro 4,1", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4,1"), -- }, -- .driver_data = (void *)&intel_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBookAir 1,1", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir1,1"), -- }, -- .driver_data = (void *)&intel_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBook 5,1", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5,1"), -- }, -- .driver_data = (void *)&nvidia_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBook 5,2", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5,2"), -- }, -- .driver_data = (void *)&nvidia_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBook 6,1", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBook6,1"), -- }, -- .driver_data = (void *)&nvidia_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBookAir 2,1", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2,1"), -- }, -- .driver_data = (void *)&nvidia_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBookPro 5,1", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,1"), -- }, -- .driver_data = (void *)&nvidia_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBookPro 5,2", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,2"), -- }, -- .driver_data = (void *)&nvidia_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBookPro 5,3", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,3"), -- }, -- .driver_data = (void *)&nvidia_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBookPro 5,4", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,4"), -- }, -- .driver_data = (void *)&nvidia_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBookPro 5,5", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,5"), -- }, -- .driver_data = (void *)&nvidia_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBookAir 3,1", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,1"), -- }, -- .driver_data = (void *)&nvidia_chipset_data, -- }, -- { -- .callback = mbp_dmi_match, -- .ident = "MacBookAir 3,2", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,2"), -- }, -- .driver_data = (void *)&nvidia_chipset_data, -- }, -- { } --}; -- --static int __init mbp_init(void) --{ -- struct backlight_properties props; -- if (!dmi_check_system(mbp_device_table)) -- return -ENODEV; -- -- if (!request_region(driver_data->iostart, driver_data->iolen, -- "Macbook Pro backlight")) -- return -ENXIO; -- -- memset(&props, 0, sizeof(struct backlight_properties)); -- props.max_brightness = 15; -- mbp_backlight_device = backlight_device_register("mbp_backlight", NULL, -- NULL, -- &driver_data->backlight_ops, -- &props); -- if (IS_ERR(mbp_backlight_device)) { -- release_region(driver_data->iostart, driver_data->iolen); -- return PTR_ERR(mbp_backlight_device); -- } -- -- mbp_backlight_device->props.brightness = -- driver_data->backlight_ops.get_brightness(mbp_backlight_device); -- backlight_update_status(mbp_backlight_device); -- -- return 0; --} -- --static void __exit mbp_exit(void) --{ -- backlight_device_unregister(mbp_backlight_device); -- -- release_region(driver_data->iostart, driver_data->iolen); --} -- --module_init(mbp_init); --module_exit(mbp_exit); -- --MODULE_AUTHOR("Matthew Garrett "); --MODULE_DESCRIPTION("Nvidia-based Macbook Pro Backlight Driver"); --MODULE_LICENSE("GPL"); --MODULE_DEVICE_TABLE(dmi, mbp_device_table); diff --git a/arm-omap-dt-compat.patch b/arm-omap-dt-compat.patch new file mode 100644 index 000000000..4046e938f --- /dev/null +++ b/arm-omap-dt-compat.patch @@ -0,0 +1,42 @@ +diff -up linux-2.6.39.armv7l/arch/arm/mach-omap2/board-omap3beagle.c.fdt linux-2.6.39.armv7l/arch/arm/mach-omap2/board-omap3beagle.c +--- linux-2.6.39.armv7l/arch/arm/mach-omap2/board-omap3beagle.c.fdt 2011-08-04 16:51:12.034188064 -0500 ++++ linux-2.6.39.armv7l/arch/arm/mach-omap2/board-omap3beagle.c 2011-08-04 22:13:52.801156923 -0500 +@@ -591,6 +591,11 @@ static void __init omap3_beagle_init(voi + beagle_opp_init(); + } + ++static const char *omap3_beagle_dt_match[] __initdata = { ++ "ti,omap3-beagle", ++ NULL ++}; ++ + MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board") + /* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */ + .boot_params = 0x80000100, +@@ -600,4 +605,5 @@ MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagl + .init_irq = omap3_beagle_init_irq, + .init_machine = omap3_beagle_init, + .timer = &omap3_secure_timer, ++ .dt_compat = omap3_beagle_dt_match, + MACHINE_END +diff -up linux-2.6.39.armv7l/arch/arm/mach-omap2/board-omap4panda.c.fdt linux-2.6.39.armv7l/arch/arm/mach-omap2/board-omap4panda.c +--- linux-2.6.39.armv7l/arch/arm/mach-omap2/board-omap4panda.c.fdt 2011-08-04 16:51:12.092169023 -0500 ++++ linux-2.6.39.armv7l/arch/arm/mach-omap2/board-omap4panda.c 2011-08-04 22:15:29.200157437 -0500 +@@ -708,6 +708,11 @@ static void __init omap4_panda_map_io(vo + omap44xx_map_common_io(); + } + ++static const char *omap4_panda_match[] __initdata = { ++ "ti,omap4-panda", ++ NULL, ++}; ++ + MACHINE_START(OMAP4_PANDA, "OMAP4 Panda board") + /* Maintainer: David Anders - Texas Instruments Inc */ + .boot_params = 0x80000100, +@@ -717,4 +722,5 @@ MACHINE_START(OMAP4_PANDA, "OMAP4 Panda + .init_irq = gic_init_irq, + .init_machine = omap4_panda_init, + .timer = &omap4_timer, ++ .dt_compat = omap4_panda_match, + MACHINE_END diff --git a/arm-readl.patch b/arm-readl.patch new file mode 100644 index 000000000..5179396f6 --- /dev/null +++ b/arm-readl.patch @@ -0,0 +1,49 @@ +--- kernel/arch/arm/include/asm/io.h.orig 2011-07-26 00:44:15.000000000 -0400 ++++ kernel/arch/arm/include/asm/io.h 2011-07-26 00:40:41.000000000 -0400 +@@ -55,6 +55,46 @@ + #define __raw_readw(a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a)) + #define __raw_readl(a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a)) + ++#undef __raw_writew ++#define __raw_writew(v,a) __dj_writew(v,a) ++static inline void ++__dj_writew(unsigned short v, unsigned short *a) ++{ ++ __chk_io_ptr(a); ++ asm volatile ("strh %0,[%1,#0]" :: "r" (v), "r" (a)); ++} ++ ++#undef __raw_writel ++#define __raw_writel(v,a) __dj_writel(v,a) ++static inline void ++__dj_writel(unsigned int v, unsigned int *a) ++{ ++ __chk_io_ptr(a); ++ asm volatile ("str %0,[%1,#0]" :: "r" (v), "r" (a)); ++} ++ ++#undef __raw_readw ++#define __raw_readw(a) __dj_readw(a) ++static inline unsigned short ++__dj_readw(unsigned short *a) ++{ ++ unsigned short rv; ++ __chk_io_ptr(a); ++ asm volatile ("ldrh %0,[%1,#0]" : "=r" (rv) : "r" (a)); ++ return rv; ++} ++ ++#undef __raw_readl ++#define __raw_readl(a) __dj_readl(a) ++static inline unsigned int ++__dj_readl(unsigned int *a) ++{ ++ unsigned long rv; ++ __chk_io_ptr(a); ++ asm volatile ("ldr %0,[%1,#0]" : "=r" (rv) : "r" (a)); ++ return rv; ++} ++ + /* + * Architecture ioremap implementation. + */ diff --git a/arm-smsc-support-reading-mac-address-from-device-tree.patch b/arm-smsc-support-reading-mac-address-from-device-tree.patch new file mode 100644 index 000000000..a36c68369 --- /dev/null +++ b/arm-smsc-support-reading-mac-address-from-device-tree.patch @@ -0,0 +1,92 @@ +From 0b608345e114681f66ca0a3cf9d9434728da62ce Mon Sep 17 00:00:00 2001 +From: Ken Cox +Date: Thu, 23 Jun 2011 10:36:43 -0500 +Subject: [PATCH] Support reading mac address from device tree. + +If CONFIG_OF is enabled, we will try to read the mac address from the device tree. This enables us the ability to have a "static" mac address on arm boards such as the pandaboard and beagleboard which generate random mac addresses. +--- + drivers/net/usb/smsc75xx.c | 17 +++++++++++++++++ + drivers/net/usb/smsc95xx.c | 18 +++++++++++++++++- + 2 files changed, 34 insertions(+), 1 deletions(-) + +diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c +index 753ee6e..ac0a200 100644 +--- a/drivers/net/usb/smsc75xx.c ++++ b/drivers/net/usb/smsc75xx.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include "smsc75xx.h" + + #define SMSC_CHIPNAME "smsc75xx" +@@ -658,6 +659,22 @@ static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) + + static void smsc75xx_init_mac_address(struct usbnet *dev) + { ++ void *address; ++#ifdef CONFIG_OF ++ struct device_node *np; ++ ++ /* try the device tree */ ++ np = of_find_node_by_name(NULL, "smsc75xx"); ++ if (np) { ++ address = of_get_property(np, "local-mac-address", NULL); ++ if (address) { ++ memcpy(dev->net->dev_addr, address, ETH_ALEN); ++ netif_dbg(dev, ifup, dev->net, "MAC address read from device tree\n"); ++ return; ++ } ++ } ++#endif ++ + /* try reading mac address from EEPROM */ + if (smsc75xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, + dev->net->dev_addr) == 0) { +diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c +index bc86f4b..c83942d 100644 +--- a/drivers/net/usb/smsc95xx.c ++++ b/drivers/net/usb/smsc95xx.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include "smsc95xx.h" + + #define SMSC_CHIPNAME "smsc95xx" +@@ -639,6 +640,22 @@ static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) + + static void smsc95xx_init_mac_address(struct usbnet *dev) + { ++ void *address; ++#ifdef CONFIG_OF ++ struct device_node *np; ++ ++ /* try the device tree */ ++ np = of_find_node_by_name(NULL, "smsc95xx"); ++ if (np) { ++ address = of_get_property(np, "local-mac-address", NULL); ++ if (address) { ++ memcpy(dev->net->dev_addr, address, ETH_ALEN); ++ netif_dbg(dev, ifup, dev->net, "MAC address read from device tree\n"); ++ return; ++ } ++ } ++#endif ++ + /* try reading mac address from EEPROM */ + if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, + dev->net->dev_addr) == 0) { +@@ -648,7 +665,6 @@ static void smsc95xx_init_mac_address(struct usbnet *dev) + return; + } + } +- + /* no eeprom, or eeprom values are invalid. generate random MAC */ + random_ether_addr(dev->net->dev_addr); + netif_dbg(dev, ifup, dev->net, "MAC address set to random_ether_addr\n"); +-- +1.7.2.3 + diff --git a/arm-tegra-nvec-kconfig.patch b/arm-tegra-nvec-kconfig.patch new file mode 100644 index 000000000..a3f568cd5 --- /dev/null +++ b/arm-tegra-nvec-kconfig.patch @@ -0,0 +1,10 @@ +--- linux-2.6.42.noarch/drivers/staging/nvec/Kconfig.orig 2012-02-02 08:16:12.512727480 -0600 ++++ linux-2.6.42.noarch/drivers/staging/nvec/Kconfig 2012-02-01 18:44:56.674990109 -0600 +@@ -1,6 +1,6 @@ + config MFD_NVEC + bool "NV Tegra Embedded Controller SMBus Interface" +- depends on I2C && GPIOLIB && ARCH_TEGRA ++ depends on I2C && GPIOLIB && ARCH_TEGRA && MFD_CORE=y + help + Say Y here to enable support for a nVidia compliant embedded + controller. diff --git a/atl1c_net_next_update-3.3.patch b/atl1c_net_next_update-3.3.patch new file mode 100644 index 000000000..6c53ed607 --- /dev/null +++ b/atl1c_net_next_update-3.3.patch @@ -0,0 +1,3633 @@ +diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c.h b/drivers/net/ethernet/atheros/atl1c/atl1c.h +index ca70e16..b2bf324 100644 +--- a/drivers/net/ethernet/atheros/atl1c/atl1c.h ++++ b/drivers/net/ethernet/atheros/atl1c/atl1c.h +@@ -74,8 +74,6 @@ + + #define AT_RX_BUF_SIZE (ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN) + #define MAX_JUMBO_FRAME_SIZE (6*1024) +-#define MAX_TSO_FRAME_SIZE (7*1024) +-#define MAX_TX_OFFLOAD_THRESH (9*1024) + + #define AT_MAX_RECEIVE_QUEUE 4 + #define AT_DEF_RECEIVE_QUEUE 1 +@@ -100,7 +98,7 @@ + #define ATL1C_ASPM_L0s_ENABLE 0x0001 + #define ATL1C_ASPM_L1_ENABLE 0x0002 + +-#define AT_REGS_LEN (75 * sizeof(u32)) ++#define AT_REGS_LEN (74 * sizeof(u32)) + #define AT_EEPROM_LEN 512 + + #define ATL1C_GET_DESC(R, i, type) (&(((type *)((R)->desc))[i])) +@@ -297,20 +295,6 @@ enum atl1c_dma_req_block { + atl1c_dma_req_4096 = 5 + }; + +-enum atl1c_rss_mode { +- atl1c_rss_mode_disable = 0, +- atl1c_rss_sig_que = 1, +- atl1c_rss_mul_que_sig_int = 2, +- atl1c_rss_mul_que_mul_int = 4, +-}; +- +-enum atl1c_rss_type { +- atl1c_rss_disable = 0, +- atl1c_rss_ipv4 = 1, +- atl1c_rss_ipv4_tcp = 2, +- atl1c_rss_ipv6 = 4, +- atl1c_rss_ipv6_tcp = 8 +-}; + + enum atl1c_nic_type { + athr_l1c = 0, +@@ -388,7 +372,6 @@ struct atl1c_hw { + enum atl1c_dma_order dma_order; + enum atl1c_dma_rcb rcb_value; + enum atl1c_dma_req_block dmar_block; +- enum atl1c_dma_req_block dmaw_block; + + u16 device_id; + u16 vendor_id; +@@ -399,8 +382,6 @@ struct atl1c_hw { + u16 phy_id2; + + u32 intr_mask; +- u8 dmaw_dly_cnt; +- u8 dmar_dly_cnt; + + u8 preamble_len; + u16 max_frame_size; +@@ -440,10 +421,6 @@ struct atl1c_hw { + #define ATL1C_FPGA_VERSION 0x8000 + u16 link_cap_flags; + #define ATL1C_LINK_CAP_1000M 0x0001 +- u16 cmb_tpd; +- u16 cmb_rrd; +- u16 cmb_rx_timer; /* 2us resolution */ +- u16 cmb_tx_timer; + u32 smb_timer; + + u16 rrd_thresh; /* Threshold of number of RRD produced to trigger +@@ -451,9 +428,6 @@ struct atl1c_hw { + u16 tpd_thresh; + u8 tpd_burst; /* Number of TPD to prefetch in cache-aligned burst. */ + u8 rfd_burst; +- enum atl1c_rss_type rss_type; +- enum atl1c_rss_mode rss_mode; +- u8 rss_hash_bits; + u32 base_cpu; + u32 indirect_tab; + u8 mac_addr[ETH_ALEN]; +@@ -462,12 +436,12 @@ struct atl1c_hw { + bool phy_configured; + bool re_autoneg; + bool emi_ca; ++ bool msi_lnkpatch; /* link patch for specific platforms */ + }; + + /* + * atl1c_ring_header represents a single, contiguous block of DMA space +- * mapped for the three descriptor rings (tpd, rfd, rrd) and the two +- * message blocks (cmb, smb) described below ++ * mapped for the three descriptor rings (tpd, rfd, rrd) described below + */ + struct atl1c_ring_header { + void *desc; /* virtual address */ +@@ -541,16 +515,6 @@ struct atl1c_rrd_ring { + u16 next_to_clean; + }; + +-struct atl1c_cmb { +- void *cmb; +- dma_addr_t dma; +-}; +- +-struct atl1c_smb { +- void *smb; +- dma_addr_t dma; +-}; +- + /* board specific private data structure */ + struct atl1c_adapter { + struct net_device *netdev; +@@ -586,11 +550,8 @@ struct atl1c_adapter { + /* All Descriptor memory */ + struct atl1c_ring_header ring_header; + struct atl1c_tpd_ring tpd_ring[AT_MAX_TRANSMIT_QUEUE]; +- struct atl1c_rfd_ring rfd_ring[AT_MAX_RECEIVE_QUEUE]; +- struct atl1c_rrd_ring rrd_ring[AT_MAX_RECEIVE_QUEUE]; +- struct atl1c_cmb cmb; +- struct atl1c_smb smb; +- int num_rx_queues; ++ struct atl1c_rfd_ring rfd_ring; ++ struct atl1c_rrd_ring rrd_ring; + u32 bd_number; /* board number;*/ + }; + +@@ -618,8 +579,14 @@ struct atl1c_adapter { + #define AT_WRITE_REGW(a, reg, value) (\ + writew((value), ((a)->hw_addr + reg))) + +-#define AT_READ_REGW(a, reg) (\ +- readw((a)->hw_addr + reg)) ++#define AT_READ_REGW(a, reg, pdata) do { \ ++ if (unlikely((a)->hibernate)) { \ ++ readw((a)->hw_addr + reg); \ ++ *(u16 *)pdata = readw((a)->hw_addr + reg); \ ++ } else { \ ++ *(u16 *)pdata = readw((a)->hw_addr + reg); \ ++ } \ ++ } while (0) + + #define AT_WRITE_REG_ARRAY(a, reg, offset, value) ( \ + writel((value), (((a)->hw_addr + reg) + ((offset) << 2)))) +diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c b/drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c +index 0a9326a..859ea84 100644 +--- a/drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c ++++ b/drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c +@@ -141,8 +141,7 @@ static void atl1c_get_regs(struct net_device *netdev, + + memset(p, 0, AT_REGS_LEN); + +- regs->version = 0; +- AT_READ_REG(hw, REG_VPD_CAP, p++); ++ regs->version = 1; + AT_READ_REG(hw, REG_PM_CTRL, p++); + AT_READ_REG(hw, REG_MAC_HALF_DUPLX_CTRL, p++); + AT_READ_REG(hw, REG_TWSI_CTRL, p++); +@@ -154,7 +153,7 @@ static void atl1c_get_regs(struct net_device *netdev, + AT_READ_REG(hw, REG_LINK_CTRL, p++); + AT_READ_REG(hw, REG_IDLE_STATUS, p++); + AT_READ_REG(hw, REG_MDIO_CTRL, p++); +- AT_READ_REG(hw, REG_SERDES_LOCK, p++); ++ AT_READ_REG(hw, REG_SERDES, p++); + AT_READ_REG(hw, REG_MAC_CTRL, p++); + AT_READ_REG(hw, REG_MAC_IPG_IFG, p++); + AT_READ_REG(hw, REG_MAC_STA_ADDR, p++); +@@ -167,9 +166,9 @@ static void atl1c_get_regs(struct net_device *netdev, + AT_READ_REG(hw, REG_WOL_CTRL, p++); + + atl1c_read_phy_reg(hw, MII_BMCR, &phy_data); +- regs_buff[73] = (u32) phy_data; ++ regs_buff[AT_REGS_LEN/sizeof(u32) - 2] = (u32) phy_data; + atl1c_read_phy_reg(hw, MII_BMSR, &phy_data); +- regs_buff[74] = (u32) phy_data; ++ regs_buff[AT_REGS_LEN/sizeof(u32) - 1] = (u32) phy_data; + } + + static int atl1c_get_eeprom_len(struct net_device *netdev) +diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c +index 23f2ab0..2ea6a21 100644 +--- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c ++++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c +@@ -43,7 +43,7 @@ int atl1c_check_eeprom_exist(struct atl1c_hw *hw) + return 0; + } + +-void atl1c_hw_set_mac_addr(struct atl1c_hw *hw) ++void atl1c_hw_set_mac_addr(struct atl1c_hw *hw, u8 *mac_addr) + { + u32 value; + /* +@@ -51,35 +51,48 @@ void atl1c_hw_set_mac_addr(struct atl1c_hw *hw) + * 0: 6AF600DC 1: 000B + * low dword + */ +- value = (((u32)hw->mac_addr[2]) << 24) | +- (((u32)hw->mac_addr[3]) << 16) | +- (((u32)hw->mac_addr[4]) << 8) | +- (((u32)hw->mac_addr[5])) ; ++ value = mac_addr[2] << 24 | ++ mac_addr[3] << 16 | ++ mac_addr[4] << 8 | ++ mac_addr[5]; + AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 0, value); + /* hight dword */ +- value = (((u32)hw->mac_addr[0]) << 8) | +- (((u32)hw->mac_addr[1])) ; ++ value = mac_addr[0] << 8 | ++ mac_addr[1]; + AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 1, value); + } + ++/* read mac address from hardware register */ ++static bool atl1c_read_current_addr(struct atl1c_hw *hw, u8 *eth_addr) ++{ ++ u32 addr[2]; ++ ++ AT_READ_REG(hw, REG_MAC_STA_ADDR, &addr[0]); ++ AT_READ_REG(hw, REG_MAC_STA_ADDR + 4, &addr[1]); ++ ++ *(u32 *) ð_addr[2] = htonl(addr[0]); ++ *(u16 *) ð_addr[0] = htons((u16)addr[1]); ++ ++ return is_valid_ether_addr(eth_addr); ++} ++ + /* + * atl1c_get_permanent_address + * return 0 if get valid mac address, + */ + static int atl1c_get_permanent_address(struct atl1c_hw *hw) + { +- u32 addr[2]; + u32 i; + u32 otp_ctrl_data; + u32 twsi_ctrl_data; +- u32 ltssm_ctrl_data; +- u32 wol_data; +- u8 eth_addr[ETH_ALEN]; + u16 phy_data; + bool raise_vol = false; + ++ /* MAC-address from BIOS is the 1st priority */ ++ if (atl1c_read_current_addr(hw, hw->perm_mac_addr)) ++ return 0; ++ + /* init */ +- addr[0] = addr[1] = 0; + AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data); + if (atl1c_check_eeprom_exist(hw)) { + if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c) { +@@ -91,33 +104,17 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw) + msleep(1); + } + } +- +- if (hw->nic_type == athr_l2c_b || +- hw->nic_type == athr_l2c_b2 || +- hw->nic_type == athr_l1d) { +- atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00); +- if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data)) +- goto out; +- phy_data &= 0xFF7F; +- atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data); +- +- atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B); +- if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data)) +- goto out; +- phy_data |= 0x8; +- atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data); ++ /* raise voltage temporally for l2cb */ ++ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2) { ++ atl1c_read_phy_dbg(hw, MIIDBG_ANACTRL, &phy_data); ++ phy_data &= ~ANACTRL_HB_EN; ++ atl1c_write_phy_dbg(hw, MIIDBG_ANACTRL, phy_data); ++ atl1c_read_phy_dbg(hw, MIIDBG_VOLT_CTRL, &phy_data); ++ phy_data |= VOLT_CTRL_SWLOWEST; ++ atl1c_write_phy_dbg(hw, MIIDBG_VOLT_CTRL, phy_data); + udelay(20); + raise_vol = true; + } +- /* close open bit of ReadOnly*/ +- AT_READ_REG(hw, REG_LTSSM_ID_CTRL, <ssm_ctrl_data); +- ltssm_ctrl_data &= ~LTSSM_ID_EN_WRO; +- AT_WRITE_REG(hw, REG_LTSSM_ID_CTRL, ltssm_ctrl_data); +- +- /* clear any WOL settings */ +- AT_WRITE_REG(hw, REG_WOL_CTRL, 0); +- AT_READ_REG(hw, REG_WOL_CTRL, &wol_data); +- + + AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data); + twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART; +@@ -138,37 +135,18 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw) + msleep(1); + } + if (raise_vol) { +- if (hw->nic_type == athr_l2c_b || +- hw->nic_type == athr_l2c_b2 || +- hw->nic_type == athr_l1d || +- hw->nic_type == athr_l1d_2) { +- atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00); +- if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data)) +- goto out; +- phy_data |= 0x80; +- atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data); +- +- atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B); +- if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data)) +- goto out; +- phy_data &= 0xFFF7; +- atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data); +- udelay(20); +- } ++ atl1c_read_phy_dbg(hw, MIIDBG_ANACTRL, &phy_data); ++ phy_data |= ANACTRL_HB_EN; ++ atl1c_write_phy_dbg(hw, MIIDBG_ANACTRL, phy_data); ++ atl1c_read_phy_dbg(hw, MIIDBG_VOLT_CTRL, &phy_data); ++ phy_data &= ~VOLT_CTRL_SWLOWEST; ++ atl1c_write_phy_dbg(hw, MIIDBG_VOLT_CTRL, phy_data); ++ udelay(20); + } + +- /* maybe MAC-address is from BIOS */ +- AT_READ_REG(hw, REG_MAC_STA_ADDR, &addr[0]); +- AT_READ_REG(hw, REG_MAC_STA_ADDR + 4, &addr[1]); +- *(u32 *) ð_addr[2] = swab32(addr[0]); +- *(u16 *) ð_addr[0] = swab16(*(u16 *)&addr[1]); +- +- if (is_valid_ether_addr(eth_addr)) { +- memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); ++ if (atl1c_read_current_addr(hw, hw->perm_mac_addr)) + return 0; +- } + +-out: + return -1; + } + +@@ -278,33 +256,158 @@ void atl1c_hash_set(struct atl1c_hw *hw, u32 hash_value) + } + + /* +- * Reads the value from a PHY register +- * hw - Struct containing variables accessed by shared code +- * reg_addr - address of the PHY register to read ++ * wait mdio module be idle ++ * return true: idle ++ * false: still busy + */ +-int atl1c_read_phy_reg(struct atl1c_hw *hw, u16 reg_addr, u16 *phy_data) ++bool atl1c_wait_mdio_idle(struct atl1c_hw *hw) + { + u32 val; + int i; + +- val = ((u32)(reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT | +- MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW | +- MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT; ++ for (i = 0; i < MDIO_MAX_AC_TO; i++) { ++ AT_READ_REG(hw, REG_MDIO_CTRL, &val); ++ if (!(val & (MDIO_CTRL_BUSY | MDIO_CTRL_START))) ++ break; ++ udelay(10); ++ } ++ ++ return i != MDIO_MAX_AC_TO; ++} ++ ++void atl1c_stop_phy_polling(struct atl1c_hw *hw) ++{ ++ if (!(hw->ctrl_flags & ATL1C_FPGA_VERSION)) ++ return; ++ ++ AT_WRITE_REG(hw, REG_MDIO_CTRL, 0); ++ atl1c_wait_mdio_idle(hw); ++} + ++void atl1c_start_phy_polling(struct atl1c_hw *hw, u16 clk_sel) ++{ ++ u32 val; ++ ++ if (!(hw->ctrl_flags & ATL1C_FPGA_VERSION)) ++ return; ++ ++ val = MDIO_CTRL_SPRES_PRMBL | ++ FIELDX(MDIO_CTRL_CLK_SEL, clk_sel) | ++ FIELDX(MDIO_CTRL_REG, 1) | ++ MDIO_CTRL_START | ++ MDIO_CTRL_OP_READ; ++ AT_WRITE_REG(hw, REG_MDIO_CTRL, val); ++ atl1c_wait_mdio_idle(hw); ++ val |= MDIO_CTRL_AP_EN; ++ val &= ~MDIO_CTRL_START; + AT_WRITE_REG(hw, REG_MDIO_CTRL, val); ++ udelay(30); ++} + +- for (i = 0; i < MDIO_WAIT_TIMES; i++) { +- udelay(2); +- AT_READ_REG(hw, REG_MDIO_CTRL, &val); +- if (!(val & (MDIO_START | MDIO_BUSY))) +- break; ++ ++/* ++ * atl1c_read_phy_core ++ * core funtion to read register in PHY via MDIO control regsiter. ++ * ext: extension register (see IEEE 802.3) ++ * dev: device address (see IEEE 802.3 DEVAD, PRTAD is fixed to 0) ++ * reg: reg to read ++ */ ++int atl1c_read_phy_core(struct atl1c_hw *hw, bool ext, u8 dev, ++ u16 reg, u16 *phy_data) ++{ ++ u32 val; ++ u16 clk_sel = MDIO_CTRL_CLK_25_4; ++ ++ atl1c_stop_phy_polling(hw); ++ ++ *phy_data = 0; ++ ++ /* only l2c_b2 & l1d_2 could use slow clock */ ++ if ((hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) && ++ hw->hibernate) ++ clk_sel = MDIO_CTRL_CLK_25_128; ++ if (ext) { ++ val = FIELDX(MDIO_EXTN_DEVAD, dev) | FIELDX(MDIO_EXTN_REG, reg); ++ AT_WRITE_REG(hw, REG_MDIO_EXTN, val); ++ val = MDIO_CTRL_SPRES_PRMBL | ++ FIELDX(MDIO_CTRL_CLK_SEL, clk_sel) | ++ MDIO_CTRL_START | ++ MDIO_CTRL_MODE_EXT | ++ MDIO_CTRL_OP_READ; ++ } else { ++ val = MDIO_CTRL_SPRES_PRMBL | ++ FIELDX(MDIO_CTRL_CLK_SEL, clk_sel) | ++ FIELDX(MDIO_CTRL_REG, reg) | ++ MDIO_CTRL_START | ++ MDIO_CTRL_OP_READ; + } +- if (!(val & (MDIO_START | MDIO_BUSY))) { +- *phy_data = (u16)val; +- return 0; ++ AT_WRITE_REG(hw, REG_MDIO_CTRL, val); ++ ++ if (!atl1c_wait_mdio_idle(hw)) ++ return -1; ++ ++ AT_READ_REG(hw, REG_MDIO_CTRL, &val); ++ *phy_data = (u16)FIELD_GETX(val, MDIO_CTRL_DATA); ++ ++ atl1c_start_phy_polling(hw, clk_sel); ++ ++ return 0; ++} ++ ++/* ++ * atl1c_write_phy_core ++ * core funtion to write to register in PHY via MDIO control regsiter. ++ * ext: extension register (see IEEE 802.3) ++ * dev: device address (see IEEE 802.3 DEVAD, PRTAD is fixed to 0) ++ * reg: reg to write ++ */ ++int atl1c_write_phy_core(struct atl1c_hw *hw, bool ext, u8 dev, ++ u16 reg, u16 phy_data) ++{ ++ u32 val; ++ u16 clk_sel = MDIO_CTRL_CLK_25_4; ++ ++ atl1c_stop_phy_polling(hw); ++ ++ ++ /* only l2c_b2 & l1d_2 could use slow clock */ ++ if ((hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) && ++ hw->hibernate) ++ clk_sel = MDIO_CTRL_CLK_25_128; ++ ++ if (ext) { ++ val = FIELDX(MDIO_EXTN_DEVAD, dev) | FIELDX(MDIO_EXTN_REG, reg); ++ AT_WRITE_REG(hw, REG_MDIO_EXTN, val); ++ val = MDIO_CTRL_SPRES_PRMBL | ++ FIELDX(MDIO_CTRL_CLK_SEL, clk_sel) | ++ FIELDX(MDIO_CTRL_DATA, phy_data) | ++ MDIO_CTRL_START | ++ MDIO_CTRL_MODE_EXT; ++ } else { ++ val = MDIO_CTRL_SPRES_PRMBL | ++ FIELDX(MDIO_CTRL_CLK_SEL, clk_sel) | ++ FIELDX(MDIO_CTRL_DATA, phy_data) | ++ FIELDX(MDIO_CTRL_REG, reg) | ++ MDIO_CTRL_START; + } ++ AT_WRITE_REG(hw, REG_MDIO_CTRL, val); + +- return -1; ++ if (!atl1c_wait_mdio_idle(hw)) ++ return -1; ++ ++ atl1c_start_phy_polling(hw, clk_sel); ++ ++ return 0; ++} ++ ++/* ++ * Reads the value from a PHY register ++ * hw - Struct containing variables accessed by shared code ++ * reg_addr - address of the PHY register to read ++ */ ++int atl1c_read_phy_reg(struct atl1c_hw *hw, u16 reg_addr, u16 *phy_data) ++{ ++ return atl1c_read_phy_core(hw, false, 0, reg_addr, phy_data); + } + + /* +@@ -315,27 +418,47 @@ int atl1c_read_phy_reg(struct atl1c_hw *hw, u16 reg_addr, u16 *phy_data) + */ + int atl1c_write_phy_reg(struct atl1c_hw *hw, u32 reg_addr, u16 phy_data) + { +- int i; +- u32 val; ++ return atl1c_write_phy_core(hw, false, 0, reg_addr, phy_data); ++} + +- val = ((u32)(phy_data & MDIO_DATA_MASK)) << MDIO_DATA_SHIFT | +- (reg_addr & MDIO_REG_ADDR_MASK) << MDIO_REG_ADDR_SHIFT | +- MDIO_SUP_PREAMBLE | MDIO_START | +- MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT; ++/* read from PHY extension register */ ++int atl1c_read_phy_ext(struct atl1c_hw *hw, u8 dev_addr, ++ u16 reg_addr, u16 *phy_data) ++{ ++ return atl1c_read_phy_core(hw, true, dev_addr, reg_addr, phy_data); ++} + +- AT_WRITE_REG(hw, REG_MDIO_CTRL, val); ++/* write to PHY extension register */ ++int atl1c_write_phy_ext(struct atl1c_hw *hw, u8 dev_addr, ++ u16 reg_addr, u16 phy_data) ++{ ++ return atl1c_write_phy_core(hw, true, dev_addr, reg_addr, phy_data); ++} + +- for (i = 0; i < MDIO_WAIT_TIMES; i++) { +- udelay(2); +- AT_READ_REG(hw, REG_MDIO_CTRL, &val); +- if (!(val & (MDIO_START | MDIO_BUSY))) +- break; +- } ++int atl1c_read_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 *phy_data) ++{ ++ int err; + +- if (!(val & (MDIO_START | MDIO_BUSY))) +- return 0; ++ err = atl1c_write_phy_reg(hw, MII_DBG_ADDR, reg_addr); ++ if (unlikely(err)) ++ return err; ++ else ++ err = atl1c_read_phy_reg(hw, MII_DBG_DATA, phy_data); + +- return -1; ++ return err; ++} ++ ++int atl1c_write_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 phy_data) ++{ ++ int err; ++ ++ err = atl1c_write_phy_reg(hw, MII_DBG_ADDR, reg_addr); ++ if (unlikely(err)) ++ return err; ++ else ++ err = atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data); ++ ++ return err; + } + + /* +@@ -380,119 +503,100 @@ static int atl1c_phy_setup_adv(struct atl1c_hw *hw) + + void atl1c_phy_disable(struct atl1c_hw *hw) + { +- AT_WRITE_REGW(hw, REG_GPHY_CTRL, +- GPHY_CTRL_PW_WOL_DIS | GPHY_CTRL_EXT_RESET); ++ atl1c_power_saving(hw, 0); + } + +-static void atl1c_phy_magic_data(struct atl1c_hw *hw) +-{ +- u16 data; +- +- data = ANA_LOOP_SEL_10BT | ANA_EN_MASK_TB | ANA_EN_10BT_IDLE | +- ((1 & ANA_INTERVAL_SEL_TIMER_MASK) << +- ANA_INTERVAL_SEL_TIMER_SHIFT); +- +- atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_18); +- atl1c_write_phy_reg(hw, MII_DBG_DATA, data); +- +- data = (2 & ANA_SERDES_CDR_BW_MASK) | ANA_MS_PAD_DBG | +- ANA_SERDES_EN_DEEM | ANA_SERDES_SEL_HSP | ANA_SERDES_EN_PLL | +- ANA_SERDES_EN_LCKDT; +- +- atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_5); +- atl1c_write_phy_reg(hw, MII_DBG_DATA, data); +- +- data = (44 & ANA_LONG_CABLE_TH_100_MASK) | +- ((33 & ANA_SHORT_CABLE_TH_100_MASK) << +- ANA_SHORT_CABLE_TH_100_SHIFT) | ANA_BP_BAD_LINK_ACCUM | +- ANA_BP_SMALL_BW; +- +- atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_54); +- atl1c_write_phy_reg(hw, MII_DBG_DATA, data); +- +- data = (11 & ANA_IECHO_ADJ_MASK) | ((11 & ANA_IECHO_ADJ_MASK) << +- ANA_IECHO_ADJ_2_SHIFT) | ((8 & ANA_IECHO_ADJ_MASK) << +- ANA_IECHO_ADJ_1_SHIFT) | ((8 & ANA_IECHO_ADJ_MASK) << +- ANA_IECHO_ADJ_0_SHIFT); +- +- atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_4); +- atl1c_write_phy_reg(hw, MII_DBG_DATA, data); +- +- data = ANA_RESTART_CAL | ((7 & ANA_MANUL_SWICH_ON_MASK) << +- ANA_MANUL_SWICH_ON_SHIFT) | ANA_MAN_ENABLE | +- ANA_SEL_HSP | ANA_EN_HB | ANA_OEN_125M; +- +- atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_0); +- atl1c_write_phy_reg(hw, MII_DBG_DATA, data); +- +- if (hw->ctrl_flags & ATL1C_HIB_DISABLE) { +- atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_41); +- if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &data) != 0) +- return; +- data &= ~ANA_TOP_PS_EN; +- atl1c_write_phy_reg(hw, MII_DBG_DATA, data); +- +- atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_11); +- if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &data) != 0) +- return; +- data &= ~ANA_PS_HIB_EN; +- atl1c_write_phy_reg(hw, MII_DBG_DATA, data); +- } +-} + + int atl1c_phy_reset(struct atl1c_hw *hw) + { + struct atl1c_adapter *adapter = hw->adapter; + struct pci_dev *pdev = adapter->pdev; + u16 phy_data; +- u32 phy_ctrl_data = GPHY_CTRL_DEFAULT; +- u32 mii_ier_data = IER_LINK_UP | IER_LINK_DOWN; ++ u32 phy_ctrl_data, lpi_ctrl; + int err; + +- if (hw->ctrl_flags & ATL1C_HIB_DISABLE) +- phy_ctrl_data &= ~GPHY_CTRL_HIB_EN; +- ++ /* reset PHY core */ ++ AT_READ_REG(hw, REG_GPHY_CTRL, &phy_ctrl_data); ++ phy_ctrl_data &= ~(GPHY_CTRL_EXT_RESET | GPHY_CTRL_PHY_IDDQ | ++ GPHY_CTRL_GATE_25M_EN | GPHY_CTRL_PWDOWN_HW | GPHY_CTRL_CLS); ++ phy_ctrl_data |= GPHY_CTRL_SEL_ANA_RST; ++ if (!(hw->ctrl_flags & ATL1C_HIB_DISABLE)) ++ phy_ctrl_data |= (GPHY_CTRL_HIB_EN | GPHY_CTRL_HIB_PULSE); ++ else ++ phy_ctrl_data &= ~(GPHY_CTRL_HIB_EN | GPHY_CTRL_HIB_PULSE); + AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl_data); + AT_WRITE_FLUSH(hw); +- msleep(40); +- phy_ctrl_data |= GPHY_CTRL_EXT_RESET; +- AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl_data); ++ udelay(10); ++ AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl_data | GPHY_CTRL_EXT_RESET); + AT_WRITE_FLUSH(hw); +- msleep(10); ++ udelay(10 * GPHY_CTRL_EXT_RST_TO); /* delay 800us */ + ++ /* switch clock */ + if (hw->nic_type == athr_l2c_b) { +- atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x0A); +- atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data); +- atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data & 0xDFFF); ++ atl1c_read_phy_dbg(hw, MIIDBG_CFGLPSPD, &phy_data); ++ atl1c_write_phy_dbg(hw, MIIDBG_CFGLPSPD, ++ phy_data & ~CFGLPSPD_RSTCNT_CLK125SW); + } + +- if (hw->nic_type == athr_l2c_b || +- hw->nic_type == athr_l2c_b2 || +- hw->nic_type == athr_l1d || +- hw->nic_type == athr_l1d_2) { +- atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B); +- atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data); +- atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data & 0xFFF7); +- msleep(20); ++ /* tx-half amplitude issue fix */ ++ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2) { ++ atl1c_read_phy_dbg(hw, MIIDBG_CABLE1TH_DET, &phy_data); ++ phy_data |= CABLE1TH_DET_EN; ++ atl1c_write_phy_dbg(hw, MIIDBG_CABLE1TH_DET, phy_data); + } +- if (hw->nic_type == athr_l1d) { +- atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29); +- atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x929D); ++ ++ /* clear bit3 of dbgport 3B to lower voltage */ ++ if (!(hw->ctrl_flags & ATL1C_HIB_DISABLE)) { ++ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2) { ++ atl1c_read_phy_dbg(hw, MIIDBG_VOLT_CTRL, &phy_data); ++ phy_data &= ~VOLT_CTRL_SWLOWEST; ++ atl1c_write_phy_dbg(hw, MIIDBG_VOLT_CTRL, phy_data); ++ } ++ /* power saving config */ ++ phy_data = ++ hw->nic_type == athr_l1d || hw->nic_type == athr_l1d_2 ? ++ L1D_LEGCYPS_DEF : L1C_LEGCYPS_DEF; ++ atl1c_write_phy_dbg(hw, MIIDBG_LEGCYPS, phy_data); ++ /* hib */ ++ atl1c_write_phy_dbg(hw, MIIDBG_SYSMODCTRL, ++ SYSMODCTRL_IECHOADJ_DEF); ++ } else { ++ /* disable pws */ ++ atl1c_read_phy_dbg(hw, MIIDBG_LEGCYPS, &phy_data); ++ atl1c_write_phy_dbg(hw, MIIDBG_LEGCYPS, ++ phy_data & ~LEGCYPS_EN); ++ /* disable hibernate */ ++ atl1c_read_phy_dbg(hw, MIIDBG_HIBNEG, &phy_data); ++ atl1c_write_phy_dbg(hw, MIIDBG_HIBNEG, ++ phy_data & HIBNEG_PSHIB_EN); + } +- if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b2 +- || hw->nic_type == athr_l2c) { +- atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29); +- atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB6DD); ++ /* disable AZ(EEE) by default */ ++ if (hw->nic_type == athr_l1d || hw->nic_type == athr_l1d_2 || ++ hw->nic_type == athr_l2c_b2) { ++ AT_READ_REG(hw, REG_LPI_CTRL, &lpi_ctrl); ++ AT_WRITE_REG(hw, REG_LPI_CTRL, lpi_ctrl & ~LPI_CTRL_EN); ++ atl1c_write_phy_ext(hw, MIIEXT_ANEG, MIIEXT_LOCAL_EEEADV, 0); ++ atl1c_write_phy_ext(hw, MIIEXT_PCS, MIIEXT_CLDCTRL3, ++ L2CB_CLDCTRL3); + } +- err = atl1c_write_phy_reg(hw, MII_IER, mii_ier_data); ++ ++ /* other debug port to set */ ++ atl1c_write_phy_dbg(hw, MIIDBG_ANACTRL, ANACTRL_DEF); ++ atl1c_write_phy_dbg(hw, MIIDBG_SRDSYSMOD, SRDSYSMOD_DEF); ++ atl1c_write_phy_dbg(hw, MIIDBG_TST10BTCFG, TST10BTCFG_DEF); ++ /* UNH-IOL test issue, set bit7 */ ++ atl1c_write_phy_dbg(hw, MIIDBG_TST100BTCFG, ++ TST100BTCFG_DEF | TST100BTCFG_LITCH_EN); ++ ++ /* set phy interrupt mask */ ++ phy_data = IER_LINK_UP | IER_LINK_DOWN; ++ err = atl1c_write_phy_reg(hw, MII_IER, phy_data); + if (err) { + if (netif_msg_hw(adapter)) + dev_err(&pdev->dev, + "Error enable PHY linkChange Interrupt\n"); + return err; + } +- if (!(hw->ctrl_flags & ATL1C_FPGA_VERSION)) +- atl1c_phy_magic_data(hw); + return 0; + } + +@@ -589,7 +693,8 @@ int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex) + return 0; + } + +-int atl1c_phy_power_saving(struct atl1c_hw *hw) ++/* select one link mode to get lower power consumption */ ++int atl1c_phy_to_ps_link(struct atl1c_hw *hw) + { + struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter; + struct pci_dev *pdev = adapter->pdev; +@@ -660,3 +765,101 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw) + + return atl1c_write_phy_reg(hw, MII_BMCR, mii_bmcr_data); + } ++ ++int atl1c_power_saving(struct atl1c_hw *hw, u32 wufc) ++{ ++ struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter; ++ struct pci_dev *pdev = adapter->pdev; ++ u32 master_ctrl, mac_ctrl, phy_ctrl; ++ u32 wol_ctrl, speed; ++ u16 phy_data; ++ ++ wol_ctrl = 0; ++ speed = adapter->link_speed == SPEED_1000 ? ++ MAC_CTRL_SPEED_1000 : MAC_CTRL_SPEED_10_100; ++ ++ AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl); ++ AT_READ_REG(hw, REG_MAC_CTRL, &mac_ctrl); ++ AT_READ_REG(hw, REG_GPHY_CTRL, &phy_ctrl); ++ ++ master_ctrl &= ~MASTER_CTRL_CLK_SEL_DIS; ++ mac_ctrl = FIELD_SETX(mac_ctrl, MAC_CTRL_SPEED, speed); ++ mac_ctrl &= ~(MAC_CTRL_DUPLX | MAC_CTRL_RX_EN | MAC_CTRL_TX_EN); ++ if (adapter->link_duplex == FULL_DUPLEX) ++ mac_ctrl |= MAC_CTRL_DUPLX; ++ phy_ctrl &= ~(GPHY_CTRL_EXT_RESET | GPHY_CTRL_CLS); ++ phy_ctrl |= GPHY_CTRL_SEL_ANA_RST | GPHY_CTRL_HIB_PULSE | ++ GPHY_CTRL_HIB_EN; ++ if (!wufc) { /* without WoL */ ++ master_ctrl |= MASTER_CTRL_CLK_SEL_DIS; ++ phy_ctrl |= GPHY_CTRL_PHY_IDDQ | GPHY_CTRL_PWDOWN_HW; ++ AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl); ++ AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl); ++ AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl); ++ AT_WRITE_REG(hw, REG_WOL_CTRL, 0); ++ hw->phy_configured = false; /* re-init PHY when resume */ ++ return 0; ++ } ++ phy_ctrl |= GPHY_CTRL_EXT_RESET; ++ if (wufc & AT_WUFC_MAG) { ++ mac_ctrl |= MAC_CTRL_RX_EN | MAC_CTRL_BC_EN; ++ wol_ctrl |= WOL_MAGIC_EN | WOL_MAGIC_PME_EN; ++ if (hw->nic_type == athr_l2c_b && hw->revision_id == L2CB_V11) ++ wol_ctrl |= WOL_PATTERN_EN | WOL_PATTERN_PME_EN; ++ } ++ if (wufc & AT_WUFC_LNKC) { ++ wol_ctrl |= WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN; ++ if (atl1c_write_phy_reg(hw, MII_IER, IER_LINK_UP) != 0) { ++ dev_dbg(&pdev->dev, "%s: write phy MII_IER faild.\n", ++ atl1c_driver_name); ++ } ++ } ++ /* clear PHY interrupt */ ++ atl1c_read_phy_reg(hw, MII_ISR, &phy_data); ++ ++ dev_dbg(&pdev->dev, "%s: suspend MAC=%x,MASTER=%x,PHY=0x%x,WOL=%x\n", ++ atl1c_driver_name, mac_ctrl, master_ctrl, phy_ctrl, wol_ctrl); ++ AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl); ++ AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl); ++ AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl); ++ AT_WRITE_REG(hw, REG_WOL_CTRL, wol_ctrl); ++ ++ return 0; ++} ++ ++ ++/* configure phy after Link change Event */ ++void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed) ++{ ++ u16 phy_val; ++ bool adj_thresh = false; ++ ++ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2 || ++ hw->nic_type == athr_l1d || hw->nic_type == athr_l1d_2) ++ adj_thresh = true; ++ ++ if (link_speed != SPEED_0) { /* link up */ ++ /* az with brcm, half-amp */ ++ if (hw->nic_type == athr_l1d_2) { ++ atl1c_read_phy_ext(hw, MIIEXT_PCS, MIIEXT_CLDCTRL6, ++ &phy_val); ++ phy_val = FIELD_GETX(phy_val, CLDCTRL6_CAB_LEN); ++ phy_val = phy_val > CLDCTRL6_CAB_LEN_SHORT ? ++ AZ_ANADECT_LONG : AZ_ANADECT_DEF; ++ atl1c_write_phy_dbg(hw, MIIDBG_AZ_ANADECT, phy_val); ++ } ++ /* threshold adjust */ ++ if (adj_thresh && link_speed == SPEED_100 && hw->msi_lnkpatch) { ++ atl1c_write_phy_dbg(hw, MIIDBG_MSE16DB, L1D_MSE16DB_UP); ++ atl1c_write_phy_dbg(hw, MIIDBG_SYSMODCTRL, ++ L1D_SYSMODCTRL_IECHOADJ_DEF); ++ } ++ } else { /* link down */ ++ if (adj_thresh && hw->msi_lnkpatch) { ++ atl1c_write_phy_dbg(hw, MIIDBG_SYSMODCTRL, ++ SYSMODCTRL_IECHOADJ_DEF); ++ atl1c_write_phy_dbg(hw, MIIDBG_MSE16DB, ++ L1D_MSE16DB_DOWN); ++ } ++ } ++} +diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h +index 655fc6c..17d935b 100644 +--- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h ++++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h +@@ -25,12 +25,18 @@ + #include + #include + ++#define FIELD_GETX(_x, _name) ((_x) >> (_name##_SHIFT) & (_name##_MASK)) ++#define FIELD_SETX(_x, _name, _v) \ ++(((_x) & ~((_name##_MASK) << (_name##_SHIFT))) |\ ++(((_v) & (_name##_MASK)) << (_name##_SHIFT))) ++#define FIELDX(_name, _v) (((_v) & (_name##_MASK)) << (_name##_SHIFT)) ++ + struct atl1c_adapter; + struct atl1c_hw; + + /* function prototype */ + void atl1c_phy_disable(struct atl1c_hw *hw); +-void atl1c_hw_set_mac_addr(struct atl1c_hw *hw); ++void atl1c_hw_set_mac_addr(struct atl1c_hw *hw, u8 *mac_addr); + int atl1c_phy_reset(struct atl1c_hw *hw); + int atl1c_read_mac_addr(struct atl1c_hw *hw); + int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex); +@@ -42,47 +48,45 @@ bool atl1c_read_eeprom(struct atl1c_hw *hw, u32 offset, u32 *p_value); + int atl1c_phy_init(struct atl1c_hw *hw); + int atl1c_check_eeprom_exist(struct atl1c_hw *hw); + int atl1c_restart_autoneg(struct atl1c_hw *hw); +-int atl1c_phy_power_saving(struct atl1c_hw *hw); ++int atl1c_phy_to_ps_link(struct atl1c_hw *hw); ++int atl1c_power_saving(struct atl1c_hw *hw, u32 wufc); ++bool atl1c_wait_mdio_idle(struct atl1c_hw *hw); ++void atl1c_stop_phy_polling(struct atl1c_hw *hw); ++void atl1c_start_phy_polling(struct atl1c_hw *hw, u16 clk_sel); ++int atl1c_read_phy_core(struct atl1c_hw *hw, bool ext, u8 dev, ++ u16 reg, u16 *phy_data); ++int atl1c_write_phy_core(struct atl1c_hw *hw, bool ext, u8 dev, ++ u16 reg, u16 phy_data); ++int atl1c_read_phy_ext(struct atl1c_hw *hw, u8 dev_addr, ++ u16 reg_addr, u16 *phy_data); ++int atl1c_write_phy_ext(struct atl1c_hw *hw, u8 dev_addr, ++ u16 reg_addr, u16 phy_data); ++int atl1c_read_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 *phy_data); ++int atl1c_write_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 phy_data); ++void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed); ++ ++/* hw-ids */ ++#define PCI_DEVICE_ID_ATTANSIC_L2C 0x1062 ++#define PCI_DEVICE_ID_ATTANSIC_L1C 0x1063 ++#define PCI_DEVICE_ID_ATHEROS_L2C_B 0x2060 /* AR8152 v1.1 Fast 10/100 */ ++#define PCI_DEVICE_ID_ATHEROS_L2C_B2 0x2062 /* AR8152 v2.0 Fast 10/100 */ ++#define PCI_DEVICE_ID_ATHEROS_L1D 0x1073 /* AR8151 v1.0 Gigabit 1000 */ ++#define PCI_DEVICE_ID_ATHEROS_L1D_2_0 0x1083 /* AR8151 v2.0 Gigabit 1000 */ ++#define L2CB_V10 0xc0 ++#define L2CB_V11 0xc1 ++ + /* register definition */ + #define REG_DEVICE_CAP 0x5C + #define DEVICE_CAP_MAX_PAYLOAD_MASK 0x7 + #define DEVICE_CAP_MAX_PAYLOAD_SHIFT 0 + +-#define REG_DEVICE_CTRL 0x60 +-#define DEVICE_CTRL_MAX_PAYLOAD_MASK 0x7 +-#define DEVICE_CTRL_MAX_PAYLOAD_SHIFT 5 +-#define DEVICE_CTRL_MAX_RREQ_SZ_MASK 0x7 +-#define DEVICE_CTRL_MAX_RREQ_SZ_SHIFT 12 ++#define DEVICE_CTRL_MAXRRS_MIN 2 + + #define REG_LINK_CTRL 0x68 + #define LINK_CTRL_L0S_EN 0x01 + #define LINK_CTRL_L1_EN 0x02 + #define LINK_CTRL_EXT_SYNC 0x80 + +-#define REG_VPD_CAP 0x6C +-#define VPD_CAP_ID_MASK 0xff +-#define VPD_CAP_ID_SHIFT 0 +-#define VPD_CAP_NEXT_PTR_MASK 0xFF +-#define VPD_CAP_NEXT_PTR_SHIFT 8 +-#define VPD_CAP_VPD_ADDR_MASK 0x7FFF +-#define VPD_CAP_VPD_ADDR_SHIFT 16 +-#define VPD_CAP_VPD_FLAG 0x80000000 +- +-#define REG_VPD_DATA 0x70 +- +-#define REG_PCIE_UC_SEVERITY 0x10C +-#define PCIE_UC_SERVRITY_TRN 0x00000001 +-#define PCIE_UC_SERVRITY_DLP 0x00000010 +-#define PCIE_UC_SERVRITY_PSN_TLP 0x00001000 +-#define PCIE_UC_SERVRITY_FCP 0x00002000 +-#define PCIE_UC_SERVRITY_CPL_TO 0x00004000 +-#define PCIE_UC_SERVRITY_CA 0x00008000 +-#define PCIE_UC_SERVRITY_UC 0x00010000 +-#define PCIE_UC_SERVRITY_ROV 0x00020000 +-#define PCIE_UC_SERVRITY_MLFP 0x00040000 +-#define PCIE_UC_SERVRITY_ECRC 0x00080000 +-#define PCIE_UC_SERVRITY_UR 0x00100000 +- + #define REG_DEV_SERIALNUM_CTRL 0x200 + #define REG_DEV_MAC_SEL_MASK 0x0 /* 0:EUI; 1:MAC */ + #define REG_DEV_MAC_SEL_SHIFT 0 +@@ -90,25 +94,17 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); + #define REG_DEV_SERIAL_NUM_EN_SHIFT 1 + + #define REG_TWSI_CTRL 0x218 ++#define TWSI_CTLR_FREQ_MASK 0x3UL ++#define TWSI_CTRL_FREQ_SHIFT 24 ++#define TWSI_CTRL_FREQ_100K 0 ++#define TWSI_CTRL_FREQ_200K 1 ++#define TWSI_CTRL_FREQ_300K 2 ++#define TWSI_CTRL_FREQ_400K 3 ++#define TWSI_CTRL_LD_EXIST BIT(23) ++#define TWSI_CTRL_HW_LDSTAT BIT(12) /* 0:finish,1:in progress */ ++#define TWSI_CTRL_SW_LDSTART BIT(11) + #define TWSI_CTRL_LD_OFFSET_MASK 0xFF + #define TWSI_CTRL_LD_OFFSET_SHIFT 0 +-#define TWSI_CTRL_LD_SLV_ADDR_MASK 0x7 +-#define TWSI_CTRL_LD_SLV_ADDR_SHIFT 8 +-#define TWSI_CTRL_SW_LDSTART 0x800 +-#define TWSI_CTRL_HW_LDSTART 0x1000 +-#define TWSI_CTRL_SMB_SLV_ADDR_MASK 0x7F +-#define TWSI_CTRL_SMB_SLV_ADDR_SHIFT 15 +-#define TWSI_CTRL_LD_EXIST 0x400000 +-#define TWSI_CTRL_READ_FREQ_SEL_MASK 0x3 +-#define TWSI_CTRL_READ_FREQ_SEL_SHIFT 23 +-#define TWSI_CTRL_FREQ_SEL_100K 0 +-#define TWSI_CTRL_FREQ_SEL_200K 1 +-#define TWSI_CTRL_FREQ_SEL_300K 2 +-#define TWSI_CTRL_FREQ_SEL_400K 3 +-#define TWSI_CTRL_SMB_SLV_ADDR +-#define TWSI_CTRL_WRITE_FREQ_SEL_MASK 0x3 +-#define TWSI_CTRL_WRITE_FREQ_SEL_SHIFT 24 +- + + #define REG_PCIE_DEV_MISC_CTRL 0x21C + #define PCIE_DEV_MISC_EXT_PIPE 0x2 +@@ -118,16 +114,23 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); + #define PCIE_DEV_MISC_SERDES_SEL_DIN 0x10 + + #define REG_PCIE_PHYMISC 0x1000 +-#define PCIE_PHYMISC_FORCE_RCV_DET 0x4 ++#define PCIE_PHYMISC_FORCE_RCV_DET BIT(2) ++#define PCIE_PHYMISC_NFTS_MASK 0xFFUL ++#define PCIE_PHYMISC_NFTS_SHIFT 16 + + #define REG_PCIE_PHYMISC2 0x1004 +-#define PCIE_PHYMISC2_SERDES_CDR_MASK 0x3 +-#define PCIE_PHYMISC2_SERDES_CDR_SHIFT 16 +-#define PCIE_PHYMISC2_SERDES_TH_MASK 0x3 +-#define PCIE_PHYMISC2_SERDES_TH_SHIFT 18 ++#define PCIE_PHYMISC2_L0S_TH_MASK 0x3UL ++#define PCIE_PHYMISC2_L0S_TH_SHIFT 18 ++#define L2CB1_PCIE_PHYMISC2_L0S_TH 3 ++#define PCIE_PHYMISC2_CDR_BW_MASK 0x3UL ++#define PCIE_PHYMISC2_CDR_BW_SHIFT 16 ++#define L2CB1_PCIE_PHYMISC2_CDR_BW 3 + + #define REG_TWSI_DEBUG 0x1108 +-#define TWSI_DEBUG_DEV_EXIST 0x20000000 ++#define TWSI_DEBUG_DEV_EXIST BIT(29) ++ ++#define REG_DMA_DBG 0x1114 ++#define DMA_DBG_VENDOR_MSG BIT(0) + + #define REG_EEPROM_CTRL 0x12C0 + #define EEPROM_CTRL_DATA_HI_MASK 0xFFFF +@@ -140,56 +143,81 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); + #define REG_EEPROM_DATA_LO 0x12C4 + + #define REG_OTP_CTRL 0x12F0 +-#define OTP_CTRL_CLK_EN 0x0002 ++#define OTP_CTRL_CLK_EN BIT(1) + + #define REG_PM_CTRL 0x12F8 +-#define PM_CTRL_SDES_EN 0x00000001 +-#define PM_CTRL_RBER_EN 0x00000002 +-#define PM_CTRL_CLK_REQ_EN 0x00000004 +-#define PM_CTRL_ASPM_L1_EN 0x00000008 +-#define PM_CTRL_SERDES_L1_EN 0x00000010 +-#define PM_CTRL_SERDES_PLL_L1_EN 0x00000020 +-#define PM_CTRL_SERDES_PD_EX_L1 0x00000040 +-#define PM_CTRL_SERDES_BUDS_RX_L1_EN 0x00000080 +-#define PM_CTRL_L0S_ENTRY_TIMER_MASK 0xF +-#define PM_CTRL_L0S_ENTRY_TIMER_SHIFT 8 +-#define PM_CTRL_ASPM_L0S_EN 0x00001000 +-#define PM_CTRL_CLK_SWH_L1 0x00002000 +-#define PM_CTRL_CLK_PWM_VER1_1 0x00004000 +-#define PM_CTRL_RCVR_WT_TIMER 0x00008000 +-#define PM_CTRL_L1_ENTRY_TIMER_MASK 0xF +-#define PM_CTRL_L1_ENTRY_TIMER_SHIFT 16 +-#define PM_CTRL_PM_REQ_TIMER_MASK 0xF +-#define PM_CTRL_PM_REQ_TIMER_SHIFT 20 +-#define PM_CTRL_LCKDET_TIMER_MASK 0xF ++#define PM_CTRL_HOTRST BIT(31) ++#define PM_CTRL_MAC_ASPM_CHK BIT(30) /* L0s/L1 dis by MAC based on ++ * thrghput(setting in 15A0) */ ++#define PM_CTRL_SA_DLY_EN BIT(29) ++#define PM_CTRL_L0S_BUFSRX_EN BIT(28) ++#define PM_CTRL_LCKDET_TIMER_MASK 0xFUL + #define PM_CTRL_LCKDET_TIMER_SHIFT 24 +-#define PM_CTRL_EN_BUFS_RX_L0S 0x10000000 +-#define PM_CTRL_SA_DLY_EN 0x20000000 +-#define PM_CTRL_MAC_ASPM_CHK 0x40000000 +-#define PM_CTRL_HOTRST 0x80000000 ++#define PM_CTRL_LCKDET_TIMER_DEF 0xC ++#define PM_CTRL_PM_REQ_TIMER_MASK 0xFUL ++#define PM_CTRL_PM_REQ_TIMER_SHIFT 20 /* pm_request_l1 time > @ ++ * ->L0s not L1 */ ++#define PM_CTRL_PM_REQ_TO_DEF 0xF ++#define PMCTRL_TXL1_AFTER_L0S BIT(19) /* l1dv2.0+ */ ++#define L1D_PMCTRL_L1_ENTRY_TM_MASK 7UL /* l1dv2.0+, 3bits */ ++#define L1D_PMCTRL_L1_ENTRY_TM_SHIFT 16 ++#define L1D_PMCTRL_L1_ENTRY_TM_DIS 0 ++#define L1D_PMCTRL_L1_ENTRY_TM_2US 1 ++#define L1D_PMCTRL_L1_ENTRY_TM_4US 2 ++#define L1D_PMCTRL_L1_ENTRY_TM_8US 3 ++#define L1D_PMCTRL_L1_ENTRY_TM_16US 4 ++#define L1D_PMCTRL_L1_ENTRY_TM_24US 5 ++#define L1D_PMCTRL_L1_ENTRY_TM_32US 6 ++#define L1D_PMCTRL_L1_ENTRY_TM_63US 7 ++#define PM_CTRL_L1_ENTRY_TIMER_MASK 0xFUL /* l1C 4bits */ ++#define PM_CTRL_L1_ENTRY_TIMER_SHIFT 16 ++#define L2CB1_PM_CTRL_L1_ENTRY_TM 7 ++#define L1C_PM_CTRL_L1_ENTRY_TM 0xF ++#define PM_CTRL_RCVR_WT_TIMER BIT(15) /* 1:1us, 0:2ms */ ++#define PM_CTRL_CLK_PWM_VER1_1 BIT(14) /* 0:1.0a,1:1.1 */ ++#define PM_CTRL_CLK_SWH_L1 BIT(13) /* en pcie clk sw in L1 */ ++#define PM_CTRL_ASPM_L0S_EN BIT(12) ++#define PM_CTRL_RXL1_AFTER_L0S BIT(11) /* l1dv2.0+ */ ++#define L1D_PMCTRL_L0S_TIMER_MASK 7UL /* l1d2.0+, 3bits*/ ++#define L1D_PMCTRL_L0S_TIMER_SHIFT 8 ++#define PM_CTRL_L0S_ENTRY_TIMER_MASK 0xFUL /* l1c, 4bits */ ++#define PM_CTRL_L0S_ENTRY_TIMER_SHIFT 8 ++#define PM_CTRL_SERDES_BUFS_RX_L1_EN BIT(7) ++#define PM_CTRL_SERDES_PD_EX_L1 BIT(6) /* power down serdes rx */ ++#define PM_CTRL_SERDES_PLL_L1_EN BIT(5) ++#define PM_CTRL_SERDES_L1_EN BIT(4) ++#define PM_CTRL_ASPM_L1_EN BIT(3) ++#define PM_CTRL_CLK_REQ_EN BIT(2) ++#define PM_CTRL_RBER_EN BIT(1) ++#define PM_CTRL_SPRSDWER_EN BIT(0) + + #define REG_LTSSM_ID_CTRL 0x12FC + #define LTSSM_ID_EN_WRO 0x1000 ++ ++ + /* Selene Master Control Register */ + #define REG_MASTER_CTRL 0x1400 +-#define MASTER_CTRL_SOFT_RST 0x1 +-#define MASTER_CTRL_TEST_MODE_MASK 0x3 +-#define MASTER_CTRL_TEST_MODE_SHIFT 2 +-#define MASTER_CTRL_BERT_START 0x10 +-#define MASTER_CTRL_OOB_DIS_OFF 0x40 +-#define MASTER_CTRL_SA_TIMER_EN 0x80 +-#define MASTER_CTRL_MTIMER_EN 0x100 +-#define MASTER_CTRL_MANUAL_INT 0x200 +-#define MASTER_CTRL_TX_ITIMER_EN 0x400 +-#define MASTER_CTRL_RX_ITIMER_EN 0x800 +-#define MASTER_CTRL_CLK_SEL_DIS 0x1000 +-#define MASTER_CTRL_CLK_SWH_MODE 0x2000 +-#define MASTER_CTRL_INT_RDCLR 0x4000 +-#define MASTER_CTRL_REV_NUM_SHIFT 16 +-#define MASTER_CTRL_REV_NUM_MASK 0xff +-#define MASTER_CTRL_DEV_ID_SHIFT 24 +-#define MASTER_CTRL_DEV_ID_MASK 0x7f +-#define MASTER_CTRL_OTP_SEL 0x80000000 ++#define MASTER_CTRL_OTP_SEL BIT(31) ++#define MASTER_DEV_NUM_MASK 0x7FUL ++#define MASTER_DEV_NUM_SHIFT 24 ++#define MASTER_REV_NUM_MASK 0xFFUL ++#define MASTER_REV_NUM_SHIFT 16 ++#define MASTER_CTRL_INT_RDCLR BIT(14) ++#define MASTER_CTRL_CLK_SEL_DIS BIT(12) /* 1:alwys sel pclk from ++ * serdes, not sw to 25M */ ++#define MASTER_CTRL_RX_ITIMER_EN BIT(11) /* IRQ MODURATION FOR RX */ ++#define MASTER_CTRL_TX_ITIMER_EN BIT(10) /* MODURATION FOR TX/RX */ ++#define MASTER_CTRL_MANU_INT BIT(9) /* SOFT MANUAL INT */ ++#define MASTER_CTRL_MANUTIMER_EN BIT(8) ++#define MASTER_CTRL_SA_TIMER_EN BIT(7) /* SYS ALIVE TIMER EN */ ++#define MASTER_CTRL_OOB_DIS BIT(6) /* OUT OF BOX DIS */ ++#define MASTER_CTRL_WAKEN_25M BIT(5) /* WAKE WO. PCIE CLK */ ++#define MASTER_CTRL_BERT_START BIT(4) ++#define MASTER_PCIE_TSTMOD_MASK 3UL ++#define MASTER_PCIE_TSTMOD_SHIFT 2 ++#define MASTER_PCIE_RST BIT(1) ++#define MASTER_CTRL_SOFT_RST BIT(0) /* RST MAC & DMA */ ++#define DMA_MAC_RST_TO 50 + + /* Timer Initial Value Register */ + #define REG_MANUAL_TIMER_INIT 0x1404 +@@ -201,87 +229,85 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); + #define IRQ_MODRT_RX_TIMER_SHIFT 16 + + #define REG_GPHY_CTRL 0x140C +-#define GPHY_CTRL_EXT_RESET 0x1 +-#define GPHY_CTRL_RTL_MODE 0x2 +-#define GPHY_CTRL_LED_MODE 0x4 +-#define GPHY_CTRL_ANEG_NOW 0x8 +-#define GPHY_CTRL_REV_ANEG 0x10 +-#define GPHY_CTRL_GATE_25M_EN 0x20 +-#define GPHY_CTRL_LPW_EXIT 0x40 +-#define GPHY_CTRL_PHY_IDDQ 0x80 +-#define GPHY_CTRL_PHY_IDDQ_DIS 0x100 +-#define GPHY_CTRL_GIGA_DIS 0x200 +-#define GPHY_CTRL_HIB_EN 0x400 +-#define GPHY_CTRL_HIB_PULSE 0x800 +-#define GPHY_CTRL_SEL_ANA_RST 0x1000 +-#define GPHY_CTRL_PHY_PLL_ON 0x2000 +-#define GPHY_CTRL_PWDOWN_HW 0x4000 +-#define GPHY_CTRL_PHY_PLL_BYPASS 0x8000 +- +-#define GPHY_CTRL_DEFAULT ( \ +- GPHY_CTRL_SEL_ANA_RST |\ +- GPHY_CTRL_HIB_PULSE |\ +- GPHY_CTRL_HIB_EN) +- +-#define GPHY_CTRL_PW_WOL_DIS ( \ +- GPHY_CTRL_SEL_ANA_RST |\ +- GPHY_CTRL_HIB_PULSE |\ +- GPHY_CTRL_HIB_EN |\ +- GPHY_CTRL_PWDOWN_HW |\ +- GPHY_CTRL_PHY_IDDQ) +- +-#define GPHY_CTRL_POWER_SAVING ( \ +- GPHY_CTRL_SEL_ANA_RST |\ +- GPHY_CTRL_HIB_EN |\ +- GPHY_CTRL_HIB_PULSE |\ +- GPHY_CTRL_PWDOWN_HW |\ +- GPHY_CTRL_PHY_IDDQ) ++#define GPHY_CTRL_ADDR_MASK 0x1FUL ++#define GPHY_CTRL_ADDR_SHIFT 19 ++#define GPHY_CTRL_BP_VLTGSW BIT(18) ++#define GPHY_CTRL_100AB_EN BIT(17) ++#define GPHY_CTRL_10AB_EN BIT(16) ++#define GPHY_CTRL_PHY_PLL_BYPASS BIT(15) ++#define GPHY_CTRL_PWDOWN_HW BIT(14) /* affect MAC&PHY, to low pw */ ++#define GPHY_CTRL_PHY_PLL_ON BIT(13) /* 1:pll always on, 0:can sw */ ++#define GPHY_CTRL_SEL_ANA_RST BIT(12) ++#define GPHY_CTRL_HIB_PULSE BIT(11) ++#define GPHY_CTRL_HIB_EN BIT(10) ++#define GPHY_CTRL_GIGA_DIS BIT(9) ++#define GPHY_CTRL_PHY_IDDQ_DIS BIT(8) /* pw on RST */ ++#define GPHY_CTRL_PHY_IDDQ BIT(7) /* bit8 affect bit7 while rb */ ++#define GPHY_CTRL_LPW_EXIT BIT(6) ++#define GPHY_CTRL_GATE_25M_EN BIT(5) ++#define GPHY_CTRL_REV_ANEG BIT(4) ++#define GPHY_CTRL_ANEG_NOW BIT(3) ++#define GPHY_CTRL_LED_MODE BIT(2) ++#define GPHY_CTRL_RTL_MODE BIT(1) ++#define GPHY_CTRL_EXT_RESET BIT(0) /* 1:out of DSP RST status */ ++#define GPHY_CTRL_EXT_RST_TO 80 /* 800us atmost */ ++#define GPHY_CTRL_CLS (\ ++ GPHY_CTRL_LED_MODE |\ ++ GPHY_CTRL_100AB_EN |\ ++ GPHY_CTRL_PHY_PLL_ON) ++ + /* Block IDLE Status Register */ +-#define REG_IDLE_STATUS 0x1410 +-#define IDLE_STATUS_MASK 0x00FF +-#define IDLE_STATUS_RXMAC_NO_IDLE 0x1 +-#define IDLE_STATUS_TXMAC_NO_IDLE 0x2 +-#define IDLE_STATUS_RXQ_NO_IDLE 0x4 +-#define IDLE_STATUS_TXQ_NO_IDLE 0x8 +-#define IDLE_STATUS_DMAR_NO_IDLE 0x10 +-#define IDLE_STATUS_DMAW_NO_IDLE 0x20 +-#define IDLE_STATUS_SMB_NO_IDLE 0x40 +-#define IDLE_STATUS_CMB_NO_IDLE 0x80 ++#define REG_IDLE_STATUS 0x1410 ++#define IDLE_STATUS_SFORCE_MASK 0xFUL ++#define IDLE_STATUS_SFORCE_SHIFT 14 ++#define IDLE_STATUS_CALIB_DONE BIT(13) ++#define IDLE_STATUS_CALIB_RES_MASK 0x1FUL ++#define IDLE_STATUS_CALIB_RES_SHIFT 8 ++#define IDLE_STATUS_CALIBERR_MASK 0xFUL ++#define IDLE_STATUS_CALIBERR_SHIFT 4 ++#define IDLE_STATUS_TXQ_BUSY BIT(3) ++#define IDLE_STATUS_RXQ_BUSY BIT(2) ++#define IDLE_STATUS_TXMAC_BUSY BIT(1) ++#define IDLE_STATUS_RXMAC_BUSY BIT(0) ++#define IDLE_STATUS_MASK (\ ++ IDLE_STATUS_TXQ_BUSY |\ ++ IDLE_STATUS_RXQ_BUSY |\ ++ IDLE_STATUS_TXMAC_BUSY |\ ++ IDLE_STATUS_RXMAC_BUSY) + + /* MDIO Control Register */ + #define REG_MDIO_CTRL 0x1414 +-#define MDIO_DATA_MASK 0xffff /* On MDIO write, the 16-bit +- * control data to write to PHY +- * MII management register */ +-#define MDIO_DATA_SHIFT 0 /* On MDIO read, the 16-bit +- * status data that was read +- * from the PHY MII management register */ +-#define MDIO_REG_ADDR_MASK 0x1f /* MDIO register address */ +-#define MDIO_REG_ADDR_SHIFT 16 +-#define MDIO_RW 0x200000 /* 1: read, 0: write */ +-#define MDIO_SUP_PREAMBLE 0x400000 /* Suppress preamble */ +-#define MDIO_START 0x800000 /* Write 1 to initiate the MDIO +- * master. And this bit is self +- * cleared after one cycle */ +-#define MDIO_CLK_SEL_SHIFT 24 +-#define MDIO_CLK_25_4 0 +-#define MDIO_CLK_25_6 2 +-#define MDIO_CLK_25_8 3 +-#define MDIO_CLK_25_10 4 +-#define MDIO_CLK_25_14 5 +-#define MDIO_CLK_25_20 6 +-#define MDIO_CLK_25_28 7 +-#define MDIO_BUSY 0x8000000 +-#define MDIO_AP_EN 0x10000000 +-#define MDIO_WAIT_TIMES 10 +- +-/* MII PHY Status Register */ +-#define REG_PHY_STATUS 0x1418 +-#define PHY_GENERAL_STATUS_MASK 0xFFFF +-#define PHY_STATUS_RECV_ENABLE 0x0001 +-#define PHY_OE_PWSP_STATUS_MASK 0x07FF +-#define PHY_OE_PWSP_STATUS_SHIFT 16 +-#define PHY_STATUS_LPW_STATE 0x80000000 ++#define MDIO_CTRL_MODE_EXT BIT(30) ++#define MDIO_CTRL_POST_READ BIT(29) ++#define MDIO_CTRL_AP_EN BIT(28) ++#define MDIO_CTRL_BUSY BIT(27) ++#define MDIO_CTRL_CLK_SEL_MASK 0x7UL ++#define MDIO_CTRL_CLK_SEL_SHIFT 24 ++#define MDIO_CTRL_CLK_25_4 0 /* 25MHz divide 4 */ ++#define MDIO_CTRL_CLK_25_6 2 ++#define MDIO_CTRL_CLK_25_8 3 ++#define MDIO_CTRL_CLK_25_10 4 ++#define MDIO_CTRL_CLK_25_32 5 ++#define MDIO_CTRL_CLK_25_64 6 ++#define MDIO_CTRL_CLK_25_128 7 ++#define MDIO_CTRL_START BIT(23) ++#define MDIO_CTRL_SPRES_PRMBL BIT(22) ++#define MDIO_CTRL_OP_READ BIT(21) /* 1:read, 0:write */ ++#define MDIO_CTRL_REG_MASK 0x1FUL ++#define MDIO_CTRL_REG_SHIFT 16 ++#define MDIO_CTRL_DATA_MASK 0xFFFFUL ++#define MDIO_CTRL_DATA_SHIFT 0 ++#define MDIO_MAX_AC_TO 120 /* 1.2ms timeout for slow clk */ ++ ++/* for extension reg access */ ++#define REG_MDIO_EXTN 0x1448 ++#define MDIO_EXTN_PORTAD_MASK 0x1FUL ++#define MDIO_EXTN_PORTAD_SHIFT 21 ++#define MDIO_EXTN_DEVAD_MASK 0x1FUL ++#define MDIO_EXTN_DEVAD_SHIFT 16 ++#define MDIO_EXTN_REG_MASK 0xFFFFUL ++#define MDIO_EXTN_REG_SHIFT 0 ++ + /* BIST Control and Status Register0 (for the Packet Memory) */ + #define REG_BIST0_CTRL 0x141c + #define BIST0_NOW 0x1 +@@ -299,50 +325,81 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); + #define BIST1_FUSE_FLAG 0x4 + + /* SerDes Lock Detect Control and Status Register */ +-#define REG_SERDES_LOCK 0x1424 +-#define SERDES_LOCK_DETECT 0x1 /* SerDes lock detected. This signal +- * comes from Analog SerDes */ +-#define SERDES_LOCK_DETECT_EN 0x2 /* 1: Enable SerDes Lock detect function */ +-#define SERDES_LOCK_STS_SELFB_PLL_SHIFT 0xE +-#define SERDES_LOCK_STS_SELFB_PLL_MASK 0x3 +-#define SERDES_OVCLK_18_25 0x0 +-#define SERDES_OVCLK_12_18 0x1 +-#define SERDES_OVCLK_0_4 0x2 +-#define SERDES_OVCLK_4_12 0x3 +-#define SERDES_MAC_CLK_SLOWDOWN 0x20000 +-#define SERDES_PYH_CLK_SLOWDOWN 0x40000 ++#define REG_SERDES 0x1424 ++#define SERDES_PHY_CLK_SLOWDOWN BIT(18) ++#define SERDES_MAC_CLK_SLOWDOWN BIT(17) ++#define SERDES_SELFB_PLL_MASK 0x3UL ++#define SERDES_SELFB_PLL_SHIFT 14 ++#define SERDES_PHYCLK_SEL_GTX BIT(13) /* 1:gtx_clk, 0:25M */ ++#define SERDES_PCIECLK_SEL_SRDS BIT(12) /* 1:serdes,0:25M */ ++#define SERDES_BUFS_RX_EN BIT(11) ++#define SERDES_PD_RX BIT(10) ++#define SERDES_PLL_EN BIT(9) ++#define SERDES_EN BIT(8) ++#define SERDES_SELFB_PLL_SEL_CSR BIT(6) /* 0:state-machine,1:csr */ ++#define SERDES_SELFB_PLL_CSR_MASK 0x3UL ++#define SERDES_SELFB_PLL_CSR_SHIFT 4 ++#define SERDES_SELFB_PLL_CSR_4 3 /* 4-12% OV-CLK */ ++#define SERDES_SELFB_PLL_CSR_0 2 /* 0-4% OV-CLK */ ++#define SERDES_SELFB_PLL_CSR_12 1 /* 12-18% OV-CLK */ ++#define SERDES_SELFB_PLL_CSR_18 0 /* 18-25% OV-CLK */ ++#define SERDES_VCO_SLOW BIT(3) ++#define SERDES_VCO_FAST BIT(2) ++#define SERDES_LOCK_DETECT_EN BIT(1) ++#define SERDES_LOCK_DETECT BIT(0) ++ ++#define REG_LPI_DECISN_TIMER 0x143C ++#define L2CB_LPI_DESISN_TIMER 0x7D00 ++ ++#define REG_LPI_CTRL 0x1440 ++#define LPI_CTRL_CHK_DA BIT(31) ++#define LPI_CTRL_ENH_TO_MASK 0x1FFFUL ++#define LPI_CTRL_ENH_TO_SHIFT 12 ++#define LPI_CTRL_ENH_TH_MASK 0x1FUL ++#define LPI_CTRL_ENH_TH_SHIFT 6 ++#define LPI_CTRL_ENH_EN BIT(5) ++#define LPI_CTRL_CHK_RX BIT(4) ++#define LPI_CTRL_CHK_STATE BIT(3) ++#define LPI_CTRL_GMII BIT(2) ++#define LPI_CTRL_TO_PHY BIT(1) ++#define LPI_CTRL_EN BIT(0) ++ ++#define REG_LPI_WAIT 0x1444 ++#define LPI_WAIT_TIMER_MASK 0xFFFFUL ++#define LPI_WAIT_TIMER_SHIFT 0 + + /* MAC Control Register */ + #define REG_MAC_CTRL 0x1480 +-#define MAC_CTRL_TX_EN 0x1 +-#define MAC_CTRL_RX_EN 0x2 +-#define MAC_CTRL_TX_FLOW 0x4 +-#define MAC_CTRL_RX_FLOW 0x8 +-#define MAC_CTRL_LOOPBACK 0x10 +-#define MAC_CTRL_DUPLX 0x20 +-#define MAC_CTRL_ADD_CRC 0x40 +-#define MAC_CTRL_PAD 0x80 +-#define MAC_CTRL_LENCHK 0x100 +-#define MAC_CTRL_HUGE_EN 0x200 +-#define MAC_CTRL_PRMLEN_SHIFT 10 +-#define MAC_CTRL_PRMLEN_MASK 0xf +-#define MAC_CTRL_RMV_VLAN 0x4000 +-#define MAC_CTRL_PROMIS_EN 0x8000 +-#define MAC_CTRL_TX_PAUSE 0x10000 +-#define MAC_CTRL_SCNT 0x20000 +-#define MAC_CTRL_SRST_TX 0x40000 +-#define MAC_CTRL_TX_SIMURST 0x80000 +-#define MAC_CTRL_SPEED_SHIFT 20 +-#define MAC_CTRL_SPEED_MASK 0x3 +-#define MAC_CTRL_DBG_TX_BKPRESURE 0x400000 +-#define MAC_CTRL_TX_HUGE 0x800000 +-#define MAC_CTRL_RX_CHKSUM_EN 0x1000000 +-#define MAC_CTRL_MC_ALL_EN 0x2000000 +-#define MAC_CTRL_BC_EN 0x4000000 +-#define MAC_CTRL_DBG 0x8000000 +-#define MAC_CTRL_SINGLE_PAUSE_EN 0x10000000 +-#define MAC_CTRL_HASH_ALG_CRC32 0x20000000 +-#define MAC_CTRL_SPEED_MODE_SW 0x40000000 ++#define MAC_CTRL_SPEED_MODE_SW BIT(30) /* 0:phy,1:sw */ ++#define MAC_CTRL_HASH_ALG_CRC32 BIT(29) /* 1:legacy,0:lw_5b */ ++#define MAC_CTRL_SINGLE_PAUSE_EN BIT(28) ++#define MAC_CTRL_DBG BIT(27) ++#define MAC_CTRL_BC_EN BIT(26) ++#define MAC_CTRL_MC_ALL_EN BIT(25) ++#define MAC_CTRL_RX_CHKSUM_EN BIT(24) ++#define MAC_CTRL_TX_HUGE BIT(23) ++#define MAC_CTRL_DBG_TX_BKPRESURE BIT(22) ++#define MAC_CTRL_SPEED_MASK 3UL ++#define MAC_CTRL_SPEED_SHIFT 20 ++#define MAC_CTRL_SPEED_10_100 1 ++#define MAC_CTRL_SPEED_1000 2 ++#define MAC_CTRL_TX_SIMURST BIT(19) ++#define MAC_CTRL_SCNT BIT(17) ++#define MAC_CTRL_TX_PAUSE BIT(16) ++#define MAC_CTRL_PROMIS_EN BIT(15) ++#define MAC_CTRL_RMV_VLAN BIT(14) ++#define MAC_CTRL_PRMLEN_MASK 0xFUL ++#define MAC_CTRL_PRMLEN_SHIFT 10 ++#define MAC_CTRL_HUGE_EN BIT(9) ++#define MAC_CTRL_LENCHK BIT(8) ++#define MAC_CTRL_PAD BIT(7) ++#define MAC_CTRL_ADD_CRC BIT(6) ++#define MAC_CTRL_DUPLX BIT(5) ++#define MAC_CTRL_LOOPBACK BIT(4) ++#define MAC_CTRL_RX_FLOW BIT(3) ++#define MAC_CTRL_TX_FLOW BIT(2) ++#define MAC_CTRL_RX_EN BIT(1) ++#define MAC_CTRL_TX_EN BIT(0) + + /* MAC IPG/IFG Control Register */ + #define REG_MAC_IPG_IFG 0x1484 +@@ -386,34 +443,53 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); + + /* Wake-On-Lan control register */ + #define REG_WOL_CTRL 0x14a0 +-#define WOL_PATTERN_EN 0x00000001 +-#define WOL_PATTERN_PME_EN 0x00000002 +-#define WOL_MAGIC_EN 0x00000004 +-#define WOL_MAGIC_PME_EN 0x00000008 +-#define WOL_LINK_CHG_EN 0x00000010 +-#define WOL_LINK_CHG_PME_EN 0x00000020 +-#define WOL_PATTERN_ST 0x00000100 +-#define WOL_MAGIC_ST 0x00000200 +-#define WOL_LINKCHG_ST 0x00000400 +-#define WOL_CLK_SWITCH_EN 0x00008000 +-#define WOL_PT0_EN 0x00010000 +-#define WOL_PT1_EN 0x00020000 +-#define WOL_PT2_EN 0x00040000 +-#define WOL_PT3_EN 0x00080000 +-#define WOL_PT4_EN 0x00100000 +-#define WOL_PT5_EN 0x00200000 +-#define WOL_PT6_EN 0x00400000 ++#define WOL_PT7_MATCH BIT(31) ++#define WOL_PT6_MATCH BIT(30) ++#define WOL_PT5_MATCH BIT(29) ++#define WOL_PT4_MATCH BIT(28) ++#define WOL_PT3_MATCH BIT(27) ++#define WOL_PT2_MATCH BIT(26) ++#define WOL_PT1_MATCH BIT(25) ++#define WOL_PT0_MATCH BIT(24) ++#define WOL_PT7_EN BIT(23) ++#define WOL_PT6_EN BIT(22) ++#define WOL_PT5_EN BIT(21) ++#define WOL_PT4_EN BIT(20) ++#define WOL_PT3_EN BIT(19) ++#define WOL_PT2_EN BIT(18) ++#define WOL_PT1_EN BIT(17) ++#define WOL_PT0_EN BIT(16) ++#define WOL_LNKCHG_ST BIT(10) ++#define WOL_MAGIC_ST BIT(9) ++#define WOL_PATTERN_ST BIT(8) ++#define WOL_OOB_EN BIT(6) ++#define WOL_LINK_CHG_PME_EN BIT(5) ++#define WOL_LINK_CHG_EN BIT(4) ++#define WOL_MAGIC_PME_EN BIT(3) ++#define WOL_MAGIC_EN BIT(2) ++#define WOL_PATTERN_PME_EN BIT(1) ++#define WOL_PATTERN_EN BIT(0) + + /* WOL Length ( 2 DWORD ) */ +-#define REG_WOL_PATTERN_LEN 0x14a4 +-#define WOL_PT_LEN_MASK 0x7f +-#define WOL_PT0_LEN_SHIFT 0 +-#define WOL_PT1_LEN_SHIFT 8 +-#define WOL_PT2_LEN_SHIFT 16 +-#define WOL_PT3_LEN_SHIFT 24 +-#define WOL_PT4_LEN_SHIFT 0 +-#define WOL_PT5_LEN_SHIFT 8 +-#define WOL_PT6_LEN_SHIFT 16 ++#define REG_WOL_PTLEN1 0x14A4 ++#define WOL_PTLEN1_3_MASK 0xFFUL ++#define WOL_PTLEN1_3_SHIFT 24 ++#define WOL_PTLEN1_2_MASK 0xFFUL ++#define WOL_PTLEN1_2_SHIFT 16 ++#define WOL_PTLEN1_1_MASK 0xFFUL ++#define WOL_PTLEN1_1_SHIFT 8 ++#define WOL_PTLEN1_0_MASK 0xFFUL ++#define WOL_PTLEN1_0_SHIFT 0 ++ ++#define REG_WOL_PTLEN2 0x14A8 ++#define WOL_PTLEN2_7_MASK 0xFFUL ++#define WOL_PTLEN2_7_SHIFT 24 ++#define WOL_PTLEN2_6_MASK 0xFFUL ++#define WOL_PTLEN2_6_SHIFT 16 ++#define WOL_PTLEN2_5_MASK 0xFFUL ++#define WOL_PTLEN2_5_SHIFT 8 ++#define WOL_PTLEN2_4_MASK 0xFFUL ++#define WOL_PTLEN2_4_SHIFT 0 + + /* Internal SRAM Partition Register */ + #define RFDX_HEAD_ADDR_MASK 0x03FF +@@ -458,66 +534,50 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); + */ + #define REG_RX_BASE_ADDR_HI 0x1540 + #define REG_TX_BASE_ADDR_HI 0x1544 +-#define REG_SMB_BASE_ADDR_HI 0x1548 +-#define REG_SMB_BASE_ADDR_LO 0x154C + #define REG_RFD0_HEAD_ADDR_LO 0x1550 +-#define REG_RFD1_HEAD_ADDR_LO 0x1554 +-#define REG_RFD2_HEAD_ADDR_LO 0x1558 +-#define REG_RFD3_HEAD_ADDR_LO 0x155C + #define REG_RFD_RING_SIZE 0x1560 + #define RFD_RING_SIZE_MASK 0x0FFF + #define REG_RX_BUF_SIZE 0x1564 + #define RX_BUF_SIZE_MASK 0xFFFF + #define REG_RRD0_HEAD_ADDR_LO 0x1568 +-#define REG_RRD1_HEAD_ADDR_LO 0x156C +-#define REG_RRD2_HEAD_ADDR_LO 0x1570 +-#define REG_RRD3_HEAD_ADDR_LO 0x1574 + #define REG_RRD_RING_SIZE 0x1578 + #define RRD_RING_SIZE_MASK 0x0FFF +-#define REG_HTPD_HEAD_ADDR_LO 0x157C +-#define REG_NTPD_HEAD_ADDR_LO 0x1580 ++#define REG_TPD_PRI1_ADDR_LO 0x157C ++#define REG_TPD_PRI0_ADDR_LO 0x1580 + #define REG_TPD_RING_SIZE 0x1584 + #define TPD_RING_SIZE_MASK 0xFFFF +-#define REG_CMB_BASE_ADDR_LO 0x1588 +- +-/* RSS about */ +-#define REG_RSS_KEY0 0x14B0 +-#define REG_RSS_KEY1 0x14B4 +-#define REG_RSS_KEY2 0x14B8 +-#define REG_RSS_KEY3 0x14BC +-#define REG_RSS_KEY4 0x14C0 +-#define REG_RSS_KEY5 0x14C4 +-#define REG_RSS_KEY6 0x14C8 +-#define REG_RSS_KEY7 0x14CC +-#define REG_RSS_KEY8 0x14D0 +-#define REG_RSS_KEY9 0x14D4 +-#define REG_IDT_TABLE0 0x14E0 +-#define REG_IDT_TABLE1 0x14E4 +-#define REG_IDT_TABLE2 0x14E8 +-#define REG_IDT_TABLE3 0x14EC +-#define REG_IDT_TABLE4 0x14F0 +-#define REG_IDT_TABLE5 0x14F4 +-#define REG_IDT_TABLE6 0x14F8 +-#define REG_IDT_TABLE7 0x14FC +-#define REG_IDT_TABLE REG_IDT_TABLE0 +-#define REG_RSS_HASH_VALUE 0x15B0 +-#define REG_RSS_HASH_FLAG 0x15B4 +-#define REG_BASE_CPU_NUMBER 0x15B8 + + /* TXQ Control Register */ +-#define REG_TXQ_CTRL 0x1590 +-#define TXQ_NUM_TPD_BURST_MASK 0xF +-#define TXQ_NUM_TPD_BURST_SHIFT 0 +-#define TXQ_CTRL_IP_OPTION_EN 0x10 +-#define TXQ_CTRL_EN 0x20 +-#define TXQ_CTRL_ENH_MODE 0x40 +-#define TXQ_CTRL_LS_8023_EN 0x80 +-#define TXQ_TXF_BURST_NUM_SHIFT 16 +-#define TXQ_TXF_BURST_NUM_MASK 0xFFFF ++#define REG_TXQ_CTRL 0x1590 ++#define TXQ_TXF_BURST_NUM_MASK 0xFFFFUL ++#define TXQ_TXF_BURST_NUM_SHIFT 16 ++#define L1C_TXQ_TXF_BURST_PREF 0x200 ++#define L2CB_TXQ_TXF_BURST_PREF 0x40 ++#define TXQ_CTRL_PEDING_CLR BIT(8) ++#define TXQ_CTRL_LS_8023_EN BIT(7) ++#define TXQ_CTRL_ENH_MODE BIT(6) ++#define TXQ_CTRL_EN BIT(5) ++#define TXQ_CTRL_IP_OPTION_EN BIT(4) ++#define TXQ_NUM_TPD_BURST_MASK 0xFUL ++#define TXQ_NUM_TPD_BURST_SHIFT 0 ++#define TXQ_NUM_TPD_BURST_DEF 5 ++#define TXQ_CFGV (\ ++ FIELDX(TXQ_NUM_TPD_BURST, TXQ_NUM_TPD_BURST_DEF) |\ ++ TXQ_CTRL_ENH_MODE |\ ++ TXQ_CTRL_LS_8023_EN |\ ++ TXQ_CTRL_IP_OPTION_EN) ++#define L1C_TXQ_CFGV (\ ++ TXQ_CFGV |\ ++ FIELDX(TXQ_TXF_BURST_NUM, L1C_TXQ_TXF_BURST_PREF)) ++#define L2CB_TXQ_CFGV (\ ++ TXQ_CFGV |\ ++ FIELDX(TXQ_TXF_BURST_NUM, L2CB_TXQ_TXF_BURST_PREF)) ++ + + /* Jumbo packet Threshold for task offload */ + #define REG_TX_TSO_OFFLOAD_THRESH 0x1594 /* In 8-bytes */ + #define TX_TSO_OFFLOAD_THRESH_MASK 0x07FF ++#define MAX_TSO_FRAME_SIZE (7*1024) + + #define REG_TXF_WATER_MARK 0x1598 /* In 8-bytes */ + #define TXF_WATER_MARK_MASK 0x0FFF +@@ -537,26 +597,21 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); + #define ASPM_THRUPUT_LIMIT_NO 0x00 + #define ASPM_THRUPUT_LIMIT_1M 0x01 + #define ASPM_THRUPUT_LIMIT_10M 0x02 +-#define ASPM_THRUPUT_LIMIT_100M 0x04 +-#define RXQ1_CTRL_EN 0x10 +-#define RXQ2_CTRL_EN 0x20 +-#define RXQ3_CTRL_EN 0x40 +-#define IPV6_CHKSUM_CTRL_EN 0x80 +-#define RSS_HASH_BITS_MASK 0x00FF +-#define RSS_HASH_BITS_SHIFT 8 +-#define RSS_HASH_IPV4 0x10000 +-#define RSS_HASH_IPV4_TCP 0x20000 +-#define RSS_HASH_IPV6 0x40000 +-#define RSS_HASH_IPV6_TCP 0x80000 ++#define ASPM_THRUPUT_LIMIT_100M 0x03 ++#define IPV6_CHKSUM_CTRL_EN BIT(7) + #define RXQ_RFD_BURST_NUM_MASK 0x003F + #define RXQ_RFD_BURST_NUM_SHIFT 20 +-#define RSS_MODE_MASK 0x0003 ++#define RXQ_NUM_RFD_PREF_DEF 8 ++#define RSS_MODE_MASK 3UL + #define RSS_MODE_SHIFT 26 +-#define RSS_NIP_QUEUE_SEL_MASK 0x1 +-#define RSS_NIP_QUEUE_SEL_SHIFT 28 +-#define RRS_HASH_CTRL_EN 0x20000000 +-#define RX_CUT_THRU_EN 0x40000000 +-#define RXQ_CTRL_EN 0x80000000 ++#define RSS_MODE_DIS 0 ++#define RSS_MODE_SQSI 1 ++#define RSS_MODE_MQSI 2 ++#define RSS_MODE_MQMI 3 ++#define RSS_NIP_QUEUE_SEL BIT(28) /* 0:q0, 1:table */ ++#define RRS_HASH_CTRL_EN BIT(29) ++#define RX_CUT_THRU_EN BIT(30) ++#define RXQ_CTRL_EN BIT(31) + + #define REG_RFD_FREE_THRESH 0x15A4 + #define RFD_FREE_THRESH_MASK 0x003F +@@ -577,57 +632,45 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); + #define RXD_DMA_DOWN_TIMER_SHIFT 16 + + /* DMA Engine Control Register */ +-#define REG_DMA_CTRL 0x15C0 +-#define DMA_CTRL_DMAR_IN_ORDER 0x1 +-#define DMA_CTRL_DMAR_ENH_ORDER 0x2 +-#define DMA_CTRL_DMAR_OUT_ORDER 0x4 +-#define DMA_CTRL_RCB_VALUE 0x8 +-#define DMA_CTRL_DMAR_BURST_LEN_MASK 0x0007 +-#define DMA_CTRL_DMAR_BURST_LEN_SHIFT 4 +-#define DMA_CTRL_DMAW_BURST_LEN_MASK 0x0007 +-#define DMA_CTRL_DMAW_BURST_LEN_SHIFT 7 +-#define DMA_CTRL_DMAR_REQ_PRI 0x400 +-#define DMA_CTRL_DMAR_DLY_CNT_MASK 0x001F +-#define DMA_CTRL_DMAR_DLY_CNT_SHIFT 11 +-#define DMA_CTRL_DMAW_DLY_CNT_MASK 0x000F +-#define DMA_CTRL_DMAW_DLY_CNT_SHIFT 16 +-#define DMA_CTRL_CMB_EN 0x100000 +-#define DMA_CTRL_SMB_EN 0x200000 +-#define DMA_CTRL_CMB_NOW 0x400000 +-#define MAC_CTRL_SMB_DIS 0x1000000 +-#define DMA_CTRL_SMB_NOW 0x80000000 +- +-/* CMB/SMB Control Register */ ++#define REG_DMA_CTRL 0x15C0 ++#define DMA_CTRL_SMB_NOW BIT(31) ++#define DMA_CTRL_WPEND_CLR BIT(30) ++#define DMA_CTRL_RPEND_CLR BIT(29) ++#define DMA_CTRL_WDLY_CNT_MASK 0xFUL ++#define DMA_CTRL_WDLY_CNT_SHIFT 16 ++#define DMA_CTRL_WDLY_CNT_DEF 4 ++#define DMA_CTRL_RDLY_CNT_MASK 0x1FUL ++#define DMA_CTRL_RDLY_CNT_SHIFT 11 ++#define DMA_CTRL_RDLY_CNT_DEF 15 ++#define DMA_CTRL_RREQ_PRI_DATA BIT(10) /* 0:tpd, 1:data */ ++#define DMA_CTRL_WREQ_BLEN_MASK 7UL ++#define DMA_CTRL_WREQ_BLEN_SHIFT 7 ++#define DMA_CTRL_RREQ_BLEN_MASK 7UL ++#define DMA_CTRL_RREQ_BLEN_SHIFT 4 ++#define L1C_CTRL_DMA_RCB_LEN128 BIT(3) /* 0:64bytes,1:128bytes */ ++#define DMA_CTRL_RORDER_MODE_MASK 7UL ++#define DMA_CTRL_RORDER_MODE_SHIFT 0 ++#define DMA_CTRL_RORDER_MODE_OUT 4 ++#define DMA_CTRL_RORDER_MODE_ENHANCE 2 ++#define DMA_CTRL_RORDER_MODE_IN 1 ++ ++/* INT-triggle/SMB Control Register */ + #define REG_SMB_STAT_TIMER 0x15C4 /* 2us resolution */ + #define SMB_STAT_TIMER_MASK 0xFFFFFF +-#define REG_CMB_TPD_THRESH 0x15C8 +-#define CMB_TPD_THRESH_MASK 0xFFFF +-#define REG_CMB_TX_TIMER 0x15CC /* 2us resolution */ +-#define CMB_TX_TIMER_MASK 0xFFFF ++#define REG_TINT_TPD_THRESH 0x15C8 /* tpd th to trig intrrupt */ + + /* Mail box */ + #define MB_RFDX_PROD_IDX_MASK 0xFFFF + #define REG_MB_RFD0_PROD_IDX 0x15E0 +-#define REG_MB_RFD1_PROD_IDX 0x15E4 +-#define REG_MB_RFD2_PROD_IDX 0x15E8 +-#define REG_MB_RFD3_PROD_IDX 0x15EC + +-#define MB_PRIO_PROD_IDX_MASK 0xFFFF +-#define REG_MB_PRIO_PROD_IDX 0x15F0 +-#define MB_HTPD_PROD_IDX_SHIFT 0 +-#define MB_NTPD_PROD_IDX_SHIFT 16 +- +-#define MB_PRIO_CONS_IDX_MASK 0xFFFF +-#define REG_MB_PRIO_CONS_IDX 0x15F4 +-#define MB_HTPD_CONS_IDX_SHIFT 0 +-#define MB_NTPD_CONS_IDX_SHIFT 16 ++#define REG_TPD_PRI1_PIDX 0x15F0 /* 16bit,hi-tpd producer idx */ ++#define REG_TPD_PRI0_PIDX 0x15F2 /* 16bit,lo-tpd producer idx */ ++#define REG_TPD_PRI1_CIDX 0x15F4 /* 16bit,hi-tpd consumer idx */ ++#define REG_TPD_PRI0_CIDX 0x15F6 /* 16bit,lo-tpd consumer idx */ + + #define REG_MB_RFD01_CONS_IDX 0x15F8 + #define MB_RFD0_CONS_IDX_MASK 0x0000FFFF + #define MB_RFD1_CONS_IDX_MASK 0xFFFF0000 +-#define REG_MB_RFD23_CONS_IDX 0x15FC +-#define MB_RFD2_CONS_IDX_MASK 0x0000FFFF +-#define MB_RFD3_CONS_IDX_MASK 0xFFFF0000 + + /* Interrupt Status Register */ + #define REG_ISR 0x1600 +@@ -705,13 +748,6 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); + #define REG_INT_RETRIG_TIMER 0x1608 + #define INT_RETRIG_TIMER_MASK 0xFFFF + +-#define REG_HDS_CTRL 0x160C +-#define HDS_CTRL_EN 0x0001 +-#define HDS_CTRL_BACKFILLSIZE_SHIFT 8 +-#define HDS_CTRL_BACKFILLSIZE_MASK 0x0FFF +-#define HDS_CTRL_MAX_HDRSIZE_SHIFT 20 +-#define HDS_CTRL_MAC_HDRSIZE_MASK 0x0FFF +- + #define REG_MAC_RX_STATUS_BIN 0x1700 + #define REG_MAC_RX_STATUS_END 0x175c + #define REG_MAC_TX_STATUS_BIN 0x1760 +@@ -796,73 +832,188 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); + #define MII_DBG_ADDR 0x1D + #define MII_DBG_DATA 0x1E + +-#define MII_ANA_CTRL_0 0x0 +-#define ANA_RESTART_CAL 0x0001 +-#define ANA_MANUL_SWICH_ON_SHIFT 0x1 +-#define ANA_MANUL_SWICH_ON_MASK 0xF +-#define ANA_MAN_ENABLE 0x0020 +-#define ANA_SEL_HSP 0x0040 +-#define ANA_EN_HB 0x0080 +-#define ANA_EN_HBIAS 0x0100 +-#define ANA_OEN_125M 0x0200 +-#define ANA_EN_LCKDT 0x0400 +-#define ANA_LCKDT_PHY 0x0800 +-#define ANA_AFE_MODE 0x1000 +-#define ANA_VCO_SLOW 0x2000 +-#define ANA_VCO_FAST 0x4000 +-#define ANA_SEL_CLK125M_DSP 0x8000 +- +-#define MII_ANA_CTRL_4 0x4 +-#define ANA_IECHO_ADJ_MASK 0xF +-#define ANA_IECHO_ADJ_3_SHIFT 0 +-#define ANA_IECHO_ADJ_2_SHIFT 4 +-#define ANA_IECHO_ADJ_1_SHIFT 8 +-#define ANA_IECHO_ADJ_0_SHIFT 12 +- +-#define MII_ANA_CTRL_5 0x5 +-#define ANA_SERDES_CDR_BW_SHIFT 0 +-#define ANA_SERDES_CDR_BW_MASK 0x3 +-#define ANA_MS_PAD_DBG 0x0004 +-#define ANA_SPEEDUP_DBG 0x0008 +-#define ANA_SERDES_TH_LOS_SHIFT 4 +-#define ANA_SERDES_TH_LOS_MASK 0x3 +-#define ANA_SERDES_EN_DEEM 0x0040 +-#define ANA_SERDES_TXELECIDLE 0x0080 +-#define ANA_SERDES_BEACON 0x0100 +-#define ANA_SERDES_HALFTXDR 0x0200 +-#define ANA_SERDES_SEL_HSP 0x0400 +-#define ANA_SERDES_EN_PLL 0x0800 +-#define ANA_SERDES_EN 0x1000 +-#define ANA_SERDES_EN_LCKDT 0x2000 +- +-#define MII_ANA_CTRL_11 0xB +-#define ANA_PS_HIB_EN 0x8000 +- +-#define MII_ANA_CTRL_18 0x12 +-#define ANA_TEST_MODE_10BT_01SHIFT 0 +-#define ANA_TEST_MODE_10BT_01MASK 0x3 +-#define ANA_LOOP_SEL_10BT 0x0004 +-#define ANA_RGMII_MODE_SW 0x0008 +-#define ANA_EN_LONGECABLE 0x0010 +-#define ANA_TEST_MODE_10BT_2 0x0020 +-#define ANA_EN_10BT_IDLE 0x0400 +-#define ANA_EN_MASK_TB 0x0800 +-#define ANA_TRIGGER_SEL_TIMER_SHIFT 12 +-#define ANA_TRIGGER_SEL_TIMER_MASK 0x3 +-#define ANA_INTERVAL_SEL_TIMER_SHIFT 14 +-#define ANA_INTERVAL_SEL_TIMER_MASK 0x3 +- +-#define MII_ANA_CTRL_41 0x29 +-#define ANA_TOP_PS_EN 0x8000 +- +-#define MII_ANA_CTRL_54 0x36 +-#define ANA_LONG_CABLE_TH_100_SHIFT 0 +-#define ANA_LONG_CABLE_TH_100_MASK 0x3F +-#define ANA_DESERVED 0x0040 +-#define ANA_EN_LIT_CH 0x0080 +-#define ANA_SHORT_CABLE_TH_100_SHIFT 8 +-#define ANA_SHORT_CABLE_TH_100_MASK 0x3F +-#define ANA_BP_BAD_LINK_ACCUM 0x4000 +-#define ANA_BP_SMALL_BW 0x8000 ++/***************************** debug port *************************************/ ++ ++#define MIIDBG_ANACTRL 0x00 ++#define ANACTRL_CLK125M_DELAY_EN 0x8000 ++#define ANACTRL_VCO_FAST 0x4000 ++#define ANACTRL_VCO_SLOW 0x2000 ++#define ANACTRL_AFE_MODE_EN 0x1000 ++#define ANACTRL_LCKDET_PHY 0x800 ++#define ANACTRL_LCKDET_EN 0x400 ++#define ANACTRL_OEN_125M 0x200 ++#define ANACTRL_HBIAS_EN 0x100 ++#define ANACTRL_HB_EN 0x80 ++#define ANACTRL_SEL_HSP 0x40 ++#define ANACTRL_CLASSA_EN 0x20 ++#define ANACTRL_MANUSWON_SWR_MASK 3U ++#define ANACTRL_MANUSWON_SWR_SHIFT 2 ++#define ANACTRL_MANUSWON_SWR_2V 0 ++#define ANACTRL_MANUSWON_SWR_1P9V 1 ++#define ANACTRL_MANUSWON_SWR_1P8V 2 ++#define ANACTRL_MANUSWON_SWR_1P7V 3 ++#define ANACTRL_MANUSWON_BW3_4M 0x2 ++#define ANACTRL_RESTART_CAL 0x1 ++#define ANACTRL_DEF 0x02EF ++ ++#define MIIDBG_SYSMODCTRL 0x04 ++#define SYSMODCTRL_IECHOADJ_PFMH_PHY 0x8000 ++#define SYSMODCTRL_IECHOADJ_BIASGEN 0x4000 ++#define SYSMODCTRL_IECHOADJ_PFML_PHY 0x2000 ++#define SYSMODCTRL_IECHOADJ_PS_MASK 3U ++#define SYSMODCTRL_IECHOADJ_PS_SHIFT 10 ++#define SYSMODCTRL_IECHOADJ_PS_40 3 ++#define SYSMODCTRL_IECHOADJ_PS_20 2 ++#define SYSMODCTRL_IECHOADJ_PS_0 1 ++#define SYSMODCTRL_IECHOADJ_10BT_100MV 0x40 /* 1:100mv, 0:200mv */ ++#define SYSMODCTRL_IECHOADJ_HLFAP_MASK 3U ++#define SYSMODCTRL_IECHOADJ_HLFAP_SHIFT 4 ++#define SYSMODCTRL_IECHOADJ_VDFULBW 0x8 ++#define SYSMODCTRL_IECHOADJ_VDBIASHLF 0x4 ++#define SYSMODCTRL_IECHOADJ_VDAMPHLF 0x2 ++#define SYSMODCTRL_IECHOADJ_VDLANSW 0x1 ++#define SYSMODCTRL_IECHOADJ_DEF 0x88BB /* ???? */ ++ ++/* for l1d & l2cb */ ++#define SYSMODCTRL_IECHOADJ_CUR_ADD 0x8000 ++#define SYSMODCTRL_IECHOADJ_CUR_MASK 7U ++#define SYSMODCTRL_IECHOADJ_CUR_SHIFT 12 ++#define SYSMODCTRL_IECHOADJ_VOL_MASK 0xFU ++#define SYSMODCTRL_IECHOADJ_VOL_SHIFT 8 ++#define SYSMODCTRL_IECHOADJ_VOL_17ALL 3 ++#define SYSMODCTRL_IECHOADJ_VOL_100M15 1 ++#define SYSMODCTRL_IECHOADJ_VOL_10M17 0 ++#define SYSMODCTRL_IECHOADJ_BIAS1_MASK 0xFU ++#define SYSMODCTRL_IECHOADJ_BIAS1_SHIFT 4 ++#define SYSMODCTRL_IECHOADJ_BIAS2_MASK 0xFU ++#define SYSMODCTRL_IECHOADJ_BIAS2_SHIFT 0 ++#define L1D_SYSMODCTRL_IECHOADJ_DEF 0x4FBB ++ ++#define MIIDBG_SRDSYSMOD 0x05 ++#define SRDSYSMOD_LCKDET_EN 0x2000 ++#define SRDSYSMOD_PLL_EN 0x800 ++#define SRDSYSMOD_SEL_HSP 0x400 ++#define SRDSYSMOD_HLFTXDR 0x200 ++#define SRDSYSMOD_TXCLK_DELAY_EN 0x100 ++#define SRDSYSMOD_TXELECIDLE 0x80 ++#define SRDSYSMOD_DEEMP_EN 0x40 ++#define SRDSYSMOD_MS_PAD 0x4 ++#define SRDSYSMOD_CDR_ADC_VLTG 0x2 ++#define SRDSYSMOD_CDR_DAC_1MA 0x1 ++#define SRDSYSMOD_DEF 0x2C46 ++ ++#define MIIDBG_CFGLPSPD 0x0A ++#define CFGLPSPD_RSTCNT_MASK 3U ++#define CFGLPSPD_RSTCNT_SHIFT 14 ++#define CFGLPSPD_RSTCNT_CLK125SW 0x2000 ++ ++#define MIIDBG_HIBNEG 0x0B ++#define HIBNEG_PSHIB_EN 0x8000 ++#define HIBNEG_WAKE_BOTH 0x4000 ++#define HIBNEG_ONOFF_ANACHG_SUDEN 0x2000 ++#define HIBNEG_HIB_PULSE 0x1000 ++#define HIBNEG_GATE_25M_EN 0x800 ++#define HIBNEG_RST_80U 0x400 ++#define HIBNEG_RST_TIMER_MASK 3U ++#define HIBNEG_RST_TIMER_SHIFT 8 ++#define HIBNEG_GTX_CLK_DELAY_MASK 3U ++#define HIBNEG_GTX_CLK_DELAY_SHIFT 5 ++#define HIBNEG_BYPSS_BRKTIMER 0x10 ++#define HIBNEG_DEF 0xBC40 ++ ++#define MIIDBG_TST10BTCFG 0x12 ++#define TST10BTCFG_INTV_TIMER_MASK 3U ++#define TST10BTCFG_INTV_TIMER_SHIFT 14 ++#define TST10BTCFG_TRIGER_TIMER_MASK 3U ++#define TST10BTCFG_TRIGER_TIMER_SHIFT 12 ++#define TST10BTCFG_DIV_MAN_MLT3_EN 0x800 ++#define TST10BTCFG_OFF_DAC_IDLE 0x400 ++#define TST10BTCFG_LPBK_DEEP 0x4 /* 1:deep,0:shallow */ ++#define TST10BTCFG_DEF 0x4C04 ++ ++#define MIIDBG_AZ_ANADECT 0x15 ++#define AZ_ANADECT_10BTRX_TH 0x8000 ++#define AZ_ANADECT_BOTH_01CHNL 0x4000 ++#define AZ_ANADECT_INTV_MASK 0x3FU ++#define AZ_ANADECT_INTV_SHIFT 8 ++#define AZ_ANADECT_THRESH_MASK 0xFU ++#define AZ_ANADECT_THRESH_SHIFT 4 ++#define AZ_ANADECT_CHNL_MASK 0xFU ++#define AZ_ANADECT_CHNL_SHIFT 0 ++#define AZ_ANADECT_DEF 0x3220 ++#define AZ_ANADECT_LONG 0xb210 ++ ++#define MIIDBG_MSE16DB 0x18 /* l1d */ ++#define L1D_MSE16DB_UP 0x05EA ++#define L1D_MSE16DB_DOWN 0x02EA ++ ++#define MIIDBG_LEGCYPS 0x29 ++#define LEGCYPS_EN 0x8000 ++#define LEGCYPS_DAC_AMP1000_MASK 7U ++#define LEGCYPS_DAC_AMP1000_SHIFT 12 ++#define LEGCYPS_DAC_AMP100_MASK 7U ++#define LEGCYPS_DAC_AMP100_SHIFT 9 ++#define LEGCYPS_DAC_AMP10_MASK 7U ++#define LEGCYPS_DAC_AMP10_SHIFT 6 ++#define LEGCYPS_UNPLUG_TIMER_MASK 7U ++#define LEGCYPS_UNPLUG_TIMER_SHIFT 3 ++#define LEGCYPS_UNPLUG_DECT_EN 0x4 ++#define LEGCYPS_ECNC_PS_EN 0x1 ++#define L1D_LEGCYPS_DEF 0x129D ++#define L1C_LEGCYPS_DEF 0x36DD ++ ++#define MIIDBG_TST100BTCFG 0x36 ++#define TST100BTCFG_NORMAL_BW_EN 0x8000 ++#define TST100BTCFG_BADLNK_BYPASS 0x4000 ++#define TST100BTCFG_SHORTCABL_TH_MASK 0x3FU ++#define TST100BTCFG_SHORTCABL_TH_SHIFT 8 ++#define TST100BTCFG_LITCH_EN 0x80 ++#define TST100BTCFG_VLT_SW 0x40 ++#define TST100BTCFG_LONGCABL_TH_MASK 0x3FU ++#define TST100BTCFG_LONGCABL_TH_SHIFT 0 ++#define TST100BTCFG_DEF 0xE12C ++ ++#define MIIDBG_VOLT_CTRL 0x3B /* only for l2cb 1 & 2 */ ++#define VOLT_CTRL_CABLE1TH_MASK 0x1FFU ++#define VOLT_CTRL_CABLE1TH_SHIFT 7 ++#define VOLT_CTRL_AMPCTRL_MASK 3U ++#define VOLT_CTRL_AMPCTRL_SHIFT 5 ++#define VOLT_CTRL_SW_BYPASS 0x10 ++#define VOLT_CTRL_SWLOWEST 0x8 ++#define VOLT_CTRL_DACAMP10_MASK 7U ++#define VOLT_CTRL_DACAMP10_SHIFT 0 ++ ++#define MIIDBG_CABLE1TH_DET 0x3E ++#define CABLE1TH_DET_EN 0x8000 ++ ++ ++/******* dev 3 *********/ ++#define MIIEXT_PCS 3 ++ ++#define MIIEXT_CLDCTRL3 0x8003 ++#define CLDCTRL3_BP_CABLE1TH_DET_GT 0x8000 ++#define CLDCTRL3_AZ_DISAMP 0x1000 ++#define L2CB_CLDCTRL3 0x4D19 ++#define L1D_CLDCTRL3 0xDD19 ++ ++#define MIIEXT_CLDCTRL6 0x8006 ++#define CLDCTRL6_CAB_LEN_MASK 0x1FFU ++#define CLDCTRL6_CAB_LEN_SHIFT 0 ++#define CLDCTRL6_CAB_LEN_SHORT 0x50 ++ ++/********* dev 7 **********/ ++#define MIIEXT_ANEG 7 ++ ++#define MIIEXT_LOCAL_EEEADV 0x3C ++#define LOCAL_EEEADV_1000BT 0x4 ++#define LOCAL_EEEADV_100BT 0x2 ++ ++#define MIIEXT_REMOTE_EEEADV 0x3D ++#define REMOTE_EEEADV_1000BT 0x4 ++#define REMOTE_EEEADV_100BT 0x2 ++ ++#define MIIEXT_EEE_ANEG 0x8000 ++#define EEE_ANEG_1000M 0x4 ++#define EEE_ANEG_100M 0x2 + + #endif /*_ATL1C_HW_H_*/ +diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +index 47a9bb2..f6f3fe3 100644 +--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c ++++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +@@ -24,14 +24,6 @@ + #define ATL1C_DRV_VERSION "1.0.1.0-NAPI" + char atl1c_driver_name[] = "atl1c"; + char atl1c_driver_version[] = ATL1C_DRV_VERSION; +-#define PCI_DEVICE_ID_ATTANSIC_L2C 0x1062 +-#define PCI_DEVICE_ID_ATTANSIC_L1C 0x1063 +-#define PCI_DEVICE_ID_ATHEROS_L2C_B 0x2060 /* AR8152 v1.1 Fast 10/100 */ +-#define PCI_DEVICE_ID_ATHEROS_L2C_B2 0x2062 /* AR8152 v2.0 Fast 10/100 */ +-#define PCI_DEVICE_ID_ATHEROS_L1D 0x1073 /* AR8151 v1.0 Gigabit 1000 */ +-#define PCI_DEVICE_ID_ATHEROS_L1D_2_0 0x1083 /* AR8151 v2.0 Gigabit 1000 */ +-#define L2CB_V10 0xc0 +-#define L2CB_V11 0xc1 + + /* + * atl1c_pci_tbl - PCI Device ID Table +@@ -54,70 +46,72 @@ static DEFINE_PCI_DEVICE_TABLE(atl1c_pci_tbl) = { + }; + MODULE_DEVICE_TABLE(pci, atl1c_pci_tbl); + +-MODULE_AUTHOR("Jie Yang "); +-MODULE_DESCRIPTION("Atheros 1000M Ethernet Network Driver"); ++MODULE_AUTHOR("Jie Yang"); ++MODULE_AUTHOR("Qualcomm Atheros Inc., "); ++MODULE_DESCRIPTION("Qualcom Atheros 100/1000M Ethernet Network Driver"); + MODULE_LICENSE("GPL"); + MODULE_VERSION(ATL1C_DRV_VERSION); + + static int atl1c_stop_mac(struct atl1c_hw *hw); +-static void atl1c_enable_rx_ctrl(struct atl1c_hw *hw); +-static void atl1c_enable_tx_ctrl(struct atl1c_hw *hw); + static void atl1c_disable_l0s_l1(struct atl1c_hw *hw); +-static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup); +-static void atl1c_setup_mac_ctrl(struct atl1c_adapter *adapter); +-static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, u8 que, ++static void atl1c_set_aspm(struct atl1c_hw *hw, u16 link_speed); ++static void atl1c_start_mac(struct atl1c_adapter *adapter); ++static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, + int *work_done, int work_to_do); + static int atl1c_up(struct atl1c_adapter *adapter); + static void atl1c_down(struct atl1c_adapter *adapter); ++static int atl1c_reset_mac(struct atl1c_hw *hw); ++static void atl1c_reset_dma_ring(struct atl1c_adapter *adapter); ++static int atl1c_configure(struct atl1c_adapter *adapter); ++static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter); + + static const u16 atl1c_pay_load_size[] = { + 128, 256, 512, 1024, 2048, 4096, + }; + +-static const u16 atl1c_rfd_prod_idx_regs[AT_MAX_RECEIVE_QUEUE] = +-{ +- REG_MB_RFD0_PROD_IDX, +- REG_MB_RFD1_PROD_IDX, +- REG_MB_RFD2_PROD_IDX, +- REG_MB_RFD3_PROD_IDX +-}; +- +-static const u16 atl1c_rfd_addr_lo_regs[AT_MAX_RECEIVE_QUEUE] = +-{ +- REG_RFD0_HEAD_ADDR_LO, +- REG_RFD1_HEAD_ADDR_LO, +- REG_RFD2_HEAD_ADDR_LO, +- REG_RFD3_HEAD_ADDR_LO +-}; +- +-static const u16 atl1c_rrd_addr_lo_regs[AT_MAX_RECEIVE_QUEUE] = +-{ +- REG_RRD0_HEAD_ADDR_LO, +- REG_RRD1_HEAD_ADDR_LO, +- REG_RRD2_HEAD_ADDR_LO, +- REG_RRD3_HEAD_ADDR_LO +-}; + + static const u32 atl1c_default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | + NETIF_MSG_LINK | NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP; + static void atl1c_pcie_patch(struct atl1c_hw *hw) + { +- u32 data; ++ u32 mst_data, data; + +- AT_READ_REG(hw, REG_PCIE_PHYMISC, &data); +- data |= PCIE_PHYMISC_FORCE_RCV_DET; +- AT_WRITE_REG(hw, REG_PCIE_PHYMISC, data); ++ /* pclk sel could switch to 25M */ ++ AT_READ_REG(hw, REG_MASTER_CTRL, &mst_data); ++ mst_data &= ~MASTER_CTRL_CLK_SEL_DIS; ++ AT_WRITE_REG(hw, REG_MASTER_CTRL, mst_data); + ++ /* WoL/PCIE related settings */ ++ if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c) { ++ AT_READ_REG(hw, REG_PCIE_PHYMISC, &data); ++ data |= PCIE_PHYMISC_FORCE_RCV_DET; ++ AT_WRITE_REG(hw, REG_PCIE_PHYMISC, data); ++ } else { /* new dev set bit5 of MASTER */ ++ if (!(mst_data & MASTER_CTRL_WAKEN_25M)) ++ AT_WRITE_REG(hw, REG_MASTER_CTRL, ++ mst_data | MASTER_CTRL_WAKEN_25M); ++ } ++ /* aspm/PCIE setting only for l2cb 1.0 */ + if (hw->nic_type == athr_l2c_b && hw->revision_id == L2CB_V10) { + AT_READ_REG(hw, REG_PCIE_PHYMISC2, &data); +- +- data &= ~(PCIE_PHYMISC2_SERDES_CDR_MASK << +- PCIE_PHYMISC2_SERDES_CDR_SHIFT); +- data |= 3 << PCIE_PHYMISC2_SERDES_CDR_SHIFT; +- data &= ~(PCIE_PHYMISC2_SERDES_TH_MASK << +- PCIE_PHYMISC2_SERDES_TH_SHIFT); +- data |= 3 << PCIE_PHYMISC2_SERDES_TH_SHIFT; ++ data = FIELD_SETX(data, PCIE_PHYMISC2_CDR_BW, ++ L2CB1_PCIE_PHYMISC2_CDR_BW); ++ data = FIELD_SETX(data, PCIE_PHYMISC2_L0S_TH, ++ L2CB1_PCIE_PHYMISC2_L0S_TH); + AT_WRITE_REG(hw, REG_PCIE_PHYMISC2, data); ++ /* extend L1 sync timer */ ++ AT_READ_REG(hw, REG_LINK_CTRL, &data); ++ data |= LINK_CTRL_EXT_SYNC; ++ AT_WRITE_REG(hw, REG_LINK_CTRL, data); ++ } ++ /* l2cb 1.x & l1d 1.x */ ++ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d) { ++ AT_READ_REG(hw, REG_PM_CTRL, &data); ++ data |= PM_CTRL_L0S_BUFSRX_EN; ++ AT_WRITE_REG(hw, REG_PM_CTRL, data); ++ /* clear vendor msg */ ++ AT_READ_REG(hw, REG_DMA_DBG, &data); ++ AT_WRITE_REG(hw, REG_DMA_DBG, data & ~DMA_DBG_VENDOR_MSG); + } + } + +@@ -130,6 +124,7 @@ static void atl1c_reset_pcie(struct atl1c_hw *hw, u32 flag) + u32 data; + u32 pci_cmd; + struct pci_dev *pdev = hw->adapter->pdev; ++ int pos; + + AT_READ_REG(hw, PCI_COMMAND, &pci_cmd); + pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; +@@ -142,14 +137,23 @@ static void atl1c_reset_pcie(struct atl1c_hw *hw, u32 flag) + */ + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); ++ /* wol sts read-clear */ ++ AT_READ_REG(hw, REG_WOL_CTRL, &data); ++ AT_WRITE_REG(hw, REG_WOL_CTRL, 0); + + /* + * Mask some pcie error bits + */ +- AT_READ_REG(hw, REG_PCIE_UC_SEVERITY, &data); +- data &= ~PCIE_UC_SERVRITY_DLP; +- data &= ~PCIE_UC_SERVRITY_FCP; +- AT_WRITE_REG(hw, REG_PCIE_UC_SEVERITY, data); ++ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); ++ pci_read_config_dword(pdev, pos + PCI_ERR_UNCOR_SEVER, &data); ++ data &= ~(PCI_ERR_UNC_DLP | PCI_ERR_UNC_FCP); ++ pci_write_config_dword(pdev, pos + PCI_ERR_UNCOR_SEVER, data); ++ /* clear error status */ ++ pci_write_config_word(pdev, pci_pcie_cap(pdev) + PCI_EXP_DEVSTA, ++ PCI_EXP_DEVSTA_NFED | ++ PCI_EXP_DEVSTA_FED | ++ PCI_EXP_DEVSTA_CED | ++ PCI_EXP_DEVSTA_URD); + + AT_READ_REG(hw, REG_LTSSM_ID_CTRL, &data); + data &= ~LTSSM_ID_EN_WRO; +@@ -158,11 +162,6 @@ static void atl1c_reset_pcie(struct atl1c_hw *hw, u32 flag) + atl1c_pcie_patch(hw); + if (flag & ATL1C_PCIE_L0S_L1_DISABLE) + atl1c_disable_l0s_l1(hw); +- if (flag & ATL1C_PCIE_PHY_RESET) +- AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT); +- else +- AT_WRITE_REG(hw, REG_GPHY_CTRL, +- GPHY_CTRL_DEFAULT | GPHY_CTRL_EXT_RESET); + + msleep(5); + } +@@ -207,14 +206,14 @@ static inline void atl1c_irq_reset(struct atl1c_adapter *adapter) + * atl1c_wait_until_idle - wait up to AT_HW_MAX_IDLE_DELAY reads + * of the idle status register until the device is actually idle + */ +-static u32 atl1c_wait_until_idle(struct atl1c_hw *hw) ++static u32 atl1c_wait_until_idle(struct atl1c_hw *hw, u32 modu_ctrl) + { + int timeout; + u32 data; + + for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) { + AT_READ_REG(hw, REG_IDLE_STATUS, &data); +- if ((data & IDLE_STATUS_MASK) == 0) ++ if ((data & modu_ctrl) == 0) + return 0; + msleep(1); + } +@@ -261,15 +260,16 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter) + + if ((phy_data & BMSR_LSTATUS) == 0) { + /* link down */ +- hw->hibernate = true; +- if (atl1c_stop_mac(hw) != 0) +- if (netif_msg_hw(adapter)) +- dev_warn(&pdev->dev, "stop mac failed\n"); +- atl1c_set_aspm(hw, false); + netif_carrier_off(netdev); + netif_stop_queue(netdev); +- atl1c_phy_reset(hw); +- atl1c_phy_init(&adapter->hw); ++ hw->hibernate = true; ++ if (atl1c_reset_mac(hw) != 0) ++ if (netif_msg_hw(adapter)) ++ dev_warn(&pdev->dev, "reset mac failed\n"); ++ atl1c_set_aspm(hw, SPEED_0); ++ atl1c_post_phy_linkchg(hw, SPEED_0); ++ atl1c_reset_dma_ring(adapter); ++ atl1c_configure(adapter); + } else { + /* Link Up */ + hw->hibernate = false; +@@ -283,10 +283,9 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter) + adapter->link_duplex != duplex) { + adapter->link_speed = speed; + adapter->link_duplex = duplex; +- atl1c_set_aspm(hw, true); +- atl1c_enable_tx_ctrl(hw); +- atl1c_enable_rx_ctrl(hw); +- atl1c_setup_mac_ctrl(adapter); ++ atl1c_set_aspm(hw, speed); ++ atl1c_post_phy_linkchg(hw, speed); ++ atl1c_start_mac(adapter); + if (netif_msg_link(adapter)) + dev_info(&pdev->dev, + "%s: %s NIC Link is Up<%d Mbps %s>\n", +@@ -337,6 +336,9 @@ static void atl1c_common_task(struct work_struct *work) + adapter = container_of(work, struct atl1c_adapter, common_task); + netdev = adapter->netdev; + ++ if (test_bit(__AT_DOWN, &adapter->flags)) ++ return; ++ + if (test_and_clear_bit(ATL1C_WORK_EVENT_RESET, &adapter->work_event)) { + netif_device_detach(netdev); + atl1c_down(adapter); +@@ -345,8 +347,11 @@ static void atl1c_common_task(struct work_struct *work) + } + + if (test_and_clear_bit(ATL1C_WORK_EVENT_LINK_CHANGE, +- &adapter->work_event)) ++ &adapter->work_event)) { ++ atl1c_irq_disable(adapter); + atl1c_check_link_status(adapter); ++ atl1c_irq_enable(adapter); ++ } + } + + +@@ -469,7 +474,7 @@ static int atl1c_set_mac_addr(struct net_device *netdev, void *p) + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len); + +- atl1c_hw_set_mac_addr(&adapter->hw); ++ atl1c_hw_set_mac_addr(&adapter->hw, adapter->hw.mac_addr); + + return 0; + } +@@ -522,11 +527,16 @@ static int atl1c_set_features(struct net_device *netdev, + static int atl1c_change_mtu(struct net_device *netdev, int new_mtu) + { + struct atl1c_adapter *adapter = netdev_priv(netdev); ++ struct atl1c_hw *hw = &adapter->hw; + int old_mtu = netdev->mtu; + int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; + +- if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) || +- (max_frame > MAX_JUMBO_FRAME_SIZE)) { ++ /* Fast Ethernet controller doesn't support jumbo packet */ ++ if (((hw->nic_type == athr_l2c || ++ hw->nic_type == athr_l2c_b || ++ hw->nic_type == athr_l2c_b2) && new_mtu > ETH_DATA_LEN) || ++ max_frame < ETH_ZLEN + ETH_FCS_LEN || ++ max_frame > MAX_JUMBO_FRAME_SIZE) { + if (netif_msg_link(adapter)) + dev_warn(&adapter->pdev->dev, "invalid MTU setting\n"); + return -EINVAL; +@@ -542,14 +552,6 @@ static int atl1c_change_mtu(struct net_device *netdev, int new_mtu) + netdev_update_features(netdev); + atl1c_up(adapter); + clear_bit(__AT_RESETTING, &adapter->flags); +- if (adapter->hw.ctrl_flags & ATL1C_FPGA_VERSION) { +- u32 phy_data; +- +- AT_READ_REG(&adapter->hw, 0x1414, &phy_data); +- phy_data |= 0x10000000; +- AT_WRITE_REG(&adapter->hw, 0x1414, phy_data); +- } +- + } + return 0; + } +@@ -562,7 +564,7 @@ static int atl1c_mdio_read(struct net_device *netdev, int phy_id, int reg_num) + struct atl1c_adapter *adapter = netdev_priv(netdev); + u16 result; + +- atl1c_read_phy_reg(&adapter->hw, reg_num & MDIO_REG_ADDR_MASK, &result); ++ atl1c_read_phy_reg(&adapter->hw, reg_num, &result); + return result; + } + +@@ -571,7 +573,7 @@ static void atl1c_mdio_write(struct net_device *netdev, int phy_id, + { + struct atl1c_adapter *adapter = netdev_priv(netdev); + +- atl1c_write_phy_reg(&adapter->hw, reg_num & MDIO_REG_ADDR_MASK, val); ++ atl1c_write_phy_reg(&adapter->hw, reg_num, val); + } + + /* +@@ -686,21 +688,15 @@ static void atl1c_set_mac_type(struct atl1c_hw *hw) + + static int atl1c_setup_mac_funcs(struct atl1c_hw *hw) + { +- u32 phy_status_data; + u32 link_ctrl_data; + + atl1c_set_mac_type(hw); +- AT_READ_REG(hw, REG_PHY_STATUS, &phy_status_data); + AT_READ_REG(hw, REG_LINK_CTRL, &link_ctrl_data); + + hw->ctrl_flags = ATL1C_INTR_MODRT_ENABLE | + ATL1C_TXQ_MODE_ENHANCE; +- if (link_ctrl_data & LINK_CTRL_L0S_EN) +- hw->ctrl_flags |= ATL1C_ASPM_L0S_SUPPORT; +- if (link_ctrl_data & LINK_CTRL_L1_EN) +- hw->ctrl_flags |= ATL1C_ASPM_L1_SUPPORT; +- if (link_ctrl_data & LINK_CTRL_EXT_SYNC) +- hw->ctrl_flags |= ATL1C_LINK_EXT_SYNC; ++ hw->ctrl_flags |= ATL1C_ASPM_L0S_SUPPORT | ++ ATL1C_ASPM_L1_SUPPORT; + hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON; + + if (hw->nic_type == athr_l1c || +@@ -709,6 +705,55 @@ static int atl1c_setup_mac_funcs(struct atl1c_hw *hw) + hw->link_cap_flags |= ATL1C_LINK_CAP_1000M; + return 0; + } ++ ++struct atl1c_platform_patch { ++ u16 pci_did; ++ u8 pci_revid; ++ u16 subsystem_vid; ++ u16 subsystem_did; ++ u32 patch_flag; ++#define ATL1C_LINK_PATCH 0x1 ++}; ++static const struct atl1c_platform_patch plats[] __devinitdata = { ++{0x2060, 0xC1, 0x1019, 0x8152, 0x1}, ++{0x2060, 0xC1, 0x1019, 0x2060, 0x1}, ++{0x2060, 0xC1, 0x1019, 0xE000, 0x1}, ++{0x2062, 0xC0, 0x1019, 0x8152, 0x1}, ++{0x2062, 0xC0, 0x1019, 0x2062, 0x1}, ++{0x2062, 0xC0, 0x1458, 0xE000, 0x1}, ++{0x2062, 0xC1, 0x1019, 0x8152, 0x1}, ++{0x2062, 0xC1, 0x1019, 0x2062, 0x1}, ++{0x2062, 0xC1, 0x1458, 0xE000, 0x1}, ++{0x2062, 0xC1, 0x1565, 0x2802, 0x1}, ++{0x2062, 0xC1, 0x1565, 0x2801, 0x1}, ++{0x1073, 0xC0, 0x1019, 0x8151, 0x1}, ++{0x1073, 0xC0, 0x1019, 0x1073, 0x1}, ++{0x1073, 0xC0, 0x1458, 0xE000, 0x1}, ++{0x1083, 0xC0, 0x1458, 0xE000, 0x1}, ++{0x1083, 0xC0, 0x1019, 0x8151, 0x1}, ++{0x1083, 0xC0, 0x1019, 0x1083, 0x1}, ++{0x1083, 0xC0, 0x1462, 0x7680, 0x1}, ++{0x1083, 0xC0, 0x1565, 0x2803, 0x1}, ++{0}, ++}; ++ ++static void __devinit atl1c_patch_assign(struct atl1c_hw *hw) ++{ ++ int i = 0; ++ ++ hw->msi_lnkpatch = false; ++ ++ while (plats[i].pci_did != 0) { ++ if (plats[i].pci_did == hw->device_id && ++ plats[i].pci_revid == hw->revision_id && ++ plats[i].subsystem_vid == hw->subsystem_vendor_id && ++ plats[i].subsystem_did == hw->subsystem_id) { ++ if (plats[i].patch_flag & ATL1C_LINK_PATCH) ++ hw->msi_lnkpatch = true; ++ } ++ i++; ++ } ++} + /* + * atl1c_sw_init - Initialize general software structures (struct atl1c_adapter) + * @adapter: board private structure to initialize +@@ -728,9 +773,8 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter) + device_set_wakeup_enable(&pdev->dev, false); + adapter->link_speed = SPEED_0; + adapter->link_duplex = FULL_DUPLEX; +- adapter->num_rx_queues = AT_DEF_RECEIVE_QUEUE; + adapter->tpd_ring[0].count = 1024; +- adapter->rfd_ring[0].count = 512; ++ adapter->rfd_ring.count = 512; + + hw->vendor_id = pdev->vendor; + hw->device_id = pdev->device; +@@ -745,26 +789,18 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter) + dev_err(&pdev->dev, "set mac function pointers failed\n"); + return -1; + } ++ atl1c_patch_assign(hw); ++ + hw->intr_mask = IMR_NORMAL_MASK; + hw->phy_configured = false; + hw->preamble_len = 7; + hw->max_frame_size = adapter->netdev->mtu; +- if (adapter->num_rx_queues < 2) { +- hw->rss_type = atl1c_rss_disable; +- hw->rss_mode = atl1c_rss_mode_disable; +- } else { +- hw->rss_type = atl1c_rss_ipv4; +- hw->rss_mode = atl1c_rss_mul_que_mul_int; +- hw->rss_hash_bits = 16; +- } + hw->autoneg_advertised = ADVERTISED_Autoneg; + hw->indirect_tab = 0xE4E4E4E4; + hw->base_cpu = 0; + + hw->ict = 50000; /* 100ms */ + hw->smb_timer = 200000; /* 400ms */ +- hw->cmb_tpd = 4; +- hw->cmb_tx_timer = 1; /* 2 us */ + hw->rx_imt = 200; + hw->tx_imt = 1000; + +@@ -772,9 +808,6 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter) + hw->rfd_burst = 8; + hw->dma_order = atl1c_dma_ord_out; + hw->dmar_block = atl1c_dma_req_1024; +- hw->dmaw_block = atl1c_dma_req_1024; +- hw->dmar_dly_cnt = 15; +- hw->dmaw_dly_cnt = 4; + + if (atl1c_alloc_queues(adapter)) { + dev_err(&pdev->dev, "Unable to allocate memory for queues\n"); +@@ -850,24 +883,22 @@ static void atl1c_clean_tx_ring(struct atl1c_adapter *adapter, + */ + static void atl1c_clean_rx_ring(struct atl1c_adapter *adapter) + { +- struct atl1c_rfd_ring *rfd_ring = adapter->rfd_ring; +- struct atl1c_rrd_ring *rrd_ring = adapter->rrd_ring; ++ struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring; ++ struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1c_buffer *buffer_info; + struct pci_dev *pdev = adapter->pdev; +- int i, j; ++ int j; + +- for (i = 0; i < adapter->num_rx_queues; i++) { +- for (j = 0; j < rfd_ring[i].count; j++) { +- buffer_info = &rfd_ring[i].buffer_info[j]; +- atl1c_clean_buffer(pdev, buffer_info, 0); +- } +- /* zero out the descriptor ring */ +- memset(rfd_ring[i].desc, 0, rfd_ring[i].size); +- rfd_ring[i].next_to_clean = 0; +- rfd_ring[i].next_to_use = 0; +- rrd_ring[i].next_to_use = 0; +- rrd_ring[i].next_to_clean = 0; ++ for (j = 0; j < rfd_ring->count; j++) { ++ buffer_info = &rfd_ring->buffer_info[j]; ++ atl1c_clean_buffer(pdev, buffer_info, 0); + } ++ /* zero out the descriptor ring */ ++ memset(rfd_ring->desc, 0, rfd_ring->size); ++ rfd_ring->next_to_clean = 0; ++ rfd_ring->next_to_use = 0; ++ rrd_ring->next_to_use = 0; ++ rrd_ring->next_to_clean = 0; + } + + /* +@@ -876,8 +907,8 @@ static void atl1c_clean_rx_ring(struct atl1c_adapter *adapter) + static void atl1c_init_ring_ptrs(struct atl1c_adapter *adapter) + { + struct atl1c_tpd_ring *tpd_ring = adapter->tpd_ring; +- struct atl1c_rfd_ring *rfd_ring = adapter->rfd_ring; +- struct atl1c_rrd_ring *rrd_ring = adapter->rrd_ring; ++ struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring; ++ struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1c_buffer *buffer_info; + int i, j; + +@@ -889,15 +920,13 @@ static void atl1c_init_ring_ptrs(struct atl1c_adapter *adapter) + ATL1C_SET_BUFFER_STATE(&buffer_info[i], + ATL1C_BUFFER_FREE); + } +- for (i = 0; i < adapter->num_rx_queues; i++) { +- rfd_ring[i].next_to_use = 0; +- rfd_ring[i].next_to_clean = 0; +- rrd_ring[i].next_to_use = 0; +- rrd_ring[i].next_to_clean = 0; +- for (j = 0; j < rfd_ring[i].count; j++) { +- buffer_info = &rfd_ring[i].buffer_info[j]; +- ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_FREE); +- } ++ rfd_ring->next_to_use = 0; ++ rfd_ring->next_to_clean = 0; ++ rrd_ring->next_to_use = 0; ++ rrd_ring->next_to_clean = 0; ++ for (j = 0; j < rfd_ring->count; j++) { ++ buffer_info = &rfd_ring->buffer_info[j]; ++ ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_FREE); + } + } + +@@ -934,27 +963,23 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) + { + struct pci_dev *pdev = adapter->pdev; + struct atl1c_tpd_ring *tpd_ring = adapter->tpd_ring; +- struct atl1c_rfd_ring *rfd_ring = adapter->rfd_ring; +- struct atl1c_rrd_ring *rrd_ring = adapter->rrd_ring; ++ struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring; ++ struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1c_ring_header *ring_header = &adapter->ring_header; +- int num_rx_queues = adapter->num_rx_queues; + int size; + int i; + int count = 0; + int rx_desc_count = 0; + u32 offset = 0; + +- rrd_ring[0].count = rfd_ring[0].count; ++ rrd_ring->count = rfd_ring->count; + for (i = 1; i < AT_MAX_TRANSMIT_QUEUE; i++) + tpd_ring[i].count = tpd_ring[0].count; + +- for (i = 1; i < adapter->num_rx_queues; i++) +- rfd_ring[i].count = rrd_ring[i].count = rfd_ring[0].count; +- + /* 2 tpd queue, one high priority queue, + * another normal priority queue */ + size = sizeof(struct atl1c_buffer) * (tpd_ring->count * 2 + +- rfd_ring->count * num_rx_queues); ++ rfd_ring->count); + tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL); + if (unlikely(!tpd_ring->buffer_info)) { + dev_err(&pdev->dev, "kzalloc failed, size = %d\n", +@@ -967,12 +992,11 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) + count += tpd_ring[i].count; + } + +- for (i = 0; i < num_rx_queues; i++) { +- rfd_ring[i].buffer_info = +- (struct atl1c_buffer *) (tpd_ring->buffer_info + count); +- count += rfd_ring[i].count; +- rx_desc_count += rfd_ring[i].count; +- } ++ rfd_ring->buffer_info = ++ (struct atl1c_buffer *) (tpd_ring->buffer_info + count); ++ count += rfd_ring->count; ++ rx_desc_count += rfd_ring->count; ++ + /* + * real ring DMA buffer + * each ring/block may need up to 8 bytes for alignment, hence the +@@ -982,8 +1006,7 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) + sizeof(struct atl1c_tpd_desc) * tpd_ring->count * 2 + + sizeof(struct atl1c_rx_free_desc) * rx_desc_count + + sizeof(struct atl1c_recv_ret_status) * rx_desc_count + +- sizeof(struct atl1c_hw_stats) + +- 8 * 4 + 8 * 2 * num_rx_queues; ++ 8 * 4; + + ring_header->desc = pci_alloc_consistent(pdev, ring_header->size, + &ring_header->dma); +@@ -1004,25 +1027,18 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) + offset += roundup(tpd_ring[i].size, 8); + } + /* init RFD ring */ +- for (i = 0; i < num_rx_queues; i++) { +- rfd_ring[i].dma = ring_header->dma + offset; +- rfd_ring[i].desc = (u8 *) ring_header->desc + offset; +- rfd_ring[i].size = sizeof(struct atl1c_rx_free_desc) * +- rfd_ring[i].count; +- offset += roundup(rfd_ring[i].size, 8); +- } ++ rfd_ring->dma = ring_header->dma + offset; ++ rfd_ring->desc = (u8 *) ring_header->desc + offset; ++ rfd_ring->size = sizeof(struct atl1c_rx_free_desc) * rfd_ring->count; ++ offset += roundup(rfd_ring->size, 8); + + /* init RRD ring */ +- for (i = 0; i < num_rx_queues; i++) { +- rrd_ring[i].dma = ring_header->dma + offset; +- rrd_ring[i].desc = (u8 *) ring_header->desc + offset; +- rrd_ring[i].size = sizeof(struct atl1c_recv_ret_status) * +- rrd_ring[i].count; +- offset += roundup(rrd_ring[i].size, 8); +- } ++ rrd_ring->dma = ring_header->dma + offset; ++ rrd_ring->desc = (u8 *) ring_header->desc + offset; ++ rrd_ring->size = sizeof(struct atl1c_recv_ret_status) * ++ rrd_ring->count; ++ offset += roundup(rrd_ring->size, 8); + +- adapter->smb.dma = ring_header->dma + offset; +- adapter->smb.smb = (u8 *)ring_header->desc + offset; + return 0; + + err_nomem: +@@ -1033,26 +1049,20 @@ err_nomem: + static void atl1c_configure_des_ring(struct atl1c_adapter *adapter) + { + struct atl1c_hw *hw = &adapter->hw; +- struct atl1c_rfd_ring *rfd_ring = (struct atl1c_rfd_ring *) +- adapter->rfd_ring; +- struct atl1c_rrd_ring *rrd_ring = (struct atl1c_rrd_ring *) +- adapter->rrd_ring; ++ struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring; ++ struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1c_tpd_ring *tpd_ring = (struct atl1c_tpd_ring *) + adapter->tpd_ring; +- struct atl1c_cmb *cmb = (struct atl1c_cmb *) &adapter->cmb; +- struct atl1c_smb *smb = (struct atl1c_smb *) &adapter->smb; +- int i; +- u32 data; + + /* TPD */ + AT_WRITE_REG(hw, REG_TX_BASE_ADDR_HI, + (u32)((tpd_ring[atl1c_trans_normal].dma & + AT_DMA_HI_ADDR_MASK) >> 32)); + /* just enable normal priority TX queue */ +- AT_WRITE_REG(hw, REG_NTPD_HEAD_ADDR_LO, ++ AT_WRITE_REG(hw, REG_TPD_PRI0_ADDR_LO, + (u32)(tpd_ring[atl1c_trans_normal].dma & + AT_DMA_LO_ADDR_MASK)); +- AT_WRITE_REG(hw, REG_HTPD_HEAD_ADDR_LO, ++ AT_WRITE_REG(hw, REG_TPD_PRI1_ADDR_LO, + (u32)(tpd_ring[atl1c_trans_high].dma & + AT_DMA_LO_ADDR_MASK)); + AT_WRITE_REG(hw, REG_TPD_RING_SIZE, +@@ -1061,31 +1071,21 @@ static void atl1c_configure_des_ring(struct atl1c_adapter *adapter) + + /* RFD */ + AT_WRITE_REG(hw, REG_RX_BASE_ADDR_HI, +- (u32)((rfd_ring[0].dma & AT_DMA_HI_ADDR_MASK) >> 32)); +- for (i = 0; i < adapter->num_rx_queues; i++) +- AT_WRITE_REG(hw, atl1c_rfd_addr_lo_regs[i], +- (u32)(rfd_ring[i].dma & AT_DMA_LO_ADDR_MASK)); ++ (u32)((rfd_ring->dma & AT_DMA_HI_ADDR_MASK) >> 32)); ++ AT_WRITE_REG(hw, REG_RFD0_HEAD_ADDR_LO, ++ (u32)(rfd_ring->dma & AT_DMA_LO_ADDR_MASK)); + + AT_WRITE_REG(hw, REG_RFD_RING_SIZE, +- rfd_ring[0].count & RFD_RING_SIZE_MASK); ++ rfd_ring->count & RFD_RING_SIZE_MASK); + AT_WRITE_REG(hw, REG_RX_BUF_SIZE, + adapter->rx_buffer_len & RX_BUF_SIZE_MASK); + + /* RRD */ +- for (i = 0; i < adapter->num_rx_queues; i++) +- AT_WRITE_REG(hw, atl1c_rrd_addr_lo_regs[i], +- (u32)(rrd_ring[i].dma & AT_DMA_LO_ADDR_MASK)); ++ AT_WRITE_REG(hw, REG_RRD0_HEAD_ADDR_LO, ++ (u32)(rrd_ring->dma & AT_DMA_LO_ADDR_MASK)); + AT_WRITE_REG(hw, REG_RRD_RING_SIZE, +- (rrd_ring[0].count & RRD_RING_SIZE_MASK)); ++ (rrd_ring->count & RRD_RING_SIZE_MASK)); + +- /* CMB */ +- AT_WRITE_REG(hw, REG_CMB_BASE_ADDR_LO, cmb->dma & AT_DMA_LO_ADDR_MASK); +- +- /* SMB */ +- AT_WRITE_REG(hw, REG_SMB_BASE_ADDR_HI, +- (u32)((smb->dma & AT_DMA_HI_ADDR_MASK) >> 32)); +- AT_WRITE_REG(hw, REG_SMB_BASE_ADDR_LO, +- (u32)(smb->dma & AT_DMA_LO_ADDR_MASK)); + if (hw->nic_type == athr_l2c_b) { + AT_WRITE_REG(hw, REG_SRAM_RXF_LEN, 0x02a0L); + AT_WRITE_REG(hw, REG_SRAM_TXF_LEN, 0x0100L); +@@ -1096,13 +1096,6 @@ static void atl1c_configure_des_ring(struct atl1c_adapter *adapter) + AT_WRITE_REG(hw, REG_TXF_WATER_MARK, 0); /* TX watermark, to enter l1 state.*/ + AT_WRITE_REG(hw, REG_RXD_DMA_CTRL, 0); /* RXD threshold.*/ + } +- if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d_2) { +- /* Power Saving for L2c_B */ +- AT_READ_REG(hw, REG_SERDES_LOCK, &data); +- data |= SERDES_MAC_CLK_SLOWDOWN; +- data |= SERDES_PYH_CLK_SLOWDOWN; +- AT_WRITE_REG(hw, REG_SERDES_LOCK, data); +- } + /* Load all of base address above */ + AT_WRITE_REG(hw, REG_LOAD_PTR, 1); + } +@@ -1110,32 +1103,26 @@ static void atl1c_configure_des_ring(struct atl1c_adapter *adapter) + static void atl1c_configure_tx(struct atl1c_adapter *adapter) + { + struct atl1c_hw *hw = &adapter->hw; +- u32 dev_ctrl_data; +- u32 max_pay_load; ++ int max_pay_load; + u16 tx_offload_thresh; + u32 txq_ctrl_data; +- u32 max_pay_load_data; + +- tx_offload_thresh = MAX_TX_OFFLOAD_THRESH; ++ tx_offload_thresh = MAX_TSO_FRAME_SIZE; + AT_WRITE_REG(hw, REG_TX_TSO_OFFLOAD_THRESH, + (tx_offload_thresh >> 3) & TX_TSO_OFFLOAD_THRESH_MASK); +- AT_READ_REG(hw, REG_DEVICE_CTRL, &dev_ctrl_data); +- max_pay_load = (dev_ctrl_data >> DEVICE_CTRL_MAX_PAYLOAD_SHIFT) & +- DEVICE_CTRL_MAX_PAYLOAD_MASK; +- hw->dmaw_block = min_t(u32, max_pay_load, hw->dmaw_block); +- max_pay_load = (dev_ctrl_data >> DEVICE_CTRL_MAX_RREQ_SZ_SHIFT) & +- DEVICE_CTRL_MAX_RREQ_SZ_MASK; ++ max_pay_load = pcie_get_readrq(adapter->pdev) >> 8; + hw->dmar_block = min_t(u32, max_pay_load, hw->dmar_block); +- +- txq_ctrl_data = (hw->tpd_burst & TXQ_NUM_TPD_BURST_MASK) << +- TXQ_NUM_TPD_BURST_SHIFT; +- if (hw->ctrl_flags & ATL1C_TXQ_MODE_ENHANCE) +- txq_ctrl_data |= TXQ_CTRL_ENH_MODE; +- max_pay_load_data = (atl1c_pay_load_size[hw->dmar_block] & +- TXQ_TXF_BURST_NUM_MASK) << TXQ_TXF_BURST_NUM_SHIFT; +- if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2) +- max_pay_load_data >>= 1; +- txq_ctrl_data |= max_pay_load_data; ++ /* ++ * if BIOS had changed the dam-read-max-length to an invalid value, ++ * restore it to default value ++ */ ++ if (hw->dmar_block < DEVICE_CTRL_MAXRRS_MIN) { ++ pcie_set_readrq(adapter->pdev, 128 << DEVICE_CTRL_MAXRRS_MIN); ++ hw->dmar_block = DEVICE_CTRL_MAXRRS_MIN; ++ } ++ txq_ctrl_data = ++ hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2 ? ++ L2CB_TXQ_CFGV : L1C_TXQ_CFGV; + + AT_WRITE_REG(hw, REG_TXQ_CTRL, txq_ctrl_data); + } +@@ -1150,34 +1137,13 @@ static void atl1c_configure_rx(struct atl1c_adapter *adapter) + + if (hw->ctrl_flags & ATL1C_RX_IPV6_CHKSUM) + rxq_ctrl_data |= IPV6_CHKSUM_CTRL_EN; +- if (hw->rss_type == atl1c_rss_ipv4) +- rxq_ctrl_data |= RSS_HASH_IPV4; +- if (hw->rss_type == atl1c_rss_ipv4_tcp) +- rxq_ctrl_data |= RSS_HASH_IPV4_TCP; +- if (hw->rss_type == atl1c_rss_ipv6) +- rxq_ctrl_data |= RSS_HASH_IPV6; +- if (hw->rss_type == atl1c_rss_ipv6_tcp) +- rxq_ctrl_data |= RSS_HASH_IPV6_TCP; +- if (hw->rss_type != atl1c_rss_disable) +- rxq_ctrl_data |= RRS_HASH_CTRL_EN; +- +- rxq_ctrl_data |= (hw->rss_mode & RSS_MODE_MASK) << +- RSS_MODE_SHIFT; +- rxq_ctrl_data |= (hw->rss_hash_bits & RSS_HASH_BITS_MASK) << +- RSS_HASH_BITS_SHIFT; +- if (hw->ctrl_flags & ATL1C_ASPM_CTRL_MON) +- rxq_ctrl_data |= (ASPM_THRUPUT_LIMIT_1M & +- ASPM_THRUPUT_LIMIT_MASK) << ASPM_THRUPUT_LIMIT_SHIFT; + +- AT_WRITE_REG(hw, REG_RXQ_CTRL, rxq_ctrl_data); +-} +- +-static void atl1c_configure_rss(struct atl1c_adapter *adapter) +-{ +- struct atl1c_hw *hw = &adapter->hw; ++ /* aspm for gigabit */ ++ if (hw->nic_type != athr_l1d_2 && (hw->device_id & 1) != 0) ++ rxq_ctrl_data = FIELD_SETX(rxq_ctrl_data, ASPM_THRUPUT_LIMIT, ++ ASPM_THRUPUT_LIMIT_100M); + +- AT_WRITE_REG(hw, REG_IDT_TABLE, hw->indirect_tab); +- AT_WRITE_REG(hw, REG_BASE_CPU_NUMBER, hw->base_cpu); ++ AT_WRITE_REG(hw, REG_RXQ_CTRL, rxq_ctrl_data); + } + + static void atl1c_configure_dma(struct atl1c_adapter *adapter) +@@ -1185,36 +1151,11 @@ static void atl1c_configure_dma(struct atl1c_adapter *adapter) + struct atl1c_hw *hw = &adapter->hw; + u32 dma_ctrl_data; + +- dma_ctrl_data = DMA_CTRL_DMAR_REQ_PRI; +- if (hw->ctrl_flags & ATL1C_CMB_ENABLE) +- dma_ctrl_data |= DMA_CTRL_CMB_EN; +- if (hw->ctrl_flags & ATL1C_SMB_ENABLE) +- dma_ctrl_data |= DMA_CTRL_SMB_EN; +- else +- dma_ctrl_data |= MAC_CTRL_SMB_DIS; +- +- switch (hw->dma_order) { +- case atl1c_dma_ord_in: +- dma_ctrl_data |= DMA_CTRL_DMAR_IN_ORDER; +- break; +- case atl1c_dma_ord_enh: +- dma_ctrl_data |= DMA_CTRL_DMAR_ENH_ORDER; +- break; +- case atl1c_dma_ord_out: +- dma_ctrl_data |= DMA_CTRL_DMAR_OUT_ORDER; +- break; +- default: +- break; +- } +- +- dma_ctrl_data |= (((u32)hw->dmar_block) & DMA_CTRL_DMAR_BURST_LEN_MASK) +- << DMA_CTRL_DMAR_BURST_LEN_SHIFT; +- dma_ctrl_data |= (((u32)hw->dmaw_block) & DMA_CTRL_DMAW_BURST_LEN_MASK) +- << DMA_CTRL_DMAW_BURST_LEN_SHIFT; +- dma_ctrl_data |= (((u32)hw->dmar_dly_cnt) & DMA_CTRL_DMAR_DLY_CNT_MASK) +- << DMA_CTRL_DMAR_DLY_CNT_SHIFT; +- dma_ctrl_data |= (((u32)hw->dmaw_dly_cnt) & DMA_CTRL_DMAW_DLY_CNT_MASK) +- << DMA_CTRL_DMAW_DLY_CNT_SHIFT; ++ dma_ctrl_data = FIELDX(DMA_CTRL_RORDER_MODE, DMA_CTRL_RORDER_MODE_OUT) | ++ DMA_CTRL_RREQ_PRI_DATA | ++ FIELDX(DMA_CTRL_RREQ_BLEN, hw->dmar_block) | ++ FIELDX(DMA_CTRL_WDLY_CNT, DMA_CTRL_WDLY_CNT_DEF) | ++ FIELDX(DMA_CTRL_RDLY_CNT, DMA_CTRL_RDLY_CNT_DEF); + + AT_WRITE_REG(hw, REG_DMA_CTRL, dma_ctrl_data); + } +@@ -1229,52 +1170,53 @@ static int atl1c_stop_mac(struct atl1c_hw *hw) + u32 data; + + AT_READ_REG(hw, REG_RXQ_CTRL, &data); +- data &= ~(RXQ1_CTRL_EN | RXQ2_CTRL_EN | +- RXQ3_CTRL_EN | RXQ_CTRL_EN); ++ data &= ~RXQ_CTRL_EN; + AT_WRITE_REG(hw, REG_RXQ_CTRL, data); + + AT_READ_REG(hw, REG_TXQ_CTRL, &data); + data &= ~TXQ_CTRL_EN; +- AT_WRITE_REG(hw, REG_TWSI_CTRL, data); ++ AT_WRITE_REG(hw, REG_TXQ_CTRL, data); + +- atl1c_wait_until_idle(hw); ++ atl1c_wait_until_idle(hw, IDLE_STATUS_RXQ_BUSY | IDLE_STATUS_TXQ_BUSY); + + AT_READ_REG(hw, REG_MAC_CTRL, &data); + data &= ~(MAC_CTRL_TX_EN | MAC_CTRL_RX_EN); + AT_WRITE_REG(hw, REG_MAC_CTRL, data); + +- return (int)atl1c_wait_until_idle(hw); ++ return (int)atl1c_wait_until_idle(hw, ++ IDLE_STATUS_TXMAC_BUSY | IDLE_STATUS_RXMAC_BUSY); + } + +-static void atl1c_enable_rx_ctrl(struct atl1c_hw *hw) ++static void atl1c_start_mac(struct atl1c_adapter *adapter) + { +- u32 data; +- +- AT_READ_REG(hw, REG_RXQ_CTRL, &data); +- switch (hw->adapter->num_rx_queues) { +- case 4: +- data |= (RXQ3_CTRL_EN | RXQ2_CTRL_EN | RXQ1_CTRL_EN); +- break; +- case 3: +- data |= (RXQ2_CTRL_EN | RXQ1_CTRL_EN); +- break; +- case 2: +- data |= RXQ1_CTRL_EN; +- break; +- default: +- break; +- } +- data |= RXQ_CTRL_EN; +- AT_WRITE_REG(hw, REG_RXQ_CTRL, data); +-} +- +-static void atl1c_enable_tx_ctrl(struct atl1c_hw *hw) +-{ +- u32 data; ++ struct atl1c_hw *hw = &adapter->hw; ++ u32 mac, txq, rxq; ++ ++ hw->mac_duplex = adapter->link_duplex == FULL_DUPLEX ? true : false; ++ hw->mac_speed = adapter->link_speed == SPEED_1000 ? ++ atl1c_mac_speed_1000 : atl1c_mac_speed_10_100; ++ ++ AT_READ_REG(hw, REG_TXQ_CTRL, &txq); ++ AT_READ_REG(hw, REG_RXQ_CTRL, &rxq); ++ AT_READ_REG(hw, REG_MAC_CTRL, &mac); ++ ++ txq |= TXQ_CTRL_EN; ++ rxq |= RXQ_CTRL_EN; ++ mac |= MAC_CTRL_TX_EN | MAC_CTRL_TX_FLOW | ++ MAC_CTRL_RX_EN | MAC_CTRL_RX_FLOW | ++ MAC_CTRL_ADD_CRC | MAC_CTRL_PAD | ++ MAC_CTRL_BC_EN | MAC_CTRL_SINGLE_PAUSE_EN | ++ MAC_CTRL_HASH_ALG_CRC32; ++ if (hw->mac_duplex) ++ mac |= MAC_CTRL_DUPLX; ++ else ++ mac &= ~MAC_CTRL_DUPLX; ++ mac = FIELD_SETX(mac, MAC_CTRL_SPEED, hw->mac_speed); ++ mac = FIELD_SETX(mac, MAC_CTRL_PRMLEN, hw->preamble_len); + +- AT_READ_REG(hw, REG_TXQ_CTRL, &data); +- data |= TXQ_CTRL_EN; +- AT_WRITE_REG(hw, REG_TXQ_CTRL, data); ++ AT_WRITE_REG(hw, REG_TXQ_CTRL, txq); ++ AT_WRITE_REG(hw, REG_RXQ_CTRL, rxq); ++ AT_WRITE_REG(hw, REG_MAC_CTRL, mac); + } + + /* +@@ -1286,10 +1228,7 @@ static int atl1c_reset_mac(struct atl1c_hw *hw) + { + struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter; + struct pci_dev *pdev = adapter->pdev; +- u32 master_ctrl_data = 0; +- +- AT_WRITE_REG(hw, REG_IMR, 0); +- AT_WRITE_REG(hw, REG_ISR, ISR_DIS_INT); ++ u32 ctrl_data = 0; + + atl1c_stop_mac(hw); + /* +@@ -1298,194 +1237,148 @@ static int atl1c_reset_mac(struct atl1c_hw *hw) + * the current PCI configuration. The global reset bit is self- + * clearing, and should clear within a microsecond. + */ +- AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data); +- master_ctrl_data |= MASTER_CTRL_OOB_DIS_OFF; +- AT_WRITE_REGW(hw, REG_MASTER_CTRL, ((master_ctrl_data | MASTER_CTRL_SOFT_RST) +- & 0xFFFF)); ++ AT_READ_REG(hw, REG_MASTER_CTRL, &ctrl_data); ++ ctrl_data |= MASTER_CTRL_OOB_DIS; ++ AT_WRITE_REG(hw, REG_MASTER_CTRL, ctrl_data | MASTER_CTRL_SOFT_RST); + + AT_WRITE_FLUSH(hw); + msleep(10); + /* Wait at least 10ms for All module to be Idle */ + +- if (atl1c_wait_until_idle(hw)) { ++ if (atl1c_wait_until_idle(hw, IDLE_STATUS_MASK)) { + dev_err(&pdev->dev, + "MAC state machine can't be idle since" + " disabled for 10ms second\n"); + return -1; + } ++ AT_WRITE_REG(hw, REG_MASTER_CTRL, ctrl_data); ++ ++ /* driver control speed/duplex */ ++ AT_READ_REG(hw, REG_MAC_CTRL, &ctrl_data); ++ AT_WRITE_REG(hw, REG_MAC_CTRL, ctrl_data | MAC_CTRL_SPEED_MODE_SW); ++ ++ /* clk switch setting */ ++ AT_READ_REG(hw, REG_SERDES, &ctrl_data); ++ switch (hw->nic_type) { ++ case athr_l2c_b: ++ ctrl_data &= ~(SERDES_PHY_CLK_SLOWDOWN | ++ SERDES_MAC_CLK_SLOWDOWN); ++ AT_WRITE_REG(hw, REG_SERDES, ctrl_data); ++ break; ++ case athr_l2c_b2: ++ case athr_l1d_2: ++ ctrl_data |= SERDES_PHY_CLK_SLOWDOWN | SERDES_MAC_CLK_SLOWDOWN; ++ AT_WRITE_REG(hw, REG_SERDES, ctrl_data); ++ break; ++ default: ++ break; ++ } ++ + return 0; + } + + static void atl1c_disable_l0s_l1(struct atl1c_hw *hw) + { +- u32 pm_ctrl_data; ++ u16 ctrl_flags = hw->ctrl_flags; + +- AT_READ_REG(hw, REG_PM_CTRL, &pm_ctrl_data); +- pm_ctrl_data &= ~(PM_CTRL_L1_ENTRY_TIMER_MASK << +- PM_CTRL_L1_ENTRY_TIMER_SHIFT); +- pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1; +- pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN; +- pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN; +- pm_ctrl_data &= ~PM_CTRL_MAC_ASPM_CHK; +- pm_ctrl_data &= ~PM_CTRL_SERDES_PD_EX_L1; +- +- pm_ctrl_data |= PM_CTRL_SERDES_BUDS_RX_L1_EN; +- pm_ctrl_data |= PM_CTRL_SERDES_PLL_L1_EN; +- pm_ctrl_data |= PM_CTRL_SERDES_L1_EN; +- AT_WRITE_REG(hw, REG_PM_CTRL, pm_ctrl_data); ++ hw->ctrl_flags &= ~(ATL1C_ASPM_L0S_SUPPORT | ATL1C_ASPM_L1_SUPPORT); ++ atl1c_set_aspm(hw, SPEED_0); ++ hw->ctrl_flags = ctrl_flags; + } + + /* + * Set ASPM state. + * Enable/disable L0s/L1 depend on link state. + */ +-static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup) ++static void atl1c_set_aspm(struct atl1c_hw *hw, u16 link_speed) + { + u32 pm_ctrl_data; +- u32 link_ctrl_data; +- u32 link_l1_timer = 0xF; ++ u32 link_l1_timer; + + AT_READ_REG(hw, REG_PM_CTRL, &pm_ctrl_data); +- AT_READ_REG(hw, REG_LINK_CTRL, &link_ctrl_data); ++ pm_ctrl_data &= ~(PM_CTRL_ASPM_L1_EN | ++ PM_CTRL_ASPM_L0S_EN | ++ PM_CTRL_MAC_ASPM_CHK); ++ /* L1 timer */ ++ if (hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) { ++ pm_ctrl_data &= ~PMCTRL_TXL1_AFTER_L0S; ++ link_l1_timer = ++ link_speed == SPEED_1000 || link_speed == SPEED_100 ? ++ L1D_PMCTRL_L1_ENTRY_TM_16US : 1; ++ pm_ctrl_data = FIELD_SETX(pm_ctrl_data, ++ L1D_PMCTRL_L1_ENTRY_TM, link_l1_timer); ++ } else { ++ link_l1_timer = hw->nic_type == athr_l2c_b ? ++ L2CB1_PM_CTRL_L1_ENTRY_TM : L1C_PM_CTRL_L1_ENTRY_TM; ++ if (link_speed != SPEED_1000 && link_speed != SPEED_100) ++ link_l1_timer = 1; ++ pm_ctrl_data = FIELD_SETX(pm_ctrl_data, ++ PM_CTRL_L1_ENTRY_TIMER, link_l1_timer); ++ } + +- pm_ctrl_data &= ~PM_CTRL_SERDES_PD_EX_L1; +- pm_ctrl_data &= ~(PM_CTRL_L1_ENTRY_TIMER_MASK << +- PM_CTRL_L1_ENTRY_TIMER_SHIFT); +- pm_ctrl_data &= ~(PM_CTRL_LCKDET_TIMER_MASK << +- PM_CTRL_LCKDET_TIMER_SHIFT); +- pm_ctrl_data |= AT_LCKDET_TIMER << PM_CTRL_LCKDET_TIMER_SHIFT; ++ /* L0S/L1 enable */ ++ if ((hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT) && link_speed != SPEED_0) ++ pm_ctrl_data |= PM_CTRL_ASPM_L0S_EN | PM_CTRL_MAC_ASPM_CHK; ++ if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT) ++ pm_ctrl_data |= PM_CTRL_ASPM_L1_EN | PM_CTRL_MAC_ASPM_CHK; + ++ /* l2cb & l1d & l2cb2 & l1d2 */ + if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d || +- hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) { +- link_ctrl_data &= ~LINK_CTRL_EXT_SYNC; +- if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE)) { +- if (hw->nic_type == athr_l2c_b && hw->revision_id == L2CB_V10) +- link_ctrl_data |= LINK_CTRL_EXT_SYNC; +- } +- +- AT_WRITE_REG(hw, REG_LINK_CTRL, link_ctrl_data); +- +- pm_ctrl_data |= PM_CTRL_RCVR_WT_TIMER; +- pm_ctrl_data &= ~(PM_CTRL_PM_REQ_TIMER_MASK << +- PM_CTRL_PM_REQ_TIMER_SHIFT); +- pm_ctrl_data |= AT_ASPM_L1_TIMER << +- PM_CTRL_PM_REQ_TIMER_SHIFT; +- pm_ctrl_data &= ~PM_CTRL_SA_DLY_EN; +- pm_ctrl_data &= ~PM_CTRL_HOTRST; +- pm_ctrl_data |= 1 << PM_CTRL_L1_ENTRY_TIMER_SHIFT; +- pm_ctrl_data |= PM_CTRL_SERDES_PD_EX_L1; +- } +- pm_ctrl_data |= PM_CTRL_MAC_ASPM_CHK; +- if (linkup) { +- pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN; +- pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN; +- if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT) +- pm_ctrl_data |= PM_CTRL_ASPM_L1_EN; +- if (hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT) +- pm_ctrl_data |= PM_CTRL_ASPM_L0S_EN; +- +- if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d || +- hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) { +- if (hw->nic_type == athr_l2c_b) +- if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE)) +- pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN; +- pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN; +- pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN; +- pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN; +- pm_ctrl_data |= PM_CTRL_CLK_SWH_L1; +- if (hw->adapter->link_speed == SPEED_100 || +- hw->adapter->link_speed == SPEED_1000) { +- pm_ctrl_data &= ~(PM_CTRL_L1_ENTRY_TIMER_MASK << +- PM_CTRL_L1_ENTRY_TIMER_SHIFT); +- if (hw->nic_type == athr_l2c_b) +- link_l1_timer = 7; +- else if (hw->nic_type == athr_l2c_b2 || +- hw->nic_type == athr_l1d_2) +- link_l1_timer = 4; +- pm_ctrl_data |= link_l1_timer << +- PM_CTRL_L1_ENTRY_TIMER_SHIFT; +- } +- } else { +- pm_ctrl_data |= PM_CTRL_SERDES_L1_EN; +- pm_ctrl_data |= PM_CTRL_SERDES_PLL_L1_EN; +- pm_ctrl_data |= PM_CTRL_SERDES_BUDS_RX_L1_EN; +- pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1; ++ hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) { ++ pm_ctrl_data = FIELD_SETX(pm_ctrl_data, ++ PM_CTRL_PM_REQ_TIMER, PM_CTRL_PM_REQ_TO_DEF); ++ pm_ctrl_data |= PM_CTRL_RCVR_WT_TIMER | ++ PM_CTRL_SERDES_PD_EX_L1 | ++ PM_CTRL_CLK_SWH_L1; ++ pm_ctrl_data &= ~(PM_CTRL_SERDES_L1_EN | ++ PM_CTRL_SERDES_PLL_L1_EN | ++ PM_CTRL_SERDES_BUFS_RX_L1_EN | ++ PM_CTRL_SA_DLY_EN | ++ PM_CTRL_HOTRST); ++ /* disable l0s if link down or l2cb */ ++ if (link_speed == SPEED_0 || hw->nic_type == athr_l2c_b) + pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN; +- pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN; +- ++ } else { /* l1c */ ++ pm_ctrl_data = ++ FIELD_SETX(pm_ctrl_data, PM_CTRL_L1_ENTRY_TIMER, 0); ++ if (link_speed != SPEED_0) { ++ pm_ctrl_data |= PM_CTRL_SERDES_L1_EN | ++ PM_CTRL_SERDES_PLL_L1_EN | ++ PM_CTRL_SERDES_BUFS_RX_L1_EN; ++ pm_ctrl_data &= ~(PM_CTRL_SERDES_PD_EX_L1 | ++ PM_CTRL_CLK_SWH_L1 | ++ PM_CTRL_ASPM_L0S_EN | ++ PM_CTRL_ASPM_L1_EN); ++ } else { /* link down */ ++ pm_ctrl_data |= PM_CTRL_CLK_SWH_L1; ++ pm_ctrl_data &= ~(PM_CTRL_SERDES_L1_EN | ++ PM_CTRL_SERDES_PLL_L1_EN | ++ PM_CTRL_SERDES_BUFS_RX_L1_EN | ++ PM_CTRL_ASPM_L0S_EN); + } +- } else { +- pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN; +- pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN; +- pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN; +- pm_ctrl_data |= PM_CTRL_CLK_SWH_L1; +- +- if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT) +- pm_ctrl_data |= PM_CTRL_ASPM_L1_EN; +- else +- pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN; + } + AT_WRITE_REG(hw, REG_PM_CTRL, pm_ctrl_data); + + return; + } + +-static void atl1c_setup_mac_ctrl(struct atl1c_adapter *adapter) +-{ +- struct atl1c_hw *hw = &adapter->hw; +- struct net_device *netdev = adapter->netdev; +- u32 mac_ctrl_data; +- +- mac_ctrl_data = MAC_CTRL_TX_EN | MAC_CTRL_RX_EN; +- mac_ctrl_data |= (MAC_CTRL_TX_FLOW | MAC_CTRL_RX_FLOW); +- +- if (adapter->link_duplex == FULL_DUPLEX) { +- hw->mac_duplex = true; +- mac_ctrl_data |= MAC_CTRL_DUPLX; +- } +- +- if (adapter->link_speed == SPEED_1000) +- hw->mac_speed = atl1c_mac_speed_1000; +- else +- hw->mac_speed = atl1c_mac_speed_10_100; +- +- mac_ctrl_data |= (hw->mac_speed & MAC_CTRL_SPEED_MASK) << +- MAC_CTRL_SPEED_SHIFT; +- +- mac_ctrl_data |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD); +- mac_ctrl_data |= ((hw->preamble_len & MAC_CTRL_PRMLEN_MASK) << +- MAC_CTRL_PRMLEN_SHIFT); +- +- __atl1c_vlan_mode(netdev->features, &mac_ctrl_data); +- +- mac_ctrl_data |= MAC_CTRL_BC_EN; +- if (netdev->flags & IFF_PROMISC) +- mac_ctrl_data |= MAC_CTRL_PROMIS_EN; +- if (netdev->flags & IFF_ALLMULTI) +- mac_ctrl_data |= MAC_CTRL_MC_ALL_EN; +- +- mac_ctrl_data |= MAC_CTRL_SINGLE_PAUSE_EN; +- if (hw->nic_type == athr_l1d || hw->nic_type == athr_l2c_b2 || +- hw->nic_type == athr_l1d_2) { +- mac_ctrl_data |= MAC_CTRL_SPEED_MODE_SW; +- mac_ctrl_data |= MAC_CTRL_HASH_ALG_CRC32; +- } +- AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data); +-} +- + /* + * atl1c_configure - Configure Transmit&Receive Unit after Reset + * @adapter: board private structure + * + * Configure the Tx /Rx unit of the MAC after a reset. + */ +-static int atl1c_configure(struct atl1c_adapter *adapter) ++static int atl1c_configure_mac(struct atl1c_adapter *adapter) + { + struct atl1c_hw *hw = &adapter->hw; + u32 master_ctrl_data = 0; + u32 intr_modrt_data; + u32 data; + ++ AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data); ++ master_ctrl_data &= ~(MASTER_CTRL_TX_ITIMER_EN | ++ MASTER_CTRL_RX_ITIMER_EN | ++ MASTER_CTRL_INT_RDCLR); + /* clear interrupt status */ + AT_WRITE_REG(hw, REG_ISR, 0xFFFFFFFF); + /* Clear any WOL status */ +@@ -1524,30 +1417,39 @@ static int atl1c_configure(struct atl1c_adapter *adapter) + master_ctrl_data |= MASTER_CTRL_SA_TIMER_EN; + AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data); + +- if (hw->ctrl_flags & ATL1C_CMB_ENABLE) { +- AT_WRITE_REG(hw, REG_CMB_TPD_THRESH, +- hw->cmb_tpd & CMB_TPD_THRESH_MASK); +- AT_WRITE_REG(hw, REG_CMB_TX_TIMER, +- hw->cmb_tx_timer & CMB_TX_TIMER_MASK); +- } ++ AT_WRITE_REG(hw, REG_SMB_STAT_TIMER, ++ hw->smb_timer & SMB_STAT_TIMER_MASK); + +- if (hw->ctrl_flags & ATL1C_SMB_ENABLE) +- AT_WRITE_REG(hw, REG_SMB_STAT_TIMER, +- hw->smb_timer & SMB_STAT_TIMER_MASK); + /* set MTU */ + AT_WRITE_REG(hw, REG_MTU, hw->max_frame_size + ETH_HLEN + + VLAN_HLEN + ETH_FCS_LEN); +- /* HDS, disable */ +- AT_WRITE_REG(hw, REG_HDS_CTRL, 0); + + atl1c_configure_tx(adapter); + atl1c_configure_rx(adapter); +- atl1c_configure_rss(adapter); + atl1c_configure_dma(adapter); + + return 0; + } + ++static int atl1c_configure(struct atl1c_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ int num; ++ ++ atl1c_init_ring_ptrs(adapter); ++ atl1c_set_multi(netdev); ++ atl1c_restore_vlan(adapter); ++ ++ num = atl1c_alloc_rx_buffer(adapter); ++ if (unlikely(num == 0)) ++ return -ENOMEM; ++ ++ if (atl1c_configure_mac(adapter)) ++ return -EIO; ++ ++ return 0; ++} ++ + static void atl1c_update_hw_stats(struct atl1c_adapter *adapter) + { + u16 hw_reg_addr = 0; +@@ -1634,16 +1536,11 @@ static bool atl1c_clean_tx_irq(struct atl1c_adapter *adapter, + struct pci_dev *pdev = adapter->pdev; + u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean); + u16 hw_next_to_clean; +- u16 shift; +- u32 data; ++ u16 reg; + +- if (type == atl1c_trans_high) +- shift = MB_HTPD_CONS_IDX_SHIFT; +- else +- shift = MB_NTPD_CONS_IDX_SHIFT; ++ reg = type == atl1c_trans_high ? REG_TPD_PRI1_CIDX : REG_TPD_PRI0_CIDX; + +- AT_READ_REG(&adapter->hw, REG_MB_PRIO_CONS_IDX, &data); +- hw_next_to_clean = (data >> shift) & MB_PRIO_PROD_IDX_MASK; ++ AT_READ_REGW(&adapter->hw, reg, &hw_next_to_clean); + + while (next_to_clean != hw_next_to_clean) { + buffer_info = &tpd_ring->buffer_info[next_to_clean]; +@@ -1745,9 +1642,9 @@ static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter, + skb_checksum_none_assert(skb); + } + +-static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, const int ringid) ++static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) + { +- struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring[ringid]; ++ struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct pci_dev *pdev = adapter->pdev; + struct atl1c_buffer *buffer_info, *next_info; + struct sk_buff *skb; +@@ -1799,7 +1696,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, const int ringid + /* TODO: update mailbox here */ + wmb(); + rfd_ring->next_to_use = rfd_next_to_use; +- AT_WRITE_REG(&adapter->hw, atl1c_rfd_prod_idx_regs[ringid], ++ AT_WRITE_REG(&adapter->hw, REG_MB_RFD0_PROD_IDX, + rfd_ring->next_to_use & MB_RFDX_PROD_IDX_MASK); + } + +@@ -1838,7 +1735,7 @@ static void atl1c_clean_rfd(struct atl1c_rfd_ring *rfd_ring, + rfd_ring->next_to_clean = rfd_index; + } + +-static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, u8 que, ++static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, + int *work_done, int work_to_do) + { + u16 rfd_num, rfd_index; +@@ -1846,8 +1743,8 @@ static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, u8 que, + u16 length; + struct pci_dev *pdev = adapter->pdev; + struct net_device *netdev = adapter->netdev; +- struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring[que]; +- struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring[que]; ++ struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring; ++ struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct sk_buff *skb; + struct atl1c_recv_ret_status *rrs; + struct atl1c_buffer *buffer_info; +@@ -1913,7 +1810,7 @@ rrs_checked: + count++; + } + if (count) +- atl1c_alloc_rx_buffer(adapter, que); ++ atl1c_alloc_rx_buffer(adapter); + } + + /* +@@ -1930,7 +1827,7 @@ static int atl1c_clean(struct napi_struct *napi, int budget) + if (!netif_carrier_ok(adapter->netdev)) + goto quit_polling; + /* just enable one RXQ */ +- atl1c_clean_rx_irq(adapter, 0, &work_done, budget); ++ atl1c_clean_rx_irq(adapter, &work_done, budget); + + if (work_done < budget) { + quit_polling: +@@ -2205,23 +2102,10 @@ static void atl1c_tx_queue(struct atl1c_adapter *adapter, struct sk_buff *skb, + struct atl1c_tpd_desc *tpd, enum atl1c_trans_queue type) + { + struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type]; +- u32 prod_data; ++ u16 reg; + +- AT_READ_REG(&adapter->hw, REG_MB_PRIO_PROD_IDX, &prod_data); +- switch (type) { +- case atl1c_trans_high: +- prod_data &= 0xFFFF0000; +- prod_data |= tpd_ring->next_to_use & 0xFFFF; +- break; +- case atl1c_trans_normal: +- prod_data &= 0x0000FFFF; +- prod_data |= (tpd_ring->next_to_use & 0xFFFF) << 16; +- break; +- default: +- break; +- } +- wmb(); +- AT_WRITE_REG(&adapter->hw, REG_MB_PRIO_PROD_IDX, prod_data); ++ reg = type == atl1c_trans_high ? REG_TPD_PRI1_PIDX : REG_TPD_PRI0_PIDX; ++ AT_WRITE_REGW(&adapter->hw, reg, tpd_ring->next_to_use); + } + + static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb, +@@ -2327,44 +2211,38 @@ static int atl1c_request_irq(struct atl1c_adapter *adapter) + return err; + } + ++ ++static void atl1c_reset_dma_ring(struct atl1c_adapter *adapter) ++{ ++ /* release tx-pending skbs and reset tx/rx ring index */ ++ atl1c_clean_tx_ring(adapter, atl1c_trans_normal); ++ atl1c_clean_tx_ring(adapter, atl1c_trans_high); ++ atl1c_clean_rx_ring(adapter); ++} ++ + static int atl1c_up(struct atl1c_adapter *adapter) + { + struct net_device *netdev = adapter->netdev; +- int num; + int err; +- int i; + + netif_carrier_off(netdev); +- atl1c_init_ring_ptrs(adapter); +- atl1c_set_multi(netdev); +- atl1c_restore_vlan(adapter); +- +- for (i = 0; i < adapter->num_rx_queues; i++) { +- num = atl1c_alloc_rx_buffer(adapter, i); +- if (unlikely(num == 0)) { +- err = -ENOMEM; +- goto err_alloc_rx; +- } +- } + +- if (atl1c_configure(adapter)) { +- err = -EIO; ++ err = atl1c_configure(adapter); ++ if (unlikely(err)) + goto err_up; +- } + + err = atl1c_request_irq(adapter); + if (unlikely(err)) + goto err_up; + ++ atl1c_check_link_status(adapter); + clear_bit(__AT_DOWN, &adapter->flags); + napi_enable(&adapter->napi); + atl1c_irq_enable(adapter); +- atl1c_check_link_status(adapter); + netif_start_queue(netdev); + return err; + + err_up: +-err_alloc_rx: + atl1c_clean_rx_ring(adapter); + return err; + } +@@ -2382,15 +2260,15 @@ static void atl1c_down(struct atl1c_adapter *adapter) + napi_disable(&adapter->napi); + atl1c_irq_disable(adapter); + atl1c_free_irq(adapter); ++ /* disable ASPM if device inactive */ ++ atl1c_disable_l0s_l1(&adapter->hw); + /* reset MAC to disable all RX/TX */ + atl1c_reset_mac(&adapter->hw); + msleep(1); + + adapter->link_speed = SPEED_0; + adapter->link_duplex = -1; +- atl1c_clean_tx_ring(adapter, atl1c_trans_normal); +- atl1c_clean_tx_ring(adapter, atl1c_trans_high); +- atl1c_clean_rx_ring(adapter); ++ atl1c_reset_dma_ring(adapter); + } + + /* +@@ -2423,13 +2301,6 @@ static int atl1c_open(struct net_device *netdev) + if (unlikely(err)) + goto err_up; + +- if (adapter->hw.ctrl_flags & ATL1C_FPGA_VERSION) { +- u32 phy_data; +- +- AT_READ_REG(&adapter->hw, REG_MDIO_CTRL, &phy_data); +- phy_data |= MDIO_AP_EN; +- AT_WRITE_REG(&adapter->hw, REG_MDIO_CTRL, phy_data); +- } + return 0; + + err_up: +@@ -2455,6 +2326,8 @@ static int atl1c_close(struct net_device *netdev) + struct atl1c_adapter *adapter = netdev_priv(netdev); + + WARN_ON(test_bit(__AT_RESETTING, &adapter->flags)); ++ set_bit(__AT_DOWN, &adapter->flags); ++ cancel_work_sync(&adapter->common_task); + atl1c_down(adapter); + atl1c_free_ring_resources(adapter); + return 0; +@@ -2466,10 +2339,6 @@ static int atl1c_suspend(struct device *dev) + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl1c_adapter *adapter = netdev_priv(netdev); + struct atl1c_hw *hw = &adapter->hw; +- u32 mac_ctrl_data = 0; +- u32 master_ctrl_data = 0; +- u32 wol_ctrl_data = 0; +- u16 mii_intr_status_data = 0; + u32 wufc = adapter->wol; + + atl1c_disable_l0s_l1(hw); +@@ -2480,75 +2349,10 @@ static int atl1c_suspend(struct device *dev) + netif_device_detach(netdev); + + if (wufc) +- if (atl1c_phy_power_saving(hw) != 0) ++ if (atl1c_phy_to_ps_link(hw) != 0) + dev_dbg(&pdev->dev, "phy power saving failed"); + +- AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data); +- AT_READ_REG(hw, REG_MAC_CTRL, &mac_ctrl_data); +- +- master_ctrl_data &= ~MASTER_CTRL_CLK_SEL_DIS; +- mac_ctrl_data &= ~(MAC_CTRL_PRMLEN_MASK << MAC_CTRL_PRMLEN_SHIFT); +- mac_ctrl_data |= (((u32)adapter->hw.preamble_len & +- MAC_CTRL_PRMLEN_MASK) << +- MAC_CTRL_PRMLEN_SHIFT); +- mac_ctrl_data &= ~(MAC_CTRL_SPEED_MASK << MAC_CTRL_SPEED_SHIFT); +- mac_ctrl_data &= ~MAC_CTRL_DUPLX; +- +- if (wufc) { +- mac_ctrl_data |= MAC_CTRL_RX_EN; +- if (adapter->link_speed == SPEED_1000 || +- adapter->link_speed == SPEED_0) { +- mac_ctrl_data |= atl1c_mac_speed_1000 << +- MAC_CTRL_SPEED_SHIFT; +- mac_ctrl_data |= MAC_CTRL_DUPLX; +- } else +- mac_ctrl_data |= atl1c_mac_speed_10_100 << +- MAC_CTRL_SPEED_SHIFT; +- +- if (adapter->link_duplex == DUPLEX_FULL) +- mac_ctrl_data |= MAC_CTRL_DUPLX; +- +- /* turn on magic packet wol */ +- if (wufc & AT_WUFC_MAG) +- wol_ctrl_data |= WOL_MAGIC_EN | WOL_MAGIC_PME_EN; +- +- if (wufc & AT_WUFC_LNKC) { +- wol_ctrl_data |= WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN; +- /* only link up can wake up */ +- if (atl1c_write_phy_reg(hw, MII_IER, IER_LINK_UP) != 0) { +- dev_dbg(&pdev->dev, "%s: read write phy " +- "register failed.\n", +- atl1c_driver_name); +- } +- } +- /* clear phy interrupt */ +- atl1c_read_phy_reg(hw, MII_ISR, &mii_intr_status_data); +- /* Config MAC Ctrl register */ +- __atl1c_vlan_mode(netdev->features, &mac_ctrl_data); +- +- /* magic packet maybe Broadcast&multicast&Unicast frame */ +- if (wufc & AT_WUFC_MAG) +- mac_ctrl_data |= MAC_CTRL_BC_EN; +- +- dev_dbg(&pdev->dev, +- "%s: suspend MAC=0x%x\n", +- atl1c_driver_name, mac_ctrl_data); +- AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data); +- AT_WRITE_REG(hw, REG_WOL_CTRL, wol_ctrl_data); +- AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data); +- +- AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT | +- GPHY_CTRL_EXT_RESET); +- } else { +- AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_POWER_SAVING); +- master_ctrl_data |= MASTER_CTRL_CLK_SEL_DIS; +- mac_ctrl_data |= atl1c_mac_speed_10_100 << MAC_CTRL_SPEED_SHIFT; +- mac_ctrl_data |= MAC_CTRL_DUPLX; +- AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data); +- AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data); +- AT_WRITE_REG(hw, REG_WOL_CTRL, 0); +- hw->phy_configured = false; /* re-init PHY when resume */ +- } ++ atl1c_power_saving(hw, wufc); + + return 0; + } +@@ -2561,8 +2365,7 @@ static int atl1c_resume(struct device *dev) + struct atl1c_adapter *adapter = netdev_priv(netdev); + + AT_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0); +- atl1c_reset_pcie(&adapter->hw, ATL1C_PCIE_L0S_L1_DISABLE | +- ATL1C_PCIE_PHY_RESET); ++ atl1c_reset_pcie(&adapter->hw, ATL1C_PCIE_L0S_L1_DISABLE); + + atl1c_phy_reset(&adapter->hw); + atl1c_reset_mac(&adapter->hw); +@@ -2713,7 +2516,7 @@ static int __devinit atl1c_probe(struct pci_dev *pdev, + adapter->mii.mdio_read = atl1c_mdio_read; + adapter->mii.mdio_write = atl1c_mdio_write; + adapter->mii.phy_id_mask = 0x1f; +- adapter->mii.reg_num_mask = MDIO_REG_ADDR_MASK; ++ adapter->mii.reg_num_mask = MDIO_CTRL_REG_MASK; + netif_napi_add(netdev, &adapter->napi, atl1c_clean, 64); + setup_timer(&adapter->phy_config_timer, atl1c_phy_config, + (unsigned long)adapter); +@@ -2723,8 +2526,7 @@ static int __devinit atl1c_probe(struct pci_dev *pdev, + dev_err(&pdev->dev, "net device private data init failed\n"); + goto err_sw_init; + } +- atl1c_reset_pcie(&adapter->hw, ATL1C_PCIE_L0S_L1_DISABLE | +- ATL1C_PCIE_PHY_RESET); ++ atl1c_reset_pcie(&adapter->hw, ATL1C_PCIE_L0S_L1_DISABLE); + + /* Init GPHY as early as possible due to power saving issue */ + atl1c_phy_reset(&adapter->hw); +@@ -2753,7 +2555,7 @@ static int __devinit atl1c_probe(struct pci_dev *pdev, + dev_dbg(&pdev->dev, "mac address : %pM\n", + adapter->hw.mac_addr); + +- atl1c_hw_set_mac_addr(&adapter->hw); ++ atl1c_hw_set_mac_addr(&adapter->hw, adapter->hw.mac_addr); + INIT_WORK(&adapter->common_task, atl1c_common_task); + adapter->work_event = 0; + err = register_netdev(netdev); +@@ -2798,6 +2600,8 @@ static void __devexit atl1c_remove(struct pci_dev *pdev) + struct atl1c_adapter *adapter = netdev_priv(netdev); + + unregister_netdev(netdev); ++ /* restore permanent address */ ++ atl1c_hw_set_mac_addr(&adapter->hw, adapter->hw.perm_mac_addr); + atl1c_phy_disable(&adapter->hw); + + iounmap(adapter->hw.hw_addr); diff --git a/bcma-brcmsmac-compat.patch b/bcma-brcmsmac-compat.patch new file mode 100644 index 000000000..269cc862f --- /dev/null +++ b/bcma-brcmsmac-compat.patch @@ -0,0 +1,35 @@ +Simple patch to remove the overlap between the bcma (i.e. b43) driver +and the brcmsmac driver. David Woodhouse +confirmed that this patch restores functionality of bcm4331 devices. + +-- John W. Linville + +diff -up linux-3.1.x86_64/drivers/bcma/host_pci.c.orig linux-3.1.x86_64/drivers/bcma/host_pci.c +--- linux-3.1.x86_64/drivers/bcma/host_pci.c.orig 2011-11-10 11:41:26.829742757 -0500 ++++ linux-3.1.x86_64/drivers/bcma/host_pci.c 2011-11-10 11:41:22.884792078 -0500 +@@ -225,11 +225,13 @@ static void bcma_host_pci_remove(struct + } + + static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = { +- { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) }, ++#if 0 /* Not in Fedora... */ ++ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, ++#endif + { 0, }, + }; + MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl); + +--- linux-2.6.43.noarch/drivers/net/wireless/brcm80211/Kconfig~ 2012-03-26 12:37:17.512820450 -0400 ++++ linux-2.6.43.noarch/drivers/net/wireless/brcm80211/Kconfig 2012-03-26 12:37:36.270777605 -0400 +@@ -4,7 +4,6 @@ config BRCMUTIL + config BRCMSMAC + tristate "Broadcom IEEE802.11n PCIe SoftMAC WLAN driver" + depends on MAC80211 +- depends on BCMA + select BRCMUTIL + select FW_LOADER + select CRC_CCITT diff --git a/binfmt_elf-fix-PIE-execution-with-random-disabled.patch b/binfmt_elf-fix-PIE-execution-with-random-disabled.patch new file mode 100644 index 000000000..b376c88a9 --- /dev/null +++ b/binfmt_elf-fix-PIE-execution-with-random-disabled.patch @@ -0,0 +1,87 @@ +On Mon, 3 Oct 2011, Josh Boyer wrote: + +> > > Perhaps another check here for randomize? Something like: +> > > +> > > #if defined(CONFIG_X86) || defined(CONFIG_ARM) +> > > if (current->flags & PF_RANDOMIZE) +> > > load_bias = 0; +> > > else if (vaddr) +> > > load_bias = 0; +> > > else +> > > load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE); +> > > #else +> > > load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); +> > > #endif +> > > +> > > If that's stupid, then feel free to tell me. I won't pretend like I +> > > understand what is going on here yet, but based on the explanation you +> > > provided that might work. +> > +> > I have just verified my hunch that the original patch from H.J. / Josh +> > breaks ASLR completely, so Andrew, please drop it for now. +> +> Yes, please drop the original. + +Thanks. + +> > I am now looking into how to fix things properly. +> > +> > Josh, looking at what you are proposing -- do you see any reason to make +> > the behavior different in #else branch and in !(current->flags & +> > PF_RANDOMIZE) case? +> +> I was mostly just trying to adapt H.J.'s patch to account for the +> PF_RANDOMIZE case. Looking at it a bit more, I'm not sure why they +> would need to be different. H.J., do you recall why you made that +> change originally? + +How about the patch below instead? It survives my testing, and I believe +it handles both cases properly. + +Confirmation from the original bug reporter would obviously be a nice +bonus too :) + + + + +From: Jiri Kosina +Subject: [PATCH] binfmt_elf: fix PIE execution with randomization disabled + +The case of address space randomization being disabled in runtime through +randomize_va_space sysctl is not treated properly in load_elf_binary(), +resulting in SIGKILL coming at exec() time for certain PIE-linked binaries +in case the randomization has been disabled at runtime prior to calling +exec(). + +Handle the randomize_va_space == 0 case the same way as if we were not +supporting .text randomization at all. + +Based on original patch by H.J. Lu and +Josh Boyer + +Cc: Ingo Molnar +Cc: Jiri Kosina +Cc: Nicolas Pitre +Cc: Russell King +Signed-off-by: Jiri Kosina +--- + fs/binfmt_elf.c | 5 ++++- + 1 files changed, 4 insertions(+), 1 deletions(-) + +diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c +index dd0fdfc..bb11fe4 100644 +--- a/fs/binfmt_elf.c ++++ b/fs/binfmt_elf.c +@@ -795,7 +795,10 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) + * might try to exec. This is because the brk will + * follow the loader, and is not movable. */ + #if defined(CONFIG_X86) || defined(CONFIG_ARM) +- load_bias = 0; ++ if (current->flags & PF_RANDOMIZE) ++ load_bias = 0; ++ else ++ load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); + #else + load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); + #endif + diff --git a/bluetooth-use-after-free.patch b/bluetooth-use-after-free.patch new file mode 100644 index 000000000..0d21cad9a --- /dev/null +++ b/bluetooth-use-after-free.patch @@ -0,0 +1,105 @@ +From 2a5a5ec620a29d4ba07743c3151cdf0a417c8f8c Mon Sep 17 00:00:00 2001 +From: Andrei Emeltchenko +Date: Thu, 2 Feb 2012 10:32:18 +0200 +Subject: [PATCH] Bluetooth: Use list _safe deleting from conn chan_list + +Fixes possible bug when deleting element from the list in +function hci_chan_list_flush. list_for_each_entry_rcu is used +and after deleting element from the list we also free pointer +and then list_entry_rcu is taken from freed pointer. + +Signed-off-by: Andrei Emeltchenko +Acked-by: Marcel Holtmann +Signed-off-by: Johan Hedberg +--- + net/bluetooth/hci_conn.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c +index b074bd6..b4ecdde 100644 +--- a/net/bluetooth/hci_conn.c ++++ b/net/bluetooth/hci_conn.c +@@ -975,10 +975,10 @@ int hci_chan_del(struct hci_chan *chan) + + void hci_chan_list_flush(struct hci_conn *conn) + { +- struct hci_chan *chan; ++ struct hci_chan *chan, *n; + + BT_DBG("conn %p", conn); + +- list_for_each_entry_rcu(chan, &conn->chan_list, list) ++ list_for_each_entry_safe(chan, n, &conn->chan_list, list) + hci_chan_del(chan); + } +-- +1.7.6.5 + +From 3c4e0df028935618d052235ba85bc7079be13394 Mon Sep 17 00:00:00 2001 +From: Andrei Emeltchenko +Date: Thu, 2 Feb 2012 10:32:17 +0200 +Subject: [PATCH] Bluetooth: Use list _safe deleting from conn_hash_list + +Use list_for_each_entry_safe which is safe version against removal +of list entry. Otherwise we remove hci_conn element and reference +next element which result in accessing LIST_POISON. + +[ 95.571834] Bluetooth: unknown link type 127 +[ 95.578349] BUG: unable to handle kernel paging request at 20002000 +[ 95.580236] IP: [<20002000>] 0x20001fff +[ 95.580763] *pde = 00000000 +[ 95.581196] Oops: 0000 [#1] SMP +... +[ 95.582298] Pid: 3355, comm: hciconfig Tainted: G O 3.2.0-VirttualBox +[ 95.582298] EIP: 0060:[<20002000>] EFLAGS: 00210206 CPU: 0 +[ 95.582298] EIP is at 0x20002000 +... +[ 95.582298] Call Trace: +[ 95.582298] [] ? hci_conn_hash_flush+0x76/0xf0 [bluetooth] +[ 95.582298] [] hci_dev_do_close+0xc1/0x2e0 [bluetooth] +[ 95.582298] [] ? hci_dev_get+0x69/0xb0 [bluetooth] +[ 95.582298] [] hci_dev_close+0x2a/0x50 [bluetooth] +[ 95.582298] [] hci_sock_ioctl+0x1af/0x3f0 [bluetooth] +[ 95.582298] [] ? handle_pte_fault+0x8a/0x8f0 +[ 95.582298] [] sock_ioctl+0x5f/0x260 +[ 95.582298] [] ? sock_fasync+0x90/0x90 +[ 95.582298] [] do_vfs_ioctl+0x83/0x5b0 +[ 95.582298] [] ? do_page_fault+0x297/0x500 +[ 95.582298] [] ? spurious_fault+0xd0/0xd0 +[ 95.582298] [] ? up_read+0x1b/0x30 +[ 95.582298] [] ? do_page_fault+0x297/0x500 +[ 95.582298] [] ? init_fpu+0xef/0x160 +[ 95.582298] [] ? do_debug+0x180/0x180 +[ 95.582298] [] ? fpu_finit+0x28/0x80 +[ 95.582298] [] sys_ioctl+0x87/0x90 +[ 95.582298] [] sysenter_do_call+0x12/0x38 +... + +Signed-off-by: Andrei Emeltchenko +Acked-by: Marcel Holtmann +Signed-off-by: Johan Hedberg +--- + net/bluetooth/hci_conn.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c +index aca71c0..b074bd6 100644 +--- a/net/bluetooth/hci_conn.c ++++ b/net/bluetooth/hci_conn.c +@@ -795,11 +795,11 @@ timer: + void hci_conn_hash_flush(struct hci_dev *hdev) + { + struct hci_conn_hash *h = &hdev->conn_hash; +- struct hci_conn *c; ++ struct hci_conn *c, *n; + + BT_DBG("hdev %s", hdev->name); + +- list_for_each_entry_rcu(c, &h->list, list) { ++ list_for_each_entry_safe(c, n, &h->list, list) { + c->state = BT_CLOSED; + + hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM); +-- +1.7.6.5 + diff --git a/config-arm b/config-arm-generic similarity index 52% rename from config-arm rename to config-arm-generic index e2d8af390..6cb515ddb 100644 --- a/config-arm +++ b/config-arm-generic @@ -9,6 +9,7 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_ARCH_VERSATILE=y CONFIG_ARCH_VERSATILE_PB=y CONFIG_MACH_VERSATILE_AB=y +CONFIG_MACH_VERSATILE_DT=y CONFIG_HIGHMEM=y # CONFIG_HIGHPTE is not set @@ -82,9 +83,12 @@ CONFIG_FB_ARMCLCD=m CONFIG_SND_ARM=y CONFIG_SND_ARMAACI=m +CONFIG_SND_SOC=m +# CONFIG_SND_SOC_CACHE_LZO is not set +# CONFIG_SND_SOC_ALL_CODECS is not set -CONFIG_USB_MUSB_HDRC=m -# CONFIG_MUSB_PIO_ONLY is not set +CONFIG_USB_MUSB_HDRC=y +CONFIG_MUSB_PIO_ONLY=y CONFIG_USB_TUSB6010=y # CONFIG_USB_MUSB_DEBUG is not set @@ -135,3 +139,75 @@ CONFIG_STRICT_DEVMEM=y # CONFIG_HVC_DCC is not set CONFIG_SPARSE_IRQ=y + +# CONFIG_ARM_PATCH_PHYS_VIRT is not set + +CONFIG_HWSPINLOCK_OMAP=m + +CONFIG_USE_OF=y +CONFIG_PROC_DEVICETREE=y +CONFIG_MTD_PHYSMAP_OF=m +CONFIG_SERIAL_OF_PLATFORM=m +CONFIG_MMC_SDHCI_OF=m +CONFIG_MMC_SDHCI_PXAV3=m +CONFIG_MMC_SDHCI_PXAV2=m + +CONFIG_ARM_APPENDED_DTB=y +CONFIG_MTD_OF_PARTS=y +CONFIG_PL330_DMA=y +# CONFIG_ARM_KPROBES_TEST is not set +# CONFIG_ARM_ATAG_DTB_COMPAT is not set + +# CONFIG_FTGMAC100 is not set +# CONFIG_FTMAC100 is not set +# +CONFIG_DEFAULT_MMAP_MIN_ADDR=32768 +CONFIG_LSM_MMAP_MIN_ADDR=32768 + +# disable TPM on arm at least on the trimslices it causes havoc +# CONFIG_TCG_TPM is not set +# CONFIG_IMA is not set + +# ERROR: "__bswapsi2" [drivers/staging/crystalhd/crystalhd.ko] undefined! +# CONFIG_CRYSTALHD is not set + +# these modules all fail with missing __bad_udelay +# http://www.spinics.net/lists/arm/msg15615.html provides some background +# CONFIG_SUNGEM is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_RADEON is not set +# CONFIG_DRM_RADEON is not set +# CONFIG_ATM_HE is not set +# CONFIG_SCSI_ACARD is not set + +# these all currently fail due to missing symbols __bad_udelay or +# error: implicit declaration of function ‘iowrite32be’ +# CONFIG_SND_ALI5451 is not set +# CONFIG_DRM_NOUVEAU is not set +# CONFIG_MLX4_EN is not set + +# FIXME: Guesses, need checking +# CONFIG_MACH_EUKREA_CPUIMX35SD is not set +CONFIG_ARM_ERRATA_720789=y +CONFIG_ARM_ERRATA_751472=y +<<<<<<< HEAD +======= +CONFIG_ARM_ERRATA_326103=y +CONFIG_OMAP4_ERRATA_I688=y +>>>>>>> 99667a9... Linux 3.3.5 +# CONFIG_FB_MX3 is not set +# CONFIG_MX3_IPU is not set +# CONFIG_MX3_IPU_IRQS is not set + +# CONFIG_OF_SELFTEST is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set + +# CONFIG_MACH_IMX51_DT is not set +# CONFIG_MACH_IMX53_DT is not set +# CONFIG_MACH_MX53_EVK is not set +# CONFIG_MACH_MX53_SMD is not set +# CONFIG_MACH_MX53_LOCO is not set +# CONFIG_MACH_MX53_ARD is not set +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set diff --git a/config-arm-highbank b/config-arm-highbank new file mode 100644 index 000000000..8cd7fc3b5 --- /dev/null +++ b/config-arm-highbank @@ -0,0 +1,17 @@ +ONFIG_ARCH_HIGHBANK=y +CONFIG_VFP=y +CONFIG_NEON=y + +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEBUG=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_NET_CALXEDA_XGMAC=y diff --git a/config-arm-imx b/config-arm-imx new file mode 100644 index 000000000..2dbe10a1f --- /dev/null +++ b/config-arm-imx @@ -0,0 +1,98 @@ +CONFIG_ARCH_MXC=y +CONFIG_ARCH_MX51=y +CONFIG_MACH_MX51_BABBAGE=y +CONFIG_MACH_MX51_3DS=y +CONFIG_MACH_EUKREA_CPUIMX51=y +CONFIG_VFP=y +CONFIG_NEON=y + +CONFIG_MACH_EUKREA_CPUIMX51SD=y +CONFIG_MACH_MX51_EFIKAMX=y +CONFIG_MACH_MX51_EFIKASB=y +# CONFIG_SWP_EMULATE is not set +# CONFIG_THUMB2_KERNEL is not set +CONFIG_CPU_FREQ_IMX=y +CONFIG_W1_MASTER_MXC=m +CONFIG_IMX_SDMA=y +CONFIG_MACH_MX31ADS=y +CONFIG_MACH_MX31LILLY=y +CONFIG_MACH_MX31LITE=y +CONFIG_MACH_PCM037=y +CONFIG_MACH_MX31_3DS=y +CONFIG_MACH_MX31MOBOARD=y +CONFIG_MACH_QONG=y +CONFIG_MACH_ARMADILLO5X0=y +CONFIG_MACH_KZM_ARM11_01=y +CONFIG_MACH_BUG=y +CONFIG_MACH_PCM043=y +CONFIG_MACH_MX35_3DS=y +CONFIG_MACH_EUKREA_CPUIMX35=y +CONFIG_MACH_VPR200=y +CONFIG_SOC_IMX6Q=y +CONFIG_MXC_IRQ_PRIOR=y +CONFIG_MXC_PWM=m +CONFIG_MXC_DEBUG_BOARD=y +# CONFIG_CPU_BPREDICT_DISABLE is not set +# CONFIG_CACHE_L2X0 is not set +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_ARM_ERRATA_411920=y +CONFIG_PL310_ERRATA_588369=y +CONFIG_PL310_ERRATA_727915=y +CONFIG_ARM_ERRATA_364296=y +CONFIG_HW_PERF_EVENTS=y +CONFIG_RFKILL_GPIO=m +CONFIG_PATA_IMX=m +CONFIG_ETHERNET=y +CONFIG_NET_VENDOR_BROADCOM=y +CONFIG_NET_VENDOR_FREESCALE=y +CONFIG_FEC=y +CONFIG_KEYBOARD_IMX=m +CONFIG_SERIAL_IMX=y +CONFIG_HW_RANDOM_MXC_RNGA=m +CONFIG_I2C_IMX=m +CONFIG_GPIO_GENERIC_PLATFORM=y +CONFIG_GPIO_MCP23S08=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_PLL=m +CONFIG_SND_IMX_SOC=m +CONFIG_USB_EHCI_MXC=y +CONFIG_USB_IMX21_HCD=m +CONFIG_MMC_SDHCI_ESDHC_IMX=m +CONFIG_MMC_MXC=m +CONFIG_RTC_MXC=m + +CONFIG_BACKLIGHT_PWM=m +CONFIG_LEDS_PWM=m + +CONFIG_MACH_PCM037_EET=y +# CONFIG_MACH_MX31_3DS_MXC_NAND_USE_BBT is not set +CONFIG_MXC_USE_EPIT=y +CONFIG_ARM_THUMBEE=y +CONFIG_ARM_ERRATA_430973=y +CONFIG_ARM_ERRATA_458693=y +CONFIG_ARM_ERRATA_460075=y +CONFIG_ARM_ERRATA_743622=y +CONFIG_ARM_ERRATA_754322=y +CONFIG_CAN_FLEXCAN=m +CONFIG_MTD_NAND_MXC=m +CONFIG_INPUT_PWM_BEEPER=m +CONFIG_SERIAL_IMX_CONSOLE=y +CONFIG_IMX2_WDT=m +CONFIG_SND_SOC_PHYCORE_AC97=m +CONFIG_SND_SOC_EUKREA_TLV320=m + +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEBUG=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y + +CONFIG_PL310_ERRATA_769419=y +CONFIG_LEDS_RENESAS_TPU=y diff --git a/config-arm-kirkwood b/config-arm-kirkwood new file mode 100644 index 000000000..415e822dc --- /dev/null +++ b/config-arm-kirkwood @@ -0,0 +1,43 @@ +CONFIG_ARCH_KIRKWOOD=y +CONFIG_MACH_DB88F6281_BP=y +CONFIG_MACH_RD88F6192_NAS=y +CONFIG_MACH_RD88F6281=y +CONFIG_MACH_MV88F6281GTW_GE=y +CONFIG_MACH_SHEEVAPLUG=y +CONFIG_MACH_ESATA_SHEEVAPLUG=y +CONFIG_MACH_GURUPLUG=y +CONFIG_MACH_DOCKSTAR=y +CONFIG_MACH_TS219=y +CONFIG_MACH_TS41X=y +CONFIG_MACH_OPENRD_BASE=y +CONFIG_MACH_OPENRD_CLIENT=y +CONFIG_MACH_OPENRD_ULTIMATE=y +CONFIG_MACH_NETSPACE_V2=y +CONFIG_MACH_INETSPACE_V2=y +CONFIG_MACH_NETSPACE_MAX_V2=y +CONFIG_MACH_D2NET_V2=y +CONFIG_MACH_NET2BIG_V2=y +CONFIG_MACH_NET5BIG_V2=y +CONFIG_MACH_T5325=y +# CONFIG_CPU_FEROCEON_OLD_ID is not set + + +CONFIG_CACHE_FEROCEON_L2=y +CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH=y +CONFIG_MTD_NAND_ORION=m +CONFIG_MV643XX_ETH=m +CONFIG_I2C_MV64XXX=m +CONFIG_GPIO_GENERIC_PLATFORM=y +CONFIG_GPIO_MCP23S08=m +CONFIG_ORION_WATCHDOG=m +CONFIG_SND_KIRKWOOD_SOC=m +CONFIG_SND_KIRKWOOD_SOC_OPENRD=m +CONFIG_SND_KIRKWOOD_SOC_T5325=m +CONFIG_MMC_MVSDIO=m +CONFIG_LEDS_NS2=m +CONFIG_LEDS_NETXBIG=m +CONFIG_RTC_DRV_MV=m +CONFIG_MV_XOR=y +CONFIG_CRYPTO_DEV_MV_CESA=m + +# CONFIG_TOUCHSCREEN_EETI is not set diff --git a/config-arm-omap-generic b/config-arm-omap-generic new file mode 100644 index 000000000..de17513e4 --- /dev/null +++ b/config-arm-omap-generic @@ -0,0 +1,1096 @@ +CONFIG_GENERIC_GPIO=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_LOCKBREAK=y +CONFIG_ARCH_HAS_CPUFREQ=y +# CONFIG_SPARSE_IRQ is not set +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_BOOST is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +# CONFIG_BLK_CGROUP is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_STOP_MACHINE=y +# CONFIG_INLINE_SPIN_UNLOCK is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y +# CONFIG_ARCH_VERSATILE is not set +CONFIG_ARCH_OMAP=y +# CONFIG_GPIO_PCA953X is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set +# TI OMAP Common Features +CONFIG_ARCH_OMAP_OTG=y +# CONFIG_ARCH_OMAP1 is not set +CONFIG_ARCH_OMAP2PLUS=y + +# +# OMAP Feature Selections +# +CONFIG_OMAP_SMARTREFLEX=y +CONFIG_OMAP_SMARTREFLEX_CLASS3=y +CONFIG_OMAP_RESET_CLOCKS=y +CONFIG_OMAP_MUX=y +# CONFIG_OMAP_MUX_DEBUG is not set +CONFIG_OMAP_MUX_WARNINGS=y +CONFIG_OMAP_MCBSP=y +CONFIG_OMAP_MBOX_FWK=m +CONFIG_OMAP_MBOX_KFIFO_SIZE=256 +CONFIG_OMAP_32K_TIMER=y +# CONFIG_OMAP3_L2_AUX_SECURE_SAVE_RESTORE is not set +CONFIG_OMAP_32K_TIMER_HZ=128 +CONFIG_OMAP_DM_TIMER=y +# CONFIG_OMAP_PM_NONE is not set +CONFIG_OMAP_PM_NOOP=y + +# +# TI OMAP2/3/4 Specific Features +# +CONFIG_ARCH_OMAP2PLUS_TYPICAL=y +# CONFIG_ARCH_OMAP2 is not set +CONFIG_ARCH_OMAP3=y +CONFIG_ARCH_OMAP4=y +CONFIG_SOC_OMAP3430=y +# CONFIG_SOC_OMAPTI816X is not set +CONFIG_OMAP_PACKAGE_CBB=y +CONFIG_OMAP_PACKAGE_CBL=y +CONFIG_OMAP_PACKAGE_CBS=y + +# +# OMAP Board Type +# +CONFIG_MACH_OMAP3_BEAGLE=y +CONFIG_MACH_DEVKIT8000=y +CONFIG_MACH_OMAP_LDP=y +CONFIG_MACH_OMAP3530_LV_SOM=y +CONFIG_MACH_OMAP3_TORPEDO=y +CONFIG_MACH_OVERO=y +CONFIG_MACH_OMAP3EVM=y +CONFIG_MACH_OMAP3517EVM=y +CONFIG_MACH_CRANEBOARD=y +CONFIG_MACH_OMAP3_PANDORA=y +CONFIG_MACH_OMAP3_TOUCHBOOK=y +CONFIG_MACH_OMAP_3430SDP=y +CONFIG_MACH_NOKIA_RM680=y +CONFIG_MACH_NOKIA_RX51=y +CONFIG_MACH_OMAP_ZOOM2=y +CONFIG_MACH_OMAP_ZOOM3=y +CONFIG_MACH_CM_T35=y +CONFIG_MACH_CM_T3517=y +CONFIG_MACH_IGEP0020=y +CONFIG_MACH_IGEP0030=y +CONFIG_MACH_SBC3530=y +CONFIG_MACH_OMAP_3630SDP=y +CONFIG_MACH_OMAP_4430SDP=y +CONFIG_MACH_OMAP4_PANDA=y +CONFIG_MACH_TI8168EVM=y +CONFIG_OMAP3_EMU=y +# CONFIG_OMAP3_SDRC_AC_TIMING is not set +# System MMU +CONFIG_CPU_32v6K=y +CONFIG_CPU_V7=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_ARM_THUMBEE=y +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_CACHE_L2X0=y +CONFIG_CACHE_PL310=y +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_CPU_HAS_PMU=y +CONFIG_ARM_ERRATA_430973=y +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +CONFIG_PL310_ERRATA_588369=y +CONFIG_PL310_ERRATA_769419=y +CONFIG_ARM_ERRATA_720789=y +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_753970 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +CONFIG_ARM_GIC=y +# CONFIG_PCI_SYSCALL is not set +# CONFIG_PCCARD is not set +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_HAVE_ARM_SCU=y +CONFIG_HAVE_ARM_TWD=y +CONFIG_NR_CPUS=2 +CONFIG_HOTPLUG_CPU=y +CONFIG_LOCAL_TIMERS=y +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_HZ=128 +# CONFIG_THUMB2_KERNEL is not set +# CONFIG_OABI_COMPAT is not set +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y +CONFIG_HW_PERF_EVENTS=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_KSM is not set +# CONFIG_CC_STACKPROTECTOR is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="" +# CONFIG_AUTO_ZRELADDR is not set +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_DEBUG=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_VFPv3=y +CONFIG_NEON=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_MISC=m +CONFIG_PM_DEBUG=y +# CONFIG_PM_ADVANCED_DEBUG is not set +# CONFIG_PM_VERBOSE is not set +CONFIG_CAN_PM_TRACE=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_APM_EMULATION is not set +CONFIG_ARCH_HAS_OPP=y +CONFIG_PM_OPP=y +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_IP_MROUTE_MULTIPLE_TABLES is not set +# CONFIG_ARPD is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +CONFIG_IPV6=y +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_SUBTREES is not set +# CONFIG_IPV6_MROUTE is not set +CONFIG_NF_DEFRAG_IPV4=m +# CONFIG_NET_DCCPPROBE is not set +# CONFIG_L2TP_V3 is not set +# CONFIG_DECNET_ROUTER is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_CLS_U32 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_RPS=y +CONFIG_XPS=y +# CONFIG_CAN_SLCAN is not set +# CONFIG_CAN_DEV is not set +CONFIG_RXKAD=m +CONFIG_FIRMWARE_IN_KERNEL=y +# CONFIG_DEBUG_DEVRES is not set +CONFIG_MTD=y +CONFIG_MTD_TESTS=m +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +CONFIG_SM_FTL=m +CONFIG_MTD_PHYSMAP=m +# CONFIG_MTD_PHYSMAP_COMPAT is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_IMPA7 is not set +# CONFIG_MTD_GPIO_ADDR is not set +CONFIG_MTD_PLATRAM=m +# CONFIG_MTD_DATAFLASH is not set +CONFIG_MTD_M25P80=m +CONFIG_M25PXX_USE_FAST_READ=y +# CONFIG_MTD_SST25L is not set +CONFIG_MTD_SLRAM=m +CONFIG_MTD_PHRAM=m +CONFIG_MTD_DOC2000=m +CONFIG_MTD_DOC2001=m +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCPROBE=m +CONFIG_MTD_DOCECC=m +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_DOCPROBE_ADDRESS=0 +CONFIG_MTD_NAND_ECC=y +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND=y +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_NAND_GPIO is not set +CONFIG_MTD_NAND_OMAP2=y +CONFIG_MTD_NAND_OMAP_PREFETCH=y +CONFIG_MTD_NAND_OMAP_PREFETCH_DMA=y +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_NANDSIM is not set +CONFIG_MTD_NAND_PLATFORM=y +# CONFIG_MTD_ALAUDA is not set +CONFIG_MTD_ONENAND=y +# CONFIG_MTD_ONENAND_VERIFY_WRITE is not set +# CONFIG_MTD_ONENAND_GENERIC is not set +CONFIG_MTD_ONENAND_OMAP2=y +# CONFIG_MTD_ONENAND_OTP is not set +CONFIG_MTD_ONENAND_2X_PROGRAM=y +CONFIG_MTD_ONENAND_SIM=m +CONFIG_MTD_UBI_GLUEBI=m +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_MG_DISK=m +CONFIG_MG_DISK_RES=0 +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +CONFIG_HMC6352=m +CONFIG_DS1682=m +CONFIG_TI_DAC7512=m +CONFIG_BMP085=m +CONFIG_C2PORT=m +CONFIG_EEPROM_AT25=m +CONFIG_EEPROM_93XX46=m +# CONFIG_IWMC3200TOP_DEBUGFS is not set +# CONFIG_SCSI_PROC_FS is not set +# CONFIG_BLK_DEV_SR_VENDOR is not set +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_LOG_USERSPACE is not set +CONFIG_DM_MULTIPATH=y +# CONFIG_TARGET_CORE is not set +# CONFIG_MACVTAP is not set +CONFIG_MII=y +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM63XX_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_AX88796 is not set +# CONFIG_SMC91X is not set +# CONFIG_TI_DAVINCI_EMAC is not set +# CONFIG_TI_DAVINCI_MDIO is not set +# CONFIG_TI_DAVINCI_CPDMA is not set +CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL=y +CONFIG_ENC28J60=m +# CONFIG_ENC28J60_WRITEVERIFY is not set +# CONFIG_ETHOC is not set +CONFIG_SMC911X=y +CONFIG_SMSC911X=y +# CONFIG_DNET is not set +# CONFIG_B44 is not set +CONFIG_KS8851=m +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +# CONFIG_ATH9K_HTC is not set +# CONFIG_AR9170_USB is not set +# CONFIG_B43_SDIO is not set +# CONFIG_B43_PHY_N is not set +# CONFIG_HOSTAP is not set +# CONFIG_IWM is not set +CONFIG_LIBERTAS_SPI=m +# CONFIG_LIBERTAS_MESH is not set +CONFIG_P54_SPI=m +# CONFIG_P54_SPI_DEFAULT_EEPROM is not set +# CONFIG_RT2800USB_RT33XX is not set +# CONFIG_RTL8192CE is not set +CONFIG_WL1251_SPI=m +CONFIG_WL12XX_SPI=m +CONFIG_WL12XX_SDIO_TEST=m +# CONFIG_WIMAX_IWMC3200_SDIO is not set +CONFIG_USB_USBNET=y +CONFIG_USB_NET_CDCETHER=y +CONFIG_USB_NET_CDC_NCM=y +CONFIG_USB_NET_RNDIS_HOST=y +# CONFIG_ATM_TCP is not set +# CONFIG_IEEE802154_FAKEHARD is not set +# CONFIG_CAIF_TTY is not set +# CONFIG_CAIF_SPI_SLAVE is not set +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPPOL2TP is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +CONFIG_INPUT_POLLDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_EVBUG=m +# CONFIG_KEYBOARD_QT2160 is not set +CONFIG_KEYBOARD_LKKBD=m +CONFIG_KEYBOARD_GPIO=m +CONFIG_KEYBOARD_TCA6416=m +CONFIG_KEYBOARD_MATRIX=m +CONFIG_KEYBOARD_LM8323=m +CONFIG_KEYBOARD_MCS=m +CONFIG_KEYBOARD_NEWTON=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_KEYBOARD_SUNKBD=m +# CONFIG_KEYBOARD_OMAP4 is not set +CONFIG_KEYBOARD_TWL4030=m +CONFIG_KEYBOARD_XTKBD=m +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_GPIO=m +CONFIG_JOYSTICK_AS5011=m +# CONFIG_TABLET_USB_HANWANG is not set +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_AD7877=m +CONFIG_TOUCHSCREEN_AD7879=m +CONFIG_TOUCHSCREEN_AD7879_I2C=m +# CONFIG_TOUCHSCREEN_AD7879_SPI is not set +CONFIG_TOUCHSCREEN_CY8CTMG110=m +CONFIG_TOUCHSCREEN_HAMPSHIRE=m +CONFIG_TOUCHSCREEN_QT602240=m +CONFIG_TOUCHSCREEN_TPS6507X=m +# CONFIG_TOUCHSCREEN_TSC2005 is not set +CONFIG_INPUT_AD714X=m +CONFIG_INPUT_AD714X_I2C=m +CONFIG_INPUT_AD714X_SPI=m +# CONFIG_INPUT_APPLEIR is not set +CONFIG_INPUT_TWL4030_PWRBUTTON=y +CONFIG_INPUT_TWL4030_VIBRA=y +CONFIG_INPUT_TWL6040_VIBRA=y +CONFIG_INPUT_UINPUT=y +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +CONFIG_INPUT_ADXL34X=m +CONFIG_INPUT_ADXL34X_I2C=m +CONFIG_INPUT_ADXL34X_SPI=m +# CONFIG_INPUT_CMA3000_I2C is not set +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_GAMEPORT_NS558 is not set +# CONFIG_GAMEPORT_L4 is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +CONFIG_SERIAL_8250_DETECT_IRQ=y +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX3107 is not set +CONFIG_SERIAL_OMAP=y +CONFIG_SERIAL_OMAP_CONSOLE=y +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_GPIO is not set +CONFIG_I2C_OMAP=y +# CONFIG_I2C_SIMTEC is not set +CONFIG_I2C_TAOS_EVM=m +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y +# SPI Master Controller Drivers +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_OC_TINY is not set +CONFIG_SPI_OMAP24XX=y +# CONFIG_SPI_PL022 is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_DESIGNWARE is not set +# SPI Protocol Masters +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_TLE62X0 is not set + +# +# PPS support +# +# CONFIG_PPS is not set +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO expanders: +# +# CONFIG_GPIO_BASIC_MMIO is not set +# CONFIG_GPIO_IT8761E is not set +# CONFIG_GPIO_PL061 is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +CONFIG_GPIO_TWL4030=y +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +# CONFIG_W1 is not set +# CONFIG_CHARGER_TWL4030 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set +CONFIG_WATCHDOG_NOWAYOUT=y +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_MPCORE_WATCHDOG is not set +CONFIG_OMAP_WATCHDOG=y +# CONFIG_TWL4030_WATCHDOG is not set +CONFIG_SSB=y +# CONFIG_SSB_SDIOHOST is not set +CONFIG_MFD_CORE=y +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS65010 is not set +CONFIG_TWL4030_CORE=y +# CONFIG_TWL4030_MADC is not set +CONFIG_TWL4030_POWER=y +CONFIG_TWL4030_CODEC=y +# CONFIG_TWL6030_PWM is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_EZX_PCAP is not set +CONFIG_MFD_OMAP_USB_HOST=y +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_WL1273_CORE is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +CONFIG_REGULATOR_FIXED_VOLTAGE=y +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_BQ24022 is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +CONFIG_REGULATOR_TWL4030=y +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_TPS6524X is not set +CONFIG_VIDEOBUF_DMA_CONTIG=m +CONFIG_V4L2_MEM2MEM_DEV=m +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set +# Encoders/decoders and other helper chips +# + +# +CONFIG_VIDEO_IR_I2C=m +CONFIG_VIDEO_CS5345=m +CONFIG_VIDEO_M52790=m +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_VP27SMPX=m +CONFIG_VIDEO_OV7670=m +CONFIG_VIDEO_SAA717X=m +CONFIG_VIDEO_SAA7127=m +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m +CONFIG_VIDEO_ADP1653=m +# +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_SAA6588 is not set +# CONFIG_VIDEO_ADV7180 is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_MT9V011 is not set +# CONFIG_VIDEO_MT9V032 is not set +# CONFIG_VIDEO_TCM825X is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA7191 is not set +# CONFIG_VIDEO_TVP514X is not set +# CONFIG_VIDEO_TVP5150 is not set +CONFIG_VIDEO_TVP7002=m +# CONFIG_VIDEO_VPX3220 is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_ADV7343 is not set +CONFIG_VIDEO_AK881X=m +# CONFIG_VIDEO_VPFE_CAPTURE is not set +CONFIG_VIDEO_OMAP2_VOUT=m +# CONFIG_VIDEO_CPIA2 is not set +# CONFIG_VIDEO_AU0828 is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_OMAP3 is not set +# CONFIG_SOC_CAMERA is not set +CONFIG_USB_ET61X251=m +CONFIG_USB_SN9C102=m +CONFIG_VIDEO_MEM2MEM_TESTDEV=m +CONFIG_RADIO_TEA5764=m +CONFIG_RADIO_SAA7706H=m +CONFIG_RADIO_TEF6862=m +# CONFIG_TTPCI_EEPROM is not set +# CONFIG_SMS_SDIO_DRV is not set +# CONFIG_DVB_DUMMY_FE is not set +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_PLL=m +# CONFIG_DRM is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_FB_DDC is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set +# CONFIG_FB_OMAP_LCD_VGA is not set +CONFIG_OMAP2_VRAM=y +CONFIG_OMAP2_VRFB=y +CONFIG_OMAP2_DSS=y +CONFIG_OMAP2_VRAM_SIZE=12 +CONFIG_OMAP2_DSS_DEBUG_SUPPORT=y +# CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS is not set +CONFIG_OMAP2_DSS_DPI=y +# CONFIG_OMAP2_DSS_RFBI is not set +CONFIG_OMAP2_DSS_VENC=y +CONFIG_OMAP4_DSS_HDMI=y +# CONFIG_OMAP2_DSS_SDI is not set +# CONFIG_OMAP2_DSS_DSI is not set +# CONFIG_OMAP2_DSS_FAKE_VSYNC is not set +CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=1 +CONFIG_OMAP2_DSS_SLEEP_BEFORE_RESET=y +CONFIG_OMAP2_DSS_SLEEP_AFTER_VENC_RESET=y +CONFIG_FB_OMAP2=y +CONFIG_FB_OMAP2_DEBUG_SUPPORT=y +CONFIG_FB_OMAP2_NUM_FBS=3 + +# +# OMAP2/3 Display Device Drivers +# +CONFIG_PANEL_GENERIC_DPI=y +CONFIG_PANEL_SHARP_LS037V7DW01=y +CONFIG_PANEL_NEC_NL8048HL11_01B=y +CONFIG_PANEL_TPO_TD043MTEA1=y +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_S6E63M0 is not set +# CONFIG_LCD_AMS369FG06 is not set +CONFIG_BACKLIGHT_GENERIC=m +CONFIG_DISPLAY_SUPPORT=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_JACK=y +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_PCM_OSS_PLUGINS=y +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_HRTIMER=m +CONFIG_SND_SEQ_HRTIMER_DEFAULT=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_RAWMIDI_SEQ=m +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_USB_UA101=m +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y +CONFIG_SND_SOC=y +# CONFIG_SND_SOC_CACHE_LZO is not set +CONFIG_SND_OMAP_SOC=y +CONFIG_SND_OMAP_SOC_MCBSP=y +CONFIG_SND_OMAP_SOC_MCPDM=y +CONFIG_SND_OMAP_SOC_RX51=y +CONFIG_SND_OMAP_SOC_OVERO=y +CONFIG_SND_OMAP_SOC_OMAP3EVM=y +CONFIG_SND_OMAP_SOC_AM3517EVM=y +CONFIG_SND_OMAP_SOC_SDP3430=y +CONFIG_SND_OMAP_SOC_SDP4430=y +CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=y +CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE=y +CONFIG_SND_OMAP_SOC_ZOOM2=y +CONFIG_SND_OMAP_SOC_IGEP0020=y +CONFIG_SND_OMAP_SOC_OMAP4_HDMI=y +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_TLV320AIC23=y +CONFIG_SND_SOC_TLV320AIC3X=y +CONFIG_SND_SOC_TWL4030=y +CONFIG_SND_SOC_TWL6040=y +# CONFIG_SOUND_PRIME is not set +# CONFIG_HID_TIVO_SLIDE is not set +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set +# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_OTG=y +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set +CONFIG_USB_EHCI_HCD_OMAP=y +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_U132_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_HWA_HCD is not set +# CONFIG_USB_MUSB_TUSB6010 is not set +CONFIG_USB_MUSB_OMAP2PLUS=y +# CONFIG_USB_MUSB_AM35X is not set +# CONFIG_USB_MUSB_HOST is not set +# CONFIG_USB_MUSB_PERIPHERAL is not set +CONFIG_USB_MUSB_OTG=y +CONFIG_USB_GADGET_MUSB_HDRC=y +CONFIG_USB_INVENTRA_DMA=y +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DATAFAB=m +CONFIG_USB_STORAGE_FREECOM=m +CONFIG_USB_STORAGE_ISD200=m +CONFIG_USB_STORAGE_USBAT=m +CONFIG_USB_STORAGE_SDDR09=m +CONFIG_USB_STORAGE_SDDR55=m +CONFIG_USB_STORAGE_JUMPSHOT=m +CONFIG_USB_STORAGE_ALAUDA=m +CONFIG_USB_STORAGE_ONETOUCH=m +CONFIG_USB_STORAGE_KARMA=m +CONFIG_USB_STORAGE_CYPRESS_ATACB=m +# CONFIG_USB_UAS is not set +# CONFIG_USB_LIBUSUAL is not set +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +# CONFIG_USB_SERIAL_SAFE_PADDED is not set +# CONFIG_USB_SERIAL_SAMBA is not set +CONFIG_USB_SERIAL_ZIO=m +CONFIG_USB_RIO500=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_TEST=m +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_R8A66597 is not set +# CONFIG_USB_GADGET_PXA_U2O is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +CONFIG_USB_ETH=y +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_ETH_EEM=y +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_NOKIA is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +CONFIG_USB_GPIO_VBUS=y +# CONFIG_ISP1301_OMAP is not set +CONFIG_TWL4030_USB=y +CONFIG_TWL6030_USB=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_MMC=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_OMAP=m +CONFIG_MMC_OMAP_HS=y +CONFIG_MMC_SPI=m +# CONFIG_MMC_DW is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_GPIO_PLATFORM=y +CONFIG_LEDS_GPIO_OF=y +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_LT3593 is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_NFC_DEVICES is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_TWL4030=m +CONFIG_RTC_DRV_S35390A=m +CONFIG_RTC_DRV_M41T94=m +CONFIG_RTC_DRV_DS1305=m +CONFIG_RTC_DRV_DS1390=m +CONFIG_RTC_DRV_MAX6902=m +CONFIG_RTC_DRV_R9701=m +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_DS3234=m +CONFIG_RTC_DRV_PCF2123=m +CONFIG_RTC_DRV_CMOS=m +CONFIG_RTC_DRV_M48T86=m +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_USB_SE401 is not set +# CONFIG_USB_VICAM is not set +CONFIG_PRISM2_USB=m +CONFIG_BRCM80211=y +CONFIG_BRCMFMAC=y +CONFIG_RT2870=m +CONFIG_R8712U=m +CONFIG_R8712_AP=y +CONFIG_ZRAM=m +# CONFIG_ZRAM_DEBUG is not set +# CONFIG_LIRC_STAGING is not set +CONFIG_TIDSPBRIDGE=m +CONFIG_TIDSPBRIDGE_MEMPOOL_SIZE=0x600000 +# CONFIG_TIDSPBRIDGE_DEBUG is not set +CONFIG_TIDSPBRIDGE_RECOVERY=y +# CONFIG_TIDSPBRIDGE_CACHE_LINE_CHECK is not set +CONFIG_TIDSPBRIDGE_WDT3=y +CONFIG_TIDSPBRIDGE_WDT_TIMEOUT=5 +# CONFIG_TIDSPBRIDGE_NTFY_PWRERR is not set +# CONFIG_TIDSPBRIDGE_BACKTRACE is not set +# CONFIG_WESTBRIDGE is not set +CONFIG_WESTBRIDGE_HAL_SELECTED=y +CONFIG_MACH_OMAP3_WESTBRIDGE_AST_PNAND_HAL=y +# CONFIG_MACH_NO_WESTBRIDGE is not set +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_JFS_STATISTICS=y +CONFIG_XFS_RT=y +CONFIG_OCFS2_FS_STATS=y +CONFIG_OCFS2_DEBUG_MASKLOG=y +# CONFIG_BTRFS_FS is not set +CONFIG_PRINT_QUOTA_WARNING=y +CONFIG_QUOTA_TREE=m +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_AUTOFS4_FS=m +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_CMODE_FAVOURLZO=y +# CONFIG_LOGFS is not set +CONFIG_NFS_FS=m +# CONFIG_NFS_V4_1 is not set +CONFIG_ROOT_NFS=y +CONFIG_NFSD_DEPRECATED=y +CONFIG_LOCKD=y +CONFIG_NFS_ACL_SUPPORT=y +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_FSCACHE is not set +# CONFIG_CIFS_ACL is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_9P_FSCACHE is not set +# CONFIG_9P_FS_POSIX_ACL is not set +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=y +# CONFIG_DLM_DEBUG is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_LOCKUP_DETECTOR is not set +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_DEBUG_PREEMPT=y +# CONFIG_BKL is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y +# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set +CONFIG_SYSCTL_SYSCALL_CHECK=y +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_KGDB_TESTS is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +CONFIG_EARLY_PRINTK=y +# CONFIG_DEBUG_ICEDCC is not set +CONFIG_OC_ETM=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_IMA is not set +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_RNG=m +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_SEQIV=m +CONFIG_CRYPTO_CTR=m +# CONFIG_CRYPTO_VMAC is not set +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_AES=m +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_USER_API=m +CONFIG_CRYPTO_USER_API_HASH=m +CONFIG_CRYPTO_USER_API_SKCIPHER=m +CONFIG_CRYPTO_DEV_OMAP_SHAM=m +CONFIG_CRYPTO_DEV_OMAP_AES=m +CONFIG_LIBCRC32C=y +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_PANEL_LGPHILIPS_LB035Q02 is not set +# CONFIG_LCD_LD9040 is not set +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_CGROUP_PERF is not set +# CONFIG_OPROFILE is not set +# CONFIG_OPROFILE is not set +# CONFIG_PATA_ARASAN_CF is not set +# CONFIG_BT_ATH3K is not set +# CONFIG_BT_WILINK is not set +# CONFIG_USB_HSO is not set + +CONFIG_CRYSTALHD=m + +CONFIG_GPIO_GENERIC_PLATFORM=y + +CONFIG_MACH_OMAP_GENERIC=y +CONFIG_PL310_ERRATA_753970=y +CONFIG_ARM_CPU_TOPOLOGY=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_ETHERNET=y +CONFIG_NET_VENDOR_BROADCOM=y +CONFIG_NET_VENDOR_MICROCHIP=y +CONFIG_SENSORS_AD7314=m +CONFIG_REGULATOR_GPIO=y +CONFIG_VIDEO_MT9P031=m +CONFIG_VIDEO_MT9T001=m +CONFIG_VIDEO_S5K6AA=m +CONFIG_PANEL_DVI=m +CONFIG_PANEL_PICODLP=m +CONFIG_USB_RENESAS_USBHS=m +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 +CONFIG_LEDS_RENESAS_TPU=y +# CONFIG_OMAP_IOMMU is not set +CONFIG_USB_RENESAS_USBHS_HCD=m + +# CONFIG_SOC_OMAPTI81XX is not set +# CONFIG_SOC_OMAPAM33XX is not set +# CONFIG_MACH_TI8148EVM is not set +# CONFIG_OMAP4_ERRATA_I688 is not set +# CONFIG_ARM_LPAE is not set +# CONFIG_MICREL_KS8995MA is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_S5M_CORE is not set +# CONFIG_VIDEO_AS3645A is not set diff --git a/config-arm-tegra b/config-arm-tegra new file mode 100644 index 000000000..9658d4989 --- /dev/null +++ b/config-arm-tegra @@ -0,0 +1,101 @@ +CONFIG_ARCH_TEGRA=y +CONFIG_MACH_HARMONY=y +CONFIG_MACH_KAEN=y +CONFIG_MACH_PAZ00=y +CONFIG_MACH_TRIMSLICE=y +CONFIG_MACH_WARIO=y +CONFIG_MACH_TEGRA_DT=y +CONFIG_TEGRA_DEBUG_UARTD=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_SMP=y +CONFIG_NR_CPUS=2 +CONFIG_PREEMPT=y +CONFIG_AEABI=y + +CONFIG_I2C_TEGRA=y + +CONFIG_MMC=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_TEGRA=y + +# CONFIG_RCU_BOOST is not set +CONFIG_TEGRA_SYSTEM_DMA=y +CONFIG_TEGRA_EMC_SCALING_ENABLE=y +CONFIG_ARM_THUMBEE=y +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_CACHE_L2X0=y +CONFIG_ARM_ERRATA_430973=y +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +CONFIG_ARM_ERRATA_742230=y +# CONFIG_ARM_ERRATA_742231 is not set +CONFIG_PL310_ERRATA_588369=y +CONFIG_PL310_ERRATA_769419=y +CONFIG_ARM_ERRATA_720789=y +# CONFIG_PL310_ERRATA_727915 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_753970 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +CONFIG_SMP_ON_UP=y +CONFIG_LOCAL_TIMERS=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_HW_PERF_EVENTS=y +# CONFIG_NEON is not set +# CONFIG_RFKILL_GPIO is not set +CONFIG_GPIO_GENERIC_PLATFORM=y +# CONFIG_GPIO_MCP23S08 is not set +CONFIG_KEYBOARD_TEGRA=y +# CONFIG_MPCORE_WATCHDOG is not set +CONFIG_USB_EHCI_TEGRA=y +CONFIG_RTC_DRV_TEGRA=m + +CONFIG_SND_SOC_TEGRA=m +CONFIG_SND_SOC_TEGRA_WM8903=m +CONFIG_SND_SOC_TEGRA_TRIMSLICE=m + +CONFIG_MFD_NVEC=y +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_RCU_CPU_STALL_VERBOSE is not set +# CONFIG_PREEMPT_TRACER is not set +CONFIG_KEYBOARD_NVEC=y +CONFIG_SERIO_NVEC_PS2=y +CONFIG_NVEC_POWER=y +CONFIG_POWER_SUPPLY=y + +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEBUG=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y + +CONFIG_CRYSTALHD=m + +CONFIG_MACH_VENTANA=y +CONFIG_PL310_ERRATA_753970=y +CONFIG_ARM_CPU_TOPOLOGY=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_LEDS_RENESAS_TPU=y + +# CONFIG_ARCH_TEGRA_2x_SOC is not set +# CONFIG_ARCH_TEGRA_3x_SOC is not set +# CONFIG_ETHERNET is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_DVB_TDA1004X is not set +# CONFIG_DVB_PLL is not set +# CONFIG_SND_SOC_TEGRA_ALC5632 is not set + diff --git a/config-debug b/config-debug index 86aa2cc04..ca1ba2b59 100644 --- a/config-debug +++ b/config-debug @@ -2,6 +2,8 @@ CONFIG_SND_VERBOSE_PRINTK=y CONFIG_SND_DEBUG=y CONFIG_SND_PCM_XRUN_DEBUG=y +CONFIG_DEBUG_ATOMIC_SLEEP=y + CONFIG_DEBUG_MUTEXES=y CONFIG_DEBUG_RT_MUTEXES=y CONFIG_DEBUG_LOCK_ALLOC=y @@ -22,6 +24,7 @@ CONFIG_FAIL_MAKE_REQUEST=y CONFIG_FAULT_INJECTION_DEBUG_FS=y CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y CONFIG_FAIL_IO_TIMEOUT=y +CONFIG_FAIL_MMC_REQUEST=y CONFIG_SLUB_DEBUG_ON=y @@ -41,6 +44,7 @@ CONFIG_DEBUG_OBJECTS=y # CONFIG_DEBUG_OBJECTS_SELFTEST is not set CONFIG_DEBUG_OBJECTS_FREE=y CONFIG_DEBUG_OBJECTS_TIMERS=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1 CONFIG_X86_PTDUMP=y @@ -69,7 +73,7 @@ CONFIG_DEBUG_PERF_USE_VMALLOC=y CONFIG_JBD2_DEBUG=y -CONFIG_DEBUG_CFQ_IOSCHED=y +CONFIG_DEBUG_BLK_CGROUP=y CONFIG_DRBD_FAULT_INJECTION=y @@ -78,7 +82,6 @@ CONFIG_CARL9170_DEBUGFS=y CONFIG_IWLWIFI_DEVICE_TRACING=y CONFIG_DEBUG_OBJECTS_WORK=y -# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set CONFIG_DMADEVICES_DEBUG=y CONFIG_DMADEVICES_VDEBUG=y @@ -88,8 +91,6 @@ CONFIG_PM_ADVANCED_DEBUG=y CONFIG_CEPH_LIB_PRETTYDEBUG=y CONFIG_QUOTA_DEBUG=y -# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set - CONFIG_PCI_DEFAULT_USE_CRS=y CONFIG_KGDB_KDB=y @@ -98,4 +99,14 @@ CONFIG_KDB_KEYBOARD=y CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y CONFIG_TEST_LIST_SORT=y -CONFIG_DEBUG_SET_MODULE_RONX=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set + +CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y + +CONFIG_DEBUG_KMEMLEAK=y +CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=1024 +# CONFIG_DEBUG_KMEMLEAK_TEST is not set +CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y + diff --git a/config-generic b/config-generic index c07e5b85a..072b025d6 100644 --- a/config-generic +++ b/config-generic @@ -6,6 +6,7 @@ CONFIG_SMP=y CONFIG_HOTPLUG_CPU=y CONFIG_LOCALVERSION="" CONFIG_CROSS_COMPILE="" +CONFIG_DEFAULT_HOSTNAME="(none)" # # Code maturity level options @@ -31,19 +32,19 @@ CONFIG_KERNEL_GZIP=y CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_BSD_PROCESS_ACCT=y -# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_FHANDLE=y CONFIG_TASKSTATS=y CONFIG_TASK_DELAY_ACCT=y CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y CONFIG_SYSCTL=y -CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_BUF_SHIFT=18 # CONFIG_IKCONFIG is not set # CONFIG_EMBEDDED is not set # CONFIG_EXPERT is not set CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y @@ -67,6 +68,7 @@ CONFIG_SLUB=y CONFIG_MISC_DEVICES=y # CONFIG_AD525X_DPOT is not set +# CONFIG_ATMEL_PWM is not set CONFIG_IWMC3200TOP=m # CONFIG_IWMC3200TOP_DEBUG is not set CONFIG_IWMC3200TOP_DEBUGFS=y @@ -79,7 +81,7 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_LOAD is not set # -- MODULE_FORCE_UNLOAD is controlled by config-debug/nodebug # CONFIG_MODVERSIONS is not set -CONFIG_MODULE_SRCVERSION_ALL=y +# CONFIG_MODULE_SRCVERSION_ALL is not set # # Bus options (PCI, PCMCIA, EISA, MCA, ISA) @@ -88,9 +90,10 @@ CONFIG_PCI=y # CONFIG_PCI_DEBUG is not set CONFIG_PCI_STUB=y CONFIG_PCI_IOV=y +CONFIG_PCI_PRI=y +CONFIG_PCI_PASID=y CONFIG_HT_IRQ=y CONFIG_PCI_MSI=y -CONFIG_PCI_MSI_DEFAULT_ON=y CONFIG_PCIEPORTBUS=y CONFIG_PCIEAER=y CONFIG_PCIEASPM=y @@ -99,7 +102,6 @@ CONFIG_PCIE_ECRC=y CONFIG_PCIEAER_INJECT=m CONFIG_HOTPLUG_PCI_PCIE=y CONFIG_HOTPLUG_PCI_FAKE=m -CONFIG_PCI_LEGACY=y CONFIG_ISA=y # CONFIG_EISA is not set @@ -116,7 +118,6 @@ CONFIG_YENTA=m CONFIG_CARDBUS=y CONFIG_I82092=m CONFIG_PD6729=m -CONFIG_PCMCIA_IOCTL=y CONFIG_PCCARD=y CONFIG_MMC=m @@ -138,6 +139,7 @@ CONFIG_MMC_SDHCI_PLTFM=m CONFIG_MMC_CB710=m CONFIG_MMC_RICOH_MMC=y CONFIG_MMC_USHC=m +CONFIG_MMC_VUB300=m CONFIG_CB710_CORE=m # CONFIG_CB710_DEBUG is not set @@ -158,6 +160,7 @@ CONFIG_INFINIBAND_AMSO1100=m # CONFIG_INFINIBAND_AMSO1100_DEBUG is not set CONFIG_INFINIBAND_CXGB3=m CONFIG_INFINIBAND_CXGB4=m +CONFIG_SCSI_CXGB3_ISCSI=m CONFIG_SCSI_CXGB4_ISCSI=m # CONFIG_INFINIBAND_CXGB3_DEBUG is not set CONFIG_MLX4_INFINIBAND=m @@ -191,9 +194,8 @@ CONFIG_EXTRA_FIRMWARE="" # CONFIG_MTD=m # CONFIG_MTD_DEBUG is not set -CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_SWAP=m CONFIG_MTD_AR7_PARTS=m -CONFIG_MTD_CONCAT=m CONFIG_MTD_CMDLINE_PARTS=y # # User Modules And Translation Layers @@ -240,6 +242,7 @@ CONFIG_MTD_ABSENT=m # CONFIG_MTD_COMPLEX_MAPPINGS=y # CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_LATCH_ADDR is not set CONFIG_MTD_SC520CDP=m CONFIG_MTD_NETSC520=m # CONFIG_MTD_SBC_GXX is not set @@ -274,6 +277,7 @@ CONFIG_MTDRAM_ERASE_SIZE=128 # CONFIG_MTD_DOCPROBE is not set # CONFIG_MTD_DOCPROBE_ADVANCED is not set # CONFIG_MTD_DOCPROBE_ADDRESS is not set +# CONFIG_MTD_DOCG3 is not set # # NAND Flash Device Drivers @@ -282,6 +286,7 @@ CONFIG_MTD_NAND=m # CONFIG_MTD_NAND_MUSEUM_IDS is not set # CONFIG_MTD_NAND_PLATFORM is not set # CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_BCH is not set # CONFIG_MTD_NAND_CAFE is not set CONFIG_MTD_NAND_IDS=m CONFIG_MTD_NAND_NANDSIM=m @@ -347,12 +352,16 @@ CONFIG_BLK_DEV_FD=m # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set + CONFIG_BLK_CPQ_DA=m CONFIG_BLK_CPQ_CISS_DA=m CONFIG_CISS_SCSI_TAPE=y CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_DRBD=m CONFIG_BLK_DEV_UMEM=m CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_OSD=m @@ -369,6 +378,7 @@ CONFIG_BLK_DEV_DELKIN=m # CONFIG_BLK_DEV_TC86C001 is not set CONFIG_LBDAF=y CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y CONFIG_BLK_DEV_INTEGRITY=y CONFIG_BLK_DEV_THROTTLING=y @@ -430,6 +440,7 @@ CONFIG_BLK_DEV_IDEDMA=y CONFIG_VIRTIO_BLK=m CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO_BALLOON=m +CONFIG_VIRTIO_MMIO=m CONFIG_VIRTIO_NET=m CONFIG_VMXNET3=m CONFIG_HW_RANDOM_VIRTIO=m @@ -447,6 +458,7 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_SRP=m CONFIG_SCSI_SRP_ATTRS=m CONFIG_SCSI_TGT=m +CONFIG_SCSI_ISCI=m CONFIG_SCSI_DH=y CONFIG_SCSI_DH_RDAC=m @@ -479,7 +491,6 @@ CONFIG_SCSI_SAS_ATTRS=m CONFIG_SCSI_SRP_TGT_ATTRS=y CONFIG_SCSI_SAS_LIBSAS=m CONFIG_SCSI_SAS_ATA=y -# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set CONFIG_SCSI_SAS_HOST_SMP=y CONFIG_RAID_ATTRS=m @@ -496,15 +507,13 @@ CONFIG_SCSI_3W_9XXX=m CONFIG_SCSI_ACARD=m CONFIG_SCSI_AACRAID=m CONFIG_SCSI_AIC7XXX=m -CONFIG_SCSI_AIC94XX=m -# CONFIG_AIC94XX_DEBUG is not set +CONFIG_SCSI_AIC7XXX_OLD=m CONFIG_AIC7XXX_CMDS_PER_DEVICE=4 CONFIG_AIC7XXX_RESET_DELAY_MS=15000 # CONFIG_AIC7XXX_BUILD_FIRMWARE is not set # CONFIG_AIC7XXX_DEBUG_ENABLE is not set CONFIG_AIC7XXX_DEBUG_MASK=0 # CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set -CONFIG_SCSI_AIC7XXX_OLD=m CONFIG_SCSI_AIC79XX=m CONFIG_AIC79XX_CMDS_PER_DEVICE=4 CONFIG_AIC79XX_RESET_DELAY_MS=15000 @@ -512,6 +521,8 @@ CONFIG_AIC79XX_RESET_DELAY_MS=15000 # CONFIG_AIC79XX_DEBUG_ENABLE is not set CONFIG_AIC79XX_DEBUG_MASK=0 # CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +CONFIG_SCSI_AIC94XX=m +# CONFIG_AIC94XX_DEBUG is not set # CONFIG_SCSI_ADVANSYS is not set CONFIG_SCSI_BFA_FC=m CONFIG_MEGARAID_NEWGEN=y @@ -521,10 +532,13 @@ CONFIG_MEGARAID_LEGACY=m CONFIG_MEGARAID_SAS=m CONFIG_SCSI_MVSAS=m # CONFIG_SCSI_MVSAS_DEBUG is not set +CONFIG_SCSI_MVSAS_TASKLET=y CONFIG_SCSI_MPT2SAS=m CONFIG_SCSI_MPT2SAS_MAX_SGE=128 CONFIG_SCSI_MPT2SAS_LOGGING=y +CONFIG_SCSI_MVUMI=m + CONFIG_SCSI_OSD_INITIATOR=m CONFIG_SCSI_OSD_ULD=m CONFIG_SCSI_OSD_DPRINT_SENSE=1 @@ -540,6 +554,59 @@ CONFIG_SCSI_PM8001=m CONFIG_VMWARE_PVSCSI=m CONFIG_VMWARE_BALLOON=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_BUSLOGIC=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_FLASHPOINT=y +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +CONFIG_SCSI_GDTH=m +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INIA100=m +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_DC395x=m +# CONFIG_SCSI_NSP32 is not set +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_DC390T=m +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_DPT_I2O is not set +CONFIG_SCSI_LPFC=m +# CONFIG_SCSI_LPFC_DEBUG_FS is not set + +# PCMCIA SCSI adapter support +# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set + +# ISA SCSI Controllers. Sorry your life sucks. +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set + + CONFIG_ATA=y CONFIG_ATA_BMDMA=y CONFIG_ATA_VERBOSE_ERROR=y @@ -569,6 +636,7 @@ CONFIG_SATA_ACARD_AHCI=m CONFIG_PATA_ACPI=m CONFIG_PATA_ALI=m CONFIG_PATA_AMD=m +CONFIG_PATA_ARASAN_CF=m CONFIG_PATA_ARTOP=m CONFIG_PATA_ATIIXP=m CONFIG_PATA_CMD640_PCI=m @@ -618,48 +686,6 @@ CONFIG_PATA_VIA=m CONFIG_PATA_WINBOND=m CONFIG_PATA_ATP867X=m -CONFIG_SCSI_BUSLOGIC=m -CONFIG_SCSI_INITIO=m -CONFIG_SCSI_FLASHPOINT=y -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -CONFIG_SCSI_GDTH=m -CONFIG_SCSI_HPTIOP=m -CONFIG_SCSI_IPS=m -CONFIG_SCSI_INIA100=m -CONFIG_SCSI_PPA=m -CONFIG_SCSI_IMM=m -# CONFIG_SCSI_IZIP_EPP16 is not set -# CONFIG_SCSI_IZIP_SLOW_CTR is not set -CONFIG_SCSI_STEX=m -CONFIG_SCSI_SYM53C8XX_2=m -CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 -CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 -CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 -CONFIG_SCSI_SYM53C8XX_MMIO=y -CONFIG_SCSI_QLOGIC_1280=m -CONFIG_SCSI_DC395x=m -# CONFIG_SCSI_NSP32 is not set -CONFIG_SCSI_DEBUG=m -CONFIG_SCSI_DC390T=m -CONFIG_SCSI_QLA_FC=m -CONFIG_SCSI_QLA_ISCSI=m -# CONFIG_SCSI_IPR is not set -# CONFIG_SCSI_DPT_I2O is not set -CONFIG_SCSI_LPFC=m - -# -# PCMCIA SCSI adapter support -# -CONFIG_SCSI_LOWLEVEL_PCMCIA=y -CONFIG_PCMCIA_AHA152X=m -# CONFIG_PCMCIA_FDOMAIN is not set -CONFIG_PCMCIA_NINJA_SCSI=m -CONFIG_PCMCIA_QLOGIC=m -CONFIG_PCMCIA_SYM53C500=m - # # Multi-device support (RAID and LVM) @@ -683,12 +709,16 @@ CONFIG_DM_DEBUG=y CONFIG_DM_MIRROR=y CONFIG_DM_MULTIPATH=m CONFIG_DM_SNAPSHOT=y +CONFIG_DM_THIN_PROVISIONING=m +# CONFIG_DM_DEBUG_BLOCK_STACK_TRACING is not set +# CONFIG_DM_DEBUG_SPACE_MAPS is not set CONFIG_DM_UEVENT=y CONFIG_DM_ZERO=y CONFIG_DM_LOG_USERSPACE=m CONFIG_DM_MULTIPATH_QL=m CONFIG_DM_MULTIPATH_ST=m CONFIG_DM_RAID=m +CONFIG_DM_FLAKEY=m # # Fusion MPT device support @@ -716,7 +746,6 @@ CONFIG_FIREWIRE_NOSY=m # # IEEE 1394 (FireWire) support # -# CONFIG_IEEE1394 is not set # # I2O device support @@ -725,10 +754,16 @@ CONFIG_FIREWIRE_NOSY=m # CONFIG_I2O_LCT_NOTIFY_ON_CHANGES is not set # +# Virtualization support drivers +# +# CONFIG_VIRT_DRIVERS is not set + # Networking support # CONFIG_NET=y +CONFIG_NET_DMA=y + CONFIG_TCP_CONG_ADVANCED=y CONFIG_TCP_CONG_BIC=m CONFIG_TCP_CONG_CUBIC=y @@ -749,7 +784,6 @@ CONFIG_TCP_MD5SIG=y # Networking options # CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y CONFIG_UNIX=y CONFIG_NET_KEY=m CONFIG_NET_KEY_MIGRATE=y @@ -759,6 +793,7 @@ CONFIG_INET_TUNNEL=m CONFIG_INET_DIAG=m CONFIG_IP_MULTICAST=y CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_FIB_TRIE_STATS=y CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_MULTIPATH=y CONFIG_IP_ROUTE_VERBOSE=y @@ -793,6 +828,7 @@ CONFIG_IP_VS_PROTO_UDP=y CONFIG_IP_VS_PROTO_ESP=y CONFIG_IP_VS_PROTO_AH=y CONFIG_IP_VS_PROTO_SCTP=y +CONFIG_IP_VS_IPV6=y CONFIG_IP_VS_RR=m CONFIG_IP_VS_WRR=m CONFIG_IP_VS_LC=m @@ -806,7 +842,7 @@ CONFIG_IP_VS_NQ=m CONFIG_IP_VS_FTP=m CONFIG_IP_VS_PE_SIP=m -CONFIG_IPV6=m +CONFIG_IPV6=y CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y @@ -834,25 +870,34 @@ CONFIG_NET_9P_VIRTIO=m # CONFIG_NET_9P_DEBUG is not set CONFIG_NET_9P_RDMA=m -CONFIG_DECNET=m -CONFIG_DECNET_ROUTER=y -# CONFIG_DECNET_NF_GRABULATOR is not set +# CONFIG_DECNET is not set CONFIG_BRIDGE=m CONFIG_BRIDGE_IGMP_SNOOPING=y + +# PHY timestamping adds overhead # CONFIG_NETWORK_PHY_TIMESTAMPING is not set + CONFIG_NETFILTER=y CONFIG_NETFILTER_ADVANCED=y -CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK=m CONFIG_NETFILTER_NETLINK=m CONFIG_NETFILTER_NETLINK_QUEUE=m CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NETFILTER_TPROXY=m CONFIG_NETFILTER_XTABLES=y +CONFIG_NETFILTER_XT_SET=m CONFIG_NETFILTER_XT_MARK=m CONFIG_NETFILTER_XT_CONNMARK=m + +CONFIG_NETFILTER_XT_TARGET_AUDIT=m +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m CONFIG_NETFILTER_XT_TARGET_CONNMARK=m CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_CT=m CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m +CONFIG_NETFILTER_XT_TARGET_LED=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m @@ -863,24 +908,31 @@ CONFIG_NETFILTER_XT_TARGET_TCPMSS=m CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m CONFIG_NETFILTER_XT_TARGET_TRACE=m CONFIG_NETFILTER_XT_TARGET_TEE=m -CONFIG_NETFILTER_XT_TARGET_LED=m -CONFIG_NETFILTER_XT_TARGET_CT=m +CONFIG_NETFILTER_XT_TARGET_TPROXY=m + +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_CLUSTER=m CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CPU=m CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m CONFIG_NETFILTER_XT_MATCH_CONNMARK=m CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m CONFIG_NETFILTER_XT_MATCH_DSCP=m CONFIG_NETFILTER_XT_MATCH_ESP=m CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_HL=m CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m CONFIG_NETFILTER_XT_MATCH_LENGTH=m CONFIG_NETFILTER_XT_MATCH_LIMIT=m CONFIG_NETFILTER_XT_MATCH_MAC=m CONFIG_NETFILTER_XT_MATCH_MARK=m CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_OSF=m CONFIG_NETFILTER_XT_MATCH_OWNER=m CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m @@ -888,20 +940,15 @@ CONFIG_NETFILTER_XT_MATCH_POLICY=m CONFIG_NETFILTER_XT_MATCH_QUOTA=m CONFIG_NETFILTER_XT_MATCH_RATEEST=m CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_RECENT=m CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_SOCKET=m CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=m CONFIG_NETFILTER_XT_MATCH_STRING=m CONFIG_NETFILTER_XT_MATCH_TCPMSS=m CONFIG_NETFILTER_XT_MATCH_TIME=m CONFIG_NETFILTER_XT_MATCH_U32=m -CONFIG_NETFILTER_XT_MATCH_CLUSTER=m -CONFIG_NETFILTER_XT_MATCH_HL=m -CONFIG_NETFILTER_XT_MATCH_OSF=m -CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m -CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m -CONFIG_NETFILTER_XT_MATCH_CPU=m -CONFIG_NETFILTER_XT_MATCH_IPVS=m # CONFIG_NETFILTER_DEBUG is not set CONFIG_BRIDGE_NETFILTER=y @@ -910,7 +957,6 @@ CONFIG_BRIDGE_NETFILTER=y # IP: Netfilter Configuration # -CONFIG_NF_CT_ACCT=y CONFIG_NF_CONNTRACK_MARK=y CONFIG_NF_CONNTRACK_SECMARK=y CONFIG_NF_CONNTRACK_EVENTS=y @@ -927,6 +973,8 @@ CONFIG_NF_CONNTRACK_SIP=m CONFIG_NF_CONNTRACK_TFTP=m CONFIG_NF_CONNTRACK_IPV4=y CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_CONNTRACK_TIMESTAMP=y +CONFIG_NF_CONNTRACK_SNMP=m CONFIG_NF_NAT=m CONFIG_NF_NAT_SNMP_BASIC=m CONFIG_NF_CT_PROTO_DCCP=m @@ -934,7 +982,6 @@ CONFIG_NF_CT_PROTO_SCTP=m CONFIG_NF_CT_NETLINK=m CONFIG_NF_CT_PROTO_UDPLITE=m -CONFIG_IP_NF_MATCH_ADDRTYPE=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m CONFIG_IP_NF_MATCH_TTL=m @@ -1016,6 +1063,20 @@ CONFIG_INET6_XFRM_MODE_TUNNEL=m CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_IP_SET=m +CONFIG_IP_SET_MAX=256 +CONFIG_IP_SET_BITMAP_IP=m +CONFIG_IP_SET_BITMAP_IPMAC=m +CONFIG_IP_SET_BITMAP_PORT=m +CONFIG_IP_SET_HASH_IP=m +CONFIG_IP_SET_HASH_IPPORT=m +CONFIG_IP_SET_HASH_IPPORTIP=m +CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_NET=m +CONFIG_IP_SET_HASH_NETPORT=m +CONFIG_IP_SET_HASH_NETIFACE=m +CONFIG_IP_SET_LIST_SET=m + # # SCTP Configuration (EXPERIMENTAL) # @@ -1034,7 +1095,7 @@ CONFIG_LLC=m CONFIG_IPX=m # CONFIG_IPX_INTERN is not set CONFIG_ATALK=m -CONFIG_DEV_APPLETALK=y +CONFIG_DEV_APPLETALK=m CONFIG_IPDDP=m CONFIG_IPDDP_ENCAP=y CONFIG_IPDDP_DECAP=y @@ -1047,9 +1108,8 @@ CONFIG_IP_DCCP_CCID2=m # CONFIG_IP_DCCP_CCID2_DEBUG is not set CONFIG_IP_DCCP_CCID3=y # CONFIG_IP_DCCP_CCID3_DEBUG is not set -CONFIG_IP_DCCP_CCID3_RTO=100 # CONFIG_IP_DCCP_DEBUG is not set -CONFIG_NET_DCCPPROBE=m +# CONFIG_NET_DCCPPROBE is not set # # TIPC Configuration (EXPERIMENTAL) @@ -1077,6 +1137,11 @@ CONFIG_NET_SCH_RED=m CONFIG_NET_SCH_SFQ=m CONFIG_NET_SCH_TBF=m CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_SFB=m +CONFIG_NET_SCH_MQPRIO=m +CONFIG_NET_SCH_MULTIQ=m +CONFIG_NET_SCH_CHOKE=m +CONFIG_NET_SCH_QFQ=m CONFIG_NET_CLS=y CONFIG_NET_CLS_ACT=y CONFIG_NET_CLS_BASIC=m @@ -1100,6 +1165,7 @@ CONFIG_NET_EMATCH_STACK=32 CONFIG_NET_EMATCH_TEXT=m CONFIG_NET_EMATCH_U32=m +CONFIG_NET_ACT_CSUM=m CONFIG_NET_ACT_GACT=m CONFIG_GACT_PROB=y CONFIG_NET_ACT_IPT=m @@ -1108,7 +1174,7 @@ CONFIG_NET_ACT_NAT=m CONFIG_NET_ACT_PEDIT=m CONFIG_NET_ACT_POLICE=m CONFIG_NET_ACT_SIMP=m -CONFIG_NET_ACT_CSUM=m +CONFIG_NET_ACT_SKBEDIT=m CONFIG_DCB=y @@ -1194,10 +1260,191 @@ CONFIG_RFKILL_INPUT=y # # Ethernet (10 or 100Mbit) # -CONFIG_NETDEV_1000=y -CONFIG_NETDEV_10000=y -CONFIG_NET_ETHERNET=y -CONFIG_PHYLIB=m + +CONFIG_NET_VENDOR_ADAPTEC=y +CONFIG_ADAPTEC_STARFIRE=m + +CONFIG_NET_VENDOR_ALTEON=y +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set + +CONFIG_NET_VENDOR_AMD=y +# CONFIG_LANCE is not set +CONFIG_PCNET32=m +CONFIG_AMD8111_ETH=m +CONFIG_PCMCIA_NMCLAN=m + +CONFIG_NET_VENDOR_ATHEROS=y +CONFIG_ATL2=m +CONFIG_ATL1=m +CONFIG_ATL1C=m +CONFIG_ATL1E=m + +CONFIG_NET_VENDOR_BROCADE=y +CONFIG_BNA=m + +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T3=m +CONFIG_CHELSIO_T4=m +CONFIG_CHELSIO_T4VF=m + +# CONFIG_NET_VENDOR_CIRRUS is not set +# +CONFIG_NET_VENDOR_CISCO=y +CONFIG_ENIC=m + +CONFIG_NET_VENDOR_DEC=y +CONFIG_EWRK3=m +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_DE2104X_DSL=0 +CONFIG_TULIP=m +# CONFIG_TULIP_NAPI is not set +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_NI5010 is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_PCMCIA_XIRCOM=m +CONFIG_ULI526X=m + +CONFIG_NET_VENDOR_DLINK=y +CONFIG_DE600=m +CONFIG_DE620=m +CONFIG_DL2K=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set + +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_BE2NET=m + +CONFIG_NET_VENDOR_EXAR=y +CONFIG_S2IO=m +CONFIG_VXGE=m +# CONFIG_VXGE_DEBUG_TRACE_ALL is not set + +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_FUJITSU is not set +# CONFIG_NET_VENDOR_HP is not set +CONFIG_NET_VENDOR_INTEL=y +CONFIG_E100=m +CONFIG_E1000=m +CONFIG_E1000E=m +CONFIG_IGB=m +CONFIG_IGB_DCA=y +CONFIG_IGBVF=m +CONFIG_IXGB=m +CONFIG_IXGBEVF=m +CONFIG_IXGBE=m +CONFIG_IXGBE_DCA=y +CONFIG_IXGBE_DCB=y + +# CONFIG_NET_VENDOR_I825XX is not set +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKGE_GENESIS=y +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set + +CONFIG_NET_VENDOR_MICREL=y +CONFIG_KSZ884X_PCI=m +# CONFIG_KS8842 is not set +# CONFIG_KS8851_MLL is not set + +CONFIG_NET_VENDOR_MYRI=y +CONFIG_MYRI10GE=m +CONFIG_MYRI10GE_DCA=y + +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NATSEMI=m +CONFIG_NS83820=m + +CONFIG_NET_VENDOR_8390=y +# CONFIG_AC3200 is not set +CONFIG_PCMCIA_AXNET=m +CONFIG_NE2K_PCI=m +CONFIG_NE3210=m +CONFIG_PCMCIA_PCNET=m + +CONFIG_NET_VENDOR_NVIDIA=y +CONFIG_FORCEDETH=m + +CONFIG_NET_VENDOR_OKI=y +# CONFIG_PCH_GBE is not set + +CONFIG_NET_PACKET_ENGINE=y +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m + +CONFIG_NET_VENDOR_QLOGIC=y +CONFIG_QLA3XXX=m +CONFIG_QLCNIC=m +CONFIG_QLGE=m +CONFIG_NETXEN_NIC=m + +CONFIG_NET_VENDOR_REALTEK=y +CONFIG_ATP=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_R8169=m + +CONFIG_NET_VENDOR_RDC=y +CONFIG_R6040=m + +# CONFIG_NET_VENDOR_SEEQ is not set + +CONFIG_NET_VENDOR_SILAN=y +CONFIG_SC92031=m + +CONFIG_NET_VENDOR_SIS=y +CONFIG_SIS900=m +CONFIG_SIS190=m + +CONFIG_NET_VENDOR_SMSC=y +# CONFIG_SMC9194 is not set +CONFIG_PCMCIA_SMC91C92=m +CONFIG_EPIC100=m +CONFIG_SMSC9420=m + +CONFIG_NET_VENDOR_STMICRO=y +CONFIG_STMMAC_ETH=m +# CONFIG_STMMAC_DA is not set +# CONFIG_STMMAC_DUAL_MAC is not set +# CONFIG_STMMAC_TIMER is not set +# CONFIG_STMMAC_DEBUG_FS is not set + +CONFIG_NET_VENDOR_SUN=y +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_CASSINI=m +CONFIG_NIU=m + +CONFIG_NET_VENDOR_TEHUTI=y +CONFIG_TEHUTI=m + +CONFIG_NET_VENDOR_TI=y +CONFIG_TLAN=m + +CONFIG_NET_VENDOR_VIA=y +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_VELOCITY=m + +CONFIG_NET_VENDOR_XIRCOM=y +CONFIG_PCMCIA_XIRC2PS=m + +CONFIG_PHYLIB=y CONFIG_BROADCOM_PHY=m CONFIG_CICADA_PHY=m CONFIG_DAVICOM_PHY=m @@ -1217,145 +1464,43 @@ CONFIG_VITESSE_PHY=m CONFIG_MICREL_PHY=m CONFIG_MII=m -CONFIG_HAPPYMEAL=m -CONFIG_SUNGEM=m CONFIG_NET_VENDOR_3COM=y CONFIG_VORTEX=m CONFIG_TYPHOON=m CONFIG_DNET=m -CONFIG_STMMAC_ETH=m -# CONFIG_STMMAC_DA is not set -# CONFIG_STMMAC_DUAL_MAC is not set -# CONFIG_STMMAC_TIMER is not set -# CONFIG_PCH_GBE is not set -# -# Tulip family network device support -# -CONFIG_NET_TULIP=y -CONFIG_DE2104X=m -CONFIG_DE2104X_DSL=0 -CONFIG_TULIP=m -# CONFIG_TULIP_NAPI is not set -# CONFIG_TULIP_MWI is not set -CONFIG_TULIP_MMIO=y -# CONFIG_NI5010 is not set -CONFIG_DE4X5=m -CONFIG_WINBOND_840=m -CONFIG_DM9102=m -CONFIG_PCMCIA_XIRCOM=m -CONFIG_ULI526X=m -# CONFIG_HP100 is not set CONFIG_LNE390=m -CONFIG_NE3210=m CONFIG_ES3210=m CONFIG_NET_PCI=y -CONFIG_PCNET32=m -CONFIG_AMD8111_ETH=m -CONFIG_ADAPTEC_STARFIRE=m -CONFIG_KSZ884X_PCI=m CONFIG_B44=m CONFIG_B44_PCI=y CONFIG_BNX2=m CONFIG_CNIC=m -CONFIG_QLA3XXX=m -CONFIG_ATL1=m -CONFIG_ATL1C=m -CONFIG_ATL2=m -CONFIG_ATL1E=m -CONFIG_E100=m CONFIG_FEALNX=m -CONFIG_FORCEDETH=m -CONFIG_FORCEDETH_NAPI=y -CONFIG_NATSEMI=m -CONFIG_NE2K_PCI=m -CONFIG_8139CP=m -CONFIG_8139TOO=m -# CONFIG_8139TOO_PIO is not set -# CONFIG_8139TOO_TUNE_TWISTER is not set -CONFIG_8139TOO_8129=y -# CONFIG_8139_OLD_RX_RESET is not set -CONFIG_SIS900=m -CONFIG_SIS190=m -CONFIG_EPIC100=m -CONFIG_SC92031=m -CONFIG_SMSC9420=m -CONFIG_SUNDANCE=m -# CONFIG_SUNDANCE_MMIO is not set -CONFIG_TLAN=m -CONFIG_VIA_RHINE=m -CONFIG_VIA_RHINE_MMIO=y -CONFIG_VIA_VELOCITY=m CONFIG_NET_POCKET=y -CONFIG_ATP=m -CONFIG_DE600=m -CONFIG_DE620=m -CONFIG_CASSINI=m CONFIG_ETHOC=m -# CONFIG_KS8842 is not set -# CONFIG_KS8851_MLL is not set # # Ethernet (1000 Mbit) # -CONFIG_ACENIC=m -# CONFIG_ACENIC_OMIT_TIGON_I is not set -CONFIG_DL2K=m -CONFIG_E1000=m -CONFIG_E1000E=m -CONFIG_IGB=m -CONFIG_IGB_DCA=y -CONFIG_IGBVF=m -CONFIG_NS83820=m -CONFIG_HAMACHI=m -CONFIG_YELLOWFIN=m -CONFIG_R8169=m -CONFIG_R8169_VLAN=y -CONFIG_SKGE=m -# CONFIG_SKGE_DEBUG is not set CONFIG_TIGON3=m -CONFIG_SKY2=m -# CONFIG_SKY2_DEBUG is not set CONFIG_JME=m # # Ethernet (10000 Mbit) # -CONFIG_CHELSIO_T1=m -CONFIG_CHELSIO_T1_1G=y -CONFIG_CHELSIO_T3=m -CONFIG_CHELSIO_T4=m -CONFIG_CHELSIO_T4VF=m CONFIG_IP1000=m -CONFIG_IXGB=m -CONFIG_IXGBEVF=m -CONFIG_IXGBE=m -CONFIG_IXGBE_DCA=y -CONFIG_IXGBE_DCB=y -CONFIG_MYRI10GE=m -CONFIG_MYRI10GE_DCA=y -CONFIG_NETXEN_NIC=m -CONFIG_NIU=m -CONFIG_S2IO=m -CONFIG_VXGE=m -# CONFIG_VXGE_DEBUG_TRACE_ALL is not set -CONFIG_TEHUTI=m -CONFIG_ENIC=m CONFIG_MLX4_EN=m # CONFIG_MLX4_DEBUG is not set -CONFIG_QLCNIC=m -CONFIG_QLGE=m -CONFIG_BNA=m CONFIG_SFC=m CONFIG_SFC_MTD=y -CONFIG_BE2NET=m -CONFIG_FDDI=y +# CONFIG_FDDI is not set # CONFIG_DEFXX is not set -CONFIG_SKFP=m +# CONFIG_SKFP is not set # CONFIG_HIPPI is not set -CONFIG_PLIP=m +# CONFIG_PLIP is not set CONFIG_PPP=m CONFIG_PPP_MULTILINK=y CONFIG_PPP_FILTER=y @@ -1363,13 +1508,10 @@ CONFIG_PPP_ASYNC=m CONFIG_PPP_SYNC_TTY=m CONFIG_PPP_DEFLATE=m CONFIG_IPPP_FILTER=y -# CONFIG_PPP_BSDCOMP is not set +CONFIG_PPP_BSDCOMP=y CONFIG_PPPOE=m CONFIG_PPP_MPPE=m -CONFIG_SLIP=m -CONFIG_SLIP_COMPRESSED=y -CONFIG_SLIP_SMART=y -# CONFIG_SLIP_MODE_SLIP6 is not set +# CONFIG_SLIP is not set # # Wireless LAN @@ -1377,9 +1519,6 @@ CONFIG_SLIP_SMART=y # CONFIG_WLAN=y # CONFIG_STRIP is not set -# CONFIG_ARLAN is not set -CONFIG_PCMCIA_WAVELAN=m -CONFIG_PCMCIA_NETWAVE=m # CONFIG_PCMCIA_RAYCS is not set CONFIG_WIRELESS=y @@ -1391,7 +1530,6 @@ CONFIG_CFG80211_DEBUGFS=y CONFIG_CFG80211_DEFAULT_PS=y CONFIG_NL80211=y # CONFIG_NL80211_TESTMODE is not set -# CONFIG_WIRELESS_OLD_REGULATORY is not set CONFIG_WIRELESS_EXT=y CONFIG_WIRELESS_EXT_SYSFS=y CONFIG_LIB80211=m @@ -1421,7 +1559,12 @@ CONFIG_ADM8211=m CONFIG_ATH_COMMON=m CONFIG_ATH5K=m CONFIG_ATH5K_DEBUG=y +# CONFIG_ATH5K_TRACER is not set +CONFIG_ATH6KL=m +CONFIG_ATH6KL_DEBUG=y CONFIG_ATH9K=m +CONFIG_ATH9K_PCI=y +CONFIG_ATH9K_AHB=y # CONFIG_ATH9K_DEBUG is not set CONFIG_ATH9K_DEBUGFS=y CONFIG_ATH9K_HTC=m @@ -1429,6 +1572,7 @@ CONFIG_ATH9K_HTC=m CONFIG_ATH9K_RATE_CONTROL=y CONFIG_CARL9170=m CONFIG_CARL9170_LEDS=y +# CONFIG_CARL9170_HWRNG is not set CONFIG_AT76C50X_USB=m CONFIG_AIRO=m CONFIG_AIRO_CS=m @@ -1436,9 +1580,12 @@ CONFIG_ATMEL=m CONFIG_B43=m CONFIG_B43_PCMCIA=y CONFIG_B43_SDIO=y +CONFIG_B43_BCMA=y +CONFIG_B43_BCMA_PIO=y # CONFIG_B43_DEBUG is not set CONFIG_B43_PHY_LP=y CONFIG_B43_PHY_N=y +CONFIG_B43_PHY_HT=y # CONFIG_B43_FORCE_PIO is not set CONFIG_B43LEGACY=m # CONFIG_B43LEGACY_DEBUG is not set @@ -1447,6 +1594,9 @@ CONFIG_B43LEGACY_PIO=y CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y # CONFIG_B43LEGACY_DMA_MODE is not set # CONFIG_B43LEGACY_PIO_MODE is not set +CONFIG_BRCMSMAC=m +CONFIG_BRCMFMAC=m +# CONFIG_BRCMDBG is not set CONFIG_HERMES=m CONFIG_HERMES_CACHE_FW_ON_INIT=y # CONFIG_HERMES_PRISM is not set @@ -1478,12 +1628,15 @@ CONFIG_LIBERTAS_MESH=y CONFIG_IWLWIFI=m CONFIG_IWLWIFI_DEBUG=y CONFIG_IWLWIFI_DEBUGFS=y -CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT=y +CONFIG_IWLWIFI_DEVICE_SVTOOL=y +# CONFIG_IWL_P2P is not set CONFIG_IWLAGN=m +CONFIG_IWLWIFI_LEGACY=m +CONFIG_IWLWIFI_LEGACY_DEBUG=y +CONFIG_IWLWIFI_LEGACY_DEBUGFS=y +# CONFIG_IWLWIFI_LEGACY_DEVICE_TRACING is not set CONFIG_IWL4965=y -CONFIG_IWL5000=y CONFIG_IWL3945=m -CONFIG_IWL3945_SPECTRUM_MEASUREMENT=y # CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE is not set CONFIG_IWM=m # CONFIG_IWM_DEBUG is not set @@ -1508,20 +1661,22 @@ CONFIG_RT2500USB=m CONFIG_RT2800USB=m CONFIG_RT2800USB_RT33XX=y CONFIG_RT2800USB_RT35XX=y +CONFIG_RT2800USB_RT53XX=y CONFIG_RT2800USB_UNKNOWN=y CONFIG_RT2800PCI=m CONFIG_RT2800PCI_RT33XX=y CONFIG_RT2800PCI_RT35XX=y +CONFIG_RT2800PCI_RT53XX=y CONFIG_RT73USB=m CONFIG_RTL8180=m CONFIG_RTL8187=m CONFIG_TMD_HERMES=m CONFIG_USB_ZD1201=m CONFIG_USB_NET_RNDIS_WLAN=m +CONFIG_USB_NET_KALMIA=m CONFIG_USB_NET_SMSC75XX=m CONFIG_ZD1211RW=m # CONFIG_ZD1211RW_DEBUG is not set -CONFIG_AR9170_USB=m CONFIG_WL12XX_MENU=m CONFIG_WL12XX=m @@ -1533,25 +1688,20 @@ CONFIG_WL12XX_SDIO=m CONFIG_WL1251=m CONFIG_WL1251_SPI=m CONFIG_WL1251_SDIO=m -CONFIG_WL1271=m -CONFIG_WL1271_SDIO=m -CONFIG_WL1271_SPI=m CONFIG_RTL8192CE=m +CONFIG_RTL8192SE=m +CONFIG_RTL8192CU=m +CONFIG_RTL8192DE=m + +CONFIG_MWIFIEX=m +CONFIG_MWIFIEX_SDIO=m +CONFIG_MWIFIEX_PCIE=m # # Token Ring devices # # CONFIG_TR is not set -# CONFIG_IBMOL is not set -# CONFIG_3C359 is not set -# Broken with gcc4.1 -# CONFIG_TMS380TR is not set -# CONFIG_TMSPCI is not set -# CONFIG_ABYSS is not set -# CONFIG_IBMLS is not set -# CONFIG_PCMCIA_IBMTR is not set - CONFIG_NET_FC=y @@ -1567,11 +1717,6 @@ CONFIG_NET_PCMCIA=y CONFIG_PCMCIA_3C589=m CONFIG_PCMCIA_3C574=m CONFIG_PCMCIA_FMVJ18X=m -CONFIG_PCMCIA_PCNET=m -CONFIG_PCMCIA_NMCLAN=m -CONFIG_PCMCIA_SMC91C92=m -CONFIG_PCMCIA_XIRC2PS=m -CONFIG_PCMCIA_AXNET=m # # Amateur Radio support @@ -1579,25 +1724,9 @@ CONFIG_PCMCIA_AXNET=m CONFIG_HAMRADIO=y CONFIG_AX25=m CONFIG_AX25_DAMA_SLAVE=y -CONFIG_CAN=m -CONFIG_CAN_RAW=m -CONFIG_CAN_BCM=m -CONFIG_CAN_VCAN=m -CONFIG_CAN_DEV=m -CONFIG_CAN_CALC_BITTIMING=y -CONFIG_CAN_SJA1000=m -CONFIG_CAN_SJA1000_ISA=m -CONFIG_CAN_SJA1000_PLATFORM=m -CONFIG_CAN_EMS_PCI=m -CONFIG_CAN_EMS_USB=m -CONFIG_CAN_ESD_USB2=m -CONFIG_CAN_KVASER_PCI=m -CONFIG_CAN_PLX_PCI=m -CONFIG_CAN_TSCAN1=m -CONFIG_CAN_SLCAN=m -CONFIG_CAN_SOFTING=m -CONFIG_CAN_SOFTING_CS=m -# CONFIG_PCH_CAN is not set + +# CONFIG_CAN is not set + CONFIG_NETROM=m CONFIG_ROSE=m CONFIG_MKISS=m @@ -1613,6 +1742,8 @@ CONFIG_BAYCOM_PAR=m CONFIG_BAYCOM_EPP=m CONFIG_YAM=m +# CONFIG_NFC is not set + # # IrDA (infrared) support # @@ -1655,9 +1786,8 @@ CONFIG_WINBOND_FIR=m # Bluetooth support # CONFIG_BT=m -CONFIG_BT_L2CAP=m -CONFIG_BT_L2CAP_EXT_FEATURES=y -CONFIG_BT_SCO=m +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y CONFIG_BT_CMTP=m CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y @@ -1689,6 +1819,7 @@ CONFIG_BT_HCIUART_LL=y CONFIG_BT_MRVL=m CONFIG_BT_MRVL_SDIO=m CONFIG_BT_ATH3K=m +CONFIG_BT_WILINK=m # # ISDN subsystem @@ -1780,8 +1911,6 @@ CONFIG_ISDN_CAPI=m CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y CONFIG_ISDN_CAPI_MIDDLEWARE=y CONFIG_ISDN_CAPI_CAPI20=m -CONFIG_ISDN_CAPI_CAPIFS_BOOL=y -CONFIG_ISDN_CAPI_CAPIFS=m # # CAPI hardware drivers @@ -1846,6 +1975,7 @@ CONFIG_INPUT_CM109=m CONFIG_INPUT_POLLDEV=m CONFIG_INPUT_SPARSEKMAP=m # CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_BMA150 is not set CONFIG_INPUT_CMA3000=m CONFIG_INPUT_CMA3000_I2C=m @@ -1880,12 +2010,14 @@ CONFIG_KEYBOARD_ATKBD=y # CONFIG_KEYBOARD_STOWAWAY is not set # CONFIG_KEYBOARD_LKKBD is not set # CONFIG_KEYBOARD_LM8323 is not set -# FIXME: Do we really need these keyboards enabled ? -CONFIG_KEYBOARD_ADP5588=m -CONFIG_KEYBOARD_MAX7359=m +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_QT1070 is not set # CONFIG_KEYBOARD_MCS is not set -CONFIG_KEYBOARD_OPENCORES=m -CONFIG_KEYBOARD_QT2160=m +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_QT2160 is not set # CONFIG_KEYBOARD_TCA6416 is not set CONFIG_INPUT_MOUSE=y CONFIG_MOUSE_PS2=y @@ -1944,9 +2076,9 @@ CONFIG_TOUCHSCREEN_INEXIO=m CONFIG_TOUCHSCREEN_MTOUCH=m CONFIG_TOUCHSCREEN_MCS5000=m CONFIG_TOUCHSCREEN_MK712=m -# CONFIG_TOUCHSCREEN_QT602240 is not set CONFIG_TOUCHSCREEN_PENMOUNT=m # CONFIG_TOUCHSCREEN_TPS6507X is not set +CONFIG_TOUCHSCREEN_TSC_SERIO=m CONFIG_TOUCHSCREEN_TSC2007=m CONFIG_TOUCHSCREEN_TOUCHIT213=m CONFIG_TOUCHSCREEN_TOUCHRIGHT=m @@ -1959,6 +2091,8 @@ CONFIG_TOUCHSCREEN_USB_COMPOSITE=m CONFIG_TOUCHSCREEN_W90X900=m # CONFIG_TOUCHSCREEN_BU21013 is not set CONFIG_TOUCHSCREEN_ST1232=m +CONFIG_TOUCHSCREEN_ATMEL_MXT=m +# CONFIG_TOUCHSCREEN_MAX11801 is not set CONFIG_INPUT_MISC=y CONFIG_INPUT_PCSPKR=m @@ -1966,7 +2100,6 @@ CONFIG_INPUT_UINPUT=m CONFIG_INPUT_WISTRON_BTNS=m CONFIG_INPUT_ATLAS_BTNS=m -CONFIG_INPUT_ATI_REMOTE=m CONFIG_INPUT_ATI_REMOTE2=m CONFIG_INPUT_KEYSPAN_REMOTE=m @@ -1974,10 +2107,13 @@ CONFIG_MAC_EMUMOUSEBTN=y CONFIG_INPUT_WM831X_ON=m -CONFIG_INPUT_APPLEIR=m # CONFIG_INPUT_AD714X is not set # CONFIG_INPUT_PCF8574 is not set +CONFIG_INPUT_MMA8450=m +CONFIG_INPUT_MPU3050=m +CONFIG_INPUT_KXTJ9=m +# CONFIG_INPUT_KXTJ9_POLLED_MODE is not set # # Character devices @@ -1993,6 +2129,7 @@ CONFIG_SYNCLINKMP=m CONFIG_SYNCLINK_GT=m CONFIG_N_HDLC=m CONFIG_N_GSM=m +# CONFIG_TRACE_SINK is not set # CONFIG_STALDRV is not set # CONFIG_IBM_ASM is not set CONFIG_TIFM_CORE=m @@ -2017,19 +2154,13 @@ CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y # CONFIG_SERIAL_8250_DETECT_IRQ is not set CONFIG_SERIAL_8250_RSA=y -# CONFIG_COMPUTONE is not set +# CONFIG_SERIAL_8250_DW is not set CONFIG_CYCLADES=m # CONFIG_CYZ_INTR is not set -# CONFIG_DIGIEPCA is not set # CONFIG_MOXA_INTELLIO is not set # CONFIG_MOXA_SMARTIO is not set # CONFIG_ISI is not set -# CONFIG_RISCOM8 is not set -# CONFIG_SPECIALIX is not set -# CONFIG_SX is not set # CONFIG_RIO is not set -# CONFIG_STALLION is not set -# CONFIG_ISTALLION is not set CONFIG_SERIAL_JSM=m # CONFIG_SERIAL_MFD_HSU is not set @@ -2041,6 +2172,7 @@ CONFIG_SERIAL_JSM=m # CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_XILINX_PS_UART is not set # CONFIG_SERIAL_TIMBERDALE is not set CONFIG_UNIX98_PTYS=y CONFIG_DEVPTS_MULTIPLE_INSTANCES=y @@ -2079,7 +2211,6 @@ CONFIG_I2C_ALGOPCA=m # CONFIG_I2C_AMD8111 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_BUS is not set -# CONFIG_I2C_DEBUG_CHIP is not set # CONFIG_I2C_ELEKTOR is not set # CONFIG_I2C_I801 is not set # CONFIG_I2C_ISCH is not set @@ -2113,6 +2244,8 @@ CONFIG_I2C_TINY_USB=m # CONFIG_I2C_DESIGNWARE is not set # CONFIG_I2C_XILINX is not set +CONFIG_I2C_DIOLAN_U2C=m + # # I2C Hardware Sensors Chip support # @@ -2130,7 +2263,6 @@ CONFIG_SENSORS_ADM9240=m CONFIG_SENSORS_ADS7828=m CONFIG_SENSORS_ADT7462=m CONFIG_SENSORS_ADT7470=m -CONFIG_SENSORS_ADT7473=m CONFIG_SENSORS_ADT7475=m CONFIG_SENSORS_APPLESMC=m CONFIG_SENSORS_ASB100=m @@ -2170,6 +2302,7 @@ CONFIG_SENSORS_LM93=m CONFIG_SENSORS_LTC4245=m CONFIG_SENSORS_MAX1619=m CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_NTC_THERMISTOR=m CONFIG_SENSORS_PC87360=m CONFIG_SENSORS_PC87427=m CONFIG_SENSORS_PCF8591=m @@ -2200,6 +2333,7 @@ CONFIG_SENSORS_W83792D=m CONFIG_SENSORS_W83793=m CONFIG_SENSORS_LTC4215=m CONFIG_SENSORS_LM95241=m +CONFIG_SENSORS_LM95245=m CONFIG_SENSORS_TMP421=m CONFIG_SENSORS_WM8350=m CONFIG_SENSORS_WM831X=m @@ -2219,28 +2353,36 @@ CONFIG_SENSORS_W83795=m # CONFIG_SENSORS_W83795_FANCTRL is not set CONFIG_SENSORS_DS620=m CONFIG_SENSORS_SHT21=m +CONFIG_SENSORS_LINEAGE=m +CONFIG_SENSORS_LTC4151=m +CONFIG_SENSORS_MAX6639=m +CONFIG_SENSORS_SCH5627=m +CONFIG_SENSORS_SCH5636=m +CONFIG_SENSORS_ADS1015=m +CONFIG_SENSORS_MAX16065=m +CONFIG_SENSORS_MAX6642=m +CONFIG_SENSORS_ADM1275=m +CONFIG_SENSORS_UCD9000=m +CONFIG_SENSORS_UCD9200=m +CONFIG_SENSORS_ZL6100=m +CONFIG_SENSORS_EMC6W201=m + +CONFIG_PMBUS=m +CONFIG_SENSORS_PMBUS=m +CONFIG_SENSORS_MAX16064=m +CONFIG_SENSORS_LM25066=m +CONFIG_SENSORS_LTC2978=m +CONFIG_SENSORS_MAX34440=m +CONFIG_SENSORS_MAX8688=m +CONFIG_SENSORS_MAX1668=m # CONFIG_HMC6352 is not set # CONFIG_BMP085 is not set # CONFIG_PCH_PHUB is not set # CONFIG_SERIAL_PCH_UART is not set +# CONFIG_USB_SWITCH_FSA9480 is not set -CONFIG_W1=m -CONFIG_W1_CON=y -# This is busted. -# If we enable it, it steals Matrox cards, and the -# framebuffer drivers stop working. -# CONFIG_W1_MASTER_MATROX is not set -CONFIG_W1_MASTER_DS2482=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS1WM=m -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2431=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2433_CRC=y -CONFIG_W1_SLAVE_DS2760=m -CONFIG_W1_SLAVE_DS2423=m +# CONFIG_W1 is not set # # Mice @@ -2260,6 +2402,7 @@ CONFIG_IPMI_POWEROFF=m # Watchdog Cards # CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y # CONFIG_WATCHDOG_NOWAYOUT is not set CONFIG_SOFT_WATCHDOG=m CONFIG_WDTPCI=m @@ -2276,6 +2419,7 @@ CONFIG_MACHZ_WDT=m # CONFIG_SC520_WDT is not set CONFIG_ALIM7101_WDT=m CONFIG_ALIM1535_WDT=m +CONFIG_IT87_WDT=m CONFIG_ITCO_WDT=m CONFIG_ITCO_VENDOR_SUPPORT=y # CONFIG_SC1200_WDT is not set @@ -2289,11 +2433,15 @@ CONFIG_IT8712F_WDT=m CONFIG_SMSC_SCH311X_WDT=m CONFIG_W83977F_WDT=m CONFIG_PCIPCWATCHDOG=m +# CONFIG_PCWATCHDOG is not set CONFIG_USBPCWATCHDOG=m # CONFIG_SBC_EPX_C3_WATCHDOG is not set CONFIG_WM8350_WATCHDOG=m CONFIG_WM831X_WATCHDOG=m # CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_DW_WATCHDOG is not set +CONFIG_W83697UG_WDT=m +# CONFIG_WDT is not set CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_TIMERIOMEM=m @@ -2310,6 +2458,7 @@ CONFIG_RTC_INTF_DEV=y # CONFIG_RTC_INTF_DEV_UIE_EMUL is not set CONFIG_RTC_DRV_CMOS=y CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1511=m CONFIG_RTC_DRV_DS1553=m CONFIG_RTC_DRV_DS1672=m CONFIG_RTC_DRV_DS1742=m @@ -2342,6 +2491,8 @@ CONFIG_RTC_DRV_WM831X=m CONFIG_RTC_DRV_BQ32K=m CONFIG_RTC_DRV_MSM6242=m CONFIG_RTC_DRV_RP5C01=m +CONFIG_RTC_DRV_EM3027=m +CONFIG_RTC_DRV_RV3029C2=m CONFIG_DTLK=m CONFIG_R3964=m @@ -2365,13 +2516,13 @@ CONFIG_AGP_EFFICEON=y CONFIG_VGA_ARB=y CONFIG_VGA_ARB_MAX_GPUS=16 CONFIG_STUB_POULSBO=m +# CONFIG_DRM_PSB is not set CONFIG_DRM=m CONFIG_DRM_TDFX=m CONFIG_DRM_R128=m CONFIG_DRM_RADEON=m CONFIG_DRM_RADEON_KMS=y CONFIG_DRM_I810=m -# CONFIG_DRM_I830 is not set CONFIG_DRM_MGA=m CONFIG_DRM_SIS=m CONFIG_DRM_SAVAGE=m @@ -2402,12 +2553,12 @@ CONFIG_HANGCHECK_TIMER=m # Multimedia devices # CONFIG_MEDIA_SUPPORT=m +CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_DEV=m # CONFIG_VIDEO_ADV_DEBUG is not set CONFIG_VIDEO_HELPER_CHIPS_AUTO=y -CONFIG_VIDEO_ALLOW_V4L1=y -CONFIG_VIDEO_V4L1_COMPAT=y CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y # CONFIG_VIDEO_VIVI is not set # @@ -2424,11 +2575,13 @@ CONFIG_VIDEO_BT848=m CONFIG_VIDEO_BT848_DVB=y CONFIG_VIDEO_BWQCAM=m CONFIG_VIDEO_SR030PC30=m +CONFIG_VIDEO_NOON010PC30=m CONFIG_VIDEO_CAFE_CCIC=m # CONFIG_VIDEO_CPIA is not set CONFIG_VIDEO_CPIA2=m CONFIG_VIDEO_CQCAM=m CONFIG_VIDEO_CX23885=m +CONFIG_MEDIA_ALTERA_CI=m CONFIG_VIDEO_CX18=m CONFIG_VIDEO_CX18_ALSA=m CONFIG_VIDEO_CX88=m @@ -2439,6 +2592,7 @@ CONFIG_VIDEO_CX88_VP3054=m CONFIG_VIDEO_EM28XX=m CONFIG_VIDEO_EM28XX_ALSA=m CONFIG_VIDEO_EM28XX_DVB=m +CONFIG_VIDEO_EM28XX_RC=y CONFIG_VIDEO_CX231XX=m CONFIG_VIDEO_CX231XX_ALSA=m CONFIG_VIDEO_CX231XX_DVB=m @@ -2448,17 +2602,14 @@ CONFIG_VIDEO_HEXIUM_GEMINI=m CONFIG_VIDEO_IVTV=m CONFIG_VIDEO_MEYE=m CONFIG_VIDEO_MXB=m -# CONFIG_VIDEO_OVCAMCHIP is not set CONFIG_VIDEO_PVRUSB2_DVB=y +# CONFIG_VIDEO_PMS is not set CONFIG_VIDEO_HDPVR=m -CONFIG_VIDEO_SAA5246A=m -CONFIG_VIDEO_SAA5249=m CONFIG_VIDEO_SAA6588=m CONFIG_VIDEO_SAA7134=m CONFIG_VIDEO_SAA7134_ALSA=m CONFIG_VIDEO_SAA7134_DVB=m CONFIG_VIDEO_SAA7134_RC=y -CONFIG_VIDEO_STRADIS=m CONFIG_VIDEO_USBVISION=m CONFIG_VIDEO_W9966=m CONFIG_VIDEO_ZORAN=m @@ -2471,8 +2622,21 @@ CONFIG_VIDEO_ZORAN_LML33R10=m CONFIG_VIDEO_ZORAN_ZR36060=m CONFIG_VIDEO_FB_IVTV=m CONFIG_VIDEO_SAA7164=m +CONFIG_VIDEO_TM6000=m +CONFIG_VIDEO_TM6000_ALSA=m +CONFIG_VIDEO_TM6000_DVB=m CONFIG_VIDEO_TLG2300=m +# CONFIG_VIDEO_ADV7183 is not set +# CONFIG_VIDEO_VS6624 is not set +# CONFIG_VIDEO_MT9M032 is not set + +CONFIG_IR_GPIO_CIR=m +CONFIG_MEDIA_TUNER_FC0011=m +CONFIG_MEDIA_TUNER_TUA9001=m +CONFIG_USB_KEENE=n + # CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_VIDEO_M5MOLS is not set CONFIG_USB_VIDEO_CLASS=m CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y @@ -2480,10 +2644,9 @@ CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y # # Radio Adapters # -CONFIG_RADIO_GEMTEK_PCI=m CONFIG_RADIO_MAXIRADIO=m -CONFIG_RADIO_MAESTRO=m CONFIG_RADIO_WL1273=m +CONFIG_RADIO_WL128X=m CONFIG_MEDIA_ATTACH=y CONFIG_MEDIA_TUNER_CUSTOMISE=y @@ -2498,17 +2661,20 @@ CONFIG_MEDIA_TUNER_MT2131=m CONFIG_MEDIA_TUNER_QT1010=m CONFIG_MEDIA_TUNER_XC2028=m CONFIG_MEDIA_TUNER_XC5000=m +CONFIG_MEDIA_TUNER_XC4000=m CONFIG_MEDIA_TUNER_MXL5005S=m CONFIG_MEDIA_TUNER_MXL5007T=m CONFIG_MEDIA_TUNER_MC44S803=m CONFIG_MEDIA_TUNER_MAX2165=m CONFIG_MEDIA_TUNER_TDA18218=m +CONFIG_MEDIA_TUNER_TDA18212=m # # Digital Video Broadcasting Devices # CONFIG_DVB_CAPTURE_DRIVERS=y CONFIG_DVB_CORE=m +CONFIG_DVB_NET=y CONFIG_DVB_MAX_ADAPTERS=8 CONFIG_DVB_DYNAMIC_MINORS=y @@ -2517,6 +2683,8 @@ CONFIG_DVB_STB0899=m CONFIG_DVB_STB6100=m CONFIG_DVB_STV090x=m CONFIG_DVB_STV6110x=m +CONFIG_DVB_DRXK=m +CONFIG_DVB_TDA18271C2DD=m CONFIG_DVB_CX24110=m CONFIG_DVB_CX24123=m CONFIG_DVB_MT312=m @@ -2574,6 +2742,14 @@ CONFIG_DVB_ATBM8830=m CONFIG_DVB_TDA665x=m CONFIG_DVB_STV0299=m CONFIG_DVB_MB86A16=m +CONFIG_DVB_DRXD=m +CONFIG_DVB_CXD2820R=m +CONFIG_DVB_USB_AZ6007=m +CONFIG_DVB_USB_RTL28XXU=m +CONFIG_DVB_USB_AF9035=m +CONFIG_DVB_RTL2830=m +CONFIG_DVB_M88RS2000=m +CONFIG_DVB_AF9033=m # # Supported Frontend Modules @@ -2591,16 +2767,25 @@ CONFIG_DVB_USB_ANYSEE=m CONFIG_DVB_USB_DW2102=m CONFIG_DVB_USB_FRIIO=m CONFIG_DVB_USB_EC168=m +CONFIG_DVB_USB_PCTV452E=m +CONFIG_DVB_USB_IT913X=m +CONFIG_DVB_USB_MXL111SF=m +CONFIG_DVB_TDA10071=m +CONFIG_DVB_LNBP22=m +CONFIG_DVB_A8293=m +CONFIG_DVB_IT913X_FE=m CONFIG_DVB_DM1105=m -CONFIG_DVB_DRX397XD=m -CONFIG_DVB_LGDT3304=m CONFIG_DVB_S921=m CONFIG_DVB_ISL6405=m CONFIG_DVB_LGS8GL5=m CONFIG_DVB_DUMMY_FE=m CONFIG_DVB_FIREDTV=m CONFIG_DVB_NGENE=m +CONFIG_DVB_DDBRIDGE=m CONFIG_DVB_MB86A20S=m +CONFIG_DVB_USB_TECHNISAT_USB2=m +CONFIG_DVB_DIB9000=m +CONFIG_DVB_STV0367=m # # Supported SAA7146 based PCI Adapters @@ -2668,16 +2853,24 @@ CONFIG_VIDEO_PVRUSB2_SYSFS=y CONFIG_RC_CORE=m CONFIG_RC_LOOPBACK=m CONFIG_RC_MAP=m +CONFIG_RC_ATI_REMOTE=m CONFIG_IR_NEC_DECODER=m CONFIG_IR_RC5_DECODER=m CONFIG_IR_RC6_DECODER=m CONFIG_IR_JVC_DECODER=m CONFIG_IR_SONY_DECODER=m CONFIG_IR_RC5_SZ_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m CONFIG_IR_LIRC_CODEC=m CONFIG_IR_IMON=m CONFIG_IR_MCEUSB=m +CONFIG_IR_ITE_CIR=m CONFIG_IR_NUVOTON=m +CONFIG_IR_FINTEK=m +CONFIG_IR_REDRAT3=m +CONFIG_IR_ENE=m +CONFIG_IR_STREAMZAP=m +CONFIG_IR_WINBOND_CIR=m CONFIG_V4L_MEM2MEM_DRIVERS=y # CONFIG_VIDEO_MEM2MEM_TESTDEV is not set @@ -2696,19 +2889,16 @@ CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_FB=y # CONFIG_FB_FOREIGN_ENDIAN is not set -CONFIG_FB_3DFX=m -CONFIG_FB_3DFX_ACCEL=y -CONFIG_FB_3DFX_I2C=y +# CONFIG_FB_3DFX is not set # CONFIG_FB_ARC is not set # CONFIG_FB_ARK is not set -CONFIG_FB_ATY128=m -CONFIG_FB_ATY=m -CONFIG_FB_ATY_CT=y -CONFIG_FB_ATY_GX=y -CONFIG_FB_ATY_GENERIC_LCD=y +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_ATY_CT is not set +# CONFIG_FB_ATY_GX is not set # CONFIG_FB_ASILIANT is not set # CONFIG_FB_CARMINE is not set -CONFIG_FB_CIRRUS=m +# CONFIG_FB_CIRRUS is not set # CONFIG_FB_CYBER2000 is not set # CONFIG_FB_GEODE is not set # CONFIG_FB_HECUBA is not set @@ -2720,38 +2910,34 @@ CONFIG_FB_I810_I2C=y # CONFIG_FB_INTEL is not set # CONFIG_FB_INTEL_DEBUG is not set # CONFIG_FB_INTEL_I2C is not set -CONFIG_FB_KYRO=m +# CONFIG_FB_KYRO is not set # CONFIG_FB_LE80578 is not set -CONFIG_FB_MATROX=m -CONFIG_FB_MATROX_MILLENIUM=y -CONFIG_FB_MATROX_MYSTIQUE=y -CONFIG_FB_MATROX_G=y -CONFIG_FB_MATROX_I2C=m -CONFIG_FB_MATROX_MAVEN=m -CONFIG_FB_NEOMAGIC=m -CONFIG_FB_NVIDIA=m +# CONFIG_FB_MATROX is not set +# CONFIG_FB_MATROX_MILLENIUM is not set +# CONFIG_FB_MATROX_MYSTIQUE is not set +# CONFIG_FB_MATROX_G is not set +# CONFIG_FB_MATROX_I2C is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_NVIDIA_I2C is not set # CONFIG_FB_NVIDIA_DEBUG is not set -CONFIG_FB_NVIDIA_I2C=y # CONFIG_FB_PM2 is not set # CONFIG_FB_PM2_FIFO_DISCONNECT is not set # CONFIG_FB_PM3 is not set -CONFIG_FB_RADEON=m +# CONFIG_FB_RADEON is not set +# CONFIG_FB_RADEON_I2C is not set # CONFIG_FB_RADEON_DEBUG is not set -CONFIG_FB_RADEON_I2C=y -CONFIG_FB_RIVA=m +# CONFIG_FB_RIVA is not set # CONFIG_FB_RIVA_DEBUG is not set # CONFIG_FB_RIVA_I2C is not set # CONFIG_FB_S1D13XXX is not set -CONFIG_FB_S3=m -CONFIG_FB_SAVAGE=m -CONFIG_FB_SAVAGE_I2C=y -CONFIG_FB_SAVAGE_ACCEL=y +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set # CONFIG_FB_SIS is not set -CONFIG_FB_SIS_300=y -CONFIG_FB_SIS_315=y -CONFIG_FB_SM501=m +# CONFIG_FB_SM501 is not set +# CONFIG_FB_SMSCUFX is not set CONFIG_FB_TILEBLITTING=y -CONFIG_FB_TRIDENT=m +# CONFIG_FB_TRIDENT is not set # CONFIG_FB_UVESA is not set CONFIG_FB_VESA=y CONFIG_FB_VGA16=m @@ -2759,15 +2945,14 @@ CONFIG_FB_VIRTUAL=m CONFIG_FB_VOODOO1=m # CONFIG_FB_VT8623 is not set CONFIG_FB_EFI=y -CONFIG_FB_VIA=m +# CONFIG_FB_VIA is not set # CONFIG_FB_VIA_DIRECT_PROCFS is not set -CONFIG_FB_METRONOME=m -CONFIG_FB_MB862XX=m -CONFIG_FB_MB862XX_PCI_GDC=y -CONFIG_FB_MB862XX_LIME=y +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set # CONFIG_FB_PRE_INIT_FB is not set # CONFIG_FB_TMIO is not set # CONFIG_FB_BROADSHEET is not set +CONFIG_FB_UDL=m # CONFIG_FIRMWARE_EDID is not set @@ -2875,6 +3060,7 @@ CONFIG_SND_ENS1371=m CONFIG_SND_ES1938=m CONFIG_SND_ES1968=m CONFIG_SND_ES1968_INPUT=y +CONFIG_SND_ES1968_RADIO=y CONFIG_SND_FM801=m CONFIG_SND_FM801_TEA575X_BOOL=y CONFIG_SND_CTXFI=m @@ -2886,24 +3072,23 @@ CONFIG_SND_HDA_INPUT_JACK=y CONFIG_SND_HDA_PATCH_LOADER=y CONFIG_SND_HDA_HWDEP=y CONFIG_SND_HDA_CODEC_REALTEK=y +CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS=y CONFIG_SND_HDA_CODEC_CA0110=y CONFIG_SND_HDA_CODEC_ANALOG=y CONFIG_SND_HDA_CODEC_SIGMATEL=y CONFIG_SND_HDA_CODEC_VIA=y -CONFIG_SND_HDA_CODEC_ATIHDMI=y CONFIG_SND_HDA_CODEC_CIRRUS=y CONFIG_SND_HDA_CODEC_CONEXANT=y CONFIG_SND_HDA_CODEC_CMEDIA=y -CONFIG_SND_HDA_CODEC_INTELHDMI=y CONFIG_SND_HDA_CODEC_SI3054=y -CONFIG_SND_HDA_CODEC_NVHDMI=y CONFIG_SND_HDA_CODEC_HDMI=y +CONFIG_SND_HDA_CODEC_CA0132=y CONFIG_SND_HDA_GENERIC=y CONFIG_SND_HDA_POWER_SAVE=y CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 CONFIG_SND_HDA_RECONFIG=y +CONFIG_SND_HDA_PREALLOC_SIZE=4096 CONFIG_SND_HDSPM=m -CONFIG_SND_HIFIER=m CONFIG_SND_ICE1712=m CONFIG_SND_ICE1724=m CONFIG_SND_INTEL8X0=y @@ -2932,6 +3117,7 @@ CONFIG_SND_VIRTUOSO=m CONFIG_SND_VX222=m CONFIG_SND_YMFPCI=m CONFIG_SND_ASIHPI=m +CONFIG_SND_LOLA=m # # ALSA USB devices @@ -2943,13 +3129,16 @@ CONFIG_SND_USB_CAIAQ_INPUT=y CONFIG_SND_USB_USX2Y=m CONFIG_SND_USB_US122L=m CONFIG_SND_USB_UA101=m +CONFIG_SND_USB_6FIRE=m # # PCMCIA devices # -CONFIG_SND_PCMCIA=y -CONFIG_SND_VXPOCKET=m -CONFIG_SND_PDAUDIOCF=m +# CONFIG_SND_PCMCIA is not set + +CONFIG_SND_FIREWIRE=y +CONFIG_SND_FIREWIRE_SPEAKERS=m +CONFIG_SND_ISIGHT=m # # Open Sound System @@ -2983,9 +3172,11 @@ CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_OHCI_HCD=y # CONFIG_USB_OHCI_HCD_SSB is not set CONFIG_USB_UHCI_HCD=y +CONFIG_USB_SL811_HCD=m +CONFIG_USB_SL811_HCD_ISO=y # CONFIG_USB_SL811_CS is not set # CONFIG_USB_R8A66597_HCD is not set -CONFIG_USB_XHCI_HCD=m +CONFIG_USB_XHCI_HCD=y # CONFIG_USB_XHCI_HCD_DEBUGGING is not set CONFIG_USB_ISP1362_HCD=m @@ -3003,19 +3194,22 @@ CONFIG_USB_TMC=m # CONFIG_BLK_DEV_UB is not set CONFIG_USB_STORAGE=m # CONFIG_USB_STORAGE_DEBUG is not set -CONFIG_USB_STORAGE_CYPRESS_ATACB=y -CONFIG_USB_STORAGE_DATAFAB=y -CONFIG_USB_STORAGE_FREECOM=y -CONFIG_USB_STORAGE_ISD200=y -CONFIG_USB_STORAGE_SDDR09=y -CONFIG_USB_STORAGE_SDDR55=y -CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=m +CONFIG_USB_STORAGE_DATAFAB=m +CONFIG_USB_STORAGE_FREECOM=m +CONFIG_USB_STORAGE_ISD200=m +CONFIG_USB_STORAGE_SDDR09=m +CONFIG_USB_STORAGE_SDDR55=m +CONFIG_USB_STORAGE_JUMPSHOT=m CONFIG_USB_STORAGE_USBAT=y -CONFIG_USB_STORAGE_ONETOUCH=y -CONFIG_USB_STORAGE_ALAUDA=y -CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_ONETOUCH=m +CONFIG_USB_STORAGE_ALAUDA=m +CONFIG_USB_STORAGE_KARMA=m +CONFIG_USB_STORAGE_REALTEK=m +CONFIG_REALTEK_AUTOPM=y +CONFIG_USB_STORAGE_ENE_UB6250=m # CONFIG_USB_LIBUSUAL is not set -CONFIG_USB_UAS=m +# CONFIG_USB_UAS is not set # @@ -3030,6 +3224,7 @@ CONFIG_HID=m CONFIG_HIDRAW=y CONFIG_HID_PID=y CONFIG_LOGITECH_FF=y +CONFIG_HID_LOGITECH_DJ=m CONFIG_LOGIWII_FF=y CONFIG_LOGIRUMBLEPAD2_FF=y CONFIG_PANTHERLORD_FF=y @@ -3042,18 +3237,15 @@ CONFIG_USB_IDMOUSE=m CONFIG_DRAGONRISE_FF=y CONFIG_GREENASIA_FF=y CONFIG_SMARTJOYPLUS_FF=y -CONFIG_HID_3M_PCT=y CONFIG_LOGIG940_FF=y +CONFIG_LOGIWHEELS_FF=y CONFIG_HID_MAGICMOUSE=y -CONFIG_HID_MOSART=y CONFIG_HID_MULTITOUCH=m CONFIG_HID_NTRIG=y CONFIG_HID_QUANTA=y -CONFIG_HID_STANTUM=y -CONFIG_HID_CANDO=m +CONFIG_HID_PRIMAX=m CONFIG_HID_PRODIKEYS=m CONFIG_HID_DRAGONRISE=m -CONFIG_HID_EGALAX=m CONFIG_HID_GYRATION=m CONFIG_HID_TWINHAN=m CONFIG_HID_ORTEK=m @@ -3071,13 +3263,22 @@ CONFIG_HID_TOPSEED=m CONFIG_HID_THRUSTMASTER=m CONFIG_HID_ZEROPLUS=m CONFIG_HID_ZYDACRON=m -CONFIG_HID_ACRUX_FF=m CONFIG_HID_EMS_FF=m CONFIG_HID_ELECOM=m CONFIG_HID_UCLOGIC=m CONFIG_HID_WALTOP=m CONFIG_HID_ROCCAT_PYRA=m CONFIG_HID_ROCCAT_KONEPLUS=m +CONFIG_HID_ACRUX=m +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_KEYTOUCH=m +CONFIG_HID_LCPOWER=m +CONFIG_HID_ROCCAT_ARVO=m +CONFIG_HID_ROCCAT_KOVAPLUS=m +CONFIG_HID_HOLTEK=m +CONFIG_HOLTEK_FF=y +CONFIG_HID_SPEEDLINK=m +CONFIG_HID_WIIMOTE=m # # USB Imaging devices @@ -3088,10 +3289,7 @@ CONFIG_USB_MICROTEK=m # # USB Multimedia devices # -CONFIG_DAB=y -CONFIG_USB_DABUSB=m -CONFIG_USB_VICAM=m CONFIG_USB_DSBR=m # CONFIG_USB_ET61X251 is not set CONFIG_USB_M5602=m @@ -3111,7 +3309,6 @@ CONFIG_USB_GSPCA_PAC207=m CONFIG_USB_GSPCA_PAC7311=m CONFIG_USB_GSPCA_SN9C2028=m CONFIG_USB_GSPCA_SN9C20X=m -CONFIG_USB_GSPCA_SN9C20X_EVDEV=y CONFIG_USB_GSPCA_SONIXB=m CONFIG_USB_GSPCA_SONIXJ=m CONFIG_USB_GSPCA_SPCA500=m @@ -3123,6 +3320,7 @@ CONFIG_USB_GSPCA_SPCA561=m CONFIG_USB_GSPCA_STK014=m CONFIG_USB_GSPCA_SUNPLUS=m CONFIG_USB_GSPCA_T613=m +CONFIG_USB_GSPCA_TOPRO=m CONFIG_USB_GSPCA_TV8532=m CONFIG_USB_GSPCA_VC032X=m CONFIG_USB_GSPCA_ZC3XX=m @@ -3136,31 +3334,17 @@ CONFIG_USB_GSPCA_KONICA=m CONFIG_USB_GSPCA_XIRLINK_CIT=m CONFIG_USB_GSPCA_SPCA1528=m CONFIG_USB_GSPCA_SQ930X=m +CONFIG_USB_GSPCA_NW80X=m +CONFIG_USB_GSPCA_VICAM=m +CONFIG_USB_GSPCA_KINECT=m +CONFIG_USB_GSPCA_SE401=m -CONFIG_USB_IBMCAM=m -CONFIG_USB_KONICAWC=m -# CONFIG_USB_OV511 is not set CONFIG_USB_S2255=m -CONFIG_USB_SE401=m # CONFIG_VIDEO_SH_MOBILE_CEU is not set # CONFIG_VIDEO_SH_MOBILE_CSI2 is not set -# CONFIG_USB_STV680 is not set # CONFIG_USB_SN9C102 is not set CONFIG_USB_ZR364XX=m -CONFIG_SOC_CAMERA=m -CONFIG_SOC_CAMERA_MT9M001=m -CONFIG_SOC_CAMERA_MT9V022=m -CONFIG_SOC_CAMERA_PLATFORM=m -CONFIG_SOC_CAMERA_MT9M111=m -CONFIG_SOC_CAMERA_MT9T031=m -CONFIG_SOC_CAMERA_TW9910=m -CONFIG_SOC_CAMERA_OV772X=m -CONFIG_SOC_CAMERA_MT9T112=m -CONFIG_SOC_CAMERA_RJ54N1=m -CONFIG_SOC_CAMERA_OV9640=m -CONFIG_SOC_CAMERA_OV6650=m -CONFIG_SOC_CAMERA_IMX074=m -CONFIG_SOC_CAMERA_OV2640=m +# CONFIG_SOC_CAMERA is not set # # USB Network adaptors @@ -3189,6 +3373,7 @@ CONFIG_USB_NET_INT51X1=m CONFIG_USB_CDC_PHONET=m CONFIG_USB_IPHETH=m CONFIG_USB_SIERRA_NET=m +CONFIG_USB_VL600=m # # USB Host-to-Host Cables @@ -3213,7 +3398,7 @@ CONFIG_USB_USS720=m # # USB Serial Converter support # -CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL=y CONFIG_USB_SERIAL_GENERIC=y CONFIG_USB_SERIAL_AIRCABLE=m CONFIG_USB_SERIAL_ARK3116=m @@ -3259,11 +3444,12 @@ CONFIG_USB_SERIAL_MOS7715_PARPORT=y CONFIG_USB_SERIAL_MOS7840=m CONFIG_USB_SERIAL_MOTOROLA=m CONFIG_USB_SERIAL_NAVMAN=m -CONFIG_USB_SERIAL_OPTION=y +CONFIG_USB_SERIAL_OPTION=m CONFIG_USB_SERIAL_OTI6858=m CONFIG_USB_SERIAL_OPTICON=m CONFIG_USB_SERIAL_OMNINET=m CONFIG_USB_SERIAL_PL2303=m +# CONFIG_USB_SERIAL_QUATECH2 is not set CONFIG_USB_SERIAL_SAFE=m CONFIG_USB_SERIAL_SAFE_PADDED=y CONFIG_USB_SERIAL_SIERRAWIRELESS=m @@ -3277,7 +3463,8 @@ CONFIG_USB_SERIAL_QCAUX=m CONFIG_USB_SERIAL_VIVOPAY_SERIAL=m CONFIG_USB_SERIAL_DEBUG=m CONFIG_USB_SERIAL_SSU100=m -CONFIG_USB_SERIAL_SAMBA=m + +CONFIG_USB_SERIAL_CONSOLE=y CONFIG_USB_EZUSB=y CONFIG_USB_EMI62=m @@ -3294,7 +3481,6 @@ CONFIG_USB_SEVSEG=m CONFIG_USB_ALI_M5632=y CONFIG_USB_APPLEDISPLAY=m CONFIG_USB_ATM=m -CONFIG_USB_BERRY_CHARGE=m CONFIG_USB_CXACRU=m # CONFIG_USB_C67X00_HCD is not set # CONFIG_USB_CYTHERM is not set @@ -3304,7 +3490,7 @@ CONFIG_USB_FTDI_ELAN=m CONFIG_USB_FILE_STORAGE=m # CONFIG_USB_FILE_STORAGE_TEST is not set # CONFIG_USB_GADGET is not set -# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_DWC3 is not set # CONFIG_USB_GADGETFS is not set # CONFIG_USB_ISP116X_HCD is not set # CONFIG_USB_ISP1760_HCD is not set @@ -3312,7 +3498,6 @@ CONFIG_USB_FILE_STORAGE=m CONFIG_USB_IOWARRIOR=m CONFIG_USB_ISIGHTFW=m CONFIG_USB_YUREX=m -CONFIG_USB_VST=m CONFIG_USB_LCD=m CONFIG_USB_LD=m CONFIG_USB_LEGOTOWER=m @@ -3321,8 +3506,6 @@ CONFIG_USB_PWC=m CONFIG_USB_PWC_INPUT_EVDEV=y # CONFIG_USB_PWC_DEBUG is not set # CONFIG_USB_RIO500 is not set -# CONFIG_USB_QUICKCAM_MESSENGER is not set -CONFIG_USB_SL811_HCD=m CONFIG_USB_SISUSBVGA=m CONFIG_USB_SISUSBVGA_CON=y CONFIG_RADIO_SI470X=y @@ -3337,7 +3520,6 @@ CONFIG_USB_TRANCEVIBRATOR=m CONFIG_USB_U132_HCD=m CONFIG_USB_UEAGLEATM=m CONFIG_USB_XUSBATM=m -# CONFIG_USB_ZC0301 is not set CONFIG_USB_ZERO=m CONFIG_USB_ANNOUNCE_NEW_DEVICES=y @@ -3362,7 +3544,6 @@ CONFIG_PCF50633_GPIO=m # CONFIG_AB3100_CORE is not set CONFIG_INPUT_PCF50633_PMU=m CONFIG_INPUT_GPIO_ROTARY_ENCODER=m -CONFIG_CHARGER_PCF50633=m CONFIG_RTC_DRV_PCF50633=m CONFIG_RTC_DRV_DS3232=m CONFIG_RTC_DRV_ISL12022=m @@ -3390,7 +3571,12 @@ CONFIG_MFD_WM8400=m # CONFIG_MFD_RDC321X is not set # CONFIG_MFD_JANZ_CMODIO is not set # CONFIG_MFD_WM831X_I2C is not set -CONFIG_MFD_CS5535=m +# CONFIG_MFD_CS5535 is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_WL1273_CORE is not set # # File systems @@ -3409,10 +3595,13 @@ CONFIG_EXT3_FS_POSIX_ACL=y CONFIG_EXT3_FS_SECURITY=y CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set + CONFIG_EXT4_FS=y CONFIG_EXT4_FS_XATTR=y CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_USE_FOR_EXT23 is not set + CONFIG_JBD2=y CONFIG_FS_MBCACHE=y CONFIG_REISERFS_FS=m @@ -3441,16 +3630,16 @@ CONFIG_QFMT_V2=y CONFIG_QUOTACTL=y CONFIG_DNOTIFY=y # Autofsv3 is obsolete. -# CONFIG_AUTOFS_FS is not set # systemd is dependant upon AUTOFS, so build it in. CONFIG_AUTOFS4_FS=y -CONFIG_EXOFS_FS=m +# CONFIG_EXOFS_FS is not set # CONFIG_EXOFS_DEBUG is not set -CONFIG_NILFS2_FS=m -CONFIG_LOGFS=m +# CONFIG_NILFS2_FS is not set +# CONFIG_LOGFS is not set CONFIG_CEPH_FS=m CONFIG_BLK_DEV_RBD=m CONFIG_CEPH_LIB=m +# CONFIG_CEPH_LIB_USE_DNS_RESOLVER is not set CONFIG_FSCACHE=m CONFIG_FSCACHE_STATS=y @@ -3488,6 +3677,7 @@ CONFIG_PROC_KCORE=y CONFIG_PROC_VMCORE=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y CONFIG_HUGETLBFS=y CONFIG_HUGETLB_PAGE=y CONFIG_DEBUG_FS=y @@ -3502,26 +3692,21 @@ CONFIG_HFS_FS=m CONFIG_HFSPLUS_FS=m CONFIG_BEFS_FS=m # CONFIG_BEFS_DEBUG is not set -CONFIG_BFS_FS=m -CONFIG_EFS_FS=m -CONFIG_JFFS2_FS=m -CONFIG_JFFS2_FS_DEBUG=0 -# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set -CONFIG_JFFS2_FS_WRITEBUFFER=y -# CONFIG_JFFS2_FS_WBUF_VERIFY is not set -CONFIG_JFFS2_SUMMARY=y -CONFIG_JFFS2_FS_XATTR=y -CONFIG_JFFS2_FS_POSIX_ACL=y -CONFIG_JFFS2_FS_SECURITY=y +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set + CONFIG_CRAMFS=m CONFIG_SQUASHFS=m CONFIG_SQUASHFS_XATTR=y CONFIG_SQUASHFS_LZO=y CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_ZLIB=y +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set # CONFIG_SQUASHFS_EMBEDDED is not set -CONFIG_VXFS_FS=m +# CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set -CONFIG_QNX4FS_FS=m +# CONFIG_QNX4FS_FS is not set CONFIG_SYSV_FS=m CONFIG_UFS_FS=m # CONFIG_UFS_FS_WRITE is not set @@ -3530,7 +3715,7 @@ CONFIG_9P_FS=m CONFIG_9P_FSCACHE=y CONFIG_9P_FS_POSIX_ACL=y CONFIG_FUSE_FS=m -CONFIG_OMFS_FS=m +# CONFIG_OMFS_FS is not set CONFIG_CUSE=m # @@ -3549,21 +3734,18 @@ CONFIG_NFSD_V4=y CONFIG_NFS_FSCACHE=y # CONFIG_NFS_USE_LEGACY_DNS is not set # CONFIG_NFS_USE_NEW_IDMAPPER is not set -# CONFIG_NFSD_DEPRECATED is not set +CONFIG_PNFS_OBJLAYOUT=m +CONFIG_PNFS_BLOCK=m CONFIG_LOCKD=m CONFIG_LOCKD_V4=y -CONFIG_EXPORTFS=m +CONFIG_EXPORTFS=y CONFIG_SUNRPC=m CONFIG_SUNRPC_GSS=m CONFIG_SUNRPC_XPRT_RDMA=m CONFIG_RPCSEC_GSS_KRB5=m -CONFIG_RPCSEC_GSS_SPKM3=m -# CONFIG_SMB_FS is not set -# CONFIG_SMB_NLS_DEFAULT is not set CONFIG_CIFS=m CONFIG_CIFS_STATS=y # CONFIG_CIFS_STATS2 is not set -CONFIG_CIFS_EXPERIMENTAL=y CONFIG_CIFS_UPCALL=y CONFIG_CIFS_XATTR=y CONFIG_CIFS_POSIX=y @@ -3572,6 +3754,7 @@ CONFIG_CIFS_ACL=y CONFIG_CIFS_WEAK_PW_HASH=y # CONFIG_CIFS_DEBUG2 is not set CONFIG_CIFS_DFS_UPCALL=y +CONFIG_CIFS_NFSD_EXPORT=y CONFIG_NCP_FS=m CONFIG_NCPFS_PACKET_SIGNING=y CONFIG_NCPFS_IOCTL_LOCKING=y @@ -3595,17 +3778,14 @@ CONFIG_OCFS2_FS_USERSPACE_CLUSTER=m CONFIG_BTRFS_FS=m CONFIG_BTRFS_FS_POSIX_ACL=y -CONFIG_CONFIGFS_FS=m +CONFIG_CONFIGFS_FS=y CONFIG_DLM=m CONFIG_DLM_DEBUG=y CONFIG_GFS2_FS=m CONFIG_GFS2_FS_LOCKING_DLM=y -CONFIG_UBIFS_FS=m -CONFIG_UBIFS_FS_XATTR=y -# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set -# CONFIG_UBIFS_FS_DEBUG is not set +# CONFIG_UBIFS_FS is not set # # Partition Types @@ -3689,27 +3869,71 @@ CONFIG_FRAME_WARN=1024 CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_INFO=y CONFIG_FRAME_POINTER=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # CONFIG_DEBUG_DRIVER is not set CONFIG_HEADERS_CHECK=y -# CONFIG_RCU_TORTURE_TEST is not set -# CONFIG_RCU_TRACE is not set # CONFIG_LKDTM is not set # CONFIG_RT_MUTEX_TESTER is not set # CONFIG_DEBUG_LOCKDEP is not set # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# DEBUG options that don't get enabled/disabled with 'make debug/release' +# +# Kmemleak still produces a lot of false positives. +# CONFIG_DEBUG_KMEMLEAK is not set +# +# This generates a huge amount of dmesg spew +# CONFIG_DEBUG_KOBJECT is not set +# +# +# These debug options are deliberatly left on (even in 'make release' kernels). +# They aren't that much of a performance impact, and the value +# from getting useful bug-reports makes it worth leaving them on. +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_HIGHMEM=y +CONFIG_BOOT_PRINTK_DELAY=y +CONFIG_DEBUG_LIST=y +CONFIG_DEBUG_SHIRQ=y +CONFIG_DEBUG_DEVRES=y +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_DEBUG_NX_TEST=m +CONFIG_DEBUG_SET_MODULE_RONX=y +CONFIG_DEBUG_BOOT_PARAMS=y +# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set +CONFIG_LOCKUP_DETECTOR=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set +CONFIG_ATOMIC64_SELFTEST=y +CONFIG_MEMORY_FAILURE=y +CONFIG_HWPOISON_INJECT=m +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +CONFIG_LATENCYTOP=y +CONFIG_RESOURCE_COUNTERS=y +# CONFIG_COMPAT_BRK is not set +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +CONFIG_EARLY_PRINTK_DBGP=y +# CONFIG_PAGE_POISONING is not set +# CONFIG_CRASH_DUMP is not set +# CONFIG_CRASH is not set +# CONFIG_GCOV_KERNEL is not set +# CONFIG_RAMOOPS is not set + CONFIG_KGDB=y CONFIG_KGDB_SERIAL_CONSOLE=y CONFIG_KGDB_TESTS=y CONFIG_KGDB_LOW_LEVEL_TRAP=y # CONFIG_KGDB_TESTS_ON_BOOT is not set + # # Security options # CONFIG_SECURITY=y +CONFIG_SECURITYFS=y # CONFIG_SECURITY_DMESG_RESTRICT is not set CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_NETWORK_XFRM=y @@ -3721,6 +3945,7 @@ CONFIG_SECURITY_SELINUX_DEVELOP=y CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=1 CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 CONFIG_SECURITY_SELINUX_AVC_STATS=y +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set # CONFIG_SECURITY_SMACK is not set # CONFIG_SECURITY_TOMOYO is not set # CONFIG_SECURITY_APPARMOR is not set @@ -3734,10 +3959,11 @@ CONFIG_CRYPTO=y CONFIG_CRYPTO_FIPS=y CONFIG_CRYPTO_USER_API_HASH=y CONFIG_CRYPTO_USER_API_SKCIPHER=y -CONFIG_CRYPTO_MANAGER_TESTS=y +CONFIG_CRYPTO_MANAGER=y +# Note, CONFIG_CRYPTO_MANAGER_DISABLE_TESTS needs to be unset, or FIPS will be disabled. +# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set CONFIG_CRYPTO_HW=y CONFIG_CRYPTO_BLKCIPHER=y -CONFIG_CRYPTO_MANAGER=m # CONFIG_CRYPTO_CRYPTD is not set CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_ARC4=m @@ -3794,6 +4020,9 @@ CONFIG_CRYPTO_ANSI_CPRNG=m CONFIG_CRYPTO_DEV_HIFN_795X=m CONFIG_CRYPTO_DEV_HIFN_795X_RNG=y CONFIG_CRYPTO_PCRYPT=m +CONFIG_CRYPTO_USER=m + + # Random number generation @@ -3805,6 +4034,9 @@ CONFIG_CRC32=m CONFIG_CRC_CCITT=m CONFIG_CRC_ITU_T=m CONFIG_CRC_T10DIF=m +CONFIG_CRC8=m +# CONFIG_CRC7 is not set +CONFIG_CORDIC=m CONFIG_CRYPTO_ZLIB=m CONFIG_ZLIB_INFLATE=y @@ -3825,6 +4057,7 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=m # CONFIG_BACKLIGHT_GENERIC is not set CONFIG_BACKLIGHT_PROGEAR=m # CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set CONFIG_FB_NVIDIA_BACKLIGHT=y CONFIG_FB_RIVA_BACKLIGHT=y CONFIG_FB_RADEON_BACKLIGHT=y @@ -3839,8 +4072,8 @@ CONFIG_LCD_PLATFORM=m CONFIG_SCHEDSTATS=y CONFIG_SCHED_DEBUG=y CONFIG_FAIR_GROUP_SCHED=y +CONFIG_CFS_BANDWIDTH=y CONFIG_SCHED_OMIT_FRAME_POINTER=y -CONFIG_GROUP_SCHED=y CONFIG_RT_GROUP_SCHED=y CONFIG_SCHED_AUTOGROUP=y @@ -3849,16 +4082,15 @@ CONFIG_PROC_PID_CPUSET=y CONFIG_CGROUPS=y # CONFIG_CGROUP_DEBUG is not set -CONFIG_CGROUP_NS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_DEVICE=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_SCHED=y CONFIG_CGROUP_MEM_RES_CTLR=y CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y # XXX disabled by default, pass 'swapaccount' -# CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED is not set +# CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED is not set +CONFIG_CGROUP_PERF=y CONFIG_BLK_CGROUP=y -# CONFIG_DEBUG_BLK_CGROUP is not set # CONFIG_SYSFS_DEPRECATED is not set # CONFIG_SYSFS_DEPRECATED_V2 is not set @@ -3873,6 +4105,8 @@ CONFIG_KEXEC=y CONFIG_HWMON=y # CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_THERMAL_HWMON=y + CONFIG_INOTIFY=y CONFIG_INOTIFY_USER=y @@ -3883,9 +4117,23 @@ CONFIG_IBMASR=m CONFIG_PM_DEBUG=y CONFIG_PM_TRACE=y -# CONFIG_PM_VERBOSE is not set +CONFIG_PM_TRACE_RTC=y # CONFIG_PM_TEST_SUSPEND is not set CONFIG_PM_RUNTIME=y +# CONFIG_PM_OPP is not set + +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEBUG=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_STAT=m +CONFIG_CPU_FREQ_STAT_DETAILS=y ## BEGIN ISA Junk. @@ -3895,58 +4143,26 @@ CONFIG_I82365=m # CONFIG_LTPC is not set # CONFIG_COPS is not set -CONFIG_SCSI_AHA152X=m -CONFIG_SCSI_AHA1542=m -# CONFIG_SCSI_IN2000 is not set -CONFIG_SCSI_ARCMSR=m -CONFIG_SCSI_ARCMSR_AER=y -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set -# CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_ULTRASTOR is not set # CONFIG_EL1 is not set # CONFIG_EL2 is not set -# CONFIG_ELPLUS is not set -# CONFIG_EL16 is not set CONFIG_EL3=m # CONFIG_3C515 is not set -# CONFIG_LANCE is not set CONFIG_NET_VENDOR_SMC=y # CONFIG_WD80x3 is not set CONFIG_ULTRA=m -# CONFIG_SMC9194 is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_NI52 is not set # CONFIG_NI65 is not set -# CONFIG_AT1700 is not set # CONFIG_DEPCA is not set CONFIG_NET_ISA=y CONFIG_NE2000=m # CONFIG_E2100 is not set -CONFIG_EWRK3=m -# CONFIG_EEXPRESS is not set -# CONFIG_EEXPRESS_PRO is not set # CONFIG_HPLAN_PLUS is not set # CONFIG_HPLAN is not set -# CONFIG_LP486E is not set -# CONFIG_ETH16I is not set -# CONFIG_ZNET is not set -# CONFIG_SEEQ8005 is not set -# CONFIG_AC3200 is not set -# CONFIG_APRICOT is not set -# CONFIG_CS89x0 is not set # CONFIG_IBMTR is not set # CONFIG_SKISA is not set # CONFIG_PROTEON is not set # CONFIG_SMCTR is not set -# CONFIG_WAVELAN is not set # CONFIG_HISAX_16_0 is not set # CONFIG_HISAX_AVM_A1 is not set # CONFIG_HISAX_IX1MICROR2 is not set @@ -3975,31 +4191,26 @@ CONFIG_EWRK3=m # CONFIG_SERIAL_8250_HUB6 is not set # CONFIG_SERIAL_8250_EXAR_ST16C554 is not set -# CONFIG_PCWATCHDOG is not set -# CONFIG_WDT is not set - -# CONFIG_VIDEO_PMS is not set CONFIG_RADIO_ADAPTERS=y -# CONFIG_RADIO_CADET is not set -# CONFIG_RADIO_RTRACK is not set -# CONFIG_RADIO_RTRACK2 is not set -# CONFIG_RADIO_AZTECH is not set -# CONFIG_RADIO_GEMTEK is not set -# CONFIG_RADIO_SF16FMI is not set -# CONFIG_RADIO_SF16FMR2 is not set -# CONFIG_RADIO_TERRATEC is not set -# CONFIG_RADIO_TRUST is not set -# CONFIG_RADIO_TEA5764 is not set -# CONFIG_RADIO_TYPHOON is not set -# CONFIG_RADIO_ZOLTRIX is not set -# CONFIG_RADIO_SAA7706H is not set +CONFIG_RADIO_TEA5764=m +CONFIG_RADIO_SAA7706H=m +CONFIG_RADIO_CADET=m +CONFIG_RADIO_RTRACK=m +CONFIG_RADIO_RTRACK2=m +CONFIG_RADIO_AZTECH=m +CONFIG_RADIO_GEMTEK=m +CONFIG_RADIO_SF16FMI=m +CONFIG_RADIO_SF16FMR2=m +CONFIG_RADIO_TERRATEC=m +CONFIG_RADIO_TRUST=m +CONFIG_RADIO_TYPHOON=m +CONFIG_RADIO_ZOLTRIX=m # CONFIG_SND_OPL4_LIB is not set # CONFIG_SND_AD1816A is not set # CONFIG_SND_AD1848 is not set # CONFIG_SND_CS4231 is not set CONFIG_SND_CS4236=m -# CONFIG_SND_ES968 is not set # CONFIG_SND_ES1688 is not set # CONFIG_SND_ES18XX is not set # CONFIG_SND_GUSCLASSIC is not set @@ -4018,9 +4229,7 @@ CONFIG_SND_SBAWE=m # CONFIG_SND_ALS100 is not set # CONFIG_SND_AZT2320 is not set # CONFIG_SND_CMI8330 is not set -# CONFIG_SND_DT019X is not set CONFIG_SND_OPL3SA2=m -# CONFIG_SND_SGALAXY is not set # CONFIG_SND_SSCAPE is not set CONFIG_SND_DARLA20=m CONFIG_SND_GINA20=m @@ -4047,6 +4256,7 @@ CONFIG_LEDS_CLASS=y # CONFIG_LEDS_AMS_DELTA is not set # CONFIG_LEDS_LOCOMO is not set # CONFIG_LEDS_NET48XX is not set +# CONFIG_LEDS_NET5501 is not set # CONFIG_LEDS_PCA9532 is not set # CONFIG_LEDS_PCA955X is not set # CONFIG_LEDS_BD2802 is not set @@ -4059,20 +4269,22 @@ CONFIG_LEDS_TRIGGER_HEARTBEAT=m CONFIG_LEDS_TRIGGER_BACKLIGHT=m CONFIG_LEDS_TRIGGER_DEFAULT_ON=m CONFIG_LEDS_ALIX2=m -CONFIG_LEDS_WM8350=m -CONFIG_LEDS_LP3944=m -CONFIG_LEDS_WM831X_STATUS=m -CONFIG_LEDS_REGULATOR=m -CONFIG_LEDS_LT3593=m -CONFIG_LEDS_TRIGGER_GPIO=m +CONFIG_LEDS_CLEVO_MAIL=m CONFIG_LEDS_INTEL_SS4200=m +CONFIG_LEDS_LM3530=m +CONFIG_LEDS_LP3944=m CONFIG_LEDS_LP5521=m CONFIG_LEDS_LP5523=m +CONFIG_LEDS_LT3593=m +CONFIG_LEDS_REGULATOR=m +CONFIG_LEDS_TRIGGER_GPIO=m +CONFIG_LEDS_WM8350=m +CONFIG_LEDS_WM831X_STATUS=m CONFIG_DMADEVICES=y CONFIG_DMA_ENGINE=y +CONFIG_DW_DMAC=m # CONFIG_TIMB_DMA is not set -CONFIG_NET_DMA=y # CONFIG_DMATEST is not set CONFIG_ASYNC_TX_DMA=y @@ -4085,9 +4297,7 @@ CONFIG_DYNAMIC_FTRACE=y # CONFIG_IRQSOFF_TRACER is not set CONFIG_SCHED_TRACER=y CONFIG_CONTEXT_SWITCH_TRACER=y -CONFIG_WORKQUEUE_TRACER=y CONFIG_FTRACE_SYSCALLS=y -CONFIG_KMEMTRACE=y CONFIG_FTRACE_MCOUNT_RECORD=y # CONFIG_FTRACE_STARTUP_TEST is not set # CONFIG_TRACE_BRANCH_PROFILING is not set @@ -4095,12 +4305,14 @@ CONFIG_FUNCTION_PROFILER=y CONFIG_RING_BUFFER_BENCHMARK=m CONFIG_FUNCTION_TRACER=y CONFIG_STACK_TRACER=y +# CONFIG_FUNCTION_GRAPH_TRACER is not set CONFIG_KPROBES=y +CONFIG_KPROBE_EVENT=y +# CONFIG_KPROBES_SANITY_TEST is not set +CONFIG_JUMP_LABEL=y CONFIG_OPTPROBES=y -# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set - CONFIG_HZ_1000=y CONFIG_TIMER_STATS=y @@ -4116,25 +4328,30 @@ CONFIG_CFAG12864B_RATE=20 CONFIG_POWER_SUPPLY=m # CONFIG_POWER_SUPPLY_DEBUG is not set + # CONFIG_TEST_POWER is not set CONFIG_APM_POWER=m # CONFIG_WM831X_POWER is not set + # CONFIG_BATTERY_DS2760 is not set # CONFIG_BATTERY_DS2782 is not set # CONFIG_BATTERY_BQ20Z75 is not set -# CONFIG_CHARGER_ISP1704 is not set -CONFIG_BATTERY_PMU=m +# CONFIG_BATTERY_DS2780 is not set # CONFIG_BATTERY_BQ27x00 is not set # CONFIG_BATTERY_MAX17040 is not set -# CONFIG_PDA_POWER is not set -# CONFIG_CHARGER_GPIO is not set # CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_PCF50633 is not set + +# CONFIG_PDA_POWER is not set + CONFIG_AUXDISPLAY=y CONFIG_UIO=m CONFIG_UIO_CIF=m -CONFIG_UIO_SMX=m # CONFIG_UIO_PDRV is not set # CONFIG_UIO_PDRV_GENIRQ is not set CONFIG_UIO_AEC=m @@ -4142,55 +4359,36 @@ CONFIG_UIO_SERCOS3=m CONFIG_UIO_PCI_GENERIC=m # CONFIG_UIO_NETX is not set -# CONFIG_CRC7 is not set # LIRC CONFIG_LIRC_STAGING=y CONFIG_LIRC_BT829=m -CONFIG_LIRC_ENE0100=m -CONFIG_LIRC_I2C=m CONFIG_LIRC_IGORPLUGUSB=m CONFIG_LIRC_IMON=m -CONFIG_LIRC_IT87=m -CONFIG_LIRC_ITE8709=m -CONFIG_LIRC_MCEUSB=m CONFIG_LIRC_ZILOG=m CONFIG_LIRC_PARALLEL=m CONFIG_LIRC_SERIAL=m CONFIG_LIRC_SERIAL_TRANSMITTER=y CONFIG_LIRC_SASEM=m CONFIG_LIRC_SIR=m -CONFIG_LIRC_STREAMZAP=m CONFIG_LIRC_TTUSBIR=m # CONFIG_SAMPLES is not set # CONFIG_DEVKMEM is not set -CONFIG_PM_TRACE_RTC=y -CONFIG_R6040=m - CONFIG_BNX2X=m +CONFIG_SCSI_BNX2X_FCOE=m + CONFIG_NOZOMI=m # CONFIG_TPS65010 is not set -# CONFIG_DEBUG_SECTION_MISMATCH is not set -# CONFIG_KPROBES_SANITY_TEST is not set -# CONFIG_BACKTRACE_SELF_TEST is not set -CONFIG_LATENCYTOP=y -CONFIG_RESOURCE_COUNTERS=y -# CONFIG_COMPAT_BRK is not set - -#FIXME: x86 generic? -CONFIG_LEDS_CLEVO_MAIL=m -CONFIG_I8K=m CONFIG_INPUT_APANEL=m # CONFIG_INTEL_MENLOW is not set CONFIG_ENCLOSURE_SERVICES=m CONFIG_IPWIRELESS=m -CONFIG_RTC_DRV_DS1511=m # CONFIG_BLK_DEV_XIP is not set CONFIG_MEMSTICK=m @@ -4199,6 +4397,7 @@ CONFIG_MEMSTICK=m CONFIG_MSPRO_BLOCK=m CONFIG_MEMSTICK_TIFM_MS=m CONFIG_MEMSTICK_JMICRON_38X=m +CONFIG_MEMSTICK_R592=m CONFIG_ACCESSIBILITY=y CONFIG_A11Y_BRAILLE_CONSOLE=y @@ -4207,42 +4406,25 @@ CONFIG_A11Y_BRAILLE_CONSOLE=y # MT9V022_PCA9536_SWITCH is not set -CONFIG_THERMAL_HWMON=y - CONFIG_OPTIMIZE_INLINING=y # FIXME: This should be x86/ia64 only # CONFIG_HP_ILO is not set # CONFIG_GPIOLIB is not set - - -CONFIG_NETFILTER_TPROXY=m -CONFIG_NETFILTER_XT_TARGET_TPROXY=m -CONFIG_NETFILTER_XT_MATCH_RECENT=m -# CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT is not set -CONFIG_NETFILTER_XT_MATCH_SOCKET=m - -# CONFIG_IP_VS_IPV6 is not set +# CONFIG_PINCTRL is not set CONFIG_NET_DSA=y CONFIG_NET_DSA_MV88E6060=y CONFIG_NET_DSA_MV88E6131=y CONFIG_NET_DSA_MV88E6123_61_65=y -CONFIG_NET_SCH_MULTIQ=m -CONFIG_NET_ACT_SKBEDIT=m +# Used by Maemo, we don't care. +# CONFIG_PHONET is not set -CONFIG_PHONET=m -# CONFIG_PHONET_PIPECTRLR is not set +# CONFIG_ICS932S401 is not set -CONFIG_ICS932S401=m # CONFIG_C2PORT is not set -CONFIG_W1_SLAVE_BQ27000=m - - -CONFIG_IT87_WDT=m -CONFIG_W83697UG_WDT=m # CONFIG_REGULATOR is not set # CONFIG_REGULATOR_DEBUG is not set @@ -4260,44 +4442,31 @@ CONFIG_USB_HWA_HCD=m CONFIG_UWB=m CONFIG_UWB_HWA=m CONFIG_UWB_WHCI=m -CONFIG_UWB_WLP=m CONFIG_UWB_I1480U=m -CONFIG_UWB_I1480U_WLP=m CONFIG_STAGING=y -# CONFIG_STAGING_EXCLUDE_BUILD is not set +CONFIG_STAGING_MEDIA=y +# CONFIG_DVB_AS102 is not set # CONFIG_ET131X is not set # CONFIG_SLICOSS is not set -# CONFIG_VIDEO_TM6000 is not set # CONFIG_WLAGS49_H2 is not set # CONFIG_WLAGS49_H25 is not set # CONFIG_VIDEO_DT3155 is not set # CONFIG_TI_ST is not set -# CONFIG_ST_BT is not set # CONFIG_FB_XGI is not set # CONFIG_VIDEO_GO7007 is not set -# CONFIG_USB_IP_COMMON is not set # CONFIG_DT3155 is not set # CONFIG_W35UND is not set # CONFIG_PRISM2_USB is not set # CONFIG_ECHO is not set CONFIG_USB_ATMEL=m -# CONFIG_POCH is not set -# CONFIG_OTUS is not set -# CONFIG_RT2860 is not set -# CONFIG_RT2870 is not set # CONFIG_COMEDI is not set # CONFIG_ASUS_OLED is not set # CONFIG_PANEL is not set -# CONFIG_ALTERA_PCIE_CHDMA is not set -# CONFIG_INPUT_MIMIO is not set # CONFIG_TRANZPORT is not set # CONFIG_POHMELFS is not set -# CONFIG_B3DFG is not set # CONFIG_IDE_PHISON is not set -# CONFIG_PLAN9AUTH is not set # CONFIG_LINE6_USB is not set -# CONFIG_RTL8192SU is not set # CONFIG_IIO is not set # CONFIG_VME_BUS is not set # CONFIG_RAR_REGISTER is not set @@ -4306,10 +4475,8 @@ CONFIG_USB_ATMEL=m # CONFIG_RTL8192E is not set # CONFIG_INPUT_GPIO is not set # CONFIG_VIDEO_CX25821 is not set -# CONFIG_HYPERV is not set # CONFIG_R8187SE is not set # CONFIG_RTL8192U is not set -# CONFIG_RAMZSWAP is not set # CONFIG_BATMAN_ADV is not set # CONFIG_FB_SM7XX is not set # CONFIG_SPECTRA is not set @@ -4317,7 +4484,6 @@ CONFIG_USB_ATMEL=m # CONFIG_EASYCAP is not set # CONFIG_SOLO6X10 is not set # CONFIG_ACPI_QUICKSTART is not set -# CONFIG_BRCM80211 is not set # CONFIG_R8712U is not set # CONFIG_ATH6K_LEGACY is not set # CONFIG_USB_ENESTORAGE is not set @@ -4327,49 +4493,42 @@ CONFIG_USB_ATMEL=m # CONFIG_DX_SEP is not set # CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set # CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set - -# -# Android +# CONFIG_RTS_PSTOR is not set +CONFIG_ALTERA_STAPL=m +# CONFIG_DVB_CXD2099 is not set +# CONFIG_USBIP_CORE is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_ZCACHE is not set +# CONFIG_RTS5139 is not set +# CONFIG_NVEC_LEDS is not set +# CONFIG_VT6655 is not set # +# END OF STAGING -# CONFIG_DEBUG_VIRTUAL is not set -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set -# CONFIG_FUNCTION_GRAPH_TRACER is not set -# CONFIG_BOOT_TRACER is not set -CONFIG_EARLY_PRINTK_DBGP=y - -CONFIG_SECURITYFS=y - -CONFIG_SCSI_CXGB3_ISCSI=m CONFIG_LIBFC=m CONFIG_LIBFCOE=m CONFIG_FCOE=m CONFIG_FCOE_FNIC=m -# CONFIG_SCSI_LPFC_DEBUG_FS is not set CONFIG_NOP_USB_XCEIV=m -CONFIG_IMA=y +# CONFIG_IMA is not set CONFIG_IMA_MEASURE_PCR_IDX=10 CONFIG_IMA_AUDIT=y CONFIG_IMA_LSM_RULES=y +# CONFIG_EVM is not set + CONFIG_LSM_MMAP_MIN_ADDR=65536 -# CONFIG_PAGE_POISONING is not set - -CONFIG_SLOW_WORK=y -CONFIG_SLOW_WORK_DEBUG=y - -# CONFIG_CRASH_DUMP is not set -# CONFIG_CRASH is not set - CONFIG_STRIP_ASM_SYMS=y # CONFIG_RCU_FANOUT_EXACT is not set -CONFIG_RCU_FAST_NO_HZ=y -CONFIG_SRCU_SYNCHRONIZE_DELAY=10 +# CONFIG_RCU_FAST_NO_HZ is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_TRACE is not set +CONFIG_SPARSE_RCU_POINTER=y CONFIG_KSM=y CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 @@ -4379,62 +4538,29 @@ CONFIG_FANOTIFY=y CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y CONFIG_IEEE802154=m +CONFIG_IEEE802154_6LOWPAN=m CONFIG_IEEE802154_DRIVERS=m CONFIG_IEEE802154_FAKEHARD=m -# CONFIG_GCOV_KERNEL is not set - CONFIG_PPS=m # CONFIG_PPS_CLIENT_KTIMER is not set CONFIG_PPS_CLIENT_LDISC=m # CONFIG_PPS_DEBUG is not set CONFIG_PPS_CLIENT_PARPORT=m CONFIG_PPS_GENERATOR_PARPORT=m +CONFIG_PPS_CLIENT_GPIO=m CONFIG_NTP_PPS=y -# CONFIG_USB_SERIAL_QUATECH2 is not set -# CONFIG_VT6655 is not set -# CONFIG_FB_UDL is not set +CONFIG_PTP_1588_CLOCK=m -# DEBUG options that don't get enabled/disabled with 'make debug/release' -# -# Kmemleak still produces a lot of false positives. -# CONFIG_DEBUG_KMEMLEAK is not set -# -# This generates a huge amount of dmesg spew -# CONFIG_DEBUG_KOBJECT is not set -# -# -# These debug options are deliberatly left on (even in 'make release' kernels). -# They aren't that much of a performance impact, and the value -# from getting useful bug-reports makes it worth leaving them on. -CONFIG_DYNAMIC_DEBUG=y -CONFIG_DEBUG_HIGHMEM=y -CONFIG_DEBUG_SPINLOCK_SLEEP=y -CONFIG_BOOT_PRINTK_DELAY=y -CONFIG_DEBUG_LIST=y -CONFIG_DEBUG_SHIRQ=y -CONFIG_DEBUG_DEVRES=y -CONFIG_DEBUG_RODATA_TEST=y -CONFIG_DEBUG_NX_TEST=m -CONFIG_DEBUG_BOOT_PARAMS=y -CONFIG_DETECT_SOFTLOCKUP=y -CONFIG_LOCKUP_DETECTOR=y -# CONFIG_DEBUG_INFO_REDUCED is not set -# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set -# CONFIG_DETECT_HUNG_TASK is not set -# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set -CONFIG_ATOMIC64_SELFTEST=y - -CONFIG_MEMORY_FAILURE=y -CONFIG_HWPOISON_INJECT=m - -CONFIG_BLK_DEV_DRBD=m +CONFIG_CLEANCACHE=y # CONFIG_MDIO_GPIO is not set # CONFIG_KEYBOARD_GPIO is not set # CONFIG_KEYBOARD_GPIO_POLLED is not set # CONFIG_MOUSE_GPIO is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set # CONFIG_I2C_GPIO is not set # CONFIG_DEBUG_GPIO is not set # CONFIG_W1_MASTER_GPIO is not set @@ -4448,47 +4574,100 @@ CONFIG_GPIO_SYSFS=y # CONFIG_GPIO_IT8761E is not set # CONFIG_GPIO_MAX7300 is not set # CONFIG_UCB1400_CORE is not set +# CONFIG_TPS6105X is not set # CONFIG_RADIO_MIROPCM20 is not set # CONFIG_USB_GPIO_VBUS is not set # CONFIG_GPIO_SCH is not set # CONFIG_GPIO_LANGWELL is not set # CONFIG_GPIO_RDC321X is not set -# CONFIG_GPIO_BASIC_MMIO is not set # CONFIG_GPIO_VX855 is not set # CONFIG_GPIO_PCH is not set # CONFIG_GPIO_ML_IOH is not set -CONFIG_KSYM_TRACER=y -CONFIG_PROFILE_KSYM_TRACER=y -CONFIG_KPROBE_EVENT=y - -# CONFIG_RAMOOPS is not set - -CONFIG_IR_CORE=m -CONFIG_IR_ENE=m -CONFIG_IR_STREAMZAP=m -CONFIG_IR_WINBOND_CIR=m - # CONFIG_GPIO_SX150X is not set -# CONFIG_MFD_STMPE is not set -# CONFIG_MFD_MAX8998 is not set -# CONFIG_MFD_TPS6586X is not set -# CONFIG_MFD_TC3589X is not set - -CONFIG_SPARSE_RCU_POINTER=y - -# CONFIG_PM_OPP is not set - -CONFIG_BKL=y +# FIXME: Why? CONFIG_EVENT_POWER_TRACING_DEPRECATED=y +CONFIG_TEST_KSTRTOX=y # CONFIG_XZ_DEC_TEST is not set -CONFIG_NFC_DEVICES=y -CONFIG_PN544_NFC=m - CONFIG_TARGET_CORE=m +CONFIG_ISCSI_TARGET=m +CONFIG_LOOPBACK_TARGET=m CONFIG_TCM_IBLOCK=m CONFIG_TCM_FILEIO=m CONFIG_TCM_PSCSI=m +CONFIG_TCM_FC=m + +CONFIG_HWSPINLOCK=m + +CONFIG_PSTORE=y + +# CONFIG_AVERAGE is not set + +# CONFIG_SIGMA is not set + +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 + +CONFIG_BCMA=m +CONFIG_BCMA_BLOCKIO=y +CONFIG_BCMA_HOST_PCI_POSSIBLE=y +CONFIG_BCMA_HOST_PCI=y +# CONFIG_BCMA_DEBUG is not set + +# CONFIG_GOOGLE_FIRMWARE is not set +# CONFIG_INTEL_MID_PTI is not set +CONFIG_IOMMU_SUPPORT=y + +# CONFIG_PM_DEVFREQ is not set +# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set +CONFIG_CGROUP_MEM_RES_CTLR_KMEM=y +CONFIG_UNIX_DIAG=m +CONFIG_INET_UDP_DIAG=m +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NETFILTER_XT_MATCH_ECN=m +CONFIG_NETFILTER_XT_MATCH_NFACCT=m +CONFIG_IP_VS_SH_TAB_BITS=8 +CONFIG_IP_NF_MATCH_RPFILTER=m +CONFIG_IP6_NF_MATCH_RPFILTER=m +CONFIG_OPENVSWITCH=m +CONFIG_NETPRIO_CGROUP=m +# CONFIG_BLK_DEV_NVME is not set +CONFIG_NET_TEAM=m +CONFIG_NET_TEAM_MODE_ROUNDROBIN=m +CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m +CONFIG_NET_CALXEDA_XGMAC=m +# CONFIG_STMMAC_PLATFORM is not set +# CONFIG_STMMAC_PCI is not set +CONFIG_ATH9K_BTCOEX_SUPPORT=y +# CONFIG_B43_BCMA_EXTRA is not set +CONFIG_BRCMFMAC_SDIO=y +# CONFIG_IWLWIFI_P2P is not set +CONFIG_IWLEGACY_DEBUG=y +CONFIG_IWLEGACY_DEBUGFS=y +CONFIG_IWLEGACY_DEBUGFS=y +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +CONFIG_TOUCHSCREEN_EGALAX=m +CONFIG_TOUCHSCREEN_PIXCIR=m +# CONFIG_BATTERY_SBS is not set +# CONFIG_CHARGER_LP8727 is not set +CONFIG_IR_SANYO_DECODER=m +CONFIG_MEDIA_TUNER_MT2063=m +CONFIG_USB_GSPCA_JL2005BCD=m +CONFIG_V4L_PCI_DRIVERS=y +# CONFIG_V4L_ISA_PARPORT_DRIVERS is not set +# CONFIG_V4L_PLATFORM_DRIVERS is not set +CONFIG_DVB_HD29L2=m +CONFIG_HID_ROCCAT_ISKU=m +CONFIG_HID_WIIMOTE_EXT=y +# CONFIG_USB_EHCI_MV is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_OT200 is not set +CONFIG_INFINIBAND_SRPT=m +# CONFIG_RTLLIB is not set +# CONFIG_ANDROID is not set +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +# CONFIG_NFSD_FAULT_INJECTION is not set diff --git a/config-ia64-generic b/config-ia64-generic deleted file mode 100644 index 5c864b3d0..000000000 --- a/config-ia64-generic +++ /dev/null @@ -1,208 +0,0 @@ -# -# Automatically generated make config: don't edit -# - -# -# Processor type and features -# -CONFIG_IA64=y -CONFIG_64BIT=y -# CONFIG_XEN is not set -CONFIG_MMU=y -CONFIG_EFI=y -# CONFIG_ITANIUM is not set -CONFIG_MCKINLEY=y -CONFIG_IA64_GENERIC=y -# CONFIG_IA64_DIG is not set -# CONFIG_IA64_HP_ZX1 is not set -# CONFIG_IA64_SGI_SN2 is not set -CONFIG_IA64_ESI=y -CONFIG_IA64_HP_AML_NFW=y -CONFIG_MSPEC=y -# CONFIG_IA64_HP_SIM is not set -# CONFIG_IA64_PAGE_SIZE_4KB is not set -# CONFIG_IA64_PAGE_SIZE_8KB is not set -CONFIG_IA64_PAGE_SIZE_16KB=y -# CONFIG_IA64_PAGE_SIZE_64KB is not set -CONFIG_IA64_L1_CACHE_SHIFT=7 -CONFIG_NUMA=y -# CONFIG_VIRTUAL_MEM_MAP is not set -CONFIG_SPARSEMEM_MANUAL=y -CONFIG_SPARSEMEM=y -CONFIG_MEMORY_HOTPLUG=y -CONFIG_MEMORY_HOTREMOVE=y -CONFIG_IA64_MCA_RECOVERY=m -CONFIG_IA64_CYCLONE=y -CONFIG_MMTIMER=y -CONFIG_IOSAPIC=y -CONFIG_FORCE_MAX_ZONEORDER=18 -CONFIG_NR_CPUS=1024 -# CONFIG_IA32_SUPPORT is not set -# CONFIG_COMPAT is not set -CONFIG_PERFMON=y -CONFIG_IA64_PALINFO=y -CONFIG_EFI_VARS=y -CONFIG_SERIAL_8250_RUNTIME_UARTS=16 -CONFIG_EFI_PCDP=y -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set - -# -# IDE chipset support/bugfixes -# -CONFIG_BLK_DEV_SGIIOC4=y - -# -# Character devices -# -CONFIG_TCG_INFINEON=m - -# -# Watchdog Cards -# -# CONFIG_HW_RANDOM is not set -# CONFIG_GEN_RTC is not set -CONFIG_EFI_RTC=y -CONFIG_RTC_DRV_EFI=y - - -# -# AGP -# -CONFIG_AGP_I460=y -CONFIG_AGP_HP_ZX1=y -CONFIG_AGP_SGI_TIOCA=y - -# -# HP Simulator drivers -# -# CONFIG_HP_SIMETH is not set -# CONFIG_HP_SIMSERIAL is not set -# CONFIG_HP_SIMSCSI is not set - -# -# Kernel hacking -# -# CONFIG_IA64_PRINT_HAZARDS is not set -# CONFIG_DISABLE_VHPT is not set -# CONFIG_IA64_DEBUG_CMPXCHG is not set -# CONFIG_IA64_DEBUG_IRQ is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# SGI -# -CONFIG_SGI_SNSC=y -CONFIG_SGI_TIOCX=y -CONFIG_SGI_MBCS=m -CONFIG_SGI_IOC3=m -CONFIG_SGI_IOC4=y -CONFIG_SGI_XP=m -CONFIG_SGI_GRU=m -# CONFIG_SGI_GRU_DEBUG is not set -CONFIG_SERIAL_SGI_L1_CONSOLE=y -CONFIG_SERIAL_SGI_IOC3=m -CONFIG_SERIAL_SGI_IOC4=m - - -# -# SCSI low-level drivers -# -# CONFIG_SCSI_BUSLOGIC is not set - -# -CONFIG_ACPI=y -CONFIG_ACPI_AC=y -# CONFIG_ACPI_ASUS is not set -CONFIG_ACPI_PROCFS_POWER=y -CONFIG_ACPI_SYSFS_POWER=y -# CONFIG_ACPI_BATTERY is not set -CONFIG_ACPI_BLACKLIST_YEAR=0 -CONFIG_ACPI_BUTTON=y -# CONFIG_ACPI_DOCK is not set -CONFIG_ACPI_FAN=y -CONFIG_ACPI_HOTPLUG_MEMORY=y -CONFIG_ACPI_NUMA=y -CONFIG_ACPI_POWER=y -CONFIG_ACPI_PROCESSOR=y -CONFIG_ACPI_PROCFS=y -CONFIG_ACPI_SLEEP=y -CONFIG_ACPI_THERMAL=y -# CONFIG_ACPI_TOSHIBA is not set -CONFIG_ACPI_VIDEO=m -# CONFIG_ACPI_PROC_EVENT is not set -CONFIG_ACPI_HED=m -CONFIG_ACPI_EC_DEBUGFS=m -CONFIG_ACPI_IPMI=m - -CONFIG_PM=y -CONFIG_HOTPLUG_PCI=y -# CONFIG_HPET is not set -# CONFIG_HOTPLUG_PCI_CPCI is not set -CONFIG_HOTPLUG_PCI_SHPC=m -CONFIG_HOTPLUG_PCI_SGI=m -CONFIG_PNPACPI=y - -CONFIG_SCHED_SMT=y - -CONFIG_ARCH_DISCONTIGMEM_ENABLE=y - -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_DEBUG=y -CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=m -CONFIG_CPU_FREQ_GOV_USERSPACE=m -CONFIG_CPU_FREQ_GOV_ONDEMAND=m -CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m -CONFIG_CPU_FREQ_STAT=m -CONFIG_CPU_FREQ_STAT_DETAILS=y - -CONFIG_IA64_ACPI_CPUFREQ=m - -# CONFIG_PERMIT_BSP_REMOVE is not set -# CONFIG_FORCE_CPEI_RETARGET is not set - -CONFIG_NODES_SHIFT=10 - - -CONFIG_HW_RANDOM_INTEL=m - -CONFIG_CRASH_DUMP=y -CONFIG_PROC_VMCORE=y - -# drivers/media/video/usbvision/usbvision-i2c.c:64:39: error: macro "outb" passed 4 arguments, but takes just 2 -# CONFIG_VIDEO_USBVISION is not set - -# CONFIG_IA64_MC_ERR_INJECT is not set - -CONFIG_DMIID=y - -CONFIG_SENSORS_I5K_AMB=m - -CONFIG_SPARSEMEM_VMEMMAP=y - -CONFIG_FRAME_WARN=2048 - -CONFIG_VIRT_CPU_ACCOUNTING=y -CONFIG_VIRTUALIZATION=y -CONFIG_KVM=m -CONFIG_KVM_INTEL=m - -CONFIG_HP_ILO=m - -CONFIG_PARAVIRT_GUEST=y -CONFIG_PARAVIRT=y - -CONFIG_DMAR_DEFAULT_ON=y - -CONFIG_RCU_FANOUT=64 - -CONFIG_ACPI_POWER_METER=m -CONFIG_I2C_SCMI=m diff --git a/config-nodebug b/config-nodebug index c81b03b85..43b70d774 100644 --- a/config-nodebug +++ b/config-nodebug @@ -2,11 +2,13 @@ CONFIG_SND_VERBOSE_PRINTK=y CONFIG_SND_DEBUG=y CONFIG_SND_PCM_XRUN_DEBUG=y +# CONFIG_DEBUG_ATOMIC_SLEEP is not set + # CONFIG_DEBUG_MUTEXES is not set # CONFIG_DEBUG_RT_MUTEXES is not set # CONFIG_DEBUG_LOCK_ALLOC is not set # CONFIG_PROVE_LOCKING is not set -# CONFIG_DEBUG_VM is not set +CONFIG_DEBUG_VM=y # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_PROVE_RCU is not set # CONFIG_PROVE_RCU_REPEATEDLY is not set @@ -22,6 +24,7 @@ CONFIG_CPUMASK_OFFSTACK=y # CONFIG_FAULT_INJECTION_DEBUG_FS is not set # CONFIG_FAULT_INJECTION_STACKTRACE_FILTER is not set # CONFIG_FAIL_IO_TIMEOUT is not set +# CONFIG_FAIL_MMC_REQUEST is not set # CONFIG_SLUB_DEBUG_ON is not set @@ -41,6 +44,7 @@ CONFIG_CPUMASK_OFFSTACK=y # CONFIG_DEBUG_OBJECTS_SELFTEST is not set # CONFIG_DEBUG_OBJECTS_FREE is not set # CONFIG_DEBUG_OBJECTS_TIMERS is not set +# CONFIG_DEBUG_OBJECTS_RCU_HEAD is not set CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1 # CONFIG_X86_PTDUMP is not set @@ -69,7 +73,7 @@ CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1 # CONFIG_JBD2_DEBUG is not set -# CONFIG_DEBUG_CFQ_IOSCHED is not set +# CONFIG_DEBUG_BLK_CGROUP is not set # CONFIG_DRBD_FAULT_INJECTION is not set @@ -78,7 +82,6 @@ CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1 # CONFIG_IWLWIFI_DEVICE_TRACING is not set # CONFIG_DEBUG_OBJECTS_WORK is not set -# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set # CONFIG_DMADEVICES_DEBUG is not set # CONFIG_DMADEVICES_VDEBUG is not set @@ -88,8 +91,6 @@ CONFIG_PM_ADVANCED_DEBUG=y # CONFIG_CEPH_LIB_PRETTYDEBUG is not set # CONFIG_QUOTA_DEBUG is not set -CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y - CONFIG_PCI_DEFAULT_USE_CRS=y CONFIG_KGDB_KDB=y @@ -98,4 +99,8 @@ CONFIG_KDB_KEYBOARD=y # CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER is not set # CONFIG_TEST_LIST_SORT is not set -# CONFIG_DEBUG_SET_MODULE_RONX is not set +# CONFIG_DETECT_HUNG_TASK is not set +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set + +# CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK is not set diff --git a/config-powerpc-generic b/config-powerpc-generic index 9cd30a459..9e6a92222 100644 --- a/config-powerpc-generic +++ b/config-powerpc-generic @@ -13,19 +13,6 @@ CONFIG_TAU_AVERAGE=y CONFIG_SECCOMP=y -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_DEBUG=y -# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set -CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=m -CONFIG_CPU_FREQ_GOV_USERSPACE=m -CONFIG_CPU_FREQ_GOV_ONDEMAND=m -CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m -CONFIG_CPU_FREQ_TABLE=y -CONFIG_CPU_FREQ_STAT=m -CONFIG_CPU_FREQ_STAT_DETAILS=y - CONFIG_PM=y CONFIG_PM_STD_PARTITION="" @@ -51,15 +38,16 @@ CONFIG_AGP_UNINORTH=y CONFIG_FB_OF=y # CONFIG_FB_CONTROL is not set CONFIG_FB_IBM_GXT4500=y -CONFIG_FB_RADEON=y CONFIG_FB_MATROX=y -CONFIG_FB_NVIDIA=m # CONFIG_FB_VGA16 is not set CONFIG_FB_ATY128_BACKLIGHT=y CONFIG_FB_ATY_BACKLIGHT=y -CONFIG_FB_RADEON_BACKLIGHT=y CONFIG_FB_RIVA_BACKLIGHT=y -CONFIG_FB_NVIDIA_BACKLIGHT=y +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_MB862XX_PCI_GDC is not set +# CONFIG_FB_MB862XX_LIME is not set +# CONFIG_FB_MB862XX_I2C is not set + CONFIG_SND_POWERMAC=m CONFIG_SND_POWERMAC_AUTO_DRC=y @@ -172,7 +160,7 @@ CONFIG_IDE_TASK_IOCTL=y # CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set -CONFIG_BLK_DEV_IDE_PMAC=y +CONFIG_BLK_DEV_IDE_PMAC=m CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y CONFIG_BLK_DEV_IDEDMA=y # CONFIG_BLK_DEV_HD is not set @@ -194,8 +182,8 @@ CONFIG_EDAC_PASEMI=m CONFIG_EDAC_AMD8131=m CONFIG_EDAC_AMD8111=m -CONFIG_AXON_RAM=m -CONFIG_OPROFILE_CELL=y +# CONFIG_AXON_RAM is not set +# CONFIG_OPROFILE_CELL is not set CONFIG_SUSPEND_FREEZER=y # CONFIG_IDEPCI_PCIBUS_ORDER is not set @@ -205,7 +193,7 @@ CONFIG_USB_EHCI_HCD_PPC_OF=y # CONFIG_MPC5121_ADS is not set # CONFIG_MPC5121_GENERIC is not set -CONFIG_MTD_OF_PARTS=m +CONFIG_MTD_OF_PARTS=y # CONFIG_MTD_NAND_FSL_ELBC is not set CONFIG_THERMAL=y @@ -216,9 +204,9 @@ CONFIG_DMADEVICES=y CONFIG_SND_PPC=y -CONFIG_PPC_82xx=y -CONFIG_PPC_83xx=y -CONFIG_PPC_86xx=y +# CONFIG_PPC_82xx is not set +# CONFIG_PPC_83xx is not set +# CONFIG_PPC_86xx is not set CONFIG_EXTRA_TARGETS="" # CONFIG_CODE_PATCHING_SELFTEST is not set # CONFIG_FTR_FIXUP_SELFTEST is not set @@ -232,27 +220,28 @@ CONFIG_EXTRA_TARGETS="" # CONFIG_SERIAL_QE is not set # CONFIG_I2C_CPM is not set +CONFIG_NET_VENDOR_IBM=y -CONFIG_SERIO_XILINX_XPS_PS2=m +# CONFIG_SERIO_XILINX_XPS_PS2 is not set # CONFIG_PPC_SMLPAR is not set -CONFIG_MGCOGE=y -CONFIG_GEF_SBC610=y -CONFIG_GEF_PPC9A=y -CONFIG_GEF_SBC310=y +# CONFIG_MGCOGE is not set +# CONFIG_GEF_SBC610 is not set +# CONFIG_GEF_PPC9A is not set +# CONFIG_GEF_SBC310 is not set -CONFIG_QUICC_ENGINE=y -CONFIG_QE_GPIO=y -CONFIG_MPC8xxx_GPIO=y +# CONFIG_QUICC_ENGINE is not set +# CONFIG_QE_GPIO is not set +# CONFIG_MPC8xxx_GPIO is not set CONFIG_IDE_GD=y CONFIG_IDE_GD_ATA=y CONFIG_IDE_GD_ATAPI=y -CONFIG_MCU_MPC8349EMITX=m +# CONFIG_MCU_MPC8349EMITX is not set -CONFIG_GPIO_XILINX=y +# CONFIG_GPIO_XILINX is not set CONFIG_PMIC_DA903X=y CONFIG_BACKLIGHT_DA903X=m @@ -273,11 +262,11 @@ CONFIG_TOUCHSCREEN_DA9034=m CONFIG_SIMPLE_GPIO=y -CONFIG_FSL_PQ_MDIO=m +# CONFIG_FSL_PQ_MDIO is not set -CONFIG_PS3_VRAM=m +# CONFIG_PS3_VRAM is not set CONFIG_MDIO_GPIO=m -CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL=m +# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set # CONFIG_DEBUG_GPIO is not set CONFIG_GPIO_PCA953X=m CONFIG_GPIO_PCF857X=m @@ -285,8 +274,6 @@ CONFIG_GPIO_PCF857X=m # CONFIG_USB_FHCI_HCD is not set # CONFIG_FHCI_DEBUG is not set -# CONFIG_DRM_RADEON_KMS is not set - # CONFIG_AMIGAONE is not set CONFIG_PPC_OF_BOOT_TRAMPOLINE=y @@ -307,34 +294,69 @@ CONFIG_SWIOTLB=y CONFIG_PPC_DISABLE_WERROR=y -CONFIG_XILINX_LL_TEMAC=m -CONFIG_XILINX_EMACLITE=m +# CONFIG_XILINX_LL_TEMAC is not set +# CONFIG_XILINX_EMACLITE is not set CONFIG_GPIO_WM831X=m # CONFIG_GPIO_LANGWELL is not set # CONFIG_GPIO_UCB1400 is not set -CONFIG_EDAC_MPC85XX=m +# CONFIG_EDAC_MPC85XX is not set CONFIG_NR_IRQS=512 CONFIG_SPARSE_IRQ=y -CONFIG_PPC_MPC5200_LPBFIFO=m -CONFIG_CAN_MSCAN=m -CONFIG_CAN_MPC5XXX=m +# CONFIG_PPC_MPC5200_LPBFIFO is not set +# CONFIG_CAN_MSCAN is not set +# CONFIG_CAN_MPC5XXX is not set CONFIG_PATA_MACIO=m CONFIG_SERIAL_GRLIB_GAISLER_APBUART=m # CONFIG_PMIC_ADP5520 is not set # CONFIG_MFD_88PM8607 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_WL1273_CORE is not set # CONFIG_XPS_USB_HCD_XILINX is not set # CONFIG_MMC_SDHCI_OF_ESDHC is not set # CONFIG_MMC_SDHCI_OF_HLWD is not set # CONFIG_MFD_TC35892 is not set +# CONFIG_MFD_AAT2870_CORE is not set # CONFIG_GPIO_SCH is not set # CONFIG_PPC_MPC512x is not set +# CONFIG_RTC_DRV_MPC5121 is not set -CONFIG_MPC512X_DMA=m +# CONFIG_MPC512X_DMA is not set CONFIG_KVM_GUEST=y + +CONFIG_I2C_MPC=m + +# CONFIG_IMA is not set +# CONFIG_TCG_TPM is not set + +CONFIG_RFKILL_GPIO=m + +# CONFIG_CRYPTO_DEV_FSL_CAAM is not set + +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_MCP23S08 is not set + +# CONFIG_CAN_FLEXCAN is not set +# CONFIG_NET_VENDOR_XILINX is not set +# CONFIG_PPC_EPAPR_HV_BYTECHAN is not set +# CONFIG_IBM_EMAC is not set +# CONFIG_NET_VENDOR_PASEMI is not set +# CONFIG_NET_VENDOR_TOSHIBA is not set + +# Disable btrfs until it is shown to work with 64k pages (rhbz 747079) +# CONFIG_BTRFS_FS is not set +# CONFIG_OF_SELFTEST is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_CPU_IDLE is not set +# CONFIG_V4L_RADIO_ISA_DRIVERS is not set +CONFIG_STRICT_DEVMEM=y diff --git a/config-powerpc32-generic b/config-powerpc32-generic index d2304955f..e856b9ff0 100644 --- a/config-powerpc32-generic +++ b/config-powerpc32-generic @@ -7,17 +7,17 @@ CONFIG_PPC32=y CONFIG_CPU_FREQ_PMAC=y CONFIG_PPC_CHRP=y CONFIG_PPC_PMAC=y -CONFIG_PPC_MPC52xx=y +# CONFIG_PPC_MPC52xx is not set CONFIG_PPC_PREP=y # CONFIG_PPC_MPC5200_SIMPLE is not set -CONFIG_SATA_FSL=m +# CONFIG_SATA_FSL is not set # CONFIG_SATA_NV is not set # busted in .28git1 # ERROR: "cacheable_memzero" [drivers/net/gianfar_driver.ko] undefined! # CONFIG_GIANFAR is not set -CONFIG_USB_EHCI_FSL=y +# CONFIG_USB_EHCI_FSL is not set CONFIG_PMAC_APM_EMU=y CONFIG_PMAC_BACKLIGHT=y @@ -41,6 +41,7 @@ CONFIG_ADB_PMU_LED=y CONFIG_ADB_PMU_LED_IDE=y CONFIG_PMAC_MEDIABAY=y +CONFIG_NET_VENDOR_APPLE=y CONFIG_BMAC=m CONFIG_MACE=m # CONFIG_MACE_AAUI_PORT is not set @@ -72,24 +73,20 @@ CONFIG_BRIQ_PANEL=m # CONFIG_ATA_PIIX is not set # CONFIG_PATA_AMD is not set # CONFIG_PATA_ATIIXP is not set -CONFIG_PATA_MPC52xx=m +# CONFIG_PATA_MPC52xx is not set # CONFIG_PATA_MPIIX is not set # CONFIG_PATA_OLDPIIX is not set # CONFIG_PATA_OPTI is not set # CONFIG_PATA_SERVERWORKS is not set -CONFIG_SERIAL_MPC52xx=y -CONFIG_SERIAL_MPC52xx_CONSOLE=y -CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=115200 +# CONFIG_SERIAL_MPC52xx is not set # CONFIG_MPC5200_WDT is not set CONFIG_8xxx_WDT=m CONFIG_GEF_WDT=m -CONFIG_PPC_MPC5200_BUGFIX=y -CONFIG_FEC_MPC52xx=m +# CONFIG_PPC_MPC5200_BUGFIX is not set +# CONFIG_NET_VENDOR_FREESCALE is not set #CHECK: This may later become a tristate. -CONFIG_FEC_MPC52xx_MDIO=y -CONFIG_PPC_MPC5200_GPIO=y CONFIG_MDIO_GPIO=m CONFIG_SERIAL_OF_PLATFORM=y @@ -137,7 +134,6 @@ CONFIG_VIRTUALIZATION=y # CONFIG_MEMSTICK is not set # CONFIG_IPMI_HANDLER is not set -# CONFIG_TCG_TPM is not set # PPC gets sad with debug alloc (bz 448598) # CONFIG_DEBUG_PAGEALLOC is not set @@ -145,26 +141,28 @@ CONFIG_VIRTUALIZATION=y CONFIG_SND_ISA=y CONFIG_CRYPTO_DEV_TALITOS=m -CONFIG_FSL_EMB_PERFMON=y -CONFIG_MPC8272_ADS=y -CONFIG_PQ2FADS=y -CONFIG_EP8248E=y -CONFIG_MPC830x_RDB=y -CONFIG_MPC831x_RDB=y -CONFIG_MPC832x_MDS=y -CONFIG_MPC832x_RDB=y -CONFIG_MPC834x_MDS=y -CONFIG_MPC834x_ITX=y -CONFIG_MPC836x_MDS=y -CONFIG_MPC836x_RDK=y -CONFIG_MPC837x_MDS=y -CONFIG_MPC837x_RDB=y -CONFIG_SBC834x=y -CONFIG_ASP834x=y -CONFIG_KMETER1=y -CONFIG_MPC8641_HPCN=y -CONFIG_SBC8641D=y -CONFIG_MPC8610_HPCD=y +# CONFIG_FSL_EMB_PERFMON is not set +# CONFIG_MPC8272_ADS is not set +# CONFIG_PQ2FADS is not set +# CONFIG_EP8248E is not set +# CONFIG_MPC830x_RDB is not set +# CONFIG_MPC831x_RDB is not set +# CONFIG_MPC832x_MDS is not set +# CONFIG_MPC832x_RDB is not set +# CONFIG_MPC834x_MDS is not set +# CONFIG_MPC834x_ITX is not set +# CONFIG_MPC836x_MDS is not set +# CONFIG_MPC836x_RDK is not set +# CONFIG_MPC837x_MDS is not set +# CONFIG_MPC837x_RDB is not set +# CONFIG_SBC834x is not set +# CONFIG_ASP834x is not set +# CONFIG_KMETER1 is not set +# CONFIG_MPC8641_HPCN is not set +# CONFIG_SBC8641D is not set +# CONFIG_MPC8610_HPCD is not set +# CONFIG_FSL_LBC is not set +# CONFIG_MTD_NAND_FSL_UPM is not set # CONFIG_USB_MUSB_HDRC is not set @@ -173,8 +171,6 @@ CONFIG_MPC8610_HPCD=y # drivers/mtd/maps/sbc8240.c:172: warning: passing argument 1 of 'simple_map_init' from incompatible pointer type # drivers/mtd/maps/sbc8240.c:177: error: 'struct mtd_info' has no member named 'module' -CONFIG_MTD_NAND_FSL_UPM=m - CONFIG_RCU_FANOUT=32 CONFIG_PERF_COUNTERS=y @@ -182,3 +178,8 @@ CONFIG_PERF_EVENTS=y CONFIG_EVENT_PROFILE=y CONFIG_KVM_BOOK3S_32=m + +# CONFIG_SCSI_QLA_ISCSI is not set + +CONFIG_BATTERY_PMU=m + diff --git a/config-powerpc64 b/config-powerpc64 index 74f33d1aa..c5c569752 100644 --- a/config-powerpc64 +++ b/config-powerpc64 @@ -2,48 +2,30 @@ CONFIG_WINDFARM_PM81=y CONFIG_WINDFARM_PM91=y CONFIG_WINDFARM_PM121=y CONFIG_PPC_PMAC64=y -CONFIG_PPC_MAPLE=y -CONFIG_PPC_CELL=y -CONFIG_PPC_IBM_CELL_BLADE=y +# CONFIG_PPC_MAPLE is not set +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_IBM_CELL_BLADE is not set CONFIG_PPC_ISERIES=y CONFIG_PPC_PSERIES=y CONFIG_PPC_PMAC=y -CONFIG_PPC_PASEMI=y +CONFIG_PPC_POWERNV=y +CONFIG_PPC_POWERNV_RTAS=y +# CONFIG_PPC_PASEMI is not set # CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE is not set -CONFIG_PPC_PS3=y -CONFIG_PPC_CELLEB=y -CONFIG_PPC_CELL_QPACE=y -CONFIG_PS3_HTAB_SIZE=20 -# CONFIG_PS3_DYNAMIC_DMA is not set -CONFIG_PS3_ADVANCED=y -CONFIG_PS3_HTAB_SIZE=20 -# CONFIG_PS3_DYNAMIC_DMA is not set -CONFIG_PS3_VUART=y -CONFIG_PS3_PS3AV=y -CONFIG_PS3_STORAGE=m -CONFIG_PS3_DISK=m -CONFIG_PS3_ROM=m -CONFIG_PS3_FLASH=m -CONFIG_PS3_LPM=y -CONFIG_SND_PS3=m -CONFIG_SND_PS3_DEFAULT_START_DELAY=1000 -CONFIG_GELIC_NET=m -CONFIG_GELIC_WIRELESS=y -CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE=y -CONFIG_CBE_THERM=m -CONFIG_CBE_CPUFREQ=m -CONFIG_CBE_CPUFREQ_PMI=m -CONFIG_CBE_CPUFREQ_PMI_ENABLE=y +# CONFIG_PPC_PS3 is not set +# CONFIG_PPC_CELLEB is not set +# CONFIG_PPC_CELL_QPACE is not set CONFIG_PMAC_RACKMETER=m CONFIG_IBMEBUS=y -CONFIG_SPU_FS=m CONFIG_RTAS_FLASH=y +# CONFIG_UDBG_RTAS_CONSOLE is not set CONFIG_PPC_SPLPAR=y CONFIG_SCANLOG=y CONFIG_LPARCFG=y CONFIG_SERIAL_ICOM=m CONFIG_HVCS=m CONFIG_HVC_CONSOLE=y +# CONFIG_HVC_OLD_HVSI is not set CONFIG_HOTPLUG_PCI=y CONFIG_THERM_PM72=y CONFIG_IBMVETH=m @@ -59,10 +41,9 @@ CONFIG_CPU_FREQ_PMAC64=y CONFIG_SCSI_IPR=m CONFIG_SCSI_IPR_TRACE=y CONFIG_SCSI_IPR_DUMP=y -CONFIG_SPIDER_NET=m CONFIG_HVC_RTAS=y CONFIG_HVC_ISERIES=y -CONFIG_CBE_RAS=y +CONFIG_HVC_OPAL=y # iSeries device drivers # @@ -74,19 +55,13 @@ CONFIG_VIOTAPE=m CONFIG_PASEMI_MAC=m CONFIG_SERIAL_OF_PLATFORM=m -CONFIG_PPC_PASEMI_IOMMU=y CONFIG_SERIAL_TXX9=y CONFIG_SERIAL_TXX9_NR_UARTS=6 CONFIG_SERIAL_TXX9_CONSOLE=y CONFIG_HVC_BEAT=y -CONFIG_FB_PS3=y -CONFIG_FB_PS3_DEFAULT_SIZE_M=18 - CONFIG_PPC_PMI=m -CONFIG_PS3_SYS_MANAGER=y -# CONFIG_BLK_DEV_CELLEB is not set CONFIG_PATA_SCC=m @@ -94,7 +69,7 @@ CONFIG_APM_EMULATION=m CONFIG_PPC64=y CONFIG_VIRT_CPU_ACCOUNTING=y -CONFIG_NR_CPUS=128 +CONFIG_NR_CPUS=1024 # CONFIG_FB_PLATINUM is not set # CONFIG_FB_VALKYRIE is not set # CONFIG_FB_CT65550 is not set @@ -107,9 +82,16 @@ CONFIG_NR_CPUS=128 CONFIG_RTAS_PROC=y CONFIG_IOMMU_VMERGE=y CONFIG_NUMA=y -# CONFIG_PPC_64K_PAGES is not set +CONFIG_PPC_64K_PAGES=y +CONFIG_PPC_SUBPAGE_PROT=y CONFIG_SCHED_SMT=y +CONFIG_HZ=100 +CONFIG_HZ_100=y +# CONFIG_HZ_1000 is not set + +CONFIG_MEMORY_HOTREMOVE=y + # CONFIG_MV643XX_ETH is not set CONFIG_IRQSTACKS=y CONFIG_DEBUG_STACKOVERFLOW=y @@ -118,7 +100,7 @@ CONFIG_DEBUG_STACKOVERFLOW=y CONFIG_EHEA=m CONFIG_INFINIBAND_EHCA=m -CONFIG_HCALL_STATS=y +# CONFIG_HCALL_STATS is not set CONFIG_XMON_DISASSEMBLY=y @@ -126,28 +108,18 @@ CONFIG_SCSI_IBMVSCSIS=m CONFIG_SECCOMP=y -CONFIG_TUNE_CELL=y +# CONFIG_TUNE_CELL is not set CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y # CONFIG_BLK_DEV_PLATFORM is not set -CONFIG_IBM_NEW_EMAC=m -CONFIG_IBM_NEW_EMAC_RXB=128 -CONFIG_IBM_NEW_EMAC_TXB=64 -CONFIG_IBM_NEW_EMAC_POLL_WEIGHT=32 -CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD=256 -CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM=0 -# CONFIG_IBM_NEW_EMAC_DEBUG is not set # CONFIG_VIRQ_DEBUG is not set -CONFIG_ELECTRA_CF=m -CONFIG_MTD_NAND_PASEMI=m -CONFIG_EDAC_CELL=m CONFIG_EDAC_CPC925=m CONFIG_FRAME_WARN=2048 CONFIG_PHYP_DUMP=y -CONFIG_FORCE_MAX_ZONEORDER=13 +CONFIG_FORCE_MAX_ZONEORDER=9 CONFIG_VIRTUALIZATION=y CONFIG_VSX=y @@ -156,14 +128,6 @@ CONFIG_SCSI_IBMVFC=m # CONFIG_SCSI_IBMVFC_TRACE is not set CONFIG_IBM_BSR=m -CONFIG_SERIO_XILINX_XPS_PS2=m - -CONFIG_PPC_IBM_CELL_RESETBUTTON=y -CONFIG_PPC_IBM_CELL_POWERBUTTON=m -CONFIG_CBE_CPUFREQ_SPU_GOVERNOR=m - -CONFIG_RTC_DRV_PS3=y - CONFIG_CRASH_DUMP=y CONFIG_RELOCATABLE=y @@ -174,6 +138,8 @@ CONFIG_PERF_EVENTS=y CONFIG_EVENT_PROFILE=y CONFIG_KVM_BOOK3S_64=m +#-- Enable _HV once publicly available POWER7 hardware can use it +# CONFIG_KVM_BOOK3S_64_HV is not set # CONFIG_KVM_EXIT_TIMING is not set #-- bz#607175 @@ -181,6 +147,17 @@ CONFIG_KVM_BOOK3S_64=m CONFIG_PPC_SMLPAR=y CONFIG_CMM=y #-- DLPAR memory remove -# CONFIG_SPARSEMEM_VMEMMAP is not set +CONFIG_SPARSEMEM_VMEMMAP=y + +# CONFIG_COMPACTION is not set CONFIG_PSERIES_ENERGY=m + +CONFIG_PPC_ICSWX=y +CONFIG_IO_EVENT_IRQ=y +CONFIG_HW_RANDOM_AMD=m + +CONFIG_BPF_JIT=y +# CONFIG_PPC_ICSWX_PID is not set +# CONFIG_PPC_ICSWX_USE_SIGILL is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set diff --git a/config-s390x b/config-s390x index 780fc9146..f03942191 100644 --- a/config-s390x +++ b/config-s390x @@ -233,3 +233,9 @@ CONFIG_SCHED_MC=y CONFIG_SCHED_BOOK=y CONFIG_STRICT_DEVMEM=y + +# CONFIG_WARN_DYNAMIC_STACK is not set + +CONFIG_CRYPTO_GHASH_S390=m +CONFIG_NET_CORE=y +CONFIG_ETHERNET=y diff --git a/config-sparc64-generic b/config-sparc64-generic index dac8a644f..2b29f9b7e 100644 --- a/config-sparc64-generic +++ b/config-sparc64-generic @@ -8,18 +8,7 @@ CONFIG_HZ=100 CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_TABLE=m -CONFIG_CPU_FREQ_DEBUG=y -# CONFIG_CPU_FREQ_STAT is not set -# CONFIG_CPU_FREQ_STAT_DETAILS is not set -CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y -# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set -CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=m -CONFIG_CPU_FREQ_GOV_USERSPACE=m -CONFIG_CPU_FREQ_GOV_ONDEMAND=m -CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m + CONFIG_US3_FREQ=m CONFIG_US2E_FREQ=m @@ -54,6 +43,7 @@ CONFIG_I2C_ALI1535=m # CONFIG_VGASTATE is not set # CONFIG_FB_DDC is not set # CONFIG_FB_BW2 is not set +# CONFIG_FB_GRVGA is not set CONFIG_FB_CG3=y CONFIG_FB_CG6=y # CONFIG_FB_RIVA is not set @@ -202,8 +192,7 @@ CONFIG_FB_XVR1000=y CONFIG_CRYPTO_DEV_NIAGARA2=y -CONFIG_JUMP_LABEL=y - # CONFIG_MTD_OF_PARTS is not set # CONFIG_MTD_PHYSMAP_OF is not set # CONFIG_MMC_SDHCI_OF is not set +# CONFIG_OF_SELFTEST is not set diff --git a/config-x86-32-generic b/config-x86-32-generic new file mode 100644 index 000000000..3f4fc346f --- /dev/null +++ b/config-x86-32-generic @@ -0,0 +1,209 @@ +# CONFIG_64BIT is not set + +CONFIG_X86_32_NON_STANDARD=y + +# CONFIG_X86_ELAN is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +CONFIG_X86_BIGSMP=y +# CONFIG_X86_VISWS is not set +# CONFIG_X86_RDC321X is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_M386 is not set +# CONFIG_M486 is not set +# CONFIG_M586 is not set +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +CONFIG_M686=y +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set + +CONFIG_NR_CPUS=32 +CONFIG_X86_GENERIC=y +# CONFIG_X86_PPRO_FENCE is not set + +CONFIG_TOSHIBA=m + +CONFIG_SONYPI=m +CONFIG_SONYPI_COMPAT=y + +# CONFIG_NUMA is not set + +# CONFIG_NOHIGHMEM is not set +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHMEM64G is not set +CONFIG_HIGHMEM=y +CONFIG_HIGHPTE=y + +# CONFIG_MATH_EMULATION is not set + +CONFIG_FB_GEODE=y +CONFIG_FB_GEODE_LX=y +CONFIG_FB_GEODE_GX=y +# CONFIG_FB_GEODE_GX1 is not set + +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GODIRECT is not set +# CONFIG_PCI_GOMMCONFIG is not set +CONFIG_PCI_GOANY=y + +CONFIG_IBM_ASM=m + +# +# APM (Advanced Power Management) BIOS Support +# +CONFIG_APM=y +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_DO_ENABLE is not set +CONFIG_APM_CPU_IDLE=y +# CONFIG_APM_DISPLAY_BLANK is not set +# CONFIG_APM_ALLOW_INTS is not set + +CONFIG_ACPI_BLACKLIST_YEAR=1999 + + +# CONFIG_X86_POWERNOW_K6 is not set +CONFIG_X86_POWERNOW_K7=y +# CONFIG_X86_GX_SUSPMOD is not set +CONFIG_X86_SPEEDSTEP_ICH=y +CONFIG_X86_SPEEDSTEP_SMI=y +CONFIG_X86_SPEEDSTEP_LIB=y +# CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK is not set +CONFIG_X86_LONGRUN=y +# CONFIG_X86_LONGHAUL is not set +# CONFIG_X86_CPUFREQ_NFORCE2 is not set +# e_powersaver is dangerous +# CONFIG_X86_E_POWERSAVER is not set + +CONFIG_X86_HT=y +CONFIG_X86_TRAMPOLINE=y + + +# CONFIG_4KSTACKS is not set + +CONFIG_PCI_DIRECT=y + +# SHPC has half-arsed PCI probing, which makes it load on too many systems +# CONFIG_HOTPLUG_PCI_SHPC is not set + +CONFIG_BLK_DEV_AMD74XX=y + +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m + +CONFIG_SCx200_ACB=m + +# CONFIG_X86_REBOOTFIXUPS is not set + +CONFIG_PC8736x_GPIO=m +# CONFIG_NSC_GPIO is not set +CONFIG_CS5535_GPIO=m +CONFIG_GPIO_SCH=m + +CONFIG_SND_ISA=y +CONFIG_SND_ES18XX=m + +CONFIG_HW_RANDOM_GEODE=m + +# CONFIG_SGI_IOC4 is not set + +CONFIG_TC1100_WMI=m + +CONFIG_IB700_WDT=m + +CONFIG_PHYSICAL_ALIGN=0x400000 +CONFIG_PHYSICAL_START=0x400000 + +# CONFIG_KEXEC_JUMP is not set + +CONFIG_CRYPTO_AES_586=y +CONFIG_CRYPTO_DEV_GEODE=m +CONFIG_CRYPTO_TWOFISH_586=m + +CONFIG_VIDEO_CAFE_CCIC=m + +CONFIG_XEN_MAX_DOMAIN_MEMORY=8 + +CONFIG_MTD_NAND_CAFE=m + +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set + + +CONFIG_OLPC=y +CONFIG_OLPC_OPENFIRMWARE=y +CONFIG_BATTERY_OLPC=y +CONFIG_MOUSE_PS2_OLPC=y +CONFIG_OLPC_XO1_PM=y +CONFIG_OLPC_XO15_SCI=y +CONFIG_OLPC_XO1_RTC=y +CONFIG_OLPC_XO1_SCI=y +# CONFIG_ALIX is not set +# staging +# CONFIG_FB_OLPC_DCON is not set + +# CONFIG_SPARSE_IRQ is not set + +CONFIG_RCU_FANOUT=32 + +# CONFIG_X86_ANCIENT_MCE is not set + +# CONFIG_X86_MRST is not set + +CONFIG_I2C_PXA=m +# CONFIG_GPIO_LANGWELL is not set + +# CONFIG_INTEL_TXT is not set + +CONFIG_GEODE_WDT=m +CONFIG_CS5535_MFGPT=m +CONFIG_CS5535_CLOCK_EVENT_SRC=m + +CONFIG_LEDS_INTEL_SS4200=m + +CONFIG_OLPC_XO1=m +CONFIG_XO1_RFKILL=m + +CONFIG_X86_32_IRIS=m + + +CONFIG_MTD_OF_PARTS=y +CONFIG_MTD_PHYSMAP_OF=m +CONFIG_PROC_DEVICETREE=y +CONFIG_SERIAL_OF_PLATFORM=m +CONFIG_SERIAL_GRLIB_GAISLER_APBUART=m +# CONFIG_MMC_SDHCI_OF is not set + +# CONFIG_X86_INTEL_MID is not set + +CONFIG_MFD_CS5535=m + +# I2O enabled only for 32-bit x86, disabled for PAE kernel +CONFIG_I2O=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m +CONFIG_I2O_CONFIG=y +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_CONFIG_OLD_IOCTL=y +CONFIG_I2O_BUS=m + +# CONFIG_EDAC_SBRIDGE is not set + +# CONFIG_X86_WANT_INTEL_MID is not set +# CONFIG_OF_SELFTEST is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set diff --git a/config-x86-generic b/config-x86-generic index d6feae847..9f9f5b5b8 100644 --- a/config-x86-generic +++ b/config-x86-generic @@ -1,68 +1,30 @@ CONFIG_UID16=y -# CONFIG_64BIT is not set -# CONFIG_KERNEL_LZMA is not set -# -# Processor type and features -# -# -# Enable summit and co via the generic arch -# CONFIG_X86_EXTENDED_PLATFORM=y -CONFIG_X86_32_NON_STANDARD=y -# CONFIG_X86_ELAN is not set -# CONFIG_X86_NUMAQ is not set -# CONFIG_X86_SUMMIT is not set -CONFIG_X86_BIGSMP=y -# CONFIG_X86_VISWS is not set -# CONFIG_X86_RDC321X is not set -# CONFIG_X86_ES7000 is not set -# CONFIG_M386 is not set -# CONFIG_M486 is not set -# CONFIG_M586 is not set -# CONFIG_M586TSC is not set -# CONFIG_M586MMX is not set -CONFIG_M686=y -# CONFIG_MPENTIUMII is not set -# CONFIG_MPENTIUMIII is not set -# CONFIG_MPENTIUMM is not set -# CONFIG_MPENTIUM4 is not set -# CONFIG_MK6 is not set -# CONFIG_MK7 is not set -# CONFIG_MK8 is not set -# CONFIG_MCRUSOE is not set -# CONFIG_MWINCHIPC6 is not set -# CONFIG_MWINCHIP3D is not set -# CONFIG_MCYRIXIII is not set -# CONFIG_MVIAC3_2 is not set CONFIG_SMP=y -CONFIG_NR_CPUS=64 + CONFIG_X86_GENERIC=y -# CONFIG_X86_PPRO_FENCE is not set + CONFIG_HPET=y CONFIG_HPET_TIMER=y # CONFIG_HPET_MMAP is not set -CONFIG_X86_MCE=y -CONFIG_TOSHIBA=m + CONFIG_I8K=m -CONFIG_SONYPI=m CONFIG_SONYPI_COMPAT=y CONFIG_MICROCODE=m +CONFIG_MICROCODE_INTEL=y +CONFIG_MICROCODE_AMD=y + CONFIG_X86_MSR=y CONFIG_X86_CPUID=y CONFIG_EDD=m # CONFIG_EDD_OFF is not set -# CONFIG_NUMA is not set -# CONFIG_NOHIGHMEM is not set -CONFIG_HIGHMEM4G=y -# CONFIG_HIGHMEM64G is not set -CONFIG_HIGHMEM=y -CONFIG_HIGHPTE=y - -# CONFIG_MATH_EMULATION is not set CONFIG_MTRR=y +CONFIG_MTRR_SANITIZER=y +CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1 +CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1 CONFIG_X86_PAT=y CONFIG_X86_PM_TIMER=y @@ -70,152 +32,80 @@ CONFIG_EFI=y CONFIG_EFI_VARS=y CONFIG_EFI_PCDP=y CONFIG_FB_EFI=y + +# FIXME: 32bit only? # CONFIG_FB_N411 is not set -CONFIG_DMAR=y +CONFIG_INTEL_IOMMU=y CONFIG_DMAR_BROKEN_GFX_WA=y -CONFIG_DMAR_FLOPPY_WA=y -CONFIG_DMAR_DEFAULT_ON=y - -CONFIG_FB_GEODE=y -CONFIG_FB_GEODE_LX=y -CONFIG_FB_GEODE_GX=y -# CONFIG_FB_GEODE_GX1 is not set - -# CONFIG_PCI_GOBIOS is not set -# CONFIG_PCI_GODIRECT is not set -# CONFIG_PCI_GOMMCONFIG is not set -CONFIG_PCI_GOANY=y - -# -# x86 specific drivers -# -CONFIG_PCMCIA_FDOMAIN=m -CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_INTEL_IOMMU_FLOPPY_WA=y +# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set CONFIG_SCSI_ADVANSYS=m -CONFIG_CC_STACKPROTECTOR=y - CONFIG_SECCOMP=y CONFIG_CAPI_EICON=y -# I2O enabled only for 32-bit x86, disabled for PAE kernel -CONFIG_I2O=m -CONFIG_I2O_BLOCK=m -CONFIG_I2O_SCSI=m -CONFIG_I2O_PROC=m -CONFIG_I2O_CONFIG=y -CONFIG_I2O_EXT_ADAPTEC=y -CONFIG_I2O_CONFIG_OLD_IOCTL=y -CONFIG_I2O_BUS=m - -# -# APM (Advanced Power Management) BIOS Support -# -CONFIG_APM=y -# CONFIG_APM_IGNORE_USER_SUSPEND is not set -# CONFIG_APM_DO_ENABLE is not set -CONFIG_APM_CPU_IDLE=y -# CONFIG_APM_DISPLAY_BLANK is not set -# CONFIG_APM_ALLOW_INTS is not set - # # Kernel debugging # CONFIG_X86_MPPARSE=y +# CONFIG_X86_VERBOSE_BOOTUP is not set +# CONFIG_MMIOTRACE_TEST is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_DEBUG_RODATA=y +CONFIG_DEBUG_STACKOVERFLOW=y CONFIG_ACPI=y CONFIG_ACPI_AC=y # CONFIG_ACPI_ASUS is not set -CONFIG_ACPI_PROCFS_POWER=y -CONFIG_ACPI_SYSFS_POWER=y CONFIG_ACPI_BATTERY=y -CONFIG_ACPI_BLACKLIST_YEAR=1999 CONFIG_ACPI_BUTTON=y CONFIG_ACPI_CONTAINER=m CONFIG_ACPI_DOCK=y CONFIG_ACPI_FAN=y CONFIG_ACPI_NUMA=y CONFIG_ACPI_PROCESSOR=y -CONFIG_ACPI_POWER=y CONFIG_ACPI_PROCFS=y CONFIG_ACPI_SBS=m CONFIG_ACPI_SLEEP=y CONFIG_ACPI_THERMAL=y -CONFIG_TOPSTAR_LAPTOP=m CONFIG_ACPI_TOSHIBA=m CONFIG_ACPI_VIDEO=m +# FIXME: Next two are deprecated. Remove them when they disappear upstream +# CONFIG_ACPI_PROCFS_POWER is not set # CONFIG_ACPI_PROC_EVENT is not set CONFIG_PNPACPI=y -CONFIG_ACPI_POWER_METER=m CONFIG_ACPI_PROCESSOR_AGGREGATOR=m CONFIG_ACPI_HED=m CONFIG_ACPI_APEI=y -CONFIG_ACPI_APEI_GHES=m +CONFIG_ACPI_APEI_PCIEAER=y +CONFIG_ACPI_APEI_GHES=y +CONFIG_ACPI_APEI_MEMORY_FAILURE=y # CONFIG_ACPI_APEI_EINJ is not set CONFIG_ACPI_IPMI=m - -# -# CPUFreq processor drivers -# -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_DEBUG=y -# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set -CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=m -CONFIG_CPU_FREQ_GOV_USERSPACE=m -CONFIG_CPU_FREQ_GOV_ONDEMAND=m -CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m -CONFIG_CPU_FREQ_TABLE=y -CONFIG_CPU_FREQ_STAT=m -CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_ACPI_CUSTOM_METHOD=m CONFIG_X86_ACPI_CPUFREQ=m CONFIG_X86_PCC_CPUFREQ=m -# CONFIG_X86_POWERNOW_K6 is not set -CONFIG_X86_POWERNOW_K7=y CONFIG_X86_POWERNOW_K8=m -# CONFIG_X86_GX_SUSPMOD is not set -# CONFIG_X86_SPEEDSTEP_CENTRINO is not set -CONFIG_X86_SPEEDSTEP_ICH=y -CONFIG_X86_SPEEDSTEP_SMI=y -CONFIG_X86_SPEEDSTEP_LIB=y -# CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK is not set CONFIG_X86_P4_CLOCKMOD=m -CONFIG_X86_LONGRUN=y -# CONFIG_X86_LONGHAUL is not set -# CONFIG_X86_CPUFREQ_NFORCE2 is not set -# e_powersaver is dangerous -# CONFIG_X86_E_POWERSAVER is not set - -CONFIG_X86_HT=y -CONFIG_X86_TRAMPOLINE=y +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set # # various x86 specific drivers # CONFIG_NVRAM=y -CONFIG_IBM_ASM=m -CONFIG_CRYPTO_AES_586=m -CONFIG_CRYPTO_TWOFISH_586=m CONFIG_CRYPTO_DEV_PADLOCK=m CONFIG_CRYPTO_DEV_PADLOCK_AES=m CONFIG_CRYPTO_DEV_PADLOCK_SHA=m CONFIG_GENERIC_ISA_DMA=y -CONFIG_SCHED_SMT=y + CONFIG_SUSPEND=y CONFIG_HIBERNATION=y CONFIG_PM_STD_PARTITION="" -CONFIG_DEBUG_RODATA=y -CONFIG_DEBUG_STACKOVERFLOW=y -# CONFIG_4KSTACKS is not set -CONFIG_DEBUG_NMI_TIMEOUT=5 - -CONFIG_PCI_DIRECT=y CONFIG_PCI_MMCONFIG=y CONFIG_PCI_BIOS=y @@ -224,8 +114,7 @@ CONFIG_HOTPLUG_PCI_COMPAQ=m # CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set CONFIG_HOTPLUG_PCI_IBM=m # CONFIG_HOTPLUG_PCI_CPCI is not set -# SHPC has half-arsed PCI probing, which makes it load on too many systems -# CONFIG_HOTPLUG_PCI_SHPC is not set + CONFIG_PM=y CONFIG_IPW2100=m @@ -238,9 +127,6 @@ CONFIG_IPW2200_QOS=y CONFIG_BLK_DEV_AMD74XX=y -CONFIG_I2C_ALI1535=m -CONFIG_I2C_ALI15X3=m -CONFIG_I2C_ALI1563=m CONFIG_I2C_AMD756=m CONFIG_I2C_AMD756_S4882=m CONFIG_I2C_AMD8111=m @@ -249,45 +135,35 @@ CONFIG_I2C_ISCH=m CONFIG_I2C_NFORCE2=m CONFIG_I2C_NFORCE2_S4985=m CONFIG_I2C_PIIX4=m -CONFIG_I2C_SIS5595=m -CONFIG_I2C_SIS630=m CONFIG_I2C_SIS96X=m - CONFIG_I2C_VIA=m CONFIG_I2C_VIAPRO=m -CONFIG_SCx200_ACB=m - -# CONFIG_X86_REBOOTFIXUPS is not set - CONFIG_DELL_RBU=m CONFIG_DCDBAS=m -CONFIG_GPIO_SCH=m -CONFIG_PC8736x_GPIO=m -# CONFIG_NSC_GPIO is not set -CONFIG_CS5535_GPIO=m - CONFIG_EDAC=y # CONFIG_EDAC_DEBUG is not set CONFIG_EDAC_MM_EDAC=m CONFIG_EDAC_AMD76X=m +CONFIG_EDAC_AMD8111=m +CONFIG_EDAC_AMD8131=m CONFIG_EDAC_E7XXX=m CONFIG_EDAC_E752X=m CONFIG_EDAC_I82860=m CONFIG_EDAC_I82875P=m CONFIG_EDAC_I82975X=m CONFIG_EDAC_I3000=m +CONFIG_EDAC_I3200=m CONFIG_EDAC_I5000=m CONFIG_EDAC_I5100=m CONFIG_EDAC_I5400=m -CONFIG_EDAC_R82600=m -CONFIG_EDAC_AMD8131=m -CONFIG_EDAC_AMD8111=m -CONFIG_EDAC_I7CORE=m -CONFIG_EDAC_I3000=m CONFIG_EDAC_I7300=m +CONFIG_EDAC_I7CORE=m +CONFIG_EDAC_R82600=m CONFIG_EDAC_X38=m +CONFIG_EDAC_MCE_INJ=m +CONFIG_EDAC_DECODE_MCE=m CONFIG_SCHED_MC=y @@ -298,90 +174,93 @@ CONFIG_TCG_INFINEON=m CONFIG_HW_RANDOM_INTEL=m CONFIG_HW_RANDOM_AMD=m -CONFIG_HW_RANDOM_GEODE=m CONFIG_HW_RANDOM_VIA=m - # CONFIG_COMPAT_VDSO is not set -# CONFIG_SGI_IOC4 is not set - CONFIG_X86_PLATFORM_DEVICES=y + CONFIG_ASUS_LAPTOP=m CONFIG_COMPAL_LAPTOP=m +CONFIG_DELL_LAPTOP=m CONFIG_EEEPC_LAPTOP=m -CONFIG_EEEPC_WMI=m CONFIG_FUJITSU_LAPTOP=m # CONFIG_FUJITSU_LAPTOP_DEBUG is not set CONFIG_IDEAPAD_LAPTOP=m CONFIG_MSI_LAPTOP=m +CONFIG_PANASONIC_LAPTOP=m +CONFIG_SAMSUNG_LAPTOP=m CONFIG_SONY_LAPTOP=m -CONFIG_DELL_LAPTOP=m +CONFIG_TOPSTAR_LAPTOP=m + CONFIG_ACPI_WMI=m CONFIG_ACER_WMI=m CONFIG_ACERHDF=m -CONFIG_TC1100_WMI=m +CONFIG_ASUS_WMI=m +CONFIG_ASUS_NB_WMI=m CONFIG_HP_WMI=m # CONFIG_INTEL_SCU_IPC is not set CONFIG_DELL_WMI=m +CONFIG_DELL_WMI_AIO=m +CONFIG_EEEPC_WMI=m +CONFIG_INTEL_OAKTRAIL=m +CONFIG_SAMSUNG_Q10=m +CONFIG_XO15_EBOOK=m # CONFIG_TOUCHSCREEN_INTEL_MID is not set # CONFIG_SMSC37B787_WDT is not set CONFIG_W83697HF_WDT=m -CONFIG_IB700_WDT=m -CONFIG_RELOCATABLE=y -CONFIG_PHYSICAL_ALIGN=0x400000 -CONFIG_PHYSICAL_START=0x400000 CONFIG_CRASH_DUMP=y -# CONFIG_KEXEC_JUMP is not set CONFIG_PROC_VMCORE=y CONFIG_CRASH=m -CONFIG_CRYPTO_DEV_GEODE=m - -CONFIG_VIDEO_CAFE_CCIC=m - CONFIG_VIRTUALIZATION=y CONFIG_KVM=m CONFIG_KVM_INTEL=m CONFIG_KVM_AMD=m CONFIG_LGUEST=m +CONFIG_LGUEST_GUEST=y CONFIG_PARAVIRT_GUEST=y CONFIG_PARAVIRT=y +CONFIG_PARAVIRT_TIME_ACCOUNTING=y # CONFIG_PARAVIRT_DEBUG is not set -# PARAVIRT_SPINLOCKS has a 5% perf hit +# PARAVIRT_SPINLOCKS has a 5% perf hit on native hw (see kconfig) # CONFIG_PARAVIRT_SPINLOCKS is not set + CONFIG_KVM_CLOCK=y CONFIG_KVM_GUEST=y CONFIG_KVM_MMU_AUDIT=y # default $x would be nice... -CONFIG_LGUEST_GUEST=y -CONFIG_VMI=y CONFIG_XEN=y -CONFIG_XEN_MAX_DOMAIN_MEMORY=8 +# CONFIG_XEN_DEBUG is not set CONFIG_XEN_BALLOON=y CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_SAVE_RESTORE=y CONFIG_HVC_XEN=y CONFIG_XEN_FBDEV_FRONTEND=y -CONFIG_XEN_KBDDEV_FRONTEND=y CONFIG_XEN_BLKDEV_FRONTEND=m CONFIG_XEN_NETDEV_FRONTEND=m +CONFIG_XEN_NETDEV_BACKEND=m +CONFIG_XEN_WDT=m +CONFIG_XEN_GRANT_DEV_ALLOC=m CONFIG_XEN_PCIDEV_FRONTEND=m CONFIG_XENFS=m CONFIG_XEN_COMPAT_XENFS=y CONFIG_XEN_BACKEND=y +CONFIG_XEN_BLKDEV_BACKEND=m CONFIG_XEN_DEBUG_FS=y -CONFIG_XEN_PLATFORM_PCI=m +CONFIG_XEN_PLATFORM_PCI=y CONFIG_XEN_GNTDEV=m +CONFIG_INPUT_XEN_KBDDEV_FRONTEND=m +CONFIG_XEN_SELFBALLOONING=y +CONFIG_XEN_PCIDEV_BACKEND=m CONFIG_MTD_ESB2ROM=m CONFIG_MTD_CK804XROM=m -CONFIG_MTD_NAND_CAFE=m CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y @@ -400,6 +279,8 @@ CONFIG_THINKPAD_ACPI_ALSA_SUPPORT=y CONFIG_MACINTOSH_DRIVERS=y CONFIG_DMIID=y +CONFIG_DMI_SYSFS=y + CONFIG_ISCSI_IBFT_FIND=y CONFIG_ISCSI_IBFT=m @@ -407,97 +288,56 @@ CONFIG_DMADEVICES=y CONFIG_INTEL_IOATDMA=m CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_FAM15H_POWER=m +CONFIG_SENSORS_ACPI_POWER=m # CONFIG_CPA_DEBUG is not set -# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set CONFIG_HP_WATCHDOG=m CONFIG_NV_TCO=m CONFIG_SP5100_TCO=m -CONFIG_OLPC=y -CONFIG_OLPC_OPENFIRMWARE=y -CONFIG_BATTERY_OLPC=y -CONFIG_MOUSE_PS2_OLPC=y - CONFIG_STRICT_DEVMEM=y # CONFIG_NO_BOOTMEM is not set # CONFIG_MEMTEST is not set # CONFIG_MAXSMP is not set -CONFIG_MTRR_SANITIZER=y -CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1 -CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1 -CONFIG_SYSPROF_TRACER=y -# CONFIG_X86_VERBOSE_BOOTUP is not set -# CONFIG_MMIOTRACE_TEST is not set - -# CONFIG_DEBUG_PER_CPU_MAPS is not set CONFIG_HP_ILO=m CONFIG_BACKLIGHT_APPLE=m -CONFIG_OPROFILE_IBS=y -CONFIG_MICROCODE_INTEL=y -CONFIG_MICROCODE_AMD=y -# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set -CONFIG_X86_RESERVE_LOW_64K=y +CONFIG_X86_CHECK_BIOS_CORRUPTION=y # CONFIG_CMDLINE_BOOL is not set -CONFIG_PANASONIC_LAPTOP=m - -CONFIG_X86_PTRACE_BTS=y CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y -CONFIG_POWER_TRACER=y -CONFIG_HW_BRANCH_TRACER=y - -# CONFIG_SPARSE_IRQ is not set - -CONFIG_RCU_FANOUT=32 # CONFIG_IOMMU_STRESS is not set CONFIG_PERF_COUNTERS=y CONFIG_PERF_EVENTS=y -CONFIG_EVENT_PROFILE=y +CONFIG_X86_MCE=y CONFIG_X86_MCE_INTEL=y CONFIG_X86_MCE_AMD=y -# CONFIG_X86_ANCIENT_MCE is not set # CONFIG_X86_MCE_INJECT is not set -# CONFIG_X86_MRST is not set CONFIG_SFI=y -CONFIG_INPUT_WINBOND_CIR=m CONFIG_I2C_SCMI=m CONFIG_SBC_FITPC2_WATCHDOG=m -CONFIG_EDAC_I3200=m -CONFIG_EDAC_DECODE_MCE=m - -# CONFIG_GPIO_LANGWELL is not set - -# CONFIG_INTEL_TXT is not set - -CONFIG_CS5535_MFGPT=m -CONFIG_GEODE_WDT=m -CONFIG_CS5535_CLOCK_EVENT_SRC=m - -CONFIG_LEDS_INTEL_SS4200=m CONFIG_X86_DECODER_SELFTEST=y CONFIG_ACPI_CMPC=m CONFIG_MSI_WMI=m CONFIG_TOSHIBA_BT_RFKILL=m -# CONFIG_SAMSUNG_LAPTOP is not set CONFIG_VGA_SWITCHEROO=y CONFIG_LPC_SCH=m @@ -506,41 +346,53 @@ CONFIG_PCI_CNB20LE_QUIRK=y CONFIG_ACPI_EC_DEBUGFS=m # CONFIG_ACPI_APEI_ERST_DEBUG is not set +# CONFIG_ACPI_QUICKSTART is not set + CONFIG_INTEL_IDLE=y + # CONFIG_TOUCHSCREEN_CY8CTMG110 is not set -CONFIG_SENSORS_PKGTEMP=m CONFIG_F71808E_WDT=m CONFIG_HPWDT_NMI_DECODING=y # CONFIG_MFD_TPS6586X is not set # CONFIG_INTEL_MID_DMAC is not set CONFIG_PCH_DMA=m -# CONFIG_ACPI_QUICKSTART is not set -CONFIG_IDEAPAD_ACPI=m CONFIG_INTEL_IPS=m # CONFIG_IBM_RTL is not set -CONFIG_OLPC_XO1=m -CONFIG_XO1_RFKILL=m CONFIG_VIDEO_VIA_CAMERA=m -CONFIG_EDAC_MCE_INJ=m CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_X86_RESERVE_LOW=64 CONFIG_PCH_GBE=m CONFIG_PCH_PHUB=m -CONFIG_JUMP_LABEL=y - -CONFIG_X86_32_IRIS=m - CONFIG_TRANSPARENT_HUGEPAGE=y -CONFIG_CRYPTO_AES_NI_INTEL=m +CONFIG_CRYPTO_AES_NI_INTEL=y -CONFIG_MTD_OF_PARTS=m -CONFIG_MTD_PHYSMAP_OF=m -CONFIG_PROC_DEVICETREE=y -CONFIG_SERIAL_OF_PLATFORM=m -CONFIG_SERIAL_GRLIB_GAISLER_APBUART=m -# CONFIG_MMC_SDHCI_OF is not set +CONFIG_HP_ACCEL=m + +# CONFIG_RAPIDIO is not set + +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_MCP23S08 is not set + +CONFIG_SCHED_SMT=y +CONFIG_CC_STACKPROTECTOR=y +CONFIG_RELOCATABLE=y + +# CONFIG_HYPERV is not set + +CONFIG_EFI_STUB=y +CONFIG_PCI_IOAPIC=y +CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m +CONFIG_VIA_WDT=m +# CONFIG_V4L_RADIO_ISA_DRIVERS is not set +CONFIG_DRM_GMA500=m +CONFIG_FUJITSU_TABLET=m +CONFIG_AMILO_RFKILL=m +# CONFIG_DEBUG_NMI_SELFTEST is not set +CONFIG_CRYPTO_SERPENT_SSE2_586=m +# CONFIG_DRM_GMA600 is not set +# CONFIG_DRM_GMA3600 is not set diff --git a/config-x86_64-generic b/config-x86_64-generic index 0154cf1b0..a41b45015 100644 --- a/config-x86_64-generic +++ b/config-x86_64-generic @@ -1,232 +1,62 @@ CONFIG_64BIT=y -CONFIG_UID16=y -# CONFIG_KERNEL_LZMA is not set # CONFIG_MK8 is not set # CONFIG_MPSC is not set CONFIG_GENERIC_CPU=y -CONFIG_X86_EXTENDED_PLATFORM=y + # CONFIG_X86_VSMP is not set # CONFIG_X86_UV is not set -CONFIG_X86_MSR=y -CONFIG_X86_CPUID=y -CONFIG_MTRR=y CONFIG_NUMA=y CONFIG_K8_NUMA=y CONFIG_AMD_NUMA=y CONFIG_X86_64_ACPI_NUMA=y # CONFIG_NUMA_EMU is not set + CONFIG_NR_CPUS=256 -CONFIG_X86_POWERNOW_K8=m -CONFIG_X86_P4_CLOCKMOD=m +CONFIG_PHYSICAL_START=0x1000000 + CONFIG_IA32_EMULATION=y # CONFIG_IA32_AOUT is not set + +CONFIG_AMD_IOMMU=y +CONFIG_AMD_IOMMU_STATS=y # CONFIG_IOMMU_DEBUG is not set -CONFIG_DEBUG_RODATA=y -CONFIG_MICROCODE=m CONFIG_SWIOTLB=y -CONFIG_CALGARY_IOMMU=y -CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT=y -CONFIG_X86_PM_TIMER=y -CONFIG_EDD=m -# CONFIG_EDD_OFF is not set -CONFIG_PCI_BIOS=y -CONFIG_PCI_MMCONFIG=y -CONFIG_DMAR=y -CONFIG_DMAR_BROKEN_GFX_WA=y -CONFIG_DMAR_FLOPPY_WA=y -CONFIG_DMAR_DEFAULT_ON=y +# CONFIG_CALGARY_IOMMU is not set CONFIG_KEXEC_JUMP=y -CONFIG_EFI=y -CONFIG_EFI_VARS=y -CONFIG_EFI_PCDP=y -CONFIG_FB_EFI=y - -CONFIG_SCSI_ADVANSYS=m - -CONFIG_SECCOMP=y - -CONFIG_CAPI_EICON=y - -CONFIG_GENERIC_ISA_DMA=y -CONFIG_SCHED_SMT=y -CONFIG_SUSPEND=y -CONFIG_HIBERNATION=y -CONFIG_PM_STD_PARTITION="" - -CONFIG_CPU_FREQ=y -# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set -CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=m -CONFIG_CPU_FREQ_GOV_USERSPACE=m -CONFIG_CPU_FREQ_GOV_ONDEMAND=m -CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m -CONFIG_CPU_FREQ_TABLE=y -CONFIG_CPU_FREQ_DEBUG=y -# CONFIG_X86_SPEEDSTEP_CENTRINO is not set -CONFIG_X86_PCC_CPUFREQ=m -CONFIG_X86_ACPI_CPUFREQ=m -CONFIG_CPU_FREQ_STAT=m -CONFIG_CPU_FREQ_STAT_DETAILS=y - -CONFIG_ACPI=y -CONFIG_ACPI_AC=y -# CONFIG_ACPI_ASUS is not set -CONFIG_ACPI_PROCFS_POWER=y -CONFIG_ACPI_SYSFS_POWER=y -CONFIG_ACPI_BATTERY=y CONFIG_ACPI_BLACKLIST_YEAR=0 -CONFIG_ACPI_BUTTON=y -CONFIG_ACPI_CONTAINER=m -CONFIG_ACPI_DOCK=y -CONFIG_ACPI_FAN=y CONFIG_ACPI_HOTPLUG_MEMORY=m -CONFIG_ACPI_NUMA=y -CONFIG_ACPI_PROCESSOR=y -CONFIG_ACPI_PROCFS=y -CONFIG_ACPI_SBS=m -CONFIG_ACPI_SLEEP=y -CONFIG_ACPI_THERMAL=y -CONFIG_ACPI_TOSHIBA=m -CONFIG_ACPI_POWER=y -CONFIG_ACPI_VIDEO=m -# CONFIG_ACPI_PROC_EVENT is not set -CONFIG_ACPI_POWER_METER=m -CONFIG_ACPI_PROCESSOR_AGGREGATOR=m -CONFIG_ACPI_HED=m -CONFIG_ACPI_APEI=y -CONFIG_ACPI_APEI_GHES=m -# CONFIG_ACPI_APEI_EINJ is not set -CONFIG_ACPI_IPMI=m -CONFIG_X86_PLATFORM_DEVICES=y -CONFIG_ASUS_LAPTOP=m -CONFIG_COMPAL_LAPTOP=m -CONFIG_FUJITSU_LAPTOP=m -# CONFIG_FUJITSU_LAPTOP_DEBUG is not set -CONFIG_MSI_LAPTOP=m -CONFIG_SONY_LAPTOP=m -CONFIG_SONYPI_COMPAT=y -CONFIG_EEEPC_LAPTOP=m -CONFIG_EEEPC_WMI=m -CONFIG_DELL_LAPTOP=m -CONFIG_ACPI_WMI=m -CONFIG_ACER_WMI=m -CONFIG_ACERHDF=m -CONFIG_HP_WMI=m -CONFIG_DELL_WMI=m # CONFIG_INTEL_SCU_IPC is not set -# CONFIG_TOUCHSCREEN_INTEL_MID is not set - -CONFIG_THINKPAD_ACPI=m -# CONFIG_THINKPAD_ACPI_DEBUG is not set -# CONFIG_THINKPAD_ACPI_DEBUGFACILITIES is not set -CONFIG_THINKPAD_ACPI_HOTKEY_POLL=y -CONFIG_THINKPAD_ACPI_VIDEO=y -CONFIG_THINKPAD_ACPI_ALSA_SUPPORT=y -# CONFIG_THINKPAD_ACPI_UNSAFE_LEDS is not set - -CONFIG_HOTPLUG_PCI=y -CONFIG_HOTPLUG_PCI_COMPAQ=m -# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set -CONFIG_HOTPLUG_PCI_IBM=m -# CONFIG_HOTPLUG_PCI_CPCI is not set # SHPC has half-arsed PCI probing, which makes it load on too many systems CONFIG_HOTPLUG_PCI_SHPC=m -CONFIG_HPET=y -# CONFIG_HPET_MMAP is not set -CONFIG_PM=y - -CONFIG_IPW2100=m -CONFIG_IPW2100_MONITOR=y -CONFIG_IPW2200=m -CONFIG_IPW2200_MONITOR=y -CONFIG_IPW2200_RADIOTAP=y -CONFIG_IPW2200_PROMISCUOUS=y -CONFIG_IPW2200_QOS=y - CONFIG_PNP=y -CONFIG_PNPACPI=y +# Really ? not 32bit only ? CONFIG_BLK_DEV_AMD74XX=y -CONFIG_CRYPTO_DEV_PADLOCK=m -CONFIG_CRYPTO_DEV_PADLOCK_AES=m -CONFIG_CRYPTO_DEV_PADLOCK_SHA=m CONFIG_CRYPTO_AES_X86_64=y -CONFIG_CRYPTO_AES_NI_INTEL=y CONFIG_CRYPTO_TWOFISH_X86_64=m CONFIG_CRYPTO_SALSA20_X86_64=m - -CONFIG_X86_MCE=y -CONFIG_X86_MCE_INTEL=y -CONFIG_X86_MCE_AMD=y +CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m +CONFIG_CRYPTO_SHA1_SSSE3=m +CONFIG_CRYPTO_BLOWFISH_X86_64=m +CONFIG_CRYPTO_TWOFISH_X86_64_3WAY=m # CONFIG_I2C_ALI1535 is not set # CONFIG_I2C_ALI1563 is not set # CONFIG_I2C_ALI15X3 is not set -CONFIG_I2C_AMD756=m -CONFIG_I2C_AMD756_S4882=m -CONFIG_I2C_AMD8111=m -CONFIG_I2C_I801=m -CONFIG_I2C_ISCH=m -CONFIG_I2C_NFORCE2_S4985=m -CONFIG_I2C_PIIX4=m # CONFIG_I2C_SIS5595 is not set # CONFIG_I2C_SIS630 is not set -CONFIG_I2C_SIS96X=m -CONFIG_I2C_VIA=m -CONFIG_I2C_VIAPRO=m - -CONFIG_DELL_RBU=m -CONFIG_DCDBAS=m - -CONFIG_NVRAM=y - -CONFIG_EDAC=y -# CONFIG_EDAC_DEBUG is not set -CONFIG_EDAC_MM_EDAC=m -CONFIG_EDAC_AMD76X=m -CONFIG_EDAC_E7XXX=m -CONFIG_EDAC_E752X=m -CONFIG_EDAC_I5000=m -CONFIG_EDAC_I5100=m -CONFIG_EDAC_I5400=m -CONFIG_EDAC_I82875P=m -CONFIG_EDAC_I82860=m -CONFIG_EDAC_I82975X=m -CONFIG_EDAC_R82600=m -CONFIG_EDAC_AMD8131=m -CONFIG_EDAC_AMD8111=m CONFIG_EDAC_AMD64=m # CONFIG_EDAC_AMD64_ERROR_INJECTION is not set -CONFIG_EDAC_DECODE_MCE=m -CONFIG_EDAC_I7CORE=m -CONFIG_EDAC_I3000=m -CONFIG_EDAC_I7300=m -CONFIG_EDAC_X38=m +CONFIG_EDAC_SBRIDGE=m -CONFIG_SCHED_MC=y - -CONFIG_TCG_INFINEON=m - -CONFIG_HW_RANDOM_INTEL=m -CONFIG_HW_RANDOM_AMD=m -CONFIG_HW_RANDOM_VIA=m - -# CONFIG_HW_RANDOM_GEODE is not set - - -CONFIG_DEBUG_STACKOVERFLOW=y -CONFIG_DEBUG_NMI_TIMEOUT=5 - -CONFIG_GPIO_SCH=m # CONFIG_PC8736x_GPIO is not set # CONFIG_DISCONTIGMEM_MANUAL is not set @@ -235,8 +65,8 @@ CONFIG_SPARSEMEM=y CONFIG_HAVE_MEMORY_PRESENT=y CONFIG_SPARSEMEM_EXTREME=y CONFIG_SPARSEMEM_VMEMMAP=y -CONFIG_MEMORY_HOTPLUG=y -CONFIG_MEMORY_HOTREMOVE=y +# CONFIG_MEMORY_HOTPLUG is not set +# CONFIG_MEMORY_HOTREMOVE is not set # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_RZ1000 is not set @@ -245,207 +75,49 @@ CONFIG_MEMORY_HOTREMOVE=y # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_CS5535 is not set -CONFIG_CC_STACKPROTECTOR=y - CONFIG_SGI_IOC4=m CONFIG_SGI_XP=m CONFIG_SGI_GRU=m # CONFIG_SGI_GRU_DEBUG is not set -# CONFIG_SMSC37B787_WDT is not set -CONFIG_W83697HF_WDT=m - # CONFIG_VIDEO_CAFE_CCIC is not set -CONFIG_MTD_ESB2ROM=m -CONFIG_MTD_CK804XROM=m - -CONFIG_RELOCATABLE=y -CONFIG_MACINTOSH_DRIVERS=y - -CONFIG_CRASH_DUMP=y -CONFIG_PHYSICAL_START=0x1000000 -CONFIG_PROC_VMCORE=y -CONFIG_CRASH=m - -CONFIG_DMIID=y -CONFIG_ISCSI_IBFT_FIND=y -CONFIG_ISCSI_IBFT=m - - -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_CPU_IDLE=y -# CONFIG_CPU_IDLE_GOV_LADDER is not set -CONFIG_CPU_IDLE_GOV_MENU=y - -CONFIG_VIRTUALIZATION=y -CONFIG_KVM=m -CONFIG_KVM_INTEL=m -CONFIG_KVM_AMD=m - -CONFIG_PARAVIRT_GUEST=y -CONFIG_PARAVIRT=y -# CONFIG_PARAVIRT_DEBUG is not set -# PARAVIRT_SPINLOCKS has a 5% perf hit -# CONFIG_PARAVIRT_SPINLOCKS is not set -CONFIG_KVM_CLOCK=y -CONFIG_KVM_GUEST=y -CONFIG_KVM_MMU_AUDIT=y - -CONFIG_XEN=y -CONFIG_XEN_MAX_DOMAIN_MEMORY=32 -CONFIG_XEN_BALLOON=y -CONFIG_XEN_SCRUB_PAGES=y -CONFIG_XEN_SAVE_RESTORE=y -CONFIG_HVC_XEN=y -CONFIG_XEN_FBDEV_FRONTEND=y -CONFIG_XEN_KBDDEV_FRONTEND=y -CONFIG_XEN_BLKDEV_FRONTEND=m -CONFIG_XEN_NETDEV_FRONTEND=m -CONFIG_XEN_PCIDEV_FRONTEND=m -CONFIG_XENFS=m -CONFIG_XEN_COMPAT_XENFS=y +CONFIG_XEN_MAX_DOMAIN_MEMORY=128 +# CONFIG_XEN_BALLOON_MEMORY_HOTPLUG is not set CONFIG_XEN_DEV_EVTCHN=m CONFIG_XEN_SYS_HYPERVISOR=y -CONFIG_XEN_BACKEND=y -CONFIG_XEN_GNTDEV=m -CONFIG_XEN_DEBUG_FS=y -CONFIG_XEN_PLATFORM_PCI=m -CONFIG_DMADEVICES=y -CONFIG_INTEL_IOATDMA=m - -CONFIG_SENSORS_I5K_AMB=m - -# CONFIG_COMPAT_VDSO is not set CONFIG_PROVIDE_OHCI1394_DMA_INIT=y -# CONFIG_DEBUG_PER_CPU_MAPS is not set -# CONFIG_CPA_DEBUG is not set - -CONFIG_HP_WATCHDOG=m -CONFIG_NV_TCO=m -CONFIG_SP5100_TCO=m CONFIG_FRAME_WARN=2048 CONFIG_NODES_SHIFT=9 -CONFIG_X86_PAT=y -# FIXME: These should be 32bit only -# CONFIG_FB_N411 is not set -CONFIG_STRICT_DEVMEM=y CONFIG_DIRECT_GBPAGES=y -# CONFIG_NO_BOOTMEM is not set - -# CONFIG_MEMTEST is not set -CONFIG_AMD_IOMMU=y -CONFIG_AMD_IOMMU_STATS=y -# CONFIG_MAXSMP is not set -CONFIG_MTRR_SANITIZER=y -CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1 -CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1 -CONFIG_SYSPROF_TRACER=y -# CONFIG_X86_VERBOSE_BOOTUP is not set -# CONFIG_MMIOTRACE_TEST is not set - CONFIG_X86_MPPARSE=y -CONFIG_BACKLIGHT_APPLE=m - -CONFIG_OPROFILE_IBS=y -CONFIG_MICROCODE_INTEL=y -CONFIG_MICROCODE_AMD=y - -# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set -CONFIG_X86_RESERVE_LOW_64K=y - -# CONFIG_CMDLINE_BOOL is not set - -CONFIG_PANASONIC_LAPTOP=m - -CONFIG_X86_PTRACE_BTS=y - CONFIG_I7300_IDLE=m -CONFIG_INTR_REMAP=y - -CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y - -CONFIG_POWER_TRACER=y -CONFIG_HW_BRANCH_TRACER=y +CONFIG_IRQ_REMAP=y CONFIG_X86_X2APIC=y CONFIG_SPARSE_IRQ=y CONFIG_RCU_FANOUT=64 -# CONFIG_IOMMU_STRESS is not set - -CONFIG_PERF_COUNTERS=y -CONFIG_PERF_EVENTS=y -CONFIG_EVENT_PROFILE=y - -# CONFIG_X86_MCE_INJECT is not set - -CONFIG_SFI=y -CONFIG_INPUT_WINBOND_CIR=m -CONFIG_I2C_SCMI=m -CONFIG_SBC_FITPC2_WATCHDOG=m -CONFIG_EDAC_I3200=m -CONFIG_TOPSTAR_LAPTOP=m CONFIG_INTEL_TXT=y + CONFIG_GPIO_LANGWELL=y CONFIG_FUNCTION_GRAPH_TRACER=y -CONFIG_ACPI_CMPC=m -CONFIG_MSI_WMI=m -CONFIG_TOSHIBA_BT_RFKILL=m -# CONFIG_SAMSUNG_LAPTOP is not set - -CONFIG_CS5535_MFGPT=m -CONFIG_GEODE_WDT=m -CONFIG_CS5535_CLOCK_EVENT_SRC=m - -CONFIG_X86_DECODER_SELFTEST=y - -CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m - -CONFIG_VGA_SWITCHEROO=y -CONFIG_LPC_SCH=m - CONFIG_I7300_IDLE=m -CONFIG_PCI_CNB20LE_QUIRK=y +CONFIG_BPF_JIT=y -CONFIG_ACPI_EC_DEBUGFS=m -# CONFIG_ACPI_APEI_ERST_DEBUG is not set -CONFIG_INTEL_IDLE=y -# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set -CONFIG_SENSORS_PKGTEMP=m -CONFIG_F71808E_WDT=m -CONFIG_HPWDT_NMI_DECODING=y -# CONFIG_MFD_TPS6586X is not set -# CONFIG_INTEL_MID_DMAC is not set -CONFIG_PCH_DMA=m -# CONFIG_ACPI_QUICKSTART is not set -CONFIG_IDEAPAD_ACPI=m -CONFIG_INTEL_IPS=m -CONFIG_IDEAPAD_LAPTOP=m -# CONFIG_IBM_RTL is not set +# Should be 32bit only, but lacks KConfig depends +# CONFIG_XO15_EBOOK is not set -CONFIG_EDAC_MCE_INJ=m -CONFIG_IRQ_TIME_ACCOUNTING=y -CONFIG_X86_RESERVE_LOW=64 - -CONFIG_PCH_GBE=m -CONFIG_PCH_PHUB=m - -CONFIG_VIDEO_VIA_CAMERA=m - -CONFIG_JUMP_LABEL=y - -CONFIG_HP_ILO=m - -CONFIG_TRANSPARENT_HUGEPAGE=y +# CONFIG_X86_NUMACHIP is not set +CONFIG_AMD_IOMMU_V2=m +CONFIG_CRYPTO_SERPENT_SSE2_X86_64=m diff --git a/disable-hid-battery.patch b/disable-hid-battery.patch new file mode 100644 index 000000000..98fe2139e --- /dev/null +++ b/disable-hid-battery.patch @@ -0,0 +1,11 @@ +--- linux-2.6.43.noarch.orig/drivers/hid/Kconfig ++++ linux-2.6.43.noarch/drivers/hid/Kconfig +@@ -34,7 +34,7 @@ config HID + config HID_BATTERY_STRENGTH + bool + depends on HID && POWER_SUPPLY && HID = POWER_SUPPLY +- default y ++ default n + + config HIDRAW + bool "/dev/hidraw raw HID device support" diff --git a/dmar-disable-when-ricoh-multifunction.patch b/dmar-disable-when-ricoh-multifunction.patch index 120730f9e..a4528617e 100644 --- a/dmar-disable-when-ricoh-multifunction.patch +++ b/dmar-disable-when-ricoh-multifunction.patch @@ -9,8 +9,8 @@ Subject: [PATCH] dmar: disable if ricoh multifunction detected diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 4789f8e..5923914 100644 ---- a/drivers/pci/intel-iommu.c -+++ b/drivers/pci/intel-iommu.c +--- a/drivers/iommu/intel-iommu.c ++++ b/drivers/iommu/intel-iommu.c @@ -3784,6 +3784,16 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_g DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt); diff --git a/drivers-media-update.patch b/drivers-media-update.patch new file mode 100644 index 000000000..f08a5d5cf --- /dev/null +++ b/drivers-media-update.patch @@ -0,0 +1,38187 @@ +Driver updates with all media stuff + +Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/az6007.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/az6007.c +@@ -0,0 +1,957 @@ ++/* ++ * Driver for AzureWave 6007 DVB-C/T USB2.0 and clones ++ * ++ * Copyright (c) Henry Wang ++ * ++ * This driver was made publicly available by Terratec, at: ++ * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz ++ * The original driver's license is GPL, as declared with MODULE_LICENSE() ++ * ++ * Copyright (c) 2010-2011 Mauro Carvalho Chehab ++ * Driver modified by in order to work with upstream drxk driver, and ++ * tons of bugs got fixed. ++ * ++ * 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 under version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include "drxk.h" ++#include "mt2063.h" ++#include "dvb_ca_en50221.h" ++ ++#define DVB_USB_LOG_PREFIX "az6007" ++#include "dvb-usb.h" ++ ++/* debug */ ++int dvb_usb_az6007_debug; ++module_param_named(debug, dvb_usb_az6007_debug, int, 0644); ++MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." ++ DVB_USB_DEBUG_STATUS); ++ ++#define deb_info(args...) dprintk(dvb_usb_az6007_debug, 0x01, args) ++#define deb_xfer(args...) dprintk(dvb_usb_az6007_debug, 0x02, args) ++#define deb_rc(args...) dprintk(dvb_usb_az6007_debug, 0x04, args) ++#define deb_fe(args...) dprintk(dvb_usb_az6007_debug, 0x08, args) ++ ++DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); ++ ++/* Known requests (Cypress FX2 firmware + az6007 "private" ones*/ ++ ++#define FX2_OED 0xb5 ++#define AZ6007_READ_DATA 0xb7 ++#define AZ6007_I2C_RD 0xb9 ++#define AZ6007_POWER 0xbc ++#define AZ6007_I2C_WR 0xbd ++#define FX2_SCON1 0xc0 ++#define AZ6007_TS_THROUGH 0xc7 ++#define AZ6007_READ_IR 0xb4 ++ ++struct az6007_device_state { ++ struct mutex mutex; ++ struct mutex ca_mutex; ++ struct dvb_ca_en50221 ca; ++ unsigned warm:1; ++ int (*gate_ctrl) (struct dvb_frontend *, int); ++ unsigned char data[4096]; ++}; ++ ++static struct drxk_config terratec_h7_drxk = { ++ .adr = 0x29, ++ .parallel_ts = true, ++ .dynamic_clk = true, ++ .single_master = true, ++ .enable_merr_cfg = true, ++ .no_i2c_bridge = false, ++ .chunk_size = 64, ++ .mpeg_out_clk_strength = 0x02, ++ .microcode_name = "dvb-usb-terratec-h7-drxk.fw", ++}; ++ ++static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) ++{ ++ struct dvb_usb_adapter *adap = fe->sec_priv; ++ struct az6007_device_state *st; ++ int status = 0; ++ ++ deb_info("%s: %s\n", __func__, enable ? "enable" : "disable"); ++ ++ if (!adap) ++ return -EINVAL; ++ ++ st = adap->dev->priv; ++ ++ if (!st) ++ return -EINVAL; ++ ++ if (enable) ++ status = st->gate_ctrl(fe, 1); ++ else ++ status = st->gate_ctrl(fe, 0); ++ ++ return status; ++} ++ ++static struct mt2063_config az6007_mt2063_config = { ++ .tuner_address = 0x60, ++ .refclock = 36125000, ++}; ++ ++static int __az6007_read(struct usb_device *udev, u8 req, u16 value, ++ u16 index, u8 *b, int blen) ++{ ++ int ret; ++ ++ ret = usb_control_msg(udev, ++ usb_rcvctrlpipe(udev, 0), ++ req, ++ USB_TYPE_VENDOR | USB_DIR_IN, ++ value, index, b, blen, 5000); ++ if (ret < 0) { ++ warn("usb read operation failed. (%d)", ret); ++ return -EIO; ++ } ++ ++ deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, ++ index); ++ debug_dump(b, blen, deb_xfer); ++ ++ return ret; ++} ++ ++static int az6007_read(struct dvb_usb_device *d, u8 req, u16 value, ++ u16 index, u8 *b, int blen) ++{ ++ struct az6007_device_state *st = d->priv; ++ int ret; ++ ++ if (mutex_lock_interruptible(&st->mutex) < 0) ++ return -EAGAIN; ++ ++ ret = __az6007_read(d->udev, req, value, index, b, blen); ++ ++ mutex_unlock(&st->mutex); ++ ++ return ret; ++} ++ ++static int __az6007_write(struct usb_device *udev, u8 req, u16 value, ++ u16 index, u8 *b, int blen) ++{ ++ int ret; ++ ++ deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, ++ index); ++ debug_dump(b, blen, deb_xfer); ++ ++ if (blen > 64) { ++ err("az6007: tried to write %d bytes, but I2C max size is 64 bytes\n", ++ blen); ++ return -EOPNOTSUPP; ++ } ++ ++ ret = usb_control_msg(udev, ++ usb_sndctrlpipe(udev, 0), ++ req, ++ USB_TYPE_VENDOR | USB_DIR_OUT, ++ value, index, b, blen, 5000); ++ if (ret != blen) { ++ err("usb write operation failed. (%d)", ret); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int az6007_write(struct dvb_usb_device *d, u8 req, u16 value, ++ u16 index, u8 *b, int blen) ++{ ++ struct az6007_device_state *st = d->priv; ++ int ret; ++ ++ if (mutex_lock_interruptible(&st->mutex) < 0) ++ return -EAGAIN; ++ ++ ret = __az6007_write(d->udev, req, value, index, b, blen); ++ ++ mutex_unlock(&st->mutex); ++ ++ return ret; ++} ++ ++static int az6007_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) ++{ ++ struct dvb_usb_device *d = adap->dev; ++ ++ deb_info("%s: %s", __func__, onoff ? "enable" : "disable"); ++ ++ return az6007_write(d, 0xbc, onoff, 0, NULL, 0); ++} ++ ++/* remote control stuff (does not work with my box) */ ++static int az6007_rc_query(struct dvb_usb_device *d) ++{ ++ struct az6007_device_state *st = d->priv; ++ unsigned code = 0; ++ ++ az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10); ++ ++ if (st->data[1] == 0x44) ++ return 0; ++ ++ if ((st->data[1] ^ st->data[2]) == 0xff) ++ code = st->data[1]; ++ else ++ code = st->data[1] << 8 | st->data[2]; ++ ++ if ((st->data[3] ^ st->data[4]) == 0xff) ++ code = code << 8 | st->data[3]; ++ else ++ code = code << 16 | st->data[3] << 8 | st->data[4]; ++ ++ rc_keydown(d->rc_dev, code, st->data[5]); ++ ++ return 0; ++} ++ ++static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, ++ int slot, ++ int address) ++{ ++ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; ++ struct az6007_device_state *state = (struct az6007_device_state *)d->priv; ++ ++ int ret; ++ u8 req; ++ u16 value; ++ u16 index; ++ int blen; ++ u8 *b; ++ ++ if (slot != 0) ++ return -EINVAL; ++ ++ b = kmalloc(12, GFP_KERNEL); ++ if (!b) ++ return -ENOMEM; ++ ++ mutex_lock(&state->ca_mutex); ++ ++ req = 0xC1; ++ value = address; ++ index = 0; ++ blen = 1; ++ ++ ret = az6007_read(d, req, value, index, b, blen); ++ if (ret < 0) { ++ warn("usb in operation failed. (%d)", ret); ++ ret = -EINVAL; ++ } else { ++ ret = b[0]; ++ } ++ ++ mutex_unlock(&state->ca_mutex); ++ kfree(b); ++ return ret; ++} ++ ++static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, ++ int slot, ++ int address, ++ u8 value) ++{ ++ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; ++ struct az6007_device_state *state = (struct az6007_device_state *)d->priv; ++ ++ int ret; ++ u8 req; ++ u16 value1; ++ u16 index; ++ int blen; ++ ++ deb_info("%s %d", __func__, slot); ++ if (slot != 0) ++ return -EINVAL; ++ ++ mutex_lock(&state->ca_mutex); ++ req = 0xC2; ++ value1 = address; ++ index = value; ++ blen = 0; ++ ++ ret = az6007_write(d, req, value1, index, NULL, blen); ++ if (ret != 0) ++ warn("usb out operation failed. (%d)", ret); ++ ++ mutex_unlock(&state->ca_mutex); ++ return ret; ++} ++ ++static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca, ++ int slot, ++ u8 address) ++{ ++ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; ++ struct az6007_device_state *state = (struct az6007_device_state *)d->priv; ++ ++ int ret; ++ u8 req; ++ u16 value; ++ u16 index; ++ int blen; ++ u8 *b; ++ ++ if (slot != 0) ++ return -EINVAL; ++ ++ b = kmalloc(12, GFP_KERNEL); ++ if (!b) ++ return -ENOMEM; ++ ++ mutex_lock(&state->ca_mutex); ++ ++ req = 0xC3; ++ value = address; ++ index = 0; ++ blen = 2; ++ ++ ret = az6007_read(d, req, value, index, b, blen); ++ if (ret < 0) { ++ warn("usb in operation failed. (%d)", ret); ++ ret = -EINVAL; ++ } else { ++ if (b[0] == 0) ++ warn("Read CI IO error"); ++ ++ ret = b[1]; ++ deb_info("read cam data = %x from 0x%x", b[1], value); ++ } ++ ++ mutex_unlock(&state->ca_mutex); ++ kfree(b); ++ return ret; ++} ++ ++static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca, ++ int slot, ++ u8 address, ++ u8 value) ++{ ++ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; ++ struct az6007_device_state *state = (struct az6007_device_state *)d->priv; ++ ++ int ret; ++ u8 req; ++ u16 value1; ++ u16 index; ++ int blen; ++ ++ if (slot != 0) ++ return -EINVAL; ++ ++ mutex_lock(&state->ca_mutex); ++ req = 0xC4; ++ value1 = address; ++ index = value; ++ blen = 0; ++ ++ ret = az6007_write(d, req, value1, index, NULL, blen); ++ if (ret != 0) { ++ warn("usb out operation failed. (%d)", ret); ++ goto failed; ++ } ++ ++failed: ++ mutex_unlock(&state->ca_mutex); ++ return ret; ++} ++ ++static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot) ++{ ++ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; ++ ++ int ret; ++ u8 req; ++ u16 value; ++ u16 index; ++ int blen; ++ u8 *b; ++ ++ b = kmalloc(12, GFP_KERNEL); ++ if (!b) ++ return -ENOMEM; ++ ++ req = 0xC8; ++ value = 0; ++ index = 0; ++ blen = 1; ++ ++ ret = az6007_read(d, req, value, index, b, blen); ++ if (ret < 0) { ++ warn("usb in operation failed. (%d)", ret); ++ ret = -EIO; ++ } else{ ++ ret = b[0]; ++ } ++ kfree(b); ++ return ret; ++} ++ ++static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) ++{ ++ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; ++ struct az6007_device_state *state = (struct az6007_device_state *)d->priv; ++ ++ int ret, i; ++ u8 req; ++ u16 value; ++ u16 index; ++ int blen; ++ ++ mutex_lock(&state->ca_mutex); ++ ++ req = 0xC6; ++ value = 1; ++ index = 0; ++ blen = 0; ++ ++ ret = az6007_write(d, req, value, index, NULL, blen); ++ if (ret != 0) { ++ warn("usb out operation failed. (%d)", ret); ++ goto failed; ++ } ++ ++ msleep(500); ++ req = 0xC6; ++ value = 0; ++ index = 0; ++ blen = 0; ++ ++ ret = az6007_write(d, req, value, index, NULL, blen); ++ if (ret != 0) { ++ warn("usb out operation failed. (%d)", ret); ++ goto failed; ++ } ++ ++ for (i = 0; i < 15; i++) { ++ msleep(100); ++ ++ if (CI_CamReady(ca, slot)) { ++ deb_info("CAM Ready"); ++ break; ++ } ++ } ++ msleep(5000); ++ ++failed: ++ mutex_unlock(&state->ca_mutex); ++ return ret; ++} ++ ++static int az6007_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) ++{ ++ return 0; ++} ++ ++static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) ++{ ++ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; ++ struct az6007_device_state *state = (struct az6007_device_state *)d->priv; ++ ++ int ret; ++ u8 req; ++ u16 value; ++ u16 index; ++ int blen; ++ ++ deb_info("%s", __func__); ++ mutex_lock(&state->ca_mutex); ++ req = 0xC7; ++ value = 1; ++ index = 0; ++ blen = 0; ++ ++ ret = az6007_write(d, req, value, index, NULL, blen); ++ if (ret != 0) { ++ warn("usb out operation failed. (%d)", ret); ++ goto failed; ++ } ++ ++failed: ++ mutex_unlock(&state->ca_mutex); ++ return ret; ++} ++ ++static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) ++{ ++ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; ++ struct az6007_device_state *state = (struct az6007_device_state *)d->priv; ++ int ret; ++ u8 req; ++ u16 value; ++ u16 index; ++ int blen; ++ u8 *b; ++ ++ b = kmalloc(12, GFP_KERNEL); ++ if (!b) ++ return -ENOMEM; ++ mutex_lock(&state->ca_mutex); ++ ++ req = 0xC5; ++ value = 0; ++ index = 0; ++ blen = 1; ++ ++ ret = az6007_read(d, req, value, index, b, blen); ++ if (ret < 0) { ++ warn("usb in operation failed. (%d)", ret); ++ ret = -EIO; ++ } else ++ ret = 0; ++ ++ if (!ret && b[0] == 1) { ++ ret = DVB_CA_EN50221_POLL_CAM_PRESENT | ++ DVB_CA_EN50221_POLL_CAM_READY; ++ } ++ ++ mutex_unlock(&state->ca_mutex); ++ kfree(b); ++ return ret; ++} ++ ++ ++static void az6007_ci_uninit(struct dvb_usb_device *d) ++{ ++ struct az6007_device_state *state; ++ ++ deb_info("%s", __func__); ++ ++ if (NULL == d) ++ return; ++ ++ state = (struct az6007_device_state *)d->priv; ++ if (NULL == state) ++ return; ++ ++ if (NULL == state->ca.data) ++ return; ++ ++ dvb_ca_en50221_release(&state->ca); ++ ++ memset(&state->ca, 0, sizeof(state->ca)); ++} ++ ++ ++static int az6007_ci_init(struct dvb_usb_adapter *a) ++{ ++ struct dvb_usb_device *d = a->dev; ++ struct az6007_device_state *state = (struct az6007_device_state *)d->priv; ++ int ret; ++ ++ deb_info("%s", __func__); ++ ++ mutex_init(&state->ca_mutex); ++ ++ state->ca.owner = THIS_MODULE; ++ state->ca.read_attribute_mem = az6007_ci_read_attribute_mem; ++ state->ca.write_attribute_mem = az6007_ci_write_attribute_mem; ++ state->ca.read_cam_control = az6007_ci_read_cam_control; ++ state->ca.write_cam_control = az6007_ci_write_cam_control; ++ state->ca.slot_reset = az6007_ci_slot_reset; ++ state->ca.slot_shutdown = az6007_ci_slot_shutdown; ++ state->ca.slot_ts_enable = az6007_ci_slot_ts_enable; ++ state->ca.poll_slot_status = az6007_ci_poll_slot_status; ++ state->ca.data = d; ++ ++ ret = dvb_ca_en50221_init(&a->dvb_adap, ++ &state->ca, ++ 0, /* flags */ ++ 1);/* n_slots */ ++ if (ret != 0) { ++ err("Cannot initialize CI: Error %d.", ret); ++ memset(&state->ca, 0, sizeof(state->ca)); ++ return ret; ++ } ++ ++ deb_info("CI initialized."); ++ ++ return 0; ++} ++ ++static int az6007_read_mac_addr(struct dvb_usb_device *d, u8 mac[6]) ++{ ++ struct az6007_device_state *st = d->priv; ++ int ret; ++ ++ ret = az6007_read(d, AZ6007_READ_DATA, 6, 0, st->data, 6); ++ memcpy(mac, st->data, sizeof(mac)); ++ ++ if (ret > 0) ++ deb_info("%s: mac is %02x:%02x:%02x:%02x:%02x:%02x\n", ++ __func__, mac[0], mac[1], mac[2], ++ mac[3], mac[4], mac[5]); ++ ++ return ret; ++} ++ ++static int az6007_frontend_attach(struct dvb_usb_adapter *adap) ++{ ++ struct az6007_device_state *st = adap->dev->priv; ++ ++ deb_info("attaching demod drxk"); ++ ++ adap->fe_adap[0].fe = dvb_attach(drxk_attach, &terratec_h7_drxk, ++ &adap->dev->i2c_adap); ++ if (!adap->fe_adap[0].fe) ++ return -EINVAL; ++ ++ adap->fe_adap[0].fe->sec_priv = adap; ++ st->gate_ctrl = adap->fe_adap[0].fe->ops.i2c_gate_ctrl; ++ adap->fe_adap[0].fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; ++ ++ az6007_ci_init(adap); ++ ++ return 0; ++} ++ ++static int az6007_tuner_attach(struct dvb_usb_adapter *adap) ++{ ++ deb_info("attaching tuner mt2063"); ++ ++ /* Attach mt2063 to DVB-C frontend */ ++ if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl) ++ adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 1); ++ if (!dvb_attach(mt2063_attach, adap->fe_adap[0].fe, ++ &az6007_mt2063_config, ++ &adap->dev->i2c_adap)) ++ return -EINVAL; ++ ++ if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl) ++ adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 0); ++ ++ return 0; ++} ++ ++int az6007_power_ctrl(struct dvb_usb_device *d, int onoff) ++{ ++ struct az6007_device_state *st = d->priv; ++ int ret; ++ ++ deb_info("%s()\n", __func__); ++ ++ if (!st->warm) { ++ mutex_init(&st->mutex); ++ ++ ret = az6007_write(d, AZ6007_POWER, 0, 2, NULL, 0); ++ if (ret < 0) ++ return ret; ++ msleep(60); ++ ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0); ++ if (ret < 0) ++ return ret; ++ msleep(100); ++ ret = az6007_write(d, AZ6007_POWER, 1, 3, NULL, 0); ++ if (ret < 0) ++ return ret; ++ msleep(20); ++ ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0); ++ if (ret < 0) ++ return ret; ++ ++ msleep(400); ++ ret = az6007_write(d, FX2_SCON1, 0, 3, NULL, 0); ++ if (ret < 0) ++ return ret; ++ msleep(150); ++ ret = az6007_write(d, FX2_SCON1, 1, 3, NULL, 0); ++ if (ret < 0) ++ return ret; ++ msleep(430); ++ ret = az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0); ++ if (ret < 0) ++ return ret; ++ ++ st->warm = true; ++ ++ return 0; ++ } ++ ++ if (!onoff) ++ return 0; ++ ++ az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0); ++ az6007_write(d, AZ6007_TS_THROUGH, 0, 0, NULL, 0); ++ ++ return 0; ++} ++ ++/* I2C */ ++static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], ++ int num) ++{ ++ struct dvb_usb_device *d = i2c_get_adapdata(adap); ++ struct az6007_device_state *st = d->priv; ++ int i, j, len; ++ int ret = 0; ++ u16 index; ++ u16 value; ++ int length; ++ u8 req, addr; ++ ++ if (mutex_lock_interruptible(&st->mutex) < 0) ++ return -EAGAIN; ++ ++ for (i = 0; i < num; i++) { ++ addr = msgs[i].addr << 1; ++ if (((i + 1) < num) ++ && (msgs[i].len == 1) ++ && (!msgs[i].flags & I2C_M_RD) ++ && (msgs[i + 1].flags & I2C_M_RD) ++ && (msgs[i].addr == msgs[i + 1].addr)) { ++ /* ++ * A write + read xfer for the same address, where ++ * the first xfer has just 1 byte length. ++ * Need to join both into one operation ++ */ ++ if (dvb_usb_az6007_debug & 2) ++ printk(KERN_DEBUG ++ "az6007 I2C xfer write+read addr=0x%x len=%d/%d: ", ++ addr, msgs[i].len, msgs[i + 1].len); ++ req = AZ6007_I2C_RD; ++ index = msgs[i].buf[0]; ++ value = addr | (1 << 8); ++ length = 6 + msgs[i + 1].len; ++ len = msgs[i + 1].len; ++ ret = __az6007_read(d->udev, req, value, index, ++ st->data, length); ++ if (ret >= len) { ++ for (j = 0; j < len; j++) { ++ msgs[i + 1].buf[j] = st->data[j + 5]; ++ if (dvb_usb_az6007_debug & 2) ++ printk(KERN_CONT ++ "0x%02x ", ++ msgs[i + 1].buf[j]); ++ } ++ } else ++ ret = -EIO; ++ i++; ++ } else if (!(msgs[i].flags & I2C_M_RD)) { ++ /* write bytes */ ++ if (dvb_usb_az6007_debug & 2) ++ printk(KERN_DEBUG ++ "az6007 I2C xfer write addr=0x%x len=%d: ", ++ addr, msgs[i].len); ++ req = AZ6007_I2C_WR; ++ index = msgs[i].buf[0]; ++ value = addr | (1 << 8); ++ length = msgs[i].len - 1; ++ len = msgs[i].len - 1; ++ if (dvb_usb_az6007_debug & 2) ++ printk(KERN_CONT "(0x%02x) ", msgs[i].buf[0]); ++ for (j = 0; j < len; j++) { ++ st->data[j] = msgs[i].buf[j + 1]; ++ if (dvb_usb_az6007_debug & 2) ++ printk(KERN_CONT "0x%02x ", ++ st->data[j]); ++ } ++ ret = __az6007_write(d->udev, req, value, index, ++ st->data, length); ++ } else { ++ /* read bytes */ ++ if (dvb_usb_az6007_debug & 2) ++ printk(KERN_DEBUG ++ "az6007 I2C xfer read addr=0x%x len=%d: ", ++ addr, msgs[i].len); ++ req = AZ6007_I2C_RD; ++ index = msgs[i].buf[0]; ++ value = addr; ++ length = msgs[i].len + 6; ++ len = msgs[i].len; ++ ret = __az6007_read(d->udev, req, value, index, ++ st->data, length); ++ for (j = 0; j < len; j++) { ++ msgs[i].buf[j] = st->data[j + 5]; ++ if (dvb_usb_az6007_debug & 2) ++ printk(KERN_CONT ++ "0x%02x ", st->data[j + 5]); ++ } ++ } ++ if (dvb_usb_az6007_debug & 2) ++ printk(KERN_CONT "\n"); ++ if (ret < 0) ++ goto err; ++ } ++err: ++ mutex_unlock(&st->mutex); ++ ++ if (ret < 0) { ++ info("%s ERROR: %i", __func__, ret); ++ return ret; ++ } ++ return num; ++} ++ ++static u32 az6007_i2c_func(struct i2c_adapter *adapter) ++{ ++ return I2C_FUNC_I2C; ++} ++ ++static struct i2c_algorithm az6007_i2c_algo = { ++ .master_xfer = az6007_i2c_xfer, ++ .functionality = az6007_i2c_func, ++}; ++ ++int az6007_identify_state(struct usb_device *udev, ++ struct dvb_usb_device_properties *props, ++ struct dvb_usb_device_description **desc, int *cold) ++{ ++ int ret; ++ u8 *mac; ++ ++ mac = kmalloc(6, GFP_ATOMIC); ++ if (!mac) ++ return -ENOMEM; ++ ++ /* Try to read the mac address */ ++ ret = __az6007_read(udev, AZ6007_READ_DATA, 6, 0, mac, 6); ++ if (ret == 6) ++ *cold = 0; ++ else ++ *cold = 1; ++ ++ kfree(mac); ++ ++ if (*cold) { ++ __az6007_write(udev, 0x09, 1, 0, NULL, 0); ++ __az6007_write(udev, 0x00, 0, 0, NULL, 0); ++ __az6007_write(udev, 0x00, 0, 0, NULL, 0); ++ } ++ ++ deb_info("Device is on %s state\n", *cold ? "warm" : "cold"); ++ return 0; ++} ++ ++static struct dvb_usb_device_properties az6007_properties; ++ ++static void az6007_usb_disconnect(struct usb_interface *intf) ++{ ++ struct dvb_usb_device *d = usb_get_intfdata(intf); ++ az6007_ci_uninit(d); ++ dvb_usb_device_exit(intf); ++} ++ ++static int az6007_usb_probe(struct usb_interface *intf, ++ const struct usb_device_id *id) ++{ ++ return dvb_usb_device_init(intf, &az6007_properties, ++ THIS_MODULE, NULL, adapter_nr); ++} ++ ++static struct usb_device_id az6007_usb_table[] = { ++ {USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007)}, ++ {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7)}, ++ {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2)}, ++ {0}, ++}; ++ ++MODULE_DEVICE_TABLE(usb, az6007_usb_table); ++ ++static struct dvb_usb_device_properties az6007_properties = { ++ .caps = DVB_USB_IS_AN_I2C_ADAPTER, ++ .usb_ctrl = CYPRESS_FX2, ++ .firmware = "dvb-usb-terratec-h7-az6007.fw", ++ .no_reconnect = 1, ++ .size_of_priv = sizeof(struct az6007_device_state), ++ .identify_state = az6007_identify_state, ++ .num_adapters = 1, ++ .adapter = { ++ { ++ .num_frontends = 1, ++ .fe = {{ ++ .streaming_ctrl = az6007_streaming_ctrl, ++ .tuner_attach = az6007_tuner_attach, ++ .frontend_attach = az6007_frontend_attach, ++ ++ /* parameter for the MPEG2-data transfer */ ++ .stream = { ++ .type = USB_BULK, ++ .count = 10, ++ .endpoint = 0x02, ++ .u = { ++ .bulk = { ++ .buffersize = 4096, ++ } ++ } ++ }, ++ } } ++ } }, ++ .power_ctrl = az6007_power_ctrl, ++ .read_mac_address = az6007_read_mac_addr, ++ ++ .rc.core = { ++ .rc_interval = 400, ++ .rc_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS, ++ .module_name = "az6007", ++ .rc_query = az6007_rc_query, ++ .allowed_protos = RC_TYPE_NEC, ++ }, ++ .i2c_algo = &az6007_i2c_algo, ++ ++ .num_device_descs = 2, ++ .devices = { ++ { .name = "AzureWave DTV StarBox DVB-T/C USB2.0 (az6007)", ++ .cold_ids = { &az6007_usb_table[0], NULL }, ++ .warm_ids = { NULL }, ++ }, ++ { .name = "TerraTec DTV StarBox DVB-T/C USB2.0 (az6007)", ++ .cold_ids = { &az6007_usb_table[1], &az6007_usb_table[2], NULL }, ++ .warm_ids = { NULL }, ++ }, ++ { NULL }, ++ } ++}; ++ ++/* usb specific object needed to register this driver with the usb subsystem */ ++static struct usb_driver az6007_usb_driver = { ++ .name = "dvb_usb_az6007", ++ .probe = az6007_usb_probe, ++ .disconnect = az6007_usb_disconnect, ++ .id_table = az6007_usb_table, ++}; ++ ++/* module stuff */ ++static int __init az6007_usb_module_init(void) ++{ ++ int result; ++ deb_info("az6007 usb module init\n"); ++ ++ result = usb_register(&az6007_usb_driver); ++ if (result) { ++ err("usb_register failed. (%d)", result); ++ return result; ++ } ++ ++ return 0; ++} ++ ++static void __exit az6007_usb_module_exit(void) ++{ ++ /* deregister this driver from the USB subsystem */ ++ deb_info("az6007 usb module exit\n"); ++ usb_deregister(&az6007_usb_driver); ++} ++ ++module_init(az6007_usb_module_init); ++module_exit(az6007_usb_module_exit); ++ ++MODULE_AUTHOR("Henry Wang "); ++MODULE_AUTHOR("Mauro Carvalho Chehab "); ++MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones"); ++MODULE_VERSION("1.1"); ++MODULE_LICENSE("GPL"); +Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/az6007.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/az6007.h +@@ -0,0 +1,18 @@ ++#ifndef _DVB_USB_AZ6007_H_ ++#define _DVB_USB_AZ6007_H_ ++ ++#define DVB_USB_LOG_PREFIX "az6007" ++#include "dvb-usb.h" ++ ++ ++extern int dvb_usb_az6007_debug; ++#define deb_info(args...) dprintk(dvb_usb_az6007_debug,0x01,args) ++#define deb_xfer(args...) dprintk(dvb_usb_az6007_debug,0x02,args) ++#define deb_rc(args...) dprintk(dvb_usb_az6007_debug,0x04,args) ++#define deb_fe(args...) dprintk(dvb_usb_az6007_debug,0x08,args) ++ ++ ++extern int vp702x_usb_out_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec); ++extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); ++ ++#endif +Index: linux-3.3.x86_64/drivers/media/common/tuners/mt2063.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/common/tuners/mt2063.c ++++ linux-3.3.x86_64/drivers/media/common/tuners/mt2063.c +@@ -350,7 +350,7 @@ static int MT2063_Sleep(struct dvb_front + /* + * ToDo: Add code here to implement a OS blocking + */ +- msleep(10); ++ msleep(100); + + return 0; + } +@@ -2226,7 +2226,7 @@ static struct dvb_tuner_ops mt2063_ops = + .info = { + .name = "MT2063 Silicon Tuner", + .frequency_min = 45000000, +- .frequency_max = 850000000, ++ .frequency_max = 865000000, + .frequency_step = 0, + }, + +Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/dvb-usb-ids.h ++++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +@@ -51,6 +51,7 @@ + #define USB_VID_PINNACLE 0x2304 + #define USB_VID_PCTV 0x2013 + #define USB_VID_PIXELVIEW 0x1554 ++#define USB_VID_REALTEK 0x0bda + #define USB_VID_TECHNOTREND 0x0b48 + #define USB_VID_TERRATEC 0x0ccd + #define USB_VID_TELESTAR 0x10b9 +@@ -75,11 +76,14 @@ + #define USB_PID_AFATECH_AF9005 0x9020 + #define USB_PID_AFATECH_AF9015_9015 0x9015 + #define USB_PID_AFATECH_AF9015_9016 0x9016 ++#define USB_PID_AFATECH_AF9035 0x9035 ++#define USB_PID_AFATECH_AF9035_2 0x1001 + #define USB_PID_TREKSTOR_DVBT 0x901b + #define USB_VID_ALINK_DTU 0xf170 + #define USB_PID_ANSONIC_DVBT_USB 0x6000 + #define USB_PID_ANYSEE 0x861f + #define USB_PID_AZUREWAVE_AD_TU700 0x3237 ++#define USB_PID_AZUREWAVE_6007 0x0ccd + #define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001 + #define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002 + #define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800 +@@ -125,6 +129,8 @@ + #define USB_PID_E3C_EC168_3 0xfffb + #define USB_PID_E3C_EC168_4 0x1001 + #define USB_PID_E3C_EC168_5 0x1002 ++#define USB_PID_FREECOM_DVBT 0x0160 ++#define USB_PID_FREECOM_DVBT_2 0x0161 + #define USB_PID_UNIWILL_STK7700P 0x6003 + #define USB_PID_GENIUS_TVGO_DVB_T03 0x4012 + #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 +@@ -148,6 +154,7 @@ + #define USB_PID_KWORLD_VSTREAM_WARM 0x17df + #define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055 + #define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2 0x0069 ++#define USB_PID_TERRATEC_CINERGY_T_STICK 0x0093 + #define USB_PID_TERRATEC_CINERGY_T_STICK_RC 0x0097 + #define USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC 0x0099 + #define USB_PID_TWINHAN_VP7041_COLD 0x3201 +@@ -217,6 +224,11 @@ + #define USB_PID_AVERMEDIA_A850T 0x850b + #define USB_PID_AVERMEDIA_A805 0xa805 + #define USB_PID_AVERMEDIA_A815M 0x815a ++#define USB_PID_AVERMEDIA_A835 0xa835 ++#define USB_PID_AVERMEDIA_B835 0xb835 ++#define USB_PID_AVERMEDIA_1867 0x1867 ++#define USB_PID_AVERMEDIA_A867 0xa867 ++#define USB_PID_AVERMEDIA_TWINSTAR 0x0825 + #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 + #define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d + #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a +@@ -226,6 +238,8 @@ + #define USB_PID_TERRATEC_CINERGY_T_EXPRESS 0x0062 + #define USB_PID_TERRATEC_CINERGY_T_XXS 0x0078 + #define USB_PID_TERRATEC_CINERGY_T_XXS_2 0x00ab ++#define USB_PID_TERRATEC_H7 0x10b4 ++#define USB_PID_TERRATEC_H7_2 0x10a3 + #define USB_PID_TERRATEC_T3 0x10a0 + #define USB_PID_TERRATEC_T5 0x10a1 + #define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e +@@ -249,6 +263,8 @@ + #define USB_PID_PCTV_400E 0x020f + #define USB_PID_PCTV_450E 0x0222 + #define USB_PID_PCTV_452E 0x021f ++#define USB_PID_REALTEK_RTL2831U 0x2831 ++#define USB_PID_REALTEK_RTL2832U 0x2832 + #define USB_PID_TECHNOTREND_CONNECT_S2_3600 0x3007 + #define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI 0x300a + #define USB_PID_NEBULA_DIGITV 0x0201 +Index: linux-3.3.x86_64/drivers/media/dvb/ddbridge/ddbridge-core.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/ddbridge/ddbridge-core.c ++++ linux-3.3.x86_64/drivers/media/dvb/ddbridge/ddbridge-core.c +@@ -578,6 +578,7 @@ static int demod_attach_drxk(struct ddb_ + struct drxk_config config; + + memset(&config, 0, sizeof(config)); ++ config.microcode_name = "drxk_a3.mc"; + config.adr = 0x29 + (input->nr & 1); + + fe = input->fe = dvb_attach(drxk_attach, &config, i2c); +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/drxk_hard.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/drxk_hard.c ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/drxk_hard.c +@@ -28,7 +28,6 @@ + #include + #include + #include +-#include + #include + + #include "dvb_frontend.h" +@@ -91,10 +90,6 @@ bool IsA1WithRomCode(struct drxk_state * + #define DRXK_MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH (0x03) + #endif + +-#ifndef DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH +-#define DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH (0x06) +-#endif +- + #define DEFAULT_DRXK_MPEG_LOCK_TIMEOUT 700 + #define DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT 500 + +@@ -650,9 +645,6 @@ static int init_state(struct drxk_state + u32 ulQual83 = DEFAULT_MER_83; + u32 ulQual93 = DEFAULT_MER_93; + +- u32 ulDVBTStaticTSClock = 1; +- u32 ulDVBCStaticTSClock = 1; +- + u32 ulMpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT; + u32 ulDemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT; + +@@ -662,7 +654,6 @@ static int init_state(struct drxk_state + u32 ulGPIOCfg = 0x0113; + u32 ulInvertTSClock = 0; + u32 ulTSDataStrength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH; +- u32 ulTSClockkStrength = DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH; + u32 ulDVBTBitrate = 50000000; + u32 ulDVBCBitrate = DRXK_QAM_SYMBOLRATE_MAX * 8; + +@@ -815,8 +806,7 @@ static int init_state(struct drxk_state + state->m_invertSTR = false; /* If TRUE; invert STR signals */ + state->m_invertVAL = false; /* If TRUE; invert VAL signals */ + state->m_invertCLK = (ulInvertTSClock != 0); /* If TRUE; invert CLK signals */ +- state->m_DVBTStaticCLK = (ulDVBTStaticTSClock != 0); +- state->m_DVBCStaticCLK = (ulDVBCStaticTSClock != 0); ++ + /* If TRUE; static MPEG clockrate will be used; + otherwise clockrate will adapt to the bitrate of the TS */ + +@@ -824,7 +814,6 @@ static int init_state(struct drxk_state + state->m_DVBCBitrate = ulDVBCBitrate; + + state->m_TSDataStrength = (ulTSDataStrength & 0x07); +- state->m_TSClockkStrength = (ulTSClockkStrength & 0x07); + + /* Maximum bitrate in b/s in case static clockrate is selected */ + state->m_mpegTsStaticBitrate = 19392658; +@@ -1189,6 +1178,7 @@ static int MPEGTSConfigurePins(struct dr + int status = -1; + u16 sioPdrMclkCfg = 0; + u16 sioPdrMdxCfg = 0; ++ u16 err_cfg = 0; + + dprintk(1, ": mpeg %s, %s mode\n", + mpegEnable ? "enable" : "disable", +@@ -1254,12 +1244,17 @@ static int MPEGTSConfigurePins(struct dr + status = write16(state, SIO_PDR_MSTRT_CFG__A, sioPdrMdxCfg); + if (status < 0) + goto error; +- status = write16(state, SIO_PDR_MERR_CFG__A, 0x0000); /* Disable */ ++ ++ if (state->enable_merr_cfg) ++ err_cfg = sioPdrMdxCfg; ++ ++ status = write16(state, SIO_PDR_MERR_CFG__A, err_cfg); + if (status < 0) + goto error; +- status = write16(state, SIO_PDR_MVAL_CFG__A, 0x0000); /* Disable */ ++ status = write16(state, SIO_PDR_MVAL_CFG__A, err_cfg); + if (status < 0) + goto error; ++ + if (state->m_enableParallel == true) { + /* paralel -> enable MD1 to MD7 */ + status = write16(state, SIO_PDR_MD1_CFG__A, sioPdrMdxCfg); +@@ -6070,9 +6065,7 @@ static int init_drxk(struct drxk_state * + if (status < 0) + goto error; + +- if (!state->microcode_name) +- load_microcode(state, "drxk_a3.mc"); +- else ++ if (state->microcode_name) + load_microcode(state, state->microcode_name); + + /* disable token-ring bus through OFDM block for possible ucode upload */ +@@ -6323,15 +6316,12 @@ static int drxk_get_tune_settings(struct + switch (p->delivery_system) { + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: ++ case SYS_DVBT: + sets->min_delay_ms = 3000; + sets->max_drift = 0; + sets->step_size = 0; + return 0; + default: +- /* +- * For DVB-T, let it use the default DVB core way, that is: +- * fepriv->step_size = fe->ops.info.frequency_stepsize * 2 +- */ + return -EINVAL; + } + } +@@ -6391,6 +6381,21 @@ struct dvb_frontend *drxk_attach(const s + state->antenna_gpio = config->antenna_gpio; + state->antenna_dvbt = config->antenna_dvbt; + state->m_ChunkSize = config->chunk_size; ++ state->enable_merr_cfg = config->enable_merr_cfg; ++ ++ if (config->dynamic_clk) { ++ state->m_DVBTStaticCLK = 0; ++ state->m_DVBCStaticCLK = 0; ++ } else { ++ state->m_DVBTStaticCLK = 1; ++ state->m_DVBCStaticCLK = 1; ++ } ++ ++ ++ if (config->mpeg_out_clk_strength) ++ state->m_TSClockkStrength = config->mpeg_out_clk_strength & 0x07; ++ else ++ state->m_TSClockkStrength = 0x06; + + if (config->parallel_ts) + state->m_enableParallel = true; +Index: linux-3.3.x86_64/drivers/media/dvb/ngene/ngene-cards.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/ngene/ngene-cards.c ++++ linux-3.3.x86_64/drivers/media/dvb/ngene/ngene-cards.c +@@ -216,6 +216,7 @@ static int demod_attach_drxk(struct ngen + struct drxk_config config; + + memset(&config, 0, sizeof(config)); ++ config.microcode_name = "drxk_a3.mc"; + config.adr = 0x29 + (chan->number ^ 2); + + chan->fe = dvb_attach(drxk_attach, &config, i2c); +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/drxk.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/drxk.h ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/drxk.h +@@ -7,15 +7,19 @@ + /** + * struct drxk_config - Configure the initial parameters for DRX-K + * +- * adr: I2C Address of the DRX-K +- * parallel_ts: true means that the device uses parallel TS, ++ * @adr: I2C Address of the DRX-K ++ * @parallel_ts: True means that the device uses parallel TS, + * Serial otherwise. +- * single_master: Device is on the single master mode +- * no_i2c_bridge: Don't switch the I2C bridge to talk with tuner +- * antenna_gpio: GPIO bit used to control the antenna +- * antenna_dvbt: GPIO bit for changing antenna to DVB-C. A value of 1 ++ * @dynamic_clk: True means that the clock will be dynamically ++ * adjusted. Static clock otherwise. ++ * @enable_merr_cfg: Enable SIO_PDR_PERR_CFG/SIO_PDR_MVAL_CFG. ++ * @single_master: Device is on the single master mode ++ * @no_i2c_bridge: Don't switch the I2C bridge to talk with tuner ++ * @antenna_gpio: GPIO bit used to control the antenna ++ * @antenna_dvbt: GPIO bit for changing antenna to DVB-C. A value of 1 + * means that 1=DVBC, 0 = DVBT. Zero means the opposite. +- * microcode_name: Name of the firmware file with the microcode ++ * @mpeg_out_clk_strength: DRXK Mpeg output clock drive strength. ++ * @microcode_name: Name of the firmware file with the microcode + * + * On the *_gpio vars, bit 0 is UIO-1, bit 1 is UIO-2 and bit 2 is + * UIO-3. +@@ -25,11 +29,14 @@ struct drxk_config { + bool single_master; + bool no_i2c_bridge; + bool parallel_ts; ++ bool dynamic_clk; ++ bool enable_merr_cfg; + + bool antenna_dvbt; + u16 antenna_gpio; + +- int chunk_size; ++ u8 mpeg_out_clk_strength; ++ int chunk_size; + + const char *microcode_name; + }; +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/drxk_hard.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/drxk_hard.h ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/drxk_hard.h +@@ -332,6 +332,7 @@ struct drxk_state { + + u16 UIO_mask; /* Bits used by UIO */ + ++ bool enable_merr_cfg; + bool single_master; + bool no_i2c_bridge; + bool antenna_dvbt; +Index: linux-3.3.x86_64/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c ++++ linux-3.3.x86_64/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c +@@ -18,6 +18,8 @@ + */ + + static struct rc_map_table nec_terratec_cinergy_xs[] = { ++ ++ /* Terratec Grey IR, with most keys in orange */ + { 0x1441, KEY_HOME}, + { 0x1401, KEY_POWER2}, + +@@ -78,6 +80,56 @@ static struct rc_map_table nec_terratec_ + { 0x144e, KEY_REWIND}, + { 0x144f, KEY_FASTFORWARD}, + { 0x145c, KEY_NEXT}, ++ ++ /* Terratec Black IR, with most keys in black */ ++ { 0x04eb01, KEY_POWER2}, ++ ++ { 0x04eb02, KEY_1}, ++ { 0x04eb03, KEY_2}, ++ { 0x04eb04, KEY_3}, ++ { 0x04eb05, KEY_4}, ++ { 0x04eb06, KEY_5}, ++ { 0x04eb07, KEY_6}, ++ { 0x04eb08, KEY_7}, ++ { 0x04eb09, KEY_8}, ++ { 0x04eb0a, KEY_9}, ++ { 0x04eb0c, KEY_0}, ++ ++ { 0x04eb0b, KEY_TEXT}, /* TXT */ ++ { 0x04eb0d, KEY_REFRESH}, /* Refresh */ ++ ++ { 0x04eb0e, KEY_HOME}, ++ { 0x04eb0f, KEY_EPG}, ++ ++ { 0x04eb10, KEY_UP}, ++ { 0x04eb11, KEY_LEFT}, ++ { 0x04eb12, KEY_OK}, ++ { 0x04eb13, KEY_RIGHT}, ++ { 0x04eb14, KEY_DOWN}, ++ ++ { 0x04eb15, KEY_BACKSPACE}, ++ { 0x04eb16, KEY_INFO}, ++ ++ { 0x04eb17, KEY_RED}, ++ { 0x04eb18, KEY_GREEN}, ++ { 0x04eb19, KEY_YELLOW}, ++ { 0x04eb1a, KEY_BLUE}, ++ ++ { 0x04eb1c, KEY_VOLUMEUP}, ++ { 0x04eb1e, KEY_VOLUMEDOWN}, ++ ++ { 0x04eb1d, KEY_MUTE}, ++ ++ { 0x04eb1b, KEY_CHANNELUP}, ++ { 0x04eb1f, KEY_CHANNELDOWN}, ++ ++ { 0x04eb40, KEY_RECORD}, ++ { 0x04eb4c, KEY_PLAY}, ++ { 0x04eb58, KEY_PAUSE}, ++ ++ { 0x04eb54, KEY_REWIND}, ++ { 0x04eb48, KEY_STOP}, ++ { 0x04eb5c, KEY_NEXT}, + }; + + static struct rc_map_list nec_terratec_cinergy_xs_map = { +Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/Kconfig +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/Kconfig ++++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/Kconfig +@@ -361,6 +361,14 @@ config DVB_USB_EC168 + help + Say Y here to support the E3C EC168 DVB-T USB2.0 receiver. + ++config DVB_USB_AZ6007 ++ tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support" ++ depends on DVB_USB ++ select DVB_DRXK if !DVB_FE_CUSTOMISE ++ select MEDIA_TUNER_MT2063 if !DVB_FE_CUSTOMISE ++ help ++ Say Y here to support theAfatech AF9005 based DVB-T/DVB-C receivers. ++ + config DVB_USB_AZ6027 + tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support" + depends on DVB_USB +@@ -378,6 +386,7 @@ config DVB_USB_LME2510 + select DVB_IX2505V if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_PLL if !DVB_FE_CUSTOMISE ++ select DVB_M88RS2000 if !DVB_FE_CUSTOMISE + help + Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 . + +@@ -403,3 +412,25 @@ config DVB_USB_MXL111SF + select VIDEO_TVEEPROM + help + Say Y here to support the MxL111SF USB2.0 DTV receiver. ++ ++config DVB_USB_RTL28XXU ++ tristate "Realtek RTL28xxU DVB USB support" ++ depends on DVB_USB && EXPERIMENTAL ++ select DVB_RTL2830 ++ select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE ++ select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE ++ select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE ++ help ++ Say Y here to support the Realtek RTL28xxU DVB USB receiver. ++ ++config DVB_USB_AF9035 ++ tristate "Afatech AF9035 DVB-T USB2.0 support" ++ depends on DVB_USB ++ select DVB_AF9033 ++ select MEDIA_TUNER_TUA9001 if !MEDIA_TUNER_CUSTOMISE ++ select MEDIA_TUNER_FC0011 if !MEDIA_TUNER_CUSTOMISE ++ select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE ++ select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE ++ help ++ Say Y here to support the Afatech AF9035 based DVB USB receiver. ++ +Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/Makefile +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/Makefile ++++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/Makefile +@@ -54,7 +54,6 @@ obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb + dvb-usb-opera-objs = opera1.o + obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o + +- + dvb-usb-af9005-objs = af9005.o af9005-fe.o + obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o + +@@ -88,6 +87,9 @@ obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-f + dvb-usb-ec168-objs = ec168.o + obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o + ++dvb-usb-az6007-objs = az6007.o ++obj-$(CONFIG_DVB_USB_AZ6007) += dvb-usb-az6007.o ++ + dvb-usb-az6027-objs = az6027.o + obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o + +@@ -105,8 +107,15 @@ obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-us + obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o + obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o + +-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ ++dvb-usb-rtl28xxu-objs = rtl28xxu.o ++obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o ++ ++dvb-usb-af9035-objs = af9035.o ++obj-$(CONFIG_DVB_USB_AF9035) += dvb-usb-af9035.o ++ ++ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core ++ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/ + # due to tuner-xc3028 +-ccflags-y += -Idrivers/media/common/tuners +-EXTRA_CFLAGS += -Idrivers/media/dvb/ttpci ++ccflags-y += -I$(srctree)/drivers/media/common/tuners ++ccflags-y += -I$(srctree)/drivers/media/dvb/ttpci + +Index: linux-3.3.x86_64/drivers/media/video/omap/omap_vout.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/omap/omap_vout.c ++++ linux-3.3.x86_64/drivers/media/video/omap/omap_vout.c +@@ -2268,13 +2268,12 @@ static struct platform_driver omap_vout_ + .driver = { + .name = VOUT_NAME, + }, +- .probe = omap_vout_probe, + .remove = omap_vout_remove, + }; + + static int __init omap_vout_init(void) + { +- if (platform_driver_register(&omap_vout_driver) != 0) { ++ if (platform_driver_probe(&omap_vout_driver, omap_vout_probe) != 0) { + printk(KERN_ERR VOUT_NAME ":Could not register Video driver\n"); + return -EINVAL; + } +Index: linux-3.3.x86_64/Documentation/DocBook/media/v4l/compat.xml +=================================================================== +--- linux-3.3.x86_64.orig/Documentation/DocBook/media/v4l/compat.xml ++++ linux-3.3.x86_64/Documentation/DocBook/media/v4l/compat.xml +@@ -2393,6 +2393,10 @@ details. + to the User controls class. + + ++ ++ Added the device_caps field to struct v4l2_capabilities and added the new ++ V4L2_CAP_DEVICE_CAPS capability. ++ + + + +Index: linux-3.3.x86_64/Documentation/DocBook/media/v4l/v4l2.xml +=================================================================== +--- linux-3.3.x86_64.orig/Documentation/DocBook/media/v4l/v4l2.xml ++++ linux-3.3.x86_64/Documentation/DocBook/media/v4l/v4l2.xml +@@ -128,6 +128,13 @@ structs, ioctls) must be noted in more d + applications. --> + + ++ 3.3 ++ 2012-01-11 ++ hv ++ Added device_caps field to struct v4l2_capabilities. ++ ++ ++ + 3.2 + 2011-08-26 + hv +@@ -417,7 +424,7 @@ and discussions on the V4L mailing list. + + + Video for Linux Two API Specification +- Revision 3.2 ++ Revision 3.3 + + + &sub-common; +Index: linux-3.3.x86_64/Documentation/DocBook/media/v4l/vidioc-querycap.xml +=================================================================== +--- linux-3.3.x86_64.orig/Documentation/DocBook/media/v4l/vidioc-querycap.xml ++++ linux-3.3.x86_64/Documentation/DocBook/media/v4l/vidioc-querycap.xml +@@ -124,12 +124,35 @@ printf ("Version: %u.%u.%u\n", + + __u32 + capabilities +- Device capabilities, see . ++ Available capabilities of the physical device as a whole, see . The same physical device can export ++ multiple devices in /dev (e.g. /dev/videoX, /dev/vbiY and /dev/radioZ). ++ The capabilities field should contain a union ++ of all capabilities available around the several V4L2 devices exported ++ to userspace. ++ For all those devices the capabilities field ++ returns the same set of capabilities. This allows applications to open ++ just one of the devices (typically the video device) and discover whether ++ video, vbi and/or radio are also supported. ++ + + + __u32 +- reserved[4] ++ device_caps ++ Device capabilities of the opened device, see . Should contain the available capabilities ++ of that specific device node. So, for example, device_caps ++ of a radio device will only contain radio related capabilities and ++ no video or vbi capabilities. This field is only set if the capabilities ++ field contains the V4L2_CAP_DEVICE_CAPS capability. ++ Only the capabilities field can have the ++ V4L2_CAP_DEVICE_CAPS capability, device_caps ++ will never set V4L2_CAP_DEVICE_CAPS. ++ ++ ++ ++ __u32 ++ reserved[3] + Reserved for future extensions. Drivers must set + this array to zero. + +@@ -276,6 +299,13 @@ linkend="async">asynchronous I/O + The device supports the streaming I/O method. + ++ ++ V4L2_CAP_DEVICE_CAPS ++ 0x80000000 ++ The driver fills the device_caps ++ field. This capability can only appear in the capabilities ++ field and never in the device_caps field. ++ + + + +Index: linux-3.3.x86_64/drivers/media/video/cx231xx/cx231xx-417.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/cx231xx/cx231xx-417.c ++++ linux-3.3.x86_64/drivers/media/video/cx231xx/cx231xx-417.c +@@ -1686,7 +1686,6 @@ static struct v4l2_capability pvr_capabi + .capabilities = (V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE), +- .reserved = {0, 0, 0, 0} + }; + static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +Index: linux-3.3.x86_64/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/pvrusb2/pvrusb2-v4l2.c ++++ linux-3.3.x86_64/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +@@ -96,7 +96,6 @@ static struct v4l2_capability pvr_capabi + .capabilities = (V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | + V4L2_CAP_READWRITE), +- .reserved = {0,0,0,0} + }; + + static struct v4l2_fmtdesc pvr_fmtdesc [] = { +Index: linux-3.3.x86_64/drivers/media/video/v4l2-ioctl.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/v4l2-ioctl.c ++++ linux-3.3.x86_64/drivers/media/video/v4l2-ioctl.c +@@ -260,6 +260,8 @@ static const char *v4l2_ioctls[] = { + [_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD", + [_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD", + ++ [_IOC_NR(VIDIOC_DECODER_CMD)] = "VIDIOC_DECODER_CMD", ++ [_IOC_NR(VIDIOC_TRY_DECODER_CMD)] = "VIDIOC_TRY_DECODER_CMD", + [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", + [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", + +@@ -540,10 +542,12 @@ static long __video_do_ioctl(struct file + if (!ret) + dbgarg(cmd, "driver=%s, card=%s, bus=%s, " + "version=0x%08x, " +- "capabilities=0x%08x\n", ++ "capabilities=0x%08x, " ++ "device_caps=0x%08x\n", + cap->driver, cap->card, cap->bus_info, + cap->version, +- cap->capabilities); ++ cap->capabilities, ++ cap->device_caps); + break; + } + +@@ -1762,6 +1766,32 @@ static long __video_do_ioctl(struct file + dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); + break; + } ++ case VIDIOC_DECODER_CMD: ++ { ++ struct v4l2_decoder_cmd *p = arg; ++ ++ if (!ops->vidioc_decoder_cmd) ++ break; ++ if (ret_prio) { ++ ret = ret_prio; ++ break; ++ } ++ ret = ops->vidioc_decoder_cmd(file, fh, p); ++ if (!ret) ++ dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); ++ break; ++ } ++ case VIDIOC_TRY_DECODER_CMD: ++ { ++ struct v4l2_decoder_cmd *p = arg; ++ ++ if (!ops->vidioc_try_decoder_cmd) ++ break; ++ ret = ops->vidioc_try_decoder_cmd(file, fh, p); ++ if (!ret) ++ dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); ++ break; ++ } + case VIDIOC_G_PARM: + { + struct v4l2_streamparm *p = arg; +@@ -1909,7 +1939,13 @@ static long __video_do_ioctl(struct file + { + if (!ops->vidioc_log_status) + break; ++ if (vfd->v4l2_dev) ++ pr_info("%s: ================= START STATUS =================\n", ++ vfd->v4l2_dev->name); + ret = ops->vidioc_log_status(file, fh); ++ if (vfd->v4l2_dev) ++ pr_info("%s: ================== END STATUS ==================\n", ++ vfd->v4l2_dev->name); + break; + } + #ifdef CONFIG_VIDEO_ADV_DEBUG +@@ -2419,7 +2455,7 @@ video_usercopy(struct file *file, unsign + /* Handles IOCTL */ + err = func(file, cmd, parg); + if (err == -ENOIOCTLCMD) +- err = -EINVAL; ++ err = -ENOTTY; + + if (has_array_args) { + *kernel_ptr = user_ptr; +Index: linux-3.3.x86_64/include/linux/videodev2.h +=================================================================== +--- linux-3.3.x86_64.orig/include/linux/videodev2.h ++++ linux-3.3.x86_64/include/linux/videodev2.h +@@ -235,16 +235,25 @@ struct v4l2_fract { + __u32 denominator; + }; + +-/* +- * D R I V E R C A P A B I L I T I E S +- */ ++/** ++ * struct v4l2_capability - Describes V4L2 device caps returned by VIDIOC_QUERYCAP ++ * ++ * @driver: name of the driver module (e.g. "bttv") ++ * @card: name of the card (e.g. "Hauppauge WinTV") ++ * @bus_info: name of the bus (e.g. "PCI:" + pci_name(pci_dev) ) ++ * @version: KERNEL_VERSION ++ * @capabilities: capabilities of the physical device as a whole ++ * @device_caps: capabilities accessed via this particular device (node) ++ * @reserved: reserved fields for future extensions ++ */ + struct v4l2_capability { +- __u8 driver[16]; /* i.e. "bttv" */ +- __u8 card[32]; /* i.e. "Hauppauge WinTV" */ +- __u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */ +- __u32 version; /* should use KERNEL_VERSION() */ +- __u32 capabilities; /* Device capabilities */ +- __u32 reserved[4]; ++ __u8 driver[16]; ++ __u8 card[32]; ++ __u8 bus_info[32]; ++ __u32 version; ++ __u32 capabilities; ++ __u32 device_caps; ++ __u32 reserved[3]; + }; + + /* Values for 'capabilities' field */ +@@ -274,6 +283,8 @@ struct v4l2_capability { + #define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */ + #define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */ + ++#define V4L2_CAP_DEVICE_CAPS 0x80000000 /* sets device capabilities field */ ++ + /* + * V I D E O I M A G E F O R M A T + */ +@@ -751,20 +762,20 @@ struct v4l2_crop { + + /* Selection targets */ + +-/* current cropping area */ +-#define V4L2_SEL_TGT_CROP_ACTIVE 0 +-/* default cropping area */ +-#define V4L2_SEL_TGT_CROP_DEFAULT 1 +-/* cropping bounds */ +-#define V4L2_SEL_TGT_CROP_BOUNDS 2 +-/* current composing area */ +-#define V4L2_SEL_TGT_COMPOSE_ACTIVE 256 +-/* default composing area */ +-#define V4L2_SEL_TGT_COMPOSE_DEFAULT 257 +-/* composing bounds */ +-#define V4L2_SEL_TGT_COMPOSE_BOUNDS 258 +-/* current composing area plus all padding pixels */ +-#define V4L2_SEL_TGT_COMPOSE_PADDED 259 ++/* Current cropping area */ ++#define V4L2_SEL_TGT_CROP_ACTIVE 0x0000 ++/* Default cropping area */ ++#define V4L2_SEL_TGT_CROP_DEFAULT 0x0001 ++/* Cropping bounds */ ++#define V4L2_SEL_TGT_CROP_BOUNDS 0x0002 ++/* Current composing area */ ++#define V4L2_SEL_TGT_COMPOSE_ACTIVE 0x0100 ++/* Default composing area */ ++#define V4L2_SEL_TGT_COMPOSE_DEFAULT 0x0101 ++/* Composing bounds */ ++#define V4L2_SEL_TGT_COMPOSE_BOUNDS 0x0102 ++/* Current composing area plus all padding pixels */ ++#define V4L2_SEL_TGT_COMPOSE_PADDED 0x0103 + + /** + * struct v4l2_selection - selection info +@@ -774,7 +785,7 @@ struct v4l2_crop { + * @r: coordinates of selection window + * @reserved: for future use, rounds structure size to 64 bytes, set to zero + * +- * Hardware may use multiple helper window to process a video stream. ++ * Hardware may use multiple helper windows to process a video stream. + * The structure is used to exchange this selection areas between + * an application and a driver. + */ +@@ -1125,6 +1136,7 @@ struct v4l2_ext_controls { + #define V4L2_CTRL_CLASS_CAMERA 0x009a0000 /* Camera class controls */ + #define V4L2_CTRL_CLASS_FM_TX 0x009b0000 /* FM Modulator control class */ + #define V4L2_CTRL_CLASS_FLASH 0x009c0000 /* Camera flash controls */ ++#define V4L2_CTRL_CLASS_JPEG 0x009d0000 /* JPEG-compression controls */ + + #define V4L2_CTRL_ID_MASK (0x0fffffff) + #define V4L2_CTRL_ID2CLASS(id) ((id) & 0x0fff0000UL) +@@ -1396,6 +1408,16 @@ enum v4l2_mpeg_audio_ac3_bitrate { + V4L2_MPEG_AUDIO_AC3_BITRATE_576K = 17, + V4L2_MPEG_AUDIO_AC3_BITRATE_640K = 18, + }; ++#define V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK (V4L2_CID_MPEG_BASE+112) ++enum v4l2_mpeg_audio_dec_playback { ++ V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO = 0, ++ V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO = 1, ++ V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT = 2, ++ V4L2_MPEG_AUDIO_DEC_PLAYBACK_RIGHT = 3, ++ V4L2_MPEG_AUDIO_DEC_PLAYBACK_MONO = 4, ++ V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO = 5, ++}; ++#define V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK (V4L2_CID_MPEG_BASE+113) + + /* MPEG video controls specific to multiplexed streams */ + #define V4L2_CID_MPEG_VIDEO_ENCODING (V4L2_CID_MPEG_BASE+200) +@@ -1446,6 +1468,9 @@ enum v4l2_mpeg_video_multi_slice_mode { + V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES = 2, + }; + #define V4L2_CID_MPEG_VIDEO_VBV_SIZE (V4L2_CID_MPEG_BASE+222) ++#define V4L2_CID_MPEG_VIDEO_DEC_PTS (V4L2_CID_MPEG_BASE+223) ++#define V4L2_CID_MPEG_VIDEO_DEC_FRAME (V4L2_CID_MPEG_BASE+224) ++ + #define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP (V4L2_CID_MPEG_BASE+300) + #define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP (V4L2_CID_MPEG_BASE+301) + #define V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP (V4L2_CID_MPEG_BASE+302) +@@ -1734,6 +1759,29 @@ enum v4l2_flash_strobe_source { + #define V4L2_CID_FLASH_CHARGE (V4L2_CID_FLASH_CLASS_BASE + 11) + #define V4L2_CID_FLASH_READY (V4L2_CID_FLASH_CLASS_BASE + 12) + ++/* JPEG-class control IDs defined by V4L2 */ ++#define V4L2_CID_JPEG_CLASS_BASE (V4L2_CTRL_CLASS_JPEG | 0x900) ++#define V4L2_CID_JPEG_CLASS (V4L2_CTRL_CLASS_JPEG | 1) ++ ++#define V4L2_CID_JPEG_CHROMA_SUBSAMPLING (V4L2_CID_JPEG_CLASS_BASE + 1) ++enum v4l2_jpeg_chroma_subsampling { ++ V4L2_JPEG_CHROMA_SUBSAMPLING_444 = 0, ++ V4L2_JPEG_CHROMA_SUBSAMPLING_422 = 1, ++ V4L2_JPEG_CHROMA_SUBSAMPLING_420 = 2, ++ V4L2_JPEG_CHROMA_SUBSAMPLING_411 = 3, ++ V4L2_JPEG_CHROMA_SUBSAMPLING_410 = 4, ++ V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY = 5, ++}; ++#define V4L2_CID_JPEG_RESTART_INTERVAL (V4L2_CID_JPEG_CLASS_BASE + 2) ++#define V4L2_CID_JPEG_COMPRESSION_QUALITY (V4L2_CID_JPEG_CLASS_BASE + 3) ++ ++#define V4L2_CID_JPEG_ACTIVE_MARKER (V4L2_CID_JPEG_CLASS_BASE + 4) ++#define V4L2_JPEG_ACTIVE_MARKER_APP0 (1 << 0) ++#define V4L2_JPEG_ACTIVE_MARKER_APP1 (1 << 1) ++#define V4L2_JPEG_ACTIVE_MARKER_COM (1 << 16) ++#define V4L2_JPEG_ACTIVE_MARKER_DQT (1 << 17) ++#define V4L2_JPEG_ACTIVE_MARKER_DHT (1 << 18) ++ + /* + * T U N I N G + */ +@@ -1897,6 +1945,54 @@ struct v4l2_encoder_cmd { + }; + }; + ++/* Decoder commands */ ++#define V4L2_DEC_CMD_START (0) ++#define V4L2_DEC_CMD_STOP (1) ++#define V4L2_DEC_CMD_PAUSE (2) ++#define V4L2_DEC_CMD_RESUME (3) ++ ++/* Flags for V4L2_DEC_CMD_START */ ++#define V4L2_DEC_CMD_START_MUTE_AUDIO (1 << 0) ++ ++/* Flags for V4L2_DEC_CMD_PAUSE */ ++#define V4L2_DEC_CMD_PAUSE_TO_BLACK (1 << 0) ++ ++/* Flags for V4L2_DEC_CMD_STOP */ ++#define V4L2_DEC_CMD_STOP_TO_BLACK (1 << 0) ++#define V4L2_DEC_CMD_STOP_IMMEDIATELY (1 << 1) ++ ++/* Play format requirements (returned by the driver): */ ++ ++/* The decoder has no special format requirements */ ++#define V4L2_DEC_START_FMT_NONE (0) ++/* The decoder requires full GOPs */ ++#define V4L2_DEC_START_FMT_GOP (1) ++ ++/* The structure must be zeroed before use by the application ++ This ensures it can be extended safely in the future. */ ++struct v4l2_decoder_cmd { ++ __u32 cmd; ++ __u32 flags; ++ union { ++ struct { ++ __u64 pts; ++ } stop; ++ ++ struct { ++ /* 0 or 1000 specifies normal speed, ++ 1 specifies forward single stepping, ++ -1 specifies backward single stepping, ++ >1: playback at speed/1000 of the normal speed, ++ <-1: reverse playback at (-speed/1000) of the normal speed. */ ++ __s32 speed; ++ __u32 format; ++ } start; ++ ++ struct { ++ __u32 data[16]; ++ } raw; ++ }; ++}; + #endif + + +@@ -2307,6 +2403,11 @@ struct v4l2_create_buffers { + #define VIDIOC_G_SELECTION _IOWR('V', 94, struct v4l2_selection) + #define VIDIOC_S_SELECTION _IOWR('V', 95, struct v4l2_selection) + ++/* Experimental, these two ioctls may change over the next couple of kernel ++ versions. */ ++#define VIDIOC_DECODER_CMD _IOWR('V', 96, struct v4l2_decoder_cmd) ++#define VIDIOC_TRY_DECODER_CMD _IOWR('V', 97, struct v4l2_decoder_cmd) ++ + /* Reminder: when adding new ioctls please add support for them to + drivers/media/video/v4l2-compat-ioctl32.c as well! */ + +Index: linux-3.3.x86_64/drivers/media/video/vivi.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/vivi.c ++++ linux-3.3.x86_64/drivers/media/video/vivi.c +@@ -819,8 +819,9 @@ static int vidioc_querycap(struct file * + strcpy(cap->driver, "vivi"); + strcpy(cap->card, "vivi"); + strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info)); +- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \ ++ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; ++ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; + } + +@@ -958,14 +959,6 @@ static int vidioc_streamoff(struct file + return vb2_streamoff(&dev->vb_vidq, i); + } + +-static int vidioc_log_status(struct file *file, void *priv) +-{ +- struct vivi_dev *dev = video_drvdata(file); +- +- v4l2_ctrl_handler_log_status(&dev->ctrl_handler, dev->v4l2_dev.name); +- return 0; +-} +- + static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) + { + return 0; +@@ -1008,17 +1001,6 @@ static int vidioc_s_input(struct file *f + return 0; + } + +-static int vidioc_subscribe_event(struct v4l2_fh *fh, +- struct v4l2_event_subscription *sub) +-{ +- switch (sub->type) { +- case V4L2_EVENT_CTRL: +- return v4l2_event_subscribe(fh, sub, 0); +- default: +- return -EINVAL; +- } +-} +- + /* --- controls ---------------------------------------------- */ + + static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +@@ -1057,17 +1039,10 @@ static unsigned int + vivi_poll(struct file *file, struct poll_table_struct *wait) + { + struct vivi_dev *dev = video_drvdata(file); +- struct v4l2_fh *fh = file->private_data; + struct vb2_queue *q = &dev->vb_vidq; +- unsigned int res; + + dprintk(dev, 1, "%s\n", __func__); +- res = vb2_poll(q, file, wait); +- if (v4l2_event_pending(fh)) +- res |= POLLPRI; +- else +- poll_wait(file, &fh->wait, wait); +- return res; ++ return vb2_poll(q, file, wait); + } + + static int vivi_close(struct file *file) +@@ -1209,8 +1184,8 @@ static const struct v4l2_ioctl_ops vivi_ + .vidioc_s_input = vidioc_s_input, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, +- .vidioc_log_status = vidioc_log_status, +- .vidioc_subscribe_event = vidioc_subscribe_event, ++ .vidioc_log_status = v4l2_ctrl_log_status, ++ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + }; + +Index: linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-driver.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ivtv/ivtv-driver.h ++++ linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-driver.h +@@ -331,6 +331,7 @@ struct ivtv_stream { + struct ivtv *itv; /* for ease of use */ + const char *name; /* name of the stream */ + int type; /* stream type */ ++ u32 caps; /* V4L2 capabilities */ + + struct v4l2_fh *fh; /* pointer to the streaming filehandle */ + spinlock_t qlock; /* locks access to the queues */ +@@ -630,6 +631,16 @@ struct ivtv { + + struct v4l2_device v4l2_dev; + struct cx2341x_handler cxhdl; ++ struct { ++ /* PTS/Frame count control cluster */ ++ struct v4l2_ctrl *ctrl_pts; ++ struct v4l2_ctrl *ctrl_frame; ++ }; ++ struct { ++ /* Audio Playback control cluster */ ++ struct v4l2_ctrl *ctrl_audio_playback; ++ struct v4l2_ctrl *ctrl_audio_multilingual_playback; ++ }; + struct v4l2_ctrl_handler hdl_gpio; + struct v4l2_subdev sd_gpio; /* GPIO sub-device */ + u16 instance; +@@ -649,7 +660,6 @@ struct ivtv { + u8 audio_stereo_mode; /* decoder setting how to handle stereo MPEG audio */ + u8 audio_bilingual_mode; /* decoder setting how to handle bilingual MPEG audio */ + +- + /* Locking */ + spinlock_t lock; /* lock access to this struct */ + struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */ +Index: linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-ioctl.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ivtv/ivtv-ioctl.c ++++ linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-ioctl.c +@@ -246,34 +246,40 @@ static int ivtv_validate_speed(int cur_s + } + + static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id, +- struct video_command *vc, int try) ++ struct v4l2_decoder_cmd *dc, int try) + { + struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; + +- switch (vc->cmd) { +- case VIDEO_CMD_PLAY: { +- vc->flags = 0; +- vc->play.speed = ivtv_validate_speed(itv->speed, vc->play.speed); +- if (vc->play.speed < 0) +- vc->play.format = VIDEO_PLAY_FMT_GOP; ++ switch (dc->cmd) { ++ case V4L2_DEC_CMD_START: { ++ dc->flags &= V4L2_DEC_CMD_START_MUTE_AUDIO; ++ dc->start.speed = ivtv_validate_speed(itv->speed, dc->start.speed); ++ if (dc->start.speed < 0) ++ dc->start.format = V4L2_DEC_START_FMT_GOP; ++ else ++ dc->start.format = V4L2_DEC_START_FMT_NONE; ++ if (dc->start.speed != 500 && dc->start.speed != 1500) ++ dc->flags = dc->start.speed == 1000 ? 0 : ++ V4L2_DEC_CMD_START_MUTE_AUDIO; + if (try) break; + ++ itv->speed_mute_audio = dc->flags & V4L2_DEC_CMD_START_MUTE_AUDIO; + if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG) + return -EBUSY; + if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) { + /* forces ivtv_set_speed to be called */ + itv->speed = 0; + } +- return ivtv_start_decoding(id, vc->play.speed); ++ return ivtv_start_decoding(id, dc->start.speed); + } + +- case VIDEO_CMD_STOP: +- vc->flags &= VIDEO_CMD_STOP_IMMEDIATELY|VIDEO_CMD_STOP_TO_BLACK; +- if (vc->flags & VIDEO_CMD_STOP_IMMEDIATELY) +- vc->stop.pts = 0; ++ case V4L2_DEC_CMD_STOP: ++ dc->flags &= V4L2_DEC_CMD_STOP_IMMEDIATELY | V4L2_DEC_CMD_STOP_TO_BLACK; ++ if (dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) ++ dc->stop.pts = 0; + if (try) break; + if (atomic_read(&itv->decoding) == 0) + return 0; +@@ -281,22 +287,22 @@ static int ivtv_video_command(struct ivt + return -EBUSY; + + itv->output_mode = OUT_NONE; +- return ivtv_stop_v4l2_decode_stream(s, vc->flags, vc->stop.pts); ++ return ivtv_stop_v4l2_decode_stream(s, dc->flags, dc->stop.pts); + +- case VIDEO_CMD_FREEZE: +- vc->flags &= VIDEO_CMD_FREEZE_TO_BLACK; ++ case V4L2_DEC_CMD_PAUSE: ++ dc->flags &= V4L2_DEC_CMD_PAUSE_TO_BLACK; + if (try) break; + if (itv->output_mode != OUT_MPG) + return -EBUSY; + if (atomic_read(&itv->decoding) > 0) { + ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, +- (vc->flags & VIDEO_CMD_FREEZE_TO_BLACK) ? 1 : 0); ++ (dc->flags & V4L2_DEC_CMD_PAUSE_TO_BLACK) ? 1 : 0); + set_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags); + } + break; + +- case VIDEO_CMD_CONTINUE: +- vc->flags = 0; ++ case V4L2_DEC_CMD_RESUME: ++ dc->flags = 0; + if (try) break; + if (itv->output_mode != OUT_MPG) + return -EBUSY; +@@ -754,12 +760,15 @@ static int ivtv_s_register(struct file * + + static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) + { +- struct ivtv *itv = fh2id(fh)->itv; ++ struct ivtv_open_id *id = fh2id(file->private_data); ++ struct ivtv *itv = id->itv; ++ struct ivtv_stream *s = &itv->streams[id->type]; + + strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); + strlcpy(vcap->card, itv->card_name, sizeof(vcap->card)); + snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev)); +- vcap->capabilities = itv->v4l2_cap; /* capabilities */ ++ vcap->capabilities = itv->v4l2_cap | V4L2_CAP_DEVICE_CAPS; ++ vcap->device_caps = s->caps; + return 0; + } + +@@ -1476,8 +1485,6 @@ static int ivtv_log_status(struct file * + struct v4l2_audio audin; + int i; + +- IVTV_INFO("================= START STATUS CARD #%d =================\n", +- itv->instance); + IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name); + if (itv->hw_flags & IVTV_HW_TVEEPROM) { + struct tveeprom tv; +@@ -1501,13 +1508,6 @@ static int ivtv_log_status(struct file * + "YUV Frames", + "Passthrough", + }; +- static const char * const audio_modes[5] = { +- "Stereo", +- "Left", +- "Right", +- "Mono", +- "Swapped" +- }; + static const char * const alpha_mode[4] = { + "None", + "Global", +@@ -1536,9 +1536,6 @@ static int ivtv_log_status(struct file * + ivtv_get_output(itv, itv->active_output, &vidout); + ivtv_get_audio_output(itv, 0, &audout); + IVTV_INFO("Video Output: %s\n", vidout.name); +- IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name, +- audio_modes[itv->audio_stereo_mode], +- audio_modes[itv->audio_bilingual_mode]); + if (mode < 0 || mode > OUT_PASSTHROUGH) + mode = OUT_NONE; + IVTV_INFO("Output Mode: %s\n", output_modes[mode]); +@@ -1566,12 +1563,27 @@ static int ivtv_log_status(struct file * + IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", + (long long)itv->mpg_data_received, + (long long)itv->vbi_data_inserted); +- IVTV_INFO("================== END STATUS CARD #%d ==================\n", +- itv->instance); +- + return 0; + } + ++static int ivtv_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec) ++{ ++ struct ivtv_open_id *id = fh2id(file->private_data); ++ struct ivtv *itv = id->itv; ++ ++ IVTV_DEBUG_IOCTL("VIDIOC_DECODER_CMD %d\n", dec->cmd); ++ return ivtv_video_command(itv, id, dec, false); ++} ++ ++static int ivtv_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec) ++{ ++ struct ivtv_open_id *id = fh2id(file->private_data); ++ struct ivtv *itv = id->itv; ++ ++ IVTV_DEBUG_IOCTL("VIDIOC_TRY_DECODER_CMD %d\n", dec->cmd); ++ return ivtv_video_command(itv, id, dec, true); ++} ++ + static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) + { + struct ivtv_open_id *id = fh2id(filp->private_data); +@@ -1605,9 +1617,15 @@ static int ivtv_decoder_ioctls(struct fi + return ivtv_yuv_prep_frame(itv, args); + } + ++ case IVTV_IOC_PASSTHROUGH_MODE: ++ IVTV_DEBUG_IOCTL("IVTV_IOC_PASSTHROUGH_MODE\n"); ++ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) ++ return -EINVAL; ++ return ivtv_passthrough_mode(itv, *(int *)arg != 0); ++ + case VIDEO_GET_PTS: { +- u32 data[CX2341X_MBOX_MAX_DATA]; +- u64 *pts = arg; ++ s64 *pts = arg; ++ s64 frame; + + IVTV_DEBUG_IOCTL("VIDEO_GET_PTS\n"); + if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { +@@ -1616,29 +1634,12 @@ static int ivtv_decoder_ioctls(struct fi + } + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; +- +- if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { +- *pts = (u64) ((u64)itv->last_dec_timing[2] << 32) | +- (u64)itv->last_dec_timing[1]; +- break; +- } +- *pts = 0; +- if (atomic_read(&itv->decoding)) { +- if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { +- IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); +- return -EIO; +- } +- memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); +- set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); +- *pts = (u64) ((u64) data[2] << 32) | (u64) data[1]; +- /*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/ +- } +- break; ++ return ivtv_g_pts_frame(itv, pts, &frame); + } + + case VIDEO_GET_FRAME_COUNT: { +- u32 data[CX2341X_MBOX_MAX_DATA]; +- u64 *frame = arg; ++ s64 *frame = arg; ++ s64 pts; + + IVTV_DEBUG_IOCTL("VIDEO_GET_FRAME_COUNT\n"); + if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { +@@ -1647,71 +1648,58 @@ static int ivtv_decoder_ioctls(struct fi + } + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; +- +- if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { +- *frame = itv->last_dec_timing[0]; +- break; +- } +- *frame = 0; +- if (atomic_read(&itv->decoding)) { +- if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { +- IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); +- return -EIO; +- } +- memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); +- set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); +- *frame = data[0]; +- } +- break; ++ return ivtv_g_pts_frame(itv, &pts, frame); + } + + case VIDEO_PLAY: { +- struct video_command vc; ++ struct v4l2_decoder_cmd dc; + + IVTV_DEBUG_IOCTL("VIDEO_PLAY\n"); +- memset(&vc, 0, sizeof(vc)); +- vc.cmd = VIDEO_CMD_PLAY; +- return ivtv_video_command(itv, id, &vc, 0); ++ memset(&dc, 0, sizeof(dc)); ++ dc.cmd = V4L2_DEC_CMD_START; ++ return ivtv_video_command(itv, id, &dc, 0); + } + + case VIDEO_STOP: { +- struct video_command vc; ++ struct v4l2_decoder_cmd dc; + + IVTV_DEBUG_IOCTL("VIDEO_STOP\n"); +- memset(&vc, 0, sizeof(vc)); +- vc.cmd = VIDEO_CMD_STOP; +- vc.flags = VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY; +- return ivtv_video_command(itv, id, &vc, 0); ++ memset(&dc, 0, sizeof(dc)); ++ dc.cmd = V4L2_DEC_CMD_STOP; ++ dc.flags = V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY; ++ return ivtv_video_command(itv, id, &dc, 0); + } + + case VIDEO_FREEZE: { +- struct video_command vc; ++ struct v4l2_decoder_cmd dc; + + IVTV_DEBUG_IOCTL("VIDEO_FREEZE\n"); +- memset(&vc, 0, sizeof(vc)); +- vc.cmd = VIDEO_CMD_FREEZE; +- return ivtv_video_command(itv, id, &vc, 0); ++ memset(&dc, 0, sizeof(dc)); ++ dc.cmd = V4L2_DEC_CMD_PAUSE; ++ return ivtv_video_command(itv, id, &dc, 0); + } + + case VIDEO_CONTINUE: { +- struct video_command vc; ++ struct v4l2_decoder_cmd dc; + + IVTV_DEBUG_IOCTL("VIDEO_CONTINUE\n"); +- memset(&vc, 0, sizeof(vc)); +- vc.cmd = VIDEO_CMD_CONTINUE; +- return ivtv_video_command(itv, id, &vc, 0); ++ memset(&dc, 0, sizeof(dc)); ++ dc.cmd = V4L2_DEC_CMD_RESUME; ++ return ivtv_video_command(itv, id, &dc, 0); + } + + case VIDEO_COMMAND: + case VIDEO_TRY_COMMAND: { +- struct video_command *vc = arg; ++ /* Note: struct v4l2_decoder_cmd has the same layout as ++ struct video_command */ ++ struct v4l2_decoder_cmd *dc = arg; + int try = (cmd == VIDEO_TRY_COMMAND); + + if (try) +- IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", vc->cmd); ++ IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", dc->cmd); + else +- IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", vc->cmd); +- return ivtv_video_command(itv, id, vc, try); ++ IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", dc->cmd); ++ return ivtv_video_command(itv, id, dc, try); + } + + case VIDEO_GET_EVENT: { +@@ -1775,17 +1763,13 @@ static int ivtv_decoder_ioctls(struct fi + IVTV_DEBUG_IOCTL("AUDIO_CHANNEL_SELECT\n"); + if (iarg > AUDIO_STEREO_SWAPPED) + return -EINVAL; +- itv->audio_stereo_mode = iarg; +- ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); +- return 0; ++ return v4l2_ctrl_s_ctrl(itv->ctrl_audio_playback, iarg + 1); + + case AUDIO_BILINGUAL_CHANNEL_SELECT: + IVTV_DEBUG_IOCTL("AUDIO_BILINGUAL_CHANNEL_SELECT\n"); + if (iarg > AUDIO_STEREO_SWAPPED) + return -EINVAL; +- itv->audio_bilingual_mode = iarg; +- ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); +- return 0; ++ return v4l2_ctrl_s_ctrl(itv->ctrl_audio_multilingual_playback, iarg + 1); + + default: + return -EINVAL; +@@ -1800,6 +1784,7 @@ static long ivtv_default(struct file *fi + + if (!valid_prio) { + switch (cmd) { ++ case IVTV_IOC_PASSTHROUGH_MODE: + case VIDEO_PLAY: + case VIDEO_STOP: + case VIDEO_FREEZE: +@@ -1825,6 +1810,7 @@ static long ivtv_default(struct file *fi + } + + case IVTV_IOC_DMA_FRAME: ++ case IVTV_IOC_PASSTHROUGH_MODE: + case VIDEO_GET_PTS: + case VIDEO_GET_FRAME_COUNT: + case VIDEO_GET_EVENT: +@@ -1889,6 +1875,8 @@ static const struct v4l2_ioctl_ops ivtv_ + .vidioc_enum_fmt_vid_cap = ivtv_enum_fmt_vid_cap, + .vidioc_encoder_cmd = ivtv_encoder_cmd, + .vidioc_try_encoder_cmd = ivtv_try_encoder_cmd, ++ .vidioc_decoder_cmd = ivtv_decoder_cmd, ++ .vidioc_try_decoder_cmd = ivtv_try_decoder_cmd, + .vidioc_enum_fmt_vid_out = ivtv_enum_fmt_vid_out, + .vidioc_g_fmt_vid_cap = ivtv_g_fmt_vid_cap, + .vidioc_g_fmt_vbi_cap = ivtv_g_fmt_vbi_cap, +Index: linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-streams.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ivtv/ivtv-streams.c ++++ linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-streams.c +@@ -78,60 +78,73 @@ static struct { + int num_offset; + int dma, pio; + enum v4l2_buf_type buf_type; ++ u32 v4l2_caps; + const struct v4l2_file_operations *fops; + } ivtv_stream_info[] = { + { /* IVTV_ENC_STREAM_TYPE_MPG */ + "encoder MPG", + VFL_TYPE_GRABBER, 0, + PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, ++ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | ++ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, + &ivtv_v4l2_enc_fops + }, + { /* IVTV_ENC_STREAM_TYPE_YUV */ + "encoder YUV", + VFL_TYPE_GRABBER, IVTV_V4L2_ENC_YUV_OFFSET, + PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, ++ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | ++ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, + &ivtv_v4l2_enc_fops + }, + { /* IVTV_ENC_STREAM_TYPE_VBI */ + "encoder VBI", + VFL_TYPE_VBI, 0, + PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VBI_CAPTURE, ++ V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_TUNER | ++ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, + &ivtv_v4l2_enc_fops + }, + { /* IVTV_ENC_STREAM_TYPE_PCM */ + "encoder PCM", + VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET, + PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE, ++ V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, + &ivtv_v4l2_enc_fops + }, + { /* IVTV_ENC_STREAM_TYPE_RAD */ + "encoder radio", + VFL_TYPE_RADIO, 0, + PCI_DMA_NONE, 1, V4L2_BUF_TYPE_PRIVATE, ++ V4L2_CAP_RADIO | V4L2_CAP_TUNER, + &ivtv_v4l2_enc_fops + }, + { /* IVTV_DEC_STREAM_TYPE_MPG */ + "decoder MPG", + VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET, + PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, ++ V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, + &ivtv_v4l2_dec_fops + }, + { /* IVTV_DEC_STREAM_TYPE_VBI */ + "decoder VBI", + VFL_TYPE_VBI, IVTV_V4L2_DEC_VBI_OFFSET, + PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_CAPTURE, ++ V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_READWRITE, + &ivtv_v4l2_enc_fops + }, + { /* IVTV_DEC_STREAM_TYPE_VOUT */ + "decoder VOUT", + VFL_TYPE_VBI, IVTV_V4L2_DEC_VOUT_OFFSET, + PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_OUTPUT, ++ V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, + &ivtv_v4l2_dec_fops + }, + { /* IVTV_DEC_STREAM_TYPE_YUV */ + "decoder YUV", + VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET, + PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, ++ V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, + &ivtv_v4l2_dec_fops + } + }; +@@ -149,6 +162,7 @@ static void ivtv_stream_init(struct ivtv + s->itv = itv; + s->type = type; + s->name = ivtv_stream_info[type].name; ++ s->caps = ivtv_stream_info[type].v4l2_caps; + + if (ivtv_stream_info[type].pio) + s->dma = PCI_DMA_NONE; +@@ -209,8 +223,8 @@ static int ivtv_prep_dev(struct ivtv *it + + s->vdev->num = num; + s->vdev->v4l2_dev = &itv->v4l2_dev; +- s->vdev->ctrl_handler = itv->v4l2_dev.ctrl_handler; + s->vdev->fops = ivtv_stream_info[type].fops; ++ s->vdev->ctrl_handler = itv->v4l2_dev.ctrl_handler; + s->vdev->release = video_device_release; + s->vdev->tvnorms = V4L2_STD_ALL; + s->vdev->lock = &itv->serialize_lock; +@@ -891,7 +905,7 @@ int ivtv_stop_v4l2_decode_stream(struct + IVTV_DEBUG_INFO("Stop Decode at %llu, flags: %x\n", (unsigned long long)pts, flags); + + /* Stop Decoder */ +- if (!(flags & VIDEO_CMD_STOP_IMMEDIATELY) || pts) { ++ if (!(flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) || pts) { + u32 tmp = 0; + + /* Wait until the decoder is no longer running */ +@@ -911,7 +925,7 @@ int ivtv_stop_v4l2_decode_stream(struct + break; + } + } +- ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & VIDEO_CMD_STOP_TO_BLACK, 0, 0); ++ ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & V4L2_DEC_CMD_STOP_TO_BLACK, 0, 0); + + /* turn off notification of dual/stereo mode change */ + ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1); +Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/it913x.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/it913x.c ++++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/it913x.c +@@ -64,6 +64,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr + struct it913x_state { + u8 id; + struct ite_config it913x_config; ++ u8 pid_filter_onoff; + }; + + struct ite_config it913x_config; +@@ -237,12 +238,27 @@ static int it913x_read_reg(struct usb_de + + static u32 it913x_query(struct usb_device *udev, u8 pro) + { +- int ret; ++ int ret, i; + u8 data[4]; +- ret = it913x_io(udev, READ_LONG, pro, CMD_DEMOD_READ, +- 0x1222, 0, &data[0], 3); ++ u8 ver; ++ ++ for (i = 0; i < 5; i++) { ++ ret = it913x_io(udev, READ_LONG, pro, CMD_DEMOD_READ, ++ 0x1222, 0, &data[0], 3); ++ ver = data[0]; ++ if (ver > 0 && ver < 3) ++ break; ++ msleep(100); ++ } + +- it913x_config.chip_ver = data[0]; ++ if (ver < 1 || ver > 2) { ++ info("Failed to identify chip version applying 1"); ++ it913x_config.chip_ver = 0x1; ++ it913x_config.chip_type = 0x9135; ++ return 0; ++ } ++ ++ it913x_config.chip_ver = ver; + it913x_config.chip_type = (u16)(data[2] << 8) + data[1]; + + info("Chip Version=%02x Chip Type=%04x", it913x_config.chip_ver, +@@ -259,15 +275,16 @@ static u32 it913x_query(struct usb_devic + + static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) + { ++ struct it913x_state *st = adap->dev->priv; + struct usb_device *udev = adap->dev->udev; + int ret; + u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; + +- if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) +- return -EAGAIN; ++ mutex_lock(&adap->dev->i2c_mutex); ++ + deb_info(1, "PID_C (%02x)", onoff); + +- ret = it913x_wr_reg(udev, pro, PID_EN, onoff); ++ ret = it913x_wr_reg(udev, pro, PID_EN, st->pid_filter_onoff); + + mutex_unlock(&adap->dev->i2c_mutex); + return ret; +@@ -276,12 +293,13 @@ static int it913x_pid_filter_ctrl(struct + static int it913x_pid_filter(struct dvb_usb_adapter *adap, + int index, u16 pid, int onoff) + { ++ struct it913x_state *st = adap->dev->priv; + struct usb_device *udev = adap->dev->udev; + int ret; + u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; + +- if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) +- return -EAGAIN; ++ mutex_lock(&adap->dev->i2c_mutex); ++ + deb_info(1, "PID_F (%02x)", onoff); + + ret = it913x_wr_reg(udev, pro, PID_LSB, (u8)(pid & 0xff)); +@@ -292,6 +310,13 @@ static int it913x_pid_filter(struct dvb_ + + ret |= it913x_wr_reg(udev, pro, PID_INX, (u8)(index & 0x1f)); + ++ if (udev->speed == USB_SPEED_HIGH && pid == 0x2000) { ++ ret |= it913x_wr_reg(udev, pro, PID_EN, !onoff); ++ st->pid_filter_onoff = !onoff; ++ } else ++ st->pid_filter_onoff = ++ adap->fe_adap[adap->active_fe].pid_filtering; ++ + mutex_unlock(&adap->dev->i2c_mutex); + return 0; + } +@@ -316,8 +341,8 @@ static int it913x_i2c_xfer(struct i2c_ad + int ret; + u32 reg; + u8 pro; +- if (mutex_lock_interruptible(&d->i2c_mutex) < 0) +- return -EAGAIN; ++ ++ mutex_lock(&d->i2c_mutex); + + debug_data_snipet(1, "Message out", msg[0].buf); + deb_info(2, "num of messages %d address %02x", num, msg[0].addr); +@@ -358,8 +383,7 @@ static int it913x_rc_query(struct dvb_us + int ret; + u32 key; + /* Avoid conflict with frontends*/ +- if (mutex_lock_interruptible(&d->i2c_mutex) < 0) +- return -EAGAIN; ++ mutex_lock(&d->i2c_mutex); + + ret = it913x_io(d->udev, READ_LONG, PRO_LINK, CMD_IR_GET, + 0, 0, &ibuf[0], sizeof(ibuf)); +@@ -388,19 +412,12 @@ static int ite_firmware_select(struct us + { + int sw; + /* auto switch */ +- if (le16_to_cpu(udev->descriptor.idProduct) == +- USB_PID_ITETECH_IT9135) +- sw = IT9135_V1_FW; +- else if (le16_to_cpu(udev->descriptor.idProduct) == +- USB_PID_ITETECH_IT9135_9005) ++ if (le16_to_cpu(udev->descriptor.idVendor) == USB_VID_KWORLD_2) ++ sw = IT9137_FW; ++ else if (it913x_config.chip_ver == 1) + sw = IT9135_V1_FW; +- else if (le16_to_cpu(udev->descriptor.idProduct) == +- USB_PID_ITETECH_IT9135_9006) { ++ else + sw = IT9135_V2_FW; +- if (it913x_config.tuner_id_0 == 0) +- it913x_config.tuner_id_0 = IT9135_60; +- } else +- sw = IT9137_FW; + + /* force switch */ + if (dvb_usb_it913x_firmware != IT9135_AUTO) +@@ -410,41 +427,103 @@ static int ite_firmware_select(struct us + case IT9135_V1_FW: + it913x_config.firmware_ver = 1; + it913x_config.adc_x2 = 1; ++ it913x_config.read_slevel = false; + props->firmware = fw_it9135_v1; + break; + case IT9135_V2_FW: + it913x_config.firmware_ver = 1; + it913x_config.adc_x2 = 1; ++ it913x_config.read_slevel = false; + props->firmware = fw_it9135_v2; ++ switch (it913x_config.tuner_id_0) { ++ case IT9135_61: ++ case IT9135_62: ++ break; ++ default: ++ info("Unknown tuner ID applying default 0x60"); ++ case IT9135_60: ++ it913x_config.tuner_id_0 = IT9135_60; ++ } + break; + case IT9137_FW: + default: + it913x_config.firmware_ver = 0; + it913x_config.adc_x2 = 0; ++ it913x_config.read_slevel = true; + props->firmware = fw_it9137; + } + + return 0; + } + ++static void it913x_select_remote(struct usb_device *udev, ++ struct dvb_usb_device_properties *props) ++{ ++ switch (le16_to_cpu(udev->descriptor.idProduct)) { ++ case USB_PID_ITETECH_IT9135_9005: ++ props->rc.core.rc_codes = RC_MAP_IT913X_V2; ++ return; ++ default: ++ props->rc.core.rc_codes = RC_MAP_IT913X_V1; ++ } ++ return; ++} ++ + #define TS_MPEG_PKT_SIZE 188 + #define EP_LOW 21 + #define TS_BUFFER_SIZE_PID (EP_LOW*TS_MPEG_PKT_SIZE) + #define EP_HIGH 348 + #define TS_BUFFER_SIZE_MAX (EP_HIGH*TS_MPEG_PKT_SIZE) + +-static int it913x_identify_state(struct usb_device *udev, +- struct dvb_usb_device_properties *props, +- struct dvb_usb_device_description **desc, +- int *cold) ++static int it913x_select_config(struct usb_device *udev, ++ struct dvb_usb_device_properties *props) + { +- int ret = 0, firm_no; +- u8 reg, remote; ++ int ret = 0, reg; ++ bool proprietary_ir = false; + +- firm_no = it913x_return_status(udev); ++ if (it913x_config.chip_ver == 0x02 ++ && it913x_config.chip_type == 0x9135) ++ reg = it913x_read_reg(udev, 0x461d); ++ else ++ reg = it913x_read_reg(udev, 0x461b); + +- /* checnk for dual mode */ +- it913x_config.dual_mode = it913x_read_reg(udev, 0x49c5); ++ if (reg < 0) ++ return reg; ++ ++ if (reg == 0) { ++ it913x_config.dual_mode = 0; ++ it913x_config.tuner_id_0 = IT9135_38; ++ proprietary_ir = true; ++ } else { ++ /* TS mode */ ++ reg = it913x_read_reg(udev, 0x49c5); ++ if (reg < 0) ++ return reg; ++ it913x_config.dual_mode = reg; ++ ++ /* IR mode type */ ++ reg = it913x_read_reg(udev, 0x49ac); ++ if (reg < 0) ++ return reg; ++ if (reg == 5) { ++ info("Remote propriety (raw) mode"); ++ proprietary_ir = true; ++ } else if (reg == 1) { ++ info("Remote HID mode NOT SUPPORTED"); ++ proprietary_ir = false; ++ props->rc.core.rc_codes = NULL; ++ } else ++ props->rc.core.rc_codes = NULL; ++ ++ /* Tuner_id */ ++ reg = it913x_read_reg(udev, 0x49d0); ++ if (reg < 0) ++ return reg; ++ it913x_config.tuner_id_0 = reg; ++ } ++ ++ if (proprietary_ir) ++ it913x_select_remote(udev, props); + + if (udev->speed != USB_SPEED_HIGH) { + props->adapter[0].fe[0].pid_filter_count = 5; +@@ -459,17 +538,6 @@ static int it913x_identify_state(struct + if(props->adapter[0].fe[0].pid_filter_count == 5) + props->adapter[0].fe[0].pid_filter_count = 31; + +- /* TODO different remotes */ +- remote = it913x_read_reg(udev, 0x49ac); /* Remote */ +- if (remote == 0) +- props->rc.core.rc_codes = NULL; +- +- /* TODO at the moment tuner_id is always assigned to 0x38 */ +- it913x_config.tuner_id_0 = it913x_read_reg(udev, 0x49d0); +- +- info("Dual mode=%x Remote=%x Tuner Type=%x", it913x_config.dual_mode +- , remote, it913x_config.tuner_id_0); +- + /* Select Stream Buffer Size and pid filter option*/ + if (pid_filter) { + props->adapter[0].fe[0].stream.u.bulk.buffersize = +@@ -490,8 +558,29 @@ static int it913x_identify_state(struct + } else + props->num_adapters = 1; + ++ info("Dual mode=%x Tuner Type=%x", it913x_config.dual_mode, ++ it913x_config.tuner_id_0); ++ + ret = ite_firmware_select(udev, props); + ++ return ret; ++} ++ ++static int it913x_identify_state(struct usb_device *udev, ++ struct dvb_usb_device_properties *props, ++ struct dvb_usb_device_description **desc, ++ int *cold) ++{ ++ int ret = 0, firm_no; ++ u8 reg; ++ ++ firm_no = it913x_return_status(udev); ++ ++ /* Read and select config */ ++ ret = it913x_select_config(udev, props); ++ if (ret < 0) ++ return ret; ++ + if (firm_no > 0) { + *cold = 0; + return 0; +@@ -538,18 +627,22 @@ static int it913x_identify_state(struct + + static int it913x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) + { ++ struct it913x_state *st = adap->dev->priv; + int ret = 0; + u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; + +- if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) +- return -EAGAIN; + deb_info(1, "STM (%02x)", onoff); + +- if (!onoff) ++ if (!onoff) { ++ mutex_lock(&adap->dev->i2c_mutex); ++ + ret = it913x_wr_reg(adap->dev->udev, pro, PID_RST, 0x1); + ++ mutex_unlock(&adap->dev->i2c_mutex); ++ st->pid_filter_onoff = ++ adap->fe_adap[adap->active_fe].pid_filtering; + +- mutex_unlock(&adap->dev->i2c_mutex); ++ } + + return ret; + } +@@ -582,30 +675,41 @@ static int it913x_download_firmware(stru + if ((packet_size > min_pkt) || (i == fw->size)) { + fw_data = (u8 *)(fw->data + pos); + pos += packet_size; +- if (packet_size > 0) +- ret |= it913x_io(udev, WRITE_DATA, ++ if (packet_size > 0) { ++ ret = it913x_io(udev, WRITE_DATA, + DEV_0, CMD_SCATTER_WRITE, 0, + 0, fw_data, packet_size); ++ if (ret < 0) ++ break; ++ } + udelay(1000); + } + } + i++; + } + +- ret |= it913x_io(udev, WRITE_CMD, DEV_0, CMD_BOOT, 0, 0, NULL, 0); +- +- msleep(100); +- + if (ret < 0) +- info("FRM Firmware Download Failed (%04x)" , ret); ++ info("FRM Firmware Download Failed (%d)" , ret); + else + info("FRM Firmware Download Completed - Resetting Device"); + +- ret |= it913x_return_status(udev); ++ msleep(30); ++ ++ ret = it913x_io(udev, WRITE_CMD, DEV_0, CMD_BOOT, 0, 0, NULL, 0); ++ if (ret < 0) ++ info("FRM Device not responding to reboot"); ++ ++ ret = it913x_return_status(udev); ++ if (ret == 0) { ++ info("FRM Failed to reboot device"); ++ return -ENODEV; ++ } + + msleep(30); + +- ret |= it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_400); ++ ret = it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_400); ++ ++ msleep(30); + + /* Tuner function */ + if (it913x_config.dual_mode) +@@ -789,7 +893,7 @@ static struct dvb_usb_device_properties + .rc_query = it913x_rc_query, + .rc_interval = IT913X_POLL, + .allowed_protos = RC_TYPE_NEC, +- .rc_codes = RC_MAP_MSI_DIGIVOX_III, ++ .rc_codes = RC_MAP_IT913X_V1, + }, + .i2c_algo = &it913x_i2c_algo, + .num_device_descs = 5, +@@ -823,5 +927,5 @@ module_usb_driver(it913x_driver); + + MODULE_AUTHOR("Malcolm Priestley "); + MODULE_DESCRIPTION("it913x USB 2 Driver"); +-MODULE_VERSION("1.22"); ++MODULE_VERSION("1.28"); + MODULE_LICENSE("GPL"); +Index: linux-3.3.x86_64/drivers/base/driver.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/base/driver.c ++++ linux-3.3.x86_64/drivers/base/driver.c +@@ -234,7 +234,6 @@ int driver_register(struct device_driver + + other = driver_find(drv->name, drv->bus); + if (other) { +- put_driver(other); + printk(KERN_ERR "Error: Driver '%s' is already registered, " + "aborting...\n", drv->name); + return -EBUSY; +@@ -275,7 +274,9 @@ EXPORT_SYMBOL_GPL(driver_unregister); + * Call kset_find_obj() to iterate over list of drivers on + * a bus to find driver by name. Return driver if found. + * +- * Note that kset_find_obj increments driver's reference count. ++ * This routine provides no locking to prevent the driver it returns ++ * from being unregistered or unloaded while the caller is using it. ++ * The caller is responsible for preventing this. + */ + struct device_driver *driver_find(const char *name, struct bus_type *bus) + { +@@ -283,6 +284,8 @@ struct device_driver *driver_find(const + struct driver_private *priv; + + if (k) { ++ /* Drop reference added by kset_find_obj() */ ++ kobject_put(k); + priv = to_driver(k); + return priv->driver; + } +Index: linux-3.3.x86_64/drivers/input/gameport/gameport.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/input/gameport/gameport.c ++++ linux-3.3.x86_64/drivers/input/gameport/gameport.c +@@ -449,7 +449,6 @@ static ssize_t gameport_rebind_driver(st + } else if ((drv = driver_find(buf, &gameport_bus)) != NULL) { + gameport_disconnect_port(gameport); + error = gameport_bind_driver(gameport, to_gameport_driver(drv)); +- put_driver(drv); + } else { + error = -EINVAL; + } +Index: linux-3.3.x86_64/drivers/input/serio/serio.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/input/serio/serio.c ++++ linux-3.3.x86_64/drivers/input/serio/serio.c +@@ -441,7 +441,6 @@ static ssize_t serio_rebind_driver(struc + } else if ((drv = driver_find(buf, &serio_bus)) != NULL) { + serio_disconnect_port(serio); + error = serio_bind_driver(serio, to_serio_driver(drv)); +- put_driver(drv); + serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT); + } else { + error = -EINVAL; +Index: linux-3.3.x86_64/drivers/media/video/cx18/cx18-alsa-main.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/cx18/cx18-alsa-main.c ++++ linux-3.3.x86_64/drivers/media/video/cx18/cx18-alsa-main.c +@@ -285,7 +285,6 @@ static void __exit cx18_alsa_exit(void) + + drv = driver_find("cx18", &pci_bus_type); + ret = driver_for_each_device(drv, NULL, NULL, cx18_alsa_exit_callback); +- put_driver(drv); + + cx18_ext_init = NULL; + printk(KERN_INFO "cx18-alsa: module unload complete\n"); +Index: linux-3.3.x86_64/drivers/media/video/ivtv/ivtvfb.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ivtv/ivtvfb.c ++++ linux-3.3.x86_64/drivers/media/video/ivtv/ivtvfb.c +@@ -1293,7 +1293,6 @@ static int __init ivtvfb_init(void) + + drv = driver_find("ivtv", &pci_bus_type); + err = driver_for_each_device(drv, NULL, ®istered, ivtvfb_callback_init); +- put_driver(drv); + if (!registered) { + printk(KERN_ERR "ivtvfb: no cards found\n"); + return -ENODEV; +@@ -1310,7 +1309,6 @@ static void ivtvfb_cleanup(void) + + drv = driver_find("ivtv", &pci_bus_type); + err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup); +- put_driver(drv); + } + + module_init(ivtvfb_init); +Index: linux-3.3.x86_64/drivers/media/video/s5p-fimc/fimc-mdevice.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s5p-fimc/fimc-mdevice.c ++++ linux-3.3.x86_64/drivers/media/video/s5p-fimc/fimc-mdevice.c +@@ -344,16 +344,13 @@ static int fimc_md_register_platform_ent + return -ENODEV; + ret = driver_for_each_device(driver, NULL, fmd, + fimc_register_callback); +- put_driver(driver); + if (ret) + return ret; + + driver = driver_find(CSIS_DRIVER_NAME, &platform_bus_type); +- if (driver) { ++ if (driver) + ret = driver_for_each_device(driver, NULL, fmd, + csis_register_callback); +- put_driver(driver); +- } + return ret; + } + +@@ -753,7 +750,7 @@ static int __devinit fimc_md_probe(struc + struct fimc_md *fmd; + int ret; + +- fmd = kzalloc(sizeof(struct fimc_md), GFP_KERNEL); ++ fmd = devm_kzalloc(&pdev->dev, sizeof(*fmd), GFP_KERNEL); + if (!fmd) + return -ENOMEM; + +@@ -774,7 +771,7 @@ static int __devinit fimc_md_probe(struc + ret = v4l2_device_register(&pdev->dev, &fmd->v4l2_dev); + if (ret < 0) { + v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret); +- goto err1; ++ return ret; + } + ret = media_device_register(&fmd->media_dev); + if (ret < 0) { +@@ -816,8 +813,6 @@ err3: + fimc_md_unregister_entities(fmd); + err2: + v4l2_device_unregister(&fmd->v4l2_dev); +-err1: +- kfree(fmd); + return ret; + } + +@@ -831,7 +826,6 @@ static int __devexit fimc_md_remove(stru + fimc_md_unregister_entities(fmd); + media_device_unregister(&fmd->media_dev); + fimc_md_put_clocks(fmd); +- kfree(fmd); + return 0; + } + +Index: linux-3.3.x86_64/drivers/media/video/s5p-tv/mixer_video.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s5p-tv/mixer_video.c ++++ linux-3.3.x86_64/drivers/media/video/s5p-tv/mixer_video.c +@@ -58,7 +58,6 @@ static struct v4l2_subdev *find_and_regi + } + + done: +- put_driver(drv); + return sd; + } + +Index: linux-3.3.x86_64/drivers/s390/net/smsgiucv_app.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/s390/net/smsgiucv_app.c ++++ linux-3.3.x86_64/drivers/s390/net/smsgiucv_app.c +@@ -168,7 +168,7 @@ static int __init smsgiucv_app_init(void + rc = dev_set_name(smsg_app_dev, KMSG_COMPONENT); + if (rc) { + kfree(smsg_app_dev); +- goto fail_put_driver; ++ goto fail; + } + smsg_app_dev->bus = &iucv_bus; + smsg_app_dev->parent = iucv_root; +@@ -177,7 +177,7 @@ static int __init smsgiucv_app_init(void + rc = device_register(smsg_app_dev); + if (rc) { + put_device(smsg_app_dev); +- goto fail_put_driver; ++ goto fail; + } + + /* convert sender to uppercase characters */ +@@ -191,12 +191,11 @@ static int __init smsgiucv_app_init(void + rc = smsg_register_callback(SMSG_PREFIX, smsg_app_callback); + if (rc) { + device_unregister(smsg_app_dev); +- goto fail_put_driver; ++ goto fail; + } + + rc = 0; +-fail_put_driver: +- put_driver(smsgiucv_drv); ++fail: + return rc; + } + module_init(smsgiucv_app_init); +Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/anysee.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/anysee.c ++++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/anysee.c +@@ -58,7 +58,7 @@ static int anysee_ctrl_msg(struct dvb_us + u8 *rbuf, u8 rlen) + { + struct anysee_state *state = d->priv; +- int act_len, ret; ++ int act_len, ret, i; + u8 buf[64]; + + memcpy(&buf[0], sbuf, slen); +@@ -73,26 +73,52 @@ static int anysee_ctrl_msg(struct dvb_us + /* We need receive one message more after dvb_usb_generic_rw due + to weird transaction flow, which is 1 x send + 2 x receive. */ + ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0); +- if (!ret) { ++ if (ret) ++ goto error_unlock; ++ ++ /* TODO FIXME: dvb_usb_generic_rw() fails rarely with error code -32 ++ * (EPIPE, Broken pipe). Function supports currently msleep() as a ++ * parameter but I would not like to use it, since according to ++ * Documentation/timers/timers-howto.txt it should not be used such ++ * short, under < 20ms, sleeps. Repeating failed message would be ++ * better choice as not to add unwanted delays... ++ * Fixing that correctly is one of those or both; ++ * 1) use repeat if possible ++ * 2) add suitable delay ++ */ ++ ++ /* get answer, retry few times if error returned */ ++ for (i = 0; i < 3; i++) { + /* receive 2nd answer */ + ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint), buf, sizeof(buf), + &act_len, 2000); +- if (ret) +- err("%s: recv bulk message failed: %d", __func__, ret); +- else { ++ ++ if (ret) { ++ deb_info("%s: recv bulk message failed: %d", ++ __func__, ret); ++ } else { + deb_xfer("<<< "); + debug_dump(buf, rlen, deb_xfer); + + if (buf[63] != 0x4f) + deb_info("%s: cmd failed\n", __func__); ++ ++ break; + } + } + ++ if (ret) { ++ /* all retries failed, it is fatal */ ++ err("%s: recv bulk message failed: %d", __func__, ret); ++ goto error_unlock; ++ } ++ + /* read request, copy returned data to return buf */ +- if (!ret && rbuf && rlen) ++ if (rbuf && rlen) + memcpy(rbuf, buf, rlen); + ++error_unlock: + mutex_unlock(&anysee_usb_mutex); + + return ret; +Index: linux-3.3.x86_64/drivers/media/video/s5p-tv/hdmi_drv.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s5p-tv/hdmi_drv.c ++++ linux-3.3.x86_64/drivers/media/video/s5p-tv/hdmi_drv.c +@@ -30,6 +30,7 @@ + #include + #include + ++#include + #include + #include + #include +@@ -66,6 +67,8 @@ struct hdmi_device { + struct v4l2_device v4l2_dev; + /** subdev of HDMIPHY interface */ + struct v4l2_subdev *phy_sd; ++ /** subdev of MHL interface */ ++ struct v4l2_subdev *mhl_sd; + /** configuration of current graphic mode */ + const struct hdmi_preset_conf *cur_conf; + /** current preset */ +@@ -74,10 +77,6 @@ struct hdmi_device { + struct hdmi_resources res; + }; + +-struct hdmi_driver_data { +- int hdmiphy_bus; +-}; +- + struct hdmi_tg_regs { + u8 cmd; + u8 h_fsz_l; +@@ -129,23 +128,11 @@ struct hdmi_preset_conf { + struct v4l2_mbus_framefmt mbus_fmt; + }; + +-/* I2C module and id for HDMIPHY */ +-static struct i2c_board_info hdmiphy_info = { +- I2C_BOARD_INFO("hdmiphy", 0x38), +-}; +- +-static struct hdmi_driver_data hdmi_driver_data[] = { +- { .hdmiphy_bus = 3 }, +- { .hdmiphy_bus = 8 }, +-}; +- + static struct platform_device_id hdmi_driver_types[] = { + { + .name = "s5pv210-hdmi", +- .driver_data = (unsigned long)&hdmi_driver_data[0], + }, { + .name = "exynos4-hdmi", +- .driver_data = (unsigned long)&hdmi_driver_data[1], + }, { + /* end node */ + } +@@ -587,7 +574,15 @@ static int hdmi_streamon(struct hdmi_dev + if (tries == 0) { + dev_err(dev, "hdmiphy's pll could not reach steady state.\n"); + v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0); +- hdmi_dumpregs(hdev, "s_stream"); ++ hdmi_dumpregs(hdev, "hdmiphy - s_stream"); ++ return -EIO; ++ } ++ ++ /* starting MHL */ ++ ret = v4l2_subdev_call(hdev->mhl_sd, video, s_stream, 1); ++ if (hdev->mhl_sd && ret) { ++ v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0); ++ hdmi_dumpregs(hdev, "mhl - s_stream"); + return -EIO; + } + +@@ -618,6 +613,7 @@ static int hdmi_streamoff(struct hdmi_de + clk_set_parent(res->sclk_hdmi, res->sclk_pixel); + clk_enable(res->sclk_hdmi); + ++ v4l2_subdev_call(hdev->mhl_sd, video, s_stream, 0); + v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0); + + hdmi_dumpregs(hdev, "streamoff"); +@@ -739,6 +735,7 @@ static int hdmi_runtime_suspend(struct d + struct hdmi_device *hdev = sd_to_hdmi_dev(sd); + + dev_dbg(dev, "%s\n", __func__); ++ v4l2_subdev_call(hdev->mhl_sd, core, s_power, 0); + hdmi_resource_poweroff(&hdev->res); + return 0; + } +@@ -757,6 +754,11 @@ static int hdmi_runtime_resume(struct de + if (ret) + goto fail; + ++ /* starting MHL */ ++ ret = v4l2_subdev_call(hdev->mhl_sd, core, s_power, 1); ++ if (hdev->mhl_sd && ret) ++ goto fail; ++ + dev_dbg(dev, "poweron succeed\n"); + + return 0; +@@ -867,15 +869,21 @@ static int __devinit hdmi_probe(struct p + { + struct device *dev = &pdev->dev; + struct resource *res; +- struct i2c_adapter *phy_adapter; ++ struct i2c_adapter *adapter; + struct v4l2_subdev *sd; + struct hdmi_device *hdmi_dev = NULL; +- struct hdmi_driver_data *drv_data; ++ struct s5p_hdmi_platform_data *pdata = dev->platform_data; + int ret; + + dev_dbg(dev, "probe start\n"); + +- hdmi_dev = kzalloc(sizeof(*hdmi_dev), GFP_KERNEL); ++ if (!pdata) { ++ dev_err(dev, "platform data is missing\n"); ++ ret = -ENODEV; ++ goto fail; ++ } ++ ++ hdmi_dev = devm_kzalloc(&pdev->dev, sizeof(*hdmi_dev), GFP_KERNEL); + if (!hdmi_dev) { + dev_err(dev, "out of memory\n"); + ret = -ENOMEM; +@@ -886,7 +894,7 @@ static int __devinit hdmi_probe(struct p + + ret = hdmi_resources_init(hdmi_dev); + if (ret) +- goto fail_hdev; ++ goto fail; + + /* mapping HDMI registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +@@ -896,24 +904,26 @@ static int __devinit hdmi_probe(struct p + goto fail_init; + } + +- hdmi_dev->regs = ioremap(res->start, resource_size(res)); ++ hdmi_dev->regs = devm_ioremap(&pdev->dev, res->start, ++ resource_size(res)); + if (hdmi_dev->regs == NULL) { + dev_err(dev, "register mapping failed.\n"); + ret = -ENXIO; +- goto fail_hdev; ++ goto fail_init; + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res == NULL) { + dev_err(dev, "get interrupt resource failed.\n"); + ret = -ENXIO; +- goto fail_regs; ++ goto fail_init; + } + +- ret = request_irq(res->start, hdmi_irq_handler, 0, "hdmi", hdmi_dev); ++ ret = devm_request_irq(&pdev->dev, res->start, hdmi_irq_handler, 0, ++ "hdmi", hdmi_dev); + if (ret) { + dev_err(dev, "request interrupt failed.\n"); +- goto fail_regs; ++ goto fail_init; + } + hdmi_dev->irq = res->start; + +@@ -924,28 +934,54 @@ static int __devinit hdmi_probe(struct p + ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev); + if (ret) { + dev_err(dev, "could not register v4l2 device.\n"); +- goto fail_irq; ++ goto fail_init; + } + +- drv_data = (struct hdmi_driver_data *) +- platform_get_device_id(pdev)->driver_data; +- phy_adapter = i2c_get_adapter(drv_data->hdmiphy_bus); +- if (phy_adapter == NULL) { +- dev_err(dev, "adapter request failed\n"); ++ /* testing if hdmiphy info is present */ ++ if (!pdata->hdmiphy_info) { ++ dev_err(dev, "hdmiphy info is missing in platform data\n"); ++ ret = -ENXIO; ++ goto fail_vdev; ++ } ++ ++ adapter = i2c_get_adapter(pdata->hdmiphy_bus); ++ if (adapter == NULL) { ++ dev_err(dev, "hdmiphy adapter request failed\n"); + ret = -ENXIO; + goto fail_vdev; + } + + hdmi_dev->phy_sd = v4l2_i2c_new_subdev_board(&hdmi_dev->v4l2_dev, +- phy_adapter, &hdmiphy_info, NULL); ++ adapter, pdata->hdmiphy_info, NULL); + /* on failure or not adapter is no longer useful */ +- i2c_put_adapter(phy_adapter); ++ i2c_put_adapter(adapter); + if (hdmi_dev->phy_sd == NULL) { + dev_err(dev, "missing subdev for hdmiphy\n"); + ret = -ENODEV; + goto fail_vdev; + } + ++ /* initialization of MHL interface if present */ ++ if (pdata->mhl_info) { ++ adapter = i2c_get_adapter(pdata->mhl_bus); ++ if (adapter == NULL) { ++ dev_err(dev, "MHL adapter request failed\n"); ++ ret = -ENXIO; ++ goto fail_vdev; ++ } ++ ++ hdmi_dev->mhl_sd = v4l2_i2c_new_subdev_board( ++ &hdmi_dev->v4l2_dev, adapter, ++ pdata->mhl_info, NULL); ++ /* on failure or not adapter is no longer useful */ ++ i2c_put_adapter(adapter); ++ if (hdmi_dev->mhl_sd == NULL) { ++ dev_err(dev, "missing subdev for MHL\n"); ++ ret = -ENODEV; ++ goto fail_vdev; ++ } ++ } ++ + clk_enable(hdmi_dev->res.hdmi); + + pm_runtime_enable(dev); +@@ -969,18 +1005,9 @@ static int __devinit hdmi_probe(struct p + fail_vdev: + v4l2_device_unregister(&hdmi_dev->v4l2_dev); + +-fail_irq: +- free_irq(hdmi_dev->irq, hdmi_dev); +- +-fail_regs: +- iounmap(hdmi_dev->regs); +- + fail_init: + hdmi_resources_cleanup(hdmi_dev); + +-fail_hdev: +- kfree(hdmi_dev); +- + fail: + dev_err(dev, "probe failed\n"); + return ret; +@@ -996,8 +1023,6 @@ static int __devexit hdmi_remove(struct + clk_disable(hdmi_dev->res.hdmi); + v4l2_device_unregister(&hdmi_dev->v4l2_dev); + disable_irq(hdmi_dev->irq); +- free_irq(hdmi_dev->irq, hdmi_dev); +- iounmap(hdmi_dev->regs); + hdmi_resources_cleanup(hdmi_dev); + kfree(hdmi_dev); + dev_info(dev, "remove sucessful\n"); +Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/lmedm04.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/lmedm04.c ++++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/lmedm04.c +@@ -77,6 +77,7 @@ + #include "stv0299.h" + #include "dvb-pll.h" + #include "z0194a.h" ++#include "m88rs2000.h" + + + +@@ -104,7 +105,7 @@ MODULE_PARM_DESC(firmware, "set default + + static int pid_filter; + module_param_named(pid, pid_filter, int, 0644); +-MODULE_PARM_DESC(pid, "set default 0=on 1=off"); ++MODULE_PARM_DESC(pid, "set default 0=default 1=off 2=on"); + + + DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); +@@ -113,6 +114,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr + #define TUNER_LG 0x1 + #define TUNER_S7395 0x2 + #define TUNER_S0194 0x3 ++#define TUNER_RS2000 0x4 + + struct lme2510_state { + u8 id; +@@ -121,6 +123,8 @@ struct lme2510_state { + u8 signal_level; + u8 signal_sn; + u8 time_key; ++ u8 last_key; ++ u8 key_timeout; + u8 i2c_talk_onoff; + u8 i2c_gate; + u8 i2c_tuner_gate_w; +@@ -128,6 +132,7 @@ struct lme2510_state { + u8 i2c_tuner_addr; + u8 stream_on; + u8 pid_size; ++ u8 pid_off; + void *buffer; + struct urb *lme_urb; + void *usb_buffer; +@@ -178,14 +183,8 @@ static int lme2510_usb_talk(struct dvb_u + /* the read/write capped at 64 */ + memcpy(buff, wbuf, (wlen < 64) ? wlen : 64); + +- ret |= usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, 0x01)); +- + ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01); + +- msleep(10); +- +- ret |= usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, 0x01)); +- + ret |= lme2510_bulk_read(d->udev, buff, (rlen < 64) ? + rlen : 64 , 0x01); + +@@ -199,9 +198,14 @@ static int lme2510_usb_talk(struct dvb_u + + static int lme2510_stream_restart(struct dvb_usb_device *d) + { +- static u8 stream_on[] = LME_ST_ON_W; ++ struct lme2510_state *st = d->priv; ++ u8 all_pids[] = LME_ALL_PIDS; ++ u8 stream_on[] = LME_ST_ON_W; + int ret; +- u8 rbuff[10]; ++ u8 rbuff[1]; ++ if (st->pid_off) ++ ret = lme2510_usb_talk(d, all_pids, sizeof(all_pids), ++ rbuff, sizeof(rbuff)); + /*Restart Stream Command*/ + ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on), + rbuff, sizeof(rbuff)); +@@ -308,6 +312,14 @@ static void lme2510_int_response(struct + ((ibuf[2] & 0x01) << 0x03); + } + break; ++ case TUNER_RS2000: ++ if (ibuf[2] > 0) ++ st->signal_lock = 0xff; ++ else ++ st->signal_lock = 0xf0; ++ st->signal_level = ibuf[4]; ++ st->signal_sn = ibuf[5]; ++ st->time_key = ibuf[7]; + default: + break; + } +@@ -359,19 +371,20 @@ static int lme2510_int_read(struct dvb_u + static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) + { + struct lme2510_state *st = adap->dev->priv; +- static u8 clear_pid_reg[] = LME_CLEAR_PID; ++ static u8 clear_pid_reg[] = LME_ALL_PIDS; + static u8 rbuf[1]; + int ret; + + deb_info(1, "PID Clearing Filter"); + +- ret = mutex_lock_interruptible(&adap->dev->i2c_mutex); +- if (ret < 0) +- return -EAGAIN; ++ mutex_lock(&adap->dev->i2c_mutex); + +- if (!onoff) ++ if (!onoff) { + ret |= lme2510_usb_talk(adap->dev, clear_pid_reg, + sizeof(clear_pid_reg), rbuf, sizeof(rbuf)); ++ st->pid_off = true; ++ } else ++ st->pid_off = false; + + st->pid_size = 0; + +@@ -389,11 +402,9 @@ static int lme2510_pid_filter(struct dvb + pid, index, onoff); + + if (onoff) { +- ret = mutex_lock_interruptible(&adap->dev->i2c_mutex); +- if (ret < 0) +- return -EAGAIN; +- ret |= lme2510_enable_pid(adap->dev, index, pid); +- mutex_unlock(&adap->dev->i2c_mutex); ++ mutex_lock(&adap->dev->i2c_mutex); ++ ret |= lme2510_enable_pid(adap->dev, index, pid); ++ mutex_unlock(&adap->dev->i2c_mutex); + } + + +@@ -425,9 +436,6 @@ static int lme2510_msg(struct dvb_usb_de + int ret = 0; + struct lme2510_state *st = d->priv; + +- if (mutex_lock_interruptible(&d->i2c_mutex) < 0) +- return -EAGAIN; +- + if (st->i2c_talk_onoff == 1) { + + ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); +@@ -456,8 +464,6 @@ static int lme2510_msg(struct dvb_usb_de + st->i2c_talk_onoff = 0; + } + } +- if ((wbuf[3] != 0x6) & (wbuf[3] != 0x5)) +- msleep(5); + } + break; + case TUNER_S0194: +@@ -472,10 +478,12 @@ static int lme2510_msg(struct dvb_usb_de + } + } + break; ++ case TUNER_RS2000: + default: + break; + } + } else { ++ /* TODO rewrite this section */ + switch (st->tuner_config) { + case TUNER_LG: + switch (wbuf[3]) { +@@ -559,6 +567,24 @@ static int lme2510_msg(struct dvb_usb_de + break; + } + break; ++ case TUNER_RS2000: ++ switch (wbuf[3]) { ++ case 0x8c: ++ rbuf[0] = 0x55; ++ rbuf[1] = 0xff; ++ if (st->last_key == st->time_key) { ++ st->key_timeout++; ++ if (st->key_timeout > 5) ++ rbuf[1] = 0; ++ } else ++ st->key_timeout = 0; ++ st->last_key = st->time_key; ++ break; ++ default: ++ lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); ++ st->i2c_talk_onoff = 1; ++ break; ++ } + default: + break; + } +@@ -568,8 +594,6 @@ static int lme2510_msg(struct dvb_usb_de + + } + +- mutex_unlock(&d->i2c_mutex); +- + return ret; + } + +@@ -584,6 +608,8 @@ static int lme2510_i2c_xfer(struct i2c_a + u16 len; + u8 gate = st->i2c_gate; + ++ mutex_lock(&d->i2c_mutex); ++ + if (gate == 0) + gate = 5; + +@@ -622,6 +648,7 @@ static int lme2510_i2c_xfer(struct i2c_a + + if (lme2510_msg(d, obuf, len, ibuf, 64) < 0) { + deb_info(1, "i2c transfer failed."); ++ mutex_unlock(&d->i2c_mutex); + return -EAGAIN; + } + +@@ -634,6 +661,8 @@ static int lme2510_i2c_xfer(struct i2c_a + } + } + } ++ ++ mutex_unlock(&d->i2c_mutex); + return i; + } + +@@ -653,7 +682,7 @@ static int lme2510_identify_state(struct + struct dvb_usb_device_description **desc, + int *cold) + { +- if (pid_filter > 0) ++ if (pid_filter != 2) + props->adapter[0].fe[0].caps &= + ~DVB_USB_ADAP_NEED_PID_FILTERING; + *cold = 0; +@@ -663,7 +692,7 @@ static int lme2510_identify_state(struct + static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) + { + struct lme2510_state *st = adap->dev->priv; +- static u8 clear_reg_3[] = LME_CLEAR_PID; ++ static u8 clear_reg_3[] = LME_ALL_PIDS; + static u8 rbuf[1]; + int ret = 0, rlen = sizeof(rbuf); + +@@ -675,8 +704,7 @@ static int lme2510_streaming_ctrl(struct + else { + deb_info(1, "STM Steam Off"); + /* mutex is here only to avoid collision with I2C */ +- if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) +- return -EAGAIN; ++ mutex_lock(&adap->dev->i2c_mutex); + + ret = lme2510_usb_talk(adap->dev, clear_reg_3, + sizeof(clear_reg_3), rbuf, rlen); +@@ -781,16 +809,18 @@ static int lme_firmware_switch(struct us + const char fw_c_s7395[] = "dvb-usb-lme2510c-s7395.fw"; + const char fw_c_lg[] = "dvb-usb-lme2510c-lg.fw"; + const char fw_c_s0194[] = "dvb-usb-lme2510c-s0194.fw"; ++ const char fw_c_rs2000[] = "dvb-usb-lme2510c-rs2000.fw"; + const char fw_lg[] = "dvb-usb-lme2510-lg.fw"; + const char fw_s0194[] = "dvb-usb-lme2510-s0194.fw"; + const char *fw_lme; +- int ret, cold_fw; ++ int ret = 0, cold_fw; + + cold = (cold > 0) ? (cold & 1) : 0; + + cold_fw = !cold; + +- if (le16_to_cpu(udev->descriptor.idProduct) == 0x1122) { ++ switch (le16_to_cpu(udev->descriptor.idProduct)) { ++ case 0x1122: + switch (dvb_usb_lme2510_firmware) { + default: + dvb_usb_lme2510_firmware = TUNER_S0194; +@@ -813,7 +843,8 @@ static int lme_firmware_switch(struct us + cold_fw = 0; + break; + } +- } else { ++ break; ++ case 0x1120: + switch (dvb_usb_lme2510_firmware) { + default: + dvb_usb_lme2510_firmware = TUNER_S7395; +@@ -842,8 +873,17 @@ static int lme_firmware_switch(struct us + cold_fw = 0; + break; + } ++ break; ++ case 0x22f0: ++ fw_lme = fw_c_rs2000; ++ ret = request_firmware(&fw, fw_lme, &udev->dev); ++ dvb_usb_lme2510_firmware = TUNER_RS2000; ++ break; ++ default: ++ fw_lme = fw_c_s7395; + } + ++ + if (cold_fw) { + info("FRM Loading %s file", fw_lme); + ret = lme2510_download_firmware(udev, fw); +@@ -906,6 +946,29 @@ static struct stv0299_config sharp_z0194 + .set_symbol_rate = sharp_z0194a_set_symbol_rate, + }; + ++static int dm04_rs2000_set_ts_param(struct dvb_frontend *fe, ++ int caller) ++{ ++ struct dvb_usb_adapter *adap = fe->dvb->priv; ++ struct dvb_usb_device *d = adap->dev; ++ struct lme2510_state *st = d->priv; ++ ++ mutex_lock(&d->i2c_mutex); ++ if ((st->i2c_talk_onoff == 1) && (st->stream_on & 1)) { ++ st->i2c_talk_onoff = 0; ++ lme2510_stream_restart(d); ++ } ++ mutex_unlock(&d->i2c_mutex); ++ ++ return 0; ++} ++ ++static struct m88rs2000_config m88rs2000_config = { ++ .demod_addr = 0xd0, ++ .tuner_addr = 0xc0, ++ .set_ts_params = dm04_rs2000_set_ts_param, ++}; ++ + static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) + { +@@ -915,8 +978,7 @@ static int dm04_lme2510_set_voltage(stru + static u8 rbuf[1]; + int ret = 0, len = 3, rlen = 1; + +- if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) +- return -EAGAIN; ++ mutex_lock(&adap->dev->i2c_mutex); + + switch (voltage) { + case SEC_VOLTAGE_18: +@@ -937,12 +999,31 @@ static int dm04_lme2510_set_voltage(stru + return (ret < 0) ? -ENODEV : 0; + } + ++static int dm04_rs2000_read_signal_strength(struct dvb_frontend *fe, ++ u16 *strength) ++{ ++ struct dvb_usb_adapter *adap = fe->dvb->priv; ++ struct lme2510_state *st = adap->dev->priv; ++ ++ *strength = (u16)((u32)st->signal_level * 0xffff / 0x7f); ++ return 0; ++} ++ ++static int dm04_rs2000_read_snr(struct dvb_frontend *fe, u16 *snr) ++{ ++ struct dvb_usb_adapter *adap = fe->dvb->priv; ++ struct lme2510_state *st = adap->dev->priv; ++ ++ *snr = (u16)((u32)st->signal_sn * 0xffff / 0xff); ++ return 0; ++} ++ + static int lme_name(struct dvb_usb_adapter *adap) + { + struct lme2510_state *st = adap->dev->priv; + const char *desc = adap->dev->desc->name; + char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395", +- " SHARP:BS2F7HZ0194"}; ++ " SHARP:BS2F7HZ0194", " RS2000"}; + char *name = adap->fe_adap[0].fe->ops.info.name; + + strlcpy(name, desc, 128); +@@ -958,60 +1039,82 @@ static int dm04_lme2510_frontend_attach( + int ret = 0; + + st->i2c_talk_onoff = 1; ++ switch (le16_to_cpu(adap->dev->udev->descriptor.idProduct)) { ++ case 0x1122: ++ case 0x1120: ++ st->i2c_gate = 4; ++ adap->fe_adap[0].fe = dvb_attach(tda10086_attach, ++ &tda10086_config, &adap->dev->i2c_adap); ++ if (adap->fe_adap[0].fe) { ++ info("TUN Found Frontend TDA10086"); ++ st->i2c_tuner_gate_w = 4; ++ st->i2c_tuner_gate_r = 4; ++ st->i2c_tuner_addr = 0xc0; ++ st->tuner_config = TUNER_LG; ++ if (dvb_usb_lme2510_firmware != TUNER_LG) { ++ dvb_usb_lme2510_firmware = TUNER_LG; ++ ret = lme_firmware_switch(adap->dev->udev, 1); ++ } ++ break; ++ } + +- st->i2c_gate = 4; +- adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config, +- &adap->dev->i2c_adap); +- +- if (adap->fe_adap[0].fe) { +- info("TUN Found Frontend TDA10086"); +- st->i2c_tuner_gate_w = 4; +- st->i2c_tuner_gate_r = 4; +- st->i2c_tuner_addr = 0xc0; +- st->tuner_config = TUNER_LG; +- if (dvb_usb_lme2510_firmware != TUNER_LG) { +- dvb_usb_lme2510_firmware = TUNER_LG; +- ret = lme_firmware_switch(adap->dev->udev, 1); ++ st->i2c_gate = 4; ++ adap->fe_adap[0].fe = dvb_attach(stv0299_attach, ++ &sharp_z0194_config, &adap->dev->i2c_adap); ++ if (adap->fe_adap[0].fe) { ++ info("FE Found Stv0299"); ++ st->i2c_tuner_gate_w = 4; ++ st->i2c_tuner_gate_r = 5; ++ st->i2c_tuner_addr = 0xc0; ++ st->tuner_config = TUNER_S0194; ++ if (dvb_usb_lme2510_firmware != TUNER_S0194) { ++ dvb_usb_lme2510_firmware = TUNER_S0194; ++ ret = lme_firmware_switch(adap->dev->udev, 1); ++ } ++ break; + } +- goto end; +- } + +- st->i2c_gate = 4; +- adap->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194_config, ++ st->i2c_gate = 5; ++ adap->fe_adap[0].fe = dvb_attach(stv0288_attach, &lme_config, + &adap->dev->i2c_adap); +- if (adap->fe_adap[0].fe) { +- info("FE Found Stv0299"); +- st->i2c_tuner_gate_w = 4; +- st->i2c_tuner_gate_r = 5; +- st->i2c_tuner_addr = 0xc0; +- st->tuner_config = TUNER_S0194; +- if (dvb_usb_lme2510_firmware != TUNER_S0194) { +- dvb_usb_lme2510_firmware = TUNER_S0194; +- ret = lme_firmware_switch(adap->dev->udev, 1); ++ ++ if (adap->fe_adap[0].fe) { ++ info("FE Found Stv0288"); ++ st->i2c_tuner_gate_w = 4; ++ st->i2c_tuner_gate_r = 5; ++ st->i2c_tuner_addr = 0xc0; ++ st->tuner_config = TUNER_S7395; ++ if (dvb_usb_lme2510_firmware != TUNER_S7395) { ++ dvb_usb_lme2510_firmware = TUNER_S7395; ++ ret = lme_firmware_switch(adap->dev->udev, 1); ++ } ++ break; + } +- goto end; +- } ++ case 0x22f0: ++ st->i2c_gate = 5; ++ adap->fe_adap[0].fe = dvb_attach(m88rs2000_attach, ++ &m88rs2000_config, &adap->dev->i2c_adap); + +- st->i2c_gate = 5; +- adap->fe_adap[0].fe = dvb_attach(stv0288_attach, &lme_config, +- &adap->dev->i2c_adap); +- if (adap->fe_adap[0].fe) { +- info("FE Found Stv0288"); +- st->i2c_tuner_gate_w = 4; +- st->i2c_tuner_gate_r = 5; +- st->i2c_tuner_addr = 0xc0; +- st->tuner_config = TUNER_S7395; +- if (dvb_usb_lme2510_firmware != TUNER_S7395) { +- dvb_usb_lme2510_firmware = TUNER_S7395; +- ret = lme_firmware_switch(adap->dev->udev, 1); ++ if (adap->fe_adap[0].fe) { ++ info("FE Found M88RS2000"); ++ st->i2c_tuner_gate_w = 5; ++ st->i2c_tuner_gate_r = 5; ++ st->i2c_tuner_addr = 0xc0; ++ st->tuner_config = TUNER_RS2000; ++ adap->fe_adap[0].fe->ops.read_signal_strength = ++ dm04_rs2000_read_signal_strength; ++ adap->fe_adap[0].fe->ops.read_snr = ++ dm04_rs2000_read_snr; + } +- } else { +- info("DM04 Not Supported"); +- return -ENODEV; ++ break; + } + ++ if (adap->fe_adap[0].fe == NULL) { ++ info("DM04/QQBOX Not Powered up or not Supported"); ++ return -ENODEV; ++ } + +-end: if (ret) { ++ if (ret) { + if (adap->fe_adap[0].fe) { + dvb_frontend_detach(adap->fe_adap[0].fe); + adap->fe_adap[0].fe = NULL; +@@ -1028,7 +1131,7 @@ end: if (ret) { + static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) + { + struct lme2510_state *st = adap->dev->priv; +- char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA"}; ++ char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA", "RS2000"}; + int ret = 0; + + switch (st->tuner_config) { +@@ -1047,6 +1150,9 @@ static int dm04_lme2510_tuner(struct dvb + &adap->dev->i2c_adap, DVB_PLL_OPERA1)) + ret = st->tuner_config; + break; ++ case TUNER_RS2000: ++ ret = st->tuner_config; ++ break; + default: + break; + } +@@ -1054,7 +1160,7 @@ static int dm04_lme2510_tuner(struct dvb + if (ret) + info("TUN Found %s tuner", tun_msg[ret]); + else { +- info("TUN No tuner found --- reseting device"); ++ info("TUN No tuner found --- resetting device"); + lme_coldreset(adap->dev->udev); + return -ENODEV; + } +@@ -1075,10 +1181,9 @@ static int lme2510_powerup(struct dvb_us + static u8 lnb_on[] = LNB_ON; + static u8 lnb_off[] = LNB_OFF; + static u8 rbuf[1]; +- int ret, len = 3, rlen = 1; ++ int ret = 0, len = 3, rlen = 1; + +- if (mutex_lock_interruptible(&d->i2c_mutex) < 0) +- return -EAGAIN; ++ mutex_lock(&d->i2c_mutex); + + if (onoff) + ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen); +@@ -1136,6 +1241,7 @@ static int lme2510_probe(struct usb_inte + static struct usb_device_id lme2510_table[] = { + { USB_DEVICE(0x3344, 0x1122) }, /* LME2510 */ + { USB_DEVICE(0x3344, 0x1120) }, /* LME2510C */ ++ { USB_DEVICE(0x3344, 0x22f0) }, /* LME2510C RS2000 */ + {} /* Terminating entry */ + }; + +@@ -1153,7 +1259,7 @@ static struct dvb_usb_device_properties + DVB_USB_ADAP_NEED_PID_FILTERING| + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .streaming_ctrl = lme2510_streaming_ctrl, +- .pid_filter_count = 15, ++ .pid_filter_count = 32, + .pid_filter = lme2510_pid_filter, + .pid_filter_ctrl = lme2510_pid_filter_ctrl, + .frontend_attach = dm04_lme2510_frontend_attach, +@@ -1204,7 +1310,7 @@ static struct dvb_usb_device_properties + DVB_USB_ADAP_NEED_PID_FILTERING| + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .streaming_ctrl = lme2510_streaming_ctrl, +- .pid_filter_count = 15, ++ .pid_filter_count = 32, + .pid_filter = lme2510_pid_filter, + .pid_filter_ctrl = lme2510_pid_filter_ctrl, + .frontend_attach = dm04_lme2510_frontend_attach, +@@ -1234,11 +1340,14 @@ static struct dvb_usb_device_properties + .identify_state = lme2510_identify_state, + .i2c_algo = &lme2510_i2c_algo, + .generic_bulk_ctrl_endpoint = 0, +- .num_device_descs = 1, ++ .num_device_descs = 2, + .devices = { + { "DM04_LME2510C_DVB-S", + { &lme2510_table[1], NULL }, + }, ++ { "DM04_LME2510C_DVB-S RS2000", ++ { &lme2510_table[2], NULL }, ++ }, + } + }; + +@@ -1295,5 +1404,5 @@ module_usb_driver(lme2510_driver); + + MODULE_AUTHOR("Malcolm Priestley "); + MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); +-MODULE_VERSION("1.91"); ++MODULE_VERSION("1.99"); + MODULE_LICENSE("GPL"); +Index: linux-3.3.x86_64/drivers/media/video/ov6650.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ov6650.c ++++ linux-3.3.x86_64/drivers/media/video/ov6650.c +@@ -649,7 +649,7 @@ static int ov6650_s_fmt(struct v4l2_subd + clkrc = CLKRC_24MHz; + } else { + dev_err(&client->dev, +- "unspported input clock, check platform data\n"); ++ "unsupported input clock, check platform data\n"); + return -EINVAL; + } + mclk = sense->master_clock; +@@ -1046,18 +1046,7 @@ static struct i2c_driver ov6650_i2c_driv + .id_table = ov6650_id, + }; + +-static int __init ov6650_module_init(void) +-{ +- return i2c_add_driver(&ov6650_i2c_driver); +-} +- +-static void __exit ov6650_module_exit(void) +-{ +- i2c_del_driver(&ov6650_i2c_driver); +-} +- +-module_init(ov6650_module_init); +-module_exit(ov6650_module_exit); ++module_i2c_driver(ov6650_i2c_driver); + + MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650"); + MODULE_AUTHOR("Janusz Krzysztofik "); +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/tda1004x.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/tda1004x.c ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/tda1004x.c +@@ -1272,7 +1272,7 @@ struct dvb_frontend* tda10045_attach(con + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL); + if (!state) { +- printk(KERN_ERR "Can't alocate memory for tda10045 state\n"); ++ printk(KERN_ERR "Can't allocate memory for tda10045 state\n"); + return NULL; + } + +@@ -1342,7 +1342,7 @@ struct dvb_frontend* tda10046_attach(con + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL); + if (!state) { +- printk(KERN_ERR "Can't alocate memory for tda10046 state\n"); ++ printk(KERN_ERR "Can't allocate memory for tda10046 state\n"); + return NULL; + } + +Index: linux-3.3.x86_64/drivers/media/video/davinci/vpif.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/davinci/vpif.h ++++ linux-3.3.x86_64/drivers/media/video/davinci/vpif.h +@@ -18,8 +18,6 @@ + + #include + #include +-#include +-#include + #include + + /* Maximum channel allowed */ +Index: linux-3.3.x86_64/drivers/media/video/davinci/vpif_display.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/davinci/vpif_display.c ++++ linux-3.3.x86_64/drivers/media/video/davinci/vpif_display.c +@@ -39,8 +39,6 @@ + #include + #include + +-#include +- + #include "vpif_display.h" + #include "vpif.h" + +Index: linux-3.3.x86_64/include/media/davinci/vpif_types.h +=================================================================== +--- linux-3.3.x86_64.orig/include/media/davinci/vpif_types.h ++++ linux-3.3.x86_64/include/media/davinci/vpif_types.h +@@ -17,6 +17,8 @@ + #ifndef _VPIF_TYPES_H + #define _VPIF_TYPES_H + ++#include ++ + #define VPIF_CAPTURE_MAX_CHANNELS 2 + + enum vpif_if_type { +Index: linux-3.3.x86_64/drivers/media/video/tm6000/tm6000-input.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/tm6000/tm6000-input.c ++++ linux-3.3.x86_64/drivers/media/video/tm6000/tm6000-input.c +@@ -481,8 +481,6 @@ int tm6000_ir_fini(struct tm6000_core *d + + dprintk(2, "%s\n",__func__); + +- rc_unregister_device(ir->rc); +- + if (!ir->polling) + __tm6000_ir_int_stop(ir->rc); + +@@ -492,6 +490,7 @@ int tm6000_ir_fini(struct tm6000_core *d + tm6000_flash_led(dev, 0); + ir->pwled = 0; + ++ rc_unregister_device(ir->rc); + + kfree(ir); + dev->ir = NULL; +Index: linux-3.3.x86_64/drivers/media/dvb/mantis/mantis_hif.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/mantis/mantis_hif.c ++++ linux-3.3.x86_64/drivers/media/dvb/mantis/mantis_hif.c +@@ -76,7 +76,7 @@ static int mantis_hif_write_wait(struct + udelay(500); + timeout++; + if (timeout > 100) { +- dprintk(MANTIS_ERROR, 1, "Adater(%d) Slot(0): Write operation timed out!", mantis->num); ++ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write operation timed out!", mantis->num); + rc = -ETIMEDOUT; + break; + } +Index: linux-3.3.x86_64/drivers/media/common/tuners/max2165.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/common/tuners/max2165.c ++++ linux-3.3.x86_64/drivers/media/common/tuners/max2165.c +@@ -168,7 +168,7 @@ int fixpt_div32(u32 dividend, u32 diviso + int i; + + if (0 == divisor) +- return -1; ++ return -EINVAL; + + q = dividend / divisor; + remainder = dividend - q * divisor; +@@ -194,10 +194,13 @@ static int max2165_set_rf(struct max2165 + u8 tf_ntch; + u32 t; + u32 quotient, fraction; ++ int ret; + + /* Set PLL divider according to RF frequency */ +- fixpt_div32(freq / 1000, priv->config->osc_clk * 1000, +- "ient, &fraction); ++ ret = fixpt_div32(freq / 1000, priv->config->osc_clk * 1000, ++ "ient, &fraction); ++ if (ret != 0) ++ return ret; + + /* 20-bit fraction */ + fraction >>= 12; +Index: linux-3.3.x86_64/drivers/media/video/v4l2-compat-ioctl32.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/v4l2-compat-ioctl32.c ++++ linux-3.3.x86_64/drivers/media/video/v4l2-compat-ioctl32.c +@@ -14,12 +14,11 @@ + */ + + #include +-#include + #include ++#include ++#include + #include + +-#ifdef CONFIG_COMPAT +- + static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + { + long ret = -ENOIOCTLCMD; +@@ -937,6 +936,7 @@ static long do_video_ioctl(struct file * + + long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) + { ++ struct video_device *vdev = video_devdata(file); + long ret = -ENOIOCTLCMD; + + if (!file->f_op->unlocked_ioctl) +@@ -1005,6 +1005,8 @@ long v4l2_compat_ioctl32(struct file *fi + case VIDIOC_G_ENC_INDEX: + case VIDIOC_ENCODER_CMD: + case VIDIOC_TRY_ENCODER_CMD: ++ case VIDIOC_DECODER_CMD: ++ case VIDIOC_TRY_DECODER_CMD: + case VIDIOC_DBG_S_REGISTER: + case VIDIOC_DBG_G_REGISTER: + case VIDIOC_DBG_G_CHIP_IDENT: +@@ -1025,14 +1027,16 @@ long v4l2_compat_ioctl32(struct file *fi + break; + + default: +- printk(KERN_WARNING "compat_ioctl32: " +- "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n", +- _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd); ++ if (vdev->fops->compat_ioctl32) ++ ret = vdev->fops->compat_ioctl32(file, cmd, arg); ++ ++ if (ret == -ENOIOCTLCMD) ++ printk(KERN_WARNING "compat_ioctl32: " ++ "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n", ++ _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), ++ cmd); + break; + } + return ret; + } + EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32); +-#endif +- +-MODULE_LICENSE("GPL"); +Index: linux-3.3.x86_64/include/media/v4l2-ioctl.h +=================================================================== +--- linux-3.3.x86_64.orig/include/media/v4l2-ioctl.h ++++ linux-3.3.x86_64/include/media/v4l2-ioctl.h +@@ -211,6 +211,10 @@ struct v4l2_ioctl_ops { + struct v4l2_encoder_cmd *a); + int (*vidioc_try_encoder_cmd) (struct file *file, void *fh, + struct v4l2_encoder_cmd *a); ++ int (*vidioc_decoder_cmd) (struct file *file, void *fh, ++ struct v4l2_decoder_cmd *a); ++ int (*vidioc_try_decoder_cmd) (struct file *file, void *fh, ++ struct v4l2_decoder_cmd *a); + + /* Stream type-dependent parameter ioctls */ + int (*vidioc_g_parm) (struct file *file, void *fh, +Index: linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-driver.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ivtv/ivtv-driver.c ++++ linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-driver.c +@@ -55,7 +55,7 @@ + #include "ivtv-routing.h" + #include "ivtv-controls.h" + #include "ivtv-gpio.h" +- ++#include + #include + #include + #include +@@ -99,7 +99,7 @@ static int i2c_clock_period[IVTV_MAX_CAR + + static unsigned int cardtype_c = 1; + static unsigned int tuner_c = 1; +-static bool radio_c = 1; ++static int radio_c = 1; + static unsigned int i2c_clock_period_c = 1; + static char pal[] = "---"; + static char secam[] = "--"; +@@ -139,7 +139,7 @@ static int tunertype = -1; + static int newi2c = -1; + + module_param_array(tuner, int, &tuner_c, 0644); +-module_param_array(radio, bool, &radio_c, 0644); ++module_param_array(radio, int, &radio_c, 0644); + module_param_array(cardtype, int, &cardtype_c, 0644); + module_param_string(pal, pal, sizeof(pal), 0644); + module_param_string(secam, secam, sizeof(secam), 0644); +@@ -744,8 +744,6 @@ static int __devinit ivtv_init_struct1(s + + itv->cur_dma_stream = -1; + itv->cur_pio_stream = -1; +- itv->audio_stereo_mode = AUDIO_STEREO; +- itv->audio_bilingual_mode = AUDIO_MONO_LEFT; + + /* Ctrls */ + itv->speed = 1000; +@@ -815,7 +813,7 @@ static int ivtv_setup_pci(struct ivtv *i + IVTV_ERR("Can't enable device!\n"); + return -EIO; + } +- if (pci_set_dma_mask(pdev, 0xffffffff)) { ++ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { + IVTV_ERR("No suitable DMA available.\n"); + return -EIO; + } +@@ -1200,6 +1198,32 @@ static int __devinit ivtv_probe(struct p + itv->tuner_std = itv->std; + + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { ++ struct v4l2_ctrl_handler *hdl = itv->v4l2_dev.ctrl_handler; ++ ++ itv->ctrl_pts = v4l2_ctrl_new_std(hdl, &ivtv_hdl_out_ops, ++ V4L2_CID_MPEG_VIDEO_DEC_PTS, 0, 0, 1, 0); ++ itv->ctrl_frame = v4l2_ctrl_new_std(hdl, &ivtv_hdl_out_ops, ++ V4L2_CID_MPEG_VIDEO_DEC_FRAME, 0, 0x7fffffff, 1, 0); ++ /* Note: V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO is not supported, ++ mask that menu item. */ ++ itv->ctrl_audio_playback = ++ v4l2_ctrl_new_std_menu(hdl, &ivtv_hdl_out_ops, ++ V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK, ++ V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO, ++ 1 << V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO, ++ V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO); ++ itv->ctrl_audio_multilingual_playback = ++ v4l2_ctrl_new_std_menu(hdl, &ivtv_hdl_out_ops, ++ V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK, ++ V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO, ++ 1 << V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO, ++ V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT); ++ if (hdl->error) { ++ retval = hdl->error; ++ goto free_i2c; ++ } ++ v4l2_ctrl_cluster(2, &itv->ctrl_pts); ++ v4l2_ctrl_cluster(2, &itv->ctrl_audio_playback); + ivtv_call_all(itv, video, s_std_output, itv->std); + /* Turn off the output signal. The mpeg decoder is not yet + active so without this you would get a green image until the +@@ -1236,6 +1260,7 @@ free_streams: + free_irq: + free_irq(itv->pdev->irq, (void *)itv); + free_i2c: ++ v4l2_ctrl_handler_free(&itv->cxhdl.hdl); + exit_ivtv_i2c(itv); + free_io: + ivtv_iounmap(itv); +@@ -1375,7 +1400,7 @@ static void ivtv_remove(struct pci_dev * + else + type = IVTV_DEC_STREAM_TYPE_MPG; + ivtv_stop_v4l2_decode_stream(&itv->streams[type], +- VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); ++ V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY, 0); + } + ivtv_halt_firmware(itv); + } +@@ -1391,6 +1416,8 @@ static void ivtv_remove(struct pci_dev * + ivtv_streams_cleanup(itv, 1); + ivtv_udma_free(itv); + ++ v4l2_ctrl_handler_free(&itv->cxhdl.hdl); ++ + exit_ivtv_i2c(itv); + + free_irq(itv->pdev->irq, (void *)itv); +Index: linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-fileops.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ivtv/ivtv-fileops.c ++++ linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-fileops.c +@@ -746,8 +746,9 @@ unsigned int ivtv_v4l2_dec_poll(struct f + return res; + } + +-unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) ++unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table *wait) + { ++ unsigned long req_events = poll_requested_events(wait); + struct ivtv_open_id *id = fh2id(filp->private_data); + struct ivtv *itv = id->itv; + struct ivtv_stream *s = &itv->streams[id->type]; +@@ -755,7 +756,8 @@ unsigned int ivtv_v4l2_enc_poll(struct f + unsigned res = 0; + + /* Start a capture if there is none */ +- if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { ++ if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags) && ++ (req_events & (POLLIN | POLLRDNORM))) { + int rc; + + rc = ivtv_start_capture(id); +@@ -900,7 +902,7 @@ int ivtv_v4l2_close(struct file *filp) + if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) { + struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT]; + +- ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); ++ ivtv_stop_decoding(id, V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY, 0); + + /* If all output streams are closed, and if the user doesn't have + IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */ +Index: linux-3.3.x86_64/drivers/media/video/v4l2-ctrls.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/v4l2-ctrls.c ++++ linux-3.3.x86_64/drivers/media/video/v4l2-ctrls.c +@@ -175,6 +175,15 @@ const char * const *v4l2_ctrl_get_menu(u + "16-bit CRC", + NULL + }; ++ static const char * const mpeg_audio_dec_playback[] = { ++ "Auto", ++ "Stereo", ++ "Left", ++ "Right", ++ "Mono", ++ "Swapped Stereo", ++ NULL ++ }; + static const char * const mpeg_video_encoding[] = { + "MPEG-1", + "MPEG-2", +@@ -236,8 +245,8 @@ const char * const *v4l2_ctrl_get_menu(u + }; + static const char * const tune_preemphasis[] = { + "No Preemphasis", +- "50 useconds", +- "75 useconds", ++ "50 Microseconds", ++ "75 Microseconds", + NULL, + }; + static const char * const header_mode[] = { +@@ -334,7 +343,7 @@ const char * const *v4l2_ctrl_get_menu(u + }; + static const char * const mpeg4_profile[] = { + "Simple", +- "Adcanved Simple", ++ "Advanced Simple", + "Core", + "Simple Scalable", + "Advanced Coding Efficency", +@@ -353,6 +362,16 @@ const char * const *v4l2_ctrl_get_menu(u + NULL, + }; + ++ static const char * const jpeg_chroma_subsampling[] = { ++ "4:4:4", ++ "4:2:2", ++ "4:2:0", ++ "4:1:1", ++ "4:1:0", ++ "Gray", ++ NULL, ++ }; ++ + switch (id) { + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + return mpeg_audio_sampling_freq; +@@ -374,6 +393,9 @@ const char * const *v4l2_ctrl_get_menu(u + return mpeg_audio_emphasis; + case V4L2_CID_MPEG_AUDIO_CRC: + return mpeg_audio_crc; ++ case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: ++ case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: ++ return mpeg_audio_dec_playback; + case V4L2_CID_MPEG_VIDEO_ENCODING: + return mpeg_video_encoding; + case V4L2_CID_MPEG_VIDEO_ASPECT: +@@ -414,6 +436,9 @@ const char * const *v4l2_ctrl_get_menu(u + return mpeg_mpeg4_level; + case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: + return mpeg4_profile; ++ case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: ++ return jpeg_chroma_subsampling; ++ + default: + return NULL; + } +@@ -492,6 +517,8 @@ const char *v4l2_ctrl_get_name(u32 id) + case V4L2_CID_MPEG_AUDIO_MUTE: return "Audio Mute"; + case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate"; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate"; ++ case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: return "Audio Playback"; ++ case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: return "Audio Multilingual Playback"; + case V4L2_CID_MPEG_VIDEO_ENCODING: return "Video Encoding"; + case V4L2_CID_MPEG_VIDEO_ASPECT: return "Video Aspect"; + case V4L2_CID_MPEG_VIDEO_B_FRAMES: return "Video B Frames"; +@@ -546,6 +573,8 @@ const char *v4l2_ctrl_get_name(u32 id) + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: return "Number of MBs in a Slice"; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: return "Slice Partitioning Method"; + case V4L2_CID_MPEG_VIDEO_VBV_SIZE: return "VBV Buffer Size"; ++ case V4L2_CID_MPEG_VIDEO_DEC_PTS: return "Video Decoder PTS"; ++ case V4L2_CID_MPEG_VIDEO_DEC_FRAME: return "Video Decoder Frame Count"; + + /* CAMERA controls */ + /* Keep the order of the 'case's the same as in videodev2.h! */ +@@ -607,6 +636,14 @@ const char *v4l2_ctrl_get_name(u32 id) + case V4L2_CID_FLASH_CHARGE: return "Charge"; + case V4L2_CID_FLASH_READY: return "Ready to Strobe"; + ++ /* JPEG encoder controls */ ++ /* Keep the order of the 'case's the same as in videodev2.h! */ ++ case V4L2_CID_JPEG_CLASS: return "JPEG Compression Controls"; ++ case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: return "Chroma Subsampling"; ++ case V4L2_CID_JPEG_RESTART_INTERVAL: return "Restart Interval"; ++ case V4L2_CID_JPEG_COMPRESSION_QUALITY: return "Compression Quality"; ++ case V4L2_CID_JPEG_ACTIVE_MARKER: return "Active Markers"; ++ + default: + return NULL; + } +@@ -674,6 +711,8 @@ void v4l2_ctrl_fill(u32 id, const char * + case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: + case V4L2_CID_MPEG_AUDIO_EMPHASIS: + case V4L2_CID_MPEG_AUDIO_CRC: ++ case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: ++ case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: + case V4L2_CID_MPEG_VIDEO_ENCODING: + case V4L2_CID_MPEG_VIDEO_ASPECT: + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: +@@ -693,6 +732,7 @@ void v4l2_ctrl_fill(u32 id, const char * + case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: + case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: + case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: ++ case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: + *type = V4L2_CTRL_TYPE_MENU; + break; + case V4L2_CID_RDS_TX_PS_NAME: +@@ -704,6 +744,7 @@ void v4l2_ctrl_fill(u32 id, const char * + case V4L2_CID_MPEG_CLASS: + case V4L2_CID_FM_TX_CLASS: + case V4L2_CID_FLASH_CLASS: ++ case V4L2_CID_JPEG_CLASS: + *type = V4L2_CTRL_TYPE_CTRL_CLASS; + /* You can neither read not write these */ + *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY; +@@ -717,6 +758,7 @@ void v4l2_ctrl_fill(u32 id, const char * + *max = 0xFFFFFF; + break; + case V4L2_CID_FLASH_FAULT: ++ case V4L2_CID_JPEG_ACTIVE_MARKER: + *type = V4L2_CTRL_TYPE_BITMASK; + break; + case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: +@@ -724,6 +766,11 @@ void v4l2_ctrl_fill(u32 id, const char * + *type = V4L2_CTRL_TYPE_INTEGER; + *flags |= V4L2_CTRL_FLAG_READ_ONLY; + break; ++ case V4L2_CID_MPEG_VIDEO_DEC_FRAME: ++ case V4L2_CID_MPEG_VIDEO_DEC_PTS: ++ *type = V4L2_CTRL_TYPE_INTEGER64; ++ *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE; ++ break; + default: + *type = V4L2_CTRL_TYPE_INTEGER; + break; +@@ -1470,7 +1517,7 @@ EXPORT_SYMBOL(v4l2_ctrl_add_ctrl); + int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl, + struct v4l2_ctrl_handler *add) + { +- struct v4l2_ctrl *ctrl; ++ struct v4l2_ctrl_ref *ref; + int ret = 0; + + /* Do nothing if either handler is NULL or if they are the same */ +@@ -1479,7 +1526,9 @@ int v4l2_ctrl_add_handler(struct v4l2_ct + if (hdl->error) + return hdl->error; + mutex_lock(&add->lock); +- list_for_each_entry(ctrl, &add->ctrls, node) { ++ list_for_each_entry(ref, &add->ctrl_refs, node) { ++ struct v4l2_ctrl *ctrl = ref->ctrl; ++ + /* Skip handler-private controls. */ + if (ctrl->is_private) + continue; +@@ -2359,3 +2408,35 @@ void v4l2_ctrl_del_event(struct v4l2_ctr + v4l2_ctrl_unlock(ctrl); + } + EXPORT_SYMBOL(v4l2_ctrl_del_event); ++ ++int v4l2_ctrl_log_status(struct file *file, void *fh) ++{ ++ struct video_device *vfd = video_devdata(file); ++ struct v4l2_fh *vfh = file->private_data; ++ ++ if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) && vfd->v4l2_dev) ++ v4l2_ctrl_handler_log_status(vfh->ctrl_handler, ++ vfd->v4l2_dev->name); ++ return 0; ++} ++EXPORT_SYMBOL(v4l2_ctrl_log_status); ++ ++int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh, ++ struct v4l2_event_subscription *sub) ++{ ++ if (sub->type == V4L2_EVENT_CTRL) ++ return v4l2_event_subscribe(fh, sub, 0); ++ return -EINVAL; ++} ++EXPORT_SYMBOL(v4l2_ctrl_subscribe_event); ++ ++unsigned int v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait) ++{ ++ struct v4l2_fh *fh = file->private_data; ++ ++ if (v4l2_event_pending(fh)) ++ return POLLPRI; ++ poll_wait(file, &fh->wait, wait); ++ return 0; ++} ++EXPORT_SYMBOL(v4l2_ctrl_poll); +Index: linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-controls.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ivtv/ivtv-controls.c ++++ linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-controls.c +@@ -21,6 +21,7 @@ + #include "ivtv-driver.h" + #include "ivtv-ioctl.h" + #include "ivtv-controls.h" ++#include "ivtv-mailbox.h" + + static int ivtv_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt) + { +@@ -99,3 +100,64 @@ struct cx2341x_handler_ops ivtv_cxhdl_op + .s_video_encoding = ivtv_s_video_encoding, + .s_stream_vbi_fmt = ivtv_s_stream_vbi_fmt, + }; ++ ++int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame) ++{ ++ u32 data[CX2341X_MBOX_MAX_DATA]; ++ ++ if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { ++ *pts = (s64)((u64)itv->last_dec_timing[2] << 32) | ++ (u64)itv->last_dec_timing[1]; ++ *frame = itv->last_dec_timing[0]; ++ return 0; ++ } ++ *pts = 0; ++ *frame = 0; ++ if (atomic_read(&itv->decoding)) { ++ if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { ++ IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); ++ return -EIO; ++ } ++ memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); ++ set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); ++ *pts = (s64)((u64) data[2] << 32) | (u64) data[1]; ++ *frame = data[0]; ++ /*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/ ++ } ++ return 0; ++} ++ ++static int ivtv_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct ivtv *itv = container_of(ctrl->handler, struct ivtv, cxhdl.hdl); ++ ++ switch (ctrl->id) { ++ /* V4L2_CID_MPEG_VIDEO_DEC_PTS and V4L2_CID_MPEG_VIDEO_DEC_FRAME ++ control cluster */ ++ case V4L2_CID_MPEG_VIDEO_DEC_PTS: ++ return ivtv_g_pts_frame(itv, &itv->ctrl_pts->val64, ++ &itv->ctrl_frame->val64); ++ } ++ return 0; ++} ++ ++static int ivtv_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct ivtv *itv = container_of(ctrl->handler, struct ivtv, cxhdl.hdl); ++ ++ switch (ctrl->id) { ++ /* V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK and MULTILINGUAL_PLAYBACK ++ control cluster */ ++ case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: ++ itv->audio_stereo_mode = itv->ctrl_audio_playback->val - 1; ++ itv->audio_bilingual_mode = itv->ctrl_audio_multilingual_playback->val - 1; ++ ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); ++ break; ++ } ++ return 0; ++} ++ ++const struct v4l2_ctrl_ops ivtv_hdl_out_ops = { ++ .s_ctrl = ivtv_s_ctrl, ++ .g_volatile_ctrl = ivtv_g_volatile_ctrl, ++}; +Index: linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-controls.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ivtv/ivtv-controls.h ++++ linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-controls.h +@@ -22,5 +22,7 @@ + #define IVTV_CONTROLS_H + + extern struct cx2341x_handler_ops ivtv_cxhdl_ops; ++extern const struct v4l2_ctrl_ops ivtv_hdl_out_ops; ++int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame); + + #endif +Index: linux-3.3.x86_64/drivers/media/dvb/ddbridge/ddbridge.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/ddbridge/ddbridge.h ++++ linux-3.3.x86_64/drivers/media/dvb/ddbridge/ddbridge.h +@@ -32,8 +32,6 @@ + #include + #include + #include +-#include +-#include + #include + + #include "dmxdev.h" +Index: linux-3.3.x86_64/drivers/media/video/cx18/cx18-driver.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/cx18/cx18-driver.h ++++ linux-3.3.x86_64/drivers/media/video/cx18/cx18-driver.h +@@ -44,8 +44,6 @@ + #include + #include + +-#include +-#include + #include + #include + #include +Index: linux-3.3.x86_64/include/linux/ivtv.h +=================================================================== +--- linux-3.3.x86_64.orig/include/linux/ivtv.h ++++ linux-3.3.x86_64/include/linux/ivtv.h +@@ -58,7 +58,11 @@ struct ivtv_dma_frame { + __u32 src_height; + }; + +-#define IVTV_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtv_dma_frame) ++#define IVTV_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtv_dma_frame) ++ ++/* Select the passthrough mode (if the argument is non-zero). In the passthrough ++ mode the output of the encoder is passed immediately into the decoder. */ ++#define IVTV_IOC_PASSTHROUGH_MODE _IOW ('V', BASE_VIDIOC_PRIVATE+1, int) + + /* Deprecated defines: applications should use the defines from videodev2.h */ + #define IVTV_SLICED_TYPE_TELETEXT_B V4L2_MPEG_VBI_IVTV_TELETEXT_B +Index: linux-3.3.x86_64/drivers/media/rc/keymaps/Makefile +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/rc/keymaps/Makefile ++++ linux-3.3.x86_64/drivers/media/rc/keymaps/Makefile +@@ -41,8 +41,11 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t + rc-imon-mce.o \ + rc-imon-pad.o \ + rc-iodata-bctv7e.o \ ++ rc-it913x-v1.o \ ++ rc-it913x-v2.o \ + rc-kaiomy.o \ + rc-kworld-315u.o \ ++ rc-kworld-pc150u.o \ + rc-kworld-plus-tv-analog.o \ + rc-leadtek-y04g0051.o \ + rc-lirc.o \ +Index: linux-3.3.x86_64/drivers/media/rc/keymaps/rc-it913x-v1.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/rc/keymaps/rc-it913x-v1.c +@@ -0,0 +1,95 @@ ++/* ITE Generic remotes Version 1 ++ * ++ * Copyright (C) 2012 Malcolm Priestley (tvboxspy@gmail.com) ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++#include ++ ++ ++static struct rc_map_table it913x_v1_rc[] = { ++ /* Type 1 */ ++ { 0x61d601, KEY_VIDEO }, /* Source */ ++ { 0x61d602, KEY_3 }, ++ { 0x61d603, KEY_POWER }, /* ShutDown */ ++ { 0x61d604, KEY_1 }, ++ { 0x61d605, KEY_5 }, ++ { 0x61d606, KEY_6 }, ++ { 0x61d607, KEY_CHANNELDOWN }, /* CH- */ ++ { 0x61d608, KEY_2 }, ++ { 0x61d609, KEY_CHANNELUP }, /* CH+ */ ++ { 0x61d60a, KEY_9 }, ++ { 0x61d60b, KEY_ZOOM }, /* Zoom */ ++ { 0x61d60c, KEY_7 }, ++ { 0x61d60d, KEY_8 }, ++ { 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */ ++ { 0x61d60f, KEY_4 }, ++ { 0x61d610, KEY_ESC }, /* [back up arrow] */ ++ { 0x61d611, KEY_0 }, ++ { 0x61d612, KEY_OK }, /* [enter arrow] */ ++ { 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */ ++ { 0x61d614, KEY_RECORD }, /* Rec */ ++ { 0x61d615, KEY_STOP }, /* Stop */ ++ { 0x61d616, KEY_PLAY }, /* Play */ ++ { 0x61d617, KEY_MUTE }, /* Mute */ ++ { 0x61d618, KEY_UP }, ++ { 0x61d619, KEY_DOWN }, ++ { 0x61d61a, KEY_LEFT }, ++ { 0x61d61b, KEY_RIGHT }, ++ { 0x61d61c, KEY_RED }, ++ { 0x61d61d, KEY_GREEN }, ++ { 0x61d61e, KEY_YELLOW }, ++ { 0x61d61f, KEY_BLUE }, ++ { 0x61d643, KEY_POWER2 }, /* [red power button] */ ++ /* Type 2 - 20 buttons */ ++ { 0x807f0d, KEY_0 }, ++ { 0x807f04, KEY_1 }, ++ { 0x807f05, KEY_2 }, ++ { 0x807f06, KEY_3 }, ++ { 0x807f07, KEY_4 }, ++ { 0x807f08, KEY_5 }, ++ { 0x807f09, KEY_6 }, ++ { 0x807f0a, KEY_7 }, ++ { 0x807f1b, KEY_8 }, ++ { 0x807f1f, KEY_9 }, ++ { 0x807f12, KEY_POWER }, ++ { 0x807f01, KEY_MEDIA_REPEAT}, /* Recall */ ++ { 0x807f19, KEY_PAUSE }, /* Timeshift */ ++ { 0x807f1e, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ ++ { 0x807f03, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ ++ { 0x807f1a, KEY_CHANNELUP }, ++ { 0x807f02, KEY_CHANNELDOWN }, ++ { 0x807f0c, KEY_ZOOM }, ++ { 0x807f00, KEY_RECORD }, ++ { 0x807f0e, KEY_STOP }, ++}; ++ ++static struct rc_map_list it913x_v1_map = { ++ .map = { ++ .scan = it913x_v1_rc, ++ .size = ARRAY_SIZE(it913x_v1_rc), ++ .rc_type = RC_TYPE_NEC, ++ .name = RC_MAP_IT913X_V1, ++ } ++}; ++ ++static int __init init_rc_it913x_v1_map(void) ++{ ++ return rc_map_register(&it913x_v1_map); ++} ++ ++static void __exit exit_rc_it913x_v1_map(void) ++{ ++ rc_map_unregister(&it913x_v1_map); ++} ++ ++module_init(init_rc_it913x_v1_map) ++module_exit(exit_rc_it913x_v1_map) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); +Index: linux-3.3.x86_64/drivers/media/rc/keymaps/rc-it913x-v2.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/rc/keymaps/rc-it913x-v2.c +@@ -0,0 +1,94 @@ ++/* ITE Generic remotes Version 2 ++ * ++ * Copyright (C) 2012 Malcolm Priestley (tvboxspy@gmail.com) ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++#include ++ ++ ++static struct rc_map_table it913x_v2_rc[] = { ++ /* Type 1 */ ++ /* 9005 remote */ ++ { 0x807f12, KEY_POWER2 }, /* Power (RED POWER BUTTON)*/ ++ { 0x807f1a, KEY_VIDEO }, /* Source */ ++ { 0x807f1e, KEY_MUTE }, /* Mute */ ++ { 0x807f01, KEY_RECORD }, /* Record */ ++ { 0x807f02, KEY_CHANNELUP }, /* Channel+ */ ++ { 0x807f03, KEY_TIME }, /* TimeShift */ ++ { 0x807f04, KEY_VOLUMEUP }, /* Volume- */ ++ { 0x807f05, KEY_SCREEN }, /* FullScreen */ ++ { 0x807f06, KEY_VOLUMEDOWN }, /* Volume- */ ++ { 0x807f07, KEY_0 }, /* 0 */ ++ { 0x807f08, KEY_CHANNELDOWN }, /* Channel- */ ++ { 0x807f09, KEY_PREVIOUS }, /* Recall */ ++ { 0x807f0a, KEY_1 }, /* 1 */ ++ { 0x807f1b, KEY_2 }, /* 2 */ ++ { 0x807f1f, KEY_3 }, /* 3 */ ++ { 0x807f0c, KEY_4 }, /* 4 */ ++ { 0x807f0d, KEY_5 }, /* 5 */ ++ { 0x807f0e, KEY_6 }, /* 6 */ ++ { 0x807f00, KEY_7 }, /* 7 */ ++ { 0x807f0f, KEY_8 }, /* 8 */ ++ { 0x807f19, KEY_9 }, /* 9 */ ++ ++ /* Type 2 */ ++ /* keys stereo, snapshot unassigned */ ++ { 0x866b00, KEY_0 }, ++ { 0x866b1b, KEY_1 }, ++ { 0x866b02, KEY_2 }, ++ { 0x866b03, KEY_3 }, ++ { 0x866b04, KEY_4 }, ++ { 0x866b05, KEY_5 }, ++ { 0x866b06, KEY_6 }, ++ { 0x866b07, KEY_7 }, ++ { 0x866b08, KEY_8 }, ++ { 0x866b09, KEY_9 }, ++ { 0x866b12, KEY_POWER }, ++ { 0x866b13, KEY_MUTE }, ++ { 0x866b0a, KEY_PREVIOUS }, /* Recall */ ++ { 0x866b1e, KEY_PAUSE }, ++ { 0x866b0c, KEY_VOLUMEUP }, ++ { 0x866b18, KEY_VOLUMEDOWN }, ++ { 0x866b0b, KEY_CHANNELUP }, ++ { 0x866b18, KEY_CHANNELDOWN }, ++ { 0x866b10, KEY_ZOOM }, ++ { 0x866b1d, KEY_RECORD }, ++ { 0x866b0e, KEY_STOP }, ++ { 0x866b11, KEY_EPG}, ++ { 0x866b1a, KEY_FASTFORWARD }, ++ { 0x866b0f, KEY_REWIND }, ++ { 0x866b1c, KEY_TV }, ++ { 0x866b1b, KEY_TEXT }, ++ ++}; ++ ++static struct rc_map_list it913x_v2_map = { ++ .map = { ++ .scan = it913x_v2_rc, ++ .size = ARRAY_SIZE(it913x_v2_rc), ++ .rc_type = RC_TYPE_NEC, ++ .name = RC_MAP_IT913X_V2, ++ } ++}; ++ ++static int __init init_rc_it913x_v2_map(void) ++{ ++ return rc_map_register(&it913x_v2_map); ++} ++ ++static void __exit exit_rc_it913x_v2_map(void) ++{ ++ rc_map_unregister(&it913x_v2_map); ++} ++ ++module_init(init_rc_it913x_v2_map) ++module_exit(exit_rc_it913x_v2_map) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); +Index: linux-3.3.x86_64/include/media/rc-map.h +=================================================================== +--- linux-3.3.x86_64.orig/include/media/rc-map.h ++++ linux-3.3.x86_64/include/media/rc-map.h +@@ -102,8 +102,11 @@ void rc_map_init(void); + #define RC_MAP_IMON_MCE "rc-imon-mce" + #define RC_MAP_IMON_PAD "rc-imon-pad" + #define RC_MAP_IODATA_BCTV7E "rc-iodata-bctv7e" ++#define RC_MAP_IT913X_V1 "rc-it913x-v1" ++#define RC_MAP_IT913X_V2 "rc-it913x-v2" + #define RC_MAP_KAIOMY "rc-kaiomy" + #define RC_MAP_KWORLD_315U "rc-kworld-315u" ++#define RC_MAP_KWORLD_PC150U "rc-kworld-pc150u" + #define RC_MAP_KWORLD_PLUS_TV_ANALOG "rc-kworld-plus-tv-analog" + #define RC_MAP_LEADTEK_Y04G0051 "rc-leadtek-y04g0051" + #define RC_MAP_LIRC "rc-lirc" +Index: linux-3.3.x86_64/drivers/media/video/bt8xx/bttv-driver.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/bt8xx/bttv-driver.c ++++ linux-3.3.x86_64/drivers/media/video/bt8xx/bttv-driver.c +@@ -2035,11 +2035,7 @@ static int bttv_log_status(struct file * + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + +- pr_info("%d: ======== START STATUS CARD #%d ========\n", +- btv->c.nr, btv->c.nr); + bttv_call_all(btv, core, log_status); +- pr_info("%d: ======== END STATUS CARD #%d ========\n", +- btv->c.nr, btv->c.nr); + return 0; + } + +Index: linux-3.3.x86_64/drivers/media/video/cx18/cx18-ioctl.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/cx18/cx18-ioctl.c ++++ linux-3.3.x86_64/drivers/media/video/cx18/cx18-ioctl.c +@@ -1085,8 +1085,6 @@ static int cx18_log_status(struct file * + struct v4l2_audio audin; + int i; + +- CX18_INFO("================= START STATUS CARD #%d " +- "=================\n", cx->instance); + CX18_INFO("Version: %s Card: %s\n", CX18_VERSION, cx->card_name); + if (cx->hw_flags & CX18_HW_TVEEPROM) { + struct tveeprom tv; +@@ -1120,8 +1118,6 @@ static int cx18_log_status(struct file * + CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", + (long long)cx->mpg_data_received, + (long long)cx->vbi_data_inserted); +- CX18_INFO("================== END STATUS CARD #%d " +- "==================\n", cx->instance); + return 0; + } + +Index: linux-3.3.x86_64/drivers/media/video/pwc/pwc-v4l.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/pwc/pwc-v4l.c ++++ linux-3.3.x86_64/drivers/media/video/pwc/pwc-v4l.c +@@ -1146,14 +1146,6 @@ leave: + return ret; + } + +-static int pwc_log_status(struct file *file, void *priv) +-{ +- struct pwc_device *pdev = video_drvdata(file); +- +- v4l2_ctrl_handler_log_status(&pdev->ctrl_handler, PWC_NAME); +- return 0; +-} +- + const struct v4l2_ioctl_ops pwc_ioctl_ops = { + .vidioc_querycap = pwc_querycap, + .vidioc_enum_input = pwc_enum_input, +@@ -1169,9 +1161,11 @@ const struct v4l2_ioctl_ops pwc_ioctl_op + .vidioc_dqbuf = pwc_dqbuf, + .vidioc_streamon = pwc_streamon, + .vidioc_streamoff = pwc_streamoff, +- .vidioc_log_status = pwc_log_status, ++ .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_enum_framesizes = pwc_enum_framesizes, + .vidioc_enum_frameintervals = pwc_enum_frameintervals, + .vidioc_g_parm = pwc_g_parm, + .vidioc_s_parm = pwc_s_parm, ++ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, ++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + }; +Index: linux-3.3.x86_64/drivers/media/video/saa7164/saa7164-encoder.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/saa7164/saa7164-encoder.c ++++ linux-3.3.x86_64/drivers/media/video/saa7164/saa7164-encoder.c +@@ -791,11 +791,6 @@ static int vidioc_s_fmt_vid_cap(struct f + return 0; + } + +-static int vidioc_log_status(struct file *file, void *priv) +-{ +- return 0; +-} +- + static int fill_queryctrl(struct saa7164_encoder_params *params, + struct v4l2_queryctrl *c) + { +@@ -1347,7 +1342,6 @@ static const struct v4l2_ioctl_ops mpeg_ + .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, + .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, + .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, +- .vidioc_log_status = vidioc_log_status, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_chip_ident = saa7164_g_chip_ident, + #ifdef CONFIG_VIDEO_ADV_DEBUG +Index: linux-3.3.x86_64/drivers/media/video/saa7164/saa7164-vbi.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/saa7164/saa7164-vbi.c ++++ linux-3.3.x86_64/drivers/media/video/saa7164/saa7164-vbi.c +@@ -730,11 +730,6 @@ static int vidioc_s_fmt_vid_cap(struct f + return 0; + } + +-static int vidioc_log_status(struct file *file, void *priv) +-{ +- return 0; +-} +- + static int fill_queryctrl(struct saa7164_vbi_params *params, + struct v4l2_queryctrl *c) + { +@@ -1256,7 +1251,6 @@ static const struct v4l2_ioctl_ops vbi_i + .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, + .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, + .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, +- .vidioc_log_status = vidioc_log_status, + .vidioc_queryctrl = vidioc_queryctrl, + #if 0 + .vidioc_g_chip_ident = saa7164_g_chip_ident, +Index: linux-3.3.x86_64/include/media/v4l2-ctrls.h +=================================================================== +--- linux-3.3.x86_64.orig/include/media/v4l2-ctrls.h ++++ linux-3.3.x86_64/include/media/v4l2-ctrls.h +@@ -33,6 +33,7 @@ struct video_device; + struct v4l2_subdev; + struct v4l2_subscribed_event; + struct v4l2_fh; ++struct poll_table_struct; + + /** struct v4l2_ctrl_ops - The control operations that the driver has to provide. + * @g_volatile_ctrl: Get a new value for this control. Generally only relevant +@@ -492,6 +493,18 @@ void v4l2_ctrl_add_event(struct v4l2_ctr + void v4l2_ctrl_del_event(struct v4l2_ctrl *ctrl, + struct v4l2_subscribed_event *sev); + ++/* Can be used as a vidioc_log_status function that just dumps all controls ++ associated with the filehandle. */ ++int v4l2_ctrl_log_status(struct file *file, void *fh); ++ ++/* Can be used as a vidioc_subscribe_event function that just subscribes ++ control events. */ ++int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh, ++ struct v4l2_event_subscription *sub); ++ ++/* Can be used as a poll function that just polls for control events. */ ++unsigned int v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait); ++ + /* Helpers for ioctl_ops. If hdl == NULL then they will all return -EINVAL. */ + int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc); + int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm); +Index: linux-3.3.x86_64/drivers/media/video/v4l2-subdev.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/v4l2-subdev.c ++++ linux-3.3.x86_64/drivers/media/video/v4l2-subdev.c +@@ -194,8 +194,16 @@ static long subdev_do_ioctl(struct file + } + #endif + +- case VIDIOC_LOG_STATUS: +- return v4l2_subdev_call(sd, core, log_status); ++ case VIDIOC_LOG_STATUS: { ++ int ret; ++ ++ pr_info("%s: ================= START STATUS =================\n", ++ sd->name); ++ ret = v4l2_subdev_call(sd, core, log_status); ++ pr_info("%s: ================== END STATUS ==================\n", ++ sd->name); ++ return ret; ++ } + + #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) + case VIDIOC_SUBDEV_G_FMT: { +Index: linux-3.3.x86_64/drivers/media/radio/Kconfig +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/radio/Kconfig ++++ linux-3.3.x86_64/drivers/media/radio/Kconfig +@@ -43,7 +43,7 @@ config USB_DSBR + + config RADIO_MAXIRADIO + tristate "Guillemot MAXI Radio FM 2000 radio" +- depends on VIDEO_V4L2 && PCI ++ depends on VIDEO_V4L2 && PCI && SND + ---help--- + Choose Y here if you have this radio card. This card may also be + found as Gemtek PCI FM. +@@ -80,6 +80,16 @@ config RADIO_SI4713 + To compile this driver as a module, choose M here: the + module will be called radio-si4713. + ++config USB_KEENE ++ tristate "Keene FM Transmitter USB support" ++ depends on USB && VIDEO_V4L2 ++ ---help--- ++ Say Y here if you want to connect this type of FM transmitter ++ to your computer's USB port. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called radio-keene. ++ + config RADIO_TEA5764 + tristate "TEA5764 I2C FM radio support" + depends on I2C && VIDEO_V4L2 +@@ -167,6 +177,10 @@ menuconfig V4L_RADIO_ISA_DRIVERS + + if V4L_RADIO_ISA_DRIVERS + ++config RADIO_ISA ++ depends on ISA ++ tristate ++ + config RADIO_CADET + tristate "ADS Cadet AM/FM Tuner" + depends on ISA && VIDEO_V4L2 +@@ -174,20 +188,13 @@ config RADIO_CADET + Choose Y here if you have one of these AM/FM radio cards, and then + fill in the port address below. + +- In order to control your radio card, you will need to use programs +- that are compatible with the Video For Linux API. Information on +- this API and pointers to "v4l" programs may be found at +- . +- +- Further documentation on this driver can be found on the WWW at +- . +- + To compile this driver as a module, choose M here: the + module will be called radio-cadet. + + config RADIO_RTRACK + tristate "AIMSlab RadioTrack (aka RadioReveal) support" + depends on ISA && VIDEO_V4L2 ++ select RADIO_ISA + ---help--- + Choose Y here if you have one of these FM radio cards, and then fill + in the port address below. +@@ -201,11 +208,7 @@ config RADIO_RTRACK + You must also pass the module a suitable io parameter, 0x248 has + been reported to be used by these cards. + +- In order to control your radio card, you will need to use programs +- that are compatible with the Video For Linux API. Information on +- this API and pointers to "v4l" programs may be found at +- . More information is +- contained in the file ++ More information is contained in the file + . + + To compile this driver as a module, choose M here: the +@@ -214,7 +217,7 @@ config RADIO_RTRACK + config RADIO_RTRACK_PORT + hex "RadioTrack i/o port (0x20f or 0x30f)" + depends on RADIO_RTRACK=y +- default "20f" ++ default "30f" + help + Enter either 0x30f or 0x20f here. The card default is 0x30f, if you + haven't changed the jumper setting on the card. +@@ -222,14 +225,14 @@ config RADIO_RTRACK_PORT + config RADIO_RTRACK2 + tristate "AIMSlab RadioTrack II support" + depends on ISA && VIDEO_V4L2 ++ select RADIO_ISA + ---help--- + Choose Y here if you have this FM radio card, and then fill in the + port address below. + +- In order to control your radio card, you will need to use programs +- that are compatible with the Video For Linux API. Information on +- this API and pointers to "v4l" programs may be found at +- . ++ Note: this driver hasn't been tested since a long time due to lack ++ of hardware. If you have this hardware, then please contact the ++ linux-media mailinglist. + + To compile this driver as a module, choose M here: the + module will be called radio-rtrack2. +@@ -245,15 +248,11 @@ config RADIO_RTRACK2_PORT + config RADIO_AZTECH + tristate "Aztech/Packard Bell Radio" + depends on ISA && VIDEO_V4L2 ++ select RADIO_ISA + ---help--- + Choose Y here if you have one of these FM radio cards, and then fill + in the port address below. + +- In order to control your radio card, you will need to use programs +- that are compatible with the Video For Linux API. Information on +- this API and pointers to "v4l" programs may be found at +- . +- + To compile this driver as a module, choose M here: the + module will be called radio-aztech. + +@@ -269,6 +268,7 @@ config RADIO_AZTECH_PORT + config RADIO_GEMTEK + tristate "GemTek Radio card (or compatible) support" + depends on ISA && VIDEO_V4L2 ++ select RADIO_ISA + ---help--- + Choose Y here if you have this FM radio card, and then fill in the + I/O port address and settings below. The following cards either have +@@ -278,23 +278,21 @@ config RADIO_GEMTEK + - Typhoon Radio card (some models) + - Hama Radio card + +- In order to control your radio card, you will need to use programs +- that are compatible with the Video For Linux API. Information on +- this API and pointers to "v4l" programs may be found at +- . +- + To compile this driver as a module, choose M here: the + module will be called radio-gemtek. + + config RADIO_GEMTEK_PORT +- hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0c24c or 0x28c)" ++ hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0x248 or 0x28c)" + depends on RADIO_GEMTEK=y + default "34c" + help +- Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is +- 0x34c, if you haven't changed the jumper setting on the card. On +- Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O ++ Enter either 0x20c, 0x30c, 0x24c, 0x34c, 0x248 or 0x28c here. The ++ card default is 0x34c, if you haven't changed the jumper setting ++ on the card. ++ ++ On Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O + port is 0x20c, 0x248 or 0x28c. ++ + If automatic I/O port probing is enabled this port will be used only + in case of automatic probing failure, ie. as a fallback. + +@@ -318,11 +316,6 @@ config RADIO_MIROPCM20 + sound card driver "Miro miroSOUND PCM1pro/PCM12/PCM20radio" as this + is required for the radio-miropcm20. + +- In order to control your radio card, you will need to use programs +- that are compatible with the Video For Linux API. Information on +- this API and pointers to "v4l" programs may be found at +- . +- + To compile this driver as a module, choose M here: the + module will be called radio-miropcm20. + +@@ -332,11 +325,6 @@ config RADIO_SF16FMI + ---help--- + Choose Y here if you have one of these FM radio cards. + +- In order to control your radio card, you will need to use programs +- that are compatible with the Video For Linux API. Information on +- this API and pointers to "v4l" programs may be found at +- . +- + To compile this driver as a module, choose M here: the + module will be called radio-sf16fmi. + +@@ -346,50 +334,35 @@ config RADIO_SF16FMR2 + ---help--- + Choose Y here if you have one of these FM radio cards. + +- In order to control your radio card, you will need to use programs +- that are compatible with the Video For Linux API. Information on +- this API and pointers to "v4l" programs may be found on the WWW at +- . +- + To compile this driver as a module, choose M here: the + module will be called radio-sf16fmr2. + + config RADIO_TERRATEC + tristate "TerraTec ActiveRadio ISA Standalone" + depends on ISA && VIDEO_V4L2 ++ select RADIO_ISA + ---help--- +- Choose Y here if you have this FM radio card, and then fill in the +- port address below. (TODO) +- +- Note: This driver is in its early stages. Right now volume and +- frequency control and muting works at least for me, but +- unfortunately I have not found anybody who wants to use this card +- with Linux. So if it is this what YOU are trying to do right now, +- PLEASE DROP ME A NOTE!! Rolf Offermanns . ++ Choose Y here if you have this FM radio card. + +- In order to control your radio card, you will need to use programs +- that are compatible with the Video For Linux API. Information on +- this API and pointers to "v4l" programs may be found at +- . ++ Note: this driver hasn't been tested since a long time due to lack ++ of hardware. If you have this hardware, then please contact the ++ linux-media mailinglist. + + To compile this driver as a module, choose M here: the + module will be called radio-terratec. + +-config RADIO_TERRATEC_PORT +- hex "Terratec i/o port (normally 0x590)" +- depends on RADIO_TERRATEC=y +- default "590" +- help +- Fill in the I/O port of your TerraTec FM radio card. If unsure, go +- with the default. +- + config RADIO_TRUST + tristate "Trust FM radio card" + depends on ISA && VIDEO_V4L2 ++ select RADIO_ISA + help + This is a driver for the Trust FM radio cards. Say Y if you have + such a card and want to use it under Linux. + ++ Note: this driver hasn't been tested since a long time due to lack ++ of hardware. If you have this hardware, then please contact the ++ linux-media mailinglist. ++ + To compile this driver as a module, choose M here: the + module will be called radio-trust. + +@@ -404,14 +377,14 @@ config RADIO_TRUST_PORT + config RADIO_TYPHOON + tristate "Typhoon Radio (a.k.a. EcoRadio)" + depends on ISA && VIDEO_V4L2 ++ select RADIO_ISA + ---help--- + Choose Y here if you have one of these FM radio cards, and then fill + in the port address and the frequency used for muting below. + +- In order to control your radio card, you will need to use programs +- that are compatible with the Video For Linux API. Information on +- this API and pointers to "v4l" programs may be found at +- . ++ Note: this driver hasn't been tested since a long time due to lack ++ of hardware. If you have this hardware, then please contact the ++ linux-media mailinglist. + + To compile this driver as a module, choose M here: the + module will be called radio-typhoon. +@@ -438,14 +411,14 @@ config RADIO_TYPHOON_MUTEFREQ + config RADIO_ZOLTRIX + tristate "Zoltrix Radio" + depends on ISA && VIDEO_V4L2 ++ select RADIO_ISA + ---help--- + Choose Y here if you have one of these FM radio cards, and then fill + in the port address below. + +- In order to control your radio card, you will need to use programs +- that are compatible with the Video For Linux API. Information on +- this API and pointers to "v4l" programs may be found at +- . ++ Note: this driver hasn't been tested since a long time due to lack ++ of hardware. If you have this hardware, then please contact the ++ linux-media mailinglist. + + To compile this driver as a module, choose M here: the + module will be called radio-zoltrix. +Index: linux-3.3.x86_64/drivers/media/radio/Makefile +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/radio/Makefile ++++ linux-3.3.x86_64/drivers/media/radio/Makefile +@@ -2,6 +2,7 @@ + # Makefile for the kernel character device drivers. + # + ++obj-$(CONFIG_RADIO_ISA) += radio-isa.o + obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o + obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o + obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o +@@ -20,6 +21,7 @@ obj-$(CONFIG_RADIO_MIROPCM20) += radio-m + obj-$(CONFIG_USB_DSBR) += dsbr100.o + obj-$(CONFIG_RADIO_SI470X) += si470x/ + obj-$(CONFIG_USB_MR800) += radio-mr800.o ++obj-$(CONFIG_USB_KEENE) += radio-keene.o + obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o + obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o + obj-$(CONFIG_RADIO_TEF6862) += tef6862.o +Index: linux-3.3.x86_64/drivers/media/radio/radio-keene.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/radio/radio-keene.c +@@ -0,0 +1,427 @@ ++/* ++ * Copyright (c) 2012 Hans Verkuil ++ * ++ * 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 ++ */ ++ ++/* kernel includes */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* driver and module definitions */ ++MODULE_AUTHOR("Hans Verkuil "); ++MODULE_DESCRIPTION("Keene FM Transmitter driver"); ++MODULE_LICENSE("GPL"); ++ ++/* Actually, it advertises itself as a Logitech */ ++#define USB_KEENE_VENDOR 0x046d ++#define USB_KEENE_PRODUCT 0x0a0e ++ ++/* Probably USB_TIMEOUT should be modified in module parameter */ ++#define BUFFER_LENGTH 8 ++#define USB_TIMEOUT 500 ++ ++/* Frequency limits in MHz */ ++#define FREQ_MIN 76U ++#define FREQ_MAX 108U ++#define FREQ_MUL 16000U ++ ++/* USB Device ID List */ ++static struct usb_device_id usb_keene_device_table[] = { ++ {USB_DEVICE_AND_INTERFACE_INFO(USB_KEENE_VENDOR, USB_KEENE_PRODUCT, ++ USB_CLASS_HID, 0, 0) }, ++ { } /* Terminating entry */ ++}; ++ ++MODULE_DEVICE_TABLE(usb, usb_keene_device_table); ++ ++struct keene_device { ++ struct usb_device *usbdev; ++ struct usb_interface *intf; ++ struct video_device vdev; ++ struct v4l2_device v4l2_dev; ++ struct v4l2_ctrl_handler hdl; ++ struct mutex lock; ++ ++ u8 *buffer; ++ unsigned curfreq; ++ u8 tx; ++ u8 pa; ++ bool stereo; ++ bool muted; ++ bool preemph_75_us; ++}; ++ ++static inline struct keene_device *to_keene_dev(struct v4l2_device *v4l2_dev) ++{ ++ return container_of(v4l2_dev, struct keene_device, v4l2_dev); ++} ++ ++/* Set frequency (if non-0), PA, mute and turn on/off the FM transmitter. */ ++static int keene_cmd_main(struct keene_device *radio, unsigned freq, bool play) ++{ ++ unsigned short freq_send = freq ? (freq - 76 * 16000) / 800 : 0; ++ int ret; ++ ++ radio->buffer[0] = 0x00; ++ radio->buffer[1] = 0x50; ++ radio->buffer[2] = (freq_send >> 8) & 0xff; ++ radio->buffer[3] = freq_send & 0xff; ++ radio->buffer[4] = radio->pa; ++ /* If bit 4 is set, then tune to the frequency. ++ If bit 3 is set, then unmute; if bit 2 is set, then mute. ++ If bit 1 is set, then enter idle mode; if bit 0 is set, ++ then enter transit mode. ++ */ ++ radio->buffer[5] = (radio->muted ? 4 : 8) | (play ? 1 : 2) | ++ (freq ? 0x10 : 0); ++ radio->buffer[6] = 0x00; ++ radio->buffer[7] = 0x00; ++ ++ ret = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0), ++ 9, 0x21, 0x200, 2, radio->buffer, BUFFER_LENGTH, USB_TIMEOUT); ++ ++ if (ret < 0) { ++ dev_warn(&radio->vdev.dev, "%s failed (%d)\n", __func__, ret); ++ return ret; ++ } ++ if (freq) ++ radio->curfreq = freq; ++ return 0; ++} ++ ++/* Set TX, stereo and preemphasis mode (50 us vs 75 us). */ ++static int keene_cmd_set(struct keene_device *radio) ++{ ++ int ret; ++ ++ radio->buffer[0] = 0x00; ++ radio->buffer[1] = 0x51; ++ radio->buffer[2] = radio->tx; ++ /* If bit 0 is set, then transmit mono, otherwise stereo. ++ If bit 2 is set, then enable 75 us preemphasis, otherwise ++ it is 50 us. */ ++ radio->buffer[3] = (!radio->stereo) | (radio->preemph_75_us ? 4 : 0); ++ radio->buffer[4] = 0x00; ++ radio->buffer[5] = 0x00; ++ radio->buffer[6] = 0x00; ++ radio->buffer[7] = 0x00; ++ ++ ret = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0), ++ 9, 0x21, 0x200, 2, radio->buffer, BUFFER_LENGTH, USB_TIMEOUT); ++ ++ if (ret < 0) { ++ dev_warn(&radio->vdev.dev, "%s failed (%d)\n", __func__, ret); ++ return ret; ++ } ++ return 0; ++} ++ ++/* Handle unplugging the device. ++ * We call video_unregister_device in any case. ++ * The last function called in this procedure is ++ * usb_keene_device_release. ++ */ ++static void usb_keene_disconnect(struct usb_interface *intf) ++{ ++ struct keene_device *radio = to_keene_dev(usb_get_intfdata(intf)); ++ ++ v4l2_device_get(&radio->v4l2_dev); ++ mutex_lock(&radio->lock); ++ usb_set_intfdata(intf, NULL); ++ video_unregister_device(&radio->vdev); ++ v4l2_device_disconnect(&radio->v4l2_dev); ++ mutex_unlock(&radio->lock); ++ v4l2_device_put(&radio->v4l2_dev); ++} ++ ++static int vidioc_querycap(struct file *file, void *priv, ++ struct v4l2_capability *v) ++{ ++ struct keene_device *radio = video_drvdata(file); ++ ++ strlcpy(v->driver, "radio-keene", sizeof(v->driver)); ++ strlcpy(v->card, "Keene FM Transmitter", sizeof(v->card)); ++ usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); ++ v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_MODULATOR; ++ v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; ++ return 0; ++} ++ ++static int vidioc_g_modulator(struct file *file, void *priv, ++ struct v4l2_modulator *v) ++{ ++ struct keene_device *radio = video_drvdata(file); ++ ++ if (v->index > 0) ++ return -EINVAL; ++ ++ strlcpy(v->name, "FM", sizeof(v->name)); ++ v->rangelow = FREQ_MIN * FREQ_MUL; ++ v->rangehigh = FREQ_MAX * FREQ_MUL; ++ v->txsubchans = radio->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; ++ v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; ++ return 0; ++} ++ ++static int vidioc_s_modulator(struct file *file, void *priv, ++ struct v4l2_modulator *v) ++{ ++ struct keene_device *radio = video_drvdata(file); ++ ++ if (v->index > 0) ++ return -EINVAL; ++ ++ radio->stereo = (v->txsubchans == V4L2_TUNER_SUB_STEREO); ++ return keene_cmd_set(radio); ++} ++ ++static int vidioc_s_frequency(struct file *file, void *priv, ++ struct v4l2_frequency *f) ++{ ++ struct keene_device *radio = video_drvdata(file); ++ ++ if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) ++ return -EINVAL; ++ f->frequency = clamp(f->frequency, ++ FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL); ++ return keene_cmd_main(radio, f->frequency, true); ++} ++ ++static int vidioc_g_frequency(struct file *file, void *priv, ++ struct v4l2_frequency *f) ++{ ++ struct keene_device *radio = video_drvdata(file); ++ ++ if (f->tuner != 0) ++ return -EINVAL; ++ f->type = V4L2_TUNER_RADIO; ++ f->frequency = radio->curfreq; ++ return 0; ++} ++ ++static int keene_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ static const u8 db2tx[] = { ++ /* -15, -12, -9, -6, -3, 0 dB */ ++ 0x03, 0x13, 0x02, 0x12, 0x22, 0x32, ++ /* 3, 6, 9, 12, 15, 18 dB */ ++ 0x21, 0x31, 0x20, 0x30, 0x40, 0x50 ++ }; ++ struct keene_device *radio = ++ container_of(ctrl->handler, struct keene_device, hdl); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUDIO_MUTE: ++ radio->muted = ctrl->val; ++ return keene_cmd_main(radio, 0, true); ++ ++ case V4L2_CID_TUNE_POWER_LEVEL: ++ /* To go from dBuV to the register value we apply the ++ following formula: */ ++ radio->pa = (ctrl->val - 71) * 100 / 62; ++ return keene_cmd_main(radio, 0, true); ++ ++ case V4L2_CID_TUNE_PREEMPHASIS: ++ radio->preemph_75_us = ctrl->val == V4L2_PREEMPHASIS_75_uS; ++ return keene_cmd_set(radio); ++ ++ case V4L2_CID_AUDIO_COMPRESSION_GAIN: ++ radio->tx = db2tx[(ctrl->val - ctrl->minimum) / ctrl->step]; ++ return keene_cmd_set(radio); ++ } ++ return -EINVAL; ++} ++ ++static int vidioc_subscribe_event(struct v4l2_fh *fh, ++ struct v4l2_event_subscription *sub) ++{ ++ switch (sub->type) { ++ case V4L2_EVENT_CTRL: ++ return v4l2_event_subscribe(fh, sub, 0); ++ default: ++ return -EINVAL; ++ } ++} ++ ++ ++/* File system interface */ ++static const struct v4l2_file_operations usb_keene_fops = { ++ .owner = THIS_MODULE, ++ .open = v4l2_fh_open, ++ .release = v4l2_fh_release, ++ .poll = v4l2_ctrl_poll, ++ .unlocked_ioctl = video_ioctl2, ++}; ++ ++static const struct v4l2_ctrl_ops keene_ctrl_ops = { ++ .s_ctrl = keene_s_ctrl, ++}; ++ ++static const struct v4l2_ioctl_ops usb_keene_ioctl_ops = { ++ .vidioc_querycap = vidioc_querycap, ++ .vidioc_g_modulator = vidioc_g_modulator, ++ .vidioc_s_modulator = vidioc_s_modulator, ++ .vidioc_g_frequency = vidioc_g_frequency, ++ .vidioc_s_frequency = vidioc_s_frequency, ++ .vidioc_log_status = v4l2_ctrl_log_status, ++ .vidioc_subscribe_event = vidioc_subscribe_event, ++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, ++}; ++ ++static void usb_keene_video_device_release(struct v4l2_device *v4l2_dev) ++{ ++ struct keene_device *radio = to_keene_dev(v4l2_dev); ++ ++ /* free rest memory */ ++ v4l2_ctrl_handler_free(&radio->hdl); ++ kfree(radio->buffer); ++ kfree(radio); ++} ++ ++/* check if the device is present and register with v4l and usb if it is */ ++static int usb_keene_probe(struct usb_interface *intf, ++ const struct usb_device_id *id) ++{ ++ struct usb_device *dev = interface_to_usbdev(intf); ++ struct keene_device *radio; ++ struct v4l2_ctrl_handler *hdl; ++ int retval = 0; ++ ++ /* ++ * The Keene FM transmitter USB device has the same USB ID as ++ * the Logitech AudioHub Speaker, but it should ignore the hid. ++ * Check if the name is that of the Keene device. ++ * If not, then someone connected the AudioHub and we shouldn't ++ * attempt to handle this driver. ++ * For reference: the product name of the AudioHub is ++ * "AudioHub Speaker". ++ */ ++ if (dev->product && strcmp(dev->product, "B-LINK USB Audio ")) ++ return -ENODEV; ++ ++ radio = kzalloc(sizeof(struct keene_device), GFP_KERNEL); ++ if (radio) ++ radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL); ++ ++ if (!radio || !radio->buffer) { ++ dev_err(&intf->dev, "kmalloc for keene_device failed\n"); ++ kfree(radio); ++ retval = -ENOMEM; ++ goto err; ++ } ++ ++ hdl = &radio->hdl; ++ v4l2_ctrl_handler_init(hdl, 4); ++ v4l2_ctrl_new_std(hdl, &keene_ctrl_ops, V4L2_CID_AUDIO_MUTE, ++ 0, 1, 1, 0); ++ v4l2_ctrl_new_std_menu(hdl, &keene_ctrl_ops, V4L2_CID_TUNE_PREEMPHASIS, ++ V4L2_PREEMPHASIS_75_uS, 1, V4L2_PREEMPHASIS_50_uS); ++ v4l2_ctrl_new_std(hdl, &keene_ctrl_ops, V4L2_CID_TUNE_POWER_LEVEL, ++ 84, 118, 1, 118); ++ v4l2_ctrl_new_std(hdl, &keene_ctrl_ops, V4L2_CID_AUDIO_COMPRESSION_GAIN, ++ -15, 18, 3, 0); ++ radio->pa = 118; ++ radio->tx = 0x32; ++ radio->stereo = true; ++ radio->curfreq = 95.16 * FREQ_MUL; ++ if (hdl->error) { ++ retval = hdl->error; ++ ++ v4l2_ctrl_handler_free(hdl); ++ goto err_v4l2; ++ } ++ retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev); ++ if (retval < 0) { ++ dev_err(&intf->dev, "couldn't register v4l2_device\n"); ++ goto err_v4l2; ++ } ++ ++ mutex_init(&radio->lock); ++ ++ radio->v4l2_dev.ctrl_handler = hdl; ++ radio->v4l2_dev.release = usb_keene_video_device_release; ++ strlcpy(radio->vdev.name, radio->v4l2_dev.name, ++ sizeof(radio->vdev.name)); ++ radio->vdev.v4l2_dev = &radio->v4l2_dev; ++ radio->vdev.fops = &usb_keene_fops; ++ radio->vdev.ioctl_ops = &usb_keene_ioctl_ops; ++ radio->vdev.lock = &radio->lock; ++ radio->vdev.release = video_device_release_empty; ++ ++ radio->usbdev = interface_to_usbdev(intf); ++ radio->intf = intf; ++ usb_set_intfdata(intf, &radio->v4l2_dev); ++ ++ video_set_drvdata(&radio->vdev, radio); ++ set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags); ++ ++ retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO, -1); ++ if (retval < 0) { ++ dev_err(&intf->dev, "could not register video device\n"); ++ goto err_vdev; ++ } ++ v4l2_ctrl_handler_setup(hdl); ++ dev_info(&intf->dev, "V4L2 device registered as %s\n", ++ video_device_node_name(&radio->vdev)); ++ return 0; ++ ++err_vdev: ++ v4l2_device_unregister(&radio->v4l2_dev); ++err_v4l2: ++ kfree(radio->buffer); ++ kfree(radio); ++err: ++ return retval; ++} ++ ++/* USB subsystem interface */ ++static struct usb_driver usb_keene_driver = { ++ .name = "radio-keene", ++ .probe = usb_keene_probe, ++ .disconnect = usb_keene_disconnect, ++ .id_table = usb_keene_device_table, ++}; ++ ++static int __init keene_init(void) ++{ ++ int retval = usb_register(&usb_keene_driver); ++ ++ if (retval) ++ pr_err(KBUILD_MODNAME ++ ": usb_register failed. Error number %d\n", retval); ++ ++ return retval; ++} ++ ++static void __exit keene_exit(void) ++{ ++ usb_deregister(&usb_keene_driver); ++} ++ ++module_init(keene_init); ++module_exit(keene_exit); ++ +Index: linux-3.3.x86_64/drivers/media/rc/fintek-cir.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/rc/fintek-cir.c ++++ linux-3.3.x86_64/drivers/media/rc/fintek-cir.c +@@ -117,7 +117,7 @@ static u8 fintek_cir_reg_read(struct fin + static void cir_dump_regs(struct fintek_dev *fintek) + { + fintek_config_mode_enable(fintek); +- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); ++ fintek_select_logical_dev(fintek, fintek->logical_dev_cir); + + pr_reg("%s: Dump CIR logical device registers:\n", FINTEK_DRIVER_NAME); + pr_reg(" * CR CIR BASE ADDR: 0x%x\n", +@@ -143,7 +143,7 @@ static int fintek_hw_detect(struct finte + u8 chip_major, chip_minor; + u8 vendor_major, vendor_minor; + u8 portsel, ir_class; +- u16 vendor; ++ u16 vendor, chip; + int ret = 0; + + fintek_config_mode_enable(fintek); +@@ -176,6 +176,7 @@ static int fintek_hw_detect(struct finte + + chip_major = fintek_cr_read(fintek, GCR_CHIP_ID_HI); + chip_minor = fintek_cr_read(fintek, GCR_CHIP_ID_LO); ++ chip = chip_major << 8 | chip_minor; + + vendor_major = fintek_cr_read(fintek, GCR_VENDOR_ID_HI); + vendor_minor = fintek_cr_read(fintek, GCR_VENDOR_ID_LO); +@@ -192,6 +193,15 @@ static int fintek_hw_detect(struct finte + fintek->chip_major = chip_major; + fintek->chip_minor = chip_minor; + fintek->chip_vendor = vendor; ++ ++ /* ++ * Newer reviews of this chipset uses port 8 instead of 5 ++ */ ++ if ((chip != 0x0408) || (chip != 0x0804)) ++ fintek->logical_dev_cir = LOGICAL_DEV_CIR_REV2; ++ else ++ fintek->logical_dev_cir = LOGICAL_DEV_CIR_REV1; ++ + spin_unlock_irqrestore(&fintek->fintek_lock, flags); + + return ret; +@@ -200,7 +210,7 @@ static int fintek_hw_detect(struct finte + static void fintek_cir_ldev_init(struct fintek_dev *fintek) + { + /* Select CIR logical device and enable */ +- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); ++ fintek_select_logical_dev(fintek, fintek->logical_dev_cir); + fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN); + + /* Write allocated CIR address and IRQ information to hardware */ +@@ -381,7 +391,7 @@ static irqreturn_t fintek_cir_isr(int ir + fit_dbg_verbose("%s firing", __func__); + + fintek_config_mode_enable(fintek); +- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); ++ fintek_select_logical_dev(fintek, fintek->logical_dev_cir); + fintek_config_mode_disable(fintek); + + /* +@@ -422,7 +432,7 @@ static void fintek_enable_cir(struct fin + fintek_config_mode_enable(fintek); + + /* enable the CIR logical device */ +- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); ++ fintek_select_logical_dev(fintek, fintek->logical_dev_cir); + fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN); + + fintek_config_mode_disable(fintek); +@@ -439,7 +449,7 @@ static void fintek_disable_cir(struct fi + fintek_config_mode_enable(fintek); + + /* disable the CIR logical device */ +- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); ++ fintek_select_logical_dev(fintek, fintek->logical_dev_cir); + fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN); + + fintek_config_mode_disable(fintek); +@@ -611,7 +621,7 @@ static int fintek_suspend(struct pnp_dev + fintek_config_mode_enable(fintek); + + /* disable cir logical dev */ +- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); ++ fintek_select_logical_dev(fintek, fintek->logical_dev_cir); + fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN); + + fintek_config_mode_disable(fintek); +@@ -634,7 +644,7 @@ static int fintek_resume(struct pnp_dev + + /* Enable CIR logical device */ + fintek_config_mode_enable(fintek); +- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); ++ fintek_select_logical_dev(fintek, fintek->logical_dev_cir); + fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN); + + fintek_config_mode_disable(fintek); +Index: linux-3.3.x86_64/drivers/media/rc/fintek-cir.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/rc/fintek-cir.h ++++ linux-3.3.x86_64/drivers/media/rc/fintek-cir.h +@@ -88,6 +88,7 @@ struct fintek_dev { + u8 chip_major; + u8 chip_minor; + u16 chip_vendor; ++ u8 logical_dev_cir; + + /* hardware features */ + bool hw_learning_capable; +@@ -172,7 +173,8 @@ struct fintek_dev { + #define LOGICAL_DEV_ENABLE 0x01 + + /* Logical device number of the CIR function */ +-#define LOGICAL_DEV_CIR 0x05 ++#define LOGICAL_DEV_CIR_REV1 0x05 ++#define LOGICAL_DEV_CIR_REV2 0x08 + + /* CIR Logical Device (LDN 0x08) config registers */ + #define CIR_CR_COMMAND_INDEX 0x04 +Index: linux-3.3.x86_64/drivers/media/radio/radio-isa.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/radio/radio-isa.c +@@ -0,0 +1,340 @@ ++/* ++ * Framework for ISA radio drivers. ++ * This takes care of all the V4L2 scaffolding, allowing the ISA drivers ++ * to concentrate on the actual hardware operation. ++ * ++ * Copyright (C) 2012 Hans Verkuil ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "radio-isa.h" ++ ++MODULE_AUTHOR("Hans Verkuil"); ++MODULE_DESCRIPTION("A framework for ISA radio drivers."); ++MODULE_LICENSE("GPL"); ++ ++#define FREQ_LOW (87U * 16000U) ++#define FREQ_HIGH (108U * 16000U) ++ ++static int radio_isa_querycap(struct file *file, void *priv, ++ struct v4l2_capability *v) ++{ ++ struct radio_isa_card *isa = video_drvdata(file); ++ ++ strlcpy(v->driver, isa->drv->driver.driver.name, sizeof(v->driver)); ++ strlcpy(v->card, isa->drv->card, sizeof(v->card)); ++ snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", isa->v4l2_dev.name); ++ ++ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; ++ v->device_caps = v->capabilities | V4L2_CAP_DEVICE_CAPS; ++ return 0; ++} ++ ++static int radio_isa_g_tuner(struct file *file, void *priv, ++ struct v4l2_tuner *v) ++{ ++ struct radio_isa_card *isa = video_drvdata(file); ++ const struct radio_isa_ops *ops = isa->drv->ops; ++ ++ if (v->index > 0) ++ return -EINVAL; ++ ++ strlcpy(v->name, "FM", sizeof(v->name)); ++ v->type = V4L2_TUNER_RADIO; ++ v->rangelow = FREQ_LOW; ++ v->rangehigh = FREQ_HIGH; ++ v->capability = V4L2_TUNER_CAP_LOW; ++ if (isa->drv->has_stereo) ++ v->capability |= V4L2_TUNER_CAP_STEREO; ++ ++ if (ops->g_rxsubchans) ++ v->rxsubchans = ops->g_rxsubchans(isa); ++ else ++ v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; ++ v->audmode = isa->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO; ++ if (ops->g_signal) ++ v->signal = ops->g_signal(isa); ++ else ++ v->signal = (v->rxsubchans & V4L2_TUNER_SUB_STEREO) ? ++ 0xffff : 0; ++ return 0; ++} ++ ++static int radio_isa_s_tuner(struct file *file, void *priv, ++ struct v4l2_tuner *v) ++{ ++ struct radio_isa_card *isa = video_drvdata(file); ++ const struct radio_isa_ops *ops = isa->drv->ops; ++ ++ if (v->index) ++ return -EINVAL; ++ if (ops->s_stereo) { ++ isa->stereo = (v->audmode == V4L2_TUNER_MODE_STEREO); ++ return ops->s_stereo(isa, isa->stereo); ++ } ++ return 0; ++} ++ ++static int radio_isa_s_frequency(struct file *file, void *priv, ++ struct v4l2_frequency *f) ++{ ++ struct radio_isa_card *isa = video_drvdata(file); ++ int res; ++ ++ if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) ++ return -EINVAL; ++ f->frequency = clamp(f->frequency, FREQ_LOW, FREQ_HIGH); ++ res = isa->drv->ops->s_frequency(isa, f->frequency); ++ if (res == 0) ++ isa->freq = f->frequency; ++ return res; ++} ++ ++static int radio_isa_g_frequency(struct file *file, void *priv, ++ struct v4l2_frequency *f) ++{ ++ struct radio_isa_card *isa = video_drvdata(file); ++ ++ if (f->tuner != 0) ++ return -EINVAL; ++ f->type = V4L2_TUNER_RADIO; ++ f->frequency = isa->freq; ++ return 0; ++} ++ ++static int radio_isa_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct radio_isa_card *isa = ++ container_of(ctrl->handler, struct radio_isa_card, hdl); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUDIO_MUTE: ++ return isa->drv->ops->s_mute_volume(isa, ctrl->val, ++ isa->volume ? isa->volume->val : 0); ++ } ++ return -EINVAL; ++} ++ ++static int radio_isa_log_status(struct file *file, void *priv) ++{ ++ struct radio_isa_card *isa = video_drvdata(file); ++ ++ v4l2_info(&isa->v4l2_dev, "I/O Port = 0x%03x\n", isa->io); ++ v4l2_ctrl_handler_log_status(&isa->hdl, isa->v4l2_dev.name); ++ return 0; ++} ++ ++static int radio_isa_subscribe_event(struct v4l2_fh *fh, ++ struct v4l2_event_subscription *sub) ++{ ++ if (sub->type == V4L2_EVENT_CTRL) ++ return v4l2_event_subscribe(fh, sub, 0); ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops radio_isa_ctrl_ops = { ++ .s_ctrl = radio_isa_s_ctrl, ++}; ++ ++static const struct v4l2_file_operations radio_isa_fops = { ++ .owner = THIS_MODULE, ++ .open = v4l2_fh_open, ++ .release = v4l2_fh_release, ++ .poll = v4l2_ctrl_poll, ++ .unlocked_ioctl = video_ioctl2, ++}; ++ ++static const struct v4l2_ioctl_ops radio_isa_ioctl_ops = { ++ .vidioc_querycap = radio_isa_querycap, ++ .vidioc_g_tuner = radio_isa_g_tuner, ++ .vidioc_s_tuner = radio_isa_s_tuner, ++ .vidioc_g_frequency = radio_isa_g_frequency, ++ .vidioc_s_frequency = radio_isa_s_frequency, ++ .vidioc_log_status = radio_isa_log_status, ++ .vidioc_subscribe_event = radio_isa_subscribe_event, ++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, ++}; ++ ++int radio_isa_match(struct device *pdev, unsigned int dev) ++{ ++ struct radio_isa_driver *drv = pdev->platform_data; ++ ++ return drv->probe || drv->io_params[dev] >= 0; ++} ++EXPORT_SYMBOL_GPL(radio_isa_match); ++ ++static bool radio_isa_valid_io(const struct radio_isa_driver *drv, int io) ++{ ++ int i; ++ ++ for (i = 0; i < drv->num_of_io_ports; i++) ++ if (drv->io_ports[i] == io) ++ return true; ++ return false; ++} ++ ++int radio_isa_probe(struct device *pdev, unsigned int dev) ++{ ++ struct radio_isa_driver *drv = pdev->platform_data; ++ const struct radio_isa_ops *ops = drv->ops; ++ struct v4l2_device *v4l2_dev; ++ struct radio_isa_card *isa; ++ int res; ++ ++ isa = drv->ops->alloc(); ++ if (isa == NULL) ++ return -ENOMEM; ++ dev_set_drvdata(pdev, isa); ++ isa->drv = drv; ++ isa->io = drv->io_params[dev]; ++ v4l2_dev = &isa->v4l2_dev; ++ strlcpy(v4l2_dev->name, dev_name(pdev), sizeof(v4l2_dev->name)); ++ ++ if (drv->probe && ops->probe) { ++ int i; ++ ++ for (i = 0; i < drv->num_of_io_ports; ++i) { ++ int io = drv->io_ports[i]; ++ ++ if (request_region(io, drv->region_size, v4l2_dev->name)) { ++ bool found = ops->probe(isa, io); ++ ++ release_region(io, drv->region_size); ++ if (found) { ++ isa->io = io; ++ break; ++ } ++ } ++ } ++ } ++ ++ if (!radio_isa_valid_io(drv, isa->io)) { ++ int i; ++ ++ if (isa->io < 0) ++ return -ENODEV; ++ v4l2_err(v4l2_dev, "you must set an I/O address with io=0x%03x", ++ drv->io_ports[0]); ++ for (i = 1; i < drv->num_of_io_ports; i++) ++ printk(KERN_CONT "/0x%03x", drv->io_ports[i]); ++ printk(KERN_CONT ".\n"); ++ kfree(isa); ++ return -EINVAL; ++ } ++ ++ if (!request_region(isa->io, drv->region_size, v4l2_dev->name)) { ++ v4l2_err(v4l2_dev, "port 0x%x already in use\n", isa->io); ++ kfree(isa); ++ return -EBUSY; ++ } ++ ++ res = v4l2_device_register(pdev, v4l2_dev); ++ if (res < 0) { ++ v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); ++ goto err_dev_reg; ++ } ++ ++ v4l2_ctrl_handler_init(&isa->hdl, 1); ++ isa->mute = v4l2_ctrl_new_std(&isa->hdl, &radio_isa_ctrl_ops, ++ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); ++ if (drv->max_volume) ++ isa->volume = v4l2_ctrl_new_std(&isa->hdl, &radio_isa_ctrl_ops, ++ V4L2_CID_AUDIO_VOLUME, 0, drv->max_volume, 1, ++ drv->max_volume); ++ v4l2_dev->ctrl_handler = &isa->hdl; ++ if (isa->hdl.error) { ++ res = isa->hdl.error; ++ v4l2_err(v4l2_dev, "Could not register controls\n"); ++ goto err_hdl; ++ } ++ if (drv->max_volume) ++ v4l2_ctrl_cluster(2, &isa->mute); ++ v4l2_dev->ctrl_handler = &isa->hdl; ++ ++ mutex_init(&isa->lock); ++ isa->vdev.lock = &isa->lock; ++ strlcpy(isa->vdev.name, v4l2_dev->name, sizeof(isa->vdev.name)); ++ isa->vdev.v4l2_dev = v4l2_dev; ++ isa->vdev.fops = &radio_isa_fops; ++ isa->vdev.ioctl_ops = &radio_isa_ioctl_ops; ++ isa->vdev.release = video_device_release_empty; ++ set_bit(V4L2_FL_USE_FH_PRIO, &isa->vdev.flags); ++ video_set_drvdata(&isa->vdev, isa); ++ isa->freq = FREQ_LOW; ++ isa->stereo = drv->has_stereo; ++ ++ if (ops->init) ++ res = ops->init(isa); ++ if (!res) ++ res = v4l2_ctrl_handler_setup(&isa->hdl); ++ if (!res) ++ res = ops->s_frequency(isa, isa->freq); ++ if (!res && ops->s_stereo) ++ res = ops->s_stereo(isa, isa->stereo); ++ if (res < 0) { ++ v4l2_err(v4l2_dev, "Could not setup card\n"); ++ goto err_node_reg; ++ } ++ res = video_register_device(&isa->vdev, VFL_TYPE_RADIO, ++ drv->radio_nr_params[dev]); ++ if (res < 0) { ++ v4l2_err(v4l2_dev, "Could not register device node\n"); ++ goto err_node_reg; ++ } ++ ++ v4l2_info(v4l2_dev, "Initialized radio card %s on port 0x%03x\n", ++ drv->card, isa->io); ++ return 0; ++ ++err_node_reg: ++ v4l2_ctrl_handler_free(&isa->hdl); ++err_hdl: ++ v4l2_device_unregister(&isa->v4l2_dev); ++err_dev_reg: ++ release_region(isa->io, drv->region_size); ++ kfree(isa); ++ return res; ++} ++EXPORT_SYMBOL_GPL(radio_isa_probe); ++ ++int radio_isa_remove(struct device *pdev, unsigned int dev) ++{ ++ struct radio_isa_card *isa = dev_get_drvdata(pdev); ++ const struct radio_isa_ops *ops = isa->drv->ops; ++ ++ ops->s_mute_volume(isa, true, isa->volume ? isa->volume->cur.val : 0); ++ video_unregister_device(&isa->vdev); ++ v4l2_ctrl_handler_free(&isa->hdl); ++ v4l2_device_unregister(&isa->v4l2_dev); ++ release_region(isa->io, isa->drv->region_size); ++ v4l2_info(&isa->v4l2_dev, "Removed radio card %s\n", isa->drv->card); ++ kfree(isa); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(radio_isa_remove); +Index: linux-3.3.x86_64/drivers/media/radio/radio-isa.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/radio/radio-isa.h +@@ -0,0 +1,105 @@ ++/* ++ * Framework for ISA radio drivers. ++ * This takes care of all the V4L2 scaffolding, allowing the ISA drivers ++ * to concentrate on the actual hardware operation. ++ * ++ * Copyright (C) 2012 Hans Verkuil ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#ifndef _RADIO_ISA_H_ ++#define _RADIO_ISA_H_ ++ ++#include ++#include ++#include ++#include ++ ++struct radio_isa_driver; ++struct radio_isa_ops; ++ ++/* Core structure for radio ISA cards */ ++struct radio_isa_card { ++ const struct radio_isa_driver *drv; ++ struct v4l2_device v4l2_dev; ++ struct v4l2_ctrl_handler hdl; ++ struct video_device vdev; ++ struct mutex lock; ++ const struct radio_isa_ops *ops; ++ struct { /* mute/volume cluster */ ++ struct v4l2_ctrl *mute; ++ struct v4l2_ctrl *volume; ++ }; ++ /* I/O port */ ++ int io; ++ ++ /* Card is in stereo audio mode */ ++ bool stereo; ++ /* Current frequency */ ++ u32 freq; ++}; ++ ++struct radio_isa_ops { ++ /* Allocate and initialize a radio_isa_card struct */ ++ struct radio_isa_card *(*alloc)(void); ++ /* Probe whether a card is present at the given port */ ++ bool (*probe)(struct radio_isa_card *isa, int io); ++ /* Special card initialization can be done here, this is called after ++ * the standard controls are registered, but before they are setup, ++ * thus allowing drivers to add their own controls here. */ ++ int (*init)(struct radio_isa_card *isa); ++ /* Set mute and volume. */ ++ int (*s_mute_volume)(struct radio_isa_card *isa, bool mute, int volume); ++ /* Set frequency */ ++ int (*s_frequency)(struct radio_isa_card *isa, u32 freq); ++ /* Set stereo/mono audio mode */ ++ int (*s_stereo)(struct radio_isa_card *isa, bool stereo); ++ /* Get rxsubchans value for VIDIOC_G_TUNER */ ++ u32 (*g_rxsubchans)(struct radio_isa_card *isa); ++ /* Get the signal strength for VIDIOC_G_TUNER */ ++ u32 (*g_signal)(struct radio_isa_card *isa); ++}; ++ ++/* Top level structure needed to instantiate the cards */ ++struct radio_isa_driver { ++ struct isa_driver driver; ++ const struct radio_isa_ops *ops; ++ /* The module_param_array with the specified I/O ports */ ++ int *io_params; ++ /* The module_param_array with the radio_nr values */ ++ int *radio_nr_params; ++ /* Whether we should probe for possible cards */ ++ bool probe; ++ /* The list of possible I/O ports */ ++ const int *io_ports; ++ /* The size of that list */ ++ int num_of_io_ports; ++ /* The region size to request */ ++ unsigned region_size; ++ /* The name of the card */ ++ const char *card; ++ /* Card can capture stereo audio */ ++ bool has_stereo; ++ /* The maximum volume for the volume control. If 0, then there ++ is no volume control possible. */ ++ int max_volume; ++}; ++ ++int radio_isa_match(struct device *pdev, unsigned int dev); ++int radio_isa_probe(struct device *pdev, unsigned int dev); ++int radio_isa_remove(struct device *pdev, unsigned int dev); ++ ++#endif +Index: linux-3.3.x86_64/drivers/media/radio/radio-aimslab.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/radio/radio-aimslab.c ++++ linux-3.3.x86_64/drivers/media/radio/radio-aimslab.c +@@ -1,16 +1,13 @@ +-/* radiotrack (radioreveal) driver for Linux radio support +- * (c) 1997 M. Kirkwood ++/* ++ * AimsLab RadioTrack (aka RadioVeveal) driver ++ * ++ * Copyright 1997 M. Kirkwood ++ * ++ * Converted to the radio-isa framework by Hans Verkuil + * Converted to V4L2 API by Mauro Carvalho Chehab + * Converted to new API by Alan Cox + * Various bugfixes and enhancements by Russell Kroll + * +- * History: +- * 1999-02-24 Russell Kroll +- * Fine tuning/VIDEO_TUNER_LOW +- * Frequency range expanded to start at 87 MHz +- * +- * TODO: Allow for more than one of these foolish entities :-) +- * + * Notes on the hardware (reverse engineered from other peoples' + * reverse engineering of AIMS' code :-) + * +@@ -26,6 +23,7 @@ + * wait(a_wee_while); + * out(port, stop_changing_the_volume); + * ++ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool. + */ + + #include /* Modules */ +@@ -34,401 +32,179 @@ + #include /* msleep */ + #include /* kernel radio structs */ + #include /* outb, outb_p */ ++#include + #include + #include ++#include ++#include "radio-isa.h" + +-MODULE_AUTHOR("M.Kirkwood"); ++MODULE_AUTHOR("M. Kirkwood"); + MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card."); + MODULE_LICENSE("GPL"); +-MODULE_VERSION("0.0.3"); ++MODULE_VERSION("1.0.0"); + + #ifndef CONFIG_RADIO_RTRACK_PORT + #define CONFIG_RADIO_RTRACK_PORT -1 + #endif + +-static int io = CONFIG_RADIO_RTRACK_PORT; +-static int radio_nr = -1; ++#define RTRACK_MAX 2 + +-module_param(io, int, 0); +-MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)"); +-module_param(radio_nr, int, 0); ++static int io[RTRACK_MAX] = { [0] = CONFIG_RADIO_RTRACK_PORT, ++ [1 ... (RTRACK_MAX - 1)] = -1 }; ++static int radio_nr[RTRACK_MAX] = { [0 ... (RTRACK_MAX - 1)] = -1 }; ++ ++module_param_array(io, int, NULL, 0444); ++MODULE_PARM_DESC(io, "I/O addresses of the RadioTrack card (0x20f or 0x30f)"); ++module_param_array(radio_nr, int, NULL, 0444); ++MODULE_PARM_DESC(radio_nr, "Radio device numbers"); + +-struct rtrack +-{ +- struct v4l2_device v4l2_dev; +- struct video_device vdev; +- int port; ++struct rtrack { ++ struct radio_isa_card isa; + int curvol; +- unsigned long curfreq; +- int muted; +- int io; +- struct mutex lock; + }; + +-static struct rtrack rtrack_card; +- +-/* local things */ +- +-static void rt_decvol(struct rtrack *rt) +-{ +- outb(0x58, rt->io); /* volume down + sigstr + on */ +- msleep(100); +- outb(0xd8, rt->io); /* volume steady + sigstr + on */ +-} +- +-static void rt_incvol(struct rtrack *rt) +-{ +- outb(0x98, rt->io); /* volume up + sigstr + on */ +- msleep(100); +- outb(0xd8, rt->io); /* volume steady + sigstr + on */ +-} +- +-static void rt_mute(struct rtrack *rt) +-{ +- rt->muted = 1; +- mutex_lock(&rt->lock); +- outb(0xd0, rt->io); /* volume steady, off */ +- mutex_unlock(&rt->lock); +-} +- +-static int rt_setvol(struct rtrack *rt, int vol) ++static struct radio_isa_card *rtrack_alloc(void) + { +- int i; +- +- mutex_lock(&rt->lock); +- +- if (vol == rt->curvol) { /* requested volume = current */ +- if (rt->muted) { /* user is unmuting the card */ +- rt->muted = 0; +- outb(0xd8, rt->io); /* enable card */ +- } +- mutex_unlock(&rt->lock); +- return 0; +- } +- +- if (vol == 0) { /* volume = 0 means mute the card */ +- outb(0x48, rt->io); /* volume down but still "on" */ +- msleep(2000); /* make sure it's totally down */ +- outb(0xd0, rt->io); /* volume steady, off */ +- rt->curvol = 0; /* track the volume state! */ +- mutex_unlock(&rt->lock); +- return 0; +- } +- +- rt->muted = 0; +- if (vol > rt->curvol) +- for (i = rt->curvol; i < vol; i++) +- rt_incvol(rt); +- else +- for (i = rt->curvol; i > vol; i--) +- rt_decvol(rt); ++ struct rtrack *rt = kzalloc(sizeof(struct rtrack), GFP_KERNEL); + +- rt->curvol = vol; +- mutex_unlock(&rt->lock); +- return 0; ++ if (rt) ++ rt->curvol = 0xff; ++ return rt ? &rt->isa : NULL; + } + +-/* the 128+64 on these outb's is to keep the volume stable while tuning +- * without them, the volume _will_ creep up with each frequency change +- * and bit 4 (+16) is to keep the signal strength meter enabled ++/* The 128+64 on these outb's is to keep the volume stable while tuning. ++ * Without them, the volume _will_ creep up with each frequency change ++ * and bit 4 (+16) is to keep the signal strength meter enabled. + */ + +-static void send_0_byte(struct rtrack *rt) ++static void send_0_byte(struct radio_isa_card *isa, int on) + { +- if (rt->curvol == 0 || rt->muted) { +- outb_p(128+64+16+ 1, rt->io); /* wr-enable + data low */ +- outb_p(128+64+16+2+1, rt->io); /* clock */ +- } +- else { +- outb_p(128+64+16+8+ 1, rt->io); /* on + wr-enable + data low */ +- outb_p(128+64+16+8+2+1, rt->io); /* clock */ +- } ++ outb_p(128+64+16+on+1, isa->io); /* wr-enable + data low */ ++ outb_p(128+64+16+on+2+1, isa->io); /* clock */ + msleep(1); + } + +-static void send_1_byte(struct rtrack *rt) ++static void send_1_byte(struct radio_isa_card *isa, int on) + { +- if (rt->curvol == 0 || rt->muted) { +- outb_p(128+64+16+4 +1, rt->io); /* wr-enable+data high */ +- outb_p(128+64+16+4+2+1, rt->io); /* clock */ +- } +- else { +- outb_p(128+64+16+8+4 +1, rt->io); /* on+wr-enable+data high */ +- outb_p(128+64+16+8+4+2+1, rt->io); /* clock */ +- } +- ++ outb_p(128+64+16+on+4+1, isa->io); /* wr-enable+data high */ ++ outb_p(128+64+16+on+4+2+1, isa->io); /* clock */ + msleep(1); + } + +-static int rt_setfreq(struct rtrack *rt, unsigned long freq) ++static int rtrack_s_frequency(struct radio_isa_card *isa, u32 freq) + { ++ int on = v4l2_ctrl_g_ctrl(isa->mute) ? 0 : 8; + int i; + +- mutex_lock(&rt->lock); /* Stop other ops interfering */ +- +- rt->curfreq = freq; +- +- /* now uses VIDEO_TUNER_LOW for fine tuning */ +- + freq += 171200; /* Add 10.7 MHz IF */ + freq /= 800; /* Convert to 50 kHz units */ + +- send_0_byte(rt); /* 0: LSB of frequency */ ++ send_0_byte(isa, on); /* 0: LSB of frequency */ + + for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ + if (freq & (1 << i)) +- send_1_byte(rt); ++ send_1_byte(isa, on); + else +- send_0_byte(rt); ++ send_0_byte(isa, on); + +- send_0_byte(rt); /* 14: test bit - always 0 */ +- send_0_byte(rt); /* 15: test bit - always 0 */ ++ send_0_byte(isa, on); /* 14: test bit - always 0 */ ++ send_0_byte(isa, on); /* 15: test bit - always 0 */ + +- send_0_byte(rt); /* 16: band data 0 - always 0 */ +- send_0_byte(rt); /* 17: band data 1 - always 0 */ +- send_0_byte(rt); /* 18: band data 2 - always 0 */ +- send_0_byte(rt); /* 19: time base - always 0 */ +- +- send_0_byte(rt); /* 20: spacing (0 = 25 kHz) */ +- send_1_byte(rt); /* 21: spacing (1 = 25 kHz) */ +- send_0_byte(rt); /* 22: spacing (0 = 25 kHz) */ +- send_1_byte(rt); /* 23: AM/FM (FM = 1, always) */ +- +- if (rt->curvol == 0 || rt->muted) +- outb(0xd0, rt->io); /* volume steady + sigstr */ +- else +- outb(0xd8, rt->io); /* volume steady + sigstr + on */ ++ send_0_byte(isa, on); /* 16: band data 0 - always 0 */ ++ send_0_byte(isa, on); /* 17: band data 1 - always 0 */ ++ send_0_byte(isa, on); /* 18: band data 2 - always 0 */ ++ send_0_byte(isa, on); /* 19: time base - always 0 */ + +- mutex_unlock(&rt->lock); ++ send_0_byte(isa, on); /* 20: spacing (0 = 25 kHz) */ ++ send_1_byte(isa, on); /* 21: spacing (1 = 25 kHz) */ ++ send_0_byte(isa, on); /* 22: spacing (0 = 25 kHz) */ ++ send_1_byte(isa, on); /* 23: AM/FM (FM = 1, always) */ + ++ outb(0xd0 + on, isa->io); /* volume steady + sigstr */ + return 0; + } + +-static int rt_getsigstr(struct rtrack *rt) ++static u32 rtrack_g_signal(struct radio_isa_card *isa) + { +- int sig = 1; +- +- mutex_lock(&rt->lock); +- if (inb(rt->io) & 2) /* bit set = no signal present */ +- sig = 0; +- mutex_unlock(&rt->lock); +- return sig; +-} +- +-static int vidioc_querycap(struct file *file, void *priv, +- struct v4l2_capability *v) +-{ +- strlcpy(v->driver, "radio-aimslab", sizeof(v->driver)); +- strlcpy(v->card, "RadioTrack", sizeof(v->card)); +- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); +- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; +- return 0; +-} +- +-static int vidioc_g_tuner(struct file *file, void *priv, +- struct v4l2_tuner *v) +-{ +- struct rtrack *rt = video_drvdata(file); +- +- if (v->index > 0) +- return -EINVAL; +- +- strlcpy(v->name, "FM", sizeof(v->name)); +- v->type = V4L2_TUNER_RADIO; +- v->rangelow = 87 * 16000; +- v->rangehigh = 108 * 16000; +- v->rxsubchans = V4L2_TUNER_SUB_MONO; +- v->capability = V4L2_TUNER_CAP_LOW; +- v->audmode = V4L2_TUNER_MODE_MONO; +- v->signal = 0xffff * rt_getsigstr(rt); +- return 0; ++ /* bit set = no signal present */ ++ return 0xffff * !(inb(isa->io) & 2); + } + +-static int vidioc_s_tuner(struct file *file, void *priv, +- struct v4l2_tuner *v) ++static int rtrack_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) + { +- return v->index ? -EINVAL : 0; +-} ++ struct rtrack *rt = container_of(isa, struct rtrack, isa); ++ int curvol = rt->curvol; + +-static int vidioc_s_frequency(struct file *file, void *priv, +- struct v4l2_frequency *f) +-{ +- struct rtrack *rt = video_drvdata(file); +- +- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) +- return -EINVAL; +- rt_setfreq(rt, f->frequency); +- return 0; +-} +- +-static int vidioc_g_frequency(struct file *file, void *priv, +- struct v4l2_frequency *f) +-{ +- struct rtrack *rt = video_drvdata(file); +- +- if (f->tuner != 0) +- return -EINVAL; +- f->type = V4L2_TUNER_RADIO; +- f->frequency = rt->curfreq; +- return 0; +-} +- +-static int vidioc_queryctrl(struct file *file, void *priv, +- struct v4l2_queryctrl *qc) +-{ +- switch (qc->id) { +- case V4L2_CID_AUDIO_MUTE: +- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); +- case V4L2_CID_AUDIO_VOLUME: +- return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff); +- } +- return -EINVAL; +-} +- +-static int vidioc_g_ctrl(struct file *file, void *priv, +- struct v4l2_control *ctrl) +-{ +- struct rtrack *rt = video_drvdata(file); +- +- switch (ctrl->id) { +- case V4L2_CID_AUDIO_MUTE: +- ctrl->value = rt->muted; +- return 0; +- case V4L2_CID_AUDIO_VOLUME: +- ctrl->value = rt->curvol; ++ if (mute) { ++ outb(0xd0, isa->io); /* volume steady + sigstr + off */ + return 0; + } +- return -EINVAL; +-} +- +-static int vidioc_s_ctrl(struct file *file, void *priv, +- struct v4l2_control *ctrl) +-{ +- struct rtrack *rt = video_drvdata(file); +- +- switch (ctrl->id) { +- case V4L2_CID_AUDIO_MUTE: +- if (ctrl->value) +- rt_mute(rt); +- else +- rt_setvol(rt, rt->curvol); +- return 0; +- case V4L2_CID_AUDIO_VOLUME: +- rt_setvol(rt, ctrl->value); +- return 0; ++ if (vol == 0) { /* volume = 0 means mute the card */ ++ outb(0x48, isa->io); /* volume down but still "on" */ ++ msleep(curvol * 3); /* make sure it's totally down */ ++ } else if (curvol < vol) { ++ outb(0x98, isa->io); /* volume up + sigstr + on */ ++ for (; curvol < vol; curvol++) ++ udelay(3000); ++ } else if (curvol > vol) { ++ outb(0x58, isa->io); /* volume down + sigstr + on */ ++ for (; curvol > vol; curvol--) ++ udelay(3000); + } +- return -EINVAL; +-} +- +-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +-{ +- *i = 0; ++ outb(0xd8, isa->io); /* volume steady + sigstr + on */ ++ rt->curvol = vol; + return 0; + } + +-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +-{ +- return i ? -EINVAL : 0; +-} +- +-static int vidioc_g_audio(struct file *file, void *priv, +- struct v4l2_audio *a) ++/* Mute card - prevents noisy bootups */ ++static int rtrack_initialize(struct radio_isa_card *isa) + { +- a->index = 0; +- strlcpy(a->name, "Radio", sizeof(a->name)); +- a->capability = V4L2_AUDCAP_STEREO; ++ /* this ensures that the volume is all the way up */ ++ outb(0x90, isa->io); /* volume up but still "on" */ ++ msleep(3000); /* make sure it's totally up */ ++ outb(0xc0, isa->io); /* steady volume, mute card */ + return 0; + } + +-static int vidioc_s_audio(struct file *file, void *priv, +- struct v4l2_audio *a) +-{ +- return a->index ? -EINVAL : 0; +-} +- +-static const struct v4l2_file_operations rtrack_fops = { +- .owner = THIS_MODULE, +- .unlocked_ioctl = video_ioctl2, ++static const struct radio_isa_ops rtrack_ops = { ++ .alloc = rtrack_alloc, ++ .init = rtrack_initialize, ++ .s_mute_volume = rtrack_s_mute_volume, ++ .s_frequency = rtrack_s_frequency, ++ .g_signal = rtrack_g_signal, + }; + +-static const struct v4l2_ioctl_ops rtrack_ioctl_ops = { +- .vidioc_querycap = vidioc_querycap, +- .vidioc_g_tuner = vidioc_g_tuner, +- .vidioc_s_tuner = vidioc_s_tuner, +- .vidioc_g_audio = vidioc_g_audio, +- .vidioc_s_audio = vidioc_s_audio, +- .vidioc_g_input = vidioc_g_input, +- .vidioc_s_input = vidioc_s_input, +- .vidioc_g_frequency = vidioc_g_frequency, +- .vidioc_s_frequency = vidioc_s_frequency, +- .vidioc_queryctrl = vidioc_queryctrl, +- .vidioc_g_ctrl = vidioc_g_ctrl, +- .vidioc_s_ctrl = vidioc_s_ctrl, ++static const int rtrack_ioports[] = { 0x20f, 0x30f }; ++ ++static struct radio_isa_driver rtrack_driver = { ++ .driver = { ++ .match = radio_isa_match, ++ .probe = radio_isa_probe, ++ .remove = radio_isa_remove, ++ .driver = { ++ .name = "radio-aimslab", ++ }, ++ }, ++ .io_params = io, ++ .radio_nr_params = radio_nr, ++ .io_ports = rtrack_ioports, ++ .num_of_io_ports = ARRAY_SIZE(rtrack_ioports), ++ .region_size = 2, ++ .card = "AIMSlab RadioTrack/RadioReveal", ++ .ops = &rtrack_ops, ++ .has_stereo = true, ++ .max_volume = 0xff, + }; + + static int __init rtrack_init(void) + { +- struct rtrack *rt = &rtrack_card; +- struct v4l2_device *v4l2_dev = &rt->v4l2_dev; +- int res; +- +- strlcpy(v4l2_dev->name, "rtrack", sizeof(v4l2_dev->name)); +- rt->io = io; +- +- if (rt->io == -1) { +- v4l2_err(v4l2_dev, "you must set an I/O address with io=0x20f or 0x30f\n"); +- return -EINVAL; +- } +- +- if (!request_region(rt->io, 2, "rtrack")) { +- v4l2_err(v4l2_dev, "port 0x%x already in use\n", rt->io); +- return -EBUSY; +- } +- +- res = v4l2_device_register(NULL, v4l2_dev); +- if (res < 0) { +- release_region(rt->io, 2); +- v4l2_err(v4l2_dev, "could not register v4l2_device\n"); +- return res; +- } +- +- strlcpy(rt->vdev.name, v4l2_dev->name, sizeof(rt->vdev.name)); +- rt->vdev.v4l2_dev = v4l2_dev; +- rt->vdev.fops = &rtrack_fops; +- rt->vdev.ioctl_ops = &rtrack_ioctl_ops; +- rt->vdev.release = video_device_release_empty; +- video_set_drvdata(&rt->vdev, rt); +- +- /* Set up the I/O locking */ +- +- mutex_init(&rt->lock); +- +- /* mute card - prevents noisy bootups */ +- +- /* this ensures that the volume is all the way down */ +- outb(0x48, rt->io); /* volume down but still "on" */ +- msleep(2000); /* make sure it's totally down */ +- outb(0xc0, rt->io); /* steady volume, mute card */ +- +- if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { +- v4l2_device_unregister(&rt->v4l2_dev); +- release_region(rt->io, 2); +- return -EINVAL; +- } +- v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n"); +- +- return 0; ++ return isa_register_driver(&rtrack_driver.driver, RTRACK_MAX); + } + + static void __exit rtrack_exit(void) + { +- struct rtrack *rt = &rtrack_card; +- +- video_unregister_device(&rt->vdev); +- v4l2_device_unregister(&rt->v4l2_dev); +- release_region(rt->io, 2); ++ isa_unregister_driver(&rtrack_driver.driver); + } + + module_init(rtrack_init); + module_exit(rtrack_exit); +- +Index: linux-3.3.x86_64/drivers/media/radio/radio-aztech.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/radio/radio-aztech.c ++++ linux-3.3.x86_64/drivers/media/radio/radio-aztech.c +@@ -1,5 +1,7 @@ +-/* radio-aztech.c - Aztech radio card driver for Linux 2.2 ++/* ++ * radio-aztech.c - Aztech radio card driver + * ++ * Converted to the radio-isa framework by Hans Verkuil + * Converted to V4L2 API by Mauro Carvalho Chehab + * Adapted to support the Video for Linux API by + * Russell Kroll . Based on original tuner code by: +@@ -10,19 +12,7 @@ + * Scott McGrath (smcgrath@twilight.vtc.vsc.edu) + * William McGrath (wmcgrath@twilight.vtc.vsc.edu) + * +- * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/ +- * along with more information on the card itself. +- * +- * History: +- * 1999-02-24 Russell Kroll +- * Fine tuning/VIDEO_TUNER_LOW +- * Range expanded to 87-108 MHz (from 87.9-107.8) +- * +- * Notable changes from the original source: +- * - includes stripped down to the essentials +- * - for loops used as delays replaced with udelay() +- * - #defines removed, changed to static values +- * - tuning structure changed - no more character arrays, other changes ++ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool. + */ + + #include /* Modules */ +@@ -31,126 +21,72 @@ + #include /* udelay */ + #include /* kernel radio structs */ + #include /* outb, outb_p */ ++#include + #include + #include ++#include ++#include "radio-isa.h" + + MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); + MODULE_DESCRIPTION("A driver for the Aztech radio card."); + MODULE_LICENSE("GPL"); +-MODULE_VERSION("0.0.3"); ++MODULE_VERSION("1.0.0"); + + /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ +- + #ifndef CONFIG_RADIO_AZTECH_PORT + #define CONFIG_RADIO_AZTECH_PORT -1 + #endif + +-static int io = CONFIG_RADIO_AZTECH_PORT; +-static int radio_nr = -1; +-static int radio_wait_time = 1000; +- +-module_param(io, int, 0); +-module_param(radio_nr, int, 0); +-MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)"); ++#define AZTECH_MAX 2 + +-struct aztech +-{ +- struct v4l2_device v4l2_dev; +- struct video_device vdev; +- int io; ++static int io[AZTECH_MAX] = { [0] = CONFIG_RADIO_AZTECH_PORT, ++ [1 ... (AZTECH_MAX - 1)] = -1 }; ++static int radio_nr[AZTECH_MAX] = { [0 ... (AZTECH_MAX - 1)] = -1 }; ++static const int radio_wait_time = 1000; ++ ++module_param_array(io, int, NULL, 0444); ++MODULE_PARM_DESC(io, "I/O addresses of the Aztech card (0x350 or 0x358)"); ++module_param_array(radio_nr, int, NULL, 0444); ++MODULE_PARM_DESC(radio_nr, "Radio device numbers"); ++ ++struct aztech { ++ struct radio_isa_card isa; + int curvol; +- unsigned long curfreq; +- int stereo; +- struct mutex lock; + }; + +-static struct aztech aztech_card; +- +-static int volconvert(int level) +-{ +- level >>= 14; /* Map 16bits down to 2 bit */ +- level &= 3; +- +- /* convert to card-friendly values */ +- switch (level) { +- case 0: +- return 0; +- case 1: +- return 1; +- case 2: +- return 4; +- case 3: +- return 5; +- } +- return 0; /* Quieten gcc */ +-} +- + static void send_0_byte(struct aztech *az) + { + udelay(radio_wait_time); +- outb_p(2 + volconvert(az->curvol), az->io); +- outb_p(64 + 2 + volconvert(az->curvol), az->io); ++ outb_p(2 + az->curvol, az->isa.io); ++ outb_p(64 + 2 + az->curvol, az->isa.io); + } + + static void send_1_byte(struct aztech *az) + { +- udelay (radio_wait_time); +- outb_p(128 + 2 + volconvert(az->curvol), az->io); +- outb_p(128 + 64 + 2 + volconvert(az->curvol), az->io); +-} +- +-static int az_setvol(struct aztech *az, int vol) +-{ +- mutex_lock(&az->lock); +- outb(volconvert(vol), az->io); +- mutex_unlock(&az->lock); +- return 0; +-} +- +-/* thanks to Michael Dwyer for giving me a dose of clues in +- * the signal strength department.. +- * +- * This card has a stereo bit - bit 0 set = mono, not set = stereo +- * It also has a "signal" bit - bit 1 set = bad signal, not set = good +- * +- */ +- +-static int az_getsigstr(struct aztech *az) +-{ +- int sig = 1; +- +- mutex_lock(&az->lock); +- if (inb(az->io) & 2) /* bit set = no signal present */ +- sig = 0; +- mutex_unlock(&az->lock); +- return sig; ++ udelay(radio_wait_time); ++ outb_p(128 + 2 + az->curvol, az->isa.io); ++ outb_p(128 + 64 + 2 + az->curvol, az->isa.io); + } + +-static int az_getstereo(struct aztech *az) ++static struct radio_isa_card *aztech_alloc(void) + { +- int stereo = 1; ++ struct aztech *az = kzalloc(sizeof(*az), GFP_KERNEL); + +- mutex_lock(&az->lock); +- if (inb(az->io) & 1) /* bit set = mono */ +- stereo = 0; +- mutex_unlock(&az->lock); +- return stereo; ++ return az ? &az->isa : NULL; + } + +-static int az_setfreq(struct aztech *az, unsigned long frequency) ++static int aztech_s_frequency(struct radio_isa_card *isa, u32 freq) + { ++ struct aztech *az = container_of(isa, struct aztech, isa); + int i; + +- mutex_lock(&az->lock); +- +- az->curfreq = frequency; +- frequency += 171200; /* Add 10.7 MHz IF */ +- frequency /= 800; /* Convert to 50 kHz units */ ++ freq += 171200; /* Add 10.7 MHz IF */ ++ freq /= 800; /* Convert to 50 kHz units */ + + send_0_byte(az); /* 0: LSB of frequency */ + + for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ +- if (frequency & (1 << i)) ++ if (freq & (1 << i)) + send_1_byte(az); + else + send_0_byte(az); +@@ -158,7 +94,7 @@ static int az_setfreq(struct aztech *az, + send_0_byte(az); /* 14: test bit - always 0 */ + send_0_byte(az); /* 15: test bit - always 0 */ + send_0_byte(az); /* 16: band data 0 - always 0 */ +- if (az->stereo) /* 17: stereo (1 to enable) */ ++ if (isa->stereo) /* 17: stereo (1 to enable) */ + send_1_byte(az); + else + send_0_byte(az); +@@ -173,225 +109,77 @@ static int az_setfreq(struct aztech *az, + /* latch frequency */ + + udelay(radio_wait_time); +- outb_p(128 + 64 + volconvert(az->curvol), az->io); +- +- mutex_unlock(&az->lock); +- +- return 0; +-} ++ outb_p(128 + 64 + az->curvol, az->isa.io); + +-static int vidioc_querycap(struct file *file, void *priv, +- struct v4l2_capability *v) +-{ +- strlcpy(v->driver, "radio-aztech", sizeof(v->driver)); +- strlcpy(v->card, "Aztech Radio", sizeof(v->card)); +- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); +- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + return 0; + } + +-static int vidioc_g_tuner(struct file *file, void *priv, +- struct v4l2_tuner *v) +-{ +- struct aztech *az = video_drvdata(file); +- +- if (v->index > 0) +- return -EINVAL; +- +- strlcpy(v->name, "FM", sizeof(v->name)); +- v->type = V4L2_TUNER_RADIO; +- +- v->rangelow = 87 * 16000; +- v->rangehigh = 108 * 16000; +- v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; +- v->capability = V4L2_TUNER_CAP_LOW; +- if (az_getstereo(az)) +- v->audmode = V4L2_TUNER_MODE_STEREO; +- else +- v->audmode = V4L2_TUNER_MODE_MONO; +- v->signal = 0xFFFF * az_getsigstr(az); +- +- return 0; +-} +- +-static int vidioc_s_tuner(struct file *file, void *priv, +- struct v4l2_tuner *v) +-{ +- return v->index ? -EINVAL : 0; +-} +- +-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +-{ +- *i = 0; +- return 0; +-} +- +-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +-{ +- return i ? -EINVAL : 0; +-} +- +-static int vidioc_g_audio(struct file *file, void *priv, +- struct v4l2_audio *a) ++/* thanks to Michael Dwyer for giving me a dose of clues in ++ * the signal strength department.. ++ * ++ * This card has a stereo bit - bit 0 set = mono, not set = stereo ++ */ ++static u32 aztech_g_rxsubchans(struct radio_isa_card *isa) + { +- a->index = 0; +- strlcpy(a->name, "Radio", sizeof(a->name)); +- a->capability = V4L2_AUDCAP_STEREO; +- return 0; ++ if (inb(isa->io) & 1) ++ return V4L2_TUNER_SUB_MONO; ++ return V4L2_TUNER_SUB_STEREO; + } + +-static int vidioc_s_audio(struct file *file, void *priv, +- struct v4l2_audio *a) ++static int aztech_s_stereo(struct radio_isa_card *isa, bool stereo) + { +- return a->index ? -EINVAL : 0; ++ return aztech_s_frequency(isa, isa->freq); + } + +-static int vidioc_s_frequency(struct file *file, void *priv, +- struct v4l2_frequency *f) ++static int aztech_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) + { +- struct aztech *az = video_drvdata(file); ++ struct aztech *az = container_of(isa, struct aztech, isa); + +- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) +- return -EINVAL; +- az_setfreq(az, f->frequency); ++ if (mute) ++ vol = 0; ++ az->curvol = (vol & 1) + ((vol & 2) << 1); ++ outb(az->curvol, isa->io); + return 0; + } + +-static int vidioc_g_frequency(struct file *file, void *priv, +- struct v4l2_frequency *f) +-{ +- struct aztech *az = video_drvdata(file); +- +- if (f->tuner != 0) +- return -EINVAL; +- f->type = V4L2_TUNER_RADIO; +- f->frequency = az->curfreq; +- return 0; +-} +- +-static int vidioc_queryctrl(struct file *file, void *priv, +- struct v4l2_queryctrl *qc) +-{ +- switch (qc->id) { +- case V4L2_CID_AUDIO_MUTE: +- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); +- case V4L2_CID_AUDIO_VOLUME: +- return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff); +- } +- return -EINVAL; +-} +- +-static int vidioc_g_ctrl(struct file *file, void *priv, +- struct v4l2_control *ctrl) +-{ +- struct aztech *az = video_drvdata(file); +- +- switch (ctrl->id) { +- case V4L2_CID_AUDIO_MUTE: +- if (az->curvol == 0) +- ctrl->value = 1; +- else +- ctrl->value = 0; +- return 0; +- case V4L2_CID_AUDIO_VOLUME: +- ctrl->value = az->curvol * 6554; +- return 0; +- } +- return -EINVAL; +-} +- +-static int vidioc_s_ctrl(struct file *file, void *priv, +- struct v4l2_control *ctrl) +-{ +- struct aztech *az = video_drvdata(file); +- +- switch (ctrl->id) { +- case V4L2_CID_AUDIO_MUTE: +- if (ctrl->value) +- az_setvol(az, 0); +- else +- az_setvol(az, az->curvol); +- return 0; +- case V4L2_CID_AUDIO_VOLUME: +- az_setvol(az, ctrl->value); +- return 0; +- } +- return -EINVAL; +-} +- +-static const struct v4l2_file_operations aztech_fops = { +- .owner = THIS_MODULE, +- .unlocked_ioctl = video_ioctl2, ++static const struct radio_isa_ops aztech_ops = { ++ .alloc = aztech_alloc, ++ .s_mute_volume = aztech_s_mute_volume, ++ .s_frequency = aztech_s_frequency, ++ .s_stereo = aztech_s_stereo, ++ .g_rxsubchans = aztech_g_rxsubchans, + }; + +-static const struct v4l2_ioctl_ops aztech_ioctl_ops = { +- .vidioc_querycap = vidioc_querycap, +- .vidioc_g_tuner = vidioc_g_tuner, +- .vidioc_s_tuner = vidioc_s_tuner, +- .vidioc_g_audio = vidioc_g_audio, +- .vidioc_s_audio = vidioc_s_audio, +- .vidioc_g_input = vidioc_g_input, +- .vidioc_s_input = vidioc_s_input, +- .vidioc_g_frequency = vidioc_g_frequency, +- .vidioc_s_frequency = vidioc_s_frequency, +- .vidioc_queryctrl = vidioc_queryctrl, +- .vidioc_g_ctrl = vidioc_g_ctrl, +- .vidioc_s_ctrl = vidioc_s_ctrl, ++static const int aztech_ioports[] = { 0x350, 0x358 }; ++ ++static struct radio_isa_driver aztech_driver = { ++ .driver = { ++ .match = radio_isa_match, ++ .probe = radio_isa_probe, ++ .remove = radio_isa_remove, ++ .driver = { ++ .name = "radio-aztech", ++ }, ++ }, ++ .io_params = io, ++ .radio_nr_params = radio_nr, ++ .io_ports = aztech_ioports, ++ .num_of_io_ports = ARRAY_SIZE(aztech_ioports), ++ .region_size = 2, ++ .card = "Aztech Radio", ++ .ops = &aztech_ops, ++ .has_stereo = true, ++ .max_volume = 3, + }; + + static int __init aztech_init(void) + { +- struct aztech *az = &aztech_card; +- struct v4l2_device *v4l2_dev = &az->v4l2_dev; +- int res; +- +- strlcpy(v4l2_dev->name, "aztech", sizeof(v4l2_dev->name)); +- az->io = io; +- +- if (az->io == -1) { +- v4l2_err(v4l2_dev, "you must set an I/O address with io=0x350 or 0x358\n"); +- return -EINVAL; +- } +- +- if (!request_region(az->io, 2, "aztech")) { +- v4l2_err(v4l2_dev, "port 0x%x already in use\n", az->io); +- return -EBUSY; +- } +- +- res = v4l2_device_register(NULL, v4l2_dev); +- if (res < 0) { +- release_region(az->io, 2); +- v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); +- return res; +- } +- +- mutex_init(&az->lock); +- strlcpy(az->vdev.name, v4l2_dev->name, sizeof(az->vdev.name)); +- az->vdev.v4l2_dev = v4l2_dev; +- az->vdev.fops = &aztech_fops; +- az->vdev.ioctl_ops = &aztech_ioctl_ops; +- az->vdev.release = video_device_release_empty; +- video_set_drvdata(&az->vdev, az); +- /* mute card - prevents noisy bootups */ +- outb(0, az->io); +- +- if (video_register_device(&az->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { +- v4l2_device_unregister(v4l2_dev); +- release_region(az->io, 2); +- return -EINVAL; +- } +- +- v4l2_info(v4l2_dev, "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n"); +- return 0; ++ return isa_register_driver(&aztech_driver.driver, AZTECH_MAX); + } + + static void __exit aztech_exit(void) + { +- struct aztech *az = &aztech_card; +- +- video_unregister_device(&az->vdev); +- v4l2_device_unregister(&az->v4l2_dev); +- release_region(az->io, 2); ++ isa_unregister_driver(&aztech_driver.driver); + } + + module_init(aztech_init); +Index: linux-3.3.x86_64/drivers/media/radio/radio-gemtek.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/radio/radio-gemtek.c ++++ linux-3.3.x86_64/drivers/media/radio/radio-gemtek.c +@@ -1,4 +1,7 @@ +-/* GemTek radio card driver for Linux (C) 1998 Jonas Munsin ++/* ++ * GemTek radio card driver ++ * ++ * Copyright 1998 Jonas Munsin + * + * GemTek hasn't released any specs on the card, so the protocol had to + * be reverse engineered with dosemu. +@@ -11,9 +14,12 @@ + * Converted to new API by Alan Cox + * Various bugfixes and enhancements by Russell Kroll + * +- * TODO: Allow for more than one of these foolish entities :-) +- * ++ * Converted to the radio-isa framework by Hans Verkuil + * Converted to V4L2 API by Mauro Carvalho Chehab ++ * ++ * Note: this card seems to swap the left and right audio channels! ++ * ++ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool. + */ + + #include /* Modules */ +@@ -23,8 +29,10 @@ + #include /* kernel radio structs */ + #include + #include /* outb, outb_p */ ++#include + #include + #include ++#include "radio-isa.h" + + /* + * Module info. +@@ -33,7 +41,7 @@ + MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen "); + MODULE_DESCRIPTION("A driver for the GemTek Radio card."); + MODULE_LICENSE("GPL"); +-MODULE_VERSION("0.0.4"); ++MODULE_VERSION("1.0.0"); + + /* + * Module params. +@@ -46,45 +54,29 @@ MODULE_VERSION("0.0.4"); + #define CONFIG_RADIO_GEMTEK_PROBE 1 + #endif + +-static int io = CONFIG_RADIO_GEMTEK_PORT; +-static bool probe = CONFIG_RADIO_GEMTEK_PROBE; +-static bool hardmute; +-static bool shutdown = 1; +-static bool keepmuted = 1; +-static bool initmute = 1; +-static int radio_nr = -1; ++#define GEMTEK_MAX 4 + +-module_param(io, int, 0444); +-MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic " +- "probing is disabled or fails. The most common I/O ports are: 0x20c " +- "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to " +- "work for the combined sound/radiocard)."); ++static bool probe = CONFIG_RADIO_GEMTEK_PROBE; ++static bool hardmute; ++static int io[GEMTEK_MAX] = { [0] = CONFIG_RADIO_GEMTEK_PORT, ++ [1 ... (GEMTEK_MAX - 1)] = -1 }; ++static int radio_nr[GEMTEK_MAX] = { [0 ... (GEMTEK_MAX - 1)] = -1 }; + + module_param(probe, bool, 0444); +-MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most " +- "common I/O ports used by the card are probed."); ++MODULE_PARM_DESC(probe, "Enable automatic device probing."); + + module_param(hardmute, bool, 0644); +-MODULE_PARM_DESC(hardmute, "Enable `hard muting' by shutting down PLL, may " ++MODULE_PARM_DESC(hardmute, "Enable 'hard muting' by shutting down PLL, may " + "reduce static noise."); + +-module_param(shutdown, bool, 0644); +-MODULE_PARM_DESC(shutdown, "Enable shutting down PLL and muting line when " +- "module is unloaded."); +- +-module_param(keepmuted, bool, 0644); +-MODULE_PARM_DESC(keepmuted, "Keep card muted even when frequency is changed."); +- +-module_param(initmute, bool, 0444); +-MODULE_PARM_DESC(initmute, "Mute card when module is loaded."); +- +-module_param(radio_nr, int, 0444); ++module_param_array(io, int, NULL, 0444); ++MODULE_PARM_DESC(io, "Force I/O ports for the GemTek Radio card if automatic " ++ "probing is disabled or fails. The most common I/O ports are: 0x20c " ++ "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to " ++ "work for the combined sound/radiocard)."); + +-/* +- * Functions for controlling the card. +- */ +-#define GEMTEK_LOWFREQ (87*16000) +-#define GEMTEK_HIGHFREQ (108*16000) ++module_param_array(radio_nr, int, NULL, 0444); ++MODULE_PARM_DESC(radio_nr, "Radio device numbers"); + + /* + * Frequency calculation constants. Intermediate frequency 10.52 MHz (nominal +@@ -108,18 +100,11 @@ module_param(radio_nr, int, 0444); + #define LONG_DELAY 75 /* usec */ + + struct gemtek { +- struct v4l2_device v4l2_dev; +- struct video_device vdev; +- struct mutex lock; +- unsigned long lastfreq; +- int muted; +- int verified; +- int io; ++ struct radio_isa_card isa; ++ bool muted; + u32 bu2614data; + }; + +-static struct gemtek gemtek_card; +- + #define BU2614_FREQ_BITS 16 /* D0..D15, Frequency data */ + #define BU2614_PORT_BITS 3 /* P0..P2, Output port control data */ + #define BU2614_VOID_BITS 4 /* unused */ +@@ -166,31 +151,24 @@ static struct gemtek gemtek_card; + */ + static void gemtek_bu2614_transmit(struct gemtek *gt) + { ++ struct radio_isa_card *isa = >->isa; + int i, bit, q, mute; + +- mutex_lock(>->lock); +- + mute = gt->muted ? GEMTEK_MT : 0x00; + +- outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io); +- udelay(SHORT_DELAY); +- outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io); ++ outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, isa->io); + udelay(LONG_DELAY); + + for (i = 0, q = gt->bu2614data; i < 32; i++, q >>= 1) { + bit = (q & 1) ? GEMTEK_DA : 0; +- outb_p(mute | GEMTEK_CE | bit, gt->io); ++ outb_p(mute | GEMTEK_CE | bit, isa->io); + udelay(SHORT_DELAY); +- outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, gt->io); ++ outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, isa->io); + udelay(SHORT_DELAY); + } + +- outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io); ++ outb_p(mute | GEMTEK_DA | GEMTEK_CK, isa->io); + udelay(SHORT_DELAY); +- outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io); +- udelay(LONG_DELAY); +- +- mutex_unlock(>->lock); + } + + /* +@@ -198,21 +176,27 @@ static void gemtek_bu2614_transmit(struc + */ + static unsigned long gemtek_convfreq(unsigned long freq) + { +- return ((freq<muted = true; ++ return gt ? >->isa : NULL; + } + + /* + * Set FM-frequency. + */ +-static void gemtek_setfreq(struct gemtek *gt, unsigned long freq) ++static int gemtek_s_frequency(struct radio_isa_card *isa, u32 freq) + { +- if (keepmuted && hardmute && gt->muted) +- return; ++ struct gemtek *gt = container_of(isa, struct gemtek, isa); + +- freq = clamp_val(freq, GEMTEK_LOWFREQ, GEMTEK_HIGHFREQ); +- +- gt->lastfreq = freq; +- gt->muted = 0; ++ if (hardmute && gt->muted) ++ return 0; + + gemtek_bu2614_set(gt, BU2614_PORT, 0); + gemtek_bu2614_set(gt, BU2614_FMES, 0); +@@ -220,23 +204,25 @@ static void gemtek_setfreq(struct gemtek + gemtek_bu2614_set(gt, BU2614_SWAL, 0); + gemtek_bu2614_set(gt, BU2614_FMUN, 1); /* GT bit set */ + gemtek_bu2614_set(gt, BU2614_TEST, 0); +- + gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_STDF_3_125_KHZ); + gemtek_bu2614_set(gt, BU2614_FREQ, gemtek_convfreq(freq)); +- + gemtek_bu2614_transmit(gt); ++ return 0; + } + + /* + * Set mute flag. + */ +-static void gemtek_mute(struct gemtek *gt) ++static int gemtek_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) + { ++ struct gemtek *gt = container_of(isa, struct gemtek, isa); + int i; + +- gt->muted = 1; +- ++ gt->muted = mute; + if (hardmute) { ++ if (!mute) ++ return gemtek_s_frequency(isa, isa->freq); ++ + /* Turn off PLL, disable data output */ + gemtek_bu2614_set(gt, BU2614_PORT, 0); + gemtek_bu2614_set(gt, BU2614_FMES, 0); /* CT bit off */ +@@ -247,367 +233,85 @@ static void gemtek_mute(struct gemtek *g + gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_PLL_OFF); + gemtek_bu2614_set(gt, BU2614_FREQ, 0); + gemtek_bu2614_transmit(gt); +- return; ++ return 0; + } + +- mutex_lock(>->lock); +- + /* Read bus contents (CE, CK and DA). */ +- i = inb_p(gt->io); ++ i = inb_p(isa->io); + /* Write it back with mute flag set. */ +- outb_p((i >> 5) | GEMTEK_MT, gt->io); ++ outb_p((i >> 5) | (mute ? GEMTEK_MT : 0), isa->io); + udelay(SHORT_DELAY); +- +- mutex_unlock(>->lock); +-} +- +-/* +- * Unset mute flag. +- */ +-static void gemtek_unmute(struct gemtek *gt) +-{ +- int i; +- +- gt->muted = 0; +- if (hardmute) { +- /* Turn PLL back on. */ +- gemtek_setfreq(gt, gt->lastfreq); +- return; +- } +- mutex_lock(>->lock); +- +- i = inb_p(gt->io); +- outb_p(i >> 5, gt->io); +- udelay(SHORT_DELAY); +- +- mutex_unlock(>->lock); ++ return 0; + } + +-/* +- * Get signal strength (= stereo status). +- */ +-static inline int gemtek_getsigstr(struct gemtek *gt) ++static u32 gemtek_g_rxsubchans(struct radio_isa_card *isa) + { +- int sig; +- +- mutex_lock(>->lock); +- sig = inb_p(gt->io) & GEMTEK_NS ? 0 : 1; +- mutex_unlock(>->lock); +- return sig; ++ if (inb_p(isa->io) & GEMTEK_NS) ++ return V4L2_TUNER_SUB_MONO; ++ return V4L2_TUNER_SUB_STEREO; + } + + /* + * Check if requested card acts like GemTek Radio card. + */ +-static int gemtek_verify(struct gemtek *gt, int port) ++static bool gemtek_probe(struct radio_isa_card *isa, int io) + { + int i, q; + +- if (gt->verified == port) +- return 1; +- +- mutex_lock(>->lock); +- +- q = inb_p(port); /* Read bus contents before probing. */ ++ q = inb_p(io); /* Read bus contents before probing. */ + /* Try to turn on CE, CK and DA respectively and check if card responds + properly. */ + for (i = 0; i < 3; ++i) { +- outb_p(1 << i, port); ++ outb_p(1 << i, io); + udelay(SHORT_DELAY); + +- if ((inb_p(port) & (~GEMTEK_NS)) != (0x17 | (1 << (i + 5)))) { +- mutex_unlock(>->lock); +- return 0; +- } ++ if ((inb_p(io) & ~GEMTEK_NS) != (0x17 | (1 << (i + 5)))) ++ return false; + } +- outb_p(q >> 5, port); /* Write bus contents back. */ ++ outb_p(q >> 5, io); /* Write bus contents back. */ + udelay(SHORT_DELAY); +- +- mutex_unlock(>->lock); +- gt->verified = port; +- +- return 1; +-} +- +-/* +- * Automatic probing for card. +- */ +-static int gemtek_probe(struct gemtek *gt) +-{ +- struct v4l2_device *v4l2_dev = >->v4l2_dev; +- int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c }; +- int i; +- +- if (!probe) { +- v4l2_info(v4l2_dev, "Automatic device probing disabled.\n"); +- return -1; +- } +- +- v4l2_info(v4l2_dev, "Automatic device probing enabled.\n"); +- +- for (i = 0; i < ARRAY_SIZE(ioports); ++i) { +- v4l2_info(v4l2_dev, "Trying I/O port 0x%x...\n", ioports[i]); +- +- if (!request_region(ioports[i], 1, "gemtek-probe")) { +- v4l2_warn(v4l2_dev, "I/O port 0x%x busy!\n", +- ioports[i]); +- continue; +- } +- +- if (gemtek_verify(gt, ioports[i])) { +- v4l2_info(v4l2_dev, "Card found from I/O port " +- "0x%x!\n", ioports[i]); +- +- release_region(ioports[i], 1); +- gt->io = ioports[i]; +- return gt->io; +- } +- +- release_region(ioports[i], 1); +- } +- +- v4l2_err(v4l2_dev, "Automatic probing failed!\n"); +- return -1; ++ return true; + } + +-/* +- * Video 4 Linux stuff. +- */ +- +-static const struct v4l2_file_operations gemtek_fops = { +- .owner = THIS_MODULE, +- .unlocked_ioctl = video_ioctl2, ++static const struct radio_isa_ops gemtek_ops = { ++ .alloc = gemtek_alloc, ++ .probe = gemtek_probe, ++ .s_mute_volume = gemtek_s_mute_volume, ++ .s_frequency = gemtek_s_frequency, ++ .g_rxsubchans = gemtek_g_rxsubchans, + }; + +-static int vidioc_querycap(struct file *file, void *priv, +- struct v4l2_capability *v) +-{ +- strlcpy(v->driver, "radio-gemtek", sizeof(v->driver)); +- strlcpy(v->card, "GemTek", sizeof(v->card)); +- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); +- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; +- return 0; +-} +- +-static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) +-{ +- struct gemtek *gt = video_drvdata(file); +- +- if (v->index > 0) +- return -EINVAL; +- +- strlcpy(v->name, "FM", sizeof(v->name)); +- v->type = V4L2_TUNER_RADIO; +- v->rangelow = GEMTEK_LOWFREQ; +- v->rangehigh = GEMTEK_HIGHFREQ; +- v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; +- v->signal = 0xffff * gemtek_getsigstr(gt); +- if (v->signal) { +- v->audmode = V4L2_TUNER_MODE_STEREO; +- v->rxsubchans = V4L2_TUNER_SUB_STEREO; +- } else { +- v->audmode = V4L2_TUNER_MODE_MONO; +- v->rxsubchans = V4L2_TUNER_SUB_MONO; +- } +- return 0; +-} +- +-static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) +-{ +- return (v->index != 0) ? -EINVAL : 0; +-} +- +-static int vidioc_g_frequency(struct file *file, void *priv, +- struct v4l2_frequency *f) +-{ +- struct gemtek *gt = video_drvdata(file); +- +- if (f->tuner != 0) +- return -EINVAL; +- f->type = V4L2_TUNER_RADIO; +- f->frequency = gt->lastfreq; +- return 0; +-} +- +-static int vidioc_s_frequency(struct file *file, void *priv, +- struct v4l2_frequency *f) +-{ +- struct gemtek *gt = video_drvdata(file); +- +- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) +- return -EINVAL; +- gemtek_setfreq(gt, f->frequency); +- return 0; +-} +- +-static int vidioc_queryctrl(struct file *file, void *priv, +- struct v4l2_queryctrl *qc) +-{ +- switch (qc->id) { +- case V4L2_CID_AUDIO_MUTE: +- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); +- default: +- return -EINVAL; +- } +-} +- +-static int vidioc_g_ctrl(struct file *file, void *priv, +- struct v4l2_control *ctrl) +-{ +- struct gemtek *gt = video_drvdata(file); +- +- switch (ctrl->id) { +- case V4L2_CID_AUDIO_MUTE: +- ctrl->value = gt->muted; +- return 0; +- } +- return -EINVAL; +-} ++static const int gemtek_ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c }; + +-static int vidioc_s_ctrl(struct file *file, void *priv, +- struct v4l2_control *ctrl) +-{ +- struct gemtek *gt = video_drvdata(file); +- +- switch (ctrl->id) { +- case V4L2_CID_AUDIO_MUTE: +- if (ctrl->value) +- gemtek_mute(gt); +- else +- gemtek_unmute(gt); +- return 0; +- } +- return -EINVAL; +-} +- +-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +-{ +- *i = 0; +- return 0; +-} +- +-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +-{ +- return (i != 0) ? -EINVAL : 0; +-} +- +-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +-{ +- a->index = 0; +- strlcpy(a->name, "Radio", sizeof(a->name)); +- a->capability = V4L2_AUDCAP_STEREO; +- return 0; +-} +- +-static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) +-{ +- return (a->index != 0) ? -EINVAL : 0; +-} +- +-static const struct v4l2_ioctl_ops gemtek_ioctl_ops = { +- .vidioc_querycap = vidioc_querycap, +- .vidioc_g_tuner = vidioc_g_tuner, +- .vidioc_s_tuner = vidioc_s_tuner, +- .vidioc_g_audio = vidioc_g_audio, +- .vidioc_s_audio = vidioc_s_audio, +- .vidioc_g_input = vidioc_g_input, +- .vidioc_s_input = vidioc_s_input, +- .vidioc_g_frequency = vidioc_g_frequency, +- .vidioc_s_frequency = vidioc_s_frequency, +- .vidioc_queryctrl = vidioc_queryctrl, +- .vidioc_g_ctrl = vidioc_g_ctrl, +- .vidioc_s_ctrl = vidioc_s_ctrl ++static struct radio_isa_driver gemtek_driver = { ++ .driver = { ++ .match = radio_isa_match, ++ .probe = radio_isa_probe, ++ .remove = radio_isa_remove, ++ .driver = { ++ .name = "radio-gemtek", ++ }, ++ }, ++ .io_params = io, ++ .radio_nr_params = radio_nr, ++ .io_ports = gemtek_ioports, ++ .num_of_io_ports = ARRAY_SIZE(gemtek_ioports), ++ .region_size = 1, ++ .card = "GemTek Radio", ++ .ops = &gemtek_ops, ++ .has_stereo = true, + }; + +-/* +- * Initialization / cleanup related stuff. +- */ +- + static int __init gemtek_init(void) + { +- struct gemtek *gt = &gemtek_card; +- struct v4l2_device *v4l2_dev = >->v4l2_dev; +- int res; +- +- strlcpy(v4l2_dev->name, "gemtek", sizeof(v4l2_dev->name)); +- +- v4l2_info(v4l2_dev, "GemTek Radio card driver: v0.0.3\n"); +- +- mutex_init(>->lock); +- +- gt->verified = -1; +- gt->io = io; +- gemtek_probe(gt); +- if (gt->io) { +- if (!request_region(gt->io, 1, "gemtek")) { +- v4l2_err(v4l2_dev, "I/O port 0x%x already in use.\n", gt->io); +- return -EBUSY; +- } +- +- if (!gemtek_verify(gt, gt->io)) +- v4l2_warn(v4l2_dev, "Card at I/O port 0x%x does not " +- "respond properly, check your " +- "configuration.\n", gt->io); +- else +- v4l2_info(v4l2_dev, "Using I/O port 0x%x.\n", gt->io); +- } else if (probe) { +- v4l2_err(v4l2_dev, "Automatic probing failed and no " +- "fixed I/O port defined.\n"); +- return -ENODEV; +- } else { +- v4l2_err(v4l2_dev, "Automatic probing disabled but no fixed " +- "I/O port defined."); +- return -EINVAL; +- } +- +- res = v4l2_device_register(NULL, v4l2_dev); +- if (res < 0) { +- v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); +- release_region(gt->io, 1); +- return res; +- } +- +- strlcpy(gt->vdev.name, v4l2_dev->name, sizeof(gt->vdev.name)); +- gt->vdev.v4l2_dev = v4l2_dev; +- gt->vdev.fops = &gemtek_fops; +- gt->vdev.ioctl_ops = &gemtek_ioctl_ops; +- gt->vdev.release = video_device_release_empty; +- video_set_drvdata(>->vdev, gt); +- +- /* Set defaults */ +- gt->lastfreq = GEMTEK_LOWFREQ; +- gt->bu2614data = 0; +- +- if (initmute) +- gemtek_mute(gt); +- +- if (video_register_device(>->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { +- v4l2_device_unregister(v4l2_dev); +- release_region(gt->io, 1); +- return -EBUSY; +- } +- +- return 0; ++ gemtek_driver.probe = probe; ++ return isa_register_driver(&gemtek_driver.driver, GEMTEK_MAX); + } + +-/* +- * Module cleanup +- */ + static void __exit gemtek_exit(void) + { +- struct gemtek *gt = &gemtek_card; +- struct v4l2_device *v4l2_dev = >->v4l2_dev; +- +- if (shutdown) { +- hardmute = 1; /* Turn off PLL */ +- gemtek_mute(gt); +- } else { +- v4l2_info(v4l2_dev, "Module unloaded but card not muted!\n"); +- } +- +- video_unregister_device(>->vdev); +- v4l2_device_unregister(>->v4l2_dev); +- release_region(gt->io, 1); ++ hardmute = 1; /* Turn off PLL */ ++ isa_unregister_driver(&gemtek_driver.driver); + } + + module_init(gemtek_init); +Index: linux-3.3.x86_64/drivers/media/radio/radio-rtrack2.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/radio/radio-rtrack2.c ++++ linux-3.3.x86_64/drivers/media/radio/radio-rtrack2.c +@@ -1,11 +1,12 @@ +-/* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff ++/* ++ * RadioTrack II driver ++ * Copyright 1998 Ben Pfaff + * + * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood + * Converted to new API by Alan Cox + * Various bugfixes and enhancements by Russell Kroll + * +- * TODO: Allow for more than one of these foolish entities :-) +- * ++ * Converted to the radio-isa framework by Hans Verkuil + * Converted to V4L2 API by Mauro Carvalho Chehab + */ + +@@ -16,325 +17,123 @@ + #include /* kernel radio structs */ + #include + #include /* outb, outb_p */ ++#include + #include + #include ++#include "radio-isa.h" + + MODULE_AUTHOR("Ben Pfaff"); + MODULE_DESCRIPTION("A driver for the RadioTrack II radio card."); + MODULE_LICENSE("GPL"); +-MODULE_VERSION("0.0.3"); ++MODULE_VERSION("0.1.99"); + + #ifndef CONFIG_RADIO_RTRACK2_PORT + #define CONFIG_RADIO_RTRACK2_PORT -1 + #endif + +-static int io = CONFIG_RADIO_RTRACK2_PORT; +-static int radio_nr = -1; +- +-module_param(io, int, 0); +-MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)"); +-module_param(radio_nr, int, 0); +- +-struct rtrack2 +-{ +- struct v4l2_device v4l2_dev; +- struct video_device vdev; +- int io; +- unsigned long curfreq; +- int muted; +- struct mutex lock; +-}; +- +-static struct rtrack2 rtrack2_card; ++#define RTRACK2_MAX 2 + ++static int io[RTRACK2_MAX] = { [0] = CONFIG_RADIO_RTRACK2_PORT, ++ [1 ... (RTRACK2_MAX - 1)] = -1 }; ++static int radio_nr[RTRACK2_MAX] = { [0 ... (RTRACK2_MAX - 1)] = -1 }; + +-/* local things */ +- +-static void rt_mute(struct rtrack2 *dev) +-{ +- if (dev->muted) +- return; +- mutex_lock(&dev->lock); +- outb(1, dev->io); +- mutex_unlock(&dev->lock); +- dev->muted = 1; +-} ++module_param_array(io, int, NULL, 0444); ++MODULE_PARM_DESC(io, "I/O addresses of the RadioTrack card (0x20f or 0x30f)"); ++module_param_array(radio_nr, int, NULL, 0444); ++MODULE_PARM_DESC(radio_nr, "Radio device numbers"); + +-static void rt_unmute(struct rtrack2 *dev) ++static struct radio_isa_card *rtrack2_alloc(void) + { +- if(dev->muted == 0) +- return; +- mutex_lock(&dev->lock); +- outb(0, dev->io); +- mutex_unlock(&dev->lock); +- dev->muted = 0; ++ return kzalloc(sizeof(struct radio_isa_card), GFP_KERNEL); + } + +-static void zero(struct rtrack2 *dev) ++static void zero(struct radio_isa_card *isa) + { +- outb_p(1, dev->io); +- outb_p(3, dev->io); +- outb_p(1, dev->io); ++ outb_p(1, isa->io); ++ outb_p(3, isa->io); ++ outb_p(1, isa->io); + } + +-static void one(struct rtrack2 *dev) ++static void one(struct radio_isa_card *isa) + { +- outb_p(5, dev->io); +- outb_p(7, dev->io); +- outb_p(5, dev->io); ++ outb_p(5, isa->io); ++ outb_p(7, isa->io); ++ outb_p(5, isa->io); + } + +-static int rt_setfreq(struct rtrack2 *dev, unsigned long freq) ++static int rtrack2_s_frequency(struct radio_isa_card *isa, u32 freq) + { + int i; + +- mutex_lock(&dev->lock); +- dev->curfreq = freq; + freq = freq / 200 + 856; + +- outb_p(0xc8, dev->io); +- outb_p(0xc9, dev->io); +- outb_p(0xc9, dev->io); ++ outb_p(0xc8, isa->io); ++ outb_p(0xc9, isa->io); ++ outb_p(0xc9, isa->io); + + for (i = 0; i < 10; i++) +- zero(dev); ++ zero(isa); + + for (i = 14; i >= 0; i--) + if (freq & (1 << i)) +- one(dev); ++ one(isa); + else +- zero(dev); +- +- outb_p(0xc8, dev->io); +- if (!dev->muted) +- outb_p(0, dev->io); +- +- mutex_unlock(&dev->lock); +- return 0; +-} +- +-static int vidioc_querycap(struct file *file, void *priv, +- struct v4l2_capability *v) +-{ +- strlcpy(v->driver, "radio-rtrack2", sizeof(v->driver)); +- strlcpy(v->card, "RadioTrack II", sizeof(v->card)); +- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); +- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; +- return 0; +-} +- +-static int vidioc_s_tuner(struct file *file, void *priv, +- struct v4l2_tuner *v) +-{ +- return v->index ? -EINVAL : 0; +-} +- +-static int rt_getsigstr(struct rtrack2 *dev) +-{ +- int sig = 1; +- +- mutex_lock(&dev->lock); +- if (inb(dev->io) & 2) /* bit set = no signal present */ +- sig = 0; +- mutex_unlock(&dev->lock); +- return sig; +-} ++ zero(isa); + +-static int vidioc_g_tuner(struct file *file, void *priv, +- struct v4l2_tuner *v) +-{ +- struct rtrack2 *rt = video_drvdata(file); +- +- if (v->index > 0) +- return -EINVAL; +- +- strlcpy(v->name, "FM", sizeof(v->name)); +- v->type = V4L2_TUNER_RADIO; +- v->rangelow = 88 * 16000; +- v->rangehigh = 108 * 16000; +- v->rxsubchans = V4L2_TUNER_SUB_MONO; +- v->capability = V4L2_TUNER_CAP_LOW; +- v->audmode = V4L2_TUNER_MODE_MONO; +- v->signal = 0xFFFF * rt_getsigstr(rt); ++ outb_p(0xc8, isa->io); ++ if (!v4l2_ctrl_g_ctrl(isa->mute)) ++ outb_p(0, isa->io); + return 0; + } + +-static int vidioc_s_frequency(struct file *file, void *priv, +- struct v4l2_frequency *f) ++static u32 rtrack2_g_signal(struct radio_isa_card *isa) + { +- struct rtrack2 *rt = video_drvdata(file); +- +- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) +- return -EINVAL; +- rt_setfreq(rt, f->frequency); +- return 0; ++ /* bit set = no signal present */ ++ return (inb(isa->io) & 2) ? 0 : 0xffff; + } + +-static int vidioc_g_frequency(struct file *file, void *priv, +- struct v4l2_frequency *f) ++static int rtrack2_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) + { +- struct rtrack2 *rt = video_drvdata(file); +- +- if (f->tuner != 0) +- return -EINVAL; +- f->type = V4L2_TUNER_RADIO; +- f->frequency = rt->curfreq; ++ outb(mute, isa->io); + return 0; + } + +-static int vidioc_queryctrl(struct file *file, void *priv, +- struct v4l2_queryctrl *qc) +-{ +- switch (qc->id) { +- case V4L2_CID_AUDIO_MUTE: +- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); +- case V4L2_CID_AUDIO_VOLUME: +- return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535); +- } +- return -EINVAL; +-} +- +-static int vidioc_g_ctrl(struct file *file, void *priv, +- struct v4l2_control *ctrl) +-{ +- struct rtrack2 *rt = video_drvdata(file); +- +- switch (ctrl->id) { +- case V4L2_CID_AUDIO_MUTE: +- ctrl->value = rt->muted; +- return 0; +- case V4L2_CID_AUDIO_VOLUME: +- if (rt->muted) +- ctrl->value = 0; +- else +- ctrl->value = 65535; +- return 0; +- } +- return -EINVAL; +-} +- +-static int vidioc_s_ctrl(struct file *file, void *priv, +- struct v4l2_control *ctrl) +-{ +- struct rtrack2 *rt = video_drvdata(file); +- +- switch (ctrl->id) { +- case V4L2_CID_AUDIO_MUTE: +- if (ctrl->value) +- rt_mute(rt); +- else +- rt_unmute(rt); +- return 0; +- case V4L2_CID_AUDIO_VOLUME: +- if (ctrl->value) +- rt_unmute(rt); +- else +- rt_mute(rt); +- return 0; +- } +- return -EINVAL; +-} +- +-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +-{ +- *i = 0; +- return 0; +-} +- +-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +-{ +- return i ? -EINVAL : 0; +-} +- +-static int vidioc_g_audio(struct file *file, void *priv, +- struct v4l2_audio *a) +-{ +- a->index = 0; +- strlcpy(a->name, "Radio", sizeof(a->name)); +- a->capability = V4L2_AUDCAP_STEREO; +- return 0; +-} +- +-static int vidioc_s_audio(struct file *file, void *priv, +- struct v4l2_audio *a) +-{ +- return a->index ? -EINVAL : 0; +-} +- +-static const struct v4l2_file_operations rtrack2_fops = { +- .owner = THIS_MODULE, +- .unlocked_ioctl = video_ioctl2, ++static const struct radio_isa_ops rtrack2_ops = { ++ .alloc = rtrack2_alloc, ++ .s_mute_volume = rtrack2_s_mute_volume, ++ .s_frequency = rtrack2_s_frequency, ++ .g_signal = rtrack2_g_signal, + }; + +-static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = { +- .vidioc_querycap = vidioc_querycap, +- .vidioc_g_tuner = vidioc_g_tuner, +- .vidioc_s_tuner = vidioc_s_tuner, +- .vidioc_g_frequency = vidioc_g_frequency, +- .vidioc_s_frequency = vidioc_s_frequency, +- .vidioc_queryctrl = vidioc_queryctrl, +- .vidioc_g_ctrl = vidioc_g_ctrl, +- .vidioc_s_ctrl = vidioc_s_ctrl, +- .vidioc_g_audio = vidioc_g_audio, +- .vidioc_s_audio = vidioc_s_audio, +- .vidioc_g_input = vidioc_g_input, +- .vidioc_s_input = vidioc_s_input, ++static const int rtrack2_ioports[] = { 0x20f, 0x30f }; ++ ++static struct radio_isa_driver rtrack2_driver = { ++ .driver = { ++ .match = radio_isa_match, ++ .probe = radio_isa_probe, ++ .remove = radio_isa_remove, ++ .driver = { ++ .name = "radio-rtrack2", ++ }, ++ }, ++ .io_params = io, ++ .radio_nr_params = radio_nr, ++ .io_ports = rtrack2_ioports, ++ .num_of_io_ports = ARRAY_SIZE(rtrack2_ioports), ++ .region_size = 4, ++ .card = "AIMSlab RadioTrack II", ++ .ops = &rtrack2_ops, ++ .has_stereo = true, + }; + + static int __init rtrack2_init(void) + { +- struct rtrack2 *dev = &rtrack2_card; +- struct v4l2_device *v4l2_dev = &dev->v4l2_dev; +- int res; +- +- strlcpy(v4l2_dev->name, "rtrack2", sizeof(v4l2_dev->name)); +- dev->io = io; +- if (dev->io == -1) { +- v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or io=0x30c\n"); +- return -EINVAL; +- } +- if (!request_region(dev->io, 4, "rtrack2")) { +- v4l2_err(v4l2_dev, "port 0x%x already in use\n", dev->io); +- return -EBUSY; +- } +- +- res = v4l2_device_register(NULL, v4l2_dev); +- if (res < 0) { +- release_region(dev->io, 4); +- v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); +- return res; +- } +- +- strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); +- dev->vdev.v4l2_dev = v4l2_dev; +- dev->vdev.fops = &rtrack2_fops; +- dev->vdev.ioctl_ops = &rtrack2_ioctl_ops; +- dev->vdev.release = video_device_release_empty; +- video_set_drvdata(&dev->vdev, dev); +- +- /* mute card - prevents noisy bootups */ +- outb(1, dev->io); +- dev->muted = 1; +- +- mutex_init(&dev->lock); +- if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { +- v4l2_device_unregister(v4l2_dev); +- release_region(dev->io, 4); +- return -EINVAL; +- } +- +- v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n"); +- +- return 0; ++ return isa_register_driver(&rtrack2_driver.driver, RTRACK2_MAX); + } + + static void __exit rtrack2_exit(void) + { +- struct rtrack2 *dev = &rtrack2_card; +- +- video_unregister_device(&dev->vdev); +- v4l2_device_unregister(&dev->v4l2_dev); +- release_region(dev->io, 4); ++ isa_unregister_driver(&rtrack2_driver.driver); + } + + module_init(rtrack2_init); +Index: linux-3.3.x86_64/drivers/media/radio/radio-terratec.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/radio/radio-terratec.c ++++ linux-3.3.x86_64/drivers/media/radio/radio-terratec.c +@@ -16,11 +16,7 @@ + * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); + * Volume Control is done digitally + * +- * there is a I2C controlled RDS decoder (SAA6588) onboard, which i would like to support someday +- * (as soon i have understand how to get started :) +- * If you can help me out with that, please contact me!! +- * +- * ++ * Converted to the radio-isa framework by Hans Verkuil + * Converted to V4L2 API by Mauro Carvalho Chehab + */ + +@@ -30,43 +26,24 @@ + #include /* kernel radio structs */ + #include + #include /* outb, outb_p */ ++#include + #include + #include ++#include "radio-isa.h" + +-MODULE_AUTHOR("R.OFFERMANNS & others"); ++MODULE_AUTHOR("R. Offermans & others"); + MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card."); + MODULE_LICENSE("GPL"); +-MODULE_VERSION("0.0.3"); +- +-#ifndef CONFIG_RADIO_TERRATEC_PORT +-#define CONFIG_RADIO_TERRATEC_PORT 0x590 +-#endif ++MODULE_VERSION("0.1.99"); + +-static int io = CONFIG_RADIO_TERRATEC_PORT; ++/* Note: there seems to be only one possible port (0x590), but without ++ hardware this is hard to verify. For now, this is the only one we will ++ support. */ ++static int io = 0x590; + static int radio_nr = -1; + +-module_param(io, int, 0); +-MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)"); +-module_param(radio_nr, int, 0); +- +-static struct v4l2_queryctrl radio_qctrl[] = { +- { +- .id = V4L2_CID_AUDIO_MUTE, +- .name = "Mute", +- .minimum = 0, +- .maximum = 1, +- .default_value = 1, +- .type = V4L2_CTRL_TYPE_BOOLEAN, +- },{ +- .id = V4L2_CID_AUDIO_VOLUME, +- .name = "Volume", +- .minimum = 0, +- .maximum = 0xff, +- .step = 1, +- .default_value = 0xff, +- .type = V4L2_CTRL_TYPE_INTEGER, +- } +-}; ++module_param(radio_nr, int, 0444); ++MODULE_PARM_DESC(radio_nr, "Radio device number"); + + #define WRT_DIS 0x00 + #define CLK_OFF 0x00 +@@ -76,63 +53,24 @@ static struct v4l2_queryctrl radio_qctrl + #define CLK_ON 0x08 + #define WRT_EN 0x10 + +-struct terratec ++static struct radio_isa_card *terratec_alloc(void) + { +- struct v4l2_device v4l2_dev; +- struct video_device vdev; +- int io; +- int curvol; +- unsigned long curfreq; +- int muted; +- struct mutex lock; +-}; +- +-static struct terratec terratec_card; +- +-/* local things */ ++ return kzalloc(sizeof(struct radio_isa_card), GFP_KERNEL); ++} + +-static void tt_write_vol(struct terratec *tt, int volume) ++static int terratec_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) + { + int i; + +- volume = volume + (volume * 32); /* change both channels */ +- mutex_lock(&tt->lock); ++ if (mute) ++ vol = 0; ++ vol = vol + (vol * 32); /* change both channels */ + for (i = 0; i < 8; i++) { +- if (volume & (0x80 >> i)) +- outb(0x80, tt->io + 1); ++ if (vol & (0x80 >> i)) ++ outb(0x80, isa->io + 1); + else +- outb(0x00, tt->io + 1); ++ outb(0x00, isa->io + 1); + } +- mutex_unlock(&tt->lock); +-} +- +- +- +-static void tt_mute(struct terratec *tt) +-{ +- tt->muted = 1; +- tt_write_vol(tt, 0); +-} +- +-static int tt_setvol(struct terratec *tt, int vol) +-{ +- if (vol == tt->curvol) { /* requested volume = current */ +- if (tt->muted) { /* user is unmuting the card */ +- tt->muted = 0; +- tt_write_vol(tt, vol); /* enable card */ +- } +- return 0; +- } +- +- if (vol == 0) { /* volume = 0 means mute the card */ +- tt_write_vol(tt, 0); /* "turn off card" by setting vol to 0 */ +- tt->curvol = vol; /* track the volume state! */ +- return 0; +- } +- +- tt->muted = 0; +- tt_write_vol(tt, vol); +- tt->curvol = vol; + return 0; + } + +@@ -140,20 +78,15 @@ static int tt_setvol(struct terratec *tt + /* this is the worst part in this driver */ + /* many more or less strange things are going on here, but hey, it works :) */ + +-static int tt_setfreq(struct terratec *tt, unsigned long freq1) ++static int terratec_s_frequency(struct radio_isa_card *isa, u32 freq) + { +- int freq; + int i; + int p; +- int temp; ++ int temp; + long rest; + unsigned char buffer[25]; /* we have to bit shift 25 registers */ + +- mutex_lock(&tt->lock); +- +- tt->curfreq = freq1; +- +- freq = freq1 / 160; /* convert the freq. to a nice to handle value */ ++ freq = freq / 160; /* convert the freq. to a nice to handle value */ + memset(buffer, 0, sizeof(buffer)); + + rest = freq * 10 + 10700; /* I once had understood what is going on here */ +@@ -175,239 +108,61 @@ static int tt_setfreq(struct terratec *t + + for (i = 24; i > -1; i--) { /* bit shift the values to the radiocard */ + if (buffer[i] == 1) { +- outb(WRT_EN | DATA, tt->io); +- outb(WRT_EN | DATA | CLK_ON, tt->io); +- outb(WRT_EN | DATA, tt->io); ++ outb(WRT_EN | DATA, isa->io); ++ outb(WRT_EN | DATA | CLK_ON, isa->io); ++ outb(WRT_EN | DATA, isa->io); + } else { +- outb(WRT_EN | 0x00, tt->io); +- outb(WRT_EN | 0x00 | CLK_ON, tt->io); +- } +- } +- outb(0x00, tt->io); +- +- mutex_unlock(&tt->lock); +- +- return 0; +-} +- +-static int tt_getsigstr(struct terratec *tt) +-{ +- if (inb(tt->io) & 2) /* bit set = no signal present */ +- return 0; +- return 1; /* signal present */ +-} +- +-static int vidioc_querycap(struct file *file, void *priv, +- struct v4l2_capability *v) +-{ +- strlcpy(v->driver, "radio-terratec", sizeof(v->driver)); +- strlcpy(v->card, "ActiveRadio", sizeof(v->card)); +- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); +- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; +- return 0; +-} +- +-static int vidioc_g_tuner(struct file *file, void *priv, +- struct v4l2_tuner *v) +-{ +- struct terratec *tt = video_drvdata(file); +- +- if (v->index > 0) +- return -EINVAL; +- +- strlcpy(v->name, "FM", sizeof(v->name)); +- v->type = V4L2_TUNER_RADIO; +- v->rangelow = 87 * 16000; +- v->rangehigh = 108 * 16000; +- v->rxsubchans = V4L2_TUNER_SUB_MONO; +- v->capability = V4L2_TUNER_CAP_LOW; +- v->audmode = V4L2_TUNER_MODE_MONO; +- v->signal = 0xFFFF * tt_getsigstr(tt); +- return 0; +-} +- +-static int vidioc_s_tuner(struct file *file, void *priv, +- struct v4l2_tuner *v) +-{ +- return v->index ? -EINVAL : 0; +-} +- +-static int vidioc_s_frequency(struct file *file, void *priv, +- struct v4l2_frequency *f) +-{ +- struct terratec *tt = video_drvdata(file); +- +- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) +- return -EINVAL; +- tt_setfreq(tt, f->frequency); +- return 0; +-} +- +-static int vidioc_g_frequency(struct file *file, void *priv, +- struct v4l2_frequency *f) +-{ +- struct terratec *tt = video_drvdata(file); +- +- if (f->tuner != 0) +- return -EINVAL; +- f->type = V4L2_TUNER_RADIO; +- f->frequency = tt->curfreq; +- return 0; +-} +- +-static int vidioc_queryctrl(struct file *file, void *priv, +- struct v4l2_queryctrl *qc) +-{ +- int i; +- +- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { +- if (qc->id && qc->id == radio_qctrl[i].id) { +- memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); +- return 0; ++ outb(WRT_EN | 0x00, isa->io); ++ outb(WRT_EN | 0x00 | CLK_ON, isa->io); + } + } +- return -EINVAL; +-} +- +-static int vidioc_g_ctrl(struct file *file, void *priv, +- struct v4l2_control *ctrl) +-{ +- struct terratec *tt = video_drvdata(file); +- +- switch (ctrl->id) { +- case V4L2_CID_AUDIO_MUTE: +- if (tt->muted) +- ctrl->value = 1; +- else +- ctrl->value = 0; +- return 0; +- case V4L2_CID_AUDIO_VOLUME: +- ctrl->value = tt->curvol * 6554; +- return 0; +- } +- return -EINVAL; +-} +- +-static int vidioc_s_ctrl(struct file *file, void *priv, +- struct v4l2_control *ctrl) +-{ +- struct terratec *tt = video_drvdata(file); +- +- switch (ctrl->id) { +- case V4L2_CID_AUDIO_MUTE: +- if (ctrl->value) +- tt_mute(tt); +- else +- tt_setvol(tt,tt->curvol); +- return 0; +- case V4L2_CID_AUDIO_VOLUME: +- tt_setvol(tt,ctrl->value); +- return 0; +- } +- return -EINVAL; +-} +- +-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +-{ +- *i = 0; ++ outb(0x00, isa->io); + return 0; + } + +-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) ++static u32 terratec_g_signal(struct radio_isa_card *isa) + { +- return i ? -EINVAL : 0; ++ /* bit set = no signal present */ ++ return (inb(isa->io) & 2) ? 0 : 0xffff; + } + +-static int vidioc_g_audio(struct file *file, void *priv, +- struct v4l2_audio *a) +-{ +- a->index = 0; +- strlcpy(a->name, "Radio", sizeof(a->name)); +- a->capability = V4L2_AUDCAP_STEREO; +- return 0; +-} +- +-static int vidioc_s_audio(struct file *file, void *priv, +- struct v4l2_audio *a) +-{ +- return a->index ? -EINVAL : 0; +-} +- +-static const struct v4l2_file_operations terratec_fops = { +- .owner = THIS_MODULE, +- .unlocked_ioctl = video_ioctl2, ++static const struct radio_isa_ops terratec_ops = { ++ .alloc = terratec_alloc, ++ .s_mute_volume = terratec_s_mute_volume, ++ .s_frequency = terratec_s_frequency, ++ .g_signal = terratec_g_signal, + }; + +-static const struct v4l2_ioctl_ops terratec_ioctl_ops = { +- .vidioc_querycap = vidioc_querycap, +- .vidioc_g_tuner = vidioc_g_tuner, +- .vidioc_s_tuner = vidioc_s_tuner, +- .vidioc_g_frequency = vidioc_g_frequency, +- .vidioc_s_frequency = vidioc_s_frequency, +- .vidioc_queryctrl = vidioc_queryctrl, +- .vidioc_g_ctrl = vidioc_g_ctrl, +- .vidioc_s_ctrl = vidioc_s_ctrl, +- .vidioc_g_audio = vidioc_g_audio, +- .vidioc_s_audio = vidioc_s_audio, +- .vidioc_g_input = vidioc_g_input, +- .vidioc_s_input = vidioc_s_input, ++static const int terratec_ioports[] = { 0x590 }; ++ ++static struct radio_isa_driver terratec_driver = { ++ .driver = { ++ .match = radio_isa_match, ++ .probe = radio_isa_probe, ++ .remove = radio_isa_remove, ++ .driver = { ++ .name = "radio-terratec", ++ }, ++ }, ++ .io_params = &io, ++ .radio_nr_params = &radio_nr, ++ .io_ports = terratec_ioports, ++ .num_of_io_ports = ARRAY_SIZE(terratec_ioports), ++ .region_size = 2, ++ .card = "TerraTec ActiveRadio", ++ .ops = &terratec_ops, ++ .has_stereo = true, ++ .max_volume = 10, + }; + + static int __init terratec_init(void) + { +- struct terratec *tt = &terratec_card; +- struct v4l2_device *v4l2_dev = &tt->v4l2_dev; +- int res; +- +- strlcpy(v4l2_dev->name, "terratec", sizeof(v4l2_dev->name)); +- tt->io = io; +- if (tt->io == -1) { +- v4l2_err(v4l2_dev, "you must set an I/O address with io=0x590 or 0x591\n"); +- return -EINVAL; +- } +- if (!request_region(tt->io, 2, "terratec")) { +- v4l2_err(v4l2_dev, "port 0x%x already in use\n", io); +- return -EBUSY; +- } +- +- res = v4l2_device_register(NULL, v4l2_dev); +- if (res < 0) { +- release_region(tt->io, 2); +- v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); +- return res; +- } +- +- strlcpy(tt->vdev.name, v4l2_dev->name, sizeof(tt->vdev.name)); +- tt->vdev.v4l2_dev = v4l2_dev; +- tt->vdev.fops = &terratec_fops; +- tt->vdev.ioctl_ops = &terratec_ioctl_ops; +- tt->vdev.release = video_device_release_empty; +- video_set_drvdata(&tt->vdev, tt); +- +- mutex_init(&tt->lock); +- +- /* mute card - prevents noisy bootups */ +- tt_write_vol(tt, 0); +- +- if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { +- v4l2_device_unregister(&tt->v4l2_dev); +- release_region(tt->io, 2); +- return -EINVAL; +- } +- +- v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n"); +- return 0; ++ return isa_register_driver(&terratec_driver.driver, 1); + } + + static void __exit terratec_exit(void) + { +- struct terratec *tt = &terratec_card; +- struct v4l2_device *v4l2_dev = &tt->v4l2_dev; +- +- video_unregister_device(&tt->vdev); +- v4l2_device_unregister(&tt->v4l2_dev); +- release_region(tt->io, 2); +- v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver unloaded.\n"); ++ isa_unregister_driver(&terratec_driver.driver); + } + + module_init(terratec_init); +Index: linux-3.3.x86_64/drivers/media/radio/radio-trust.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/radio/radio-trust.c ++++ linux-3.3.x86_64/drivers/media/radio/radio-trust.c +@@ -21,13 +21,15 @@ + #include + #include + #include ++#include + #include + #include ++#include "radio-isa.h" + + MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); + MODULE_DESCRIPTION("A driver for the Trust FM Radio card."); + MODULE_LICENSE("GPL"); +-MODULE_VERSION("0.0.3"); ++MODULE_VERSION("0.1.99"); + + /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ + +@@ -35,39 +37,38 @@ MODULE_VERSION("0.0.3"); + #define CONFIG_RADIO_TRUST_PORT -1 + #endif + +-static int io = CONFIG_RADIO_TRUST_PORT; +-static int radio_nr = -1; ++#define TRUST_MAX 2 + +-module_param(io, int, 0); +-MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)"); +-module_param(radio_nr, int, 0); ++static int io[TRUST_MAX] = { [0] = CONFIG_RADIO_TRUST_PORT, ++ [1 ... (TRUST_MAX - 1)] = -1 }; ++static int radio_nr[TRUST_MAX] = { [0 ... (TRUST_MAX - 1)] = -1 }; ++ ++module_param_array(io, int, NULL, 0444); ++MODULE_PARM_DESC(io, "I/O addresses of the Trust FM Radio card (0x350 or 0x358)"); ++module_param_array(radio_nr, int, NULL, 0444); ++MODULE_PARM_DESC(radio_nr, "Radio device numbers"); + + struct trust { +- struct v4l2_device v4l2_dev; +- struct video_device vdev; +- int io; ++ struct radio_isa_card isa; + int ioval; +- __u16 curvol; +- __u16 curbass; +- __u16 curtreble; +- int muted; +- unsigned long curfreq; +- int curstereo; +- int curmute; +- struct mutex lock; + }; + +-static struct trust trust_card; ++static struct radio_isa_card *trust_alloc(void) ++{ ++ struct trust *tr = kzalloc(sizeof(*tr), GFP_KERNEL); ++ ++ return tr ? &tr->isa : NULL; ++} + + /* i2c addresses */ + #define TDA7318_ADDR 0x88 + #define TSA6060T_ADDR 0xc4 + +-#define TR_DELAY do { inb(tr->io); inb(tr->io); inb(tr->io); } while (0) +-#define TR_SET_SCL outb(tr->ioval |= 2, tr->io) +-#define TR_CLR_SCL outb(tr->ioval &= 0xfd, tr->io) +-#define TR_SET_SDA outb(tr->ioval |= 1, tr->io) +-#define TR_CLR_SDA outb(tr->ioval &= 0xfe, tr->io) ++#define TR_DELAY do { inb(tr->isa.io); inb(tr->isa.io); inb(tr->isa.io); } while (0) ++#define TR_SET_SCL outb(tr->ioval |= 2, tr->isa.io) ++#define TR_CLR_SCL outb(tr->ioval &= 0xfd, tr->isa.io) ++#define TR_SET_SDA outb(tr->ioval |= 1, tr->isa.io) ++#define TR_CLR_SDA outb(tr->ioval &= 0xfe, tr->isa.io) + + static void write_i2c(struct trust *tr, int n, ...) + { +@@ -84,10 +85,10 @@ static void write_i2c(struct trust *tr, + TR_CLR_SCL; + TR_DELAY; + +- for(; n; n--) { ++ for (; n; n--) { + val = va_arg(args, unsigned); +- for(mask = 0x80; mask; mask >>= 1) { +- if(val & mask) ++ for (mask = 0x80; mask; mask >>= 1) { ++ if (val & mask) + TR_SET_SDA; + else + TR_CLR_SDA; +@@ -115,317 +116,128 @@ static void write_i2c(struct trust *tr, + va_end(args); + } + +-static void tr_setvol(struct trust *tr, __u16 vol) ++static int trust_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) + { +- mutex_lock(&tr->lock); +- tr->curvol = vol / 2048; +- write_i2c(tr, 2, TDA7318_ADDR, tr->curvol ^ 0x1f); +- mutex_unlock(&tr->lock); +-} ++ struct trust *tr = container_of(isa, struct trust, isa); + +-static int basstreble2chip[15] = { +- 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8 +-}; +- +-static void tr_setbass(struct trust *tr, __u16 bass) +-{ +- mutex_lock(&tr->lock); +- tr->curbass = bass / 4370; +- write_i2c(tr, 2, TDA7318_ADDR, 0x60 | basstreble2chip[tr->curbass]); +- mutex_unlock(&tr->lock); ++ tr->ioval = (tr->ioval & 0xf7) | (mute << 3); ++ outb(tr->ioval, isa->io); ++ write_i2c(tr, 2, TDA7318_ADDR, vol ^ 0x1f); ++ return 0; + } + +-static void tr_settreble(struct trust *tr, __u16 treble) ++static int trust_s_stereo(struct radio_isa_card *isa, bool stereo) + { +- mutex_lock(&tr->lock); +- tr->curtreble = treble / 4370; +- write_i2c(tr, 2, TDA7318_ADDR, 0x70 | basstreble2chip[tr->curtreble]); +- mutex_unlock(&tr->lock); +-} ++ struct trust *tr = container_of(isa, struct trust, isa); + +-static void tr_setstereo(struct trust *tr, int stereo) +-{ +- mutex_lock(&tr->lock); +- tr->curstereo = !!stereo; +- tr->ioval = (tr->ioval & 0xfb) | (!tr->curstereo << 2); +- outb(tr->ioval, tr->io); +- mutex_unlock(&tr->lock); +-} +- +-static void tr_setmute(struct trust *tr, int mute) +-{ +- mutex_lock(&tr->lock); +- tr->curmute = !!mute; +- tr->ioval = (tr->ioval & 0xf7) | (tr->curmute << 3); +- outb(tr->ioval, tr->io); +- mutex_unlock(&tr->lock); ++ tr->ioval = (tr->ioval & 0xfb) | (!stereo << 2); ++ outb(tr->ioval, isa->io); ++ return 0; + } + +-static int tr_getsigstr(struct trust *tr) ++static u32 trust_g_signal(struct radio_isa_card *isa) + { + int i, v; + +- mutex_lock(&tr->lock); + for (i = 0, v = 0; i < 100; i++) +- v |= inb(tr->io); +- mutex_unlock(&tr->lock); ++ v |= inb(isa->io); + return (v & 1) ? 0 : 0xffff; + } + +-static int tr_getstereo(struct trust *tr) +-{ +- /* don't know how to determine it, just return the setting */ +- return tr->curstereo; +-} +- +-static void tr_setfreq(struct trust *tr, unsigned long f) +-{ +- mutex_lock(&tr->lock); +- tr->curfreq = f; +- f /= 160; /* Convert to 10 kHz units */ +- f += 1070; /* Add 10.7 MHz IF */ +- write_i2c(tr, 5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0); +- mutex_unlock(&tr->lock); +-} +- +-static int vidioc_querycap(struct file *file, void *priv, +- struct v4l2_capability *v) +-{ +- strlcpy(v->driver, "radio-trust", sizeof(v->driver)); +- strlcpy(v->card, "Trust FM Radio", sizeof(v->card)); +- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); +- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; +- return 0; +-} +- +-static int vidioc_g_tuner(struct file *file, void *priv, +- struct v4l2_tuner *v) +-{ +- struct trust *tr = video_drvdata(file); +- +- if (v->index > 0) +- return -EINVAL; +- +- strlcpy(v->name, "FM", sizeof(v->name)); +- v->type = V4L2_TUNER_RADIO; +- v->rangelow = 87.5 * 16000; +- v->rangehigh = 108 * 16000; +- v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; +- v->capability = V4L2_TUNER_CAP_LOW; +- if (tr_getstereo(tr)) +- v->audmode = V4L2_TUNER_MODE_STEREO; +- else +- v->audmode = V4L2_TUNER_MODE_MONO; +- v->signal = tr_getsigstr(tr); +- return 0; +-} +- +-static int vidioc_s_tuner(struct file *file, void *priv, +- struct v4l2_tuner *v) ++static int trust_s_frequency(struct radio_isa_card *isa, u32 freq) + { +- struct trust *tr = video_drvdata(file); ++ struct trust *tr = container_of(isa, struct trust, isa); + +- if (v->index) +- return -EINVAL; +- tr_setstereo(tr, v->audmode == V4L2_TUNER_MODE_STEREO); ++ freq /= 160; /* Convert to 10 kHz units */ ++ freq += 1070; /* Add 10.7 MHz IF */ ++ write_i2c(tr, 5, TSA6060T_ADDR, (freq << 1) | 1, ++ freq >> 7, 0x60 | ((freq >> 15) & 1), 0); + return 0; + } + +-static int vidioc_s_frequency(struct file *file, void *priv, +- struct v4l2_frequency *f) +-{ +- struct trust *tr = video_drvdata(file); +- +- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) +- return -EINVAL; +- tr_setfreq(tr, f->frequency); +- return 0; +-} +- +-static int vidioc_g_frequency(struct file *file, void *priv, +- struct v4l2_frequency *f) +-{ +- struct trust *tr = video_drvdata(file); +- +- if (f->tuner != 0) +- return -EINVAL; +- f->type = V4L2_TUNER_RADIO; +- f->frequency = tr->curfreq; +- return 0; +-} +- +-static int vidioc_queryctrl(struct file *file, void *priv, +- struct v4l2_queryctrl *qc) +-{ +- switch (qc->id) { +- case V4L2_CID_AUDIO_MUTE: +- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); +- case V4L2_CID_AUDIO_VOLUME: +- return v4l2_ctrl_query_fill(qc, 0, 65535, 2048, 65535); +- case V4L2_CID_AUDIO_BASS: +- case V4L2_CID_AUDIO_TREBLE: +- return v4l2_ctrl_query_fill(qc, 0, 65535, 4370, 32768); +- } +- return -EINVAL; +-} +- +-static int vidioc_g_ctrl(struct file *file, void *priv, +- struct v4l2_control *ctrl) +-{ +- struct trust *tr = video_drvdata(file); +- +- switch (ctrl->id) { +- case V4L2_CID_AUDIO_MUTE: +- ctrl->value = tr->curmute; +- return 0; +- case V4L2_CID_AUDIO_VOLUME: +- ctrl->value = tr->curvol * 2048; +- return 0; +- case V4L2_CID_AUDIO_BASS: +- ctrl->value = tr->curbass * 4370; +- return 0; +- case V4L2_CID_AUDIO_TREBLE: +- ctrl->value = tr->curtreble * 4370; +- return 0; +- } +- return -EINVAL; +-} ++static int basstreble2chip[15] = { ++ 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8 ++}; + +-static int vidioc_s_ctrl(struct file *file, void *priv, +- struct v4l2_control *ctrl) ++static int trust_s_ctrl(struct v4l2_ctrl *ctrl) + { +- struct trust *tr = video_drvdata(file); ++ struct radio_isa_card *isa = ++ container_of(ctrl->handler, struct radio_isa_card, hdl); ++ struct trust *tr = container_of(isa, struct trust, isa); + + switch (ctrl->id) { +- case V4L2_CID_AUDIO_MUTE: +- tr_setmute(tr, ctrl->value); +- return 0; +- case V4L2_CID_AUDIO_VOLUME: +- tr_setvol(tr, ctrl->value); +- return 0; + case V4L2_CID_AUDIO_BASS: +- tr_setbass(tr, ctrl->value); ++ write_i2c(tr, 2, TDA7318_ADDR, 0x60 | basstreble2chip[ctrl->val]); + return 0; + case V4L2_CID_AUDIO_TREBLE: +- tr_settreble(tr, ctrl->value); ++ write_i2c(tr, 2, TDA7318_ADDR, 0x70 | basstreble2chip[ctrl->val]); + return 0; + } + return -EINVAL; + } + +-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +-{ +- *i = 0; +- return 0; +-} +- +-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +-{ +- return i ? -EINVAL : 0; +-} +- +-static int vidioc_g_audio(struct file *file, void *priv, +- struct v4l2_audio *a) +-{ +- a->index = 0; +- strlcpy(a->name, "Radio", sizeof(a->name)); +- a->capability = V4L2_AUDCAP_STEREO; +- return 0; +-} +- +-static int vidioc_s_audio(struct file *file, void *priv, +- struct v4l2_audio *a) +-{ +- return a->index ? -EINVAL : 0; +-} +- +-static const struct v4l2_file_operations trust_fops = { +- .owner = THIS_MODULE, +- .unlocked_ioctl = video_ioctl2, +-}; +- +-static const struct v4l2_ioctl_ops trust_ioctl_ops = { +- .vidioc_querycap = vidioc_querycap, +- .vidioc_g_tuner = vidioc_g_tuner, +- .vidioc_s_tuner = vidioc_s_tuner, +- .vidioc_g_frequency = vidioc_g_frequency, +- .vidioc_s_frequency = vidioc_s_frequency, +- .vidioc_queryctrl = vidioc_queryctrl, +- .vidioc_g_ctrl = vidioc_g_ctrl, +- .vidioc_s_ctrl = vidioc_s_ctrl, +- .vidioc_g_audio = vidioc_g_audio, +- .vidioc_s_audio = vidioc_s_audio, +- .vidioc_g_input = vidioc_g_input, +- .vidioc_s_input = vidioc_s_input, ++static const struct v4l2_ctrl_ops trust_ctrl_ops = { ++ .s_ctrl = trust_s_ctrl, + }; + +-static int __init trust_init(void) ++static int trust_initialize(struct radio_isa_card *isa) + { +- struct trust *tr = &trust_card; +- struct v4l2_device *v4l2_dev = &tr->v4l2_dev; +- int res; ++ struct trust *tr = container_of(isa, struct trust, isa); + +- strlcpy(v4l2_dev->name, "trust", sizeof(v4l2_dev->name)); +- tr->io = io; + tr->ioval = 0xf; +- mutex_init(&tr->lock); +- +- if (tr->io == -1) { +- v4l2_err(v4l2_dev, "You must set an I/O address with io=0x0x350 or 0x358\n"); +- return -EINVAL; +- } +- if (!request_region(tr->io, 2, "Trust FM Radio")) { +- v4l2_err(v4l2_dev, "port 0x%x already in use\n", tr->io); +- return -EBUSY; +- } +- +- res = v4l2_device_register(NULL, v4l2_dev); +- if (res < 0) { +- release_region(tr->io, 2); +- v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); +- return res; +- } +- +- strlcpy(tr->vdev.name, v4l2_dev->name, sizeof(tr->vdev.name)); +- tr->vdev.v4l2_dev = v4l2_dev; +- tr->vdev.fops = &trust_fops; +- tr->vdev.ioctl_ops = &trust_ioctl_ops; +- tr->vdev.release = video_device_release_empty; +- video_set_drvdata(&tr->vdev, tr); +- + write_i2c(tr, 2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */ + write_i2c(tr, 2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */ + write_i2c(tr, 2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */ + write_i2c(tr, 2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */ + write_i2c(tr, 2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */ + +- tr_setvol(tr, 0xffff); +- tr_setbass(tr, 0x8000); +- tr_settreble(tr, 0x8000); +- tr_setstereo(tr, 1); +- +- /* mute card - prevents noisy bootups */ +- tr_setmute(tr, 1); +- +- if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { +- v4l2_device_unregister(v4l2_dev); +- release_region(tr->io, 2); +- return -EINVAL; +- } ++ v4l2_ctrl_new_std(&isa->hdl, &trust_ctrl_ops, ++ V4L2_CID_AUDIO_BASS, 0, 15, 1, 8); ++ v4l2_ctrl_new_std(&isa->hdl, &trust_ctrl_ops, ++ V4L2_CID_AUDIO_TREBLE, 0, 15, 1, 8); ++ return isa->hdl.error; ++} + +- v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n"); ++static const struct radio_isa_ops trust_ops = { ++ .init = trust_initialize, ++ .alloc = trust_alloc, ++ .s_mute_volume = trust_s_mute_volume, ++ .s_frequency = trust_s_frequency, ++ .s_stereo = trust_s_stereo, ++ .g_signal = trust_g_signal, ++}; + +- return 0; +-} ++static const int trust_ioports[] = { 0x350, 0x358 }; ++ ++static struct radio_isa_driver trust_driver = { ++ .driver = { ++ .match = radio_isa_match, ++ .probe = radio_isa_probe, ++ .remove = radio_isa_remove, ++ .driver = { ++ .name = "radio-trust", ++ }, ++ }, ++ .io_params = io, ++ .radio_nr_params = radio_nr, ++ .io_ports = trust_ioports, ++ .num_of_io_ports = ARRAY_SIZE(trust_ioports), ++ .region_size = 2, ++ .card = "Trust FM Radio", ++ .ops = &trust_ops, ++ .has_stereo = true, ++ .max_volume = 31, ++}; + +-static void __exit cleanup_trust_module(void) ++static int __init trust_init(void) + { +- struct trust *tr = &trust_card; ++ return isa_register_driver(&trust_driver.driver, TRUST_MAX); ++} + +- video_unregister_device(&tr->vdev); +- v4l2_device_unregister(&tr->v4l2_dev); +- release_region(tr->io, 2); ++static void __exit trust_exit(void) ++{ ++ isa_unregister_driver(&trust_driver.driver); + } + + module_init(trust_init); +-module_exit(cleanup_trust_module); ++module_exit(trust_exit); +Index: linux-3.3.x86_64/drivers/media/radio/radio-typhoon.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/radio/radio-typhoon.c ++++ linux-3.3.x86_64/drivers/media/radio/radio-typhoon.c +@@ -33,63 +33,53 @@ + #include /* request_region */ + #include /* kernel radio structs */ + #include /* outb, outb_p */ ++#include + #include + #include ++#include "radio-isa.h" + + #define DRIVER_VERSION "0.1.2" + + MODULE_AUTHOR("Dr. Henrik Seidel"); + MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio)."); + MODULE_LICENSE("GPL"); +-MODULE_VERSION(DRIVER_VERSION); ++MODULE_VERSION("0.1.99"); + + #ifndef CONFIG_RADIO_TYPHOON_PORT + #define CONFIG_RADIO_TYPHOON_PORT -1 + #endif + + #ifndef CONFIG_RADIO_TYPHOON_MUTEFREQ +-#define CONFIG_RADIO_TYPHOON_MUTEFREQ 0 ++#define CONFIG_RADIO_TYPHOON_MUTEFREQ 87000 + #endif + +-static int io = CONFIG_RADIO_TYPHOON_PORT; +-static int radio_nr = -1; +- +-module_param(io, int, 0); +-MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)"); +- +-module_param(radio_nr, int, 0); ++#define TYPHOON_MAX 2 + ++static int io[TYPHOON_MAX] = { [0] = CONFIG_RADIO_TYPHOON_PORT, ++ [1 ... (TYPHOON_MAX - 1)] = -1 }; ++static int radio_nr[TYPHOON_MAX] = { [0 ... (TYPHOON_MAX - 1)] = -1 }; + static unsigned long mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ; ++ ++module_param_array(io, int, NULL, 0444); ++MODULE_PARM_DESC(io, "I/O addresses of the Typhoon card (0x316 or 0x336)"); ++module_param_array(radio_nr, int, NULL, 0444); ++MODULE_PARM_DESC(radio_nr, "Radio device numbers"); + module_param(mutefreq, ulong, 0); + MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)"); + +-#define BANNER "Typhoon Radio Card driver v" DRIVER_VERSION "\n" +- + struct typhoon { +- struct v4l2_device v4l2_dev; +- struct video_device vdev; +- int io; +- int curvol; ++ struct radio_isa_card isa; + int muted; +- unsigned long curfreq; +- unsigned long mutefreq; +- struct mutex lock; + }; + +-static struct typhoon typhoon_card; +- +-static void typhoon_setvol_generic(struct typhoon *dev, int vol) ++static struct radio_isa_card *typhoon_alloc(void) + { +- mutex_lock(&dev->lock); +- vol >>= 14; /* Map 16 bit to 2 bit */ +- vol &= 3; +- outb_p(vol / 2, dev->io); /* Set the volume, high bit. */ +- outb_p(vol % 2, dev->io + 2); /* Set the volume, low bit. */ +- mutex_unlock(&dev->lock); ++ struct typhoon *ty = kzalloc(sizeof(*ty), GFP_KERNEL); ++ ++ return ty ? &ty->isa : NULL; + } + +-static int typhoon_setfreq_generic(struct typhoon *dev, +- unsigned long frequency) ++static int typhoon_s_frequency(struct radio_isa_card *isa, u32 freq) + { + unsigned long outval; + unsigned long x; +@@ -105,302 +95,86 @@ static int typhoon_setfreq_generic(struc + * + */ + +- mutex_lock(&dev->lock); +- x = frequency / 160; ++ x = freq / 160; + outval = (x * x + 2500) / 5000; + outval = (outval * x + 5000) / 10000; + outval -= (10 * x * x + 10433) / 20866; + outval += 4 * x - 11505; + +- outb_p((outval >> 8) & 0x01, dev->io + 4); +- outb_p(outval >> 9, dev->io + 6); +- outb_p(outval & 0xff, dev->io + 8); +- mutex_unlock(&dev->lock); +- +- return 0; +-} +- +-static int typhoon_setfreq(struct typhoon *dev, unsigned long frequency) +-{ +- typhoon_setfreq_generic(dev, frequency); +- dev->curfreq = frequency; +- return 0; +-} +- +-static void typhoon_mute(struct typhoon *dev) +-{ +- if (dev->muted == 1) +- return; +- typhoon_setvol_generic(dev, 0); +- typhoon_setfreq_generic(dev, dev->mutefreq); +- dev->muted = 1; +-} +- +-static void typhoon_unmute(struct typhoon *dev) +-{ +- if (dev->muted == 0) +- return; +- typhoon_setfreq_generic(dev, dev->curfreq); +- typhoon_setvol_generic(dev, dev->curvol); +- dev->muted = 0; +-} +- +-static int typhoon_setvol(struct typhoon *dev, int vol) +-{ +- if (dev->muted && vol != 0) { /* user is unmuting the card */ +- dev->curvol = vol; +- typhoon_unmute(dev); +- return 0; +- } +- if (vol == dev->curvol) /* requested volume == current */ +- return 0; +- +- if (vol == 0) { /* volume == 0 means mute the card */ +- typhoon_mute(dev); +- dev->curvol = vol; +- return 0; +- } +- typhoon_setvol_generic(dev, vol); +- dev->curvol = vol; +- return 0; +-} +- +-static int vidioc_querycap(struct file *file, void *priv, +- struct v4l2_capability *v) +-{ +- strlcpy(v->driver, "radio-typhoon", sizeof(v->driver)); +- strlcpy(v->card, "Typhoon Radio", sizeof(v->card)); +- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); +- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; +- return 0; +-} +- +-static int vidioc_g_tuner(struct file *file, void *priv, +- struct v4l2_tuner *v) +-{ +- if (v->index > 0) +- return -EINVAL; +- +- strlcpy(v->name, "FM", sizeof(v->name)); +- v->type = V4L2_TUNER_RADIO; +- v->rangelow = 87.5 * 16000; +- v->rangehigh = 108 * 16000; +- v->rxsubchans = V4L2_TUNER_SUB_MONO; +- v->capability = V4L2_TUNER_CAP_LOW; +- v->audmode = V4L2_TUNER_MODE_MONO; +- v->signal = 0xFFFF; /* We can't get the signal strength */ ++ outb_p((outval >> 8) & 0x01, isa->io + 4); ++ outb_p(outval >> 9, isa->io + 6); ++ outb_p(outval & 0xff, isa->io + 8); + return 0; + } + +-static int vidioc_s_tuner(struct file *file, void *priv, +- struct v4l2_tuner *v) +-{ +- return v->index ? -EINVAL : 0; +-} +- +-static int vidioc_g_frequency(struct file *file, void *priv, +- struct v4l2_frequency *f) ++static int typhoon_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) + { +- struct typhoon *dev = video_drvdata(file); ++ struct typhoon *ty = container_of(isa, struct typhoon, isa); + +- if (f->tuner != 0) +- return -EINVAL; +- f->type = V4L2_TUNER_RADIO; +- f->frequency = dev->curfreq; +- return 0; +-} +- +-static int vidioc_s_frequency(struct file *file, void *priv, +- struct v4l2_frequency *f) +-{ +- struct typhoon *dev = video_drvdata(file); +- +- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) +- return -EINVAL; +- dev->curfreq = f->frequency; +- typhoon_setfreq(dev, dev->curfreq); +- return 0; +-} +- +-static int vidioc_queryctrl(struct file *file, void *priv, +- struct v4l2_queryctrl *qc) +-{ +- switch (qc->id) { +- case V4L2_CID_AUDIO_MUTE: +- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); +- case V4L2_CID_AUDIO_VOLUME: +- return v4l2_ctrl_query_fill(qc, 0, 65535, 16384, 65535); +- } +- return -EINVAL; +-} +- +-static int vidioc_g_ctrl(struct file *file, void *priv, +- struct v4l2_control *ctrl) +-{ +- struct typhoon *dev = video_drvdata(file); ++ if (mute) ++ vol = 0; ++ vol >>= 14; /* Map 16 bit to 2 bit */ ++ vol &= 3; ++ outb_p(vol / 2, isa->io); /* Set the volume, high bit. */ ++ outb_p(vol % 2, isa->io + 2); /* Set the volume, low bit. */ + +- switch (ctrl->id) { +- case V4L2_CID_AUDIO_MUTE: +- ctrl->value = dev->muted; +- return 0; +- case V4L2_CID_AUDIO_VOLUME: +- ctrl->value = dev->curvol; +- return 0; ++ if (vol == 0 && !ty->muted) { ++ ty->muted = true; ++ return typhoon_s_frequency(isa, mutefreq << 4); + } +- return -EINVAL; +-} +- +-static int vidioc_s_ctrl (struct file *file, void *priv, +- struct v4l2_control *ctrl) +-{ +- struct typhoon *dev = video_drvdata(file); +- +- switch (ctrl->id) { +- case V4L2_CID_AUDIO_MUTE: +- if (ctrl->value) +- typhoon_mute(dev); +- else +- typhoon_unmute(dev); +- return 0; +- case V4L2_CID_AUDIO_VOLUME: +- typhoon_setvol(dev, ctrl->value); +- return 0; ++ if (vol && ty->muted) { ++ ty->muted = false; ++ return typhoon_s_frequency(isa, isa->freq); + } +- return -EINVAL; +-} +- +-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +-{ +- *i = 0; + return 0; + } + +-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +-{ +- return i ? -EINVAL : 0; +-} +- +-static int vidioc_g_audio(struct file *file, void *priv, +- struct v4l2_audio *a) +-{ +- a->index = 0; +- strlcpy(a->name, "Radio", sizeof(a->name)); +- a->capability = V4L2_AUDCAP_STEREO; +- return 0; +-} +- +-static int vidioc_s_audio(struct file *file, void *priv, +- struct v4l2_audio *a) +-{ +- return a->index ? -EINVAL : 0; +-} +- +-static int vidioc_log_status(struct file *file, void *priv) +-{ +- struct typhoon *dev = video_drvdata(file); +- struct v4l2_device *v4l2_dev = &dev->v4l2_dev; +- +- v4l2_info(v4l2_dev, BANNER); +-#ifdef MODULE +- v4l2_info(v4l2_dev, "Load type: Driver loaded as a module\n\n"); +-#else +- v4l2_info(v4l2_dev, "Load type: Driver compiled into kernel\n\n"); +-#endif +- v4l2_info(v4l2_dev, "frequency = %lu kHz\n", dev->curfreq >> 4); +- v4l2_info(v4l2_dev, "volume = %d\n", dev->curvol); +- v4l2_info(v4l2_dev, "mute = %s\n", dev->muted ? "on" : "off"); +- v4l2_info(v4l2_dev, "io = 0x%x\n", dev->io); +- v4l2_info(v4l2_dev, "mute frequency = %lu kHz\n", dev->mutefreq >> 4); +- return 0; +-} +- +-static const struct v4l2_file_operations typhoon_fops = { +- .owner = THIS_MODULE, +- .unlocked_ioctl = video_ioctl2, ++static const struct radio_isa_ops typhoon_ops = { ++ .alloc = typhoon_alloc, ++ .s_mute_volume = typhoon_s_mute_volume, ++ .s_frequency = typhoon_s_frequency, + }; + +-static const struct v4l2_ioctl_ops typhoon_ioctl_ops = { +- .vidioc_log_status = vidioc_log_status, +- .vidioc_querycap = vidioc_querycap, +- .vidioc_g_tuner = vidioc_g_tuner, +- .vidioc_s_tuner = vidioc_s_tuner, +- .vidioc_g_audio = vidioc_g_audio, +- .vidioc_s_audio = vidioc_s_audio, +- .vidioc_g_input = vidioc_g_input, +- .vidioc_s_input = vidioc_s_input, +- .vidioc_g_frequency = vidioc_g_frequency, +- .vidioc_s_frequency = vidioc_s_frequency, +- .vidioc_queryctrl = vidioc_queryctrl, +- .vidioc_g_ctrl = vidioc_g_ctrl, +- .vidioc_s_ctrl = vidioc_s_ctrl, ++static const int typhoon_ioports[] = { 0x316, 0x336 }; ++ ++static struct radio_isa_driver typhoon_driver = { ++ .driver = { ++ .match = radio_isa_match, ++ .probe = radio_isa_probe, ++ .remove = radio_isa_remove, ++ .driver = { ++ .name = "radio-typhoon", ++ }, ++ }, ++ .io_params = io, ++ .radio_nr_params = radio_nr, ++ .io_ports = typhoon_ioports, ++ .num_of_io_ports = ARRAY_SIZE(typhoon_ioports), ++ .region_size = 8, ++ .card = "Typhoon Radio", ++ .ops = &typhoon_ops, ++ .has_stereo = true, ++ .max_volume = 3, + }; + + static int __init typhoon_init(void) + { +- struct typhoon *dev = &typhoon_card; +- struct v4l2_device *v4l2_dev = &dev->v4l2_dev; +- int res; +- +- strlcpy(v4l2_dev->name, "typhoon", sizeof(v4l2_dev->name)); +- dev->io = io; +- +- if (dev->io == -1) { +- v4l2_err(v4l2_dev, "You must set an I/O address with io=0x316 or io=0x336\n"); +- return -EINVAL; +- } +- +- if (mutefreq < 87000 || mutefreq > 108500) { +- v4l2_err(v4l2_dev, "You must set a frequency (in kHz) used when muting the card,\n"); +- v4l2_err(v4l2_dev, "e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n"); +- return -EINVAL; ++ if (mutefreq < 87000 || mutefreq > 108000) { ++ printk(KERN_ERR "%s: You must set a frequency (in kHz) used when muting the card,\n", ++ typhoon_driver.driver.driver.name); ++ printk(KERN_ERR "%s: e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108000)\n", ++ typhoon_driver.driver.driver.name); ++ return -ENODEV; + } +- dev->curfreq = dev->mutefreq = mutefreq << 4; +- +- mutex_init(&dev->lock); +- if (!request_region(dev->io, 8, "typhoon")) { +- v4l2_err(v4l2_dev, "port 0x%x already in use\n", +- dev->io); +- return -EBUSY; +- } +- +- res = v4l2_device_register(NULL, v4l2_dev); +- if (res < 0) { +- release_region(dev->io, 8); +- v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); +- return res; +- } +- v4l2_info(v4l2_dev, BANNER); +- +- strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); +- dev->vdev.v4l2_dev = v4l2_dev; +- dev->vdev.fops = &typhoon_fops; +- dev->vdev.ioctl_ops = &typhoon_ioctl_ops; +- dev->vdev.release = video_device_release_empty; +- video_set_drvdata(&dev->vdev, dev); +- +- /* mute card - prevents noisy bootups */ +- typhoon_mute(dev); +- +- if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { +- v4l2_device_unregister(&dev->v4l2_dev); +- release_region(dev->io, 8); +- return -EINVAL; +- } +- v4l2_info(v4l2_dev, "port 0x%x.\n", dev->io); +- v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", mutefreq); +- +- return 0; ++ return isa_register_driver(&typhoon_driver.driver, TYPHOON_MAX); + } + + static void __exit typhoon_exit(void) + { +- struct typhoon *dev = &typhoon_card; +- +- video_unregister_device(&dev->vdev); +- v4l2_device_unregister(&dev->v4l2_dev); +- release_region(dev->io, 8); ++ isa_unregister_driver(&typhoon_driver.driver); + } + ++ + module_init(typhoon_init); + module_exit(typhoon_exit); + +Index: linux-3.3.x86_64/drivers/media/radio/radio-zoltrix.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/radio/radio-zoltrix.c ++++ linux-3.3.x86_64/drivers/media/radio/radio-zoltrix.c +@@ -1,5 +1,6 @@ +-/* zoltrix radio plus driver for Linux radio support +- * (c) 1998 C. van Schaik ++/* ++ * Zoltrix Radio Plus driver ++ * Copyright 1998 C. van Schaik + * + * BUGS + * Due to the inconsistency in reading from the signal flags +@@ -27,6 +28,14 @@ + * + * 2006-07-24 - Converted to V4L2 API + * by Mauro Carvalho Chehab ++ * ++ * Converted to the radio-isa framework by Hans Verkuil ++ * ++ * Note that this is the driver for the Zoltrix Radio Plus. ++ * This driver does not work for the Zoltrix Radio Plus 108 or the ++ * Zoltrix Radio Plus for Windows. ++ * ++ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool. + */ + + #include /* Modules */ +@@ -36,82 +45,70 @@ + #include /* kernel radio structs */ + #include + #include /* outb, outb_p */ ++#include + #include + #include ++#include "radio-isa.h" + +-MODULE_AUTHOR("C.van Schaik"); ++MODULE_AUTHOR("C. van Schaik"); + MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus."); + MODULE_LICENSE("GPL"); +-MODULE_VERSION("0.0.3"); ++MODULE_VERSION("0.1.99"); + + #ifndef CONFIG_RADIO_ZOLTRIX_PORT + #define CONFIG_RADIO_ZOLTRIX_PORT -1 + #endif + +-static int io = CONFIG_RADIO_ZOLTRIX_PORT; +-static int radio_nr = -1; ++#define ZOLTRIX_MAX 2 + +-module_param(io, int, 0); +-MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)"); +-module_param(radio_nr, int, 0); ++static int io[ZOLTRIX_MAX] = { [0] = CONFIG_RADIO_ZOLTRIX_PORT, ++ [1 ... (ZOLTRIX_MAX - 1)] = -1 }; ++static int radio_nr[ZOLTRIX_MAX] = { [0 ... (ZOLTRIX_MAX - 1)] = -1 }; ++ ++module_param_array(io, int, NULL, 0444); ++MODULE_PARM_DESC(io, "I/O addresses of the Zoltrix Radio Plus card (0x20c or 0x30c)"); ++module_param_array(radio_nr, int, NULL, 0444); ++MODULE_PARM_DESC(radio_nr, "Radio device numbers"); + + struct zoltrix { +- struct v4l2_device v4l2_dev; +- struct video_device vdev; +- int io; ++ struct radio_isa_card isa; + int curvol; +- unsigned long curfreq; +- int muted; +- unsigned int stereo; +- struct mutex lock; ++ bool muted; + }; + +-static struct zoltrix zoltrix_card; ++static struct radio_isa_card *zoltrix_alloc(void) ++{ ++ struct zoltrix *zol = kzalloc(sizeof(*zol), GFP_KERNEL); + +-static int zol_setvol(struct zoltrix *zol, int vol) ++ return zol ? &zol->isa : NULL; ++} ++ ++static int zoltrix_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) + { +- zol->curvol = vol; +- if (zol->muted) +- return 0; ++ struct zoltrix *zol = container_of(isa, struct zoltrix, isa); + +- mutex_lock(&zol->lock); +- if (vol == 0) { +- outb(0, zol->io); +- outb(0, zol->io); +- inb(zol->io + 3); /* Zoltrix needs to be read to confirm */ +- mutex_unlock(&zol->lock); ++ zol->curvol = vol; ++ zol->muted = mute; ++ if (mute || vol == 0) { ++ outb(0, isa->io); ++ outb(0, isa->io); ++ inb(isa->io + 3); /* Zoltrix needs to be read to confirm */ + return 0; + } + +- outb(zol->curvol-1, zol->io); ++ outb(vol - 1, isa->io); + msleep(10); +- inb(zol->io + 2); +- mutex_unlock(&zol->lock); ++ inb(isa->io + 2); + return 0; + } + +-static void zol_mute(struct zoltrix *zol) +-{ +- zol->muted = 1; +- mutex_lock(&zol->lock); +- outb(0, zol->io); +- outb(0, zol->io); +- inb(zol->io + 3); /* Zoltrix needs to be read to confirm */ +- mutex_unlock(&zol->lock); +-} +- +-static void zol_unmute(struct zoltrix *zol) +-{ +- zol->muted = 0; +- zol_setvol(zol, zol->curvol); +-} +- +-static int zol_setfreq(struct zoltrix *zol, unsigned long freq) ++/* tunes the radio to the desired frequency */ ++static int zoltrix_s_frequency(struct radio_isa_card *isa, u32 freq) + { +- /* tunes the radio to the desired frequency */ +- struct v4l2_device *v4l2_dev = &zol->v4l2_dev; ++ struct zoltrix *zol = container_of(isa, struct zoltrix, isa); ++ struct v4l2_device *v4l2_dev = &isa->v4l2_dev; + unsigned long long bitmask, f, m; +- unsigned int stereo = zol->stereo; ++ bool stereo = isa->stereo; + int i; + + if (freq == 0) { +@@ -125,340 +122,125 @@ static int zol_setfreq(struct zoltrix *z + bitmask = 0xc480402c10080000ull; + i = 45; + +- mutex_lock(&zol->lock); +- +- zol->curfreq = freq; ++ outb(0, isa->io); ++ outb(0, isa->io); ++ inb(isa->io + 3); /* Zoltrix needs to be read to confirm */ + +- outb(0, zol->io); +- outb(0, zol->io); +- inb(zol->io + 3); /* Zoltrix needs to be read to confirm */ +- +- outb(0x40, zol->io); +- outb(0xc0, zol->io); ++ outb(0x40, isa->io); ++ outb(0xc0, isa->io); + + bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ (stereo << 31)); + while (i--) { + if ((bitmask & 0x8000000000000000ull) != 0) { +- outb(0x80, zol->io); ++ outb(0x80, isa->io); + udelay(50); +- outb(0x00, zol->io); ++ outb(0x00, isa->io); + udelay(50); +- outb(0x80, zol->io); ++ outb(0x80, isa->io); + udelay(50); + } else { +- outb(0xc0, zol->io); ++ outb(0xc0, isa->io); + udelay(50); +- outb(0x40, zol->io); ++ outb(0x40, isa->io); + udelay(50); +- outb(0xc0, zol->io); ++ outb(0xc0, isa->io); + udelay(50); + } + bitmask *= 2; + } + /* termination sequence */ +- outb(0x80, zol->io); +- outb(0xc0, zol->io); +- outb(0x40, zol->io); ++ outb(0x80, isa->io); ++ outb(0xc0, isa->io); ++ outb(0x40, isa->io); + udelay(1000); +- inb(zol->io + 2); +- ++ inb(isa->io + 2); + udelay(1000); + +- if (zol->muted) { +- outb(0, zol->io); +- outb(0, zol->io); +- inb(zol->io + 3); +- udelay(1000); +- } +- +- mutex_unlock(&zol->lock); +- +- if (!zol->muted) +- zol_setvol(zol, zol->curvol); +- return 0; ++ return zoltrix_s_mute_volume(isa, zol->muted, zol->curvol); + } + + /* Get signal strength */ +-static int zol_getsigstr(struct zoltrix *zol) ++static u32 zoltrix_g_rxsubchans(struct radio_isa_card *isa) + { ++ struct zoltrix *zol = container_of(isa, struct zoltrix, isa); + int a, b; + +- mutex_lock(&zol->lock); +- outb(0x00, zol->io); /* This stuff I found to do nothing */ +- outb(zol->curvol, zol->io); ++ outb(0x00, isa->io); /* This stuff I found to do nothing */ ++ outb(zol->curvol, isa->io); + msleep(20); + +- a = inb(zol->io); ++ a = inb(isa->io); + msleep(10); +- b = inb(zol->io); +- +- mutex_unlock(&zol->lock); ++ b = inb(isa->io); + +- if (a != b) +- return 0; +- +- /* I found this out by playing with a binary scanner on the card io */ +- return a == 0xcf || a == 0xdf || a == 0xef; ++ return (a == b && a == 0xcf) ? ++ V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + } + +-static int zol_is_stereo(struct zoltrix *zol) ++static u32 zoltrix_g_signal(struct radio_isa_card *isa) + { +- int x1, x2; +- +- mutex_lock(&zol->lock); ++ struct zoltrix *zol = container_of(isa, struct zoltrix, isa); ++ int a, b; + +- outb(0x00, zol->io); +- outb(zol->curvol, zol->io); ++ outb(0x00, isa->io); /* This stuff I found to do nothing */ ++ outb(zol->curvol, isa->io); + msleep(20); + +- x1 = inb(zol->io); ++ a = inb(isa->io); + msleep(10); +- x2 = inb(zol->io); +- +- mutex_unlock(&zol->lock); +- +- return x1 == x2 && x1 == 0xcf; +-} +- +-static int vidioc_querycap(struct file *file, void *priv, +- struct v4l2_capability *v) +-{ +- strlcpy(v->driver, "radio-zoltrix", sizeof(v->driver)); +- strlcpy(v->card, "Zoltrix Radio", sizeof(v->card)); +- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); +- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; +- return 0; +-} +- +-static int vidioc_g_tuner(struct file *file, void *priv, +- struct v4l2_tuner *v) +-{ +- struct zoltrix *zol = video_drvdata(file); +- +- if (v->index > 0) +- return -EINVAL; +- +- strlcpy(v->name, "FM", sizeof(v->name)); +- v->type = V4L2_TUNER_RADIO; +- v->rangelow = 88 * 16000; +- v->rangehigh = 108 * 16000; +- v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; +- v->capability = V4L2_TUNER_CAP_LOW; +- if (zol_is_stereo(zol)) +- v->audmode = V4L2_TUNER_MODE_STEREO; +- else +- v->audmode = V4L2_TUNER_MODE_MONO; +- v->signal = 0xFFFF * zol_getsigstr(zol); +- return 0; +-} +- +-static int vidioc_s_tuner(struct file *file, void *priv, +- struct v4l2_tuner *v) +-{ +- return v->index ? -EINVAL : 0; +-} +- +-static int vidioc_s_frequency(struct file *file, void *priv, +- struct v4l2_frequency *f) +-{ +- struct zoltrix *zol = video_drvdata(file); +- +- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) +- return -EINVAL; +- if (zol_setfreq(zol, f->frequency) != 0) +- return -EINVAL; +- return 0; +-} +- +-static int vidioc_g_frequency(struct file *file, void *priv, +- struct v4l2_frequency *f) +-{ +- struct zoltrix *zol = video_drvdata(file); +- +- if (f->tuner != 0) +- return -EINVAL; +- f->type = V4L2_TUNER_RADIO; +- f->frequency = zol->curfreq; +- return 0; +-} +- +-static int vidioc_queryctrl(struct file *file, void *priv, +- struct v4l2_queryctrl *qc) +-{ +- switch (qc->id) { +- case V4L2_CID_AUDIO_MUTE: +- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); +- case V4L2_CID_AUDIO_VOLUME: +- return v4l2_ctrl_query_fill(qc, 0, 65535, 4096, 65535); +- } +- return -EINVAL; +-} +- +-static int vidioc_g_ctrl(struct file *file, void *priv, +- struct v4l2_control *ctrl) +-{ +- struct zoltrix *zol = video_drvdata(file); +- +- switch (ctrl->id) { +- case V4L2_CID_AUDIO_MUTE: +- ctrl->value = zol->muted; +- return 0; +- case V4L2_CID_AUDIO_VOLUME: +- ctrl->value = zol->curvol * 4096; +- return 0; +- } +- return -EINVAL; +-} ++ b = inb(isa->io); + +-static int vidioc_s_ctrl(struct file *file, void *priv, +- struct v4l2_control *ctrl) +-{ +- struct zoltrix *zol = video_drvdata(file); +- +- switch (ctrl->id) { +- case V4L2_CID_AUDIO_MUTE: +- if (ctrl->value) +- zol_mute(zol); +- else { +- zol_unmute(zol); +- zol_setvol(zol, zol->curvol); +- } +- return 0; +- case V4L2_CID_AUDIO_VOLUME: +- zol_setvol(zol, ctrl->value / 4096); ++ if (a != b) + return 0; +- } +- zol->stereo = 1; +- if (zol_setfreq(zol, zol->curfreq) != 0) +- return -EINVAL; +-#if 0 +-/* FIXME: Implement stereo/mono switch on V4L2 */ +- if (v->mode & VIDEO_SOUND_STEREO) { +- zol->stereo = 1; +- zol_setfreq(zol, zol->curfreq); +- } +- if (v->mode & VIDEO_SOUND_MONO) { +- zol->stereo = 0; +- zol_setfreq(zol, zol->curfreq); +- } +-#endif +- return -EINVAL; +-} +- +-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +-{ +- *i = 0; +- return 0; +-} +- +-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +-{ +- return i ? -EINVAL : 0; +-} + +-static int vidioc_g_audio(struct file *file, void *priv, +- struct v4l2_audio *a) +-{ +- a->index = 0; +- strlcpy(a->name, "Radio", sizeof(a->name)); +- a->capability = V4L2_AUDCAP_STEREO; +- return 0; ++ /* I found this out by playing with a binary scanner on the card io */ ++ return (a == 0xcf || a == 0xdf || a == 0xef) ? 0xffff : 0; + } + +-static int vidioc_s_audio(struct file *file, void *priv, +- struct v4l2_audio *a) ++static int zoltrix_s_stereo(struct radio_isa_card *isa, bool stereo) + { +- return a->index ? -EINVAL : 0; ++ return zoltrix_s_frequency(isa, isa->freq); + } + +-static const struct v4l2_file_operations zoltrix_fops = +-{ +- .owner = THIS_MODULE, +- .unlocked_ioctl = video_ioctl2, ++static const struct radio_isa_ops zoltrix_ops = { ++ .alloc = zoltrix_alloc, ++ .s_mute_volume = zoltrix_s_mute_volume, ++ .s_frequency = zoltrix_s_frequency, ++ .s_stereo = zoltrix_s_stereo, ++ .g_rxsubchans = zoltrix_g_rxsubchans, ++ .g_signal = zoltrix_g_signal, + }; + +-static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = { +- .vidioc_querycap = vidioc_querycap, +- .vidioc_g_tuner = vidioc_g_tuner, +- .vidioc_s_tuner = vidioc_s_tuner, +- .vidioc_g_audio = vidioc_g_audio, +- .vidioc_s_audio = vidioc_s_audio, +- .vidioc_g_input = vidioc_g_input, +- .vidioc_s_input = vidioc_s_input, +- .vidioc_g_frequency = vidioc_g_frequency, +- .vidioc_s_frequency = vidioc_s_frequency, +- .vidioc_queryctrl = vidioc_queryctrl, +- .vidioc_g_ctrl = vidioc_g_ctrl, +- .vidioc_s_ctrl = vidioc_s_ctrl, ++static const int zoltrix_ioports[] = { 0x20c, 0x30c }; ++ ++static struct radio_isa_driver zoltrix_driver = { ++ .driver = { ++ .match = radio_isa_match, ++ .probe = radio_isa_probe, ++ .remove = radio_isa_remove, ++ .driver = { ++ .name = "radio-zoltrix", ++ }, ++ }, ++ .io_params = io, ++ .radio_nr_params = radio_nr, ++ .io_ports = zoltrix_ioports, ++ .num_of_io_ports = ARRAY_SIZE(zoltrix_ioports), ++ .region_size = 2, ++ .card = "Zoltrix Radio Plus", ++ .ops = &zoltrix_ops, ++ .has_stereo = true, ++ .max_volume = 15, + }; + + static int __init zoltrix_init(void) + { +- struct zoltrix *zol = &zoltrix_card; +- struct v4l2_device *v4l2_dev = &zol->v4l2_dev; +- int res; +- +- strlcpy(v4l2_dev->name, "zoltrix", sizeof(v4l2_dev->name)); +- zol->io = io; +- if (zol->io == -1) { +- v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or 0x30c\n"); +- return -EINVAL; +- } +- if (zol->io != 0x20c && zol->io != 0x30c) { +- v4l2_err(v4l2_dev, "invalid port, try 0x20c or 0x30c\n"); +- return -ENXIO; +- } +- +- if (!request_region(zol->io, 2, "zoltrix")) { +- v4l2_err(v4l2_dev, "port 0x%x already in use\n", zol->io); +- return -EBUSY; +- } +- +- res = v4l2_device_register(NULL, v4l2_dev); +- if (res < 0) { +- release_region(zol->io, 2); +- v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); +- return res; +- } +- +- mutex_init(&zol->lock); +- +- /* mute card - prevents noisy bootups */ +- +- /* this ensures that the volume is all the way down */ +- +- outb(0, zol->io); +- outb(0, zol->io); +- msleep(20); +- inb(zol->io + 3); +- +- zol->curvol = 0; +- zol->stereo = 1; +- +- strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name)); +- zol->vdev.v4l2_dev = v4l2_dev; +- zol->vdev.fops = &zoltrix_fops; +- zol->vdev.ioctl_ops = &zoltrix_ioctl_ops; +- zol->vdev.release = video_device_release_empty; +- video_set_drvdata(&zol->vdev, zol); +- +- if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { +- v4l2_device_unregister(v4l2_dev); +- release_region(zol->io, 2); +- return -EINVAL; +- } +- v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n"); +- +- return 0; ++ return isa_register_driver(&zoltrix_driver.driver, ZOLTRIX_MAX); + } + + static void __exit zoltrix_exit(void) + { +- struct zoltrix *zol = &zoltrix_card; +- +- video_unregister_device(&zol->vdev); +- v4l2_device_unregister(&zol->v4l2_dev); +- release_region(zol->io, 2); ++ isa_unregister_driver(&zoltrix_driver.driver); + } + + module_init(zoltrix_init); +Index: linux-3.3.x86_64/drivers/media/dvb/dvb-core/dvb_frontend.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-core/dvb_frontend.c ++++ linux-3.3.x86_64/drivers/media/dvb/dvb-core/dvb_frontend.c +@@ -148,7 +148,7 @@ static int dtv_property_legacy_params_sy + + static bool has_get_frontend(struct dvb_frontend *fe) + { +- return fe->ops.get_frontend; ++ return fe->ops.get_frontend != NULL; + } + + /* +Index: linux-3.3.x86_64/drivers/media/common/tuners/xc5000.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/common/tuners/xc5000.c ++++ linux-3.3.x86_64/drivers/media/common/tuners/xc5000.c +@@ -49,9 +49,6 @@ static LIST_HEAD(hybrid_tuner_instance_l + #define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) + +-#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.6.114.fw" +-#define XC5000_DEFAULT_FIRMWARE_SIZE 12401 +- + struct xc5000_priv { + struct tuner_i2c_props i2c_props; + struct list_head hybrid_tuner_instance_list; +@@ -62,6 +59,8 @@ struct xc5000_priv { + u8 video_standard; + u8 rf_mode; + u8 radio_input; ++ ++ int chip_id; + }; + + /* Misc Defines */ +@@ -204,6 +203,33 @@ static struct XC_TV_STANDARD XC5000_Stan + {"FM Radio-INPUT1_MONO", 0x0278, 0x9002} + }; + ++ ++struct xc5000_fw_cfg { ++ char *name; ++ u16 size; ++}; ++ ++static const struct xc5000_fw_cfg xc5000a_1_6_114 = { ++ .name = "dvb-fe-xc5000-1.6.114.fw", ++ .size = 12401, ++}; ++ ++static const struct xc5000_fw_cfg xc5000c_41_024_5_31875 = { ++ .name = "dvb-fe-xc5000c-41.024.5-31875.fw", ++ .size = 16503, ++}; ++ ++static inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id) ++{ ++ switch (chip_id) { ++ default: ++ case XC5000A: ++ return &xc5000a_1_6_114; ++ case XC5000C: ++ return &xc5000c_41_024_5_31875; ++ } ++} ++ + static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe); + static int xc5000_is_firmware_loaded(struct dvb_frontend *fe); + static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val); +@@ -552,12 +578,14 @@ static int xc5000_fwupload(struct dvb_fr + struct xc5000_priv *priv = fe->tuner_priv; + const struct firmware *fw; + int ret; ++ const struct xc5000_fw_cfg *desired_fw = ++ xc5000_assign_firmware(priv->chip_id); + + /* request the firmware, this will block and timeout */ + printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", +- XC5000_DEFAULT_FIRMWARE); ++ desired_fw->name); + +- ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, ++ ret = request_firmware(&fw, desired_fw->name, + priv->i2c_props.adap->dev.parent); + if (ret) { + printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); +@@ -569,7 +597,7 @@ static int xc5000_fwupload(struct dvb_fr + ret = XC_RESULT_SUCCESS; + } + +- if (fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) { ++ if (fw->size != desired_fw->size) { + printk(KERN_ERR "xc5000: firmware incorrect size\n"); + ret = XC_RESULT_RESET_FAILURE; + } else { +@@ -1139,6 +1167,13 @@ struct dvb_frontend *xc5000_attach(struc + if (priv->radio_input == 0) + priv->radio_input = cfg->radio_input; + ++ /* don't override chip id if it's already been set ++ unless explicitly specified */ ++ if ((priv->chip_id == 0) || (cfg->chip_id)) ++ /* use default chip id if none specified, set to 0 so ++ it can be overridden if this is a hybrid driver */ ++ priv->chip_id = (cfg->chip_id) ? cfg->chip_id : 0; ++ + /* Check if firmware has been loaded. It is possible that another + instance of the driver has loaded the firmware. + */ +Index: linux-3.3.x86_64/drivers/media/common/tuners/xc5000.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/common/tuners/xc5000.h ++++ linux-3.3.x86_64/drivers/media/common/tuners/xc5000.h +@@ -27,10 +27,15 @@ + struct dvb_frontend; + struct i2c_adapter; + ++#define XC5000A 1 ++#define XC5000C 2 ++ + struct xc5000_config { + u8 i2c_address; + u32 if_khz; + u8 radio_input; ++ ++ int chip_id; + }; + + /* xc5000 callback command */ +Index: linux-3.3.x86_64/drivers/media/common/tuners/tuner-types.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/common/tuners/tuner-types.c ++++ linux-3.3.x86_64/drivers/media/common/tuners/tuner-types.c +@@ -1868,6 +1868,10 @@ struct tunertype tuners[] = { + .params = tuner_tena_tnf_5337_params, + .count = ARRAY_SIZE(tuner_tena_tnf_5337_params), + }, ++ [TUNER_XC5000C] = { /* Xceive 5000C */ ++ .name = "Xceive 5000C tuner", ++ /* see xc5000.c for details */ ++ }, + }; + EXPORT_SYMBOL(tuners); + +Index: linux-3.3.x86_64/drivers/media/video/tuner-core.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/tuner-core.c ++++ linux-3.3.x86_64/drivers/media/video/tuner-core.c +@@ -380,6 +380,21 @@ static void set_type(struct i2c_client * + tune_now = 0; + break; + } ++ case TUNER_XC5000C: ++ { ++ struct xc5000_config xc5000c_cfg = { ++ .i2c_address = t->i2c->addr, ++ /* if_khz will be set at dvb_attach() */ ++ .if_khz = 0, ++ .chip_id = XC5000C, ++ }; ++ ++ if (!dvb_attach(xc5000_attach, ++ &t->fe, t->i2c->adapter, &xc5000c_cfg)) ++ goto attach_failed; ++ tune_now = 0; ++ break; ++ } + case TUNER_NXP_TDA18271: + { + struct tda18271_config cfg = { +@@ -1314,18 +1329,7 @@ static struct i2c_driver tuner_driver = + .id_table = tuner_id, + }; + +-static __init int init_tuner(void) +-{ +- return i2c_add_driver(&tuner_driver); +-} +- +-static __exit void exit_tuner(void) +-{ +- i2c_del_driver(&tuner_driver); +-} +- +-module_init(init_tuner); +-module_exit(exit_tuner); ++module_i2c_driver(tuner_driver); + + MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners"); + MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); +Index: linux-3.3.x86_64/include/media/tuner.h +=================================================================== +--- linux-3.3.x86_64.orig/include/media/tuner.h ++++ linux-3.3.x86_64/include/media/tuner.h +@@ -136,6 +136,7 @@ + #define TUNER_TENA_TNF_5337 86 + + #define TUNER_XC4000 87 /* Xceive Silicon Tuner */ ++#define TUNER_XC5000C 88 /* Xceive Silicon Tuner */ + + /* tv card specific */ + #define TDA9887_PRESENT (1<<0) +Index: linux-3.3.x86_64/drivers/media/video/tveeprom.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/tveeprom.c ++++ linux-3.3.x86_64/drivers/media/video/tveeprom.c +@@ -286,8 +286,16 @@ hauppauge_tuner[] = + { TUNER_ABSENT, "MaxLinear 301"}, + { TUNER_ABSENT, "Mirics MSi001"}, + { TUNER_ABSENT, "MaxLinear MxL241SF"}, +- { TUNER_ABSENT, "Xceive XC5000C"}, ++ { TUNER_XC5000C, "Xceive XC5000C"}, + { TUNER_ABSENT, "Montage M68TS2020"}, ++ { TUNER_ABSENT, "Siano SMS1530"}, ++ { TUNER_ABSENT, "Dibcom 7090"}, ++ { TUNER_ABSENT, "Xceive XC5200C"}, ++ { TUNER_ABSENT, "NXP 18273"}, ++ { TUNER_ABSENT, "Montage M88TS2022"}, ++ /* 180-189 */ ++ { TUNER_ABSENT, "NXP 18272M"}, ++ { TUNER_ABSENT, "NXP 18272S"}, + }; + + /* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are +Index: linux-3.3.x86_64/drivers/media/radio/radio-sf16fmr2.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/radio/radio-sf16fmr2.c ++++ linux-3.3.x86_64/drivers/media/radio/radio-sf16fmr2.c +@@ -9,16 +9,23 @@ + #include + #include /* Modules */ + #include /* Initdata */ ++#include + #include /* request_region */ + #include /* outb, outb_p */ ++#include + #include + + MODULE_AUTHOR("Ondrej Zary"); + MODULE_DESCRIPTION("MediaForte SF16-FMR2 FM radio card driver"); + MODULE_LICENSE("GPL"); + ++static int radio_nr = -1; ++module_param(radio_nr, int, 0444); ++MODULE_PARM_DESC(radio_nr, "Radio device number"); ++ + struct fmr2 { + int io; ++ struct v4l2_device v4l2_dev; + struct snd_tea575x tea; + struct v4l2_ctrl *volume; + struct v4l2_ctrl *balance; +@@ -26,7 +33,6 @@ struct fmr2 { + + /* the port is hardwired so no need to support multiple cards */ + #define FMR2_PORT 0x384 +-static struct fmr2 fmr2_card; + + /* TEA575x tuner pins */ + #define STR_DATA (1 << 0) +@@ -172,7 +178,7 @@ static int fmr2_tea_ext_init(struct snd_ + fmr2->volume = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_VOLUME, 0, 68, 2, 56); + fmr2->balance = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_BALANCE, -68, 68, 2, 0); + if (tea->ctrl_handler.error) { +- printk(KERN_ERR "radio-sf16fmr2: can't initialize contrls\n"); ++ printk(KERN_ERR "radio-sf16fmr2: can't initialize controls\n"); + return tea->ctrl_handler.error; + } + } +@@ -180,26 +186,46 @@ static int fmr2_tea_ext_init(struct snd_ + return 0; + } + +-static int __init fmr2_init(void) ++static int __devinit fmr2_probe(struct device *pdev, unsigned int dev) + { +- struct fmr2 *fmr2 = &fmr2_card; ++ struct fmr2 *fmr2; ++ int err; ++ ++ fmr2 = kzalloc(sizeof(*fmr2), GFP_KERNEL); ++ if (fmr2 == NULL) ++ return -ENOMEM; + ++ strlcpy(fmr2->v4l2_dev.name, dev_name(pdev), ++ sizeof(fmr2->v4l2_dev.name)); + fmr2->io = FMR2_PORT; + +- if (!request_region(fmr2->io, 2, "SF16-FMR2")) { ++ if (!request_region(fmr2->io, 2, fmr2->v4l2_dev.name)) { + printk(KERN_ERR "radio-sf16fmr2: I/O port 0x%x already in use\n", fmr2->io); ++ kfree(fmr2); + return -EBUSY; + } + ++ dev_set_drvdata(pdev, fmr2); ++ err = v4l2_device_register(pdev, &fmr2->v4l2_dev); ++ if (err < 0) { ++ v4l2_err(&fmr2->v4l2_dev, "Could not register v4l2_device\n"); ++ release_region(fmr2->io, 2); ++ kfree(fmr2); ++ return err; ++ } ++ fmr2->tea.v4l2_dev = &fmr2->v4l2_dev; + fmr2->tea.private_data = fmr2; ++ fmr2->tea.radio_nr = radio_nr; + fmr2->tea.ops = &fmr2_tea_ops; + fmr2->tea.ext_init = fmr2_tea_ext_init; + strlcpy(fmr2->tea.card, "SF16-FMR2", sizeof(fmr2->tea.card)); +- strcpy(fmr2->tea.bus_info, "ISA"); ++ snprintf(fmr2->tea.bus_info, sizeof(fmr2->tea.bus_info), "ISA:%s", ++ fmr2->v4l2_dev.name); + + if (snd_tea575x_init(&fmr2->tea)) { + printk(KERN_ERR "radio-sf16fmr2: Unable to detect TEA575x tuner\n"); + release_region(fmr2->io, 2); ++ kfree(fmr2); + return -ENODEV; + } + +@@ -207,12 +233,33 @@ static int __init fmr2_init(void) + return 0; + } + +-static void __exit fmr2_exit(void) ++static int __exit fmr2_remove(struct device *pdev, unsigned int dev) + { +- struct fmr2 *fmr2 = &fmr2_card; ++ struct fmr2 *fmr2 = dev_get_drvdata(pdev); + + snd_tea575x_exit(&fmr2->tea); + release_region(fmr2->io, 2); ++ v4l2_device_unregister(&fmr2->v4l2_dev); ++ kfree(fmr2); ++ return 0; ++} ++ ++struct isa_driver fmr2_driver = { ++ .probe = fmr2_probe, ++ .remove = fmr2_remove, ++ .driver = { ++ .name = "radio-sf16fmr2", ++ }, ++}; ++ ++static int __init fmr2_init(void) ++{ ++ return isa_register_driver(&fmr2_driver, 1); ++} ++ ++static void __exit fmr2_exit(void) ++{ ++ isa_unregister_driver(&fmr2_driver); + } + + module_init(fmr2_init); +Index: linux-3.3.x86_64/drivers/media/video/davinci/dm355_ccdc.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/davinci/dm355_ccdc.c ++++ linux-3.3.x86_64/drivers/media/video/davinci/dm355_ccdc.c +@@ -292,7 +292,7 @@ static int validate_ccdc_param(struct cc + if ((ccdcparam->med_filt_thres < 0) || + (ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) { + dev_dbg(ccdc_cfg.dev, +- "Invalid value of median filter thresold\n"); ++ "Invalid value of median filter threshold\n"); + return -EINVAL; + } + +Index: linux-3.3.x86_64/drivers/media/video/Kconfig +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/Kconfig ++++ linux-3.3.x86_64/drivers/media/video/Kconfig +@@ -273,6 +273,16 @@ config VIDEO_ADV7180 + To compile this driver as a module, choose M here: the + module will be called adv7180. + ++config VIDEO_ADV7183 ++ tristate "Analog Devices ADV7183 decoder" ++ depends on VIDEO_V4L2 && I2C ++ ---help--- ++ V4l2 subdevice driver for the Analog Devices ++ ADV7183 video decoder. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called adv7183. ++ + config VIDEO_BT819 + tristate "BT819A VideoStream decoder" + depends on VIDEO_V4L2 && I2C +@@ -459,6 +469,9 @@ config VIDEO_AK881X + + comment "Camera sensor devices" + ++config VIDEO_APTINA_PLL ++ tristate ++ + config VIDEO_OV7670 + tristate "OmniVision OV7670 sensor support" + depends on I2C && VIDEO_V4L2 +@@ -467,9 +480,28 @@ config VIDEO_OV7670 + OV7670 VGA camera. It currently only works with the M88ALP01 + controller. + ++config VIDEO_VS6624 ++ tristate "ST VS6624 sensor support" ++ depends on VIDEO_V4L2 && I2C ++ ---help--- ++ This is a Video4Linux2 sensor-level driver for the ST VS6624 ++ camera. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called vs6624. ++ ++config VIDEO_MT9M032 ++ tristate "MT9M032 camera sensor support" ++ depends on I2C && VIDEO_V4L2 ++ select VIDEO_APTINA_PLL ++ ---help--- ++ This driver supports MT9M032 camera sensors from Aptina, monochrome ++ models only. ++ + config VIDEO_MT9P031 + tristate "Aptina MT9P031 support" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API ++ select VIDEO_APTINA_PLL + ---help--- + This is a Video4Linux2 sensor-level driver for the Aptina + (Micron) mt9p031 5 Mpixel camera. +@@ -851,6 +883,8 @@ source "drivers/media/video/davinci/Kcon + + source "drivers/media/video/omap/Kconfig" + ++source "drivers/media/video/blackfin/Kconfig" ++ + config VIDEO_SH_VOU + tristate "SuperH VOU video output driver" + depends on VIDEO_DEV && ARCH_SHMOBILE +@@ -1087,7 +1121,7 @@ config VIDEO_MX2_HOSTSUPPORT + config VIDEO_MX2 + tristate "i.MX27/i.MX25 Camera Sensor Interface driver" + depends on VIDEO_DEV && SOC_CAMERA && (MACH_MX27 || ARCH_MX25) +- select VIDEOBUF_DMA_CONTIG ++ select VIDEOBUF2_DMA_CONTIG + select VIDEO_MX2_HOSTSUPPORT + ---help--- + This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor +@@ -1116,7 +1150,8 @@ config VIDEO_ATMEL_ISI + + config VIDEO_S5P_MIPI_CSIS + tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver" +- depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P && VIDEO_V4L2_SUBDEV_API ++ depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P ++ depends on VIDEO_V4L2_SUBDEV_API && REGULATOR + ---help--- + This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver. + +@@ -1176,4 +1211,14 @@ config VIDEO_SAMSUNG_S5P_MFC + help + MFC 5.1 driver for V4L2. + ++config VIDEO_MX2_EMMAPRP ++ tristate "MX2 eMMa-PrP support" ++ depends on VIDEO_DEV && VIDEO_V4L2 && SOC_IMX27 ++ select VIDEOBUF2_DMA_CONTIG ++ select V4L2_MEM2MEM_DEV ++ help ++ MX2X chips have a PrP that can be used to process buffers from ++ memory to memory. Operations include resizing and format ++ conversion. ++ + endif # V4L_MEM2MEM_DRIVERS +Index: linux-3.3.x86_64/drivers/media/video/Makefile +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/Makefile ++++ linux-3.3.x86_64/drivers/media/video/Makefile +@@ -12,16 +12,19 @@ omap2cam-objs := omap24xxcam.o omap24xxc + + videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \ + v4l2-event.o v4l2-ctrls.o v4l2-subdev.o ++ifeq ($(CONFIG_COMPAT),y) ++ videodev-objs += v4l2-compat-ioctl32.o ++endif + + # V4L2 core modules + + obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o +-ifeq ($(CONFIG_COMPAT),y) +- obj-$(CONFIG_VIDEO_DEV) += v4l2-compat-ioctl32.o +-endif +- + obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o + ++# Helper modules ++ ++obj-$(CONFIG_VIDEO_APTINA_PLL) += aptina-pll.o ++ + # All i2c modules must come first: + + obj-$(CONFIG_VIDEO_TUNER) += tuner.o +@@ -40,8 +43,10 @@ obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o + obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o + obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o + obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o ++obj-$(CONFIG_VIDEO_ADV7183) += adv7183.o + obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o + obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o ++obj-$(CONFIG_VIDEO_VS6624) += vs6624.o + obj-$(CONFIG_VIDEO_BT819) += bt819.o + obj-$(CONFIG_VIDEO_BT856) += bt856.o + obj-$(CONFIG_VIDEO_BT866) += bt866.o +@@ -65,6 +70,7 @@ obj-$(CONFIG_VIDEO_UPD64083) += upd64083 + obj-$(CONFIG_VIDEO_OV7670) += ov7670.o + obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o + obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o ++obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o + obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o + obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o + obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o +@@ -177,6 +183,8 @@ obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_ + obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o + obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o + ++obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o ++ + obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/ + obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/ + obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/ +@@ -184,6 +192,8 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV) += s5 + + obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/ + ++obj-$(CONFIG_BLACKFIN) += blackfin/ ++ + obj-$(CONFIG_ARCH_DAVINCI) += davinci/ + + obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o +@@ -199,6 +209,6 @@ obj-y += davinci/ + + obj-$(CONFIG_ARCH_OMAP) += omap/ + +-ccflags-y += -Idrivers/media/dvb/dvb-core +-ccflags-y += -Idrivers/media/dvb/frontends +-ccflags-y += -Idrivers/media/common/tuners ++ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core ++ccflags-y += -I$(srctree)/drivers/media/dvb/frontends ++ccflags-y += -I$(srctree)/drivers/media/common/tuners +Index: linux-3.3.x86_64/drivers/media/video/mx2_emmaprp.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/video/mx2_emmaprp.c +@@ -0,0 +1,1008 @@ ++/* ++ * Support eMMa-PrP through mem2mem framework. ++ * ++ * eMMa-PrP is a piece of HW that allows fetching buffers ++ * from one memory location and do several operations on ++ * them such as scaling or format conversion giving, as a result ++ * a new processed buffer in another memory location. ++ * ++ * Based on mem2mem_testdev.c by Pawel Osciak. ++ * ++ * Copyright (c) 2011 Vista Silicon S.L. ++ * Javier Martin ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define EMMAPRP_MODULE_NAME "mem2mem-emmaprp" ++ ++MODULE_DESCRIPTION("Mem-to-mem device which supports eMMa-PrP present in mx2 SoCs"); ++MODULE_AUTHOR("Javier Martin v4l2_dev, "%s: " fmt, __func__, ## arg) ++ ++/* EMMA PrP */ ++#define PRP_CNTL 0x00 ++#define PRP_INTR_CNTL 0x04 ++#define PRP_INTRSTATUS 0x08 ++#define PRP_SOURCE_Y_PTR 0x0c ++#define PRP_SOURCE_CB_PTR 0x10 ++#define PRP_SOURCE_CR_PTR 0x14 ++#define PRP_DEST_RGB1_PTR 0x18 ++#define PRP_DEST_RGB2_PTR 0x1c ++#define PRP_DEST_Y_PTR 0x20 ++#define PRP_DEST_CB_PTR 0x24 ++#define PRP_DEST_CR_PTR 0x28 ++#define PRP_SRC_FRAME_SIZE 0x2c ++#define PRP_DEST_CH1_LINE_STRIDE 0x30 ++#define PRP_SRC_PIXEL_FORMAT_CNTL 0x34 ++#define PRP_CH1_PIXEL_FORMAT_CNTL 0x38 ++#define PRP_CH1_OUT_IMAGE_SIZE 0x3c ++#define PRP_CH2_OUT_IMAGE_SIZE 0x40 ++#define PRP_SRC_LINE_STRIDE 0x44 ++#define PRP_CSC_COEF_012 0x48 ++#define PRP_CSC_COEF_345 0x4c ++#define PRP_CSC_COEF_678 0x50 ++#define PRP_CH1_RZ_HORI_COEF1 0x54 ++#define PRP_CH1_RZ_HORI_COEF2 0x58 ++#define PRP_CH1_RZ_HORI_VALID 0x5c ++#define PRP_CH1_RZ_VERT_COEF1 0x60 ++#define PRP_CH1_RZ_VERT_COEF2 0x64 ++#define PRP_CH1_RZ_VERT_VALID 0x68 ++#define PRP_CH2_RZ_HORI_COEF1 0x6c ++#define PRP_CH2_RZ_HORI_COEF2 0x70 ++#define PRP_CH2_RZ_HORI_VALID 0x74 ++#define PRP_CH2_RZ_VERT_COEF1 0x78 ++#define PRP_CH2_RZ_VERT_COEF2 0x7c ++#define PRP_CH2_RZ_VERT_VALID 0x80 ++ ++#define PRP_CNTL_CH1EN (1 << 0) ++#define PRP_CNTL_CH2EN (1 << 1) ++#define PRP_CNTL_CSIEN (1 << 2) ++#define PRP_CNTL_DATA_IN_YUV420 (0 << 3) ++#define PRP_CNTL_DATA_IN_YUV422 (1 << 3) ++#define PRP_CNTL_DATA_IN_RGB16 (2 << 3) ++#define PRP_CNTL_DATA_IN_RGB32 (3 << 3) ++#define PRP_CNTL_CH1_OUT_RGB8 (0 << 5) ++#define PRP_CNTL_CH1_OUT_RGB16 (1 << 5) ++#define PRP_CNTL_CH1_OUT_RGB32 (2 << 5) ++#define PRP_CNTL_CH1_OUT_YUV422 (3 << 5) ++#define PRP_CNTL_CH2_OUT_YUV420 (0 << 7) ++#define PRP_CNTL_CH2_OUT_YUV422 (1 << 7) ++#define PRP_CNTL_CH2_OUT_YUV444 (2 << 7) ++#define PRP_CNTL_CH1_LEN (1 << 9) ++#define PRP_CNTL_CH2_LEN (1 << 10) ++#define PRP_CNTL_SKIP_FRAME (1 << 11) ++#define PRP_CNTL_SWRST (1 << 12) ++#define PRP_CNTL_CLKEN (1 << 13) ++#define PRP_CNTL_WEN (1 << 14) ++#define PRP_CNTL_CH1BYP (1 << 15) ++#define PRP_CNTL_IN_TSKIP(x) ((x) << 16) ++#define PRP_CNTL_CH1_TSKIP(x) ((x) << 19) ++#define PRP_CNTL_CH2_TSKIP(x) ((x) << 22) ++#define PRP_CNTL_INPUT_FIFO_LEVEL(x) ((x) << 25) ++#define PRP_CNTL_RZ_FIFO_LEVEL(x) ((x) << 27) ++#define PRP_CNTL_CH2B1EN (1 << 29) ++#define PRP_CNTL_CH2B2EN (1 << 30) ++#define PRP_CNTL_CH2FEN (1 << 31) ++ ++#define PRP_SIZE_HEIGHT(x) (x) ++#define PRP_SIZE_WIDTH(x) ((x) << 16) ++ ++/* IRQ Enable and status register */ ++#define PRP_INTR_RDERR (1 << 0) ++#define PRP_INTR_CH1WERR (1 << 1) ++#define PRP_INTR_CH2WERR (1 << 2) ++#define PRP_INTR_CH1FC (1 << 3) ++#define PRP_INTR_CH2FC (1 << 5) ++#define PRP_INTR_LBOVF (1 << 7) ++#define PRP_INTR_CH2OVF (1 << 8) ++ ++#define PRP_INTR_ST_RDERR (1 << 0) ++#define PRP_INTR_ST_CH1WERR (1 << 1) ++#define PRP_INTR_ST_CH2WERR (1 << 2) ++#define PRP_INTR_ST_CH2B2CI (1 << 3) ++#define PRP_INTR_ST_CH2B1CI (1 << 4) ++#define PRP_INTR_ST_CH1B2CI (1 << 5) ++#define PRP_INTR_ST_CH1B1CI (1 << 6) ++#define PRP_INTR_ST_LBOVF (1 << 7) ++#define PRP_INTR_ST_CH2OVF (1 << 8) ++ ++struct emmaprp_fmt { ++ char *name; ++ u32 fourcc; ++ /* Types the format can be used for */ ++ u32 types; ++}; ++ ++static struct emmaprp_fmt formats[] = { ++ { ++ .name = "YUV 4:2:0 Planar", ++ .fourcc = V4L2_PIX_FMT_YUV420, ++ .types = MEM2MEM_CAPTURE, ++ }, ++ { ++ .name = "4:2:2, packed, YUYV", ++ .fourcc = V4L2_PIX_FMT_YUYV, ++ .types = MEM2MEM_OUTPUT, ++ }, ++}; ++ ++/* Per-queue, driver-specific private data */ ++struct emmaprp_q_data { ++ unsigned int width; ++ unsigned int height; ++ unsigned int sizeimage; ++ struct emmaprp_fmt *fmt; ++}; ++ ++enum { ++ V4L2_M2M_SRC = 0, ++ V4L2_M2M_DST = 1, ++}; ++ ++#define NUM_FORMATS ARRAY_SIZE(formats) ++ ++static struct emmaprp_fmt *find_format(struct v4l2_format *f) ++{ ++ struct emmaprp_fmt *fmt; ++ unsigned int k; ++ ++ for (k = 0; k < NUM_FORMATS; k++) { ++ fmt = &formats[k]; ++ if (fmt->fourcc == f->fmt.pix.pixelformat) ++ break; ++ } ++ ++ if (k == NUM_FORMATS) ++ return NULL; ++ ++ return &formats[k]; ++} ++ ++struct emmaprp_dev { ++ struct v4l2_device v4l2_dev; ++ struct video_device *vfd; ++ ++ struct mutex dev_mutex; ++ spinlock_t irqlock; ++ ++ int irq_emma; ++ void __iomem *base_emma; ++ struct clk *clk_emma; ++ struct resource *res_emma; ++ ++ struct v4l2_m2m_dev *m2m_dev; ++ struct vb2_alloc_ctx *alloc_ctx; ++}; ++ ++struct emmaprp_ctx { ++ struct emmaprp_dev *dev; ++ /* Abort requested by m2m */ ++ int aborting; ++ struct emmaprp_q_data q_data[2]; ++ struct v4l2_m2m_ctx *m2m_ctx; ++}; ++ ++static struct emmaprp_q_data *get_q_data(struct emmaprp_ctx *ctx, ++ enum v4l2_buf_type type) ++{ ++ switch (type) { ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ return &(ctx->q_data[V4L2_M2M_SRC]); ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ return &(ctx->q_data[V4L2_M2M_DST]); ++ default: ++ BUG(); ++ } ++ return NULL; ++} ++ ++/* ++ * mem2mem callbacks ++ */ ++static void emmaprp_job_abort(void *priv) ++{ ++ struct emmaprp_ctx *ctx = priv; ++ struct emmaprp_dev *pcdev = ctx->dev; ++ ++ ctx->aborting = 1; ++ ++ dprintk(pcdev, "Aborting task\n"); ++ ++ v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx); ++} ++ ++static void emmaprp_lock(void *priv) ++{ ++ struct emmaprp_ctx *ctx = priv; ++ struct emmaprp_dev *pcdev = ctx->dev; ++ mutex_lock(&pcdev->dev_mutex); ++} ++ ++static void emmaprp_unlock(void *priv) ++{ ++ struct emmaprp_ctx *ctx = priv; ++ struct emmaprp_dev *pcdev = ctx->dev; ++ mutex_unlock(&pcdev->dev_mutex); ++} ++ ++static inline void emmaprp_dump_regs(struct emmaprp_dev *pcdev) ++{ ++ dprintk(pcdev, ++ "eMMa-PrP Registers:\n" ++ " SOURCE_Y_PTR = 0x%08X\n" ++ " SRC_FRAME_SIZE = 0x%08X\n" ++ " DEST_Y_PTR = 0x%08X\n" ++ " DEST_CR_PTR = 0x%08X\n" ++ " DEST_CB_PTR = 0x%08X\n" ++ " CH2_OUT_IMAGE_SIZE = 0x%08X\n" ++ " CNTL = 0x%08X\n", ++ readl(pcdev->base_emma + PRP_SOURCE_Y_PTR), ++ readl(pcdev->base_emma + PRP_SRC_FRAME_SIZE), ++ readl(pcdev->base_emma + PRP_DEST_Y_PTR), ++ readl(pcdev->base_emma + PRP_DEST_CR_PTR), ++ readl(pcdev->base_emma + PRP_DEST_CB_PTR), ++ readl(pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE), ++ readl(pcdev->base_emma + PRP_CNTL)); ++} ++ ++static void emmaprp_device_run(void *priv) ++{ ++ struct emmaprp_ctx *ctx = priv; ++ struct emmaprp_q_data *s_q_data, *d_q_data; ++ struct vb2_buffer *src_buf, *dst_buf; ++ struct emmaprp_dev *pcdev = ctx->dev; ++ unsigned int s_width, s_height; ++ unsigned int d_width, d_height; ++ unsigned int d_size; ++ dma_addr_t p_in, p_out; ++ u32 tmp; ++ ++ src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); ++ dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); ++ ++ s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); ++ s_width = s_q_data->width; ++ s_height = s_q_data->height; ++ ++ d_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); ++ d_width = d_q_data->width; ++ d_height = d_q_data->height; ++ d_size = d_width * d_height; ++ ++ p_in = vb2_dma_contig_plane_dma_addr(src_buf, 0); ++ p_out = vb2_dma_contig_plane_dma_addr(dst_buf, 0); ++ if (!p_in || !p_out) { ++ v4l2_err(&pcdev->v4l2_dev, ++ "Acquiring kernel pointers to buffers failed\n"); ++ return; ++ } ++ ++ /* Input frame parameters */ ++ writel(p_in, pcdev->base_emma + PRP_SOURCE_Y_PTR); ++ writel(PRP_SIZE_WIDTH(s_width) | PRP_SIZE_HEIGHT(s_height), ++ pcdev->base_emma + PRP_SRC_FRAME_SIZE); ++ ++ /* Output frame parameters */ ++ writel(p_out, pcdev->base_emma + PRP_DEST_Y_PTR); ++ writel(p_out + d_size, pcdev->base_emma + PRP_DEST_CB_PTR); ++ writel(p_out + d_size + (d_size >> 2), ++ pcdev->base_emma + PRP_DEST_CR_PTR); ++ writel(PRP_SIZE_WIDTH(d_width) | PRP_SIZE_HEIGHT(d_height), ++ pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE); ++ ++ /* IRQ configuration */ ++ tmp = readl(pcdev->base_emma + PRP_INTR_CNTL); ++ writel(tmp | PRP_INTR_RDERR | ++ PRP_INTR_CH2WERR | ++ PRP_INTR_CH2FC, ++ pcdev->base_emma + PRP_INTR_CNTL); ++ ++ emmaprp_dump_regs(pcdev); ++ ++ /* Enable transfer */ ++ tmp = readl(pcdev->base_emma + PRP_CNTL); ++ writel(tmp | PRP_CNTL_CH2_OUT_YUV420 | ++ PRP_CNTL_DATA_IN_YUV422 | ++ PRP_CNTL_CH2EN, ++ pcdev->base_emma + PRP_CNTL); ++} ++ ++static irqreturn_t emmaprp_irq(int irq_emma, void *data) ++{ ++ struct emmaprp_dev *pcdev = data; ++ struct emmaprp_ctx *curr_ctx; ++ struct vb2_buffer *src_vb, *dst_vb; ++ unsigned long flags; ++ u32 irqst; ++ ++ /* Check irq flags and clear irq */ ++ irqst = readl(pcdev->base_emma + PRP_INTRSTATUS); ++ writel(irqst, pcdev->base_emma + PRP_INTRSTATUS); ++ dprintk(pcdev, "irqst = 0x%08x\n", irqst); ++ ++ curr_ctx = v4l2_m2m_get_curr_priv(pcdev->m2m_dev); ++ if (curr_ctx == NULL) { ++ pr_err("Instance released before the end of transaction\n"); ++ return IRQ_HANDLED; ++ } ++ ++ if (!curr_ctx->aborting) { ++ if ((irqst & PRP_INTR_ST_RDERR) || ++ (irqst & PRP_INTR_ST_CH2WERR)) { ++ pr_err("PrP bus error ocurred, this transfer is probably corrupted\n"); ++ writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL); ++ } else if (irqst & PRP_INTR_ST_CH2B1CI) { /* buffer ready */ ++ src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); ++ dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); ++ ++ spin_lock_irqsave(&pcdev->irqlock, flags); ++ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); ++ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); ++ spin_unlock_irqrestore(&pcdev->irqlock, flags); ++ } ++ } ++ ++ v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx); ++ return IRQ_HANDLED; ++} ++ ++/* ++ * video ioctls ++ */ ++static int vidioc_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1); ++ strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); ++ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT ++ | V4L2_CAP_STREAMING; ++ ++ return 0; ++} ++ ++static int enum_fmt(struct v4l2_fmtdesc *f, u32 type) ++{ ++ int i, num; ++ struct emmaprp_fmt *fmt; ++ ++ num = 0; ++ ++ for (i = 0; i < NUM_FORMATS; ++i) { ++ if (formats[i].types & type) { ++ /* index-th format of type type found ? */ ++ if (num == f->index) ++ break; ++ /* Correct type but haven't reached our index yet, ++ * just increment per-type index */ ++ ++num; ++ } ++ } ++ ++ if (i < NUM_FORMATS) { ++ /* Format found */ ++ fmt = &formats[i]; ++ strlcpy(f->description, fmt->name, sizeof(f->description) - 1); ++ f->pixelformat = fmt->fourcc; ++ return 0; ++ } ++ ++ /* Format not found */ ++ return -EINVAL; ++} ++ ++static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ return enum_fmt(f, MEM2MEM_CAPTURE); ++} ++ ++static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ return enum_fmt(f, MEM2MEM_OUTPUT); ++} ++ ++static int vidioc_g_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f) ++{ ++ struct vb2_queue *vq; ++ struct emmaprp_q_data *q_data; ++ ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if (!vq) ++ return -EINVAL; ++ ++ q_data = get_q_data(ctx, f->type); ++ ++ f->fmt.pix.width = q_data->width; ++ f->fmt.pix.height = q_data->height; ++ f->fmt.pix.field = V4L2_FIELD_NONE; ++ f->fmt.pix.pixelformat = q_data->fmt->fourcc; ++ if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) ++ f->fmt.pix.bytesperline = q_data->width * 3 / 2; ++ else /* YUYV */ ++ f->fmt.pix.bytesperline = q_data->width * 2; ++ f->fmt.pix.sizeimage = q_data->sizeimage; ++ ++ return 0; ++} ++ ++static int vidioc_g_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ return vidioc_g_fmt(priv, f); ++} ++ ++static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ return vidioc_g_fmt(priv, f); ++} ++ ++static int vidioc_try_fmt(struct v4l2_format *f) ++{ ++ enum v4l2_field field; ++ ++ ++ if (!find_format(f)) ++ return -EINVAL; ++ ++ field = f->fmt.pix.field; ++ if (field == V4L2_FIELD_ANY) ++ field = V4L2_FIELD_NONE; ++ else if (V4L2_FIELD_NONE != field) ++ return -EINVAL; ++ ++ /* V4L2 specification suggests the driver corrects the format struct ++ * if any of the dimensions is unsupported */ ++ f->fmt.pix.field = field; ++ ++ if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) { ++ v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W, ++ W_ALIGN_YUV420, &f->fmt.pix.height, ++ MIN_H, MAX_H, H_ALIGN, S_ALIGN); ++ f->fmt.pix.bytesperline = f->fmt.pix.width * 3 / 2; ++ } else { ++ v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W, ++ W_ALIGN_OTHERS, &f->fmt.pix.height, ++ MIN_H, MAX_H, H_ALIGN, S_ALIGN); ++ f->fmt.pix.bytesperline = f->fmt.pix.width * 2; ++ } ++ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; ++ ++ return 0; ++} ++ ++static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct emmaprp_fmt *fmt; ++ struct emmaprp_ctx *ctx = priv; ++ ++ fmt = find_format(f); ++ if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) { ++ v4l2_err(&ctx->dev->v4l2_dev, ++ "Fourcc format (0x%08x) invalid.\n", ++ f->fmt.pix.pixelformat); ++ return -EINVAL; ++ } ++ ++ return vidioc_try_fmt(f); ++} ++ ++static int vidioc_try_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct emmaprp_fmt *fmt; ++ struct emmaprp_ctx *ctx = priv; ++ ++ fmt = find_format(f); ++ if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) { ++ v4l2_err(&ctx->dev->v4l2_dev, ++ "Fourcc format (0x%08x) invalid.\n", ++ f->fmt.pix.pixelformat); ++ return -EINVAL; ++ } ++ ++ return vidioc_try_fmt(f); ++} ++ ++static int vidioc_s_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f) ++{ ++ struct emmaprp_q_data *q_data; ++ struct vb2_queue *vq; ++ int ret; ++ ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if (!vq) ++ return -EINVAL; ++ ++ q_data = get_q_data(ctx, f->type); ++ if (!q_data) ++ return -EINVAL; ++ ++ if (vb2_is_busy(vq)) { ++ v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__); ++ return -EBUSY; ++ } ++ ++ ret = vidioc_try_fmt(f); ++ if (ret) ++ return ret; ++ ++ q_data->fmt = find_format(f); ++ q_data->width = f->fmt.pix.width; ++ q_data->height = f->fmt.pix.height; ++ if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420) ++ q_data->sizeimage = q_data->width * q_data->height * 3 / 2; ++ else /* YUYV */ ++ q_data->sizeimage = q_data->width * q_data->height * 2; ++ ++ dprintk(ctx->dev, ++ "Setting format for type %d, wxh: %dx%d, fmt: %d\n", ++ f->type, q_data->width, q_data->height, q_data->fmt->fourcc); ++ ++ return 0; ++} ++ ++static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ int ret; ++ ++ ret = vidioc_try_fmt_vid_cap(file, priv, f); ++ if (ret) ++ return ret; ++ ++ return vidioc_s_fmt(priv, f); ++} ++ ++static int vidioc_s_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ int ret; ++ ++ ret = vidioc_try_fmt_vid_out(file, priv, f); ++ if (ret) ++ return ret; ++ ++ return vidioc_s_fmt(priv, f); ++} ++ ++static int vidioc_reqbufs(struct file *file, void *priv, ++ struct v4l2_requestbuffers *reqbufs) ++{ ++ struct emmaprp_ctx *ctx = priv; ++ ++ return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); ++} ++ ++static int vidioc_querybuf(struct file *file, void *priv, ++ struct v4l2_buffer *buf) ++{ ++ struct emmaprp_ctx *ctx = priv; ++ ++ return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); ++} ++ ++static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) ++{ ++ struct emmaprp_ctx *ctx = priv; ++ ++ return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); ++} ++ ++static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) ++{ ++ struct emmaprp_ctx *ctx = priv; ++ ++ return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); ++} ++ ++static int vidioc_streamon(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct emmaprp_ctx *ctx = priv; ++ ++ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); ++} ++ ++static int vidioc_streamoff(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct emmaprp_ctx *ctx = priv; ++ ++ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); ++} ++ ++static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = { ++ .vidioc_querycap = vidioc_querycap, ++ ++ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, ++ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, ++ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, ++ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, ++ ++ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, ++ .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, ++ .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, ++ .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, ++ ++ .vidioc_reqbufs = vidioc_reqbufs, ++ .vidioc_querybuf = vidioc_querybuf, ++ ++ .vidioc_qbuf = vidioc_qbuf, ++ .vidioc_dqbuf = vidioc_dqbuf, ++ ++ .vidioc_streamon = vidioc_streamon, ++ .vidioc_streamoff = vidioc_streamoff, ++}; ++ ++ ++/* ++ * Queue operations ++ */ ++static int emmaprp_queue_setup(struct vb2_queue *vq, ++ const struct v4l2_format *fmt, ++ unsigned int *nbuffers, unsigned int *nplanes, ++ unsigned int sizes[], void *alloc_ctxs[]) ++{ ++ struct emmaprp_ctx *ctx = vb2_get_drv_priv(vq); ++ struct emmaprp_q_data *q_data; ++ unsigned int size, count = *nbuffers; ++ ++ q_data = get_q_data(ctx, vq->type); ++ ++ if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420) ++ size = q_data->width * q_data->height * 3 / 2; ++ else ++ size = q_data->width * q_data->height * 2; ++ ++ while (size * count > MEM2MEM_VID_MEM_LIMIT) ++ (count)--; ++ ++ *nplanes = 1; ++ *nbuffers = count; ++ sizes[0] = size; ++ ++ alloc_ctxs[0] = ctx->dev->alloc_ctx; ++ ++ dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size); ++ ++ return 0; ++} ++ ++static int emmaprp_buf_prepare(struct vb2_buffer *vb) ++{ ++ struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct emmaprp_q_data *q_data; ++ ++ dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type); ++ ++ q_data = get_q_data(ctx, vb->vb2_queue->type); ++ ++ if (vb2_plane_size(vb, 0) < q_data->sizeimage) { ++ dprintk(ctx->dev, "%s data will not fit into plane" ++ "(%lu < %lu)\n", __func__, ++ vb2_plane_size(vb, 0), ++ (long)q_data->sizeimage); ++ return -EINVAL; ++ } ++ ++ vb2_set_plane_payload(vb, 0, q_data->sizeimage); ++ ++ return 0; ++} ++ ++static void emmaprp_buf_queue(struct vb2_buffer *vb) ++{ ++ struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); ++} ++ ++static struct vb2_ops emmaprp_qops = { ++ .queue_setup = emmaprp_queue_setup, ++ .buf_prepare = emmaprp_buf_prepare, ++ .buf_queue = emmaprp_buf_queue, ++}; ++ ++static int queue_init(void *priv, struct vb2_queue *src_vq, ++ struct vb2_queue *dst_vq) ++{ ++ struct emmaprp_ctx *ctx = priv; ++ int ret; ++ ++ memset(src_vq, 0, sizeof(*src_vq)); ++ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ src_vq->io_modes = VB2_MMAP; ++ src_vq->drv_priv = ctx; ++ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); ++ src_vq->ops = &emmaprp_qops; ++ src_vq->mem_ops = &vb2_dma_contig_memops; ++ ++ ret = vb2_queue_init(src_vq); ++ if (ret) ++ return ret; ++ ++ memset(dst_vq, 0, sizeof(*dst_vq)); ++ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ dst_vq->io_modes = VB2_MMAP; ++ dst_vq->drv_priv = ctx; ++ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); ++ dst_vq->ops = &emmaprp_qops; ++ dst_vq->mem_ops = &vb2_dma_contig_memops; ++ ++ return vb2_queue_init(dst_vq); ++} ++ ++/* ++ * File operations ++ */ ++static int emmaprp_open(struct file *file) ++{ ++ struct emmaprp_dev *pcdev = video_drvdata(file); ++ struct emmaprp_ctx *ctx; ++ ++ ctx = kzalloc(sizeof *ctx, GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; ++ ++ file->private_data = ctx; ++ ctx->dev = pcdev; ++ ++ ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init); ++ ++ if (IS_ERR(ctx->m2m_ctx)) { ++ int ret = PTR_ERR(ctx->m2m_ctx); ++ ++ kfree(ctx); ++ return ret; ++ } ++ ++ clk_enable(pcdev->clk_emma); ++ ctx->q_data[V4L2_M2M_SRC].fmt = &formats[1]; ++ ctx->q_data[V4L2_M2M_DST].fmt = &formats[0]; ++ ++ dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx); ++ ++ return 0; ++} ++ ++static int emmaprp_release(struct file *file) ++{ ++ struct emmaprp_dev *pcdev = video_drvdata(file); ++ struct emmaprp_ctx *ctx = file->private_data; ++ ++ dprintk(pcdev, "Releasing instance %p\n", ctx); ++ ++ clk_disable(pcdev->clk_emma); ++ v4l2_m2m_ctx_release(ctx->m2m_ctx); ++ kfree(ctx); ++ ++ return 0; ++} ++ ++static unsigned int emmaprp_poll(struct file *file, ++ struct poll_table_struct *wait) ++{ ++ struct emmaprp_ctx *ctx = file->private_data; ++ ++ return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); ++} ++ ++static int emmaprp_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ struct emmaprp_ctx *ctx = file->private_data; ++ ++ return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); ++} ++ ++static const struct v4l2_file_operations emmaprp_fops = { ++ .owner = THIS_MODULE, ++ .open = emmaprp_open, ++ .release = emmaprp_release, ++ .poll = emmaprp_poll, ++ .unlocked_ioctl = video_ioctl2, ++ .mmap = emmaprp_mmap, ++}; ++ ++static struct video_device emmaprp_videodev = { ++ .name = MEM2MEM_NAME, ++ .fops = &emmaprp_fops, ++ .ioctl_ops = &emmaprp_ioctl_ops, ++ .minor = -1, ++ .release = video_device_release, ++}; ++ ++static struct v4l2_m2m_ops m2m_ops = { ++ .device_run = emmaprp_device_run, ++ .job_abort = emmaprp_job_abort, ++ .lock = emmaprp_lock, ++ .unlock = emmaprp_unlock, ++}; ++ ++static int emmaprp_probe(struct platform_device *pdev) ++{ ++ struct emmaprp_dev *pcdev; ++ struct video_device *vfd; ++ struct resource *res_emma; ++ int irq_emma; ++ int ret; ++ ++ pcdev = kzalloc(sizeof *pcdev, GFP_KERNEL); ++ if (!pcdev) ++ return -ENOMEM; ++ ++ spin_lock_init(&pcdev->irqlock); ++ ++ pcdev->clk_emma = clk_get(&pdev->dev, NULL); ++ if (IS_ERR(pcdev->clk_emma)) { ++ ret = PTR_ERR(pcdev->clk_emma); ++ goto free_dev; ++ } ++ ++ irq_emma = platform_get_irq(pdev, 0); ++ res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (irq_emma < 0 || res_emma == NULL) { ++ dev_err(&pdev->dev, "Missing platform resources data\n"); ++ ret = -ENODEV; ++ goto free_clk; ++ } ++ ++ ret = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev); ++ if (ret) ++ goto free_clk; ++ ++ mutex_init(&pcdev->dev_mutex); ++ ++ vfd = video_device_alloc(); ++ if (!vfd) { ++ v4l2_err(&pcdev->v4l2_dev, "Failed to allocate video device\n"); ++ ret = -ENOMEM; ++ goto unreg_dev; ++ } ++ ++ *vfd = emmaprp_videodev; ++ vfd->lock = &pcdev->dev_mutex; ++ ++ video_set_drvdata(vfd, pcdev); ++ snprintf(vfd->name, sizeof(vfd->name), "%s", emmaprp_videodev.name); ++ pcdev->vfd = vfd; ++ v4l2_info(&pcdev->v4l2_dev, EMMAPRP_MODULE_NAME ++ " Device registered as /dev/video%d\n", vfd->num); ++ ++ platform_set_drvdata(pdev, pcdev); ++ ++ if (devm_request_mem_region(&pdev->dev, res_emma->start, ++ resource_size(res_emma), MEM2MEM_NAME) == NULL) ++ goto rel_vdev; ++ ++ pcdev->base_emma = devm_ioremap(&pdev->dev, res_emma->start, ++ resource_size(res_emma)); ++ if (!pcdev->base_emma) ++ goto rel_vdev; ++ ++ pcdev->irq_emma = irq_emma; ++ pcdev->res_emma = res_emma; ++ ++ if (devm_request_irq(&pdev->dev, pcdev->irq_emma, emmaprp_irq, ++ 0, MEM2MEM_NAME, pcdev) < 0) ++ goto rel_vdev; ++ ++ pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); ++ if (IS_ERR(pcdev->alloc_ctx)) { ++ v4l2_err(&pcdev->v4l2_dev, "Failed to alloc vb2 context\n"); ++ ret = PTR_ERR(pcdev->alloc_ctx); ++ goto rel_vdev; ++ } ++ ++ pcdev->m2m_dev = v4l2_m2m_init(&m2m_ops); ++ if (IS_ERR(pcdev->m2m_dev)) { ++ v4l2_err(&pcdev->v4l2_dev, "Failed to init mem2mem device\n"); ++ ret = PTR_ERR(pcdev->m2m_dev); ++ goto rel_ctx; ++ } ++ ++ ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); ++ if (ret) { ++ v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n"); ++ goto rel_m2m; ++ } ++ ++ return 0; ++ ++ ++rel_m2m: ++ v4l2_m2m_release(pcdev->m2m_dev); ++rel_ctx: ++ vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); ++rel_vdev: ++ video_device_release(vfd); ++unreg_dev: ++ v4l2_device_unregister(&pcdev->v4l2_dev); ++free_clk: ++ clk_put(pcdev->clk_emma); ++free_dev: ++ kfree(pcdev); ++ ++ return ret; ++} ++ ++static int emmaprp_remove(struct platform_device *pdev) ++{ ++ struct emmaprp_dev *pcdev = platform_get_drvdata(pdev); ++ ++ v4l2_info(&pcdev->v4l2_dev, "Removing " EMMAPRP_MODULE_NAME); ++ ++ video_unregister_device(pcdev->vfd); ++ v4l2_m2m_release(pcdev->m2m_dev); ++ vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); ++ v4l2_device_unregister(&pcdev->v4l2_dev); ++ clk_put(pcdev->clk_emma); ++ kfree(pcdev); ++ ++ return 0; ++} ++ ++static struct platform_driver emmaprp_pdrv = { ++ .probe = emmaprp_probe, ++ .remove = emmaprp_remove, ++ .driver = { ++ .name = MEM2MEM_NAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static void __exit emmaprp_exit(void) ++{ ++ platform_driver_unregister(&emmaprp_pdrv); ++} ++ ++static int __init emmaprp_init(void) ++{ ++ return platform_driver_register(&emmaprp_pdrv); ++} ++ ++module_init(emmaprp_init); ++module_exit(emmaprp_exit); +Index: linux-3.3.x86_64/drivers/media/common/tuners/mt2063.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/common/tuners/mt2063.h ++++ linux-3.3.x86_64/drivers/media/common/tuners/mt2063.h +@@ -23,10 +23,6 @@ static inline struct dvb_frontend *mt206 + return NULL; + } + +-int mt2063_setTune(struct dvb_frontend *fe, u32 f_in, +- u32 bw_in, +- enum MTTune_atv_standard tv_type); +- + /* FIXME: Should use the standard DVB attachment interfaces */ + unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe); + unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe); +Index: linux-3.3.x86_64/drivers/media/video/s5p-tv/sdo_drv.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s5p-tv/sdo_drv.c ++++ linux-3.3.x86_64/drivers/media/video/s5p-tv/sdo_drv.c +@@ -301,7 +301,7 @@ static int __devinit sdo_probe(struct pl + struct clk *sclk_vpll; + + dev_info(dev, "probe start\n"); +- sdev = kzalloc(sizeof *sdev, GFP_KERNEL); ++ sdev = devm_kzalloc(&pdev->dev, sizeof *sdev, GFP_KERNEL); + if (!sdev) { + dev_err(dev, "not enough memory.\n"); + ret = -ENOMEM; +@@ -314,14 +314,14 @@ static int __devinit sdo_probe(struct pl + if (res == NULL) { + dev_err(dev, "get memory resource failed.\n"); + ret = -ENXIO; +- goto fail_sdev; ++ goto fail; + } + +- sdev->regs = ioremap(res->start, resource_size(res)); ++ sdev->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (sdev->regs == NULL) { + dev_err(dev, "register mapping failed.\n"); + ret = -ENXIO; +- goto fail_sdev; ++ goto fail; + } + + /* acquiring interrupt */ +@@ -329,12 +329,13 @@ static int __devinit sdo_probe(struct pl + if (res == NULL) { + dev_err(dev, "get interrupt resource failed.\n"); + ret = -ENXIO; +- goto fail_regs; ++ goto fail; + } +- ret = request_irq(res->start, sdo_irq_handler, 0, "s5p-sdo", sdev); ++ ret = devm_request_irq(&pdev->dev, res->start, sdo_irq_handler, 0, ++ "s5p-sdo", sdev); + if (ret) { + dev_err(dev, "request interrupt failed.\n"); +- goto fail_regs; ++ goto fail; + } + sdev->irq = res->start; + +@@ -343,7 +344,7 @@ static int __devinit sdo_probe(struct pl + if (IS_ERR_OR_NULL(sdev->sclk_dac)) { + dev_err(dev, "failed to get clock 'sclk_dac'\n"); + ret = -ENXIO; +- goto fail_irq; ++ goto fail; + } + sdev->dac = clk_get(dev, "dac"); + if (IS_ERR_OR_NULL(sdev->dac)) { +@@ -415,12 +416,6 @@ fail_dac: + clk_put(sdev->dac); + fail_sclk_dac: + clk_put(sdev->sclk_dac); +-fail_irq: +- free_irq(sdev->irq, sdev); +-fail_regs: +- iounmap(sdev->regs); +-fail_sdev: +- kfree(sdev); + fail: + dev_info(dev, "probe failed\n"); + return ret; +@@ -439,9 +434,6 @@ static int __devexit sdo_remove(struct p + clk_put(sdev->dacphy); + clk_put(sdev->dac); + clk_put(sdev->sclk_dac); +- free_irq(sdev->irq, sdev); +- iounmap(sdev->regs); +- kfree(sdev); + + dev_info(&pdev->dev, "remove successful\n"); + return 0; +Index: linux-3.3.x86_64/drivers/media/video/s5p-tv/Kconfig +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s5p-tv/Kconfig ++++ linux-3.3.x86_64/drivers/media/video/s5p-tv/Kconfig +@@ -46,6 +46,16 @@ config VIDEO_SAMSUNG_S5P_HDMIPHY + as module. It is an I2C driver, that exposes a V4L2 + subdev for use by other drivers. + ++config VIDEO_SAMSUNG_S5P_SII9234 ++ tristate "Samsung SII9234 Driver" ++ depends on VIDEO_DEV && VIDEO_V4L2 && I2C ++ depends on VIDEO_SAMSUNG_S5P_TV ++ help ++ Say Y here if you want support for the MHL interface ++ in S5P Samsung SoC. The driver can be compiled ++ as module. It is an I2C driver, that exposes a V4L2 ++ subdev for use by other drivers. ++ + config VIDEO_SAMSUNG_S5P_SDO + tristate "Samsung Analog TV Driver" + depends on VIDEO_DEV && VIDEO_V4L2 +Index: linux-3.3.x86_64/drivers/media/video/s5p-tv/Makefile +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s5p-tv/Makefile ++++ linux-3.3.x86_64/drivers/media/video/s5p-tv/Makefile +@@ -8,6 +8,8 @@ + + obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMIPHY) += s5p-hdmiphy.o + s5p-hdmiphy-y += hdmiphy_drv.o ++obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SII9234) += s5p-sii9234.o ++s5p-sii9234-y += sii9234_drv.o + obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMI) += s5p-hdmi.o + s5p-hdmi-y += hdmi_drv.o + obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SDO) += s5p-sdo.o +Index: linux-3.3.x86_64/drivers/media/video/s5p-tv/sii9234_drv.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/video/s5p-tv/sii9234_drv.c +@@ -0,0 +1,432 @@ ++/* ++ * Samsung MHL interface driver ++ * ++ * Copyright (C) 2011 Samsung Electronics Co.Ltd ++ * Author: Tomasz Stanislawski ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++MODULE_AUTHOR("Tomasz Stanislawski "); ++MODULE_DESCRIPTION("Samsung MHL interface driver"); ++MODULE_LICENSE("GPL"); ++ ++struct sii9234_context { ++ struct i2c_client *client; ++ struct regulator *power; ++ int gpio_n_reset; ++ struct v4l2_subdev sd; ++}; ++ ++static inline struct sii9234_context *sd_to_context(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct sii9234_context, sd); ++} ++ ++static inline int sii9234_readb(struct i2c_client *client, int addr) ++{ ++ return i2c_smbus_read_byte_data(client, addr); ++} ++ ++static inline int sii9234_writeb(struct i2c_client *client, int addr, int value) ++{ ++ return i2c_smbus_write_byte_data(client, addr, value); ++} ++ ++static inline int sii9234_writeb_mask(struct i2c_client *client, int addr, ++ int value, int mask) ++{ ++ int ret; ++ ++ ret = i2c_smbus_read_byte_data(client, addr); ++ if (ret < 0) ++ return ret; ++ ret = (ret & ~mask) | (value & mask); ++ return i2c_smbus_write_byte_data(client, addr, ret); ++} ++ ++static inline int sii9234_readb_idx(struct i2c_client *client, int addr) ++{ ++ int ret; ++ ret = i2c_smbus_write_byte_data(client, 0xbc, addr >> 8); ++ if (ret < 0) ++ return ret; ++ ret = i2c_smbus_write_byte_data(client, 0xbd, addr & 0xff); ++ if (ret < 0) ++ return ret; ++ return i2c_smbus_read_byte_data(client, 0xbe); ++} ++ ++static inline int sii9234_writeb_idx(struct i2c_client *client, int addr, ++ int value) ++{ ++ int ret; ++ ret = i2c_smbus_write_byte_data(client, 0xbc, addr >> 8); ++ if (ret < 0) ++ return ret; ++ ret = i2c_smbus_write_byte_data(client, 0xbd, addr & 0xff); ++ if (ret < 0) ++ return ret; ++ ret = i2c_smbus_write_byte_data(client, 0xbe, value); ++ return ret; ++} ++ ++static inline int sii9234_writeb_idx_mask(struct i2c_client *client, int addr, ++ int value, int mask) ++{ ++ int ret; ++ ++ ret = sii9234_readb_idx(client, addr); ++ if (ret < 0) ++ return ret; ++ ret = (ret & ~mask) | (value & mask); ++ return sii9234_writeb_idx(client, addr, ret); ++} ++ ++static int sii9234_reset(struct sii9234_context *ctx) ++{ ++ struct i2c_client *client = ctx->client; ++ struct device *dev = &client->dev; ++ int ret, tries; ++ ++ gpio_direction_output(ctx->gpio_n_reset, 1); ++ mdelay(1); ++ gpio_direction_output(ctx->gpio_n_reset, 0); ++ mdelay(1); ++ gpio_direction_output(ctx->gpio_n_reset, 1); ++ mdelay(1); ++ ++ /* going to TTPI mode */ ++ ret = sii9234_writeb(client, 0xc7, 0); ++ if (ret < 0) { ++ dev_err(dev, "failed to set TTPI mode\n"); ++ return ret; ++ } ++ for (tries = 0; tries < 100 ; ++tries) { ++ ret = sii9234_readb(client, 0x1b); ++ if (ret > 0) ++ break; ++ if (ret < 0) { ++ dev_err(dev, "failed to reset device\n"); ++ return -EIO; ++ } ++ mdelay(1); ++ } ++ if (tries == 100) { ++ dev_err(dev, "maximal number of tries reached\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int sii9234_verify_version(struct i2c_client *client) ++{ ++ struct device *dev = &client->dev; ++ int family, rev, tpi_rev, dev_id, sub_id, hdcp, id; ++ ++ family = sii9234_readb(client, 0x1b); ++ rev = sii9234_readb(client, 0x1c) & 0x0f; ++ tpi_rev = sii9234_readb(client, 0x1d) & 0x7f; ++ dev_id = sii9234_readb_idx(client, 0x0103); ++ sub_id = sii9234_readb_idx(client, 0x0102); ++ hdcp = sii9234_readb(client, 0x30); ++ ++ if (family < 0 || rev < 0 || tpi_rev < 0 || dev_id < 0 || ++ sub_id < 0 || hdcp < 0) { ++ dev_err(dev, "failed to read chip's version\n"); ++ return -EIO; ++ } ++ ++ id = (dev_id << 8) | sub_id; ++ ++ dev_info(dev, "chip: SiL%02x family: %02x, rev: %02x\n", ++ id, family, rev); ++ dev_info(dev, "tpi_rev:%02x, hdcp: %02x\n", tpi_rev, hdcp); ++ if (id != 0x9234) { ++ dev_err(dev, "not supported chip\n"); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static u8 data[][3] = { ++/* setup from driver created by doonsoo45.kim */ ++ { 0x01, 0x05, 0x04 }, /* Enable Auto soft reset on SCDT = 0 */ ++ { 0x01, 0x08, 0x35 }, /* Power Up TMDS Tx Core */ ++ { 0x01, 0x0d, 0x1c }, /* HDMI Transcode mode enable */ ++ { 0x01, 0x2b, 0x01 }, /* Enable HDCP Compliance workaround */ ++ { 0x01, 0x79, 0x40 }, /* daniel test...MHL_INT */ ++ { 0x01, 0x80, 0x34 }, /* Enable Rx PLL Clock Value */ ++ { 0x01, 0x90, 0x27 }, /* Enable CBUS discovery */ ++ { 0x01, 0x91, 0xe5 }, /* Skip RGND detection */ ++ { 0x01, 0x92, 0x46 }, /* Force MHD mode */ ++ { 0x01, 0x93, 0xdc }, /* Disable CBUS pull-up during RGND measurement */ ++ { 0x01, 0x94, 0x66 }, /* 1.8V CBUS VTH & GND threshold */ ++ { 0x01, 0x95, 0x31 }, /* RGND block & single discovery attempt */ ++ { 0x01, 0x96, 0x22 }, /* use 1K and 2K setting */ ++ { 0x01, 0xa0, 0x10 }, /* SIMG: Term mode */ ++ { 0x01, 0xa1, 0xfc }, /* Disable internal Mobile HD driver */ ++ { 0x01, 0xa3, 0xfa }, /* SIMG: Output Swing default EB, 3x Clk Mult */ ++ { 0x01, 0xa5, 0x80 }, /* SIMG: RGND Hysterisis, 3x mode for Beast */ ++ { 0x01, 0xa6, 0x0c }, /* SIMG: Swing Offset */ ++ { 0x02, 0x3d, 0x3f }, /* Power up CVCC 1.2V core */ ++ { 0x03, 0x00, 0x00 }, /* SIMG: correcting HW default */ ++ { 0x03, 0x11, 0x01 }, /* Enable TxPLL Clock */ ++ { 0x03, 0x12, 0x15 }, /* Enable Tx Clock Path & Equalizer */ ++ { 0x03, 0x13, 0x60 }, /* SIMG: Set termination value */ ++ { 0x03, 0x14, 0xf0 }, /* SIMG: Change CKDT level */ ++ { 0x03, 0x17, 0x07 }, /* SIMG: PLL Calrefsel */ ++ { 0x03, 0x1a, 0x20 }, /* VCO Cal */ ++ { 0x03, 0x22, 0xe0 }, /* SIMG: Auto EQ */ ++ { 0x03, 0x23, 0xc0 }, /* SIMG: Auto EQ */ ++ { 0x03, 0x24, 0xa0 }, /* SIMG: Auto EQ */ ++ { 0x03, 0x25, 0x80 }, /* SIMG: Auto EQ */ ++ { 0x03, 0x26, 0x60 }, /* SIMG: Auto EQ */ ++ { 0x03, 0x27, 0x40 }, /* SIMG: Auto EQ */ ++ { 0x03, 0x28, 0x20 }, /* SIMG: Auto EQ */ ++ { 0x03, 0x29, 0x00 }, /* SIMG: Auto EQ */ ++ { 0x03, 0x31, 0x0b }, /* SIMG: Rx PLL BW value from I2C BW ~ 4MHz */ ++ { 0x03, 0x45, 0x06 }, /* SIMG: DPLL Mode */ ++ { 0x03, 0x4b, 0x06 }, /* SIMG: Correcting HW default */ ++ { 0x03, 0x4c, 0xa0 }, /* Manual zone control */ ++ { 0x03, 0x4d, 0x02 }, /* SIMG: PLL Mode Value (order is important) */ ++}; ++ ++static int sii9234_set_internal(struct sii9234_context *ctx) ++{ ++ struct i2c_client *client = ctx->client; ++ int i, ret; ++ ++ for (i = 0; i < ARRAY_SIZE(data); ++i) { ++ int addr = (data[i][0] << 8) | data[i][1]; ++ ret = sii9234_writeb_idx(client, addr, data[i][2]); ++ if (ret < 0) ++ return ret; ++ } ++ return 0; ++} ++ ++static int sii9234_runtime_suspend(struct device *dev) ++{ ++ struct v4l2_subdev *sd = dev_get_drvdata(dev); ++ struct sii9234_context *ctx = sd_to_context(sd); ++ struct i2c_client *client = ctx->client; ++ ++ dev_info(dev, "suspend start\n"); ++ ++ sii9234_writeb_mask(client, 0x1e, 3, 3); ++ regulator_disable(ctx->power); ++ ++ return 0; ++} ++ ++static int sii9234_runtime_resume(struct device *dev) ++{ ++ struct v4l2_subdev *sd = dev_get_drvdata(dev); ++ struct sii9234_context *ctx = sd_to_context(sd); ++ struct i2c_client *client = ctx->client; ++ int ret; ++ ++ dev_info(dev, "resume start\n"); ++ regulator_enable(ctx->power); ++ ++ ret = sii9234_reset(ctx); ++ if (ret) ++ goto fail; ++ ++ /* enable tpi */ ++ ret = sii9234_writeb_mask(client, 0x1e, 1, 0); ++ if (ret < 0) ++ goto fail; ++ ret = sii9234_set_internal(ctx); ++ if (ret < 0) ++ goto fail; ++ ++ return 0; ++ ++fail: ++ dev_err(dev, "failed to resume\n"); ++ regulator_disable(ctx->power); ++ ++ return ret; ++} ++ ++static const struct dev_pm_ops sii9234_pm_ops = { ++ .runtime_suspend = sii9234_runtime_suspend, ++ .runtime_resume = sii9234_runtime_resume, ++}; ++ ++static int sii9234_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct sii9234_context *ctx = sd_to_context(sd); ++ int ret; ++ ++ if (on) ++ ret = pm_runtime_get_sync(&ctx->client->dev); ++ else ++ ret = pm_runtime_put(&ctx->client->dev); ++ /* only values < 0 indicate errors */ ++ return IS_ERR_VALUE(ret) ? ret : 0; ++} ++ ++static int sii9234_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct sii9234_context *ctx = sd_to_context(sd); ++ ++ /* (dis/en)able TDMS output */ ++ sii9234_writeb_mask(ctx->client, 0x1a, enable ? 0 : ~0 , 1 << 4); ++ return 0; ++} ++ ++static const struct v4l2_subdev_core_ops sii9234_core_ops = { ++ .s_power = sii9234_s_power, ++}; ++ ++static const struct v4l2_subdev_video_ops sii9234_video_ops = { ++ .s_stream = sii9234_s_stream, ++}; ++ ++static const struct v4l2_subdev_ops sii9234_ops = { ++ .core = &sii9234_core_ops, ++ .video = &sii9234_video_ops, ++}; ++ ++static int __devinit sii9234_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct device *dev = &client->dev; ++ struct sii9234_platform_data *pdata = dev->platform_data; ++ struct sii9234_context *ctx; ++ int ret; ++ ++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) { ++ dev_err(dev, "out of memory\n"); ++ ret = -ENOMEM; ++ goto fail; ++ } ++ ctx->client = client; ++ ++ ctx->power = regulator_get(dev, "hdmi-en"); ++ if (IS_ERR(ctx->power)) { ++ dev_err(dev, "failed to acquire regulator hdmi-en\n"); ++ ret = PTR_ERR(ctx->power); ++ goto fail_ctx; ++ } ++ ++ ctx->gpio_n_reset = pdata->gpio_n_reset; ++ ret = gpio_request(ctx->gpio_n_reset, "MHL_RST"); ++ if (ret) { ++ dev_err(dev, "failed to acquire MHL_RST gpio\n"); ++ goto fail_power; ++ } ++ ++ v4l2_i2c_subdev_init(&ctx->sd, client, &sii9234_ops); ++ ++ pm_runtime_enable(dev); ++ ++ /* enable device */ ++ ret = pm_runtime_get_sync(dev); ++ if (ret) ++ goto fail_pm; ++ ++ /* verify chip version */ ++ ret = sii9234_verify_version(client); ++ if (ret) ++ goto fail_pm_get; ++ ++ /* stop processing */ ++ pm_runtime_put(dev); ++ ++ dev_info(dev, "probe successful\n"); ++ ++ return 0; ++ ++fail_pm_get: ++ pm_runtime_put_sync(dev); ++ ++fail_pm: ++ pm_runtime_disable(dev); ++ gpio_free(ctx->gpio_n_reset); ++ ++fail_power: ++ regulator_put(ctx->power); ++ ++fail_ctx: ++ kfree(ctx); ++ ++fail: ++ dev_err(dev, "probe failed\n"); ++ ++ return ret; ++} ++ ++static int __devexit sii9234_remove(struct i2c_client *client) ++{ ++ struct device *dev = &client->dev; ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct sii9234_context *ctx = sd_to_context(sd); ++ ++ pm_runtime_disable(dev); ++ gpio_free(ctx->gpio_n_reset); ++ regulator_put(ctx->power); ++ kfree(ctx); ++ ++ dev_info(dev, "remove successful\n"); ++ ++ return 0; ++} ++ ++ ++static const struct i2c_device_id sii9234_id[] = { ++ { "SII9234", 0 }, ++ { }, ++}; ++ ++MODULE_DEVICE_TABLE(i2c, sii9234_id); ++static struct i2c_driver sii9234_driver = { ++ .driver = { ++ .name = "sii9234", ++ .owner = THIS_MODULE, ++ .pm = &sii9234_pm_ops, ++ }, ++ .probe = sii9234_probe, ++ .remove = __devexit_p(sii9234_remove), ++ .id_table = sii9234_id, ++}; ++ ++static int __init sii9234_init(void) ++{ ++ return i2c_add_driver(&sii9234_driver); ++} ++module_init(sii9234_init); ++ ++static void __exit sii9234_exit(void) ++{ ++ i2c_del_driver(&sii9234_driver); ++} ++module_exit(sii9234_exit); +Index: linux-3.3.x86_64/include/media/sii9234.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/include/media/sii9234.h +@@ -0,0 +1,24 @@ ++/* ++ * Driver header for SII9234 MHL converter chip. ++ * ++ * Copyright (c) 2011 Samsung Electronics, Co. Ltd ++ * Contact: Tomasz Stanislawski ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#ifndef SII9234_H ++#define SII9234_H ++ ++/** ++ * @gpio_n_reset: GPIO driving nRESET pin ++ */ ++ ++struct sii9234_platform_data { ++ int gpio_n_reset; ++}; ++ ++#endif /* SII9234_H */ +Index: linux-3.3.x86_64/include/media/s5p_hdmi.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/include/media/s5p_hdmi.h +@@ -0,0 +1,35 @@ ++/* ++ * Driver header for S5P HDMI chip. ++ * ++ * Copyright (c) 2011 Samsung Electronics, Co. Ltd ++ * Contact: Tomasz Stanislawski ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#ifndef S5P_HDMI_H ++#define S5P_HDMI_H ++ ++struct i2c_board_info; ++ ++/** ++ * @hdmiphy_bus: controller id for HDMIPHY bus ++ * @hdmiphy_info: template for HDMIPHY I2C device ++ * @mhl_bus: controller id for MHL control bus ++ * @mhl_info: template for MHL I2C device ++ * ++ * NULL pointer for *_info fields indicates that ++ * the corresponding chip is not present ++ */ ++struct s5p_hdmi_platform_data { ++ int hdmiphy_bus; ++ struct i2c_board_info *hdmiphy_info; ++ int mhl_bus; ++ struct i2c_board_info *mhl_info; ++}; ++ ++#endif /* S5P_HDMI_H */ ++ +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/Kconfig +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/Kconfig ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/Kconfig +@@ -425,6 +425,13 @@ config DVB_CXD2820R + help + Say Y when you want to support this frontend. + ++config DVB_RTL2830 ++ tristate "Realtek RTL2830 DVB-T" ++ depends on DVB_CORE && I2C ++ default m if DVB_FE_CUSTOMISE ++ help ++ Say Y when you want to support this frontend. ++ + comment "DVB-C (cable) frontends" + depends on DVB_CORE + +@@ -698,6 +705,19 @@ config DVB_IT913X_FE + A DVB-T tuner module. + Say Y when you want to support this frontend. + ++config DVB_M88RS2000 ++ tristate "M88RS2000 DVB-S demodulator and tuner" ++ depends on DVB_CORE && I2C ++ default m if DVB_FE_CUSTOMISE ++ help ++ A DVB-S tuner module. ++ Say Y when you want to support this frontend. ++ ++config DVB_AF9033 ++ tristate "Afatech AF9033 DVB-T demodulator" ++ depends on DVB_CORE && I2C ++ default m if DVB_FE_CUSTOMISE ++ + comment "Tools to develop new frontends" + + config DVB_DUMMY_FE +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/Makefile +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/Makefile ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/Makefile +@@ -2,8 +2,8 @@ + # Makefile for the kernel DVB frontend device drivers. + # + +-ccflags-y += -Idrivers/media/dvb/dvb-core/ +-ccflags-y += -Idrivers/media/common/tuners/ ++ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core/ ++ccflags-y += -I$(srctree)/drivers/media/common/tuners/ + + stb0899-objs = stb0899_drv.o stb0899_algo.o + stv0900-objs = stv0900_core.o stv0900_sw.o +@@ -96,4 +96,7 @@ obj-$(CONFIG_DVB_TDA18271C2DD) += tda182 + obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o + obj-$(CONFIG_DVB_A8293) += a8293.o + obj-$(CONFIG_DVB_TDA10071) += tda10071.o ++obj-$(CONFIG_DVB_RTL2830) += rtl2830.o ++obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o ++obj-$(CONFIG_DVB_AF9033) += af9033.o + +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/rtl2830.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/rtl2830.c +@@ -0,0 +1,562 @@ ++/* ++ * Realtek RTL2830 DVB-T demodulator driver ++ * ++ * Copyright (C) 2011 Antti Palosaari ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++ ++/* ++ * Driver implements own I2C-adapter for tuner I2C access. That's since chip ++ * have unusual I2C-gate control which closes gate automatically after each ++ * I2C transfer. Using own I2C adapter we can workaround that. ++ */ ++ ++#include "rtl2830_priv.h" ++ ++int rtl2830_debug; ++module_param_named(debug, rtl2830_debug, int, 0644); ++MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); ++ ++/* write multiple hardware registers */ ++static int rtl2830_wr(struct rtl2830_priv *priv, u8 reg, u8 *val, int len) ++{ ++ int ret; ++ u8 buf[1+len]; ++ struct i2c_msg msg[1] = { ++ { ++ .addr = priv->cfg.i2c_addr, ++ .flags = 0, ++ .len = 1+len, ++ .buf = buf, ++ } ++ }; ++ ++ buf[0] = reg; ++ memcpy(&buf[1], val, len); ++ ++ ret = i2c_transfer(priv->i2c, msg, 1); ++ if (ret == 1) { ++ ret = 0; ++ } else { ++ warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len); ++ ret = -EREMOTEIO; ++ } ++ return ret; ++} ++ ++/* read multiple hardware registers */ ++static int rtl2830_rd(struct rtl2830_priv *priv, u8 reg, u8 *val, int len) ++{ ++ int ret; ++ struct i2c_msg msg[2] = { ++ { ++ .addr = priv->cfg.i2c_addr, ++ .flags = 0, ++ .len = 1, ++ .buf = ®, ++ }, { ++ .addr = priv->cfg.i2c_addr, ++ .flags = I2C_M_RD, ++ .len = len, ++ .buf = val, ++ } ++ }; ++ ++ ret = i2c_transfer(priv->i2c, msg, 2); ++ if (ret == 2) { ++ ret = 0; ++ } else { ++ warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len); ++ ret = -EREMOTEIO; ++ } ++ return ret; ++} ++ ++/* write multiple registers */ ++static int rtl2830_wr_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len) ++{ ++ int ret; ++ u8 reg2 = (reg >> 0) & 0xff; ++ u8 page = (reg >> 8) & 0xff; ++ ++ /* switch bank if needed */ ++ if (page != priv->page) { ++ ret = rtl2830_wr(priv, 0x00, &page, 1); ++ if (ret) ++ return ret; ++ ++ priv->page = page; ++ } ++ ++ return rtl2830_wr(priv, reg2, val, len); ++} ++ ++/* read multiple registers */ ++static int rtl2830_rd_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len) ++{ ++ int ret; ++ u8 reg2 = (reg >> 0) & 0xff; ++ u8 page = (reg >> 8) & 0xff; ++ ++ /* switch bank if needed */ ++ if (page != priv->page) { ++ ret = rtl2830_wr(priv, 0x00, &page, 1); ++ if (ret) ++ return ret; ++ ++ priv->page = page; ++ } ++ ++ return rtl2830_rd(priv, reg2, val, len); ++} ++ ++#if 0 /* currently not used */ ++/* write single register */ ++static int rtl2830_wr_reg(struct rtl2830_priv *priv, u16 reg, u8 val) ++{ ++ return rtl2830_wr_regs(priv, reg, &val, 1); ++} ++#endif ++ ++/* read single register */ ++static int rtl2830_rd_reg(struct rtl2830_priv *priv, u16 reg, u8 *val) ++{ ++ return rtl2830_rd_regs(priv, reg, val, 1); ++} ++ ++/* write single register with mask */ ++int rtl2830_wr_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 val, u8 mask) ++{ ++ int ret; ++ u8 tmp; ++ ++ /* no need for read if whole reg is written */ ++ if (mask != 0xff) { ++ ret = rtl2830_rd_regs(priv, reg, &tmp, 1); ++ if (ret) ++ return ret; ++ ++ val &= mask; ++ tmp &= ~mask; ++ val |= tmp; ++ } ++ ++ return rtl2830_wr_regs(priv, reg, &val, 1); ++} ++ ++/* read single register with mask */ ++int rtl2830_rd_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 *val, u8 mask) ++{ ++ int ret, i; ++ u8 tmp; ++ ++ ret = rtl2830_rd_regs(priv, reg, &tmp, 1); ++ if (ret) ++ return ret; ++ ++ tmp &= mask; ++ ++ /* find position of the first bit */ ++ for (i = 0; i < 8; i++) { ++ if ((mask >> i) & 0x01) ++ break; ++ } ++ *val = tmp >> i; ++ ++ return 0; ++} ++ ++static int rtl2830_init(struct dvb_frontend *fe) ++{ ++ struct rtl2830_priv *priv = fe->demodulator_priv; ++ int ret, i; ++ u64 num; ++ u8 buf[3], tmp; ++ u32 if_ctl; ++ struct rtl2830_reg_val_mask tab[] = { ++ { 0x00d, 0x01, 0x03 }, ++ { 0x00d, 0x10, 0x10 }, ++ { 0x104, 0x00, 0x1e }, ++ { 0x105, 0x80, 0x80 }, ++ { 0x110, 0x02, 0x03 }, ++ { 0x110, 0x08, 0x0c }, ++ { 0x17b, 0x00, 0x40 }, ++ { 0x17d, 0x05, 0x0f }, ++ { 0x17d, 0x50, 0xf0 }, ++ { 0x18c, 0x08, 0x0f }, ++ { 0x18d, 0x00, 0xc0 }, ++ { 0x188, 0x05, 0x0f }, ++ { 0x189, 0x00, 0xfc }, ++ { 0x2d5, 0x02, 0x02 }, ++ { 0x2f1, 0x02, 0x06 }, ++ { 0x2f1, 0x20, 0xf8 }, ++ { 0x16d, 0x00, 0x01 }, ++ { 0x1a6, 0x00, 0x80 }, ++ { 0x106, priv->cfg.vtop, 0x3f }, ++ { 0x107, priv->cfg.krf, 0x3f }, ++ { 0x112, 0x28, 0xff }, ++ { 0x103, priv->cfg.agc_targ_val, 0xff }, ++ { 0x00a, 0x02, 0x07 }, ++ { 0x140, 0x0c, 0x3c }, ++ { 0x140, 0x40, 0xc0 }, ++ { 0x15b, 0x05, 0x07 }, ++ { 0x15b, 0x28, 0x38 }, ++ { 0x15c, 0x05, 0x07 }, ++ { 0x15c, 0x28, 0x38 }, ++ { 0x115, priv->cfg.spec_inv, 0x01 }, ++ { 0x16f, 0x01, 0x07 }, ++ { 0x170, 0x18, 0x38 }, ++ { 0x172, 0x0f, 0x0f }, ++ { 0x173, 0x08, 0x38 }, ++ { 0x175, 0x01, 0x07 }, ++ { 0x176, 0x00, 0xc0 }, ++ }; ++ ++ for (i = 0; i < ARRAY_SIZE(tab); i++) { ++ ret = rtl2830_wr_reg_mask(priv, tab[i].reg, tab[i].val, ++ tab[i].mask); ++ if (ret) ++ goto err; ++ } ++ ++ ret = rtl2830_wr_regs(priv, 0x18f, "\x28\x00", 2); ++ if (ret) ++ goto err; ++ ++ ret = rtl2830_wr_regs(priv, 0x195, ++ "\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8); ++ if (ret) ++ goto err; ++ ++ num = priv->cfg.if_dvbt % priv->cfg.xtal; ++ num *= 0x400000; ++ num = div_u64(num, priv->cfg.xtal); ++ num = -num; ++ if_ctl = num & 0x3fffff; ++ dbg("%s: if_ctl=%08x", __func__, if_ctl); ++ ++ ret = rtl2830_rd_reg_mask(priv, 0x119, &tmp, 0xc0); /* b[7:6] */ ++ if (ret) ++ goto err; ++ ++ buf[0] = tmp << 6; ++ buf[0] = (if_ctl >> 16) & 0x3f; ++ buf[1] = (if_ctl >> 8) & 0xff; ++ buf[2] = (if_ctl >> 0) & 0xff; ++ ++ ret = rtl2830_wr_regs(priv, 0x119, buf, 3); ++ if (ret) ++ goto err; ++ ++ /* TODO: spec init */ ++ ++ /* soft reset */ ++ ret = rtl2830_wr_reg_mask(priv, 0x101, 0x04, 0x04); ++ if (ret) ++ goto err; ++ ++ ret = rtl2830_wr_reg_mask(priv, 0x101, 0x00, 0x04); ++ if (ret) ++ goto err; ++ ++ priv->sleeping = false; ++ ++ return ret; ++err: ++ dbg("%s: failed=%d", __func__, ret); ++ return ret; ++} ++ ++static int rtl2830_sleep(struct dvb_frontend *fe) ++{ ++ struct rtl2830_priv *priv = fe->demodulator_priv; ++ priv->sleeping = true; ++ return 0; ++} ++ ++int rtl2830_get_tune_settings(struct dvb_frontend *fe, ++ struct dvb_frontend_tune_settings *s) ++{ ++ s->min_delay_ms = 500; ++ s->step_size = fe->ops.info.frequency_stepsize * 2; ++ s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; ++ ++ return 0; ++} ++ ++static int rtl2830_set_frontend(struct dvb_frontend *fe) ++{ ++ struct rtl2830_priv *priv = fe->demodulator_priv; ++ struct dtv_frontend_properties *c = &fe->dtv_property_cache; ++ int ret, i; ++ static u8 bw_params1[3][34] = { ++ { ++ 0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xfa, 0x00, 0x17, 0x00, 0x41, ++ 0x00, 0x64, 0x00, 0x67, 0x00, 0x38, 0x1f, 0xde, 0x1f, 0x7a, ++ 0x1f, 0x47, 0x1f, 0x7c, 0x00, 0x30, 0x01, 0x4b, 0x02, 0x82, ++ 0x03, 0x73, 0x03, 0xcf, /* 6 MHz */ ++ }, { ++ 0x1f, 0xfa, 0x1f, 0xda, 0x1f, 0xc1, 0x1f, 0xb3, 0x1f, 0xca, ++ 0x00, 0x07, 0x00, 0x4d, 0x00, 0x6d, 0x00, 0x40, 0x1f, 0xca, ++ 0x1f, 0x4d, 0x1f, 0x2a, 0x1f, 0xb2, 0x00, 0xec, 0x02, 0x7e, ++ 0x03, 0xd0, 0x04, 0x53, /* 7 MHz */ ++ }, { ++ 0x00, 0x10, 0x00, 0x0e, 0x1f, 0xf7, 0x1f, 0xc9, 0x1f, 0xa0, ++ 0x1f, 0xa6, 0x1f, 0xec, 0x00, 0x4e, 0x00, 0x7d, 0x00, 0x3a, ++ 0x1f, 0x98, 0x1f, 0x10, 0x1f, 0x40, 0x00, 0x75, 0x02, 0x5f, ++ 0x04, 0x24, 0x04, 0xdb, /* 8 MHz */ ++ }, ++ }; ++ static u8 bw_params2[3][6] = { ++ {0xc3, 0x0c, 0x44, 0x33, 0x33, 0x30,}, /* 6 MHz */ ++ {0xb8, 0xe3, 0x93, 0x99, 0x99, 0x98,}, /* 7 MHz */ ++ {0xae, 0xba, 0xf3, 0x26, 0x66, 0x64,}, /* 8 MHz */ ++ }; ++ ++ ++ dbg("%s: frequency=%d bandwidth_hz=%d inversion=%d", __func__, ++ c->frequency, c->bandwidth_hz, c->inversion); ++ ++ /* program tuner */ ++ if (fe->ops.tuner_ops.set_params) ++ fe->ops.tuner_ops.set_params(fe); ++ ++ switch (c->bandwidth_hz) { ++ case 6000000: ++ i = 0; ++ break; ++ case 7000000: ++ i = 1; ++ break; ++ case 8000000: ++ i = 2; ++ break; ++ default: ++ dbg("invalid bandwidth"); ++ return -EINVAL; ++ } ++ ++ ret = rtl2830_wr_reg_mask(priv, 0x008, i << 1, 0x06); ++ if (ret) ++ goto err; ++ ++ /* 1/2 split I2C write */ ++ ret = rtl2830_wr_regs(priv, 0x11c, &bw_params1[i][0], 17); ++ if (ret) ++ goto err; ++ ++ /* 2/2 split I2C write */ ++ ret = rtl2830_wr_regs(priv, 0x12d, &bw_params1[i][17], 17); ++ if (ret) ++ goto err; ++ ++ ret = rtl2830_wr_regs(priv, 0x19d, bw_params2[i], 6); ++ if (ret) ++ goto err; ++ ++ return ret; ++err: ++ dbg("%s: failed=%d", __func__, ret); ++ return ret; ++} ++ ++static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status) ++{ ++ struct rtl2830_priv *priv = fe->demodulator_priv; ++ int ret; ++ u8 tmp; ++ *status = 0; ++ ++ if (priv->sleeping) ++ return 0; ++ ++ ret = rtl2830_rd_reg_mask(priv, 0x351, &tmp, 0x78); /* [6:3] */ ++ if (ret) ++ goto err; ++ ++ if (tmp == 11) { ++ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | ++ FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; ++ } else if (tmp == 10) { ++ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | ++ FE_HAS_VITERBI; ++ } ++ ++ return ret; ++err: ++ dbg("%s: failed=%d", __func__, ret); ++ return ret; ++} ++ ++static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr) ++{ ++ *snr = 0; ++ return 0; ++} ++ ++static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber) ++{ ++ *ber = 0; ++ return 0; ++} ++ ++static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) ++{ ++ *ucblocks = 0; ++ return 0; ++} ++ ++static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength) ++{ ++ *strength = 0; ++ return 0; ++} ++ ++static struct dvb_frontend_ops rtl2830_ops; ++ ++static u32 rtl2830_tuner_i2c_func(struct i2c_adapter *adapter) ++{ ++ return I2C_FUNC_I2C; ++} ++ ++static int rtl2830_tuner_i2c_xfer(struct i2c_adapter *i2c_adap, ++ struct i2c_msg msg[], int num) ++{ ++ struct rtl2830_priv *priv = i2c_get_adapdata(i2c_adap); ++ int ret; ++ ++ /* open i2c-gate */ ++ ret = rtl2830_wr_reg_mask(priv, 0x101, 0x08, 0x08); ++ if (ret) ++ goto err; ++ ++ ret = i2c_transfer(priv->i2c, msg, num); ++ if (ret < 0) ++ warn("tuner i2c failed=%d", ret); ++ ++ return ret; ++err: ++ dbg("%s: failed=%d", __func__, ret); ++ return ret; ++} ++ ++static struct i2c_algorithm rtl2830_tuner_i2c_algo = { ++ .master_xfer = rtl2830_tuner_i2c_xfer, ++ .functionality = rtl2830_tuner_i2c_func, ++}; ++ ++struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(struct dvb_frontend *fe) ++{ ++ struct rtl2830_priv *priv = fe->demodulator_priv; ++ return &priv->tuner_i2c_adapter; ++} ++EXPORT_SYMBOL(rtl2830_get_tuner_i2c_adapter); ++ ++static void rtl2830_release(struct dvb_frontend *fe) ++{ ++ struct rtl2830_priv *priv = fe->demodulator_priv; ++ ++ i2c_del_adapter(&priv->tuner_i2c_adapter); ++ kfree(priv); ++} ++ ++struct dvb_frontend *rtl2830_attach(const struct rtl2830_config *cfg, ++ struct i2c_adapter *i2c) ++{ ++ struct rtl2830_priv *priv = NULL; ++ int ret = 0; ++ u8 tmp; ++ ++ /* allocate memory for the internal state */ ++ priv = kzalloc(sizeof(struct rtl2830_priv), GFP_KERNEL); ++ if (priv == NULL) ++ goto err; ++ ++ /* setup the priv */ ++ priv->i2c = i2c; ++ memcpy(&priv->cfg, cfg, sizeof(struct rtl2830_config)); ++ ++ /* check if the demod is there */ ++ ret = rtl2830_rd_reg(priv, 0x000, &tmp); ++ if (ret) ++ goto err; ++ ++ /* create dvb_frontend */ ++ memcpy(&priv->fe.ops, &rtl2830_ops, sizeof(struct dvb_frontend_ops)); ++ priv->fe.demodulator_priv = priv; ++ ++ /* create tuner i2c adapter */ ++ strlcpy(priv->tuner_i2c_adapter.name, "RTL2830 tuner I2C adapter", ++ sizeof(priv->tuner_i2c_adapter.name)); ++ priv->tuner_i2c_adapter.algo = &rtl2830_tuner_i2c_algo; ++ priv->tuner_i2c_adapter.algo_data = NULL; ++ i2c_set_adapdata(&priv->tuner_i2c_adapter, priv); ++ if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) { ++ err("tuner I2C bus could not be initialized"); ++ goto err; ++ } ++ ++ priv->sleeping = true; ++ ++ return &priv->fe; ++err: ++ dbg("%s: failed=%d", __func__, ret); ++ kfree(priv); ++ return NULL; ++} ++EXPORT_SYMBOL(rtl2830_attach); ++ ++static struct dvb_frontend_ops rtl2830_ops = { ++ .delsys = { SYS_DVBT }, ++ .info = { ++ .name = "Realtek RTL2830 (DVB-T)", ++ .caps = FE_CAN_FEC_1_2 | ++ FE_CAN_FEC_2_3 | ++ FE_CAN_FEC_3_4 | ++ FE_CAN_FEC_5_6 | ++ FE_CAN_FEC_7_8 | ++ FE_CAN_FEC_AUTO | ++ FE_CAN_QPSK | ++ FE_CAN_QAM_16 | ++ FE_CAN_QAM_64 | ++ FE_CAN_QAM_AUTO | ++ FE_CAN_TRANSMISSION_MODE_AUTO | ++ FE_CAN_GUARD_INTERVAL_AUTO | ++ FE_CAN_HIERARCHY_AUTO | ++ FE_CAN_RECOVER | ++ FE_CAN_MUTE_TS ++ }, ++ ++ .release = rtl2830_release, ++ ++ .init = rtl2830_init, ++ .sleep = rtl2830_sleep, ++ ++ .get_tune_settings = rtl2830_get_tune_settings, ++ ++ .set_frontend = rtl2830_set_frontend, ++ ++ .read_status = rtl2830_read_status, ++ .read_snr = rtl2830_read_snr, ++ .read_ber = rtl2830_read_ber, ++ .read_ucblocks = rtl2830_read_ucblocks, ++ .read_signal_strength = rtl2830_read_signal_strength, ++}; ++ ++MODULE_AUTHOR("Antti Palosaari "); ++MODULE_DESCRIPTION("Realtek RTL2830 DVB-T demodulator driver"); ++MODULE_LICENSE("GPL"); +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/rtl2830.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/rtl2830.h +@@ -0,0 +1,97 @@ ++/* ++ * Realtek RTL2830 DVB-T demodulator driver ++ * ++ * Copyright (C) 2011 Antti Palosaari ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#ifndef RTL2830_H ++#define RTL2830_H ++ ++#include ++ ++struct rtl2830_config { ++ /* ++ * Demodulator I2C address. ++ */ ++ u8 i2c_addr; ++ ++ /* ++ * Xtal frequency. ++ * Hz ++ * 4000000, 16000000, 25000000, 28800000 ++ */ ++ u32 xtal; ++ ++ /* ++ * TS output mode. ++ */ ++ u8 ts_mode; ++ ++ /* ++ * Spectrum inversion. ++ */ ++ bool spec_inv; ++ ++ /* ++ * IFs for all used modes. ++ * Hz ++ * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000 ++ */ ++ u32 if_dvbt; ++ ++ /* ++ */ ++ u8 vtop; ++ ++ /* ++ */ ++ u8 krf; ++ ++ /* ++ */ ++ u8 agc_targ_val; ++}; ++ ++#if defined(CONFIG_DVB_RTL2830) || \ ++ (defined(CONFIG_DVB_RTL2830_MODULE) && defined(MODULE)) ++extern struct dvb_frontend *rtl2830_attach( ++ const struct rtl2830_config *config, ++ struct i2c_adapter *i2c ++); ++ ++extern struct i2c_adapter *rtl2830_get_tuner_i2c_adapter( ++ struct dvb_frontend *fe ++); ++#else ++static inline struct dvb_frontend *rtl2830_attach( ++ const struct rtl2830_config *config, ++ struct i2c_adapter *i2c ++) ++{ ++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); ++ return NULL; ++} ++ ++static inline struct i2c_adapter *rtl2830_get_tuner_i2c_adapter( ++ struct dvb_frontend *fe ++) ++{ ++ return NULL; ++} ++#endif ++ ++#endif /* RTL2830_H */ +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/rtl2830_priv.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/rtl2830_priv.h +@@ -0,0 +1,57 @@ ++/* ++ * Realtek RTL2830 DVB-T demodulator driver ++ * ++ * Copyright (C) 2011 Antti Palosaari ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#ifndef RTL2830_PRIV_H ++#define RTL2830_PRIV_H ++ ++#include "dvb_frontend.h" ++#include "rtl2830.h" ++ ++#define LOG_PREFIX "rtl2830" ++ ++#undef dbg ++#define dbg(f, arg...) \ ++ if (rtl2830_debug) \ ++ printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) ++#undef err ++#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) ++#undef info ++#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) ++#undef warn ++#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) ++ ++struct rtl2830_priv { ++ struct i2c_adapter *i2c; ++ struct dvb_frontend fe; ++ struct rtl2830_config cfg; ++ struct i2c_adapter tuner_i2c_adapter; ++ ++ bool sleeping; ++ ++ u8 page; /* active register page */ ++}; ++ ++struct rtl2830_reg_val_mask { ++ u16 reg; ++ u8 val; ++ u8 mask; ++}; ++ ++#endif /* RTL2830_PRIV_H */ +Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/rtl28xxu.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/rtl28xxu.c +@@ -0,0 +1,982 @@ ++/* ++ * Realtek RTL28xxU DVB USB driver ++ * ++ * Copyright (C) 2009 Antti Palosaari ++ * Copyright (C) 2011 Antti Palosaari ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include "rtl28xxu.h" ++ ++#include "rtl2830.h" ++ ++#include "qt1010.h" ++#include "mt2060.h" ++#include "mxl5005s.h" ++ ++/* debug */ ++static int dvb_usb_rtl28xxu_debug; ++module_param_named(debug, dvb_usb_rtl28xxu_debug, int, 0644); ++MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); ++DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); ++ ++static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req) ++{ ++ int ret; ++ unsigned int pipe; ++ u8 requesttype; ++ u8 *buf; ++ ++ buf = kmalloc(req->size, GFP_KERNEL); ++ if (!buf) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ if (req->index & CMD_WR_FLAG) { ++ /* write */ ++ memcpy(buf, req->data, req->size); ++ requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); ++ pipe = usb_sndctrlpipe(d->udev, 0); ++ } else { ++ /* read */ ++ requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); ++ pipe = usb_rcvctrlpipe(d->udev, 0); ++ } ++ ++ ret = usb_control_msg(d->udev, pipe, 0, requesttype, req->value, ++ req->index, buf, req->size, 1000); ++ if (ret > 0) ++ ret = 0; ++ ++ deb_dump(0, requesttype, req->value, req->index, buf, req->size, ++ deb_xfer); ++ ++ /* read request, copy returned data to return buf */ ++ if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) ++ memcpy(req->data, buf, req->size); ++ ++ kfree(buf); ++ ++ if (ret) ++ goto err; ++ ++ return ret; ++err: ++ deb_info("%s: failed=%d\n", __func__, ret); ++ return ret; ++} ++ ++static int rtl2831_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len) ++{ ++ struct rtl28xxu_req req; ++ ++ if (reg < 0x3000) ++ req.index = CMD_USB_WR; ++ else if (reg < 0x4000) ++ req.index = CMD_SYS_WR; ++ else ++ req.index = CMD_IR_WR; ++ ++ req.value = reg; ++ req.size = len; ++ req.data = val; ++ ++ return rtl28xxu_ctrl_msg(d, &req); ++} ++ ++static int rtl2831_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len) ++{ ++ struct rtl28xxu_req req; ++ ++ if (reg < 0x3000) ++ req.index = CMD_USB_RD; ++ else if (reg < 0x4000) ++ req.index = CMD_SYS_RD; ++ else ++ req.index = CMD_IR_RD; ++ ++ req.value = reg; ++ req.size = len; ++ req.data = val; ++ ++ return rtl28xxu_ctrl_msg(d, &req); ++} ++ ++static int rtl2831_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val) ++{ ++ return rtl2831_wr_regs(d, reg, &val, 1); ++} ++ ++static int rtl2831_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val) ++{ ++ return rtl2831_rd_regs(d, reg, val, 1); ++} ++ ++/* I2C */ ++static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ++ int num) ++{ ++ int ret; ++ struct dvb_usb_device *d = i2c_get_adapdata(adap); ++ struct rtl28xxu_priv *priv = d->priv; ++ struct rtl28xxu_req req; ++ ++ /* ++ * It is not known which are real I2C bus xfer limits, but testing ++ * with RTL2831U + MT2060 gives max RD 24 and max WR 22 bytes. ++ * TODO: find out RTL2832U lens ++ */ ++ ++ /* ++ * I2C adapter logic looks rather complicated due to fact it handles ++ * three different access methods. Those methods are; ++ * 1) integrated demod access ++ * 2) old I2C access ++ * 3) new I2C access ++ * ++ * Used method is selected in order 1, 2, 3. Method 3 can handle all ++ * requests but there is two reasons why not use it always; ++ * 1) It is most expensive, usually two USB messages are needed ++ * 2) At least RTL2831U does not support it ++ * ++ * Method 3 is needed in case of I2C write+read (typical register read) ++ * where write is more than one byte. ++ */ ++ ++ if (mutex_lock_interruptible(&d->i2c_mutex) < 0) ++ return -EAGAIN; ++ ++ if (num == 2 && !(msg[0].flags & I2C_M_RD) && ++ (msg[1].flags & I2C_M_RD)) { ++ if (msg[0].len > 24 || msg[1].len > 24) { ++ /* TODO: check msg[0].len max */ ++ ret = -EOPNOTSUPP; ++ goto err_mutex_unlock; ++ } else if (msg[0].addr == 0x10) { ++ /* method 1 - integrated demod */ ++ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); ++ req.index = CMD_DEMOD_RD | priv->page; ++ req.size = msg[1].len; ++ req.data = &msg[1].buf[0]; ++ ret = rtl28xxu_ctrl_msg(d, &req); ++ } else if (msg[0].len < 2) { ++ /* method 2 - old I2C */ ++ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); ++ req.index = CMD_I2C_RD; ++ req.size = msg[1].len; ++ req.data = &msg[1].buf[0]; ++ ret = rtl28xxu_ctrl_msg(d, &req); ++ } else { ++ /* method 3 - new I2C */ ++ req.value = (msg[0].addr << 1); ++ req.index = CMD_I2C_DA_WR; ++ req.size = msg[0].len; ++ req.data = msg[0].buf; ++ ret = rtl28xxu_ctrl_msg(d, &req); ++ if (ret) ++ goto err_mutex_unlock; ++ ++ req.value = (msg[0].addr << 1); ++ req.index = CMD_I2C_DA_RD; ++ req.size = msg[1].len; ++ req.data = msg[1].buf; ++ ret = rtl28xxu_ctrl_msg(d, &req); ++ } ++ } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) { ++ if (msg[0].len > 22) { ++ /* TODO: check msg[0].len max */ ++ ret = -EOPNOTSUPP; ++ goto err_mutex_unlock; ++ } else if (msg[0].addr == 0x10) { ++ /* method 1 - integrated demod */ ++ if (msg[0].buf[0] == 0x00) { ++ /* save demod page for later demod access */ ++ priv->page = msg[0].buf[1]; ++ ret = 0; ++ } else { ++ req.value = (msg[0].buf[0] << 8) | ++ (msg[0].addr << 1); ++ req.index = CMD_DEMOD_WR | priv->page; ++ req.size = msg[0].len-1; ++ req.data = &msg[0].buf[1]; ++ ret = rtl28xxu_ctrl_msg(d, &req); ++ } ++ } else if (msg[0].len < 23) { ++ /* method 2 - old I2C */ ++ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); ++ req.index = CMD_I2C_WR; ++ req.size = msg[0].len-1; ++ req.data = &msg[0].buf[1]; ++ ret = rtl28xxu_ctrl_msg(d, &req); ++ } else { ++ /* method 3 - new I2C */ ++ req.value = (msg[0].addr << 1); ++ req.index = CMD_I2C_DA_WR; ++ req.size = msg[0].len; ++ req.data = msg[0].buf; ++ ret = rtl28xxu_ctrl_msg(d, &req); ++ } ++ } else { ++ ret = -EINVAL; ++ } ++ ++err_mutex_unlock: ++ mutex_unlock(&d->i2c_mutex); ++ ++ return ret ? ret : num; ++} ++ ++static u32 rtl28xxu_i2c_func(struct i2c_adapter *adapter) ++{ ++ return I2C_FUNC_I2C; ++} ++ ++static struct i2c_algorithm rtl28xxu_i2c_algo = { ++ .master_xfer = rtl28xxu_i2c_xfer, ++ .functionality = rtl28xxu_i2c_func, ++}; ++ ++static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = { ++ .i2c_addr = 0x10, /* 0x20 */ ++ .xtal = 28800000, ++ .ts_mode = 0, ++ .spec_inv = 1, ++ .if_dvbt = 36150000, ++ .vtop = 0x20, ++ .krf = 0x04, ++ .agc_targ_val = 0x2d, ++ ++}; ++ ++static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = { ++ .i2c_addr = 0x10, /* 0x20 */ ++ .xtal = 28800000, ++ .ts_mode = 0, ++ .spec_inv = 1, ++ .if_dvbt = 36125000, ++ .vtop = 0x20, ++ .krf = 0x04, ++ .agc_targ_val = 0x2d, ++}; ++ ++static struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = { ++ .i2c_addr = 0x10, /* 0x20 */ ++ .xtal = 28800000, ++ .ts_mode = 0, ++ .spec_inv = 0, ++ .if_dvbt = 4570000, ++ .vtop = 0x3f, ++ .krf = 0x04, ++ .agc_targ_val = 0x3e, ++}; ++ ++static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap) ++{ ++ int ret; ++ struct rtl28xxu_priv *priv = adap->dev->priv; ++ u8 buf[1]; ++ struct rtl2830_config *rtl2830_config; ++ /* open RTL2831U/RTL2830 I2C gate */ ++ struct rtl28xxu_req req_gate = { 0x0120, 0x0011, 0x0001, "\x08" }; ++ /* for MT2060 tuner probe */ ++ struct rtl28xxu_req req_mt2060 = { 0x00c0, CMD_I2C_RD, 1, buf }; ++ /* for QT1010 tuner probe */ ++ struct rtl28xxu_req req_qt1010 = { 0x0fc4, CMD_I2C_RD, 1, buf }; ++ ++ deb_info("%s:\n", __func__); ++ ++ /* ++ * RTL2831U GPIOs ++ * ========================================================= ++ * GPIO0 | tuner#0 | 0 off | 1 on | MXL5005S (?) ++ * GPIO2 | LED | 0 off | 1 on | ++ * GPIO4 | tuner#1 | 0 on | 1 off | MT2060 ++ */ ++ ++ /* GPIO direction */ ++ ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a); ++ if (ret) ++ goto err; ++ ++ /* enable as output GPIO0, GPIO2, GPIO4 */ ++ ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15); ++ if (ret) ++ goto err; ++ ++ /* ++ * Probe used tuner. We need to know used tuner before demod attach ++ * since there is some demod params needed to set according to tuner. ++ */ ++ ++ /* open demod I2C gate */ ++ ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate); ++ if (ret) ++ goto err; ++ ++ /* check QT1010 ID(?) register; reg=0f val=2c */ ++ ret = rtl28xxu_ctrl_msg(adap->dev, &req_qt1010); ++ if (ret == 0 && buf[0] == 0x2c) { ++ priv->tuner = TUNER_RTL2830_QT1010; ++ rtl2830_config = &rtl28xxu_rtl2830_qt1010_config; ++ deb_info("%s: QT1010\n", __func__); ++ goto found; ++ } else { ++ deb_info("%s: QT1010 probe failed=%d - %02x\n", ++ __func__, ret, buf[0]); ++ } ++ ++ /* open demod I2C gate */ ++ ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate); ++ if (ret) ++ goto err; ++ ++ /* check MT2060 ID register; reg=00 val=63 */ ++ ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2060); ++ if (ret == 0 && buf[0] == 0x63) { ++ priv->tuner = TUNER_RTL2830_MT2060; ++ rtl2830_config = &rtl28xxu_rtl2830_mt2060_config; ++ deb_info("%s: MT2060\n", __func__); ++ goto found; ++ } else { ++ deb_info("%s: MT2060 probe failed=%d - %02x\n", ++ __func__, ret, buf[0]); ++ } ++ ++ /* assume MXL5005S */ ++ ret = 0; ++ priv->tuner = TUNER_RTL2830_MXL5005S; ++ rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config; ++ deb_info("%s: MXL5005S\n", __func__); ++ goto found; ++ ++found: ++ /* attach demodulator */ ++ adap->fe_adap[0].fe = dvb_attach(rtl2830_attach, rtl2830_config, ++ &adap->dev->i2c_adap); ++ if (adap->fe_adap[0].fe == NULL) { ++ ret = -ENODEV; ++ goto err; ++ } ++ ++ return ret; ++err: ++ deb_info("%s: failed=%d\n", __func__, ret); ++ return ret; ++} ++ ++static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) ++{ ++ int ret; ++ struct rtl28xxu_priv *priv = adap->dev->priv; ++ u8 buf[1]; ++ /* open RTL2832U/RTL2832 I2C gate */ ++ struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"}; ++ /* close RTL2832U/RTL2832 I2C gate */ ++ struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"}; ++ /* for FC2580 tuner probe */ ++ struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf}; ++ ++ deb_info("%s:\n", __func__); ++ ++ /* GPIO direction */ ++ ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a); ++ if (ret) ++ goto err; ++ ++ /* enable as output GPIO0, GPIO2, GPIO4 */ ++ ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15); ++ if (ret) ++ goto err; ++ ++ ret = rtl2831_wr_reg(adap->dev, SYS_DEMOD_CTL, 0xe8); ++ if (ret) ++ goto err; ++ ++ /* ++ * Probe used tuner. We need to know used tuner before demod attach ++ * since there is some demod params needed to set according to tuner. ++ */ ++ ++ /* open demod I2C gate */ ++ ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_open); ++ if (ret) ++ goto err; ++ ++ /* check FC2580 ID register; reg=01 val=56 */ ++ ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc2580); ++ if (ret == 0 && buf[0] == 0x56) { ++ priv->tuner = TUNER_RTL2832_FC2580; ++ deb_info("%s: FC2580\n", __func__); ++ goto found; ++ } else { ++ deb_info("%s: FC2580 probe failed=%d - %02x\n", ++ __func__, ret, buf[0]); ++ } ++ ++ /* close demod I2C gate */ ++ ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close); ++ if (ret) ++ goto err; ++ ++ /* tuner not found */ ++ ret = -ENODEV; ++ goto err; ++ ++found: ++ /* close demod I2C gate */ ++ ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close); ++ if (ret) ++ goto err; ++ ++ /* attach demodulator */ ++ /* TODO: */ ++ ++ return ret; ++err: ++ deb_info("%s: failed=%d\n", __func__, ret); ++ return ret; ++} ++ ++static struct qt1010_config rtl28xxu_qt1010_config = { ++ .i2c_address = 0x62, /* 0xc4 */ ++}; ++ ++static struct mt2060_config rtl28xxu_mt2060_config = { ++ .i2c_address = 0x60, /* 0xc0 */ ++ .clock_out = 0, ++}; ++ ++static struct mxl5005s_config rtl28xxu_mxl5005s_config = { ++ .i2c_address = 0x63, /* 0xc6 */ ++ .if_freq = IF_FREQ_4570000HZ, ++ .xtal_freq = CRYSTAL_FREQ_16000000HZ, ++ .agc_mode = MXL_SINGLE_AGC, ++ .tracking_filter = MXL_TF_C_H, ++ .rssi_enable = MXL_RSSI_ENABLE, ++ .cap_select = MXL_CAP_SEL_ENABLE, ++ .div_out = MXL_DIV_OUT_4, ++ .clock_out = MXL_CLOCK_OUT_DISABLE, ++ .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, ++ .top = MXL5005S_TOP_25P2, ++ .mod_mode = MXL_DIGITAL_MODE, ++ .if_mode = MXL_ZERO_IF, ++ .AgcMasterByte = 0x00, ++}; ++ ++static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap) ++{ ++ int ret; ++ struct rtl28xxu_priv *priv = adap->dev->priv; ++ struct i2c_adapter *rtl2830_tuner_i2c; ++ struct dvb_frontend *fe; ++ ++ deb_info("%s:\n", __func__); ++ ++ /* use rtl2830 driver I2C adapter, for more info see rtl2830 driver */ ++ rtl2830_tuner_i2c = rtl2830_get_tuner_i2c_adapter(adap->fe_adap[0].fe); ++ ++ switch (priv->tuner) { ++ case TUNER_RTL2830_QT1010: ++ fe = dvb_attach(qt1010_attach, adap->fe_adap[0].fe, ++ rtl2830_tuner_i2c, &rtl28xxu_qt1010_config); ++ break; ++ case TUNER_RTL2830_MT2060: ++ fe = dvb_attach(mt2060_attach, adap->fe_adap[0].fe, ++ rtl2830_tuner_i2c, &rtl28xxu_mt2060_config, ++ 1220); ++ break; ++ case TUNER_RTL2830_MXL5005S: ++ fe = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, ++ rtl2830_tuner_i2c, &rtl28xxu_mxl5005s_config); ++ break; ++ default: ++ fe = NULL; ++ err("unknown tuner=%d", priv->tuner); ++ } ++ ++ if (fe == NULL) { ++ ret = -ENODEV; ++ goto err; ++ } ++ ++ return 0; ++err: ++ deb_info("%s: failed=%d\n", __func__, ret); ++ return ret; ++} ++ ++static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) ++{ ++ int ret; ++ struct rtl28xxu_priv *priv = adap->dev->priv; ++ struct dvb_frontend *fe; ++ ++ deb_info("%s:\n", __func__); ++ ++ switch (priv->tuner) { ++ case TUNER_RTL2832_FC2580: ++ /* TODO: */ ++ fe = NULL; ++ break; ++ default: ++ fe = NULL; ++ err("unknown tuner=%d", priv->tuner); ++ } ++ ++ if (fe == NULL) { ++ ret = -ENODEV; ++ goto err; ++ } ++ ++ return 0; ++err: ++ deb_info("%s: failed=%d\n", __func__, ret); ++ return ret; ++} ++ ++static int rtl28xxu_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff) ++{ ++ int ret; ++ u8 buf[2], gpio; ++ ++ deb_info("%s: onoff=%d\n", __func__, onoff); ++ ++ ret = rtl2831_rd_reg(adap->dev, SYS_GPIO_OUT_VAL, &gpio); ++ if (ret) ++ goto err; ++ ++ if (onoff) { ++ buf[0] = 0x00; ++ buf[1] = 0x00; ++ gpio |= 0x04; /* LED on */ ++ } else { ++ buf[0] = 0x10; /* stall EPA */ ++ buf[1] = 0x02; /* reset EPA */ ++ gpio &= (~0x04); /* LED off */ ++ } ++ ++ ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_VAL, gpio); ++ if (ret) ++ goto err; ++ ++ ret = rtl2831_wr_regs(adap->dev, USB_EPA_CTL, buf, 2); ++ if (ret) ++ goto err; ++ ++ return ret; ++err: ++ deb_info("%s: failed=%d\n", __func__, ret); ++ return ret; ++} ++ ++static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff) ++{ ++ int ret; ++ u8 gpio, sys0; ++ ++ deb_info("%s: onoff=%d\n", __func__, onoff); ++ ++ /* demod adc */ ++ ret = rtl2831_rd_reg(d, SYS_SYS0, &sys0); ++ if (ret) ++ goto err; ++ ++ /* tuner power, read GPIOs */ ++ ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio); ++ if (ret) ++ goto err; ++ ++ deb_info("%s: RD SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio); ++ ++ if (onoff) { ++ gpio |= 0x01; /* GPIO0 = 1 */ ++ gpio &= (~0x10); /* GPIO4 = 0 */ ++ sys0 = sys0 & 0x0f; ++ sys0 |= 0xe0; ++ } else { ++ gpio &= (~0x01); /* GPIO0 = 0 */ ++ gpio |= 0x10; /* GPIO4 = 1 */ ++ sys0 = sys0 & (~0xc0); ++ } ++ ++ deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio); ++ ++ /* demod adc */ ++ ret = rtl2831_wr_reg(d, SYS_SYS0, sys0); ++ if (ret) ++ goto err; ++ ++ /* tuner power, write GPIOs */ ++ ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, gpio); ++ if (ret) ++ goto err; ++ ++ return ret; ++err: ++ deb_info("%s: failed=%d\n", __func__, ret); ++ return ret; ++} ++ ++static int rtl2831u_rc_query(struct dvb_usb_device *d) ++{ ++ int ret, i; ++ struct rtl28xxu_priv *priv = d->priv; ++ u8 buf[5]; ++ u32 rc_code; ++ struct rtl28xxu_reg_val rc_nec_tab[] = { ++ { 0x3033, 0x80 }, ++ { 0x3020, 0x43 }, ++ { 0x3021, 0x16 }, ++ { 0x3022, 0x16 }, ++ { 0x3023, 0x5a }, ++ { 0x3024, 0x2d }, ++ { 0x3025, 0x16 }, ++ { 0x3026, 0x01 }, ++ { 0x3028, 0xb0 }, ++ { 0x3029, 0x04 }, ++ { 0x302c, 0x88 }, ++ { 0x302e, 0x13 }, ++ { 0x3030, 0xdf }, ++ { 0x3031, 0x05 }, ++ }; ++ ++ /* init remote controller */ ++ if (!priv->rc_active) { ++ for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) { ++ ret = rtl2831_wr_reg(d, rc_nec_tab[i].reg, ++ rc_nec_tab[i].val); ++ if (ret) ++ goto err; ++ } ++ priv->rc_active = true; ++ } ++ ++ ret = rtl2831_rd_regs(d, SYS_IRRC_RP, buf, 5); ++ if (ret) ++ goto err; ++ ++ if (buf[4] & 0x01) { ++ if (buf[2] == (u8) ~buf[3]) { ++ if (buf[0] == (u8) ~buf[1]) { ++ /* NEC standard (16 bit) */ ++ rc_code = buf[0] << 8 | buf[2]; ++ } else { ++ /* NEC extended (24 bit) */ ++ rc_code = buf[0] << 16 | ++ buf[1] << 8 | buf[2]; ++ } ++ } else { ++ /* NEC full (32 bit) */ ++ rc_code = buf[0] << 24 | buf[1] << 16 | ++ buf[2] << 8 | buf[3]; ++ } ++ ++ rc_keydown(d->rc_dev, rc_code, 0); ++ ++ ret = rtl2831_wr_reg(d, SYS_IRRC_SR, 1); ++ if (ret) ++ goto err; ++ ++ /* repeated intentionally to avoid extra keypress */ ++ ret = rtl2831_wr_reg(d, SYS_IRRC_SR, 1); ++ if (ret) ++ goto err; ++ } ++ ++ return ret; ++err: ++ deb_info("%s: failed=%d\n", __func__, ret); ++ return ret; ++} ++ ++static int rtl2832u_rc_query(struct dvb_usb_device *d) ++{ ++ int ret, i; ++ struct rtl28xxu_priv *priv = d->priv; ++ u8 buf[128]; ++ int len; ++ struct rtl28xxu_reg_val rc_nec_tab[] = { ++ { IR_RX_CTRL, 0x20 }, ++ { IR_RX_BUF_CTRL, 0x80 }, ++ { IR_RX_IF, 0xff }, ++ { IR_RX_IE, 0xff }, ++ { IR_MAX_DURATION0, 0xd0 }, ++ { IR_MAX_DURATION1, 0x07 }, ++ { IR_IDLE_LEN0, 0xc0 }, ++ { IR_IDLE_LEN1, 0x00 }, ++ { IR_GLITCH_LEN, 0x03 }, ++ { IR_RX_CLK, 0x09 }, ++ { IR_RX_CFG, 0x1c }, ++ { IR_MAX_H_TOL_LEN, 0x1e }, ++ { IR_MAX_L_TOL_LEN, 0x1e }, ++ { IR_RX_CTRL, 0x80 }, ++ }; ++ ++ /* init remote controller */ ++ if (!priv->rc_active) { ++ for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) { ++ ret = rtl2831_wr_reg(d, rc_nec_tab[i].reg, ++ rc_nec_tab[i].val); ++ if (ret) ++ goto err; ++ } ++ priv->rc_active = true; ++ } ++ ++ ret = rtl2831_rd_reg(d, IR_RX_IF, &buf[0]); ++ if (ret) ++ goto err; ++ ++ if (buf[0] != 0x83) ++ goto exit; ++ ++ ret = rtl2831_rd_reg(d, IR_RX_BC, &buf[0]); ++ if (ret) ++ goto err; ++ ++ len = buf[0]; ++ ret = rtl2831_rd_regs(d, IR_RX_BUF, buf, len); ++ ++ /* TODO: pass raw IR to Kernel IR decoder */ ++ ++ ret = rtl2831_wr_reg(d, IR_RX_IF, 0x03); ++ ret = rtl2831_wr_reg(d, IR_RX_BUF_CTRL, 0x80); ++ ret = rtl2831_wr_reg(d, IR_RX_CTRL, 0x80); ++ ++exit: ++ return ret; ++err: ++ deb_info("%s: failed=%d\n", __func__, ret); ++ return ret; ++} ++ ++enum rtl28xxu_usb_table_entry { ++ RTL2831U_0BDA_2831, ++ RTL2831U_14AA_0160, ++ RTL2831U_14AA_0161, ++}; ++ ++static struct usb_device_id rtl28xxu_table[] = { ++ /* RTL2831U */ ++ [RTL2831U_0BDA_2831] = { ++ USB_DEVICE(USB_VID_REALTEK, USB_PID_REALTEK_RTL2831U)}, ++ [RTL2831U_14AA_0160] = { ++ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT)}, ++ [RTL2831U_14AA_0161] = { ++ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2)}, ++ ++ /* RTL2832U */ ++ {} /* terminating entry */ ++}; ++ ++MODULE_DEVICE_TABLE(usb, rtl28xxu_table); ++ ++static struct dvb_usb_device_properties rtl28xxu_properties[] = { ++ { ++ .caps = DVB_USB_IS_AN_I2C_ADAPTER, ++ ++ .usb_ctrl = DEVICE_SPECIFIC, ++ .no_reconnect = 1, ++ ++ .size_of_priv = sizeof(struct rtl28xxu_priv), ++ ++ .num_adapters = 1, ++ .adapter = { ++ { ++ .num_frontends = 1, ++ .fe = { ++ { ++ .frontend_attach = rtl2831u_frontend_attach, ++ .tuner_attach = rtl2831u_tuner_attach, ++ .streaming_ctrl = rtl28xxu_streaming_ctrl, ++ .stream = { ++ .type = USB_BULK, ++ .count = 6, ++ .endpoint = 0x81, ++ .u = { ++ .bulk = { ++ .buffersize = 8*512, ++ } ++ } ++ } ++ } ++ } ++ } ++ }, ++ ++ .power_ctrl = rtl28xxu_power_ctrl, ++ ++ .rc.core = { ++ .protocol = RC_TYPE_NEC, ++ .module_name = "rtl28xxu", ++ .rc_query = rtl2831u_rc_query, ++ .rc_interval = 400, ++ .allowed_protos = RC_TYPE_NEC, ++ .rc_codes = RC_MAP_EMPTY, ++ }, ++ ++ .i2c_algo = &rtl28xxu_i2c_algo, ++ ++ .num_device_descs = 2, ++ .devices = { ++ { ++ .name = "Realtek RTL2831U reference design", ++ .warm_ids = { ++ &rtl28xxu_table[RTL2831U_0BDA_2831], ++ }, ++ }, ++ { ++ .name = "Freecom USB2.0 DVB-T", ++ .warm_ids = { ++ &rtl28xxu_table[RTL2831U_14AA_0160], ++ &rtl28xxu_table[RTL2831U_14AA_0161], ++ }, ++ }, ++ } ++ }, ++ { ++ .caps = DVB_USB_IS_AN_I2C_ADAPTER, ++ ++ .usb_ctrl = DEVICE_SPECIFIC, ++ .no_reconnect = 1, ++ ++ .size_of_priv = sizeof(struct rtl28xxu_priv), ++ ++ .num_adapters = 1, ++ .adapter = { ++ { ++ .num_frontends = 1, ++ .fe = { ++ { ++ .frontend_attach = rtl2832u_frontend_attach, ++ .tuner_attach = rtl2832u_tuner_attach, ++ .streaming_ctrl = rtl28xxu_streaming_ctrl, ++ .stream = { ++ .type = USB_BULK, ++ .count = 6, ++ .endpoint = 0x81, ++ .u = { ++ .bulk = { ++ .buffersize = 8*512, ++ } ++ } ++ } ++ } ++ } ++ } ++ }, ++ ++ .power_ctrl = rtl28xxu_power_ctrl, ++ ++ .rc.core = { ++ .protocol = RC_TYPE_NEC, ++ .module_name = "rtl28xxu", ++ .rc_query = rtl2832u_rc_query, ++ .rc_interval = 400, ++ .allowed_protos = RC_TYPE_NEC, ++ .rc_codes = RC_MAP_EMPTY, ++ }, ++ ++ .i2c_algo = &rtl28xxu_i2c_algo, ++ ++ .num_device_descs = 0, /* disabled as no support for RTL2832 */ ++ .devices = { ++ { ++ .name = "Realtek RTL2832U reference design", ++ }, ++ } ++ }, ++ ++}; ++ ++static int rtl28xxu_probe(struct usb_interface *intf, ++ const struct usb_device_id *id) ++{ ++ int ret, i; ++ int properties_count = ARRAY_SIZE(rtl28xxu_properties); ++ struct dvb_usb_device *d; ++ ++ deb_info("%s: interface=%d\n", __func__, ++ intf->cur_altsetting->desc.bInterfaceNumber); ++ ++ if (intf->cur_altsetting->desc.bInterfaceNumber != 0) ++ return 0; ++ ++ for (i = 0; i < properties_count; i++) { ++ ret = dvb_usb_device_init(intf, &rtl28xxu_properties[i], ++ THIS_MODULE, &d, adapter_nr); ++ if (ret == 0 || ret != -ENODEV) ++ break; ++ } ++ ++ if (ret) ++ goto err; ++ ++ /* init USB endpoints */ ++ ret = rtl2831_wr_reg(d, USB_SYSCTL_0, 0x09); ++ if (ret) ++ goto err; ++ ++ ret = rtl2831_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4); ++ if (ret) ++ goto err; ++ ++ ret = rtl2831_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4); ++ if (ret) ++ goto err; ++ ++ return ret; ++err: ++ deb_info("%s: failed=%d\n", __func__, ret); ++ return ret; ++} ++ ++static struct usb_driver rtl28xxu_driver = { ++ .name = "dvb_usb_rtl28xxu", ++ .probe = rtl28xxu_probe, ++ .disconnect = dvb_usb_device_exit, ++ .id_table = rtl28xxu_table, ++}; ++ ++/* module stuff */ ++static int __init rtl28xxu_module_init(void) ++{ ++ int ret; ++ ++ deb_info("%s:\n", __func__); ++ ++ ret = usb_register(&rtl28xxu_driver); ++ if (ret) ++ err("usb_register failed=%d", ret); ++ ++ return ret; ++} ++ ++static void __exit rtl28xxu_module_exit(void) ++{ ++ deb_info("%s:\n", __func__); ++ ++ /* deregister this driver from the USB subsystem */ ++ usb_deregister(&rtl28xxu_driver); ++} ++ ++module_init(rtl28xxu_module_init); ++module_exit(rtl28xxu_module_exit); ++ ++MODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver"); ++MODULE_AUTHOR("Antti Palosaari "); ++MODULE_LICENSE("GPL"); +Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/rtl28xxu.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/rtl28xxu.h +@@ -0,0 +1,264 @@ ++/* ++ * Realtek RTL28xxU DVB USB driver ++ * ++ * Copyright (C) 2009 Antti Palosaari ++ * Copyright (C) 2011 Antti Palosaari ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#ifndef RTL28XXU_H ++#define RTL28XXU_H ++ ++#define DVB_USB_LOG_PREFIX "rtl28xxu" ++#include "dvb-usb.h" ++ ++#define deb_info(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x01, args) ++#define deb_rc(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x02, args) ++#define deb_xfer(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x04, args) ++#define deb_reg(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x08, args) ++#define deb_i2c(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x10, args) ++#define deb_fw(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x20, args) ++ ++#define deb_dump(r, t, v, i, b, l, func) { \ ++ int loop_; \ ++ func("%02x %02x %02x %02x %02x %02x %02x %02x", \ ++ t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \ ++ if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ ++ func(" >>> "); \ ++ else \ ++ func(" <<< "); \ ++ for (loop_ = 0; loop_ < l; loop_++) \ ++ func("%02x ", b[loop_]); \ ++ func("\n");\ ++} ++ ++/* ++ * USB commands ++ * (usb_control_msg() index parameter) ++ */ ++ ++#define DEMOD 0x0000 ++#define USB 0x0100 ++#define SYS 0x0200 ++#define I2C 0x0300 ++#define I2C_DA 0x0600 ++ ++#define CMD_WR_FLAG 0x0010 ++#define CMD_DEMOD_RD 0x0000 ++#define CMD_DEMOD_WR 0x0010 ++#define CMD_USB_RD 0x0100 ++#define CMD_USB_WR 0x0110 ++#define CMD_SYS_RD 0x0200 ++#define CMD_IR_RD 0x0201 ++#define CMD_IR_WR 0x0211 ++#define CMD_SYS_WR 0x0210 ++#define CMD_I2C_RD 0x0300 ++#define CMD_I2C_WR 0x0310 ++#define CMD_I2C_DA_RD 0x0600 ++#define CMD_I2C_DA_WR 0x0610 ++ ++ ++struct rtl28xxu_priv { ++ u8 chip_id; ++ u8 tuner; ++ u8 page; /* integrated demod active register page */ ++ bool rc_active; ++}; ++ ++enum rtl28xxu_chip_id { ++ CHIP_ID_NONE, ++ CHIP_ID_RTL2831U, ++ CHIP_ID_RTL2832U, ++}; ++ ++enum rtl28xxu_tuner { ++ TUNER_NONE, ++ ++ TUNER_RTL2830_QT1010, ++ TUNER_RTL2830_MT2060, ++ TUNER_RTL2830_MXL5005S, ++ ++ TUNER_RTL2832_MT2266, ++ TUNER_RTL2832_FC2580, ++ TUNER_RTL2832_MT2063, ++ TUNER_RTL2832_MAX3543, ++ TUNER_RTL2832_TUA9001, ++ TUNER_RTL2832_MXL5007T, ++ TUNER_RTL2832_FC0012, ++ TUNER_RTL2832_E4000, ++ TUNER_RTL2832_TDA18272, ++ TUNER_RTL2832_FC0013, ++}; ++ ++struct rtl28xxu_req { ++ u16 value; ++ u16 index; ++ u16 size; ++ u8 *data; ++}; ++ ++struct rtl28xxu_reg_val { ++ u16 reg; ++ u8 val; ++}; ++ ++/* ++ * memory map ++ * ++ * 0x0000 DEMOD : demodulator ++ * 0x2000 USB : SIE, USB endpoint, debug, DMA ++ * 0x3000 SYS : system ++ * 0xfc00 RC : remote controller (not RTL2831U) ++ */ ++ ++/* ++ * USB registers ++ */ ++/* SIE Control Registers */ ++#define USB_SYSCTL 0x2000 /* USB system control */ ++#define USB_SYSCTL_0 0x2000 /* USB system control */ ++#define USB_SYSCTL_1 0x2001 /* USB system control */ ++#define USB_SYSCTL_2 0x2002 /* USB system control */ ++#define USB_SYSCTL_3 0x2003 /* USB system control */ ++#define USB_IRQSTAT 0x2008 /* SIE interrupt status */ ++#define USB_IRQEN 0x200C /* SIE interrupt enable */ ++#define USB_CTRL 0x2010 /* USB control */ ++#define USB_STAT 0x2014 /* USB status */ ++#define USB_DEVADDR 0x2018 /* USB device address */ ++#define USB_TEST 0x201C /* USB test mode */ ++#define USB_FRAME_NUMBER 0x2020 /* frame number */ ++#define USB_FIFO_ADDR 0x2028 /* address of SIE FIFO RAM */ ++#define USB_FIFO_CMD 0x202A /* SIE FIFO RAM access command */ ++#define USB_FIFO_DATA 0x2030 /* SIE FIFO RAM data */ ++/* Endpoint Registers */ ++#define EP0_SETUPA 0x20F8 /* EP 0 setup packet lower byte */ ++#define EP0_SETUPB 0x20FC /* EP 0 setup packet higher byte */ ++#define USB_EP0_CFG 0x2104 /* EP 0 configure */ ++#define USB_EP0_CTL 0x2108 /* EP 0 control */ ++#define USB_EP0_STAT 0x210C /* EP 0 status */ ++#define USB_EP0_IRQSTAT 0x2110 /* EP 0 interrupt status */ ++#define USB_EP0_IRQEN 0x2114 /* EP 0 interrupt enable */ ++#define USB_EP0_MAXPKT 0x2118 /* EP 0 max packet size */ ++#define USB_EP0_BC 0x2120 /* EP 0 FIFO byte counter */ ++#define USB_EPA_CFG 0x2144 /* EP A configure */ ++#define USB_EPA_CFG_0 0x2144 /* EP A configure */ ++#define USB_EPA_CFG_1 0x2145 /* EP A configure */ ++#define USB_EPA_CFG_2 0x2146 /* EP A configure */ ++#define USB_EPA_CFG_3 0x2147 /* EP A configure */ ++#define USB_EPA_CTL 0x2148 /* EP A control */ ++#define USB_EPA_CTL_0 0x2148 /* EP A control */ ++#define USB_EPA_CTL_1 0x2149 /* EP A control */ ++#define USB_EPA_CTL_2 0x214A /* EP A control */ ++#define USB_EPA_CTL_3 0x214B /* EP A control */ ++#define USB_EPA_STAT 0x214C /* EP A status */ ++#define USB_EPA_IRQSTAT 0x2150 /* EP A interrupt status */ ++#define USB_EPA_IRQEN 0x2154 /* EP A interrupt enable */ ++#define USB_EPA_MAXPKT 0x2158 /* EP A max packet size */ ++#define USB_EPA_MAXPKT_0 0x2158 /* EP A max packet size */ ++#define USB_EPA_MAXPKT_1 0x2159 /* EP A max packet size */ ++#define USB_EPA_MAXPKT_2 0x215A /* EP A max packet size */ ++#define USB_EPA_MAXPKT_3 0x215B /* EP A max packet size */ ++#define USB_EPA_FIFO_CFG 0x2160 /* EP A FIFO configure */ ++#define USB_EPA_FIFO_CFG_0 0x2160 /* EP A FIFO configure */ ++#define USB_EPA_FIFO_CFG_1 0x2161 /* EP A FIFO configure */ ++#define USB_EPA_FIFO_CFG_2 0x2162 /* EP A FIFO configure */ ++#define USB_EPA_FIFO_CFG_3 0x2163 /* EP A FIFO configure */ ++/* Debug Registers */ ++#define USB_PHYTSTDIS 0x2F04 /* PHY test disable */ ++#define USB_TOUT_VAL 0x2F08 /* USB time-out time */ ++#define USB_VDRCTRL 0x2F10 /* UTMI vendor signal control */ ++#define USB_VSTAIN 0x2F14 /* UTMI vendor signal status in */ ++#define USB_VLOADM 0x2F18 /* UTMI load vendor signal status in */ ++#define USB_VSTAOUT 0x2F1C /* UTMI vendor signal status out */ ++#define USB_UTMI_TST 0x2F80 /* UTMI test */ ++#define USB_UTMI_STATUS 0x2F84 /* UTMI status */ ++#define USB_TSTCTL 0x2F88 /* test control */ ++#define USB_TSTCTL2 0x2F8C /* test control 2 */ ++#define USB_PID_FORCE 0x2F90 /* force PID */ ++#define USB_PKTERR_CNT 0x2F94 /* packet error counter */ ++#define USB_RXERR_CNT 0x2F98 /* RX error counter */ ++#define USB_MEM_BIST 0x2F9C /* MEM BIST test */ ++#define USB_SLBBIST 0x2FA0 /* self-loop-back BIST */ ++#define USB_CNTTEST 0x2FA4 /* counter test */ ++#define USB_PHYTST 0x2FC0 /* USB PHY test */ ++#define USB_DBGIDX 0x2FF0 /* select individual block debug signal */ ++#define USB_DBGMUX 0x2FF4 /* debug signal module mux */ ++ ++/* ++ * SYS registers ++ */ ++/* demod control registers */ ++#define SYS_SYS0 0x3000 /* include DEMOD_CTL, GPO, GPI, GPOE */ ++#define SYS_DEMOD_CTL 0x3000 /* control register for DVB-T demodulator */ ++/* GPIO registers */ ++#define SYS_GPIO_OUT_VAL 0x3001 /* output value of GPIO */ ++#define SYS_GPIO_IN_VAL 0x3002 /* input value of GPIO */ ++#define SYS_GPIO_OUT_EN 0x3003 /* output enable of GPIO */ ++#define SYS_SYS1 0x3004 /* include GPD, SYSINTE, SYSINTS, GP_CFG0 */ ++#define SYS_GPIO_DIR 0x3004 /* direction control for GPIO */ ++#define SYS_SYSINTE 0x3005 /* system interrupt enable */ ++#define SYS_SYSINTS 0x3006 /* system interrupt status */ ++#define SYS_GPIO_CFG0 0x3007 /* PAD configuration for GPIO0-GPIO3 */ ++#define SYS_SYS2 0x3008 /* include GP_CFG1 and 3 reserved bytes */ ++#define SYS_GPIO_CFG1 0x3008 /* PAD configuration for GPIO4 */ ++#define SYS_DEMOD_CTL1 0x300B ++ ++/* IrDA registers */ ++#define SYS_IRRC_PSR 0x3020 /* IR protocol selection */ ++#define SYS_IRRC_PER 0x3024 /* IR protocol extension */ ++#define SYS_IRRC_SF 0x3028 /* IR sampling frequency */ ++#define SYS_IRRC_DPIR 0x302C /* IR data package interval */ ++#define SYS_IRRC_CR 0x3030 /* IR control */ ++#define SYS_IRRC_RP 0x3034 /* IR read port */ ++#define SYS_IRRC_SR 0x3038 /* IR status */ ++/* I2C master registers */ ++#define SYS_I2CCR 0x3040 /* I2C clock */ ++#define SYS_I2CMCR 0x3044 /* I2C master control */ ++#define SYS_I2CMSTR 0x3048 /* I2C master SCL timing */ ++#define SYS_I2CMSR 0x304C /* I2C master status */ ++#define SYS_I2CMFR 0x3050 /* I2C master FIFO */ ++ ++/* ++ * IR registers ++ */ ++#define IR_RX_BUF 0xFC00 ++#define IR_RX_IE 0xFD00 ++#define IR_RX_IF 0xFD01 ++#define IR_RX_CTRL 0xFD02 ++#define IR_RX_CFG 0xFD03 ++#define IR_MAX_DURATION0 0xFD04 ++#define IR_MAX_DURATION1 0xFD05 ++#define IR_IDLE_LEN0 0xFD06 ++#define IR_IDLE_LEN1 0xFD07 ++#define IR_GLITCH_LEN 0xFD08 ++#define IR_RX_BUF_CTRL 0xFD09 ++#define IR_RX_BUF_DATA 0xFD0A ++#define IR_RX_BC 0xFD0B ++#define IR_RX_CLK 0xFD0C ++#define IR_RX_C_COUNT_L 0xFD0D ++#define IR_RX_C_COUNT_H 0xFD0E ++#define IR_SUSPEND_CTRL 0xFD10 ++#define IR_ERR_TOL_CTRL 0xFD11 ++#define IR_UNIT_LEN 0xFD12 ++#define IR_ERR_TOL_LEN 0xFD13 ++#define IR_MAX_H_TOL_LEN 0xFD14 ++#define IR_MAX_L_TOL_LEN 0xFD15 ++#define IR_MASK_CTRL 0xFD16 ++#define IR_MASK_DATA 0xFD17 ++#define IR_RES_MASK_ADDR 0xFD18 ++#define IR_RES_MASK_T_LEN 0xFD19 ++ ++#endif +Index: linux-3.3.x86_64/drivers/media/video/s5p-jpeg/jpeg-core.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s5p-jpeg/jpeg-core.c ++++ linux-3.3.x86_64/drivers/media/video/s5p-jpeg/jpeg-core.c +@@ -32,10 +32,9 @@ + + static struct s5p_jpeg_fmt formats_enc[] = { + { +- .name = "YUV 4:2:0 planar, YCbCr", +- .fourcc = V4L2_PIX_FMT_YUV420, +- .depth = 12, +- .colplanes = 3, ++ .name = "JPEG JFIF", ++ .fourcc = V4L2_PIX_FMT_JPEG, ++ .colplanes = 1, + .types = MEM2MEM_CAPTURE, + }, + { +@@ -43,7 +42,7 @@ static struct s5p_jpeg_fmt formats_enc[] + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + .colplanes = 1, +- .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, ++ .types = MEM2MEM_OUTPUT, + }, + { + .name = "RGB565", +@@ -203,6 +202,16 @@ static const unsigned char hactblg0[162] + 0xf9, 0xfa + }; + ++static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c) ++{ ++ return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler); ++} ++ ++static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh) ++{ ++ return container_of(fh, struct s5p_jpeg_ctx, fh); ++} ++ + static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl, + unsigned long tab, int len) + { +@@ -269,6 +278,7 @@ static int queue_init(void *priv, struct + struct vb2_queue *dst_vq); + static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode, + __u32 pixelformat); ++static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx); + + static int s5p_jpeg_open(struct file *file) + { +@@ -276,12 +286,18 @@ static int s5p_jpeg_open(struct file *fi + struct video_device *vfd = video_devdata(file); + struct s5p_jpeg_ctx *ctx; + struct s5p_jpeg_fmt *out_fmt; ++ int ret = 0; + + ctx = kzalloc(sizeof *ctx, GFP_KERNEL); + if (!ctx) + return -ENOMEM; + +- file->private_data = ctx; ++ v4l2_fh_init(&ctx->fh, vfd); ++ /* Use separate control handler per file handle */ ++ ctx->fh.ctrl_handler = &ctx->ctrl_handler; ++ file->private_data = &ctx->fh; ++ v4l2_fh_add(&ctx->fh); ++ + ctx->jpeg = jpeg; + if (vfd == jpeg->vfd_encoder) { + ctx->mode = S5P_JPEG_ENCODE; +@@ -291,24 +307,35 @@ static int s5p_jpeg_open(struct file *fi + out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG); + } + ++ ret = s5p_jpeg_controls_create(ctx); ++ if (ret < 0) ++ goto error; ++ + ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init); + if (IS_ERR(ctx->m2m_ctx)) { +- int err = PTR_ERR(ctx->m2m_ctx); +- kfree(ctx); +- return err; ++ ret = PTR_ERR(ctx->m2m_ctx); ++ goto error; + } + + ctx->out_q.fmt = out_fmt; + ctx->cap_q.fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV); +- + return 0; ++ ++error: ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ kfree(ctx); ++ return ret; + } + + static int s5p_jpeg_release(struct file *file) + { +- struct s5p_jpeg_ctx *ctx = file->private_data; ++ struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data); + + v4l2_m2m_ctx_release(ctx->m2m_ctx); ++ v4l2_ctrl_handler_free(&ctx->ctrl_handler); ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); + kfree(ctx); + + return 0; +@@ -317,14 +344,14 @@ static int s5p_jpeg_release(struct file + static unsigned int s5p_jpeg_poll(struct file *file, + struct poll_table_struct *wait) + { +- struct s5p_jpeg_ctx *ctx = file->private_data; ++ struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data); + + return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); + } + + static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma) + { +- struct s5p_jpeg_ctx *ctx = file->private_data; ++ struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data); + + return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); + } +@@ -448,7 +475,7 @@ static bool s5p_jpeg_parse_hdr(struct s5 + static int s5p_jpeg_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) + { +- struct s5p_jpeg_ctx *ctx = priv; ++ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + + if (ctx->mode == S5P_JPEG_ENCODE) { + strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder", +@@ -497,9 +524,7 @@ static int enum_fmt(struct s5p_jpeg_fmt + static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) + { +- struct s5p_jpeg_ctx *ctx; +- +- ctx = priv; ++ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + + if (ctx->mode == S5P_JPEG_ENCODE) + return enum_fmt(formats_enc, NUM_FORMATS_ENC, f, +@@ -511,9 +536,7 @@ static int s5p_jpeg_enum_fmt_vid_cap(str + static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) + { +- struct s5p_jpeg_ctx *ctx; +- +- ctx = priv; ++ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + + if (ctx->mode == S5P_JPEG_ENCODE) + return enum_fmt(formats_enc, NUM_FORMATS_ENC, f, +@@ -538,7 +561,7 @@ static int s5p_jpeg_g_fmt(struct file *f + struct vb2_queue *vq; + struct s5p_jpeg_q_data *q_data = NULL; + struct v4l2_pix_format *pix = &f->fmt.pix; +- struct s5p_jpeg_ctx *ct = priv; ++ struct s5p_jpeg_ctx *ct = fh_to_ctx(priv); + + vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type); + if (!vq) +@@ -659,8 +682,8 @@ static int vidioc_try_fmt(struct v4l2_fo + static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) + { ++ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + struct s5p_jpeg_fmt *fmt; +- struct s5p_jpeg_ctx *ctx = priv; + + fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat); + if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) { +@@ -676,8 +699,8 @@ static int s5p_jpeg_try_fmt_vid_cap(stru + static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) + { ++ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + struct s5p_jpeg_fmt *fmt; +- struct s5p_jpeg_ctx *ctx = priv; + + fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat); + if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) { +@@ -728,7 +751,7 @@ static int s5p_jpeg_s_fmt_vid_cap(struct + if (ret) + return ret; + +- return s5p_jpeg_s_fmt(priv, f); ++ return s5p_jpeg_s_fmt(fh_to_ctx(priv), f); + } + + static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv, +@@ -740,13 +763,13 @@ static int s5p_jpeg_s_fmt_vid_out(struct + if (ret) + return ret; + +- return s5p_jpeg_s_fmt(priv, f); ++ return s5p_jpeg_s_fmt(fh_to_ctx(priv), f); + } + + static int s5p_jpeg_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *reqbufs) + { +- struct s5p_jpeg_ctx *ctx = priv; ++ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + + return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); + } +@@ -754,14 +777,14 @@ static int s5p_jpeg_reqbufs(struct file + static int s5p_jpeg_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) + { +- struct s5p_jpeg_ctx *ctx = priv; ++ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + + return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); + } + + static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) + { +- struct s5p_jpeg_ctx *ctx = priv; ++ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + + return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); + } +@@ -769,7 +792,7 @@ static int s5p_jpeg_qbuf(struct file *fi + static int s5p_jpeg_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) + { +- struct s5p_jpeg_ctx *ctx = priv; ++ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + + return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); + } +@@ -777,7 +800,7 @@ static int s5p_jpeg_dqbuf(struct file *f + static int s5p_jpeg_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) + { +- struct s5p_jpeg_ctx *ctx = priv; ++ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + + return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); + } +@@ -785,7 +808,7 @@ static int s5p_jpeg_streamon(struct file + static int s5p_jpeg_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) + { +- struct s5p_jpeg_ctx *ctx = priv; ++ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + + return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); + } +@@ -793,7 +816,7 @@ static int s5p_jpeg_streamoff(struct fil + int s5p_jpeg_g_selection(struct file *file, void *priv, + struct v4l2_selection *s) + { +- struct s5p_jpeg_ctx *ctx = priv; ++ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && + s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) +@@ -822,33 +845,89 @@ int s5p_jpeg_g_selection(struct file *fi + return 0; + } + +-static int s5p_jpeg_g_jpegcomp(struct file *file, void *priv, +- struct v4l2_jpegcompression *compr) ++/* ++ * V4L2 controls ++ */ ++ ++static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl) + { +- struct s5p_jpeg_ctx *ctx = priv; ++ struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl); ++ struct s5p_jpeg *jpeg = ctx->jpeg; ++ unsigned long flags; + +- if (ctx->mode == S5P_JPEG_DECODE) +- return -ENOTTY; ++ switch (ctrl->id) { ++ case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: ++ spin_lock_irqsave(&jpeg->slock, flags); ++ ++ WARN_ON(ctx->subsampling > S5P_SUBSAMPLING_MODE_GRAY); ++ if (ctx->subsampling > 2) ++ ctrl->val = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY; ++ else ++ ctrl->val = ctx->subsampling; ++ spin_unlock_irqrestore(&jpeg->slock, flags); ++ break; ++ } + +- memset(compr, 0, sizeof(*compr)); +- compr->quality = ctx->compr_quality; ++ return 0; ++} ++ ++static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ctx->jpeg->slock, flags); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_JPEG_COMPRESSION_QUALITY: ++ ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - ctrl->val; ++ break; ++ case V4L2_CID_JPEG_RESTART_INTERVAL: ++ ctx->restart_interval = ctrl->val; ++ break; ++ case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: ++ ctx->subsampling = ctrl->val; ++ break; ++ } + ++ spin_unlock_irqrestore(&ctx->jpeg->slock, flags); + return 0; + } + +-static int s5p_jpeg_s_jpegcomp(struct file *file, void *priv, +- struct v4l2_jpegcompression *compr) ++static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = { ++ .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl, ++ .s_ctrl = s5p_jpeg_s_ctrl, ++}; ++ ++static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx) + { +- struct s5p_jpeg_ctx *ctx = priv; ++ unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */ ++ struct v4l2_ctrl *ctrl; + +- if (ctx->mode == S5P_JPEG_DECODE) +- return -ENOTTY; ++ v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); + +- compr->quality = clamp(compr->quality, S5P_JPEG_COMPR_QUAL_BEST, +- S5P_JPEG_COMPR_QUAL_WORST); ++ if (ctx->mode == S5P_JPEG_ENCODE) { ++ v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops, ++ V4L2_CID_JPEG_COMPRESSION_QUALITY, ++ 0, 3, 1, 3); ++ ++ v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops, ++ V4L2_CID_JPEG_RESTART_INTERVAL, ++ 0, 3, 0xffff, 0); ++ mask = ~0x06; /* 422, 420 */ ++ } ++ ++ ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops, ++ V4L2_CID_JPEG_CHROMA_SUBSAMPLING, ++ V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask, ++ V4L2_JPEG_CHROMA_SUBSAMPLING_422); + +- ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - compr->quality; ++ if (ctx->ctrl_handler.error) ++ return ctx->ctrl_handler.error; + ++ if (ctx->mode == S5P_JPEG_DECODE) ++ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE | ++ V4L2_CTRL_FLAG_READ_ONLY; + return 0; + } + +@@ -877,9 +956,6 @@ static const struct v4l2_ioctl_ops s5p_j + .vidioc_streamoff = s5p_jpeg_streamoff, + + .vidioc_g_selection = s5p_jpeg_g_selection, +- +- .vidioc_g_jpegcomp = s5p_jpeg_g_jpegcomp, +- .vidioc_s_jpegcomp = s5p_jpeg_s_jpegcomp, + }; + + /* +@@ -908,13 +984,8 @@ static void s5p_jpeg_device_run(void *pr + jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565); + else + jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422); +- if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV) +- jpeg_subsampling_mode(jpeg->regs, +- S5P_JPEG_SUBSAMPLING_422); +- else +- jpeg_subsampling_mode(jpeg->regs, +- S5P_JPEG_SUBSAMPLING_420); +- jpeg_dri(jpeg->regs, 0); ++ jpeg_subsampling_mode(jpeg->regs, ctx->subsampling); ++ jpeg_dri(jpeg->regs, ctx->restart_interval); + jpeg_x(jpeg->regs, ctx->out_q.w); + jpeg_y(jpeg->regs, ctx->out_q.h); + jpeg_imgadr(jpeg->regs, src_addr); +@@ -953,14 +1024,18 @@ static void s5p_jpeg_device_run(void *pr + jpeg_htbl_dc(jpeg->regs, 2); + jpeg_htbl_ac(jpeg->regs, 3); + jpeg_htbl_dc(jpeg->regs, 3); +- } else { ++ } else { /* S5P_JPEG_DECODE */ + jpeg_rst_int_enable(jpeg->regs, true); + jpeg_data_num_int_enable(jpeg->regs, true); + jpeg_final_mcu_num_int_enable(jpeg->regs, true); +- jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422); ++ if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV) ++ jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422); ++ else ++ jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420); + jpeg_jpgadr(jpeg->regs, src_addr); + jpeg_imgadr(jpeg->regs, dst_addr); + } ++ + jpeg_start(jpeg->regs); + } + +@@ -1162,6 +1237,8 @@ static irqreturn_t s5p_jpeg_irq(int irq, + bool timer_elapsed = false; + bool op_completed = false; + ++ spin_lock(&jpeg->slock); ++ + curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); + + src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); +@@ -1192,6 +1269,9 @@ static irqreturn_t s5p_jpeg_irq(int irq, + v4l2_m2m_buf_done(dst_buf, state); + v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx); + ++ curr_ctx->subsampling = jpeg_get_subsampling_mode(jpeg->regs); ++ spin_unlock(&jpeg->slock); ++ + jpeg_clear_int(jpeg->regs); + + return IRQ_HANDLED; +@@ -1215,6 +1295,7 @@ static int s5p_jpeg_probe(struct platfor + return -ENOMEM; + + mutex_init(&jpeg->lock); ++ spin_lock_init(&jpeg->slock); + jpeg->dev = &pdev->dev; + + /* memory-mapped registers */ +Index: linux-3.3.x86_64/drivers/media/video/s5p-jpeg/jpeg-core.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s5p-jpeg/jpeg-core.h ++++ linux-3.3.x86_64/drivers/media/video/s5p-jpeg/jpeg-core.h +@@ -14,6 +14,8 @@ + #define JPEG_CORE_H_ + + #include ++#include ++#include + + #define S5P_JPEG_M2M_NAME "s5p-jpeg" + +@@ -47,6 +49,7 @@ + /** + * struct s5p_jpeg - JPEG IP abstraction + * @lock: the mutex protecting this structure ++ * @slock: spinlock protecting the device contexts + * @v4l2_dev: v4l2 device for mem2mem mode + * @vfd_encoder: video device node for encoder mem2mem mode + * @vfd_decoder: video device node for decoder mem2mem mode +@@ -60,6 +63,7 @@ + */ + struct s5p_jpeg { + struct mutex lock; ++ struct spinlock slock; + + struct v4l2_device v4l2_dev; + struct video_device *vfd_encoder; +@@ -117,15 +121,20 @@ struct s5p_jpeg_q_data { + * @out_q: source (output) queue information + * @cap_fmt: destination (capture) queue queue information + * @hdr_parsed: set if header has been parsed during decompression ++ * @ctrl_handler: controls handler + */ + struct s5p_jpeg_ctx { + struct s5p_jpeg *jpeg; + unsigned int mode; +- unsigned int compr_quality; ++ unsigned short compr_quality; ++ unsigned short restart_interval; ++ unsigned short subsampling; + struct v4l2_m2m_ctx *m2m_ctx; + struct s5p_jpeg_q_data out_q; + struct s5p_jpeg_q_data cap_q; ++ struct v4l2_fh fh; + bool hdr_parsed; ++ struct v4l2_ctrl_handler ctrl_handler; + }; + + /** +Index: linux-3.3.x86_64/drivers/media/video/s5p-jpeg/jpeg-hw.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s5p-jpeg/jpeg-hw.h ++++ linux-3.3.x86_64/drivers/media/video/s5p-jpeg/jpeg-hw.h +@@ -13,6 +13,7 @@ + #define JPEG_HW_H_ + + #include ++#include + + #include "jpeg-hw.h" + #include "jpeg-regs.h" +@@ -25,8 +26,6 @@ + #define S5P_JPEG_DECODE 1 + #define S5P_JPEG_RAW_IN_565 0 + #define S5P_JPEG_RAW_IN_422 1 +-#define S5P_JPEG_SUBSAMPLING_422 0 +-#define S5P_JPEG_SUBSAMPLING_420 1 + #define S5P_JPEG_RAW_OUT_422 0 + #define S5P_JPEG_RAW_OUT_420 1 + +@@ -91,21 +90,26 @@ static inline void jpeg_proc_mode(void _ + writel(reg, regs + S5P_JPGMOD); + } + +-static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned long mode) ++static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned int mode) + { + unsigned long reg, m; + +- m = S5P_SUBSAMPLING_MODE_422; +- if (mode == S5P_JPEG_SUBSAMPLING_422) +- m = S5P_SUBSAMPLING_MODE_422; +- else if (mode == S5P_JPEG_SUBSAMPLING_420) ++ if (mode == V4L2_JPEG_CHROMA_SUBSAMPLING_420) + m = S5P_SUBSAMPLING_MODE_420; ++ else ++ m = S5P_SUBSAMPLING_MODE_422; ++ + reg = readl(regs + S5P_JPGMOD); + reg &= ~S5P_SUBSAMPLING_MODE_MASK; + reg |= m; + writel(reg, regs + S5P_JPGMOD); + } + ++static inline unsigned int jpeg_get_subsampling_mode(void __iomem *regs) ++{ ++ return readl(regs + S5P_JPGMOD) & S5P_SUBSAMPLING_MODE_MASK; ++} ++ + static inline void jpeg_dri(void __iomem *regs, unsigned int dri) + { + unsigned long reg; +Index: linux-3.3.x86_64/drivers/media/video/s5p-fimc/fimc-core.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s5p-fimc/fimc-core.c ++++ linux-3.3.x86_64/drivers/media/video/s5p-fimc/fimc-core.c +@@ -1602,24 +1602,35 @@ static void fimc_clk_put(struct fimc_dev + { + int i; + for (i = 0; i < fimc->num_clocks; i++) { +- if (fimc->clock[i]) +- clk_put(fimc->clock[i]); ++ if (IS_ERR_OR_NULL(fimc->clock[i])) ++ continue; ++ clk_unprepare(fimc->clock[i]); ++ clk_put(fimc->clock[i]); ++ fimc->clock[i] = NULL; + } + } + + static int fimc_clk_get(struct fimc_dev *fimc) + { +- int i; ++ int i, ret; ++ + for (i = 0; i < fimc->num_clocks; i++) { + fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]); +- if (!IS_ERR_OR_NULL(fimc->clock[i])) +- continue; +- dev_err(&fimc->pdev->dev, "failed to get fimc clock: %s\n", +- fimc_clocks[i]); +- return -ENXIO; ++ if (IS_ERR(fimc->clock[i])) ++ goto err; ++ ret = clk_prepare(fimc->clock[i]); ++ if (ret < 0) { ++ clk_put(fimc->clock[i]); ++ fimc->clock[i] = NULL; ++ goto err; ++ } + } +- + return 0; ++err: ++ fimc_clk_put(fimc); ++ dev_err(&fimc->pdev->dev, "failed to get clock: %s\n", ++ fimc_clocks[i]); ++ return -ENXIO; + } + + static int fimc_m2m_suspend(struct fimc_dev *fimc) +@@ -1667,8 +1678,6 @@ static int fimc_probe(struct platform_de + struct s5p_platform_fimc *pdata; + int ret = 0; + +- dev_dbg(&pdev->dev, "%s():\n", __func__); +- + drv_data = (struct samsung_fimc_driverdata *) + platform_get_device_id(pdev)->driver_data; + +@@ -1678,7 +1687,7 @@ static int fimc_probe(struct platform_de + return -EINVAL; + } + +- fimc = kzalloc(sizeof(struct fimc_dev), GFP_KERNEL); ++ fimc = devm_kzalloc(&pdev->dev, sizeof(*fimc), GFP_KERNEL); + if (!fimc) + return -ENOMEM; + +@@ -1689,51 +1698,35 @@ static int fimc_probe(struct platform_de + pdata = pdev->dev.platform_data; + fimc->pdata = pdata; + +- + init_waitqueue_head(&fimc->irq_queue); + spin_lock_init(&fimc->slock); + mutex_init(&fimc->lock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (!res) { +- dev_err(&pdev->dev, "failed to find the registers\n"); +- ret = -ENOENT; +- goto err_info; +- } +- +- fimc->regs_res = request_mem_region(res->start, resource_size(res), +- dev_name(&pdev->dev)); +- if (!fimc->regs_res) { +- dev_err(&pdev->dev, "failed to obtain register region\n"); +- ret = -ENOENT; +- goto err_info; +- } +- +- fimc->regs = ioremap(res->start, resource_size(res)); +- if (!fimc->regs) { +- dev_err(&pdev->dev, "failed to map registers\n"); +- ret = -ENXIO; +- goto err_req_region; ++ fimc->regs = devm_request_and_ioremap(&pdev->dev, res); ++ if (fimc->regs == NULL) { ++ dev_err(&pdev->dev, "Failed to obtain io memory\n"); ++ return -ENOENT; + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); +- if (!res) { +- dev_err(&pdev->dev, "failed to get IRQ resource\n"); +- ret = -ENXIO; +- goto err_regs_unmap; ++ if (res == NULL) { ++ dev_err(&pdev->dev, "Failed to get IRQ resource\n"); ++ return -ENXIO; + } + fimc->irq = res->start; + + fimc->num_clocks = MAX_FIMC_CLOCKS; + ret = fimc_clk_get(fimc); + if (ret) +- goto err_regs_unmap; ++ return ret; + clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency); + clk_enable(fimc->clock[CLK_BUS]); + + platform_set_drvdata(pdev, fimc); + +- ret = request_irq(fimc->irq, fimc_irq_handler, 0, pdev->name, fimc); ++ ret = devm_request_irq(&pdev->dev, fimc->irq, fimc_irq_handler, ++ 0, pdev->name, fimc); + if (ret) { + dev_err(&pdev->dev, "failed to install irq (%d)\n", ret); + goto err_clk; +@@ -1742,7 +1735,7 @@ static int fimc_probe(struct platform_de + pm_runtime_enable(&pdev->dev); + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) +- goto err_irq; ++ goto err_clk; + /* Initialize contiguous memory allocator */ + fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + if (IS_ERR(fimc->alloc_ctx)) { +@@ -1757,17 +1750,8 @@ static int fimc_probe(struct platform_de + + err_pm: + pm_runtime_put(&pdev->dev); +-err_irq: +- free_irq(fimc->irq, fimc); + err_clk: + fimc_clk_put(fimc); +-err_regs_unmap: +- iounmap(fimc->regs); +-err_req_region: +- release_resource(fimc->regs_res); +- kfree(fimc->regs_res); +-err_info: +- kfree(fimc); + return ret; + } + +@@ -1854,11 +1838,6 @@ static int __devexit fimc_remove(struct + + clk_disable(fimc->clock[CLK_BUS]); + fimc_clk_put(fimc); +- free_irq(fimc->irq, fimc); +- iounmap(fimc->regs); +- release_resource(fimc->regs_res); +- kfree(fimc->regs_res); +- kfree(fimc); + + dev_info(&pdev->dev, "driver unloaded\n"); + return 0; +Index: linux-3.3.x86_64/drivers/media/video/s5p-fimc/mipi-csis.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s5p-fimc/mipi-csis.c ++++ linux-3.3.x86_64/drivers/media/video/s5p-fimc/mipi-csis.c +@@ -1,8 +1,8 @@ + /* + * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver + * +- * Copyright (C) 2011 Samsung Electronics Co., Ltd. +- * Contact: Sylwester Nawrocki, ++ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. ++ * Sylwester Nawrocki, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as +@@ -100,7 +100,6 @@ enum { + * @pads: CSIS pads array + * @sd: v4l2_subdev associated with CSIS device instance + * @pdev: CSIS platform device +- * @regs_res: requested I/O register memory resource + * @regs: mmaped I/O registers memory + * @clock: CSIS clocks + * @irq: requested s5p-mipi-csis irq number +@@ -113,7 +112,6 @@ struct csis_state { + struct media_pad pads[CSIS_PADS_NUM]; + struct v4l2_subdev sd; + struct platform_device *pdev; +- struct resource *regs_res; + void __iomem *regs; + struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES]; + struct clk *clock[NUM_CSIS_CLOCKS]; +@@ -258,26 +256,36 @@ static void s5pcsis_clk_put(struct csis_ + { + int i; + +- for (i = 0; i < NUM_CSIS_CLOCKS; i++) +- if (!IS_ERR_OR_NULL(state->clock[i])) +- clk_put(state->clock[i]); ++ for (i = 0; i < NUM_CSIS_CLOCKS; i++) { ++ if (IS_ERR_OR_NULL(state->clock[i])) ++ continue; ++ clk_unprepare(state->clock[i]); ++ clk_put(state->clock[i]); ++ state->clock[i] = NULL; ++ } + } + + static int s5pcsis_clk_get(struct csis_state *state) + { + struct device *dev = &state->pdev->dev; +- int i; ++ int i, ret; + + for (i = 0; i < NUM_CSIS_CLOCKS; i++) { + state->clock[i] = clk_get(dev, csi_clock_name[i]); +- if (IS_ERR(state->clock[i])) { +- s5pcsis_clk_put(state); +- dev_err(dev, "failed to get clock: %s\n", +- csi_clock_name[i]); +- return -ENXIO; ++ if (IS_ERR(state->clock[i])) ++ goto err; ++ ret = clk_prepare(state->clock[i]); ++ if (ret < 0) { ++ clk_put(state->clock[i]); ++ state->clock[i] = NULL; ++ goto err; + } + } + return 0; ++err: ++ s5pcsis_clk_put(state); ++ dev_err(dev, "failed to get clock: %s\n", csi_clock_name[i]); ++ return -ENXIO; + } + + static int s5pcsis_s_power(struct v4l2_subdev *sd, int on) +@@ -480,12 +488,11 @@ static int __devinit s5pcsis_probe(struc + { + struct s5p_platform_mipi_csis *pdata; + struct resource *mem_res; +- struct resource *regs_res; + struct csis_state *state; + int ret = -ENOMEM; + int i; + +- state = kzalloc(sizeof(*state), GFP_KERNEL); ++ state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + +@@ -495,52 +502,27 @@ static int __devinit s5pcsis_probe(struc + pdata = pdev->dev.platform_data; + if (pdata == NULL || pdata->phy_enable == NULL) { + dev_err(&pdev->dev, "Platform data not fully specified\n"); +- goto e_free; ++ return -EINVAL; + } + + if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) || + pdata->lanes > CSIS0_MAX_LANES) { +- ret = -EINVAL; + dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n", + pdata->lanes); +- goto e_free; ++ return -EINVAL; + } + + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (!mem_res) { +- dev_err(&pdev->dev, "Failed to get IO memory region\n"); +- goto e_free; +- } +- +- regs_res = request_mem_region(mem_res->start, resource_size(mem_res), +- pdev->name); +- if (!regs_res) { +- dev_err(&pdev->dev, "Failed to request IO memory region\n"); +- goto e_free; +- } +- state->regs_res = regs_res; +- +- state->regs = ioremap(mem_res->start, resource_size(mem_res)); +- if (!state->regs) { +- dev_err(&pdev->dev, "Failed to remap IO region\n"); +- goto e_reqmem; ++ state->regs = devm_request_and_ioremap(&pdev->dev, mem_res); ++ if (state->regs == NULL) { ++ dev_err(&pdev->dev, "Failed to request and remap io memory\n"); ++ return -ENXIO; + } + +- ret = s5pcsis_clk_get(state); +- if (ret) +- goto e_unmap; +- +- clk_enable(state->clock[CSIS_CLK_MUX]); +- if (pdata->clk_rate) +- clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate); +- else +- dev_WARN(&pdev->dev, "No clock frequency specified!\n"); +- + state->irq = platform_get_irq(pdev, 0); + if (state->irq < 0) { +- ret = state->irq; + dev_err(&pdev->dev, "Failed to get irq\n"); +- goto e_clkput; ++ return state->irq; + } + + for (i = 0; i < CSIS_NUM_SUPPLIES; i++) +@@ -549,12 +531,22 @@ static int __devinit s5pcsis_probe(struc + ret = regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES, + state->supplies); + if (ret) ++ return ret; ++ ++ ret = s5pcsis_clk_get(state); ++ if (ret) + goto e_clkput; + +- ret = request_irq(state->irq, s5pcsis_irq_handler, 0, +- dev_name(&pdev->dev), state); ++ clk_enable(state->clock[CSIS_CLK_MUX]); ++ if (pdata->clk_rate) ++ clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate); ++ else ++ dev_WARN(&pdev->dev, "No clock frequency specified!\n"); ++ ++ ret = devm_request_irq(&pdev->dev, state->irq, s5pcsis_irq_handler, ++ 0, dev_name(&pdev->dev), state); + if (ret) { +- dev_err(&pdev->dev, "request_irq failed\n"); ++ dev_err(&pdev->dev, "Interrupt request failed\n"); + goto e_regput; + } + +@@ -573,7 +565,7 @@ static int __devinit s5pcsis_probe(struc + ret = media_entity_init(&state->sd.entity, + CSIS_PADS_NUM, state->pads, 0); + if (ret < 0) +- goto e_irqfree; ++ goto e_clkput; + + /* This allows to retrieve the platform device id by the host driver */ + v4l2_set_subdevdata(&state->sd, pdev); +@@ -582,22 +574,13 @@ static int __devinit s5pcsis_probe(struc + platform_set_drvdata(pdev, &state->sd); + + pm_runtime_enable(&pdev->dev); +- + return 0; + +-e_irqfree: +- free_irq(state->irq, state); + e_regput: + regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies); + e_clkput: + clk_disable(state->clock[CSIS_CLK_MUX]); + s5pcsis_clk_put(state); +-e_unmap: +- iounmap(state->regs); +-e_reqmem: +- release_mem_region(regs_res->start, resource_size(regs_res)); +-e_free: +- kfree(state); + return ret; + } + +@@ -699,21 +682,15 @@ static int __devexit s5pcsis_remove(stru + { + struct v4l2_subdev *sd = platform_get_drvdata(pdev); + struct csis_state *state = sd_to_csis_state(sd); +- struct resource *res = state->regs_res; + + pm_runtime_disable(&pdev->dev); +- s5pcsis_suspend(&pdev->dev); ++ s5pcsis_pm_suspend(&pdev->dev, false); + clk_disable(state->clock[CSIS_CLK_MUX]); + pm_runtime_set_suspended(&pdev->dev); +- + s5pcsis_clk_put(state); + regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies); + + media_entity_cleanup(&state->sd.entity); +- free_irq(state->irq, state); +- iounmap(state->regs); +- release_mem_region(res->start, resource_size(res)); +- kfree(state); + + return 0; + } +Index: linux-3.3.x86_64/drivers/media/video/s5p-fimc/fimc-core.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s5p-fimc/fimc-core.h ++++ linux-3.3.x86_64/drivers/media/video/s5p-fimc/fimc-core.h +@@ -434,7 +434,6 @@ struct fimc_ctx; + * @num_clocks: the number of clocks managed by this device instance + * @clock: clocks required for FIMC operation + * @regs: the mapped hardware registers +- * @regs_res: the resource claimed for IO registers + * @irq: FIMC interrupt number + * @irq_queue: interrupt handler waitqueue + * @v4l2_dev: root v4l2_device +@@ -454,7 +453,6 @@ struct fimc_dev { + u16 num_clocks; + struct clk *clock[MAX_FIMC_CLOCKS]; + void __iomem *regs; +- struct resource *regs_res; + int irq; + wait_queue_head_t irq_queue; + struct v4l2_device *v4l2_dev; +Index: linux-3.3.x86_64/drivers/media/video/s5p-fimc/fimc-capture.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s5p-fimc/fimc-capture.c ++++ linux-3.3.x86_64/drivers/media/video/s5p-fimc/fimc-capture.c +@@ -1019,52 +1019,117 @@ static int fimc_cap_dqbuf(struct file *f + return vb2_dqbuf(&fimc->vid_cap.vbq, buf, file->f_flags & O_NONBLOCK); + } + +-static int fimc_cap_cropcap(struct file *file, void *fh, +- struct v4l2_cropcap *cr) ++static int fimc_cap_create_bufs(struct file *file, void *priv, ++ struct v4l2_create_buffers *create) + { + struct fimc_dev *fimc = video_drvdata(file); +- struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame; + +- if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) +- return -EINVAL; ++ return vb2_create_bufs(&fimc->vid_cap.vbq, create); ++} + +- cr->bounds.left = 0; +- cr->bounds.top = 0; +- cr->bounds.width = f->o_width; +- cr->bounds.height = f->o_height; +- cr->defrect = cr->bounds; ++static int fimc_cap_prepare_buf(struct file *file, void *priv, ++ struct v4l2_buffer *b) ++{ ++ struct fimc_dev *fimc = video_drvdata(file); + +- return 0; ++ return vb2_prepare_buf(&fimc->vid_cap.vbq, b); + } + +-static int fimc_cap_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) ++static int fimc_cap_g_selection(struct file *file, void *fh, ++ struct v4l2_selection *s) + { + struct fimc_dev *fimc = video_drvdata(file); +- struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame; ++ struct fimc_ctx *ctx = fimc->vid_cap.ctx; ++ struct fimc_frame *f = &ctx->s_frame; + +- cr->c.left = f->offs_h; +- cr->c.top = f->offs_v; +- cr->c.width = f->width; +- cr->c.height = f->height; ++ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ++ return -EINVAL; + +- return 0; ++ switch (s->target) { ++ case V4L2_SEL_TGT_COMPOSE_DEFAULT: ++ case V4L2_SEL_TGT_COMPOSE_BOUNDS: ++ f = &ctx->d_frame; ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ s->r.left = 0; ++ s->r.top = 0; ++ s->r.width = f->o_width; ++ s->r.height = f->o_height; ++ return 0; ++ ++ case V4L2_SEL_TGT_COMPOSE_ACTIVE: ++ f = &ctx->d_frame; ++ case V4L2_SEL_TGT_CROP_ACTIVE: ++ s->r.left = f->offs_h; ++ s->r.top = f->offs_v; ++ s->r.width = f->width; ++ s->r.height = f->height; ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */ ++int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) ++{ ++ if (a->left < b->left || a->top < b->top) ++ return 0; ++ if (a->left + a->width > b->left + b->width) ++ return 0; ++ if (a->top + a->height > b->top + b->height) ++ return 0; ++ ++ return 1; + } + +-static int fimc_cap_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) ++static int fimc_cap_s_selection(struct file *file, void *fh, ++ struct v4l2_selection *s) + { + struct fimc_dev *fimc = video_drvdata(file); + struct fimc_ctx *ctx = fimc->vid_cap.ctx; +- struct fimc_frame *ff; ++ struct v4l2_rect rect = s->r; ++ struct fimc_frame *f; + unsigned long flags; ++ unsigned int pad; ++ ++ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ++ return -EINVAL; ++ ++ switch (s->target) { ++ case V4L2_SEL_TGT_COMPOSE_DEFAULT: ++ case V4L2_SEL_TGT_COMPOSE_BOUNDS: ++ case V4L2_SEL_TGT_COMPOSE_ACTIVE: ++ f = &ctx->d_frame; ++ pad = FIMC_SD_PAD_SOURCE; ++ break; ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ case V4L2_SEL_TGT_CROP_ACTIVE: ++ f = &ctx->s_frame; ++ pad = FIMC_SD_PAD_SINK; ++ break; ++ default: ++ return -EINVAL; ++ } + +- fimc_capture_try_crop(ctx, &cr->c, FIMC_SD_PAD_SINK); +- ff = &ctx->s_frame; ++ fimc_capture_try_crop(ctx, &rect, pad); + ++ if (s->flags & V4L2_SEL_FLAG_LE && ++ !enclosed_rectangle(&rect, &s->r)) ++ return -ERANGE; ++ ++ if (s->flags & V4L2_SEL_FLAG_GE && ++ !enclosed_rectangle(&s->r, &rect)) ++ return -ERANGE; ++ ++ s->r = rect; + spin_lock_irqsave(&fimc->slock, flags); +- set_frame_crop(ff, cr->c.left, cr->c.top, cr->c.width, cr->c.height); +- set_bit(ST_CAPT_APPLY_CFG, &fimc->state); ++ set_frame_crop(f, s->r.left, s->r.top, s->r.width, ++ s->r.height); + spin_unlock_irqrestore(&fimc->slock, flags); + ++ set_bit(ST_CAPT_APPLY_CFG, &fimc->state); + return 0; + } + +@@ -1082,12 +1147,14 @@ static const struct v4l2_ioctl_ops fimc_ + .vidioc_qbuf = fimc_cap_qbuf, + .vidioc_dqbuf = fimc_cap_dqbuf, + ++ .vidioc_prepare_buf = fimc_cap_prepare_buf, ++ .vidioc_create_bufs = fimc_cap_create_bufs, ++ + .vidioc_streamon = fimc_cap_streamon, + .vidioc_streamoff = fimc_cap_streamoff, + +- .vidioc_g_crop = fimc_cap_g_crop, +- .vidioc_s_crop = fimc_cap_s_crop, +- .vidioc_cropcap = fimc_cap_cropcap, ++ .vidioc_g_selection = fimc_cap_g_selection, ++ .vidioc_s_selection = fimc_cap_s_selection, + + .vidioc_enum_input = fimc_cap_enum_input, + .vidioc_s_input = fimc_cap_s_input, +Index: linux-3.3.x86_64/drivers/media/video/videobuf2-vmalloc.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/videobuf2-vmalloc.c ++++ linux-3.3.x86_64/drivers/media/video/videobuf2-vmalloc.c +@@ -10,6 +10,7 @@ + * the Free Software Foundation. + */ + ++#include + #include + #include + #include +@@ -22,6 +23,7 @@ + struct vb2_vmalloc_buf { + void *vaddr; + struct page **pages; ++ struct vm_area_struct *vma; + int write; + unsigned long size; + unsigned int n_pages; +@@ -71,6 +73,8 @@ static void *vb2_vmalloc_get_userptr(voi + struct vb2_vmalloc_buf *buf; + unsigned long first, last; + int n_pages, offset; ++ struct vm_area_struct *vma; ++ dma_addr_t physp; + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) +@@ -80,23 +84,37 @@ static void *vb2_vmalloc_get_userptr(voi + offset = vaddr & ~PAGE_MASK; + buf->size = size; + +- first = vaddr >> PAGE_SHIFT; +- last = (vaddr + size - 1) >> PAGE_SHIFT; +- buf->n_pages = last - first + 1; +- buf->pages = kzalloc(buf->n_pages * sizeof(struct page *), GFP_KERNEL); +- if (!buf->pages) +- goto fail_pages_array_alloc; +- +- /* current->mm->mmap_sem is taken by videobuf2 core */ +- n_pages = get_user_pages(current, current->mm, vaddr & PAGE_MASK, +- buf->n_pages, write, 1, /* force */ +- buf->pages, NULL); +- if (n_pages != buf->n_pages) +- goto fail_get_user_pages; +- +- buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1, PAGE_KERNEL); +- if (!buf->vaddr) +- goto fail_get_user_pages; ++ ++ vma = find_vma(current->mm, vaddr); ++ if (vma && (vma->vm_flags & VM_PFNMAP) && (vma->vm_pgoff)) { ++ if (vb2_get_contig_userptr(vaddr, size, &vma, &physp)) ++ goto fail_pages_array_alloc; ++ buf->vma = vma; ++ buf->vaddr = ioremap_nocache(physp, size); ++ if (!buf->vaddr) ++ goto fail_pages_array_alloc; ++ } else { ++ first = vaddr >> PAGE_SHIFT; ++ last = (vaddr + size - 1) >> PAGE_SHIFT; ++ buf->n_pages = last - first + 1; ++ buf->pages = kzalloc(buf->n_pages * sizeof(struct page *), ++ GFP_KERNEL); ++ if (!buf->pages) ++ goto fail_pages_array_alloc; ++ ++ /* current->mm->mmap_sem is taken by videobuf2 core */ ++ n_pages = get_user_pages(current, current->mm, ++ vaddr & PAGE_MASK, buf->n_pages, ++ write, 1, /* force */ ++ buf->pages, NULL); ++ if (n_pages != buf->n_pages) ++ goto fail_get_user_pages; ++ ++ buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1, ++ PAGE_KERNEL); ++ if (!buf->vaddr) ++ goto fail_get_user_pages; ++ } + + buf->vaddr += offset; + return buf; +@@ -120,14 +138,20 @@ static void vb2_vmalloc_put_userptr(void + unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK; + unsigned int i; + +- if (vaddr) +- vm_unmap_ram((void *)vaddr, buf->n_pages); +- for (i = 0; i < buf->n_pages; ++i) { +- if (buf->write) +- set_page_dirty_lock(buf->pages[i]); +- put_page(buf->pages[i]); ++ if (buf->pages) { ++ if (vaddr) ++ vm_unmap_ram((void *)vaddr, buf->n_pages); ++ for (i = 0; i < buf->n_pages; ++i) { ++ if (buf->write) ++ set_page_dirty_lock(buf->pages[i]); ++ put_page(buf->pages[i]); ++ } ++ kfree(buf->pages); ++ } else { ++ if (buf->vma) ++ vb2_put_vma(buf->vma); ++ iounmap(buf->vaddr); + } +- kfree(buf->pages); + kfree(buf); + } + +Index: linux-3.3.x86_64/drivers/media/video/s5p-g2d/g2d.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s5p-g2d/g2d.c ++++ linux-3.3.x86_64/drivers/media/video/s5p-g2d/g2d.c +@@ -178,6 +178,9 @@ static int g2d_s_ctrl(struct v4l2_ctrl * + { + struct g2d_ctx *ctx = container_of(ctrl->handler, struct g2d_ctx, + ctrl_handler); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ctx->dev->ctrl_lock, flags); + switch (ctrl->id) { + case V4L2_CID_COLORFX: + if (ctrl->val == V4L2_COLORFX_NEGATIVE) +@@ -185,10 +188,13 @@ static int g2d_s_ctrl(struct v4l2_ctrl * + else + ctx->rop = ROP4_COPY; + break; +- default: +- v4l2_err(&ctx->dev->v4l2_dev, "unknown control\n"); +- return -EINVAL; ++ ++ case V4L2_CID_HFLIP: ++ ctx->flip = ctx->ctrl_hflip->val | (ctx->ctrl_vflip->val << 1); ++ break; ++ + } ++ spin_unlock_irqrestore(&ctx->dev->ctrl_lock, flags); + return 0; + } + +@@ -200,11 +206,13 @@ int g2d_setup_ctrls(struct g2d_ctx *ctx) + { + struct g2d_dev *dev = ctx->dev; + +- v4l2_ctrl_handler_init(&ctx->ctrl_handler, 1); +- if (ctx->ctrl_handler.error) { +- v4l2_err(&dev->v4l2_dev, "v4l2_ctrl_handler_init failed\n"); +- return ctx->ctrl_handler.error; +- } ++ v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); ++ ++ ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ ++ ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); + + v4l2_ctrl_new_std_menu( + &ctx->ctrl_handler, +@@ -215,10 +223,14 @@ int g2d_setup_ctrls(struct g2d_ctx *ctx) + V4L2_COLORFX_NONE); + + if (ctx->ctrl_handler.error) { +- v4l2_err(&dev->v4l2_dev, "v4l2_ctrl_handler_init failed\n"); +- return ctx->ctrl_handler.error; ++ int err = ctx->ctrl_handler.error; ++ v4l2_err(&dev->v4l2_dev, "g2d_setup_ctrls failed\n"); ++ v4l2_ctrl_handler_free(&ctx->ctrl_handler); ++ return err; + } + ++ v4l2_ctrl_cluster(2, &ctx->ctrl_hflip); ++ + return 0; + } + +@@ -547,6 +559,7 @@ static void device_run(void *prv) + struct g2d_ctx *ctx = prv; + struct g2d_dev *dev = ctx->dev; + struct vb2_buffer *src, *dst; ++ unsigned long flags; + u32 cmd = 0; + + dev->curr = ctx; +@@ -557,6 +570,8 @@ static void device_run(void *prv) + clk_enable(dev->gate); + g2d_reset(dev); + ++ spin_lock_irqsave(&dev->ctrl_lock, flags); ++ + g2d_set_src_size(dev, &ctx->in); + g2d_set_src_addr(dev, vb2_dma_contig_plane_dma_addr(src, 0)); + +@@ -564,11 +579,15 @@ static void device_run(void *prv) + g2d_set_dst_addr(dev, vb2_dma_contig_plane_dma_addr(dst, 0)); + + g2d_set_rop4(dev, ctx->rop); ++ g2d_set_flip(dev, ctx->flip); ++ + if (ctx->in.c_width != ctx->out.c_width || + ctx->in.c_height != ctx->out.c_height) + cmd |= g2d_cmd_stretch(1); + g2d_set_cmd(dev, cmd); + g2d_start(dev); ++ ++ spin_unlock_irqrestore(&dev->ctrl_lock, flags); + } + + static irqreturn_t g2d_isr(int irq, void *prv) +@@ -658,7 +677,7 @@ static int g2d_probe(struct platform_dev + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; +- spin_lock_init(&dev->irqlock); ++ spin_lock_init(&dev->ctrl_lock); + mutex_init(&dev->mutex); + atomic_set(&dev->num_inst, 0); + init_waitqueue_head(&dev->irq_queue); +@@ -693,18 +712,30 @@ static int g2d_probe(struct platform_dev + goto unmap_regs; + } + ++ ret = clk_prepare(dev->clk); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to prepare g2d clock\n"); ++ goto put_clk; ++ } ++ + dev->gate = clk_get(&pdev->dev, "fimg2d"); + if (IS_ERR_OR_NULL(dev->gate)) { + dev_err(&pdev->dev, "failed to get g2d clock gate\n"); + ret = -ENXIO; +- goto put_clk; ++ goto unprep_clk; ++ } ++ ++ ret = clk_prepare(dev->gate); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to prepare g2d clock gate\n"); ++ goto put_clk_gate; + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(&pdev->dev, "failed to find IRQ\n"); + ret = -ENXIO; +- goto put_clk_gate; ++ goto unprep_clk_gate; + } + + dev->irq = res->start; +@@ -764,8 +795,12 @@ alloc_ctx_cleanup: + vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); + rel_irq: + free_irq(dev->irq, dev); ++unprep_clk_gate: ++ clk_unprepare(dev->gate); + put_clk_gate: + clk_put(dev->gate); ++unprep_clk: ++ clk_unprepare(dev->clk); + put_clk: + clk_put(dev->clk); + unmap_regs: +@@ -787,7 +822,9 @@ static int g2d_remove(struct platform_de + v4l2_device_unregister(&dev->v4l2_dev); + vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); + free_irq(dev->irq, dev); ++ clk_unprepare(dev->gate); + clk_put(dev->gate); ++ clk_unprepare(dev->clk); + clk_put(dev->clk); + iounmap(dev->regs); + release_resource(dev->res_regs); +Index: linux-3.3.x86_64/drivers/media/video/s5p-mfc/s5p_mfc_pm.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s5p-mfc/s5p_mfc_pm.c ++++ linux-3.3.x86_64/drivers/media/video/s5p-mfc/s5p_mfc_pm.c +@@ -41,15 +41,29 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev * + pm->clock_gate = clk_get(&dev->plat_dev->dev, MFC_GATE_CLK_NAME); + if (IS_ERR(pm->clock_gate)) { + mfc_err("Failed to get clock-gating control\n"); +- ret = -ENOENT; ++ ret = PTR_ERR(pm->clock_gate); + goto err_g_ip_clk; + } ++ ++ ret = clk_prepare(pm->clock_gate); ++ if (ret) { ++ mfc_err("Failed to preapre clock-gating control\n"); ++ goto err_p_ip_clk; ++ } ++ + pm->clock = clk_get(&dev->plat_dev->dev, MFC_CLKNAME); + if (IS_ERR(pm->clock)) { + mfc_err("Failed to get MFC clock\n"); +- ret = -ENOENT; ++ ret = PTR_ERR(pm->clock); + goto err_g_ip_clk_2; + } ++ ++ ret = clk_prepare(pm->clock); ++ if (ret) { ++ mfc_err("Failed to prepare MFC clock\n"); ++ goto err_p_ip_clk_2; ++ } ++ + atomic_set(&pm->power, 0); + #ifdef CONFIG_PM_RUNTIME + pm->device = &dev->plat_dev->dev; +@@ -59,7 +73,11 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev * + atomic_set(&clk_ref, 0); + #endif + return 0; ++err_p_ip_clk_2: ++ clk_put(pm->clock); + err_g_ip_clk_2: ++ clk_unprepare(pm->clock_gate); ++err_p_ip_clk: + clk_put(pm->clock_gate); + err_g_ip_clk: + return ret; +@@ -67,7 +85,9 @@ err_g_ip_clk: + + void s5p_mfc_final_pm(struct s5p_mfc_dev *dev) + { ++ clk_unprepare(pm->clock_gate); + clk_put(pm->clock_gate); ++ clk_unprepare(pm->clock); + clk_put(pm->clock); + #ifdef CONFIG_PM_RUNTIME + pm_runtime_disable(pm->device); +Index: linux-3.3.x86_64/drivers/media/video/s5p-g2d/g2d-hw.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s5p-g2d/g2d-hw.c ++++ linux-3.3.x86_64/drivers/media/video/s5p-g2d/g2d-hw.c +@@ -77,6 +77,11 @@ void g2d_set_rop4(struct g2d_dev *d, u32 + w(r, ROP4_REG); + } + ++void g2d_set_flip(struct g2d_dev *d, u32 r) ++{ ++ w(r, SRC_MSK_DIRECT_REG); ++} ++ + u32 g2d_cmd_stretch(u32 e) + { + e &= 1; +Index: linux-3.3.x86_64/drivers/media/video/s5p-g2d/g2d.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s5p-g2d/g2d.h ++++ linux-3.3.x86_64/drivers/media/video/s5p-g2d/g2d.h +@@ -20,7 +20,7 @@ struct g2d_dev { + struct v4l2_m2m_dev *m2m_dev; + struct video_device *vfd; + struct mutex mutex; +- spinlock_t irqlock; ++ spinlock_t ctrl_lock; + atomic_t num_inst; + struct vb2_alloc_ctx *alloc_ctx; + struct resource *res_regs; +@@ -57,8 +57,11 @@ struct g2d_ctx { + struct v4l2_m2m_ctx *m2m_ctx; + struct g2d_frame in; + struct g2d_frame out; ++ struct v4l2_ctrl *ctrl_hflip; ++ struct v4l2_ctrl *ctrl_vflip; + struct v4l2_ctrl_handler ctrl_handler; + u32 rop; ++ u32 flip; + }; + + struct g2d_fmt { +@@ -77,6 +80,7 @@ void g2d_set_dst_addr(struct g2d_dev *d, + void g2d_start(struct g2d_dev *d); + void g2d_clear_int(struct g2d_dev *d); + void g2d_set_rop4(struct g2d_dev *d, u32 r); ++void g2d_set_flip(struct g2d_dev *d, u32 r); + u32 g2d_cmd_stretch(u32 e); + void g2d_set_cmd(struct g2d_dev *d, u32 c); + +Index: linux-3.3.x86_64/drivers/media/video/s5k6aa.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s5k6aa.c ++++ linux-3.3.x86_64/drivers/media/video/s5k6aa.c +@@ -1582,8 +1582,8 @@ static int s5k6aa_probe(struct i2c_clien + s5k6aa->inv_vflip = pdata->vert_flip; + + sd = &s5k6aa->sd; +- strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name)); + v4l2_i2c_subdev_init(sd, client, &s5k6aa_subdev_ops); ++ strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name)); + + sd->internal_ops = &s5k6aa_subdev_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; +@@ -1663,18 +1663,7 @@ static struct i2c_driver s5k6aa_i2c_driv + .id_table = s5k6aa_id, + }; + +-static int __init s5k6aa_init(void) +-{ +- return i2c_add_driver(&s5k6aa_i2c_driver); +-} +- +-static void __exit s5k6aa_exit(void) +-{ +- i2c_del_driver(&s5k6aa_i2c_driver); +-} +- +-module_init(s5k6aa_init); +-module_exit(s5k6aa_exit); ++module_i2c_driver(s5k6aa_i2c_driver); + + MODULE_DESCRIPTION("Samsung S5K6AA(FX) SXGA camera driver"); + MODULE_AUTHOR("Sylwester Nawrocki "); +Index: linux-3.3.x86_64/drivers/media/video/noon010pc30.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/noon010pc30.c ++++ linux-3.3.x86_64/drivers/media/video/noon010pc30.c +@@ -725,8 +725,8 @@ static int noon010_probe(struct i2c_clie + + mutex_init(&info->lock); + sd = &info->sd; +- strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); + v4l2_i2c_subdev_init(sd, client, &noon010_ops); ++ strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); + + sd->internal_ops = &noon010_subdev_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; +@@ -844,18 +844,7 @@ static struct i2c_driver noon010_i2c_dri + .id_table = noon010_id, + }; + +-static int __init noon010_init(void) +-{ +- return i2c_add_driver(&noon010_i2c_driver); +-} +- +-static void __exit noon010_exit(void) +-{ +- i2c_del_driver(&noon010_i2c_driver); +-} +- +-module_init(noon010_init); +-module_exit(noon010_exit); ++module_i2c_driver(noon010_i2c_driver); + + MODULE_DESCRIPTION("Siliconfile NOON010PC30 camera driver"); + MODULE_AUTHOR("Sylwester Nawrocki "); +Index: linux-3.3.x86_64/drivers/media/video/m5mols/m5mols_core.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/m5mols/m5mols_core.c ++++ linux-3.3.x86_64/drivers/media/video/m5mols/m5mols_core.c +@@ -982,8 +982,8 @@ static int __devinit m5mols_probe(struct + } + + sd = &info->sd; +- strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); + v4l2_i2c_subdev_init(sd, client, &m5mols_ops); ++ strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + sd->internal_ops = &m5mols_subdev_internal_ops; +@@ -1057,18 +1057,7 @@ static struct i2c_driver m5mols_i2c_driv + .id_table = m5mols_id, + }; + +-static int __init m5mols_mod_init(void) +-{ +- return i2c_add_driver(&m5mols_i2c_driver); +-} +- +-static void __exit m5mols_mod_exit(void) +-{ +- i2c_del_driver(&m5mols_i2c_driver); +-} +- +-module_init(m5mols_mod_init); +-module_exit(m5mols_mod_exit); ++module_i2c_driver(m5mols_i2c_driver); + + MODULE_AUTHOR("HeungJun Kim "); + MODULE_AUTHOR("Dongsoo Kim "); +Index: linux-3.3.x86_64/Documentation/video4linux/gspca.txt +=================================================================== +--- linux-3.3.x86_64.orig/Documentation/video4linux/gspca.txt ++++ linux-3.3.x86_64/Documentation/video4linux/gspca.txt +@@ -217,6 +217,7 @@ ov534_9 06f8:3003 Hercules Dualpix HD W + sonixj 06f8:3004 Hercules Classic Silver + sonixj 06f8:3008 Hercules Deluxe Optical Glass + pac7302 06f8:3009 Hercules Classic Link ++pac7302 06f8:301b Hercules Link + nw80x 0728:d001 AVerMedia Camguard + spca508 0733:0110 ViewQuest VQ110 + spca501 0733:0401 Intel Create and Share +Index: linux-3.3.x86_64/drivers/media/video/gspca/pac7302.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/gspca/pac7302.c ++++ linux-3.3.x86_64/drivers/media/video/gspca/pac7302.c +@@ -1,8 +1,8 @@ + /* +- * Pixart PAC7302 library +- * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li ++ * Pixart PAC7302 driver + * +- * V4L2 by Jean-Francois Moine ++ * Copyright (C) 2008-2012 Jean-Francois Moine ++ * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li + * + * Separated from Pixart PAC7311 library by Márton Németh + * Camera button input handling by Márton Németh +@@ -63,67 +63,61 @@ + + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +-#define MODULE_NAME "pac7302" +- + #include + #include + #include "gspca.h" ++/* Include pac common sof detection functions */ ++#include "pac_common.h" + +-MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li"); ++MODULE_AUTHOR("Jean-Francois Moine , " ++ "Thomas Kaiser thomas@kaiser-linux.li"); + MODULE_DESCRIPTION("Pixart PAC7302"); + MODULE_LICENSE("GPL"); + ++enum e_ctrl { ++ BRIGHTNESS, ++ CONTRAST, ++ COLORS, ++ WHITE_BALANCE, ++ RED_BALANCE, ++ BLUE_BALANCE, ++ GAIN, ++ AUTOGAIN, ++ EXPOSURE, ++ VFLIP, ++ HFLIP, ++ NCTRLS /* number of controls */ ++}; ++ + /* specific webcam descriptor for pac7302 */ + struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + +- unsigned char brightness; +- unsigned char contrast; +- unsigned char colors; +- unsigned char white_balance; +- unsigned char red_balance; +- unsigned char blue_balance; +- unsigned char gain; +- unsigned char autogain; +- unsigned short exposure; +- __u8 hflip; +- __u8 vflip; ++ struct gspca_ctrl ctrls[NCTRLS]; ++ + u8 flags; + #define FL_HFLIP 0x01 /* mirrored by default */ + #define FL_VFLIP 0x02 /* vertical flipped by default */ + + u8 sof_read; +- u8 autogain_ignore_frames; ++ s8 autogain_ignore_frames; + + atomic_t avg_lum; + }; + + /* 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_setcolors(struct gspca_dev *gspca_dev, __s32 val); +-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); +-static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val); +-static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val); +-static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val); +-static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val); +-static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val); +-static int sd_getbluebalance(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 void setbrightcont(struct gspca_dev *gspca_dev); ++static void setcolors(struct gspca_dev *gspca_dev); ++static void setwhitebalance(struct gspca_dev *gspca_dev); ++static void setredbalance(struct gspca_dev *gspca_dev); ++static void setbluebalance(struct gspca_dev *gspca_dev); ++static void setgain(struct gspca_dev *gspca_dev); ++static void setexposure(struct gspca_dev *gspca_dev); ++static void setautogain(struct gspca_dev *gspca_dev); ++static void sethvflip(struct gspca_dev *gspca_dev); + + static const struct ctrl sd_ctrls[] = { +- { ++[BRIGHTNESS] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, +@@ -132,13 +126,11 @@ static const struct ctrl sd_ctrls[] = { + #define BRIGHTNESS_MAX 0x20 + .maximum = BRIGHTNESS_MAX, + .step = 1, +-#define BRIGHTNESS_DEF 0x10 +- .default_value = BRIGHTNESS_DEF, ++ .default_value = 0x10, + }, +- .set = sd_setbrightness, +- .get = sd_getbrightness, ++ .set_control = setbrightcont + }, +- { ++[CONTRAST] = { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, +@@ -147,13 +139,11 @@ static const struct ctrl sd_ctrls[] = { + #define CONTRAST_MAX 255 + .maximum = CONTRAST_MAX, + .step = 1, +-#define CONTRAST_DEF 127 +- .default_value = CONTRAST_DEF, ++ .default_value = 127, + }, +- .set = sd_setcontrast, +- .get = sd_getcontrast, ++ .set_control = setbrightcont + }, +- { ++[COLORS] = { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, +@@ -162,13 +152,11 @@ static const struct ctrl sd_ctrls[] = { + #define COLOR_MAX 255 + .maximum = COLOR_MAX, + .step = 1, +-#define COLOR_DEF 127 +- .default_value = COLOR_DEF, ++ .default_value = 127 + }, +- .set = sd_setcolors, +- .get = sd_getcolors, ++ .set_control = setcolors + }, +- { ++[WHITE_BALANCE] = { + { + .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE, + .type = V4L2_CTRL_TYPE_INTEGER, +@@ -176,13 +164,11 @@ static const struct ctrl sd_ctrls[] = { + .minimum = 0, + .maximum = 255, + .step = 1, +-#define WHITEBALANCE_DEF 4 +- .default_value = WHITEBALANCE_DEF, ++ .default_value = 4, + }, +- .set = sd_setwhitebalance, +- .get = sd_getwhitebalance, ++ .set_control = setwhitebalance + }, +- { ++[RED_BALANCE] = { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, +@@ -190,13 +176,11 @@ static const struct ctrl sd_ctrls[] = { + .minimum = 0, + .maximum = 3, + .step = 1, +-#define REDBALANCE_DEF 1 +- .default_value = REDBALANCE_DEF, ++ .default_value = 1, + }, +- .set = sd_setredbalance, +- .get = sd_getredbalance, ++ .set_control = setredbalance + }, +- { ++[BLUE_BALANCE] = { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, +@@ -204,29 +188,25 @@ static const struct ctrl sd_ctrls[] = { + .minimum = 0, + .maximum = 3, + .step = 1, +-#define BLUEBALANCE_DEF 1 +- .default_value = BLUEBALANCE_DEF, ++ .default_value = 1, + }, +- .set = sd_setbluebalance, +- .get = sd_getbluebalance, ++ .set_control = setbluebalance + }, +- { ++[GAIN] = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, +-#define GAIN_MAX 255 +- .maximum = GAIN_MAX, ++ .maximum = 255, + .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, ++ .set_control = setgain + }, +- { ++[EXPOSURE] = { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, +@@ -238,10 +218,9 @@ static const struct ctrl sd_ctrls[] = { + #define EXPOSURE_KNEE 133 /* 66 ms / 15 fps */ + .default_value = EXPOSURE_DEF, + }, +- .set = sd_setexposure, +- .get = sd_getexposure, ++ .set_control = setexposure + }, +- { ++[AUTOGAIN] = { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, +@@ -252,10 +231,9 @@ static const struct ctrl sd_ctrls[] = { + #define AUTOGAIN_DEF 1 + .default_value = AUTOGAIN_DEF, + }, +- .set = sd_setautogain, +- .get = sd_getautogain, ++ .set_control = setautogain, + }, +- { ++[HFLIP] = { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, +@@ -263,13 +241,11 @@ static const struct ctrl sd_ctrls[] = { + .minimum = 0, + .maximum = 1, + .step = 1, +-#define HFLIP_DEF 0 +- .default_value = HFLIP_DEF, ++ .default_value = 0, + }, +- .set = sd_sethflip, +- .get = sd_gethflip, ++ .set_control = sethvflip, + }, +- { ++[VFLIP] = { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, +@@ -277,11 +253,9 @@ static const struct ctrl sd_ctrls[] = { + .minimum = 0, + .maximum = 1, + .step = 1, +-#define VFLIP_DEF 0 +- .default_value = VFLIP_DEF, ++ .default_value = 0, + }, +- .set = sd_setvflip, +- .get = sd_getvflip, ++ .set_control = sethvflip + }, + }; + +@@ -290,21 +264,21 @@ static const struct v4l2_pix_format vga_ + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, +- .priv = 0}, ++ }, + }; + + #define LOAD_PAGE3 255 + #define END_OF_SEQUENCE 0 + + /* pac 7302 */ +-static const __u8 init_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[] = { ++static const u8 start_7302[] = { + /* index, len, [value]* */ + 0xff, 1, 0x00, /* page 0 */ + 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80, +@@ -319,7 +293,7 @@ static const __u8 start_7302[] = { + 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11, + 0x00, 0x54, 0x11, + 0x55, 1, 0x00, +- 0x62, 4, 0x10, 0x1e, 0x1e, 0x18, ++ 0x62, 4, 0x10, 0x1e, 0x1e, 0x18, + 0x6b, 1, 0x00, + 0x6e, 3, 0x08, 0x06, 0x00, + 0x72, 3, 0x00, 0xff, 0x00, +@@ -370,7 +344,7 @@ static const __u8 start_7302[] = { + + #define SKIP 0xaa + /* page 3 - the value SKIP says skip the index - see reg_w_page() */ +-static const __u8 page3_7302[] = { ++static const u8 page3_7302[] = { + 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16, + 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00, + 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +@@ -394,7 +368,7 @@ static const __u8 page3_7302[] = { + }; + + static void reg_w_buf(struct gspca_dev *gspca_dev, +- __u8 index, ++ u8 index, + const u8 *buffer, int len) + { + int ret; +@@ -410,7 +384,7 @@ static void reg_w_buf(struct gspca_dev * + index, gspca_dev->usb_buf, len, + 500); + if (ret < 0) { +- pr_err("reg_w_buf failed index 0x%02x, error %d\n", ++ pr_err("reg_w_buf failed i: %02x error %d\n", + index, ret); + gspca_dev->usb_err = ret; + } +@@ -418,8 +392,8 @@ static void reg_w_buf(struct gspca_dev * + + + static void reg_w(struct gspca_dev *gspca_dev, +- __u8 index, +- __u8 value) ++ u8 index, ++ u8 value) + { + int ret; + +@@ -433,14 +407,14 @@ static void reg_w(struct gspca_dev *gspc + 0, index, gspca_dev->usb_buf, 1, + 500); + if (ret < 0) { +- pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n", ++ pr_err("reg_w() failed i: %02x v: %02x error %d\n", + index, value, ret); + gspca_dev->usb_err = ret; + } + } + + static void reg_w_seq(struct gspca_dev *gspca_dev, +- const __u8 *seq, int len) ++ const u8 *seq, int len) + { + while (--len >= 0) { + reg_w(gspca_dev, seq[0], seq[1]); +@@ -450,7 +424,7 @@ static void reg_w_seq(struct gspca_dev * + + /* load the beginning of a page */ + static void reg_w_page(struct gspca_dev *gspca_dev, +- const __u8 *page, int len) ++ const u8 *page, int len) + { + int index; + int ret = 0; +@@ -468,7 +442,7 @@ static void reg_w_page(struct gspca_dev + 0, index, gspca_dev->usb_buf, 1, + 500); + if (ret < 0) { +- pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n", ++ pr_err("reg_w_page() failed i: %02x v: %02x error %d\n", + index, page[index], ret); + gspca_dev->usb_err = ret; + break; +@@ -478,8 +452,8 @@ static void reg_w_page(struct gspca_dev + + /* output a variable sequence */ + static void reg_w_var(struct gspca_dev *gspca_dev, +- const __u8 *seq, +- const __u8 *page3, unsigned int page3_len) ++ const u8 *seq, ++ const u8 *page3, unsigned int page3_len) + { + int index, len; + +@@ -493,11 +467,13 @@ static void reg_w_var(struct gspca_dev * + reg_w_page(gspca_dev, page3, page3_len); + break; + default: ++#ifdef GSPCA_DEBUG + if (len > USB_BUF_SZ) { + PDEBUG(D_ERR|D_STREAM, + "Incorrect variable sequence"); + return; + } ++#endif + while (len > 0) { + if (len < 8) { + reg_w_buf(gspca_dev, +@@ -524,21 +500,11 @@ static int sd_config(struct gspca_dev *g + + cam = &gspca_dev->cam; + +- PDEBUG(D_CONF, "Find Sensor PAC7302"); + cam->cam_mode = vga_mode; /* only 640x480 */ + cam->nmodes = ARRAY_SIZE(vga_mode); + +- sd->brightness = BRIGHTNESS_DEF; +- sd->contrast = CONTRAST_DEF; +- sd->colors = COLOR_DEF; +- sd->white_balance = WHITEBALANCE_DEF; +- sd->red_balance = REDBALANCE_DEF; +- sd->blue_balance = BLUEBALANCE_DEF; +- sd->gain = GAIN_DEF; +- sd->exposure = EXPOSURE_DEF; +- sd->autogain = AUTOGAIN_DEF; +- sd->hflip = HFLIP_DEF; +- sd->vflip = VFLIP_DEF; ++ gspca_dev->cam.ctrls = sd->ctrls; ++ + sd->flags = id->driver_info; + return 0; + } +@@ -548,19 +514,19 @@ static void setbrightcont(struct gspca_d + { + struct sd *sd = (struct sd *) gspca_dev; + int i, v; +- static const __u8 max[10] = ++ static const u8 max[10] = + {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb, + 0xd4, 0xec}; +- static const __u8 delta[10] = ++ 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) ++ v += (sd->ctrls[BRIGHTNESS].val - BRIGHTNESS_MAX) + * 150 / BRIGHTNESS_MAX; /* 200 ? */ +- v -= delta[i] * sd->contrast / CONTRAST_MAX; ++ v -= delta[i] * sd->ctrls[CONTRAST].val / CONTRAST_MAX; + if (v < 0) + v = 0; + else if (v > 0xff) +@@ -584,12 +550,11 @@ static void setcolors(struct gspca_dev * + reg_w(gspca_dev, 0x11, 0x01); + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + for (i = 0; i < 9; i++) { +- v = a[i] * sd->colors / COLOR_MAX + b[i]; ++ v = a[i] * sd->ctrls[COLORS].val / 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 setwhitebalance(struct gspca_dev *gspca_dev) +@@ -597,10 +562,9 @@ static void setwhitebalance(struct gspca + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ +- reg_w(gspca_dev, 0xc6, sd->white_balance); ++ reg_w(gspca_dev, 0xc6, sd->ctrls[WHITE_BALANCE].val); + + reg_w(gspca_dev, 0xdc, 0x01); +- PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance); + } + + static void setredbalance(struct gspca_dev *gspca_dev) +@@ -608,10 +572,9 @@ static void setredbalance(struct gspca_d + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ +- reg_w(gspca_dev, 0xc5, sd->red_balance); ++ reg_w(gspca_dev, 0xc5, sd->ctrls[RED_BALANCE].val); + + reg_w(gspca_dev, 0xdc, 0x01); +- PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance); + } + + static void setbluebalance(struct gspca_dev *gspca_dev) +@@ -619,10 +582,9 @@ static void setbluebalance(struct gspca_ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ +- reg_w(gspca_dev, 0xc7, sd->blue_balance); ++ reg_w(gspca_dev, 0xc7, sd->ctrls[BLUE_BALANCE].val); + + reg_w(gspca_dev, 0xdc, 0x01); +- PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance); + } + + static void setgain(struct gspca_dev *gspca_dev) +@@ -630,7 +592,7 @@ static void setgain(struct gspca_dev *gs + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ +- reg_w(gspca_dev, 0x10, sd->gain >> 3); ++ reg_w(gspca_dev, 0x10, sd->ctrls[GAIN].val >> 3); + + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); +@@ -639,13 +601,13 @@ static void setgain(struct gspca_dev *gs + static void setexposure(struct gspca_dev *gspca_dev) + { + struct sd *sd = (struct sd *) gspca_dev; +- __u8 clockdiv; +- __u16 exposure; ++ u8 clockdiv; ++ u16 exposure; + + /* register 2 of frame 3 contains the clock divider configuring the + no fps according to the formula: 90 / reg. sd->exposure is the + desired exposure time in 0.5 ms. */ +- clockdiv = (90 * sd->exposure + 1999) / 2000; ++ clockdiv = (90 * sd->ctrls[EXPOSURE].val + 1999) / 2000; + + /* Note clockdiv = 3 also works, but when running at 30 fps, depending + on the scene being recorded, the camera switches to another +@@ -664,7 +626,7 @@ static void setexposure(struct gspca_dev + + /* frame exposure time in ms = 1000 * clockdiv / 90 -> + exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */ +- exposure = (sd->exposure * 45 * 448) / (1000 * clockdiv); ++ exposure = (sd->ctrls[EXPOSURE].val * 45 * 448) / (1000 * clockdiv); + /* 0 = use full frametime, 448 = no exposure, reverse it */ + exposure = 448 - exposure; + +@@ -677,15 +639,35 @@ static void setexposure(struct gspca_dev + reg_w(gspca_dev, 0x11, 0x01); + } + ++static void setautogain(struct gspca_dev *gspca_dev) ++{ ++ struct sd *sd = (struct sd *) 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->ctrls[AUTOGAIN].val) { ++ sd->ctrls[EXPOSURE].val = EXPOSURE_DEF; ++ sd->ctrls[GAIN].val = GAIN_DEF; ++ sd->autogain_ignore_frames = ++ PAC_AUTOGAIN_IGNORE_FRAMES; ++ } else { ++ sd->autogain_ignore_frames = -1; ++ } ++ setexposure(gspca_dev); ++ setgain(gspca_dev); ++} ++ + static void sethvflip(struct gspca_dev *gspca_dev) + { + struct sd *sd = (struct sd *) gspca_dev; + u8 data, hflip, vflip; + +- hflip = sd->hflip; ++ hflip = sd->ctrls[HFLIP].val; + if (sd->flags & FL_HFLIP) + hflip = !hflip; +- vflip = sd->vflip; ++ vflip = sd->ctrls[VFLIP].val; + if (sd->flags & FL_VFLIP) + vflip = !vflip; + +@@ -708,8 +690,6 @@ static int sd_start(struct gspca_dev *gs + { + struct sd *sd = (struct sd *) gspca_dev; + +- sd->sof_read = 0; +- + reg_w_var(gspca_dev, start_7302, + page3_7302, sizeof(page3_7302)); + setbrightcont(gspca_dev); +@@ -717,15 +697,13 @@ static int sd_start(struct gspca_dev *gs + setwhitebalance(gspca_dev); + setredbalance(gspca_dev); + setbluebalance(gspca_dev); +- setgain(gspca_dev); +- setexposure(gspca_dev); ++ setautogain(gspca_dev); + sethvflip(gspca_dev); + + /* only resolution 640x480 is supported for pac7302 */ + + sd->sof_read = 0; +- sd->autogain_ignore_frames = 0; +- atomic_set(&sd->avg_lum, -1); ++ atomic_set(&sd->avg_lum, 270 + sd->ctrls[BRIGHTNESS].val); + + /* start stream */ + reg_w(gspca_dev, 0xff, 0x01); +@@ -751,8 +729,10 @@ static void sd_stop0(struct gspca_dev *g + reg_w(gspca_dev, 0x78, 0x40); + } + +-/* Include pac common sof detection functions */ +-#include "pac_common.h" ++/* !! coarse_grained_expo_autogain is not used !! */ ++#define exp_too_low_cnt flags ++#define exp_too_high_cnt sof_read ++#include "autogain_functions.h" + + static void do_autogain(struct gspca_dev *gspca_dev) + { +@@ -761,65 +741,44 @@ static void do_autogain(struct gspca_dev + int desired_lum; + const int deadzone = 30; + +- if (avg_lum == -1) ++ if (sd->autogain_ignore_frames < 0) + return; + +- desired_lum = 270 + sd->brightness; +- +- if (sd->autogain_ignore_frames > 0) ++ 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)) ++ } else { ++ desired_lum = 270 + sd->ctrls[BRIGHTNESS].val; ++ ++ auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum, ++ deadzone, GAIN_KNEE, EXPOSURE_KNEE); + sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; ++ } + } + +-/* JPEG header, part 1 */ +-static const unsigned char pac_jpeg_header1[] = { +- 0xff, 0xd8, /* SOI: Start of Image */ +- +- 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */ +- 0x00, 0x11, /* length = 17 bytes (including this length field) */ +- 0x08 /* Precision: 8 */ +- /* 2 bytes is placed here: number of image lines */ +- /* 2 bytes is placed here: samples per line */ +-}; +- +-/* JPEG header, continued */ +-static const unsigned char pac_jpeg_header2[] = { +- 0x03, /* Number of image components: 3 */ +- 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */ +- 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */ +- 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */ +- +- 0xff, 0xda, /* SOS: Start Of Scan */ +- 0x00, 0x0c, /* length = 12 bytes (including this length field) */ +- 0x03, /* number of components: 3 */ +- 0x01, 0x00, /* selector 1, table 0x00 */ +- 0x02, 0x11, /* selector 2, table 0x11 */ +- 0x03, 0x11, /* selector 3, table 0x11 */ +- 0x00, 0x3f, /* Spectral selection: 0 .. 63 */ +- 0x00 /* Successive approximation: 0 */ ++/* JPEG header */ ++static const u8 jpeg_header[] = { ++ 0xff, 0xd8, /* SOI: Start of Image */ ++ ++ 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */ ++ 0x00, 0x11, /* length = 17 bytes (including this length field) */ ++ 0x08, /* Precision: 8 */ ++ 0x02, 0x80, /* height = 640 (image rotated) */ ++ 0x01, 0xe0, /* width = 480 */ ++ 0x03, /* Number of image components: 3 */ ++ 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */ ++ 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */ ++ 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */ ++ ++ 0xff, 0xda, /* SOS: Start Of Scan */ ++ 0x00, 0x0c, /* length = 12 bytes (including this length field) */ ++ 0x03, /* number of components: 3 */ ++ 0x01, 0x00, /* selector 1, table 0x00 */ ++ 0x02, 0x11, /* selector 2, table 0x11 */ ++ 0x03, 0x11, /* selector 3, table 0x11 */ ++ 0x00, 0x3f, /* Spectral selection: 0 .. 63 */ ++ 0x00 /* Successive approximation: 0 */ + }; + +-static void pac_start_frame(struct gspca_dev *gspca_dev, +- __u16 lines, __u16 samples_per_line) +-{ +- unsigned char tmpbuf[4]; +- +- gspca_frame_add(gspca_dev, FIRST_PACKET, +- pac_jpeg_header1, sizeof(pac_jpeg_header1)); +- +- tmpbuf[0] = lines >> 8; +- tmpbuf[1] = lines & 0xff; +- tmpbuf[2] = samples_per_line >> 8; +- tmpbuf[3] = samples_per_line & 0xff; +- +- gspca_frame_add(gspca_dev, INTER_PACKET, +- tmpbuf, sizeof(tmpbuf)); +- gspca_frame_add(gspca_dev, INTER_PACKET, +- pac_jpeg_header2, sizeof(pac_jpeg_header2)); +-} +- + /* this function is run at interrupt level */ + static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ +@@ -827,7 +786,7 @@ static void sd_pkt_scan(struct gspca_dev + { + struct sd *sd = (struct sd *) gspca_dev; + u8 *image; +- unsigned char *sof; ++ u8 *sof; + + sof = pac_find_sof(&sd->sof_read, data, len); + if (sof) { +@@ -864,234 +823,21 @@ static void sd_pkt_scan(struct gspca_dev + 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 */ + /* The PAC7302 has the image rotated 90 degrees */ +- pac_start_frame(gspca_dev, +- gspca_dev->width, gspca_dev->height); ++ gspca_frame_add(gspca_dev, FIRST_PACKET, ++ jpeg_header, sizeof jpeg_header); + } + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); + } + +-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) +- setbrightcont(gspca_dev); +- return gspca_dev->usb_err; +-} +- +-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- +- *val = sd->brightness; +- return 0; +-} +- +-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) +- setbrightcont(gspca_dev); +- return gspca_dev->usb_err; +-} +- +-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- +- *val = sd->contrast; +- return 0; +-} +- +-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- +- sd->colors = val; +- if (gspca_dev->streaming) +- setcolors(gspca_dev); +- return gspca_dev->usb_err; +-} +- +-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- +- *val = sd->colors; +- return 0; +-} +- +-static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- +- sd->white_balance = val; +- if (gspca_dev->streaming) +- setwhitebalance(gspca_dev); +- return gspca_dev->usb_err; +-} +- +-static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- +- *val = sd->white_balance; +- return 0; +-} +- +-static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- +- sd->red_balance = val; +- if (gspca_dev->streaming) +- setredbalance(gspca_dev); +- return gspca_dev->usb_err; +-} +- +-static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- +- *val = sd->red_balance; +- return 0; +-} +- +-static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- +- sd->blue_balance = val; +- if (gspca_dev->streaming) +- setbluebalance(gspca_dev); +- return gspca_dev->usb_err; +-} +- +-static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- +- *val = sd->blue_balance; +- 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 gspca_dev->usb_err; +-} +- +-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 gspca_dev->usb_err; +-} +- +-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; +- /* 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 gspca_dev->usb_err; +-} +- +-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- +- *val = sd->autogain; +- 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 gspca_dev->usb_err; +-} +- +-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 gspca_dev->usb_err; +-} +- +-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- +- *val = sd->vflip; +- return 0; +-} +- + #ifdef CONFIG_VIDEO_ADV_DEBUG + static int sd_dbg_s_register(struct gspca_dev *gspca_dev, + struct v4l2_dbg_register *reg) + { +- __u8 index; +- __u8 value; ++ u8 index; ++ u8 value; + + /* reg->reg: bit0..15: reserved for register index (wIndex is 16bit + long on the USB bus) +@@ -1103,8 +849,8 @@ static int sd_dbg_s_register(struct gspc + ) { + /* Currently writing to page 0 is only supported. */ + /* reg_w() only supports 8bit index */ +- index = reg->reg & 0x000000ff; +- value = reg->val & 0x000000ff; ++ index = reg->reg; ++ value = reg->val; + + /* Note that there shall be no access to other page + by any other function between the page swith and +@@ -1165,7 +911,7 @@ static int sd_int_pkt_scan(struct gspca_ + + /* sub-driver description for pac7302 */ + static const struct sd_desc sd_desc = { +- .name = MODULE_NAME, ++ .name = KBUILD_MODNAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, +@@ -1187,6 +933,7 @@ static const struct sd_desc sd_desc = { + /* -- module initialisation -- */ + static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x06f8, 0x3009)}, ++ {USB_DEVICE(0x06f8, 0x301b)}, + {USB_DEVICE(0x093a, 0x2620)}, + {USB_DEVICE(0x093a, 0x2621)}, + {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP}, +@@ -1211,7 +958,7 @@ static int sd_probe(struct usb_interface + } + + static struct usb_driver sd_driver = { +- .name = MODULE_NAME, ++ .name = KBUILD_MODNAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +Index: linux-3.3.x86_64/drivers/media/video/gspca/sonixj.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/gspca/sonixj.c ++++ linux-3.3.x86_64/drivers/media/video/gspca/sonixj.c +@@ -39,7 +39,9 @@ enum e_ctrl { + BLUE, + RED, + GAMMA, ++ EXPOSURE, + AUTOGAIN, ++ GAIN, + HFLIP, + VFLIP, + SHARPNESS, +@@ -131,7 +133,9 @@ static void setcontrast(struct gspca_dev + static void setcolors(struct gspca_dev *gspca_dev); + static void setredblue(struct gspca_dev *gspca_dev); + static void setgamma(struct gspca_dev *gspca_dev); +-static void setautogain(struct gspca_dev *gspca_dev); ++static void setexposure(struct gspca_dev *gspca_dev); ++static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); ++static void setgain(struct gspca_dev *gspca_dev); + static void sethvflip(struct gspca_dev *gspca_dev); + static void setsharpness(struct gspca_dev *gspca_dev); + static void setillum(struct gspca_dev *gspca_dev); +@@ -213,6 +217,18 @@ static const struct ctrl sd_ctrls[NCTRLS + }, + .set_control = setgamma + }, ++[EXPOSURE] = { ++ { ++ .id = V4L2_CID_EXPOSURE, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .name = "Exposure", ++ .minimum = 500, ++ .maximum = 1500, ++ .step = 1, ++ .default_value = 1024 ++ }, ++ .set_control = setexposure ++ }, + [AUTOGAIN] = { + { + .id = V4L2_CID_AUTOGAIN, +@@ -223,7 +239,19 @@ static const struct ctrl sd_ctrls[NCTRLS + .step = 1, + .default_value = 1 + }, +- .set_control = setautogain ++ .set = sd_setautogain, ++ }, ++[GAIN] = { ++ { ++ .id = V4L2_CID_GAIN, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .name = "Gain", ++ .minimum = 4, ++ .maximum = 49, ++ .step = 1, ++ .default_value = 15 ++ }, ++ .set_control = setgain + }, + [HFLIP] = { + { +@@ -290,60 +318,87 @@ static const struct ctrl sd_ctrls[NCTRLS + + /* table of the disabled controls */ + static const __u32 ctrl_dis[] = { +-[SENSOR_ADCM1700] = (1 << AUTOGAIN) | ++[SENSOR_ADCM1700] = (1 << EXPOSURE) | ++ (1 << AUTOGAIN) | ++ (1 << GAIN) | + (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), + +-[SENSOR_GC0307] = (1 << HFLIP) | ++[SENSOR_GC0307] = (1 << EXPOSURE) | ++ (1 << GAIN) | ++ (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), + +-[SENSOR_HV7131R] = (1 << HFLIP) | ++[SENSOR_HV7131R] = (1 << EXPOSURE) | ++ (1 << GAIN) | ++ (1 << HFLIP) | + (1 << FREQ), + +-[SENSOR_MI0360] = (1 << HFLIP) | ++[SENSOR_MI0360] = (1 << EXPOSURE) | ++ (1 << GAIN) | ++ (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), + +-[SENSOR_MI0360B] = (1 << HFLIP) | ++[SENSOR_MI0360B] = (1 << EXPOSURE) | ++ (1 << GAIN) | ++ (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), + +-[SENSOR_MO4000] = (1 << HFLIP) | ++[SENSOR_MO4000] = (1 << EXPOSURE) | ++ (1 << GAIN) | ++ (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), + +-[SENSOR_MT9V111] = (1 << HFLIP) | ++[SENSOR_MT9V111] = (1 << EXPOSURE) | ++ (1 << GAIN) | ++ (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), + +-[SENSOR_OM6802] = (1 << HFLIP) | ++[SENSOR_OM6802] = (1 << EXPOSURE) | ++ (1 << GAIN) | ++ (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), + +-[SENSOR_OV7630] = (1 << HFLIP), +- +-[SENSOR_OV7648] = (1 << HFLIP), +- +-[SENSOR_OV7660] = (1 << AUTOGAIN) | ++[SENSOR_OV7630] = (1 << EXPOSURE) | ++ (1 << GAIN) | ++ (1 << HFLIP), ++ ++[SENSOR_OV7648] = (1 << EXPOSURE) | ++ (1 << GAIN) | ++ (1 << HFLIP), ++ ++[SENSOR_OV7660] = (1 << EXPOSURE) | ++ (1 << AUTOGAIN) | ++ (1 << GAIN) | + (1 << HFLIP) | + (1 << VFLIP), + +-[SENSOR_PO1030] = (1 << AUTOGAIN) | ++[SENSOR_PO1030] = (1 << EXPOSURE) | ++ (1 << AUTOGAIN) | ++ (1 << GAIN) | + (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), + +-[SENSOR_PO2030N] = (1 << AUTOGAIN) | +- (1 << FREQ), ++[SENSOR_PO2030N] = (1 << FREQ), + +-[SENSOR_SOI768] = (1 << AUTOGAIN) | ++[SENSOR_SOI768] = (1 << EXPOSURE) | ++ (1 << AUTOGAIN) | ++ (1 << GAIN) | + (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), + +-[SENSOR_SP80708] = (1 << AUTOGAIN) | ++[SENSOR_SP80708] = (1 << EXPOSURE) | ++ (1 << AUTOGAIN) | ++ (1 << GAIN) | + (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), +@@ -1242,14 +1297,6 @@ static const u8 po2030n_sensor_param1[][ + {0xa1, 0x6e, 0x05, 0x6f, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x6e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x6e, 0x07, 0x25, 0x00, 0x00, 0x00, 0x10}, +- {0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10}, +- {0xc1, 0x6e, 0x16, 0x52, 0x40, 0x48, 0x00, 0x10}, +-/*after start*/ +- {0xa1, 0x6e, 0x15, 0x0f, 0x00, 0x00, 0x00, 0x10}, +- {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */ +- {0xa1, 0x6e, 0x1a, 0x05, 0x00, 0x00, 0x00, 0x10}, +- {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */ +- {0xa1, 0x6e, 0x1b, 0x53, 0x00, 0x00, 0x00, 0x10}, + {} + }; + +@@ -1858,7 +1905,7 @@ static int sd_init(struct gspca_dev *gsp + return gspca_dev->usb_err; + } + +-static u32 setexposure(struct gspca_dev *gspca_dev, ++static u32 expo_adjust(struct gspca_dev *gspca_dev, + u32 expo) + { + struct sd *sd = (struct sd *) gspca_dev; +@@ -1982,28 +2029,28 @@ static void setbrightness(struct gspca_d + expo = 0x002dc6c0; + else if (expo < 0x02a0) + expo = 0x02a0; +- sd->exposure = setexposure(gspca_dev, expo); ++ sd->exposure = expo_adjust(gspca_dev, expo); + break; + case SENSOR_MI0360: + case SENSOR_MO4000: + expo = brightness << 4; +- sd->exposure = setexposure(gspca_dev, expo); ++ sd->exposure = expo_adjust(gspca_dev, expo); + break; + case SENSOR_MI0360B: + expo = brightness << 2; +- sd->exposure = setexposure(gspca_dev, expo); ++ sd->exposure = expo_adjust(gspca_dev, expo); + break; + case SENSOR_GC0307: + expo = brightness; +- sd->exposure = setexposure(gspca_dev, expo); ++ sd->exposure = expo_adjust(gspca_dev, expo); + return; /* don't set the Y offset */ + case SENSOR_MT9V111: + expo = brightness << 2; +- sd->exposure = setexposure(gspca_dev, expo); ++ sd->exposure = expo_adjust(gspca_dev, expo); + return; /* don't set the Y offset */ + case SENSOR_OM6802: + expo = brightness << 2; +- sd->exposure = setexposure(gspca_dev, expo); ++ sd->exposure = expo_adjust(gspca_dev, expo); + return; /* Y offset already set */ + } + +@@ -2112,6 +2159,23 @@ static void setgamma(struct gspca_dev *g + reg_w(gspca_dev, 0x20, gamma, sizeof gamma); + } + ++static void setexposure(struct gspca_dev *gspca_dev) ++{ ++ struct sd *sd = (struct sd *) gspca_dev; ++ ++ if (sd->sensor == SENSOR_PO2030N) { ++ u8 rexpo[] = /* 1a: expo H, 1b: expo M */ ++ {0xa1, 0x6e, 0x1a, 0x00, 0x40, 0x00, 0x00, 0x10}; ++ ++ rexpo[3] = sd->ctrls[EXPOSURE].val >> 8; ++ i2c_w8(gspca_dev, rexpo); ++ msleep(6); ++ rexpo[2] = 0x1b; ++ rexpo[3] = sd->ctrls[EXPOSURE].val; ++ i2c_w8(gspca_dev, rexpo); ++ } ++} ++ + static void setautogain(struct gspca_dev *gspca_dev) + { + struct sd *sd = (struct sd *) gspca_dev; +@@ -2139,6 +2203,19 @@ static void setautogain(struct gspca_dev + sd->ag_cnt = -1; + } + ++static void setgain(struct gspca_dev *gspca_dev) ++{ ++ struct sd *sd = (struct sd *) gspca_dev; ++ ++ if (sd->sensor == SENSOR_PO2030N) { ++ u8 rgain[] = /* 15: gain */ ++ {0xa1, 0x6e, 0x15, 0x00, 0x40, 0x00, 0x00, 0x15}; ++ ++ rgain[3] = sd->ctrls[GAIN].val; ++ i2c_w8(gspca_dev, rgain); ++ } ++} ++ + static void sethvflip(struct gspca_dev *gspca_dev) + { + struct sd *sd = (struct sd *) gspca_dev; +@@ -2623,6 +2700,10 @@ static int sd_start(struct gspca_dev *gs + setcontrast(gspca_dev); + setcolors(gspca_dev); + setautogain(gspca_dev); ++ if (!(gspca_dev->ctrl_inac & ((1 << EXPOSURE) | (1 << GAIN)))) { ++ setexposure(gspca_dev); ++ setgain(gspca_dev); ++ } + setfreq(gspca_dev); + + sd->pktsz = sd->npkt = 0; +@@ -2719,6 +2800,12 @@ static void sd_stop0(struct gspca_dev *g + } + } + ++/* !! coarse_grained_expo_autogain is not used !! */ ++#define exp_too_low_cnt bridge ++#define exp_too_high_cnt sensor ++ ++#include "autogain_functions.h" ++ + static void do_autogain(struct gspca_dev *gspca_dev) + { + struct sd *sd = (struct sd *) gspca_dev; +@@ -2736,6 +2823,13 @@ static void do_autogain(struct gspca_dev + + delta = atomic_read(&sd->avg_lum); + PDEBUG(D_FRAM, "mean lum %d", delta); ++ ++ if (sd->sensor == SENSOR_PO2030N) { ++ auto_gain_n_exposure(gspca_dev, delta, luma_mean, luma_delta, ++ 15, 1024); ++ return; ++ } ++ + if (delta < luma_mean - luma_delta || + delta > luma_mean + luma_delta) { + switch (sd->sensor) { +@@ -2744,7 +2838,7 @@ static void do_autogain(struct gspca_dev + expotimes += (luma_mean - delta) >> 6; + if (expotimes < 0) + expotimes = 0; +- sd->exposure = setexposure(gspca_dev, ++ sd->exposure = expo_adjust(gspca_dev, + (unsigned int) expotimes); + break; + case SENSOR_HV7131R: +@@ -2752,7 +2846,7 @@ static void do_autogain(struct gspca_dev + expotimes += (luma_mean - delta) >> 4; + if (expotimes < 0) + expotimes = 0; +- sd->exposure = setexposure(gspca_dev, ++ sd->exposure = expo_adjust(gspca_dev, + (unsigned int) (expotimes << 8)); + break; + case SENSOR_OM6802: +@@ -2761,7 +2855,7 @@ static void do_autogain(struct gspca_dev + expotimes += (luma_mean - delta) >> 2; + if (expotimes < 0) + expotimes = 0; +- sd->exposure = setexposure(gspca_dev, ++ sd->exposure = expo_adjust(gspca_dev, + (unsigned int) expotimes); + setredblue(gspca_dev); + break; +@@ -2773,7 +2867,7 @@ static void do_autogain(struct gspca_dev + expotimes += (luma_mean - delta) >> 6; + if (expotimes < 0) + expotimes = 0; +- sd->exposure = setexposure(gspca_dev, ++ sd->exposure = expo_adjust(gspca_dev, + (unsigned int) expotimes); + setredblue(gspca_dev); + break; +@@ -2948,16 +3042,18 @@ marker_found: + } + } + +-static int sd_get_jcomp(struct gspca_dev *gspca_dev, +- struct v4l2_jpegcompression *jcomp) ++static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) + { + struct sd *sd = (struct sd *) gspca_dev; + +- memset(jcomp, 0, sizeof *jcomp); +- jcomp->quality = sd->quality; +- jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT +- | V4L2_JPEG_MARKER_DQT; +- return 0; ++ sd->ctrls[AUTOGAIN].val = val; ++ if (val) ++ gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN); ++ else ++ gspca_dev->ctrl_inac &= ~(1 << EXPOSURE) & ~(1 << GAIN); ++ if (gspca_dev->streaming) ++ setautogain(gspca_dev); ++ return gspca_dev->usb_err; + } + + static int sd_querymenu(struct gspca_dev *gspca_dev, +@@ -3012,7 +3108,6 @@ static const struct sd_desc sd_desc = { + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, + .dq_callback = do_autogain, +- .get_jcomp = sd_get_jcomp, + .querymenu = sd_querymenu, + #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .int_pkt_scan = sd_int_pkt_scan, +Index: linux-3.3.x86_64/drivers/media/video/gspca/zc3xx.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/gspca/zc3xx.c ++++ linux-3.3.x86_64/drivers/media/video/gspca/zc3xx.c +@@ -1,7 +1,7 @@ + /* +- * Z-Star/Vimicro zc301/zc302p/vc30x library ++ * Z-Star/Vimicro zc301/zc302p/vc30x driver + * +- * Copyright (C) 2009-2011 Jean-Francois Moine ++ * Copyright (C) 2009-2012 Jean-Francois Moine + * Copyright (C) 2004 2005 2006 Michel Xhaard mxhaard@magic.fr + * + * This program is free software; you can redistribute it and/or modify +@@ -21,8 +21,6 @@ + + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +-#define MODULE_NAME "zc3xx" +- + #include + #include "gspca.h" + #include "jpeg.h" +@@ -34,7 +32,7 @@ MODULE_LICENSE("GPL"); + + static int force_sensor = -1; + +-#define QUANT_VAL 1 /* quantization table */ ++#define REG08_DEF 3 /* default JPEG compression (70%) */ + #include "zc3xx-reg.h" + + /* controls */ +@@ -46,6 +44,7 @@ enum e_ctrl { + AUTOGAIN, + LIGHTFREQ, + SHARPNESS, ++ QUALITY, + NCTRLS /* number of controls */ + }; + +@@ -57,10 +56,10 @@ struct sd { + + struct gspca_ctrl ctrls[NCTRLS]; + +- u8 quality; /* image quality */ +-#define QUALITY_MIN 50 +-#define QUALITY_MAX 80 +-#define QUALITY_DEF 70 ++ struct work_struct work; ++ struct workqueue_struct *work_thread; ++ ++ u8 reg08; /* webcam compression quality */ + + u8 bridge; + u8 sensor; /* Type of image sensor chip */ +@@ -101,6 +100,7 @@ static void setexposure(struct gspca_dev + static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); + static void setlightfreq(struct gspca_dev *gspca_dev); + static void setsharpness(struct gspca_dev *gspca_dev); ++static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val); + + static const struct ctrl sd_ctrls[NCTRLS] = { + [BRIGHTNESS] = { +@@ -188,6 +188,18 @@ static const struct ctrl sd_ctrls[NCTRLS + }, + .set_control = setsharpness + }, ++[QUALITY] = { ++ { ++ .id = V4L2_CID_JPEG_COMPRESSION_QUALITY, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .name = "Compression Quality", ++ .minimum = 40, ++ .maximum = 70, ++ .step = 1, ++ .default_value = 70 /* updated in sd_init() */ ++ }, ++ .set = sd_setquality ++ }, + }; + + static const struct v4l2_pix_format vga_mode[] = { +@@ -229,6 +241,9 @@ static const struct v4l2_pix_format sif_ + .priv = 0}, + }; + ++/* bridge reg08 -> JPEG quality conversion table */ ++static u8 jpeg_qual[] = {40, 50, 60, 70, /*80*/}; ++ + /* usb exchanges */ + struct usb_action { + u8 req; +@@ -3894,7 +3909,6 @@ static const struct usb_action pas106b_I + /* Gains */ + {0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, +- {0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + /* Auto correction */ + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, +@@ -5640,7 +5654,7 @@ static const struct usb_action gc0303_No + {} + }; + +-static u8 reg_r_i(struct gspca_dev *gspca_dev, ++static u8 reg_r(struct gspca_dev *gspca_dev, + u16 index) + { + int ret; +@@ -5655,24 +5669,14 @@ static u8 reg_r_i(struct gspca_dev *gspc + index, gspca_dev->usb_buf, 1, + 500); + if (ret < 0) { +- pr_err("reg_r_i err %d\n", ret); ++ pr_err("reg_r err %d\n", ret); + gspca_dev->usb_err = ret; + return 0; + } + return gspca_dev->usb_buf[0]; + } + +-static u8 reg_r(struct gspca_dev *gspca_dev, +- u16 index) +-{ +- u8 ret; +- +- ret = reg_r_i(gspca_dev, index); +- PDEBUG(D_USBI, "reg r [%04x] -> %02x", index, ret); +- return ret; +-} +- +-static void reg_w_i(struct gspca_dev *gspca_dev, ++static void reg_w(struct gspca_dev *gspca_dev, + u8 value, + u16 index) + { +@@ -5692,14 +5696,6 @@ static void reg_w_i(struct gspca_dev *gs + } + } + +-static void reg_w(struct gspca_dev *gspca_dev, +- u8 value, +- u16 index) +-{ +- PDEBUG(D_USBO, "reg w [%04x] = %02x", index, value); +- reg_w_i(gspca_dev, value, index); +-} +- + static u16 i2c_read(struct gspca_dev *gspca_dev, + u8 reg) + { +@@ -5708,16 +5704,14 @@ static u16 i2c_read(struct gspca_dev *gs + + if (gspca_dev->usb_err < 0) + return 0; +- reg_w_i(gspca_dev, reg, 0x0092); +- reg_w_i(gspca_dev, 0x02, 0x0090); /* <- read command */ ++ reg_w(gspca_dev, reg, 0x0092); ++ reg_w(gspca_dev, 0x02, 0x0090); /* <- read command */ + msleep(20); +- retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ ++ retbyte = reg_r(gspca_dev, 0x0091); /* read status */ + if (retbyte != 0x00) + pr_err("i2c_r status error %02x\n", retbyte); +- retval = reg_r_i(gspca_dev, 0x0095); /* read Lowbyte */ +- retval |= reg_r_i(gspca_dev, 0x0096) << 8; /* read Hightbyte */ +- PDEBUG(D_USBI, "i2c r [%02x] -> %04x (%02x)", +- reg, retval, retbyte); ++ retval = reg_r(gspca_dev, 0x0095); /* read Lowbyte */ ++ retval |= reg_r(gspca_dev, 0x0096) << 8; /* read Hightbyte */ + return retval; + } + +@@ -5730,16 +5724,14 @@ static u8 i2c_write(struct gspca_dev *gs + + if (gspca_dev->usb_err < 0) + return 0; +- reg_w_i(gspca_dev, reg, 0x92); +- reg_w_i(gspca_dev, valL, 0x93); +- reg_w_i(gspca_dev, valH, 0x94); +- reg_w_i(gspca_dev, 0x01, 0x90); /* <- write command */ ++ reg_w(gspca_dev, reg, 0x92); ++ reg_w(gspca_dev, valL, 0x93); ++ reg_w(gspca_dev, valH, 0x94); ++ reg_w(gspca_dev, 0x01, 0x90); /* <- write command */ + msleep(1); +- retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ ++ retbyte = reg_r(gspca_dev, 0x0091); /* read status */ + if (retbyte != 0x00) + pr_err("i2c_w status error %02x\n", retbyte); +- PDEBUG(D_USBO, "i2c w [%02x] = %02x%02x (%02x)", +- reg, valH, valL, retbyte); + return retbyte; + } + +@@ -5906,6 +5898,8 @@ static void getexposure(struct gspca_dev + { + struct sd *sd = (struct sd *) gspca_dev; + ++ if (sd->sensor != SENSOR_HV7131R) ++ return; + sd->ctrls[EXPOSURE].val = (i2c_read(gspca_dev, 0x25) << 9) + | (i2c_read(gspca_dev, 0x26) << 1) + | (i2c_read(gspca_dev, 0x27) >> 7); +@@ -5916,6 +5910,8 @@ static void setexposure(struct gspca_dev + struct sd *sd = (struct sd *) gspca_dev; + int val; + ++ if (sd->sensor != SENSOR_HV7131R) ++ return; + val = sd->ctrls[EXPOSURE].val; + i2c_write(gspca_dev, 0x25, val >> 9, 0x00); + i2c_write(gspca_dev, 0x26, val >> 1, 0x00); +@@ -5925,32 +5921,20 @@ static void setexposure(struct gspca_dev + static void setquality(struct gspca_dev *gspca_dev) + { + struct sd *sd = (struct sd *) gspca_dev; +- u8 frxt; ++ s8 reg07; + ++ reg07 = 0; + switch (sd->sensor) { +- case SENSOR_ADCM2700: +- case SENSOR_GC0305: +- case SENSOR_HV7131B: +- case SENSOR_HV7131R: + case SENSOR_OV7620: ++ reg07 = 0x30; ++ break; ++ case SENSOR_HV7131R: + case SENSOR_PAS202B: +- case SENSOR_PO2030: +- return; ++ return; /* done by work queue */ + } +-/*fixme: is it really 0008 0007 0018 for all other sensors? */ +- reg_w(gspca_dev, QUANT_VAL, 0x0008); +- frxt = 0x30; +- reg_w(gspca_dev, frxt, 0x0007); +-#if QUANT_VAL == 0 || QUANT_VAL == 1 || QUANT_VAL == 2 +- frxt = 0xff; +-#elif QUANT_VAL == 3 +- frxt = 0xf0; +-#elif QUANT_VAL == 4 +- frxt = 0xe0; +-#else +- frxt = 0x20; +-#endif +- reg_w(gspca_dev, frxt, 0x0018); ++ reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING); ++ if (reg07 != 0) ++ reg_w(gspca_dev, reg07, 0x0007); + } + + /* Matches the sensor's internal frame rate to the lighting frequency. +@@ -6084,6 +6068,115 @@ static void setautogain(struct gspca_dev + reg_w(gspca_dev, autoval, 0x0180); + } + ++/* update the transfer parameters */ ++/* This function is executed from a work queue. */ ++/* The exact use of the bridge registers 07 and 08 is not known. ++ * The following algorithm has been adapted from ms-win traces */ ++static void transfer_update(struct work_struct *work) ++{ ++ struct sd *sd = container_of(work, struct sd, work); ++ struct gspca_dev *gspca_dev = &sd->gspca_dev; ++ int change, good; ++ u8 reg07, reg11; ++ ++ /* synchronize with the main driver and initialize the registers */ ++ mutex_lock(&gspca_dev->usb_lock); ++ reg07 = 0; /* max */ ++ reg_w(gspca_dev, reg07, 0x0007); ++ reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING); ++ mutex_unlock(&gspca_dev->usb_lock); ++ ++ good = 0; ++ for (;;) { ++ msleep(100); ++ ++ /* get the transfer status */ ++ /* the bit 0 of the bridge register 11 indicates overflow */ ++ mutex_lock(&gspca_dev->usb_lock); ++ if (!gspca_dev->present || !gspca_dev->streaming) ++ goto err; ++ reg11 = reg_r(gspca_dev, 0x0011); ++ if (gspca_dev->usb_err < 0 ++ || !gspca_dev->present || !gspca_dev->streaming) ++ goto err; ++ ++ change = reg11 & 0x01; ++ if (change) { /* overflow */ ++ switch (reg07) { ++ case 0: /* max */ ++ reg07 = sd->sensor == SENSOR_HV7131R ++ ? 0x30 : 0x32; ++ if (sd->reg08 != 0) { ++ change = 3; ++ sd->reg08--; ++ } ++ break; ++ case 0x32: ++ reg07 -= 4; ++ break; ++ default: ++ reg07 -= 2; ++ break; ++ case 2: ++ change = 0; /* already min */ ++ break; ++ } ++ good = 0; ++ } else { /* no overflow */ ++ if (reg07 != 0) { /* if not max */ ++ good++; ++ if (good >= 10) { ++ good = 0; ++ change = 1; ++ reg07 += 2; ++ switch (reg07) { ++ case 0x30: ++ if (sd->sensor == SENSOR_PAS202B) ++ reg07 += 2; ++ break; ++ case 0x32: ++ case 0x34: ++ reg07 = 0; ++ break; ++ } ++ } ++ } else { /* reg07 max */ ++ if (sd->reg08 < sizeof jpeg_qual - 1) { ++ good++; ++ if (good > 10) { ++ sd->reg08++; ++ change = 2; ++ } ++ } ++ } ++ } ++ if (change) { ++ if (change & 1) { ++ reg_w(gspca_dev, reg07, 0x0007); ++ if (gspca_dev->usb_err < 0 ++ || !gspca_dev->present ++ || !gspca_dev->streaming) ++ goto err; ++ } ++ if (change & 2) { ++ reg_w(gspca_dev, sd->reg08, ++ ZC3XX_R008_CLOCKSETTING); ++ if (gspca_dev->usb_err < 0 ++ || !gspca_dev->present ++ || !gspca_dev->streaming) ++ goto err; ++ sd->ctrls[QUALITY].val = jpeg_qual[sd->reg08]; ++ jpeg_set_qual(sd->jpeg_hdr, ++ jpeg_qual[sd->reg08]); ++ } ++ } ++ mutex_unlock(&gspca_dev->usb_lock); ++ } ++ return; ++err: ++ mutex_unlock(&gspca_dev->usb_lock); ++} ++ + static void send_unknown(struct gspca_dev *gspca_dev, int sensor) + { + reg_w(gspca_dev, 0x01, 0x0000); /* bridge reset */ +@@ -6411,7 +6504,9 @@ static int sd_config(struct gspca_dev *g + sd->sensor = id->driver_info; + + gspca_dev->cam.ctrls = sd->ctrls; +- sd->quality = QUALITY_DEF; ++ sd->reg08 = REG08_DEF; ++ ++ INIT_WORK(&sd->work, transfer_update); + + return 0; + } +@@ -6464,6 +6559,27 @@ static int sd_init(struct gspca_dev *gsp + [SENSOR_PO2030] = 1, + [SENSOR_TAS5130C] = 1, + }; ++ static const u8 reg08_tb[SENSOR_MAX] = { ++ [SENSOR_ADCM2700] = 1, ++ [SENSOR_CS2102] = 3, ++ [SENSOR_CS2102K] = 3, ++ [SENSOR_GC0303] = 2, ++ [SENSOR_GC0305] = 3, ++ [SENSOR_HDCS2020] = 1, ++ [SENSOR_HV7131B] = 3, ++ [SENSOR_HV7131R] = 3, ++ [SENSOR_ICM105A] = 3, ++ [SENSOR_MC501CB] = 3, ++ [SENSOR_MT9V111_1] = 3, ++ [SENSOR_MT9V111_3] = 3, ++ [SENSOR_OV7620] = 1, ++ [SENSOR_OV7630C] = 3, ++ [SENSOR_PAS106] = 3, ++ [SENSOR_PAS202B] = 3, ++ [SENSOR_PB0330] = 3, ++ [SENSOR_PO2030] = 2, ++ [SENSOR_TAS5130C] = 3, ++ }; + + sensor = zcxx_probeSensor(gspca_dev); + if (sensor >= 0) +@@ -6528,7 +6644,6 @@ static int sd_init(struct gspca_dev *gsp + case 0x0e: + PDEBUG(D_PROBE, "Find Sensor PAS202B"); + sd->sensor = SENSOR_PAS202B; +-/* sd->sharpness = 1; */ + break; + case 0x0f: + PDEBUG(D_PROBE, "Find Sensor PAS106"); +@@ -6616,13 +6731,21 @@ static int sd_init(struct gspca_dev *gsp + } + + sd->ctrls[GAMMA].def = gamma[sd->sensor]; ++ sd->reg08 = reg08_tb[sd->sensor]; ++ sd->ctrls[QUALITY].def = jpeg_qual[sd->reg08]; ++ sd->ctrls[QUALITY].min = jpeg_qual[0]; ++ sd->ctrls[QUALITY].max = jpeg_qual[ARRAY_SIZE(jpeg_qual) - 1]; + + switch (sd->sensor) { + case SENSOR_HV7131R: ++ gspca_dev->ctrl_dis = (1 << QUALITY); + break; + case SENSOR_OV7630C: + gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE); + break; ++ case SENSOR_PAS202B: ++ gspca_dev->ctrl_dis = (1 << QUALITY) | (1 << EXPOSURE); ++ break; + default: + gspca_dev->ctrl_dis = (1 << EXPOSURE); + break; +@@ -6685,7 +6808,6 @@ static int sd_start(struct gspca_dev *gs + /* create the JPEG header */ + jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, + 0x21); /* JPEG 422 */ +- jpeg_set_qual(sd->jpeg_hdr, sd->quality); + + mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + switch (sd->sensor) { +@@ -6761,10 +6883,9 @@ static int sd_start(struct gspca_dev *gs + reg_r(gspca_dev, 0x0180); /* from win */ + reg_w(gspca_dev, 0x00, 0x0180); + break; +- default: +- setquality(gspca_dev); +- break; + } ++ setquality(gspca_dev); ++ jpeg_set_qual(sd->jpeg_hdr, jpeg_qual[sd->reg08]); + setlightfreq(gspca_dev); + + switch (sd->sensor) { +@@ -6776,8 +6897,7 @@ static int sd_start(struct gspca_dev *gs + reg_w(gspca_dev, 0x40, 0x0117); + break; + case SENSOR_HV7131R: +- if (!sd->ctrls[AUTOGAIN].val) +- setexposure(gspca_dev); ++ setexposure(gspca_dev); + reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN); + break; + case SENSOR_GC0305: +@@ -6802,13 +6922,19 @@ static int sd_start(struct gspca_dev *gs + } + + setautogain(gspca_dev); +- switch (sd->sensor) { +- case SENSOR_PO2030: +- msleep(50); +- reg_w(gspca_dev, 0x00, 0x0007); /* (from win traces) */ +- reg_w(gspca_dev, 0x02, ZC3XX_R008_CLOCKSETTING); +- break; ++ ++ /* start the transfer update thread if needed */ ++ if (gspca_dev->usb_err >= 0) { ++ switch (sd->sensor) { ++ case SENSOR_HV7131R: ++ case SENSOR_PAS202B: ++ sd->work_thread = ++ create_singlethread_workqueue(KBUILD_MODNAME); ++ queue_work(sd->work_thread, &sd->work); ++ break; ++ } + } ++ + return gspca_dev->usb_err; + } + +@@ -6817,6 +6943,12 @@ static void sd_stop0(struct gspca_dev *g + { + struct sd *sd = (struct sd *) gspca_dev; + ++ if (sd->work_thread != NULL) { ++ mutex_unlock(&gspca_dev->usb_lock); ++ destroy_workqueue(sd->work_thread); ++ mutex_lock(&gspca_dev->usb_lock); ++ sd->work_thread = NULL; ++ } + if (!gspca_dev->present) + return; + send_unknown(gspca_dev, sd->sensor); +@@ -6893,19 +7025,33 @@ static int sd_querymenu(struct gspca_dev + return -EINVAL; + } + ++static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val) ++{ ++ struct sd *sd = (struct sd *) gspca_dev; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(jpeg_qual) - 1; i++) { ++ if (val <= jpeg_qual[i]) ++ break; ++ } ++ if (i > 0 ++ && i == sd->reg08 ++ && val < jpeg_qual[sd->reg08]) ++ i--; ++ sd->reg08 = i; ++ sd->ctrls[QUALITY].val = jpeg_qual[i]; ++ if (gspca_dev->streaming) ++ jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val); ++ return gspca_dev->usb_err; ++} ++ + static int sd_set_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) + { + struct sd *sd = (struct sd *) gspca_dev; + +- if (jcomp->quality < QUALITY_MIN) +- sd->quality = QUALITY_MIN; +- else if (jcomp->quality > QUALITY_MAX) +- sd->quality = QUALITY_MAX; +- else +- sd->quality = jcomp->quality; +- if (gspca_dev->streaming) +- jpeg_set_qual(sd->jpeg_hdr, sd->quality); ++ sd_setquality(gspca_dev, jcomp->quality); ++ jcomp->quality = sd->ctrls[QUALITY].val; + return gspca_dev->usb_err; + } + +@@ -6915,7 +7061,7 @@ static int sd_get_jcomp(struct gspca_dev + struct sd *sd = (struct sd *) gspca_dev; + + memset(jcomp, 0, sizeof *jcomp); +- jcomp->quality = sd->quality; ++ jcomp->quality = sd->ctrls[QUALITY].val; + jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT + | V4L2_JPEG_MARKER_DQT; + return 0; +@@ -6938,7 +7084,7 @@ static int sd_int_pkt_scan(struct gspca_ + #endif + + static const struct sd_desc sd_desc = { +- .name = MODULE_NAME, ++ .name = KBUILD_MODNAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, +@@ -7023,7 +7169,7 @@ static int sd_probe(struct usb_interface + + /* USB driver */ + static struct usb_driver sd_driver = { +- .name = MODULE_NAME, ++ .name = KBUILD_MODNAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/au8522_decoder.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/au8522_decoder.c ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/au8522_decoder.c +@@ -839,15 +839,4 @@ static struct i2c_driver au8522_driver = + .id_table = au8522_id, + }; + +-static __init int init_au8522(void) +-{ +- return i2c_add_driver(&au8522_driver); +-} +- +-static __exit void exit_au8522(void) +-{ +- i2c_del_driver(&au8522_driver); +-} +- +-module_init(init_au8522); +-module_exit(exit_au8522); ++module_i2c_driver(au8522_driver); +Index: linux-3.3.x86_64/drivers/media/radio/radio-tea5764.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/radio/radio-tea5764.c ++++ linux-3.3.x86_64/drivers/media/radio/radio-tea5764.c +@@ -575,21 +575,7 @@ static struct i2c_driver tea5764_i2c_dri + .id_table = tea5764_id, + }; + +-/* init the driver */ +-static int __init tea5764_init(void) +-{ +- int ret = i2c_add_driver(&tea5764_i2c_driver); +- +- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ": " +- DRIVER_DESC "\n"); +- return ret; +-} +- +-/* cleanup the driver */ +-static void __exit tea5764_exit(void) +-{ +- i2c_del_driver(&tea5764_i2c_driver); +-} ++module_i2c_driver(tea5764_i2c_driver); + + MODULE_AUTHOR(DRIVER_AUTHOR); + MODULE_DESCRIPTION(DRIVER_DESC); +@@ -600,6 +586,3 @@ module_param(use_xtal, int, 0); + MODULE_PARM_DESC(use_xtal, "Chip have a xtal connected in board"); + module_param(radio_nr, int, 0); + MODULE_PARM_DESC(radio_nr, "video4linux device number to use"); +- +-module_init(tea5764_init); +-module_exit(tea5764_exit); +Index: linux-3.3.x86_64/drivers/media/radio/saa7706h.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/radio/saa7706h.c ++++ linux-3.3.x86_64/drivers/media/radio/saa7706h.c +@@ -434,18 +434,7 @@ static struct i2c_driver saa7706h_driver + .id_table = saa7706h_id, + }; + +-static __init int saa7706h_init(void) +-{ +- return i2c_add_driver(&saa7706h_driver); +-} +- +-static __exit void saa7706h_exit(void) +-{ +- i2c_del_driver(&saa7706h_driver); +-} +- +-module_init(saa7706h_init); +-module_exit(saa7706h_exit); ++module_i2c_driver(saa7706h_driver); + + MODULE_DESCRIPTION("SAA7706H Car Radio DSP driver"); + MODULE_AUTHOR("Mocean Laboratories"); +Index: linux-3.3.x86_64/drivers/media/radio/si470x/radio-si470x-i2c.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/radio/si470x/radio-si470x-i2c.c ++++ linux-3.3.x86_64/drivers/media/radio/si470x/radio-si470x-i2c.c +@@ -539,33 +539,7 @@ static struct i2c_driver si470x_i2c_driv + .id_table = si470x_i2c_id, + }; + +- +- +-/************************************************************************** +- * Module Interface +- **************************************************************************/ +- +-/* +- * si470x_i2c_init - module init +- */ +-static int __init si470x_i2c_init(void) +-{ +- printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n"); +- return i2c_add_driver(&si470x_i2c_driver); +-} +- +- +-/* +- * si470x_i2c_exit - module exit +- */ +-static void __exit si470x_i2c_exit(void) +-{ +- i2c_del_driver(&si470x_i2c_driver); +-} +- +- +-module_init(si470x_i2c_init); +-module_exit(si470x_i2c_exit); ++module_i2c_driver(si470x_i2c_driver); + + MODULE_LICENSE("GPL"); + MODULE_AUTHOR(DRIVER_AUTHOR); +Index: linux-3.3.x86_64/drivers/media/radio/si4713-i2c.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/radio/si4713-i2c.c ++++ linux-3.3.x86_64/drivers/media/radio/si4713-i2c.c +@@ -2106,17 +2106,4 @@ static struct i2c_driver si4713_i2c_driv + .id_table = si4713_id, + }; + +-/* Module Interface */ +-static int __init si4713_module_init(void) +-{ +- return i2c_add_driver(&si4713_i2c_driver); +-} +- +-static void __exit si4713_module_exit(void) +-{ +- i2c_del_driver(&si4713_i2c_driver); +-} +- +-module_init(si4713_module_init); +-module_exit(si4713_module_exit); +- ++module_i2c_driver(si4713_i2c_driver); +Index: linux-3.3.x86_64/drivers/media/radio/tef6862.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/radio/tef6862.c ++++ linux-3.3.x86_64/drivers/media/radio/tef6862.c +@@ -215,20 +215,8 @@ static struct i2c_driver tef6862_driver + .id_table = tef6862_id, + }; + +-static __init int tef6862_init(void) +-{ +- return i2c_add_driver(&tef6862_driver); +-} +- +-static __exit void tef6862_exit(void) +-{ +- i2c_del_driver(&tef6862_driver); +-} +- +-module_init(tef6862_init); +-module_exit(tef6862_exit); ++module_i2c_driver(tef6862_driver); + + MODULE_DESCRIPTION("TEF6862 Car Radio Enhanced Selectivity Tuner"); + MODULE_AUTHOR("Mocean Laboratories"); + MODULE_LICENSE("GPL v2"); +- +Index: linux-3.3.x86_64/drivers/media/video/adp1653.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/adp1653.c ++++ linux-3.3.x86_64/drivers/media/video/adp1653.c +@@ -33,7 +33,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -482,24 +481,7 @@ static struct i2c_driver adp1653_i2c_dri + .id_table = adp1653_id_table, + }; + +-static int __init adp1653_init(void) +-{ +- int rval; +- +- rval = i2c_add_driver(&adp1653_i2c_driver); +- if (rval) +- printk(KERN_ALERT "%s: failed at i2c_add_driver\n", __func__); +- +- return rval; +-} +- +-static void __exit adp1653_exit(void) +-{ +- i2c_del_driver(&adp1653_i2c_driver); +-} +- +-module_init(adp1653_init); +-module_exit(adp1653_exit); ++module_i2c_driver(adp1653_i2c_driver); + + MODULE_AUTHOR("Sakari Ailus "); + MODULE_DESCRIPTION("Analog Devices ADP1653 LED flash driver"); +Index: linux-3.3.x86_64/drivers/media/video/adv7170.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/adv7170.c ++++ linux-3.3.x86_64/drivers/media/video/adv7170.c +@@ -407,15 +407,4 @@ static struct i2c_driver adv7170_driver + .id_table = adv7170_id, + }; + +-static __init int init_adv7170(void) +-{ +- return i2c_add_driver(&adv7170_driver); +-} +- +-static __exit void exit_adv7170(void) +-{ +- i2c_del_driver(&adv7170_driver); +-} +- +-module_init(init_adv7170); +-module_exit(exit_adv7170); ++module_i2c_driver(adv7170_driver); +Index: linux-3.3.x86_64/drivers/media/video/adv7175.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/adv7175.c ++++ linux-3.3.x86_64/drivers/media/video/adv7175.c +@@ -457,15 +457,4 @@ static struct i2c_driver adv7175_driver + .id_table = adv7175_id, + }; + +-static __init int init_adv7175(void) +-{ +- return i2c_add_driver(&adv7175_driver); +-} +- +-static __exit void exit_adv7175(void) +-{ +- i2c_del_driver(&adv7175_driver); +-} +- +-module_init(init_adv7175); +-module_exit(exit_adv7175); ++module_i2c_driver(adv7175_driver); +Index: linux-3.3.x86_64/drivers/media/video/adv7180.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/adv7180.c ++++ linux-3.3.x86_64/drivers/media/video/adv7180.c +@@ -444,20 +444,8 @@ static struct i2c_driver adv7180_driver + .id_table = adv7180_id, + }; + +-static __init int adv7180_init(void) +-{ +- return i2c_add_driver(&adv7180_driver); +-} +- +-static __exit void adv7180_exit(void) +-{ +- i2c_del_driver(&adv7180_driver); +-} +- +-module_init(adv7180_init); +-module_exit(adv7180_exit); ++module_i2c_driver(adv7180_driver); + + MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver"); + MODULE_AUTHOR("Mocean Laboratories"); + MODULE_LICENSE("GPL v2"); +- +Index: linux-3.3.x86_64/drivers/media/video/adv7343.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/adv7343.c ++++ linux-3.3.x86_64/drivers/media/video/adv7343.c +@@ -475,15 +475,4 @@ static struct i2c_driver adv7343_driver + .id_table = adv7343_id, + }; + +-static __init int init_adv7343(void) +-{ +- return i2c_add_driver(&adv7343_driver); +-} +- +-static __exit void exit_adv7343(void) +-{ +- i2c_del_driver(&adv7343_driver); +-} +- +-module_init(init_adv7343); +-module_exit(exit_adv7343); ++module_i2c_driver(adv7343_driver); +Index: linux-3.3.x86_64/drivers/media/video/ak881x.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ak881x.c ++++ linux-3.3.x86_64/drivers/media/video/ak881x.c +@@ -352,18 +352,7 @@ static struct i2c_driver ak881x_i2c_driv + .id_table = ak881x_id, + }; + +-static int __init ak881x_module_init(void) +-{ +- return i2c_add_driver(&ak881x_i2c_driver); +-} +- +-static void __exit ak881x_module_exit(void) +-{ +- i2c_del_driver(&ak881x_i2c_driver); +-} +- +-module_init(ak881x_module_init); +-module_exit(ak881x_module_exit); ++module_i2c_driver(ak881x_i2c_driver); + + MODULE_DESCRIPTION("TV-output driver for ak8813/ak8814"); + MODULE_AUTHOR("Guennadi Liakhovetski "); +Index: linux-3.3.x86_64/drivers/media/video/as3645a.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/as3645a.c ++++ linux-3.3.x86_64/drivers/media/video/as3645a.c +@@ -881,24 +881,7 @@ static struct i2c_driver as3645a_i2c_dri + .id_table = as3645a_id_table, + }; + +-static int __init as3645a_init(void) +-{ +- int rval; +- +- rval = i2c_add_driver(&as3645a_i2c_driver); +- if (rval) +- pr_err("%s: Failed to register the driver\n", AS3645A_NAME); +- +- return rval; +-} +- +-static void __exit as3645a_exit(void) +-{ +- i2c_del_driver(&as3645a_i2c_driver); +-} +- +-module_init(as3645a_init); +-module_exit(as3645a_exit); ++module_i2c_driver(as3645a_i2c_driver); + + MODULE_AUTHOR("Laurent Pinchart "); + MODULE_DESCRIPTION("LED flash driver for AS3645A, LM3555 and their clones"); +Index: linux-3.3.x86_64/drivers/media/video/bt819.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/bt819.c ++++ linux-3.3.x86_64/drivers/media/video/bt819.c +@@ -514,15 +514,4 @@ static struct i2c_driver bt819_driver = + .id_table = bt819_id, + }; + +-static __init int init_bt819(void) +-{ +- return i2c_add_driver(&bt819_driver); +-} +- +-static __exit void exit_bt819(void) +-{ +- i2c_del_driver(&bt819_driver); +-} +- +-module_init(init_bt819); +-module_exit(exit_bt819); ++module_i2c_driver(bt819_driver); +Index: linux-3.3.x86_64/drivers/media/video/bt856.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/bt856.c ++++ linux-3.3.x86_64/drivers/media/video/bt856.c +@@ -270,15 +270,4 @@ static struct i2c_driver bt856_driver = + .id_table = bt856_id, + }; + +-static __init int init_bt856(void) +-{ +- return i2c_add_driver(&bt856_driver); +-} +- +-static __exit void exit_bt856(void) +-{ +- i2c_del_driver(&bt856_driver); +-} +- +-module_init(init_bt856); +-module_exit(exit_bt856); ++module_i2c_driver(bt856_driver); +Index: linux-3.3.x86_64/drivers/media/video/bt866.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/bt866.c ++++ linux-3.3.x86_64/drivers/media/video/bt866.c +@@ -240,15 +240,4 @@ static struct i2c_driver bt866_driver = + .id_table = bt866_id, + }; + +-static __init int init_bt866(void) +-{ +- return i2c_add_driver(&bt866_driver); +-} +- +-static __exit void exit_bt866(void) +-{ +- i2c_del_driver(&bt866_driver); +-} +- +-module_init(init_bt866); +-module_exit(exit_bt866); ++module_i2c_driver(bt866_driver); +Index: linux-3.3.x86_64/drivers/media/video/cs5345.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/cs5345.c ++++ linux-3.3.x86_64/drivers/media/video/cs5345.c +@@ -249,15 +249,4 @@ static struct i2c_driver cs5345_driver = + .id_table = cs5345_id, + }; + +-static __init int init_cs5345(void) +-{ +- return i2c_add_driver(&cs5345_driver); +-} +- +-static __exit void exit_cs5345(void) +-{ +- i2c_del_driver(&cs5345_driver); +-} +- +-module_init(init_cs5345); +-module_exit(exit_cs5345); ++module_i2c_driver(cs5345_driver); +Index: linux-3.3.x86_64/drivers/media/video/cs53l32a.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/cs53l32a.c ++++ linux-3.3.x86_64/drivers/media/video/cs53l32a.c +@@ -248,15 +248,4 @@ static struct i2c_driver cs53l32a_driver + .id_table = cs53l32a_id, + }; + +-static __init int init_cs53l32a(void) +-{ +- return i2c_add_driver(&cs53l32a_driver); +-} +- +-static __exit void exit_cs53l32a(void) +-{ +- i2c_del_driver(&cs53l32a_driver); +-} +- +-module_init(init_cs53l32a); +-module_exit(exit_cs53l32a); ++module_i2c_driver(cs53l32a_driver); +Index: linux-3.3.x86_64/drivers/media/video/cx25840/cx25840-core.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/cx25840/cx25840-core.c ++++ linux-3.3.x86_64/drivers/media/video/cx25840/cx25840-core.c +@@ -5301,15 +5301,4 @@ static struct i2c_driver cx25840_driver + .id_table = cx25840_id, + }; + +-static __init int init_cx25840(void) +-{ +- return i2c_add_driver(&cx25840_driver); +-} +- +-static __exit void exit_cx25840(void) +-{ +- i2c_del_driver(&cx25840_driver); +-} +- +-module_init(init_cx25840); +-module_exit(exit_cx25840); ++module_i2c_driver(cx25840_driver); +Index: linux-3.3.x86_64/drivers/media/video/imx074.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/imx074.c ++++ linux-3.3.x86_64/drivers/media/video/imx074.c +@@ -468,18 +468,7 @@ static struct i2c_driver imx074_i2c_driv + .id_table = imx074_id, + }; + +-static int __init imx074_mod_init(void) +-{ +- return i2c_add_driver(&imx074_i2c_driver); +-} +- +-static void __exit imx074_mod_exit(void) +-{ +- i2c_del_driver(&imx074_i2c_driver); +-} +- +-module_init(imx074_mod_init); +-module_exit(imx074_mod_exit); ++module_i2c_driver(imx074_i2c_driver); + + MODULE_DESCRIPTION("Sony IMX074 Camera driver"); + MODULE_AUTHOR("Guennadi Liakhovetski "); +Index: linux-3.3.x86_64/drivers/media/video/indycam.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/indycam.c ++++ linux-3.3.x86_64/drivers/media/video/indycam.c +@@ -387,15 +387,4 @@ static struct i2c_driver indycam_driver + .id_table = indycam_id, + }; + +-static __init int init_indycam(void) +-{ +- return i2c_add_driver(&indycam_driver); +-} +- +-static __exit void exit_indycam(void) +-{ +- i2c_del_driver(&indycam_driver); +-} +- +-module_init(init_indycam); +-module_exit(exit_indycam); ++module_i2c_driver(indycam_driver); +Index: linux-3.3.x86_64/drivers/media/video/ir-kbd-i2c.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ir-kbd-i2c.c ++++ linux-3.3.x86_64/drivers/media/video/ir-kbd-i2c.c +@@ -471,7 +471,7 @@ static const struct i2c_device_id ir_kbd + { } + }; + +-static struct i2c_driver driver = { ++static struct i2c_driver ir_kbd_driver = { + .driver = { + .name = "ir-kbd-i2c", + }, +@@ -480,21 +480,10 @@ static struct i2c_driver driver = { + .id_table = ir_kbd_id, + }; + ++module_i2c_driver(ir_kbd_driver); ++ + /* ----------------------------------------------------------------------- */ + + MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller"); + MODULE_DESCRIPTION("input driver for i2c IR remote controls"); + MODULE_LICENSE("GPL"); +- +-static int __init ir_init(void) +-{ +- return i2c_add_driver(&driver); +-} +- +-static void __exit ir_fini(void) +-{ +- i2c_del_driver(&driver); +-} +- +-module_init(ir_init); +-module_exit(ir_fini); +Index: linux-3.3.x86_64/drivers/media/video/ks0127.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ks0127.c ++++ linux-3.3.x86_64/drivers/media/video/ks0127.c +@@ -721,15 +721,4 @@ static struct i2c_driver ks0127_driver = + .id_table = ks0127_id, + }; + +-static __init int init_ks0127(void) +-{ +- return i2c_add_driver(&ks0127_driver); +-} +- +-static __exit void exit_ks0127(void) +-{ +- i2c_del_driver(&ks0127_driver); +-} +- +-module_init(init_ks0127); +-module_exit(exit_ks0127); ++module_i2c_driver(ks0127_driver); +Index: linux-3.3.x86_64/drivers/media/video/m52790.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/m52790.c ++++ linux-3.3.x86_64/drivers/media/video/m52790.c +@@ -213,15 +213,4 @@ static struct i2c_driver m52790_driver = + .id_table = m52790_id, + }; + +-static __init int init_m52790(void) +-{ +- return i2c_add_driver(&m52790_driver); +-} +- +-static __exit void exit_m52790(void) +-{ +- i2c_del_driver(&m52790_driver); +-} +- +-module_init(init_m52790); +-module_exit(exit_m52790); ++module_i2c_driver(m52790_driver); +Index: linux-3.3.x86_64/drivers/media/video/msp3400-driver.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/msp3400-driver.c ++++ linux-3.3.x86_64/drivers/media/video/msp3400-driver.c +@@ -881,18 +881,7 @@ static struct i2c_driver msp_driver = { + .id_table = msp_id, + }; + +-static __init int init_msp(void) +-{ +- return i2c_add_driver(&msp_driver); +-} +- +-static __exit void exit_msp(void) +-{ +- i2c_del_driver(&msp_driver); +-} +- +-module_init(init_msp); +-module_exit(exit_msp); ++module_i2c_driver(msp_driver); + + /* + * Overrides for Emacs so that we follow Linus's tabbing style. +Index: linux-3.3.x86_64/drivers/media/video/mt9m001.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/mt9m001.c ++++ linux-3.3.x86_64/drivers/media/video/mt9m001.c +@@ -730,18 +730,7 @@ static struct i2c_driver mt9m001_i2c_dri + .id_table = mt9m001_id, + }; + +-static int __init mt9m001_mod_init(void) +-{ +- return i2c_add_driver(&mt9m001_i2c_driver); +-} +- +-static void __exit mt9m001_mod_exit(void) +-{ +- i2c_del_driver(&mt9m001_i2c_driver); +-} +- +-module_init(mt9m001_mod_init); +-module_exit(mt9m001_mod_exit); ++module_i2c_driver(mt9m001_i2c_driver); + + MODULE_DESCRIPTION("Micron MT9M001 Camera driver"); + MODULE_AUTHOR("Guennadi Liakhovetski "); +Index: linux-3.3.x86_64/drivers/media/video/mt9m111.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/mt9m111.c ++++ linux-3.3.x86_64/drivers/media/video/mt9m111.c +@@ -1008,18 +1008,7 @@ static struct i2c_driver mt9m111_i2c_dri + .id_table = mt9m111_id, + }; + +-static int __init mt9m111_mod_init(void) +-{ +- return i2c_add_driver(&mt9m111_i2c_driver); +-} +- +-static void __exit mt9m111_mod_exit(void) +-{ +- i2c_del_driver(&mt9m111_i2c_driver); +-} +- +-module_init(mt9m111_mod_init); +-module_exit(mt9m111_mod_exit); ++module_i2c_driver(mt9m111_i2c_driver); + + MODULE_DESCRIPTION("Micron/Aptina MT9M111/MT9M112/MT9M131 Camera driver"); + MODULE_AUTHOR("Robert Jarzmik"); +Index: linux-3.3.x86_64/drivers/media/video/mt9p031.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/mt9p031.c ++++ linux-3.3.x86_64/drivers/media/video/mt9p031.c +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + #include + + #include +@@ -28,6 +27,8 @@ + #include + #include + ++#include "aptina-pll.h" ++ + #define MT9P031_PIXEL_ARRAY_WIDTH 2752 + #define MT9P031_PIXEL_ARRAY_HEIGHT 2004 + +@@ -98,14 +99,6 @@ + #define MT9P031_TEST_PATTERN_RED 0xa2 + #define MT9P031_TEST_PATTERN_BLUE 0xa3 + +-struct mt9p031_pll_divs { +- u32 ext_freq; +- u32 target_freq; +- u8 m; +- u8 n; +- u8 p1; +-}; +- + struct mt9p031 { + struct v4l2_subdev subdev; + struct media_pad pad; +@@ -115,10 +108,8 @@ struct mt9p031 { + struct mt9p031_platform_data *pdata; + struct mutex power_lock; /* lock to protect power_count */ + int power_count; +- u16 xskip; +- u16 yskip; + +- const struct mt9p031_pll_divs *pll; ++ struct aptina_pll pll; + + /* Registers cache */ + u16 output_control; +@@ -186,33 +177,31 @@ static int mt9p031_reset(struct mt9p031 + 0); + } + +-/* +- * This static table uses ext_freq and vdd_io values to select suitable +- * PLL dividers m, n and p1 which have been calculated as specifiec in p36 +- * of Aptina's mt9p031 datasheet. New values should be added here. +- */ +-static const struct mt9p031_pll_divs mt9p031_divs[] = { +- /* ext_freq target_freq m n p1 */ +- {21000000, 48000000, 26, 2, 6} +-}; +- +-static int mt9p031_pll_get_divs(struct mt9p031 *mt9p031) ++static int mt9p031_pll_setup(struct mt9p031 *mt9p031) + { ++ static const struct aptina_pll_limits limits = { ++ .ext_clock_min = 6000000, ++ .ext_clock_max = 27000000, ++ .int_clock_min = 2000000, ++ .int_clock_max = 13500000, ++ .out_clock_min = 180000000, ++ .out_clock_max = 360000000, ++ .pix_clock_max = 96000000, ++ .n_min = 1, ++ .n_max = 64, ++ .m_min = 16, ++ .m_max = 255, ++ .p1_min = 1, ++ .p1_max = 128, ++ }; ++ + struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); +- int i; ++ struct mt9p031_platform_data *pdata = mt9p031->pdata; + +- for (i = 0; i < ARRAY_SIZE(mt9p031_divs); i++) { +- if (mt9p031_divs[i].ext_freq == mt9p031->pdata->ext_freq && +- mt9p031_divs[i].target_freq == mt9p031->pdata->target_freq) { +- mt9p031->pll = &mt9p031_divs[i]; +- return 0; +- } +- } ++ mt9p031->pll.ext_clock = pdata->ext_freq; ++ mt9p031->pll.pix_clock = pdata->target_freq; + +- dev_err(&client->dev, "Couldn't find PLL dividers for ext_freq = %d, " +- "target_freq = %d\n", mt9p031->pdata->ext_freq, +- mt9p031->pdata->target_freq); +- return -EINVAL; ++ return aptina_pll_calculate(&client->dev, &limits, &mt9p031->pll); + } + + static int mt9p031_pll_enable(struct mt9p031 *mt9p031) +@@ -226,11 +215,11 @@ static int mt9p031_pll_enable(struct mt9 + return ret; + + ret = mt9p031_write(client, MT9P031_PLL_CONFIG_1, +- (mt9p031->pll->m << 8) | (mt9p031->pll->n - 1)); ++ (mt9p031->pll.m << 8) | (mt9p031->pll.n - 1)); + if (ret < 0) + return ret; + +- ret = mt9p031_write(client, MT9P031_PLL_CONFIG_2, mt9p031->pll->p1 - 1); ++ ret = mt9p031_write(client, MT9P031_PLL_CONFIG_2, mt9p031->pll.p1 - 1); + if (ret < 0) + return ret; + +@@ -785,8 +774,6 @@ static int mt9p031_open(struct v4l2_subd + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_SRGB; + +- mt9p031->xskip = 1; +- mt9p031->yskip = 1; + return mt9p031_set_power(subdev, 1); + } + +@@ -905,7 +892,7 @@ static int mt9p031_probe(struct i2c_clie + mt9p031->format.field = V4L2_FIELD_NONE; + mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB; + +- ret = mt9p031_pll_get_divs(mt9p031); ++ ret = mt9p031_pll_setup(mt9p031); + + done: + if (ret < 0) { +@@ -945,18 +932,7 @@ static struct i2c_driver mt9p031_i2c_dri + .id_table = mt9p031_id, + }; + +-static int __init mt9p031_mod_init(void) +-{ +- return i2c_add_driver(&mt9p031_i2c_driver); +-} +- +-static void __exit mt9p031_mod_exit(void) +-{ +- i2c_del_driver(&mt9p031_i2c_driver); +-} +- +-module_init(mt9p031_mod_init); +-module_exit(mt9p031_mod_exit); ++module_i2c_driver(mt9p031_i2c_driver); + + MODULE_DESCRIPTION("Aptina MT9P031 Camera driver"); + MODULE_AUTHOR("Bastian Hecht "); +Index: linux-3.3.x86_64/drivers/media/video/mt9t001.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/mt9t001.c ++++ linux-3.3.x86_64/drivers/media/video/mt9t001.c +@@ -817,18 +817,7 @@ static struct i2c_driver mt9t001_driver + .id_table = mt9t001_id, + }; + +-static int __init mt9t001_init(void) +-{ +- return i2c_add_driver(&mt9t001_driver); +-} +- +-static void __exit mt9t001_exit(void) +-{ +- i2c_del_driver(&mt9t001_driver); +-} +- +-module_init(mt9t001_init); +-module_exit(mt9t001_exit); ++module_i2c_driver(mt9t001_driver); + + MODULE_DESCRIPTION("Aptina (Micron) MT9T001 Camera driver"); + MODULE_AUTHOR("Laurent Pinchart "); +Index: linux-3.3.x86_64/drivers/media/video/mt9t031.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/mt9t031.c ++++ linux-3.3.x86_64/drivers/media/video/mt9t031.c +@@ -850,18 +850,7 @@ static struct i2c_driver mt9t031_i2c_dri + .id_table = mt9t031_id, + }; + +-static int __init mt9t031_mod_init(void) +-{ +- return i2c_add_driver(&mt9t031_i2c_driver); +-} +- +-static void __exit mt9t031_mod_exit(void) +-{ +- i2c_del_driver(&mt9t031_i2c_driver); +-} +- +-module_init(mt9t031_mod_init); +-module_exit(mt9t031_mod_exit); ++module_i2c_driver(mt9t031_i2c_driver); + + MODULE_DESCRIPTION("Micron MT9T031 Camera driver"); + MODULE_AUTHOR("Guennadi Liakhovetski "); +Index: linux-3.3.x86_64/drivers/media/video/mt9t112.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/mt9t112.c ++++ linux-3.3.x86_64/drivers/media/video/mt9t112.c +@@ -1117,21 +1117,7 @@ static struct i2c_driver mt9t112_i2c_dri + .id_table = mt9t112_id, + }; + +-/************************************************************************ +- module function +-************************************************************************/ +-static int __init mt9t112_module_init(void) +-{ +- return i2c_add_driver(&mt9t112_i2c_driver); +-} +- +-static void __exit mt9t112_module_exit(void) +-{ +- i2c_del_driver(&mt9t112_i2c_driver); +-} +- +-module_init(mt9t112_module_init); +-module_exit(mt9t112_module_exit); ++module_i2c_driver(mt9t112_i2c_driver); + + MODULE_DESCRIPTION("SoC Camera driver for mt9t112"); + MODULE_AUTHOR("Kuninori Morimoto"); +Index: linux-3.3.x86_64/drivers/media/video/mt9v011.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/mt9v011.c ++++ linux-3.3.x86_64/drivers/media/video/mt9v011.c +@@ -709,15 +709,4 @@ static struct i2c_driver mt9v011_driver + .id_table = mt9v011_id, + }; + +-static __init int init_mt9v011(void) +-{ +- return i2c_add_driver(&mt9v011_driver); +-} +- +-static __exit void exit_mt9v011(void) +-{ +- i2c_del_driver(&mt9v011_driver); +-} +- +-module_init(init_mt9v011); +-module_exit(exit_mt9v011); ++module_i2c_driver(mt9v011_driver); +Index: linux-3.3.x86_64/drivers/media/video/mt9v022.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/mt9v022.c ++++ linux-3.3.x86_64/drivers/media/video/mt9v022.c +@@ -872,18 +872,7 @@ static struct i2c_driver mt9v022_i2c_dri + .id_table = mt9v022_id, + }; + +-static int __init mt9v022_mod_init(void) +-{ +- return i2c_add_driver(&mt9v022_i2c_driver); +-} +- +-static void __exit mt9v022_mod_exit(void) +-{ +- i2c_del_driver(&mt9v022_i2c_driver); +-} +- +-module_init(mt9v022_mod_init); +-module_exit(mt9v022_mod_exit); ++module_i2c_driver(mt9v022_i2c_driver); + + MODULE_DESCRIPTION("Micron MT9V022 Camera driver"); + MODULE_AUTHOR("Guennadi Liakhovetski "); +Index: linux-3.3.x86_64/drivers/media/video/mt9v032.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/mt9v032.c ++++ linux-3.3.x86_64/drivers/media/video/mt9v032.c +@@ -756,18 +756,7 @@ static struct i2c_driver mt9v032_driver + .id_table = mt9v032_id, + }; + +-static int __init mt9v032_init(void) +-{ +- return i2c_add_driver(&mt9v032_driver); +-} +- +-static void __exit mt9v032_exit(void) +-{ +- i2c_del_driver(&mt9v032_driver); +-} +- +-module_init(mt9v032_init); +-module_exit(mt9v032_exit); ++module_i2c_driver(mt9v032_driver); + + MODULE_DESCRIPTION("Aptina MT9V032 Camera driver"); + MODULE_AUTHOR("Laurent Pinchart "); +Index: linux-3.3.x86_64/drivers/media/video/ov2640.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ov2640.c ++++ linux-3.3.x86_64/drivers/media/video/ov2640.c +@@ -1103,21 +1103,7 @@ static struct i2c_driver ov2640_i2c_driv + .id_table = ov2640_id, + }; + +-/* +- * Module functions +- */ +-static int __init ov2640_module_init(void) +-{ +- return i2c_add_driver(&ov2640_i2c_driver); +-} +- +-static void __exit ov2640_module_exit(void) +-{ +- i2c_del_driver(&ov2640_i2c_driver); +-} +- +-module_init(ov2640_module_init); +-module_exit(ov2640_module_exit); ++module_i2c_driver(ov2640_i2c_driver); + + MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 2640 sensor"); + MODULE_AUTHOR("Alberto Panizzo"); +Index: linux-3.3.x86_64/drivers/media/video/ov5642.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ov5642.c ++++ linux-3.3.x86_64/drivers/media/video/ov5642.c +@@ -1068,18 +1068,7 @@ static struct i2c_driver ov5642_i2c_driv + .id_table = ov5642_id, + }; + +-static int __init ov5642_mod_init(void) +-{ +- return i2c_add_driver(&ov5642_i2c_driver); +-} +- +-static void __exit ov5642_mod_exit(void) +-{ +- i2c_del_driver(&ov5642_i2c_driver); +-} +- +-module_init(ov5642_mod_init); +-module_exit(ov5642_mod_exit); ++module_i2c_driver(ov5642_i2c_driver); + + MODULE_DESCRIPTION("Omnivision OV5642 Camera driver"); + MODULE_AUTHOR("Bastian Hecht "); +Index: linux-3.3.x86_64/drivers/media/video/ov7670.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ov7670.c ++++ linux-3.3.x86_64/drivers/media/video/ov7670.c +@@ -1583,15 +1583,4 @@ static struct i2c_driver ov7670_driver = + .id_table = ov7670_id, + }; + +-static __init int init_ov7670(void) +-{ +- return i2c_add_driver(&ov7670_driver); +-} +- +-static __exit void exit_ov7670(void) +-{ +- i2c_del_driver(&ov7670_driver); +-} +- +-module_init(init_ov7670); +-module_exit(exit_ov7670); ++module_i2c_driver(ov7670_driver); +Index: linux-3.3.x86_64/drivers/media/video/ov772x.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ov772x.c ++++ linux-3.3.x86_64/drivers/media/video/ov772x.c +@@ -1123,22 +1123,7 @@ static struct i2c_driver ov772x_i2c_driv + .id_table = ov772x_id, + }; + +-/* +- * module function +- */ +- +-static int __init ov772x_module_init(void) +-{ +- return i2c_add_driver(&ov772x_i2c_driver); +-} +- +-static void __exit ov772x_module_exit(void) +-{ +- i2c_del_driver(&ov772x_i2c_driver); +-} +- +-module_init(ov772x_module_init); +-module_exit(ov772x_module_exit); ++module_i2c_driver(ov772x_i2c_driver); + + MODULE_DESCRIPTION("SoC Camera driver for ov772x"); + MODULE_AUTHOR("Kuninori Morimoto"); +Index: linux-3.3.x86_64/drivers/media/video/ov9640.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ov9640.c ++++ linux-3.3.x86_64/drivers/media/video/ov9640.c +@@ -738,18 +738,7 @@ static struct i2c_driver ov9640_i2c_driv + .id_table = ov9640_id, + }; + +-static int __init ov9640_module_init(void) +-{ +- return i2c_add_driver(&ov9640_i2c_driver); +-} +- +-static void __exit ov9640_module_exit(void) +-{ +- i2c_del_driver(&ov9640_i2c_driver); +-} +- +-module_init(ov9640_module_init); +-module_exit(ov9640_module_exit); ++module_i2c_driver(ov9640_i2c_driver); + + MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV96xx"); + MODULE_AUTHOR("Marek Vasut "); +Index: linux-3.3.x86_64/drivers/media/video/ov9740.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ov9740.c ++++ linux-3.3.x86_64/drivers/media/video/ov9740.c +@@ -998,18 +998,7 @@ static struct i2c_driver ov9740_i2c_driv + .id_table = ov9740_id, + }; + +-static int __init ov9740_module_init(void) +-{ +- return i2c_add_driver(&ov9740_i2c_driver); +-} +- +-static void __exit ov9740_module_exit(void) +-{ +- i2c_del_driver(&ov9740_i2c_driver); +-} +- +-module_init(ov9740_module_init); +-module_exit(ov9740_module_exit); ++module_i2c_driver(ov9740_i2c_driver); + + MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV9740"); + MODULE_AUTHOR("Andrew Chew "); +Index: linux-3.3.x86_64/drivers/media/video/rj54n1cb0c.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/rj54n1cb0c.c ++++ linux-3.3.x86_64/drivers/media/video/rj54n1cb0c.c +@@ -1407,18 +1407,7 @@ static struct i2c_driver rj54n1_i2c_driv + .id_table = rj54n1_id, + }; + +-static int __init rj54n1_mod_init(void) +-{ +- return i2c_add_driver(&rj54n1_i2c_driver); +-} +- +-static void __exit rj54n1_mod_exit(void) +-{ +- i2c_del_driver(&rj54n1_i2c_driver); +-} +- +-module_init(rj54n1_mod_init); +-module_exit(rj54n1_mod_exit); ++module_i2c_driver(rj54n1_i2c_driver); + + MODULE_DESCRIPTION("Sharp RJ54N1CB0C Camera driver"); + MODULE_AUTHOR("Guennadi Liakhovetski "); +Index: linux-3.3.x86_64/drivers/media/video/s5p-tv/hdmiphy_drv.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s5p-tv/hdmiphy_drv.c ++++ linux-3.3.x86_64/drivers/media/video/s5p-tv/hdmiphy_drv.c +@@ -175,14 +175,4 @@ static struct i2c_driver hdmiphy_driver + .id_table = hdmiphy_id, + }; + +-static int __init hdmiphy_init(void) +-{ +- return i2c_add_driver(&hdmiphy_driver); +-} +-module_init(hdmiphy_init); +- +-static void __exit hdmiphy_exit(void) +-{ +- i2c_del_driver(&hdmiphy_driver); +-} +-module_exit(hdmiphy_exit); ++module_i2c_driver(hdmiphy_driver); +Index: linux-3.3.x86_64/drivers/media/video/saa6588.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/saa6588.c ++++ linux-3.3.x86_64/drivers/media/video/saa6588.c +@@ -539,15 +539,4 @@ static struct i2c_driver saa6588_driver + .id_table = saa6588_id, + }; + +-static __init int init_saa6588(void) +-{ +- return i2c_add_driver(&saa6588_driver); +-} +- +-static __exit void exit_saa6588(void) +-{ +- i2c_del_driver(&saa6588_driver); +-} +- +-module_init(init_saa6588); +-module_exit(exit_saa6588); ++module_i2c_driver(saa6588_driver); +Index: linux-3.3.x86_64/drivers/media/video/saa7110.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/saa7110.c ++++ linux-3.3.x86_64/drivers/media/video/saa7110.c +@@ -491,15 +491,4 @@ static struct i2c_driver saa7110_driver + .id_table = saa7110_id, + }; + +-static __init int init_saa7110(void) +-{ +- return i2c_add_driver(&saa7110_driver); +-} +- +-static __exit void exit_saa7110(void) +-{ +- i2c_del_driver(&saa7110_driver); +-} +- +-module_init(init_saa7110); +-module_exit(exit_saa7110); ++module_i2c_driver(saa7110_driver); +Index: linux-3.3.x86_64/drivers/media/video/saa7115.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/saa7115.c ++++ linux-3.3.x86_64/drivers/media/video/saa7115.c +@@ -1724,15 +1724,4 @@ static struct i2c_driver saa711x_driver + .id_table = saa711x_id, + }; + +-static __init int init_saa711x(void) +-{ +- return i2c_add_driver(&saa711x_driver); +-} +- +-static __exit void exit_saa711x(void) +-{ +- i2c_del_driver(&saa711x_driver); +-} +- +-module_init(init_saa711x); +-module_exit(exit_saa711x); ++module_i2c_driver(saa711x_driver); +Index: linux-3.3.x86_64/drivers/media/video/saa7127.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/saa7127.c ++++ linux-3.3.x86_64/drivers/media/video/saa7127.c +@@ -852,15 +852,4 @@ static struct i2c_driver saa7127_driver + .id_table = saa7127_id, + }; + +-static __init int init_saa7127(void) +-{ +- return i2c_add_driver(&saa7127_driver); +-} +- +-static __exit void exit_saa7127(void) +-{ +- i2c_del_driver(&saa7127_driver); +-} +- +-module_init(init_saa7127); +-module_exit(exit_saa7127); ++module_i2c_driver(saa7127_driver); +Index: linux-3.3.x86_64/drivers/media/video/saa7134/saa6752hs.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/saa7134/saa6752hs.c ++++ linux-3.3.x86_64/drivers/media/video/saa7134/saa6752hs.c +@@ -1001,18 +1001,7 @@ static struct i2c_driver saa6752hs_drive + .id_table = saa6752hs_id, + }; + +-static __init int init_saa6752hs(void) +-{ +- return i2c_add_driver(&saa6752hs_driver); +-} +- +-static __exit void exit_saa6752hs(void) +-{ +- i2c_del_driver(&saa6752hs_driver); +-} +- +-module_init(init_saa6752hs); +-module_exit(exit_saa6752hs); ++module_i2c_driver(saa6752hs_driver); + + /* + * Overrides for Emacs so that we follow Linus's tabbing style. +Index: linux-3.3.x86_64/drivers/media/video/saa717x.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/saa717x.c ++++ linux-3.3.x86_64/drivers/media/video/saa717x.c +@@ -1375,15 +1375,4 @@ static struct i2c_driver saa717x_driver + .id_table = saa717x_id, + }; + +-static __init int init_saa717x(void) +-{ +- return i2c_add_driver(&saa717x_driver); +-} +- +-static __exit void exit_saa717x(void) +-{ +- i2c_del_driver(&saa717x_driver); +-} +- +-module_init(init_saa717x); +-module_exit(exit_saa717x); ++module_i2c_driver(saa717x_driver); +Index: linux-3.3.x86_64/drivers/media/video/saa7185.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/saa7185.c ++++ linux-3.3.x86_64/drivers/media/video/saa7185.c +@@ -374,15 +374,4 @@ static struct i2c_driver saa7185_driver + .id_table = saa7185_id, + }; + +-static __init int init_saa7185(void) +-{ +- return i2c_add_driver(&saa7185_driver); +-} +- +-static __exit void exit_saa7185(void) +-{ +- i2c_del_driver(&saa7185_driver); +-} +- +-module_init(init_saa7185); +-module_exit(exit_saa7185); ++module_i2c_driver(saa7185_driver); +Index: linux-3.3.x86_64/drivers/media/video/saa7191.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/saa7191.c ++++ linux-3.3.x86_64/drivers/media/video/saa7191.c +@@ -656,15 +656,4 @@ static struct i2c_driver saa7191_driver + .id_table = saa7191_id, + }; + +-static __init int init_saa7191(void) +-{ +- return i2c_add_driver(&saa7191_driver); +-} +- +-static __exit void exit_saa7191(void) +-{ +- i2c_del_driver(&saa7191_driver); +-} +- +-module_init(init_saa7191); +-module_exit(exit_saa7191); ++module_i2c_driver(saa7191_driver); +Index: linux-3.3.x86_64/drivers/media/video/sr030pc30.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/sr030pc30.c ++++ linux-3.3.x86_64/drivers/media/video/sr030pc30.c +@@ -864,18 +864,7 @@ static struct i2c_driver sr030pc30_i2c_d + .id_table = sr030pc30_id, + }; + +-static int __init sr030pc30_init(void) +-{ +- return i2c_add_driver(&sr030pc30_i2c_driver); +-} +- +-static void __exit sr030pc30_exit(void) +-{ +- i2c_del_driver(&sr030pc30_i2c_driver); +-} +- +-module_init(sr030pc30_init); +-module_exit(sr030pc30_exit); ++module_i2c_driver(sr030pc30_i2c_driver); + + MODULE_DESCRIPTION("Siliconfile SR030PC30 camera driver"); + MODULE_AUTHOR("Sylwester Nawrocki "); +Index: linux-3.3.x86_64/drivers/media/video/tda7432.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/tda7432.c ++++ linux-3.3.x86_64/drivers/media/video/tda7432.c +@@ -482,15 +482,4 @@ static struct i2c_driver tda7432_driver + .id_table = tda7432_id, + }; + +-static __init int init_tda7432(void) +-{ +- return i2c_add_driver(&tda7432_driver); +-} +- +-static __exit void exit_tda7432(void) +-{ +- i2c_del_driver(&tda7432_driver); +-} +- +-module_init(init_tda7432); +-module_exit(exit_tda7432); ++module_i2c_driver(tda7432_driver); +Index: linux-3.3.x86_64/drivers/media/video/tda9840.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/tda9840.c ++++ linux-3.3.x86_64/drivers/media/video/tda9840.c +@@ -208,15 +208,4 @@ static struct i2c_driver tda9840_driver + .id_table = tda9840_id, + }; + +-static __init int init_tda9840(void) +-{ +- return i2c_add_driver(&tda9840_driver); +-} +- +-static __exit void exit_tda9840(void) +-{ +- i2c_del_driver(&tda9840_driver); +-} +- +-module_init(init_tda9840); +-module_exit(exit_tda9840); ++module_i2c_driver(tda9840_driver); +Index: linux-3.3.x86_64/drivers/media/video/tea6415c.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/tea6415c.c ++++ linux-3.3.x86_64/drivers/media/video/tea6415c.c +@@ -184,15 +184,4 @@ static struct i2c_driver tea6415c_driver + .id_table = tea6415c_id, + }; + +-static __init int init_tea6415c(void) +-{ +- return i2c_add_driver(&tea6415c_driver); +-} +- +-static __exit void exit_tea6415c(void) +-{ +- i2c_del_driver(&tea6415c_driver); +-} +- +-module_init(init_tea6415c); +-module_exit(exit_tea6415c); ++module_i2c_driver(tea6415c_driver); +Index: linux-3.3.x86_64/drivers/media/video/tea6420.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/tea6420.c ++++ linux-3.3.x86_64/drivers/media/video/tea6420.c +@@ -166,15 +166,4 @@ static struct i2c_driver tea6420_driver + .id_table = tea6420_id, + }; + +-static __init int init_tea6420(void) +-{ +- return i2c_add_driver(&tea6420_driver); +-} +- +-static __exit void exit_tea6420(void) +-{ +- i2c_del_driver(&tea6420_driver); +-} +- +-module_init(init_tea6420); +-module_exit(exit_tea6420); ++module_i2c_driver(tea6420_driver); +Index: linux-3.3.x86_64/drivers/media/video/ths7303.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ths7303.c ++++ linux-3.3.x86_64/drivers/media/video/ths7303.c +@@ -137,16 +137,4 @@ static struct i2c_driver ths7303_driver + .id_table = ths7303_id, + }; + +-static int __init ths7303_init(void) +-{ +- return i2c_add_driver(&ths7303_driver); +-} +- +-static void __exit ths7303_exit(void) +-{ +- i2c_del_driver(&ths7303_driver); +-} +- +-module_init(ths7303_init); +-module_exit(ths7303_exit); +- ++module_i2c_driver(ths7303_driver); +Index: linux-3.3.x86_64/drivers/media/video/tlv320aic23b.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/tlv320aic23b.c ++++ linux-3.3.x86_64/drivers/media/video/tlv320aic23b.c +@@ -227,15 +227,4 @@ static struct i2c_driver tlv320aic23b_dr + .id_table = tlv320aic23b_id, + }; + +-static __init int init_tlv320aic23b(void) +-{ +- return i2c_add_driver(&tlv320aic23b_driver); +-} +- +-static __exit void exit_tlv320aic23b(void) +-{ +- i2c_del_driver(&tlv320aic23b_driver); +-} +- +-module_init(init_tlv320aic23b); +-module_exit(exit_tlv320aic23b); ++module_i2c_driver(tlv320aic23b_driver); +Index: linux-3.3.x86_64/drivers/media/video/tvaudio.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/tvaudio.c ++++ linux-3.3.x86_64/drivers/media/video/tvaudio.c +@@ -2078,15 +2078,4 @@ static struct i2c_driver tvaudio_driver + .id_table = tvaudio_id, + }; + +-static __init int init_tvaudio(void) +-{ +- return i2c_add_driver(&tvaudio_driver); +-} +- +-static __exit void exit_tvaudio(void) +-{ +- i2c_del_driver(&tvaudio_driver); +-} +- +-module_init(init_tvaudio); +-module_exit(exit_tvaudio); ++module_i2c_driver(tvaudio_driver); +Index: linux-3.3.x86_64/drivers/media/video/tvp514x.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/tvp514x.c ++++ linux-3.3.x86_64/drivers/media/video/tvp514x.c +@@ -1163,15 +1163,4 @@ static struct i2c_driver tvp514x_driver + .id_table = tvp514x_id, + }; + +-static int __init tvp514x_init(void) +-{ +- return i2c_add_driver(&tvp514x_driver); +-} +- +-static void __exit tvp514x_exit(void) +-{ +- i2c_del_driver(&tvp514x_driver); +-} +- +-module_init(tvp514x_init); +-module_exit(tvp514x_exit); ++module_i2c_driver(tvp514x_driver); +Index: linux-3.3.x86_64/drivers/media/video/tvp5150.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/tvp5150.c ++++ linux-3.3.x86_64/drivers/media/video/tvp5150.c +@@ -17,6 +17,13 @@ + + #include "tvp5150_reg.h" + ++#define TVP5150_H_MAX 720 ++#define TVP5150_V_MAX_525_60 480 ++#define TVP5150_V_MAX_OTHERS 576 ++#define TVP5150_MAX_CROP_LEFT 511 ++#define TVP5150_MAX_CROP_TOP 127 ++#define TVP5150_CROP_SHIFT 2 ++ + MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver"); + MODULE_AUTHOR("Mauro Carvalho Chehab"); + MODULE_LICENSE("GPL"); +@@ -29,6 +36,7 @@ MODULE_PARM_DESC(debug, "Debug level (0- + struct tvp5150 { + struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; ++ struct v4l2_rect rect; + + v4l2_std_id norm; /* Current set standard */ + u32 input; +@@ -732,6 +740,13 @@ static int tvp5150_s_std(struct v4l2_sub + if (decoder->norm == std) + return 0; + ++ /* Change cropping height limits */ ++ if (std & V4L2_STD_525_60) ++ decoder->rect.height = TVP5150_V_MAX_525_60; ++ else ++ decoder->rect.height = TVP5150_V_MAX_OTHERS; ++ ++ + return tvp5150_set_std(sd, std); + } + +@@ -828,11 +843,8 @@ static int tvp5150_mbus_fmt(struct v4l2_ + else + std = decoder->norm; + +- f->width = 720; +- if (std & V4L2_STD_525_60) +- f->height = 480; +- else +- f->height = 576; ++ f->width = decoder->rect.width; ++ f->height = decoder->rect.height; + + f->code = V4L2_MBUS_FMT_YUYV8_2X8; + f->field = V4L2_FIELD_SEQ_TB; +@@ -843,6 +855,99 @@ static int tvp5150_mbus_fmt(struct v4l2_ + return 0; + } + ++static int tvp5150_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) ++{ ++ struct v4l2_rect rect = a->c; ++ struct tvp5150 *decoder = to_tvp5150(sd); ++ v4l2_std_id std; ++ int hmax; ++ ++ v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n", ++ __func__, rect.left, rect.top, rect.width, rect.height); ++ ++ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ ++ /* tvp5150 has some special limits */ ++ rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT); ++ rect.width = clamp(rect.width, ++ TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left, ++ TVP5150_H_MAX - rect.left); ++ rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP); ++ ++ /* Calculate height based on current standard */ ++ if (decoder->norm == V4L2_STD_ALL) ++ std = tvp5150_read_std(sd); ++ else ++ std = decoder->norm; ++ ++ if (std & V4L2_STD_525_60) ++ hmax = TVP5150_V_MAX_525_60; ++ else ++ hmax = TVP5150_V_MAX_OTHERS; ++ ++ rect.height = clamp(rect.height, ++ hmax - TVP5150_MAX_CROP_TOP - rect.top, ++ hmax - rect.top); ++ ++ tvp5150_write(sd, TVP5150_VERT_BLANKING_START, rect.top); ++ tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, ++ rect.top + rect.height - hmax); ++ tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_MSB, ++ rect.left >> TVP5150_CROP_SHIFT); ++ tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_LSB, ++ rect.left | (1 << TVP5150_CROP_SHIFT)); ++ tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_MSB, ++ (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >> ++ TVP5150_CROP_SHIFT); ++ tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_LSB, ++ rect.left + rect.width - TVP5150_MAX_CROP_LEFT); ++ ++ decoder->rect = rect; ++ ++ return 0; ++} ++ ++static int tvp5150_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) ++{ ++ struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd); ++ ++ a->c = decoder->rect; ++ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ ++ return 0; ++} ++ ++static int tvp5150_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) ++{ ++ struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd); ++ v4l2_std_id std; ++ ++ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ ++ a->bounds.left = 0; ++ a->bounds.top = 0; ++ a->bounds.width = TVP5150_H_MAX; ++ ++ /* Calculate height based on current standard */ ++ if (decoder->norm == V4L2_STD_ALL) ++ std = tvp5150_read_std(sd); ++ else ++ std = decoder->norm; ++ ++ if (std & V4L2_STD_525_60) ++ a->bounds.height = TVP5150_V_MAX_525_60; ++ else ++ a->bounds.height = TVP5150_V_MAX_OTHERS; ++ ++ a->defrect = a->bounds; ++ a->pixelaspect.numerator = 1; ++ a->pixelaspect.denominator = 1; ++ ++ return 0; ++} ++ + /**************************************************************************** + I2C Command + ****************************************************************************/ +@@ -998,6 +1103,10 @@ static const struct v4l2_subdev_video_op + .enum_mbus_fmt = tvp5150_enum_mbus_fmt, + .s_mbus_fmt = tvp5150_mbus_fmt, + .try_mbus_fmt = tvp5150_mbus_fmt, ++ .g_mbus_fmt = tvp5150_mbus_fmt, ++ .s_crop = tvp5150_s_crop, ++ .g_crop = tvp5150_g_crop, ++ .cropcap = tvp5150_cropcap, + }; + + static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { +@@ -1083,6 +1192,15 @@ static int tvp5150_probe(struct i2c_clie + } + v4l2_ctrl_handler_setup(&core->hdl); + ++ /* Default is no cropping */ ++ core->rect.top = 0; ++ if (tvp5150_read_std(sd) & V4L2_STD_525_60) ++ core->rect.height = TVP5150_V_MAX_525_60; ++ else ++ core->rect.height = TVP5150_V_MAX_OTHERS; ++ core->rect.left = 0; ++ core->rect.width = TVP5150_H_MAX; ++ + if (debug > 1) + tvp5150_log_status(sd); + return 0; +@@ -1121,15 +1239,4 @@ static struct i2c_driver tvp5150_driver + .id_table = tvp5150_id, + }; + +-static __init int init_tvp5150(void) +-{ +- return i2c_add_driver(&tvp5150_driver); +-} +- +-static __exit void exit_tvp5150(void) +-{ +- i2c_del_driver(&tvp5150_driver); +-} +- +-module_init(init_tvp5150); +-module_exit(exit_tvp5150); ++module_i2c_driver(tvp5150_driver); +Index: linux-3.3.x86_64/drivers/media/video/tvp7002.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/tvp7002.c ++++ linux-3.3.x86_64/drivers/media/video/tvp7002.c +@@ -1069,27 +1069,4 @@ static struct i2c_driver tvp7002_driver + .id_table = tvp7002_id, + }; + +-/* +- * tvp7002_init - Initialize driver via I2C interface +- * +- * Register the TVP7002 driver. +- * Return 0 on success or error code on failure. +- */ +-static int __init tvp7002_init(void) +-{ +- return i2c_add_driver(&tvp7002_driver); +-} +- +-/* +- * tvp7002_exit - Remove driver via I2C interface +- * +- * Unregister the TVP7002 driver. +- * Returns nothing. +- */ +-static void __exit tvp7002_exit(void) +-{ +- i2c_del_driver(&tvp7002_driver); +-} +- +-module_init(tvp7002_init); +-module_exit(tvp7002_exit); ++module_i2c_driver(tvp7002_driver); +Index: linux-3.3.x86_64/drivers/media/video/tw9910.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/tw9910.c ++++ linux-3.3.x86_64/drivers/media/video/tw9910.c +@@ -951,21 +951,7 @@ static struct i2c_driver tw9910_i2c_driv + .id_table = tw9910_id, + }; + +-/* +- * module function +- */ +-static int __init tw9910_module_init(void) +-{ +- return i2c_add_driver(&tw9910_i2c_driver); +-} +- +-static void __exit tw9910_module_exit(void) +-{ +- i2c_del_driver(&tw9910_i2c_driver); +-} +- +-module_init(tw9910_module_init); +-module_exit(tw9910_module_exit); ++module_i2c_driver(tw9910_i2c_driver); + + MODULE_DESCRIPTION("SoC Camera driver for tw9910"); + MODULE_AUTHOR("Kuninori Morimoto"); +Index: linux-3.3.x86_64/drivers/media/video/upd64031a.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/upd64031a.c ++++ linux-3.3.x86_64/drivers/media/video/upd64031a.c +@@ -271,15 +271,4 @@ static struct i2c_driver upd64031a_drive + .id_table = upd64031a_id, + }; + +-static __init int init_upd64031a(void) +-{ +- return i2c_add_driver(&upd64031a_driver); +-} +- +-static __exit void exit_upd64031a(void) +-{ +- i2c_del_driver(&upd64031a_driver); +-} +- +-module_init(init_upd64031a); +-module_exit(exit_upd64031a); ++module_i2c_driver(upd64031a_driver); +Index: linux-3.3.x86_64/drivers/media/video/upd64083.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/upd64083.c ++++ linux-3.3.x86_64/drivers/media/video/upd64083.c +@@ -243,15 +243,4 @@ static struct i2c_driver upd64083_driver + .id_table = upd64083_id, + }; + +-static __init int init_upd64083(void) +-{ +- return i2c_add_driver(&upd64083_driver); +-} +- +-static __exit void exit_upd64083(void) +-{ +- i2c_del_driver(&upd64083_driver); +-} +- +-module_init(init_upd64083); +-module_exit(exit_upd64083); ++module_i2c_driver(upd64083_driver); +Index: linux-3.3.x86_64/drivers/media/video/vp27smpx.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/vp27smpx.c ++++ linux-3.3.x86_64/drivers/media/video/vp27smpx.c +@@ -208,15 +208,4 @@ static struct i2c_driver vp27smpx_driver + .id_table = vp27smpx_id, + }; + +-static __init int init_vp27smpx(void) +-{ +- return i2c_add_driver(&vp27smpx_driver); +-} +- +-static __exit void exit_vp27smpx(void) +-{ +- i2c_del_driver(&vp27smpx_driver); +-} +- +-module_init(init_vp27smpx); +-module_exit(exit_vp27smpx); ++module_i2c_driver(vp27smpx_driver); +Index: linux-3.3.x86_64/drivers/media/video/vpx3220.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/vpx3220.c ++++ linux-3.3.x86_64/drivers/media/video/vpx3220.c +@@ -588,15 +588,4 @@ static struct i2c_driver vpx3220_driver + .id_table = vpx3220_id, + }; + +-static __init int init_vpx3220(void) +-{ +- return i2c_add_driver(&vpx3220_driver); +-} +- +-static __exit void exit_vpx3220(void) +-{ +- i2c_del_driver(&vpx3220_driver); +-} +- +-module_init(init_vpx3220); +-module_exit(exit_vpx3220); ++module_i2c_driver(vpx3220_driver); +Index: linux-3.3.x86_64/drivers/media/video/wm8739.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/wm8739.c ++++ linux-3.3.x86_64/drivers/media/video/wm8739.c +@@ -291,15 +291,4 @@ static struct i2c_driver wm8739_driver = + .id_table = wm8739_id, + }; + +-static __init int init_wm8739(void) +-{ +- return i2c_add_driver(&wm8739_driver); +-} +- +-static __exit void exit_wm8739(void) +-{ +- i2c_del_driver(&wm8739_driver); +-} +- +-module_init(init_wm8739); +-module_exit(exit_wm8739); ++module_i2c_driver(wm8739_driver); +Index: linux-3.3.x86_64/drivers/media/video/wm8775.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/wm8775.c ++++ linux-3.3.x86_64/drivers/media/video/wm8775.c +@@ -339,15 +339,4 @@ static struct i2c_driver wm8775_driver = + .id_table = wm8775_id, + }; + +-static __init int init_wm8775(void) +-{ +- return i2c_add_driver(&wm8775_driver); +-} +- +-static __exit void exit_wm8775(void) +-{ +- i2c_del_driver(&wm8775_driver); +-} +- +-module_init(init_wm8775); +-module_exit(exit_wm8775); ++module_i2c_driver(wm8775_driver); +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/it913x-fe-priv.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/it913x-fe-priv.h ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/it913x-fe-priv.h +@@ -201,6 +201,11 @@ fe_modulation_t fe_con[] = { + QAM_64, + }; + ++enum { ++ PRIORITY_HIGH = 0, /* High-priority stream */ ++ PRIORITY_LOW, /* Low-priority stream */ ++}; ++ + /* Standard demodulator functions */ + static struct it913xset set_solo_fe[] = { + {PRO_LINK, GPIOH5_EN, {0x01}, 0x01}, +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/it913x-fe.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/it913x-fe.c ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/it913x-fe.c +@@ -57,6 +57,7 @@ struct it913x_fe_state { + u32 frequency; + fe_modulation_t constellation; + fe_transmit_mode_t transmission_mode; ++ u8 priority; + u32 crystalFrequency; + u32 adcFrequency; + u8 tuner_type; +@@ -500,19 +501,87 @@ static int it913x_fe_read_status(struct + return 0; + } + ++/* FEC values based on fe_code_rate_t non supported values 0*/ ++int it913x_qpsk_pval[] = {0, -93, -91, -90, 0, -89, -88}; ++int it913x_16qam_pval[] = {0, -87, -85, -84, 0, -83, -82}; ++int it913x_64qam_pval[] = {0, -82, -80, -78, 0, -77, -76}; ++ ++static int it913x_get_signal_strength(struct dvb_frontend *fe) ++{ ++ struct dtv_frontend_properties *p = &fe->dtv_property_cache; ++ struct it913x_fe_state *state = fe->demodulator_priv; ++ u8 code_rate; ++ int ret, temp; ++ u8 lna_gain_os; ++ ++ ret = it913x_read_reg_u8(state, VAR_P_INBAND); ++ if (ret < 0) ++ return ret; ++ ++ /* VHF/UHF gain offset */ ++ if (state->frequency < 300000000) ++ lna_gain_os = 7; ++ else ++ lna_gain_os = 14; ++ ++ temp = (ret - 100) - lna_gain_os; ++ ++ if (state->priority == PRIORITY_HIGH) ++ code_rate = p->code_rate_HP; ++ else ++ code_rate = p->code_rate_LP; ++ ++ if (code_rate >= ARRAY_SIZE(it913x_qpsk_pval)) ++ return -EINVAL; ++ ++ deb_info("Reg VAR_P_INBAND:%d Calc Offset Value:%d", ret, temp); ++ ++ /* Apply FEC offset values*/ ++ switch (p->modulation) { ++ case QPSK: ++ temp -= it913x_qpsk_pval[code_rate]; ++ break; ++ case QAM_16: ++ temp -= it913x_16qam_pval[code_rate]; ++ break; ++ case QAM_64: ++ temp -= it913x_64qam_pval[code_rate]; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (temp < -15) ++ ret = 0; ++ else if ((-15 <= temp) && (temp < 0)) ++ ret = (2 * (temp + 15)) / 3; ++ else if ((0 <= temp) && (temp < 20)) ++ ret = 4 * temp + 10; ++ else if ((20 <= temp) && (temp < 35)) ++ ret = (2 * (temp - 20)) / 3 + 90; ++ else if (temp >= 35) ++ ret = 100; ++ ++ deb_info("Signal Strength :%d", ret); ++ ++ return ret; ++} ++ + static int it913x_fe_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) + { + struct it913x_fe_state *state = fe->demodulator_priv; +- int ret = it913x_read_reg_u8(state, SIGNAL_LEVEL); +- /*SIGNAL_LEVEL always returns 100%! so using FE_HAS_SIGNAL as switch*/ +- if (state->it913x_status & FE_HAS_SIGNAL) +- ret = (ret * 0xff) / 0x64; +- else +- ret = 0x0; +- ret |= ret << 0x8; +- *strength = ret; +- return 0; ++ int ret = 0; ++ if (state->config->read_slevel) { ++ if (state->it913x_status & FE_HAS_SIGNAL) ++ ret = it913x_read_reg_u8(state, SIGNAL_LEVEL); ++ } else ++ ret = it913x_get_signal_strength(fe); ++ ++ if (ret >= 0) ++ *strength = (u16)((u32)ret * 0xffff / 0x64); ++ ++ return (ret < 0) ? -ENODEV : 0; + } + + static int it913x_fe_read_snr(struct dvb_frontend *fe, u16 *snr) +@@ -606,6 +675,8 @@ static int it913x_fe_get_frontend(struct + if (reg[2] < 4) + p->hierarchy = fe_hi[reg[2]]; + ++ state->priority = reg[5]; ++ + p->code_rate_HP = (reg[6] < 6) ? fe_code[reg[6]] : FEC_NONE; + p->code_rate_LP = (reg[7] < 6) ? fe_code[reg[7]] : FEC_NONE; + +@@ -972,5 +1043,5 @@ static struct dvb_frontend_ops it913x_fe + + MODULE_DESCRIPTION("it913x Frontend and it9137 tuner"); + MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); +-MODULE_VERSION("1.13"); ++MODULE_VERSION("1.15"); + MODULE_LICENSE("GPL"); +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/it913x-fe.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/it913x-fe.h ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/it913x-fe.h +@@ -34,6 +34,8 @@ struct ite_config { + u8 tuner_id_1; + u8 dual_mode; + u8 adf; ++ /* option to read SIGNAL_LEVEL */ ++ u8 read_slevel; + }; + + #if defined(CONFIG_DVB_IT913X_FE) || (defined(CONFIG_DVB_IT913X_FE_MODULE) && \ +@@ -168,6 +170,8 @@ static inline struct dvb_frontend *it913 + #define EST_SIGNAL_LEVEL 0x004a + #define FREE_BAND 0x004b + #define SUSPEND_FLAG 0x004c ++#define VAR_P_INBAND 0x00f7 ++ + /* Build in tuner types */ + #define IT9137 0x38 + #define IT9135_38 0x38 +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/cx22702.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/cx22702.c ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/cx22702.c +@@ -502,10 +502,26 @@ static int cx22702_read_signal_strength( + u16 *signal_strength) + { + struct cx22702_state *state = fe->demodulator_priv; ++ u8 reg23; + +- u16 rs_ber; +- rs_ber = cx22702_readreg(state, 0x23); +- *signal_strength = (rs_ber << 8) | rs_ber; ++ /* ++ * Experience suggests that the strength signal register works as ++ * follows: ++ * - In the absence of signal, value is 0xff. ++ * - In the presence of a weak signal, bit 7 is set, not sure what ++ * the lower 7 bits mean. ++ * - In the presence of a strong signal, the register holds a 7-bit ++ * value (bit 7 is cleared), with greater values standing for ++ * weaker signals. ++ */ ++ reg23 = cx22702_readreg(state, 0x23); ++ if (reg23 & 0x80) { ++ *signal_strength = 0; ++ } else { ++ reg23 = ~reg23 & 0x7f; ++ /* Scale to 16 bit */ ++ *signal_strength = (reg23 << 9) | (reg23 << 2) | (reg23 >> 5); ++ } + + return 0; + } +Index: linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-cards.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/em28xx/em28xx-cards.c ++++ linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-cards.c +@@ -353,6 +353,44 @@ static struct em28xx_reg_seq hauppauge_9 + }; + #endif + ++/* 1b80:e425 MaxMedia UB425-TC ++ * GPIO_6 - demod reset, 0=active ++ * GPIO_7 - LED, 0=active ++ */ ++static struct em28xx_reg_seq maxmedia_ub425_tc[] = { ++ {EM2874_R80_GPIO, 0x83, 0xff, 100}, ++ {EM2874_R80_GPIO, 0xc3, 0xff, 100}, /* GPIO_6 = 1 */ ++ {EM2874_R80_GPIO, 0x43, 0xff, 000}, /* GPIO_7 = 0 */ ++ {-1, -1, -1, -1}, ++}; ++ ++/* 2304:0242 PCTV QuatroStick (510e) ++ * GPIO_2: decoder reset, 0=active ++ * GPIO_4: decoder suspend, 0=active ++ * GPIO_6: demod reset, 0=active ++ * GPIO_7: LED, 1=active ++ */ ++static struct em28xx_reg_seq pctv_510e[] = { ++ {EM2874_R80_GPIO, 0x10, 0xff, 100}, ++ {EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */ ++ {EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */ ++ { -1, -1, -1, -1}, ++}; ++ ++/* 2013:0251 PCTV QuatroStick nano (520e) ++ * GPIO_2: decoder reset, 0=active ++ * GPIO_4: decoder suspend, 0=active ++ * GPIO_6: demod reset, 0=active ++ * GPIO_7: LED, 1=active ++ */ ++static struct em28xx_reg_seq pctv_520e[] = { ++ {EM2874_R80_GPIO, 0x10, 0xff, 100}, ++ {EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */ ++ {EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */ ++ {EM2874_R80_GPIO, 0xd4, 0xff, 000}, /* GPIO_7 = 1 */ ++ { -1, -1, -1, -1}, ++}; ++ + /* + * Board definitions + */ +@@ -1908,6 +1946,41 @@ struct em28xx_board em28xx_boards[] = { + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, ++ /* 1b80:e425 MaxMedia UB425-TC ++ * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2 */ ++ [EM2874_BOARD_MAXMEDIA_UB425_TC] = { ++ .name = "MaxMedia UB425-TC", ++ .tuner_type = TUNER_ABSENT, ++ .tuner_gpio = maxmedia_ub425_tc, ++ .has_dvb = 1, ++ .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | ++ EM28XX_I2C_CLK_WAIT_ENABLE | ++ EM28XX_I2C_FREQ_400_KHZ, ++ }, ++ /* 2304:0242 PCTV QuatroStick (510e) ++ * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */ ++ [EM2884_BOARD_PCTV_510E] = { ++ .name = "PCTV QuatroStick (510e)", ++ .tuner_type = TUNER_ABSENT, ++ .tuner_gpio = pctv_510e, ++ .has_dvb = 1, ++ .ir_codes = RC_MAP_PINNACLE_PCTV_HD, ++ .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | ++ EM28XX_I2C_CLK_WAIT_ENABLE | ++ EM28XX_I2C_FREQ_400_KHZ, ++ }, ++ /* 2013:0251 PCTV QuatroStick nano (520e) ++ * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */ ++ [EM2884_BOARD_PCTV_520E] = { ++ .name = "PCTV QuatroStick nano (520e)", ++ .tuner_type = TUNER_ABSENT, ++ .tuner_gpio = pctv_520e, ++ .has_dvb = 1, ++ .ir_codes = RC_MAP_PINNACLE_PCTV_HD, ++ .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | ++ EM28XX_I2C_CLK_WAIT_ENABLE | ++ EM28XX_I2C_FREQ_400_KHZ, ++ }, + }; + const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); + +@@ -2059,6 +2132,12 @@ struct usb_device_id em28xx_id_table[] = + .driver_info = EM2860_BOARD_HT_VIDBOX_NW03 }, + { USB_DEVICE(0x1b80, 0xe309), /* Sveon STV40 */ + .driver_info = EM2860_BOARD_EASYCAP }, ++ { USB_DEVICE(0x1b80, 0xe425), ++ .driver_info = EM2874_BOARD_MAXMEDIA_UB425_TC }, ++ { USB_DEVICE(0x2304, 0x0242), ++ .driver_info = EM2884_BOARD_PCTV_510E }, ++ { USB_DEVICE(0x2013, 0x0251), ++ .driver_info = EM2884_BOARD_PCTV_520E }, + { }, + }; + MODULE_DEVICE_TABLE(usb, em28xx_id_table); +@@ -3122,7 +3201,6 @@ static int em28xx_usb_probe(struct usb_i + int i, nr; + const int ifnum = interface->altsetting[0].desc.bInterfaceNumber; + char *speed; +- char descr[255] = ""; + + udev = usb_get_dev(interface_to_usbdev(interface)); + +@@ -3227,21 +3305,11 @@ static int em28xx_usb_probe(struct usb_i + speed = "unknown"; + } + +- if (udev->manufacturer) +- strlcpy(descr, udev->manufacturer, sizeof(descr)); +- +- if (udev->product) { +- if (*descr) +- strlcat(descr, " ", sizeof(descr)); +- strlcat(descr, udev->product, sizeof(descr)); +- } +- +- if (*descr) +- strlcat(descr, " ", sizeof(descr)); +- + printk(KERN_INFO DRIVER_NAME +- ": New device %s@ %s Mbps (%04x:%04x, interface %d, class %d)\n", +- descr, ++ ": New device %s %s @ %s Mbps " ++ "(%04x:%04x, interface %d, class %d)\n", ++ udev->manufacturer ? udev->manufacturer : "", ++ udev->product ? udev->product : "", + speed, + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), +@@ -3307,6 +3375,17 @@ static int em28xx_usb_probe(struct usb_i + goto unlock_and_free; + } + ++ if (has_dvb) { ++ /* pre-allocate DVB isoc transfer buffers */ ++ retval = em28xx_alloc_isoc(dev, EM28XX_DIGITAL_MODE, ++ EM28XX_DVB_MAX_PACKETS, ++ EM28XX_DVB_NUM_BUFS, ++ dev->dvb_max_pkt_size); ++ if (retval) { ++ goto unlock_and_free; ++ } ++ } ++ + request_modules(dev); + + /* Should be the last thing to do, to avoid newer udev's to +@@ -3379,7 +3458,7 @@ static void em28xx_usb_disconnect(struct + video_device_node_name(dev->vdev)); + + dev->state |= DEV_MISCONFIGURED; +- em28xx_uninit_isoc(dev); ++ em28xx_uninit_isoc(dev, dev->mode); + dev->state |= DEV_DISCONNECTED; + wake_up_interruptible(&dev->wait_frame); + wake_up_interruptible(&dev->wait_stream); +@@ -3388,6 +3467,9 @@ static void em28xx_usb_disconnect(struct + em28xx_release_resources(dev); + } + ++ /* free DVB isoc buffers */ ++ em28xx_uninit_isoc(dev, EM28XX_DIGITAL_MODE); ++ + mutex_unlock(&dev->lock); + + em28xx_close_extension(dev); +Index: linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-core.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/em28xx/em28xx-core.c ++++ linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-core.c +@@ -666,6 +666,7 @@ int em28xx_capture_start(struct em28xx * + + return rc; + } ++EXPORT_SYMBOL_GPL(em28xx_capture_start); + + int em28xx_vbi_supported(struct em28xx *dev) + { +@@ -961,146 +962,192 @@ static void em28xx_irq_callback(struct u + /* + * Stop and Deallocate URBs + */ +-void em28xx_uninit_isoc(struct em28xx *dev) ++void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode) + { + struct urb *urb; ++ struct em28xx_usb_isoc_bufs *isoc_bufs; + int i; + +- em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n"); ++ em28xx_isocdbg("em28xx: called em28xx_uninit_isoc in mode %d\n", mode); ++ ++ if (mode == EM28XX_DIGITAL_MODE) ++ isoc_bufs = &dev->isoc_ctl.digital_bufs; ++ else ++ isoc_bufs = &dev->isoc_ctl.analog_bufs; + + dev->isoc_ctl.nfields = -1; +- for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { +- urb = dev->isoc_ctl.urb[i]; ++ for (i = 0; i < isoc_bufs->num_bufs; i++) { ++ urb = isoc_bufs->urb[i]; + if (urb) { + if (!irqs_disabled()) + usb_kill_urb(urb); + else + usb_unlink_urb(urb); + +- if (dev->isoc_ctl.transfer_buffer[i]) { ++ if (isoc_bufs->transfer_buffer[i]) { + usb_free_coherent(dev->udev, + urb->transfer_buffer_length, +- dev->isoc_ctl.transfer_buffer[i], ++ isoc_bufs->transfer_buffer[i], + urb->transfer_dma); + } + usb_free_urb(urb); +- dev->isoc_ctl.urb[i] = NULL; ++ isoc_bufs->urb[i] = NULL; + } +- dev->isoc_ctl.transfer_buffer[i] = NULL; ++ isoc_bufs->transfer_buffer[i] = NULL; + } + +- kfree(dev->isoc_ctl.urb); +- kfree(dev->isoc_ctl.transfer_buffer); ++ kfree(isoc_bufs->urb); ++ kfree(isoc_bufs->transfer_buffer); + +- dev->isoc_ctl.urb = NULL; +- dev->isoc_ctl.transfer_buffer = NULL; +- dev->isoc_ctl.num_bufs = 0; ++ isoc_bufs->urb = NULL; ++ isoc_bufs->transfer_buffer = NULL; ++ isoc_bufs->num_bufs = 0; + + em28xx_capture_start(dev, 0); + } + EXPORT_SYMBOL_GPL(em28xx_uninit_isoc); + + /* +- * Allocate URBs and start IRQ ++ * Allocate URBs + */ +-int em28xx_init_isoc(struct em28xx *dev, int max_packets, +- int num_bufs, int max_pkt_size, +- int (*isoc_copy) (struct em28xx *dev, struct urb *urb)) ++int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode, ++ int max_packets, int num_bufs, int max_pkt_size) + { +- struct em28xx_dmaqueue *dma_q = &dev->vidq; +- struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq; ++ struct em28xx_usb_isoc_bufs *isoc_bufs; + int i; + int sb_size, pipe; + struct urb *urb; + int j, k; +- int rc; + +- em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n"); ++ em28xx_isocdbg("em28xx: called em28xx_alloc_isoc in mode %d\n", mode); ++ ++ if (mode == EM28XX_DIGITAL_MODE) ++ isoc_bufs = &dev->isoc_ctl.digital_bufs; ++ else ++ isoc_bufs = &dev->isoc_ctl.analog_bufs; + + /* De-allocates all pending stuff */ +- em28xx_uninit_isoc(dev); ++ em28xx_uninit_isoc(dev, mode); + +- dev->isoc_ctl.isoc_copy = isoc_copy; +- dev->isoc_ctl.num_bufs = num_bufs; ++ isoc_bufs->num_bufs = num_bufs; + +- dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); +- if (!dev->isoc_ctl.urb) { ++ isoc_bufs->urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); ++ if (!isoc_bufs->urb) { + em28xx_errdev("cannot alloc memory for usb buffers\n"); + return -ENOMEM; + } + +- dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs, +- GFP_KERNEL); +- if (!dev->isoc_ctl.transfer_buffer) { ++ isoc_bufs->transfer_buffer = kzalloc(sizeof(void *)*num_bufs, ++ GFP_KERNEL); ++ if (!isoc_bufs->transfer_buffer) { + em28xx_errdev("cannot allocate memory for usb transfer\n"); +- kfree(dev->isoc_ctl.urb); ++ kfree(isoc_bufs->urb); + return -ENOMEM; + } + +- dev->isoc_ctl.max_pkt_size = max_pkt_size; ++ isoc_bufs->max_pkt_size = max_pkt_size; ++ isoc_bufs->num_packets = max_packets; + dev->isoc_ctl.vid_buf = NULL; + dev->isoc_ctl.vbi_buf = NULL; + +- sb_size = max_packets * dev->isoc_ctl.max_pkt_size; ++ sb_size = isoc_bufs->num_packets * isoc_bufs->max_pkt_size; + + /* allocate urbs and transfer buffers */ +- for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { +- urb = usb_alloc_urb(max_packets, GFP_KERNEL); ++ for (i = 0; i < isoc_bufs->num_bufs; i++) { ++ urb = usb_alloc_urb(isoc_bufs->num_packets, GFP_KERNEL); + if (!urb) { + em28xx_err("cannot alloc isoc_ctl.urb %i\n", i); +- em28xx_uninit_isoc(dev); ++ em28xx_uninit_isoc(dev, mode); + return -ENOMEM; + } +- dev->isoc_ctl.urb[i] = urb; ++ isoc_bufs->urb[i] = urb; + +- dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev, ++ isoc_bufs->transfer_buffer[i] = usb_alloc_coherent(dev->udev, + sb_size, GFP_KERNEL, &urb->transfer_dma); +- if (!dev->isoc_ctl.transfer_buffer[i]) { ++ if (!isoc_bufs->transfer_buffer[i]) { + em28xx_err("unable to allocate %i bytes for transfer" + " buffer %i%s\n", + sb_size, i, + in_interrupt() ? " while in int" : ""); +- em28xx_uninit_isoc(dev); ++ em28xx_uninit_isoc(dev, mode); + return -ENOMEM; + } +- memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size); ++ memset(isoc_bufs->transfer_buffer[i], 0, sb_size); + + /* FIXME: this is a hack - should be + 'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK' + should also be using 'desc.bInterval' + */ + pipe = usb_rcvisocpipe(dev->udev, +- dev->mode == EM28XX_ANALOG_MODE ? ++ mode == EM28XX_ANALOG_MODE ? + EM28XX_EP_ANALOG : EM28XX_EP_DIGITAL); + + usb_fill_int_urb(urb, dev->udev, pipe, +- dev->isoc_ctl.transfer_buffer[i], sb_size, ++ isoc_bufs->transfer_buffer[i], sb_size, + em28xx_irq_callback, dev, 1); + +- urb->number_of_packets = max_packets; ++ urb->number_of_packets = isoc_bufs->num_packets; + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + + k = 0; +- for (j = 0; j < max_packets; j++) { ++ for (j = 0; j < isoc_bufs->num_packets; j++) { + urb->iso_frame_desc[j].offset = k; + urb->iso_frame_desc[j].length = +- dev->isoc_ctl.max_pkt_size; +- k += dev->isoc_ctl.max_pkt_size; ++ isoc_bufs->max_pkt_size; ++ k += isoc_bufs->max_pkt_size; + } + } + ++ return 0; ++} ++EXPORT_SYMBOL_GPL(em28xx_alloc_isoc); ++ ++/* ++ * Allocate URBs and start IRQ ++ */ ++int em28xx_init_isoc(struct em28xx *dev, enum em28xx_mode mode, ++ int max_packets, int num_bufs, int max_pkt_size, ++ int (*isoc_copy) (struct em28xx *dev, struct urb *urb)) ++{ ++ struct em28xx_dmaqueue *dma_q = &dev->vidq; ++ struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq; ++ struct em28xx_usb_isoc_bufs *isoc_bufs; ++ int i; ++ int rc; ++ int alloc; ++ ++ em28xx_isocdbg("em28xx: called em28xx_init_isoc in mode %d\n", mode); ++ ++ dev->isoc_ctl.isoc_copy = isoc_copy; ++ ++ if (mode == EM28XX_DIGITAL_MODE) { ++ isoc_bufs = &dev->isoc_ctl.digital_bufs; ++ /* no need to free/alloc isoc buffers in digital mode */ ++ alloc = 0; ++ } else { ++ isoc_bufs = &dev->isoc_ctl.analog_bufs; ++ alloc = 1; ++ } ++ ++ if (alloc) { ++ rc = em28xx_alloc_isoc(dev, mode, max_packets, ++ num_bufs, max_pkt_size); ++ if (rc) ++ return rc; ++ } ++ + init_waitqueue_head(&dma_q->wq); + init_waitqueue_head(&vbi_dma_q->wq); + + em28xx_capture_start(dev, 1); + + /* submit urbs and enables IRQ */ +- for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { +- rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC); ++ for (i = 0; i < isoc_bufs->num_bufs; i++) { ++ rc = usb_submit_urb(isoc_bufs->urb[i], GFP_ATOMIC); + if (rc) { + em28xx_err("submit of urb %i failed (error=%i)\n", i, + rc); +- em28xx_uninit_isoc(dev); ++ em28xx_uninit_isoc(dev, mode); + return rc; + } + } +Index: linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-dvb.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/em28xx/em28xx-dvb.c ++++ linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-dvb.c +@@ -61,9 +61,6 @@ if (debug >= level) \ + printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \ + } while (0) + +-#define EM28XX_DVB_NUM_BUFS 5 +-#define EM28XX_DVB_MAX_PACKETS 64 +- + struct em28xx_dvb { + struct dvb_frontend *fe[2]; + +@@ -172,20 +169,21 @@ static int em28xx_start_streaming(struct + max_dvb_packet_size = dev->dvb_max_pkt_size; + if (max_dvb_packet_size < 0) + return max_dvb_packet_size; +- dprintk(1, "Using %d buffers each with %d bytes\n", ++ dprintk(1, "Using %d buffers each with %d x %d bytes\n", + EM28XX_DVB_NUM_BUFS, ++ EM28XX_DVB_MAX_PACKETS, + max_dvb_packet_size); + +- return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS, +- EM28XX_DVB_NUM_BUFS, max_dvb_packet_size, +- em28xx_dvb_isoc_copy); ++ return em28xx_init_isoc(dev, EM28XX_DIGITAL_MODE, ++ EM28XX_DVB_MAX_PACKETS, EM28XX_DVB_NUM_BUFS, ++ max_dvb_packet_size, em28xx_dvb_isoc_copy); + } + + static int em28xx_stop_streaming(struct em28xx_dvb *dvb) + { + struct em28xx *dev = dvb->adapter.priv; + +- em28xx_uninit_isoc(dev); ++ em28xx_capture_start(dev, 0); + + em28xx_set_mode(dev, EM28XX_SUSPEND); + +@@ -327,6 +325,19 @@ struct drxk_config hauppauge_930c_drxk = + .chunk_size = 56, + }; + ++struct drxk_config maxmedia_ub425_tc_drxk = { ++ .adr = 0x29, ++ .single_master = 1, ++ .no_i2c_bridge = 1, ++}; ++ ++struct drxk_config pctv_520e_drxk = { ++ .adr = 0x29, ++ .single_master = 1, ++ .microcode_name = "dvb-demod-drxk-pctv.fw", ++ .chunk_size = 58, ++}; ++ + static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) + { + struct em28xx_dvb *dvb = fe->sec_priv; +@@ -460,6 +471,33 @@ static void terratec_h5_init(struct em28 + em28xx_gpio_set(dev, terratec_h5_end); + }; + ++static void pctv_520e_init(struct em28xx *dev) ++{ ++ /* ++ * Init TDA8295(?) analog demodulator. Looks like I2C traffic to ++ * digital demodulator and tuner are routed via TDA8295. ++ */ ++ int i; ++ struct { ++ unsigned char r[4]; ++ int len; ++ } regs[] = { ++ {{ 0x06, 0x02, 0x00, 0x31 }, 4}, ++ {{ 0x01, 0x02 }, 2}, ++ {{ 0x01, 0x02, 0x00, 0xc6 }, 4}, ++ {{ 0x01, 0x00 }, 2}, ++ {{ 0x01, 0x00, 0xff, 0xaf }, 4}, ++ {{ 0x01, 0x00, 0x03, 0xa0 }, 4}, ++ {{ 0x01, 0x00 }, 2}, ++ {{ 0x01, 0x00, 0x73, 0xaf }, 4}, ++ }; ++ ++ dev->i2c_client.addr = 0x82 >> 1; /* 0x41 */ ++ ++ for (i = 0; i < ARRAY_SIZE(regs); i++) ++ i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len); ++}; ++ + static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe) + { + /* Values extracted from a USB trace of the Terratec Windows driver */ +@@ -938,6 +976,48 @@ static int em28xx_dvb_init(struct em28xx + dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap, + &em28xx_a8293_config); + break; ++ case EM2874_BOARD_MAXMEDIA_UB425_TC: ++ /* attach demodulator */ ++ dvb->fe[0] = dvb_attach(drxk_attach, &maxmedia_ub425_tc_drxk, ++ &dev->i2c_adap); ++ ++ if (dvb->fe[0]) { ++ /* disable I2C-gate */ ++ dvb->fe[0]->ops.i2c_gate_ctrl = NULL; ++ ++ /* attach tuner */ ++ if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], ++ &dev->i2c_adap, 0x60)) { ++ dvb_frontend_detach(dvb->fe[0]); ++ result = -EINVAL; ++ goto out_free; ++ } ++ } ++ ++ /* TODO: we need drx-3913k firmware in order to support DVB-T */ ++ em28xx_info("MaxMedia UB425-TC: only DVB-C supported by that " \ ++ "driver version\n"); ++ ++ break; ++ case EM2884_BOARD_PCTV_510E: ++ case EM2884_BOARD_PCTV_520E: ++ pctv_520e_init(dev); ++ ++ /* attach demodulator */ ++ dvb->fe[0] = dvb_attach(drxk_attach, &pctv_520e_drxk, ++ &dev->i2c_adap); ++ ++ if (dvb->fe[0]) { ++ /* attach tuner */ ++ if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, ++ &dev->i2c_adap, ++ &em28xx_cxd2820r_tda18271_config)) { ++ dvb_frontend_detach(dvb->fe[0]); ++ result = -EINVAL; ++ goto out_free; ++ } ++ } ++ break; + default: + em28xx_errdev("/2: The frontend of your DVB/ATSC card" + " isn't supported yet\n"); +Index: linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-video.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/em28xx/em28xx-video.c ++++ linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-video.c +@@ -760,17 +760,19 @@ buffer_prepare(struct videobuf_queue *vq + goto fail; + } + +- if (!dev->isoc_ctl.num_bufs) ++ if (!dev->isoc_ctl.analog_bufs.num_bufs) + urb_init = 1; + + if (urb_init) { + if (em28xx_vbi_supported(dev) == 1) +- rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS, ++ rc = em28xx_init_isoc(dev, EM28XX_ANALOG_MODE, ++ EM28XX_NUM_PACKETS, + EM28XX_NUM_BUFS, + dev->max_pkt_size, + em28xx_isoc_copy_vbi); + else +- rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS, ++ rc = em28xx_init_isoc(dev, EM28XX_ANALOG_MODE, ++ EM28XX_NUM_PACKETS, + EM28XX_NUM_BUFS, + dev->max_pkt_size, + em28xx_isoc_copy); +@@ -2267,7 +2269,7 @@ static int em28xx_v4l2_close(struct file + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); + + /* do this before setting alternate! */ +- em28xx_uninit_isoc(dev); ++ em28xx_uninit_isoc(dev, EM28XX_ANALOG_MODE); + em28xx_set_mode(dev, EM28XX_SUSPEND); + + /* set alternate 0 */ +Index: linux-3.3.x86_64/drivers/media/video/em28xx/em28xx.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/em28xx/em28xx.h ++++ linux-3.3.x86_64/drivers/media/video/em28xx/em28xx.h +@@ -125,6 +125,9 @@ + #define EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C 81 + #define EM2884_BOARD_CINERGY_HTC_STICK 82 + #define EM2860_BOARD_HT_VIDBOX_NW03 83 ++#define EM2874_BOARD_MAXMEDIA_UB425_TC 84 ++#define EM2884_BOARD_PCTV_510E 85 ++#define EM2884_BOARD_PCTV_520E 86 + + /* Limits minimum and default number of buffers */ + #define EM28XX_MIN_BUF 4 +@@ -151,12 +154,14 @@ + + /* number of buffers for isoc transfers */ + #define EM28XX_NUM_BUFS 5 ++#define EM28XX_DVB_NUM_BUFS 5 + + /* number of packets for each buffer + windows requests only 64 packets .. so we better do the same + this is what I found out for all alternate numbers there! + */ + #define EM28XX_NUM_PACKETS 64 ++#define EM28XX_DVB_MAX_PACKETS 64 + + #define EM28XX_INTERLACED_DEFAULT 1 + +@@ -197,10 +202,13 @@ enum em28xx_mode { + + struct em28xx; + +-struct em28xx_usb_isoc_ctl { ++struct em28xx_usb_isoc_bufs { + /* max packet size of isoc transaction */ + int max_pkt_size; + ++ /* number of packets in each buffer */ ++ int num_packets; ++ + /* number of allocated urbs */ + int num_bufs; + +@@ -209,6 +217,14 @@ struct em28xx_usb_isoc_ctl { + + /* transfer buffers for isoc transfer */ + char **transfer_buffer; ++}; ++ ++struct em28xx_usb_isoc_ctl { ++ /* isoc transfer buffers for analog mode */ ++ struct em28xx_usb_isoc_bufs analog_bufs; ++ ++ /* isoc transfer buffers for digital mode */ ++ struct em28xx_usb_isoc_bufs digital_bufs; + + /* Last buffer command and region */ + u8 cmd; +@@ -600,9 +616,6 @@ struct em28xx { + unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ + int dvb_alt; /* alternate for DVB */ + unsigned int dvb_max_pkt_size; /* wMaxPacketSize for DVB */ +- struct urb *urb[EM28XX_NUM_BUFS]; /* urb for isoc transfers */ +- char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc +- transfer */ + char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */ + + /* helper funcs that call usb_control_msg */ +@@ -676,10 +689,12 @@ int em28xx_vbi_supported(struct em28xx * + int em28xx_set_outfmt(struct em28xx *dev); + int em28xx_resolution_set(struct em28xx *dev); + int em28xx_set_alternate(struct em28xx *dev); +-int em28xx_init_isoc(struct em28xx *dev, int max_packets, +- int num_bufs, int max_pkt_size, ++int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode, ++ int max_packets, int num_bufs, int max_pkt_size); ++int em28xx_init_isoc(struct em28xx *dev, enum em28xx_mode mode, ++ int max_packets, int num_bufs, int max_pkt_size, + int (*isoc_copy) (struct em28xx *dev, struct urb *urb)); +-void em28xx_uninit_isoc(struct em28xx *dev); ++void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode); + int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev); + int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode); + int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio); +Index: linux-3.3.x86_64/drivers/media/video/mx2_camera.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/mx2_camera.c ++++ linux-3.3.x86_64/drivers/media/video/mx2_camera.c +@@ -3,6 +3,7 @@ + * + * Copyright (C) 2008, Sascha Hauer, Pengutronix + * Copyright (C) 2010, Baruch Siach, Orex Computed Radiography ++ * Copyright (C) 2012, Javier Martin, Vista Silicon S.L. + * + * 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 +@@ -18,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -30,17 +32,14 @@ + + #include + #include +-#include +-#include ++#include ++#include + #include + #include + + #include + + #include +-#ifdef CONFIG_MACH_MX27 +-#include +-#endif + #include + + #include +@@ -206,10 +205,23 @@ + #define PRP_INTR_LBOVF (1 << 7) + #define PRP_INTR_CH2OVF (1 << 8) + +-#define mx27_camera_emma(pcdev) (cpu_is_mx27() && pcdev->use_emma) ++/* Resizing registers */ ++#define PRP_RZ_VALID_TBL_LEN(x) ((x) << 24) ++#define PRP_RZ_VALID_BILINEAR (1 << 31) + + #define MAX_VIDEO_MEM 16 + ++#define RESIZE_NUM_MIN 1 ++#define RESIZE_NUM_MAX 20 ++#define BC_COEF 3 ++#define SZ_COEF (1 << BC_COEF) ++ ++#define RESIZE_DIR_H 0 ++#define RESIZE_DIR_V 1 ++ ++#define RESIZE_ALGO_BILINEAR 0 ++#define RESIZE_ALGO_AVERAGING 1 ++ + struct mx2_prp_cfg { + int channel; + u32 in_fmt; +@@ -219,6 +231,13 @@ struct mx2_prp_cfg { + u32 irq_flags; + }; + ++/* prp resizing parameters */ ++struct emma_prp_resize { ++ int algo; /* type of algorithm used */ ++ int len; /* number of coefficients */ ++ unsigned char s[RESIZE_NUM_MAX]; /* table of coefficients */ ++}; ++ + /* prp configuration for a client-host fmt pair */ + struct mx2_fmt_cfg { + enum v4l2_mbus_pixelcode in_fmt; +@@ -226,6 +245,26 @@ struct mx2_fmt_cfg { + struct mx2_prp_cfg cfg; + }; + ++enum mx2_buffer_state { ++ MX2_STATE_QUEUED, ++ MX2_STATE_ACTIVE, ++ MX2_STATE_DONE, ++}; ++ ++struct mx2_buf_internal { ++ struct list_head queue; ++ int bufnum; ++ bool discard; ++}; ++ ++/* buffer for one video frame */ ++struct mx2_buffer { ++ /* common v4l buffer stuff -- must be first */ ++ struct vb2_buffer vb; ++ enum mx2_buffer_state state; ++ struct mx2_buf_internal internal; ++}; ++ + struct mx2_camera_dev { + struct device *dev; + struct soc_camera_host soc_host; +@@ -242,6 +281,7 @@ struct mx2_camera_dev { + + struct list_head capture; + struct list_head active_bufs; ++ struct list_head discard; + + spinlock_t lock; + +@@ -250,26 +290,23 @@ struct mx2_camera_dev { + struct mx2_buffer *fb1_active; + struct mx2_buffer *fb2_active; + +- int use_emma; +- + u32 csicr1; + ++ struct mx2_buf_internal buf_discard[2]; + void *discard_buffer; + dma_addr_t discard_buffer_dma; + size_t discard_size; + struct mx2_fmt_cfg *emma_prp; ++ struct emma_prp_resize resizing[2]; ++ unsigned int s_width, s_height; + u32 frame_count; ++ struct vb2_alloc_ctx *alloc_ctx; + }; + +-/* buffer for one video frame */ +-struct mx2_buffer { +- /* common v4l buffer stuff -- must be first */ +- struct videobuf_buffer vb; +- +- enum v4l2_mbus_pixelcode code; +- +- int bufnum; +-}; ++static struct mx2_buffer *mx2_ibuf_to_buf(struct mx2_buf_internal *int_buf) ++{ ++ return container_of(int_buf, struct mx2_buffer, internal); ++} + + static struct mx2_fmt_cfg mx27_emma_prp_table[] = { + /* +@@ -324,13 +361,36 @@ static struct mx2_fmt_cfg *mx27_emma_prp + return &mx27_emma_prp_table[0]; + }; + ++static void mx27_update_emma_buf(struct mx2_camera_dev *pcdev, ++ unsigned long phys, int bufnum) ++{ ++ struct mx2_fmt_cfg *prp = pcdev->emma_prp; ++ ++ if (prp->cfg.channel == 1) { ++ writel(phys, pcdev->base_emma + ++ PRP_DEST_RGB1_PTR + 4 * bufnum); ++ } else { ++ writel(phys, pcdev->base_emma + ++ PRP_DEST_Y_PTR - 0x14 * bufnum); ++ if (prp->out_fmt == V4L2_PIX_FMT_YUV420) { ++ u32 imgsize = pcdev->icd->user_height * ++ pcdev->icd->user_width; ++ ++ writel(phys + imgsize, pcdev->base_emma + ++ PRP_DEST_CB_PTR - 0x14 * bufnum); ++ writel(phys + ((5 * imgsize) / 4), pcdev->base_emma + ++ PRP_DEST_CR_PTR - 0x14 * bufnum); ++ } ++ } ++} ++ + static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev) + { + unsigned long flags; + + clk_disable(pcdev->clk_csi); + writel(0, pcdev->base_csi + CSICR1); +- if (mx27_camera_emma(pcdev)) { ++ if (cpu_is_mx27()) { + writel(0, pcdev->base_emma + PRP_CNTL); + } else if (cpu_is_mx25()) { + spin_lock_irqsave(&pcdev->lock, flags); +@@ -362,7 +422,7 @@ static int mx2_camera_add_device(struct + + csicr1 = CSICR1_MCLKEN; + +- if (mx27_camera_emma(pcdev)) { ++ if (cpu_is_mx27()) { + csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC | + CSICR1_RXFF_LEVEL(0); + } else if (cpu_is_mx27()) +@@ -392,56 +452,13 @@ static void mx2_camera_remove_device(str + + mx2_camera_deactivate(pcdev); + +- if (pcdev->discard_buffer) { +- dma_free_coherent(ici->v4l2_dev.dev, pcdev->discard_size, +- pcdev->discard_buffer, +- pcdev->discard_buffer_dma); +- pcdev->discard_buffer = NULL; +- } +- + pcdev->icd = NULL; + } + +-#ifdef CONFIG_MACH_MX27 +-static void mx27_camera_dma_enable(struct mx2_camera_dev *pcdev) +-{ +- u32 tmp; +- +- imx_dma_enable(pcdev->dma); +- +- tmp = readl(pcdev->base_csi + CSICR1); +- tmp |= CSICR1_RF_OR_INTEN; +- writel(tmp, pcdev->base_csi + CSICR1); +-} +- +-static irqreturn_t mx27_camera_irq(int irq_csi, void *data) +-{ +- struct mx2_camera_dev *pcdev = data; +- u32 status = readl(pcdev->base_csi + CSISR); +- +- if (status & CSISR_SOF_INT && pcdev->active) { +- u32 tmp; +- +- tmp = readl(pcdev->base_csi + CSICR1); +- writel(tmp | CSICR1_CLR_RXFIFO, pcdev->base_csi + CSICR1); +- mx27_camera_dma_enable(pcdev); +- } +- +- writel(CSISR_SOF_INT | CSISR_RFF_OR_INT, pcdev->base_csi + CSISR); +- +- return IRQ_HANDLED; +-} +-#else +-static irqreturn_t mx27_camera_irq(int irq_csi, void *data) +-{ +- return IRQ_NONE; +-} +-#endif /* CONFIG_MACH_MX27 */ +- + static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb, + int state) + { +- struct videobuf_buffer *vb; ++ struct vb2_buffer *vb; + struct mx2_buffer *buf; + struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active : + &pcdev->fb2_active; +@@ -454,25 +471,24 @@ static void mx25_camera_frame_done(struc + goto out; + + vb = &(*fb_active)->vb; +- dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, +- vb, vb->baddr, vb->bsize); +- +- vb->state = state; +- do_gettimeofday(&vb->ts); +- vb->field_count++; ++ dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, ++ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); + +- wake_up(&vb->done); ++ do_gettimeofday(&vb->v4l2_buf.timestamp); ++ vb->v4l2_buf.sequence++; ++ vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + + if (list_empty(&pcdev->capture)) { + buf = NULL; + writel(0, pcdev->base_csi + fb_reg); + } else { +- buf = list_entry(pcdev->capture.next, struct mx2_buffer, +- vb.queue); ++ buf = list_first_entry(&pcdev->capture, struct mx2_buffer, ++ internal.queue); + vb = &buf->vb; +- list_del(&vb->queue); +- vb->state = VIDEOBUF_ACTIVE; +- writel(videobuf_to_dma_contig(vb), pcdev->base_csi + fb_reg); ++ list_del(&buf->internal.queue); ++ buf->state = MX2_STATE_ACTIVE; ++ writel(vb2_dma_contig_plane_dma_addr(vb, 0), ++ pcdev->base_csi + fb_reg); + } + + *fb_active = buf; +@@ -487,9 +503,9 @@ static irqreturn_t mx25_camera_irq(int i + u32 status = readl(pcdev->base_csi + CSISR); + + if (status & CSISR_DMA_TSF_FB1_INT) +- mx25_camera_frame_done(pcdev, 1, VIDEOBUF_DONE); ++ mx25_camera_frame_done(pcdev, 1, MX2_STATE_DONE); + else if (status & CSISR_DMA_TSF_FB2_INT) +- mx25_camera_frame_done(pcdev, 2, VIDEOBUF_DONE); ++ mx25_camera_frame_done(pcdev, 2, MX2_STATE_DONE); + + /* FIXME: handle CSISR_RFF_OR_INT */ + +@@ -501,59 +517,50 @@ static irqreturn_t mx25_camera_irq(int i + /* + * Videobuf operations + */ +-static int mx2_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, +- unsigned int *size) ++static int mx2_videobuf_setup(struct vb2_queue *vq, ++ const struct v4l2_format *fmt, ++ unsigned int *count, unsigned int *num_planes, ++ unsigned int sizes[], void *alloc_ctxs[]) + { +- struct soc_camera_device *icd = vq->priv_data; ++ struct soc_camera_device *icd = soc_camera_from_vb2q(vq); ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct mx2_camera_dev *pcdev = ici->priv; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + +- dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size); ++ dev_dbg(icd->parent, "count=%d, size=%d\n", *count, sizes[0]); ++ ++ /* TODO: support for VIDIOC_CREATE_BUFS not ready */ ++ if (fmt != NULL) ++ return -ENOTTY; + + if (bytes_per_line < 0) + return bytes_per_line; + +- *size = bytes_per_line * icd->user_height; ++ alloc_ctxs[0] = pcdev->alloc_ctx; ++ ++ sizes[0] = bytes_per_line * icd->user_height; + + if (0 == *count) + *count = 32; +- if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024) +- *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size; ++ if (!*num_planes && ++ sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024) ++ *count = (MAX_VIDEO_MEM * 1024 * 1024) / sizes[0]; + +- return 0; +-} +- +-static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf) +-{ +- struct soc_camera_device *icd = vq->priv_data; +- struct videobuf_buffer *vb = &buf->vb; ++ *num_planes = 1; + +- dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, +- vb, vb->baddr, vb->bsize); +- +- /* +- * This waits until this buffer is out of danger, i.e., until it is no +- * longer in state VIDEOBUF_QUEUED or VIDEOBUF_ACTIVE +- */ +- videobuf_waiton(vq, vb, 0, 0); +- +- videobuf_dma_contig_free(vq, vb); +- dev_dbg(icd->parent, "%s freed\n", __func__); +- +- vb->state = VIDEOBUF_NEEDS_INIT; ++ return 0; + } + +-static int mx2_videobuf_prepare(struct videobuf_queue *vq, +- struct videobuf_buffer *vb, enum v4l2_field field) ++static int mx2_videobuf_prepare(struct vb2_buffer *vb) + { +- struct soc_camera_device *icd = vq->priv_data; +- struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); ++ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + int ret = 0; + +- dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, +- vb, vb->baddr, vb->bsize); ++ dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, ++ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); + + if (bytes_per_line < 0) + return bytes_per_line; +@@ -563,99 +570,58 @@ static int mx2_videobuf_prepare(struct v + * This can be useful if you want to see if we actually fill + * the buffer with something + */ +- memset((void *)vb->baddr, 0xaa, vb->bsize); ++ memset((void *)vb2_plane_vaddr(vb, 0), ++ 0xaa, vb2_get_plane_payload(vb, 0)); + #endif + +- if (buf->code != icd->current_fmt->code || +- vb->width != icd->user_width || +- vb->height != icd->user_height || +- vb->field != field) { +- buf->code = icd->current_fmt->code; +- vb->width = icd->user_width; +- vb->height = icd->user_height; +- vb->field = field; +- vb->state = VIDEOBUF_NEEDS_INIT; +- } +- +- vb->size = bytes_per_line * vb->height; +- if (vb->baddr && vb->bsize < vb->size) { ++ vb2_set_plane_payload(vb, 0, bytes_per_line * icd->user_height); ++ if (vb2_plane_vaddr(vb, 0) && ++ vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) { + ret = -EINVAL; + goto out; + } + +- if (vb->state == VIDEOBUF_NEEDS_INIT) { +- ret = videobuf_iolock(vq, vb, NULL); +- if (ret) +- goto fail; +- +- vb->state = VIDEOBUF_PREPARED; +- } +- + return 0; + +-fail: +- free_buffer(vq, buf); + out: + return ret; + } + +-static void mx2_videobuf_queue(struct videobuf_queue *vq, +- struct videobuf_buffer *vb) ++static void mx2_videobuf_queue(struct vb2_buffer *vb) + { +- struct soc_camera_device *icd = vq->priv_data; ++ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); + struct soc_camera_host *ici = + to_soc_camera_host(icd->parent); + struct mx2_camera_dev *pcdev = ici->priv; + struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); + unsigned long flags; + +- dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, +- vb, vb->baddr, vb->bsize); ++ dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, ++ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); + + spin_lock_irqsave(&pcdev->lock, flags); + +- vb->state = VIDEOBUF_QUEUED; +- list_add_tail(&vb->queue, &pcdev->capture); +- +- if (mx27_camera_emma(pcdev)) { +- goto out; +-#ifdef CONFIG_MACH_MX27 +- } else if (cpu_is_mx27()) { +- int ret; +- +- if (pcdev->active == NULL) { +- ret = imx_dma_setup_single(pcdev->dma, +- videobuf_to_dma_contig(vb), vb->size, +- (u32)pcdev->base_dma + 0x10, +- DMA_MODE_READ); +- if (ret) { +- vb->state = VIDEOBUF_ERROR; +- wake_up(&vb->done); +- goto out; +- } ++ buf->state = MX2_STATE_QUEUED; ++ list_add_tail(&buf->internal.queue, &pcdev->capture); + +- vb->state = VIDEOBUF_ACTIVE; +- pcdev->active = buf; +- } +-#endif +- } else { /* cpu_is_mx25() */ ++ if (cpu_is_mx25()) { + u32 csicr3, dma_inten = 0; + + if (pcdev->fb1_active == NULL) { +- writel(videobuf_to_dma_contig(vb), ++ writel(vb2_dma_contig_plane_dma_addr(vb, 0), + pcdev->base_csi + CSIDMASA_FB1); + pcdev->fb1_active = buf; + dma_inten = CSICR1_FB1_DMA_INTEN; + } else if (pcdev->fb2_active == NULL) { +- writel(videobuf_to_dma_contig(vb), ++ writel(vb2_dma_contig_plane_dma_addr(vb, 0), + pcdev->base_csi + CSIDMASA_FB2); + pcdev->fb2_active = buf; + dma_inten = CSICR1_FB2_DMA_INTEN; + } + + if (dma_inten) { +- list_del(&vb->queue); +- vb->state = VIDEOBUF_ACTIVE; ++ list_del(&buf->internal.queue); ++ buf->state = MX2_STATE_ACTIVE; + + csicr3 = readl(pcdev->base_csi + CSICR3); + +@@ -674,36 +640,31 @@ static void mx2_videobuf_queue(struct vi + } + } + +-out: + spin_unlock_irqrestore(&pcdev->lock, flags); + } + +-static void mx2_videobuf_release(struct videobuf_queue *vq, +- struct videobuf_buffer *vb) ++static void mx2_videobuf_release(struct vb2_buffer *vb) + { +- struct soc_camera_device *icd = vq->priv_data; ++ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct mx2_camera_dev *pcdev = ici->priv; + struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); + unsigned long flags; + + #ifdef DEBUG +- dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, +- vb, vb->baddr, vb->bsize); ++ dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, ++ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); + +- switch (vb->state) { +- case VIDEOBUF_ACTIVE: ++ switch (buf->state) { ++ case MX2_STATE_ACTIVE: + dev_info(icd->parent, "%s (active)\n", __func__); + break; +- case VIDEOBUF_QUEUED: ++ case MX2_STATE_QUEUED: + dev_info(icd->parent, "%s (queued)\n", __func__); + break; +- case VIDEOBUF_PREPARED: +- dev_info(icd->parent, "%s (prepared)\n", __func__); +- break; + default: + dev_info(icd->parent, "%s (unknown) %d\n", __func__, +- vb->state); ++ buf->state); + break; + } + #endif +@@ -717,11 +678,9 @@ static void mx2_videobuf_release(struct + * state. This requires a specific handling for each of the these DMA + * types. + */ ++ + spin_lock_irqsave(&pcdev->lock, flags); +- if (vb->state == VIDEOBUF_QUEUED) { +- list_del(&vb->queue); +- vb->state = VIDEOBUF_ERROR; +- } else if (cpu_is_mx25() && vb->state == VIDEOBUF_ACTIVE) { ++ if (cpu_is_mx25() && buf->state == MX2_STATE_ACTIVE) { + if (pcdev->fb1_active == buf) { + pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN; + writel(0, pcdev->base_csi + CSIDMASA_FB1); +@@ -732,30 +691,260 @@ static void mx2_videobuf_release(struct + pcdev->fb2_active = NULL; + } + writel(pcdev->csicr1, pcdev->base_csi + CSICR1); +- vb->state = VIDEOBUF_ERROR; + } + spin_unlock_irqrestore(&pcdev->lock, flags); ++} ++ ++static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, ++ int bytesperline) ++{ ++ struct soc_camera_host *ici = ++ to_soc_camera_host(icd->parent); ++ struct mx2_camera_dev *pcdev = ici->priv; ++ struct mx2_fmt_cfg *prp = pcdev->emma_prp; ++ ++ writel((pcdev->s_width << 16) | pcdev->s_height, ++ pcdev->base_emma + PRP_SRC_FRAME_SIZE); ++ writel(prp->cfg.src_pixel, ++ pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); ++ if (prp->cfg.channel == 1) { ++ writel((icd->user_width << 16) | icd->user_height, ++ pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE); ++ writel(bytesperline, ++ pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE); ++ writel(prp->cfg.ch1_pixel, ++ pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL); ++ } else { /* channel 2 */ ++ writel((icd->user_width << 16) | icd->user_height, ++ pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE); ++ } ++ ++ /* Enable interrupts */ ++ writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL); ++} ++ ++static void mx2_prp_resize_commit(struct mx2_camera_dev *pcdev) ++{ ++ int dir; ++ ++ for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) { ++ unsigned char *s = pcdev->resizing[dir].s; ++ int len = pcdev->resizing[dir].len; ++ unsigned int coeff[2] = {0, 0}; ++ unsigned int valid = 0; ++ int i; ++ ++ if (len == 0) ++ continue; ++ ++ for (i = RESIZE_NUM_MAX - 1; i >= 0; i--) { ++ int j; ++ ++ j = i > 9 ? 1 : 0; ++ coeff[j] = (coeff[j] << BC_COEF) | ++ (s[i] & (SZ_COEF - 1)); ++ ++ if (i == 5 || i == 15) ++ coeff[j] <<= 1; ++ ++ valid = (valid << 1) | (s[i] >> BC_COEF); ++ } ++ ++ valid |= PRP_RZ_VALID_TBL_LEN(len); ++ ++ if (pcdev->resizing[dir].algo == RESIZE_ALGO_BILINEAR) ++ valid |= PRP_RZ_VALID_BILINEAR; ++ ++ if (pcdev->emma_prp->cfg.channel == 1) { ++ if (dir == RESIZE_DIR_H) { ++ writel(coeff[0], pcdev->base_emma + ++ PRP_CH1_RZ_HORI_COEF1); ++ writel(coeff[1], pcdev->base_emma + ++ PRP_CH1_RZ_HORI_COEF2); ++ writel(valid, pcdev->base_emma + ++ PRP_CH1_RZ_HORI_VALID); ++ } else { ++ writel(coeff[0], pcdev->base_emma + ++ PRP_CH1_RZ_VERT_COEF1); ++ writel(coeff[1], pcdev->base_emma + ++ PRP_CH1_RZ_VERT_COEF2); ++ writel(valid, pcdev->base_emma + ++ PRP_CH1_RZ_VERT_VALID); ++ } ++ } else { ++ if (dir == RESIZE_DIR_H) { ++ writel(coeff[0], pcdev->base_emma + ++ PRP_CH2_RZ_HORI_COEF1); ++ writel(coeff[1], pcdev->base_emma + ++ PRP_CH2_RZ_HORI_COEF2); ++ writel(valid, pcdev->base_emma + ++ PRP_CH2_RZ_HORI_VALID); ++ } else { ++ writel(coeff[0], pcdev->base_emma + ++ PRP_CH2_RZ_VERT_COEF1); ++ writel(coeff[1], pcdev->base_emma + ++ PRP_CH2_RZ_VERT_COEF2); ++ writel(valid, pcdev->base_emma + ++ PRP_CH2_RZ_VERT_VALID); ++ } ++ } ++ } ++} ++ ++static int mx2_start_streaming(struct vb2_queue *q, unsigned int count) ++{ ++ struct soc_camera_device *icd = soc_camera_from_vb2q(q); ++ struct soc_camera_host *ici = ++ to_soc_camera_host(icd->parent); ++ struct mx2_camera_dev *pcdev = ici->priv; ++ struct mx2_fmt_cfg *prp = pcdev->emma_prp; ++ struct vb2_buffer *vb; ++ struct mx2_buffer *buf; ++ unsigned long phys; ++ int bytesperline; ++ ++ if (cpu_is_mx27()) { ++ unsigned long flags; ++ if (count < 2) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&pcdev->lock, flags); ++ ++ buf = list_first_entry(&pcdev->capture, struct mx2_buffer, ++ internal.queue); ++ buf->internal.bufnum = 0; ++ vb = &buf->vb; ++ buf->state = MX2_STATE_ACTIVE; ++ ++ phys = vb2_dma_contig_plane_dma_addr(vb, 0); ++ mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum); ++ list_move_tail(pcdev->capture.next, &pcdev->active_bufs); ++ ++ buf = list_first_entry(&pcdev->capture, struct mx2_buffer, ++ internal.queue); ++ buf->internal.bufnum = 1; ++ vb = &buf->vb; ++ buf->state = MX2_STATE_ACTIVE; ++ ++ phys = vb2_dma_contig_plane_dma_addr(vb, 0); ++ mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum); ++ list_move_tail(pcdev->capture.next, &pcdev->active_bufs); ++ ++ bytesperline = soc_mbus_bytes_per_line(icd->user_width, ++ icd->current_fmt->host_fmt); ++ if (bytesperline < 0) ++ return bytesperline; ++ ++ /* ++ * I didn't manage to properly enable/disable the prp ++ * on a per frame basis during running transfers, ++ * thus we allocate a buffer here and use it to ++ * discard frames when no buffer is available. ++ * Feel free to work on this ;) ++ */ ++ pcdev->discard_size = icd->user_height * bytesperline; ++ pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev, ++ pcdev->discard_size, &pcdev->discard_buffer_dma, ++ GFP_KERNEL); ++ if (!pcdev->discard_buffer) ++ return -ENOMEM; ++ ++ pcdev->buf_discard[0].discard = true; ++ list_add_tail(&pcdev->buf_discard[0].queue, ++ &pcdev->discard); ++ ++ pcdev->buf_discard[1].discard = true; ++ list_add_tail(&pcdev->buf_discard[1].queue, ++ &pcdev->discard); ++ ++ mx2_prp_resize_commit(pcdev); ++ ++ mx27_camera_emma_buf_init(icd, bytesperline); ++ ++ if (prp->cfg.channel == 1) { ++ writel(PRP_CNTL_CH1EN | ++ PRP_CNTL_CSIEN | ++ prp->cfg.in_fmt | ++ prp->cfg.out_fmt | ++ PRP_CNTL_CH1_LEN | ++ PRP_CNTL_CH1BYP | ++ PRP_CNTL_CH1_TSKIP(0) | ++ PRP_CNTL_IN_TSKIP(0), ++ pcdev->base_emma + PRP_CNTL); ++ } else { ++ writel(PRP_CNTL_CH2EN | ++ PRP_CNTL_CSIEN | ++ prp->cfg.in_fmt | ++ prp->cfg.out_fmt | ++ PRP_CNTL_CH2_LEN | ++ PRP_CNTL_CH2_TSKIP(0) | ++ PRP_CNTL_IN_TSKIP(0), ++ pcdev->base_emma + PRP_CNTL); ++ } ++ spin_unlock_irqrestore(&pcdev->lock, flags); ++ } ++ ++ return 0; ++} ++ ++static int mx2_stop_streaming(struct vb2_queue *q) ++{ ++ struct soc_camera_device *icd = soc_camera_from_vb2q(q); ++ struct soc_camera_host *ici = ++ to_soc_camera_host(icd->parent); ++ struct mx2_camera_dev *pcdev = ici->priv; ++ struct mx2_fmt_cfg *prp = pcdev->emma_prp; ++ unsigned long flags; ++ void *b; ++ u32 cntl; ++ ++ if (cpu_is_mx27()) { ++ spin_lock_irqsave(&pcdev->lock, flags); ++ ++ cntl = readl(pcdev->base_emma + PRP_CNTL); ++ if (prp->cfg.channel == 1) { ++ writel(cntl & ~PRP_CNTL_CH1EN, ++ pcdev->base_emma + PRP_CNTL); ++ } else { ++ writel(cntl & ~PRP_CNTL_CH2EN, ++ pcdev->base_emma + PRP_CNTL); ++ } ++ INIT_LIST_HEAD(&pcdev->capture); ++ INIT_LIST_HEAD(&pcdev->active_bufs); ++ INIT_LIST_HEAD(&pcdev->discard); ++ ++ b = pcdev->discard_buffer; ++ pcdev->discard_buffer = NULL; ++ ++ spin_unlock_irqrestore(&pcdev->lock, flags); ++ ++ dma_free_coherent(ici->v4l2_dev.dev, ++ pcdev->discard_size, b, pcdev->discard_buffer_dma); ++ } + +- free_buffer(vq, buf); ++ return 0; + } + +-static struct videobuf_queue_ops mx2_videobuf_ops = { +- .buf_setup = mx2_videobuf_setup, +- .buf_prepare = mx2_videobuf_prepare, +- .buf_queue = mx2_videobuf_queue, +- .buf_release = mx2_videobuf_release, ++static struct vb2_ops mx2_videobuf_ops = { ++ .queue_setup = mx2_videobuf_setup, ++ .buf_prepare = mx2_videobuf_prepare, ++ .buf_queue = mx2_videobuf_queue, ++ .buf_cleanup = mx2_videobuf_release, ++ .start_streaming = mx2_start_streaming, ++ .stop_streaming = mx2_stop_streaming, + }; + +-static void mx2_camera_init_videobuf(struct videobuf_queue *q, ++static int mx2_camera_init_videobuf(struct vb2_queue *q, + struct soc_camera_device *icd) + { +- struct soc_camera_host *ici = to_soc_camera_host(icd->parent); +- struct mx2_camera_dev *pcdev = ici->priv; ++ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ q->io_modes = VB2_MMAP | VB2_USERPTR; ++ q->drv_priv = icd; ++ q->ops = &mx2_videobuf_ops; ++ q->mem_ops = &vb2_dma_contig_memops; ++ q->buf_struct_size = sizeof(struct mx2_buffer); + +- videobuf_queue_dma_contig_init(q, &mx2_videobuf_ops, pcdev->dev, +- &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, +- V4L2_FIELD_NONE, sizeof(struct mx2_buffer), +- icd, &icd->video_lock); ++ return vb2_queue_init(q); + } + + #define MX2_BUS_FLAGS (V4L2_MBUS_MASTER | \ +@@ -785,82 +974,6 @@ static int mx27_camera_emma_prp_reset(st + return -ETIMEDOUT; + } + +-static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, +- int bytesperline) +-{ +- struct soc_camera_host *ici = +- to_soc_camera_host(icd->parent); +- struct mx2_camera_dev *pcdev = ici->priv; +- struct mx2_fmt_cfg *prp = pcdev->emma_prp; +- u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width; +- +- if (prp->cfg.channel == 1) { +- writel(pcdev->discard_buffer_dma, +- pcdev->base_emma + PRP_DEST_RGB1_PTR); +- writel(pcdev->discard_buffer_dma, +- pcdev->base_emma + PRP_DEST_RGB2_PTR); +- +- writel(PRP_CNTL_CH1EN | +- PRP_CNTL_CSIEN | +- prp->cfg.in_fmt | +- prp->cfg.out_fmt | +- PRP_CNTL_CH1_LEN | +- PRP_CNTL_CH1BYP | +- PRP_CNTL_CH1_TSKIP(0) | +- PRP_CNTL_IN_TSKIP(0), +- pcdev->base_emma + PRP_CNTL); +- +- writel((icd->user_width << 16) | icd->user_height, +- pcdev->base_emma + PRP_SRC_FRAME_SIZE); +- writel((icd->user_width << 16) | icd->user_height, +- pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE); +- writel(bytesperline, +- pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE); +- writel(prp->cfg.src_pixel, +- pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); +- writel(prp->cfg.ch1_pixel, +- pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL); +- } else { /* channel 2 */ +- writel(pcdev->discard_buffer_dma, +- pcdev->base_emma + PRP_DEST_Y_PTR); +- writel(pcdev->discard_buffer_dma, +- pcdev->base_emma + PRP_SOURCE_Y_PTR); +- +- if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) { +- writel(pcdev->discard_buffer_dma + imgsize, +- pcdev->base_emma + PRP_DEST_CB_PTR); +- writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4), +- pcdev->base_emma + PRP_DEST_CR_PTR); +- writel(pcdev->discard_buffer_dma + imgsize, +- pcdev->base_emma + PRP_SOURCE_CB_PTR); +- writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4), +- pcdev->base_emma + PRP_SOURCE_CR_PTR); +- } +- +- writel(PRP_CNTL_CH2EN | +- PRP_CNTL_CSIEN | +- prp->cfg.in_fmt | +- prp->cfg.out_fmt | +- PRP_CNTL_CH2_LEN | +- PRP_CNTL_CH2_TSKIP(0) | +- PRP_CNTL_IN_TSKIP(0), +- pcdev->base_emma + PRP_CNTL); +- +- writel((icd->user_width << 16) | icd->user_height, +- pcdev->base_emma + PRP_SRC_FRAME_SIZE); +- +- writel((icd->user_width << 16) | icd->user_height, +- pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE); +- +- writel(prp->cfg.src_pixel, +- pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); +- +- } +- +- /* Enable interrupts */ +- writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL); +-} +- + static int mx2_camera_set_bus_param(struct soc_camera_device *icd) + { + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); +@@ -939,31 +1052,10 @@ static int mx2_camera_set_bus_param(stru + if (bytesperline < 0) + return bytesperline; + +- if (mx27_camera_emma(pcdev)) { ++ if (cpu_is_mx27()) { + ret = mx27_camera_emma_prp_reset(pcdev); + if (ret) + return ret; +- +- if (pcdev->discard_buffer) +- dma_free_coherent(ici->v4l2_dev.dev, +- pcdev->discard_size, pcdev->discard_buffer, +- pcdev->discard_buffer_dma); +- +- /* +- * I didn't manage to properly enable/disable the prp +- * on a per frame basis during running transfers, +- * thus we allocate a buffer here and use it to +- * discard frames when no buffer is available. +- * Feel free to work on this ;) +- */ +- pcdev->discard_size = icd->user_height * bytesperline; +- pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev, +- pcdev->discard_size, &pcdev->discard_buffer_dma, +- GFP_KERNEL); +- if (!pcdev->discard_buffer) +- return -ENOMEM; +- +- mx27_camera_emma_buf_init(icd, bytesperline); + } else if (cpu_is_mx25()) { + writel((bytesperline * icd->user_height) >> 2, + pcdev->base_csi + CSIRXCNT); +@@ -1052,6 +1144,123 @@ static int mx2_camera_get_formats(struct + return formats; + } + ++static int mx2_emmaprp_resize(struct mx2_camera_dev *pcdev, ++ struct v4l2_mbus_framefmt *mf_in, ++ struct v4l2_pix_format *pix_out, bool apply) ++{ ++ int num, den; ++ unsigned long m; ++ int i, dir; ++ ++ for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) { ++ struct emma_prp_resize tmprsz; ++ unsigned char *s = tmprsz.s; ++ int len = 0; ++ int in, out; ++ ++ if (dir == RESIZE_DIR_H) { ++ in = mf_in->width; ++ out = pix_out->width; ++ } else { ++ in = mf_in->height; ++ out = pix_out->height; ++ } ++ ++ if (in < out) ++ return -EINVAL; ++ else if (in == out) ++ continue; ++ ++ /* Calculate ratio */ ++ m = gcd(in, out); ++ num = in / m; ++ den = out / m; ++ if (num > RESIZE_NUM_MAX) ++ return -EINVAL; ++ ++ if ((num >= 2 * den) && (den == 1) && ++ (num < 9) && (!(num & 0x01))) { ++ int sum = 0; ++ int j; ++ ++ /* Average scaling for >= 2:1 ratios */ ++ /* Support can be added for num >=9 and odd values */ ++ ++ tmprsz.algo = RESIZE_ALGO_AVERAGING; ++ len = num; ++ ++ for (i = 0; i < (len / 2); i++) ++ s[i] = 8; ++ ++ do { ++ for (i = 0; i < (len / 2); i++) { ++ s[i] = s[i] >> 1; ++ sum = 0; ++ for (j = 0; j < (len / 2); j++) ++ sum += s[j]; ++ if (sum == 4) ++ break; ++ } ++ } while (sum != 4); ++ ++ for (i = (len / 2); i < len; i++) ++ s[i] = s[len - i - 1]; ++ ++ s[len - 1] |= SZ_COEF; ++ } else { ++ /* bilinear scaling for < 2:1 ratios */ ++ int v; /* overflow counter */ ++ int coeff, nxt; /* table output */ ++ int in_pos_inc = 2 * den; ++ int out_pos = num; ++ int out_pos_inc = 2 * num; ++ int init_carry = num - den; ++ int carry = init_carry; ++ ++ tmprsz.algo = RESIZE_ALGO_BILINEAR; ++ v = den + in_pos_inc; ++ do { ++ coeff = v - out_pos; ++ out_pos += out_pos_inc; ++ carry += out_pos_inc; ++ for (nxt = 0; v < out_pos; nxt++) { ++ v += in_pos_inc; ++ carry -= in_pos_inc; ++ } ++ ++ if (len > RESIZE_NUM_MAX) ++ return -EINVAL; ++ ++ coeff = ((coeff << BC_COEF) + ++ (in_pos_inc >> 1)) / in_pos_inc; ++ ++ if (coeff >= (SZ_COEF - 1)) ++ coeff--; ++ ++ coeff |= SZ_COEF; ++ s[len] = (unsigned char)coeff; ++ len++; ++ ++ for (i = 1; i < nxt; i++) { ++ if (len >= RESIZE_NUM_MAX) ++ return -EINVAL; ++ s[len] = 0; ++ len++; ++ } ++ } while (carry != init_carry); ++ } ++ tmprsz.len = len; ++ if (dir == RESIZE_DIR_H) ++ mf_in->width = pix_out->width; ++ else ++ mf_in->height = pix_out->height; ++ ++ if (apply) ++ memcpy(&pcdev->resizing[dir], &tmprsz, sizeof(tmprsz)); ++ } ++ return 0; ++} ++ + static int mx2_camera_set_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) + { +@@ -1063,6 +1272,9 @@ static int mx2_camera_set_fmt(struct soc + struct v4l2_mbus_framefmt mf; + int ret; + ++ dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n", ++ __func__, pix->width, pix->height); ++ + xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); + if (!xlate) { + dev_warn(icd->parent, "Format %x not found\n", +@@ -1080,6 +1292,22 @@ static int mx2_camera_set_fmt(struct soc + if (ret < 0 && ret != -ENOIOCTLCMD) + return ret; + ++ /* Store width and height returned by the sensor for resizing */ ++ pcdev->s_width = mf.width; ++ pcdev->s_height = mf.height; ++ dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n", ++ __func__, pcdev->s_width, pcdev->s_height); ++ ++ pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code, ++ xlate->host_fmt->fourcc); ++ ++ memset(pcdev->resizing, 0, sizeof(pcdev->resizing)); ++ if ((mf.width != pix->width || mf.height != pix->height) && ++ pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { ++ if (mx2_emmaprp_resize(pcdev, &mf, pix, true) < 0) ++ dev_dbg(icd->parent, "%s: can't resize\n", __func__); ++ } ++ + if (mf.code != xlate->code) + return -EINVAL; + +@@ -1089,9 +1317,8 @@ static int mx2_camera_set_fmt(struct soc + pix->colorspace = mf.colorspace; + icd->current_fmt = xlate; + +- if (mx27_camera_emma(pcdev)) +- pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code, +- xlate->host_fmt->fourcc); ++ dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n", ++ __func__, pix->width, pix->height); + + return 0; + } +@@ -1104,9 +1331,14 @@ static int mx2_camera_try_fmt(struct soc + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_mbus_framefmt mf; + __u32 pixfmt = pix->pixelformat; ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct mx2_camera_dev *pcdev = ici->priv; + unsigned int width_limit; + int ret; + ++ dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n", ++ __func__, pix->width, pix->height); ++ + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); + if (pixfmt && !xlate) { + dev_warn(icd->parent, "Format %x not found\n", pixfmt); +@@ -1156,6 +1388,20 @@ static int mx2_camera_try_fmt(struct soc + if (ret < 0) + return ret; + ++ dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n", ++ __func__, pcdev->s_width, pcdev->s_height); ++ ++ /* If the sensor does not support image size try PrP resizing */ ++ pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code, ++ xlate->host_fmt->fourcc); ++ ++ memset(pcdev->resizing, 0, sizeof(pcdev->resizing)); ++ if ((mf.width != pix->width || mf.height != pix->height) && ++ pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { ++ if (mx2_emmaprp_resize(pcdev, &mf, pix, false) < 0) ++ dev_dbg(icd->parent, "%s: can't resize\n", __func__); ++ } ++ + if (mf.field == V4L2_FIELD_ANY) + mf.field = V4L2_FIELD_NONE; + /* +@@ -1174,6 +1420,9 @@ static int mx2_camera_try_fmt(struct soc + pix->field = mf.field; + pix->colorspace = mf.colorspace; + ++ dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n", ++ __func__, pix->width, pix->height); ++ + return 0; + } + +@@ -1187,136 +1436,11 @@ static int mx2_camera_querycap(struct so + return 0; + } + +-static int mx2_camera_reqbufs(struct soc_camera_device *icd, +- struct v4l2_requestbuffers *p) +-{ +- int i; +- +- for (i = 0; i < p->count; i++) { +- struct mx2_buffer *buf = container_of(icd->vb_vidq.bufs[i], +- struct mx2_buffer, vb); +- INIT_LIST_HEAD(&buf->vb.queue); +- } +- +- return 0; +-} +- +-#ifdef CONFIG_MACH_MX27 +-static void mx27_camera_frame_done(struct mx2_camera_dev *pcdev, int state) +-{ +- struct videobuf_buffer *vb; +- struct mx2_buffer *buf; +- unsigned long flags; +- int ret; +- +- spin_lock_irqsave(&pcdev->lock, flags); +- +- if (!pcdev->active) { +- dev_err(pcdev->dev, "%s called with no active buffer!\n", +- __func__); +- goto out; +- } +- +- vb = &pcdev->active->vb; +- buf = container_of(vb, struct mx2_buffer, vb); +- WARN_ON(list_empty(&vb->queue)); +- dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, +- vb, vb->baddr, vb->bsize); +- +- /* _init is used to debug races, see comment in pxa_camera_reqbufs() */ +- list_del_init(&vb->queue); +- vb->state = state; +- do_gettimeofday(&vb->ts); +- vb->field_count++; +- +- wake_up(&vb->done); +- +- if (list_empty(&pcdev->capture)) { +- pcdev->active = NULL; +- goto out; +- } +- +- pcdev->active = list_entry(pcdev->capture.next, +- struct mx2_buffer, vb.queue); +- +- vb = &pcdev->active->vb; +- vb->state = VIDEOBUF_ACTIVE; +- +- ret = imx_dma_setup_single(pcdev->dma, videobuf_to_dma_contig(vb), +- vb->size, (u32)pcdev->base_dma + 0x10, DMA_MODE_READ); +- +- if (ret) { +- vb->state = VIDEOBUF_ERROR; +- pcdev->active = NULL; +- wake_up(&vb->done); +- } +- +-out: +- spin_unlock_irqrestore(&pcdev->lock, flags); +-} +- +-static void mx27_camera_dma_err_callback(int channel, void *data, int err) +-{ +- struct mx2_camera_dev *pcdev = data; +- +- mx27_camera_frame_done(pcdev, VIDEOBUF_ERROR); +-} +- +-static void mx27_camera_dma_callback(int channel, void *data) +-{ +- struct mx2_camera_dev *pcdev = data; +- +- mx27_camera_frame_done(pcdev, VIDEOBUF_DONE); +-} +- +-#define DMA_REQ_CSI_RX 31 /* FIXME: Add this to a resource */ +- +-static int __devinit mx27_camera_dma_init(struct platform_device *pdev, +- struct mx2_camera_dev *pcdev) +-{ +- int err; +- +- pcdev->dma = imx_dma_request_by_prio("CSI RX DMA", DMA_PRIO_HIGH); +- if (pcdev->dma < 0) { +- dev_err(&pdev->dev, "%s failed to request DMA channel\n", +- __func__); +- return pcdev->dma; +- } +- +- err = imx_dma_setup_handlers(pcdev->dma, mx27_camera_dma_callback, +- mx27_camera_dma_err_callback, pcdev); +- if (err) { +- dev_err(&pdev->dev, "%s failed to set DMA callback\n", +- __func__); +- goto err_out; +- } +- +- err = imx_dma_config_channel(pcdev->dma, +- IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_FIFO, +- IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, +- DMA_REQ_CSI_RX, 1); +- if (err) { +- dev_err(&pdev->dev, "%s failed to config DMA channel\n", +- __func__); +- goto err_out; +- } +- +- imx_dma_config_burstlen(pcdev->dma, 64); +- +- return 0; +- +-err_out: +- imx_dma_free(pcdev->dma); +- +- return err; +-} +-#endif /* CONFIG_MACH_MX27 */ +- + static unsigned int mx2_camera_poll(struct file *file, poll_table *pt) + { + struct soc_camera_device *icd = file->private_data; + +- return videobuf_poll_stream(file, &icd->vb_vidq, pt); ++ return vb2_poll(&icd->vb2_vidq, file, pt); + } + + static struct soc_camera_host_ops mx2_soc_camera_host_ops = { +@@ -1327,144 +1451,148 @@ static struct soc_camera_host_ops mx2_so + .set_crop = mx2_camera_set_crop, + .get_formats = mx2_camera_get_formats, + .try_fmt = mx2_camera_try_fmt, +- .init_videobuf = mx2_camera_init_videobuf, +- .reqbufs = mx2_camera_reqbufs, ++ .init_videobuf2 = mx2_camera_init_videobuf, + .poll = mx2_camera_poll, + .querycap = mx2_camera_querycap, + .set_bus_param = mx2_camera_set_bus_param, + }; + + static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, +- int bufnum, int state) ++ int bufnum, bool err) + { +- u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width; ++#ifdef DEBUG + struct mx2_fmt_cfg *prp = pcdev->emma_prp; ++#endif ++ struct mx2_buf_internal *ibuf; + struct mx2_buffer *buf; +- struct videobuf_buffer *vb; ++ struct vb2_buffer *vb; + unsigned long phys; + +- if (!list_empty(&pcdev->active_bufs)) { +- buf = list_entry(pcdev->active_bufs.next, +- struct mx2_buffer, vb.queue); ++ ibuf = list_first_entry(&pcdev->active_bufs, struct mx2_buf_internal, ++ queue); + +- BUG_ON(buf->bufnum != bufnum); ++ BUG_ON(ibuf->bufnum != bufnum); ++ ++ if (ibuf->discard) { ++ /* ++ * Discard buffer must not be returned to user space. ++ * Just return it to the discard queue. ++ */ ++ list_move_tail(pcdev->active_bufs.next, &pcdev->discard); ++ } else { ++ buf = mx2_ibuf_to_buf(ibuf); + + vb = &buf->vb; + #ifdef DEBUG +- phys = videobuf_to_dma_contig(vb); ++ phys = vb2_dma_contig_plane_dma_addr(vb, 0); + if (prp->cfg.channel == 1) { + if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR + + 4 * bufnum) != phys) { +- dev_err(pcdev->dev, "%p != %p\n", phys, +- readl(pcdev->base_emma + +- PRP_DEST_RGB1_PTR + +- 4 * bufnum)); ++ dev_err(pcdev->dev, "%lx != %x\n", phys, ++ readl(pcdev->base_emma + ++ PRP_DEST_RGB1_PTR + 4 * bufnum)); + } + } else { + if (readl(pcdev->base_emma + PRP_DEST_Y_PTR - + 0x14 * bufnum) != phys) { +- dev_err(pcdev->dev, "%p != %p\n", phys, +- readl(pcdev->base_emma + +- PRP_DEST_Y_PTR - +- 0x14 * bufnum)); ++ dev_err(pcdev->dev, "%lx != %x\n", phys, ++ readl(pcdev->base_emma + ++ PRP_DEST_Y_PTR - 0x14 * bufnum)); + } + } + #endif +- dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, +- vb->baddr, vb->bsize); +- +- list_del(&vb->queue); +- vb->state = state; +- do_gettimeofday(&vb->ts); +- vb->field_count = pcdev->frame_count * 2; +- pcdev->frame_count++; +- +- wake_up(&vb->done); ++ dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb, ++ vb2_plane_vaddr(vb, 0), ++ vb2_get_plane_payload(vb, 0)); ++ ++ list_del_init(&buf->internal.queue); ++ do_gettimeofday(&vb->v4l2_buf.timestamp); ++ vb->v4l2_buf.sequence = pcdev->frame_count; ++ if (err) ++ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); ++ else ++ vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + } + ++ pcdev->frame_count++; ++ + if (list_empty(&pcdev->capture)) { +- if (prp->cfg.channel == 1) { +- writel(pcdev->discard_buffer_dma, pcdev->base_emma + +- PRP_DEST_RGB1_PTR + 4 * bufnum); +- } else { +- writel(pcdev->discard_buffer_dma, pcdev->base_emma + +- PRP_DEST_Y_PTR - +- 0x14 * bufnum); +- if (prp->out_fmt == V4L2_PIX_FMT_YUV420) { +- writel(pcdev->discard_buffer_dma + imgsize, +- pcdev->base_emma + PRP_DEST_CB_PTR - +- 0x14 * bufnum); +- writel(pcdev->discard_buffer_dma + +- ((5 * imgsize) / 4), pcdev->base_emma + +- PRP_DEST_CR_PTR - 0x14 * bufnum); +- } ++ if (list_empty(&pcdev->discard)) { ++ dev_warn(pcdev->dev, "%s: trying to access empty discard list\n", ++ __func__); ++ return; + } ++ ++ ibuf = list_first_entry(&pcdev->discard, ++ struct mx2_buf_internal, queue); ++ ibuf->bufnum = bufnum; ++ ++ list_move_tail(pcdev->discard.next, &pcdev->active_bufs); ++ mx27_update_emma_buf(pcdev, pcdev->discard_buffer_dma, bufnum); + return; + } + +- buf = list_entry(pcdev->capture.next, +- struct mx2_buffer, vb.queue); ++ buf = list_first_entry(&pcdev->capture, struct mx2_buffer, ++ internal.queue); + +- buf->bufnum = !bufnum; ++ buf->internal.bufnum = bufnum; + + list_move_tail(pcdev->capture.next, &pcdev->active_bufs); + + vb = &buf->vb; +- vb->state = VIDEOBUF_ACTIVE; ++ buf->state = MX2_STATE_ACTIVE; + +- phys = videobuf_to_dma_contig(vb); +- if (prp->cfg.channel == 1) { +- writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum); +- } else { +- writel(phys, pcdev->base_emma + +- PRP_DEST_Y_PTR - 0x14 * bufnum); +- if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) { +- writel(phys + imgsize, pcdev->base_emma + +- PRP_DEST_CB_PTR - 0x14 * bufnum); +- writel(phys + ((5 * imgsize) / 4), pcdev->base_emma + +- PRP_DEST_CR_PTR - 0x14 * bufnum); +- } +- } ++ phys = vb2_dma_contig_plane_dma_addr(vb, 0); ++ mx27_update_emma_buf(pcdev, phys, bufnum); + } + + static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) + { + struct mx2_camera_dev *pcdev = data; + unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS); +- struct mx2_buffer *buf; ++ struct mx2_buf_internal *ibuf; ++ ++ spin_lock(&pcdev->lock); ++ ++ if (list_empty(&pcdev->active_bufs)) { ++ dev_warn(pcdev->dev, "%s: called while active list is empty\n", ++ __func__); ++ ++ if (!status) { ++ spin_unlock(&pcdev->lock); ++ return IRQ_NONE; ++ } ++ } + + if (status & (1 << 7)) { /* overflow */ +- u32 cntl; +- /* +- * We only disable channel 1 here since this is the only +- * enabled channel +- * +- * FIXME: the correct DMA overflow handling should be resetting +- * the buffer, returning an error frame, and continuing with +- * the next one. +- */ +- cntl = readl(pcdev->base_emma + PRP_CNTL); ++ u32 cntl = readl(pcdev->base_emma + PRP_CNTL); + writel(cntl & ~(PRP_CNTL_CH1EN | PRP_CNTL_CH2EN), + pcdev->base_emma + PRP_CNTL); + writel(cntl, pcdev->base_emma + PRP_CNTL); +- } +- if ((((status & (3 << 5)) == (3 << 5)) || +- ((status & (3 << 3)) == (3 << 3))) +- && !list_empty(&pcdev->active_bufs)) { ++ ++ ibuf = list_first_entry(&pcdev->active_bufs, ++ struct mx2_buf_internal, queue); ++ mx27_camera_frame_done_emma(pcdev, ++ ibuf->bufnum, true); ++ ++ status &= ~(1 << 7); ++ } else if (((status & (3 << 5)) == (3 << 5)) || ++ ((status & (3 << 3)) == (3 << 3))) { + /* + * Both buffers have triggered, process the one we're expecting + * to first + */ +- buf = list_entry(pcdev->active_bufs.next, +- struct mx2_buffer, vb.queue); +- mx27_camera_frame_done_emma(pcdev, buf->bufnum, VIDEOBUF_DONE); +- status &= ~(1 << (6 - buf->bufnum)); /* mark processed */ +- } +- if ((status & (1 << 6)) || (status & (1 << 4))) +- mx27_camera_frame_done_emma(pcdev, 0, VIDEOBUF_DONE); +- if ((status & (1 << 5)) || (status & (1 << 3))) +- mx27_camera_frame_done_emma(pcdev, 1, VIDEOBUF_DONE); ++ ibuf = list_first_entry(&pcdev->active_bufs, ++ struct mx2_buf_internal, queue); ++ mx27_camera_frame_done_emma(pcdev, ibuf->bufnum, false); ++ status &= ~(1 << (6 - ibuf->bufnum)); /* mark processed */ ++ } else if ((status & (1 << 6)) || (status & (1 << 4))) { ++ mx27_camera_frame_done_emma(pcdev, 0, false); ++ } else if ((status & (1 << 5)) || (status & (1 << 3))) { ++ mx27_camera_frame_done_emma(pcdev, 1, false); ++ } + ++ spin_unlock(&pcdev->lock); + writel(status, pcdev->base_emma + PRP_INTRSTATUS); + + return IRQ_HANDLED; +@@ -1527,8 +1655,6 @@ static int __devinit mx2_camera_probe(st + struct resource *res_csi, *res_emma; + void __iomem *base_csi; + int irq_csi, irq_emma; +- irq_handler_t mx2_cam_irq_handler = cpu_is_mx25() ? mx25_camera_irq +- : mx27_camera_irq; + int err = 0; + + dev_dbg(&pdev->dev, "initialising\n"); +@@ -1550,22 +1676,11 @@ static int __devinit mx2_camera_probe(st + + pcdev->clk_csi = clk_get(&pdev->dev, NULL); + if (IS_ERR(pcdev->clk_csi)) { ++ dev_err(&pdev->dev, "Could not get csi clock\n"); + err = PTR_ERR(pcdev->clk_csi); + goto exit_kfree; + } + +- dev_dbg(&pdev->dev, "Camera clock frequency: %ld\n", +- clk_get_rate(pcdev->clk_csi)); +- +- /* Initialize DMA */ +-#ifdef CONFIG_MACH_MX27 +- if (cpu_is_mx27()) { +- err = mx27_camera_dma_init(pdev, pcdev); +- if (err) +- goto exit_clk_put; +- } +-#endif /* CONFIG_MACH_MX27 */ +- + pcdev->res_csi = res_csi; + pcdev->pdata = pdev->dev.platform_data; + if (pcdev->pdata) { +@@ -1585,6 +1700,7 @@ static int __devinit mx2_camera_probe(st + + INIT_LIST_HEAD(&pcdev->capture); + INIT_LIST_HEAD(&pcdev->active_bufs); ++ INIT_LIST_HEAD(&pcdev->discard); + spin_lock_init(&pcdev->lock); + + /* +@@ -1606,11 +1722,13 @@ static int __devinit mx2_camera_probe(st + pcdev->base_dma = res_csi->start; + pcdev->dev = &pdev->dev; + +- err = request_irq(pcdev->irq_csi, mx2_cam_irq_handler, 0, +- MX2_CAM_DRV_NAME, pcdev); +- if (err) { +- dev_err(pcdev->dev, "Camera interrupt register failed \n"); +- goto exit_iounmap; ++ if (cpu_is_mx25()) { ++ err = request_irq(pcdev->irq_csi, mx25_camera_irq, 0, ++ MX2_CAM_DRV_NAME, pcdev); ++ if (err) { ++ dev_err(pcdev->dev, "Camera interrupt register failed \n"); ++ goto exit_iounmap; ++ } + } + + if (cpu_is_mx27()) { +@@ -1618,14 +1736,15 @@ static int __devinit mx2_camera_probe(st + res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1); + irq_emma = platform_get_irq(pdev, 1); + +- if (res_emma && irq_emma >= 0) { +- dev_info(&pdev->dev, "Using EMMA\n"); +- pcdev->use_emma = 1; +- pcdev->res_emma = res_emma; +- pcdev->irq_emma = irq_emma; +- if (mx27_camera_emma_init(pcdev)) +- goto exit_free_irq; ++ if (!res_emma || !irq_emma) { ++ dev_err(&pdev->dev, "no EMMA resources\n"); ++ goto exit_free_irq; + } ++ ++ pcdev->res_emma = res_emma; ++ pcdev->irq_emma = irq_emma; ++ if (mx27_camera_emma_init(pcdev)) ++ goto exit_free_irq; + } + + pcdev->soc_host.drv_name = MX2_CAM_DRV_NAME, +@@ -1633,6 +1752,12 @@ static int __devinit mx2_camera_probe(st + pcdev->soc_host.priv = pcdev; + pcdev->soc_host.v4l2_dev.dev = &pdev->dev; + pcdev->soc_host.nr = pdev->id; ++ ++ pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); ++ if (IS_ERR(pcdev->alloc_ctx)) { ++ err = PTR_ERR(pcdev->alloc_ctx); ++ goto eallocctx; ++ } + err = soc_camera_host_register(&pcdev->soc_host); + if (err) + goto exit_free_emma; +@@ -1643,26 +1768,24 @@ static int __devinit mx2_camera_probe(st + return 0; + + exit_free_emma: +- if (mx27_camera_emma(pcdev)) { ++ vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); ++eallocctx: ++ if (cpu_is_mx27()) { + free_irq(pcdev->irq_emma, pcdev); + clk_disable(pcdev->clk_emma); + clk_put(pcdev->clk_emma); + iounmap(pcdev->base_emma); +- release_mem_region(res_emma->start, resource_size(res_emma)); ++ release_mem_region(pcdev->res_emma->start, resource_size(pcdev->res_emma)); + } + exit_free_irq: +- free_irq(pcdev->irq_csi, pcdev); ++ if (cpu_is_mx25()) ++ free_irq(pcdev->irq_csi, pcdev); + exit_iounmap: + iounmap(base_csi); + exit_release: + release_mem_region(res_csi->start, resource_size(res_csi)); + exit_dma_free: +-#ifdef CONFIG_MACH_MX27 +- if (cpu_is_mx27()) +- imx_dma_free(pcdev->dma); +-exit_clk_put: + clk_put(pcdev->clk_csi); +-#endif /* CONFIG_MACH_MX27 */ + exit_kfree: + kfree(pcdev); + exit: +@@ -1677,19 +1800,18 @@ static int __devexit mx2_camera_remove(s + struct resource *res; + + clk_put(pcdev->clk_csi); +-#ifdef CONFIG_MACH_MX27 ++ if (cpu_is_mx25()) ++ free_irq(pcdev->irq_csi, pcdev); + if (cpu_is_mx27()) +- imx_dma_free(pcdev->dma); +-#endif /* CONFIG_MACH_MX27 */ +- free_irq(pcdev->irq_csi, pcdev); +- if (mx27_camera_emma(pcdev)) + free_irq(pcdev->irq_emma, pcdev); + + soc_camera_host_unregister(&pcdev->soc_host); + ++ vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); ++ + iounmap(pcdev->base_csi); + +- if (mx27_camera_emma(pcdev)) { ++ if (cpu_is_mx27()) { + clk_disable(pcdev->clk_emma); + clk_put(pcdev->clk_emma); + iounmap(pcdev->base_emma); +Index: linux-3.3.x86_64/drivers/media/rc/rc-core-priv.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/rc/rc-core-priv.h ++++ linux-3.3.x86_64/drivers/media/rc/rc-core-priv.h +@@ -35,7 +35,7 @@ struct ir_raw_event_ctrl { + struct list_head list; /* to keep track of raw clients */ + struct task_struct *thread; + spinlock_t lock; +- struct kfifo kfifo; /* fifo for the pulse/space durations */ ++ struct kfifo_rec_ptr_1 kfifo; /* fifo for the pulse/space durations */ + ktime_t last_event; /* when last event occurred */ + enum raw_event_type last_type; /* last event type */ + struct rc_dev *dev; /* pointer to the parent rc_dev */ +Index: linux-3.3.x86_64/drivers/media/video/s2255drv.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/s2255drv.c ++++ linux-3.3.x86_64/drivers/media/video/s2255drv.c +@@ -134,7 +134,7 @@ + + /* usb config commands */ + #define IN_DATA_TOKEN cpu_to_le32(0x2255c0de) +-#define CMD_2255 cpu_to_le32(0xc2255000) ++#define CMD_2255 0xc2255000 + #define CMD_SET_MODE cpu_to_le32((CMD_2255 | 0x10)) + #define CMD_START cpu_to_le32((CMD_2255 | 0x20)) + #define CMD_STOP cpu_to_le32((CMD_2255 | 0x30)) +@@ -852,15 +852,13 @@ static int vidioc_querycap(struct file * + static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) + { +- int index = 0; +- if (f) +- index = f->index; ++ int index = f->index; + + if (index >= ARRAY_SIZE(formats)) + return -EINVAL; +- if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) || +- (formats[index].fourcc == V4L2_PIX_FMT_MJPEG))) +- return -EINVAL; ++ if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) || ++ (formats[index].fourcc == V4L2_PIX_FMT_MJPEG))) ++ return -EINVAL; + dprintk(4, "name %s\n", formats[index].name); + strlcpy(f->description, formats[index].name, sizeof(f->description)); + f->pixelformat = formats[index].fourcc; +@@ -2027,7 +2025,7 @@ static int save_frame(struct s2255_dev * + pdata[1]); + offset = jj + PREFIX_SIZE; + bframe = 1; +- cc = pdword[1]; ++ cc = le32_to_cpu(pdword[1]); + if (cc >= MAX_CHANNELS) { + printk(KERN_ERR + "bad channel\n"); +@@ -2036,22 +2034,22 @@ static int save_frame(struct s2255_dev * + /* reverse it */ + dev->cc = G_chnmap[cc]; + channel = &dev->channel[dev->cc]; +- payload = pdword[3]; ++ payload = le32_to_cpu(pdword[3]); + if (payload > channel->req_image_size) { + channel->bad_payload++; + /* discard the bad frame */ + return -EINVAL; + } + channel->pkt_size = payload; +- channel->jpg_size = pdword[4]; ++ channel->jpg_size = le32_to_cpu(pdword[4]); + break; + case S2255_MARKER_RESPONSE: + + pdata += DEF_USB_BLOCK; + jj += DEF_USB_BLOCK; +- if (pdword[1] >= MAX_CHANNELS) ++ if (le32_to_cpu(pdword[1]) >= MAX_CHANNELS) + break; +- cc = G_chnmap[pdword[1]]; ++ cc = G_chnmap[le32_to_cpu(pdword[1])]; + if (cc >= MAX_CHANNELS) + break; + channel = &dev->channel[cc]; +@@ -2074,11 +2072,11 @@ static int save_frame(struct s2255_dev * + wake_up(&dev->fw_data->wait_fw); + break; + case S2255_RESPONSE_STATUS: +- channel->vidstatus = pdword[3]; ++ channel->vidstatus = le32_to_cpu(pdword[3]); + channel->vidstatus_ready = 1; + wake_up(&channel->wait_vidstatus); + dprintk(5, "got vidstatus %x chan %d\n", +- pdword[3], cc); ++ le32_to_cpu(pdword[3]), cc); + break; + default: + printk(KERN_INFO "s2255 unknown resp\n"); +@@ -2605,10 +2603,11 @@ static int s2255_probe(struct usb_interf + __le32 *pRel; + pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4]; + printk(KERN_INFO "s2255 dsp fw version %x\n", *pRel); +- dev->dsp_fw_ver = *pRel; +- if (*pRel < S2255_CUR_DSP_FWVER) ++ dev->dsp_fw_ver = le32_to_cpu(*pRel); ++ if (dev->dsp_fw_ver < S2255_CUR_DSP_FWVER) + printk(KERN_INFO "s2255: f2255usb.bin out of date.\n"); +- if (dev->pid == 0x2257 && *pRel < S2255_MIN_DSP_COLORFILTER) ++ if (dev->pid == 0x2257 && ++ dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) + printk(KERN_WARNING "s2255: 2257 requires firmware %d" + " or above.\n", S2255_MIN_DSP_COLORFILTER); + } +Index: linux-3.3.x86_64/drivers/media/common/tuners/Makefile +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/common/tuners/Makefile ++++ linux-3.3.x86_64/drivers/media/common/tuners/Makefile +@@ -28,6 +28,8 @@ obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc + obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o + obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o + obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o ++obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o ++obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o + +-ccflags-y += -Idrivers/media/dvb/dvb-core +-ccflags-y += -Idrivers/media/dvb/frontends ++ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core ++ccflags-y += -I$(srctree)/drivers/media/dvb/frontends +Index: linux-3.3.x86_64/drivers/media/video/saa7134/Makefile +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/saa7134/Makefile ++++ linux-3.3.x86_64/drivers/media/video/saa7134/Makefile +@@ -10,7 +10,7 @@ obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7 + + obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o + +-ccflags-y += -Idrivers/media/video +-ccflags-y += -Idrivers/media/common/tuners +-ccflags-y += -Idrivers/media/dvb/dvb-core +-ccflags-y += -Idrivers/media/dvb/frontends ++ccflags-y += -I$(srctree)/drivers/media/video ++ccflags-y += -I$(srctree)/drivers/media/common/tuners ++ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core ++ccflags-y += -I$(srctree)/drivers/media/dvb/frontends +Index: linux-3.3.x86_64/drivers/media/video/saa7164/Makefile +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/saa7164/Makefile ++++ linux-3.3.x86_64/drivers/media/video/saa7164/Makefile +@@ -4,9 +4,9 @@ saa7164-objs := saa7164-cards.o saa7164- + + obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o + +-ccflags-y += -Idrivers/media/video +-ccflags-y += -Idrivers/media/common/tuners +-ccflags-y += -Idrivers/media/dvb/dvb-core +-ccflags-y += -Idrivers/media/dvb/frontends ++ccflags-y += -I$(srctree)/drivers/media/video ++ccflags-y += -I$(srctree)/drivers/media/common/tuners ++ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core ++ccflags-y += -I$(srctree)/drivers/media/dvb/frontends + + ccflags-y += $(extra-cflags-y) $(extra-cflags-m) +Index: linux-3.3.x86_64/drivers/media/video/ivtv/Makefile +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ivtv/Makefile ++++ linux-3.3.x86_64/drivers/media/video/ivtv/Makefile +@@ -7,8 +7,8 @@ ivtv-objs := ivtv-routing.o ivtv-cards.o + obj-$(CONFIG_VIDEO_IVTV) += ivtv.o + obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o + +-ccflags-y += -Idrivers/media/video +-ccflags-y += -Idrivers/media/common/tuners +-ccflags-y += -Idrivers/media/dvb/dvb-core +-ccflags-y += -Idrivers/media/dvb/frontends ++ccflags-y += -I$(srctree)/drivers/media/video ++ccflags-y += -I$(srctree)/drivers/media/common/tuners ++ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core ++ccflags-y += -I$(srctree)/drivers/media/dvb/frontends + +Index: linux-3.3.x86_64/drivers/media/video/gspca/gl860/Makefile +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/gspca/gl860/Makefile ++++ linux-3.3.x86_64/drivers/media/video/gspca/gl860/Makefile +@@ -6,5 +6,5 @@ gspca_gl860-objs := gl860.o \ + gl860-ov9655.o \ + gl860-mi2020.o + +-ccflags-y += -Idrivers/media/video/gspca ++ccflags-y += -I$(srctree)/drivers/media/video/gspca + +Index: linux-3.3.x86_64/drivers/media/video/gspca/m5602/Makefile +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/gspca/m5602/Makefile ++++ linux-3.3.x86_64/drivers/media/video/gspca/m5602/Makefile +@@ -8,4 +8,4 @@ gspca_m5602-objs := m5602_core.o \ + m5602_s5k83a.o \ + m5602_s5k4aa.o + +-ccflags-y += -Idrivers/media/video/gspca ++ccflags-y += -I$(srctree)/drivers/media/video/gspca +Index: linux-3.3.x86_64/drivers/media/video/gspca/stv06xx/Makefile +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/gspca/stv06xx/Makefile ++++ linux-3.3.x86_64/drivers/media/video/gspca/stv06xx/Makefile +@@ -6,5 +6,5 @@ gspca_stv06xx-objs := stv06xx.o \ + stv06xx_pb0100.o \ + stv06xx_st6422.o + +-ccflags-y += -Idrivers/media/video/gspca ++ccflags-y += -I$(srctree)/drivers/media/video/gspca + +Index: linux-3.3.x86_64/Documentation/dvb/cards.txt +=================================================================== +--- linux-3.3.x86_64.orig/Documentation/dvb/cards.txt ++++ linux-3.3.x86_64/Documentation/dvb/cards.txt +@@ -119,4 +119,5 @@ o Cards based on the Phillips saa7134 PC + - Compro Videomate DVB-T300 + - Compro Videomate DVB-T200 + - AVerMedia AVerTVHD MCE A180 ++ - KWorld PC150-U ATSC Hybrid + +Index: linux-3.3.x86_64/drivers/media/rc/keymaps/rc-kworld-pc150u.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/rc/keymaps/rc-kworld-pc150u.c +@@ -0,0 +1,102 @@ ++/* kworld-pc150u.c - Keytable for kworld_pc150u Remote Controller ++ * ++ * keymap imported from ir-keymaps.c ++ * ++ * Copyright (c) 2010 by Kyle Strickland ++ * (based on kworld-plus-tv-analog.c by ++ * Mauro Carvalho Chehab ) ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++#include ++ ++/* Kworld PC150-U ++ Kyle Strickland ++ */ ++ ++static struct rc_map_table kworld_pc150u[] = { ++ { 0x0c, KEY_MEDIA }, /* Kworld key */ ++ { 0x16, KEY_EJECTCLOSECD }, /* -> ) */ ++ { 0x1d, KEY_POWER2 }, ++ ++ { 0x00, KEY_1 }, ++ { 0x01, KEY_2 }, ++ { 0x02, KEY_3 }, ++ { 0x03, KEY_4 }, ++ { 0x04, KEY_5 }, ++ { 0x05, KEY_6 }, ++ { 0x06, KEY_7 }, ++ { 0x07, KEY_8 }, ++ { 0x08, KEY_9 }, ++ { 0x0a, KEY_0 }, ++ ++ { 0x09, KEY_AGAIN }, ++ { 0x14, KEY_MUTE }, ++ ++ { 0x1e, KEY_LAST }, ++ { 0x17, KEY_ZOOM }, ++ { 0x1f, KEY_HOMEPAGE }, ++ { 0x0e, KEY_ESC }, ++ ++ { 0x20, KEY_UP }, ++ { 0x21, KEY_DOWN }, ++ { 0x42, KEY_LEFT }, ++ { 0x43, KEY_RIGHT }, ++ { 0x0b, KEY_ENTER }, ++ ++ { 0x10, KEY_CHANNELUP }, ++ { 0x11, KEY_CHANNELDOWN }, ++ ++ { 0x13, KEY_VOLUMEUP }, ++ { 0x12, KEY_VOLUMEDOWN }, ++ ++ { 0x19, KEY_TIME}, /* Timeshift */ ++ { 0x1a, KEY_STOP}, ++ { 0x1b, KEY_RECORD}, ++ { 0x4b, KEY_EMAIL}, ++ ++ { 0x40, KEY_REWIND}, ++ { 0x44, KEY_PLAYPAUSE}, ++ { 0x41, KEY_FORWARD}, ++ { 0x22, KEY_TEXT}, ++ ++ { 0x15, KEY_AUDIO}, /* ((*)) */ ++ { 0x0f, KEY_MODE}, /* display ratio */ ++ { 0x1c, KEY_SYSRQ}, /* snapshot */ ++ { 0x4a, KEY_SLEEP}, /* sleep timer */ ++ ++ { 0x48, KEY_SOUND}, /* switch theater mode */ ++ { 0x49, KEY_BLUE}, /* A */ ++ { 0x18, KEY_RED}, /* B */ ++ { 0x23, KEY_GREEN}, /* C */ ++}; ++ ++static struct rc_map_list kworld_pc150u_map = { ++ .map = { ++ .scan = kworld_pc150u, ++ .size = ARRAY_SIZE(kworld_pc150u), ++ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ ++ .name = RC_MAP_KWORLD_PC150U, ++ } ++}; ++ ++static int __init init_rc_map_kworld_pc150u(void) ++{ ++ return rc_map_register(&kworld_pc150u_map); ++} ++ ++static void __exit exit_rc_map_kworld_pc150u(void) ++{ ++ rc_map_unregister(&kworld_pc150u_map); ++} ++ ++module_init(init_rc_map_kworld_pc150u) ++module_exit(exit_rc_map_kworld_pc150u) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Kyle Strickland "); +Index: linux-3.3.x86_64/drivers/media/video/saa7134/saa7134-cards.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/saa7134/saa7134-cards.c ++++ linux-3.3.x86_64/drivers/media/video/saa7134/saa7134-cards.c +@@ -33,6 +33,7 @@ + #include "tea5767.h" + #include "tda18271.h" + #include "xc5000.h" ++#include "s5h1411.h" + + /* commly used strings */ + static char name_mute[] = "mute"; +@@ -5712,6 +5713,36 @@ struct saa7134_board saa7134_boards[] = + .amux = LINE1, + } }, + }, ++ [SAA7134_BOARD_KWORLD_PC150U] = { ++ .name = "Kworld PC150-U", ++ .audio_clock = 0x00187de7, ++ .tuner_type = TUNER_PHILIPS_TDA8290, ++ .radio_type = UNSET, ++ .tuner_addr = ADDR_UNSET, ++ .radio_addr = ADDR_UNSET, ++ .mpeg = SAA7134_MPEG_DVB, ++ .gpiomask = 1 << 21, ++ .ts_type = SAA7134_MPEG_TS_PARALLEL, ++ .inputs = { { ++ .name = name_tv, ++ .vmux = 1, ++ .amux = TV, ++ .tv = 1, ++ }, { ++ .name = name_comp, ++ .vmux = 3, ++ .amux = LINE1, ++ }, { ++ .name = name_svideo, ++ .vmux = 8, ++ .amux = LINE2, ++ } }, ++ .radio = { ++ .name = name_radio, ++ .amux = TV, ++ .gpio = 0x0000000, ++ }, ++ }, + + }; + +@@ -6306,6 +6337,12 @@ struct pci_device_id saa7134_pci_tbl[] = + .driver_data = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */ + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, ++ .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */ ++ .subvendor = 0x17de, ++ .subdevice = 0xa134, ++ .driver_data = SAA7134_BOARD_KWORLD_PC150U, ++ }, { ++ .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x1461, + .subdevice = 0x7360, +@@ -7134,6 +7171,23 @@ static inline int saa7134_kworld_sbtvd_t + return 0; + } + ++static int saa7134_kworld_pc150u_toggle_agc(struct saa7134_dev *dev, ++ enum tda18271_mode mode) ++{ ++ switch (mode) { ++ case TDA18271_ANALOG: ++ saa7134_set_gpio(dev, 18, 0); ++ break; ++ case TDA18271_DIGITAL: ++ saa7134_set_gpio(dev, 18, 1); ++ msleep(30); ++ break; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ + static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev, + int command, int arg) + { +@@ -7150,6 +7204,9 @@ static int saa7134_tda8290_18271_callbac + case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: + ret = saa7134_kworld_sbtvd_toggle_agc(dev, arg); + break; ++ case SAA7134_BOARD_KWORLD_PC150U: ++ ret = saa7134_kworld_pc150u_toggle_agc(dev, arg); ++ break; + default: + break; + } +@@ -7171,6 +7228,7 @@ static int saa7134_tda8290_callback(stru + case SAA7134_BOARD_HAUPPAUGE_HVR1120: + case SAA7134_BOARD_AVERMEDIA_M733A: + case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: ++ case SAA7134_BOARD_KWORLD_PC150U: + case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2: + /* tda8290 + tda18271 */ + ret = saa7134_tda8290_18271_callback(dev, command, arg); +@@ -7452,6 +7510,7 @@ int saa7134_board_init1(struct saa7134_d + case SAA7134_BOARD_BEHOLD_X7: + case SAA7134_BOARD_BEHOLD_H7: + case SAA7134_BOARD_BEHOLD_A7: ++ case SAA7134_BOARD_KWORLD_PC150U: + dev->has_remote = SAA7134_REMOTE_I2C; + break; + case SAA7134_BOARD_AVERMEDIA_A169_B: +Index: linux-3.3.x86_64/drivers/media/video/saa7134/saa7134-dvb.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/saa7134/saa7134-dvb.c ++++ linux-3.3.x86_64/drivers/media/video/saa7134/saa7134-dvb.c +@@ -61,6 +61,7 @@ + #include "zl10036.h" + #include "zl10039.h" + #include "mt312.h" ++#include "s5h1411.h" + + MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); + MODULE_LICENSE("GPL"); +@@ -1158,6 +1159,33 @@ static struct tda18271_config prohdtv_pr + .output_opt = TDA18271_OUTPUT_LT_OFF, + }; + ++static struct tda18271_std_map kworld_tda18271_std_map = { ++ .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 3, ++ .if_lvl = 6, .rfagc_top = 0x37 }, ++ .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0, ++ .if_lvl = 6, .rfagc_top = 0x37 }, ++}; ++ ++static struct tda18271_config kworld_pc150u_tda18271_config = { ++ .std_map = &kworld_tda18271_std_map, ++ .gate = TDA18271_GATE_ANALOG, ++ .output_opt = TDA18271_OUTPUT_LT_OFF, ++ .config = 3, /* Use tuner callback for AGC */ ++ .rf_cal_on_startup = 1 ++}; ++ ++static struct s5h1411_config kworld_s5h1411_config = { ++ .output_mode = S5H1411_PARALLEL_OUTPUT, ++ .gpio = S5H1411_GPIO_OFF, ++ .qam_if = S5H1411_IF_4000, ++ .vsb_if = S5H1411_IF_3250, ++ .inversion = S5H1411_INVERSION_ON, ++ .status_mode = S5H1411_DEMODLOCKING, ++ .mpeg_timing = ++ S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, ++}; ++ ++ + /* ================================================================== + * Core code + */ +@@ -1438,6 +1466,22 @@ static int dvb_init(struct saa7134_dev * + &dev->i2c_adap, 0x61, + TUNER_PHILIPS_TUV1236D); + break; ++ case SAA7134_BOARD_KWORLD_PC150U: ++ saa7134_set_gpio(dev, 18, 1); /* Switch to digital mode */ ++ saa7134_tuner_callback(dev, 0, ++ TDA18271_CALLBACK_CMD_AGC_ENABLE, 1); ++ fe0->dvb.frontend = dvb_attach(s5h1411_attach, ++ &kworld_s5h1411_config, ++ &dev->i2c_adap); ++ if (fe0->dvb.frontend != NULL) { ++ dvb_attach(tda829x_attach, fe0->dvb.frontend, ++ &dev->i2c_adap, 0x4b, ++ &tda829x_no_probe); ++ dvb_attach(tda18271_attach, fe0->dvb.frontend, ++ 0x60, &dev->i2c_adap, ++ &kworld_pc150u_tda18271_config); ++ } ++ break; + case SAA7134_BOARD_FLYDVBS_LR300: + fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, + &dev->i2c_adap); +Index: linux-3.3.x86_64/drivers/media/video/saa7134/saa7134-i2c.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/saa7134/saa7134-i2c.c ++++ linux-3.3.x86_64/drivers/media/video/saa7134/saa7134-i2c.c +@@ -254,7 +254,9 @@ static int saa7134_i2c_xfer(struct i2c_a + addr = msgs[i].addr << 1; + if (msgs[i].flags & I2C_M_RD) + addr |= 1; +- if (i > 0 && msgs[i].flags & I2C_M_RD && msgs[i].addr != 0x40) { ++ if (i > 0 && msgs[i].flags & ++ I2C_M_RD && msgs[i].addr != 0x40 && ++ msgs[i].addr != 0x19) { + /* workaround for a saa7134 i2c bug + * needed to talk to the mt352 demux + * thanks to pinnacle for the hint */ +@@ -279,6 +281,16 @@ static int saa7134_i2c_xfer(struct i2c_a + d1printk("%02x", rc); + msgs[i].buf[byte] = rc; + } ++ /* discard mysterious extra byte when reading ++ from Samsung S5H1411. i2c bus gets error ++ if we do not. */ ++ if (0x19 == msgs[i].addr) { ++ d1printk(" ?"); ++ rc = i2c_recv_byte(dev); ++ if (rc < 0) ++ goto err; ++ d1printk("%02x", rc); ++ } + } else { + /* write bytes */ + d2printk("write bytes\n"); +Index: linux-3.3.x86_64/drivers/media/video/saa7134/saa7134-input.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/saa7134/saa7134-input.c ++++ linux-3.3.x86_64/drivers/media/video/saa7134/saa7134-input.c +@@ -210,6 +210,54 @@ static int get_key_msi_tvanywhere_plus(s + return 1; + } + ++/* copied and modified from get_key_msi_tvanywhere_plus() */ ++static int get_key_kworld_pc150u(struct IR_i2c *ir, u32 *ir_key, ++ u32 *ir_raw) ++{ ++ unsigned char b; ++ unsigned int gpio; ++ ++ /* is needed to access GPIO. Used by the saa_readl macro. */ ++ struct saa7134_dev *dev = ir->c->adapter->algo_data; ++ if (dev == NULL) { ++ i2cdprintk("get_key_kworld_pc150u: " ++ "ir->c->adapter->algo_data is NULL!\n"); ++ return -EIO; ++ } ++ ++ /* rising SAA7134_GPIO_GPRESCAN reads the status */ ++ ++ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); ++ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); ++ ++ gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); ++ ++ /* GPIO&0x100 is pulsed low when a button is pressed. Don't do ++ I2C receive if gpio&0x100 is not low. */ ++ ++ if (gpio & 0x100) ++ return 0; /* No button press */ ++ ++ /* GPIO says there is a button press. Get it. */ ++ ++ if (1 != i2c_master_recv(ir->c, &b, 1)) { ++ i2cdprintk("read error\n"); ++ return -EIO; ++ } ++ ++ /* No button press */ ++ ++ if (b == 0xff) ++ return 0; ++ ++ /* Button pressed */ ++ ++ dprintk("get_key_kworld_pc150u: Key = 0x%02X\n", b); ++ *ir_key = b; ++ *ir_raw = b; ++ return 1; ++} ++ + static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) + { + unsigned char b; +@@ -894,6 +942,21 @@ void saa7134_probe_i2c_ir(struct saa7134 + info.addr = 0x30; + /* MSI TV@nywhere Plus controller doesn't seem to + respond to probes unless we read something from ++ an existing device. Weird... ++ REVISIT: might no longer be needed */ ++ rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1); ++ dprintk("probe 0x%02x @ %s: %s\n", ++ msg_msi.addr, dev->i2c_adap.name, ++ (1 == rc) ? "yes" : "no"); ++ break; ++ case SAA7134_BOARD_KWORLD_PC150U: ++ /* copied and modified from MSI TV@nywhere Plus */ ++ dev->init_data.name = "Kworld PC150-U"; ++ dev->init_data.get_key = get_key_kworld_pc150u; ++ dev->init_data.ir_codes = RC_MAP_KWORLD_PC150U; ++ info.addr = 0x30; ++ /* MSI TV@nywhere Plus controller doesn't seem to ++ respond to probes unless we read something from + an existing device. Weird... + REVISIT: might no longer be needed */ + rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1); +Index: linux-3.3.x86_64/drivers/media/video/saa7134/saa7134.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/saa7134/saa7134.h ++++ linux-3.3.x86_64/drivers/media/video/saa7134/saa7134.h +@@ -126,8 +126,8 @@ struct saa7134_card_ir { + unsigned users; + + u32 polling; +- u32 last_gpio; +- u32 mask_keycode, mask_keydown, mask_keyup; ++ u32 last_gpio; ++ u32 mask_keycode, mask_keydown, mask_keyup; + + bool running; + bool active; +@@ -331,6 +331,7 @@ struct saa7134_card_ir { + #define SAA7134_BOARD_BEHOLD_501 186 + #define SAA7134_BOARD_BEHOLD_503FM 187 + #define SAA7134_BOARD_SENSORAY811_911 188 ++#define SAA7134_BOARD_KWORLD_PC150U 189 + + #define SAA7134_MAXBOARDS 32 + #define SAA7134_INPUT_MAX 8 +Index: linux-3.3.x86_64/drivers/media/video/cx18/cx18-driver.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/cx18/cx18-driver.c ++++ linux-3.3.x86_64/drivers/media/video/cx18/cx18-driver.c +@@ -38,7 +38,7 @@ + #include "cx18-ioctl.h" + #include "cx18-controls.h" + #include "tuner-xc2028.h" +- ++#include + #include + + /* If you have already X v4l cards, then set this to X. This way +@@ -75,7 +75,7 @@ static int radio[CX18_MAX_CARDS] = { -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; + static unsigned cardtype_c = 1; + static unsigned tuner_c = 1; +-static bool radio_c = 1; ++static unsigned radio_c = 1; + static char pal[] = "--"; + static char secam[] = "--"; + static char ntsc[] = "-"; +@@ -110,7 +110,7 @@ static int retry_mmio = 1; + int cx18_debug; + + module_param_array(tuner, int, &tuner_c, 0644); +-module_param_array(radio, bool, &radio_c, 0644); ++module_param_array(radio, int, &radio_c, 0644); + module_param_array(cardtype, int, &cardtype_c, 0644); + module_param_string(pal, pal, sizeof(pal), 0644); + module_param_string(secam, secam, sizeof(secam), 0644); +@@ -812,7 +812,7 @@ static int cx18_setup_pci(struct cx18 *c + CX18_ERR("Can't enable device %d!\n", cx->instance); + return -EIO; + } +- if (pci_set_dma_mask(pci_dev, 0xffffffff)) { ++ if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32))) { + CX18_ERR("No suitable DMA available, card %d\n", cx->instance); + return -EIO; + } +Index: linux-3.3.x86_64/drivers/media/rc/Kconfig +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/rc/Kconfig ++++ linux-3.3.x86_64/drivers/media/rc/Kconfig +@@ -266,4 +266,13 @@ config RC_LOOPBACK + To compile this driver as a module, choose M here: the module will + be called rc_loopback. + ++config IR_GPIO_CIR ++ tristate "GPIO IR remote control" ++ depends on RC_CORE ++ ---help--- ++ Say Y if you want to use GPIO based IR Receiver. ++ ++ To compile this driver as a module, choose M here: the module will ++ be called gpio-ir-recv. ++ + endif #RC_CORE +Index: linux-3.3.x86_64/drivers/media/rc/Makefile +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/rc/Makefile ++++ linux-3.3.x86_64/drivers/media/rc/Makefile +@@ -26,3 +26,4 @@ obj-$(CONFIG_IR_REDRAT3) += redrat3.o + obj-$(CONFIG_IR_STREAMZAP) += streamzap.o + obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o + obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o ++obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o +Index: linux-3.3.x86_64/drivers/media/rc/gpio-ir-recv.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/rc/gpio-ir-recv.c +@@ -0,0 +1,205 @@ ++/* Copyright (c) 2012, Code Aurora Forum. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define GPIO_IR_DRIVER_NAME "gpio-rc-recv" ++#define GPIO_IR_DEVICE_NAME "gpio_ir_recv" ++ ++struct gpio_rc_dev { ++ struct rc_dev *rcdev; ++ int gpio_nr; ++ bool active_low; ++}; ++ ++static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id) ++{ ++ struct gpio_rc_dev *gpio_dev = dev_id; ++ int gval; ++ int rc = 0; ++ enum raw_event_type type = IR_SPACE; ++ ++ gval = gpio_get_value_cansleep(gpio_dev->gpio_nr); ++ ++ if (gval < 0) ++ goto err_get_value; ++ ++ if (gpio_dev->active_low) ++ gval = !gval; ++ ++ if (gval == 1) ++ type = IR_PULSE; ++ ++ rc = ir_raw_event_store_edge(gpio_dev->rcdev, type); ++ if (rc < 0) ++ goto err_get_value; ++ ++ ir_raw_event_handle(gpio_dev->rcdev); ++ ++err_get_value: ++ return IRQ_HANDLED; ++} ++ ++static int __devinit gpio_ir_recv_probe(struct platform_device *pdev) ++{ ++ struct gpio_rc_dev *gpio_dev; ++ struct rc_dev *rcdev; ++ const struct gpio_ir_recv_platform_data *pdata = ++ pdev->dev.platform_data; ++ int rc; ++ ++ if (!pdata) ++ return -EINVAL; ++ ++ if (pdata->gpio_nr < 0) ++ return -EINVAL; ++ ++ gpio_dev = kzalloc(sizeof(struct gpio_rc_dev), GFP_KERNEL); ++ if (!gpio_dev) ++ return -ENOMEM; ++ ++ rcdev = rc_allocate_device(); ++ if (!rcdev) { ++ rc = -ENOMEM; ++ goto err_allocate_device; ++ } ++ ++ rcdev->driver_type = RC_DRIVER_IR_RAW; ++ rcdev->allowed_protos = RC_TYPE_ALL; ++ rcdev->input_name = GPIO_IR_DEVICE_NAME; ++ rcdev->input_id.bustype = BUS_HOST; ++ rcdev->driver_name = GPIO_IR_DRIVER_NAME; ++ rcdev->map_name = RC_MAP_EMPTY; ++ ++ gpio_dev->rcdev = rcdev; ++ gpio_dev->gpio_nr = pdata->gpio_nr; ++ gpio_dev->active_low = pdata->active_low; ++ ++ rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv"); ++ if (rc < 0) ++ goto err_gpio_request; ++ rc = gpio_direction_input(pdata->gpio_nr); ++ if (rc < 0) ++ goto err_gpio_direction_input; ++ ++ rc = rc_register_device(rcdev); ++ if (rc < 0) { ++ dev_err(&pdev->dev, "failed to register rc device\n"); ++ goto err_register_rc_device; ++ } ++ ++ platform_set_drvdata(pdev, gpio_dev); ++ ++ rc = request_any_context_irq(gpio_to_irq(pdata->gpio_nr), ++ gpio_ir_recv_irq, ++ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, ++ "gpio-ir-recv-irq", gpio_dev); ++ if (rc < 0) ++ goto err_request_irq; ++ ++ return 0; ++ ++err_request_irq: ++ platform_set_drvdata(pdev, NULL); ++ rc_unregister_device(rcdev); ++err_register_rc_device: ++err_gpio_direction_input: ++ gpio_free(pdata->gpio_nr); ++err_gpio_request: ++ rc_free_device(rcdev); ++ rcdev = NULL; ++err_allocate_device: ++ kfree(gpio_dev); ++ return rc; ++} ++ ++static int __devexit gpio_ir_recv_remove(struct platform_device *pdev) ++{ ++ struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); ++ ++ free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev); ++ platform_set_drvdata(pdev, NULL); ++ rc_unregister_device(gpio_dev->rcdev); ++ gpio_free(gpio_dev->gpio_nr); ++ rc_free_device(gpio_dev->rcdev); ++ kfree(gpio_dev); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int gpio_ir_recv_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); ++ ++ if (device_may_wakeup(dev)) ++ enable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr)); ++ else ++ disable_irq(gpio_to_irq(gpio_dev->gpio_nr)); ++ ++ return 0; ++} ++ ++static int gpio_ir_recv_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); ++ ++ if (device_may_wakeup(dev)) ++ disable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr)); ++ else ++ enable_irq(gpio_to_irq(gpio_dev->gpio_nr)); ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops gpio_ir_recv_pm_ops = { ++ .suspend = gpio_ir_recv_suspend, ++ .resume = gpio_ir_recv_resume, ++}; ++#endif ++ ++static struct platform_driver gpio_ir_recv_driver = { ++ .probe = gpio_ir_recv_probe, ++ .remove = __devexit_p(gpio_ir_recv_remove), ++ .driver = { ++ .name = GPIO_IR_DRIVER_NAME, ++ .owner = THIS_MODULE, ++#ifdef CONFIG_PM ++ .pm = &gpio_ir_recv_pm_ops, ++#endif ++ }, ++}; ++ ++static int __init gpio_ir_recv_init(void) ++{ ++ return platform_driver_register(&gpio_ir_recv_driver); ++} ++module_init(gpio_ir_recv_init); ++ ++static void __exit gpio_ir_recv_exit(void) ++{ ++ platform_driver_unregister(&gpio_ir_recv_driver); ++} ++module_exit(gpio_ir_recv_exit); ++ ++MODULE_DESCRIPTION("GPIO IR Receiver driver"); ++MODULE_LICENSE("GPL v2"); +Index: linux-3.3.x86_64/include/media/gpio-ir-recv.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/include/media/gpio-ir-recv.h +@@ -0,0 +1,22 @@ ++/* Copyright (c) 2012, Code Aurora Forum. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#ifndef __GPIO_IR_RECV_H__ ++#define __GPIO_IR_RECV_H__ ++ ++struct gpio_ir_recv_platform_data { ++ int gpio_nr; ++ bool active_low; ++}; ++ ++#endif /* __GPIO_IR_RECV_H__ */ ++ +Index: linux-3.3.x86_64/drivers/media/rc/ir-sony-decoder.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/rc/ir-sony-decoder.c ++++ linux-3.3.x86_64/drivers/media/rc/ir-sony-decoder.c +@@ -130,7 +130,7 @@ static int ir_sony_decode(struct rc_dev + case 15: + device = bitrev8((data->bits >> 0) & 0xFF); + subdevice = 0; +- function = bitrev8((data->bits >> 7) & 0xFD); ++ function = bitrev8((data->bits >> 7) & 0xFE); + break; + case 20: + device = bitrev8((data->bits >> 5) & 0xF8); +Index: linux-3.3.x86_64/drivers/media/video/cx25821/cx25821-core.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/cx25821/cx25821-core.c ++++ linux-3.3.x86_64/drivers/media/video/cx25821/cx25821-core.c +@@ -1474,8 +1474,13 @@ static DEFINE_PCI_DEVICE_TABLE(cx25821_p + .device = 0x8210, + .subvendor = 0x14f1, + .subdevice = 0x0920, +- }, +- { ++ }, { ++ /* CX25821 No Brand */ ++ .vendor = 0x14f1, ++ .device = 0x8210, ++ .subvendor = 0x0000, ++ .subdevice = 0x0000, ++ }, { + /* --- end of list --- */ + } + }; +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/dib0090.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/dib0090.c ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/dib0090.c +@@ -519,7 +519,7 @@ static int dib0090_fw_identify(struct dv + return 0; + + identification_error: +- return -EIO;; ++ return -EIO; + } + + static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg) +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/stb0899_drv.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/stb0899_drv.c ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/stb0899_drv.c +@@ -67,7 +67,7 @@ static const struct stb0899_tab stb0899_ + * Crude linear extrapolation below -84.8dBm and above -8.0dBm. + */ + static const struct stb0899_tab stb0899_dvbsrf_tab[] = { +- { -950, -128 }, ++ { -750, -128 }, + { -748, -94 }, + { -745, -92 }, + { -735, -90 }, +@@ -131,7 +131,7 @@ static const struct stb0899_tab stb0899_ + { -730, 13645 }, + { -750, 13909 }, + { -766, 14153 }, +- { -999, 16383 } ++ { -950, 16383 } + }; + + /* DVB-S2 Es/N0 quant in dB/100 vs read value * 100*/ +@@ -964,6 +964,7 @@ static int stb0899_read_signal_strength( + + int val; + u32 reg; ++ *strength = 0; + switch (state->delsys) { + case SYS_DVBS: + case SYS_DSS: +@@ -983,11 +984,11 @@ static int stb0899_read_signal_strength( + break; + case SYS_DVBS2: + if (internal->lock) { +- reg = STB0899_READ_S2REG(STB0899_DEMOD, IF_AGC_GAIN); ++ reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_GAIN); + val = STB0899_GETFIELD(IF_AGC_GAIN, reg); + + *strength = stb0899_table_lookup(stb0899_dvbs2rf_tab, ARRAY_SIZE(stb0899_dvbs2rf_tab) - 1, val); +- *strength += 750; ++ *strength += 950; + dprintk(state->verbose, FE_DEBUG, 1, "IF_AGC_GAIN = 0x%04x, C = %d * 0.1 dBm", + val & 0x3fff, *strength); + } +@@ -1009,6 +1010,7 @@ static int stb0899_read_snr(struct dvb_f + u8 buf[2]; + u32 reg; + ++ *snr = 0; + reg = stb0899_read_reg(state, STB0899_VSTATUS); + switch (state->delsys) { + case SYS_DVBS: +@@ -1071,7 +1073,7 @@ static int stb0899_read_status(struct dv + reg = stb0899_read_reg(state, STB0899_VSTATUS); + if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) { + dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_CARRIER | FE_HAS_LOCK"); +- *status |= FE_HAS_CARRIER | FE_HAS_LOCK; ++ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; + + reg = stb0899_read_reg(state, STB0899_PLPARM); + if (STB0899_GETFIELD(VITCURPUN, reg)) { +Index: linux-3.3.x86_64/include/sound/tea575x-tuner.h +=================================================================== +--- linux-3.3.x86_64.orig/include/sound/tea575x-tuner.h ++++ linux-3.3.x86_64/include/sound/tea575x-tuner.h +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + #define TEA575X_FMIF 10700 + +@@ -42,13 +43,16 @@ struct snd_tea575x_ops { + }; + + struct snd_tea575x { ++ struct v4l2_device *v4l2_dev; + struct video_device vd; /* video device */ ++ int radio_nr; /* radio_nr */ + bool tea5759; /* 5759 chip is present */ ++ bool cannot_read_data; /* Device cannot read the data pin */ + bool mute; /* Device is muted? */ + bool stereo; /* receiving stereo */ + bool tuned; /* tuned to a station */ + unsigned int val; /* hw value */ +- unsigned long freq; /* frequency */ ++ u32 freq; /* frequency */ + struct mutex mutex; + struct snd_tea575x_ops *ops; + void *private_data; +Index: linux-3.3.x86_64/sound/i2c/other/tea575x-tuner.c +=================================================================== +--- linux-3.3.x86_64.orig/sound/i2c/other/tea575x-tuner.c ++++ linux-3.3.x86_64/sound/i2c/other/tea575x-tuner.c +@@ -25,21 +25,20 @@ + #include + #include + #include +-#include ++#include ++#include + #include ++#include + #include ++#include + #include + + MODULE_AUTHOR("Jaroslav Kysela "); + MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips"); + MODULE_LICENSE("GPL"); + +-static int radio_nr = -1; +-module_param(radio_nr, int, 0); +- +-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) +-#define FREQ_LO (50UL * 16000) +-#define FREQ_HI (150UL * 16000) ++#define FREQ_LO (76U * 16000) ++#define FREQ_HI (108U * 16000) + + /* + * definitions +@@ -121,28 +120,10 @@ static unsigned int snd_tea575x_read(str + return data; + } + +-static void snd_tea575x_get_freq(struct snd_tea575x *tea) +-{ +- unsigned long freq; +- +- freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK; +- /* freq *= 12.5 */ +- freq *= 125; +- freq /= 10; +- /* crystal fixup */ +- if (tea->tea5759) +- freq += TEA575X_FMIF; +- else +- freq -= TEA575X_FMIF; +- +- tea->freq = freq * 16; /* from kHz */ +-} +- + static void snd_tea575x_set_freq(struct snd_tea575x *tea) + { +- unsigned long freq; ++ u32 freq = tea->freq; + +- freq = clamp(tea->freq, FREQ_LO, FREQ_HI); + freq /= 16; /* to kHz */ + /* crystal fixup */ + if (tea->tea5759) +@@ -167,12 +148,14 @@ static int vidioc_querycap(struct file * + { + struct snd_tea575x *tea = video_drvdata(file); + +- strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver)); ++ strlcpy(v->driver, tea->v4l2_dev->name, sizeof(v->driver)); + strlcpy(v->card, tea->card, sizeof(v->card)); + strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card)); + strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info)); +- v->version = RADIO_VERSION; +- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; ++ v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; ++ if (!tea->cannot_read_data) ++ v->device_caps |= V4L2_CAP_HW_FREQ_SEEK; ++ v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; + } + +@@ -191,18 +174,24 @@ static int vidioc_g_tuner(struct file *f + v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; + v->rangelow = FREQ_LO; + v->rangehigh = FREQ_HI; +- v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; +- v->audmode = tea->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO; ++ v->rxsubchans = tea->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; ++ v->audmode = (tea->val & TEA575X_BIT_MONO) ? ++ V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO; + v->signal = tea->tuned ? 0xffff : 0; +- + return 0; + } + + static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) + { +- if (v->index > 0) ++ struct snd_tea575x *tea = video_drvdata(file); ++ ++ if (v->index) + return -EINVAL; ++ tea->val &= ~TEA575X_BIT_MONO; ++ if (v->audmode == V4L2_TUNER_MODE_MONO) ++ tea->val |= TEA575X_BIT_MONO; ++ snd_tea575x_write(tea, tea->val); + return 0; + } + +@@ -214,7 +203,6 @@ static int vidioc_g_frequency(struct fil + if (f->tuner != 0) + return -EINVAL; + f->type = V4L2_TUNER_RADIO; +- snd_tea575x_get_freq(tea); + f->frequency = tea->freq; + return 0; + } +@@ -227,32 +215,47 @@ static int vidioc_s_frequency(struct fil + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + +- if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) +- return -EINVAL; +- +- tea->freq = f->frequency; +- ++ tea->val &= ~TEA575X_BIT_SEARCH; ++ tea->freq = clamp(f->frequency, FREQ_LO, FREQ_HI); + snd_tea575x_set_freq(tea); +- + return 0; + } + +-static int vidioc_g_audio(struct file *file, void *priv, +- struct v4l2_audio *a) ++static int vidioc_s_hw_freq_seek(struct file *file, void *fh, ++ struct v4l2_hw_freq_seek *a) + { +- if (a->index > 1) +- return -EINVAL; +- +- strcpy(a->name, "Radio"); +- a->capability = V4L2_AUDCAP_STEREO; +- return 0; +-} ++ struct snd_tea575x *tea = video_drvdata(file); + +-static int vidioc_s_audio(struct file *file, void *priv, +- struct v4l2_audio *a) +-{ +- if (a->index != 0) ++ if (tea->cannot_read_data) ++ return -ENOTTY; ++ if (a->tuner || a->wrap_around) + return -EINVAL; ++ tea->val |= TEA575X_BIT_SEARCH; ++ tea->val &= ~TEA575X_BIT_UPDOWN; ++ if (a->seek_upward) ++ tea->val |= TEA575X_BIT_UPDOWN; ++ snd_tea575x_write(tea, tea->val); ++ for (;;) { ++ unsigned val = snd_tea575x_read(tea); ++ ++ if (!(val & TEA575X_BIT_SEARCH)) { ++ /* Found a frequency */ ++ val &= TEA575X_BIT_FREQ_MASK; ++ val = (val * 10) / 125; ++ if (tea->tea5759) ++ val += TEA575X_FMIF; ++ else ++ val -= TEA575X_FMIF; ++ tea->freq = clamp(val * 16, FREQ_LO, FREQ_HI); ++ return 0; ++ } ++ if (schedule_timeout_interruptible(msecs_to_jiffies(10))) { ++ /* some signal arrived, stop search */ ++ tea->val &= ~TEA575X_BIT_SEARCH; ++ snd_tea575x_write(tea, tea->val); ++ return -ERESTARTSYS; ++ } ++ } + return 0; + } + +@@ -273,23 +276,27 @@ static int tea575x_s_ctrl(struct v4l2_ct + static const struct v4l2_file_operations tea575x_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, ++ .open = v4l2_fh_open, ++ .release = v4l2_fh_release, ++ .poll = v4l2_ctrl_poll, + }; + + static const struct v4l2_ioctl_ops tea575x_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, +- .vidioc_g_audio = vidioc_g_audio, +- .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, ++ .vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek, ++ .vidioc_log_status = v4l2_ctrl_log_status, ++ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, ++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + }; + +-static struct video_device tea575x_radio = { +- .name = "tea575x-tuner", ++static const struct video_device tea575x_radio = { + .fops = &tea575x_fops, + .ioctl_ops = &tea575x_ioctl_ops, +- .release = video_device_release_empty, ++ .release = video_device_release_empty, + }; + + static const struct v4l2_ctrl_ops tea575x_ctrl_ops = { +@@ -303,11 +310,15 @@ int snd_tea575x_init(struct snd_tea575x + { + int retval; + +- tea->mute = 1; ++ tea->mute = true; + +- snd_tea575x_write(tea, 0x55AA); +- if (snd_tea575x_read(tea) != 0x55AA) +- return -ENODEV; ++ /* Not all devices can or know how to read the data back. ++ Such devices can set cannot_read_data to true. */ ++ if (!tea->cannot_read_data) { ++ snd_tea575x_write(tea, 0x55AA); ++ if (snd_tea575x_read(tea) != 0x55AA) ++ return -ENODEV; ++ } + + tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40; + tea->freq = 90500 * 16; /* 90.5Mhz default */ +@@ -316,14 +327,17 @@ int snd_tea575x_init(struct snd_tea575x + tea->vd = tea575x_radio; + video_set_drvdata(&tea->vd, tea); + mutex_init(&tea->mutex); ++ strlcpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name)); + tea->vd.lock = &tea->mutex; ++ tea->vd.v4l2_dev = tea->v4l2_dev; ++ tea->vd.ctrl_handler = &tea->ctrl_handler; ++ set_bit(V4L2_FL_USE_FH_PRIO, &tea->vd.flags); + + v4l2_ctrl_handler_init(&tea->ctrl_handler, 1); +- tea->vd.ctrl_handler = &tea->ctrl_handler; + v4l2_ctrl_new_std(&tea->ctrl_handler, &tea575x_ctrl_ops, V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); + retval = tea->ctrl_handler.error; + if (retval) { +- printk(KERN_ERR "tea575x-tuner: can't initialize controls\n"); ++ v4l2_err(tea->v4l2_dev, "can't initialize controls\n"); + v4l2_ctrl_handler_free(&tea->ctrl_handler); + return retval; + } +@@ -338,9 +352,9 @@ int snd_tea575x_init(struct snd_tea575x + + v4l2_ctrl_handler_setup(&tea->ctrl_handler); + +- retval = video_register_device(&tea->vd, VFL_TYPE_RADIO, radio_nr); ++ retval = video_register_device(&tea->vd, VFL_TYPE_RADIO, tea->radio_nr); + if (retval) { +- printk(KERN_ERR "tea575x-tuner: can't register video device!\n"); ++ v4l2_err(tea->v4l2_dev, "can't register video device!\n"); + v4l2_ctrl_handler_free(&tea->ctrl_handler); + return retval; + } +Index: linux-3.3.x86_64/sound/pci/es1968.c +=================================================================== +--- linux-3.3.x86_64.orig/sound/pci/es1968.c ++++ linux-3.3.x86_64/sound/pci/es1968.c +@@ -142,6 +142,7 @@ static int enable_mpu[SNDRV_CARDS] = {[0 + #ifdef SUPPORT_JOYSTICK + static bool joystick[SNDRV_CARDS]; + #endif ++static int radio_nr[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1}; + + module_param_array(index, int, NULL, 0444); + MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); +@@ -165,6 +166,9 @@ MODULE_PARM_DESC(enable_mpu, "Enable MPU + module_param_array(joystick, bool, NULL, 0444); + MODULE_PARM_DESC(joystick, "Enable joystick."); + #endif ++module_param_array(radio_nr, int, NULL, 0444); ++MODULE_PARM_DESC(radio_nr, "Radio device numbers"); ++ + + + #define NR_APUS 64 +@@ -558,6 +562,7 @@ struct es1968 { + struct work_struct hwvol_work; + + #ifdef CONFIG_SND_ES1968_RADIO ++ struct v4l2_device v4l2_dev; + struct snd_tea575x tea; + #endif + }; +@@ -2613,6 +2618,7 @@ static int snd_es1968_free(struct es1968 + + #ifdef CONFIG_SND_ES1968_RADIO + snd_tea575x_exit(&chip->tea); ++ v4l2_device_unregister(&chip->v4l2_dev); + #endif + + if (chip->irq >= 0) +@@ -2655,6 +2661,7 @@ static int __devinit snd_es1968_create(s + int capt_streams, + int chip_type, + int do_pm, ++ int radio_nr, + struct es1968 **chip_ret) + { + static struct snd_device_ops ops = { +@@ -2751,7 +2758,14 @@ static int __devinit snd_es1968_create(s + snd_card_set_dev(card, &pci->dev); + + #ifdef CONFIG_SND_ES1968_RADIO ++ err = v4l2_device_register(&pci->dev, &chip->v4l2_dev); ++ if (err < 0) { ++ snd_es1968_free(chip); ++ return err; ++ } ++ chip->tea.v4l2_dev = &chip->v4l2_dev; + chip->tea.private_data = chip; ++ chip->tea.radio_nr = radio_nr; + chip->tea.ops = &snd_es1968_tea_ops; + strlcpy(chip->tea.card, "SF64-PCE2", sizeof(chip->tea.card)); + sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci)); +@@ -2797,6 +2811,7 @@ static int __devinit snd_es1968_probe(st + pcm_substreams_c[dev], + pci_id->driver_data, + use_pm[dev], ++ radio_nr[dev], + &chip)) < 0) { + snd_card_free(card); + return err; +Index: linux-3.3.x86_64/sound/pci/fm801.c +=================================================================== +--- linux-3.3.x86_64.orig/sound/pci/fm801.c ++++ linux-3.3.x86_64/sound/pci/fm801.c +@@ -58,6 +58,7 @@ static bool enable[SNDRV_CARDS] = SNDRV_ + * High 16-bits are video (radio) device number + 1 + */ + static int tea575x_tuner[SNDRV_CARDS]; ++static int radio_nr[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1}; + + module_param_array(index, int, NULL, 0444); + MODULE_PARM_DESC(index, "Index value for the FM801 soundcard."); +@@ -67,6 +68,9 @@ module_param_array(enable, bool, NULL, 0 + MODULE_PARM_DESC(enable, "Enable FM801 soundcard."); + module_param_array(tea575x_tuner, int, NULL, 0444); + MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (0 = auto, 1 = SF256-PCS, 2=SF256-PCP, 3=SF64-PCR, 8=disable, +16=tuner-only)."); ++module_param_array(radio_nr, int, NULL, 0444); ++MODULE_PARM_DESC(radio_nr, "Radio device numbers"); ++ + + #define TUNER_DISABLED (1<<3) + #define TUNER_ONLY (1<<4) +@@ -197,6 +201,7 @@ struct fm801 { + struct snd_info_entry *proc_entry; + + #ifdef CONFIG_SND_FM801_TEA575X_BOOL ++ struct v4l2_device v4l2_dev; + struct snd_tea575x tea; + #endif + +@@ -1154,8 +1159,10 @@ static int snd_fm801_free(struct fm801 * + + __end_hw: + #ifdef CONFIG_SND_FM801_TEA575X_BOOL +- if (!(chip->tea575x_tuner & TUNER_DISABLED)) ++ if (!(chip->tea575x_tuner & TUNER_DISABLED)) { + snd_tea575x_exit(&chip->tea); ++ v4l2_device_unregister(&chip->v4l2_dev); ++ } + #endif + if (chip->irq >= 0) + free_irq(chip->irq, chip); +@@ -1175,6 +1182,7 @@ static int snd_fm801_dev_free(struct snd + static int __devinit snd_fm801_create(struct snd_card *card, + struct pci_dev * pci, + int tea575x_tuner, ++ int radio_nr, + struct fm801 ** rchip) + { + struct fm801 *chip; +@@ -1234,6 +1242,13 @@ static int __devinit snd_fm801_create(st + snd_card_set_dev(card, &pci->dev); + + #ifdef CONFIG_SND_FM801_TEA575X_BOOL ++ err = v4l2_device_register(&pci->dev, &chip->v4l2_dev); ++ if (err < 0) { ++ snd_fm801_free(chip); ++ return err; ++ } ++ chip->tea.v4l2_dev = &chip->v4l2_dev; ++ chip->tea.radio_nr = radio_nr; + chip->tea.private_data = chip; + chip->tea.ops = &snd_fm801_tea_ops; + sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci)); +@@ -1241,6 +1256,7 @@ static int __devinit snd_fm801_create(st + (tea575x_tuner & TUNER_TYPE_MASK) < 4) { + if (snd_tea575x_init(&chip->tea)) { + snd_printk(KERN_ERR "TEA575x radio not found\n"); ++ snd_fm801_free(chip); + return -ENODEV; + } + } else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0) { +@@ -1287,7 +1303,7 @@ static int __devinit snd_card_fm801_prob + err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + if (err < 0) + return err; +- if ((err = snd_fm801_create(card, pci, tea575x_tuner[dev], &chip)) < 0) { ++ if ((err = snd_fm801_create(card, pci, tea575x_tuner[dev], radio_nr[dev], &chip)) < 0) { + snd_card_free(card); + return err; + } +Index: linux-3.3.x86_64/drivers/media/radio/radio-maxiradio.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/radio/radio-maxiradio.c ++++ linux-3.3.x86_64/drivers/media/radio/radio-maxiradio.c +@@ -42,67 +42,37 @@ + #include + #include + #include ++#include + #include + #include +- +-#define DRIVER_VERSION "0.7.8" +- ++#include ++#include ++#include + + MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net"); +-MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio."); ++MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000."); + MODULE_LICENSE("GPL"); +-MODULE_VERSION(DRIVER_VERSION); ++MODULE_VERSION("1.0.0"); + + static int radio_nr = -1; +-module_param(radio_nr, int, 0); +- +-static int debug; +- +-module_param(debug, int, 0644); +-MODULE_PARM_DESC(debug, "activates debug info"); +- +-#define dprintk(dev, num, fmt, arg...) \ +- v4l2_dbg(num, debug, &dev->v4l2_dev, fmt, ## arg) +- +-#ifndef PCI_VENDOR_ID_GUILLEMOT +-#define PCI_VENDOR_ID_GUILLEMOT 0x5046 +-#endif +- +-#ifndef PCI_DEVICE_ID_GUILLEMOT +-#define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001 +-#endif +- ++module_param(radio_nr, int, 0644); ++MODULE_PARM_DESC(radio_nr, "Radio device number"); + + /* TEA5757 pin mappings */ + static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16; + +-#define FREQ_LO (87 * 16000) +-#define FREQ_HI (108 * 16000) +- +-#define FREQ_IF 171200 /* 10.7*16000 */ +-#define FREQ_STEP 200 /* 12.5*16 */ +- +-/* (x==fmhz*16*1000) -> bits */ +-#define FREQ2BITS(x) \ +- ((((unsigned int)(x) + FREQ_IF + (FREQ_STEP << 1)) / (FREQ_STEP << 2)) << 2) +- +-#define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF) ++static atomic_t maxiradio_instance = ATOMIC_INIT(0); + ++#define PCI_VENDOR_ID_GUILLEMOT 0x5046 ++#define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001 + + struct maxiradio + { ++ struct snd_tea575x tea; + struct v4l2_device v4l2_dev; +- struct video_device vdev; + struct pci_dev *pdev; + + u16 io; /* base of radio io */ +- u16 muted; /* VIDEO_AUDIO_MUTE */ +- u16 stereo; /* VIDEO_TUNER_STEREO_ON */ +- u16 tuned; /* signal strength (0 or 0xffff) */ +- +- unsigned long freq; +- +- struct mutex lock; + }; + + static inline struct maxiradio *to_maxiradio(struct v4l2_device *v4l2_dev) +@@ -110,259 +80,41 @@ static inline struct maxiradio *to_maxir + return container_of(v4l2_dev, struct maxiradio, v4l2_dev); + } + +-static void outbit(unsigned long bit, u16 io) +-{ +- int val = power | wren | (bit ? data : 0); +- +- outb(val, io); +- udelay(4); +- outb(val | clk, io); +- udelay(4); +- outb(val, io); +- udelay(4); +-} +- +-static void turn_power(struct maxiradio *dev, int p) +-{ +- if (p != 0) { +- dprintk(dev, 1, "Radio powered on\n"); +- outb(power, dev->io); +- } else { +- dprintk(dev, 1, "Radio powered off\n"); +- outb(0, dev->io); +- } +-} +- +-static void set_freq(struct maxiradio *dev, u32 freq) +-{ +- unsigned long int si; +- int bl; +- int io = dev->io; +- 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); /* 22 stereo/mono */ +- +- 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); /* 17 search level */ +- outbit(0, io); /* 16 search level */ +- +- si = 0x8000; +- for (bl = 1; bl <= 16; bl++) { +- outbit(val & si, io); +- si >>= 1; +- } +- +- dprintk(dev, 1, "Radio freq set to %d.%02d MHz\n", +- freq / 16000, +- freq % 16000 * 100 / 16000); +- +- turn_power(dev, 1); +-} +- +-static int get_stereo(u16 io) +-{ +- outb(power,io); +- udelay(4); +- +- return !(inb(io) & mo_st); +-} +- +-static int get_tune(u16 io) +-{ +- outb(power+clk,io); +- udelay(4); +- +- return !(inb(io) & mo_st); +-} +- +- +-static int vidioc_querycap(struct file *file, void *priv, +- struct v4l2_capability *v) +-{ +- struct maxiradio *dev = video_drvdata(file); +- +- strlcpy(v->driver, "radio-maxiradio", sizeof(v->driver)); +- strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof(v->card)); +- snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev)); +- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; +- return 0; +-} +- +-static int vidioc_g_tuner(struct file *file, void *priv, +- struct v4l2_tuner *v) ++static void maxiradio_tea575x_set_pins(struct snd_tea575x *tea, u8 pins) + { +- struct maxiradio *dev = video_drvdata(file); ++ struct maxiradio *dev = tea->private_data; ++ u8 bits = 0; + +- if (v->index > 0) +- return -EINVAL; ++ bits |= (pins & TEA575X_DATA) ? data : 0; ++ bits |= (pins & TEA575X_CLK) ? clk : 0; ++ bits |= (pins & TEA575X_WREN) ? wren : 0; ++ bits |= power; + +- mutex_lock(&dev->lock); +- strlcpy(v->name, "FM", sizeof(v->name)); +- v->type = V4L2_TUNER_RADIO; +- v->rangelow = FREQ_LO; +- v->rangehigh = FREQ_HI; +- v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; +- v->capability = V4L2_TUNER_CAP_LOW; +- if (get_stereo(dev->io)) +- v->audmode = V4L2_TUNER_MODE_STEREO; +- else +- v->audmode = V4L2_TUNER_MODE_MONO; +- v->signal = 0xffff * get_tune(dev->io); +- mutex_unlock(&dev->lock); +- +- return 0; +-} +- +-static int vidioc_s_tuner(struct file *file, void *priv, +- struct v4l2_tuner *v) +-{ +- return v->index ? -EINVAL : 0; +-} +- +-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +-{ +- *i = 0; +- return 0; +-} +- +-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +-{ +- return i ? -EINVAL : 0; +-} +- +-static int vidioc_g_audio(struct file *file, void *priv, +- struct v4l2_audio *a) +-{ +- a->index = 0; +- strlcpy(a->name, "Radio", sizeof(a->name)); +- a->capability = V4L2_AUDCAP_STEREO; +- return 0; +-} +- +- +-static int vidioc_s_audio(struct file *file, void *priv, +- struct v4l2_audio *a) +-{ +- return a->index ? -EINVAL : 0; +-} +- +-static int vidioc_s_frequency(struct file *file, void *priv, +- struct v4l2_frequency *f) +-{ +- struct maxiradio *dev = video_drvdata(file); +- +- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) +- return -EINVAL; +- if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) { +- dprintk(dev, 1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n", +- f->frequency / 16000, +- f->frequency % 16000 * 100 / 16000, +- FREQ_LO / 16000, FREQ_HI / 16000); +- +- return -EINVAL; +- } +- +- mutex_lock(&dev->lock); +- dev->freq = f->frequency; +- set_freq(dev, dev->freq); +- msleep(125); +- mutex_unlock(&dev->lock); +- +- return 0; +-} +- +-static int vidioc_g_frequency(struct file *file, void *priv, +- struct v4l2_frequency *f) +-{ +- struct maxiradio *dev = video_drvdata(file); +- +- if (f->tuner != 0) +- return -EINVAL; +- f->type = V4L2_TUNER_RADIO; +- f->frequency = dev->freq; +- +- dprintk(dev, 4, "radio freq is %d.%02d MHz", +- f->frequency / 16000, +- f->frequency % 16000 * 100 / 16000); +- +- return 0; +-} +- +-static int vidioc_queryctrl(struct file *file, void *priv, +- struct v4l2_queryctrl *qc) +-{ +- switch (qc->id) { +- case V4L2_CID_AUDIO_MUTE: +- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); +- } +- return -EINVAL; ++ outb(bits, dev->io); + } + +-static int vidioc_g_ctrl(struct file *file, void *priv, +- struct v4l2_control *ctrl) ++/* Note: this card cannot read out the data of the shift registers, ++ only the mono/stereo pin works. */ ++static u8 maxiradio_tea575x_get_pins(struct snd_tea575x *tea) + { +- struct maxiradio *dev = video_drvdata(file); ++ struct maxiradio *dev = tea->private_data; ++ u8 bits = inb(dev->io); + +- switch (ctrl->id) { +- case V4L2_CID_AUDIO_MUTE: +- ctrl->value = dev->muted; +- return 0; +- } +- +- return -EINVAL; ++ return ((bits & data) ? TEA575X_DATA : 0) | ++ ((bits & mo_st) ? TEA575X_MOST : 0); + } + +-static int vidioc_s_ctrl(struct file *file, void *priv, +- struct v4l2_control *ctrl) ++static void maxiradio_tea575x_set_direction(struct snd_tea575x *tea, bool output) + { +- struct maxiradio *dev = video_drvdata(file); +- +- switch (ctrl->id) { +- case V4L2_CID_AUDIO_MUTE: +- mutex_lock(&dev->lock); +- dev->muted = ctrl->value; +- if (dev->muted) +- turn_power(dev, 0); +- else +- set_freq(dev, dev->freq); +- mutex_unlock(&dev->lock); +- return 0; +- } +- +- return -EINVAL; + } + +-static const struct v4l2_file_operations maxiradio_fops = { +- .owner = THIS_MODULE, +- .unlocked_ioctl = video_ioctl2, +-}; +- +-static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = { +- .vidioc_querycap = vidioc_querycap, +- .vidioc_g_tuner = vidioc_g_tuner, +- .vidioc_s_tuner = vidioc_s_tuner, +- .vidioc_g_audio = vidioc_g_audio, +- .vidioc_s_audio = vidioc_s_audio, +- .vidioc_g_input = vidioc_g_input, +- .vidioc_s_input = vidioc_s_input, +- .vidioc_g_frequency = vidioc_g_frequency, +- .vidioc_s_frequency = vidioc_s_frequency, +- .vidioc_queryctrl = vidioc_queryctrl, +- .vidioc_g_ctrl = vidioc_g_ctrl, +- .vidioc_s_ctrl = vidioc_s_ctrl, ++static struct snd_tea575x_ops maxiradio_tea_ops = { ++ .set_pins = maxiradio_tea575x_set_pins, ++ .get_pins = maxiradio_tea575x_get_pins, ++ .set_direction = maxiradio_tea575x_set_direction, + }; + +-static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ++static int __devinit maxiradio_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + { + struct maxiradio *dev; + struct v4l2_device *v4l2_dev; +@@ -375,63 +127,60 @@ static int __devinit maxiradio_init_one( + } + + v4l2_dev = &dev->v4l2_dev; +- mutex_init(&dev->lock); +- dev->pdev = pdev; +- dev->muted = 1; +- dev->freq = FREQ_LO; +- +- strlcpy(v4l2_dev->name, "maxiradio", sizeof(v4l2_dev->name)); ++ v4l2_device_set_name(v4l2_dev, "maxiradio", &maxiradio_instance); + + retval = v4l2_device_register(&pdev->dev, v4l2_dev); + if (retval < 0) { + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + goto errfr; + } ++ dev->tea.private_data = dev; ++ dev->tea.ops = &maxiradio_tea_ops; ++ /* The data pin cannot be read. This may be a hardware limitation, or ++ we just don't know how to read it. */ ++ dev->tea.cannot_read_data = true; ++ dev->tea.v4l2_dev = v4l2_dev; ++ dev->tea.radio_nr = radio_nr; ++ strlcpy(dev->tea.card, "Maxi Radio FM2000", sizeof(dev->tea.card)); ++ snprintf(dev->tea.bus_info, sizeof(dev->tea.bus_info), ++ "PCI:%s", pci_name(pdev)); ++ ++ retval = -ENODEV; + + if (!request_region(pci_resource_start(pdev, 0), +- pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) { +- v4l2_err(v4l2_dev, "can't reserve I/O ports\n"); +- goto err_out; ++ pci_resource_len(pdev, 0), v4l2_dev->name)) { ++ dev_err(&pdev->dev, "can't reserve I/O ports\n"); ++ goto err_hdl; + } + + if (pci_enable_device(pdev)) + goto err_out_free_region; + + dev->io = pci_resource_start(pdev, 0); +- strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); +- dev->vdev.v4l2_dev = v4l2_dev; +- dev->vdev.fops = &maxiradio_fops; +- dev->vdev.ioctl_ops = &maxiradio_ioctl_ops; +- dev->vdev.release = video_device_release_empty; +- video_set_drvdata(&dev->vdev, dev); +- +- if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { +- v4l2_err(v4l2_dev, "can't register device!"); ++ if (snd_tea575x_init(&dev->tea)) { ++ printk(KERN_ERR "radio-maxiradio: Unable to detect TEA575x tuner\n"); + goto err_out_free_region; + } +- +- v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n"); +- +- v4l2_info(v4l2_dev, "found Guillemot MAXI Radio device (io = 0x%x)\n", +- dev->io); + return 0; + + err_out_free_region: + release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); +-err_out: ++err_hdl: + v4l2_device_unregister(v4l2_dev); + errfr: + kfree(dev); +- return -ENODEV; ++ return retval; + } + +-static void __devexit maxiradio_remove_one(struct pci_dev *pdev) ++static void __devexit maxiradio_remove(struct pci_dev *pdev) + { + struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); + struct maxiradio *dev = to_maxiradio(v4l2_dev); + +- video_unregister_device(&dev->vdev); +- v4l2_device_unregister(&dev->v4l2_dev); ++ snd_tea575x_exit(&dev->tea); ++ /* Turn off power */ ++ outb(0, dev->io); ++ v4l2_device_unregister(v4l2_dev); + release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + } + +@@ -446,19 +195,19 @@ MODULE_DEVICE_TABLE(pci, maxiradio_pci_t + static struct pci_driver maxiradio_driver = { + .name = "radio-maxiradio", + .id_table = maxiradio_pci_tbl, +- .probe = maxiradio_init_one, +- .remove = __devexit_p(maxiradio_remove_one), ++ .probe = maxiradio_probe, ++ .remove = __devexit_p(maxiradio_remove), + }; + +-static int __init maxiradio_radio_init(void) ++static int __init maxiradio_init(void) + { + return pci_register_driver(&maxiradio_driver); + } + +-static void __exit maxiradio_radio_exit(void) ++static void __exit maxiradio_exit(void) + { + pci_unregister_driver(&maxiradio_driver); + } + +-module_init(maxiradio_radio_init); +-module_exit(maxiradio_radio_exit); ++module_init(maxiradio_init); ++module_exit(maxiradio_exit); +Index: linux-3.3.x86_64/include/media/v4l2-dev.h +=================================================================== +--- linux-3.3.x86_64.orig/include/media/v4l2-dev.h ++++ linux-3.3.x86_64/include/media/v4l2-dev.h +@@ -62,6 +62,9 @@ struct v4l2_file_operations { + unsigned int (*poll) (struct file *, struct poll_table_struct *); + long (*ioctl) (struct file *, unsigned int, unsigned long); + long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); ++#ifdef CONFIG_COMPAT ++ long (*compat_ioctl32) (struct file *, unsigned int, unsigned long); ++#endif + unsigned long (*get_unmapped_area) (struct file *, unsigned long, + unsigned long, unsigned long, unsigned long); + int (*mmap) (struct file *, struct vm_area_struct *); +Index: linux-3.3.x86_64/drivers/media/video/uvc/uvc_v4l2.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/uvc/uvc_v4l2.c ++++ linux-3.3.x86_64/drivers/media/video/uvc/uvc_v4l2.c +@@ -11,6 +11,7 @@ + * + */ + ++#include + #include + #include + #include +@@ -1012,7 +1013,7 @@ static long uvc_v4l2_do_ioctl(struct fil + + default: + uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n", cmd); +- return -EINVAL; ++ return -ENOTTY; + } + + return ret; +@@ -1030,6 +1031,207 @@ static long uvc_v4l2_ioctl(struct file * + return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl); + } + ++#ifdef CONFIG_COMPAT ++struct uvc_xu_control_mapping32 { ++ __u32 id; ++ __u8 name[32]; ++ __u8 entity[16]; ++ __u8 selector; ++ ++ __u8 size; ++ __u8 offset; ++ __u32 v4l2_type; ++ __u32 data_type; ++ ++ compat_caddr_t menu_info; ++ __u32 menu_count; ++ ++ __u32 reserved[4]; ++}; ++ ++static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp, ++ const struct uvc_xu_control_mapping32 __user *up) ++{ ++ struct uvc_menu_info __user *umenus; ++ struct uvc_menu_info __user *kmenus; ++ compat_caddr_t p; ++ ++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || ++ __copy_from_user(kp, up, offsetof(typeof(*up), menu_info)) || ++ __get_user(kp->menu_count, &up->menu_count)) ++ return -EFAULT; ++ ++ memset(kp->reserved, 0, sizeof(kp->reserved)); ++ ++ if (kp->menu_count == 0) { ++ kp->menu_info = NULL; ++ return 0; ++ } ++ ++ if (__get_user(p, &up->menu_info)) ++ return -EFAULT; ++ umenus = compat_ptr(p); ++ if (!access_ok(VERIFY_READ, umenus, kp->menu_count * sizeof(*umenus))) ++ return -EFAULT; ++ ++ kmenus = compat_alloc_user_space(kp->menu_count * sizeof(*kmenus)); ++ if (kmenus == NULL) ++ return -EFAULT; ++ kp->menu_info = kmenus; ++ ++ if (copy_in_user(kmenus, umenus, kp->menu_count * sizeof(*umenus))) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp, ++ struct uvc_xu_control_mapping32 __user *up) ++{ ++ struct uvc_menu_info __user *umenus; ++ struct uvc_menu_info __user *kmenus = kp->menu_info; ++ compat_caddr_t p; ++ ++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || ++ __copy_to_user(up, kp, offsetof(typeof(*up), menu_info)) || ++ __put_user(kp->menu_count, &up->menu_count)) ++ return -EFAULT; ++ ++ __clear_user(up->reserved, sizeof(up->reserved)); ++ ++ if (kp->menu_count == 0) ++ return 0; ++ ++ if (get_user(p, &up->menu_info)) ++ return -EFAULT; ++ umenus = compat_ptr(p); ++ if (!access_ok(VERIFY_WRITE, umenus, kp->menu_count * sizeof(*umenus))) ++ return -EFAULT; ++ ++ if (copy_in_user(umenus, kmenus, kp->menu_count * sizeof(*umenus))) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++struct uvc_xu_control_query32 { ++ __u8 unit; ++ __u8 selector; ++ __u8 query; ++ __u16 size; ++ compat_caddr_t data; ++}; ++ ++static int uvc_v4l2_get_xu_query(struct uvc_xu_control_query *kp, ++ const struct uvc_xu_control_query32 __user *up) ++{ ++ u8 __user *udata; ++ u8 __user *kdata; ++ compat_caddr_t p; ++ ++ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || ++ __copy_from_user(kp, up, offsetof(typeof(*up), data))) ++ return -EFAULT; ++ ++ if (kp->size == 0) { ++ kp->data = NULL; ++ return 0; ++ } ++ ++ if (__get_user(p, &up->data)) ++ return -EFAULT; ++ udata = compat_ptr(p); ++ if (!access_ok(VERIFY_READ, udata, kp->size)) ++ return -EFAULT; ++ ++ kdata = compat_alloc_user_space(kp->size); ++ if (kdata == NULL) ++ return -EFAULT; ++ kp->data = kdata; ++ ++ if (copy_in_user(kdata, udata, kp->size)) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp, ++ struct uvc_xu_control_query32 __user *up) ++{ ++ u8 __user *udata; ++ u8 __user *kdata = kp->data; ++ compat_caddr_t p; ++ ++ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || ++ __copy_to_user(up, kp, offsetof(typeof(*up), data))) ++ return -EFAULT; ++ ++ if (kp->size == 0) ++ return 0; ++ ++ if (get_user(p, &up->data)) ++ return -EFAULT; ++ udata = compat_ptr(p); ++ if (!access_ok(VERIFY_READ, udata, kp->size)) ++ return -EFAULT; ++ ++ if (copy_in_user(udata, kdata, kp->size)) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++#define UVCIOC_CTRL_MAP32 _IOWR('u', 0x20, struct uvc_xu_control_mapping32) ++#define UVCIOC_CTRL_QUERY32 _IOWR('u', 0x21, struct uvc_xu_control_query32) ++ ++static long uvc_v4l2_compat_ioctl32(struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ union { ++ struct uvc_xu_control_mapping xmap; ++ struct uvc_xu_control_query xqry; ++ } karg; ++ void __user *up = compat_ptr(arg); ++ mm_segment_t old_fs; ++ long ret; ++ ++ switch (cmd) { ++ case UVCIOC_CTRL_MAP32: ++ cmd = UVCIOC_CTRL_MAP; ++ ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up); ++ break; ++ ++ case UVCIOC_CTRL_QUERY32: ++ cmd = UVCIOC_CTRL_QUERY; ++ ret = uvc_v4l2_get_xu_query(&karg.xqry, up); ++ break; ++ ++ default: ++ return -ENOIOCTLCMD; ++ } ++ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ret = uvc_v4l2_ioctl(file, cmd, (unsigned long)&karg); ++ set_fs(old_fs); ++ ++ if (ret < 0) ++ return ret; ++ ++ switch (cmd) { ++ case UVCIOC_CTRL_MAP: ++ ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up); ++ break; ++ ++ case UVCIOC_CTRL_QUERY: ++ ret = uvc_v4l2_put_xu_query(&karg.xqry, up); ++ break; ++ } ++ ++ return ret; ++} ++#endif ++ + static ssize_t uvc_v4l2_read(struct file *file, char __user *data, + size_t count, loff_t *ppos) + { +@@ -1076,6 +1278,9 @@ const struct v4l2_file_operations uvc_fo + .open = uvc_v4l2_open, + .release = uvc_v4l2_release, + .unlocked_ioctl = uvc_v4l2_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl32 = uvc_v4l2_compat_ioctl32, ++#endif + .read = uvc_v4l2_read, + .mmap = uvc_v4l2_mmap, + .poll = uvc_v4l2_poll, +Index: linux-3.3.x86_64/drivers/media/video/uvc/uvc_queue.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/uvc/uvc_queue.c ++++ linux-3.3.x86_64/drivers/media/video/uvc/uvc_queue.c +@@ -126,7 +126,7 @@ void uvc_queue_init(struct uvc_video_que + int drop_corrupted) + { + queue->queue.type = type; +- queue->queue.io_modes = VB2_MMAP; ++ queue->queue.io_modes = VB2_MMAP | VB2_USERPTR; + queue->queue.drv_priv = queue; + queue->queue.buf_struct_size = sizeof(struct uvc_buffer); + queue->queue.ops = &uvc_queue_qops; +Index: linux-3.3.x86_64/drivers/media/video/uvc/uvc_driver.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/uvc/uvc_driver.c ++++ linux-3.3.x86_64/drivers/media/video/uvc/uvc_driver.c +@@ -23,6 +23,7 @@ + * codec can't handle MJPEG data. + */ + ++#include + #include + #include + #include +@@ -32,7 +33,6 @@ + #include + #include + #include +-#include + #include + + #include +@@ -2139,6 +2139,15 @@ static struct usb_device_id uvc_ids[] = + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_MINMAX }, ++ /* Dell XPS m1530 */ ++ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE ++ | USB_DEVICE_ID_MATCH_INT_INFO, ++ .idVendor = 0x05a9, ++ .idProduct = 0x2640, ++ .bInterfaceClass = USB_CLASS_VIDEO, ++ .bInterfaceSubClass = 1, ++ .bInterfaceProtocol = 0, ++ .driver_info = UVC_QUIRK_PROBE_DEF }, + /* Apple Built-In iSight */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/stv0288.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/stv0288.c ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/stv0288.c +@@ -506,7 +506,7 @@ static int stv0288_set_frontend(struct d + tda[1] = (unsigned char)tm; + stv0288_writeregI(state, 0x2b, tda[1]); + stv0288_writeregI(state, 0x2c, tda[2]); +- udelay(30); ++ msleep(30); + } + state->tuner_frequency = c->frequency; + state->fec_inner = FEC_AUTO; +Index: linux-3.3.x86_64/drivers/media/video/cx231xx/cx231xx-cards.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/cx231xx/cx231xx-cards.c ++++ linux-3.3.x86_64/drivers/media/video/cx231xx/cx231xx-cards.c +@@ -861,7 +861,6 @@ void cx231xx_release_resources(struct cx + kfree(dev->sliced_cc_mode.alt_max_pkt_size); + kfree(dev->ts1_mode.alt_max_pkt_size); + kfree(dev); +- dev = NULL; + } + + /* +Index: linux-3.3.x86_64/drivers/media/video/cx231xx/cx231xx-video.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/cx231xx/cx231xx-video.c ++++ linux-3.3.x86_64/drivers/media/video/cx231xx/cx231xx-video.c +@@ -2319,8 +2319,7 @@ static int cx231xx_v4l2_close(struct fil + if (dev->state & DEV_DISCONNECTED) { + if (atomic_read(&dev->devlist_count) > 0) { + cx231xx_release_resources(dev); +- kfree(dev); +- dev = NULL; ++ fh->dev = NULL; + return 0; + } + return 0; +@@ -2350,8 +2349,7 @@ static int cx231xx_v4l2_close(struct fil + free the remaining resources */ + if (dev->state & DEV_DISCONNECTED) { + cx231xx_release_resources(dev); +- kfree(dev); +- dev = NULL; ++ fh->dev = NULL; + return 0; + } + +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/dib9000.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/dib9000.c ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/dib9000.c +@@ -33,7 +33,7 @@ struct i2c_device { + + /* lock */ + #define DIB_LOCK struct mutex +-#define DibAcquireLock(lock) do { if (mutex_lock_interruptible(lock) < 0) dprintk("could not get the lock"); } while (0) ++#define DibAcquireLock(lock) mutex_lock_interruptible(lock) + #define DibReleaseLock(lock) mutex_unlock(lock) + #define DibInitLock(lock) mutex_init(lock) + #define DibFreeLock(lock) +@@ -446,7 +446,10 @@ static int dib9000_risc_mem_read(struct + if (!state->platform.risc.fw_is_running) + return -EIO; + +- DibAcquireLock(&state->platform.risc.mem_lock); ++ if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) { ++ dprintk("could not get the lock"); ++ return -EINTR; ++ } + dib9000_risc_mem_setup(state, cmd | 0x80); + dib9000_risc_mem_read_chunks(state, b, len); + DibReleaseLock(&state->platform.risc.mem_lock); +@@ -459,7 +462,10 @@ static int dib9000_risc_mem_write(struct + if (!state->platform.risc.fw_is_running) + return -EIO; + +- DibAcquireLock(&state->platform.risc.mem_lock); ++ if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) { ++ dprintk("could not get the lock"); ++ return -EINTR; ++ } + dib9000_risc_mem_setup(state, cmd); + dib9000_risc_mem_write_chunks(state, b, m->size); + DibReleaseLock(&state->platform.risc.mem_lock); +@@ -531,7 +537,10 @@ static int dib9000_mbx_send_attr(struct + if (!state->platform.risc.fw_is_running) + return -EINVAL; + +- DibAcquireLock(&state->platform.risc.mbx_if_lock); ++ if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) { ++ dprintk("could not get the lock"); ++ return -EINTR; ++ } + tmp = MAX_MAILBOX_TRY; + do { + size = dib9000_read_word_attr(state, 1043, attr) & 0xff; +@@ -593,7 +602,10 @@ static u8 dib9000_mbx_read(struct dib900 + if (!state->platform.risc.fw_is_running) + return 0; + +- DibAcquireLock(&state->platform.risc.mbx_if_lock); ++ if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) { ++ dprintk("could not get the lock"); ++ return 0; ++ } + if (risc_id == 1) + mc_base = 16; + else +@@ -701,7 +713,10 @@ static int dib9000_mbx_process(struct di + if (!state->platform.risc.fw_is_running) + return -1; + +- DibAcquireLock(&state->platform.risc.mbx_lock); ++ if (DibAcquireLock(&state->platform.risc.mbx_lock) < 0) { ++ dprintk("could not get the lock"); ++ return -1; ++ } + + if (dib9000_mbx_count(state, 1, attr)) /* 1=RiscB */ + ret = dib9000_mbx_fetch_to_cache(state, attr); +@@ -1178,7 +1193,10 @@ static int dib9000_fw_get_channel(struct + struct dibDVBTChannel *ch; + int ret = 0; + +- DibAcquireLock(&state->platform.risc.mem_mbx_lock); ++ if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { ++ dprintk("could not get the lock"); ++ return -EINTR; ++ } + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { + ret = -EIO; + goto error; +@@ -1660,7 +1678,10 @@ static int dib9000_fw_component_bus_xfer + p[12] = 0; + } + +- DibAcquireLock(&state->platform.risc.mem_mbx_lock); ++ if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { ++ dprintk("could not get the lock"); ++ return 0; ++ } + + dib9000_risc_mem_write(state, FE_MM_W_COMPONENT_ACCESS, p); + +@@ -1768,7 +1789,10 @@ int dib9000_fw_pid_filter_ctrl(struct dv + return 0; + } + +- DibAcquireLock(&state->demod_lock); ++ if (DibAcquireLock(&state->demod_lock) < 0) { ++ dprintk("could not get the lock"); ++ return -EINTR; ++ } + + val = dib9000_read_word(state, 294 + 1) & 0xffef; + val |= (onoff & 0x1) << 4; +@@ -1800,7 +1824,10 @@ int dib9000_fw_pid_filter(struct dvb_fro + return 0; + } + +- DibAcquireLock(&state->demod_lock); ++ if (DibAcquireLock(&state->demod_lock) < 0) { ++ dprintk("could not get the lock"); ++ return -EINTR; ++ } + dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); + ret = dib9000_write_word(state, 300 + 1 + id, + onoff ? (1 << 13) | pid : 0); +@@ -1848,7 +1875,10 @@ static int dib9000_sleep(struct dvb_fron + u8 index_frontend; + int ret = 0; + +- DibAcquireLock(&state->demod_lock); ++ if (DibAcquireLock(&state->demod_lock) < 0) { ++ dprintk("could not get the lock"); ++ return -EINTR; ++ } + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); + if (ret < 0) +@@ -1874,8 +1904,12 @@ static int dib9000_get_frontend(struct d + fe_status_t stat; + int ret = 0; + +- if (state->get_frontend_internal == 0) +- DibAcquireLock(&state->demod_lock); ++ if (state->get_frontend_internal == 0) { ++ if (DibAcquireLock(&state->demod_lock) < 0) { ++ dprintk("could not get the lock"); ++ return -EINTR; ++ } ++ } + + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); +@@ -1978,7 +2012,10 @@ static int dib9000_set_frontend(struct d + } + + state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */ +- DibAcquireLock(&state->demod_lock); ++ if (DibAcquireLock(&state->demod_lock) < 0) { ++ dprintk("could not get the lock"); ++ return 0; ++ } + + fe->dtv_property_cache.delivery_system = SYS_DVBT; + +@@ -2138,7 +2175,10 @@ static int dib9000_read_status(struct dv + u8 index_frontend; + u16 lock = 0, lock_slave = 0; + +- DibAcquireLock(&state->demod_lock); ++ if (DibAcquireLock(&state->demod_lock) < 0) { ++ dprintk("could not get the lock"); ++ return -EINTR; ++ } + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + lock_slave |= dib9000_read_lock(state->fe[index_frontend]); + +@@ -2168,8 +2208,15 @@ static int dib9000_read_ber(struct dvb_f + u16 *c; + int ret = 0; + +- DibAcquireLock(&state->demod_lock); +- DibAcquireLock(&state->platform.risc.mem_mbx_lock); ++ if (DibAcquireLock(&state->demod_lock) < 0) { ++ dprintk("could not get the lock"); ++ return -EINTR; ++ } ++ if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { ++ dprintk("could not get the lock"); ++ ret = -EINTR; ++ goto error; ++ } + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + ret = -EIO; +@@ -2196,7 +2243,10 @@ static int dib9000_read_signal_strength( + u16 val; + int ret = 0; + +- DibAcquireLock(&state->demod_lock); ++ if (DibAcquireLock(&state->demod_lock) < 0) { ++ dprintk("could not get the lock"); ++ return -EINTR; ++ } + *strength = 0; + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); +@@ -2206,8 +2256,13 @@ static int dib9000_read_signal_strength( + *strength += val; + } + +- DibAcquireLock(&state->platform.risc.mem_mbx_lock); ++ if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { ++ dprintk("could not get the lock"); ++ ret = -EINTR; ++ goto error; ++ } + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { ++ DibReleaseLock(&state->platform.risc.mem_mbx_lock); + ret = -EIO; + goto error; + } +@@ -2232,9 +2287,14 @@ static u32 dib9000_get_snr(struct dvb_fr + u32 n, s, exp; + u16 val; + +- DibAcquireLock(&state->platform.risc.mem_mbx_lock); +- if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) +- return -EIO; ++ if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { ++ dprintk("could not get the lock"); ++ return 0; ++ } ++ if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { ++ DibReleaseLock(&state->platform.risc.mem_mbx_lock); ++ return 0; ++ } + dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + +@@ -2266,7 +2326,10 @@ static int dib9000_read_snr(struct dvb_f + u8 index_frontend; + u32 snr_master; + +- DibAcquireLock(&state->demod_lock); ++ if (DibAcquireLock(&state->demod_lock) < 0) { ++ dprintk("could not get the lock"); ++ return -EINTR; ++ } + snr_master = dib9000_get_snr(fe); + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + snr_master += dib9000_get_snr(state->fe[index_frontend]); +@@ -2288,9 +2351,17 @@ static int dib9000_read_unc_blocks(struc + u16 *c = (u16 *)state->i2c_read_buffer; + int ret = 0; + +- DibAcquireLock(&state->demod_lock); +- DibAcquireLock(&state->platform.risc.mem_mbx_lock); ++ if (DibAcquireLock(&state->demod_lock) < 0) { ++ dprintk("could not get the lock"); ++ return -EINTR; ++ } ++ if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { ++ dprintk("could not get the lock"); ++ ret = -EINTR; ++ goto error; ++ } + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { ++ DibReleaseLock(&state->platform.risc.mem_mbx_lock); + ret = -EIO; + goto error; + } +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/drxd_hard.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/drxd_hard.c ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/drxd_hard.c +@@ -101,9 +101,9 @@ struct SCfgAgc { + + struct SNoiseCal { + int cpOpt; +- u16 cpNexpOfs; +- u16 tdCal2k; +- u16 tdCal8k; ++ short cpNexpOfs; ++ short tdCal2k; ++ short tdCal8k; + }; + + enum app_env { +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/m88rs2000.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/m88rs2000.c +@@ -0,0 +1,904 @@ ++/* ++ Driver for M88RS2000 demodulator and tuner ++ ++ Copyright (C) 2012 Malcolm Priestley (tvboxspy@gmail.com) ++ Beta Driver ++ ++ Include various calculation code from DS3000 driver. ++ Copyright (C) 2009 Konstantin Dimitrov. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ ++*/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include "dvb_frontend.h" ++#include "m88rs2000.h" ++ ++struct m88rs2000_state { ++ struct i2c_adapter *i2c; ++ const struct m88rs2000_config *config; ++ struct dvb_frontend frontend; ++ u8 no_lock_count; ++ u32 tuner_frequency; ++ u32 symbol_rate; ++ fe_code_rate_t fec_inner; ++ u8 tuner_level; ++ int errmode; ++}; ++ ++static int m88rs2000_debug; ++ ++module_param_named(debug, m88rs2000_debug, int, 0644); ++MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); ++ ++#define dprintk(level, args...) do { \ ++ if (level & m88rs2000_debug) \ ++ printk(KERN_DEBUG "m88rs2000-fe: " args); \ ++} while (0) ++ ++#define deb_info(args...) dprintk(0x01, args) ++#define info(format, arg...) \ ++ printk(KERN_INFO "m88rs2000-fe: " format "\n" , ## arg) ++ ++static int m88rs2000_writereg(struct m88rs2000_state *state, u8 tuner, ++ u8 reg, u8 data) ++{ ++ int ret; ++ u8 addr = (tuner == 0) ? state->config->tuner_addr : ++ state->config->demod_addr; ++ u8 buf[] = { reg, data }; ++ struct i2c_msg msg = { ++ .addr = addr, ++ .flags = 0, ++ .buf = buf, ++ .len = 2 ++ }; ++ ++ ret = i2c_transfer(state->i2c, &msg, 1); ++ ++ if (ret != 1) ++ deb_info("%s: writereg error (reg == 0x%02x, val == 0x%02x, " ++ "ret == %i)\n", __func__, reg, data, ret); ++ ++ return (ret != 1) ? -EREMOTEIO : 0; ++} ++ ++static int m88rs2000_demod_write(struct m88rs2000_state *state, u8 reg, u8 data) ++{ ++ return m88rs2000_writereg(state, 1, reg, data); ++} ++ ++static int m88rs2000_tuner_write(struct m88rs2000_state *state, u8 reg, u8 data) ++{ ++ m88rs2000_demod_write(state, 0x81, 0x84); ++ udelay(10); ++ return m88rs2000_writereg(state, 0, reg, data); ++ ++} ++ ++static int m88rs2000_write(struct dvb_frontend *fe, const u8 buf[], int len) ++{ ++ struct m88rs2000_state *state = fe->demodulator_priv; ++ ++ if (len != 2) ++ return -EINVAL; ++ ++ return m88rs2000_writereg(state, 1, buf[0], buf[1]); ++} ++ ++static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 tuner, u8 reg) ++{ ++ int ret; ++ u8 b0[] = { reg }; ++ u8 b1[] = { 0 }; ++ u8 addr = (tuner == 0) ? state->config->tuner_addr : ++ state->config->demod_addr; ++ struct i2c_msg msg[] = { ++ { ++ .addr = addr, ++ .flags = 0, ++ .buf = b0, ++ .len = 1 ++ }, { ++ .addr = addr, ++ .flags = I2C_M_RD, ++ .buf = b1, ++ .len = 1 ++ } ++ }; ++ ++ ret = i2c_transfer(state->i2c, msg, 2); ++ ++ if (ret != 2) ++ deb_info("%s: readreg error (reg == 0x%02x, ret == %i)\n", ++ __func__, reg, ret); ++ ++ return b1[0]; ++} ++ ++static u8 m88rs2000_demod_read(struct m88rs2000_state *state, u8 reg) ++{ ++ return m88rs2000_readreg(state, 1, reg); ++} ++ ++static u8 m88rs2000_tuner_read(struct m88rs2000_state *state, u8 reg) ++{ ++ m88rs2000_demod_write(state, 0x81, 0x85); ++ udelay(10); ++ return m88rs2000_readreg(state, 0, reg); ++} ++ ++static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate) ++{ ++ struct m88rs2000_state *state = fe->demodulator_priv; ++ int ret; ++ u32 temp; ++ u8 b[3]; ++ ++ if ((srate < 1000000) || (srate > 45000000)) ++ return -EINVAL; ++ ++ temp = srate / 1000; ++ temp *= 11831; ++ temp /= 68; ++ temp -= 3; ++ ++ b[0] = (u8) (temp >> 16) & 0xff; ++ b[1] = (u8) (temp >> 8) & 0xff; ++ b[2] = (u8) temp & 0xff; ++ ret = m88rs2000_demod_write(state, 0x93, b[2]); ++ ret |= m88rs2000_demod_write(state, 0x94, b[1]); ++ ret |= m88rs2000_demod_write(state, 0x95, b[0]); ++ ++ deb_info("m88rs2000: m88rs2000_set_symbolrate\n"); ++ return ret; ++} ++ ++static int m88rs2000_send_diseqc_msg(struct dvb_frontend *fe, ++ struct dvb_diseqc_master_cmd *m) ++{ ++ struct m88rs2000_state *state = fe->demodulator_priv; ++ ++ int i; ++ u8 reg; ++ deb_info("%s\n", __func__); ++ m88rs2000_demod_write(state, 0x9a, 0x30); ++ reg = m88rs2000_demod_read(state, 0xb2); ++ reg &= 0x3f; ++ m88rs2000_demod_write(state, 0xb2, reg); ++ for (i = 0; i < m->msg_len; i++) ++ m88rs2000_demod_write(state, 0xb3 + i, m->msg[i]); ++ ++ reg = m88rs2000_demod_read(state, 0xb1); ++ reg &= 0x87; ++ reg |= ((m->msg_len - 1) << 3) | 0x07; ++ reg &= 0x7f; ++ m88rs2000_demod_write(state, 0xb1, reg); ++ ++ for (i = 0; i < 15; i++) { ++ if ((m88rs2000_demod_read(state, 0xb1) & 0x40) == 0x0) ++ break; ++ msleep(20); ++ } ++ ++ reg = m88rs2000_demod_read(state, 0xb1); ++ if ((reg & 0x40) > 0x0) { ++ reg &= 0x7f; ++ reg |= 0x40; ++ m88rs2000_demod_write(state, 0xb1, reg); ++ } ++ ++ reg = m88rs2000_demod_read(state, 0xb2); ++ reg &= 0x3f; ++ reg |= 0x80; ++ m88rs2000_demod_write(state, 0xb2, reg); ++ m88rs2000_demod_write(state, 0x9a, 0xb0); ++ ++ ++ return 0; ++} ++ ++static int m88rs2000_send_diseqc_burst(struct dvb_frontend *fe, ++ fe_sec_mini_cmd_t burst) ++{ ++ struct m88rs2000_state *state = fe->demodulator_priv; ++ u8 reg0, reg1; ++ deb_info("%s\n", __func__); ++ m88rs2000_demod_write(state, 0x9a, 0x30); ++ msleep(50); ++ reg0 = m88rs2000_demod_read(state, 0xb1); ++ reg1 = m88rs2000_demod_read(state, 0xb2); ++ /* TODO complete this section */ ++ m88rs2000_demod_write(state, 0xb2, reg1); ++ m88rs2000_demod_write(state, 0xb1, reg0); ++ m88rs2000_demod_write(state, 0x9a, 0xb0); ++ ++ return 0; ++} ++ ++static int m88rs2000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) ++{ ++ struct m88rs2000_state *state = fe->demodulator_priv; ++ u8 reg0, reg1; ++ m88rs2000_demod_write(state, 0x9a, 0x30); ++ reg0 = m88rs2000_demod_read(state, 0xb1); ++ reg1 = m88rs2000_demod_read(state, 0xb2); ++ ++ reg1 &= 0x3f; ++ ++ switch (tone) { ++ case SEC_TONE_ON: ++ reg0 |= 0x4; ++ reg0 &= 0xbc; ++ break; ++ case SEC_TONE_OFF: ++ reg1 |= 0x80; ++ break; ++ default: ++ break; ++ } ++ m88rs2000_demod_write(state, 0xb2, reg1); ++ m88rs2000_demod_write(state, 0xb1, reg0); ++ m88rs2000_demod_write(state, 0x9a, 0xb0); ++ return 0; ++} ++ ++struct inittab { ++ u8 cmd; ++ u8 reg; ++ u8 val; ++}; ++ ++struct inittab m88rs2000_setup[] = { ++ {DEMOD_WRITE, 0x9a, 0x30}, ++ {DEMOD_WRITE, 0x00, 0x01}, ++ {WRITE_DELAY, 0x19, 0x00}, ++ {DEMOD_WRITE, 0x00, 0x00}, ++ {DEMOD_WRITE, 0x9a, 0xb0}, ++ {DEMOD_WRITE, 0x81, 0xc1}, ++ {TUNER_WRITE, 0x42, 0x73}, ++ {TUNER_WRITE, 0x05, 0x07}, ++ {TUNER_WRITE, 0x20, 0x27}, ++ {TUNER_WRITE, 0x07, 0x02}, ++ {TUNER_WRITE, 0x11, 0xff}, ++ {TUNER_WRITE, 0x60, 0xf9}, ++ {TUNER_WRITE, 0x08, 0x01}, ++ {TUNER_WRITE, 0x00, 0x41}, ++ {DEMOD_WRITE, 0x81, 0x81}, ++ {DEMOD_WRITE, 0x86, 0xc6}, ++ {DEMOD_WRITE, 0x9a, 0x30}, ++ {DEMOD_WRITE, 0xf0, 0x22}, ++ {DEMOD_WRITE, 0xf1, 0xbf}, ++ {DEMOD_WRITE, 0xb0, 0x45}, ++ {DEMOD_WRITE, 0xb2, 0x01}, /* set voltage pin always set 1*/ ++ {DEMOD_WRITE, 0x9a, 0xb0}, ++ {0xff, 0xaa, 0xff} ++}; ++ ++struct inittab m88rs2000_shutdown[] = { ++ {DEMOD_WRITE, 0x9a, 0x30}, ++ {DEMOD_WRITE, 0xb0, 0x00}, ++ {DEMOD_WRITE, 0xf1, 0x89}, ++ {DEMOD_WRITE, 0x00, 0x01}, ++ {DEMOD_WRITE, 0x9a, 0xb0}, ++ {TUNER_WRITE, 0x00, 0x40}, ++ {DEMOD_WRITE, 0x81, 0x81}, ++ {0xff, 0xaa, 0xff} ++}; ++ ++struct inittab tuner_reset[] = { ++ {TUNER_WRITE, 0x42, 0x73}, ++ {TUNER_WRITE, 0x05, 0x07}, ++ {TUNER_WRITE, 0x20, 0x27}, ++ {TUNER_WRITE, 0x07, 0x02}, ++ {TUNER_WRITE, 0x11, 0xff}, ++ {TUNER_WRITE, 0x60, 0xf9}, ++ {TUNER_WRITE, 0x08, 0x01}, ++ {TUNER_WRITE, 0x00, 0x41}, ++ {0xff, 0xaa, 0xff} ++}; ++ ++struct inittab fe_reset[] = { ++ {DEMOD_WRITE, 0x00, 0x01}, ++ {DEMOD_WRITE, 0xf1, 0xbf}, ++ {DEMOD_WRITE, 0x00, 0x01}, ++ {DEMOD_WRITE, 0x20, 0x81}, ++ {DEMOD_WRITE, 0x21, 0x80}, ++ {DEMOD_WRITE, 0x10, 0x33}, ++ {DEMOD_WRITE, 0x11, 0x44}, ++ {DEMOD_WRITE, 0x12, 0x07}, ++ {DEMOD_WRITE, 0x18, 0x20}, ++ {DEMOD_WRITE, 0x28, 0x04}, ++ {DEMOD_WRITE, 0x29, 0x8e}, ++ {DEMOD_WRITE, 0x3b, 0xff}, ++ {DEMOD_WRITE, 0x32, 0x10}, ++ {DEMOD_WRITE, 0x33, 0x02}, ++ {DEMOD_WRITE, 0x34, 0x30}, ++ {DEMOD_WRITE, 0x35, 0xff}, ++ {DEMOD_WRITE, 0x38, 0x50}, ++ {DEMOD_WRITE, 0x39, 0x68}, ++ {DEMOD_WRITE, 0x3c, 0x7f}, ++ {DEMOD_WRITE, 0x3d, 0x0f}, ++ {DEMOD_WRITE, 0x45, 0x20}, ++ {DEMOD_WRITE, 0x46, 0x24}, ++ {DEMOD_WRITE, 0x47, 0x7c}, ++ {DEMOD_WRITE, 0x48, 0x16}, ++ {DEMOD_WRITE, 0x49, 0x04}, ++ {DEMOD_WRITE, 0x4a, 0x01}, ++ {DEMOD_WRITE, 0x4b, 0x78}, ++ {DEMOD_WRITE, 0X4d, 0xd2}, ++ {DEMOD_WRITE, 0x4e, 0x6d}, ++ {DEMOD_WRITE, 0x50, 0x30}, ++ {DEMOD_WRITE, 0x51, 0x30}, ++ {DEMOD_WRITE, 0x54, 0x7b}, ++ {DEMOD_WRITE, 0x56, 0x09}, ++ {DEMOD_WRITE, 0x58, 0x59}, ++ {DEMOD_WRITE, 0x59, 0x37}, ++ {DEMOD_WRITE, 0x63, 0xfa}, ++ {0xff, 0xaa, 0xff} ++}; ++ ++struct inittab fe_trigger[] = { ++ {DEMOD_WRITE, 0x97, 0x04}, ++ {DEMOD_WRITE, 0x99, 0x77}, ++ {DEMOD_WRITE, 0x9b, 0x64}, ++ {DEMOD_WRITE, 0x9e, 0x00}, ++ {DEMOD_WRITE, 0x9f, 0xf8}, ++ {DEMOD_WRITE, 0xa0, 0x20}, ++ {DEMOD_WRITE, 0xa1, 0xe0}, ++ {DEMOD_WRITE, 0xa3, 0x38}, ++ {DEMOD_WRITE, 0x98, 0xff}, ++ {DEMOD_WRITE, 0xc0, 0x0f}, ++ {DEMOD_WRITE, 0x89, 0x01}, ++ {DEMOD_WRITE, 0x00, 0x00}, ++ {WRITE_DELAY, 0x0a, 0x00}, ++ {DEMOD_WRITE, 0x00, 0x01}, ++ {DEMOD_WRITE, 0x00, 0x00}, ++ {DEMOD_WRITE, 0x9a, 0xb0}, ++ {0xff, 0xaa, 0xff} ++}; ++ ++static int m88rs2000_tab_set(struct m88rs2000_state *state, ++ struct inittab *tab) ++{ ++ int ret = 0; ++ u8 i; ++ if (tab == NULL) ++ return -EINVAL; ++ ++ for (i = 0; i < 255; i++) { ++ switch (tab[i].cmd) { ++ case 0x01: ++ ret = m88rs2000_demod_write(state, tab[i].reg, ++ tab[i].val); ++ break; ++ case 0x02: ++ ret = m88rs2000_tuner_write(state, tab[i].reg, ++ tab[i].val); ++ break; ++ case 0x10: ++ if (tab[i].reg > 0) ++ mdelay(tab[i].reg); ++ break; ++ case 0xff: ++ if (tab[i].reg == 0xaa && tab[i].val == 0xff) ++ return 0; ++ case 0x00: ++ break; ++ default: ++ return -EINVAL; ++ } ++ if (ret < 0) ++ return -ENODEV; ++ } ++ return 0; ++} ++ ++static int m88rs2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) ++{ ++ deb_info("%s: %s\n", __func__, ++ volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : ++ volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); ++ ++ return 0; ++} ++ ++static int m88rs2000_startup(struct m88rs2000_state *state) ++{ ++ int ret = 0; ++ u8 reg; ++ ++ reg = m88rs2000_tuner_read(state, 0x00); ++ if ((reg & 0x40) == 0) ++ ret = -ENODEV; ++ ++ return ret; ++} ++ ++static int m88rs2000_init(struct dvb_frontend *fe) ++{ ++ struct m88rs2000_state *state = fe->demodulator_priv; ++ int ret; ++ ++ deb_info("m88rs2000: init chip\n"); ++ /* Setup frontend from shutdown/cold */ ++ ret = m88rs2000_tab_set(state, m88rs2000_setup); ++ ++ return ret; ++} ++ ++static int m88rs2000_sleep(struct dvb_frontend *fe) ++{ ++ struct m88rs2000_state *state = fe->demodulator_priv; ++ int ret; ++ /* Shutdown the frondend */ ++ ret = m88rs2000_tab_set(state, m88rs2000_shutdown); ++ return ret; ++} ++ ++static int m88rs2000_read_status(struct dvb_frontend *fe, fe_status_t *status) ++{ ++ struct m88rs2000_state *state = fe->demodulator_priv; ++ u8 reg = m88rs2000_demod_read(state, 0x8c); ++ ++ *status = 0; ++ ++ if ((reg & 0x7) == 0x7) { ++ *status = FE_HAS_CARRIER | FE_HAS_SIGNAL | FE_HAS_VITERBI ++ | FE_HAS_LOCK; ++ if (state->config->set_ts_params) ++ state->config->set_ts_params(fe, CALL_IS_READ); ++ } ++ return 0; ++} ++ ++/* Extact code for these unknown but lmedm04 driver uses interupt callbacks */ ++ ++static int m88rs2000_read_ber(struct dvb_frontend *fe, u32 *ber) ++{ ++ deb_info("m88rs2000_read_ber %d\n", *ber); ++ *ber = 0; ++ return 0; ++} ++ ++static int m88rs2000_read_signal_strength(struct dvb_frontend *fe, ++ u16 *strength) ++{ ++ *strength = 0; ++ return 0; ++} ++ ++static int m88rs2000_read_snr(struct dvb_frontend *fe, u16 *snr) ++{ ++ deb_info("m88rs2000_read_snr %d\n", *snr); ++ *snr = 0; ++ return 0; ++} ++ ++static int m88rs2000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) ++{ ++ deb_info("m88rs2000_read_ber %d\n", *ucblocks); ++ *ucblocks = 0; ++ return 0; ++} ++ ++static int m88rs2000_tuner_gate_ctrl(struct m88rs2000_state *state, u8 offset) ++{ ++ int ret; ++ ret = m88rs2000_tuner_write(state, 0x51, 0x1f - offset); ++ ret |= m88rs2000_tuner_write(state, 0x51, 0x1f); ++ ret |= m88rs2000_tuner_write(state, 0x50, offset); ++ ret |= m88rs2000_tuner_write(state, 0x50, 0x00); ++ msleep(20); ++ return ret; ++} ++ ++static int m88rs2000_set_tuner_rf(struct dvb_frontend *fe) ++{ ++ struct m88rs2000_state *state = fe->demodulator_priv; ++ int reg; ++ reg = m88rs2000_tuner_read(state, 0x3d); ++ reg &= 0x7f; ++ if (reg < 0x16) ++ reg = 0xa1; ++ else if (reg == 0x16) ++ reg = 0x99; ++ else ++ reg = 0xf9; ++ ++ m88rs2000_tuner_write(state, 0x60, reg); ++ reg = m88rs2000_tuner_gate_ctrl(state, 0x08); ++ ++ if (fe->ops.i2c_gate_ctrl) ++ fe->ops.i2c_gate_ctrl(fe, 0); ++ return reg; ++} ++ ++static int m88rs2000_set_tuner(struct dvb_frontend *fe, u16 *offset) ++{ ++ struct dtv_frontend_properties *c = &fe->dtv_property_cache; ++ struct m88rs2000_state *state = fe->demodulator_priv; ++ int ret; ++ u32 frequency = c->frequency; ++ s32 offset_khz; ++ s32 tmp; ++ u32 symbol_rate = (c->symbol_rate / 1000); ++ u32 f3db, gdiv28; ++ u16 value, ndiv, lpf_coeff; ++ u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf; ++ u8 lo = 0x01, div4 = 0x0; ++ ++ /* Reset Tuner */ ++ ret = m88rs2000_tab_set(state, tuner_reset); ++ ++ /* Calculate frequency divider */ ++ if (frequency < 1060000) { ++ lo |= 0x10; ++ div4 = 0x1; ++ ndiv = (frequency * 14 * 4) / FE_CRYSTAL_KHZ; ++ } else ++ ndiv = (frequency * 14 * 2) / FE_CRYSTAL_KHZ; ++ ndiv = ndiv + ndiv % 2; ++ ndiv = ndiv - 1024; ++ ++ ret = m88rs2000_tuner_write(state, 0x10, 0x80 | lo); ++ ++ /* Set frequency divider */ ++ ret |= m88rs2000_tuner_write(state, 0x01, (ndiv >> 8) & 0xf); ++ ret |= m88rs2000_tuner_write(state, 0x02, ndiv & 0xff); ++ ++ ret |= m88rs2000_tuner_write(state, 0x03, 0x06); ++ ret |= m88rs2000_tuner_gate_ctrl(state, 0x10); ++ if (ret < 0) ++ return -ENODEV; ++ ++ /* Tuner Frequency Range */ ++ ret = m88rs2000_tuner_write(state, 0x10, lo); ++ ++ ret |= m88rs2000_tuner_gate_ctrl(state, 0x08); ++ ++ /* Tuner RF */ ++ ret |= m88rs2000_set_tuner_rf(fe); ++ ++ gdiv28 = (FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000; ++ ret |= m88rs2000_tuner_write(state, 0x04, gdiv28 & 0xff); ++ ret |= m88rs2000_tuner_gate_ctrl(state, 0x04); ++ if (ret < 0) ++ return -ENODEV; ++ ++ value = m88rs2000_tuner_read(state, 0x26); ++ ++ f3db = (symbol_rate * 135) / 200 + 2000; ++ f3db += FREQ_OFFSET_LOW_SYM_RATE; ++ if (f3db < 7000) ++ f3db = 7000; ++ if (f3db > 40000) ++ f3db = 40000; ++ ++ gdiv28 = gdiv28 * 207 / (value * 2 + 151); ++ mlpf_max = gdiv28 * 135 / 100; ++ mlpf_min = gdiv28 * 78 / 100; ++ if (mlpf_max > 63) ++ mlpf_max = 63; ++ ++ lpf_coeff = 2766; ++ ++ nlpf = (f3db * gdiv28 * 2 / lpf_coeff / ++ (FE_CRYSTAL_KHZ / 1000) + 1) / 2; ++ if (nlpf > 23) ++ nlpf = 23; ++ if (nlpf < 1) ++ nlpf = 1; ++ ++ lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000) ++ * lpf_coeff * 2 / f3db + 1) / 2; ++ ++ if (lpf_mxdiv < mlpf_min) { ++ nlpf++; ++ lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000) ++ * lpf_coeff * 2 / f3db + 1) / 2; ++ } ++ ++ if (lpf_mxdiv > mlpf_max) ++ lpf_mxdiv = mlpf_max; ++ ++ ret = m88rs2000_tuner_write(state, 0x04, lpf_mxdiv); ++ ret |= m88rs2000_tuner_write(state, 0x06, nlpf); ++ ++ ret |= m88rs2000_tuner_gate_ctrl(state, 0x04); ++ ++ ret |= m88rs2000_tuner_gate_ctrl(state, 0x01); ++ ++ msleep(80); ++ /* calculate offset assuming 96000kHz*/ ++ offset_khz = (ndiv - ndiv % 2 + 1024) * FE_CRYSTAL_KHZ ++ / 14 / (div4 + 1) / 2; ++ ++ offset_khz -= frequency; ++ ++ tmp = offset_khz; ++ tmp *= 65536; ++ ++ tmp = (2 * tmp + 96000) / (2 * 96000); ++ if (tmp < 0) ++ tmp += 65536; ++ ++ *offset = tmp & 0xffff; ++ ++ if (fe->ops.i2c_gate_ctrl) ++ fe->ops.i2c_gate_ctrl(fe, 0); ++ ++ return (ret < 0) ? -EINVAL : 0; ++} ++ ++static int m88rs2000_set_fec(struct m88rs2000_state *state, ++ fe_code_rate_t fec) ++{ ++ int ret; ++ u16 fec_set; ++ switch (fec) { ++ /* This is not confirmed kept for reference */ ++/* case FEC_1_2: ++ fec_set = 0x88; ++ break; ++ case FEC_2_3: ++ fec_set = 0x68; ++ break; ++ case FEC_3_4: ++ fec_set = 0x48; ++ break; ++ case FEC_5_6: ++ fec_set = 0x28; ++ break; ++ case FEC_7_8: ++ fec_set = 0x18; ++ break; */ ++ case FEC_AUTO: ++ default: ++ fec_set = 0x08; ++ } ++ ret = m88rs2000_demod_write(state, 0x76, fec_set); ++ ++ return 0; ++} ++ ++ ++static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state) ++{ ++ u8 reg; ++ m88rs2000_demod_write(state, 0x9a, 0x30); ++ reg = m88rs2000_demod_read(state, 0x76); ++ m88rs2000_demod_write(state, 0x9a, 0xb0); ++ ++ switch (reg) { ++ case 0x88: ++ return FEC_1_2; ++ case 0x68: ++ return FEC_2_3; ++ case 0x48: ++ return FEC_3_4; ++ case 0x28: ++ return FEC_5_6; ++ case 0x18: ++ return FEC_7_8; ++ case 0x08: ++ default: ++ break; ++ } ++ ++ return FEC_AUTO; ++} ++ ++static int m88rs2000_set_frontend(struct dvb_frontend *fe) ++{ ++ struct m88rs2000_state *state = fe->demodulator_priv; ++ struct dtv_frontend_properties *c = &fe->dtv_property_cache; ++ fe_status_t status; ++ int i, ret; ++ u16 offset = 0; ++ u8 reg; ++ ++ state->no_lock_count = 0; ++ ++ if (c->delivery_system != SYS_DVBS) { ++ deb_info("%s: unsupported delivery " ++ "system selected (%d)\n", ++ __func__, c->delivery_system); ++ return -EOPNOTSUPP; ++ } ++ ++ /* Set Tuner */ ++ ret = m88rs2000_set_tuner(fe, &offset); ++ if (ret < 0) ++ return -ENODEV; ++ ++ ret = m88rs2000_demod_write(state, 0x9a, 0x30); ++ /* Unknown usually 0xc6 sometimes 0xc1 */ ++ reg = m88rs2000_demod_read(state, 0x86); ++ ret |= m88rs2000_demod_write(state, 0x86, reg); ++ /* Offset lower nibble always 0 */ ++ ret |= m88rs2000_demod_write(state, 0x9c, (offset >> 8)); ++ ret |= m88rs2000_demod_write(state, 0x9d, offset & 0xf0); ++ ++ ++ /* Reset Demod */ ++ ret = m88rs2000_tab_set(state, fe_reset); ++ if (ret < 0) ++ return -ENODEV; ++ ++ /* Unknown */ ++ reg = m88rs2000_demod_read(state, 0x70); ++ ret = m88rs2000_demod_write(state, 0x70, reg); ++ ++ /* Set FEC */ ++ ret |= m88rs2000_set_fec(state, c->fec_inner); ++ ret |= m88rs2000_demod_write(state, 0x85, 0x1); ++ ret |= m88rs2000_demod_write(state, 0x8a, 0xbf); ++ ret |= m88rs2000_demod_write(state, 0x8d, 0x1e); ++ ret |= m88rs2000_demod_write(state, 0x90, 0xf1); ++ ret |= m88rs2000_demod_write(state, 0x91, 0x08); ++ ++ if (ret < 0) ++ return -ENODEV; ++ ++ /* Set Symbol Rate */ ++ ret = m88rs2000_set_symbolrate(fe, c->symbol_rate); ++ if (ret < 0) ++ return -ENODEV; ++ ++ /* Set up Demod */ ++ ret = m88rs2000_tab_set(state, fe_trigger); ++ if (ret < 0) ++ return -ENODEV; ++ ++ for (i = 0; i < 25; i++) { ++ u8 reg = m88rs2000_demod_read(state, 0x8c); ++ if ((reg & 0x7) == 0x7) { ++ status = FE_HAS_LOCK; ++ break; ++ } ++ state->no_lock_count++; ++ if (state->no_lock_count > 15) { ++ reg = m88rs2000_demod_read(state, 0x70); ++ reg ^= 0x4; ++ m88rs2000_demod_write(state, 0x70, reg); ++ state->no_lock_count = 0; ++ } ++ if (state->no_lock_count == 20) ++ m88rs2000_set_tuner_rf(fe); ++ msleep(20); ++ } ++ ++ if (status & FE_HAS_LOCK) { ++ state->fec_inner = m88rs2000_get_fec(state); ++ /* Uknown suspect SNR level */ ++ reg = m88rs2000_demod_read(state, 0x65); ++ } ++ ++ state->tuner_frequency = c->frequency; ++ state->symbol_rate = c->symbol_rate; ++ return 0; ++} ++ ++static int m88rs2000_get_frontend(struct dvb_frontend *fe) ++{ ++ struct dtv_frontend_properties *c = &fe->dtv_property_cache; ++ struct m88rs2000_state *state = fe->demodulator_priv; ++ c->fec_inner = state->fec_inner; ++ c->frequency = state->tuner_frequency; ++ c->symbol_rate = state->symbol_rate; ++ return 0; ++} ++ ++static int m88rs2000_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) ++{ ++ struct m88rs2000_state *state = fe->demodulator_priv; ++ ++ if (enable) ++ m88rs2000_demod_write(state, 0x81, 0x84); ++ else ++ m88rs2000_demod_write(state, 0x81, 0x81); ++ udelay(10); ++ return 0; ++} ++ ++static void m88rs2000_release(struct dvb_frontend *fe) ++{ ++ struct m88rs2000_state *state = fe->demodulator_priv; ++ kfree(state); ++} ++ ++static struct dvb_frontend_ops m88rs2000_ops = { ++ .delsys = { SYS_DVBS }, ++ .info = { ++ .name = "M88RS2000 DVB-S", ++ .frequency_min = 950000, ++ .frequency_max = 2150000, ++ .frequency_stepsize = 1000, /* kHz for QPSK frontends */ ++ .frequency_tolerance = 5000, ++ .symbol_rate_min = 1000000, ++ .symbol_rate_max = 45000000, ++ .symbol_rate_tolerance = 500, /* ppm */ ++ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | ++ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | ++ FE_CAN_QPSK | ++ FE_CAN_FEC_AUTO ++ }, ++ ++ .release = m88rs2000_release, ++ .init = m88rs2000_init, ++ .sleep = m88rs2000_sleep, ++ .write = m88rs2000_write, ++ .i2c_gate_ctrl = m88rs2000_i2c_gate_ctrl, ++ .read_status = m88rs2000_read_status, ++ .read_ber = m88rs2000_read_ber, ++ .read_signal_strength = m88rs2000_read_signal_strength, ++ .read_snr = m88rs2000_read_snr, ++ .read_ucblocks = m88rs2000_read_ucblocks, ++ .diseqc_send_master_cmd = m88rs2000_send_diseqc_msg, ++ .diseqc_send_burst = m88rs2000_send_diseqc_burst, ++ .set_tone = m88rs2000_set_tone, ++ .set_voltage = m88rs2000_set_voltage, ++ ++ .set_frontend = m88rs2000_set_frontend, ++ .get_frontend = m88rs2000_get_frontend, ++}; ++ ++struct dvb_frontend *m88rs2000_attach(const struct m88rs2000_config *config, ++ struct i2c_adapter *i2c) ++{ ++ struct m88rs2000_state *state = NULL; ++ ++ /* allocate memory for the internal state */ ++ state = kzalloc(sizeof(struct m88rs2000_state), GFP_KERNEL); ++ if (state == NULL) ++ goto error; ++ ++ /* setup the state */ ++ state->config = config; ++ state->i2c = i2c; ++ state->tuner_frequency = 0; ++ state->symbol_rate = 0; ++ state->fec_inner = 0; ++ ++ if (m88rs2000_startup(state) < 0) ++ goto error; ++ ++ /* create dvb_frontend */ ++ memcpy(&state->frontend.ops, &m88rs2000_ops, ++ sizeof(struct dvb_frontend_ops)); ++ state->frontend.demodulator_priv = state; ++ return &state->frontend; ++ ++error: ++ kfree(state); ++ ++ return NULL; ++} ++EXPORT_SYMBOL(m88rs2000_attach); ++ ++MODULE_DESCRIPTION("M88RS2000 DVB-S Demodulator driver"); ++MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION("1.13"); ++ +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/m88rs2000.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/m88rs2000.h +@@ -0,0 +1,66 @@ ++/* ++ Driver for M88RS2000 demodulator ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ ++*/ ++ ++#ifndef M88RS2000_H ++#define M88RS2000_H ++ ++#include ++#include "dvb_frontend.h" ++ ++struct m88rs2000_config { ++ /* Demodulator i2c address */ ++ u8 demod_addr; ++ /* Tuner address */ ++ u8 tuner_addr; ++ ++ u8 *inittab; ++ ++ /* minimum delay before retuning */ ++ int min_delay_ms; ++ ++ int (*set_ts_params)(struct dvb_frontend *, int); ++}; ++ ++enum { ++ CALL_IS_SET_FRONTEND = 0x0, ++ CALL_IS_READ, ++}; ++ ++#if defined(CONFIG_DVB_M88RS2000) || (defined(CONFIG_DVB_M88RS2000_MODULE) && \ ++ defined(MODULE)) ++extern struct dvb_frontend *m88rs2000_attach( ++ const struct m88rs2000_config *config, struct i2c_adapter *i2c); ++#else ++static inline struct dvb_frontend *m88rs2000_attach( ++ const struct m88rs2000_config *config, struct i2c_adapter *i2c) ++{ ++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); ++ return NULL; ++} ++#endif /* CONFIG_DVB_M88RS2000 */ ++ ++#define FE_CRYSTAL_KHZ 27000 ++#define FREQ_OFFSET_LOW_SYM_RATE 3000 ++ ++enum { ++ DEMOD_WRITE = 0x1, ++ TUNER_WRITE, ++ WRITE_DELAY = 0x10, ++}; ++#endif /* M88RS2000_H */ +Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/lmedm04.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/lmedm04.h ++++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/lmedm04.h +@@ -41,6 +41,7 @@ + #define LME_ST_ON_W {0x06, 0x00} + #define LME_CLEAR_PID {0x03, 0x02, 0x20, 0xa0} + #define LME_ZERO_PID {0x03, 0x06, 0x00, 0x00, 0x01, 0x00, 0x20, 0x9c} ++#define LME_ALL_PIDS {0x03, 0x06, 0x00, 0xff, 0x01, 0x1f, 0x20, 0x81} + + /* LNB Voltage + * 07 XX XX +Index: linux-3.3.x86_64/drivers/media/video/adv7183.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/video/adv7183.c +@@ -0,0 +1,699 @@ ++/* ++ * adv7183.c Analog Devices ADV7183 video decoder driver ++ * ++ * Copyright (c) 2011 Analog Devices Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "adv7183_regs.h" ++ ++struct adv7183 { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ ++ v4l2_std_id std; /* Current set standard */ ++ u32 input; ++ u32 output; ++ unsigned reset_pin; ++ unsigned oe_pin; ++ struct v4l2_mbus_framefmt fmt; ++}; ++ ++/* EXAMPLES USING 27 MHz CLOCK ++ * Mode 1 CVBS Input (Composite Video on AIN5) ++ * All standards are supported through autodetect, 8-bit, 4:2:2, ITU-R BT.656 output on P15 to P8. ++ */ ++static const unsigned char adv7183_init_regs[] = { ++ ADV7183_IN_CTRL, 0x04, /* CVBS input on AIN5 */ ++ ADV7183_DIGI_CLAMP_CTRL_1, 0x00, /* Slow down digital clamps */ ++ ADV7183_SHAP_FILT_CTRL, 0x41, /* Set CSFM to SH1 */ ++ ADV7183_ADC_CTRL, 0x16, /* Power down ADC 1 and ADC 2 */ ++ ADV7183_CTI_DNR_CTRL_4, 0x04, /* Set DNR threshold to 4 for flat response */ ++ /* ADI recommended programming sequence */ ++ ADV7183_ADI_CTRL, 0x80, ++ ADV7183_CTI_DNR_CTRL_4, 0x20, ++ 0x52, 0x18, ++ 0x58, 0xED, ++ 0x77, 0xC5, ++ 0x7C, 0x93, ++ 0x7D, 0x00, ++ 0xD0, 0x48, ++ 0xD5, 0xA0, ++ 0xD7, 0xEA, ++ ADV7183_SD_SATURATION_CR, 0x3E, ++ ADV7183_PAL_V_END, 0x3E, ++ ADV7183_PAL_F_TOGGLE, 0x0F, ++ ADV7183_ADI_CTRL, 0x00, ++}; ++ ++static inline struct adv7183 *to_adv7183(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct adv7183, sd); ++} ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct adv7183, hdl)->sd; ++} ++ ++static inline int adv7183_read(struct v4l2_subdev *sd, unsigned char reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ return i2c_smbus_read_byte_data(client, reg); ++} ++ ++static inline int adv7183_write(struct v4l2_subdev *sd, unsigned char reg, ++ unsigned char value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ return i2c_smbus_write_byte_data(client, reg, value); ++} ++ ++static int adv7183_writeregs(struct v4l2_subdev *sd, ++ const unsigned char *regs, unsigned int num) ++{ ++ unsigned char reg, data; ++ unsigned int cnt = 0; ++ ++ if (num & 0x1) { ++ v4l2_err(sd, "invalid regs array\n"); ++ return -1; ++ } ++ ++ while (cnt < num) { ++ reg = *regs++; ++ data = *regs++; ++ cnt += 2; ++ ++ adv7183_write(sd, reg, data); ++ } ++ return 0; ++} ++ ++static int adv7183_log_status(struct v4l2_subdev *sd) ++{ ++ struct adv7183 *decoder = to_adv7183(sd); ++ ++ v4l2_info(sd, "adv7183: Input control = 0x%02x\n", ++ adv7183_read(sd, ADV7183_IN_CTRL)); ++ v4l2_info(sd, "adv7183: Video selection = 0x%02x\n", ++ adv7183_read(sd, ADV7183_VD_SEL)); ++ v4l2_info(sd, "adv7183: Output control = 0x%02x\n", ++ adv7183_read(sd, ADV7183_OUT_CTRL)); ++ v4l2_info(sd, "adv7183: Extended output control = 0x%02x\n", ++ adv7183_read(sd, ADV7183_EXT_OUT_CTRL)); ++ v4l2_info(sd, "adv7183: Autodetect enable = 0x%02x\n", ++ adv7183_read(sd, ADV7183_AUTO_DET_EN)); ++ v4l2_info(sd, "adv7183: Contrast = 0x%02x\n", ++ adv7183_read(sd, ADV7183_CONTRAST)); ++ v4l2_info(sd, "adv7183: Brightness = 0x%02x\n", ++ adv7183_read(sd, ADV7183_BRIGHTNESS)); ++ v4l2_info(sd, "adv7183: Hue = 0x%02x\n", ++ adv7183_read(sd, ADV7183_HUE)); ++ v4l2_info(sd, "adv7183: Default value Y = 0x%02x\n", ++ adv7183_read(sd, ADV7183_DEF_Y)); ++ v4l2_info(sd, "adv7183: Default value C = 0x%02x\n", ++ adv7183_read(sd, ADV7183_DEF_C)); ++ v4l2_info(sd, "adv7183: ADI control = 0x%02x\n", ++ adv7183_read(sd, ADV7183_ADI_CTRL)); ++ v4l2_info(sd, "adv7183: Power Management = 0x%02x\n", ++ adv7183_read(sd, ADV7183_POW_MANAGE)); ++ v4l2_info(sd, "adv7183: Status 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n", ++ adv7183_read(sd, ADV7183_STATUS_1), ++ adv7183_read(sd, ADV7183_STATUS_2), ++ adv7183_read(sd, ADV7183_STATUS_3)); ++ v4l2_info(sd, "adv7183: Ident = 0x%02x\n", ++ adv7183_read(sd, ADV7183_IDENT)); ++ v4l2_info(sd, "adv7183: Analog clamp control = 0x%02x\n", ++ adv7183_read(sd, ADV7183_ANAL_CLAMP_CTRL)); ++ v4l2_info(sd, "adv7183: Digital clamp control 1 = 0x%02x\n", ++ adv7183_read(sd, ADV7183_DIGI_CLAMP_CTRL_1)); ++ v4l2_info(sd, "adv7183: Shaping filter control 1 and 2 = 0x%02x 0x%02x\n", ++ adv7183_read(sd, ADV7183_SHAP_FILT_CTRL), ++ adv7183_read(sd, ADV7183_SHAP_FILT_CTRL_2)); ++ v4l2_info(sd, "adv7183: Comb filter control = 0x%02x\n", ++ adv7183_read(sd, ADV7183_COMB_FILT_CTRL)); ++ v4l2_info(sd, "adv7183: ADI control 2 = 0x%02x\n", ++ adv7183_read(sd, ADV7183_ADI_CTRL_2)); ++ v4l2_info(sd, "adv7183: Pixel delay control = 0x%02x\n", ++ adv7183_read(sd, ADV7183_PIX_DELAY_CTRL)); ++ v4l2_info(sd, "adv7183: Misc gain control = 0x%02x\n", ++ adv7183_read(sd, ADV7183_MISC_GAIN_CTRL)); ++ v4l2_info(sd, "adv7183: AGC mode control = 0x%02x\n", ++ adv7183_read(sd, ADV7183_AGC_MODE_CTRL)); ++ v4l2_info(sd, "adv7183: Chroma gain control 1 and 2 = 0x%02x 0x%02x\n", ++ adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_1), ++ adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_2)); ++ v4l2_info(sd, "adv7183: Luma gain control 1 and 2 = 0x%02x 0x%02x\n", ++ adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_1), ++ adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_2)); ++ v4l2_info(sd, "adv7183: Vsync field control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n", ++ adv7183_read(sd, ADV7183_VS_FIELD_CTRL_1), ++ adv7183_read(sd, ADV7183_VS_FIELD_CTRL_2), ++ adv7183_read(sd, ADV7183_VS_FIELD_CTRL_3)); ++ v4l2_info(sd, "adv7183: Hsync positon control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n", ++ adv7183_read(sd, ADV7183_HS_POS_CTRL_1), ++ adv7183_read(sd, ADV7183_HS_POS_CTRL_2), ++ adv7183_read(sd, ADV7183_HS_POS_CTRL_3)); ++ v4l2_info(sd, "adv7183: Polarity = 0x%02x\n", ++ adv7183_read(sd, ADV7183_POLARITY)); ++ v4l2_info(sd, "adv7183: ADC control = 0x%02x\n", ++ adv7183_read(sd, ADV7183_ADC_CTRL)); ++ v4l2_info(sd, "adv7183: SD offset Cb and Cr = 0x%02x 0x%02x\n", ++ adv7183_read(sd, ADV7183_SD_OFFSET_CB), ++ adv7183_read(sd, ADV7183_SD_OFFSET_CR)); ++ v4l2_info(sd, "adv7183: SD saturation Cb and Cr = 0x%02x 0x%02x\n", ++ adv7183_read(sd, ADV7183_SD_SATURATION_CB), ++ adv7183_read(sd, ADV7183_SD_SATURATION_CR)); ++ v4l2_info(sd, "adv7183: Drive strength = 0x%02x\n", ++ adv7183_read(sd, ADV7183_DRIVE_STR)); ++ v4l2_ctrl_handler_log_status(&decoder->hdl, sd->name); ++ return 0; ++} ++ ++static int adv7183_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) ++{ ++ struct adv7183 *decoder = to_adv7183(sd); ++ ++ *std = decoder->std; ++ return 0; ++} ++ ++static int adv7183_s_std(struct v4l2_subdev *sd, v4l2_std_id std) ++{ ++ struct adv7183 *decoder = to_adv7183(sd); ++ int reg; ++ ++ reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF; ++ if (std == V4L2_STD_PAL_60) ++ reg |= 0x60; ++ else if (std == V4L2_STD_NTSC_443) ++ reg |= 0x70; ++ else if (std == V4L2_STD_PAL_N) ++ reg |= 0x90; ++ else if (std == V4L2_STD_PAL_M) ++ reg |= 0xA0; ++ else if (std == V4L2_STD_PAL_Nc) ++ reg |= 0xC0; ++ else if (std & V4L2_STD_PAL) ++ reg |= 0x80; ++ else if (std & V4L2_STD_NTSC) ++ reg |= 0x50; ++ else if (std & V4L2_STD_SECAM) ++ reg |= 0xE0; ++ else ++ return -EINVAL; ++ adv7183_write(sd, ADV7183_IN_CTRL, reg); ++ ++ decoder->std = std; ++ ++ return 0; ++} ++ ++static int adv7183_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ int reg; ++ ++ reg = adv7183_read(sd, ADV7183_POW_MANAGE) | 0x80; ++ adv7183_write(sd, ADV7183_POW_MANAGE, reg); ++ /* wait 5ms before any further i2c writes are performed */ ++ usleep_range(5000, 10000); ++ return 0; ++} ++ ++static int adv7183_s_routing(struct v4l2_subdev *sd, ++ u32 input, u32 output, u32 config) ++{ ++ struct adv7183 *decoder = to_adv7183(sd); ++ int reg; ++ ++ if ((input > ADV7183_COMPONENT1) || (output > ADV7183_16BIT_OUT)) ++ return -EINVAL; ++ ++ if (input != decoder->input) { ++ decoder->input = input; ++ reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF0; ++ switch (input) { ++ case ADV7183_COMPOSITE1: ++ reg |= 0x1; ++ break; ++ case ADV7183_COMPOSITE2: ++ reg |= 0x2; ++ break; ++ case ADV7183_COMPOSITE3: ++ reg |= 0x3; ++ break; ++ case ADV7183_COMPOSITE4: ++ reg |= 0x4; ++ break; ++ case ADV7183_COMPOSITE5: ++ reg |= 0x5; ++ break; ++ case ADV7183_COMPOSITE6: ++ reg |= 0xB; ++ break; ++ case ADV7183_COMPOSITE7: ++ reg |= 0xC; ++ break; ++ case ADV7183_COMPOSITE8: ++ reg |= 0xD; ++ break; ++ case ADV7183_COMPOSITE9: ++ reg |= 0xE; ++ break; ++ case ADV7183_COMPOSITE10: ++ reg |= 0xF; ++ break; ++ case ADV7183_SVIDEO0: ++ reg |= 0x6; ++ break; ++ case ADV7183_SVIDEO1: ++ reg |= 0x7; ++ break; ++ case ADV7183_SVIDEO2: ++ reg |= 0x8; ++ break; ++ case ADV7183_COMPONENT0: ++ reg |= 0x9; ++ break; ++ case ADV7183_COMPONENT1: ++ reg |= 0xA; ++ break; ++ default: ++ break; ++ } ++ adv7183_write(sd, ADV7183_IN_CTRL, reg); ++ } ++ ++ if (output != decoder->output) { ++ decoder->output = output; ++ reg = adv7183_read(sd, ADV7183_OUT_CTRL) & 0xC0; ++ switch (output) { ++ case ADV7183_16BIT_OUT: ++ reg |= 0x9; ++ break; ++ default: ++ reg |= 0xC; ++ break; ++ } ++ adv7183_write(sd, ADV7183_OUT_CTRL, reg); ++ } ++ ++ return 0; ++} ++ ++static int adv7183_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ int val = ctrl->val; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ if (val < 0) ++ val = 127 - val; ++ adv7183_write(sd, ADV7183_BRIGHTNESS, val); ++ break; ++ case V4L2_CID_CONTRAST: ++ adv7183_write(sd, ADV7183_CONTRAST, val); ++ break; ++ case V4L2_CID_SATURATION: ++ adv7183_write(sd, ADV7183_SD_SATURATION_CB, val >> 8); ++ adv7183_write(sd, ADV7183_SD_SATURATION_CR, (val & 0xFF)); ++ break; ++ case V4L2_CID_HUE: ++ adv7183_write(sd, ADV7183_SD_OFFSET_CB, val >> 8); ++ adv7183_write(sd, ADV7183_SD_OFFSET_CR, (val & 0xFF)); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int adv7183_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) ++{ ++ struct adv7183 *decoder = to_adv7183(sd); ++ int reg; ++ ++ /* enable autodetection block */ ++ reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF; ++ adv7183_write(sd, ADV7183_IN_CTRL, reg); ++ ++ /* wait autodetection switch */ ++ mdelay(10); ++ ++ /* get autodetection result */ ++ reg = adv7183_read(sd, ADV7183_STATUS_1); ++ switch ((reg >> 0x4) & 0x7) { ++ case 0: ++ *std = V4L2_STD_NTSC; ++ break; ++ case 1: ++ *std = V4L2_STD_NTSC_443; ++ break; ++ case 2: ++ *std = V4L2_STD_PAL_M; ++ break; ++ case 3: ++ *std = V4L2_STD_PAL_60; ++ break; ++ case 4: ++ *std = V4L2_STD_PAL; ++ break; ++ case 5: ++ *std = V4L2_STD_SECAM; ++ break; ++ case 6: ++ *std = V4L2_STD_PAL_Nc; ++ break; ++ case 7: ++ *std = V4L2_STD_SECAM; ++ break; ++ default: ++ *std = V4L2_STD_UNKNOWN; ++ break; ++ } ++ ++ /* after std detection, write back user set std */ ++ adv7183_s_std(sd, decoder->std); ++ return 0; ++} ++ ++static int adv7183_g_input_status(struct v4l2_subdev *sd, u32 *status) ++{ ++ int reg; ++ ++ *status = V4L2_IN_ST_NO_SIGNAL; ++ reg = adv7183_read(sd, ADV7183_STATUS_1); ++ if (reg < 0) ++ return reg; ++ if (reg & 0x1) ++ *status = 0; ++ return 0; ++} ++ ++static int adv7183_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, ++ enum v4l2_mbus_pixelcode *code) ++{ ++ if (index > 0) ++ return -EINVAL; ++ ++ *code = V4L2_MBUS_FMT_UYVY8_2X8; ++ return 0; ++} ++ ++static int adv7183_try_mbus_fmt(struct v4l2_subdev *sd, ++ struct v4l2_mbus_framefmt *fmt) ++{ ++ struct adv7183 *decoder = to_adv7183(sd); ++ ++ fmt->code = V4L2_MBUS_FMT_UYVY8_2X8; ++ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ if (decoder->std & V4L2_STD_525_60) { ++ fmt->field = V4L2_FIELD_SEQ_TB; ++ fmt->width = 720; ++ fmt->height = 480; ++ } else { ++ fmt->field = V4L2_FIELD_SEQ_BT; ++ fmt->width = 720; ++ fmt->height = 576; ++ } ++ return 0; ++} ++ ++static int adv7183_s_mbus_fmt(struct v4l2_subdev *sd, ++ struct v4l2_mbus_framefmt *fmt) ++{ ++ struct adv7183 *decoder = to_adv7183(sd); ++ ++ adv7183_try_mbus_fmt(sd, fmt); ++ decoder->fmt = *fmt; ++ return 0; ++} ++ ++static int adv7183_g_mbus_fmt(struct v4l2_subdev *sd, ++ struct v4l2_mbus_framefmt *fmt) ++{ ++ struct adv7183 *decoder = to_adv7183(sd); ++ ++ *fmt = decoder->fmt; ++ return 0; ++} ++ ++static int adv7183_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct adv7183 *decoder = to_adv7183(sd); ++ ++ if (enable) ++ gpio_direction_output(decoder->oe_pin, 0); ++ else ++ gpio_direction_output(decoder->oe_pin, 1); ++ udelay(1); ++ return 0; ++} ++ ++static int adv7183_g_chip_ident(struct v4l2_subdev *sd, ++ struct v4l2_dbg_chip_ident *chip) ++{ ++ int rev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ /* 0x11 for adv7183, 0x13 for adv7183b */ ++ rev = adv7183_read(sd, ADV7183_IDENT); ++ ++ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7183, rev); ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int adv7183_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (!v4l2_chip_match_i2c_client(client, ®->match)) ++ return -EINVAL; ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ reg->val = adv7183_read(sd, reg->reg & 0xff); ++ reg->size = 1; ++ return 0; ++} ++ ++static int adv7183_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (!v4l2_chip_match_i2c_client(client, ®->match)) ++ return -EINVAL; ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ adv7183_write(sd, reg->reg & 0xff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++static const struct v4l2_ctrl_ops adv7183_ctrl_ops = { ++ .s_ctrl = adv7183_s_ctrl, ++}; ++ ++static const struct v4l2_subdev_core_ops adv7183_core_ops = { ++ .log_status = adv7183_log_status, ++ .g_std = adv7183_g_std, ++ .s_std = adv7183_s_std, ++ .reset = adv7183_reset, ++ .g_chip_ident = adv7183_g_chip_ident, ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = adv7183_g_register, ++ .s_register = adv7183_s_register, ++#endif ++}; ++ ++static const struct v4l2_subdev_video_ops adv7183_video_ops = { ++ .s_routing = adv7183_s_routing, ++ .querystd = adv7183_querystd, ++ .g_input_status = adv7183_g_input_status, ++ .enum_mbus_fmt = adv7183_enum_mbus_fmt, ++ .try_mbus_fmt = adv7183_try_mbus_fmt, ++ .s_mbus_fmt = adv7183_s_mbus_fmt, ++ .g_mbus_fmt = adv7183_g_mbus_fmt, ++ .s_stream = adv7183_s_stream, ++}; ++ ++static const struct v4l2_subdev_ops adv7183_ops = { ++ .core = &adv7183_core_ops, ++ .video = &adv7183_video_ops, ++}; ++ ++static int adv7183_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct adv7183 *decoder; ++ struct v4l2_subdev *sd; ++ struct v4l2_ctrl_handler *hdl; ++ int ret; ++ struct v4l2_mbus_framefmt fmt; ++ const unsigned *pin_array; ++ ++ /* Check if the adapter supports the needed features */ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) ++ return -EIO; ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ pin_array = client->dev.platform_data; ++ if (pin_array == NULL) ++ return -EINVAL; ++ ++ decoder = kzalloc(sizeof(struct adv7183), GFP_KERNEL); ++ if (decoder == NULL) ++ return -ENOMEM; ++ ++ decoder->reset_pin = pin_array[0]; ++ decoder->oe_pin = pin_array[1]; ++ ++ if (gpio_request(decoder->reset_pin, "ADV7183 Reset")) { ++ v4l_err(client, "failed to request GPIO %d\n", decoder->reset_pin); ++ ret = -EBUSY; ++ goto err_free_decoder; ++ } ++ ++ if (gpio_request(decoder->oe_pin, "ADV7183 Output Enable")) { ++ v4l_err(client, "failed to request GPIO %d\n", decoder->oe_pin); ++ ret = -EBUSY; ++ goto err_free_reset; ++ } ++ ++ sd = &decoder->sd; ++ v4l2_i2c_subdev_init(sd, client, &adv7183_ops); ++ ++ hdl = &decoder->hdl; ++ v4l2_ctrl_handler_init(hdl, 4); ++ v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); ++ v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x80); ++ v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops, ++ V4L2_CID_SATURATION, 0, 0xFFFF, 1, 0x8080); ++ v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops, ++ V4L2_CID_HUE, 0, 0xFFFF, 1, 0x8080); ++ /* hook the control handler into the driver */ ++ sd->ctrl_handler = hdl; ++ if (hdl->error) { ++ ret = hdl->error; ++ ++ v4l2_ctrl_handler_free(hdl); ++ goto err_free_oe; ++ } ++ ++ /* v4l2 doesn't support an autodetect standard, pick PAL as default */ ++ decoder->std = V4L2_STD_PAL; ++ decoder->input = ADV7183_COMPOSITE4; ++ decoder->output = ADV7183_8BIT_OUT; ++ ++ gpio_direction_output(decoder->oe_pin, 1); ++ /* reset chip */ ++ gpio_direction_output(decoder->reset_pin, 0); ++ /* reset pulse width at least 5ms */ ++ mdelay(10); ++ gpio_direction_output(decoder->reset_pin, 1); ++ /* wait 5ms before any further i2c writes are performed */ ++ mdelay(5); ++ ++ adv7183_writeregs(sd, adv7183_init_regs, ARRAY_SIZE(adv7183_init_regs)); ++ adv7183_s_std(sd, decoder->std); ++ fmt.width = 720; ++ fmt.height = 576; ++ adv7183_s_mbus_fmt(sd, &fmt); ++ ++ /* initialize the hardware to the default control values */ ++ ret = v4l2_ctrl_handler_setup(hdl); ++ if (ret) { ++ v4l2_ctrl_handler_free(hdl); ++ goto err_free_oe; ++ } ++ ++ return 0; ++err_free_oe: ++ gpio_free(decoder->oe_pin); ++err_free_reset: ++ gpio_free(decoder->reset_pin); ++err_free_decoder: ++ kfree(decoder); ++ return ret; ++} ++ ++static int adv7183_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct adv7183 *decoder = to_adv7183(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(sd->ctrl_handler); ++ gpio_free(decoder->oe_pin); ++ gpio_free(decoder->reset_pin); ++ kfree(decoder); ++ return 0; ++} ++ ++static const struct i2c_device_id adv7183_id[] = { ++ {"adv7183", 0}, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(i2c, adv7183_id); ++ ++static struct i2c_driver adv7183_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "adv7183", ++ }, ++ .probe = adv7183_probe, ++ .remove = __devexit_p(adv7183_remove), ++ .id_table = adv7183_id, ++}; ++ ++static __init int adv7183_init(void) ++{ ++ return i2c_add_driver(&adv7183_driver); ++} ++ ++static __exit void adv7183_exit(void) ++{ ++ i2c_del_driver(&adv7183_driver); ++} ++ ++module_init(adv7183_init); ++module_exit(adv7183_exit); ++ ++MODULE_DESCRIPTION("Analog Devices ADV7183 video decoder driver"); ++MODULE_AUTHOR("Scott Jiang "); ++MODULE_LICENSE("GPL v2"); +Index: linux-3.3.x86_64/drivers/media/video/adv7183_regs.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/video/adv7183_regs.h +@@ -0,0 +1,107 @@ ++/* ++ * adv7183 - Analog Devices ADV7183 video decoder registers ++ * ++ * Copyright (c) 2011 Analog Devices Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#ifndef _ADV7183_REGS_H_ ++#define _ADV7183_REGS_H_ ++ ++#define ADV7183_IN_CTRL 0x00 /* Input control */ ++#define ADV7183_VD_SEL 0x01 /* Video selection */ ++#define ADV7183_OUT_CTRL 0x03 /* Output control */ ++#define ADV7183_EXT_OUT_CTRL 0x04 /* Extended output control */ ++#define ADV7183_AUTO_DET_EN 0x07 /* Autodetect enable */ ++#define ADV7183_CONTRAST 0x08 /* Contrast */ ++#define ADV7183_BRIGHTNESS 0x0A /* Brightness */ ++#define ADV7183_HUE 0x0B /* Hue */ ++#define ADV7183_DEF_Y 0x0C /* Default value Y */ ++#define ADV7183_DEF_C 0x0D /* Default value C */ ++#define ADV7183_ADI_CTRL 0x0E /* ADI control */ ++#define ADV7183_POW_MANAGE 0x0F /* Power Management */ ++#define ADV7183_STATUS_1 0x10 /* Status 1 */ ++#define ADV7183_IDENT 0x11 /* Ident */ ++#define ADV7183_STATUS_2 0x12 /* Status 2 */ ++#define ADV7183_STATUS_3 0x13 /* Status 3 */ ++#define ADV7183_ANAL_CLAMP_CTRL 0x14 /* Analog clamp control */ ++#define ADV7183_DIGI_CLAMP_CTRL_1 0x15 /* Digital clamp control 1 */ ++#define ADV7183_SHAP_FILT_CTRL 0x17 /* Shaping filter control */ ++#define ADV7183_SHAP_FILT_CTRL_2 0x18 /* Shaping filter control 2 */ ++#define ADV7183_COMB_FILT_CTRL 0x19 /* Comb filter control */ ++#define ADV7183_ADI_CTRL_2 0x1D /* ADI control 2 */ ++#define ADV7183_PIX_DELAY_CTRL 0x27 /* Pixel delay control */ ++#define ADV7183_MISC_GAIN_CTRL 0x2B /* Misc gain control */ ++#define ADV7183_AGC_MODE_CTRL 0x2C /* AGC mode control */ ++#define ADV7183_CHRO_GAIN_CTRL_1 0x2D /* Chroma gain control 1 */ ++#define ADV7183_CHRO_GAIN_CTRL_2 0x2E /* Chroma gain control 2 */ ++#define ADV7183_LUMA_GAIN_CTRL_1 0x2F /* Luma gain control 1 */ ++#define ADV7183_LUMA_GAIN_CTRL_2 0x30 /* Luma gain control 2 */ ++#define ADV7183_VS_FIELD_CTRL_1 0x31 /* Vsync field control 1 */ ++#define ADV7183_VS_FIELD_CTRL_2 0x32 /* Vsync field control 2 */ ++#define ADV7183_VS_FIELD_CTRL_3 0x33 /* Vsync field control 3 */ ++#define ADV7183_HS_POS_CTRL_1 0x34 /* Hsync positon control 1 */ ++#define ADV7183_HS_POS_CTRL_2 0x35 /* Hsync positon control 2 */ ++#define ADV7183_HS_POS_CTRL_3 0x36 /* Hsync positon control 3 */ ++#define ADV7183_POLARITY 0x37 /* Polarity */ ++#define ADV7183_NTSC_COMB_CTRL 0x38 /* NTSC comb control */ ++#define ADV7183_PAL_COMB_CTRL 0x39 /* PAL comb control */ ++#define ADV7183_ADC_CTRL 0x3A /* ADC control */ ++#define ADV7183_MAN_WIN_CTRL 0x3D /* Manual window control */ ++#define ADV7183_RESAMPLE_CTRL 0x41 /* Resample control */ ++#define ADV7183_GEMSTAR_CTRL_1 0x48 /* Gemstar ctrl 1 */ ++#define ADV7183_GEMSTAR_CTRL_2 0x49 /* Gemstar ctrl 2 */ ++#define ADV7183_GEMSTAR_CTRL_3 0x4A /* Gemstar ctrl 3 */ ++#define ADV7183_GEMSTAR_CTRL_4 0x4B /* Gemstar ctrl 4 */ ++#define ADV7183_GEMSTAR_CTRL_5 0x4C /* Gemstar ctrl 5 */ ++#define ADV7183_CTI_DNR_CTRL_1 0x4D /* CTI DNR ctrl 1 */ ++#define ADV7183_CTI_DNR_CTRL_2 0x4E /* CTI DNR ctrl 2 */ ++#define ADV7183_CTI_DNR_CTRL_4 0x50 /* CTI DNR ctrl 4 */ ++#define ADV7183_LOCK_CNT 0x51 /* Lock count */ ++#define ADV7183_FREE_LINE_LEN 0x8F /* Free-Run line length 1 */ ++#define ADV7183_VBI_INFO 0x90 /* VBI info */ ++#define ADV7183_WSS_1 0x91 /* WSS 1 */ ++#define ADV7183_WSS_2 0x92 /* WSS 2 */ ++#define ADV7183_EDTV_1 0x93 /* EDTV 1 */ ++#define ADV7183_EDTV_2 0x94 /* EDTV 2 */ ++#define ADV7183_EDTV_3 0x95 /* EDTV 3 */ ++#define ADV7183_CGMS_1 0x96 /* CGMS 1 */ ++#define ADV7183_CGMS_2 0x97 /* CGMS 2 */ ++#define ADV7183_CGMS_3 0x98 /* CGMS 3 */ ++#define ADV7183_CCAP_1 0x99 /* CCAP 1 */ ++#define ADV7183_CCAP_2 0x9A /* CCAP 2 */ ++#define ADV7183_LETTERBOX_1 0x9B /* Letterbox 1 */ ++#define ADV7183_LETTERBOX_2 0x9C /* Letterbox 2 */ ++#define ADV7183_LETTERBOX_3 0x9D /* Letterbox 3 */ ++#define ADV7183_CRC_EN 0xB2 /* CRC enable */ ++#define ADV7183_ADC_SWITCH_1 0xC3 /* ADC switch 1 */ ++#define ADV7183_ADC_SWITCH_2 0xC4 /* ADC swithc 2 */ ++#define ADV7183_LETTERBOX_CTRL_1 0xDC /* Letterbox control 1 */ ++#define ADV7183_LETTERBOX_CTRL_2 0xDD /* Letterbox control 2 */ ++#define ADV7183_SD_OFFSET_CB 0xE1 /* SD offset Cb */ ++#define ADV7183_SD_OFFSET_CR 0xE2 /* SD offset Cr */ ++#define ADV7183_SD_SATURATION_CB 0xE3 /* SD saturation Cb */ ++#define ADV7183_SD_SATURATION_CR 0xE4 /* SD saturation Cr */ ++#define ADV7183_NTSC_V_BEGIN 0xE5 /* NTSC V bit begin */ ++#define ADV7183_NTSC_V_END 0xE6 /* NTSC V bit end */ ++#define ADV7183_NTSC_F_TOGGLE 0xE7 /* NTSC F bit toggle */ ++#define ADV7183_PAL_V_BEGIN 0xE8 /* PAL V bit begin */ ++#define ADV7183_PAL_V_END 0xE9 /* PAL V bit end */ ++#define ADV7183_PAL_F_TOGGLE 0xEA /* PAL F bit toggle */ ++#define ADV7183_DRIVE_STR 0xF4 /* Drive strength */ ++#define ADV7183_IF_COMP_CTRL 0xF8 /* IF comp control */ ++#define ADV7183_VS_MODE_CTRL 0xF9 /* VS mode control */ ++ ++#endif +Index: linux-3.3.x86_64/include/media/adv7183.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/include/media/adv7183.h +@@ -0,0 +1,47 @@ ++/* ++ * adv7183.h - definition for adv7183 inputs and outputs ++ * ++ * Copyright (c) 2011 Analog Devices Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#ifndef _ADV7183_H_ ++#define _ADV7183_H_ ++ ++/* ADV7183 HW inputs */ ++#define ADV7183_COMPOSITE0 0 /* CVBS in on AIN1 */ ++#define ADV7183_COMPOSITE1 1 /* CVBS in on AIN2 */ ++#define ADV7183_COMPOSITE2 2 /* CVBS in on AIN3 */ ++#define ADV7183_COMPOSITE3 3 /* CVBS in on AIN4 */ ++#define ADV7183_COMPOSITE4 4 /* CVBS in on AIN5 */ ++#define ADV7183_COMPOSITE5 5 /* CVBS in on AIN6 */ ++#define ADV7183_COMPOSITE6 6 /* CVBS in on AIN7 */ ++#define ADV7183_COMPOSITE7 7 /* CVBS in on AIN8 */ ++#define ADV7183_COMPOSITE8 8 /* CVBS in on AIN9 */ ++#define ADV7183_COMPOSITE9 9 /* CVBS in on AIN10 */ ++#define ADV7183_COMPOSITE10 10 /* CVBS in on AIN11 */ ++ ++#define ADV7183_SVIDEO0 11 /* Y on AIN1, C on AIN4 */ ++#define ADV7183_SVIDEO1 12 /* Y on AIN2, C on AIN5 */ ++#define ADV7183_SVIDEO2 13 /* Y on AIN3, C on AIN6 */ ++ ++#define ADV7183_COMPONENT0 14 /* Y on AIN1, Pr on AIN4, Pb on AIN5 */ ++#define ADV7183_COMPONENT1 15 /* Y on AIN2, Pr on AIN3, Pb on AIN6 */ ++ ++/* ADV7183 HW outputs */ ++#define ADV7183_8BIT_OUT 0 ++#define ADV7183_16BIT_OUT 1 ++ ++#endif +Index: linux-3.3.x86_64/include/media/v4l2-chip-ident.h +=================================================================== +--- linux-3.3.x86_64.orig/include/media/v4l2-chip-ident.h ++++ linux-3.3.x86_64/include/media/v4l2-chip-ident.h +@@ -143,6 +143,9 @@ enum { + /* module saa6588: just ident 6588 */ + V4L2_IDENT_SAA6588 = 6588, + ++ /* module vs6624: just ident 6624 */ ++ V4L2_IDENT_VS6624 = 6624, ++ + /* module saa6752hs: reserved range 6750-6759 */ + V4L2_IDENT_SAA6752HS = 6752, + V4L2_IDENT_SAA6752HS_AC3 = 6753, +@@ -162,6 +165,9 @@ enum { + /* module adv7180: just ident 7180 */ + V4L2_IDENT_ADV7180 = 7180, + ++ /* module adv7183: just ident 7183 */ ++ V4L2_IDENT_ADV7183 = 7183, ++ + /* module saa7185: just ident 7185 */ + V4L2_IDENT_SAA7185 = 7185, + +Index: linux-3.3.x86_64/drivers/media/video/vs6624.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/video/vs6624.c +@@ -0,0 +1,928 @@ ++/* ++ * vs6624.c ST VS6624 CMOS image sensor driver ++ * ++ * Copyright (c) 2011 Analog Devices Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "vs6624_regs.h" ++ ++#define VGA_WIDTH 640 ++#define VGA_HEIGHT 480 ++#define QVGA_WIDTH 320 ++#define QVGA_HEIGHT 240 ++#define QQVGA_WIDTH 160 ++#define QQVGA_HEIGHT 120 ++#define CIF_WIDTH 352 ++#define CIF_HEIGHT 288 ++#define QCIF_WIDTH 176 ++#define QCIF_HEIGHT 144 ++#define QQCIF_WIDTH 88 ++#define QQCIF_HEIGHT 72 ++ ++#define MAX_FRAME_RATE 30 ++ ++struct vs6624 { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_fract frame_rate; ++ struct v4l2_mbus_framefmt fmt; ++ unsigned ce_pin; ++}; ++ ++static const struct vs6624_format { ++ enum v4l2_mbus_pixelcode mbus_code; ++ enum v4l2_colorspace colorspace; ++} vs6624_formats[] = { ++ { ++ .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, ++ .colorspace = V4L2_COLORSPACE_JPEG, ++ }, ++ { ++ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, ++ .colorspace = V4L2_COLORSPACE_JPEG, ++ }, ++ { ++ .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++}; ++ ++static struct v4l2_mbus_framefmt vs6624_default_fmt = { ++ .width = VGA_WIDTH, ++ .height = VGA_HEIGHT, ++ .code = V4L2_MBUS_FMT_UYVY8_2X8, ++ .field = V4L2_FIELD_NONE, ++ .colorspace = V4L2_COLORSPACE_JPEG, ++}; ++ ++static const u16 vs6624_p1[] = { ++ 0x8104, 0x03, ++ 0x8105, 0x01, ++ 0xc900, 0x03, ++ 0xc904, 0x47, ++ 0xc905, 0x10, ++ 0xc906, 0x80, ++ 0xc907, 0x3a, ++ 0x903a, 0x02, ++ 0x903b, 0x47, ++ 0x903c, 0x15, ++ 0xc908, 0x31, ++ 0xc909, 0xdc, ++ 0xc90a, 0x80, ++ 0xc90b, 0x44, ++ 0x9044, 0x02, ++ 0x9045, 0x31, ++ 0x9046, 0xe2, ++ 0xc90c, 0x07, ++ 0xc90d, 0xe0, ++ 0xc90e, 0x80, ++ 0xc90f, 0x47, ++ 0x9047, 0x90, ++ 0x9048, 0x83, ++ 0x9049, 0x81, ++ 0x904a, 0xe0, ++ 0x904b, 0x60, ++ 0x904c, 0x08, ++ 0x904d, 0x90, ++ 0x904e, 0xc0, ++ 0x904f, 0x43, ++ 0x9050, 0x74, ++ 0x9051, 0x01, ++ 0x9052, 0xf0, ++ 0x9053, 0x80, ++ 0x9054, 0x05, ++ 0x9055, 0xE4, ++ 0x9056, 0x90, ++ 0x9057, 0xc0, ++ 0x9058, 0x43, ++ 0x9059, 0xf0, ++ 0x905a, 0x02, ++ 0x905b, 0x07, ++ 0x905c, 0xec, ++ 0xc910, 0x5d, ++ 0xc911, 0xca, ++ 0xc912, 0x80, ++ 0xc913, 0x5d, ++ 0x905d, 0xa3, ++ 0x905e, 0x04, ++ 0x905f, 0xf0, ++ 0x9060, 0xa3, ++ 0x9061, 0x04, ++ 0x9062, 0xf0, ++ 0x9063, 0x22, ++ 0xc914, 0x72, ++ 0xc915, 0x92, ++ 0xc916, 0x80, ++ 0xc917, 0x64, ++ 0x9064, 0x74, ++ 0x9065, 0x01, ++ 0x9066, 0x02, ++ 0x9067, 0x72, ++ 0x9068, 0x95, ++ 0xc918, 0x47, ++ 0xc919, 0xf2, ++ 0xc91a, 0x81, ++ 0xc91b, 0x69, ++ 0x9169, 0x74, ++ 0x916a, 0x02, ++ 0x916b, 0xf0, ++ 0x916c, 0xec, ++ 0x916d, 0xb4, ++ 0x916e, 0x10, ++ 0x916f, 0x0a, ++ 0x9170, 0x90, ++ 0x9171, 0x80, ++ 0x9172, 0x16, ++ 0x9173, 0xe0, ++ 0x9174, 0x70, ++ 0x9175, 0x04, ++ 0x9176, 0x90, ++ 0x9177, 0xd3, ++ 0x9178, 0xc4, ++ 0x9179, 0xf0, ++ 0x917a, 0x22, ++ 0xc91c, 0x0a, ++ 0xc91d, 0xbe, ++ 0xc91e, 0x80, ++ 0xc91f, 0x73, ++ 0x9073, 0xfc, ++ 0x9074, 0xa3, ++ 0x9075, 0xe0, ++ 0x9076, 0xf5, ++ 0x9077, 0x82, ++ 0x9078, 0x8c, ++ 0x9079, 0x83, ++ 0x907a, 0xa3, ++ 0x907b, 0xa3, ++ 0x907c, 0xe0, ++ 0x907d, 0xfc, ++ 0x907e, 0xa3, ++ 0x907f, 0xe0, ++ 0x9080, 0xc3, ++ 0x9081, 0x9f, ++ 0x9082, 0xff, ++ 0x9083, 0xec, ++ 0x9084, 0x9e, ++ 0x9085, 0xfe, ++ 0x9086, 0x02, ++ 0x9087, 0x0a, ++ 0x9088, 0xea, ++ 0xc920, 0x47, ++ 0xc921, 0x38, ++ 0xc922, 0x80, ++ 0xc923, 0x89, ++ 0x9089, 0xec, ++ 0x908a, 0xd3, ++ 0x908b, 0x94, ++ 0x908c, 0x20, ++ 0x908d, 0x40, ++ 0x908e, 0x01, ++ 0x908f, 0x1c, ++ 0x9090, 0x90, ++ 0x9091, 0xd3, ++ 0x9092, 0xd4, ++ 0x9093, 0xec, ++ 0x9094, 0xf0, ++ 0x9095, 0x02, ++ 0x9096, 0x47, ++ 0x9097, 0x3d, ++ 0xc924, 0x45, ++ 0xc925, 0xca, ++ 0xc926, 0x80, ++ 0xc927, 0x98, ++ 0x9098, 0x12, ++ 0x9099, 0x77, ++ 0x909a, 0xd6, ++ 0x909b, 0x02, ++ 0x909c, 0x45, ++ 0x909d, 0xcd, ++ 0xc928, 0x20, ++ 0xc929, 0xd5, ++ 0xc92a, 0x80, ++ 0xc92b, 0x9e, ++ 0x909e, 0x90, ++ 0x909f, 0x82, ++ 0x90a0, 0x18, ++ 0x90a1, 0xe0, ++ 0x90a2, 0xb4, ++ 0x90a3, 0x03, ++ 0x90a4, 0x0e, ++ 0x90a5, 0x90, ++ 0x90a6, 0x83, ++ 0x90a7, 0xbf, ++ 0x90a8, 0xe0, ++ 0x90a9, 0x60, ++ 0x90aa, 0x08, ++ 0x90ab, 0x90, ++ 0x90ac, 0x81, ++ 0x90ad, 0xfc, ++ 0x90ae, 0xe0, ++ 0x90af, 0xff, ++ 0x90b0, 0xc3, ++ 0x90b1, 0x13, ++ 0x90b2, 0xf0, ++ 0x90b3, 0x90, ++ 0x90b4, 0x81, ++ 0x90b5, 0xfc, ++ 0x90b6, 0xe0, ++ 0x90b7, 0xff, ++ 0x90b8, 0x02, ++ 0x90b9, 0x20, ++ 0x90ba, 0xda, ++ 0xc92c, 0x70, ++ 0xc92d, 0xbc, ++ 0xc92e, 0x80, ++ 0xc92f, 0xbb, ++ 0x90bb, 0x90, ++ 0x90bc, 0x82, ++ 0x90bd, 0x18, ++ 0x90be, 0xe0, ++ 0x90bf, 0xb4, ++ 0x90c0, 0x03, ++ 0x90c1, 0x06, ++ 0x90c2, 0x90, ++ 0x90c3, 0xc1, ++ 0x90c4, 0x06, ++ 0x90c5, 0x74, ++ 0x90c6, 0x05, ++ 0x90c7, 0xf0, ++ 0x90c8, 0x90, ++ 0x90c9, 0xd3, ++ 0x90ca, 0xa0, ++ 0x90cb, 0x02, ++ 0x90cc, 0x70, ++ 0x90cd, 0xbf, ++ 0xc930, 0x72, ++ 0xc931, 0x21, ++ 0xc932, 0x81, ++ 0xc933, 0x3b, ++ 0x913b, 0x7d, ++ 0x913c, 0x02, ++ 0x913d, 0x7f, ++ 0x913e, 0x7b, ++ 0x913f, 0x02, ++ 0x9140, 0x72, ++ 0x9141, 0x25, ++ 0xc934, 0x28, ++ 0xc935, 0xae, ++ 0xc936, 0x80, ++ 0xc937, 0xd2, ++ 0x90d2, 0xf0, ++ 0x90d3, 0x90, ++ 0x90d4, 0xd2, ++ 0x90d5, 0x0a, ++ 0x90d6, 0x02, ++ 0x90d7, 0x28, ++ 0x90d8, 0xb4, ++ 0xc938, 0x28, ++ 0xc939, 0xb1, ++ 0xc93a, 0x80, ++ 0xc93b, 0xd9, ++ 0x90d9, 0x90, ++ 0x90da, 0x83, ++ 0x90db, 0xba, ++ 0x90dc, 0xe0, ++ 0x90dd, 0xff, ++ 0x90de, 0x90, ++ 0x90df, 0xd2, ++ 0x90e0, 0x08, ++ 0x90e1, 0xe0, ++ 0x90e2, 0xe4, ++ 0x90e3, 0xef, ++ 0x90e4, 0xf0, ++ 0x90e5, 0xa3, ++ 0x90e6, 0xe0, ++ 0x90e7, 0x74, ++ 0x90e8, 0xff, ++ 0x90e9, 0xf0, ++ 0x90ea, 0x90, ++ 0x90eb, 0xd2, ++ 0x90ec, 0x0a, ++ 0x90ed, 0x02, ++ 0x90ee, 0x28, ++ 0x90ef, 0xb4, ++ 0xc93c, 0x29, ++ 0xc93d, 0x79, ++ 0xc93e, 0x80, ++ 0xc93f, 0xf0, ++ 0x90f0, 0xf0, ++ 0x90f1, 0x90, ++ 0x90f2, 0xd2, ++ 0x90f3, 0x0e, ++ 0x90f4, 0x02, ++ 0x90f5, 0x29, ++ 0x90f6, 0x7f, ++ 0xc940, 0x29, ++ 0xc941, 0x7c, ++ 0xc942, 0x80, ++ 0xc943, 0xf7, ++ 0x90f7, 0x90, ++ 0x90f8, 0x83, ++ 0x90f9, 0xba, ++ 0x90fa, 0xe0, ++ 0x90fb, 0xff, ++ 0x90fc, 0x90, ++ 0x90fd, 0xd2, ++ 0x90fe, 0x0c, ++ 0x90ff, 0xe0, ++ 0x9100, 0xe4, ++ 0x9101, 0xef, ++ 0x9102, 0xf0, ++ 0x9103, 0xa3, ++ 0x9104, 0xe0, ++ 0x9105, 0x74, ++ 0x9106, 0xff, ++ 0x9107, 0xf0, ++ 0x9108, 0x90, ++ 0x9109, 0xd2, ++ 0x910a, 0x0e, ++ 0x910b, 0x02, ++ 0x910c, 0x29, ++ 0x910d, 0x7f, ++ 0xc944, 0x2a, ++ 0xc945, 0x42, ++ 0xc946, 0x81, ++ 0xc947, 0x0e, ++ 0x910e, 0xf0, ++ 0x910f, 0x90, ++ 0x9110, 0xd2, ++ 0x9111, 0x12, ++ 0x9112, 0x02, ++ 0x9113, 0x2a, ++ 0x9114, 0x48, ++ 0xc948, 0x2a, ++ 0xc949, 0x45, ++ 0xc94a, 0x81, ++ 0xc94b, 0x15, ++ 0x9115, 0x90, ++ 0x9116, 0x83, ++ 0x9117, 0xba, ++ 0x9118, 0xe0, ++ 0x9119, 0xff, ++ 0x911a, 0x90, ++ 0x911b, 0xd2, ++ 0x911c, 0x10, ++ 0x911d, 0xe0, ++ 0x911e, 0xe4, ++ 0x911f, 0xef, ++ 0x9120, 0xf0, ++ 0x9121, 0xa3, ++ 0x9122, 0xe0, ++ 0x9123, 0x74, ++ 0x9124, 0xff, ++ 0x9125, 0xf0, ++ 0x9126, 0x90, ++ 0x9127, 0xd2, ++ 0x9128, 0x12, ++ 0x9129, 0x02, ++ 0x912a, 0x2a, ++ 0x912b, 0x48, ++ 0xc900, 0x01, ++ 0x0000, 0x00, ++}; ++ ++static const u16 vs6624_p2[] = { ++ 0x806f, 0x01, ++ 0x058c, 0x01, ++ 0x0000, 0x00, ++}; ++ ++static const u16 vs6624_run_setup[] = { ++ 0x1d18, 0x00, /* Enableconstrainedwhitebalance */ ++ VS6624_PEAK_MIN_OUT_G_MSB, 0x3c, /* Damper PeakGain Output MSB */ ++ VS6624_PEAK_MIN_OUT_G_LSB, 0x66, /* Damper PeakGain Output LSB */ ++ VS6624_CM_LOW_THR_MSB, 0x65, /* Damper Low MSB */ ++ VS6624_CM_LOW_THR_LSB, 0xd1, /* Damper Low LSB */ ++ VS6624_CM_HIGH_THR_MSB, 0x66, /* Damper High MSB */ ++ VS6624_CM_HIGH_THR_LSB, 0x62, /* Damper High LSB */ ++ VS6624_CM_MIN_OUT_MSB, 0x00, /* Damper Min output MSB */ ++ VS6624_CM_MIN_OUT_LSB, 0x00, /* Damper Min output LSB */ ++ VS6624_NORA_DISABLE, 0x00, /* Nora fDisable */ ++ VS6624_NORA_USAGE, 0x04, /* Nora usage */ ++ VS6624_NORA_LOW_THR_MSB, 0x63, /* Damper Low MSB Changed 0x63 to 0x65 */ ++ VS6624_NORA_LOW_THR_LSB, 0xd1, /* Damper Low LSB */ ++ VS6624_NORA_HIGH_THR_MSB, 0x68, /* Damper High MSB */ ++ VS6624_NORA_HIGH_THR_LSB, 0xdd, /* Damper High LSB */ ++ VS6624_NORA_MIN_OUT_MSB, 0x3a, /* Damper Min output MSB */ ++ VS6624_NORA_MIN_OUT_LSB, 0x00, /* Damper Min output LSB */ ++ VS6624_F2B_DISABLE, 0x00, /* Disable */ ++ 0x1d8a, 0x30, /* MAXWeightHigh */ ++ 0x1d91, 0x62, /* fpDamperLowThresholdHigh MSB */ ++ 0x1d92, 0x4a, /* fpDamperLowThresholdHigh LSB */ ++ 0x1d95, 0x65, /* fpDamperHighThresholdHigh MSB */ ++ 0x1d96, 0x0e, /* fpDamperHighThresholdHigh LSB */ ++ 0x1da1, 0x3a, /* fpMinimumDamperOutputLow MSB */ ++ 0x1da2, 0xb8, /* fpMinimumDamperOutputLow LSB */ ++ 0x1e08, 0x06, /* MAXWeightLow */ ++ 0x1e0a, 0x0a, /* MAXWeightHigh */ ++ 0x1601, 0x3a, /* Red A MSB */ ++ 0x1602, 0x14, /* Red A LSB */ ++ 0x1605, 0x3b, /* Blue A MSB */ ++ 0x1606, 0x85, /* BLue A LSB */ ++ 0x1609, 0x3b, /* RED B MSB */ ++ 0x160a, 0x85, /* RED B LSB */ ++ 0x160d, 0x3a, /* Blue B MSB */ ++ 0x160e, 0x14, /* Blue B LSB */ ++ 0x1611, 0x30, /* Max Distance from Locus MSB */ ++ 0x1612, 0x8f, /* Max Distance from Locus MSB */ ++ 0x1614, 0x01, /* Enable constrainer */ ++ 0x0000, 0x00, ++}; ++ ++static const u16 vs6624_default[] = { ++ VS6624_CONTRAST0, 0x84, ++ VS6624_SATURATION0, 0x75, ++ VS6624_GAMMA0, 0x11, ++ VS6624_CONTRAST1, 0x84, ++ VS6624_SATURATION1, 0x75, ++ VS6624_GAMMA1, 0x11, ++ VS6624_MAN_RG, 0x80, ++ VS6624_MAN_GG, 0x80, ++ VS6624_MAN_BG, 0x80, ++ VS6624_WB_MODE, 0x1, ++ VS6624_EXPO_COMPENSATION, 0xfe, ++ VS6624_EXPO_METER, 0x0, ++ VS6624_LIGHT_FREQ, 0x64, ++ VS6624_PEAK_GAIN, 0xe, ++ VS6624_PEAK_LOW_THR, 0x28, ++ VS6624_HMIRROR0, 0x0, ++ VS6624_VFLIP0, 0x0, ++ VS6624_ZOOM_HSTEP0_MSB, 0x0, ++ VS6624_ZOOM_HSTEP0_LSB, 0x1, ++ VS6624_ZOOM_VSTEP0_MSB, 0x0, ++ VS6624_ZOOM_VSTEP0_LSB, 0x1, ++ VS6624_PAN_HSTEP0_MSB, 0x0, ++ VS6624_PAN_HSTEP0_LSB, 0xf, ++ VS6624_PAN_VSTEP0_MSB, 0x0, ++ VS6624_PAN_VSTEP0_LSB, 0xf, ++ VS6624_SENSOR_MODE, 0x1, ++ VS6624_SYNC_CODE_SETUP, 0x21, ++ VS6624_DISABLE_FR_DAMPER, 0x0, ++ VS6624_FR_DEN, 0x1, ++ VS6624_FR_NUM_LSB, 0xf, ++ VS6624_INIT_PIPE_SETUP, 0x0, ++ VS6624_IMG_FMT0, 0x0, ++ VS6624_YUV_SETUP, 0x1, ++ VS6624_IMAGE_SIZE0, 0x2, ++ 0x0000, 0x00, ++}; ++ ++static inline struct vs6624 *to_vs6624(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct vs6624, sd); ++} ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct vs6624, hdl)->sd; ++} ++ ++static int vs6624_read(struct v4l2_subdev *sd, u16 index) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u8 buf[2]; ++ ++ buf[0] = index >> 8; ++ buf[1] = index; ++ i2c_master_send(client, buf, 2); ++ i2c_master_recv(client, buf, 1); ++ ++ return buf[0]; ++} ++ ++static int vs6624_write(struct v4l2_subdev *sd, u16 index, ++ u8 value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u8 buf[3]; ++ ++ buf[0] = index >> 8; ++ buf[1] = index; ++ buf[2] = value; ++ ++ return i2c_master_send(client, buf, 3); ++} ++ ++static int vs6624_writeregs(struct v4l2_subdev *sd, const u16 *regs) ++{ ++ u16 reg; ++ u8 data; ++ ++ while (*regs != 0x00) { ++ reg = *regs++; ++ data = *regs++; ++ ++ vs6624_write(sd, reg, data); ++ } ++ return 0; ++} ++ ++static int vs6624_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_CONTRAST: ++ vs6624_write(sd, VS6624_CONTRAST0, ctrl->val); ++ break; ++ case V4L2_CID_SATURATION: ++ vs6624_write(sd, VS6624_SATURATION0, ctrl->val); ++ break; ++ case V4L2_CID_HFLIP: ++ vs6624_write(sd, VS6624_HMIRROR0, ctrl->val); ++ break; ++ case V4L2_CID_VFLIP: ++ vs6624_write(sd, VS6624_VFLIP0, ctrl->val); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int vs6624_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, ++ enum v4l2_mbus_pixelcode *code) ++{ ++ if (index >= ARRAY_SIZE(vs6624_formats)) ++ return -EINVAL; ++ ++ *code = vs6624_formats[index].mbus_code; ++ return 0; ++} ++ ++static int vs6624_try_mbus_fmt(struct v4l2_subdev *sd, ++ struct v4l2_mbus_framefmt *fmt) ++{ ++ int index; ++ ++ for (index = 0; index < ARRAY_SIZE(vs6624_formats); index++) ++ if (vs6624_formats[index].mbus_code == fmt->code) ++ break; ++ if (index >= ARRAY_SIZE(vs6624_formats)) { ++ /* default to first format */ ++ index = 0; ++ fmt->code = vs6624_formats[0].mbus_code; ++ } ++ ++ /* sensor mode is VGA */ ++ if (fmt->width > VGA_WIDTH) ++ fmt->width = VGA_WIDTH; ++ if (fmt->height > VGA_HEIGHT) ++ fmt->height = VGA_HEIGHT; ++ fmt->width = fmt->width & (~3); ++ fmt->height = fmt->height & (~3); ++ fmt->field = V4L2_FIELD_NONE; ++ fmt->colorspace = vs6624_formats[index].colorspace; ++ return 0; ++} ++ ++static int vs6624_s_mbus_fmt(struct v4l2_subdev *sd, ++ struct v4l2_mbus_framefmt *fmt) ++{ ++ struct vs6624 *sensor = to_vs6624(sd); ++ int ret; ++ ++ ret = vs6624_try_mbus_fmt(sd, fmt); ++ if (ret) ++ return ret; ++ ++ /* set image format */ ++ switch (fmt->code) { ++ case V4L2_MBUS_FMT_UYVY8_2X8: ++ vs6624_write(sd, VS6624_IMG_FMT0, 0x0); ++ vs6624_write(sd, VS6624_YUV_SETUP, 0x1); ++ break; ++ case V4L2_MBUS_FMT_YUYV8_2X8: ++ vs6624_write(sd, VS6624_IMG_FMT0, 0x0); ++ vs6624_write(sd, VS6624_YUV_SETUP, 0x3); ++ break; ++ case V4L2_MBUS_FMT_RGB565_2X8_LE: ++ vs6624_write(sd, VS6624_IMG_FMT0, 0x4); ++ vs6624_write(sd, VS6624_RGB_SETUP, 0x0); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* set image size */ ++ if ((fmt->width == VGA_WIDTH) && (fmt->height == VGA_HEIGHT)) ++ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x2); ++ else if ((fmt->width == QVGA_WIDTH) && (fmt->height == QVGA_HEIGHT)) ++ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x4); ++ else if ((fmt->width == QQVGA_WIDTH) && (fmt->height == QQVGA_HEIGHT)) ++ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x6); ++ else if ((fmt->width == CIF_WIDTH) && (fmt->height == CIF_HEIGHT)) ++ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x3); ++ else if ((fmt->width == QCIF_WIDTH) && (fmt->height == QCIF_HEIGHT)) ++ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x5); ++ else if ((fmt->width == QQCIF_WIDTH) && (fmt->height == QQCIF_HEIGHT)) ++ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x7); ++ else { ++ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x8); ++ vs6624_write(sd, VS6624_MAN_HSIZE0_MSB, fmt->width >> 8); ++ vs6624_write(sd, VS6624_MAN_HSIZE0_LSB, fmt->width & 0xFF); ++ vs6624_write(sd, VS6624_MAN_VSIZE0_MSB, fmt->height >> 8); ++ vs6624_write(sd, VS6624_MAN_VSIZE0_LSB, fmt->height & 0xFF); ++ vs6624_write(sd, VS6624_CROP_CTRL0, 0x1); ++ } ++ ++ sensor->fmt = *fmt; ++ ++ return 0; ++} ++ ++static int vs6624_g_mbus_fmt(struct v4l2_subdev *sd, ++ struct v4l2_mbus_framefmt *fmt) ++{ ++ struct vs6624 *sensor = to_vs6624(sd); ++ ++ *fmt = sensor->fmt; ++ return 0; ++} ++ ++static int vs6624_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct vs6624 *sensor = to_vs6624(sd); ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ ++ memset(cp, 0, sizeof(*cp)); ++ cp->capability = V4L2_CAP_TIMEPERFRAME; ++ cp->timeperframe.numerator = sensor->frame_rate.denominator; ++ cp->timeperframe.denominator = sensor->frame_rate.numerator; ++ return 0; ++} ++ ++static int vs6624_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) ++{ ++ struct vs6624 *sensor = to_vs6624(sd); ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ struct v4l2_fract *tpf = &cp->timeperframe; ++ ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ if (cp->extendedmode != 0) ++ return -EINVAL; ++ ++ if (tpf->numerator == 0 || tpf->denominator == 0 ++ || (tpf->denominator > tpf->numerator * MAX_FRAME_RATE)) { ++ /* reset to max frame rate */ ++ tpf->numerator = 1; ++ tpf->denominator = MAX_FRAME_RATE; ++ } ++ sensor->frame_rate.numerator = tpf->denominator; ++ sensor->frame_rate.denominator = tpf->numerator; ++ vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0); ++ vs6624_write(sd, VS6624_FR_NUM_MSB, ++ sensor->frame_rate.numerator >> 8); ++ vs6624_write(sd, VS6624_FR_NUM_LSB, ++ sensor->frame_rate.numerator & 0xFF); ++ vs6624_write(sd, VS6624_FR_DEN, ++ sensor->frame_rate.denominator & 0xFF); ++ return 0; ++} ++ ++static int vs6624_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ if (enable) ++ vs6624_write(sd, VS6624_USER_CMD, 0x2); ++ else ++ vs6624_write(sd, VS6624_USER_CMD, 0x4); ++ udelay(100); ++ return 0; ++} ++ ++static int vs6624_g_chip_ident(struct v4l2_subdev *sd, ++ struct v4l2_dbg_chip_ident *chip) ++{ ++ int rev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ rev = (vs6624_read(sd, VS6624_FW_VSN_MAJOR) << 8) ++ | vs6624_read(sd, VS6624_FW_VSN_MINOR); ++ ++ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_VS6624, rev); ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (!v4l2_chip_match_i2c_client(client, ®->match)) ++ return -EINVAL; ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ reg->val = vs6624_read(sd, reg->reg & 0xffff); ++ reg->size = 1; ++ return 0; ++} ++ ++static int vs6624_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (!v4l2_chip_match_i2c_client(client, ®->match)) ++ return -EINVAL; ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ vs6624_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++static const struct v4l2_ctrl_ops vs6624_ctrl_ops = { ++ .s_ctrl = vs6624_s_ctrl, ++}; ++ ++static const struct v4l2_subdev_core_ops vs6624_core_ops = { ++ .g_chip_ident = vs6624_g_chip_ident, ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = vs6624_g_register, ++ .s_register = vs6624_s_register, ++#endif ++}; ++ ++static const struct v4l2_subdev_video_ops vs6624_video_ops = { ++ .enum_mbus_fmt = vs6624_enum_mbus_fmt, ++ .try_mbus_fmt = vs6624_try_mbus_fmt, ++ .s_mbus_fmt = vs6624_s_mbus_fmt, ++ .g_mbus_fmt = vs6624_g_mbus_fmt, ++ .s_parm = vs6624_s_parm, ++ .g_parm = vs6624_g_parm, ++ .s_stream = vs6624_s_stream, ++}; ++ ++static const struct v4l2_subdev_ops vs6624_ops = { ++ .core = &vs6624_core_ops, ++ .video = &vs6624_video_ops, ++}; ++ ++static int __devinit vs6624_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct vs6624 *sensor; ++ struct v4l2_subdev *sd; ++ struct v4l2_ctrl_handler *hdl; ++ const unsigned *ce; ++ int ret; ++ ++ /* Check if the adapter supports the needed features */ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) ++ return -EIO; ++ ++ ce = client->dev.platform_data; ++ if (ce == NULL) ++ return -EINVAL; ++ ++ ret = gpio_request(*ce, "VS6624 Chip Enable"); ++ if (ret) { ++ v4l_err(client, "failed to request GPIO %d\n", *ce); ++ return ret; ++ } ++ gpio_direction_output(*ce, 1); ++ /* wait 100ms before any further i2c writes are performed */ ++ mdelay(100); ++ ++ sensor = kzalloc(sizeof(*sensor), GFP_KERNEL); ++ if (sensor == NULL) { ++ gpio_free(*ce); ++ return -ENOMEM; ++ } ++ ++ sd = &sensor->sd; ++ v4l2_i2c_subdev_init(sd, client, &vs6624_ops); ++ ++ vs6624_writeregs(sd, vs6624_p1); ++ vs6624_write(sd, VS6624_MICRO_EN, 0x2); ++ vs6624_write(sd, VS6624_DIO_EN, 0x1); ++ mdelay(10); ++ vs6624_writeregs(sd, vs6624_p2); ++ ++ vs6624_writeregs(sd, vs6624_default); ++ vs6624_write(sd, VS6624_HSYNC_SETUP, 0xF); ++ vs6624_writeregs(sd, vs6624_run_setup); ++ ++ /* set frame rate */ ++ sensor->frame_rate.numerator = MAX_FRAME_RATE; ++ sensor->frame_rate.denominator = 1; ++ vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0); ++ vs6624_write(sd, VS6624_FR_NUM_MSB, ++ sensor->frame_rate.numerator >> 8); ++ vs6624_write(sd, VS6624_FR_NUM_LSB, ++ sensor->frame_rate.numerator & 0xFF); ++ vs6624_write(sd, VS6624_FR_DEN, ++ sensor->frame_rate.denominator & 0xFF); ++ ++ sensor->fmt = vs6624_default_fmt; ++ sensor->ce_pin = *ce; ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ hdl = &sensor->hdl; ++ v4l2_ctrl_handler_init(hdl, 4); ++ v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x87); ++ v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops, ++ V4L2_CID_SATURATION, 0, 0xFF, 1, 0x78); ++ v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ /* hook the control handler into the driver */ ++ sd->ctrl_handler = hdl; ++ if (hdl->error) { ++ int err = hdl->error; ++ ++ v4l2_ctrl_handler_free(hdl); ++ kfree(sensor); ++ gpio_free(*ce); ++ return err; ++ } ++ ++ /* initialize the hardware to the default control values */ ++ ret = v4l2_ctrl_handler_setup(hdl); ++ if (ret) { ++ v4l2_ctrl_handler_free(hdl); ++ kfree(sensor); ++ gpio_free(*ce); ++ } ++ return ret; ++} ++ ++static int __devexit vs6624_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct vs6624 *sensor = to_vs6624(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(sd->ctrl_handler); ++ gpio_free(sensor->ce_pin); ++ kfree(sensor); ++ return 0; ++} ++ ++static const struct i2c_device_id vs6624_id[] = { ++ {"vs6624", 0}, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(i2c, vs6624_id); ++ ++static struct i2c_driver vs6624_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "vs6624", ++ }, ++ .probe = vs6624_probe, ++ .remove = __devexit_p(vs6624_remove), ++ .id_table = vs6624_id, ++}; ++ ++static __init int vs6624_init(void) ++{ ++ return i2c_add_driver(&vs6624_driver); ++} ++ ++static __exit void vs6624_exit(void) ++{ ++ i2c_del_driver(&vs6624_driver); ++} ++ ++module_init(vs6624_init); ++module_exit(vs6624_exit); ++ ++MODULE_DESCRIPTION("VS6624 sensor driver"); ++MODULE_AUTHOR("Scott Jiang "); ++MODULE_LICENSE("GPL v2"); +Index: linux-3.3.x86_64/drivers/media/video/vs6624_regs.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/video/vs6624_regs.h +@@ -0,0 +1,337 @@ ++/* ++ * vs6624 - ST VS6624 CMOS image sensor registers ++ * ++ * Copyright (c) 2011 Analog Devices Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#ifndef _VS6624_REGS_H_ ++#define _VS6624_REGS_H_ ++ ++/* low level control registers */ ++#define VS6624_MICRO_EN 0xC003 /* power enable for all MCU clock */ ++#define VS6624_DIO_EN 0xC044 /* enable digital I/O */ ++/* device parameters */ ++#define VS6624_DEV_ID_MSB 0x0001 /* device id MSB */ ++#define VS6624_DEV_ID_LSB 0x0002 /* device id LSB */ ++#define VS6624_FW_VSN_MAJOR 0x0004 /* firmware version major */ ++#define VS6624_FW_VSN_MINOR 0x0006 /* firmware version minor */ ++#define VS6624_PATCH_VSN_MAJOR 0x0008 /* patch version major */ ++#define VS6624_PATCH_VSN_MINOR 0x000A /* patch version minor */ ++/* host interface manager control */ ++#define VS6624_USER_CMD 0x0180 /* user level control of operating states */ ++/* host interface manager status */ ++#define VS6624_STATE 0x0202 /* current state of the mode manager */ ++/* run mode control */ ++#define VS6624_METER_ON 0x0280 /* if false AE and AWB are disabled */ ++/* mode setup */ ++#define VS6624_ACTIVE_PIPE_SETUP 0x0302 /* select the active bank for non view live mode */ ++#define VS6624_SENSOR_MODE 0x0308 /* select the different sensor mode */ ++/* pipe setup bank0 */ ++#define VS6624_IMAGE_SIZE0 0x0380 /* required output dimension */ ++#define VS6624_MAN_HSIZE0_MSB 0x0383 /* input required manual H size MSB */ ++#define VS6624_MAN_HSIZE0_LSB 0x0384 /* input required manual H size LSB */ ++#define VS6624_MAN_VSIZE0_MSB 0x0387 /* input required manual V size MSB */ ++#define VS6624_MAN_VSIZE0_LSB 0x0388 /* input required manual V size LSB */ ++#define VS6624_ZOOM_HSTEP0_MSB 0x038B /* set the zoom H step MSB */ ++#define VS6624_ZOOM_HSTEP0_LSB 0x038C /* set the zoom H step LSB */ ++#define VS6624_ZOOM_VSTEP0_MSB 0x038F /* set the zoom V step MSB */ ++#define VS6624_ZOOM_VSTEP0_LSB 0x0390 /* set the zoom V step LSB */ ++#define VS6624_ZOOM_CTRL0 0x0392 /* control zoon in, out and stop */ ++#define VS6624_PAN_HSTEP0_MSB 0x0395 /* set the pan H step MSB */ ++#define VS6624_PAN_HSTEP0_LSB 0x0396 /* set the pan H step LSB */ ++#define VS6624_PAN_VSTEP0_MSB 0x0399 /* set the pan V step MSB */ ++#define VS6624_PAN_VSTEP0_LSB 0x039A /* set the pan V step LSB */ ++#define VS6624_PAN_CTRL0 0x039C /* control pan operation */ ++#define VS6624_CROP_CTRL0 0x039E /* select cropping mode */ ++#define VS6624_CROP_HSTART0_MSB 0x03A1 /* set the cropping H start address MSB */ ++#define VS6624_CROP_HSTART0_LSB 0x03A2 /* set the cropping H start address LSB */ ++#define VS6624_CROP_HSIZE0_MSB 0x03A5 /* set the cropping H size MSB */ ++#define VS6624_CROP_HSIZE0_LSB 0x03A6 /* set the cropping H size LSB */ ++#define VS6624_CROP_VSTART0_MSB 0x03A9 /* set the cropping V start address MSB */ ++#define VS6624_CROP_VSTART0_LSB 0x03AA /* set the cropping V start address LSB */ ++#define VS6624_CROP_VSIZE0_MSB 0x03AD /* set the cropping V size MSB */ ++#define VS6624_CROP_VSIZE0_LSB 0x03AE /* set the cropping V size LSB */ ++#define VS6624_IMG_FMT0 0x03B0 /* select required output image format */ ++#define VS6624_BAYER_OUT_ALIGN0 0x03B2 /* set bayer output alignment */ ++#define VS6624_CONTRAST0 0x03B4 /* contrast control for output */ ++#define VS6624_SATURATION0 0x03B6 /* saturation control for output */ ++#define VS6624_GAMMA0 0x03B8 /* gamma settings */ ++#define VS6624_HMIRROR0 0x03BA /* horizontal image orientation flip */ ++#define VS6624_VFLIP0 0x03BC /* vertical image orientation flip */ ++#define VS6624_CHANNEL_ID0 0x03BE /* logical DMA channel number */ ++/* pipe setup bank1 */ ++#define VS6624_IMAGE_SIZE1 0x0400 /* required output dimension */ ++#define VS6624_MAN_HSIZE1_MSB 0x0403 /* input required manual H size MSB */ ++#define VS6624_MAN_HSIZE1_LSB 0x0404 /* input required manual H size LSB */ ++#define VS6624_MAN_VSIZE1_MSB 0x0407 /* input required manual V size MSB */ ++#define VS6624_MAN_VSIZE1_LSB 0x0408 /* input required manual V size LSB */ ++#define VS6624_ZOOM_HSTEP1_MSB 0x040B /* set the zoom H step MSB */ ++#define VS6624_ZOOM_HSTEP1_LSB 0x040C /* set the zoom H step LSB */ ++#define VS6624_ZOOM_VSTEP1_MSB 0x040F /* set the zoom V step MSB */ ++#define VS6624_ZOOM_VSTEP1_LSB 0x0410 /* set the zoom V step LSB */ ++#define VS6624_ZOOM_CTRL1 0x0412 /* control zoon in, out and stop */ ++#define VS6624_PAN_HSTEP1_MSB 0x0415 /* set the pan H step MSB */ ++#define VS6624_PAN_HSTEP1_LSB 0x0416 /* set the pan H step LSB */ ++#define VS6624_PAN_VSTEP1_MSB 0x0419 /* set the pan V step MSB */ ++#define VS6624_PAN_VSTEP1_LSB 0x041A /* set the pan V step LSB */ ++#define VS6624_PAN_CTRL1 0x041C /* control pan operation */ ++#define VS6624_CROP_CTRL1 0x041E /* select cropping mode */ ++#define VS6624_CROP_HSTART1_MSB 0x0421 /* set the cropping H start address MSB */ ++#define VS6624_CROP_HSTART1_LSB 0x0422 /* set the cropping H start address LSB */ ++#define VS6624_CROP_HSIZE1_MSB 0x0425 /* set the cropping H size MSB */ ++#define VS6624_CROP_HSIZE1_LSB 0x0426 /* set the cropping H size LSB */ ++#define VS6624_CROP_VSTART1_MSB 0x0429 /* set the cropping V start address MSB */ ++#define VS6624_CROP_VSTART1_LSB 0x042A /* set the cropping V start address LSB */ ++#define VS6624_CROP_VSIZE1_MSB 0x042D /* set the cropping V size MSB */ ++#define VS6624_CROP_VSIZE1_LSB 0x042E /* set the cropping V size LSB */ ++#define VS6624_IMG_FMT1 0x0430 /* select required output image format */ ++#define VS6624_BAYER_OUT_ALIGN1 0x0432 /* set bayer output alignment */ ++#define VS6624_CONTRAST1 0x0434 /* contrast control for output */ ++#define VS6624_SATURATION1 0x0436 /* saturation control for output */ ++#define VS6624_GAMMA1 0x0438 /* gamma settings */ ++#define VS6624_HMIRROR1 0x043A /* horizontal image orientation flip */ ++#define VS6624_VFLIP1 0x043C /* vertical image orientation flip */ ++#define VS6624_CHANNEL_ID1 0x043E /* logical DMA channel number */ ++/* view live control */ ++#define VS6624_VIEW_LIVE_EN 0x0480 /* enable view live mode */ ++#define VS6624_INIT_PIPE_SETUP 0x0482 /* select initial pipe setup bank */ ++/* view live status */ ++#define VS6624_CUR_PIPE_SETUP 0x0500 /* indicates most recently applied setup bank */ ++/* power management */ ++#define VS6624_TIME_TO_POWER_DOWN 0x0580 /* automatically transition time to stop mode */ ++/* video timing parameter host inputs */ ++#define VS6624_EXT_CLK_FREQ_NUM_MSB 0x0605 /* external clock frequency numerator MSB */ ++#define VS6624_EXT_CLK_FREQ_NUM_LSB 0x0606 /* external clock frequency numerator LSB */ ++#define VS6624_EXT_CLK_FREQ_DEN 0x0608 /* external clock frequency denominator */ ++/* video timing control */ ++#define VS6624_SYS_CLK_MODE 0x0880 /* decides system clock frequency */ ++/* frame dimension parameter host inputs */ ++#define VS6624_LIGHT_FREQ 0x0C80 /* AC frequency used for flicker free time */ ++#define VS6624_FLICKER_COMPAT 0x0C82 /* flicker compatible frame length */ ++/* static frame rate control */ ++#define VS6624_FR_NUM_MSB 0x0D81 /* desired frame rate numerator MSB */ ++#define VS6624_FR_NUM_LSB 0x0D82 /* desired frame rate numerator LSB */ ++#define VS6624_FR_DEN 0x0D84 /* desired frame rate denominator */ ++/* automatic frame rate control */ ++#define VS6624_DISABLE_FR_DAMPER 0x0E80 /* defines frame rate mode */ ++#define VS6624_MIN_DAMPER_OUT_MSB 0x0E8C /* minimum frame rate MSB */ ++#define VS6624_MIN_DAMPER_OUT_LSB 0x0E8A /* minimum frame rate LSB */ ++/* exposure controls */ ++#define VS6624_EXPO_MODE 0x1180 /* exposure mode */ ++#define VS6624_EXPO_METER 0x1182 /* weights to be associated with the zones */ ++#define VS6624_EXPO_TIME_NUM 0x1184 /* exposure time numerator */ ++#define VS6624_EXPO_TIME_DEN 0x1186 /* exposure time denominator */ ++#define VS6624_EXPO_TIME_MSB 0x1189 /* exposure time for the Manual Mode MSB */ ++#define VS6624_EXPO_TIME_LSB 0x118A /* exposure time for the Manual Mode LSB */ ++#define VS6624_EXPO_COMPENSATION 0x1190 /* exposure compensation */ ++#define VS6624_DIRECT_COARSE_MSB 0x1195 /* coarse integration lines for Direct Mode MSB */ ++#define VS6624_DIRECT_COARSE_LSB 0x1196 /* coarse integration lines for Direct Mode LSB */ ++#define VS6624_DIRECT_FINE_MSB 0x1199 /* fine integration pixels for Direct Mode MSB */ ++#define VS6624_DIRECT_FINE_LSB 0x119A /* fine integration pixels for Direct Mode LSB */ ++#define VS6624_DIRECT_ANAL_GAIN_MSB 0x119D /* analog gain for Direct Mode MSB */ ++#define VS6624_DIRECT_ANAL_GAIN_LSB 0x119E /* analog gain for Direct Mode LSB */ ++#define VS6624_DIRECT_DIGI_GAIN_MSB 0x11A1 /* digital gain for Direct Mode MSB */ ++#define VS6624_DIRECT_DIGI_GAIN_LSB 0x11A2 /* digital gain for Direct Mode LSB */ ++#define VS6624_FLASH_COARSE_MSB 0x11A5 /* coarse integration lines for Flash Gun Mode MSB */ ++#define VS6624_FLASH_COARSE_LSB 0x11A6 /* coarse integration lines for Flash Gun Mode LSB */ ++#define VS6624_FLASH_FINE_MSB 0x11A9 /* fine integration pixels for Flash Gun Mode MSB */ ++#define VS6624_FLASH_FINE_LSB 0x11AA /* fine integration pixels for Flash Gun Mode LSB */ ++#define VS6624_FLASH_ANAL_GAIN_MSB 0x11AD /* analog gain for Flash Gun Mode MSB */ ++#define VS6624_FLASH_ANAL_GAIN_LSB 0x11AE /* analog gain for Flash Gun Mode LSB */ ++#define VS6624_FLASH_DIGI_GAIN_MSB 0x11B1 /* digital gain for Flash Gun Mode MSB */ ++#define VS6624_FLASH_DIGI_GAIN_LSB 0x11B2 /* digital gain for Flash Gun Mode LSB */ ++#define VS6624_FREEZE_AE 0x11B4 /* freeze auto exposure */ ++#define VS6624_MAX_INT_TIME_MSB 0x11B7 /* user maximum integration time MSB */ ++#define VS6624_MAX_INT_TIME_LSB 0x11B8 /* user maximum integration time LSB */ ++#define VS6624_FLASH_AG_THR_MSB 0x11BB /* recommend flash gun analog gain threshold MSB */ ++#define VS6624_FLASH_AG_THR_LSB 0x11BC /* recommend flash gun analog gain threshold LSB */ ++#define VS6624_ANTI_FLICKER_MODE 0x11C0 /* anti flicker mode */ ++/* white balance control */ ++#define VS6624_WB_MODE 0x1480 /* set white balance mode */ ++#define VS6624_MAN_RG 0x1482 /* user setting for red channel gain */ ++#define VS6624_MAN_GG 0x1484 /* user setting for green channel gain */ ++#define VS6624_MAN_BG 0x1486 /* user setting for blue channel gain */ ++#define VS6624_FLASH_RG_MSB 0x148B /* red gain for Flash Gun MSB */ ++#define VS6624_FLASH_RG_LSB 0x148C /* red gain for Flash Gun LSB */ ++#define VS6624_FLASH_GG_MSB 0x148F /* green gain for Flash Gun MSB */ ++#define VS6624_FLASH_GG_LSB 0x1490 /* green gain for Flash Gun LSB */ ++#define VS6624_FLASH_BG_MSB 0x1493 /* blue gain for Flash Gun MSB */ ++#define VS6624_FLASH_BG_LSB 0x1494 /* blue gain for Flash Gun LSB */ ++/* sensor setup */ ++#define VS6624_BC_OFFSET 0x1990 /* Black Correction Offset */ ++/* image stability */ ++#define VS6624_STABLE_WB 0x1900 /* white balance stable */ ++#define VS6624_STABLE_EXPO 0x1902 /* exposure stable */ ++#define VS6624_STABLE 0x1906 /* system stable */ ++/* flash control */ ++#define VS6624_FLASH_MODE 0x1A80 /* flash mode */ ++#define VS6624_FLASH_OFF_LINE_MSB 0x1A83 /* off line at flash pulse mode MSB */ ++#define VS6624_FLASH_OFF_LINE_LSB 0x1A84 /* off line at flash pulse mode LSB */ ++/* flash status */ ++#define VS6624_FLASH_RECOM 0x1B00 /* flash gun is recommended */ ++#define VS6624_FLASH_GRAB_COMPLETE 0x1B02 /* flash gun image has been grabbed */ ++/* scythe filter controls */ ++#define VS6624_SCYTHE_FILTER 0x1D80 /* disable scythe defect correction */ ++/* jack filter controls */ ++#define VS6624_JACK_FILTER 0x1E00 /* disable jack defect correction */ ++/* demosaic control */ ++#define VS6624_ANTI_ALIAS_FILTER 0x1E80 /* anti alias filter suppress */ ++/* color matrix dampers */ ++#define VS6624_CM_DISABLE 0x1F00 /* disable color matrix damper */ ++#define VS6624_CM_LOW_THR_MSB 0x1F03 /* low threshold for exposure MSB */ ++#define VS6624_CM_LOW_THR_LSB 0x1F04 /* low threshold for exposure LSB */ ++#define VS6624_CM_HIGH_THR_MSB 0x1F07 /* high threshold for exposure MSB */ ++#define VS6624_CM_HIGH_THR_LSB 0x1F08 /* high threshold for exposure LSB */ ++#define VS6624_CM_MIN_OUT_MSB 0x1F0B /* minimum possible damper output MSB */ ++#define VS6624_CM_MIN_OUT_LSB 0x1F0C /* minimum possible damper output LSB */ ++/* peaking control */ ++#define VS6624_PEAK_GAIN 0x2000 /* controls peaking gain */ ++#define VS6624_PEAK_G_DISABLE 0x2002 /* disable peak gain damping */ ++#define VS6624_PEAK_LOW_THR_G_MSB 0x2005 /* low threshold for exposure for gain MSB */ ++#define VS6624_PEAK_LOW_THR_G_LSB 0x2006 /* low threshold for exposure for gain LSB */ ++#define VS6624_PEAK_HIGH_THR_G_MSB 0x2009 /* high threshold for exposure for gain MSB */ ++#define VS6624_PEAK_HIGH_THR_G_LSB 0x200A /* high threshold for exposure for gain LSB */ ++#define VS6624_PEAK_MIN_OUT_G_MSB 0x200D /* minimum damper output for gain MSB */ ++#define VS6624_PEAK_MIN_OUT_G_LSB 0x200E /* minimum damper output for gain LSB */ ++#define VS6624_PEAK_LOW_THR 0x2010 /* adjust degree of coring */ ++#define VS6624_PEAK_C_DISABLE 0x2012 /* disable coring damping */ ++#define VS6624_PEAK_HIGH_THR 0x2014 /* adjust maximum gain */ ++#define VS6624_PEAK_LOW_THR_C_MSB 0x2017 /* low threshold for exposure for coring MSB */ ++#define VS6624_PEAK_LOW_THR_C_LSB 0x2018 /* low threshold for exposure for coring LSB */ ++#define VS6624_PEAK_HIGH_THR_C_MSB 0x201B /* high threshold for exposure for coring MSB */ ++#define VS6624_PEAK_HIGH_THR_C_LSB 0x201C /* high threshold for exposure for coring LSB */ ++#define VS6624_PEAK_MIN_OUT_C_MSB 0x201F /* minimum damper output for coring MSB */ ++#define VS6624_PEAK_MIN_OUT_C_LSB 0x2020 /* minimum damper output for coring LSB */ ++/* pipe 0 RGB to YUV matrix manual control */ ++#define VS6624_RYM0_MAN_CTRL 0x2180 /* enable manual RGB to YUV matrix */ ++#define VS6624_RYM0_W00_MSB 0x2183 /* row 0 column 0 of YUV matrix MSB */ ++#define VS6624_RYM0_W00_LSB 0x2184 /* row 0 column 0 of YUV matrix LSB */ ++#define VS6624_RYM0_W01_MSB 0x2187 /* row 0 column 1 of YUV matrix MSB */ ++#define VS6624_RYM0_W01_LSB 0x2188 /* row 0 column 1 of YUV matrix LSB */ ++#define VS6624_RYM0_W02_MSB 0x218C /* row 0 column 2 of YUV matrix MSB */ ++#define VS6624_RYM0_W02_LSB 0x218D /* row 0 column 2 of YUV matrix LSB */ ++#define VS6624_RYM0_W10_MSB 0x2190 /* row 1 column 0 of YUV matrix MSB */ ++#define VS6624_RYM0_W10_LSB 0x218F /* row 1 column 0 of YUV matrix LSB */ ++#define VS6624_RYM0_W11_MSB 0x2193 /* row 1 column 1 of YUV matrix MSB */ ++#define VS6624_RYM0_W11_LSB 0x2194 /* row 1 column 1 of YUV matrix LSB */ ++#define VS6624_RYM0_W12_MSB 0x2197 /* row 1 column 2 of YUV matrix MSB */ ++#define VS6624_RYM0_W12_LSB 0x2198 /* row 1 column 2 of YUV matrix LSB */ ++#define VS6624_RYM0_W20_MSB 0x219B /* row 2 column 0 of YUV matrix MSB */ ++#define VS6624_RYM0_W20_LSB 0x219C /* row 2 column 0 of YUV matrix LSB */ ++#define VS6624_RYM0_W21_MSB 0x21A0 /* row 2 column 1 of YUV matrix MSB */ ++#define VS6624_RYM0_W21_LSB 0x219F /* row 2 column 1 of YUV matrix LSB */ ++#define VS6624_RYM0_W22_MSB 0x21A3 /* row 2 column 2 of YUV matrix MSB */ ++#define VS6624_RYM0_W22_LSB 0x21A4 /* row 2 column 2 of YUV matrix LSB */ ++#define VS6624_RYM0_YINY_MSB 0x21A7 /* Y in Y MSB */ ++#define VS6624_RYM0_YINY_LSB 0x21A8 /* Y in Y LSB */ ++#define VS6624_RYM0_YINCB_MSB 0x21AB /* Y in Cb MSB */ ++#define VS6624_RYM0_YINCB_LSB 0x21AC /* Y in Cb LSB */ ++#define VS6624_RYM0_YINCR_MSB 0x21B0 /* Y in Cr MSB */ ++#define VS6624_RYM0_YINCR_LSB 0x21AF /* Y in Cr LSB */ ++/* pipe 1 RGB to YUV matrix manual control */ ++#define VS6624_RYM1_MAN_CTRL 0x2200 /* enable manual RGB to YUV matrix */ ++#define VS6624_RYM1_W00_MSB 0x2203 /* row 0 column 0 of YUV matrix MSB */ ++#define VS6624_RYM1_W00_LSB 0x2204 /* row 0 column 0 of YUV matrix LSB */ ++#define VS6624_RYM1_W01_MSB 0x2207 /* row 0 column 1 of YUV matrix MSB */ ++#define VS6624_RYM1_W01_LSB 0x2208 /* row 0 column 1 of YUV matrix LSB */ ++#define VS6624_RYM1_W02_MSB 0x220C /* row 0 column 2 of YUV matrix MSB */ ++#define VS6624_RYM1_W02_LSB 0x220D /* row 0 column 2 of YUV matrix LSB */ ++#define VS6624_RYM1_W10_MSB 0x2210 /* row 1 column 0 of YUV matrix MSB */ ++#define VS6624_RYM1_W10_LSB 0x220F /* row 1 column 0 of YUV matrix LSB */ ++#define VS6624_RYM1_W11_MSB 0x2213 /* row 1 column 1 of YUV matrix MSB */ ++#define VS6624_RYM1_W11_LSB 0x2214 /* row 1 column 1 of YUV matrix LSB */ ++#define VS6624_RYM1_W12_MSB 0x2217 /* row 1 column 2 of YUV matrix MSB */ ++#define VS6624_RYM1_W12_LSB 0x2218 /* row 1 column 2 of YUV matrix LSB */ ++#define VS6624_RYM1_W20_MSB 0x221B /* row 2 column 0 of YUV matrix MSB */ ++#define VS6624_RYM1_W20_LSB 0x221C /* row 2 column 0 of YUV matrix LSB */ ++#define VS6624_RYM1_W21_MSB 0x2220 /* row 2 column 1 of YUV matrix MSB */ ++#define VS6624_RYM1_W21_LSB 0x221F /* row 2 column 1 of YUV matrix LSB */ ++#define VS6624_RYM1_W22_MSB 0x2223 /* row 2 column 2 of YUV matrix MSB */ ++#define VS6624_RYM1_W22_LSB 0x2224 /* row 2 column 2 of YUV matrix LSB */ ++#define VS6624_RYM1_YINY_MSB 0x2227 /* Y in Y MSB */ ++#define VS6624_RYM1_YINY_LSB 0x2228 /* Y in Y LSB */ ++#define VS6624_RYM1_YINCB_MSB 0x222B /* Y in Cb MSB */ ++#define VS6624_RYM1_YINCB_LSB 0x222C /* Y in Cb LSB */ ++#define VS6624_RYM1_YINCR_MSB 0x2220 /* Y in Cr MSB */ ++#define VS6624_RYM1_YINCR_LSB 0x222F /* Y in Cr LSB */ ++/* pipe 0 gamma manual control */ ++#define VS6624_GAMMA_MAN_CTRL0 0x2280 /* enable manual gamma setup */ ++#define VS6624_GAMMA_PEAK_R0 0x2282 /* peaked red channel gamma value */ ++#define VS6624_GAMMA_PEAK_G0 0x2284 /* peaked green channel gamma value */ ++#define VS6624_GAMMA_PEAK_B0 0x2286 /* peaked blue channel gamma value */ ++#define VS6624_GAMMA_UNPEAK_R0 0x2288 /* unpeaked red channel gamma value */ ++#define VS6624_GAMMA_UNPEAK_G0 0x228A /* unpeaked green channel gamma value */ ++#define VS6624_GAMMA_UNPEAK_B0 0x228C /* unpeaked blue channel gamma value */ ++/* pipe 1 gamma manual control */ ++#define VS6624_GAMMA_MAN_CTRL1 0x2300 /* enable manual gamma setup */ ++#define VS6624_GAMMA_PEAK_R1 0x2302 /* peaked red channel gamma value */ ++#define VS6624_GAMMA_PEAK_G1 0x2304 /* peaked green channel gamma value */ ++#define VS6624_GAMMA_PEAK_B1 0x2306 /* peaked blue channel gamma value */ ++#define VS6624_GAMMA_UNPEAK_R1 0x2308 /* unpeaked red channel gamma value */ ++#define VS6624_GAMMA_UNPEAK_G1 0x230A /* unpeaked green channel gamma value */ ++#define VS6624_GAMMA_UNPEAK_B1 0x230C /* unpeaked blue channel gamma value */ ++/* fade to black */ ++#define VS6624_F2B_DISABLE 0x2480 /* disable fade to black */ ++#define VS6624_F2B_BLACK_VAL_MSB 0x2483 /* black value MSB */ ++#define VS6624_F2B_BLACK_VAL_LSB 0x2484 /* black value LSB */ ++#define VS6624_F2B_LOW_THR_MSB 0x2487 /* low threshold for exposure MSB */ ++#define VS6624_F2B_LOW_THR_LSB 0x2488 /* low threshold for exposure LSB */ ++#define VS6624_F2B_HIGH_THR_MSB 0x248B /* high threshold for exposure MSB */ ++#define VS6624_F2B_HIGH_THR_LSB 0x248C /* high threshold for exposure LSB */ ++#define VS6624_F2B_MIN_OUT_MSB 0x248F /* minimum damper output MSB */ ++#define VS6624_F2B_MIN_OUT_LSB 0x2490 /* minimum damper output LSB */ ++/* output formatter control */ ++#define VS6624_CODE_CK_EN 0x2580 /* code check enable */ ++#define VS6624_BLANK_FMT 0x2582 /* blank format */ ++#define VS6624_SYNC_CODE_SETUP 0x2584 /* sync code setup */ ++#define VS6624_HSYNC_SETUP 0x2586 /* H sync setup */ ++#define VS6624_VSYNC_SETUP 0x2588 /* V sync setup */ ++#define VS6624_PCLK_SETUP 0x258A /* PCLK setup */ ++#define VS6624_PCLK_EN 0x258C /* PCLK enable */ ++#define VS6624_OPF_SP_SETUP 0x258E /* output formatter sp setup */ ++#define VS6624_BLANK_DATA_MSB 0x2590 /* blank data MSB */ ++#define VS6624_BLANK_DATA_LSB 0x2592 /* blank data LSB */ ++#define VS6624_RGB_SETUP 0x2594 /* RGB setup */ ++#define VS6624_YUV_SETUP 0x2596 /* YUV setup */ ++#define VS6624_VSYNC_RIS_COARSE_H 0x2598 /* V sync rising coarse high */ ++#define VS6624_VSYNC_RIS_COARSE_L 0x259A /* V sync rising coarse low */ ++#define VS6624_VSYNC_RIS_FINE_H 0x259C /* V sync rising fine high */ ++#define VS6624_VSYNC_RIS_FINE_L 0x259E /* V sync rising fine low */ ++#define VS6624_VSYNC_FALL_COARSE_H 0x25A0 /* V sync falling coarse high */ ++#define VS6624_VSYNC_FALL_COARSE_L 0x25A2 /* V sync falling coarse low */ ++#define VS6624_VSYNC_FALL_FINE_H 0x25A4 /* V sync falling fine high */ ++#define VS6624_VSYNC_FALL_FINE_L 0x25A6 /* V sync falling fine low */ ++#define VS6624_HSYNC_RIS_H 0x25A8 /* H sync rising high */ ++#define VS6624_HSYNC_RIS_L 0x25AA /* H sync rising low */ ++#define VS6624_HSYNC_FALL_H 0x25AC /* H sync falling high */ ++#define VS6624_HSYNC_FALL_L 0x25AE /* H sync falling low */ ++#define VS6624_OUT_IF 0x25B0 /* output interface */ ++#define VS6624_CCP_EXT_DATA 0x25B2 /* CCP extra data */ ++/* NoRA controls */ ++#define VS6624_NORA_DISABLE 0x2600 /* NoRA control mode */ ++#define VS6624_NORA_USAGE 0x2602 /* usage */ ++#define VS6624_NORA_SPLIT_KN 0x2604 /* split kn */ ++#define VS6624_NORA_SPLIT_NI 0x2606 /* split ni */ ++#define VS6624_NORA_TIGHT_G 0x2608 /* tight green */ ++#define VS6624_NORA_DISABLE_NP 0x260A /* disable noro promoting */ ++#define VS6624_NORA_LOW_THR_MSB 0x260D /* low threshold for exposure MSB */ ++#define VS6624_NORA_LOW_THR_LSB 0x260E /* low threshold for exposure LSB */ ++#define VS6624_NORA_HIGH_THR_MSB 0x2611 /* high threshold for exposure MSB */ ++#define VS6624_NORA_HIGH_THR_LSB 0x2612 /* high threshold for exposure LSB */ ++#define VS6624_NORA_MIN_OUT_MSB 0x2615 /* minimum damper output MSB */ ++#define VS6624_NORA_MIN_OUT_LSB 0x2616 /* minimum damper output LSB */ ++ ++#endif +Index: linux-3.3.x86_64/drivers/media/video/blackfin/Kconfig +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/video/blackfin/Kconfig +@@ -0,0 +1,10 @@ ++config VIDEO_BLACKFIN_CAPTURE ++ tristate "Blackfin Video Capture Driver" ++ depends on VIDEO_V4L2 && BLACKFIN && I2C ++ select VIDEOBUF2_DMA_CONTIG ++ help ++ V4L2 bridge driver for Blackfin video capture device. ++ Choose PPI or EPPI as its interface. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called bfin_video_capture. +Index: linux-3.3.x86_64/drivers/media/video/blackfin/Makefile +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/video/blackfin/Makefile +@@ -0,0 +1,2 @@ ++bfin_video_capture-objs := bfin_capture.o ppi.o ++obj-$(CONFIG_VIDEO_BLACKFIN_CAPTURE) += bfin_video_capture.o +Index: linux-3.3.x86_64/drivers/media/video/blackfin/bfin_capture.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/video/blackfin/bfin_capture.c +@@ -0,0 +1,1059 @@ ++/* ++ * Analog Devices video capture driver ++ * ++ * Copyright (c) 2011 Analog Devices Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++#define CAPTURE_DRV_NAME "bfin_capture" ++#define BCAP_MIN_NUM_BUF 2 ++ ++struct bcap_format { ++ char *desc; ++ u32 pixelformat; ++ enum v4l2_mbus_pixelcode mbus_code; ++ int bpp; /* bits per pixel */ ++}; ++ ++struct bcap_buffer { ++ struct vb2_buffer vb; ++ struct list_head list; ++}; ++ ++struct bcap_device { ++ /* capture device instance */ ++ struct v4l2_device v4l2_dev; ++ /* v4l2 control handler */ ++ struct v4l2_ctrl_handler ctrl_handler; ++ /* device node data */ ++ struct video_device *video_dev; ++ /* sub device instance */ ++ struct v4l2_subdev *sd; ++ /* capture config */ ++ struct bfin_capture_config *cfg; ++ /* ppi interface */ ++ struct ppi_if *ppi; ++ /* current input */ ++ unsigned int cur_input; ++ /* current selected standard */ ++ v4l2_std_id std; ++ /* used to store pixel format */ ++ struct v4l2_pix_format fmt; ++ /* bits per pixel*/ ++ int bpp; ++ /* used to store sensor supported format */ ++ struct bcap_format *sensor_formats; ++ /* number of sensor formats array */ ++ int num_sensor_formats; ++ /* pointing to current video buffer */ ++ struct bcap_buffer *cur_frm; ++ /* pointing to next video buffer */ ++ struct bcap_buffer *next_frm; ++ /* buffer queue used in videobuf2 */ ++ struct vb2_queue buffer_queue; ++ /* allocator-specific contexts for each plane */ ++ struct vb2_alloc_ctx *alloc_ctx; ++ /* queue of filled frames */ ++ struct list_head dma_queue; ++ /* used in videobuf2 callback */ ++ spinlock_t lock; ++ /* used to access capture device */ ++ struct mutex mutex; ++ /* used to wait ppi to complete one transfer */ ++ struct completion comp; ++ /* prepare to stop */ ++ bool stop; ++}; ++ ++struct bcap_fh { ++ struct v4l2_fh fh; ++ /* indicates whether this file handle is doing IO */ ++ bool io_allowed; ++}; ++ ++static const struct bcap_format bcap_formats[] = { ++ { ++ .desc = "YCbCr 4:2:2 Interleaved UYVY", ++ .pixelformat = V4L2_PIX_FMT_UYVY, ++ .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, ++ .bpp = 16, ++ }, ++ { ++ .desc = "YCbCr 4:2:2 Interleaved YUYV", ++ .pixelformat = V4L2_PIX_FMT_YUYV, ++ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, ++ .bpp = 16, ++ }, ++ { ++ .desc = "RGB 565", ++ .pixelformat = V4L2_PIX_FMT_RGB565, ++ .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE, ++ .bpp = 16, ++ }, ++ { ++ .desc = "RGB 444", ++ .pixelformat = V4L2_PIX_FMT_RGB444, ++ .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE, ++ .bpp = 16, ++ }, ++ ++}; ++#define BCAP_MAX_FMTS ARRAY_SIZE(bcap_formats) ++ ++static irqreturn_t bcap_isr(int irq, void *dev_id); ++ ++static struct bcap_buffer *to_bcap_vb(struct vb2_buffer *vb) ++{ ++ return container_of(vb, struct bcap_buffer, vb); ++} ++ ++static int bcap_init_sensor_formats(struct bcap_device *bcap_dev) ++{ ++ enum v4l2_mbus_pixelcode code; ++ struct bcap_format *sf; ++ unsigned int num_formats = 0; ++ int i, j; ++ ++ while (!v4l2_subdev_call(bcap_dev->sd, video, ++ enum_mbus_fmt, num_formats, &code)) ++ num_formats++; ++ if (!num_formats) ++ return -ENXIO; ++ ++ sf = kzalloc(num_formats * sizeof(*sf), GFP_KERNEL); ++ if (!sf) ++ return -ENOMEM; ++ ++ for (i = 0; i < num_formats; i++) { ++ v4l2_subdev_call(bcap_dev->sd, video, ++ enum_mbus_fmt, i, &code); ++ for (j = 0; j < BCAP_MAX_FMTS; j++) ++ if (code == bcap_formats[j].mbus_code) ++ break; ++ if (j == BCAP_MAX_FMTS) { ++ /* we don't allow this sensor working with our bridge */ ++ kfree(sf); ++ return -EINVAL; ++ } ++ sf[i] = bcap_formats[j]; ++ } ++ bcap_dev->sensor_formats = sf; ++ bcap_dev->num_sensor_formats = num_formats; ++ return 0; ++} ++ ++static void bcap_free_sensor_formats(struct bcap_device *bcap_dev) ++{ ++ bcap_dev->num_sensor_formats = 0; ++ kfree(bcap_dev->sensor_formats); ++ bcap_dev->sensor_formats = NULL; ++} ++ ++static int bcap_open(struct file *file) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ struct video_device *vfd = bcap_dev->video_dev; ++ struct bcap_fh *bcap_fh; ++ ++ if (!bcap_dev->sd) { ++ v4l2_err(&bcap_dev->v4l2_dev, "No sub device registered\n"); ++ return -ENODEV; ++ } ++ ++ bcap_fh = kzalloc(sizeof(*bcap_fh), GFP_KERNEL); ++ if (!bcap_fh) { ++ v4l2_err(&bcap_dev->v4l2_dev, ++ "unable to allocate memory for file handle object\n"); ++ return -ENOMEM; ++ } ++ ++ v4l2_fh_init(&bcap_fh->fh, vfd); ++ ++ /* store pointer to v4l2_fh in private_data member of file */ ++ file->private_data = &bcap_fh->fh; ++ v4l2_fh_add(&bcap_fh->fh); ++ bcap_fh->io_allowed = false; ++ return 0; ++} ++ ++static int bcap_release(struct file *file) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ struct v4l2_fh *fh = file->private_data; ++ struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); ++ ++ /* if this instance is doing IO */ ++ if (bcap_fh->io_allowed) ++ vb2_queue_release(&bcap_dev->buffer_queue); ++ ++ file->private_data = NULL; ++ v4l2_fh_del(&bcap_fh->fh); ++ v4l2_fh_exit(&bcap_fh->fh); ++ kfree(bcap_fh); ++ return 0; ++} ++ ++static int bcap_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ ++ return vb2_mmap(&bcap_dev->buffer_queue, vma); ++} ++ ++#ifndef CONFIG_MMU ++static unsigned long bcap_get_unmapped_area(struct file *file, ++ unsigned long addr, ++ unsigned long len, ++ unsigned long pgoff, ++ unsigned long flags) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ ++ return vb2_get_unmapped_area(&bcap_dev->buffer_queue, ++ addr, ++ len, ++ pgoff, ++ flags); ++} ++#endif ++ ++static unsigned int bcap_poll(struct file *file, poll_table *wait) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ ++ return vb2_poll(&bcap_dev->buffer_queue, file, wait); ++} ++ ++static int bcap_queue_setup(struct vb2_queue *vq, ++ const struct v4l2_format *fmt, ++ unsigned int *nbuffers, unsigned int *nplanes, ++ unsigned int sizes[], void *alloc_ctxs[]) ++{ ++ struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); ++ ++ if (*nbuffers < BCAP_MIN_NUM_BUF) ++ *nbuffers = BCAP_MIN_NUM_BUF; ++ ++ *nplanes = 1; ++ sizes[0] = bcap_dev->fmt.sizeimage; ++ alloc_ctxs[0] = bcap_dev->alloc_ctx; ++ ++ return 0; ++} ++ ++static int bcap_buffer_init(struct vb2_buffer *vb) ++{ ++ struct bcap_buffer *buf = to_bcap_vb(vb); ++ ++ INIT_LIST_HEAD(&buf->list); ++ return 0; ++} ++ ++static int bcap_buffer_prepare(struct vb2_buffer *vb) ++{ ++ struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); ++ struct bcap_buffer *buf = to_bcap_vb(vb); ++ unsigned long size; ++ ++ size = bcap_dev->fmt.sizeimage; ++ if (vb2_plane_size(vb, 0) < size) { ++ v4l2_err(&bcap_dev->v4l2_dev, "buffer too small (%lu < %lu)\n", ++ vb2_plane_size(vb, 0), size); ++ return -EINVAL; ++ } ++ vb2_set_plane_payload(&buf->vb, 0, size); ++ ++ return 0; ++} ++ ++static void bcap_buffer_queue(struct vb2_buffer *vb) ++{ ++ struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); ++ struct bcap_buffer *buf = to_bcap_vb(vb); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&bcap_dev->lock, flags); ++ list_add_tail(&buf->list, &bcap_dev->dma_queue); ++ spin_unlock_irqrestore(&bcap_dev->lock, flags); ++} ++ ++static void bcap_buffer_cleanup(struct vb2_buffer *vb) ++{ ++ struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); ++ struct bcap_buffer *buf = to_bcap_vb(vb); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&bcap_dev->lock, flags); ++ list_del_init(&buf->list); ++ spin_unlock_irqrestore(&bcap_dev->lock, flags); ++} ++ ++static void bcap_lock(struct vb2_queue *vq) ++{ ++ struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); ++ mutex_lock(&bcap_dev->mutex); ++} ++ ++static void bcap_unlock(struct vb2_queue *vq) ++{ ++ struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); ++ mutex_unlock(&bcap_dev->mutex); ++} ++ ++static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count) ++{ ++ struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); ++ struct ppi_if *ppi = bcap_dev->ppi; ++ struct ppi_params params; ++ int ret; ++ ++ /* enable streamon on the sub device */ ++ ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 1); ++ if (ret && (ret != -ENOIOCTLCMD)) { ++ v4l2_err(&bcap_dev->v4l2_dev, "stream on failed in subdev\n"); ++ return ret; ++ } ++ ++ /* set ppi params */ ++ params.width = bcap_dev->fmt.width; ++ params.height = bcap_dev->fmt.height; ++ params.bpp = bcap_dev->bpp; ++ params.ppi_control = bcap_dev->cfg->ppi_control; ++ params.int_mask = bcap_dev->cfg->int_mask; ++ params.blank_clocks = bcap_dev->cfg->blank_clocks; ++ ret = ppi->ops->set_params(ppi, ¶ms); ++ if (ret < 0) { ++ v4l2_err(&bcap_dev->v4l2_dev, ++ "Error in setting ppi params\n"); ++ return ret; ++ } ++ ++ /* attach ppi DMA irq handler */ ++ ret = ppi->ops->attach_irq(ppi, bcap_isr); ++ if (ret < 0) { ++ v4l2_err(&bcap_dev->v4l2_dev, ++ "Error in attaching interrupt handler\n"); ++ return ret; ++ } ++ ++ INIT_COMPLETION(bcap_dev->comp); ++ bcap_dev->stop = false; ++ return 0; ++} ++ ++static int bcap_stop_streaming(struct vb2_queue *vq) ++{ ++ struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); ++ struct ppi_if *ppi = bcap_dev->ppi; ++ int ret; ++ ++ if (!vb2_is_streaming(vq)) ++ return 0; ++ ++ bcap_dev->stop = true; ++ wait_for_completion(&bcap_dev->comp); ++ ppi->ops->stop(ppi); ++ ppi->ops->detach_irq(ppi); ++ ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 0); ++ if (ret && (ret != -ENOIOCTLCMD)) ++ v4l2_err(&bcap_dev->v4l2_dev, ++ "stream off failed in subdev\n"); ++ ++ /* release all active buffers */ ++ while (!list_empty(&bcap_dev->dma_queue)) { ++ bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next, ++ struct bcap_buffer, list); ++ list_del(&bcap_dev->next_frm->list); ++ vb2_buffer_done(&bcap_dev->next_frm->vb, VB2_BUF_STATE_ERROR); ++ } ++ return 0; ++} ++ ++static struct vb2_ops bcap_video_qops = { ++ .queue_setup = bcap_queue_setup, ++ .buf_init = bcap_buffer_init, ++ .buf_prepare = bcap_buffer_prepare, ++ .buf_cleanup = bcap_buffer_cleanup, ++ .buf_queue = bcap_buffer_queue, ++ .wait_prepare = bcap_unlock, ++ .wait_finish = bcap_lock, ++ .start_streaming = bcap_start_streaming, ++ .stop_streaming = bcap_stop_streaming, ++}; ++ ++static int bcap_reqbufs(struct file *file, void *priv, ++ struct v4l2_requestbuffers *req_buf) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ struct vb2_queue *vq = &bcap_dev->buffer_queue; ++ struct v4l2_fh *fh = file->private_data; ++ struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); ++ ++ if (vb2_is_busy(vq)) ++ return -EBUSY; ++ ++ bcap_fh->io_allowed = true; ++ ++ return vb2_reqbufs(vq, req_buf); ++} ++ ++static int bcap_querybuf(struct file *file, void *priv, ++ struct v4l2_buffer *buf) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ ++ return vb2_querybuf(&bcap_dev->buffer_queue, buf); ++} ++ ++static int bcap_qbuf(struct file *file, void *priv, ++ struct v4l2_buffer *buf) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ struct v4l2_fh *fh = file->private_data; ++ struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); ++ ++ if (!bcap_fh->io_allowed) ++ return -EBUSY; ++ ++ return vb2_qbuf(&bcap_dev->buffer_queue, buf); ++} ++ ++static int bcap_dqbuf(struct file *file, void *priv, ++ struct v4l2_buffer *buf) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ struct v4l2_fh *fh = file->private_data; ++ struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); ++ ++ if (!bcap_fh->io_allowed) ++ return -EBUSY; ++ ++ return vb2_dqbuf(&bcap_dev->buffer_queue, ++ buf, file->f_flags & O_NONBLOCK); ++} ++ ++static irqreturn_t bcap_isr(int irq, void *dev_id) ++{ ++ struct ppi_if *ppi = dev_id; ++ struct bcap_device *bcap_dev = ppi->priv; ++ struct timeval timevalue; ++ struct vb2_buffer *vb = &bcap_dev->cur_frm->vb; ++ dma_addr_t addr; ++ ++ spin_lock(&bcap_dev->lock); ++ ++ if (bcap_dev->cur_frm != bcap_dev->next_frm) { ++ do_gettimeofday(&timevalue); ++ vb->v4l2_buf.timestamp = timevalue; ++ vb2_buffer_done(vb, VB2_BUF_STATE_DONE); ++ bcap_dev->cur_frm = bcap_dev->next_frm; ++ } ++ ++ ppi->ops->stop(ppi); ++ ++ if (bcap_dev->stop) { ++ complete(&bcap_dev->comp); ++ } else { ++ if (!list_empty(&bcap_dev->dma_queue)) { ++ bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next, ++ struct bcap_buffer, list); ++ list_del(&bcap_dev->next_frm->list); ++ addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->next_frm->vb, 0); ++ ppi->ops->update_addr(ppi, (unsigned long)addr); ++ } ++ ppi->ops->start(ppi); ++ } ++ ++ spin_unlock(&bcap_dev->lock); ++ ++ return IRQ_HANDLED; ++} ++ ++static int bcap_streamon(struct file *file, void *priv, ++ enum v4l2_buf_type buf_type) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ struct bcap_fh *fh = file->private_data; ++ struct ppi_if *ppi = bcap_dev->ppi; ++ dma_addr_t addr; ++ int ret; ++ ++ if (!fh->io_allowed) ++ return -EBUSY; ++ ++ /* call streamon to start streaming in videobuf */ ++ ret = vb2_streamon(&bcap_dev->buffer_queue, buf_type); ++ if (ret) ++ return ret; ++ ++ /* if dma queue is empty, return error */ ++ if (list_empty(&bcap_dev->dma_queue)) { ++ v4l2_err(&bcap_dev->v4l2_dev, "dma queue is empty\n"); ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ /* get the next frame from the dma queue */ ++ bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next, ++ struct bcap_buffer, list); ++ bcap_dev->cur_frm = bcap_dev->next_frm; ++ /* remove buffer from the dma queue */ ++ list_del(&bcap_dev->cur_frm->list); ++ addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->cur_frm->vb, 0); ++ /* update DMA address */ ++ ppi->ops->update_addr(ppi, (unsigned long)addr); ++ /* enable ppi */ ++ ppi->ops->start(ppi); ++ ++ return 0; ++err: ++ vb2_streamoff(&bcap_dev->buffer_queue, buf_type); ++ return ret; ++} ++ ++static int bcap_streamoff(struct file *file, void *priv, ++ enum v4l2_buf_type buf_type) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ struct bcap_fh *fh = file->private_data; ++ ++ if (!fh->io_allowed) ++ return -EBUSY; ++ ++ return vb2_streamoff(&bcap_dev->buffer_queue, buf_type); ++} ++ ++static int bcap_querystd(struct file *file, void *priv, v4l2_std_id *std) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ ++ return v4l2_subdev_call(bcap_dev->sd, video, querystd, std); ++} ++ ++static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ ++ *std = bcap_dev->std; ++ return 0; ++} ++ ++static int bcap_s_std(struct file *file, void *priv, v4l2_std_id *std) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ int ret; ++ ++ if (vb2_is_busy(&bcap_dev->buffer_queue)) ++ return -EBUSY; ++ ++ ret = v4l2_subdev_call(bcap_dev->sd, core, s_std, *std); ++ if (ret < 0) ++ return ret; ++ ++ bcap_dev->std = *std; ++ return 0; ++} ++ ++static int bcap_enum_input(struct file *file, void *priv, ++ struct v4l2_input *input) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ struct bfin_capture_config *config = bcap_dev->cfg; ++ int ret; ++ u32 status; ++ ++ if (input->index >= config->num_inputs) ++ return -EINVAL; ++ ++ *input = config->inputs[input->index]; ++ /* get input status */ ++ ret = v4l2_subdev_call(bcap_dev->sd, video, g_input_status, &status); ++ if (!ret) ++ input->status = status; ++ return 0; ++} ++ ++static int bcap_g_input(struct file *file, void *priv, unsigned int *index) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ ++ *index = bcap_dev->cur_input; ++ return 0; ++} ++ ++static int bcap_s_input(struct file *file, void *priv, unsigned int index) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ struct bfin_capture_config *config = bcap_dev->cfg; ++ struct bcap_route *route; ++ int ret; ++ ++ if (vb2_is_busy(&bcap_dev->buffer_queue)) ++ return -EBUSY; ++ ++ if (index >= config->num_inputs) ++ return -EINVAL; ++ ++ route = &config->routes[index]; ++ ret = v4l2_subdev_call(bcap_dev->sd, video, s_routing, ++ route->input, route->output, 0); ++ if ((ret < 0) && (ret != -ENOIOCTLCMD)) { ++ v4l2_err(&bcap_dev->v4l2_dev, "Failed to set input\n"); ++ return ret; ++ } ++ bcap_dev->cur_input = index; ++ return 0; ++} ++ ++static int bcap_try_format(struct bcap_device *bcap, ++ struct v4l2_pix_format *pixfmt, ++ enum v4l2_mbus_pixelcode *mbus_code, ++ int *bpp) ++{ ++ struct bcap_format *sf = bcap->sensor_formats; ++ struct bcap_format *fmt = NULL; ++ struct v4l2_mbus_framefmt mbus_fmt; ++ int ret, i; ++ ++ for (i = 0; i < bcap->num_sensor_formats; i++) { ++ fmt = &sf[i]; ++ if (pixfmt->pixelformat == fmt->pixelformat) ++ break; ++ } ++ if (i == bcap->num_sensor_formats) ++ fmt = &sf[0]; ++ ++ if (mbus_code) ++ *mbus_code = fmt->mbus_code; ++ if (bpp) ++ *bpp = fmt->bpp; ++ v4l2_fill_mbus_format(&mbus_fmt, pixfmt, fmt->mbus_code); ++ ret = v4l2_subdev_call(bcap->sd, video, ++ try_mbus_fmt, &mbus_fmt); ++ if (ret < 0) ++ return ret; ++ v4l2_fill_pix_format(pixfmt, &mbus_fmt); ++ pixfmt->bytesperline = pixfmt->width * fmt->bpp / 8; ++ pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; ++ return 0; ++} ++ ++static int bcap_enum_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_fmtdesc *fmt) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ struct bcap_format *sf = bcap_dev->sensor_formats; ++ ++ if (fmt->index >= bcap_dev->num_sensor_formats) ++ return -EINVAL; ++ ++ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ strlcpy(fmt->description, ++ sf[fmt->index].desc, ++ sizeof(fmt->description)); ++ fmt->pixelformat = sf[fmt->index].pixelformat; ++ return 0; ++} ++ ++static int bcap_try_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *fmt) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; ++ ++ return bcap_try_format(bcap_dev, pixfmt, NULL, NULL); ++} ++ ++static int bcap_g_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *fmt) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ ++ fmt->fmt.pix = bcap_dev->fmt; ++ return 0; ++} ++ ++static int bcap_s_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *fmt) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ struct v4l2_mbus_framefmt mbus_fmt; ++ enum v4l2_mbus_pixelcode mbus_code; ++ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; ++ int ret, bpp; ++ ++ if (vb2_is_busy(&bcap_dev->buffer_queue)) ++ return -EBUSY; ++ ++ /* see if format works */ ++ ret = bcap_try_format(bcap_dev, pixfmt, &mbus_code, &bpp); ++ if (ret < 0) ++ return ret; ++ ++ v4l2_fill_mbus_format(&mbus_fmt, pixfmt, mbus_code); ++ ret = v4l2_subdev_call(bcap_dev->sd, video, s_mbus_fmt, &mbus_fmt); ++ if (ret < 0) ++ return ret; ++ bcap_dev->fmt = *pixfmt; ++ bcap_dev->bpp = bpp; ++ return 0; ++} ++ ++static int bcap_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ ++ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; ++ strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); ++ strlcpy(cap->bus_info, "Blackfin Platform", sizeof(cap->bus_info)); ++ strlcpy(cap->card, bcap_dev->cfg->card_name, sizeof(cap->card)); ++ return 0; ++} ++ ++static int bcap_g_parm(struct file *file, void *fh, ++ struct v4l2_streamparm *a) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ ++ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ return v4l2_subdev_call(bcap_dev->sd, video, g_parm, a); ++} ++ ++static int bcap_s_parm(struct file *file, void *fh, ++ struct v4l2_streamparm *a) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ ++ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ return v4l2_subdev_call(bcap_dev->sd, video, s_parm, a); ++} ++ ++static int bcap_g_chip_ident(struct file *file, void *priv, ++ struct v4l2_dbg_chip_ident *chip) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ ++ chip->ident = V4L2_IDENT_NONE; ++ chip->revision = 0; ++ if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER && ++ chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) ++ return -EINVAL; ++ ++ return v4l2_subdev_call(bcap_dev->sd, core, ++ g_chip_ident, chip); ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int bcap_dbg_g_register(struct file *file, void *priv, ++ struct v4l2_dbg_register *reg) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ ++ return v4l2_subdev_call(bcap_dev->sd, core, ++ g_register, reg); ++} ++ ++static int bcap_dbg_s_register(struct file *file, void *priv, ++ struct v4l2_dbg_register *reg) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ ++ return v4l2_subdev_call(bcap_dev->sd, core, ++ s_register, reg); ++} ++#endif ++ ++static int bcap_log_status(struct file *file, void *priv) ++{ ++ struct bcap_device *bcap_dev = video_drvdata(file); ++ /* status for sub devices */ ++ v4l2_device_call_all(&bcap_dev->v4l2_dev, 0, core, log_status); ++ return 0; ++} ++ ++static const struct v4l2_ioctl_ops bcap_ioctl_ops = { ++ .vidioc_querycap = bcap_querycap, ++ .vidioc_g_fmt_vid_cap = bcap_g_fmt_vid_cap, ++ .vidioc_enum_fmt_vid_cap = bcap_enum_fmt_vid_cap, ++ .vidioc_s_fmt_vid_cap = bcap_s_fmt_vid_cap, ++ .vidioc_try_fmt_vid_cap = bcap_try_fmt_vid_cap, ++ .vidioc_enum_input = bcap_enum_input, ++ .vidioc_g_input = bcap_g_input, ++ .vidioc_s_input = bcap_s_input, ++ .vidioc_querystd = bcap_querystd, ++ .vidioc_s_std = bcap_s_std, ++ .vidioc_g_std = bcap_g_std, ++ .vidioc_reqbufs = bcap_reqbufs, ++ .vidioc_querybuf = bcap_querybuf, ++ .vidioc_qbuf = bcap_qbuf, ++ .vidioc_dqbuf = bcap_dqbuf, ++ .vidioc_streamon = bcap_streamon, ++ .vidioc_streamoff = bcap_streamoff, ++ .vidioc_g_parm = bcap_g_parm, ++ .vidioc_s_parm = bcap_s_parm, ++ .vidioc_g_chip_ident = bcap_g_chip_ident, ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .vidioc_g_register = bcap_dbg_g_register, ++ .vidioc_s_register = bcap_dbg_s_register, ++#endif ++ .vidioc_log_status = bcap_log_status, ++}; ++ ++static struct v4l2_file_operations bcap_fops = { ++ .owner = THIS_MODULE, ++ .open = bcap_open, ++ .release = bcap_release, ++ .unlocked_ioctl = video_ioctl2, ++ .mmap = bcap_mmap, ++#ifndef CONFIG_MMU ++ .get_unmapped_area = bcap_get_unmapped_area, ++#endif ++ .poll = bcap_poll ++}; ++ ++static int __devinit bcap_probe(struct platform_device *pdev) ++{ ++ struct bcap_device *bcap_dev; ++ struct video_device *vfd; ++ struct i2c_adapter *i2c_adap; ++ struct bfin_capture_config *config; ++ struct vb2_queue *q; ++ int ret; ++ ++ config = pdev->dev.platform_data; ++ if (!config) { ++ v4l2_err(pdev->dev.driver, "Unable to get board config\n"); ++ return -ENODEV; ++ } ++ ++ bcap_dev = kzalloc(sizeof(*bcap_dev), GFP_KERNEL); ++ if (!bcap_dev) { ++ v4l2_err(pdev->dev.driver, "Unable to alloc bcap_dev\n"); ++ return -ENOMEM; ++ } ++ ++ bcap_dev->cfg = config; ++ ++ bcap_dev->ppi = ppi_create_instance(config->ppi_info); ++ if (!bcap_dev->ppi) { ++ v4l2_err(pdev->dev.driver, "Unable to create ppi\n"); ++ ret = -ENODEV; ++ goto err_free_dev; ++ } ++ bcap_dev->ppi->priv = bcap_dev; ++ ++ bcap_dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); ++ if (IS_ERR(bcap_dev->alloc_ctx)) { ++ ret = PTR_ERR(bcap_dev->alloc_ctx); ++ goto err_free_ppi; ++ } ++ ++ vfd = video_device_alloc(); ++ if (!vfd) { ++ ret = -ENOMEM; ++ v4l2_err(pdev->dev.driver, "Unable to alloc video device\n"); ++ goto err_cleanup_ctx; ++ } ++ ++ /* initialize field of video device */ ++ vfd->release = video_device_release; ++ vfd->fops = &bcap_fops; ++ vfd->ioctl_ops = &bcap_ioctl_ops; ++ vfd->tvnorms = 0; ++ vfd->v4l2_dev = &bcap_dev->v4l2_dev; ++ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); ++ strncpy(vfd->name, CAPTURE_DRV_NAME, sizeof(vfd->name)); ++ bcap_dev->video_dev = vfd; ++ ++ ret = v4l2_device_register(&pdev->dev, &bcap_dev->v4l2_dev); ++ if (ret) { ++ v4l2_err(pdev->dev.driver, ++ "Unable to register v4l2 device\n"); ++ goto err_release_vdev; ++ } ++ v4l2_info(&bcap_dev->v4l2_dev, "v4l2 device registered\n"); ++ ++ bcap_dev->v4l2_dev.ctrl_handler = &bcap_dev->ctrl_handler; ++ ret = v4l2_ctrl_handler_init(&bcap_dev->ctrl_handler, 0); ++ if (ret) { ++ v4l2_err(&bcap_dev->v4l2_dev, ++ "Unable to init control handler\n"); ++ goto err_unreg_v4l2; ++ } ++ ++ spin_lock_init(&bcap_dev->lock); ++ /* initialize queue */ ++ q = &bcap_dev->buffer_queue; ++ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ q->io_modes = VB2_MMAP; ++ q->drv_priv = bcap_dev; ++ q->buf_struct_size = sizeof(struct bcap_buffer); ++ q->ops = &bcap_video_qops; ++ q->mem_ops = &vb2_dma_contig_memops; ++ ++ vb2_queue_init(q); ++ ++ mutex_init(&bcap_dev->mutex); ++ init_completion(&bcap_dev->comp); ++ ++ /* init video dma queues */ ++ INIT_LIST_HEAD(&bcap_dev->dma_queue); ++ ++ vfd->lock = &bcap_dev->mutex; ++ ++ /* register video device */ ++ ret = video_register_device(bcap_dev->video_dev, VFL_TYPE_GRABBER, -1); ++ if (ret) { ++ v4l2_err(&bcap_dev->v4l2_dev, ++ "Unable to register video device\n"); ++ goto err_free_handler; ++ } ++ video_set_drvdata(bcap_dev->video_dev, bcap_dev); ++ v4l2_info(&bcap_dev->v4l2_dev, "video device registered as: %s\n", ++ video_device_node_name(vfd)); ++ ++ /* load up the subdevice */ ++ i2c_adap = i2c_get_adapter(config->i2c_adapter_id); ++ if (!i2c_adap) { ++ v4l2_err(&bcap_dev->v4l2_dev, ++ "Unable to find i2c adapter\n"); ++ goto err_unreg_vdev; ++ ++ } ++ bcap_dev->sd = v4l2_i2c_new_subdev_board(&bcap_dev->v4l2_dev, ++ i2c_adap, ++ &config->board_info, ++ NULL); ++ if (bcap_dev->sd) { ++ int i; ++ /* update tvnorms from the sub devices */ ++ for (i = 0; i < config->num_inputs; i++) ++ vfd->tvnorms |= config->inputs[i].std; ++ } else { ++ v4l2_err(&bcap_dev->v4l2_dev, ++ "Unable to register sub device\n"); ++ goto err_unreg_vdev; ++ } ++ ++ v4l2_info(&bcap_dev->v4l2_dev, "v4l2 sub device registered\n"); ++ ++ /* now we can probe the default state */ ++ if (vfd->tvnorms) { ++ v4l2_std_id std; ++ ret = v4l2_subdev_call(bcap_dev->sd, core, g_std, &std); ++ if (ret) { ++ v4l2_err(&bcap_dev->v4l2_dev, ++ "Unable to get std\n"); ++ goto err_unreg_vdev; ++ } ++ bcap_dev->std = std; ++ } ++ ret = bcap_init_sensor_formats(bcap_dev); ++ if (ret) { ++ v4l2_err(&bcap_dev->v4l2_dev, ++ "Unable to create sensor formats table\n"); ++ goto err_unreg_vdev; ++ } ++ return 0; ++err_unreg_vdev: ++ video_unregister_device(bcap_dev->video_dev); ++ bcap_dev->video_dev = NULL; ++err_free_handler: ++ v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); ++err_unreg_v4l2: ++ v4l2_device_unregister(&bcap_dev->v4l2_dev); ++err_release_vdev: ++ if (bcap_dev->video_dev) ++ video_device_release(bcap_dev->video_dev); ++err_cleanup_ctx: ++ vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); ++err_free_ppi: ++ ppi_delete_instance(bcap_dev->ppi); ++err_free_dev: ++ kfree(bcap_dev); ++ return ret; ++} ++ ++static int __devexit bcap_remove(struct platform_device *pdev) ++{ ++ struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); ++ struct bcap_device *bcap_dev = container_of(v4l2_dev, ++ struct bcap_device, v4l2_dev); ++ ++ bcap_free_sensor_formats(bcap_dev); ++ video_unregister_device(bcap_dev->video_dev); ++ v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); ++ v4l2_device_unregister(v4l2_dev); ++ vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); ++ ppi_delete_instance(bcap_dev->ppi); ++ kfree(bcap_dev); ++ return 0; ++} ++ ++static struct platform_driver bcap_driver = { ++ .driver = { ++ .name = CAPTURE_DRV_NAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = bcap_probe, ++ .remove = __devexit_p(bcap_remove), ++}; ++ ++static __init int bcap_init(void) ++{ ++ return platform_driver_register(&bcap_driver); ++} ++ ++static __exit void bcap_exit(void) ++{ ++ platform_driver_unregister(&bcap_driver); ++} ++ ++module_init(bcap_init); ++module_exit(bcap_exit); ++ ++MODULE_DESCRIPTION("Analog Devices blackfin video capture driver"); ++MODULE_AUTHOR("Scott Jiang "); ++MODULE_LICENSE("GPL v2"); +Index: linux-3.3.x86_64/drivers/media/video/blackfin/ppi.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/video/blackfin/ppi.c +@@ -0,0 +1,271 @@ ++/* ++ * ppi.c Analog Devices Parallel Peripheral Interface driver ++ * ++ * Copyright (c) 2011 Analog Devices Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler); ++static void ppi_detach_irq(struct ppi_if *ppi); ++static int ppi_start(struct ppi_if *ppi); ++static int ppi_stop(struct ppi_if *ppi); ++static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params); ++static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr); ++ ++static const struct ppi_ops ppi_ops = { ++ .attach_irq = ppi_attach_irq, ++ .detach_irq = ppi_detach_irq, ++ .start = ppi_start, ++ .stop = ppi_stop, ++ .set_params = ppi_set_params, ++ .update_addr = ppi_update_addr, ++}; ++ ++static irqreturn_t ppi_irq_err(int irq, void *dev_id) ++{ ++ struct ppi_if *ppi = dev_id; ++ const struct ppi_info *info = ppi->info; ++ ++ switch (info->type) { ++ case PPI_TYPE_PPI: ++ { ++ struct bfin_ppi_regs *reg = info->base; ++ unsigned short status; ++ ++ /* register on bf561 is cleared when read ++ * others are W1C ++ */ ++ status = bfin_read16(®->status); ++ bfin_write16(®->status, 0xff00); ++ break; ++ } ++ case PPI_TYPE_EPPI: ++ { ++ struct bfin_eppi_regs *reg = info->base; ++ bfin_write16(®->status, 0xffff); ++ break; ++ } ++ default: ++ break; ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler) ++{ ++ const struct ppi_info *info = ppi->info; ++ int ret; ++ ++ ret = request_dma(info->dma_ch, "PPI_DMA"); ++ ++ if (ret) { ++ pr_err("Unable to allocate DMA channel for PPI\n"); ++ return ret; ++ } ++ set_dma_callback(info->dma_ch, handler, ppi); ++ ++ if (ppi->err_int) { ++ ret = request_irq(info->irq_err, ppi_irq_err, 0, "PPI ERROR", ppi); ++ if (ret) { ++ pr_err("Unable to allocate IRQ for PPI\n"); ++ free_dma(info->dma_ch); ++ } ++ } ++ return ret; ++} ++ ++static void ppi_detach_irq(struct ppi_if *ppi) ++{ ++ const struct ppi_info *info = ppi->info; ++ ++ if (ppi->err_int) ++ free_irq(info->irq_err, ppi); ++ free_dma(info->dma_ch); ++} ++ ++static int ppi_start(struct ppi_if *ppi) ++{ ++ const struct ppi_info *info = ppi->info; ++ ++ /* enable DMA */ ++ enable_dma(info->dma_ch); ++ ++ /* enable PPI */ ++ ppi->ppi_control |= PORT_EN; ++ switch (info->type) { ++ case PPI_TYPE_PPI: ++ { ++ struct bfin_ppi_regs *reg = info->base; ++ bfin_write16(®->control, ppi->ppi_control); ++ break; ++ } ++ case PPI_TYPE_EPPI: ++ { ++ struct bfin_eppi_regs *reg = info->base; ++ bfin_write32(®->control, ppi->ppi_control); ++ break; ++ } ++ default: ++ return -EINVAL; ++ } ++ ++ SSYNC(); ++ return 0; ++} ++ ++static int ppi_stop(struct ppi_if *ppi) ++{ ++ const struct ppi_info *info = ppi->info; ++ ++ /* disable PPI */ ++ ppi->ppi_control &= ~PORT_EN; ++ switch (info->type) { ++ case PPI_TYPE_PPI: ++ { ++ struct bfin_ppi_regs *reg = info->base; ++ bfin_write16(®->control, ppi->ppi_control); ++ break; ++ } ++ case PPI_TYPE_EPPI: ++ { ++ struct bfin_eppi_regs *reg = info->base; ++ bfin_write32(®->control, ppi->ppi_control); ++ break; ++ } ++ default: ++ return -EINVAL; ++ } ++ ++ /* disable DMA */ ++ clear_dma_irqstat(info->dma_ch); ++ disable_dma(info->dma_ch); ++ ++ SSYNC(); ++ return 0; ++} ++ ++static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params) ++{ ++ const struct ppi_info *info = ppi->info; ++ int dma32 = 0; ++ int dma_config, bytes_per_line, lines_per_frame; ++ ++ bytes_per_line = params->width * params->bpp / 8; ++ lines_per_frame = params->height; ++ if (params->int_mask == 0xFFFFFFFF) ++ ppi->err_int = false; ++ else ++ ppi->err_int = true; ++ ++ dma_config = (DMA_FLOW_STOP | WNR | RESTART | DMA2D | DI_EN); ++ ppi->ppi_control = params->ppi_control & ~PORT_EN; ++ switch (info->type) { ++ case PPI_TYPE_PPI: ++ { ++ struct bfin_ppi_regs *reg = info->base; ++ ++ if (params->ppi_control & DMA32) ++ dma32 = 1; ++ ++ bfin_write16(®->control, ppi->ppi_control); ++ bfin_write16(®->count, bytes_per_line - 1); ++ bfin_write16(®->frame, lines_per_frame); ++ break; ++ } ++ case PPI_TYPE_EPPI: ++ { ++ struct bfin_eppi_regs *reg = info->base; ++ ++ if ((params->ppi_control & PACK_EN) ++ || (params->ppi_control & 0x38000) > DLEN_16) ++ dma32 = 1; ++ ++ bfin_write32(®->control, ppi->ppi_control); ++ bfin_write16(®->line, bytes_per_line + params->blank_clocks); ++ bfin_write16(®->frame, lines_per_frame); ++ bfin_write16(®->hdelay, 0); ++ bfin_write16(®->vdelay, 0); ++ bfin_write16(®->hcount, bytes_per_line); ++ bfin_write16(®->vcount, lines_per_frame); ++ break; ++ } ++ default: ++ return -EINVAL; ++ } ++ ++ if (dma32) { ++ dma_config |= WDSIZE_32; ++ set_dma_x_count(info->dma_ch, bytes_per_line >> 2); ++ set_dma_x_modify(info->dma_ch, 4); ++ set_dma_y_modify(info->dma_ch, 4); ++ } else { ++ dma_config |= WDSIZE_16; ++ set_dma_x_count(info->dma_ch, bytes_per_line >> 1); ++ set_dma_x_modify(info->dma_ch, 2); ++ set_dma_y_modify(info->dma_ch, 2); ++ } ++ set_dma_y_count(info->dma_ch, lines_per_frame); ++ set_dma_config(info->dma_ch, dma_config); ++ ++ SSYNC(); ++ return 0; ++} ++ ++static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr) ++{ ++ set_dma_start_addr(ppi->info->dma_ch, addr); ++} ++ ++struct ppi_if *ppi_create_instance(const struct ppi_info *info) ++{ ++ struct ppi_if *ppi; ++ ++ if (!info || !info->pin_req) ++ return NULL; ++ ++ if (peripheral_request_list(info->pin_req, KBUILD_MODNAME)) { ++ pr_err("request peripheral failed\n"); ++ return NULL; ++ } ++ ++ ppi = kzalloc(sizeof(*ppi), GFP_KERNEL); ++ if (!ppi) { ++ peripheral_free_list(info->pin_req); ++ pr_err("unable to allocate memory for ppi handle\n"); ++ return NULL; ++ } ++ ppi->ops = &ppi_ops; ++ ppi->info = info; ++ ++ pr_info("ppi probe success\n"); ++ return ppi; ++} ++ ++void ppi_delete_instance(struct ppi_if *ppi) ++{ ++ peripheral_free_list(ppi->info->pin_req); ++ kfree(ppi); ++} +Index: linux-3.3.x86_64/include/media/blackfin/bfin_capture.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/include/media/blackfin/bfin_capture.h +@@ -0,0 +1,37 @@ ++#ifndef _BFIN_CAPTURE_H_ ++#define _BFIN_CAPTURE_H_ ++ ++#include ++ ++struct v4l2_input; ++struct ppi_info; ++ ++struct bcap_route { ++ u32 input; ++ u32 output; ++}; ++ ++struct bfin_capture_config { ++ /* card name */ ++ char *card_name; ++ /* inputs available at the sub device */ ++ struct v4l2_input *inputs; ++ /* number of inputs supported */ ++ int num_inputs; ++ /* routing information for each input */ ++ struct bcap_route *routes; ++ /* i2c bus adapter no */ ++ int i2c_adapter_id; ++ /* i2c subdevice board info */ ++ struct i2c_board_info board_info; ++ /* ppi board info */ ++ const struct ppi_info *ppi_info; ++ /* ppi control */ ++ unsigned long ppi_control; ++ /* ppi interrupt mask */ ++ u32 int_mask; ++ /* horizontal blanking clocks */ ++ int blank_clocks; ++}; ++ ++#endif +Index: linux-3.3.x86_64/include/media/blackfin/ppi.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/include/media/blackfin/ppi.h +@@ -0,0 +1,74 @@ ++/* ++ * Analog Devices PPI header file ++ * ++ * Copyright (c) 2011 Analog Devices Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#ifndef _PPI_H_ ++#define _PPI_H_ ++ ++#include ++ ++#ifdef EPPI_EN ++#define PORT_EN EPPI_EN ++#define DMA32 0 ++#define PACK_EN PACKEN ++#endif ++ ++struct ppi_if; ++ ++struct ppi_params { ++ int width; ++ int height; ++ int bpp; ++ unsigned long ppi_control; ++ u32 int_mask; ++ int blank_clocks; ++}; ++ ++struct ppi_ops { ++ int (*attach_irq)(struct ppi_if *ppi, irq_handler_t handler); ++ void (*detach_irq)(struct ppi_if *ppi); ++ int (*start)(struct ppi_if *ppi); ++ int (*stop)(struct ppi_if *ppi); ++ int (*set_params)(struct ppi_if *ppi, struct ppi_params *params); ++ void (*update_addr)(struct ppi_if *ppi, unsigned long addr); ++}; ++ ++enum ppi_type { ++ PPI_TYPE_PPI, ++ PPI_TYPE_EPPI, ++}; ++ ++struct ppi_info { ++ enum ppi_type type; ++ int dma_ch; ++ int irq_err; ++ void __iomem *base; ++ const unsigned short *pin_req; ++}; ++ ++struct ppi_if { ++ unsigned long ppi_control; ++ const struct ppi_ops *ops; ++ const struct ppi_info *info; ++ bool err_int; ++ void *priv; ++}; ++ ++struct ppi_if *ppi_create_instance(const struct ppi_info *info); ++void ppi_delete_instance(struct ppi_if *ppi); ++#endif +Index: linux-3.3.x86_64/Documentation/DocBook/media/v4l/selection-api.xml +=================================================================== +--- linux-3.3.x86_64.orig/Documentation/DocBook/media/v4l/selection-api.xml ++++ linux-3.3.x86_64/Documentation/DocBook/media/v4l/selection-api.xml +@@ -52,6 +52,10 @@ cropping and composing rectangles have t + + + ++ ++For complete list of the available selection targets see table ++ + + +
+@@ -186,7 +190,7 @@ V4L2_SEL_TGT_COMPOSE_ACTIVE + +
+ +- Scaling control. ++ Scaling control + + An application can detect if scaling is performed by comparing the width + and the height of rectangles obtained using V4L2_SEL_TGT_CROP_ACTIVE +@@ -200,7 +204,7 @@ the scaling ratios using these values. + +- Comparison with old cropping API. ++ Comparison with old cropping API + + The selection API was introduced to cope with deficiencies of previous + API , that was designed to control simple capture +Index: linux-3.3.x86_64/Documentation/DocBook/media/v4l/vidioc-g-selection.xml +=================================================================== +--- linux-3.3.x86_64.orig/Documentation/DocBook/media/v4l/vidioc-g-selection.xml ++++ linux-3.3.x86_64/Documentation/DocBook/media/v4l/vidioc-g-selection.xml +@@ -58,43 +58,43 @@ + + The ioctls are used to query and configure selection rectangles. + +- To query the cropping (composing) rectangle set +-&v4l2-selection;::type to the respective buffer type. Do not +-use multiplanar buffers. Use V4L2_BUF_TYPE_VIDEO_CAPTURE ++ To query the cropping (composing) rectangle set &v4l2-selection; ++ type field to the respective buffer type. ++Do not use multiplanar buffers. Use V4L2_BUF_TYPE_VIDEO_CAPTURE + instead of V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE + . Use V4L2_BUF_TYPE_VIDEO_OUTPUT instead of + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE . The next step is +-setting &v4l2-selection;::target to value +- V4L2_SEL_TGT_CROP_ACTIVE ( ++setting the value of &v4l2-selection; target field ++to V4L2_SEL_TGT_CROP_ACTIVE ( + V4L2_SEL_TGT_COMPOSE_ACTIVE ). Please refer to table or for additional +-targets. Fields &v4l2-selection;::flags and +- &v4l2-selection;::reserved are ignored and they +-must be filled with zeros. The driver fills the rest of the structure or ++targets. The flags and reserved ++ fields of &v4l2-selection; are ignored and they must be filled ++with zeros. The driver fills the rest of the structure or + returns &EINVAL; if incorrect buffer type or target was used. If cropping + (composing) is not supported then the active rectangle is not mutable and it is +-always equal to the bounds rectangle. Finally, structure +-&v4l2-selection;::r is filled with the current cropping ++always equal to the bounds rectangle. Finally, the &v4l2-rect; ++r rectangle is filled with the current cropping + (composing) coordinates. The coordinates are expressed in driver-dependent + units. The only exception are rectangles for images in raw formats, whose + coordinates are always expressed in pixels. + +- To change the cropping (composing) rectangle set +-&v4l2-selection;::type to the respective buffer type. Do not ++ To change the cropping (composing) rectangle set the &v4l2-selection; ++type field to the respective buffer type. Do not + use multiplanar buffers. Use V4L2_BUF_TYPE_VIDEO_CAPTURE + instead of V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE + . Use V4L2_BUF_TYPE_VIDEO_OUTPUT instead of + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE . The next step is +-setting &v4l2-selection;::target to value +- V4L2_SEL_TGT_CROP_ACTIVE ( ++setting the value of &v4l2-selection; target to ++V4L2_SEL_TGT_CROP_ACTIVE ( + V4L2_SEL_TGT_COMPOSE_ACTIVE ). Please refer to table or for additional +-targets. Set desired active area into the field +-&v4l2-selection;::r . Field +-&v4l2-selection;::reserved is ignored and must be filled with +-zeros. The driver may adjust the rectangle coordinates. An application may +-introduce constraints to control rounding behaviour. Set the field +- &v4l2-selection;::flags to one of values: ++targets. The &v4l2-rect; r rectangle need to be ++set to the desired active area. Field &v4l2-selection; reserved ++ is ignored and must be filled with zeros. The driver may adjust ++coordinates of the requested rectangle. An application may ++introduce constraints to control rounding behaviour. The &v4l2-selection; ++flags field must be set to one of the following: + + + +@@ -129,7 +129,7 @@ and vertical offset and sizes are chosen + + + +- Satisfy constraints from &v4l2-selection;::flags. ++ Satisfy constraints from &v4l2-selection; flags. + + + Adjust width, height, left, and top to hardware limits and alignments. +@@ -145,7 +145,7 @@ and vertical offset and sizes are chosen + + + +-On success the field &v4l2-selection;::r contains ++On success the &v4l2-rect; r field contains + the adjusted rectangle. When the parameters are unsuitable the application may + modify the cropping (composing) or image parameters and repeat the cycle until + satisfactory parameters have been negotiated. If constraints flags have to be +@@ -162,38 +162,38 @@ exist no rectangle that sati + + + V4L2_SEL_TGT_CROP_ACTIVE +- 0 +- area that is currently cropped by hardware ++ 0x0000 ++ The area that is currently cropped by hardware. + + + V4L2_SEL_TGT_CROP_DEFAULT +- 1 +- suggested cropping rectangle that covers the "whole picture" ++ 0x0001 ++ Suggested cropping rectangle that covers the "whole picture". + + + V4L2_SEL_TGT_CROP_BOUNDS +- 2 +- limits for the cropping rectangle ++ 0x0002 ++ Limits for the cropping rectangle. + + + V4L2_SEL_TGT_COMPOSE_ACTIVE +- 256 +- area to which data are composed by hardware ++ 0x0100 ++ The area to which data is composed by hardware. + + + V4L2_SEL_TGT_COMPOSE_DEFAULT +- 257 +- suggested composing rectangle that covers the "whole picture" ++ 0x0101 ++ Suggested composing rectangle that covers the "whole picture". + + + V4L2_SEL_TGT_COMPOSE_BOUNDS +- 258 +- limits for the composing rectangle ++ 0x0102 ++ Limits for the composing rectangle. + + + V4L2_SEL_TGT_COMPOSE_PADDED +- 259 +- the active area and all padding pixels that are inserted or modified by the hardware ++ 0x0103 ++ The active area and all padding pixels that are inserted or modified by hardware. + + + +@@ -209,12 +209,14 @@ exist no rectangle that sati + + V4L2_SEL_FLAG_GE + 0x00000001 +- indicate that adjusted rectangle must contain a rectangle from &v4l2-selection;::r ++ Indicates that the adjusted rectangle must contain the original ++ &v4l2-selection; r rectangle. + + + V4L2_SEL_FLAG_LE + 0x00000002 +- indicate that adjusted rectangle must be inside a rectangle from &v4l2-selection;::r ++ Indicates that the adjusted rectangle must be inside the original ++ &v4l2-rect; r rectangle. + + + +@@ -245,27 +247,29 @@ exist no rectangle that sati + + __u32 + type +- Type of the buffer (from &v4l2-buf-type;) ++ Type of the buffer (from &v4l2-buf-type;). + + + __u32 + target +- used to select between cropping and composing rectangles ++ Used to select between cropping ++ and composing rectangles. + + + __u32 + flags +- control over coordinates adjustments, refer to selection flags ++ Flags controlling the selection rectangle adjustments, refer to ++ selection flags. + + + &v4l2-rect; + r +- selection rectangle ++ The selection rectangle. + + + __u32 + reserved[9] +- Reserved fields for future use ++ Reserved fields for future use. + + + +@@ -278,24 +282,24 @@ exist no rectangle that sati + + EINVAL + +- The buffer &v4l2-selection;::type +-or &v4l2-selection;::target is not supported, or +-the &v4l2-selection;::flags are invalid. ++ Given buffer type type or ++the selection target target is not supported, ++or the flags argument is not valid. + + + + ERANGE + +- it is not possible to adjust a rectangle +-&v4l2-selection;::r that satisfies all contraints from +- &v4l2-selection;::flags . ++ It is not possible to adjust &v4l2-rect; ++r rectangle to satisfy all contraints given in the ++flags argument. + + + + EBUSY + +- it is not possible to apply change of selection rectangle at the moment. +-Usually because streaming is in progress. ++ It is not possible to apply change of the selection rectangle ++at the moment. Usually because streaming is in progress. + + + +Index: linux-3.3.x86_64/drivers/media/video/w9966.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/w9966.c ++++ linux-3.3.x86_64/drivers/media/video/w9966.c +@@ -129,9 +129,9 @@ MODULE_LICENSE("GPL"); + MODULE_VERSION("0.33.1"); + + #ifdef MODULE +-static const char *pardev[] = {[0 ... W9966_MAXCAMS] = ""}; ++static char *pardev[] = {[0 ... W9966_MAXCAMS] = ""}; + #else +-static const char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"}; ++static char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"}; + #endif + module_param_array(pardev, charp, NULL, 0); + MODULE_PARM_DESC(pardev, "pardev: where to search for\n" +Index: linux-3.3.x86_64/drivers/media/dvb/pt1/pt1.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/pt1/pt1.c ++++ linux-3.3.x86_64/drivers/media/dvb/pt1/pt1.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #include "dvbdev.h" + #include "dvb_demux.h" +@@ -77,6 +78,8 @@ struct pt1 { + struct pt1_adapter *adaps[PT1_NR_ADAPS]; + struct pt1_table *tables; + struct task_struct *kthread; ++ int table_index; ++ int buf_index; + + struct mutex lock; + int power; +@@ -90,12 +93,12 @@ struct pt1_adapter { + u8 *buf; + int upacket_count; + int packet_count; ++ int st_count; + + struct dvb_adapter adap; + struct dvb_demux demux; + int users; + struct dmxdev dmxdev; +- struct dvb_net net; + struct dvb_frontend *fe; + int (*orig_set_voltage)(struct dvb_frontend *fe, + fe_sec_voltage_t voltage); +@@ -119,7 +122,7 @@ static u32 pt1_read_reg(struct pt1 *pt1, + return readl(pt1->regs + reg * 4); + } + +-static int pt1_nr_tables = 64; ++static int pt1_nr_tables = 8; + module_param_named(nr_tables, pt1_nr_tables, int, 0); + + static void pt1_increment_table_count(struct pt1 *pt1) +@@ -264,6 +267,7 @@ static int pt1_filter(struct pt1 *pt1, s + struct pt1_adapter *adap; + int offset; + u8 *buf; ++ int sc; + + if (!page->upackets[PT1_NR_UPACKETS - 1]) + return 0; +@@ -280,6 +284,16 @@ static int pt1_filter(struct pt1 *pt1, s + else if (!adap->upacket_count) + continue; + ++ if (upacket >> 24 & 1) ++ printk_ratelimited(KERN_INFO "earth-pt1: device " ++ "buffer overflowing. table[%d] buf[%d]\n", ++ pt1->table_index, pt1->buf_index); ++ sc = upacket >> 26 & 0x7; ++ if (adap->st_count != -1 && sc != ((adap->st_count + 1) & 0x7)) ++ printk_ratelimited(KERN_INFO "earth-pt1: data loss" ++ " in streamID(adapter)[%d]\n", index); ++ adap->st_count = sc; ++ + buf = adap->buf; + offset = adap->packet_count * 188 + adap->upacket_count * 3; + buf[offset] = upacket >> 16; +@@ -303,30 +317,25 @@ static int pt1_filter(struct pt1 *pt1, s + static int pt1_thread(void *data) + { + struct pt1 *pt1; +- int table_index; +- int buf_index; + struct pt1_buffer_page *page; + + pt1 = data; + set_freezable(); + +- table_index = 0; +- buf_index = 0; +- + while (!kthread_should_stop()) { + try_to_freeze(); + +- page = pt1->tables[table_index].bufs[buf_index].page; ++ page = pt1->tables[pt1->table_index].bufs[pt1->buf_index].page; + if (!pt1_filter(pt1, page)) { + schedule_timeout_interruptible((HZ + 999) / 1000); + continue; + } + +- if (++buf_index >= PT1_NR_BUFS) { ++ if (++pt1->buf_index >= PT1_NR_BUFS) { + pt1_increment_table_count(pt1); +- buf_index = 0; +- if (++table_index >= pt1_nr_tables) +- table_index = 0; ++ pt1->buf_index = 0; ++ if (++pt1->table_index >= pt1_nr_tables) ++ pt1->table_index = 0; + } + } + +@@ -477,21 +486,60 @@ err: + return ret; + } + ++static int pt1_start_polling(struct pt1 *pt1) ++{ ++ int ret = 0; ++ ++ mutex_lock(&pt1->lock); ++ if (!pt1->kthread) { ++ pt1->kthread = kthread_run(pt1_thread, pt1, "earth-pt1"); ++ if (IS_ERR(pt1->kthread)) { ++ ret = PTR_ERR(pt1->kthread); ++ pt1->kthread = NULL; ++ } ++ } ++ mutex_unlock(&pt1->lock); ++ return ret; ++} ++ + static int pt1_start_feed(struct dvb_demux_feed *feed) + { + struct pt1_adapter *adap; + adap = container_of(feed->demux, struct pt1_adapter, demux); +- if (!adap->users++) ++ if (!adap->users++) { ++ int ret; ++ ++ ret = pt1_start_polling(adap->pt1); ++ if (ret) ++ return ret; + pt1_set_stream(adap->pt1, adap->index, 1); ++ } + return 0; + } + ++static void pt1_stop_polling(struct pt1 *pt1) ++{ ++ int i, count; ++ ++ mutex_lock(&pt1->lock); ++ for (i = 0, count = 0; i < PT1_NR_ADAPS; i++) ++ count += pt1->adaps[i]->users; ++ ++ if (count == 0 && pt1->kthread) { ++ kthread_stop(pt1->kthread); ++ pt1->kthread = NULL; ++ } ++ mutex_unlock(&pt1->lock); ++} ++ + static int pt1_stop_feed(struct dvb_demux_feed *feed) + { + struct pt1_adapter *adap; + adap = container_of(feed->demux, struct pt1_adapter, demux); +- if (!--adap->users) ++ if (!--adap->users) { + pt1_set_stream(adap->pt1, adap->index, 0); ++ pt1_stop_polling(adap->pt1); ++ } + return 0; + } + +@@ -575,7 +623,6 @@ static int pt1_wakeup(struct dvb_fronten + + static void pt1_free_adapter(struct pt1_adapter *adap) + { +- dvb_net_release(&adap->net); + adap->demux.dmx.close(&adap->demux.dmx); + dvb_dmxdev_release(&adap->dmxdev); + dvb_dmx_release(&adap->demux); +@@ -616,6 +663,7 @@ pt1_alloc_adapter(struct pt1 *pt1) + adap->buf = buf; + adap->upacket_count = 0; + adap->packet_count = 0; ++ adap->st_count = -1; + + dvb_adap = &adap->adap; + dvb_adap->priv = adap; +@@ -644,8 +692,6 @@ pt1_alloc_adapter(struct pt1 *pt1) + if (ret < 0) + goto err_dmx_release; + +- dvb_net_init(dvb_adap, &adap->net, &demux->dmx); +- + return adap; + + err_dmx_release: +@@ -1020,7 +1066,8 @@ static void __devexit pt1_remove(struct + pt1 = pci_get_drvdata(pdev); + regs = pt1->regs; + +- kthread_stop(pt1->kthread); ++ if (pt1->kthread) ++ kthread_stop(pt1->kthread); + pt1_cleanup_tables(pt1); + pt1_cleanup_frontends(pt1); + pt1_disable_ram(pt1); +@@ -1043,7 +1090,6 @@ pt1_probe(struct pci_dev *pdev, const st + void __iomem *regs; + struct pt1 *pt1; + struct i2c_adapter *i2c_adap; +- struct task_struct *kthread; + + ret = pci_enable_device(pdev); + if (ret < 0) +@@ -1139,17 +1185,8 @@ pt1_probe(struct pci_dev *pdev, const st + if (ret < 0) + goto err_pt1_cleanup_frontends; + +- kthread = kthread_run(pt1_thread, pt1, "pt1"); +- if (IS_ERR(kthread)) { +- ret = PTR_ERR(kthread); +- goto err_pt1_cleanup_tables; +- } +- +- pt1->kthread = kthread; + return 0; + +-err_pt1_cleanup_tables: +- pt1_cleanup_tables(pt1); + err_pt1_cleanup_frontends: + pt1_cleanup_frontends(pt1); + err_pt1_disable_ram: +Index: linux-3.3.x86_64/drivers/media/video/aptina-pll.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/video/aptina-pll.c +@@ -0,0 +1,174 @@ ++/* ++ * Aptina Sensor PLL Configuration ++ * ++ * Copyright (C) 2012 Laurent Pinchart ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "aptina-pll.h" ++ ++int aptina_pll_calculate(struct device *dev, ++ const struct aptina_pll_limits *limits, ++ struct aptina_pll *pll) ++{ ++ unsigned int mf_min; ++ unsigned int mf_max; ++ unsigned int p1_min; ++ unsigned int p1_max; ++ unsigned int p1; ++ unsigned int div; ++ ++ dev_dbg(dev, "PLL: ext clock %u pix clock %u\n", ++ pll->ext_clock, pll->pix_clock); ++ ++ if (pll->ext_clock < limits->ext_clock_min || ++ pll->ext_clock > limits->ext_clock_max) { ++ dev_err(dev, "pll: invalid external clock frequency.\n"); ++ return -EINVAL; ++ } ++ ++ if (pll->pix_clock == 0 || pll->pix_clock > limits->pix_clock_max) { ++ dev_err(dev, "pll: invalid pixel clock frequency.\n"); ++ return -EINVAL; ++ } ++ ++ /* Compute the multiplier M and combined N*P1 divisor. */ ++ div = gcd(pll->pix_clock, pll->ext_clock); ++ pll->m = pll->pix_clock / div; ++ div = pll->ext_clock / div; ++ ++ /* We now have the smallest M and N*P1 values that will result in the ++ * desired pixel clock frequency, but they might be out of the valid ++ * range. Compute the factor by which we should multiply them given the ++ * following constraints: ++ * ++ * - minimum/maximum multiplier ++ * - minimum/maximum multiplier output clock frequency assuming the ++ * minimum/maximum N value ++ * - minimum/maximum combined N*P1 divisor ++ */ ++ mf_min = DIV_ROUND_UP(limits->m_min, pll->m); ++ mf_min = max(mf_min, limits->out_clock_min / ++ (pll->ext_clock / limits->n_min * pll->m)); ++ mf_min = max(mf_min, limits->n_min * limits->p1_min / div); ++ mf_max = limits->m_max / pll->m; ++ mf_max = min(mf_max, limits->out_clock_max / ++ (pll->ext_clock / limits->n_max * pll->m)); ++ mf_max = min(mf_max, DIV_ROUND_UP(limits->n_max * limits->p1_max, div)); ++ ++ dev_dbg(dev, "pll: mf min %u max %u\n", mf_min, mf_max); ++ if (mf_min > mf_max) { ++ dev_err(dev, "pll: no valid combined N*P1 divisor.\n"); ++ return -EINVAL; ++ } ++ ++ /* ++ * We're looking for the highest acceptable P1 value for which a ++ * multiplier factor MF exists that fulfills the following conditions: ++ * ++ * 1. p1 is in the [p1_min, p1_max] range given by the limits and is ++ * even ++ * 2. mf is in the [mf_min, mf_max] range computed above ++ * 3. div * mf is a multiple of p1, in order to compute ++ * n = div * mf / p1 ++ * m = pll->m * mf ++ * 4. the internal clock frequency, given by ext_clock / n, is in the ++ * [int_clock_min, int_clock_max] range given by the limits ++ * 5. the output clock frequency, given by ext_clock / n * m, is in the ++ * [out_clock_min, out_clock_max] range given by the limits ++ * ++ * The first naive approach is to iterate over all p1 values acceptable ++ * according to (1) and all mf values acceptable according to (2), and ++ * stop at the first combination that fulfills (3), (4) and (5). This ++ * has a O(n^2) complexity. ++ * ++ * Instead of iterating over all mf values in the [mf_min, mf_max] range ++ * we can compute the mf increment between two acceptable values ++ * according to (3) with ++ * ++ * mf_inc = p1 / gcd(div, p1) (6) ++ * ++ * and round the minimum up to the nearest multiple of mf_inc. This will ++ * restrict the number of mf values to be checked. ++ * ++ * Furthermore, conditions (4) and (5) only restrict the range of ++ * acceptable p1 and mf values by modifying the minimum and maximum ++ * limits. (5) can be expressed as ++ * ++ * ext_clock / (div * mf / p1) * m * mf >= out_clock_min ++ * ext_clock / (div * mf / p1) * m * mf <= out_clock_max ++ * ++ * or ++ * ++ * p1 >= out_clock_min * div / (ext_clock * m) (7) ++ * p1 <= out_clock_max * div / (ext_clock * m) ++ * ++ * Similarly, (4) can be expressed as ++ * ++ * mf >= ext_clock * p1 / (int_clock_max * div) (8) ++ * mf <= ext_clock * p1 / (int_clock_min * div) ++ * ++ * We can thus iterate over the restricted p1 range defined by the ++ * combination of (1) and (7), and then compute the restricted mf range ++ * defined by the combination of (2), (6) and (8). If the resulting mf ++ * range is not empty, any value in the mf range is acceptable. We thus ++ * select the mf lwoer bound and the corresponding p1 value. ++ */ ++ if (limits->p1_min == 0) { ++ dev_err(dev, "pll: P1 minimum value must be >0.\n"); ++ return -EINVAL; ++ } ++ ++ p1_min = max(limits->p1_min, DIV_ROUND_UP(limits->out_clock_min * div, ++ pll->ext_clock * pll->m)); ++ p1_max = min(limits->p1_max, limits->out_clock_max * div / ++ (pll->ext_clock * pll->m)); ++ ++ for (p1 = p1_max & ~1; p1 >= p1_min; p1 -= 2) { ++ unsigned int mf_inc = p1 / gcd(div, p1); ++ unsigned int mf_high; ++ unsigned int mf_low; ++ ++ mf_low = max(roundup(mf_min, mf_inc), ++ DIV_ROUND_UP(pll->ext_clock * p1, ++ limits->int_clock_max * div)); ++ mf_high = min(mf_max, pll->ext_clock * p1 / ++ (limits->int_clock_min * div)); ++ ++ if (mf_low > mf_high) ++ continue; ++ ++ pll->n = div * mf_low / p1; ++ pll->m *= mf_low; ++ pll->p1 = p1; ++ dev_dbg(dev, "PLL: N %u M %u P1 %u\n", pll->n, pll->m, pll->p1); ++ return 0; ++ } ++ ++ dev_err(dev, "pll: no valid N and P1 divisors found.\n"); ++ return -EINVAL; ++} ++EXPORT_SYMBOL_GPL(aptina_pll_calculate); ++ ++MODULE_DESCRIPTION("Aptina PLL Helpers"); ++MODULE_AUTHOR("Laurent Pinchart "); ++MODULE_LICENSE("GPL v2"); +Index: linux-3.3.x86_64/drivers/media/video/aptina-pll.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/video/aptina-pll.h +@@ -0,0 +1,56 @@ ++/* ++ * Aptina Sensor PLL Configuration ++ * ++ * Copyright (C) 2012 Laurent Pinchart ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#ifndef __APTINA_PLL_H ++#define __APTINA_PLL_H ++ ++struct aptina_pll { ++ unsigned int ext_clock; ++ unsigned int pix_clock; ++ ++ unsigned int n; ++ unsigned int m; ++ unsigned int p1; ++}; ++ ++struct aptina_pll_limits { ++ unsigned int ext_clock_min; ++ unsigned int ext_clock_max; ++ unsigned int int_clock_min; ++ unsigned int int_clock_max; ++ unsigned int out_clock_min; ++ unsigned int out_clock_max; ++ unsigned int pix_clock_max; ++ ++ unsigned int n_min; ++ unsigned int n_max; ++ unsigned int m_min; ++ unsigned int m_max; ++ unsigned int p1_min; ++ unsigned int p1_max; ++}; ++ ++struct device; ++ ++int aptina_pll_calculate(struct device *dev, ++ const struct aptina_pll_limits *limits, ++ struct aptina_pll *pll); ++ ++#endif /* __APTINA_PLL_H */ +Index: linux-3.3.x86_64/drivers/media/video/mt9m032.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/video/mt9m032.c +@@ -0,0 +1,868 @@ ++/* ++ * Driver for MT9M032 CMOS Image Sensor from Micron ++ * ++ * Copyright (C) 2010-2011 Lund Engineering ++ * Contact: Gil Lund ++ * Author: Martin Hostettler ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "aptina-pll.h" ++ ++/* ++ * width and height include active boundary and black parts ++ * ++ * column 0- 15 active boundary ++ * column 16-1455 image ++ * column 1456-1471 active boundary ++ * column 1472-1599 black ++ * ++ * row 0- 51 black ++ * row 53- 59 active boundary ++ * row 60-1139 image ++ * row 1140-1147 active boundary ++ * row 1148-1151 black ++ */ ++ ++#define MT9M032_PIXEL_ARRAY_WIDTH 1600 ++#define MT9M032_PIXEL_ARRAY_HEIGHT 1152 ++ ++#define MT9M032_CHIP_VERSION 0x00 ++#define MT9M032_CHIP_VERSION_VALUE 0x1402 ++#define MT9M032_ROW_START 0x01 ++#define MT9M032_ROW_START_MIN 0 ++#define MT9M032_ROW_START_MAX 1152 ++#define MT9M032_ROW_START_DEF 60 ++#define MT9M032_COLUMN_START 0x02 ++#define MT9M032_COLUMN_START_MIN 0 ++#define MT9M032_COLUMN_START_MAX 1600 ++#define MT9M032_COLUMN_START_DEF 16 ++#define MT9M032_ROW_SIZE 0x03 ++#define MT9M032_ROW_SIZE_MIN 32 ++#define MT9M032_ROW_SIZE_MAX 1152 ++#define MT9M032_ROW_SIZE_DEF 1080 ++#define MT9M032_COLUMN_SIZE 0x04 ++#define MT9M032_COLUMN_SIZE_MIN 32 ++#define MT9M032_COLUMN_SIZE_MAX 1600 ++#define MT9M032_COLUMN_SIZE_DEF 1440 ++#define MT9M032_HBLANK 0x05 ++#define MT9M032_VBLANK 0x06 ++#define MT9M032_VBLANK_MAX 0x7ff ++#define MT9M032_SHUTTER_WIDTH_HIGH 0x08 ++#define MT9M032_SHUTTER_WIDTH_LOW 0x09 ++#define MT9M032_SHUTTER_WIDTH_MIN 1 ++#define MT9M032_SHUTTER_WIDTH_MAX 1048575 ++#define MT9M032_SHUTTER_WIDTH_DEF 1943 ++#define MT9M032_PIX_CLK_CTRL 0x0a ++#define MT9M032_PIX_CLK_CTRL_INV_PIXCLK 0x8000 ++#define MT9M032_RESTART 0x0b ++#define MT9M032_RESET 0x0d ++#define MT9M032_PLL_CONFIG1 0x11 ++#define MT9M032_PLL_CONFIG1_OUTDIV_MASK 0x3f ++#define MT9M032_PLL_CONFIG1_MUL_SHIFT 8 ++#define MT9M032_READ_MODE1 0x1e ++#define MT9M032_READ_MODE2 0x20 ++#define MT9M032_READ_MODE2_VFLIP_SHIFT 15 ++#define MT9M032_READ_MODE2_HFLIP_SHIFT 14 ++#define MT9M032_READ_MODE2_ROW_BLC 0x40 ++#define MT9M032_GAIN_GREEN1 0x2b ++#define MT9M032_GAIN_BLUE 0x2c ++#define MT9M032_GAIN_RED 0x2d ++#define MT9M032_GAIN_GREEN2 0x2e ++ ++/* write only */ ++#define MT9M032_GAIN_ALL 0x35 ++#define MT9M032_GAIN_DIGITAL_MASK 0x7f ++#define MT9M032_GAIN_DIGITAL_SHIFT 8 ++#define MT9M032_GAIN_AMUL_SHIFT 6 ++#define MT9M032_GAIN_ANALOG_MASK 0x3f ++#define MT9M032_FORMATTER1 0x9e ++#define MT9M032_FORMATTER2 0x9f ++#define MT9M032_FORMATTER2_DOUT_EN 0x1000 ++#define MT9M032_FORMATTER2_PIXCLK_EN 0x2000 ++ ++/* ++ * The available MT9M032 datasheet is missing documentation for register 0x10 ++ * MT9P031 seems to be close enough, so use constants from that datasheet for ++ * now. ++ * But keep the name MT9P031 to remind us, that this isn't really confirmed ++ * for this sensor. ++ */ ++#define MT9P031_PLL_CONTROL 0x10 ++#define MT9P031_PLL_CONTROL_PWROFF 0x0050 ++#define MT9P031_PLL_CONTROL_PWRON 0x0051 ++#define MT9P031_PLL_CONTROL_USEPLL 0x0052 ++#define MT9P031_PLL_CONFIG2 0x11 ++#define MT9P031_PLL_CONFIG2_P1_DIV_MASK 0x1f ++ ++struct mt9m032 { ++ struct v4l2_subdev subdev; ++ struct media_pad pad; ++ struct mt9m032_platform_data *pdata; ++ ++ unsigned int pix_clock; ++ ++ struct v4l2_ctrl_handler ctrls; ++ struct { ++ struct v4l2_ctrl *hflip; ++ struct v4l2_ctrl *vflip; ++ }; ++ ++ struct mutex lock; /* Protects streaming, format, interval and crop */ ++ ++ bool streaming; ++ ++ struct v4l2_mbus_framefmt format; ++ struct v4l2_rect crop; ++ struct v4l2_fract frame_interval; ++}; ++ ++#define to_mt9m032(sd) container_of(sd, struct mt9m032, subdev) ++#define to_dev(sensor) \ ++ (&((struct i2c_client *)v4l2_get_subdevdata(&(sensor)->subdev))->dev) ++ ++static int mt9m032_read(struct i2c_client *client, u8 reg) ++{ ++ return i2c_smbus_read_word_swapped(client, reg); ++} ++ ++static int mt9m032_write(struct i2c_client *client, u8 reg, const u16 data) ++{ ++ return i2c_smbus_write_word_swapped(client, reg, data); ++} ++ ++static u32 mt9m032_row_time(struct mt9m032 *sensor, unsigned int width) ++{ ++ unsigned int effective_width; ++ u32 ns; ++ ++ effective_width = width + 716; /* empirical value */ ++ ns = div_u64(1000000000ULL * effective_width, sensor->pix_clock); ++ dev_dbg(to_dev(sensor), "MT9M032 line time: %u ns\n", ns); ++ return ns; ++} ++ ++static int mt9m032_update_timing(struct mt9m032 *sensor, ++ struct v4l2_fract *interval) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); ++ struct v4l2_rect *crop = &sensor->crop; ++ unsigned int min_vblank; ++ unsigned int vblank; ++ u32 row_time; ++ ++ if (!interval) ++ interval = &sensor->frame_interval; ++ ++ row_time = mt9m032_row_time(sensor, crop->width); ++ ++ vblank = div_u64(1000000000ULL * interval->numerator, ++ (u64)row_time * interval->denominator) ++ - crop->height; ++ ++ if (vblank > MT9M032_VBLANK_MAX) { ++ /* hardware limits to 11 bit values */ ++ interval->denominator = 1000; ++ interval->numerator = ++ div_u64((crop->height + MT9M032_VBLANK_MAX) * ++ (u64)row_time * interval->denominator, ++ 1000000000ULL); ++ vblank = div_u64(1000000000ULL * interval->numerator, ++ (u64)row_time * interval->denominator) ++ - crop->height; ++ } ++ /* enforce minimal 1.6ms blanking time. */ ++ min_vblank = 1600000 / row_time; ++ vblank = clamp_t(unsigned int, vblank, min_vblank, MT9M032_VBLANK_MAX); ++ ++ return mt9m032_write(client, MT9M032_VBLANK, vblank); ++} ++ ++static int mt9m032_update_geom_timing(struct mt9m032 *sensor) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); ++ int ret; ++ ++ ret = mt9m032_write(client, MT9M032_COLUMN_SIZE, ++ sensor->crop.width - 1); ++ if (!ret) ++ ret = mt9m032_write(client, MT9M032_ROW_SIZE, ++ sensor->crop.height - 1); ++ if (!ret) ++ ret = mt9m032_write(client, MT9M032_COLUMN_START, ++ sensor->crop.left); ++ if (!ret) ++ ret = mt9m032_write(client, MT9M032_ROW_START, ++ sensor->crop.top); ++ if (!ret) ++ ret = mt9m032_update_timing(sensor, NULL); ++ return ret; ++} ++ ++static int update_formatter2(struct mt9m032 *sensor, bool streaming) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); ++ u16 reg_val = MT9M032_FORMATTER2_DOUT_EN ++ | 0x0070; /* parts reserved! */ ++ /* possibly for changing to 14-bit mode */ ++ ++ if (streaming) ++ reg_val |= MT9M032_FORMATTER2_PIXCLK_EN; /* pixclock enable */ ++ ++ return mt9m032_write(client, MT9M032_FORMATTER2, reg_val); ++} ++ ++static int mt9m032_setup_pll(struct mt9m032 *sensor) ++{ ++ static const struct aptina_pll_limits limits = { ++ .ext_clock_min = 8000000, ++ .ext_clock_max = 16500000, ++ .int_clock_min = 2000000, ++ .int_clock_max = 24000000, ++ .out_clock_min = 322000000, ++ .out_clock_max = 693000000, ++ .pix_clock_max = 99000000, ++ .n_min = 1, ++ .n_max = 64, ++ .m_min = 16, ++ .m_max = 255, ++ .p1_min = 1, ++ .p1_max = 128, ++ }; ++ ++ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); ++ struct mt9m032_platform_data *pdata = sensor->pdata; ++ struct aptina_pll pll; ++ int ret; ++ ++ pll.ext_clock = pdata->ext_clock; ++ pll.pix_clock = pdata->pix_clock; ++ ++ ret = aptina_pll_calculate(&client->dev, &limits, &pll); ++ if (ret < 0) ++ return ret; ++ ++ sensor->pix_clock = pdata->pix_clock; ++ ++ ret = mt9m032_write(client, MT9M032_PLL_CONFIG1, ++ (pll.m << MT9M032_PLL_CONFIG1_MUL_SHIFT) ++ | (pll.p1 - 1)); ++ if (!ret) ++ ret = mt9m032_write(client, MT9P031_PLL_CONFIG2, pll.n - 1); ++ if (!ret) ++ ret = mt9m032_write(client, MT9P031_PLL_CONTROL, ++ MT9P031_PLL_CONTROL_PWRON | ++ MT9P031_PLL_CONTROL_USEPLL); ++ if (!ret) /* more reserved, Continuous, Master Mode */ ++ ret = mt9m032_write(client, MT9M032_READ_MODE1, 0x8006); ++ if (!ret) /* Set 14-bit mode, select 7 divider */ ++ ret = mt9m032_write(client, MT9M032_FORMATTER1, 0x111e); ++ ++ return ret; ++} ++ ++/* ----------------------------------------------------------------------------- ++ * Subdev pad operations ++ */ ++ ++static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev, ++ struct v4l2_subdev_fh *fh, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->index != 0) ++ return -EINVAL; ++ ++ code->code = V4L2_MBUS_FMT_Y8_1X8; ++ return 0; ++} ++ ++static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev, ++ struct v4l2_subdev_fh *fh, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ if (fse->index != 0 || fse->code != V4L2_MBUS_FMT_Y8_1X8) ++ return -EINVAL; ++ ++ fse->min_width = MT9M032_COLUMN_SIZE_DEF; ++ fse->max_width = MT9M032_COLUMN_SIZE_DEF; ++ fse->min_height = MT9M032_ROW_SIZE_DEF; ++ fse->max_height = MT9M032_ROW_SIZE_DEF; ++ ++ return 0; ++} ++ ++/** ++ * __mt9m032_get_pad_crop() - get crop rect ++ * @sensor: pointer to the sensor struct ++ * @fh: file handle for getting the try crop rect from ++ * @which: select try or active crop rect ++ * ++ * Returns a pointer the current active or fh relative try crop rect ++ */ ++static struct v4l2_rect * ++__mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh, ++ enum v4l2_subdev_format_whence which) ++{ ++ switch (which) { ++ case V4L2_SUBDEV_FORMAT_TRY: ++ return v4l2_subdev_get_try_crop(fh, 0); ++ case V4L2_SUBDEV_FORMAT_ACTIVE: ++ return &sensor->crop; ++ default: ++ return NULL; ++ } ++} ++ ++/** ++ * __mt9m032_get_pad_format() - get format ++ * @sensor: pointer to the sensor struct ++ * @fh: file handle for getting the try format from ++ * @which: select try or active format ++ * ++ * Returns a pointer the current active or fh relative try format ++ */ ++static struct v4l2_mbus_framefmt * ++__mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh, ++ enum v4l2_subdev_format_whence which) ++{ ++ switch (which) { ++ case V4L2_SUBDEV_FORMAT_TRY: ++ return v4l2_subdev_get_try_format(fh, 0); ++ case V4L2_SUBDEV_FORMAT_ACTIVE: ++ return &sensor->format; ++ default: ++ return NULL; ++ } ++} ++ ++static int mt9m032_get_pad_format(struct v4l2_subdev *subdev, ++ struct v4l2_subdev_fh *fh, ++ struct v4l2_subdev_format *fmt) ++{ ++ struct mt9m032 *sensor = to_mt9m032(subdev); ++ ++ mutex_lock(&sensor->lock); ++ fmt->format = *__mt9m032_get_pad_format(sensor, fh, fmt->which); ++ mutex_unlock(&sensor->lock); ++ ++ return 0; ++} ++ ++static int mt9m032_set_pad_format(struct v4l2_subdev *subdev, ++ struct v4l2_subdev_fh *fh, ++ struct v4l2_subdev_format *fmt) ++{ ++ struct mt9m032 *sensor = to_mt9m032(subdev); ++ int ret; ++ ++ mutex_lock(&sensor->lock); ++ ++ if (sensor->streaming && fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { ++ ret = -EBUSY; ++ goto done; ++ } ++ ++ /* Scaling is not supported, the format is thus fixed. */ ++ ret = mt9m032_get_pad_format(subdev, fh, fmt); ++ ++done: ++ mutex_lock(&sensor->lock); ++ return ret; ++} ++ ++static int mt9m032_get_pad_crop(struct v4l2_subdev *subdev, ++ struct v4l2_subdev_fh *fh, ++ struct v4l2_subdev_crop *crop) ++{ ++ struct mt9m032 *sensor = to_mt9m032(subdev); ++ ++ mutex_lock(&sensor->lock); ++ crop->rect = *__mt9m032_get_pad_crop(sensor, fh, crop->which); ++ mutex_unlock(&sensor->lock); ++ ++ return 0; ++} ++ ++static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev, ++ struct v4l2_subdev_fh *fh, ++ struct v4l2_subdev_crop *crop) ++{ ++ struct mt9m032 *sensor = to_mt9m032(subdev); ++ struct v4l2_mbus_framefmt *format; ++ struct v4l2_rect *__crop; ++ struct v4l2_rect rect; ++ int ret = 0; ++ ++ mutex_lock(&sensor->lock); ++ ++ if (sensor->streaming && crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) { ++ ret = -EBUSY; ++ goto done; ++ } ++ ++ /* Clamp the crop rectangle boundaries and align them to a multiple of 2 ++ * pixels to ensure a GRBG Bayer pattern. ++ */ ++ rect.left = clamp(ALIGN(crop->rect.left, 2), MT9M032_COLUMN_START_MIN, ++ MT9M032_COLUMN_START_MAX); ++ rect.top = clamp(ALIGN(crop->rect.top, 2), MT9M032_ROW_START_MIN, ++ MT9M032_ROW_START_MAX); ++ rect.width = clamp(ALIGN(crop->rect.width, 2), MT9M032_COLUMN_SIZE_MIN, ++ MT9M032_COLUMN_SIZE_MAX); ++ rect.height = clamp(ALIGN(crop->rect.height, 2), MT9M032_ROW_SIZE_MIN, ++ MT9M032_ROW_SIZE_MAX); ++ ++ rect.width = min(rect.width, MT9M032_PIXEL_ARRAY_WIDTH - rect.left); ++ rect.height = min(rect.height, MT9M032_PIXEL_ARRAY_HEIGHT - rect.top); ++ ++ __crop = __mt9m032_get_pad_crop(sensor, fh, crop->which); ++ ++ if (rect.width != __crop->width || rect.height != __crop->height) { ++ /* Reset the output image size if the crop rectangle size has ++ * been modified. ++ */ ++ format = __mt9m032_get_pad_format(sensor, fh, crop->which); ++ format->width = rect.width; ++ format->height = rect.height; ++ } ++ ++ *__crop = rect; ++ crop->rect = rect; ++ ++ if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) ++ ret = mt9m032_update_geom_timing(sensor); ++ ++done: ++ mutex_unlock(&sensor->lock); ++ return ret; ++} ++ ++static int mt9m032_get_frame_interval(struct v4l2_subdev *subdev, ++ struct v4l2_subdev_frame_interval *fi) ++{ ++ struct mt9m032 *sensor = to_mt9m032(subdev); ++ ++ mutex_lock(&sensor->lock); ++ memset(fi, 0, sizeof(*fi)); ++ fi->interval = sensor->frame_interval; ++ mutex_unlock(&sensor->lock); ++ ++ return 0; ++} ++ ++static int mt9m032_set_frame_interval(struct v4l2_subdev *subdev, ++ struct v4l2_subdev_frame_interval *fi) ++{ ++ struct mt9m032 *sensor = to_mt9m032(subdev); ++ int ret; ++ ++ mutex_lock(&sensor->lock); ++ ++ if (sensor->streaming) { ++ ret = -EBUSY; ++ goto done; ++ } ++ ++ /* Avoid divisions by 0. */ ++ if (fi->interval.denominator == 0) ++ fi->interval.denominator = 1; ++ ++ ret = mt9m032_update_timing(sensor, &fi->interval); ++ if (!ret) ++ sensor->frame_interval = fi->interval; ++ ++done: ++ mutex_unlock(&sensor->lock); ++ return ret; ++} ++ ++static int mt9m032_s_stream(struct v4l2_subdev *subdev, int streaming) ++{ ++ struct mt9m032 *sensor = to_mt9m032(subdev); ++ int ret; ++ ++ mutex_lock(&sensor->lock); ++ ret = update_formatter2(sensor, streaming); ++ if (!ret) ++ sensor->streaming = streaming; ++ mutex_unlock(&sensor->lock); ++ ++ return ret; ++} ++ ++/* ----------------------------------------------------------------------------- ++ * V4L2 subdev core operations ++ */ ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int mt9m032_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct mt9m032 *sensor = to_mt9m032(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); ++ int val; ++ ++ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) ++ return -EINVAL; ++ if (reg->match.addr != client->addr) ++ return -ENODEV; ++ ++ val = mt9m032_read(client, reg->reg); ++ if (val < 0) ++ return -EIO; ++ ++ reg->size = 2; ++ reg->val = val; ++ ++ return 0; ++} ++ ++static int mt9m032_s_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct mt9m032 *sensor = to_mt9m032(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); ++ ++ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) ++ return -EINVAL; ++ ++ if (reg->match.addr != client->addr) ++ return -ENODEV; ++ ++ return mt9m032_write(client, reg->reg, reg->val); ++} ++#endif ++ ++/* ----------------------------------------------------------------------------- ++ * V4L2 subdev control operations ++ */ ++ ++static int update_read_mode2(struct mt9m032 *sensor, bool vflip, bool hflip) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); ++ int reg_val = (vflip << MT9M032_READ_MODE2_VFLIP_SHIFT) ++ | (hflip << MT9M032_READ_MODE2_HFLIP_SHIFT) ++ | MT9M032_READ_MODE2_ROW_BLC ++ | 0x0007; ++ ++ return mt9m032_write(client, MT9M032_READ_MODE2, reg_val); ++} ++ ++static int mt9m032_set_gain(struct mt9m032 *sensor, s32 val) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); ++ int digital_gain_val; /* in 1/8th (0..127) */ ++ int analog_mul; /* 0 or 1 */ ++ int analog_gain_val; /* in 1/16th. (0..63) */ ++ u16 reg_val; ++ ++ digital_gain_val = 51; /* from setup example */ ++ ++ if (val < 63) { ++ analog_mul = 0; ++ analog_gain_val = val; ++ } else { ++ analog_mul = 1; ++ analog_gain_val = val / 2; ++ } ++ ++ /* a_gain = (1 + analog_mul) + (analog_gain_val + 1) / 16 */ ++ /* overall_gain = a_gain * (1 + digital_gain_val / 8) */ ++ ++ reg_val = ((digital_gain_val & MT9M032_GAIN_DIGITAL_MASK) ++ << MT9M032_GAIN_DIGITAL_SHIFT) ++ | ((analog_mul & 1) << MT9M032_GAIN_AMUL_SHIFT) ++ | (analog_gain_val & MT9M032_GAIN_ANALOG_MASK); ++ ++ return mt9m032_write(client, MT9M032_GAIN_ALL, reg_val); ++} ++ ++static int mt9m032_try_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ if (ctrl->id == V4L2_CID_GAIN && ctrl->val >= 63) { ++ /* round because of multiplier used for values >= 63 */ ++ ctrl->val &= ~1; ++ } ++ ++ return 0; ++} ++ ++static int mt9m032_set_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct mt9m032 *sensor = ++ container_of(ctrl->handler, struct mt9m032, ctrls); ++ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); ++ int ret; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_GAIN: ++ return mt9m032_set_gain(sensor, ctrl->val); ++ ++ case V4L2_CID_HFLIP: ++ /* case V4L2_CID_VFLIP: -- In the same cluster */ ++ return update_read_mode2(sensor, sensor->vflip->val, ++ sensor->hflip->val); ++ ++ case V4L2_CID_EXPOSURE: ++ ret = mt9m032_write(client, MT9M032_SHUTTER_WIDTH_HIGH, ++ (ctrl->val >> 16) & 0xffff); ++ if (ret < 0) ++ return ret; ++ ++ return mt9m032_write(client, MT9M032_SHUTTER_WIDTH_LOW, ++ ctrl->val & 0xffff); ++ } ++ ++ return 0; ++} ++ ++static struct v4l2_ctrl_ops mt9m032_ctrl_ops = { ++ .s_ctrl = mt9m032_set_ctrl, ++ .try_ctrl = mt9m032_try_ctrl, ++}; ++ ++/* -------------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops mt9m032_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = mt9m032_g_register, ++ .s_register = mt9m032_s_register, ++#endif ++}; ++ ++static const struct v4l2_subdev_video_ops mt9m032_video_ops = { ++ .s_stream = mt9m032_s_stream, ++ .g_frame_interval = mt9m032_get_frame_interval, ++ .s_frame_interval = mt9m032_set_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops mt9m032_pad_ops = { ++ .enum_mbus_code = mt9m032_enum_mbus_code, ++ .enum_frame_size = mt9m032_enum_frame_size, ++ .get_fmt = mt9m032_get_pad_format, ++ .set_fmt = mt9m032_set_pad_format, ++ .set_crop = mt9m032_set_pad_crop, ++ .get_crop = mt9m032_get_pad_crop, ++}; ++ ++static const struct v4l2_subdev_ops mt9m032_ops = { ++ .core = &mt9m032_core_ops, ++ .video = &mt9m032_video_ops, ++ .pad = &mt9m032_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------------- ++ * Driver initialization and probing ++ */ ++ ++static int mt9m032_probe(struct i2c_client *client, ++ const struct i2c_device_id *devid) ++{ ++ struct i2c_adapter *adapter = client->adapter; ++ struct mt9m032 *sensor; ++ int chip_version; ++ int ret; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { ++ dev_warn(&client->dev, ++ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); ++ return -EIO; ++ } ++ ++ if (!client->dev.platform_data) ++ return -ENODEV; ++ ++ sensor = kzalloc(sizeof(*sensor), GFP_KERNEL); ++ if (sensor == NULL) ++ return -ENOMEM; ++ ++ mutex_init(&sensor->lock); ++ ++ sensor->pdata = client->dev.platform_data; ++ ++ v4l2_i2c_subdev_init(&sensor->subdev, client, &mt9m032_ops); ++ sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ chip_version = mt9m032_read(client, MT9M032_CHIP_VERSION); ++ if (chip_version != MT9M032_CHIP_VERSION_VALUE) { ++ dev_err(&client->dev, "MT9M032 not detected, wrong version " ++ "0x%04x\n", chip_version); ++ ret = -ENODEV; ++ goto error_sensor; ++ } ++ ++ dev_info(&client->dev, "MT9M032 detected at address 0x%02x\n", ++ client->addr); ++ ++ sensor->frame_interval.numerator = 1; ++ sensor->frame_interval.denominator = 30; ++ ++ sensor->crop.left = MT9M032_COLUMN_START_DEF; ++ sensor->crop.top = MT9M032_ROW_START_DEF; ++ sensor->crop.width = MT9M032_COLUMN_SIZE_DEF; ++ sensor->crop.height = MT9M032_ROW_SIZE_DEF; ++ ++ sensor->format.width = sensor->crop.width; ++ sensor->format.height = sensor->crop.height; ++ sensor->format.code = V4L2_MBUS_FMT_Y8_1X8; ++ sensor->format.field = V4L2_FIELD_NONE; ++ sensor->format.colorspace = V4L2_COLORSPACE_SRGB; ++ ++ v4l2_ctrl_handler_init(&sensor->ctrls, 4); ++ ++ v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops, ++ V4L2_CID_GAIN, 0, 127, 1, 64); ++ ++ sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls, ++ &mt9m032_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls, ++ &mt9m032_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ ++ v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops, ++ V4L2_CID_EXPOSURE, MT9M032_SHUTTER_WIDTH_MIN, ++ MT9M032_SHUTTER_WIDTH_MAX, 1, ++ MT9M032_SHUTTER_WIDTH_DEF); ++ ++ if (sensor->ctrls.error) { ++ ret = sensor->ctrls.error; ++ dev_err(&client->dev, "control initialization error %d\n", ret); ++ goto error_ctrl; ++ } ++ ++ v4l2_ctrl_cluster(2, &sensor->hflip); ++ ++ sensor->subdev.ctrl_handler = &sensor->ctrls; ++ sensor->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_init(&sensor->subdev.entity, 1, &sensor->pad, 0); ++ if (ret < 0) ++ goto error_ctrl; ++ ++ ret = mt9m032_write(client, MT9M032_RESET, 1); /* reset on */ ++ if (ret < 0) ++ goto error_entity; ++ mt9m032_write(client, MT9M032_RESET, 0); /* reset off */ ++ if (ret < 0) ++ goto error_entity; ++ ++ ret = mt9m032_setup_pll(sensor); ++ if (ret < 0) ++ goto error_entity; ++ usleep_range(10000, 11000); ++ ++ ret = v4l2_ctrl_handler_setup(&sensor->ctrls); ++ if (ret < 0) ++ goto error_entity; ++ ++ /* SIZE */ ++ ret = mt9m032_update_geom_timing(sensor); ++ if (ret < 0) ++ goto error_entity; ++ ++ ret = mt9m032_write(client, 0x41, 0x0000); /* reserved !!! */ ++ if (ret < 0) ++ goto error_entity; ++ ret = mt9m032_write(client, 0x42, 0x0003); /* reserved !!! */ ++ if (ret < 0) ++ goto error_entity; ++ ret = mt9m032_write(client, 0x43, 0x0003); /* reserved !!! */ ++ if (ret < 0) ++ goto error_entity; ++ ret = mt9m032_write(client, 0x7f, 0x0000); /* reserved !!! */ ++ if (ret < 0) ++ goto error_entity; ++ if (sensor->pdata->invert_pixclock) { ++ ret = mt9m032_write(client, MT9M032_PIX_CLK_CTRL, ++ MT9M032_PIX_CLK_CTRL_INV_PIXCLK); ++ if (ret < 0) ++ goto error_entity; ++ } ++ ++ ret = mt9m032_write(client, MT9M032_RESTART, 1); /* Restart on */ ++ if (ret < 0) ++ goto error_entity; ++ msleep(100); ++ ret = mt9m032_write(client, MT9M032_RESTART, 0); /* Restart off */ ++ if (ret < 0) ++ goto error_entity; ++ msleep(100); ++ ret = update_formatter2(sensor, false); ++ if (ret < 0) ++ goto error_entity; ++ ++ return ret; ++ ++error_entity: ++ media_entity_cleanup(&sensor->subdev.entity); ++error_ctrl: ++ v4l2_ctrl_handler_free(&sensor->ctrls); ++error_sensor: ++ mutex_destroy(&sensor->lock); ++ kfree(sensor); ++ return ret; ++} ++ ++static int mt9m032_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *subdev = i2c_get_clientdata(client); ++ struct mt9m032 *sensor = to_mt9m032(subdev); ++ ++ v4l2_device_unregister_subdev(&sensor->subdev); ++ v4l2_ctrl_handler_free(&sensor->ctrls); ++ media_entity_cleanup(&sensor->subdev.entity); ++ mutex_destroy(&sensor->lock); ++ kfree(sensor); ++ return 0; ++} ++ ++static const struct i2c_device_id mt9m032_id_table[] = { ++ { MT9M032_NAME, 0 }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(i2c, mt9m032_id_table); ++ ++static struct i2c_driver mt9m032_i2c_driver = { ++ .driver = { ++ .name = MT9M032_NAME, ++ }, ++ .probe = mt9m032_probe, ++ .remove = mt9m032_remove, ++ .id_table = mt9m032_id_table, ++}; ++ ++module_i2c_driver(mt9m032_i2c_driver); ++ ++MODULE_AUTHOR("Martin Hostettler "); ++MODULE_DESCRIPTION("MT9M032 camera sensor driver"); ++MODULE_LICENSE("GPL v2"); +Index: linux-3.3.x86_64/include/media/mt9m032.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/include/media/mt9m032.h +@@ -0,0 +1,36 @@ ++/* ++ * Driver for MT9M032 CMOS Image Sensor from Micron ++ * ++ * Copyright (C) 2010-2011 Lund Engineering ++ * Contact: Gil Lund ++ * Author: Martin Hostettler ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ * ++ */ ++ ++#ifndef MT9M032_H ++#define MT9M032_H ++ ++#define MT9M032_NAME "mt9m032" ++#define MT9M032_I2C_ADDR (0xb8 >> 1) ++ ++struct mt9m032_platform_data { ++ u32 ext_clock; ++ u32 pix_clock; ++ bool invert_pixclock; ++ ++}; ++#endif /* MT9M032_H */ +Index: linux-3.3.x86_64/drivers/media/video/v4l2-dev.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/v4l2-dev.c ++++ linux-3.3.x86_64/drivers/media/video/v4l2-dev.c +@@ -788,7 +788,7 @@ static void __exit videodev_exit(void) + unregister_chrdev_region(dev, VIDEO_NUM_DEVICES); + } + +-module_init(videodev_init) ++subsys_initcall(videodev_init); + module_exit(videodev_exit) + + MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab "); +Index: linux-3.3.x86_64/drivers/media/media-devnode.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/media-devnode.c ++++ linux-3.3.x86_64/drivers/media/media-devnode.c +@@ -312,7 +312,7 @@ static void __exit media_devnode_exit(vo + unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES); + } + +-module_init(media_devnode_init) ++subsys_initcall(media_devnode_init); + module_exit(media_devnode_exit) + + MODULE_AUTHOR("Laurent Pinchart "); +Index: linux-3.3.x86_64/drivers/media/rc/mceusb.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/rc/mceusb.c ++++ linux-3.3.x86_64/drivers/media/rc/mceusb.c +@@ -361,6 +361,8 @@ static struct usb_device_id mceusb_dev_t + { USB_DEVICE(VENDOR_FORMOSA, 0xe03c) }, + /* Formosa Industrial Computing */ + { USB_DEVICE(VENDOR_FORMOSA, 0xe03e) }, ++ /* Formosa Industrial Computing */ ++ { USB_DEVICE(VENDOR_FORMOSA, 0xe042) }, + /* Fintek eHome Infrared Transceiver (HP branded) */ + { USB_DEVICE(VENDOR_FINTEK, 0x5168) }, + /* Fintek eHome Infrared Transceiver */ +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/au8522_dig.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/au8522_dig.c ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/au8522_dig.c +@@ -604,6 +604,11 @@ static int au8522_set_frontend(struct dv + + au8522_enable_modulation(fe, c->modulation); + ++ /* Allow the tuner to settle */ ++ msleep(100); ++ ++ au8522_enable_modulation(fe, c->modulation); ++ + state->current_frequency = c->frequency; + + return 0; +Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/dib0700_core.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/dib0700_core.c ++++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/dib0700_core.c +@@ -677,11 +677,9 @@ static void dib0700_rc_urb_completion(st + u8 toggle; + + deb_info("%s()\n", __func__); +- if (d == NULL) +- return; +- + if (d->rc_dev == NULL) { + /* This will occur if disable_rc_polling=1 */ ++ kfree(purb->transfer_buffer); + usb_free_urb(purb); + return; + } +@@ -690,6 +688,7 @@ static void dib0700_rc_urb_completion(st + + if (purb->status < 0) { + deb_info("discontinuing polling\n"); ++ kfree(purb->transfer_buffer); + usb_free_urb(purb); + return; + } +@@ -784,8 +783,11 @@ int dib0700_rc_setup(struct dvb_usb_devi + dib0700_rc_urb_completion, d); + + ret = usb_submit_urb(purb, GFP_ATOMIC); +- if (ret) ++ if (ret) { + err("rc submit urb failed\n"); ++ kfree(purb->transfer_buffer); ++ usb_free_urb(purb); ++ } + + return ret; + } +Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/af9015.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/af9015.c ++++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/af9015.c +@@ -1164,6 +1164,41 @@ static int af9015_af9013_sleep(struct dv + return ret; + } + ++/* override tuner callbacks for resource locking */ ++static int af9015_tuner_init(struct dvb_frontend *fe) ++{ ++ int ret; ++ struct dvb_usb_adapter *adap = fe->dvb->priv; ++ struct af9015_state *priv = adap->dev->priv; ++ ++ if (mutex_lock_interruptible(&adap->dev->usb_mutex)) ++ return -EAGAIN; ++ ++ ret = priv->tuner_init[adap->id](fe); ++ ++ mutex_unlock(&adap->dev->usb_mutex); ++ ++ return ret; ++} ++ ++/* override tuner callbacks for resource locking */ ++static int af9015_tuner_sleep(struct dvb_frontend *fe) ++{ ++ int ret; ++ struct dvb_usb_adapter *adap = fe->dvb->priv; ++ struct af9015_state *priv = adap->dev->priv; ++ ++ if (mutex_lock_interruptible(&adap->dev->usb_mutex)) ++ return -EAGAIN; ++ ++ ret = priv->tuner_sleep[adap->id](fe); ++ ++ mutex_unlock(&adap->dev->usb_mutex); ++ ++ return ret; ++} ++ ++ + static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) + { + int ret; +@@ -1283,6 +1318,7 @@ static struct mxl5007t_config af9015_mxl + static int af9015_tuner_attach(struct dvb_usb_adapter *adap) + { + int ret; ++ struct af9015_state *state = adap->dev->priv; + deb_info("%s:\n", __func__); + + switch (af9015_af9013_config[adap->id].tuner) { +@@ -1340,6 +1376,19 @@ static int af9015_tuner_attach(struct dv + err("Unknown tuner id:%d", + af9015_af9013_config[adap->id].tuner); + } ++ ++ if (adap->fe_adap[0].fe->ops.tuner_ops.init) { ++ state->tuner_init[adap->id] = ++ adap->fe_adap[0].fe->ops.tuner_ops.init; ++ adap->fe_adap[0].fe->ops.tuner_ops.init = af9015_tuner_init; ++ } ++ ++ if (adap->fe_adap[0].fe->ops.tuner_ops.sleep) { ++ state->tuner_sleep[adap->id] = ++ adap->fe_adap[0].fe->ops.tuner_ops.sleep; ++ adap->fe_adap[0].fe->ops.tuner_ops.sleep = af9015_tuner_sleep; ++ } ++ + return ret; + } + +Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/af9015.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/af9015.h ++++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/af9015.h +@@ -108,6 +108,8 @@ struct af9015_state { + int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status); + int (*init[2]) (struct dvb_frontend *fe); + int (*sleep[2]) (struct dvb_frontend *fe); ++ int (*tuner_init[2]) (struct dvb_frontend *fe); ++ int (*tuner_sleep[2]) (struct dvb_frontend *fe); + }; + + struct af9015_config { +Index: linux-3.3.x86_64/drivers/media/rc/rc-main.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/rc/rc-main.c ++++ linux-3.3.x86_64/drivers/media/rc/rc-main.c +@@ -1029,6 +1029,7 @@ EXPORT_SYMBOL_GPL(rc_free_device); + + int rc_register_device(struct rc_dev *dev) + { ++ static bool raw_init = false; /* raw decoders loaded? */ + static atomic_t devno = ATOMIC_INIT(0); + struct rc_map *rc_map; + const char *path; +@@ -1103,6 +1104,12 @@ int rc_register_device(struct rc_dev *de + kfree(path); + + if (dev->driver_type == RC_DRIVER_IR_RAW) { ++ /* Load raw decoders, if they aren't already */ ++ if (!raw_init) { ++ IR_dprintk(1, "Loading raw decoders\n"); ++ ir_raw_init(); ++ raw_init = true; ++ } + rc = ir_raw_event_register(dev); + if (rc < 0) + goto out_input; +@@ -1176,8 +1183,6 @@ static int __init rc_core_init(void) + return rc; + } + +- /* Initialize/load the decoders/keymap code that will be used */ +- ir_raw_init(); + rc_map_register(&empty_map); + + return 0; +Index: linux-3.3.x86_64/drivers/media/video/soc_camera.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/soc_camera.c ++++ linux-3.3.x86_64/drivers/media/video/soc_camera.c +@@ -526,10 +526,6 @@ static int soc_camera_open(struct file * + }, + }; + +- ret = soc_camera_power_on(icd, icl); +- if (ret < 0) +- goto epower; +- + /* The camera could have been already on, try to reset */ + if (icl->reset) + icl->reset(icd->pdev); +@@ -540,6 +536,10 @@ static int soc_camera_open(struct file * + goto eiciadd; + } + ++ ret = soc_camera_power_on(icd, icl); ++ if (ret < 0) ++ goto epower; ++ + pm_runtime_enable(&icd->vdev->dev); + ret = pm_runtime_resume(&icd->vdev->dev); + if (ret < 0 && ret != -ENOSYS) +@@ -578,10 +578,10 @@ einitvb: + esfmt: + pm_runtime_disable(&icd->vdev->dev); + eresume: +- ici->ops->remove(icd); +-eiciadd: + soc_camera_power_off(icd, icl); + epower: ++ ici->ops->remove(icd); ++eiciadd: + icd->use_count--; + module_put(ici->ops->owner); + +@@ -1050,6 +1050,14 @@ static int soc_camera_probe(struct soc_c + if (ret < 0) + goto ereg; + ++ /* The camera could have been already on, try to reset */ ++ if (icl->reset) ++ icl->reset(icd->pdev); ++ ++ ret = ici->ops->add(icd); ++ if (ret < 0) ++ goto eadd; ++ + /* + * This will not yet call v4l2_subdev_core_ops::s_power(1), because the + * subdevice has not been initialised yet. We'll have to call it once +@@ -1060,14 +1068,6 @@ static int soc_camera_probe(struct soc_c + if (ret < 0) + goto epower; + +- /* The camera could have been already on, try to reset */ +- if (icl->reset) +- icl->reset(icd->pdev); +- +- ret = ici->ops->add(icd); +- if (ret < 0) +- goto eadd; +- + /* Must have icd->vdev before registering the device */ + ret = video_dev_create(icd); + if (ret < 0) +@@ -1165,10 +1165,10 @@ eadddev: + video_device_release(icd->vdev); + icd->vdev = NULL; + evdc: +- ici->ops->remove(icd); +-eadd: + soc_camera_power_off(icd, icl); + epower: ++ ici->ops->remove(icd); ++eadd: + regulator_bulk_free(icl->num_regulators, icl->regulators); + ereg: + v4l2_ctrl_handler_free(&icd->ctrl_handler); +Index: linux-3.3.x86_64/drivers/media/video/sh_mobile_ceu_camera.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/sh_mobile_ceu_camera.c ++++ linux-3.3.x86_64/drivers/media/video/sh_mobile_ceu_camera.c +@@ -112,6 +112,10 @@ struct sh_mobile_ceu_dev { + + u32 cflcr; + ++ /* static max sizes either from platform data or default */ ++ int max_width; ++ int max_height; ++ + enum v4l2_field field; + int sequence; + +@@ -1081,7 +1085,15 @@ static int sh_mobile_ceu_get_formats(str + if (ret < 0) + return ret; + +- while ((mf.width > 2560 || mf.height > 1920) && shift < 4) { ++ /* ++ * All currently existing CEU implementations support 2560x1920 ++ * or larger frames. If the sensor is proposing too big a frame, ++ * don't bother with possibly supportred by the CEU larger ++ * sizes, just try VGA multiples. If needed, this can be ++ * adjusted in the future. ++ */ ++ while ((mf.width > pcdev->max_width || ++ mf.height > pcdev->max_height) && shift < 4) { + /* Try 2560x1920, 1280x960, 640x480, 320x240 */ + mf.width = 2560 >> shift; + mf.height = 1920 >> shift; +@@ -1377,6 +1389,8 @@ static int client_s_crop(struct soc_came + static int client_s_fmt(struct soc_camera_device *icd, + struct v4l2_mbus_framefmt *mf, bool ceu_can_scale) + { ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct sh_mobile_ceu_dev *pcdev = ici->priv; + struct sh_mobile_ceu_cam *cam = icd->host_priv; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct device *dev = icd->parent; +@@ -1410,8 +1424,8 @@ static int client_s_fmt(struct soc_camer + if (ret < 0) + return ret; + +- max_width = min(cap.bounds.width, 2560); +- max_height = min(cap.bounds.height, 1920); ++ max_width = min(cap.bounds.width, pcdev->max_width); ++ max_height = min(cap.bounds.height, pcdev->max_height); + + /* Camera set a format, but geometry is not precise, try to improve */ + tmp_w = mf->width; +@@ -1551,7 +1565,7 @@ static int sh_mobile_ceu_set_crop(struct + if (ret < 0) + return ret; + +- if (mf.width > 2560 || mf.height > 1920) ++ if (mf.width > pcdev->max_width || mf.height > pcdev->max_height) + return -EINVAL; + + /* 4. Calculate camera scales */ +@@ -1834,6 +1848,8 @@ static int sh_mobile_ceu_set_fmt(struct + static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) + { ++ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); ++ struct sh_mobile_ceu_dev *pcdev = ici->priv; + const struct soc_camera_format_xlate *xlate; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); +@@ -1854,8 +1870,8 @@ static int sh_mobile_ceu_try_fmt(struct + /* FIXME: calculate using depth and bus width */ + + /* CFSZR requires height and width to be 4-pixel aligned */ +- v4l_bound_align_image(&pix->width, 2, 2560, 2, +- &pix->height, 4, 1920, 2, 0); ++ v4l_bound_align_image(&pix->width, 2, pcdev->max_width, 2, ++ &pix->height, 4, pcdev->max_height, 2, 0); + + width = pix->width; + height = pix->height; +@@ -1890,8 +1906,8 @@ static int sh_mobile_ceu_try_fmt(struct + * requested a bigger rectangle, it will not return a + * smaller one. + */ +- mf.width = 2560; +- mf.height = 1920; ++ mf.width = pcdev->max_width; ++ mf.height = pcdev->max_height; + ret = v4l2_device_call_until_err(sd->v4l2_dev, + soc_camera_grp_id(icd), video, + try_mbus_fmt, &mf); +@@ -2082,6 +2098,9 @@ static int __devinit sh_mobile_ceu_probe + goto exit_kfree; + } + ++ pcdev->max_width = pcdev->pdata->max_width ? : 2560; ++ pcdev->max_height = pcdev->pdata->max_height ? : 1920; ++ + base = ioremap_nocache(res->start, resource_size(res)); + if (!base) { + err = -ENXIO; +Index: linux-3.3.x86_64/include/media/sh_mobile_ceu.h +=================================================================== +--- linux-3.3.x86_64.orig/include/media/sh_mobile_ceu.h ++++ linux-3.3.x86_64/include/media/sh_mobile_ceu.h +@@ -18,6 +18,8 @@ struct sh_mobile_ceu_companion { + + struct sh_mobile_ceu_info { + unsigned long flags; ++ int max_width; ++ int max_height; + struct sh_mobile_ceu_companion *csi2; + }; + +Index: linux-3.3.x86_64/drivers/media/video/pxa_camera.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/pxa_camera.c ++++ linux-3.3.x86_64/drivers/media/video/pxa_camera.c +@@ -921,12 +921,12 @@ static void pxa_camera_activate(struct p + /* "Safe default" - 13MHz */ + recalculate_fifo_timeout(pcdev, 13000000); + +- clk_enable(pcdev->clk); ++ clk_prepare_enable(pcdev->clk); + } + + static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev) + { +- clk_disable(pcdev->clk); ++ clk_disable_unprepare(pcdev->clk); + } + + static irqreturn_t pxa_camera_irq(int irq, void *data) +Index: linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-i2c.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/em28xx/em28xx-i2c.c ++++ linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-i2c.c +@@ -41,14 +41,6 @@ static unsigned int i2c_debug; + module_param(i2c_debug, int, 0644); + MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); + +- +-#define dprintk1(lvl, fmt, args...) \ +-do { \ +- if (i2c_debug >= lvl) { \ +- printk(fmt, ##args); \ +- } \ +-} while (0) +- + #define dprintk2(lvl, fmt, args...) \ + do { \ + if (i2c_debug >= lvl) { \ +Index: linux-3.3.x86_64/drivers/media/video/marvell-ccic/mcam-core.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/marvell-ccic/mcam-core.c ++++ linux-3.3.x86_64/drivers/media/video/marvell-ccic/mcam-core.c +@@ -509,11 +509,17 @@ static void mcam_sg_next_buffer(struct m + + buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue); + list_del_init(&buf->queue); ++ /* ++ * Very Bad Not Good Things happen if you don't clear ++ * C1_DESC_ENA before making any descriptor changes. ++ */ ++ mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA); + mcam_reg_write(cam, REG_DMA_DESC_Y, buf->dma_desc_pa); + mcam_reg_write(cam, REG_DESC_LEN_Y, + buf->dma_desc_nent*sizeof(struct mcam_dma_desc)); + mcam_reg_write(cam, REG_DESC_LEN_U, 0); + mcam_reg_write(cam, REG_DESC_LEN_V, 0); ++ mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA); + cam->vb_bufs[0] = buf; + } + +@@ -533,7 +539,6 @@ static void mcam_ctlr_dma_sg(struct mcam + + mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD); + mcam_sg_next_buffer(cam); +- mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA); + cam->nbufs = 3; + } + +@@ -556,17 +561,16 @@ static void mcam_dma_sg_done(struct mcam + struct mcam_vb_buffer *buf = cam->vb_bufs[0]; + + /* +- * Very Bad Not Good Things happen if you don't clear +- * C1_DESC_ENA before making any descriptor changes. ++ * If we're no longer supposed to be streaming, don't do anything. + */ +- mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA); ++ if (cam->state != S_STREAMING) ++ return; + /* + * If we have another buffer available, put it in and + * restart the engine. + */ + if (!list_empty(&cam->buffers)) { + mcam_sg_next_buffer(cam); +- mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA); + mcam_ctlr_start(cam); + /* + * Otherwise set CF_SG_RESTART and the controller will +@@ -737,7 +741,14 @@ static void mcam_ctlr_stop_dma(struct mc + mcam_ctlr_stop(cam); + cam->state = S_IDLE; + spin_unlock_irqrestore(&cam->dev_lock, flags); +- msleep(40); ++ /* ++ * This is a brutally long sleep, but experience shows that ++ * it can take the controller a while to get the message that ++ * it needs to stop grabbing frames. In particular, we can ++ * sometimes (on mmp) get a frame at the end WITHOUT the ++ * start-of-frame indication. ++ */ ++ msleep(150); + if (test_bit(CF_DMA_ACTIVE, &cam->flags)) + cam_err(cam, "Timeout waiting for DMA to end\n"); + /* This would be bad news - what now? */ +@@ -880,6 +891,7 @@ static int mcam_read_setup(struct mcam_c + * Turn it loose. + */ + spin_lock_irqsave(&cam->dev_lock, flags); ++ clear_bit(CF_DMA_ACTIVE, &cam->flags); + mcam_reset_buffers(cam); + mcam_ctlr_irq_enable(cam); + cam->state = S_STREAMING; +@@ -922,7 +934,7 @@ static void mcam_vb_buf_queue(struct vb2 + spin_lock_irqsave(&cam->dev_lock, flags); + start = (cam->state == S_BUFWAIT) && !list_empty(&cam->buffers); + list_add(&mvb->queue, &cam->buffers); +- if (test_bit(CF_SG_RESTART, &cam->flags)) ++ if (cam->state == S_STREAMING && test_bit(CF_SG_RESTART, &cam->flags)) + mcam_sg_restart(cam); + spin_unlock_irqrestore(&cam->dev_lock, flags); + if (start) +@@ -1555,15 +1567,12 @@ static int mcam_v4l_release(struct file + { + struct mcam_camera *cam = filp->private_data; + +- cam_err(cam, "Release, %d frames, %d singles, %d delivered\n", frames, ++ cam_dbg(cam, "Release, %d frames, %d singles, %d delivered\n", frames, + singles, delivered); + mutex_lock(&cam->s_mutex); + (cam->users)--; +- if (filp == cam->owner) { +- mcam_ctlr_stop_dma(cam); +- cam->owner = NULL; +- } + if (cam->users == 0) { ++ mcam_ctlr_stop_dma(cam); + mcam_cleanup_vb2(cam); + mcam_ctlr_power_down(cam); + if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read) +@@ -1688,6 +1697,8 @@ int mccic_irq(struct mcam_camera *cam, u + if (irqs & (IRQ_EOF0 << frame)) { + mcam_frame_complete(cam, frame); + handled = 1; ++ if (cam->buffer_mode == B_DMA_sg) ++ break; + } + /* + * If a frame starts, note that we have DMA active. This +Index: linux-3.3.x86_64/drivers/media/video/marvell-ccic/mcam-core.h +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/marvell-ccic/mcam-core.h ++++ linux-3.3.x86_64/drivers/media/video/marvell-ccic/mcam-core.h +@@ -107,7 +107,6 @@ struct mcam_camera { + enum mcam_state state; + unsigned long flags; /* Buffer status, mainly (dev_lock) */ + int users; /* How many open FDs */ +- struct file *owner; /* Who has data access (v4l2) */ + + /* + * Subsystem structures. +Index: linux-3.3.x86_64/drivers/media/video/marvell-ccic/mmp-driver.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/marvell-ccic/mmp-driver.c ++++ linux-3.3.x86_64/drivers/media/video/marvell-ccic/mmp-driver.c +@@ -106,6 +106,13 @@ static struct mmp_camera *mmpcam_find_de + /* + * Power control. + */ ++static void mmpcam_power_up_ctlr(struct mmp_camera *cam) ++{ ++ iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR); ++ iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR); ++ mdelay(1); ++} ++ + static void mmpcam_power_up(struct mcam_camera *mcam) + { + struct mmp_camera *cam = mcam_to_cam(mcam); +@@ -113,9 +120,7 @@ static void mmpcam_power_up(struct mcam_ + /* + * Turn on power and clocks to the controller. + */ +- iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR); +- iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR); +- mdelay(1); ++ mmpcam_power_up_ctlr(cam); + /* + * Provide power to the sensor. + */ +@@ -335,7 +340,7 @@ static int mmpcam_resume(struct platform + * touch a register even if nothing was active before; trust + * me, it's better this way. + */ +- mmpcam_power_up(&cam->mcam); ++ mmpcam_power_up_ctlr(cam); + return mccic_resume(&cam->mcam); + } + +Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/mxl111sf.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/mxl111sf.c ++++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/mxl111sf.c +@@ -340,7 +340,6 @@ static int mxl111sf_ep6_streaming_ctrl(s + struct mxl111sf_state *state = d->priv; + struct mxl111sf_adap_state *adap_state = adap->fe_adap[adap->active_fe].priv; + int ret = 0; +- u8 tmp; + + deb_info("%s(%d)\n", __func__, onoff); + +Index: linux-3.3.x86_64/drivers/media/video/gspca/ov534_9.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/gspca/ov534_9.c ++++ linux-3.3.x86_64/drivers/media/video/gspca/ov534_9.c +@@ -1107,16 +1107,34 @@ static void setbrightness(struct gspca_d + { + struct sd *sd = (struct sd *) gspca_dev; + u8 val; ++ s8 sval; + + if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS)) + return; +- val = sd->ctrls[BRIGHTNESS].val; +- if (val < 8) +- val = 15 - val; /* f .. 8 */ +- else +- val = val - 8; /* 0 .. 7 */ +- sccb_write(gspca_dev, 0x55, /* brtn - brightness adjustment */ +- 0x0f | (val << 4)); ++ if (sd->sensor == SENSOR_OV562x) { ++ sval = sd->ctrls[BRIGHTNESS].val; ++ val = 0x76; ++ val += sval; ++ sccb_write(gspca_dev, 0x24, val); ++ val = 0x6a; ++ val += sval; ++ sccb_write(gspca_dev, 0x25, val); ++ if (sval < -40) ++ val = 0x71; ++ else if (sval < 20) ++ val = 0x94; ++ else ++ val = 0xe6; ++ sccb_write(gspca_dev, 0x26, val); ++ } else { ++ val = sd->ctrls[BRIGHTNESS].val; ++ if (val < 8) ++ val = 15 - val; /* f .. 8 */ ++ else ++ val = val - 8; /* 0 .. 7 */ ++ sccb_write(gspca_dev, 0x55, /* brtn - brightness adjustment */ ++ 0x0f | (val << 4)); ++ } + } + + static void setcontrast(struct gspca_dev *gspca_dev) +@@ -1339,7 +1357,16 @@ static int sd_init(struct gspca_dev *gsp + reg_w(gspca_dev, 0x56, 0x17); + } else if ((sensor_id & 0xfff0) == 0x5620) { + sd->sensor = SENSOR_OV562x; +- ++ gspca_dev->ctrl_dis = (1 << CONTRAST) | ++ (1 << AUTOGAIN) | ++ (1 << EXPOSURE) | ++ (1 << SHARPNESS) | ++ (1 << SATUR) | ++ (1 << LIGHTFREQ); ++ ++ sd->ctrls[BRIGHTNESS].min = -90; ++ sd->ctrls[BRIGHTNESS].max = 90; ++ sd->ctrls[BRIGHTNESS].def = 0; + gspca_dev->cam.cam_mode = ov562x_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(ov562x_mode); + +@@ -1360,8 +1387,12 @@ static int sd_start(struct gspca_dev *gs + { + struct sd *sd = (struct sd *) gspca_dev; + +- if (sd->sensor == SENSOR_OV971x || sd->sensor == SENSOR_OV562x) ++ if (sd->sensor == SENSOR_OV971x) + return gspca_dev->usb_err; ++ else if (sd->sensor == SENSOR_OV562x) { ++ setbrightness(gspca_dev); ++ return gspca_dev->usb_err; ++ } + switch (gspca_dev->curr_mode) { + case QVGA_MODE: /* 320x240 */ + sccb_w_array(gspca_dev, ov965x_start_1_vga, +Index: linux-3.3.x86_64/drivers/media/video/gspca/sn9c20x.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/gspca/sn9c20x.c ++++ linux-3.3.x86_64/drivers/media/video/gspca/sn9c20x.c +@@ -1,5 +1,7 @@ + /* + * Sonix sn9c201 sn9c202 library ++ * ++ * Copyright (C) 2012 Jean-Francois Moine + * Copyright (C) 2008-2009 microdia project + * Copyright (C) 2009 Brian Johnson + * +@@ -33,8 +35,6 @@ MODULE_AUTHOR("Brian Johnson dev; + int result; ++ ++ if (gspca_dev->usb_err < 0) ++ return; + result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + 0x00, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, +@@ -1125,17 +1103,19 @@ static int reg_r(struct gspca_dev *gspca + length, + 500); + if (unlikely(result < 0 || result != length)) { +- pr_err("Read register failed 0x%02X\n", reg); +- return -EIO; ++ pr_err("Read register %02x failed %d\n", reg, result); ++ gspca_dev->usb_err = result; + } +- return 0; + } + +-static int reg_w(struct gspca_dev *gspca_dev, u16 reg, ++static void reg_w(struct gspca_dev *gspca_dev, u16 reg, + const u8 *buffer, int length) + { + struct usb_device *dev = gspca_dev->dev; + int result; ++ ++ if (gspca_dev->usb_err < 0) ++ return; + memcpy(gspca_dev->usb_buf, buffer, length); + result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x08, +@@ -1146,38 +1126,41 @@ static int reg_w(struct gspca_dev *gspca + length, + 500); + if (unlikely(result < 0 || result != length)) { +- pr_err("Write register failed index 0x%02X\n", reg); +- return -EIO; ++ pr_err("Write register %02x failed %d\n", reg, result); ++ gspca_dev->usb_err = result; + } +- return 0; + } + +-static int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value) ++static void reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value) + { +- u8 data[1] = {value}; +- return reg_w(gspca_dev, reg, data, 1); ++ reg_w(gspca_dev, reg, &value, 1); + } + +-static int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer) ++static void i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer) + { + int i; ++ + reg_w(gspca_dev, 0x10c0, buffer, 8); + for (i = 0; i < 5; i++) { + reg_r(gspca_dev, 0x10c0, 1); ++ if (gspca_dev->usb_err < 0) ++ return; + if (gspca_dev->usb_buf[0] & 0x04) { +- if (gspca_dev->usb_buf[0] & 0x08) +- return -EIO; +- return 0; ++ if (gspca_dev->usb_buf[0] & 0x08) { ++ pr_err("i2c_w error\n"); ++ gspca_dev->usb_err = -EIO; ++ } ++ return; + } +- msleep(1); ++ msleep(10); + } +- return -EIO; ++ pr_err("i2c_w reg %02x no response\n", buffer[2]); ++/* gspca_dev->usb_err = -EIO; fixme: may occur */ + } + +-static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val) ++static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val) + { + struct sd *sd = (struct sd *) gspca_dev; +- + u8 row[8]; + + /* +@@ -1193,10 +1176,19 @@ static int i2c_w1(struct gspca_dev *gspc + row[6] = 0x00; + row[7] = 0x10; + +- return i2c_w(gspca_dev, row); ++ i2c_w(gspca_dev, row); ++} ++ ++static void i2c_w1_buf(struct gspca_dev *gspca_dev, ++ struct i2c_reg_u8 *buf, int sz) ++{ ++ while (--sz >= 0) { ++ i2c_w1(gspca_dev, buf->reg, buf->val); ++ buf++; ++ } + } + +-static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val) ++static void i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val) + { + struct sd *sd = (struct sd *) gspca_dev; + u8 row[8]; +@@ -1208,16 +1200,25 @@ static int i2c_w2(struct gspca_dev *gspc + row[0] = 0x81 | (3 << 4); + row[1] = sd->i2c_addr; + row[2] = reg; +- row[3] = (val >> 8) & 0xff; +- row[4] = val & 0xff; ++ row[3] = val >> 8; ++ row[4] = val; + row[5] = 0x00; + row[6] = 0x00; + row[7] = 0x10; + +- return i2c_w(gspca_dev, row); ++ i2c_w(gspca_dev, row); + } + +-static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val) ++static void i2c_w2_buf(struct gspca_dev *gspca_dev, ++ struct i2c_reg_u16 *buf, int sz) ++{ ++ while (--sz >= 0) { ++ i2c_w2(gspca_dev, buf->reg, buf->val); ++ buf++; ++ } ++} ++ ++static void i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val) + { + struct sd *sd = (struct sd *) gspca_dev; + u8 row[8]; +@@ -1230,19 +1231,15 @@ static int i2c_r1(struct gspca_dev *gspc + row[5] = 0; + row[6] = 0; + row[7] = 0x10; +- if (i2c_w(gspca_dev, row) < 0) +- return -EIO; ++ i2c_w(gspca_dev, row); + row[0] = 0x81 | (1 << 4) | 0x02; + row[2] = 0; +- if (i2c_w(gspca_dev, row) < 0) +- return -EIO; +- if (reg_r(gspca_dev, 0x10c2, 5) < 0) +- return -EIO; ++ i2c_w(gspca_dev, row); ++ reg_r(gspca_dev, 0x10c2, 5); + *val = gspca_dev->usb_buf[4]; +- return 0; + } + +-static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val) ++static void i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val) + { + struct sd *sd = (struct sd *) gspca_dev; + u8 row[8]; +@@ -1255,233 +1252,204 @@ static int i2c_r2(struct gspca_dev *gspc + row[5] = 0; + row[6] = 0; + row[7] = 0x10; +- if (i2c_w(gspca_dev, row) < 0) +- return -EIO; ++ i2c_w(gspca_dev, row); + row[0] = 0x81 | (2 << 4) | 0x02; + row[2] = 0; +- if (i2c_w(gspca_dev, row) < 0) +- return -EIO; +- if (reg_r(gspca_dev, 0x10c2, 5) < 0) +- return -EIO; ++ i2c_w(gspca_dev, row); ++ reg_r(gspca_dev, 0x10c2, 5); + *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4]; +- return 0; + } + +-static int ov9650_init_sensor(struct gspca_dev *gspca_dev) ++static void ov9650_init_sensor(struct gspca_dev *gspca_dev) + { +- int i; + u16 id; + struct sd *sd = (struct sd *) gspca_dev; + +- if (i2c_r2(gspca_dev, 0x1c, &id) < 0) +- return -EINVAL; ++ i2c_r2(gspca_dev, 0x1c, &id); ++ if (gspca_dev->usb_err < 0) ++ return; + + if (id != 0x7fa2) { + pr_err("sensor id for ov9650 doesn't match (0x%04x)\n", id); +- return -ENODEV; ++ gspca_dev->usb_err = -ENODEV; ++ return; + } + +- for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) { +- if (i2c_w1(gspca_dev, ov9650_init[i].reg, +- ov9650_init[i].val) < 0) { +- pr_err("OV9650 sensor initialization failed\n"); +- return -ENODEV; +- } +- } ++ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */ ++ msleep(200); ++ i2c_w1_buf(gspca_dev, ov9650_init, ARRAY_SIZE(ov9650_init)); ++ if (gspca_dev->usb_err < 0) ++ pr_err("OV9650 sensor initialization failed\n"); + sd->hstart = 1; + sd->vstart = 7; +- return 0; + } + +-static int ov9655_init_sensor(struct gspca_dev *gspca_dev) ++static void ov9655_init_sensor(struct gspca_dev *gspca_dev) + { +- int i; + struct sd *sd = (struct sd *) gspca_dev; + +- for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) { +- if (i2c_w1(gspca_dev, ov9655_init[i].reg, +- ov9655_init[i].val) < 0) { +- pr_err("OV9655 sensor initialization failed\n"); +- return -ENODEV; +- } +- } ++ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */ ++ msleep(200); ++ i2c_w1_buf(gspca_dev, ov9655_init, ARRAY_SIZE(ov9655_init)); ++ if (gspca_dev->usb_err < 0) ++ pr_err("OV9655 sensor initialization failed\n"); ++ + /* disable hflip and vflip */ +- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); ++ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP); + sd->hstart = 1; + sd->vstart = 2; +- return 0; + } + +-static int soi968_init_sensor(struct gspca_dev *gspca_dev) ++static void soi968_init_sensor(struct gspca_dev *gspca_dev) + { +- int i; + struct sd *sd = (struct sd *) gspca_dev; + +- for (i = 0; i < ARRAY_SIZE(soi968_init); i++) { +- if (i2c_w1(gspca_dev, soi968_init[i].reg, +- soi968_init[i].val) < 0) { +- pr_err("SOI968 sensor initialization failed\n"); +- return -ENODEV; +- } +- } ++ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */ ++ msleep(200); ++ i2c_w1_buf(gspca_dev, soi968_init, ARRAY_SIZE(soi968_init)); ++ if (gspca_dev->usb_err < 0) ++ pr_err("SOI968 sensor initialization failed\n"); ++ + /* disable hflip and vflip */ +- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) +- | (1 << EXPOSURE_IDX); ++ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP) ++ | (1 << EXPOSURE); + sd->hstart = 60; + sd->vstart = 11; +- return 0; + } + +-static int ov7660_init_sensor(struct gspca_dev *gspca_dev) ++static void ov7660_init_sensor(struct gspca_dev *gspca_dev) + { +- int i; + struct sd *sd = (struct sd *) gspca_dev; + +- for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) { +- if (i2c_w1(gspca_dev, ov7660_init[i].reg, +- ov7660_init[i].val) < 0) { +- pr_err("OV7660 sensor initialization failed\n"); +- return -ENODEV; +- } +- } ++ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */ ++ msleep(200); ++ i2c_w1_buf(gspca_dev, ov7660_init, ARRAY_SIZE(ov7660_init)); ++ if (gspca_dev->usb_err < 0) ++ pr_err("OV7660 sensor initialization failed\n"); + sd->hstart = 3; + sd->vstart = 3; +- return 0; + } + +-static int ov7670_init_sensor(struct gspca_dev *gspca_dev) ++static void ov7670_init_sensor(struct gspca_dev *gspca_dev) + { +- int i; + struct sd *sd = (struct sd *) gspca_dev; + +- for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) { +- if (i2c_w1(gspca_dev, ov7670_init[i].reg, +- ov7670_init[i].val) < 0) { +- pr_err("OV7670 sensor initialization failed\n"); +- return -ENODEV; +- } +- } ++ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */ ++ msleep(200); ++ i2c_w1_buf(gspca_dev, ov7670_init, ARRAY_SIZE(ov7670_init)); ++ if (gspca_dev->usb_err < 0) ++ pr_err("OV7670 sensor initialization failed\n"); ++ + /* disable hflip and vflip */ +- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); ++ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP); + sd->hstart = 0; + sd->vstart = 1; +- return 0; + } + +-static int mt9v_init_sensor(struct gspca_dev *gspca_dev) ++static void mt9v_init_sensor(struct gspca_dev *gspca_dev) + { + struct sd *sd = (struct sd *) gspca_dev; +- int i; + u16 value; +- int ret; + + sd->i2c_addr = 0x5d; +- ret = i2c_r2(gspca_dev, 0xff, &value); +- if ((ret == 0) && (value == 0x8243)) { +- for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) { +- if (i2c_w2(gspca_dev, mt9v011_init[i].reg, +- mt9v011_init[i].val) < 0) { +- pr_err("MT9V011 sensor initialization failed\n"); +- return -ENODEV; +- } ++ i2c_r2(gspca_dev, 0xff, &value); ++ if (gspca_dev->usb_err >= 0 ++ && value == 0x8243) { ++ i2c_w2_buf(gspca_dev, mt9v011_init, ARRAY_SIZE(mt9v011_init)); ++ if (gspca_dev->usb_err < 0) { ++ pr_err("MT9V011 sensor initialization failed\n"); ++ return; + } + sd->hstart = 2; + sd->vstart = 2; + sd->sensor = SENSOR_MT9V011; + pr_info("MT9V011 sensor detected\n"); +- return 0; ++ return; + } + ++ gspca_dev->usb_err = 0; + sd->i2c_addr = 0x5c; + i2c_w2(gspca_dev, 0x01, 0x0004); +- ret = i2c_r2(gspca_dev, 0xff, &value); +- if ((ret == 0) && (value == 0x823a)) { +- for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) { +- if (i2c_w2(gspca_dev, mt9v111_init[i].reg, +- mt9v111_init[i].val) < 0) { +- pr_err("MT9V111 sensor initialization failed\n"); +- return -ENODEV; +- } ++ i2c_r2(gspca_dev, 0xff, &value); ++ if (gspca_dev->usb_err >= 0 ++ && value == 0x823a) { ++ i2c_w2_buf(gspca_dev, mt9v111_init, ARRAY_SIZE(mt9v111_init)); ++ if (gspca_dev->usb_err < 0) { ++ pr_err("MT9V111 sensor initialization failed\n"); ++ return; + } +- gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) +- | (1 << AUTOGAIN_IDX) +- | (1 << GAIN_IDX); ++ gspca_dev->ctrl_dis = (1 << EXPOSURE) ++ | (1 << AUTOGAIN) ++ | (1 << GAIN); + sd->hstart = 2; + sd->vstart = 2; + sd->sensor = SENSOR_MT9V111; + pr_info("MT9V111 sensor detected\n"); +- return 0; ++ return; + } + ++ gspca_dev->usb_err = 0; + sd->i2c_addr = 0x5d; +- ret = i2c_w2(gspca_dev, 0xf0, 0x0000); +- if (ret < 0) { ++ i2c_w2(gspca_dev, 0xf0, 0x0000); ++ if (gspca_dev->usb_err < 0) { ++ gspca_dev->usb_err = 0; + sd->i2c_addr = 0x48; + i2c_w2(gspca_dev, 0xf0, 0x0000); + } +- ret = i2c_r2(gspca_dev, 0x00, &value); +- if ((ret == 0) && (value == 0x1229)) { +- for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) { +- if (i2c_w2(gspca_dev, mt9v112_init[i].reg, +- mt9v112_init[i].val) < 0) { +- pr_err("MT9V112 sensor initialization failed\n"); +- return -ENODEV; +- } ++ i2c_r2(gspca_dev, 0x00, &value); ++ if (gspca_dev->usb_err >= 0 ++ && value == 0x1229) { ++ i2c_w2_buf(gspca_dev, mt9v112_init, ARRAY_SIZE(mt9v112_init)); ++ if (gspca_dev->usb_err < 0) { ++ pr_err("MT9V112 sensor initialization failed\n"); ++ return; + } + sd->hstart = 6; + sd->vstart = 2; + sd->sensor = SENSOR_MT9V112; + pr_info("MT9V112 sensor detected\n"); +- return 0; ++ return; + } + +- return -ENODEV; ++ gspca_dev->usb_err = -ENODEV; + } + +-static int mt9m112_init_sensor(struct gspca_dev *gspca_dev) ++static void mt9m112_init_sensor(struct gspca_dev *gspca_dev) + { + struct sd *sd = (struct sd *) gspca_dev; +- int i; +- for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) { +- if (i2c_w2(gspca_dev, mt9m112_init[i].reg, +- mt9m112_init[i].val) < 0) { +- pr_err("MT9M112 sensor initialization failed\n"); +- return -ENODEV; +- } +- } +- gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) +- | (1 << GAIN_IDX); ++ ++ i2c_w2_buf(gspca_dev, mt9m112_init, ARRAY_SIZE(mt9m112_init)); ++ if (gspca_dev->usb_err < 0) ++ pr_err("MT9M112 sensor initialization failed\n"); ++ ++ gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN) ++ | (1 << GAIN); + sd->hstart = 0; + sd->vstart = 2; +- return 0; + } + +-static int mt9m111_init_sensor(struct gspca_dev *gspca_dev) ++static void mt9m111_init_sensor(struct gspca_dev *gspca_dev) + { + struct sd *sd = (struct sd *) gspca_dev; +- int i; +- for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) { +- if (i2c_w2(gspca_dev, mt9m111_init[i].reg, +- mt9m111_init[i].val) < 0) { +- pr_err("MT9M111 sensor initialization failed\n"); +- return -ENODEV; +- } +- } +- gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) +- | (1 << GAIN_IDX); ++ ++ i2c_w2_buf(gspca_dev, mt9m111_init, ARRAY_SIZE(mt9m111_init)); ++ if (gspca_dev->usb_err < 0) ++ pr_err("MT9M111 sensor initialization failed\n"); ++ ++ gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN) ++ | (1 << GAIN); + sd->hstart = 0; + sd->vstart = 2; +- return 0; + } + +-static int mt9m001_init_sensor(struct gspca_dev *gspca_dev) ++static void mt9m001_init_sensor(struct gspca_dev *gspca_dev) + { + struct sd *sd = (struct sd *) gspca_dev; +- int i; + u16 id; + +- if (i2c_r2(gspca_dev, 0x00, &id) < 0) +- return -EINVAL; ++ i2c_r2(gspca_dev, 0x00, &id); ++ if (gspca_dev->usb_err < 0) ++ return; + + /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */ + switch (id) { +@@ -1494,85 +1462,78 @@ static int mt9m001_init_sensor(struct gs + break; + default: + pr_err("No MT9M001 chip detected, ID = %x\n\n", id); +- return -ENODEV; ++ gspca_dev->usb_err = -ENODEV; ++ return; + } + +- for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) { +- if (i2c_w2(gspca_dev, mt9m001_init[i].reg, +- mt9m001_init[i].val) < 0) { +- pr_err("MT9M001 sensor initialization failed\n"); +- return -ENODEV; +- } +- } ++ i2c_w2_buf(gspca_dev, mt9m001_init, ARRAY_SIZE(mt9m001_init)); ++ if (gspca_dev->usb_err < 0) ++ pr_err("MT9M001 sensor initialization failed\n"); ++ + /* disable hflip and vflip */ +- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); ++ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP); + sd->hstart = 1; + sd->vstart = 1; +- return 0; + } + +-static int hv7131r_init_sensor(struct gspca_dev *gspca_dev) ++static void hv7131r_init_sensor(struct gspca_dev *gspca_dev) + { +- int i; + struct sd *sd = (struct sd *) gspca_dev; + +- for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) { +- if (i2c_w1(gspca_dev, hv7131r_init[i].reg, +- hv7131r_init[i].val) < 0) { +- pr_err("HV7131R Sensor initialization failed\n"); +- return -ENODEV; +- } +- } ++ i2c_w1_buf(gspca_dev, hv7131r_init, ARRAY_SIZE(hv7131r_init)); ++ if (gspca_dev->usb_err < 0) ++ pr_err("HV7131R Sensor initialization failed\n"); ++ + sd->hstart = 0; + sd->vstart = 1; +- return 0; + } + +-static int set_cmatrix(struct gspca_dev *gspca_dev) ++static void set_cmatrix(struct gspca_dev *gspca_dev) + { + struct sd *sd = (struct sd *) gspca_dev; +- s32 hue_coord, hue_index = 180 + sd->hue; ++ int satur; ++ s32 hue_coord, hue_index = 180 + sd->ctrls[HUE].val; + u8 cmatrix[21]; + + memset(cmatrix, 0, sizeof cmatrix); +- cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26; ++ cmatrix[2] = (sd->ctrls[CONTRAST].val * 0x25 / 0x100) + 0x26; + cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25; + cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25; +- cmatrix[18] = sd->brightness - 0x80; ++ cmatrix[18] = sd->ctrls[BRIGHTNESS].val - 0x80; + +- hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8; ++ satur = sd->ctrls[SATURATION].val; ++ hue_coord = (hsv_red_x[hue_index] * satur) >> 8; + cmatrix[6] = hue_coord; + cmatrix[7] = (hue_coord >> 8) & 0x0f; + +- hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8; ++ hue_coord = (hsv_red_y[hue_index] * satur) >> 8; + cmatrix[8] = hue_coord; + cmatrix[9] = (hue_coord >> 8) & 0x0f; + +- hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8; ++ hue_coord = (hsv_green_x[hue_index] * satur) >> 8; + cmatrix[10] = hue_coord; + cmatrix[11] = (hue_coord >> 8) & 0x0f; + +- hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8; ++ hue_coord = (hsv_green_y[hue_index] * satur) >> 8; + cmatrix[12] = hue_coord; + cmatrix[13] = (hue_coord >> 8) & 0x0f; + +- hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8; ++ hue_coord = (hsv_blue_x[hue_index] * satur) >> 8; + cmatrix[14] = hue_coord; + cmatrix[15] = (hue_coord >> 8) & 0x0f; + +- hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8; ++ hue_coord = (hsv_blue_y[hue_index] * satur) >> 8; + cmatrix[16] = hue_coord; + cmatrix[17] = (hue_coord >> 8) & 0x0f; + +- return reg_w(gspca_dev, 0x10e1, cmatrix, 21); ++ reg_w(gspca_dev, 0x10e1, cmatrix, 21); + } + +-static int set_gamma(struct gspca_dev *gspca_dev) ++static void set_gamma(struct gspca_dev *gspca_dev) + { + struct sd *sd = (struct sd *) gspca_dev; + u8 gamma[17]; +- u8 gval = sd->gamma * 0xb8 / 0x100; +- ++ u8 gval = sd->ctrls[GAMMA].val * 0xb8 / 0x100; + + gamma[0] = 0x0a; + gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8); +@@ -1592,29 +1553,29 @@ static int set_gamma(struct gspca_dev *g + gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8); + gamma[16] = 0xf5; + +- return reg_w(gspca_dev, 0x1190, gamma, 17); ++ reg_w(gspca_dev, 0x1190, gamma, 17); + } + +-static int set_redblue(struct gspca_dev *gspca_dev) ++static void set_redblue(struct gspca_dev *gspca_dev) + { + struct sd *sd = (struct sd *) gspca_dev; +- reg_w1(gspca_dev, 0x118c, sd->red); +- reg_w1(gspca_dev, 0x118f, sd->blue); +- return 0; ++ ++ reg_w1(gspca_dev, 0x118c, sd->ctrls[RED].val); ++ reg_w1(gspca_dev, 0x118f, sd->ctrls[BLUE].val); + } + +-static int set_hvflip(struct gspca_dev *gspca_dev) ++static void set_hvflip(struct gspca_dev *gspca_dev) + { + u8 value, tslb, hflip, vflip; + u16 value2; + struct sd *sd = (struct sd *) gspca_dev; + + if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) { +- hflip = !sd->hflip; +- vflip = !sd->vflip; ++ hflip = !sd->ctrls[HFLIP].val; ++ vflip = !sd->ctrls[VFLIP].val; + } else { +- hflip = sd->hflip; +- vflip = sd->vflip; ++ hflip = sd->ctrls[HFLIP].val; ++ vflip = sd->ctrls[VFLIP].val; + } + + switch (sd->sensor) { +@@ -1625,8 +1586,9 @@ static int set_hvflip(struct gspca_dev * + if (vflip) { + value |= 0x10; + sd->vstart = 2; +- } else ++ } else { + sd->vstart = 3; ++ } + reg_w1(gspca_dev, 0x1182, sd->vstart); + i2c_w1(gspca_dev, 0x1e, value); + break; +@@ -1674,13 +1636,15 @@ static int set_hvflip(struct gspca_dev * + i2c_w1(gspca_dev, 0x01, value); + break; + } +- return 0; + } + +-static int set_exposure(struct gspca_dev *gspca_dev) ++static void set_exposure(struct gspca_dev *gspca_dev) + { + struct sd *sd = (struct sd *) gspca_dev; + u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e}; ++ int expo; ++ ++ expo = sd->ctrls[EXPOSURE].val; + switch (sd->sensor) { + case SENSOR_OV7660: + case SENSOR_OV7670: +@@ -1688,35 +1652,37 @@ static int set_exposure(struct gspca_dev + case SENSOR_OV9650: + exp[0] |= (3 << 4); + exp[2] = 0x2d; +- exp[3] = sd->exposure & 0xff; +- exp[4] = sd->exposure >> 8; ++ exp[3] = expo; ++ exp[4] = expo >> 8; + break; + case SENSOR_MT9M001: + case SENSOR_MT9V112: + case SENSOR_MT9V011: + exp[0] |= (3 << 4); + exp[2] = 0x09; +- exp[3] = sd->exposure >> 8; +- exp[4] = sd->exposure & 0xff; ++ exp[3] = expo >> 8; ++ exp[4] = expo; + break; + case SENSOR_HV7131R: + exp[0] |= (4 << 4); + exp[2] = 0x25; +- exp[3] = (sd->exposure >> 5) & 0xff; +- exp[4] = (sd->exposure << 3) & 0xff; ++ exp[3] = expo >> 5; ++ exp[4] = expo << 3; + exp[5] = 0; + break; + default: +- return 0; ++ return; + } + i2c_w(gspca_dev, exp); +- return 0; + } + +-static int set_gain(struct gspca_dev *gspca_dev) ++static void set_gain(struct gspca_dev *gspca_dev) + { + struct sd *sd = (struct sd *) gspca_dev; + u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d}; ++ int g; ++ ++ g = sd->ctrls[GAIN].val; + switch (sd->sensor) { + case SENSOR_OV7660: + case SENSOR_OV7670: +@@ -1724,238 +1690,50 @@ static int set_gain(struct gspca_dev *gs + case SENSOR_OV9655: + case SENSOR_OV9650: + gain[0] |= (2 << 4); +- gain[3] = ov_gain[sd->gain]; ++ gain[3] = ov_gain[g]; + break; + case SENSOR_MT9V011: + gain[0] |= (3 << 4); + gain[2] = 0x35; +- gain[3] = micron1_gain[sd->gain] >> 8; +- gain[4] = micron1_gain[sd->gain] & 0xff; ++ gain[3] = micron1_gain[g] >> 8; ++ gain[4] = micron1_gain[g]; + break; + case SENSOR_MT9V112: + gain[0] |= (3 << 4); + gain[2] = 0x2f; +- gain[3] = micron1_gain[sd->gain] >> 8; +- gain[4] = micron1_gain[sd->gain] & 0xff; ++ gain[3] = micron1_gain[g] >> 8; ++ gain[4] = micron1_gain[g]; + break; + case SENSOR_MT9M001: + gain[0] |= (3 << 4); + gain[2] = 0x2f; +- gain[3] = micron2_gain[sd->gain] >> 8; +- gain[4] = micron2_gain[sd->gain] & 0xff; ++ gain[3] = micron2_gain[g] >> 8; ++ gain[4] = micron2_gain[g]; + break; + case SENSOR_HV7131R: + gain[0] |= (2 << 4); + gain[2] = 0x30; +- gain[3] = hv7131r_gain[sd->gain]; ++ gain[3] = hv7131r_gain[g]; + break; + default: +- return 0; ++ return; + } + i2c_w(gspca_dev, gain); +- return 0; +-} +- +-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) +- return set_cmatrix(gspca_dev); +- return 0; +-} +- +-static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- *val = sd->brightness; +- return 0; +-} +- +- +-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) +- return set_cmatrix(gspca_dev); +- return 0; +-} +- +-static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- *val = sd->contrast; +- return 0; +-} +- +-static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- +- sd->saturation = val; +- if (gspca_dev->streaming) +- return set_cmatrix(gspca_dev); +- return 0; +-} +- +-static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- *val = sd->saturation; +- return 0; +-} +- +-static int sd_sethue(struct gspca_dev *gspca_dev, s32 val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- +- sd->hue = val; +- if (gspca_dev->streaming) +- return set_cmatrix(gspca_dev); +- return 0; +-} +- +-static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- *val = sd->hue; +- return 0; +-} +- +-static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- +- sd->gamma = val; +- if (gspca_dev->streaming) +- return set_gamma(gspca_dev); +- return 0; +-} +- +-static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- *val = sd->gamma; +- return 0; +-} +- +-static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- +- sd->red = val; +- if (gspca_dev->streaming) +- return set_redblue(gspca_dev); +- return 0; +-} +- +-static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- *val = sd->red; +- return 0; +-} +- +-static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- +- sd->blue = val; +- if (gspca_dev->streaming) +- return set_redblue(gspca_dev); +- return 0; +-} +- +-static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- *val = sd->blue; +- 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) +- return set_hvflip(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) +- return set_hvflip(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; +-} +- +-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) +- return set_exposure(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_setgain(struct gspca_dev *gspca_dev, s32 val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- +- sd->gain = val; +- if (gspca_dev->streaming) +- return set_gain(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_setautoexposure(struct gspca_dev *gspca_dev, s32 val) ++static void set_quality(struct gspca_dev *gspca_dev) + { + struct sd *sd = (struct sd *) gspca_dev; +- sd->auto_exposure = val; +- return 0; +-} + +-static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val) +-{ +- struct sd *sd = (struct sd *) gspca_dev; +- *val = sd->auto_exposure; +- return 0; ++ jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val); ++ reg_w1(gspca_dev, 0x1061, 0x01); /* stop transfer */ ++ reg_w1(gspca_dev, 0x10e0, sd->fmt | 0x20); /* write QTAB */ ++ reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64); ++ reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64); ++ reg_w1(gspca_dev, 0x1061, 0x03); /* restart transfer */ ++ reg_w1(gspca_dev, 0x10e0, sd->fmt); ++ sd->fmt ^= 0x0c; /* invert QTAB use + write */ ++ reg_w1(gspca_dev, 0x10e0, sd->fmt); + } + + #ifdef CONFIG_VIDEO_ADV_DEBUG +@@ -1963,28 +1741,26 @@ static int sd_dbg_g_register(struct gspc + struct v4l2_dbg_register *reg) + { + struct sd *sd = (struct sd *) gspca_dev; ++ + switch (reg->match.type) { + case V4L2_CHIP_MATCH_HOST: + if (reg->match.addr != 0) + return -EINVAL; + if (reg->reg < 0x1000 || reg->reg > 0x11ff) + return -EINVAL; +- if (reg_r(gspca_dev, reg->reg, 1) < 0) +- return -EINVAL; ++ reg_r(gspca_dev, reg->reg, 1); + reg->val = gspca_dev->usb_buf[0]; +- return 0; ++ return gspca_dev->usb_err; + case V4L2_CHIP_MATCH_I2C_ADDR: + if (reg->match.addr != sd->i2c_addr) + return -EINVAL; + if (sd->sensor >= SENSOR_MT9V011 && + sd->sensor <= SENSOR_MT9M112) { +- if (i2c_r2(gspca_dev, reg->reg, (u16 *)®->val) < 0) +- return -EINVAL; ++ i2c_r2(gspca_dev, reg->reg, (u16 *) ®->val); + } else { +- if (i2c_r1(gspca_dev, reg->reg, (u8 *)®->val) < 0) +- return -EINVAL; ++ i2c_r1(gspca_dev, reg->reg, (u8 *) ®->val); + } +- return 0; ++ return gspca_dev->usb_err; + } + return -EINVAL; + } +@@ -1993,27 +1769,25 @@ static int sd_dbg_s_register(struct gspc + struct v4l2_dbg_register *reg) + { + struct sd *sd = (struct sd *) gspca_dev; ++ + switch (reg->match.type) { + case V4L2_CHIP_MATCH_HOST: + if (reg->match.addr != 0) + return -EINVAL; + if (reg->reg < 0x1000 || reg->reg > 0x11ff) + return -EINVAL; +- if (reg_w1(gspca_dev, reg->reg, reg->val) < 0) +- return -EINVAL; +- return 0; ++ reg_w1(gspca_dev, reg->reg, reg->val); ++ return gspca_dev->usb_err; + case V4L2_CHIP_MATCH_I2C_ADDR: + if (reg->match.addr != sd->i2c_addr) + return -EINVAL; + if (sd->sensor >= SENSOR_MT9V011 && + sd->sensor <= SENSOR_MT9M112) { +- if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0) +- return -EINVAL; ++ i2c_w2(gspca_dev, reg->reg, reg->val); + } else { +- if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0) +- return -EINVAL; ++ i2c_w1(gspca_dev, reg->reg, reg->val); + } +- return 0; ++ return gspca_dev->usb_err; + } + return -EINVAL; + } +@@ -2050,9 +1824,9 @@ static int sd_config(struct gspca_dev *g + cam = &gspca_dev->cam; + cam->needs_full_bandwidth = 1; + +- sd->sensor = (id->driver_info >> 8) & 0xff; +- sd->i2c_addr = id->driver_info & 0xff; +- sd->flags = (id->driver_info >> 16) & 0xff; ++ sd->sensor = id->driver_info >> 8; ++ sd->i2c_addr = id->driver_info; ++ sd->flags = id->driver_info >> 16; + + switch (sd->sensor) { + case SENSOR_MT9M112: +@@ -2076,21 +1850,9 @@ static int sd_config(struct gspca_dev *g + sd->older_step = 0; + sd->exposure_step = 16; + +- sd->brightness = BRIGHTNESS_DEFAULT; +- sd->contrast = CONTRAST_DEFAULT; +- sd->saturation = SATURATION_DEFAULT; +- sd->hue = HUE_DEFAULT; +- sd->gamma = GAMMA_DEFAULT; +- sd->red = RED_DEFAULT; +- sd->blue = BLUE_DEFAULT; +- +- sd->hflip = HFLIP_DEFAULT; +- sd->vflip = VFLIP_DEFAULT; +- sd->exposure = EXPOSURE_DEFAULT; +- sd->gain = GAIN_DEFAULT; +- sd->auto_exposure = AUTO_EXPOSURE_DEFAULT; ++ gspca_dev->cam.ctrls = sd->ctrls; + +- sd->quality = 95; ++ INIT_WORK(&sd->work, qual_upd); + + return 0; + } +@@ -2105,9 +1867,10 @@ static int sd_init(struct gspca_dev *gsp + + for (i = 0; i < ARRAY_SIZE(bridge_init); i++) { + value = bridge_init[i][1]; +- if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) { ++ reg_w(gspca_dev, bridge_init[i][0], &value, 1); ++ if (gspca_dev->usb_err < 0) { + pr_err("Device initialization failed\n"); +- return -ENODEV; ++ return gspca_dev->usb_err; + } + } + +@@ -2116,72 +1879,85 @@ static int sd_init(struct gspca_dev *gsp + else + reg_w1(gspca_dev, 0x1006, 0x20); + +- if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) { ++ reg_w(gspca_dev, 0x10c0, i2c_init, 9); ++ if (gspca_dev->usb_err < 0) { + pr_err("Device initialization failed\n"); +- return -ENODEV; ++ return gspca_dev->usb_err; + } + + switch (sd->sensor) { + case SENSOR_OV9650: +- if (ov9650_init_sensor(gspca_dev) < 0) +- return -ENODEV; ++ ov9650_init_sensor(gspca_dev); ++ if (gspca_dev->usb_err < 0) ++ break; + pr_info("OV9650 sensor detected\n"); + break; + case SENSOR_OV9655: +- if (ov9655_init_sensor(gspca_dev) < 0) +- return -ENODEV; ++ ov9655_init_sensor(gspca_dev); ++ if (gspca_dev->usb_err < 0) ++ break; + pr_info("OV9655 sensor detected\n"); + break; + case SENSOR_SOI968: +- if (soi968_init_sensor(gspca_dev) < 0) +- return -ENODEV; ++ soi968_init_sensor(gspca_dev); ++ if (gspca_dev->usb_err < 0) ++ break; + pr_info("SOI968 sensor detected\n"); + break; + case SENSOR_OV7660: +- if (ov7660_init_sensor(gspca_dev) < 0) +- return -ENODEV; ++ ov7660_init_sensor(gspca_dev); ++ if (gspca_dev->usb_err < 0) ++ break; + pr_info("OV7660 sensor detected\n"); + break; + case SENSOR_OV7670: +- if (ov7670_init_sensor(gspca_dev) < 0) +- return -ENODEV; ++ ov7670_init_sensor(gspca_dev); ++ if (gspca_dev->usb_err < 0) ++ break; + pr_info("OV7670 sensor detected\n"); + break; + case SENSOR_MT9VPRB: +- if (mt9v_init_sensor(gspca_dev) < 0) +- return -ENODEV; ++ mt9v_init_sensor(gspca_dev); ++ if (gspca_dev->usb_err < 0) ++ break; ++ pr_info("MT9VPRB sensor detected\n"); + break; + case SENSOR_MT9M111: +- if (mt9m111_init_sensor(gspca_dev) < 0) +- return -ENODEV; ++ mt9m111_init_sensor(gspca_dev); ++ if (gspca_dev->usb_err < 0) ++ break; + pr_info("MT9M111 sensor detected\n"); + break; + case SENSOR_MT9M112: +- if (mt9m112_init_sensor(gspca_dev) < 0) +- return -ENODEV; ++ mt9m112_init_sensor(gspca_dev); ++ if (gspca_dev->usb_err < 0) ++ break; + pr_info("MT9M112 sensor detected\n"); + break; + case SENSOR_MT9M001: +- if (mt9m001_init_sensor(gspca_dev) < 0) +- return -ENODEV; ++ mt9m001_init_sensor(gspca_dev); ++ if (gspca_dev->usb_err < 0) ++ break; + break; + case SENSOR_HV7131R: +- if (hv7131r_init_sensor(gspca_dev) < 0) +- return -ENODEV; ++ hv7131r_init_sensor(gspca_dev); ++ if (gspca_dev->usb_err < 0) ++ break; + pr_info("HV7131R sensor detected\n"); + break; + default: +- pr_info("Unsupported Sensor\n"); +- return -ENODEV; ++ pr_err("Unsupported sensor\n"); ++ gspca_dev->usb_err = -ENODEV; + } + +- return 0; ++ return gspca_dev->usb_err; + } + + static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode) + { + struct sd *sd = (struct sd *) gspca_dev; + u8 value; ++ + switch (sd->sensor) { + case SENSOR_SOI968: + if (mode & MODE_SXGA) { +@@ -2264,6 +2040,7 @@ static int sd_isoc_init(struct gspca_dev + break; + default: /* >= 640x480 */ + gspca_dev->alt = 9; ++ break; + } + } + +@@ -2290,14 +2067,15 @@ static int sd_start(struct gspca_dev *gs + + jpeg_define(sd->jpeg_hdr, height, width, + 0x21); +- jpeg_set_qual(sd->jpeg_hdr, sd->quality); ++ jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val); + + if (mode & MODE_RAW) + fmt = 0x2d; + else if (mode & MODE_JPEG) +- fmt = 0x2c; ++ fmt = 0x24; + else + fmt = 0x2f; /* YUV 420 */ ++ sd->fmt = fmt; + + switch (mode & SCALE_MASK) { + case SCALE_1280x1024: +@@ -2334,18 +2112,37 @@ static int sd_start(struct gspca_dev *gs + set_hvflip(gspca_dev); + + reg_w1(gspca_dev, 0x1007, 0x20); ++ reg_w1(gspca_dev, 0x1061, 0x03); + +- reg_r(gspca_dev, 0x1061, 1); +- reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02); +- return 0; ++ /* if JPEG, prepare the compression quality update */ ++ if (mode & MODE_JPEG) { ++ sd->pktsz = sd->npkt = 0; ++ sd->nchg = 0; ++ sd->work_thread = ++ create_singlethread_workqueue(KBUILD_MODNAME); ++ } ++ ++ return gspca_dev->usb_err; + } + + static void sd_stopN(struct gspca_dev *gspca_dev) + { + reg_w1(gspca_dev, 0x1007, 0x00); ++ reg_w1(gspca_dev, 0x1061, 0x01); ++} + +- reg_r(gspca_dev, 0x1061, 1); +- reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02); ++/* called on streamoff with alt==0 and on disconnect */ ++/* the usb_lock is held at entry - restore on exit */ ++static void sd_stop0(struct gspca_dev *gspca_dev) ++{ ++ struct sd *sd = (struct sd *) gspca_dev; ++ ++ if (sd->work_thread != NULL) { ++ mutex_unlock(&gspca_dev->usb_lock); ++ destroy_workqueue(sd->work_thread); ++ mutex_lock(&gspca_dev->usb_lock); ++ sd->work_thread = NULL; ++ } + } + + static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum) +@@ -2359,15 +2156,15 @@ static void do_autoexposure(struct gspca + * and exposure steps + */ + if (avg_lum < MIN_AVG_LUM) { +- if (sd->exposure > 0x1770) ++ if (sd->ctrls[EXPOSURE].val > 0x1770) + return; + +- new_exp = sd->exposure + sd->exposure_step; ++ new_exp = sd->ctrls[EXPOSURE].val + sd->exposure_step; + if (new_exp > 0x1770) + new_exp = 0x1770; + if (new_exp < 0x10) + new_exp = 0x10; +- sd->exposure = new_exp; ++ sd->ctrls[EXPOSURE].val = new_exp; + set_exposure(gspca_dev); + + sd->older_step = sd->old_step; +@@ -2379,14 +2176,14 @@ static void do_autoexposure(struct gspca + sd->exposure_step += 2; + } + if (avg_lum > MAX_AVG_LUM) { +- if (sd->exposure < 0x10) ++ if (sd->ctrls[EXPOSURE].val < 0x10) + return; +- new_exp = sd->exposure - sd->exposure_step; ++ new_exp = sd->ctrls[EXPOSURE].val - sd->exposure_step; + if (new_exp > 0x1700) + new_exp = 0x1770; + if (new_exp < 0x10) + new_exp = 0x10; +- sd->exposure = new_exp; ++ sd->ctrls[EXPOSURE].val = new_exp; + set_exposure(gspca_dev); + sd->older_step = sd->old_step; + sd->old_step = 0; +@@ -2403,14 +2200,14 @@ static void do_autogain(struct gspca_dev + struct sd *sd = (struct sd *) gspca_dev; + + if (avg_lum < MIN_AVG_LUM) { +- if (sd->gain + 1 <= 28) { +- sd->gain++; ++ if (sd->ctrls[GAIN].val + 1 <= 28) { ++ sd->ctrls[GAIN].val++; + set_gain(gspca_dev); + } + } + if (avg_lum > MAX_AVG_LUM) { +- if (sd->gain > 0) { +- sd->gain--; ++ if (sd->ctrls[GAIN].val > 0) { ++ sd->ctrls[GAIN].val--; + set_gain(gspca_dev); + } + } +@@ -2421,7 +2218,7 @@ static void sd_dqcallback(struct gspca_d + struct sd *sd = (struct sd *) gspca_dev; + int avg_lum; + +- if (!sd->auto_exposure) ++ if (!sd->ctrls[AUTOGAIN].val) + return; + + avg_lum = atomic_read(&sd->avg_lum); +@@ -2431,33 +2228,92 @@ static void sd_dqcallback(struct gspca_d + do_autoexposure(gspca_dev, avg_lum); + } + ++/* JPEG quality update */ ++/* This function is executed from a work queue. */ ++static void qual_upd(struct work_struct *work) ++{ ++ struct sd *sd = container_of(work, struct sd, work); ++ struct gspca_dev *gspca_dev = &sd->gspca_dev; ++ ++ mutex_lock(&gspca_dev->usb_lock); ++ PDEBUG(D_STREAM, "qual_upd %d%%", sd->ctrls[QUALITY].val); ++ set_quality(gspca_dev); ++ mutex_unlock(&gspca_dev->usb_lock); ++} ++ + #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* interrupt packet */ + int len) /* interrupt packet length */ + { + struct sd *sd = (struct sd *) gspca_dev; +- int ret = -EINVAL; ++ + if (!(sd->flags & HAS_NO_BUTTON) && len == 1) { +- input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); +- input_sync(gspca_dev->input_dev); +- input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); +- input_sync(gspca_dev->input_dev); +- ret = 0; ++ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); ++ input_sync(gspca_dev->input_dev); ++ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); ++ input_sync(gspca_dev->input_dev); ++ return 0; + } +- return ret; ++ return -EINVAL; + } + #endif + ++/* check the JPEG compression */ ++static void transfer_check(struct gspca_dev *gspca_dev, ++ u8 *data) ++{ ++ struct sd *sd = (struct sd *) gspca_dev; ++ int new_qual, r; ++ ++ new_qual = 0; ++ ++ /* if USB error, discard the frame and decrease the quality */ ++ if (data[6] & 0x08) { /* USB FIFO full */ ++ gspca_dev->last_packet_type = DISCARD_PACKET; ++ new_qual = -5; ++ } else { ++ ++ /* else, compute the filling rate and a new JPEG quality */ ++ r = (sd->pktsz * 100) / ++ (sd->npkt * ++ gspca_dev->urb[0]->iso_frame_desc[0].length); ++ if (r >= 85) ++ new_qual = -3; ++ else if (r < 75) ++ new_qual = 2; ++ } ++ if (new_qual != 0) { ++ sd->nchg += new_qual; ++ if (sd->nchg < -6 || sd->nchg >= 12) { ++ sd->nchg = 0; ++ new_qual += sd->ctrls[QUALITY].val; ++ if (new_qual < QUALITY_MIN) ++ new_qual = QUALITY_MIN; ++ else if (new_qual > QUALITY_MAX) ++ new_qual = QUALITY_MAX; ++ if (new_qual != sd->ctrls[QUALITY].val) { ++ sd->ctrls[QUALITY].val = new_qual; ++ queue_work(sd->work_thread, &sd->work); ++ } ++ } ++ } else { ++ sd->nchg = 0; ++ } ++ sd->pktsz = sd->npkt = 0; ++} ++ + 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; +- int avg_lum; ++ int avg_lum, is_jpeg; + static u8 frame_header[] = + {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; +- if (len == 64 && memcmp(data, frame_header, 6) == 0) { ++ ++ is_jpeg = (sd->fmt & 0x03) == 0; ++ if (len >= 64 && memcmp(data, frame_header, 6) == 0) { + avg_lum = ((data[35] >> 2) & 3) | + (data[20] << 2) | + (data[19] << 10); +@@ -2484,12 +2340,18 @@ static void sd_pkt_scan(struct gspca_dev + (data[33] << 10); + avg_lum >>= 9; + atomic_set(&sd->avg_lum, avg_lum); ++ ++ if (is_jpeg) ++ transfer_check(gspca_dev, data); ++ + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); +- return; ++ len -= 64; ++ if (len == 0) ++ return; ++ data += 64; + } + if (gspca_dev->last_packet_type == LAST_PACKET) { +- if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv +- & MODE_JPEG) { ++ if (is_jpeg) { + gspca_frame_add(gspca_dev, FIRST_PACKET, + sd->jpeg_hdr, JPEG_HDR_SZ); + gspca_frame_add(gspca_dev, INTER_PACKET, +@@ -2499,13 +2361,18 @@ static void sd_pkt_scan(struct gspca_dev + data, len); + } + } else { ++ /* if JPEG, count the packets and their size */ ++ if (is_jpeg) { ++ sd->npkt++; ++ sd->pktsz += len; ++ } + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); + } + } + + /* sub-driver description */ + static const struct sd_desc sd_desc = { +- .name = MODULE_NAME, ++ .name = KBUILD_MODNAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, +@@ -2513,6 +2380,7 @@ static const struct sd_desc sd_desc = { + .isoc_init = sd_isoc_init, + .start = sd_start, + .stopN = sd_stopN, ++ .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, + #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .int_pkt_scan = sd_int_pkt_scan, +@@ -2581,7 +2449,7 @@ static int sd_probe(struct usb_interface + } + + static struct usb_driver sd_driver = { +- .name = MODULE_NAME, ++ .name = KBUILD_MODNAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +Index: linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-udma.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/ivtv/ivtv-udma.c ++++ linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-udma.c +@@ -57,9 +57,9 @@ int ivtv_udma_fill_sg_list (struct ivtv_ + if (dma->bouncemap[map_offset] == NULL) + return -1; + local_irq_save(flags); +- src = kmap_atomic(dma->map[map_offset], KM_BOUNCE_READ) + offset; ++ src = kmap_atomic(dma->map[map_offset]) + offset; + memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len); +- kunmap_atomic(src, KM_BOUNCE_READ); ++ kunmap_atomic(src); + local_irq_restore(flags); + sg_set_page(&dma->SGlist[map_offset], dma->bouncemap[map_offset], len, offset); + } +Index: linux-3.3.x86_64/drivers/media/video/videobuf2-core.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/videobuf2-core.c ++++ linux-3.3.x86_64/drivers/media/video/videobuf2-core.c +@@ -19,6 +19,9 @@ + #include + #include + ++#include ++#include ++#include + #include + + static int debug; +@@ -1642,32 +1645,46 @@ static int __vb2_cleanup_fileio(struct v + * For OUTPUT queues, if a buffer is ready to be dequeued, the file descriptor + * will be reported as available for writing. + * ++ * If the driver uses struct v4l2_fh, then vb2_poll() will also check for any ++ * pending events. ++ * + * The return values from this function are intended to be directly returned + * from poll handler in driver. + */ + unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) + { +- unsigned long flags; +- unsigned int ret; ++ struct video_device *vfd = video_devdata(file); ++ unsigned long req_events = poll_requested_events(wait); + struct vb2_buffer *vb = NULL; ++ unsigned int res = 0; ++ unsigned long flags; ++ ++ if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { ++ struct v4l2_fh *fh = file->private_data; ++ ++ if (v4l2_event_pending(fh)) ++ res = POLLPRI; ++ else if (req_events & POLLPRI) ++ poll_wait(file, &fh->wait, wait); ++ } + + /* + * Start file I/O emulator only if streaming API has not been used yet. + */ + if (q->num_buffers == 0 && q->fileio == NULL) { +- if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ)) { +- ret = __vb2_init_fileio(q, 1); +- if (ret) +- return POLLERR; ++ if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ) && ++ (req_events & (POLLIN | POLLRDNORM))) { ++ if (__vb2_init_fileio(q, 1)) ++ return res | POLLERR; + } +- if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE)) { +- ret = __vb2_init_fileio(q, 0); +- if (ret) +- return POLLERR; ++ if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE) && ++ (req_events & (POLLOUT | POLLWRNORM))) { ++ if (__vb2_init_fileio(q, 0)) ++ return res | POLLERR; + /* + * Write to OUTPUT queue can be done immediately. + */ +- return POLLOUT | POLLWRNORM; ++ return res | POLLOUT | POLLWRNORM; + } + } + +@@ -1675,7 +1692,7 @@ unsigned int vb2_poll(struct vb2_queue * + * There is nothing to wait for if no buffers have already been queued. + */ + if (list_empty(&q->queued_list)) +- return POLLERR; ++ return res | POLLERR; + + poll_wait(file, &q->done_wq, wait); + +@@ -1690,10 +1707,11 @@ unsigned int vb2_poll(struct vb2_queue * + + if (vb && (vb->state == VB2_BUF_STATE_DONE + || vb->state == VB2_BUF_STATE_ERROR)) { +- return (V4L2_TYPE_IS_OUTPUT(q->type)) ? POLLOUT | POLLWRNORM : +- POLLIN | POLLRDNORM; ++ return (V4L2_TYPE_IS_OUTPUT(q->type)) ? ++ res | POLLOUT | POLLWRNORM : ++ res | POLLIN | POLLRDNORM; + } +- return 0; ++ return res; + } + EXPORT_SYMBOL_GPL(vb2_poll); + +Index: linux-3.3.x86_64/drivers/media/video/videobuf-core.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/videobuf-core.c ++++ linux-3.3.x86_64/drivers/media/video/videobuf-core.c +@@ -1129,6 +1129,7 @@ unsigned int videobuf_poll_stream(struct + struct videobuf_queue *q, + poll_table *wait) + { ++ unsigned long req_events = poll_requested_events(wait); + struct videobuf_buffer *buf = NULL; + unsigned int rc = 0; + +@@ -1137,7 +1138,7 @@ unsigned int videobuf_poll_stream(struct + if (!list_empty(&q->stream)) + buf = list_entry(q->stream.next, + struct videobuf_buffer, stream); +- } else { ++ } else if (req_events & (POLLIN | POLLRDNORM)) { + if (!q->reading) + __videobuf_read_start(q); + if (!q->reading) { +Index: linux-3.3.x86_64/drivers/media/video/pwc/pwc-if.c +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/video/pwc/pwc-if.c ++++ linux-3.3.x86_64/drivers/media/video/pwc/pwc-if.c +@@ -625,10 +625,19 @@ static ssize_t pwc_video_read(struct fil + static unsigned int pwc_video_poll(struct file *file, poll_table *wait) + { + struct pwc_device *pdev = video_drvdata(file); ++ unsigned long req_events = poll_requested_events(wait); + + if (!pdev->udev) + return POLL_ERR; + ++ if ((req_events & (POLLIN | POLLRDNORM)) && ++ pdev->vb_queue.num_buffers == 0 && ++ !pdev->iso_init) { ++ /* This poll will start a read stream, check capt_file */ ++ if (pwc_test_n_set_capt_file(pdev, file)) ++ return POLL_ERR; ++ } ++ + return vb2_poll(&pdev->vb_queue, file, wait); + } + +Index: linux-3.3.x86_64/drivers/media/common/tuners/Kconfig +=================================================================== +--- linux-3.3.x86_64.orig/drivers/media/common/tuners/Kconfig ++++ linux-3.3.x86_64/drivers/media/common/tuners/Kconfig +@@ -204,6 +204,13 @@ config MEDIA_TUNER_TDA18218 + help + NXP TDA18218 silicon tuner driver. + ++config MEDIA_TUNER_FC0011 ++ tristate "Fitipower FC0011 silicon tuner" ++ depends on VIDEO_MEDIA && I2C ++ default m if MEDIA_TUNER_CUSTOMISE ++ help ++ Fitipower FC0011 silicon tuner driver. ++ + config MEDIA_TUNER_TDA18212 + tristate "NXP TDA18212 silicon tuner" + depends on VIDEO_MEDIA && I2C +@@ -211,4 +218,10 @@ config MEDIA_TUNER_TDA18212 + help + NXP TDA18212 silicon tuner driver. + ++config MEDIA_TUNER_TUA9001 ++ tristate "Infineon TUA 9001 silicon tuner" ++ depends on VIDEO_MEDIA && I2C ++ default m if MEDIA_TUNER_CUSTOMISE ++ help ++ Infineon TUA 9001 silicon tuner driver. + endmenu +Index: linux-3.3.x86_64/drivers/media/common/tuners/tua9001.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/common/tuners/tua9001.c +@@ -0,0 +1,215 @@ ++/* ++ * Infineon TUA 9001 silicon tuner driver ++ * ++ * Copyright (C) 2009 Antti Palosaari ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include "tua9001.h" ++#include "tua9001_priv.h" ++ ++/* write register */ ++static int tua9001_wr_reg(struct tua9001_priv *priv, u8 reg, u16 val) ++{ ++ int ret; ++ u8 buf[3] = { reg, (val >> 8) & 0xff, (val >> 0) & 0xff }; ++ struct i2c_msg msg[1] = { ++ { ++ .addr = priv->cfg->i2c_addr, ++ .flags = 0, ++ .len = sizeof(buf), ++ .buf = buf, ++ } ++ }; ++ ++ ret = i2c_transfer(priv->i2c, msg, 1); ++ if (ret == 1) { ++ ret = 0; ++ } else { ++ printk(KERN_WARNING "%s: I2C wr failed=%d reg=%02x\n", ++ __func__, ret, reg); ++ ret = -EREMOTEIO; ++ } ++ ++ return ret; ++} ++ ++static int tua9001_release(struct dvb_frontend *fe) ++{ ++ kfree(fe->tuner_priv); ++ fe->tuner_priv = NULL; ++ ++ return 0; ++} ++ ++static int tua9001_init(struct dvb_frontend *fe) ++{ ++ struct tua9001_priv *priv = fe->tuner_priv; ++ int ret = 0; ++ u8 i; ++ struct reg_val data[] = { ++ { 0x1e, 0x6512 }, ++ { 0x25, 0xb888 }, ++ { 0x39, 0x5460 }, ++ { 0x3b, 0x00c0 }, ++ { 0x3a, 0xf000 }, ++ { 0x08, 0x0000 }, ++ { 0x32, 0x0030 }, ++ { 0x41, 0x703a }, ++ { 0x40, 0x1c78 }, ++ { 0x2c, 0x1c00 }, ++ { 0x36, 0xc013 }, ++ { 0x37, 0x6f18 }, ++ { 0x27, 0x0008 }, ++ { 0x2a, 0x0001 }, ++ { 0x34, 0x0a40 }, ++ }; ++ ++ if (fe->ops.i2c_gate_ctrl) ++ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */ ++ ++ for (i = 0; i < ARRAY_SIZE(data); i++) { ++ ret = tua9001_wr_reg(priv, data[i].reg, data[i].val); ++ if (ret) ++ break; ++ } ++ ++ if (fe->ops.i2c_gate_ctrl) ++ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */ ++ ++ if (ret < 0) ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static int tua9001_set_params(struct dvb_frontend *fe) ++{ ++ struct tua9001_priv *priv = fe->tuner_priv; ++ struct dtv_frontend_properties *c = &fe->dtv_property_cache; ++ int ret, i; ++ u16 val; ++ u32 frequency; ++ struct reg_val data[2]; ++ ++ pr_debug("%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n", ++ __func__, c->delivery_system, c->frequency, ++ c->bandwidth_hz); ++ ++ switch (c->delivery_system) { ++ case SYS_DVBT: ++ switch (c->bandwidth_hz) { ++ case 8000000: ++ val = 0x0000; ++ break; ++ case 7000000: ++ val = 0x1000; ++ break; ++ case 6000000: ++ val = 0x2000; ++ break; ++ case 5000000: ++ val = 0x3000; ++ break; ++ default: ++ ret = -EINVAL; ++ goto err; ++ } ++ break; ++ default: ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ data[0].reg = 0x04; ++ data[0].val = val; ++ ++ frequency = (c->frequency - 150000000); ++ frequency /= 100; ++ frequency *= 48; ++ frequency /= 10000; ++ ++ data[1].reg = 0x1f; ++ data[1].val = frequency; ++ ++ if (fe->ops.i2c_gate_ctrl) ++ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */ ++ ++ for (i = 0; i < ARRAY_SIZE(data); i++) { ++ ret = tua9001_wr_reg(priv, data[i].reg, data[i].val); ++ if (ret < 0) ++ break; ++ } ++ ++ if (fe->ops.i2c_gate_ctrl) ++ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */ ++ ++err: ++ if (ret < 0) ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static int tua9001_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) ++{ ++ *frequency = 0; /* Zero-IF */ ++ ++ return 0; ++} ++ ++static const struct dvb_tuner_ops tua9001_tuner_ops = { ++ .info = { ++ .name = "Infineon TUA 9001", ++ ++ .frequency_min = 170000000, ++ .frequency_max = 862000000, ++ .frequency_step = 0, ++ }, ++ ++ .release = tua9001_release, ++ ++ .init = tua9001_init, ++ .set_params = tua9001_set_params, ++ ++ .get_if_frequency = tua9001_get_if_frequency, ++}; ++ ++struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, ++ struct i2c_adapter *i2c, struct tua9001_config *cfg) ++{ ++ struct tua9001_priv *priv = NULL; ++ ++ priv = kzalloc(sizeof(struct tua9001_priv), GFP_KERNEL); ++ if (priv == NULL) ++ return NULL; ++ ++ priv->cfg = cfg; ++ priv->i2c = i2c; ++ ++ printk(KERN_INFO "Infineon TUA 9001 successfully attached."); ++ ++ memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops, ++ sizeof(struct dvb_tuner_ops)); ++ ++ fe->tuner_priv = priv; ++ return fe; ++} ++EXPORT_SYMBOL(tua9001_attach); ++ ++MODULE_DESCRIPTION("Infineon TUA 9001 silicon tuner driver"); ++MODULE_AUTHOR("Antti Palosaari "); ++MODULE_LICENSE("GPL"); +Index: linux-3.3.x86_64/drivers/media/common/tuners/tua9001.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/common/tuners/tua9001.h +@@ -0,0 +1,46 @@ ++/* ++ * Infineon TUA 9001 silicon tuner driver ++ * ++ * Copyright (C) 2009 Antti Palosaari ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#ifndef TUA9001_H ++#define TUA9001_H ++ ++#include "dvb_frontend.h" ++ ++struct tua9001_config { ++ /* ++ * I2C address ++ */ ++ u8 i2c_addr; ++}; ++ ++#if defined(CONFIG_MEDIA_TUNER_TUA9001) || \ ++ (defined(CONFIG_MEDIA_TUNER_TUA9001_MODULE) && defined(MODULE)) ++extern struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, ++ struct i2c_adapter *i2c, struct tua9001_config *cfg); ++#else ++static inline struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, ++ struct i2c_adapter *i2c, struct tua9001_config *cfg) ++{ ++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); ++ return NULL; ++} ++#endif ++ ++#endif +Index: linux-3.3.x86_64/drivers/media/common/tuners/tua9001_priv.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/common/tuners/tua9001_priv.h +@@ -0,0 +1,34 @@ ++/* ++ * Infineon TUA 9001 silicon tuner driver ++ * ++ * Copyright (C) 2009 Antti Palosaari ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#ifndef TUA9001_PRIV_H ++#define TUA9001_PRIV_H ++ ++struct reg_val { ++ u8 reg; ++ u16 val; ++}; ++ ++struct tua9001_priv { ++ struct tua9001_config *cfg; ++ struct i2c_adapter *i2c; ++}; ++ ++#endif +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/af9033.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/af9033.c +@@ -0,0 +1,919 @@ ++/* ++ * Afatech AF9033 demodulator driver ++ * ++ * Copyright (C) 2009 Antti Palosaari ++ * Copyright (C) 2012 Antti Palosaari ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include "af9033_priv.h" ++ ++struct af9033_state { ++ struct i2c_adapter *i2c; ++ struct dvb_frontend fe; ++ struct af9033_config cfg; ++ ++ u32 bandwidth_hz; ++ bool ts_mode_parallel; ++ bool ts_mode_serial; ++}; ++ ++/* write multiple registers */ ++static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val, ++ int len) ++{ ++ int ret; ++ u8 buf[3 + len]; ++ struct i2c_msg msg[1] = { ++ { ++ .addr = state->cfg.i2c_addr, ++ .flags = 0, ++ .len = sizeof(buf), ++ .buf = buf, ++ } ++ }; ++ ++ buf[0] = (reg >> 16) & 0xff; ++ buf[1] = (reg >> 8) & 0xff; ++ buf[2] = (reg >> 0) & 0xff; ++ memcpy(&buf[3], val, len); ++ ++ ret = i2c_transfer(state->i2c, msg, 1); ++ if (ret == 1) { ++ ret = 0; ++ } else { ++ printk(KERN_WARNING "%s: i2c wr failed=%d reg=%06x len=%d\n", ++ __func__, ret, reg, len); ++ ret = -EREMOTEIO; ++ } ++ ++ return ret; ++} ++ ++/* read multiple registers */ ++static int af9033_rd_regs(struct af9033_state *state, u32 reg, u8 *val, int len) ++{ ++ int ret; ++ u8 buf[3] = { (reg >> 16) & 0xff, (reg >> 8) & 0xff, ++ (reg >> 0) & 0xff }; ++ struct i2c_msg msg[2] = { ++ { ++ .addr = state->cfg.i2c_addr, ++ .flags = 0, ++ .len = sizeof(buf), ++ .buf = buf ++ }, { ++ .addr = state->cfg.i2c_addr, ++ .flags = I2C_M_RD, ++ .len = len, ++ .buf = val ++ } ++ }; ++ ++ ret = i2c_transfer(state->i2c, msg, 2); ++ if (ret == 2) { ++ ret = 0; ++ } else { ++ printk(KERN_WARNING "%s: i2c rd failed=%d reg=%06x len=%d\n", ++ __func__, ret, reg, len); ++ ret = -EREMOTEIO; ++ } ++ ++ return ret; ++} ++ ++ ++/* write single register */ ++static int af9033_wr_reg(struct af9033_state *state, u32 reg, u8 val) ++{ ++ return af9033_wr_regs(state, reg, &val, 1); ++} ++ ++/* read single register */ ++static int af9033_rd_reg(struct af9033_state *state, u32 reg, u8 *val) ++{ ++ return af9033_rd_regs(state, reg, val, 1); ++} ++ ++/* write single register with mask */ ++static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val, ++ u8 mask) ++{ ++ int ret; ++ u8 tmp; ++ ++ /* no need for read if whole reg is written */ ++ if (mask != 0xff) { ++ ret = af9033_rd_regs(state, reg, &tmp, 1); ++ if (ret) ++ return ret; ++ ++ val &= mask; ++ tmp &= ~mask; ++ val |= tmp; ++ } ++ ++ return af9033_wr_regs(state, reg, &val, 1); ++} ++ ++/* read single register with mask */ ++static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val, ++ u8 mask) ++{ ++ int ret, i; ++ u8 tmp; ++ ++ ret = af9033_rd_regs(state, reg, &tmp, 1); ++ if (ret) ++ return ret; ++ ++ tmp &= mask; ++ ++ /* find position of the first bit */ ++ for (i = 0; i < 8; i++) { ++ if ((mask >> i) & 0x01) ++ break; ++ } ++ *val = tmp >> i; ++ ++ return 0; ++} ++ ++static u32 af9033_div(u32 a, u32 b, u32 x) ++{ ++ u32 r = 0, c = 0, i; ++ ++ pr_debug("%s: a=%d b=%d x=%d\n", __func__, a, b, x); ++ ++ if (a > b) { ++ c = a / b; ++ a = a - c * b; ++ } ++ ++ for (i = 0; i < x; i++) { ++ if (a >= b) { ++ r += 1; ++ a -= b; ++ } ++ a <<= 1; ++ r <<= 1; ++ } ++ r = (c << (u32)x) + r; ++ ++ pr_debug("%s: a=%d b=%d x=%d r=%d r=%x\n", __func__, a, b, x, r, r); ++ ++ return r; ++} ++ ++static void af9033_release(struct dvb_frontend *fe) ++{ ++ struct af9033_state *state = fe->demodulator_priv; ++ ++ kfree(state); ++} ++ ++static int af9033_init(struct dvb_frontend *fe) ++{ ++ struct af9033_state *state = fe->demodulator_priv; ++ int ret, i, len; ++ const struct reg_val *init; ++ u8 buf[4]; ++ u32 adc_cw, clock_cw; ++ struct reg_val_mask tab[] = { ++ { 0x80fb24, 0x00, 0x08 }, ++ { 0x80004c, 0x00, 0xff }, ++ { 0x00f641, state->cfg.tuner, 0xff }, ++ { 0x80f5ca, 0x01, 0x01 }, ++ { 0x80f715, 0x01, 0x01 }, ++ { 0x00f41f, 0x04, 0x04 }, ++ { 0x00f41a, 0x01, 0x01 }, ++ { 0x80f731, 0x00, 0x01 }, ++ { 0x00d91e, 0x00, 0x01 }, ++ { 0x00d919, 0x00, 0x01 }, ++ { 0x80f732, 0x00, 0x01 }, ++ { 0x00d91f, 0x00, 0x01 }, ++ { 0x00d91a, 0x00, 0x01 }, ++ { 0x80f730, 0x00, 0x01 }, ++ { 0x80f778, 0x00, 0xff }, ++ { 0x80f73c, 0x01, 0x01 }, ++ { 0x80f776, 0x00, 0x01 }, ++ { 0x00d8fd, 0x01, 0xff }, ++ { 0x00d830, 0x01, 0xff }, ++ { 0x00d831, 0x00, 0xff }, ++ { 0x00d832, 0x00, 0xff }, ++ { 0x80f985, state->ts_mode_serial, 0x01 }, ++ { 0x80f986, state->ts_mode_parallel, 0x01 }, ++ { 0x00d827, 0x00, 0xff }, ++ { 0x00d829, 0x00, 0xff }, ++ }; ++ ++ /* program clock control */ ++ clock_cw = af9033_div(state->cfg.clock, 1000000ul, 19ul); ++ buf[0] = (clock_cw >> 0) & 0xff; ++ buf[1] = (clock_cw >> 8) & 0xff; ++ buf[2] = (clock_cw >> 16) & 0xff; ++ buf[3] = (clock_cw >> 24) & 0xff; ++ ++ pr_debug("%s: clock=%d clock_cw=%08x\n", __func__, state->cfg.clock, ++ clock_cw); ++ ++ ret = af9033_wr_regs(state, 0x800025, buf, 4); ++ if (ret < 0) ++ goto err; ++ ++ /* program ADC control */ ++ for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) { ++ if (clock_adc_lut[i].clock == state->cfg.clock) ++ break; ++ } ++ ++ adc_cw = af9033_div(clock_adc_lut[i].adc, 1000000ul, 19ul); ++ buf[0] = (adc_cw >> 0) & 0xff; ++ buf[1] = (adc_cw >> 8) & 0xff; ++ buf[2] = (adc_cw >> 16) & 0xff; ++ ++ pr_debug("%s: adc=%d adc_cw=%06x\n", __func__, clock_adc_lut[i].adc, ++ adc_cw); ++ ++ ret = af9033_wr_regs(state, 0x80f1cd, buf, 3); ++ if (ret < 0) ++ goto err; ++ ++ /* program register table */ ++ for (i = 0; i < ARRAY_SIZE(tab); i++) { ++ ret = af9033_wr_reg_mask(state, tab[i].reg, tab[i].val, ++ tab[i].mask); ++ if (ret < 0) ++ goto err; ++ } ++ ++ /* settings for TS interface */ ++ if (state->cfg.ts_mode == AF9033_TS_MODE_USB) { ++ ret = af9033_wr_reg_mask(state, 0x80f9a5, 0x00, 0x01); ++ if (ret < 0) ++ goto err; ++ ++ ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x01, 0x01); ++ if (ret < 0) ++ goto err; ++ } else { ++ ret = af9033_wr_reg_mask(state, 0x80f990, 0x00, 0x01); ++ if (ret < 0) ++ goto err; ++ ++ ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x00, 0x01); ++ if (ret < 0) ++ goto err; ++ } ++ ++ /* load OFSM settings */ ++ pr_debug("%s: load ofsm settings\n", __func__); ++ len = ARRAY_SIZE(ofsm_init); ++ init = ofsm_init; ++ for (i = 0; i < len; i++) { ++ ret = af9033_wr_reg(state, init[i].reg, init[i].val); ++ if (ret < 0) ++ goto err; ++ } ++ ++ /* load tuner specific settings */ ++ pr_debug("%s: load tuner specific settings\n", ++ __func__); ++ switch (state->cfg.tuner) { ++ case AF9033_TUNER_TUA9001: ++ len = ARRAY_SIZE(tuner_init_tua9001); ++ init = tuner_init_tua9001; ++ break; ++ case AF9033_TUNER_FC0011: ++ len = ARRAY_SIZE(tuner_init_fc0011); ++ init = tuner_init_fc0011; ++ break; ++ case AF9033_TUNER_MXL5007T: ++ len = ARRAY_SIZE(tuner_init_mxl5007t); ++ init = tuner_init_mxl5007t; ++ break; ++ case AF9033_TUNER_TDA18218: ++ len = ARRAY_SIZE(tuner_init_tda18218); ++ init = tuner_init_tda18218; ++ break; ++ default: ++ pr_debug("%s: unsupported tuner ID=%d\n", __func__, ++ state->cfg.tuner); ++ ret = -ENODEV; ++ goto err; ++ } ++ ++ for (i = 0; i < len; i++) { ++ ret = af9033_wr_reg(state, init[i].reg, init[i].val); ++ if (ret < 0) ++ goto err; ++ } ++ ++ state->bandwidth_hz = 0; /* force to program all parameters */ ++ ++ return 0; ++ ++err: ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static int af9033_sleep(struct dvb_frontend *fe) ++{ ++ struct af9033_state *state = fe->demodulator_priv; ++ int ret, i; ++ u8 tmp; ++ ++ ret = af9033_wr_reg(state, 0x80004c, 1); ++ if (ret < 0) ++ goto err; ++ ++ ret = af9033_wr_reg(state, 0x800000, 0); ++ if (ret < 0) ++ goto err; ++ ++ for (i = 100, tmp = 1; i && tmp; i--) { ++ ret = af9033_rd_reg(state, 0x80004c, &tmp); ++ if (ret < 0) ++ goto err; ++ ++ usleep_range(200, 10000); ++ } ++ ++ pr_debug("%s: loop=%d\n", __func__, i); ++ ++ if (i == 0) { ++ ret = -ETIMEDOUT; ++ goto err; ++ } ++ ++ ret = af9033_wr_reg_mask(state, 0x80fb24, 0x08, 0x08); ++ if (ret < 0) ++ goto err; ++ ++ /* prevent current leak (?) */ ++ if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) { ++ /* enable parallel TS */ ++ ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01); ++ if (ret < 0) ++ goto err; ++ ++ ret = af9033_wr_reg_mask(state, 0x00d916, 0x01, 0x01); ++ if (ret < 0) ++ goto err; ++ } ++ ++ return 0; ++ ++err: ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static int af9033_get_tune_settings(struct dvb_frontend *fe, ++ struct dvb_frontend_tune_settings *fesettings) ++{ ++ fesettings->min_delay_ms = 800; ++ fesettings->step_size = 0; ++ fesettings->max_drift = 0; ++ ++ return 0; ++} ++ ++static int af9033_set_frontend(struct dvb_frontend *fe) ++{ ++ struct af9033_state *state = fe->demodulator_priv; ++ struct dtv_frontend_properties *c = &fe->dtv_property_cache; ++ int ret, i, spec_inv; ++ u8 tmp, buf[3], bandwidth_reg_val; ++ u32 if_frequency, freq_cw, adc_freq; ++ ++ pr_debug("%s: frequency=%d bandwidth_hz=%d\n", __func__, c->frequency, ++ c->bandwidth_hz); ++ ++ /* check bandwidth */ ++ switch (c->bandwidth_hz) { ++ case 6000000: ++ bandwidth_reg_val = 0x00; ++ break; ++ case 7000000: ++ bandwidth_reg_val = 0x01; ++ break; ++ case 8000000: ++ bandwidth_reg_val = 0x02; ++ break; ++ default: ++ pr_debug("%s: invalid bandwidth_hz\n", __func__); ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ /* program tuner */ ++ if (fe->ops.tuner_ops.set_params) ++ fe->ops.tuner_ops.set_params(fe); ++ ++ /* program CFOE coefficients */ ++ if (c->bandwidth_hz != state->bandwidth_hz) { ++ for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) { ++ if (coeff_lut[i].clock == state->cfg.clock && ++ coeff_lut[i].bandwidth_hz == c->bandwidth_hz) { ++ break; ++ } ++ } ++ ret = af9033_wr_regs(state, 0x800001, ++ coeff_lut[i].val, sizeof(coeff_lut[i].val)); ++ } ++ ++ /* program frequency control */ ++ if (c->bandwidth_hz != state->bandwidth_hz) { ++ spec_inv = state->cfg.spec_inv ? -1 : 1; ++ ++ for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) { ++ if (clock_adc_lut[i].clock == state->cfg.clock) ++ break; ++ } ++ adc_freq = clock_adc_lut[i].adc; ++ ++ /* get used IF frequency */ ++ if (fe->ops.tuner_ops.get_if_frequency) ++ fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); ++ else ++ if_frequency = 0; ++ ++ while (if_frequency > (adc_freq / 2)) ++ if_frequency -= adc_freq; ++ ++ if (if_frequency >= 0) ++ spec_inv *= -1; ++ else ++ if_frequency *= -1; ++ ++ freq_cw = af9033_div(if_frequency, adc_freq, 23ul); ++ ++ if (spec_inv == -1) ++ freq_cw *= -1; ++ ++ /* get adc multiplies */ ++ ret = af9033_rd_reg(state, 0x800045, &tmp); ++ if (ret < 0) ++ goto err; ++ ++ if (tmp == 1) ++ freq_cw /= 2; ++ ++ buf[0] = (freq_cw >> 0) & 0xff; ++ buf[1] = (freq_cw >> 8) & 0xff; ++ buf[2] = (freq_cw >> 16) & 0x7f; ++ ret = af9033_wr_regs(state, 0x800029, buf, 3); ++ if (ret < 0) ++ goto err; ++ ++ state->bandwidth_hz = c->bandwidth_hz; ++ } ++ ++ ret = af9033_wr_reg_mask(state, 0x80f904, bandwidth_reg_val, 0x03); ++ if (ret < 0) ++ goto err; ++ ++ ret = af9033_wr_reg(state, 0x800040, 0x00); ++ if (ret < 0) ++ goto err; ++ ++ ret = af9033_wr_reg(state, 0x800047, 0x00); ++ if (ret < 0) ++ goto err; ++ ++ ret = af9033_wr_reg_mask(state, 0x80f999, 0x00, 0x01); ++ if (ret < 0) ++ goto err; ++ ++ if (c->frequency <= 230000000) ++ tmp = 0x00; /* VHF */ ++ else ++ tmp = 0x01; /* UHF */ ++ ++ ret = af9033_wr_reg(state, 0x80004b, tmp); ++ if (ret < 0) ++ goto err; ++ ++ ret = af9033_wr_reg(state, 0x800000, 0x00); ++ if (ret < 0) ++ goto err; ++ ++ return 0; ++ ++err: ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static int af9033_get_frontend(struct dvb_frontend *fe) ++{ ++ struct af9033_state *state = fe->demodulator_priv; ++ struct dtv_frontend_properties *c = &fe->dtv_property_cache; ++ int ret; ++ u8 buf[8]; ++ ++ pr_debug("%s\n", __func__); ++ ++ /* read all needed registers */ ++ ret = af9033_rd_regs(state, 0x80f900, buf, sizeof(buf)); ++ if (ret < 0) ++ goto err; ++ ++ switch ((buf[0] >> 0) & 3) { ++ case 0: ++ c->transmission_mode = TRANSMISSION_MODE_2K; ++ break; ++ case 1: ++ c->transmission_mode = TRANSMISSION_MODE_8K; ++ break; ++ } ++ ++ switch ((buf[1] >> 0) & 3) { ++ case 0: ++ c->guard_interval = GUARD_INTERVAL_1_32; ++ break; ++ case 1: ++ c->guard_interval = GUARD_INTERVAL_1_16; ++ break; ++ case 2: ++ c->guard_interval = GUARD_INTERVAL_1_8; ++ break; ++ case 3: ++ c->guard_interval = GUARD_INTERVAL_1_4; ++ break; ++ } ++ ++ switch ((buf[2] >> 0) & 7) { ++ case 0: ++ c->hierarchy = HIERARCHY_NONE; ++ break; ++ case 1: ++ c->hierarchy = HIERARCHY_1; ++ break; ++ case 2: ++ c->hierarchy = HIERARCHY_2; ++ break; ++ case 3: ++ c->hierarchy = HIERARCHY_4; ++ break; ++ } ++ ++ switch ((buf[3] >> 0) & 3) { ++ case 0: ++ c->modulation = QPSK; ++ break; ++ case 1: ++ c->modulation = QAM_16; ++ break; ++ case 2: ++ c->modulation = QAM_64; ++ break; ++ } ++ ++ switch ((buf[4] >> 0) & 3) { ++ case 0: ++ c->bandwidth_hz = 6000000; ++ break; ++ case 1: ++ c->bandwidth_hz = 7000000; ++ break; ++ case 2: ++ c->bandwidth_hz = 8000000; ++ break; ++ } ++ ++ switch ((buf[6] >> 0) & 7) { ++ case 0: ++ c->code_rate_HP = FEC_1_2; ++ break; ++ case 1: ++ c->code_rate_HP = FEC_2_3; ++ break; ++ case 2: ++ c->code_rate_HP = FEC_3_4; ++ break; ++ case 3: ++ c->code_rate_HP = FEC_5_6; ++ break; ++ case 4: ++ c->code_rate_HP = FEC_7_8; ++ break; ++ case 5: ++ c->code_rate_HP = FEC_NONE; ++ break; ++ } ++ ++ switch ((buf[7] >> 0) & 7) { ++ case 0: ++ c->code_rate_LP = FEC_1_2; ++ break; ++ case 1: ++ c->code_rate_LP = FEC_2_3; ++ break; ++ case 2: ++ c->code_rate_LP = FEC_3_4; ++ break; ++ case 3: ++ c->code_rate_LP = FEC_5_6; ++ break; ++ case 4: ++ c->code_rate_LP = FEC_7_8; ++ break; ++ case 5: ++ c->code_rate_LP = FEC_NONE; ++ break; ++ } ++ ++ return 0; ++ ++err: ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status) ++{ ++ struct af9033_state *state = fe->demodulator_priv; ++ int ret; ++ u8 tmp; ++ ++ *status = 0; ++ ++ /* radio channel status, 0=no result, 1=has signal, 2=no signal */ ++ ret = af9033_rd_reg(state, 0x800047, &tmp); ++ if (ret < 0) ++ goto err; ++ ++ /* has signal */ ++ if (tmp == 0x01) ++ *status |= FE_HAS_SIGNAL; ++ ++ if (tmp != 0x02) { ++ /* TPS lock */ ++ ret = af9033_rd_reg_mask(state, 0x80f5a9, &tmp, 0x01); ++ if (ret < 0) ++ goto err; ++ ++ if (tmp) ++ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | ++ FE_HAS_VITERBI; ++ ++ /* full lock */ ++ ret = af9033_rd_reg_mask(state, 0x80f999, &tmp, 0x01); ++ if (ret < 0) ++ goto err; ++ ++ if (tmp) ++ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | ++ FE_HAS_VITERBI | FE_HAS_SYNC | ++ FE_HAS_LOCK; ++ } ++ ++ return 0; ++ ++err: ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr) ++{ ++ struct af9033_state *state = fe->demodulator_priv; ++ int ret, i, len; ++ u8 buf[3], tmp; ++ u32 snr_val; ++ const struct val_snr *uninitialized_var(snr_lut); ++ ++ /* read value */ ++ ret = af9033_rd_regs(state, 0x80002c, buf, 3); ++ if (ret < 0) ++ goto err; ++ ++ snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0]; ++ ++ /* read current modulation */ ++ ret = af9033_rd_reg(state, 0x80f903, &tmp); ++ if (ret < 0) ++ goto err; ++ ++ switch ((tmp >> 0) & 3) { ++ case 0: ++ len = ARRAY_SIZE(qpsk_snr_lut); ++ snr_lut = qpsk_snr_lut; ++ break; ++ case 1: ++ len = ARRAY_SIZE(qam16_snr_lut); ++ snr_lut = qam16_snr_lut; ++ break; ++ case 2: ++ len = ARRAY_SIZE(qam64_snr_lut); ++ snr_lut = qam64_snr_lut; ++ break; ++ default: ++ goto err; ++ } ++ ++ for (i = 0; i < len; i++) { ++ tmp = snr_lut[i].snr; ++ ++ if (snr_val < snr_lut[i].val) ++ break; ++ } ++ ++ *snr = tmp * 10; /* dB/10 */ ++ ++ return 0; ++ ++err: ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength) ++{ ++ struct af9033_state *state = fe->demodulator_priv; ++ int ret; ++ u8 strength2; ++ ++ /* read signal strength of 0-100 scale */ ++ ret = af9033_rd_reg(state, 0x800048, &strength2); ++ if (ret < 0) ++ goto err; ++ ++ /* scale value to 0x0000-0xffff */ ++ *strength = strength2 * 0xffff / 100; ++ ++ return 0; ++ ++err: ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static int af9033_read_ber(struct dvb_frontend *fe, u32 *ber) ++{ ++ *ber = 0; ++ ++ return 0; ++} ++ ++static int af9033_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) ++{ ++ *ucblocks = 0; ++ ++ return 0; ++} ++ ++static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) ++{ ++ struct af9033_state *state = fe->demodulator_priv; ++ int ret; ++ ++ pr_debug("%s: enable=%d\n", __func__, enable); ++ ++ ret = af9033_wr_reg_mask(state, 0x00fa04, enable, 0x01); ++ if (ret < 0) ++ goto err; ++ ++ return 0; ++ ++err: ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static struct dvb_frontend_ops af9033_ops; ++ ++struct dvb_frontend *af9033_attach(const struct af9033_config *config, ++ struct i2c_adapter *i2c) ++{ ++ int ret; ++ struct af9033_state *state; ++ u8 buf[8]; ++ ++ pr_debug("%s:\n", __func__); ++ ++ /* allocate memory for the internal state */ ++ state = kzalloc(sizeof(struct af9033_state), GFP_KERNEL); ++ if (state == NULL) ++ goto err; ++ ++ /* setup the state */ ++ state->i2c = i2c; ++ memcpy(&state->cfg, config, sizeof(struct af9033_config)); ++ ++ if (state->cfg.clock != 12000000) { ++ printk(KERN_INFO "af9033: unsupported clock=%d, only " \ ++ "12000000 Hz is supported currently\n", ++ state->cfg.clock); ++ goto err; ++ } ++ ++ /* firmware version */ ++ ret = af9033_rd_regs(state, 0x0083e9, &buf[0], 4); ++ if (ret < 0) ++ goto err; ++ ++ ret = af9033_rd_regs(state, 0x804191, &buf[4], 4); ++ if (ret < 0) ++ goto err; ++ ++ printk(KERN_INFO "af9033: firmware version: LINK=%d.%d.%d.%d " \ ++ "OFDM=%d.%d.%d.%d\n", buf[0], buf[1], buf[2], buf[3], ++ buf[4], buf[5], buf[6], buf[7]); ++ ++ /* configure internal TS mode */ ++ switch (state->cfg.ts_mode) { ++ case AF9033_TS_MODE_PARALLEL: ++ state->ts_mode_parallel = true; ++ break; ++ case AF9033_TS_MODE_SERIAL: ++ state->ts_mode_serial = true; ++ break; ++ case AF9033_TS_MODE_USB: ++ /* usb mode for AF9035 */ ++ default: ++ break; ++ } ++ ++ /* create dvb_frontend */ ++ memcpy(&state->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops)); ++ state->fe.demodulator_priv = state; ++ ++ return &state->fe; ++ ++err: ++ kfree(state); ++ return NULL; ++} ++EXPORT_SYMBOL(af9033_attach); ++ ++static struct dvb_frontend_ops af9033_ops = { ++ .delsys = { SYS_DVBT }, ++ .info = { ++ .name = "Afatech AF9033 (DVB-T)", ++ .frequency_min = 174000000, ++ .frequency_max = 862000000, ++ .frequency_stepsize = 250000, ++ .frequency_tolerance = 0, ++ .caps = FE_CAN_FEC_1_2 | ++ FE_CAN_FEC_2_3 | ++ FE_CAN_FEC_3_4 | ++ FE_CAN_FEC_5_6 | ++ FE_CAN_FEC_7_8 | ++ FE_CAN_FEC_AUTO | ++ FE_CAN_QPSK | ++ FE_CAN_QAM_16 | ++ FE_CAN_QAM_64 | ++ FE_CAN_QAM_AUTO | ++ FE_CAN_TRANSMISSION_MODE_AUTO | ++ FE_CAN_GUARD_INTERVAL_AUTO | ++ FE_CAN_HIERARCHY_AUTO | ++ FE_CAN_RECOVER | ++ FE_CAN_MUTE_TS ++ }, ++ ++ .release = af9033_release, ++ ++ .init = af9033_init, ++ .sleep = af9033_sleep, ++ ++ .get_tune_settings = af9033_get_tune_settings, ++ .set_frontend = af9033_set_frontend, ++ .get_frontend = af9033_get_frontend, ++ ++ .read_status = af9033_read_status, ++ .read_snr = af9033_read_snr, ++ .read_signal_strength = af9033_read_signal_strength, ++ .read_ber = af9033_read_ber, ++ .read_ucblocks = af9033_read_ucblocks, ++ ++ .i2c_gate_ctrl = af9033_i2c_gate_ctrl, ++}; ++ ++MODULE_AUTHOR("Antti Palosaari "); ++MODULE_DESCRIPTION("Afatech AF9033 DVB-T demodulator driver"); ++MODULE_LICENSE("GPL"); +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/af9033.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/af9033.h +@@ -0,0 +1,75 @@ ++/* ++ * Afatech AF9033 demodulator driver ++ * ++ * Copyright (C) 2009 Antti Palosaari ++ * Copyright (C) 2012 Antti Palosaari ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#ifndef AF9033_H ++#define AF9033_H ++ ++struct af9033_config { ++ /* ++ * I2C address ++ */ ++ u8 i2c_addr; ++ ++ /* ++ * clock Hz ++ * 12000000, 22000000, 24000000, 34000000, 32000000, 28000000, 26000000, ++ * 30000000, 36000000, 20480000, 16384000 ++ */ ++ u32 clock; ++ ++ /* ++ * tuner ++ */ ++#define AF9033_TUNER_TUA9001 0x27 /* Infineon TUA 9001 */ ++#define AF9033_TUNER_FC0011 0x28 /* Fitipower FC0011 */ ++#define AF9033_TUNER_MXL5007T 0xa0 /* MaxLinear MxL5007T */ ++#define AF9033_TUNER_TDA18218 0xa1 /* NXP TDA 18218HN */ ++ u8 tuner; ++ ++ /* ++ * TS settings ++ */ ++#define AF9033_TS_MODE_USB 0 ++#define AF9033_TS_MODE_PARALLEL 1 ++#define AF9033_TS_MODE_SERIAL 2 ++ u8 ts_mode:2; ++ ++ /* ++ * input spectrum inversion ++ */ ++ bool spec_inv; ++}; ++ ++ ++#if defined(CONFIG_DVB_AF9033) || \ ++ (defined(CONFIG_DVB_AF9033_MODULE) && defined(MODULE)) ++extern struct dvb_frontend *af9033_attach(const struct af9033_config *config, ++ struct i2c_adapter *i2c); ++#else ++static inline struct dvb_frontend *af9033_attach( ++ const struct af9033_config *config, struct i2c_adapter *i2c) ++{ ++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); ++ return NULL; ++} ++#endif ++ ++#endif /* AF9033_H */ +Index: linux-3.3.x86_64/drivers/media/dvb/frontends/af9033_priv.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/dvb/frontends/af9033_priv.h +@@ -0,0 +1,470 @@ ++/* ++ * Afatech AF9033 demodulator driver ++ * ++ * Copyright (C) 2009 Antti Palosaari ++ * Copyright (C) 2012 Antti Palosaari ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#ifndef AF9033_PRIV_H ++#define AF9033_PRIV_H ++ ++#include "dvb_frontend.h" ++#include "af9033.h" ++ ++struct reg_val { ++ u32 reg; ++ u8 val; ++}; ++ ++struct reg_val_mask { ++ u32 reg; ++ u8 val; ++ u8 mask; ++}; ++ ++struct coeff { ++ u32 clock; ++ u32 bandwidth_hz; ++ u8 val[36]; ++}; ++ ++struct clock_adc { ++ u32 clock; ++ u32 adc; ++}; ++ ++struct val_snr { ++ u32 val; ++ u8 snr; ++}; ++ ++/* Xtal clock vs. ADC clock lookup table */ ++static const struct clock_adc clock_adc_lut[] = { ++ { 16384000, 20480000 }, ++ { 20480000, 20480000 }, ++ { 36000000, 20250000 }, ++ { 30000000, 20156250 }, ++ { 26000000, 20583333 }, ++ { 28000000, 20416667 }, ++ { 32000000, 20500000 }, ++ { 34000000, 20187500 }, ++ { 24000000, 20500000 }, ++ { 22000000, 20625000 }, ++ { 12000000, 20250000 }, ++}; ++ ++/* pre-calculated coeff lookup table */ ++static const struct coeff coeff_lut[] = { ++ /* 12.000 MHz */ ++ { 12000000, 8000000, { ++ 0x01, 0xce, 0x55, 0xc9, 0x00, 0xe7, 0x2a, 0xe4, 0x00, 0x73, ++ 0x99, 0x0f, 0x00, 0x73, 0x95, 0x72, 0x00, 0x73, 0x91, 0xd5, ++ 0x00, 0x39, 0xca, 0xb9, 0x00, 0xe7, 0x2a, 0xe4, 0x00, 0x73, ++ 0x95, 0x72, 0x37, 0x02, 0xce, 0x01 } ++ }, ++ { 12000000, 7000000, { ++ 0x01, 0x94, 0x8b, 0x10, 0x00, 0xca, 0x45, 0x88, 0x00, 0x65, ++ 0x25, 0xed, 0x00, 0x65, 0x22, 0xc4, 0x00, 0x65, 0x1f, 0x9b, ++ 0x00, 0x32, 0x91, 0x62, 0x00, 0xca, 0x45, 0x88, 0x00, 0x65, ++ 0x22, 0xc4, 0x88, 0x02, 0x95, 0x01 } ++ }, ++ { 12000000, 6000000, { ++ 0x01, 0x5a, 0xc0, 0x56, 0x00, 0xad, 0x60, 0x2b, 0x00, 0x56, ++ 0xb2, 0xcb, 0x00, 0x56, 0xb0, 0x15, 0x00, 0x56, 0xad, 0x60, ++ 0x00, 0x2b, 0x58, 0x0b, 0x00, 0xad, 0x60, 0x2b, 0x00, 0x56, ++ 0xb0, 0x15, 0xf4, 0x02, 0x5b, 0x01 } ++ }, ++}; ++ ++/* QPSK SNR lookup table */ ++static const struct val_snr qpsk_snr_lut[] = { ++ { 0x0b4771, 0 }, ++ { 0x0c1aed, 1 }, ++ { 0x0d0d27, 2 }, ++ { 0x0e4d19, 3 }, ++ { 0x0e5da8, 4 }, ++ { 0x107097, 5 }, ++ { 0x116975, 6 }, ++ { 0x1252d9, 7 }, ++ { 0x131fa4, 8 }, ++ { 0x13d5e1, 9 }, ++ { 0x148e53, 10 }, ++ { 0x15358b, 11 }, ++ { 0x15dd29, 12 }, ++ { 0x168112, 13 }, ++ { 0x170b61, 14 }, ++ { 0x17a532, 15 }, ++ { 0x180f94, 16 }, ++ { 0x186ed2, 17 }, ++ { 0x18b271, 18 }, ++ { 0x18e118, 19 }, ++ { 0x18ff4b, 20 }, ++ { 0x190af1, 21 }, ++ { 0x191451, 22 }, ++ { 0xffffff, 23 }, ++}; ++ ++/* QAM16 SNR lookup table */ ++static const struct val_snr qam16_snr_lut[] = { ++ { 0x04f0d5, 0 }, ++ { 0x05387a, 1 }, ++ { 0x0573a4, 2 }, ++ { 0x05a99e, 3 }, ++ { 0x05cc80, 4 }, ++ { 0x05eb62, 5 }, ++ { 0x05fecf, 6 }, ++ { 0x060b80, 7 }, ++ { 0x062501, 8 }, ++ { 0x064865, 9 }, ++ { 0x069604, 10 }, ++ { 0x06f356, 11 }, ++ { 0x07706a, 12 }, ++ { 0x0804d3, 13 }, ++ { 0x089d1a, 14 }, ++ { 0x093e3d, 15 }, ++ { 0x09e35d, 16 }, ++ { 0x0a7c3c, 17 }, ++ { 0x0afaf8, 18 }, ++ { 0x0b719d, 19 }, ++ { 0x0bda6a, 20 }, ++ { 0x0c0c75, 21 }, ++ { 0x0c3f7d, 22 }, ++ { 0x0c5e62, 23 }, ++ { 0x0c6c31, 24 }, ++ { 0x0c7925, 25 }, ++ { 0xffffff, 26 }, ++}; ++ ++/* QAM64 SNR lookup table */ ++static const struct val_snr qam64_snr_lut[] = { ++ { 0x0256d0, 0 }, ++ { 0x027a65, 1 }, ++ { 0x029873, 2 }, ++ { 0x02b7fe, 3 }, ++ { 0x02cf1e, 4 }, ++ { 0x02e234, 5 }, ++ { 0x02f409, 6 }, ++ { 0x030046, 7 }, ++ { 0x030844, 8 }, ++ { 0x030a02, 9 }, ++ { 0x030cde, 10 }, ++ { 0x031031, 11 }, ++ { 0x03144c, 12 }, ++ { 0x0315dd, 13 }, ++ { 0x031920, 14 }, ++ { 0x0322d0, 15 }, ++ { 0x0339fc, 16 }, ++ { 0x0364a1, 17 }, ++ { 0x038bcc, 18 }, ++ { 0x03c7d3, 19 }, ++ { 0x0408cc, 20 }, ++ { 0x043bed, 21 }, ++ { 0x048061, 22 }, ++ { 0x04be95, 23 }, ++ { 0x04fa7d, 24 }, ++ { 0x052405, 25 }, ++ { 0x05570d, 26 }, ++ { 0x059feb, 27 }, ++ { 0x05bf38, 28 }, ++ { 0xffffff, 29 }, ++}; ++ ++static const struct reg_val ofsm_init[] = { ++ { 0x800051, 0x01 }, ++ { 0x800070, 0x0a }, ++ { 0x80007e, 0x04 }, ++ { 0x800081, 0x0a }, ++ { 0x80008a, 0x01 }, ++ { 0x80008e, 0x01 }, ++ { 0x800092, 0x06 }, ++ { 0x800099, 0x01 }, ++ { 0x80009f, 0xe1 }, ++ { 0x8000a0, 0xcf }, ++ { 0x8000a3, 0x01 }, ++ { 0x8000a5, 0x01 }, ++ { 0x8000a6, 0x01 }, ++ { 0x8000a9, 0x00 }, ++ { 0x8000aa, 0x01 }, ++ { 0x8000ab, 0x01 }, ++ { 0x8000b0, 0x01 }, ++ { 0x8000c0, 0x05 }, ++ { 0x8000c4, 0x19 }, ++ { 0x80f000, 0x0f }, ++ { 0x80f016, 0x10 }, ++ { 0x80f017, 0x04 }, ++ { 0x80f018, 0x05 }, ++ { 0x80f019, 0x04 }, ++ { 0x80f01a, 0x05 }, ++ { 0x80f021, 0x03 }, ++ { 0x80f022, 0x0a }, ++ { 0x80f023, 0x0a }, ++ { 0x80f02b, 0x00 }, ++ { 0x80f02c, 0x01 }, ++ { 0x80f064, 0x03 }, ++ { 0x80f065, 0xf9 }, ++ { 0x80f066, 0x03 }, ++ { 0x80f067, 0x01 }, ++ { 0x80f06f, 0xe0 }, ++ { 0x80f070, 0x03 }, ++ { 0x80f072, 0x0f }, ++ { 0x80f073, 0x03 }, ++ { 0x80f078, 0x00 }, ++ { 0x80f087, 0x00 }, ++ { 0x80f09b, 0x3f }, ++ { 0x80f09c, 0x00 }, ++ { 0x80f09d, 0x20 }, ++ { 0x80f09e, 0x00 }, ++ { 0x80f09f, 0x0c }, ++ { 0x80f0a0, 0x00 }, ++ { 0x80f130, 0x04 }, ++ { 0x80f132, 0x04 }, ++ { 0x80f144, 0x1a }, ++ { 0x80f146, 0x00 }, ++ { 0x80f14a, 0x01 }, ++ { 0x80f14c, 0x00 }, ++ { 0x80f14d, 0x00 }, ++ { 0x80f14f, 0x04 }, ++ { 0x80f158, 0x7f }, ++ { 0x80f15a, 0x00 }, ++ { 0x80f15b, 0x08 }, ++ { 0x80f15d, 0x03 }, ++ { 0x80f15e, 0x05 }, ++ { 0x80f163, 0x05 }, ++ { 0x80f166, 0x01 }, ++ { 0x80f167, 0x40 }, ++ { 0x80f168, 0x0f }, ++ { 0x80f17a, 0x00 }, ++ { 0x80f17b, 0x00 }, ++ { 0x80f183, 0x01 }, ++ { 0x80f19d, 0x40 }, ++ { 0x80f1bc, 0x36 }, ++ { 0x80f1bd, 0x00 }, ++ { 0x80f1cb, 0xa0 }, ++ { 0x80f1cc, 0x01 }, ++ { 0x80f204, 0x10 }, ++ { 0x80f214, 0x00 }, ++ { 0x80f40e, 0x0a }, ++ { 0x80f40f, 0x40 }, ++ { 0x80f410, 0x08 }, ++ { 0x80f55f, 0x0a }, ++ { 0x80f561, 0x15 }, ++ { 0x80f562, 0x20 }, ++ { 0x80f5df, 0xfb }, ++ { 0x80f5e0, 0x00 }, ++ { 0x80f5e3, 0x09 }, ++ { 0x80f5e4, 0x01 }, ++ { 0x80f5e5, 0x01 }, ++ { 0x80f5f8, 0x01 }, ++ { 0x80f5fd, 0x01 }, ++ { 0x80f600, 0x05 }, ++ { 0x80f601, 0x08 }, ++ { 0x80f602, 0x0b }, ++ { 0x80f603, 0x0e }, ++ { 0x80f604, 0x11 }, ++ { 0x80f605, 0x14 }, ++ { 0x80f606, 0x17 }, ++ { 0x80f607, 0x1f }, ++ { 0x80f60e, 0x00 }, ++ { 0x80f60f, 0x04 }, ++ { 0x80f610, 0x32 }, ++ { 0x80f611, 0x10 }, ++ { 0x80f707, 0xfc }, ++ { 0x80f708, 0x00 }, ++ { 0x80f709, 0x37 }, ++ { 0x80f70a, 0x00 }, ++ { 0x80f78b, 0x01 }, ++ { 0x80f80f, 0x40 }, ++ { 0x80f810, 0x54 }, ++ { 0x80f811, 0x5a }, ++ { 0x80f905, 0x01 }, ++ { 0x80fb06, 0x03 }, ++ { 0x80fd8b, 0x00 }, ++}; ++ ++/* Infineon TUA 9001 tuner init ++ AF9033_TUNER_TUA9001 = 0x27 */ ++static const struct reg_val tuner_init_tua9001[] = { ++ { 0x800046, 0x27 }, ++ { 0x800057, 0x00 }, ++ { 0x800058, 0x01 }, ++ { 0x80005f, 0x00 }, ++ { 0x800060, 0x00 }, ++ { 0x80006d, 0x00 }, ++ { 0x800071, 0x05 }, ++ { 0x800072, 0x02 }, ++ { 0x800074, 0x01 }, ++ { 0x800075, 0x03 }, ++ { 0x800076, 0x02 }, ++ { 0x800077, 0x00 }, ++ { 0x800078, 0x01 }, ++ { 0x800079, 0x00 }, ++ { 0x80007a, 0x7e }, ++ { 0x80007b, 0x3e }, ++ { 0x800093, 0x00 }, ++ { 0x800094, 0x01 }, ++ { 0x800095, 0x02 }, ++ { 0x800096, 0x01 }, ++ { 0x800098, 0x0a }, ++ { 0x80009b, 0x05 }, ++ { 0x80009c, 0x80 }, ++ { 0x8000b3, 0x00 }, ++ { 0x8000c1, 0x01 }, ++ { 0x8000c2, 0x00 }, ++ { 0x80f007, 0x00 }, ++ { 0x80f01f, 0x82 }, ++ { 0x80f020, 0x00 }, ++ { 0x80f029, 0x82 }, ++ { 0x80f02a, 0x00 }, ++ { 0x80f047, 0x00 }, ++ { 0x80f054, 0x00 }, ++ { 0x80f055, 0x00 }, ++ { 0x80f077, 0x01 }, ++ { 0x80f1e6, 0x00 }, ++}; ++ ++/* Fitipower fc0011 tuner init ++ AF9033_TUNER_FC0011 = 0x28 */ ++static const struct reg_val tuner_init_fc0011[] = { ++ { 0x800046, AF9033_TUNER_FC0011 }, ++ { 0x800057, 0x00 }, ++ { 0x800058, 0x01 }, ++ { 0x80005f, 0x00 }, ++ { 0x800060, 0x00 }, ++ { 0x800068, 0xa5 }, ++ { 0x80006e, 0x01 }, ++ { 0x800071, 0x0A }, ++ { 0x800072, 0x02 }, ++ { 0x800074, 0x01 }, ++ { 0x800079, 0x01 }, ++ { 0x800093, 0x00 }, ++ { 0x800094, 0x00 }, ++ { 0x800095, 0x00 }, ++ { 0x800096, 0x00 }, ++ { 0x80009b, 0x2D }, ++ { 0x80009c, 0x60 }, ++ { 0x80009d, 0x23 }, ++ { 0x8000a4, 0x50 }, ++ { 0x8000ad, 0x50 }, ++ { 0x8000b3, 0x01 }, ++ { 0x8000b7, 0x88 }, ++ { 0x8000b8, 0xa6 }, ++ { 0x8000c3, 0x01 }, ++ { 0x8000c4, 0x01 }, ++ { 0x8000c7, 0x69 }, ++ { 0x80F007, 0x00 }, ++ { 0x80F00A, 0x1B }, ++ { 0x80F00B, 0x1B }, ++ { 0x80F00C, 0x1B }, ++ { 0x80F00D, 0x1B }, ++ { 0x80F00E, 0xFF }, ++ { 0x80F00F, 0x01 }, ++ { 0x80F010, 0x00 }, ++ { 0x80F011, 0x02 }, ++ { 0x80F012, 0xFF }, ++ { 0x80F013, 0x01 }, ++ { 0x80F014, 0x00 }, ++ { 0x80F015, 0x02 }, ++ { 0x80F01B, 0xEF }, ++ { 0x80F01C, 0x01 }, ++ { 0x80F01D, 0x0f }, ++ { 0x80F01E, 0x02 }, ++ { 0x80F01F, 0x6E }, ++ { 0x80F020, 0x00 }, ++ { 0x80F025, 0xDE }, ++ { 0x80F026, 0x00 }, ++ { 0x80F027, 0x0A }, ++ { 0x80F028, 0x03 }, ++ { 0x80F029, 0x6E }, ++ { 0x80F02A, 0x00 }, ++ { 0x80F047, 0x00 }, ++ { 0x80F054, 0x00 }, ++ { 0x80F055, 0x00 }, ++ { 0x80F077, 0x01 }, ++ { 0x80F1E6, 0x00 }, ++}; ++ ++/* MaxLinear MxL5007T tuner init ++ AF9033_TUNER_MXL5007T = 0xa0 */ ++static const struct reg_val tuner_init_mxl5007t[] = { ++ { 0x800046, 0x1b }, ++ { 0x800057, 0x01 }, ++ { 0x800058, 0x01 }, ++ { 0x80005f, 0x00 }, ++ { 0x800060, 0x00 }, ++ { 0x800068, 0x96 }, ++ { 0x800071, 0x05 }, ++ { 0x800072, 0x02 }, ++ { 0x800074, 0x01 }, ++ { 0x800079, 0x01 }, ++ { 0x800093, 0x00 }, ++ { 0x800094, 0x00 }, ++ { 0x800095, 0x00 }, ++ { 0x800096, 0x00 }, ++ { 0x8000b3, 0x01 }, ++ { 0x8000c1, 0x01 }, ++ { 0x8000c2, 0x00 }, ++ { 0x80f007, 0x00 }, ++ { 0x80f00c, 0x19 }, ++ { 0x80f00d, 0x1a }, ++ { 0x80f012, 0xda }, ++ { 0x80f013, 0x00 }, ++ { 0x80f014, 0x00 }, ++ { 0x80f015, 0x02 }, ++ { 0x80f01f, 0x82 }, ++ { 0x80f020, 0x00 }, ++ { 0x80f029, 0x82 }, ++ { 0x80f02a, 0x00 }, ++ { 0x80f077, 0x02 }, ++ { 0x80f1e6, 0x00 }, ++}; ++ ++/* NXP TDA 18218HN tuner init ++ AF9033_TUNER_TDA18218 = 0xa1 */ ++static const struct reg_val tuner_init_tda18218[] = { ++ {0x800046, 0xa1}, ++ {0x800057, 0x01}, ++ {0x800058, 0x01}, ++ {0x80005f, 0x00}, ++ {0x800060, 0x00}, ++ {0x800071, 0x05}, ++ {0x800072, 0x02}, ++ {0x800074, 0x01}, ++ {0x800079, 0x01}, ++ {0x800093, 0x00}, ++ {0x800094, 0x00}, ++ {0x800095, 0x00}, ++ {0x800096, 0x00}, ++ {0x8000b3, 0x01}, ++ {0x8000c3, 0x01}, ++ {0x8000c4, 0x00}, ++ {0x80f007, 0x00}, ++ {0x80f00c, 0x19}, ++ {0x80f00d, 0x1a}, ++ {0x80f012, 0xda}, ++ {0x80f013, 0x00}, ++ {0x80f014, 0x00}, ++ {0x80f015, 0x02}, ++ {0x80f01f, 0x82}, ++ {0x80f020, 0x00}, ++ {0x80f029, 0x82}, ++ {0x80f02a, 0x00}, ++ {0x80f077, 0x02}, ++ {0x80f1e6, 0x00}, ++}; ++ ++#endif /* AF9033_PRIV_H */ ++ +Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/af9035.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/af9035.c +@@ -0,0 +1,1164 @@ ++/* ++ * Afatech AF9035 DVB USB driver ++ * ++ * Copyright (C) 2009 Antti Palosaari ++ * Copyright (C) 2012 Antti Palosaari ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include "af9035.h" ++#include "af9033.h" ++#include "tua9001.h" ++#include "fc0011.h" ++#include "mxl5007t.h" ++#include "tda18218.h" ++ ++DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); ++static DEFINE_MUTEX(af9035_usb_mutex); ++static struct config af9035_config; ++static struct dvb_usb_device_properties af9035_properties[2]; ++static int af9035_properties_count = ARRAY_SIZE(af9035_properties); ++static struct af9033_config af9035_af9033_config[] = { ++ { ++ .ts_mode = AF9033_TS_MODE_USB, ++ }, { ++ .ts_mode = AF9033_TS_MODE_SERIAL, ++ } ++}; ++ ++static u16 af9035_checksum(const u8 *buf, size_t len) ++{ ++ size_t i; ++ u16 checksum = 0; ++ ++ for (i = 1; i < len; i++) { ++ if (i % 2) ++ checksum += buf[i] << 8; ++ else ++ checksum += buf[i]; ++ } ++ checksum = ~checksum; ++ ++ return checksum; ++} ++ ++static int af9035_ctrl_msg(struct usb_device *udev, struct usb_req *req) ++{ ++#define BUF_LEN 63 ++#define REQ_HDR_LEN 4 /* send header size */ ++#define ACK_HDR_LEN 3 /* rece header size */ ++#define CHECKSUM_LEN 2 ++#define USB_TIMEOUT 2000 ++ ++ int ret, act_len; ++ u8 buf[BUF_LEN]; ++ u32 msg_len; ++ static u8 seq; /* packet sequence number */ ++ u16 checksum, tmpsum; ++ ++ /* buffer overflow check */ ++ if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) || ++ req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) { ++ pr_debug("%s: too much data wlen=%d rlen=%d\n", __func__, ++ req->wlen, req->rlen); ++ return -EINVAL; ++ } ++ ++ if (mutex_lock_interruptible(&af9035_usb_mutex) < 0) ++ return -EAGAIN; ++ ++ buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1; ++ buf[1] = req->mbox; ++ buf[2] = req->cmd; ++ buf[3] = seq++; ++ if (req->wlen) ++ memcpy(&buf[4], req->wbuf, req->wlen); ++ ++ /* calc and add checksum */ ++ checksum = af9035_checksum(buf, buf[0] - 1); ++ buf[buf[0]-1] = (checksum >> 8); ++ buf[buf[0]-0] = (checksum & 0xff); ++ ++ msg_len = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN ; ++ ++ /* send req */ ++ ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len, ++ &act_len, USB_TIMEOUT); ++ if (ret < 0) ++ err("bulk message failed=%d (%d/%d)", ret, msg_len, act_len); ++ else ++ if (act_len != msg_len) ++ ret = -EIO; /* all data is not send */ ++ if (ret < 0) ++ goto err_mutex_unlock; ++ ++ /* no ack for those packets */ ++ if (req->cmd == CMD_FW_DL) ++ goto exit_mutex_unlock; ++ ++ /* receive ack and data if read req */ ++ msg_len = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN; ++ ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len, ++ &act_len, USB_TIMEOUT); ++ if (ret < 0) { ++ err("recv bulk message failed=%d", ret); ++ ret = -EIO; ++ goto err_mutex_unlock; ++ } ++ if (act_len != msg_len) { ++ err("recv bulk message truncated (%d != %u)\n", ++ act_len, (unsigned int)msg_len); ++ ret = -EIO; ++ goto err_mutex_unlock; ++ } ++ ++ /* verify checksum */ ++ checksum = af9035_checksum(buf, act_len - 2); ++ tmpsum = (buf[act_len - 2] << 8) | buf[act_len - 1]; ++ if (tmpsum != checksum) { ++ err("%s: command=%02X checksum mismatch (%04X != %04X)\n", ++ __func__, req->cmd, ++ (unsigned int)tmpsum, (unsigned int)checksum); ++ ret = -EIO; ++ goto err_mutex_unlock; ++ } ++ /* check status */ ++ if (buf[2]) { ++ pr_debug("%s: command=%02x failed fw error=%d\n", __func__, ++ req->cmd, buf[2]); ++ ret = -EIO; ++ goto err_mutex_unlock; ++ } ++ ++ /* read request, copy returned data to return buf */ ++ if (req->rlen) ++ memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen); ++ ++err_mutex_unlock: ++exit_mutex_unlock: ++ mutex_unlock(&af9035_usb_mutex); ++ ++ return ret; ++} ++ ++/* write multiple registers */ ++static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len) ++{ ++ u8 wbuf[6 + len]; ++ u8 mbox = (reg >> 16) & 0xff; ++ struct usb_req req = { CMD_MEM_WR, mbox, sizeof(wbuf), wbuf, 0, NULL }; ++ ++ wbuf[0] = len; ++ wbuf[1] = 2; ++ wbuf[2] = 0; ++ wbuf[3] = 0; ++ wbuf[4] = (reg >> 8) & 0xff; ++ wbuf[5] = (reg >> 0) & 0xff; ++ memcpy(&wbuf[6], val, len); ++ ++ return af9035_ctrl_msg(d->udev, &req); ++} ++ ++/* read multiple registers */ ++static int af9035_rd_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len) ++{ ++ u8 wbuf[] = { len, 2, 0, 0, (reg >> 8) & 0xff, reg & 0xff }; ++ u8 mbox = (reg >> 16) & 0xff; ++ struct usb_req req = { CMD_MEM_RD, mbox, sizeof(wbuf), wbuf, len, val }; ++ ++ return af9035_ctrl_msg(d->udev, &req); ++} ++ ++/* write single register */ ++static int af9035_wr_reg(struct dvb_usb_device *d, u32 reg, u8 val) ++{ ++ return af9035_wr_regs(d, reg, &val, 1); ++} ++ ++/* read single register */ ++static int af9035_rd_reg(struct dvb_usb_device *d, u32 reg, u8 *val) ++{ ++ return af9035_rd_regs(d, reg, val, 1); ++} ++ ++/* write single register with mask */ ++static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val, ++ u8 mask) ++{ ++ int ret; ++ u8 tmp; ++ ++ /* no need for read if whole reg is written */ ++ if (mask != 0xff) { ++ ret = af9035_rd_regs(d, reg, &tmp, 1); ++ if (ret) ++ return ret; ++ ++ val &= mask; ++ tmp &= ~mask; ++ val |= tmp; ++ } ++ ++ return af9035_wr_regs(d, reg, &val, 1); ++} ++ ++static int af9035_i2c_master_xfer(struct i2c_adapter *adap, ++ struct i2c_msg msg[], int num) ++{ ++ struct dvb_usb_device *d = i2c_get_adapdata(adap); ++ int ret; ++ ++ if (mutex_lock_interruptible(&d->i2c_mutex) < 0) ++ return -EAGAIN; ++ ++ /* ++ * I2C sub header is 5 bytes long. Meaning of those bytes are: ++ * 0: data len ++ * 1: I2C addr << 1 ++ * 2: reg addr len ++ * byte 3 and 4 can be used as reg addr ++ * 3: reg addr MSB ++ * used when reg addr len is set to 2 ++ * 4: reg addr LSB ++ * used when reg addr len is set to 1 or 2 ++ * ++ * For the simplify we do not use register addr at all. ++ * NOTE: As a firmware knows tuner type there is very small possibility ++ * there could be some tuner I2C hacks done by firmware and this may ++ * lead problems if firmware expects those bytes are used. ++ */ ++ if (num == 2 && !(msg[0].flags & I2C_M_RD) && ++ (msg[1].flags & I2C_M_RD)) { ++ if (msg[0].len > 40 || msg[1].len > 40) { ++ /* TODO: correct limits > 40 */ ++ ret = -EOPNOTSUPP; ++ } else if (msg[0].addr == af9035_af9033_config[0].i2c_addr) { ++ /* integrated demod */ ++ u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | ++ msg[0].buf[2]; ++ ret = af9035_rd_regs(d, reg, &msg[1].buf[0], ++ msg[1].len); ++ } else { ++ /* I2C */ ++ u8 buf[5 + msg[0].len]; ++ struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf), ++ buf, msg[1].len, msg[1].buf }; ++ buf[0] = msg[1].len; ++ buf[1] = msg[0].addr << 1; ++ buf[2] = 0x00; /* reg addr len */ ++ buf[3] = 0x00; /* reg addr MSB */ ++ buf[4] = 0x00; /* reg addr LSB */ ++ memcpy(&buf[5], msg[0].buf, msg[0].len); ++ ret = af9035_ctrl_msg(d->udev, &req); ++ } ++ } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) { ++ if (msg[0].len > 40) { ++ /* TODO: correct limits > 40 */ ++ ret = -EOPNOTSUPP; ++ } else if (msg[0].addr == af9035_af9033_config[0].i2c_addr) { ++ /* integrated demod */ ++ u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | ++ msg[0].buf[2]; ++ ret = af9035_wr_regs(d, reg, &msg[0].buf[3], ++ msg[0].len - 3); ++ } else { ++ /* I2C */ ++ u8 buf[5 + msg[0].len]; ++ struct usb_req req = { CMD_I2C_WR, 0, sizeof(buf), buf, ++ 0, NULL }; ++ buf[0] = msg[0].len; ++ buf[1] = msg[0].addr << 1; ++ buf[2] = 0x00; /* reg addr len */ ++ buf[3] = 0x00; /* reg addr MSB */ ++ buf[4] = 0x00; /* reg addr LSB */ ++ memcpy(&buf[5], msg[0].buf, msg[0].len); ++ ret = af9035_ctrl_msg(d->udev, &req); ++ } ++ } else { ++ /* ++ * We support only two kind of I2C transactions: ++ * 1) 1 x read + 1 x write ++ * 2) 1 x write ++ */ ++ ret = -EOPNOTSUPP; ++ } ++ ++ mutex_unlock(&d->i2c_mutex); ++ ++ if (ret < 0) ++ return ret; ++ else ++ return num; ++} ++ ++static u32 af9035_i2c_functionality(struct i2c_adapter *adapter) ++{ ++ return I2C_FUNC_I2C; ++} ++ ++static struct i2c_algorithm af9035_i2c_algo = { ++ .master_xfer = af9035_i2c_master_xfer, ++ .functionality = af9035_i2c_functionality, ++}; ++ ++static int af9035_init(struct dvb_usb_device *d) ++{ ++ int ret, i; ++ u16 frame_size = 87 * 188 / 4; ++ u8 packet_size = 512 / 4; ++ struct reg_val_mask tab[] = { ++ { 0x80f99d, 0x01, 0x01 }, ++ { 0x80f9a4, 0x01, 0x01 }, ++ { 0x00dd11, 0x00, 0x20 }, ++ { 0x00dd11, 0x00, 0x40 }, ++ { 0x00dd13, 0x00, 0x20 }, ++ { 0x00dd13, 0x00, 0x40 }, ++ { 0x00dd11, 0x20, 0x20 }, ++ { 0x00dd88, (frame_size >> 0) & 0xff, 0xff}, ++ { 0x00dd89, (frame_size >> 8) & 0xff, 0xff}, ++ { 0x00dd0c, packet_size, 0xff}, ++ { 0x00dd11, af9035_config.dual_mode << 6, 0x40 }, ++ { 0x00dd8a, (frame_size >> 0) & 0xff, 0xff}, ++ { 0x00dd8b, (frame_size >> 8) & 0xff, 0xff}, ++ { 0x00dd0d, packet_size, 0xff }, ++ { 0x80f9a3, 0x00, 0x01 }, ++ { 0x80f9cd, 0x00, 0x01 }, ++ { 0x80f99d, 0x00, 0x01 }, ++ { 0x80f9a4, 0x00, 0x01 }, ++ }; ++ ++ pr_debug("%s: USB speed=%d frame_size=%04x packet_size=%02x\n", ++ __func__, d->udev->speed, frame_size, packet_size); ++ ++ /* init endpoints */ ++ for (i = 0; i < ARRAY_SIZE(tab); i++) { ++ ret = af9035_wr_reg_mask(d, tab[i].reg, tab[i].val, ++ tab[i].mask); ++ if (ret < 0) ++ goto err; ++ } ++ ++ return 0; ++ ++err: ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static int af9035_identify_state(struct usb_device *udev, ++ struct dvb_usb_device_properties *props, ++ struct dvb_usb_device_description **desc, ++ int *cold) ++{ ++ int ret; ++ u8 wbuf[1] = { 1 }; ++ u8 rbuf[4]; ++ struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf, ++ sizeof(rbuf), rbuf }; ++ ++ ret = af9035_ctrl_msg(udev, &req); ++ if (ret < 0) ++ goto err; ++ ++ pr_debug("%s: reply=%02x %02x %02x %02x\n", __func__, ++ rbuf[0], rbuf[1], rbuf[2], rbuf[3]); ++ if (rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3]) ++ *cold = 0; ++ else ++ *cold = 1; ++ ++ return 0; ++ ++err: ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static int af9035_download_firmware(struct usb_device *udev, ++ const struct firmware *fw) ++{ ++ int ret, i, j, len; ++ u8 wbuf[1]; ++ u8 rbuf[4]; ++ struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; ++ struct usb_req req_fw_dl = { CMD_FW_DL, 0, 0, wbuf, 0, NULL }; ++ struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ; ++ u8 hdr_core; ++ u16 hdr_addr, hdr_data_len, hdr_checksum; ++ #define MAX_DATA 57 ++ #define HDR_SIZE 7 ++ ++ /* ++ * Thanks to Daniel Glöckner about that info! ++ * ++ * byte 0: MCS 51 core ++ * There are two inside the AF9035 (1=Link and 2=OFDM) with separate ++ * address spaces ++ * byte 1-2: Big endian destination address ++ * byte 3-4: Big endian number of data bytes following the header ++ * byte 5-6: Big endian header checksum, apparently ignored by the chip ++ * Calculated as ~(h[0]*256+h[1]+h[2]*256+h[3]+h[4]*256) ++ */ ++ ++ for (i = fw->size; i > HDR_SIZE;) { ++ hdr_core = fw->data[fw->size - i + 0]; ++ hdr_addr = fw->data[fw->size - i + 1] << 8; ++ hdr_addr |= fw->data[fw->size - i + 2] << 0; ++ hdr_data_len = fw->data[fw->size - i + 3] << 8; ++ hdr_data_len |= fw->data[fw->size - i + 4] << 0; ++ hdr_checksum = fw->data[fw->size - i + 5] << 8; ++ hdr_checksum |= fw->data[fw->size - i + 6] << 0; ++ ++ pr_debug("%s: core=%d addr=%04x data_len=%d checksum=%04x\n", ++ __func__, hdr_core, hdr_addr, hdr_data_len, ++ hdr_checksum); ++ ++ if (((hdr_core != 1) && (hdr_core != 2)) || ++ (hdr_data_len > i)) { ++ pr_debug("%s: bad firmware\n", __func__); ++ break; ++ } ++ ++ /* download begin packet */ ++ req.cmd = CMD_FW_DL_BEGIN; ++ ret = af9035_ctrl_msg(udev, &req); ++ if (ret < 0) ++ goto err; ++ ++ /* download firmware packet(s) */ ++ for (j = HDR_SIZE + hdr_data_len; j > 0; j -= MAX_DATA) { ++ len = j; ++ if (len > MAX_DATA) ++ len = MAX_DATA; ++ req_fw_dl.wlen = len; ++ req_fw_dl.wbuf = (u8 *) &fw->data[fw->size - i + ++ HDR_SIZE + hdr_data_len - j]; ++ ret = af9035_ctrl_msg(udev, &req_fw_dl); ++ if (ret < 0) ++ goto err; ++ } ++ ++ /* download end packet */ ++ req.cmd = CMD_FW_DL_END; ++ ret = af9035_ctrl_msg(udev, &req); ++ if (ret < 0) ++ goto err; ++ ++ i -= hdr_data_len + HDR_SIZE; ++ ++ pr_debug("%s: data uploaded=%zu\n", __func__, fw->size - i); ++ } ++ ++ /* firmware loaded, request boot */ ++ req.cmd = CMD_FW_BOOT; ++ ret = af9035_ctrl_msg(udev, &req); ++ if (ret < 0) ++ goto err; ++ ++ /* ensure firmware starts */ ++ wbuf[0] = 1; ++ ret = af9035_ctrl_msg(udev, &req_fw_ver); ++ if (ret < 0) ++ goto err; ++ ++ if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) { ++ info("firmware did not run"); ++ ret = -ENODEV; ++ goto err; ++ } ++ ++ info("firmware version=%d.%d.%d.%d", rbuf[0], rbuf[1], rbuf[2], ++ rbuf[3]); ++ ++ return 0; ++ ++err: ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static int af9035_download_firmware_it9135(struct usb_device *udev, ++ const struct firmware *fw) ++{ ++ int ret, i, i_prev; ++ u8 wbuf[1]; ++ u8 rbuf[4]; ++ struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; ++ struct usb_req req_fw_dl = { CMD_FW_SCATTER_WR, 0, 0, NULL, 0, NULL }; ++ struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ; ++ #define HDR_SIZE 7 ++ ++ /* ++ * There seems to be following firmware header. Meaning of bytes 0-3 ++ * is unknown. ++ * ++ * 0: 3 ++ * 1: 0, 1 ++ * 2: 0 ++ * 3: 1, 2, 3 ++ * 4: addr MSB ++ * 5: addr LSB ++ * 6: count of data bytes ? ++ */ ++ ++ for (i = HDR_SIZE, i_prev = 0; i <= fw->size; i++) { ++ if (i == fw->size || ++ (fw->data[i + 0] == 0x03 && ++ (fw->data[i + 1] == 0x00 || ++ fw->data[i + 1] == 0x01) && ++ fw->data[i + 2] == 0x00)) { ++ req_fw_dl.wlen = i - i_prev; ++ req_fw_dl.wbuf = (u8 *) &fw->data[i_prev]; ++ i_prev = i; ++ ret = af9035_ctrl_msg(udev, &req_fw_dl); ++ if (ret < 0) ++ goto err; ++ ++ pr_debug("%s: data uploaded=%d\n", __func__, i); ++ } ++ } ++ ++ /* firmware loaded, request boot */ ++ req.cmd = CMD_FW_BOOT; ++ ret = af9035_ctrl_msg(udev, &req); ++ if (ret < 0) ++ goto err; ++ ++ /* ensure firmware starts */ ++ wbuf[0] = 1; ++ ret = af9035_ctrl_msg(udev, &req_fw_ver); ++ if (ret < 0) ++ goto err; ++ ++ if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) { ++ info("firmware did not run"); ++ ret = -ENODEV; ++ goto err; ++ } ++ ++ info("firmware version=%d.%d.%d.%d", rbuf[0], rbuf[1], rbuf[2], ++ rbuf[3]); ++ ++ return 0; ++ ++err: ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++/* abuse that callback as there is no better one for reading eeprom */ ++static int af9035_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) ++{ ++ int ret, i, eeprom_shift = 0; ++ u8 tmp; ++ u16 tmp16; ++ ++ /* check if there is dual tuners */ ++ ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp); ++ if (ret < 0) ++ goto err; ++ ++ af9035_config.dual_mode = tmp; ++ pr_debug("%s: dual mode=%d\n", __func__, af9035_config.dual_mode); ++ ++ for (i = 0; i < af9035_properties[0].num_adapters; i++) { ++ /* tuner */ ++ ret = af9035_rd_reg(d, EEPROM_1_TUNER_ID + eeprom_shift, &tmp); ++ if (ret < 0) ++ goto err; ++ ++ af9035_af9033_config[i].tuner = tmp; ++ pr_debug("%s: [%d]tuner=%02x\n", __func__, i, tmp); ++ ++ switch (tmp) { ++ case AF9033_TUNER_TUA9001: ++ case AF9033_TUNER_FC0011: ++ case AF9033_TUNER_MXL5007T: ++ case AF9033_TUNER_TDA18218: ++ af9035_af9033_config[i].spec_inv = 1; ++ break; ++ default: ++ af9035_config.hw_not_supported = true; ++ warn("tuner ID=%02x not supported, please report!", ++ tmp); ++ }; ++ ++ /* tuner IF frequency */ ++ ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp); ++ if (ret < 0) ++ goto err; ++ ++ tmp16 = tmp; ++ ++ ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_H + eeprom_shift, &tmp); ++ if (ret < 0) ++ goto err; ++ ++ tmp16 |= tmp << 8; ++ ++ pr_debug("%s: [%d]IF=%d\n", __func__, i, tmp16); ++ ++ eeprom_shift = 0x10; /* shift for the 2nd tuner params */ ++ } ++ ++ /* get demod clock */ ++ ret = af9035_rd_reg(d, 0x00d800, &tmp); ++ if (ret < 0) ++ goto err; ++ ++ tmp = (tmp >> 0) & 0x0f; ++ ++ for (i = 0; i < af9035_properties[0].num_adapters; i++) ++ af9035_af9033_config[i].clock = clock_lut[tmp]; ++ ++ return 0; ++ ++err: ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++/* abuse that callback as there is no better one for reading eeprom */ ++static int af9035_read_mac_address_it9135(struct dvb_usb_device *d, u8 mac[6]) ++{ ++ int ret, i; ++ u8 tmp; ++ ++ af9035_config.dual_mode = 0; ++ ++ /* get demod clock */ ++ ret = af9035_rd_reg(d, 0x00d800, &tmp); ++ if (ret < 0) ++ goto err; ++ ++ tmp = (tmp >> 0) & 0x0f; ++ ++ for (i = 0; i < af9035_properties[0].num_adapters; i++) ++ af9035_af9033_config[i].clock = clock_lut_it9135[tmp]; ++ ++ return 0; ++ ++err: ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static int af9035_fc0011_tuner_callback(struct dvb_usb_device *d, ++ int cmd, int arg) ++{ ++ int ret; ++ ++ switch (cmd) { ++ case FC0011_FE_CALLBACK_POWER: ++ /* Tuner enable */ ++ ret = af9035_wr_reg_mask(d, 0xd8eb, 1, 1); ++ if (ret < 0) ++ goto err; ++ ++ ret = af9035_wr_reg_mask(d, 0xd8ec, 1, 1); ++ if (ret < 0) ++ goto err; ++ ++ ret = af9035_wr_reg_mask(d, 0xd8ed, 1, 1); ++ if (ret < 0) ++ goto err; ++ ++ /* LED */ ++ ret = af9035_wr_reg_mask(d, 0xd8d0, 1, 1); ++ if (ret < 0) ++ goto err; ++ ++ ret = af9035_wr_reg_mask(d, 0xd8d1, 1, 1); ++ if (ret < 0) ++ goto err; ++ ++ usleep_range(10000, 50000); ++ break; ++ case FC0011_FE_CALLBACK_RESET: ++ ret = af9035_wr_reg(d, 0xd8e9, 1); ++ if (ret < 0) ++ goto err; ++ ++ ret = af9035_wr_reg(d, 0xd8e8, 1); ++ if (ret < 0) ++ goto err; ++ ++ ret = af9035_wr_reg(d, 0xd8e7, 1); ++ if (ret < 0) ++ goto err; ++ ++ usleep_range(10000, 20000); ++ ++ ret = af9035_wr_reg(d, 0xd8e7, 0); ++ if (ret < 0) ++ goto err; ++ ++ usleep_range(10000, 20000); ++ break; ++ default: ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ return 0; ++ ++err: ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static int af9035_tuner_callback(struct dvb_usb_device *d, int cmd, int arg) ++{ ++ switch (af9035_af9033_config[0].tuner) { ++ case AF9033_TUNER_FC0011: ++ return af9035_fc0011_tuner_callback(d, cmd, arg); ++ default: ++ break; ++ } ++ ++ return -ENODEV; ++} ++ ++static int af9035_frontend_callback(void *adapter_priv, int component, ++ int cmd, int arg) ++{ ++ struct i2c_adapter *adap = adapter_priv; ++ struct dvb_usb_device *d = i2c_get_adapdata(adap); ++ ++ switch (component) { ++ case DVB_FRONTEND_COMPONENT_TUNER: ++ return af9035_tuner_callback(d, cmd, arg); ++ default: ++ break; ++ } ++ ++ return -EINVAL; ++} ++ ++static int af9035_frontend_attach(struct dvb_usb_adapter *adap) ++{ ++ int ret; ++ ++ if (af9035_config.hw_not_supported) { ++ ret = -ENODEV; ++ goto err; ++ } ++ ++ if (adap->id == 0) { ++ ret = af9035_wr_reg(adap->dev, 0x00417f, ++ af9035_af9033_config[1].i2c_addr); ++ if (ret < 0) ++ goto err; ++ ++ ret = af9035_wr_reg(adap->dev, 0x00d81a, ++ af9035_config.dual_mode); ++ if (ret < 0) ++ goto err; ++ } ++ ++ /* attach demodulator */ ++ adap->fe_adap[0].fe = dvb_attach(af9033_attach, ++ &af9035_af9033_config[adap->id], &adap->dev->i2c_adap); ++ if (adap->fe_adap[0].fe == NULL) { ++ ret = -ENODEV; ++ goto err; ++ } ++ ++ /* disable I2C-gate */ ++ adap->fe_adap[0].fe->ops.i2c_gate_ctrl = NULL; ++ adap->fe_adap[0].fe->callback = af9035_frontend_callback; ++ ++ return 0; ++ ++err: ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static struct tua9001_config af9035_tua9001_config = { ++ .i2c_addr = 0x60, ++}; ++ ++static const struct fc0011_config af9035_fc0011_config = { ++ .i2c_address = 0x60, ++}; ++ ++static struct mxl5007t_config af9035_mxl5007t_config = { ++ .xtal_freq_hz = MxL_XTAL_24_MHZ, ++ .if_freq_hz = MxL_IF_4_57_MHZ, ++ .invert_if = 0, ++ .loop_thru_enable = 0, ++ .clk_out_enable = 0, ++ .clk_out_amp = MxL_CLKOUT_AMP_0_94V, ++}; ++ ++static struct tda18218_config af9035_tda18218_config = { ++ .i2c_address = 0x60, ++ .i2c_wr_max = 21, ++}; ++ ++static int af9035_tuner_attach(struct dvb_usb_adapter *adap) ++{ ++ int ret; ++ struct dvb_frontend *fe; ++ ++ switch (af9035_af9033_config[adap->id].tuner) { ++ case AF9033_TUNER_TUA9001: ++ /* AF9035 gpiot3 = TUA9001 RESETN ++ AF9035 gpiot2 = TUA9001 RXEN */ ++ ++ /* configure gpiot2 and gpiot2 as output */ ++ ret = af9035_wr_reg_mask(adap->dev, 0x00d8ec, 0x01, 0x01); ++ if (ret < 0) ++ goto err; ++ ++ ret = af9035_wr_reg_mask(adap->dev, 0x00d8ed, 0x01, 0x01); ++ if (ret < 0) ++ goto err; ++ ++ ret = af9035_wr_reg_mask(adap->dev, 0x00d8e8, 0x01, 0x01); ++ if (ret < 0) ++ goto err; ++ ++ ret = af9035_wr_reg_mask(adap->dev, 0x00d8e9, 0x01, 0x01); ++ if (ret < 0) ++ goto err; ++ ++ /* reset tuner */ ++ ret = af9035_wr_reg_mask(adap->dev, 0x00d8e7, 0x00, 0x01); ++ if (ret < 0) ++ goto err; ++ ++ usleep_range(2000, 20000); ++ ++ ret = af9035_wr_reg_mask(adap->dev, 0x00d8e7, 0x01, 0x01); ++ if (ret < 0) ++ goto err; ++ ++ /* activate tuner RX */ ++ /* TODO: use callback for TUA9001 RXEN */ ++ ret = af9035_wr_reg_mask(adap->dev, 0x00d8eb, 0x01, 0x01); ++ if (ret < 0) ++ goto err; ++ ++ /* attach tuner */ ++ fe = dvb_attach(tua9001_attach, adap->fe_adap[0].fe, ++ &adap->dev->i2c_adap, &af9035_tua9001_config); ++ break; ++ case AF9033_TUNER_FC0011: ++ fe = dvb_attach(fc0011_attach, adap->fe_adap[0].fe, ++ &adap->dev->i2c_adap, &af9035_fc0011_config); ++ break; ++ case AF9033_TUNER_MXL5007T: ++ ret = af9035_wr_reg(adap->dev, 0x00d8e0, 1); ++ if (ret < 0) ++ goto err; ++ ret = af9035_wr_reg(adap->dev, 0x00d8e1, 1); ++ if (ret < 0) ++ goto err; ++ ret = af9035_wr_reg(adap->dev, 0x00d8df, 0); ++ if (ret < 0) ++ goto err; ++ ++ msleep(30); ++ ++ ret = af9035_wr_reg(adap->dev, 0x00d8df, 1); ++ if (ret < 0) ++ goto err; ++ ++ msleep(300); ++ ++ ret = af9035_wr_reg(adap->dev, 0x00d8c0, 1); ++ if (ret < 0) ++ goto err; ++ ret = af9035_wr_reg(adap->dev, 0x00d8c1, 1); ++ if (ret < 0) ++ goto err; ++ ret = af9035_wr_reg(adap->dev, 0x00d8bf, 0); ++ if (ret < 0) ++ goto err; ++ ret = af9035_wr_reg(adap->dev, 0x00d8b4, 1); ++ if (ret < 0) ++ goto err; ++ ret = af9035_wr_reg(adap->dev, 0x00d8b5, 1); ++ if (ret < 0) ++ goto err; ++ ret = af9035_wr_reg(adap->dev, 0x00d8b3, 1); ++ if (ret < 0) ++ goto err; ++ ++ /* attach tuner */ ++ fe = dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe, ++ &adap->dev->i2c_adap, 0x60, &af9035_mxl5007t_config); ++ break; ++ case AF9033_TUNER_TDA18218: ++ /* attach tuner */ ++ fe = dvb_attach(tda18218_attach, adap->fe_adap[0].fe, ++ &adap->dev->i2c_adap, &af9035_tda18218_config); ++ break; ++ default: ++ fe = NULL; ++ } ++ ++ if (fe == NULL) { ++ ret = -ENODEV; ++ goto err; ++ } ++ ++ return 0; ++ ++err: ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++enum af9035_id_entry { ++ AF9035_15A4_9035, ++ AF9035_15A4_1001, ++ AF9035_0CCD_0093, ++ AF9035_07CA_A835, ++ AF9035_07CA_B835, ++ AF9035_07CA_1867, ++ AF9035_07CA_A867, ++ AF9035_07CA_0825, ++}; ++ ++static struct usb_device_id af9035_id[] = { ++ [AF9035_15A4_9035] = { ++ USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035)}, ++ [AF9035_15A4_1001] = { ++ USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_2)}, ++ [AF9035_0CCD_0093] = { ++ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK)}, ++ [AF9035_07CA_A835] = { ++ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835)}, ++ [AF9035_07CA_B835] = { ++ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_B835)}, ++ [AF9035_07CA_1867] = { ++ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_1867)}, ++ [AF9035_07CA_A867] = { ++ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A867)}, ++ [AF9035_07CA_0825] = { ++ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TWINSTAR)}, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(usb, af9035_id); ++ ++static struct dvb_usb_device_properties af9035_properties[] = { ++ { ++ .caps = DVB_USB_IS_AN_I2C_ADAPTER, ++ ++ .usb_ctrl = DEVICE_SPECIFIC, ++ .download_firmware = af9035_download_firmware, ++ .firmware = "dvb-usb-af9035-02.fw", ++ .no_reconnect = 1, ++ ++ .num_adapters = 1, ++ .adapter = { ++ { ++ .num_frontends = 1, ++ .fe = { ++ { ++ .frontend_attach = af9035_frontend_attach, ++ .tuner_attach = af9035_tuner_attach, ++ .stream = { ++ .type = USB_BULK, ++ .count = 6, ++ .endpoint = 0x84, ++ .u = { ++ .bulk = { ++ .buffersize = (87 * 188), ++ } ++ } ++ } ++ } ++ } ++ } ++ }, ++ ++ .identify_state = af9035_identify_state, ++ .read_mac_address = af9035_read_mac_address, ++ ++ .i2c_algo = &af9035_i2c_algo, ++ ++ .num_device_descs = 5, ++ .devices = { ++ { ++ .name = "Afatech AF9035 reference design", ++ .cold_ids = { ++ &af9035_id[AF9035_15A4_9035], ++ &af9035_id[AF9035_15A4_1001], ++ }, ++ }, { ++ .name = "TerraTec Cinergy T Stick", ++ .cold_ids = { ++ &af9035_id[AF9035_0CCD_0093], ++ }, ++ }, { ++ .name = "AVerMedia AVerTV Volar HD/PRO (A835)", ++ .cold_ids = { ++ &af9035_id[AF9035_07CA_A835], ++ &af9035_id[AF9035_07CA_B835], ++ }, ++ }, { ++ .name = "AVerMedia HD Volar (A867)", ++ .cold_ids = { ++ &af9035_id[AF9035_07CA_1867], ++ &af9035_id[AF9035_07CA_A867], ++ }, ++ }, { ++ .name = "AVerMedia Twinstar (A825)", ++ .cold_ids = { ++ &af9035_id[AF9035_07CA_0825], ++ }, ++ }, ++ } ++ }, ++ { ++ .caps = DVB_USB_IS_AN_I2C_ADAPTER, ++ ++ .usb_ctrl = DEVICE_SPECIFIC, ++ .download_firmware = af9035_download_firmware_it9135, ++ .firmware = "dvb-usb-it9135-01.fw", ++ .no_reconnect = 1, ++ ++ .num_adapters = 1, ++ .adapter = { ++ { ++ .num_frontends = 1, ++ .fe = { ++ { ++ .frontend_attach = af9035_frontend_attach, ++ .tuner_attach = af9035_tuner_attach, ++ .stream = { ++ .type = USB_BULK, ++ .count = 6, ++ .endpoint = 0x84, ++ .u = { ++ .bulk = { ++ .buffersize = (87 * 188), ++ } ++ } ++ } ++ } ++ } ++ } ++ }, ++ ++ .identify_state = af9035_identify_state, ++ .read_mac_address = af9035_read_mac_address_it9135, ++ ++ .i2c_algo = &af9035_i2c_algo, ++ ++ .num_device_descs = 0, /* disabled as no support for IT9135 */ ++ .devices = { ++ { ++ .name = "ITE Tech. IT9135 reference design", ++ }, ++ } ++ }, ++}; ++ ++static int af9035_usb_probe(struct usb_interface *intf, ++ const struct usb_device_id *id) ++{ ++ int ret, i; ++ struct dvb_usb_device *d = NULL; ++ struct usb_device *udev; ++ bool found; ++ ++ pr_debug("%s: interface=%d\n", __func__, ++ intf->cur_altsetting->desc.bInterfaceNumber); ++ ++ /* interface 0 is used by DVB-T receiver and ++ interface 1 is for remote controller (HID) */ ++ if (intf->cur_altsetting->desc.bInterfaceNumber != 0) ++ return 0; ++ ++ /* Dynamic USB ID support. Replaces first device ID with current one. */ ++ udev = interface_to_usbdev(intf); ++ ++ for (i = 0, found = false; i < ARRAY_SIZE(af9035_id) - 1; i++) { ++ if (af9035_id[i].idVendor == ++ le16_to_cpu(udev->descriptor.idVendor) && ++ af9035_id[i].idProduct == ++ le16_to_cpu(udev->descriptor.idProduct)) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) { ++ pr_debug("%s: using dynamic ID %04x:%04x\n", __func__, ++ le16_to_cpu(udev->descriptor.idVendor), ++ le16_to_cpu(udev->descriptor.idProduct)); ++ af9035_properties[0].devices[0].cold_ids[0]->idVendor = ++ le16_to_cpu(udev->descriptor.idVendor); ++ af9035_properties[0].devices[0].cold_ids[0]->idProduct = ++ le16_to_cpu(udev->descriptor.idProduct); ++ } ++ ++ ++ for (i = 0; i < af9035_properties_count; i++) { ++ ret = dvb_usb_device_init(intf, &af9035_properties[i], ++ THIS_MODULE, &d, adapter_nr); ++ ++ if (ret == -ENODEV) ++ continue; ++ else ++ break; ++ } ++ ++ if (ret < 0) ++ goto err; ++ ++ if (d) { ++ ret = af9035_init(d); ++ if (ret < 0) ++ goto err; ++ } ++ ++ return 0; ++ ++err: ++ pr_debug("%s: failed=%d\n", __func__, ret); ++ ++ return ret; ++} ++ ++/* usb specific object needed to register this driver with the usb subsystem */ ++static struct usb_driver af9035_usb_driver = { ++ .name = "dvb_usb_af9035", ++ .probe = af9035_usb_probe, ++ .disconnect = dvb_usb_device_exit, ++ .id_table = af9035_id, ++}; ++ ++module_usb_driver(af9035_usb_driver); ++ ++MODULE_AUTHOR("Antti Palosaari "); ++MODULE_DESCRIPTION("Afatech AF9035 driver"); ++MODULE_LICENSE("GPL"); +Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/af9035.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/af9035.h +@@ -0,0 +1,120 @@ ++/* ++ * Afatech AF9035 DVB USB driver ++ * ++ * Copyright (C) 2009 Antti Palosaari ++ * Copyright (C) 2012 Antti Palosaari ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#ifndef AF9035_H ++#define AF9035_H ++ ++/* prefix for dvb-usb log writings */ ++#define DVB_USB_LOG_PREFIX "af9035" ++ ++#include "dvb-usb.h" ++ ++struct reg_val { ++ u32 reg; ++ u8 val; ++}; ++ ++struct reg_val_mask { ++ u32 reg; ++ u8 val; ++ u8 mask; ++}; ++ ++struct usb_req { ++ u8 cmd; ++ u8 mbox; ++ u8 wlen; ++ u8 *wbuf; ++ u8 rlen; ++ u8 *rbuf; ++}; ++ ++struct config { ++ bool dual_mode; ++ bool hw_not_supported; ++}; ++ ++struct fw_segment { ++#define SEGMENT_FW_DL 0 ++#define SEGMENT_ROM_COPY 1 ++#define SEGMENT_DIRECT_CMD 2 ++ u8 type; ++ u32 len; ++}; ++ ++struct fw_header { ++#define SEGMENT_MAX_COUNT 6 ++ u8 segment_count; ++ struct fw_segment segment[SEGMENT_MAX_COUNT]; ++}; ++ ++u32 clock_lut[] = { ++ 20480000, /* FPGA */ ++ 16384000, /* 16.38 MHz */ ++ 20480000, /* 20.48 MHz */ ++ 36000000, /* 36.00 MHz */ ++ 30000000, /* 30.00 MHz */ ++ 26000000, /* 26.00 MHz */ ++ 28000000, /* 28.00 MHz */ ++ 32000000, /* 32.00 MHz */ ++ 34000000, /* 34.00 MHz */ ++ 24000000, /* 24.00 MHz */ ++ 22000000, /* 22.00 MHz */ ++ 12000000, /* 12.00 MHz */ ++}; ++ ++u32 clock_lut_it9135[] = { ++ 12000000, /* 12.00 MHz */ ++ 20480000, /* 20.48 MHz */ ++ 36000000, /* 36.00 MHz */ ++ 30000000, /* 30.00 MHz */ ++ 26000000, /* 26.00 MHz */ ++ 28000000, /* 28.00 MHz */ ++ 32000000, /* 32.00 MHz */ ++ 34000000, /* 34.00 MHz */ ++ 24000000, /* 24.00 MHz */ ++ 22000000, /* 22.00 MHz */ ++}; ++ ++/* EEPROM locations */ ++#define EEPROM_IR_MODE 0x430d ++#define EEPROM_DUAL_MODE 0x4326 ++#define EEPROM_IR_TYPE 0x4329 ++#define EEPROM_1_IFFREQ_L 0x432d ++#define EEPROM_1_IFFREQ_H 0x432e ++#define EEPROM_1_TUNER_ID 0x4331 ++#define EEPROM_2_IFFREQ_L 0x433d ++#define EEPROM_2_IFFREQ_H 0x433e ++#define EEPROM_2_TUNER_ID 0x4341 ++ ++/* USB commands */ ++#define CMD_MEM_RD 0x00 ++#define CMD_MEM_WR 0x01 ++#define CMD_I2C_RD 0x02 ++#define CMD_I2C_WR 0x03 ++#define CMD_FW_DL 0x21 ++#define CMD_FW_QUERYINFO 0x22 ++#define CMD_FW_BOOT 0x23 ++#define CMD_FW_DL_BEGIN 0x24 ++#define CMD_FW_DL_END 0x25 ++#define CMD_FW_SCATTER_WR 0x29 ++ ++#endif +Index: linux-3.3.x86_64/MAINTAINERS +=================================================================== +--- linux-3.3.x86_64.orig/MAINTAINERS ++++ linux-3.3.x86_64/MAINTAINERS +@@ -2659,6 +2659,13 @@ S: Maintained + F: Documentation/hwmon/f71805f + F: drivers/hwmon/f71805f.c + ++FC0011 TUNER DRIVER ++M: Michael Buesch ++L: linux-media@vger.kernel.org ++S: Maintained ++F: drivers/media/common/tuners/fc0011.h ++F: drivers/media/common/tuners/fc0011.c ++ + FANOTIFY + M: Eric Paris + S: Maintained +Index: linux-3.3.x86_64/drivers/media/common/tuners/fc0011.c +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/common/tuners/fc0011.c +@@ -0,0 +1,524 @@ ++/* ++ * Fitipower FC0011 tuner driver ++ * ++ * Copyright (C) 2012 Michael Buesch ++ * ++ * Derived from FC0012 tuner driver: ++ * Copyright (C) 2012 Hans-Frieder Vogt ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include "fc0011.h" ++ ++ ++/* Tuner registers */ ++enum { ++ FC11_REG_0, ++ FC11_REG_FA, /* FA */ ++ FC11_REG_FP, /* FP */ ++ FC11_REG_XINHI, /* XIN high 8 bit */ ++ FC11_REG_XINLO, /* XIN low 8 bit */ ++ FC11_REG_VCO, /* VCO */ ++ FC11_REG_VCOSEL, /* VCO select */ ++ FC11_REG_7, /* Unknown tuner reg 7 */ ++ FC11_REG_8, /* Unknown tuner reg 8 */ ++ FC11_REG_9, ++ FC11_REG_10, /* Unknown tuner reg 10 */ ++ FC11_REG_11, /* Unknown tuner reg 11 */ ++ FC11_REG_12, ++ FC11_REG_RCCAL, /* RC calibrate */ ++ FC11_REG_VCOCAL, /* VCO calibrate */ ++ FC11_REG_15, ++ FC11_REG_16, /* Unknown tuner reg 16 */ ++ FC11_REG_17, ++ ++ FC11_NR_REGS, /* Number of registers */ ++}; ++ ++enum FC11_REG_VCOSEL_bits { ++ FC11_VCOSEL_2 = 0x08, /* VCO select 2 */ ++ FC11_VCOSEL_1 = 0x10, /* VCO select 1 */ ++ FC11_VCOSEL_CLKOUT = 0x20, /* Fix clock out */ ++ FC11_VCOSEL_BW7M = 0x40, /* 7MHz bw */ ++ FC11_VCOSEL_BW6M = 0x80, /* 6MHz bw */ ++}; ++ ++enum FC11_REG_RCCAL_bits { ++ FC11_RCCAL_FORCE = 0x10, /* force */ ++}; ++ ++enum FC11_REG_VCOCAL_bits { ++ FC11_VCOCAL_RUN = 0, /* VCO calibration run */ ++ FC11_VCOCAL_VALUEMASK = 0x3F, /* VCO calibration value mask */ ++ FC11_VCOCAL_OK = 0x40, /* VCO calibration Ok */ ++ FC11_VCOCAL_RESET = 0x80, /* VCO calibration reset */ ++}; ++ ++ ++struct fc0011_priv { ++ struct i2c_adapter *i2c; ++ u8 addr; ++ ++ u32 frequency; ++ u32 bandwidth; ++}; ++ ++ ++static int fc0011_writereg(struct fc0011_priv *priv, u8 reg, u8 val) ++{ ++ u8 buf[2] = { reg, val }; ++ struct i2c_msg msg = { .addr = priv->addr, ++ .flags = 0, .buf = buf, .len = 2 }; ++ ++ if (i2c_transfer(priv->i2c, &msg, 1) != 1) { ++ dev_err(&priv->i2c->dev, ++ "I2C write reg failed, reg: %02x, val: %02x\n", ++ reg, val); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int fc0011_readreg(struct fc0011_priv *priv, u8 reg, u8 *val) ++{ ++ u8 dummy; ++ struct i2c_msg msg[2] = { ++ { .addr = priv->addr, ++ .flags = 0, .buf = ®, .len = 1 }, ++ { .addr = priv->addr, ++ .flags = I2C_M_RD, .buf = val ? : &dummy, .len = 1 }, ++ }; ++ ++ if (i2c_transfer(priv->i2c, msg, 2) != 2) { ++ dev_err(&priv->i2c->dev, ++ "I2C read failed, reg: %02x\n", reg); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int fc0011_release(struct dvb_frontend *fe) ++{ ++ kfree(fe->tuner_priv); ++ fe->tuner_priv = NULL; ++ ++ return 0; ++} ++ ++static int fc0011_init(struct dvb_frontend *fe) ++{ ++ struct fc0011_priv *priv = fe->tuner_priv; ++ int err; ++ ++ if (WARN_ON(!fe->callback)) ++ return -EINVAL; ++ ++ err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, ++ FC0011_FE_CALLBACK_POWER, priv->addr); ++ if (err) { ++ dev_err(&priv->i2c->dev, "Power-on callback failed\n"); ++ return err; ++ } ++ err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, ++ FC0011_FE_CALLBACK_RESET, priv->addr); ++ if (err) { ++ dev_err(&priv->i2c->dev, "Reset callback failed\n"); ++ return err; ++ } ++ ++ return 0; ++} ++ ++/* Initiate VCO calibration */ ++static int fc0011_vcocal_trigger(struct fc0011_priv *priv) ++{ ++ int err; ++ ++ err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RESET); ++ if (err) ++ return err; ++ err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++/* Read VCO calibration value */ ++static int fc0011_vcocal_read(struct fc0011_priv *priv, u8 *value) ++{ ++ int err; ++ ++ err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN); ++ if (err) ++ return err; ++ usleep_range(10000, 20000); ++ err = fc0011_readreg(priv, FC11_REG_VCOCAL, value); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++static int fc0011_set_params(struct dvb_frontend *fe) ++{ ++ struct dtv_frontend_properties *p = &fe->dtv_property_cache; ++ struct fc0011_priv *priv = fe->tuner_priv; ++ int err; ++ unsigned int i, vco_retries; ++ u32 freq = p->frequency / 1000; ++ u32 bandwidth = p->bandwidth_hz / 1000; ++ u32 fvco, xin, xdiv, xdivr; ++ u16 frac; ++ u8 fa, fp, vco_sel, vco_cal; ++ u8 regs[FC11_NR_REGS] = { }; ++ ++ regs[FC11_REG_7] = 0x0F; ++ regs[FC11_REG_8] = 0x3E; ++ regs[FC11_REG_10] = 0xB8; ++ regs[FC11_REG_11] = 0x80; ++ regs[FC11_REG_RCCAL] = 0x04; ++ err = fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]); ++ err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]); ++ err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]); ++ err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]); ++ err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); ++ if (err) ++ return -EIO; ++ ++ /* Set VCO freq and VCO div */ ++ if (freq < 54000) { ++ fvco = freq * 64; ++ regs[FC11_REG_VCO] = 0x82; ++ } else if (freq < 108000) { ++ fvco = freq * 32; ++ regs[FC11_REG_VCO] = 0x42; ++ } else if (freq < 216000) { ++ fvco = freq * 16; ++ regs[FC11_REG_VCO] = 0x22; ++ } else if (freq < 432000) { ++ fvco = freq * 8; ++ regs[FC11_REG_VCO] = 0x12; ++ } else { ++ fvco = freq * 4; ++ regs[FC11_REG_VCO] = 0x0A; ++ } ++ ++ /* Calc XIN. The PLL reference frequency is 18 MHz. */ ++ xdiv = fvco / 18000; ++ frac = fvco - xdiv * 18000; ++ frac = (frac << 15) / 18000; ++ if (frac >= 16384) ++ frac += 32786; ++ if (!frac) ++ xin = 0; ++ else if (frac < 511) ++ xin = 512; ++ else if (frac < 65026) ++ xin = frac; ++ else ++ xin = 65024; ++ regs[FC11_REG_XINHI] = xin >> 8; ++ regs[FC11_REG_XINLO] = xin; ++ ++ /* Calc FP and FA */ ++ xdivr = xdiv; ++ if (fvco - xdiv * 18000 >= 9000) ++ xdivr += 1; /* round */ ++ fp = xdivr / 8; ++ fa = xdivr - fp * 8; ++ if (fa < 2) { ++ fp -= 1; ++ fa += 8; ++ } ++ if (fp > 0x1F) { ++ fp &= 0x1F; ++ fa &= 0xF; ++ } ++ if (fa >= fp) { ++ dev_warn(&priv->i2c->dev, ++ "fa %02X >= fp %02X, but trying to continue\n", ++ (unsigned int)(u8)fa, (unsigned int)(u8)fp); ++ } ++ regs[FC11_REG_FA] = fa; ++ regs[FC11_REG_FP] = fp; ++ ++ /* Select bandwidth */ ++ switch (bandwidth) { ++ case 8000: ++ break; ++ case 7000: ++ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW7M; ++ break; ++ default: ++ dev_warn(&priv->i2c->dev, "Unsupported bandwidth %u kHz. " ++ "Using 6000 kHz.\n", ++ bandwidth); ++ bandwidth = 6000; ++ /* fallthrough */ ++ case 6000: ++ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW6M; ++ break; ++ } ++ ++ /* Pre VCO select */ ++ if (fvco < 2320000) { ++ vco_sel = 0; ++ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); ++ } else if (fvco < 3080000) { ++ vco_sel = 1; ++ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); ++ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; ++ } else { ++ vco_sel = 2; ++ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); ++ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; ++ } ++ ++ /* Fix for low freqs */ ++ if (freq < 45000) { ++ regs[FC11_REG_FA] = 0x6; ++ regs[FC11_REG_FP] = 0x11; ++ } ++ ++ /* Clock out fix */ ++ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_CLKOUT; ++ ++ /* Write the cached registers */ ++ for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) { ++ err = fc0011_writereg(priv, i, regs[i]); ++ if (err) ++ return err; ++ } ++ ++ /* VCO calibration */ ++ err = fc0011_vcocal_trigger(priv); ++ if (err) ++ return err; ++ err = fc0011_vcocal_read(priv, &vco_cal); ++ if (err) ++ return err; ++ vco_retries = 0; ++ while (!(vco_cal & FC11_VCOCAL_OK) && vco_retries < 3) { ++ /* Reset the tuner and try again */ ++ err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, ++ FC0011_FE_CALLBACK_RESET, priv->addr); ++ if (err) { ++ dev_err(&priv->i2c->dev, "Failed to reset tuner\n"); ++ return err; ++ } ++ /* Reinit tuner config */ ++ err = 0; ++ for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) ++ err |= fc0011_writereg(priv, i, regs[i]); ++ err |= fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]); ++ err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]); ++ err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]); ++ err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]); ++ err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); ++ if (err) ++ return -EIO; ++ /* VCO calibration */ ++ err = fc0011_vcocal_trigger(priv); ++ if (err) ++ return err; ++ err = fc0011_vcocal_read(priv, &vco_cal); ++ if (err) ++ return err; ++ vco_retries++; ++ } ++ if (!(vco_cal & FC11_VCOCAL_OK)) { ++ dev_err(&priv->i2c->dev, ++ "Failed to read VCO calibration value (got %02X)\n", ++ (unsigned int)vco_cal); ++ return -EIO; ++ } ++ vco_cal &= FC11_VCOCAL_VALUEMASK; ++ ++ switch (vco_sel) { ++ case 0: ++ if (vco_cal < 8) { ++ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); ++ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; ++ err = fc0011_writereg(priv, FC11_REG_VCOSEL, ++ regs[FC11_REG_VCOSEL]); ++ if (err) ++ return err; ++ err = fc0011_vcocal_trigger(priv); ++ if (err) ++ return err; ++ } else { ++ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); ++ err = fc0011_writereg(priv, FC11_REG_VCOSEL, ++ regs[FC11_REG_VCOSEL]); ++ if (err) ++ return err; ++ } ++ break; ++ case 1: ++ if (vco_cal < 5) { ++ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); ++ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; ++ err = fc0011_writereg(priv, FC11_REG_VCOSEL, ++ regs[FC11_REG_VCOSEL]); ++ if (err) ++ return err; ++ err = fc0011_vcocal_trigger(priv); ++ if (err) ++ return err; ++ } else if (vco_cal <= 48) { ++ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); ++ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; ++ err = fc0011_writereg(priv, FC11_REG_VCOSEL, ++ regs[FC11_REG_VCOSEL]); ++ if (err) ++ return err; ++ } else { ++ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); ++ err = fc0011_writereg(priv, FC11_REG_VCOSEL, ++ regs[FC11_REG_VCOSEL]); ++ if (err) ++ return err; ++ err = fc0011_vcocal_trigger(priv); ++ if (err) ++ return err; ++ } ++ break; ++ case 2: ++ if (vco_cal > 53) { ++ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); ++ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; ++ err = fc0011_writereg(priv, FC11_REG_VCOSEL, ++ regs[FC11_REG_VCOSEL]); ++ if (err) ++ return err; ++ err = fc0011_vcocal_trigger(priv); ++ if (err) ++ return err; ++ } else { ++ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); ++ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; ++ err = fc0011_writereg(priv, FC11_REG_VCOSEL, ++ regs[FC11_REG_VCOSEL]); ++ if (err) ++ return err; ++ } ++ break; ++ } ++ err = fc0011_vcocal_read(priv, NULL); ++ if (err) ++ return err; ++ usleep_range(10000, 50000); ++ ++ err = fc0011_readreg(priv, FC11_REG_RCCAL, ®s[FC11_REG_RCCAL]); ++ if (err) ++ return err; ++ regs[FC11_REG_RCCAL] |= FC11_RCCAL_FORCE; ++ err = fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); ++ if (err) ++ return err; ++ err = fc0011_writereg(priv, FC11_REG_16, 0xB); ++ if (err) ++ return err; ++ ++ dev_dbg(&priv->i2c->dev, "Tuned to " ++ "fa=%02X fp=%02X xin=%02X%02X vco=%02X vcosel=%02X " ++ "vcocal=%02X(%u) bw=%u\n", ++ (unsigned int)regs[FC11_REG_FA], ++ (unsigned int)regs[FC11_REG_FP], ++ (unsigned int)regs[FC11_REG_XINHI], ++ (unsigned int)regs[FC11_REG_XINLO], ++ (unsigned int)regs[FC11_REG_VCO], ++ (unsigned int)regs[FC11_REG_VCOSEL], ++ (unsigned int)vco_cal, vco_retries, ++ (unsigned int)bandwidth); ++ ++ priv->frequency = p->frequency; ++ priv->bandwidth = p->bandwidth_hz; ++ ++ return 0; ++} ++ ++static int fc0011_get_frequency(struct dvb_frontend *fe, u32 *frequency) ++{ ++ struct fc0011_priv *priv = fe->tuner_priv; ++ ++ *frequency = priv->frequency; ++ ++ return 0; ++} ++ ++static int fc0011_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) ++{ ++ *frequency = 0; ++ ++ return 0; ++} ++ ++static int fc0011_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) ++{ ++ struct fc0011_priv *priv = fe->tuner_priv; ++ ++ *bandwidth = priv->bandwidth; ++ ++ return 0; ++} ++ ++static const struct dvb_tuner_ops fc0011_tuner_ops = { ++ .info = { ++ .name = "Fitipower FC0011", ++ ++ .frequency_min = 45000000, ++ .frequency_max = 1000000000, ++ }, ++ ++ .release = fc0011_release, ++ .init = fc0011_init, ++ ++ .set_params = fc0011_set_params, ++ ++ .get_frequency = fc0011_get_frequency, ++ .get_if_frequency = fc0011_get_if_frequency, ++ .get_bandwidth = fc0011_get_bandwidth, ++}; ++ ++struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, ++ struct i2c_adapter *i2c, ++ const struct fc0011_config *config) ++{ ++ struct fc0011_priv *priv; ++ ++ priv = kzalloc(sizeof(struct fc0011_priv), GFP_KERNEL); ++ if (!priv) ++ return NULL; ++ ++ priv->i2c = i2c; ++ priv->addr = config->i2c_address; ++ ++ fe->tuner_priv = priv; ++ fe->ops.tuner_ops = fc0011_tuner_ops; ++ ++ dev_info(&priv->i2c->dev, "Fitipower FC0011 tuner attached\n"); ++ ++ return fe; ++} ++EXPORT_SYMBOL(fc0011_attach); ++ ++MODULE_DESCRIPTION("Fitipower FC0011 silicon tuner driver"); ++MODULE_AUTHOR("Michael Buesch "); ++MODULE_LICENSE("GPL"); +Index: linux-3.3.x86_64/drivers/media/common/tuners/fc0011.h +=================================================================== +--- /dev/null ++++ linux-3.3.x86_64/drivers/media/common/tuners/fc0011.h +@@ -0,0 +1,41 @@ ++#ifndef LINUX_FC0011_H_ ++#define LINUX_FC0011_H_ ++ ++#include "dvb_frontend.h" ++ ++ ++/** struct fc0011_config - fc0011 hardware config ++ * ++ * @i2c_address: I2C bus address. ++ */ ++struct fc0011_config { ++ u8 i2c_address; ++}; ++ ++/** enum fc0011_fe_callback_commands - Frontend callbacks ++ * ++ * @FC0011_FE_CALLBACK_POWER: Power on tuner hardware. ++ * @FC0011_FE_CALLBACK_RESET: Request a tuner reset. ++ */ ++enum fc0011_fe_callback_commands { ++ FC0011_FE_CALLBACK_POWER, ++ FC0011_FE_CALLBACK_RESET, ++}; ++ ++#if defined(CONFIG_MEDIA_TUNER_FC0011) ||\ ++ defined(CONFIG_MEDIA_TUNER_FC0011_MODULE) ++struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, ++ struct i2c_adapter *i2c, ++ const struct fc0011_config *config); ++#else ++static inline ++struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, ++ struct i2c_adapter *i2c, ++ const struct fc0011_config *config) ++{ ++ dev_err(&i2c->dev, "fc0011 driver disabled in Kconfig\n"); ++ return NULL; ++} ++#endif ++ ++#endif /* LINUX_FC0011_H_ */ diff --git a/drm-i915-dp-stfu.patch b/drm-i915-dp-stfu.patch new file mode 100644 index 000000000..8948229dc --- /dev/null +++ b/drm-i915-dp-stfu.patch @@ -0,0 +1,69 @@ +From 04a43e2598db35b3d0ec25925bb8475b5c0a3809 Mon Sep 17 00:00:00 2001 +From: Adam Jackson +Date: Fri, 16 Mar 2012 16:39:11 -0400 +Subject: [PATCH] drm/i915/dp: Use DRM_ERROR not WARN for sanity checks + +These are noisy as shit and creating a ton of abrt reports. I don't +need more, thanks. Proper fix upstream eventually. + +Signed-off-by: Adam Jackson +--- + drivers/gpu/drm/i915/intel_dp.c | 14 ++++++++------ + 1 files changed, 8 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c +index 94f860c..6bf27c9 100644 +--- a/drivers/gpu/drm/i915/intel_dp.c ++++ b/drivers/gpu/drm/i915/intel_dp.c +@@ -331,7 +331,7 @@ intel_dp_check_edp(struct intel_dp *intel_dp) + if (!is_edp(intel_dp)) + return; + if (!ironlake_edp_have_panel_power(intel_dp) && !ironlake_edp_have_panel_vdd(intel_dp)) { +- WARN(1, "eDP powered off while attempting aux channel communication.\n"); ++ DRM_ERROR("eDP powered off while attempting aux channel communication.\n"); + DRM_DEBUG_KMS("Status 0x%08x Control 0x%08x\n", + I915_READ(PCH_PP_STATUS), + I915_READ(PCH_PP_CONTROL)); +@@ -386,7 +386,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, + } + + if (try == 3) { +- WARN(1, "dp_aux_ch not started status 0x%08x\n", ++ DRM_ERROR("dp_aux_ch not started status 0x%08x\n", + I915_READ(ch_ctl)); + return -EBUSY; + } +@@ -992,8 +992,8 @@ static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) + return; + DRM_DEBUG_KMS("Turn eDP VDD on\n"); + +- WARN(intel_dp->want_panel_vdd, +- "eDP VDD already requested on\n"); ++ if (intel_dp->want_panel_vdd) ++ DRM_ERROR("eDP VDD already requested on\n"); + + intel_dp->want_panel_vdd = true; + +@@ -1058,7 +1058,8 @@ static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) + return; + + DRM_DEBUG_KMS("Turn eDP VDD off %d\n", intel_dp->want_panel_vdd); +- WARN(!intel_dp->want_panel_vdd, "eDP VDD not forced on"); ++ if (!intel_dp->want_panel_vdd) ++ DRM_ERROR("eDP VDD not forced on"); + + intel_dp->want_panel_vdd = false; + +@@ -1128,7 +1129,8 @@ static void ironlake_edp_panel_off(struct intel_dp *intel_dp) + + DRM_DEBUG_KMS("Turn eDP power off\n"); + +- WARN(intel_dp->want_panel_vdd, "Cannot turn power off while VDD is on\n"); ++ if (intel_dp->want_panel_vdd) ++ DRM_ERROR("Cannot turn power off while VDD is on\n"); + + pp = ironlake_get_pp_control(dev_priv); + pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE); +-- +1.7.7.6 + diff --git a/drm-i915-fbc-stfu.patch b/drm-i915-fbc-stfu.patch new file mode 100644 index 000000000..9240387ee --- /dev/null +++ b/drm-i915-fbc-stfu.patch @@ -0,0 +1,102 @@ +From c5d1455d9340c63e5c5d987e2d816e77538caa90 Mon Sep 17 00:00:00 2001 +From: Adam Jackson +Date: Tue, 13 Sep 2011 12:07:37 -0400 +Subject: [PATCH] drm/i915: Shut the fbc messages up + +FB compression enable/disable fires on pretty much every pageflip now, +which is just uncredibly excessive. Hush that noise. + +Signed-off-by: Adam Jackson +--- + drivers/gpu/drm/i915/intel_display.c | 19 ------------------- + 1 files changed, 0 insertions(+), 19 deletions(-) + +diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c +index 56a8554..a6d14eb 100644 +--- a/drivers/gpu/drm/i915/intel_display.c ++++ b/drivers/gpu/drm/i915/intel_display.c +@@ -1474,8 +1474,6 @@ static void i8xx_disable_fbc(struct drm_device *dev) + DRM_DEBUG_KMS("FBC idle timed out\n"); + return; + } +- +- DRM_DEBUG_KMS("disabled FBC\n"); + } + + static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +@@ -1516,9 +1514,6 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) + fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT; + fbc_ctl |= obj->fence_reg; + I915_WRITE(FBC_CONTROL, fbc_ctl); +- +- DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %d, ", +- cfb_pitch, crtc->y, intel_crtc->plane); + } + + static bool i8xx_fbc_enabled(struct drm_device *dev) +@@ -1551,8 +1546,6 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) + + /* enable it... */ + I915_WRITE(DPFC_CONTROL, I915_READ(DPFC_CONTROL) | DPFC_CTL_EN); +- +- DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); + } + + static void g4x_disable_fbc(struct drm_device *dev) +@@ -1565,8 +1558,6 @@ static void g4x_disable_fbc(struct drm_device *dev) + if (dpfc_ctl & DPFC_CTL_EN) { + dpfc_ctl &= ~DPFC_CTL_EN; + I915_WRITE(DPFC_CONTROL, dpfc_ctl); +- +- DRM_DEBUG_KMS("disabled FBC\n"); + } + } + +@@ -1631,8 +1622,6 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) + I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); + sandybridge_blit_fbc_update(dev); + } +- +- DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); + } + + static void ironlake_disable_fbc(struct drm_device *dev) +@@ -1645,8 +1634,6 @@ static void ironlake_disable_fbc(struct drm_device *dev) + if (dpfc_ctl & DPFC_CTL_EN) { + dpfc_ctl &= ~DPFC_CTL_EN; + I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl); +- +- DRM_DEBUG_KMS("disabled FBC\n"); + } + } + +@@ -1701,8 +1688,6 @@ static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv) + if (dev_priv->fbc_work == NULL) + return; + +- DRM_DEBUG_KMS("cancelling pending FBC enable\n"); +- + /* Synchronisation is provided by struct_mutex and checking of + * dev_priv->fbc_work, so we can perform the cancellation + * entirely asynchronously. +@@ -1743,8 +1728,6 @@ static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval) + + dev_priv->fbc_work = work; + +- DRM_DEBUG_KMS("scheduling delayed FBC enable\n"); +- + /* Delay the actual enabling to let pageflipping cease and the + * display to settle before starting the compression. Note that + * this delay also serves a second purpose: it allows for a +@@ -1800,8 +1783,6 @@ static void intel_update_fbc(struct drm_device *dev) + struct drm_i915_gem_object *obj; + int enable_fbc; + +- DRM_DEBUG_KMS("\n"); +- + if (!i915_powersave) + return; + +-- +1.7.6 + diff --git a/drm-i915-gen4-has-non-power-of-two-strides.patch b/drm-i915-gen4-has-non-power-of-two-strides.patch deleted file mode 100644 index f111614bc..000000000 --- a/drm-i915-gen4-has-non-power-of-two-strides.patch +++ /dev/null @@ -1,69 +0,0 @@ -From bea96046b4245e9abd65ed7acfed9adfd5f6c639 Mon Sep 17 00:00:00 2001 -From: Chris Wilson -Date: Thu, 3 Mar 2011 23:43:02 +0000 -Subject: [PATCH] drm/i915: Gen4+ has non-power-of-two strides - -In c2e0eb16707, we started checking that the buffer was the correct size -for tiled access by ensuring that the size was a multiple of tiles. -However, gen4+ complicates the issue by allowing any multiple of 4096 -bytes for the stride and so the simple check based on a power-of-two -stride was failing for valid bo. - -Reported-by: Dan Williams -Reported-by: Robert Hooker -Cc: Daniel Vetter -Signed-off-by: Chris Wilson ---- - drivers/gpu/drm/i915/i915_gem_tiling.c | 29 ++++++++++++++--------------- - 1 files changed, 14 insertions(+), 15 deletions(-) - -diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c -index 79a04fd..654f350 100644 ---- a/drivers/gpu/drm/i915/i915_gem_tiling.c -+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c -@@ -215,6 +215,19 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) - } - } - -+ if (INTEL_INFO(dev)->gen >= 4) { -+ /* 965+ just needs multiples of tile width */ -+ if (stride & (tile_width - 1)) -+ return false; -+ } else { -+ /* Pre-965 needs power of two tile widths */ -+ if (stride < tile_width) -+ return false; -+ -+ if (stride & (stride - 1)) -+ return false; -+ } -+ - if (IS_GEN2(dev) || - (tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev))) - tile_height = 32; -@@ -226,21 +239,7 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) - tile_height *= 2; - - /* Size needs to be aligned to a full tile row */ -- if (size & (tile_height * stride - 1)) -- return false; -- -- /* 965+ just needs multiples of tile width */ -- if (INTEL_INFO(dev)->gen >= 4) { -- if (stride & (tile_width - 1)) -- return false; -- return true; -- } -- -- /* Pre-965 needs power of two tile widths */ -- if (stride < tile_width) -- return false; -- -- if (stride & (stride - 1)) -+ if (size % (tile_height * stride)) - return false; - - return true; --- -1.7.4.1 - diff --git a/drm-intel-big-hammer.patch b/drm-intel-big-hammer.patch deleted file mode 100644 index bf152af3b..000000000 --- a/drm-intel-big-hammer.patch +++ /dev/null @@ -1,21 +0,0 @@ -omgwtfbbqchainsaw? ---- - drivers/gpu/drm/i915/i915_gem_execbuffer.c | 5 +++++ - 1 files changed, 5 insertions(+), 0 deletions(-) - -diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c -index e698343..21e601d1 100644 ---- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c -+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c -@@ -1090,6 +1090,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, - if (ret) - goto pre_mutex_err; - -+ /* We don't get the flushing right for these chipsets, use the -+ * big hammer for now to avoid random crashiness. */ -+ if (IS_I85X(dev) || IS_I865G(dev)) -+ wbinvd(); -+ - if (dev_priv->mm.suspended) { - mutex_unlock(&dev->struct_mutex); - ret = -EBUSY; diff --git a/drm-intel-crtc-dpms-fix.patch b/drm-intel-crtc-dpms-fix.patch new file mode 100644 index 000000000..eb582cbec --- /dev/null +++ b/drm-intel-crtc-dpms-fix.patch @@ -0,0 +1,40 @@ +From aed3f09db39596e539f90b11a5016aea4d8442e1 Mon Sep 17 00:00:00 2001 +From: Alban Browaeys +Date: Fri, 24 Feb 2012 17:12:45 +0000 +Subject: [PATCH] drm/i915: Prevent a machine hang by checking crtc->active + before loading lut + +Before loading the lut (gamma), check the active state of intel_crtc, +otherwise at least on gen2 hang ensue. + +This is reproducible in Xorg via: + xset dpms force off +then + xgamma -rgamma 2.0 # freeze. + +Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=44505 +Signed-off-by: Alban Browaeys +Signed-off-by: Chris Wilson +Reviewed-by: Jesse Barnes +Cc: stable@kernel.org +Signed-off-by: Jesse Barnes +--- + drivers/gpu/drm/i915/intel_display.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c +index 4871ba0..f851db7 100644 +--- a/drivers/gpu/drm/i915/intel_display.c ++++ b/drivers/gpu/drm/i915/intel_display.c +@@ -6184,7 +6184,7 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) + int i; + + /* The clocks have to be on to load the palette. */ +- if (!crtc->enabled) ++ if (!crtc->enabled || !intel_crtc->active) + return; + + /* use legacy palette for Ironlake */ +-- +1.7.7.6 + diff --git a/drm-intel-edp-fixes.patch b/drm-intel-edp-fixes.patch deleted file mode 100644 index c77ef116c..000000000 --- a/drm-intel-edp-fixes.patch +++ /dev/null @@ -1,44 +0,0 @@ -diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c -index f737960..b1f8164 100644 ---- a/drivers/gpu/drm/i915/i915_drv.c -+++ b/drivers/gpu/drm/i915/i915_drv.c -@@ -509,6 +509,8 @@ i915_pci_remove(struct pci_dev *pdev) - { - struct drm_device *dev = pci_get_drvdata(pdev); - -+ pci_disable_device(pdev); /* core did previous enable */ -+ - drm_put_dev(dev); - } - -diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c -index 300f64b..2e3db37 100644 ---- a/drivers/gpu/drm/i915/intel_dp.c -+++ b/drivers/gpu/drm/i915/intel_dp.c -@@ -795,7 +795,8 @@ static bool ironlake_edp_panel_on (struct intel_dp *intel_dp) - { - struct drm_device *dev = intel_dp->base.base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; -- u32 pp, idle_on_mask = PP_ON | PP_SEQUENCE_STATE_ON_IDLE; -+ u32 pp, idle_on = PP_ON | PP_SEQUENCE_STATE_ON_IDLE; -+ u32 idle_on_mask = PP_ON | PP_SEQUENCE_STATE_MASK; - - if (I915_READ(PCH_PP_STATUS) & PP_ON) - return true; -@@ -816,7 +817,7 @@ static bool ironlake_edp_panel_on (struct intel_dp *intel_dp) - */ - msleep(300); - -- if (wait_for((I915_READ(PCH_PP_STATUS) & idle_on_mask) == idle_on_mask, -+ if (wait_for((I915_READ(PCH_PP_STATUS) & idle_on_mask) == idle_on, - 5000)) - DRM_ERROR("panel on wait timed out: 0x%08x\n", - I915_READ(PCH_PP_STATUS)); -@@ -922,6 +923,7 @@ static void intel_dp_prepare(struct drm_encoder *encoder) - - if (is_edp(intel_dp)) { - ironlake_edp_backlight_off(dev); -+ ironlake_edp_panel_off(dev); - ironlake_edp_panel_on(intel_dp); - if (!is_pch_edp(intel_dp)) - ironlake_edp_pll_on(encoder); diff --git a/drm-intel-make-lvds-work.patch b/drm-intel-make-lvds-work.patch deleted file mode 100644 index 209deb295..000000000 --- a/drm-intel-make-lvds-work.patch +++ /dev/null @@ -1,23 +0,0 @@ - drivers/gpu/drm/i915/intel_display.c | 2 -- - 1 files changed, 0 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c -index 990f065..171a797 100644 ---- a/drivers/gpu/drm/i915/intel_display.c -+++ b/drivers/gpu/drm/i915/intel_display.c -@@ -4568,7 +4568,6 @@ void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, - struct drm_connector *connector, int dpms_mode) - { - struct drm_encoder *encoder = &intel_encoder->base; -- struct drm_device *dev = encoder->dev; - struct drm_crtc *crtc = encoder->crtc; - struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; - struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; -@@ -4578,7 +4577,6 @@ void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, - connector->encoder = NULL; - intel_encoder->load_detect_temp = false; - crtc->enabled = drm_helper_crtc_in_use(crtc); -- drm_helper_disable_unused_functions(dev); - } - - /* Switch crtc and encoder back off if necessary */ diff --git a/drm-nouveau-updates.patch b/drm-nouveau-updates.patch deleted file mode 100644 index 3bd652fa6..000000000 --- a/drm-nouveau-updates.patch +++ /dev/null @@ -1,1875 +0,0 @@ - drivers/gpu/drm/nouveau/nouveau_bios.c | 25 +-- - drivers/gpu/drm/nouveau/nouveau_bo.c | 6 +- - drivers/gpu/drm/nouveau/nouveau_channel.c | 2 +- - drivers/gpu/drm/nouveau/nouveau_display.c | 2 +- - drivers/gpu/drm/nouveau/nouveau_dp.c | 2 - - drivers/gpu/drm/nouveau/nouveau_drv.h | 15 +- - drivers/gpu/drm/nouveau/nouveau_fence.c | 190 ++++++++++------ - drivers/gpu/drm/nouveau/nouveau_mem.c | 50 +++- - drivers/gpu/drm/nouveau/nouveau_object.c | 22 ++- - drivers/gpu/drm/nouveau/nouveau_sgdma.c | 341 +++++++++++++++++++++++++---- - drivers/gpu/drm/nouveau/nouveau_state.c | 10 +- - drivers/gpu/drm/nouveau/nouveau_temp.c | 4 +- - drivers/gpu/drm/nouveau/nouveau_util.c | 23 ++- - drivers/gpu/drm/nouveau/nouveau_util.h | 4 + - drivers/gpu/drm/nouveau/nouveau_vm.c | 13 +- - drivers/gpu/drm/nouveau/nv04_fifo.c | 19 ++- - drivers/gpu/drm/nouveau/nv40_fb.c | 59 +++++- - drivers/gpu/drm/nouveau/nv50_display.c | 7 +- - drivers/gpu/drm/nouveau/nv50_fb.c | 150 ++++++++++++- - drivers/gpu/drm/nouveau/nv50_fifo.c | 3 +- - drivers/gpu/drm/nouveau/nv50_gpio.c | 13 +- - drivers/gpu/drm/nouveau/nv50_graph.c | 142 +++++++----- - drivers/gpu/drm/nouveau/nv50_vm.c | 1 - - drivers/gpu/drm/nouveau/nv84_crypt.c | 2 +- - drivers/gpu/drm/nouveau/nvc0_fifo.c | 15 +- - drivers/gpu/drm/nouveau/nvc0_graph.c | 2 - - 26 files changed, 841 insertions(+), 281 deletions(-) - -diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c -index 6bdab89..b8ff1e7 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_bios.c -+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c -@@ -5950,6 +5950,11 @@ apply_dcb_connector_quirks(struct nvbios *bios, int idx) - } - } - -+static const u8 hpd_gpio[16] = { -+ 0xff, 0x07, 0x08, 0xff, 0xff, 0x51, 0x52, 0xff, -+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x5e, 0x5f, 0x60, -+}; -+ - static void - parse_dcb_connector_table(struct nvbios *bios) - { -@@ -5986,23 +5991,9 @@ parse_dcb_connector_table(struct nvbios *bios) - - cte->type = (cte->entry & 0x000000ff) >> 0; - cte->index2 = (cte->entry & 0x00000f00) >> 8; -- switch (cte->entry & 0x00033000) { -- case 0x00001000: -- cte->gpio_tag = 0x07; -- break; -- case 0x00002000: -- cte->gpio_tag = 0x08; -- break; -- case 0x00010000: -- cte->gpio_tag = 0x51; -- break; -- case 0x00020000: -- cte->gpio_tag = 0x52; -- break; -- default: -- cte->gpio_tag = 0xff; -- break; -- } -+ -+ cte->gpio_tag = ffs((cte->entry & 0x07033000) >> 12); -+ cte->gpio_tag = hpd_gpio[cte->gpio_tag]; - - if (cte->type == 0xff) - continue; -diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c -index a521840..53a8000 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_bo.c -+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c -@@ -385,7 +385,8 @@ nouveau_bo_create_ttm_backend_entry(struct ttm_bo_device *bdev) - case NOUVEAU_GART_AGP: - return ttm_agp_backend_init(bdev, dev->agp->bridge); - #endif -- case NOUVEAU_GART_SGDMA: -+ case NOUVEAU_GART_PDMA: -+ case NOUVEAU_GART_HW: - return nouveau_sgdma_init_ttm(dev); - default: - NV_ERROR(dev, "Unknown GART type %d\n", -@@ -439,7 +440,8 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, - TTM_PL_FLAG_WC; - man->default_caching = TTM_PL_FLAG_WC; - break; -- case NOUVEAU_GART_SGDMA: -+ case NOUVEAU_GART_PDMA: -+ case NOUVEAU_GART_HW: - man->flags = TTM_MEMTYPE_FLAG_MAPPABLE | - TTM_MEMTYPE_FLAG_CMA; - man->available_caching = TTM_PL_MASK_CACHING; -diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c -index 3960d66..3d7b316 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_channel.c -+++ b/drivers/gpu/drm/nouveau/nouveau_channel.c -@@ -35,7 +35,7 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan) - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_bo *pb = chan->pushbuf_bo; - struct nouveau_gpuobj *pushbuf = NULL; -- int ret; -+ int ret = 0; - - if (dev_priv->card_type >= NV_50) { - if (dev_priv->card_type < NV_C0) { -diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c -index 505c6bf..566466b 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_display.c -+++ b/drivers/gpu/drm/nouveau/nouveau_display.c -@@ -244,7 +244,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, - - /* Initialize a page flip struct */ - *s = (struct nouveau_page_flip_state) -- { { }, s->event, nouveau_crtc(crtc)->index, -+ { { }, event, nouveau_crtc(crtc)->index, - fb->bits_per_pixel, fb->pitch, crtc->x, crtc->y, - new_bo->bo.offset }; - -diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c -index 38d5995..7beb82a 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_dp.c -+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c -@@ -175,7 +175,6 @@ nouveau_dp_link_train_adjust(struct drm_encoder *encoder, uint8_t *config) - { - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct drm_device *dev = encoder->dev; -- struct bit_displayport_encoder_table_entry *dpse; - struct bit_displayport_encoder_table *dpe; - int ret, i, dpe_headerlen, vs = 0, pre = 0; - uint8_t request[2]; -@@ -183,7 +182,6 @@ nouveau_dp_link_train_adjust(struct drm_encoder *encoder, uint8_t *config) - dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); - if (!dpe) - return false; -- dpse = (void *)((char *)dpe + dpe_headerlen); - - ret = auxch_rd(encoder, DP_ADJUST_REQUEST_LANE0_1, request, 2); - if (ret) -diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h -index 982d70b..2cae8e7 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_drv.h -+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h -@@ -652,7 +652,6 @@ struct drm_nouveau_private { - /* interrupt handling */ - void (*irq_handler[32])(struct drm_device *); - bool msi_enabled; -- struct workqueue_struct *wq; - struct work_struct irq_work; - - struct list_head vbl_waiting; -@@ -691,13 +690,21 @@ struct drm_nouveau_private { - struct { - enum { - NOUVEAU_GART_NONE = 0, -- NOUVEAU_GART_AGP, -- NOUVEAU_GART_SGDMA -+ NOUVEAU_GART_AGP, /* AGP */ -+ NOUVEAU_GART_PDMA, /* paged dma object */ -+ NOUVEAU_GART_HW /* on-chip gart/vm */ - } type; - uint64_t aper_base; - uint64_t aper_size; - uint64_t aper_free; - -+ struct ttm_backend_func *func; -+ -+ struct { -+ struct page *page; -+ dma_addr_t addr; -+ } dummy; -+ - struct nouveau_gpuobj *sg_ctxdma; - struct nouveau_vma vma; - } gart_info; -@@ -1076,7 +1083,7 @@ extern void nv40_fb_set_tile_region(struct drm_device *dev, int i); - /* nv50_fb.c */ - extern int nv50_fb_init(struct drm_device *); - extern void nv50_fb_takedown(struct drm_device *); --extern void nv50_fb_vm_trap(struct drm_device *, int display, const char *); -+extern void nv50_fb_vm_trap(struct drm_device *, int display); - - /* nvc0_fb.c */ - extern int nvc0_fb_init(struct drm_device *); -diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c -index 221b846..8b46392 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_fence.c -+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c -@@ -32,8 +32,7 @@ - #include "nouveau_dma.h" - - #define USE_REFCNT(dev) (nouveau_private(dev)->chipset >= 0x10) --#define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17 && \ -- nouveau_private(dev)->card_type < NV_C0) -+#define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17) - - struct nouveau_fence { - struct nouveau_channel *channel; -@@ -259,11 +258,12 @@ __nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr) - } - - static struct nouveau_semaphore * --alloc_semaphore(struct drm_device *dev) -+semaphore_alloc(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_semaphore *sema; -- int ret; -+ int size = (dev_priv->chipset < 0x84) ? 4 : 16; -+ int ret, i; - - if (!USE_SEMA(dev)) - return NULL; -@@ -277,9 +277,9 @@ alloc_semaphore(struct drm_device *dev) - goto fail; - - spin_lock(&dev_priv->fence.lock); -- sema->mem = drm_mm_search_free(&dev_priv->fence.heap, 4, 0, 0); -+ sema->mem = drm_mm_search_free(&dev_priv->fence.heap, size, 0, 0); - if (sema->mem) -- sema->mem = drm_mm_get_block_atomic(sema->mem, 4, 0); -+ sema->mem = drm_mm_get_block_atomic(sema->mem, size, 0); - spin_unlock(&dev_priv->fence.lock); - - if (!sema->mem) -@@ -287,7 +287,8 @@ alloc_semaphore(struct drm_device *dev) - - kref_init(&sema->ref); - sema->dev = dev; -- nouveau_bo_wr32(dev_priv->fence.bo, sema->mem->start / 4, 0); -+ for (i = sema->mem->start; i < sema->mem->start + size; i += 4) -+ nouveau_bo_wr32(dev_priv->fence.bo, i / 4, 0); - - return sema; - fail: -@@ -296,7 +297,7 @@ fail: - } - - static void --free_semaphore(struct kref *ref) -+semaphore_free(struct kref *ref) - { - struct nouveau_semaphore *sema = - container_of(ref, struct nouveau_semaphore, ref); -@@ -318,61 +319,107 @@ semaphore_work(void *priv, bool signalled) - if (unlikely(!signalled)) - nouveau_bo_wr32(dev_priv->fence.bo, sema->mem->start / 4, 1); - -- kref_put(&sema->ref, free_semaphore); -+ kref_put(&sema->ref, semaphore_free); - } - - static int --emit_semaphore(struct nouveau_channel *chan, int method, -- struct nouveau_semaphore *sema) -+semaphore_acquire(struct nouveau_channel *chan, struct nouveau_semaphore *sema) - { -- struct drm_nouveau_private *dev_priv = sema->dev->dev_private; -- struct nouveau_fence *fence; -- bool smart = (dev_priv->card_type >= NV_50); -+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private; -+ struct nouveau_fence *fence = NULL; - int ret; - -- ret = RING_SPACE(chan, smart ? 8 : 4); -+ if (dev_priv->chipset < 0x84) { -+ ret = RING_SPACE(chan, 3); -+ if (ret) -+ return ret; -+ -+ BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_OFFSET, 2); -+ OUT_RING (chan, sema->mem->start); -+ OUT_RING (chan, 1); -+ } else -+ if (dev_priv->chipset < 0xc0) { -+ struct nouveau_vma *vma = &dev_priv->fence.bo->vma; -+ u64 offset = vma->offset + sema->mem->start; -+ -+ ret = RING_SPACE(chan, 5); -+ if (ret) -+ return ret; -+ -+ BEGIN_RING(chan, NvSubSw, 0x0010, 4); -+ OUT_RING (chan, upper_32_bits(offset)); -+ OUT_RING (chan, lower_32_bits(offset)); -+ OUT_RING (chan, 1); -+ OUT_RING (chan, 1); /* ACQUIRE_EQ */ -+ } else { -+ struct nouveau_vma *vma = &dev_priv->fence.bo->vma; -+ u64 offset = vma->offset + sema->mem->start; -+ -+ ret = RING_SPACE(chan, 5); -+ if (ret) -+ return ret; -+ -+ BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4); -+ OUT_RING (chan, upper_32_bits(offset)); -+ OUT_RING (chan, lower_32_bits(offset)); -+ OUT_RING (chan, 1); -+ OUT_RING (chan, 0x1001); /* ACQUIRE_EQ */ -+ } -+ -+ /* Delay semaphore destruction until its work is done */ -+ ret = nouveau_fence_new(chan, &fence, true); - if (ret) - return ret; - -- if (smart) { -- BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1); -- OUT_RING(chan, NvSema); -- } -- BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_OFFSET, 1); -- OUT_RING(chan, sema->mem->start); -- -- if (smart && method == NV_SW_SEMAPHORE_ACQUIRE) { -- /* -- * NV50 tries to be too smart and context-switch -- * between semaphores instead of doing a "first come, -- * first served" strategy like previous cards -- * do. -- * -- * That's bad because the ACQUIRE latency can get as -- * large as the PFIFO context time slice in the -- * typical DRI2 case where you have several -- * outstanding semaphores at the same moment. -- * -- * If we're going to ACQUIRE, force the card to -- * context switch before, just in case the matching -- * RELEASE is already scheduled to be executed in -- * another channel. -- */ -- BEGIN_RING(chan, NvSubSw, NV_SW_YIELD, 1); -- OUT_RING(chan, 0); -- } -+ kref_get(&sema->ref); -+ nouveau_fence_work(fence, semaphore_work, sema); -+ nouveau_fence_unref(&fence); -+ return 0; -+} -+ -+static int -+semaphore_release(struct nouveau_channel *chan, struct nouveau_semaphore *sema) -+{ -+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private; -+ struct nouveau_fence *fence = NULL; -+ int ret; -+ -+ if (dev_priv->chipset < 0x84) { -+ ret = RING_SPACE(chan, 4); -+ if (ret) -+ return ret; -+ -+ BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_OFFSET, 1); -+ OUT_RING (chan, sema->mem->start); -+ BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_RELEASE, 1); -+ OUT_RING (chan, 1); -+ } else -+ if (dev_priv->chipset < 0xc0) { -+ struct nouveau_vma *vma = &dev_priv->fence.bo->vma; -+ u64 offset = vma->offset + sema->mem->start; - -- BEGIN_RING(chan, NvSubSw, method, 1); -- OUT_RING(chan, 1); -- -- if (smart && method == NV_SW_SEMAPHORE_RELEASE) { -- /* -- * Force the card to context switch, there may be -- * another channel waiting for the semaphore we just -- * released. -- */ -- BEGIN_RING(chan, NvSubSw, NV_SW_YIELD, 1); -- OUT_RING(chan, 0); -+ ret = RING_SPACE(chan, 5); -+ if (ret) -+ return ret; -+ -+ BEGIN_RING(chan, NvSubSw, 0x0010, 4); -+ OUT_RING (chan, upper_32_bits(offset)); -+ OUT_RING (chan, lower_32_bits(offset)); -+ OUT_RING (chan, 1); -+ OUT_RING (chan, 2); /* RELEASE */ -+ } else { -+ struct nouveau_vma *vma = &dev_priv->fence.bo->vma; -+ u64 offset = vma->offset + sema->mem->start; -+ -+ ret = RING_SPACE(chan, 5); -+ if (ret) -+ return ret; -+ -+ BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4); -+ OUT_RING (chan, upper_32_bits(offset)); -+ OUT_RING (chan, lower_32_bits(offset)); -+ OUT_RING (chan, 1); -+ OUT_RING (chan, 0x1002); /* RELEASE */ - } - - /* Delay semaphore destruction until its work is done */ -@@ -383,7 +430,6 @@ emit_semaphore(struct nouveau_channel *chan, int method, - kref_get(&sema->ref); - nouveau_fence_work(fence, semaphore_work, sema); - nouveau_fence_unref(&fence); -- - return 0; - } - -@@ -400,7 +446,7 @@ nouveau_fence_sync(struct nouveau_fence *fence, - nouveau_fence_signalled(fence))) - goto out; - -- sema = alloc_semaphore(dev); -+ sema = semaphore_alloc(dev); - if (!sema) { - /* Early card or broken userspace, fall back to - * software sync. */ -@@ -418,17 +464,17 @@ nouveau_fence_sync(struct nouveau_fence *fence, - } - - /* Make wchan wait until it gets signalled */ -- ret = emit_semaphore(wchan, NV_SW_SEMAPHORE_ACQUIRE, sema); -+ ret = semaphore_acquire(wchan, sema); - if (ret) - goto out_unlock; - - /* Signal the semaphore from chan */ -- ret = emit_semaphore(chan, NV_SW_SEMAPHORE_RELEASE, sema); -+ ret = semaphore_release(chan, sema); - - out_unlock: - mutex_unlock(&chan->mutex); - out_unref: -- kref_put(&sema->ref, free_semaphore); -+ kref_put(&sema->ref, semaphore_free); - out: - if (chan) - nouveau_channel_put_unlocked(&chan); -@@ -449,22 +495,23 @@ nouveau_fence_channel_init(struct nouveau_channel *chan) - struct nouveau_gpuobj *obj = NULL; - int ret; - -+ if (dev_priv->card_type >= NV_C0) -+ goto out_initialised; -+ - /* Create an NV_SW object for various sync purposes */ - ret = nouveau_gpuobj_gr_new(chan, NvSw, NV_SW); - if (ret) - return ret; - - /* we leave subchannel empty for nvc0 */ -- if (dev_priv->card_type < NV_C0) { -- ret = RING_SPACE(chan, 2); -- if (ret) -- return ret; -- BEGIN_RING(chan, NvSubSw, 0, 1); -- OUT_RING(chan, NvSw); -- } -+ ret = RING_SPACE(chan, 2); -+ if (ret) -+ return ret; -+ BEGIN_RING(chan, NvSubSw, 0, 1); -+ OUT_RING(chan, NvSw); - - /* Create a DMA object for the shared cross-channel sync area. */ -- if (USE_SEMA(dev)) { -+ if (USE_SEMA(dev) && dev_priv->chipset < 0x84) { - struct ttm_mem_reg *mem = &dev_priv->fence.bo->bo.mem; - - ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, -@@ -484,14 +531,20 @@ nouveau_fence_channel_init(struct nouveau_channel *chan) - return ret; - BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1); - OUT_RING(chan, NvSema); -+ } else { -+ ret = RING_SPACE(chan, 2); -+ if (ret) -+ return ret; -+ BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1); -+ OUT_RING (chan, chan->vram_handle); /* whole VM */ - } - - FIRE_RING(chan); - -+out_initialised: - INIT_LIST_HEAD(&chan->fence.pending); - spin_lock_init(&chan->fence.lock); - atomic_set(&chan->fence.last_sequence_irq, 0); -- - return 0; - } - -@@ -519,11 +572,12 @@ int - nouveau_fence_init(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -+ int size = (dev_priv->chipset < 0x84) ? 4096 : 16384; - int ret; - - /* Create a shared VRAM heap for cross-channel sync. */ - if (USE_SEMA(dev)) { -- ret = nouveau_bo_new(dev, NULL, 4096, 0, TTM_PL_FLAG_VRAM, -+ ret = nouveau_bo_new(dev, NULL, size, 0, TTM_PL_FLAG_VRAM, - 0, 0, false, true, &dev_priv->fence.bo); - if (ret) - return ret; -diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c -index b0fb9bd..5b769eb 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_mem.c -+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c -@@ -393,11 +393,17 @@ nouveau_mem_vram_init(struct drm_device *dev) - struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; - int ret, dma_bits; - -- if (dev_priv->card_type >= NV_50 && -- pci_dma_supported(dev->pdev, DMA_BIT_MASK(40))) -- dma_bits = 40; -- else -- dma_bits = 32; -+ dma_bits = 32; -+ if (dev_priv->card_type >= NV_50) { -+ if (pci_dma_supported(dev->pdev, DMA_BIT_MASK(40))) -+ dma_bits = 40; -+ } else -+ if (drm_device_is_pcie(dev) && -+ dev_priv->chipset != 0x40 && -+ dev_priv->chipset != 0x45) { -+ if (pci_dma_supported(dev->pdev, DMA_BIT_MASK(39))) -+ dma_bits = 39; -+ } - - ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(dma_bits)); - if (ret) -@@ -419,14 +425,32 @@ nouveau_mem_vram_init(struct drm_device *dev) - } - - /* reserve space at end of VRAM for PRAMIN */ -- if (dev_priv->chipset == 0x40 || dev_priv->chipset == 0x47 || -- dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b) -- dev_priv->ramin_rsvd_vram = (2 * 1024 * 1024); -- else -- if (dev_priv->card_type >= NV_40) -- dev_priv->ramin_rsvd_vram = (1 * 1024 * 1024); -- else -- dev_priv->ramin_rsvd_vram = (512 * 1024); -+ if (dev_priv->card_type >= NV_50) { -+ dev_priv->ramin_rsvd_vram = 1 * 1024 * 1024; -+ } else -+ if (dev_priv->card_type >= NV_40) { -+ u32 vs = hweight8((nv_rd32(dev, 0x001540) & 0x0000ff00) >> 8); -+ u32 rsvd; -+ -+ /* estimate grctx size, the magics come from nv40_grctx.c */ -+ if (dev_priv->chipset == 0x40) rsvd = 0x6aa0 * vs; -+ else if (dev_priv->chipset < 0x43) rsvd = 0x4f00 * vs; -+ else if (nv44_graph_class(dev)) rsvd = 0x4980 * vs; -+ else rsvd = 0x4a40 * vs; -+ rsvd += 16 * 1024; -+ rsvd *= dev_priv->engine.fifo.channels; -+ -+ /* pciegart table */ -+ if (drm_device_is_pcie(dev)) -+ rsvd += 512 * 1024; -+ -+ /* object storage */ -+ rsvd += 512 * 1024; -+ -+ dev_priv->ramin_rsvd_vram = round_up(rsvd, 4096); -+ } else { -+ dev_priv->ramin_rsvd_vram = 512 * 1024; -+ } - - ret = dev_priv->engine.vram.init(dev); - if (ret) -diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c -index 30b6544..3c12461 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_object.c -+++ b/drivers/gpu/drm/nouveau/nouveau_object.c -@@ -490,16 +490,22 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base, - } - - if (target == NV_MEM_TARGET_GART) { -- if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) { -- target = NV_MEM_TARGET_PCI_NOSNOOP; -- base += dev_priv->gart_info.aper_base; -- } else -- if (base != 0) { -- base = nouveau_sgdma_get_physical(dev, base); -+ struct nouveau_gpuobj *gart = dev_priv->gart_info.sg_ctxdma; -+ -+ if (dev_priv->gart_info.type == NOUVEAU_GART_PDMA) { -+ if (base == 0) { -+ nouveau_gpuobj_ref(gart, pobj); -+ return 0; -+ } -+ -+ base = nouveau_sgdma_get_physical(dev, base); - target = NV_MEM_TARGET_PCI; - } else { -- nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, pobj); -- return 0; -+ base += dev_priv->gart_info.aper_base; -+ if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) -+ target = NV_MEM_TARGET_PCI_NOSNOOP; -+ else -+ target = NV_MEM_TARGET_PCI; - } - } - -diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c -index 9a250eb..a26383b 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c -+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c -@@ -74,8 +74,24 @@ nouveau_sgdma_clear(struct ttm_backend *be) - } - } - -+static void -+nouveau_sgdma_destroy(struct ttm_backend *be) -+{ -+ struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; -+ -+ if (be) { -+ NV_DEBUG(nvbe->dev, "\n"); -+ -+ if (nvbe) { -+ if (nvbe->pages) -+ be->func->clear(be); -+ kfree(nvbe); -+ } -+ } -+} -+ - static int --nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) -+nv04_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) - { - struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; - struct drm_device *dev = nvbe->dev; -@@ -102,7 +118,7 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) - } - - static int --nouveau_sgdma_unbind(struct ttm_backend *be) -+nv04_sgdma_unbind(struct ttm_backend *be) - { - struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; - struct drm_device *dev = nvbe->dev; -@@ -125,23 +141,222 @@ nouveau_sgdma_unbind(struct ttm_backend *be) - return 0; - } - -+static struct ttm_backend_func nv04_sgdma_backend = { -+ .populate = nouveau_sgdma_populate, -+ .clear = nouveau_sgdma_clear, -+ .bind = nv04_sgdma_bind, -+ .unbind = nv04_sgdma_unbind, -+ .destroy = nouveau_sgdma_destroy -+}; -+ - static void --nouveau_sgdma_destroy(struct ttm_backend *be) -+nv41_sgdma_flush(struct nouveau_sgdma_be *nvbe) -+{ -+ struct drm_device *dev = nvbe->dev; -+ -+ nv_wr32(dev, 0x100810, 0x00000022); -+ if (!nv_wait(dev, 0x100810, 0x00000100, 0x00000100)) -+ NV_ERROR(dev, "vm flush timeout: 0x%08x\n", -+ nv_rd32(dev, 0x100810)); -+ nv_wr32(dev, 0x100810, 0x00000000); -+} -+ -+static int -+nv41_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) - { - struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; -+ struct drm_nouveau_private *dev_priv = nvbe->dev->dev_private; -+ struct nouveau_gpuobj *pgt = dev_priv->gart_info.sg_ctxdma; -+ dma_addr_t *list = nvbe->pages; -+ u32 pte = mem->start << 2; -+ u32 cnt = nvbe->nr_pages; - -- if (be) { -- NV_DEBUG(nvbe->dev, "\n"); -+ nvbe->offset = mem->start << PAGE_SHIFT; - -- if (nvbe) { -- if (nvbe->pages) -- be->func->clear(be); -- kfree(nvbe); -+ while (cnt--) { -+ nv_wo32(pgt, pte, (*list++ >> 7) | 1); -+ pte += 4; -+ } -+ -+ nv41_sgdma_flush(nvbe); -+ nvbe->bound = true; -+ return 0; -+} -+ -+static int -+nv41_sgdma_unbind(struct ttm_backend *be) -+{ -+ struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; -+ struct drm_nouveau_private *dev_priv = nvbe->dev->dev_private; -+ struct nouveau_gpuobj *pgt = dev_priv->gart_info.sg_ctxdma; -+ u32 pte = (nvbe->offset >> 12) << 2; -+ u32 cnt = nvbe->nr_pages; -+ -+ while (cnt--) { -+ nv_wo32(pgt, pte, 0x00000000); -+ pte += 4; -+ } -+ -+ nv41_sgdma_flush(nvbe); -+ nvbe->bound = false; -+ return 0; -+} -+ -+static struct ttm_backend_func nv41_sgdma_backend = { -+ .populate = nouveau_sgdma_populate, -+ .clear = nouveau_sgdma_clear, -+ .bind = nv41_sgdma_bind, -+ .unbind = nv41_sgdma_unbind, -+ .destroy = nouveau_sgdma_destroy -+}; -+ -+static void -+nv44_sgdma_flush(struct nouveau_sgdma_be *nvbe) -+{ -+ struct drm_device *dev = nvbe->dev; -+ -+ nv_wr32(dev, 0x100814, (nvbe->nr_pages - 1) << 12); -+ nv_wr32(dev, 0x100808, nvbe->offset | 0x20); -+ if (!nv_wait(dev, 0x100808, 0x00000001, 0x00000001)) -+ NV_ERROR(dev, "gart flush timeout: 0x%08x\n", -+ nv_rd32(dev, 0x100808)); -+ nv_wr32(dev, 0x100808, 0x00000000); -+} -+ -+static void -+nv44_sgdma_fill(struct nouveau_gpuobj *pgt, dma_addr_t *list, u32 base, u32 cnt) -+{ -+ struct drm_nouveau_private *dev_priv = pgt->dev->dev_private; -+ dma_addr_t dummy = dev_priv->gart_info.dummy.addr; -+ u32 pte, tmp[4]; -+ -+ pte = base >> 2; -+ base &= ~0x0000000f; -+ -+ tmp[0] = nv_ro32(pgt, base + 0x0); -+ tmp[1] = nv_ro32(pgt, base + 0x4); -+ tmp[2] = nv_ro32(pgt, base + 0x8); -+ tmp[3] = nv_ro32(pgt, base + 0xc); -+ while (cnt--) { -+ u32 addr = list ? (*list++ >> 12) : (dummy >> 12); -+ switch (pte++ & 0x3) { -+ case 0: -+ tmp[0] &= ~0x07ffffff; -+ tmp[0] |= addr; -+ break; -+ case 1: -+ tmp[0] &= ~0xf8000000; -+ tmp[0] |= addr << 27; -+ tmp[1] &= ~0x003fffff; -+ tmp[1] |= addr >> 5; -+ break; -+ case 2: -+ tmp[1] &= ~0xffc00000; -+ tmp[1] |= addr << 22; -+ tmp[2] &= ~0x0001ffff; -+ tmp[2] |= addr >> 10; -+ break; -+ case 3: -+ tmp[2] &= ~0xfffe0000; -+ tmp[2] |= addr << 17; -+ tmp[3] &= ~0x00000fff; -+ tmp[3] |= addr >> 15; -+ break; - } - } -+ -+ tmp[3] |= 0x40000000; -+ -+ nv_wo32(pgt, base + 0x0, tmp[0]); -+ nv_wo32(pgt, base + 0x4, tmp[1]); -+ nv_wo32(pgt, base + 0x8, tmp[2]); -+ nv_wo32(pgt, base + 0xc, tmp[3]); - } - - static int -+nv44_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) -+{ -+ struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; -+ struct drm_nouveau_private *dev_priv = nvbe->dev->dev_private; -+ struct nouveau_gpuobj *pgt = dev_priv->gart_info.sg_ctxdma; -+ dma_addr_t *list = nvbe->pages; -+ u32 pte = mem->start << 2, tmp[4]; -+ u32 cnt = nvbe->nr_pages; -+ int i; -+ -+ nvbe->offset = mem->start << PAGE_SHIFT; -+ -+ if (pte & 0x0000000c) { -+ u32 max = 4 - ((pte >> 2) & 0x3); -+ u32 part = (cnt > max) ? max : cnt; -+ nv44_sgdma_fill(pgt, list, pte, part); -+ pte += (part << 2); -+ list += part; -+ cnt -= part; -+ } -+ -+ while (cnt >= 4) { -+ for (i = 0; i < 4; i++) -+ tmp[i] = *list++ >> 12; -+ nv_wo32(pgt, pte + 0x0, tmp[0] >> 0 | tmp[1] << 27); -+ nv_wo32(pgt, pte + 0x4, tmp[1] >> 5 | tmp[2] << 22); -+ nv_wo32(pgt, pte + 0x8, tmp[2] >> 10 | tmp[3] << 17); -+ nv_wo32(pgt, pte + 0xc, tmp[3] >> 15 | 0x40000000); -+ pte += 0x10; -+ cnt -= 4; -+ } -+ -+ if (cnt) -+ nv44_sgdma_fill(pgt, list, pte, cnt); -+ -+ nv44_sgdma_flush(nvbe); -+ nvbe->bound = true; -+ return 0; -+} -+ -+static int -+nv44_sgdma_unbind(struct ttm_backend *be) -+{ -+ struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; -+ struct drm_nouveau_private *dev_priv = nvbe->dev->dev_private; -+ struct nouveau_gpuobj *pgt = dev_priv->gart_info.sg_ctxdma; -+ u32 pte = (nvbe->offset >> 12) << 2; -+ u32 cnt = nvbe->nr_pages; -+ -+ if (pte & 0x0000000c) { -+ u32 max = 4 - ((pte >> 2) & 0x3); -+ u32 part = (cnt > max) ? max : cnt; -+ nv44_sgdma_fill(pgt, NULL, pte, part); -+ pte += (part << 2); -+ cnt -= part; -+ } -+ -+ while (cnt >= 4) { -+ nv_wo32(pgt, pte + 0x0, 0x00000000); -+ nv_wo32(pgt, pte + 0x4, 0x00000000); -+ nv_wo32(pgt, pte + 0x8, 0x00000000); -+ nv_wo32(pgt, pte + 0xc, 0x00000000); -+ pte += 0x10; -+ cnt -= 4; -+ } -+ -+ if (cnt) -+ nv44_sgdma_fill(pgt, NULL, pte, cnt); -+ -+ nv44_sgdma_flush(nvbe); -+ nvbe->bound = false; -+ return 0; -+} -+ -+static struct ttm_backend_func nv44_sgdma_backend = { -+ .populate = nouveau_sgdma_populate, -+ .clear = nouveau_sgdma_clear, -+ .bind = nv44_sgdma_bind, -+ .unbind = nv44_sgdma_unbind, -+ .destroy = nouveau_sgdma_destroy -+}; -+ -+static int - nv50_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) - { - struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; -@@ -170,14 +385,6 @@ nv50_sgdma_unbind(struct ttm_backend *be) - return 0; - } - --static struct ttm_backend_func nouveau_sgdma_backend = { -- .populate = nouveau_sgdma_populate, -- .clear = nouveau_sgdma_clear, -- .bind = nouveau_sgdma_bind, -- .unbind = nouveau_sgdma_unbind, -- .destroy = nouveau_sgdma_destroy --}; -- - static struct ttm_backend_func nv50_sgdma_backend = { - .populate = nouveau_sgdma_populate, - .clear = nouveau_sgdma_clear, -@@ -198,10 +405,7 @@ nouveau_sgdma_init_ttm(struct drm_device *dev) - - nvbe->dev = dev; - -- if (dev_priv->card_type < NV_50) -- nvbe->backend.func = &nouveau_sgdma_backend; -- else -- nvbe->backend.func = &nv50_sgdma_backend; -+ nvbe->backend.func = dev_priv->gart_info.func; - return &nvbe->backend; - } - -@@ -210,21 +414,70 @@ nouveau_sgdma_init(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpuobj *gpuobj = NULL; -- uint32_t aper_size, obj_size; -- int i, ret; -+ u32 aper_size, align; -+ int ret; -+ -+ if (dev_priv->card_type >= NV_50 || drm_device_is_pcie(dev)) -+ aper_size = 512 * 1024 * 1024; -+ else -+ aper_size = 64 * 1024 * 1024; -+ -+ /* Dear NVIDIA, NV44+ would like proper present bits in PTEs for -+ * christmas. The cards before it have them, the cards after -+ * it have them, why is NV44 so unloved? -+ */ -+ dev_priv->gart_info.dummy.page = alloc_page(GFP_DMA32 | GFP_KERNEL); -+ if (!dev_priv->gart_info.dummy.page) -+ return -ENOMEM; -+ -+ dev_priv->gart_info.dummy.addr = -+ pci_map_page(dev->pdev, dev_priv->gart_info.dummy.page, -+ 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); -+ if (pci_dma_mapping_error(dev->pdev, dev_priv->gart_info.dummy.addr)) { -+ NV_ERROR(dev, "error mapping dummy page\n"); -+ __free_page(dev_priv->gart_info.dummy.page); -+ dev_priv->gart_info.dummy.page = NULL; -+ return -ENOMEM; -+ } - -- if (dev_priv->card_type < NV_50) { -- if(dev_priv->ramin_rsvd_vram < 2 * 1024 * 1024) -- aper_size = 64 * 1024 * 1024; -- else -- aper_size = 512 * 1024 * 1024; -+ if (dev_priv->card_type >= NV_50) { -+ ret = nouveau_vm_get(dev_priv->chan_vm, aper_size, -+ 12, NV_MEM_ACCESS_RW, -+ &dev_priv->gart_info.vma); -+ if (ret) -+ return ret; -+ -+ dev_priv->gart_info.aper_base = dev_priv->gart_info.vma.offset; -+ dev_priv->gart_info.aper_size = aper_size; -+ dev_priv->gart_info.type = NOUVEAU_GART_HW; -+ dev_priv->gart_info.func = &nv50_sgdma_backend; -+ } else -+ if (0 && drm_device_is_pcie(dev) && -+ dev_priv->chipset != 0x40 && dev_priv->chipset != 0x45) { -+ if (nv44_graph_class(dev)) { -+ dev_priv->gart_info.func = &nv44_sgdma_backend; -+ align = 512 * 1024; -+ } else { -+ dev_priv->gart_info.func = &nv41_sgdma_backend; -+ align = 16; -+ } - -- obj_size = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 4; -- obj_size += 8; /* ctxdma header */ -+ ret = nouveau_gpuobj_new(dev, NULL, aper_size / 1024, align, -+ NVOBJ_FLAG_ZERO_ALLOC | -+ NVOBJ_FLAG_ZERO_FREE, &gpuobj); -+ if (ret) { -+ NV_ERROR(dev, "Error creating sgdma object: %d\n", ret); -+ return ret; -+ } - -- ret = nouveau_gpuobj_new(dev, NULL, obj_size, 16, -- NVOBJ_FLAG_ZERO_ALLOC | -- NVOBJ_FLAG_ZERO_FREE, &gpuobj); -+ dev_priv->gart_info.sg_ctxdma = gpuobj; -+ dev_priv->gart_info.aper_base = 0; -+ dev_priv->gart_info.aper_size = aper_size; -+ dev_priv->gart_info.type = NOUVEAU_GART_HW; -+ } else { -+ ret = nouveau_gpuobj_new(dev, NULL, (aper_size / 1024) + 8, 16, -+ NVOBJ_FLAG_ZERO_ALLOC | -+ NVOBJ_FLAG_ZERO_FREE, &gpuobj); - if (ret) { - NV_ERROR(dev, "Error creating sgdma object: %d\n", ret); - return ret; -@@ -236,25 +489,14 @@ nouveau_sgdma_init(struct drm_device *dev) - (0 << 14) /* RW */ | - (2 << 16) /* PCI */); - nv_wo32(gpuobj, 4, aper_size - 1); -- for (i = 2; i < 2 + (aper_size >> 12); i++) -- nv_wo32(gpuobj, i * 4, 0x00000000); - - dev_priv->gart_info.sg_ctxdma = gpuobj; - dev_priv->gart_info.aper_base = 0; - dev_priv->gart_info.aper_size = aper_size; -- } else -- if (dev_priv->chan_vm) { -- ret = nouveau_vm_get(dev_priv->chan_vm, 512 * 1024 * 1024, -- 12, NV_MEM_ACCESS_RW, -- &dev_priv->gart_info.vma); -- if (ret) -- return ret; -- -- dev_priv->gart_info.aper_base = dev_priv->gart_info.vma.offset; -- dev_priv->gart_info.aper_size = 512 * 1024 * 1024; -+ dev_priv->gart_info.type = NOUVEAU_GART_PDMA; -+ dev_priv->gart_info.func = &nv04_sgdma_backend; - } - -- dev_priv->gart_info.type = NOUVEAU_GART_SGDMA; - return 0; - } - -@@ -265,6 +507,13 @@ nouveau_sgdma_takedown(struct drm_device *dev) - - nouveau_gpuobj_ref(NULL, &dev_priv->gart_info.sg_ctxdma); - nouveau_vm_put(&dev_priv->gart_info.vma); -+ -+ if (dev_priv->gart_info.dummy.page) { -+ pci_unmap_page(dev->pdev, dev_priv->gart_info.dummy.addr, -+ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); -+ __free_page(dev_priv->gart_info.dummy.page); -+ dev_priv->gart_info.dummy.page = NULL; -+ } - } - - uint32_t -diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c -index a54fc43..916505d 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_state.c -+++ b/drivers/gpu/drm/nouveau/nouveau_state.c -@@ -929,12 +929,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) - NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n", - dev->pci_vendor, dev->pci_device, dev->pdev->class); - -- dev_priv->wq = create_workqueue("nouveau"); -- if (!dev_priv->wq) { -- ret = -EINVAL; -- goto err_priv; -- } -- - /* resource 0 is mmio regs */ - /* resource 1 is linear FB */ - /* resource 2 is RAMIN (mmio regs + 0x1000000) */ -@@ -947,7 +941,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) - NV_ERROR(dev, "Unable to initialize the mmio mapping. " - "Please report your setup to " DRIVER_EMAIL "\n"); - ret = -EINVAL; -- goto err_wq; -+ goto err_priv; - } - NV_DEBUG(dev, "regs mapped ok at 0x%llx\n", - (unsigned long long)mmio_start_offs); -@@ -1054,8 +1048,6 @@ err_ramin: - iounmap(dev_priv->ramin); - err_mmio: - iounmap(dev_priv->mmio); --err_wq: -- destroy_workqueue(dev_priv->wq); - err_priv: - kfree(dev_priv); - dev->dev_private = NULL; -diff --git a/drivers/gpu/drm/nouveau/nouveau_temp.c b/drivers/gpu/drm/nouveau/nouveau_temp.c -index 8d9968e..649b041 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_temp.c -+++ b/drivers/gpu/drm/nouveau/nouveau_temp.c -@@ -239,11 +239,9 @@ static bool - probe_monitoring_device(struct nouveau_i2c_chan *i2c, - struct i2c_board_info *info) - { -- char modalias[16] = "i2c:"; - struct i2c_client *client; - -- strlcat(modalias, info->type, sizeof(modalias)); -- request_module(modalias); -+ request_module("%s%s", I2C_MODULE_PREFIX, info->type); - - client = i2c_new_device(&i2c->adapter, info); - if (!client) -diff --git a/drivers/gpu/drm/nouveau/nouveau_util.c b/drivers/gpu/drm/nouveau/nouveau_util.c -index fbe0fb1..e51b515 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_util.c -+++ b/drivers/gpu/drm/nouveau/nouveau_util.c -@@ -47,18 +47,27 @@ nouveau_bitfield_print(const struct nouveau_bitfield *bf, u32 value) - printk(" (unknown bits 0x%08x)", value); - } - --void --nouveau_enum_print(const struct nouveau_enum *en, u32 value) -+const struct nouveau_enum * -+nouveau_enum_find(const struct nouveau_enum *en, u32 value) - { - while (en->name) { -- if (value == en->value) { -- printk("%s", en->name); -- return; -- } -- -+ if (en->value == value) -+ return en; - en++; - } - -+ return NULL; -+} -+ -+void -+nouveau_enum_print(const struct nouveau_enum *en, u32 value) -+{ -+ en = nouveau_enum_find(en, value); -+ if (en) { -+ printk("%s", en->name); -+ return; -+ } -+ - printk("(unknown enum 0x%08x)", value); - } - -diff --git a/drivers/gpu/drm/nouveau/nouveau_util.h b/drivers/gpu/drm/nouveau/nouveau_util.h -index d9ceaea..b97719f 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_util.h -+++ b/drivers/gpu/drm/nouveau/nouveau_util.h -@@ -36,10 +36,14 @@ struct nouveau_bitfield { - struct nouveau_enum { - u32 value; - const char *name; -+ void *data; - }; - - void nouveau_bitfield_print(const struct nouveau_bitfield *, u32 value); - void nouveau_enum_print(const struct nouveau_enum *, u32 value); -+const struct nouveau_enum * -+nouveau_enum_find(const struct nouveau_enum *, u32 value); -+ - int nouveau_ratelimit(void); - - #endif -diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.c b/drivers/gpu/drm/nouveau/nouveau_vm.c -index 97d82ae..b4658f7 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_vm.c -+++ b/drivers/gpu/drm/nouveau/nouveau_vm.c -@@ -311,18 +311,7 @@ nouveau_vm_new(struct drm_device *dev, u64 offset, u64 length, u64 mm_offset, - vm->spg_shift = 12; - vm->lpg_shift = 17; - pgt_bits = 27; -- -- /* Should be 4096 everywhere, this is a hack that's -- * currently necessary to avoid an elusive bug that -- * causes corruption when mixing small/large pages -- */ -- if (length < (1ULL << 40)) -- block = 4096; -- else { -- block = (1 << pgt_bits); -- if (length < block) -- block = length; -- } -+ block = 4096; - } else { - kfree(vm); - return -ENOSYS; -diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c -index f89d104..db465a3 100644 ---- a/drivers/gpu/drm/nouveau/nv04_fifo.c -+++ b/drivers/gpu/drm/nouveau/nv04_fifo.c -@@ -379,6 +379,15 @@ out: - return handled; - } - -+static const char *nv_dma_state_err(u32 state) -+{ -+ static const char * const desc[] = { -+ "NONE", "CALL_SUBR_ACTIVE", "INVALID_MTHD", "RET_SUBR_INACTIVE", -+ "INVALID_CMD", "IB_EMPTY"/* NV50+ */, "MEM_FAULT", "UNK" -+ }; -+ return desc[(state >> 29) & 0x7]; -+} -+ - void - nv04_fifo_isr(struct drm_device *dev) - { -@@ -460,9 +469,10 @@ nv04_fifo_isr(struct drm_device *dev) - if (nouveau_ratelimit()) - NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x " - "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x " -- "State 0x%08x Push 0x%08x\n", -+ "State 0x%08x (err: %s) Push 0x%08x\n", - chid, ho_get, dma_get, ho_put, - dma_put, ib_get, ib_put, state, -+ nv_dma_state_err(state), - push); - - /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ -@@ -476,8 +486,9 @@ nv04_fifo_isr(struct drm_device *dev) - } - } else { - NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x " -- "Put 0x%08x State 0x%08x Push 0x%08x\n", -- chid, dma_get, dma_put, state, push); -+ "Put 0x%08x State 0x%08x (err: %s) Push 0x%08x\n", -+ chid, dma_get, dma_put, state, -+ nv_dma_state_err(state), push); - - if (dma_get != dma_put) - nv_wr32(dev, 0x003244, dma_put); -@@ -505,7 +516,7 @@ nv04_fifo_isr(struct drm_device *dev) - - if (dev_priv->card_type == NV_50) { - if (status & 0x00000010) { -- nv50_fb_vm_trap(dev, 1, "PFIFO_BAR_FAULT"); -+ nv50_fb_vm_trap(dev, nouveau_ratelimit()); - status &= ~0x00000010; - nv_wr32(dev, 0x002100, 0x00000010); - } -diff --git a/drivers/gpu/drm/nouveau/nv40_fb.c b/drivers/gpu/drm/nouveau/nv40_fb.c -index f3d9c05..f0ac2a7 100644 ---- a/drivers/gpu/drm/nouveau/nv40_fb.c -+++ b/drivers/gpu/drm/nouveau/nv40_fb.c -@@ -24,6 +24,53 @@ nv40_fb_set_tile_region(struct drm_device *dev, int i) - } - } - -+static void -+nv40_fb_init_gart(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_gpuobj *gart = dev_priv->gart_info.sg_ctxdma; -+ -+ if (dev_priv->gart_info.type != NOUVEAU_GART_HW) { -+ nv_wr32(dev, 0x100800, 0x00000001); -+ return; -+ } -+ -+ nv_wr32(dev, 0x100800, gart->pinst | 0x00000002); -+ nv_mask(dev, 0x10008c, 0x00000100, 0x00000100); -+ nv_wr32(dev, 0x100820, 0x00000000); -+} -+ -+static void -+nv44_fb_init_gart(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_gpuobj *gart = dev_priv->gart_info.sg_ctxdma; -+ u32 vinst; -+ -+ if (dev_priv->gart_info.type != NOUVEAU_GART_HW) { -+ nv_wr32(dev, 0x100850, 0x80000000); -+ nv_wr32(dev, 0x100800, 0x00000001); -+ return; -+ } -+ -+ /* calculate vram address of this PRAMIN block, object -+ * must be allocated on 512KiB alignment, and not exceed -+ * a total size of 512KiB for this to work correctly -+ */ -+ vinst = nv_rd32(dev, 0x10020c); -+ vinst -= ((gart->pinst >> 19) + 1) << 19; -+ -+ nv_wr32(dev, 0x100850, 0x80000000); -+ nv_wr32(dev, 0x100818, dev_priv->gart_info.dummy.addr); -+ -+ nv_wr32(dev, 0x100804, dev_priv->gart_info.aper_size); -+ nv_wr32(dev, 0x100850, 0x00008000); -+ nv_mask(dev, 0x10008c, 0x00000200, 0x00000200); -+ nv_wr32(dev, 0x100820, 0x00000000); -+ nv_wr32(dev, 0x10082c, 0x00000001); -+ nv_wr32(dev, 0x100800, vinst | 0x00000010); -+} -+ - int - nv40_fb_init(struct drm_device *dev) - { -@@ -32,12 +79,12 @@ nv40_fb_init(struct drm_device *dev) - uint32_t tmp; - int i; - -- /* This is strictly a NV4x register (don't know about NV5x). */ -- /* The blob sets these to all kinds of values, and they mess up our setup. */ -- /* I got value 0x52802 instead. For some cards the blob even sets it back to 0x1. */ -- /* Note: the blob doesn't read this value, so i'm pretty sure this is safe for all cards. */ -- /* Any idea what this is? */ -- nv_wr32(dev, NV40_PFB_UNK_800, 0x1); -+ if (dev_priv->chipset != 0x40 && dev_priv->chipset != 0x45) { -+ if (nv44_graph_class(dev)) -+ nv44_fb_init_gart(dev); -+ else -+ nv40_fb_init_gart(dev); -+ } - - switch (dev_priv->chipset) { - case 0x40: -diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c -index 7cc94ed..a804a35 100644 ---- a/drivers/gpu/drm/nouveau/nv50_display.c -+++ b/drivers/gpu/drm/nouveau/nv50_display.c -@@ -345,12 +345,15 @@ int nv50_display_create(struct drm_device *dev) - void - nv50_display_destroy(struct drm_device *dev) - { -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ - NV_DEBUG_KMS(dev, "\n"); - - drm_mode_config_cleanup(dev); - - nv50_display_disable(dev); - nouveau_irq_unregister(dev, 26); -+ flush_work_sync(&dev_priv->irq_work); - } - - static u16 -@@ -587,7 +590,7 @@ static void - nv50_display_unk20_handler(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- u32 unk30 = nv_rd32(dev, 0x610030), tmp, pclk, script, mc; -+ u32 unk30 = nv_rd32(dev, 0x610030), tmp, pclk, script, mc = 0; - struct dcb_entry *dcb; - int i, crtc, or, type = OUTPUT_ANY; - -@@ -836,7 +839,7 @@ nv50_display_isr(struct drm_device *dev) - if (clock) { - nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); - if (!work_pending(&dev_priv->irq_work)) -- queue_work(dev_priv->wq, &dev_priv->irq_work); -+ schedule_work(&dev_priv->irq_work); - delayed |= clock; - intr1 &= ~clock; - } -diff --git a/drivers/gpu/drm/nouveau/nv50_fb.c b/drivers/gpu/drm/nouveau/nv50_fb.c -index 50290de..efc8cd4 100644 ---- a/drivers/gpu/drm/nouveau/nv50_fb.c -+++ b/drivers/gpu/drm/nouveau/nv50_fb.c -@@ -95,12 +95,109 @@ nv50_fb_takedown(struct drm_device *dev) - kfree(priv); - } - -+static struct nouveau_enum vm_dispatch_subclients[] = { -+ { 0x00000000, "GRCTX", NULL }, -+ { 0x00000001, "NOTIFY", NULL }, -+ { 0x00000002, "QUERY", NULL }, -+ { 0x00000003, "COND", NULL }, -+ { 0x00000004, "M2M_IN", NULL }, -+ { 0x00000005, "M2M_OUT", NULL }, -+ { 0x00000006, "M2M_NOTIFY", NULL }, -+ {} -+}; -+ -+static struct nouveau_enum vm_ccache_subclients[] = { -+ { 0x00000000, "CB", NULL }, -+ { 0x00000001, "TIC", NULL }, -+ { 0x00000002, "TSC", NULL }, -+ {} -+}; -+ -+static struct nouveau_enum vm_prop_subclients[] = { -+ { 0x00000000, "RT0", NULL }, -+ { 0x00000001, "RT1", NULL }, -+ { 0x00000002, "RT2", NULL }, -+ { 0x00000003, "RT3", NULL }, -+ { 0x00000004, "RT4", NULL }, -+ { 0x00000005, "RT5", NULL }, -+ { 0x00000006, "RT6", NULL }, -+ { 0x00000007, "RT7", NULL }, -+ { 0x00000008, "ZETA", NULL }, -+ { 0x00000009, "LOCAL", NULL }, -+ { 0x0000000a, "GLOBAL", NULL }, -+ { 0x0000000b, "STACK", NULL }, -+ { 0x0000000c, "DST2D", NULL }, -+ {} -+}; -+ -+static struct nouveau_enum vm_pfifo_subclients[] = { -+ { 0x00000000, "PUSHBUF", NULL }, -+ { 0x00000001, "SEMAPHORE", NULL }, -+ {} -+}; -+ -+static struct nouveau_enum vm_bar_subclients[] = { -+ { 0x00000000, "FB", NULL }, -+ { 0x00000001, "IN", NULL }, -+ {} -+}; -+ -+static struct nouveau_enum vm_client[] = { -+ { 0x00000000, "STRMOUT", NULL }, -+ { 0x00000003, "DISPATCH", vm_dispatch_subclients }, -+ { 0x00000004, "PFIFO_WRITE", NULL }, -+ { 0x00000005, "CCACHE", vm_ccache_subclients }, -+ { 0x00000006, "PPPP", NULL }, -+ { 0x00000007, "CLIPID", NULL }, -+ { 0x00000008, "PFIFO_READ", NULL }, -+ { 0x00000009, "VFETCH", NULL }, -+ { 0x0000000a, "TEXTURE", NULL }, -+ { 0x0000000b, "PROP", vm_prop_subclients }, -+ { 0x0000000c, "PVP", NULL }, -+ { 0x0000000d, "PBSP", NULL }, -+ { 0x0000000e, "PCRYPT", NULL }, -+ { 0x0000000f, "PCOUNTER", NULL }, -+ { 0x00000011, "PDAEMON", NULL }, -+ {} -+}; -+ -+static struct nouveau_enum vm_engine[] = { -+ { 0x00000000, "PGRAPH", NULL }, -+ { 0x00000001, "PVP", NULL }, -+ { 0x00000004, "PEEPHOLE", NULL }, -+ { 0x00000005, "PFIFO", vm_pfifo_subclients }, -+ { 0x00000006, "BAR", vm_bar_subclients }, -+ { 0x00000008, "PPPP", NULL }, -+ { 0x00000009, "PBSP", NULL }, -+ { 0x0000000a, "PCRYPT", NULL }, -+ { 0x0000000b, "PCOUNTER", NULL }, -+ { 0x0000000c, "SEMAPHORE_BG", NULL }, -+ { 0x0000000d, "PCOPY", NULL }, -+ { 0x0000000e, "PDAEMON", NULL }, -+ {} -+}; -+ -+static struct nouveau_enum vm_fault[] = { -+ { 0x00000000, "PT_NOT_PRESENT", NULL }, -+ { 0x00000001, "PT_TOO_SHORT", NULL }, -+ { 0x00000002, "PAGE_NOT_PRESENT", NULL }, -+ { 0x00000003, "PAGE_SYSTEM_ONLY", NULL }, -+ { 0x00000004, "PAGE_READ_ONLY", NULL }, -+ { 0x00000006, "NULL_DMAOBJ", NULL }, -+ { 0x00000007, "WRONG_MEMTYPE", NULL }, -+ { 0x0000000b, "VRAM_LIMIT", NULL }, -+ { 0x0000000f, "DMAOBJ_LIMIT", NULL }, -+ {} -+}; -+ - void --nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name) -+nv50_fb_vm_trap(struct drm_device *dev, int display) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -+ const struct nouveau_enum *en, *cl; - unsigned long flags; - u32 trap[6], idx, chinst; -+ u8 st0, st1, st2, st3; - int i, ch; - - idx = nv_rd32(dev, 0x100c90); -@@ -117,8 +214,8 @@ nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name) - if (!display) - return; - -+ /* lookup channel id */ - chinst = (trap[2] << 16) | trap[1]; -- - spin_lock_irqsave(&dev_priv->channels.lock, flags); - for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) { - struct nouveau_channel *chan = dev_priv->channels.ptr[ch]; -@@ -131,9 +228,48 @@ nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name) - } - spin_unlock_irqrestore(&dev_priv->channels.lock, flags); - -- NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x " -- "channel %d (0x%08x)\n", -- name, (trap[5] & 0x100 ? "read" : "write"), -- trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, -- trap[0], ch, chinst); -+ /* decode status bits into something more useful */ -+ if (dev_priv->chipset < 0xa3 || -+ dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) { -+ st0 = (trap[0] & 0x0000000f) >> 0; -+ st1 = (trap[0] & 0x000000f0) >> 4; -+ st2 = (trap[0] & 0x00000f00) >> 8; -+ st3 = (trap[0] & 0x0000f000) >> 12; -+ } else { -+ st0 = (trap[0] & 0x000000ff) >> 0; -+ st1 = (trap[0] & 0x0000ff00) >> 8; -+ st2 = (trap[0] & 0x00ff0000) >> 16; -+ st3 = (trap[0] & 0xff000000) >> 24; -+ } -+ -+ NV_INFO(dev, "VM: trapped %s at 0x%02x%04x%04x on ch %d [0x%08x] ", -+ (trap[5] & 0x00000100) ? "read" : "write", -+ trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, ch, chinst); -+ -+ en = nouveau_enum_find(vm_engine, st0); -+ if (en) -+ printk("%s/", en->name); -+ else -+ printk("%02x/", st0); -+ -+ cl = nouveau_enum_find(vm_client, st2); -+ if (cl) -+ printk("%s/", cl->name); -+ else -+ printk("%02x/", st2); -+ -+ if (cl && cl->data) cl = nouveau_enum_find(cl->data, st3); -+ else if (en && en->data) cl = nouveau_enum_find(en->data, st3); -+ else cl = NULL; -+ if (cl) -+ printk("%s", cl->name); -+ else -+ printk("%02x", st3); -+ -+ printk(" reason: "); -+ en = nouveau_enum_find(vm_fault, st1); -+ if (en) -+ printk("%s\n", en->name); -+ else -+ printk("0x%08x\n", st1); - } -diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c -index 8dd04c5..c34a074 100644 ---- a/drivers/gpu/drm/nouveau/nv50_fifo.c -+++ b/drivers/gpu/drm/nouveau/nv50_fifo.c -@@ -149,6 +149,7 @@ nv50_fifo_init_regs(struct drm_device *dev) - nv_wr32(dev, 0x3204, 0); - nv_wr32(dev, 0x3210, 0); - nv_wr32(dev, 0x3270, 0); -+ nv_wr32(dev, 0x2044, 0x01003fff); - - /* Enable dummy channels setup by nv50_instmem.c */ - nv50_fifo_channel_enable(dev, 0); -@@ -273,7 +274,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan) - nv_wo32(ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | - (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj->cinst >> 4)); -- nv_wo32(ramfc, 0x44, 0x2101ffff); -+ nv_wo32(ramfc, 0x44, 0x01003fff); - nv_wo32(ramfc, 0x60, 0x7fffffff); - nv_wo32(ramfc, 0x40, 0x00000000); - nv_wo32(ramfc, 0x7c, 0x30000001); -diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c -index 6b149c0..d4f4206 100644 ---- a/drivers/gpu/drm/nouveau/nv50_gpio.c -+++ b/drivers/gpu/drm/nouveau/nv50_gpio.c -@@ -137,6 +137,7 @@ nv50_gpio_irq_unregister(struct drm_device *dev, enum dcb_gpio_tag tag, - struct nv50_gpio_priv *priv = pgpio->priv; - struct nv50_gpio_handler *gpioh, *tmp; - struct dcb_gpio_entry *gpio; -+ LIST_HEAD(tofree); - unsigned long flags; - - gpio = nouveau_bios_gpio_entry(dev, tag); -@@ -149,10 +150,14 @@ nv50_gpio_irq_unregister(struct drm_device *dev, enum dcb_gpio_tag tag, - gpioh->handler != handler || - gpioh->data != data) - continue; -- list_del(&gpioh->head); -- kfree(gpioh); -+ list_move(&gpioh->head, &tofree); - } - spin_unlock_irqrestore(&priv->lock, flags); -+ -+ list_for_each_entry_safe(gpioh, tmp, &tofree, head) { -+ flush_work_sync(&gpioh->work); -+ kfree(gpioh); -+ } - } - - bool -@@ -205,7 +210,6 @@ nv50_gpio_init(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; -- struct nv50_gpio_priv *priv; - int ret; - - if (!pgpio->priv) { -@@ -213,7 +217,6 @@ nv50_gpio_init(struct drm_device *dev) - if (ret) - return ret; - } -- priv = pgpio->priv; - - /* disable, and ack any pending gpio interrupts */ - nv_wr32(dev, 0xe050, 0x00000000); -@@ -293,7 +296,7 @@ nv50_gpio_isr(struct drm_device *dev) - continue; - gpioh->inhibit = true; - -- queue_work(dev_priv->wq, &gpioh->work); -+ schedule_work(&gpioh->work); - } - spin_unlock(&priv->lock); - } -diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c -index 37e21d2..a32b301 100644 ---- a/drivers/gpu/drm/nouveau/nv50_graph.c -+++ b/drivers/gpu/drm/nouveau/nv50_graph.c -@@ -95,13 +95,41 @@ nv50_graph_init_regs__nv(struct drm_device *dev) - } - - static void --nv50_graph_init_regs(struct drm_device *dev) -+nv50_graph_init_zcull(struct drm_device *dev) - { -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ int i; -+ - NV_DEBUG(dev, "\n"); - -- nv_wr32(dev, NV04_PGRAPH_DEBUG_3, -- (1 << 2) /* HW_CONTEXT_SWITCH_ENABLED */); -- nv_wr32(dev, 0x402ca8, 0x800); -+ switch (dev_priv->chipset & 0xf0) { -+ case 0x50: -+ case 0x80: -+ case 0x90: -+ nv_wr32(dev, 0x402ca8, 0x00000800); -+ break; -+ case 0xa0: -+ default: -+ nv_wr32(dev, 0x402cc0, 0x00000000); -+ if (dev_priv->chipset == 0xa0 || -+ dev_priv->chipset == 0xaa || -+ dev_priv->chipset == 0xac) { -+ nv_wr32(dev, 0x402ca8, 0x00000802); -+ } else { -+ nv_wr32(dev, 0x402cc0, 0x00000000); -+ nv_wr32(dev, 0x402ca8, 0x00000002); -+ } -+ -+ break; -+ } -+ -+ /* zero out zcull regions */ -+ for (i = 0; i < 8; i++) { -+ nv_wr32(dev, 0x402c20 + (i * 8), 0x00000000); -+ nv_wr32(dev, 0x402c24 + (i * 8), 0x00000000); -+ nv_wr32(dev, 0x402c28 + (i * 8), 0x00000000); -+ nv_wr32(dev, 0x402c2c + (i * 8), 0x00000000); -+ } - } - - static int -@@ -136,6 +164,7 @@ nv50_graph_init_ctxctl(struct drm_device *dev) - } - kfree(cp); - -+ nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */ - nv_wr32(dev, 0x400320, 4); - nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0); - nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, 0); -@@ -151,7 +180,7 @@ nv50_graph_init(struct drm_device *dev) - - nv50_graph_init_reset(dev); - nv50_graph_init_regs__nv(dev); -- nv50_graph_init_regs(dev); -+ nv50_graph_init_zcull(dev); - - ret = nv50_graph_init_ctxctl(dev); - if (ret) -@@ -526,11 +555,11 @@ nv86_graph_tlb_flush(struct drm_device *dev) - - static struct nouveau_enum nv50_mp_exec_error_names[] = - { -- { 3, "STACK_UNDERFLOW" }, -- { 4, "QUADON_ACTIVE" }, -- { 8, "TIMEOUT" }, -- { 0x10, "INVALID_OPCODE" }, -- { 0x40, "BREAKPOINT" }, -+ { 3, "STACK_UNDERFLOW", NULL }, -+ { 4, "QUADON_ACTIVE", NULL }, -+ { 8, "TIMEOUT", NULL }, -+ { 0x10, "INVALID_OPCODE", NULL }, -+ { 0x40, "BREAKPOINT", NULL }, - {} - }; - -@@ -558,47 +587,47 @@ static struct nouveau_bitfield nv50_graph_trap_ccache[] = { - - /* There must be a *lot* of these. Will take some time to gather them up. */ - struct nouveau_enum nv50_data_error_names[] = { -- { 0x00000003, "INVALID_QUERY_OR_TEXTURE" }, -- { 0x00000004, "INVALID_VALUE" }, -- { 0x00000005, "INVALID_ENUM" }, -- { 0x00000008, "INVALID_OBJECT" }, -- { 0x00000009, "READ_ONLY_OBJECT" }, -- { 0x0000000a, "SUPERVISOR_OBJECT" }, -- { 0x0000000b, "INVALID_ADDRESS_ALIGNMENT" }, -- { 0x0000000c, "INVALID_BITFIELD" }, -- { 0x0000000d, "BEGIN_END_ACTIVE" }, -- { 0x0000000e, "SEMANTIC_COLOR_BACK_OVER_LIMIT" }, -- { 0x0000000f, "VIEWPORT_ID_NEEDS_GP" }, -- { 0x00000010, "RT_DOUBLE_BIND" }, -- { 0x00000011, "RT_TYPES_MISMATCH" }, -- { 0x00000012, "RT_LINEAR_WITH_ZETA" }, -- { 0x00000015, "FP_TOO_FEW_REGS" }, -- { 0x00000016, "ZETA_FORMAT_CSAA_MISMATCH" }, -- { 0x00000017, "RT_LINEAR_WITH_MSAA" }, -- { 0x00000018, "FP_INTERPOLANT_START_OVER_LIMIT" }, -- { 0x00000019, "SEMANTIC_LAYER_OVER_LIMIT" }, -- { 0x0000001a, "RT_INVALID_ALIGNMENT" }, -- { 0x0000001b, "SAMPLER_OVER_LIMIT" }, -- { 0x0000001c, "TEXTURE_OVER_LIMIT" }, -- { 0x0000001e, "GP_TOO_MANY_OUTPUTS" }, -- { 0x0000001f, "RT_BPP128_WITH_MS8" }, -- { 0x00000021, "Z_OUT_OF_BOUNDS" }, -- { 0x00000023, "XY_OUT_OF_BOUNDS" }, -- { 0x00000027, "CP_MORE_PARAMS_THAN_SHARED" }, -- { 0x00000028, "CP_NO_REG_SPACE_STRIPED" }, -- { 0x00000029, "CP_NO_REG_SPACE_PACKED" }, -- { 0x0000002a, "CP_NOT_ENOUGH_WARPS" }, -- { 0x0000002b, "CP_BLOCK_SIZE_MISMATCH" }, -- { 0x0000002c, "CP_NOT_ENOUGH_LOCAL_WARPS" }, -- { 0x0000002d, "CP_NOT_ENOUGH_STACK_WARPS" }, -- { 0x0000002e, "CP_NO_BLOCKDIM_LATCH" }, -- { 0x00000031, "ENG2D_FORMAT_MISMATCH" }, -- { 0x0000003f, "PRIMITIVE_ID_NEEDS_GP" }, -- { 0x00000044, "SEMANTIC_VIEWPORT_OVER_LIMIT" }, -- { 0x00000045, "SEMANTIC_COLOR_FRONT_OVER_LIMIT" }, -- { 0x00000046, "LAYER_ID_NEEDS_GP" }, -- { 0x00000047, "SEMANTIC_CLIP_OVER_LIMIT" }, -- { 0x00000048, "SEMANTIC_PTSZ_OVER_LIMIT" }, -+ { 0x00000003, "INVALID_QUERY_OR_TEXTURE", NULL }, -+ { 0x00000004, "INVALID_VALUE", NULL }, -+ { 0x00000005, "INVALID_ENUM", NULL }, -+ { 0x00000008, "INVALID_OBJECT", NULL }, -+ { 0x00000009, "READ_ONLY_OBJECT", NULL }, -+ { 0x0000000a, "SUPERVISOR_OBJECT", NULL }, -+ { 0x0000000b, "INVALID_ADDRESS_ALIGNMENT", NULL }, -+ { 0x0000000c, "INVALID_BITFIELD", NULL }, -+ { 0x0000000d, "BEGIN_END_ACTIVE", NULL }, -+ { 0x0000000e, "SEMANTIC_COLOR_BACK_OVER_LIMIT", NULL }, -+ { 0x0000000f, "VIEWPORT_ID_NEEDS_GP", NULL }, -+ { 0x00000010, "RT_DOUBLE_BIND", NULL }, -+ { 0x00000011, "RT_TYPES_MISMATCH", NULL }, -+ { 0x00000012, "RT_LINEAR_WITH_ZETA", NULL }, -+ { 0x00000015, "FP_TOO_FEW_REGS", NULL }, -+ { 0x00000016, "ZETA_FORMAT_CSAA_MISMATCH", NULL }, -+ { 0x00000017, "RT_LINEAR_WITH_MSAA", NULL }, -+ { 0x00000018, "FP_INTERPOLANT_START_OVER_LIMIT", NULL }, -+ { 0x00000019, "SEMANTIC_LAYER_OVER_LIMIT", NULL }, -+ { 0x0000001a, "RT_INVALID_ALIGNMENT", NULL }, -+ { 0x0000001b, "SAMPLER_OVER_LIMIT", NULL }, -+ { 0x0000001c, "TEXTURE_OVER_LIMIT", NULL }, -+ { 0x0000001e, "GP_TOO_MANY_OUTPUTS", NULL }, -+ { 0x0000001f, "RT_BPP128_WITH_MS8", NULL }, -+ { 0x00000021, "Z_OUT_OF_BOUNDS", NULL }, -+ { 0x00000023, "XY_OUT_OF_BOUNDS", NULL }, -+ { 0x00000027, "CP_MORE_PARAMS_THAN_SHARED", NULL }, -+ { 0x00000028, "CP_NO_REG_SPACE_STRIPED", NULL }, -+ { 0x00000029, "CP_NO_REG_SPACE_PACKED", NULL }, -+ { 0x0000002a, "CP_NOT_ENOUGH_WARPS", NULL }, -+ { 0x0000002b, "CP_BLOCK_SIZE_MISMATCH", NULL }, -+ { 0x0000002c, "CP_NOT_ENOUGH_LOCAL_WARPS", NULL }, -+ { 0x0000002d, "CP_NOT_ENOUGH_STACK_WARPS", NULL }, -+ { 0x0000002e, "CP_NO_BLOCKDIM_LATCH", NULL }, -+ { 0x00000031, "ENG2D_FORMAT_MISMATCH", NULL }, -+ { 0x0000003f, "PRIMITIVE_ID_NEEDS_GP", NULL }, -+ { 0x00000044, "SEMANTIC_VIEWPORT_OVER_LIMIT", NULL }, -+ { 0x00000045, "SEMANTIC_COLOR_FRONT_OVER_LIMIT", NULL }, -+ { 0x00000046, "LAYER_ID_NEEDS_GP", NULL }, -+ { 0x00000047, "SEMANTIC_CLIP_OVER_LIMIT", NULL }, -+ { 0x00000048, "SEMANTIC_PTSZ_OVER_LIMIT", NULL }, - {} - }; - -@@ -678,7 +707,6 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, - tps++; - switch (type) { - case 6: /* texture error... unknown for now */ -- nv50_fb_vm_trap(dev, display, name); - if (display) { - NV_ERROR(dev, "magic set %d:\n", i); - for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4) -@@ -701,7 +729,6 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, - uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14); - uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18); - uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c); -- nv50_fb_vm_trap(dev, display, name); - /* 2d engine destination */ - if (ustatus & 0x00000010) { - if (display) { -@@ -912,10 +939,10 @@ nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid - printk("\n"); - NV_INFO(dev, "PGRAPH - TRAP_CCACHE %08x %08x %08x %08x" - " %08x %08x %08x\n", -- nv_rd32(dev, 0x405800), nv_rd32(dev, 0x405804), -- nv_rd32(dev, 0x405808), nv_rd32(dev, 0x40580c), -- nv_rd32(dev, 0x405810), nv_rd32(dev, 0x405814), -- nv_rd32(dev, 0x40581c)); -+ nv_rd32(dev, 0x405000), nv_rd32(dev, 0x405004), -+ nv_rd32(dev, 0x405008), nv_rd32(dev, 0x40500c), -+ nv_rd32(dev, 0x405010), nv_rd32(dev, 0x405014), -+ nv_rd32(dev, 0x40501c)); - - } - -@@ -1044,6 +1071,7 @@ nv50_graph_isr(struct drm_device *dev) - NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) subc %d " - "class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, inst, subc, class, mthd, data); -+ nv50_fb_vm_trap(dev, 1); - } - } - -diff --git a/drivers/gpu/drm/nouveau/nv50_vm.c b/drivers/gpu/drm/nouveau/nv50_vm.c -index 6144156..1f47c75 100644 ---- a/drivers/gpu/drm/nouveau/nv50_vm.c -+++ b/drivers/gpu/drm/nouveau/nv50_vm.c -@@ -31,7 +31,6 @@ void - nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde, - struct nouveau_gpuobj *pgt[2]) - { -- struct drm_nouveau_private *dev_priv = pgd->dev->dev_private; - u64 phys = 0xdeadcafe00000000ULL; - u32 coverage = 0; - -diff --git a/drivers/gpu/drm/nouveau/nv84_crypt.c b/drivers/gpu/drm/nouveau/nv84_crypt.c -index ec18ae1..fabc7fd 100644 ---- a/drivers/gpu/drm/nouveau/nv84_crypt.c -+++ b/drivers/gpu/drm/nouveau/nv84_crypt.c -@@ -136,5 +136,5 @@ nv84_crypt_isr(struct drm_device *dev) - nv_wr32(dev, 0x102130, stat); - nv_wr32(dev, 0x10200c, 0x10); - -- nv50_fb_vm_trap(dev, show, "PCRYPT"); -+ nv50_fb_vm_trap(dev, show); - } -diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c -index e6f92c5..e9f8643 100644 ---- a/drivers/gpu/drm/nouveau/nvc0_fifo.c -+++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c -@@ -418,6 +418,12 @@ nvc0_fifo_isr(struct drm_device *dev) - { - u32 stat = nv_rd32(dev, 0x002100); - -+ if (stat & 0x00000100) { -+ NV_INFO(dev, "PFIFO: unknown status 0x00000100\n"); -+ nv_wr32(dev, 0x002100, 0x00000100); -+ stat &= ~0x00000100; -+ } -+ - if (stat & 0x10000000) { - u32 units = nv_rd32(dev, 0x00259c); - u32 u = units; -@@ -446,10 +452,15 @@ nvc0_fifo_isr(struct drm_device *dev) - stat &= ~0x20000000; - } - -+ if (stat & 0x40000000) { -+ NV_INFO(dev, "PFIFO: unknown status 0x40000000\n"); -+ nv_mask(dev, 0x002a00, 0x00000000, 0x00000000); -+ stat &= ~0x40000000; -+ } -+ - if (stat) { - NV_INFO(dev, "PFIFO: unhandled status 0x%08x\n", stat); - nv_wr32(dev, 0x002100, stat); -+ nv_wr32(dev, 0x002140, 0); - } -- -- nv_wr32(dev, 0x2140, 0); - } -diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c -index eb18a7e..afa7afe 100644 ---- a/drivers/gpu/drm/nouveau/nvc0_graph.c -+++ b/drivers/gpu/drm/nouveau/nvc0_graph.c -@@ -640,7 +640,6 @@ nvc0_graph_init(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; -- struct nvc0_graph_priv *priv; - int ret; - - dev_priv->engine.graph.accel_blocked = true; -@@ -665,7 +664,6 @@ nvc0_graph_init(struct drm_device *dev) - if (ret) - return ret; - } -- priv = pgraph->priv; - - nvc0_graph_init_obj418880(dev); - nvc0_graph_init_regs(dev); diff --git a/efi-dont-map-boot-services-on-32bit.patch b/efi-dont-map-boot-services-on-32bit.patch new file mode 100644 index 000000000..7cc614992 --- /dev/null +++ b/efi-dont-map-boot-services-on-32bit.patch @@ -0,0 +1,22 @@ +diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c +index 3ae4128..ff7dc70 100644 +--- a/arch/x86/platform/efi/efi.c ++++ b/arch/x86/platform/efi/efi.c +@@ -659,10 +659,13 @@ void __init efi_enter_virtual_mode(void) + + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { + md = p; +- if (!(md->attribute & EFI_MEMORY_RUNTIME) && +- md->type != EFI_BOOT_SERVICES_CODE && +- md->type != EFI_BOOT_SERVICES_DATA) +- continue; ++ if (!(md->attribute & EFI_MEMORY_RUNTIME)) { ++#ifdef CONFIG_X86_64 ++ if (md->type != EFI_BOOT_SERVICES_CODE && ++ md->type != EFI_BOOT_SERVICES_DATA) ++#endif ++ continue; ++ } + + size = md->num_pages << EFI_PAGE_SHIFT; + end = md->phys_addr + size; diff --git a/efi_default_physical.patch b/efi_default_physical.patch deleted file mode 100644 index 41de7809e..000000000 --- a/efi_default_physical.patch +++ /dev/null @@ -1,403 +0,0 @@ -Default EFI to physical rather than virtual. Upstream seem to be going -in this direction. - -diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h -index 8e4a165..3c62f15 100644 ---- a/arch/x86/include/asm/efi.h -+++ b/arch/x86/include/asm/efi.h -@@ -93,6 +93,9 @@ extern int add_efi_memmap; - extern void efi_memblock_x86_reserve_range(void); - extern void efi_call_phys_prelog(void); - extern void efi_call_phys_epilog(void); -+extern void efi_call_phys_prelog_in_physmode(void); -+extern void efi_call_phys_epilog_in_physmode(void); -+extern void efi_pagetable_init(void); - - #ifndef CONFIG_EFI - /* -diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c -index 0fe27d7..e1158b0 100644 ---- a/arch/x86/platform/efi/efi.c -+++ b/arch/x86/platform/efi/efi.c -@@ -58,6 +58,7 @@ struct efi_memory_map memmap; - - static struct efi efi_phys __initdata; - static efi_system_table_t efi_systab __initdata; -+static efi_runtime_services_t phys_runtime; - - static int __init setup_noefi(char *arg) - { -@@ -172,7 +173,7 @@ static efi_status_t __init phys_efi_set_virtual_address_map( - return status; - } - --static efi_status_t __init phys_efi_get_time(efi_time_t *tm, -+static efi_status_t __init phys_efi_get_time_early(efi_time_t *tm, - efi_time_cap_t *tc) - { - efi_status_t status; -@@ -183,6 +184,112 @@ static efi_status_t __init phys_efi_get_time(efi_time_t *tm, - return status; - } - -+static efi_status_t phys_efi_get_time(efi_time_t *tm, -+ efi_time_cap_t *tc) -+{ -+ efi_status_t status; -+ -+ efi_call_phys_prelog_in_physmode(); -+ status = efi_call_phys2((void*)phys_runtime.get_time, tm, tc); -+ efi_call_phys_epilog_in_physmode(); -+ return status; -+} -+ -+static efi_status_t __init phys_efi_set_time(efi_time_t *tm) -+{ -+ efi_status_t status; -+ -+ efi_call_phys_prelog_in_physmode(); -+ status = efi_call_phys1((void*)phys_runtime.set_time, tm); -+ efi_call_phys_epilog_in_physmode(); -+ return status; -+} -+ -+static efi_status_t phys_efi_get_wakeup_time(efi_bool_t *enabled, -+ efi_bool_t *pending, -+ efi_time_t *tm) -+{ -+ efi_status_t status; -+ -+ efi_call_phys_prelog_in_physmode(); -+ status = efi_call_phys3((void*)phys_runtime.get_wakeup_time, enabled, -+ pending, tm); -+ efi_call_phys_epilog_in_physmode(); -+ return status; -+} -+ -+static efi_status_t phys_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) -+{ -+ efi_status_t status; -+ efi_call_phys_prelog_in_physmode(); -+ status = efi_call_phys2((void*)phys_runtime.set_wakeup_time, enabled, -+ tm); -+ efi_call_phys_epilog_in_physmode(); -+ return status; -+} -+ -+static efi_status_t phys_efi_get_variable(efi_char16_t *name, -+ efi_guid_t *vendor, -+ u32 *attr, -+ unsigned long *data_size, -+ void *data) -+{ -+ efi_status_t status; -+ efi_call_phys_prelog_in_physmode(); -+ status = efi_call_phys5((void*)phys_runtime.get_variable, name, vendor, -+ attr, data_size, data); -+ efi_call_phys_epilog_in_physmode(); -+ return status; -+} -+ -+static efi_status_t phys_efi_get_next_variable(unsigned long *name_size, -+ efi_char16_t *name, -+ efi_guid_t *vendor) -+{ -+ efi_status_t status; -+ -+ efi_call_phys_prelog_in_physmode(); -+ status = efi_call_phys3((void*)phys_runtime.get_next_variable, -+ name_size, name, vendor); -+ efi_call_phys_epilog_in_physmode(); -+ return status; -+} -+ -+static efi_status_t phys_efi_set_variable(efi_char16_t *name, -+ efi_guid_t *vendor, -+ unsigned long attr, -+ unsigned long data_size, -+ void *data) -+{ -+ efi_status_t status; -+ efi_call_phys_prelog_in_physmode(); -+ status = efi_call_phys5((void*)phys_runtime.set_variable, name, -+ vendor, attr, data_size, data); -+ efi_call_phys_epilog_in_physmode(); -+ return status; -+} -+ -+static efi_status_t phys_efi_get_next_high_mono_count(u32 *count) -+{ -+ efi_status_t status; -+ efi_call_phys_prelog_in_physmode(); -+ status = efi_call_phys1((void*)phys_runtime.get_next_high_mono_count, -+ count); -+ efi_call_phys_epilog_in_physmode(); -+ return status; -+} -+ -+static void phys_efi_reset_system(int reset_type, -+ efi_status_t status, -+ unsigned long data_size, -+ efi_char16_t *data) -+{ -+ efi_call_phys_prelog_in_physmode(); -+ efi_call_phys4((void*)phys_runtime.reset_system, reset_type, status, -+ data_size, data); -+ efi_call_phys_epilog_in_physmode(); -+} -+ - int efi_set_rtc_mmss(unsigned long nowtime) - { - int real_seconds, real_minutes; -@@ -435,7 +542,9 @@ void __init efi_init(void) - * Make efi_get_time can be called before entering - * virtual mode. - */ -- efi.get_time = phys_efi_get_time; -+ efi.get_time = phys_efi_get_time_early; -+ -+ memcpy(&phys_runtime, runtime, sizeof(efi_runtime_services_t)); - } else - printk(KERN_ERR "Could not map the EFI runtime service " - "table!\n"); -@@ -466,6 +575,14 @@ void __init efi_init(void) - #if EFI_DEBUG - print_efi_memmap(); - #endif -+ -+#ifndef CONFIG_X86_64 -+ /* -+ * Only x86_64 supports physical mode as of now. Use virtual mode -+ * forcibly. -+ */ -+ usevirtefi = 1; -+#endif - } - - static void __init runtime_code_page_mkexec(void) -@@ -579,6 +696,27 @@ void __init efi_enter_virtual_mode(void) - memmap.map = NULL; - } - -+void __init efi_setup_physical_mode(void) -+{ -+#ifdef CONFIG_X86_64 -+ efi_pagetable_init(); -+#endif -+ efi.get_time = phys_efi_get_time; -+ efi.set_time = phys_efi_set_time; -+ efi.get_wakeup_time = phys_efi_get_wakeup_time; -+ efi.set_wakeup_time = phys_efi_set_wakeup_time; -+ efi.get_variable = phys_efi_get_variable; -+ efi.get_next_variable = phys_efi_get_next_variable; -+ efi.set_variable = phys_efi_set_variable; -+ efi.get_next_high_mono_count = -+ phys_efi_get_next_high_mono_count; -+ efi.reset_system = phys_efi_reset_system; -+ efi.set_virtual_address_map = NULL; /* Not needed */ -+ -+ early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size); -+ memmap.map = NULL; -+} -+ - /* - * Convenience functions to obtain memory types and attributes - */ -diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c -index 5cab48e..90767b1 100644 ---- a/arch/x86/platform/efi/efi_32.c -+++ b/arch/x86/platform/efi/efi_32.c -@@ -110,3 +110,7 @@ void efi_call_phys_epilog(void) - - local_irq_restore(efi_rt_eflags); - } -+ -+void efi_call_phys_prelog_in_physmode(void) { /* Not supported */ } -+void efi_call_phys_epilog_in_physmode(void) { /* Not supported */ } -+ -diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c -index ac0621a..ad19fe9 100644 ---- a/arch/x86/platform/efi/efi_64.c -+++ b/arch/x86/platform/efi/efi_64.c -@@ -39,7 +39,9 @@ - #include - - static pgd_t save_pgd __initdata; --static unsigned long efi_flags __initdata; -+static DEFINE_PER_CPU(unsigned long, efi_flags); -+static DEFINE_PER_CPU(unsigned long, save_cr3); -+static pgd_t efi_pgd[PTRS_PER_PGD] __page_aligned_bss; - - static void __init early_mapping_set_exec(unsigned long start, - unsigned long end, -@@ -80,7 +82,7 @@ void __init efi_call_phys_prelog(void) - unsigned long vaddress; - - early_runtime_code_mapping_set_exec(1); -- local_irq_save(efi_flags); -+ local_irq_save(get_cpu_var(efi_flags)); - vaddress = (unsigned long)__va(0x0UL); - save_pgd = *pgd_offset_k(0x0UL); - set_pgd(pgd_offset_k(0x0UL), *pgd_offset_k(vaddress)); -@@ -94,10 +96,23 @@ void __init efi_call_phys_epilog(void) - */ - set_pgd(pgd_offset_k(0x0UL), save_pgd); - __flush_tlb_all(); -- local_irq_restore(efi_flags); -+ local_irq_restore(get_cpu_var(efi_flags)); - early_runtime_code_mapping_set_exec(0); - } - -+void efi_call_phys_prelog_in_physmode(void) -+{ -+ local_irq_save(get_cpu_var(efi_flags)); -+ get_cpu_var(save_cr3)= read_cr3(); -+ write_cr3(virt_to_phys(efi_pgd)); -+} -+ -+void efi_call_phys_epilog_in_physmode(void) -+{ -+ write_cr3(get_cpu_var(save_cr3)); -+ local_irq_restore(get_cpu_var(efi_flags)); -+} -+ - void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size, - u32 type) - { -@@ -112,3 +127,78 @@ void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size, - - return (void __iomem *)__va(phys_addr); - } -+ -+static pud_t *fill_pud(pgd_t *pgd, unsigned long vaddr) -+{ -+ if (pgd_none(*pgd)) { -+ pud_t *pud = (pud_t *)get_zeroed_page(GFP_ATOMIC); -+ set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pud))); -+ if (pud != pud_offset(pgd, 0)) -+ printk(KERN_ERR "EFI PAGETABLE BUG #00! %p <-> %p\n", -+ pud, pud_offset(pgd, 0)); -+ } -+ return pud_offset(pgd, vaddr); -+} -+ -+static pmd_t *fill_pmd(pud_t *pud, unsigned long vaddr) -+{ -+ if (pud_none(*pud)) { -+ pmd_t *pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC); -+ set_pud(pud, __pud(_PAGE_TABLE | __pa(pmd))); -+ if (pmd != pmd_offset(pud, 0)) -+ printk(KERN_ERR "EFI PAGETABLE BUG #01! %p <-> %p\n", -+ pmd, pmd_offset(pud, 0)); -+ } -+ return pmd_offset(pud, vaddr); -+} -+ -+static pte_t *fill_pte(pmd_t *pmd, unsigned long vaddr) -+{ -+ if (pmd_none(*pmd)) { -+ pte_t *pte = (pte_t *)get_zeroed_page(GFP_ATOMIC); -+ set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte))); -+ if (pte != pte_offset_kernel(pmd, 0)) -+ printk(KERN_ERR "EFI PAGETABLE BUG #02!\n"); -+ } -+ return pte_offset_kernel(pmd, vaddr); -+} -+ -+void __init efi_pagetable_init(void) -+{ -+ efi_memory_desc_t *md; -+ unsigned long size; -+ u64 start_pfn, end_pfn, pfn, vaddr; -+ void *p; -+ pgd_t *pgd; -+ pud_t *pud; -+ pmd_t *pmd; -+ pte_t *pte; -+ -+ memset(efi_pgd, 0, sizeof(efi_pgd)); -+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { -+ md = p; -+ if (!(md->type & EFI_RUNTIME_SERVICES_CODE) && -+ !(md->type & EFI_RUNTIME_SERVICES_DATA)) -+ continue; -+ -+ start_pfn = md->phys_addr >> PAGE_SHIFT; -+ size = md->num_pages << EFI_PAGE_SHIFT; -+ end_pfn = PFN_UP(md->phys_addr + size); -+ -+ for (pfn = start_pfn; pfn <= end_pfn; pfn++) { -+ vaddr = pfn << PAGE_SHIFT; -+ pgd = efi_pgd + pgd_index(vaddr); -+ pud = fill_pud(pgd, vaddr); -+ pmd = fill_pmd(pud, vaddr); -+ pte = fill_pte(pmd, vaddr); -+ if (md->type & EFI_RUNTIME_SERVICES_CODE) -+ set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); -+ else -+ set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); -+ } -+ } -+ pgd = efi_pgd + pgd_index(PAGE_OFFSET); -+ set_pgd(pgd, *pgd_offset_k(PAGE_OFFSET)); -+ pgd = efi_pgd + pgd_index(__START_KERNEL_map); -+ set_pgd(pgd, *pgd_offset_k(__START_KERNEL_map)); -+} -diff --git a/include/linux/efi.h b/include/linux/efi.h -index fb737bc..c4e310e 100644 ---- a/include/linux/efi.h -+++ b/include/linux/efi.h -@@ -290,6 +290,7 @@ extern void efi_map_pal_code (void); - extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg); - extern void efi_gettimeofday (struct timespec *ts); - extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */ -+extern void efi_setup_physical_mode(void); - extern u64 efi_get_iobase (void); - extern u32 efi_mem_type (unsigned long phys_addr); - extern u64 efi_mem_attributes (unsigned long phys_addr); -diff --git a/include/linux/init.h b/include/linux/init.h -index 577671c..2f1b28f 100644 ---- a/include/linux/init.h -+++ b/include/linux/init.h -@@ -149,6 +149,7 @@ extern int do_one_initcall(initcall_t fn); - extern char __initdata boot_command_line[]; - extern char *saved_command_line; - extern unsigned int reset_devices; -+extern unsigned int usevirtefi; - - /* used by init/main.c */ - void setup_arch(char **); -diff --git a/init/main.c b/init/main.c -index 8646401..726025e 100644 ---- a/init/main.c -+++ b/init/main.c -@@ -196,6 +196,14 @@ static int __init set_reset_devices(char *str) - - __setup("reset_devices", set_reset_devices); - -+unsigned int usevirtefi; -+static int __init set_virt_efi(char *str) -+{ -+ usevirtefi = 1; -+ return 1; -+} -+__setup("virtefi", set_virt_efi); -+ - static const char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; - const char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; - static const char *panic_later, *panic_param; -@@ -668,8 +676,12 @@ asmlinkage void __init start_kernel(void) - pidmap_init(); - anon_vma_init(); - #ifdef CONFIG_X86 -- if (efi_enabled) -- efi_enter_virtual_mode(); -+ if (efi_enabled) { -+ if (usevirtefi) -+ efi_enter_virtual_mode(); -+ else -+ efi_setup_physical_mode(); -+ } - #endif - thread_info_cache_init(); - cred_init(); diff --git a/efifb_update.patch b/efifb_update.patch deleted file mode 100644 index 7058ba610..000000000 --- a/efifb_update.patch +++ /dev/null @@ -1,217 +0,0 @@ -Fix up efifb so it works properly on the 11" Macbook Air. Upstream in .38? - -diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c -index 70477c2..476ffb1 100644 ---- a/drivers/video/efifb.c -+++ b/drivers/video/efifb.c -@@ -53,6 +53,7 @@ enum { - M_MB_7_1, /* MacBook, 7th rev. */ - M_MB_SR, /* MacBook, 2nd gen, (Santa Rosa) */ - M_MBA, /* MacBook Air */ -+ M_MBA_3, /* Macbook Air, 3rd rev */ - M_MBP, /* MacBook Pro */ - M_MBP_2, /* MacBook Pro 2nd gen */ - M_MBP_2_2, /* MacBook Pro 2,2nd gen */ -@@ -67,40 +68,49 @@ enum { - M_UNKNOWN /* placeholder */ - }; - -+#define OVERRIDE_NONE 0x0 -+#define OVERRIDE_BASE 0x1 -+#define OVERRIDE_STRIDE 0x2 -+#define OVERRIDE_HEIGHT 0x4 -+#define OVERRIDE_WIDTH 0x8 -+ - static struct efifb_dmi_info { - char *optname; - unsigned long base; - int stride; - int width; - int height; -+ int flags; - } dmi_list[] __initdata = { -- [M_I17] = { "i17", 0x80010000, 1472 * 4, 1440, 900 }, -- [M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050 }, /* guess */ -- [M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050 }, -- [M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200 }, /* guess */ -- [M_I24_8_1] = { "imac8", 0xc0060000, 2048 * 4, 1920, 1200 }, -- [M_I24_10_1] = { "imac10", 0xc0010000, 2048 * 4, 1920, 1080 }, -- [M_I27_11_1] = { "imac11", 0xc0010000, 2560 * 4, 2560, 1440 }, -- [M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768 }, -- [M_MINI_3_1] = { "mini31", 0x40010000, 1024 * 4, 1024, 768 }, -- [M_MINI_4_1] = { "mini41", 0xc0010000, 2048 * 4, 1920, 1200 }, -- [M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800 }, -- [M_MB_5_1] = { "macbook51", 0x80010000, 2048 * 4, 1280, 800 }, -- [M_MB_6_1] = { "macbook61", 0x80010000, 2048 * 4, 1280, 800 }, -- [M_MB_7_1] = { "macbook71", 0x80010000, 2048 * 4, 1280, 800 }, -- [M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800 }, -- [M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900 }, -- [M_MBP_2] = { "mbp2", 0, 0, 0, 0 }, /* placeholder */ -- [M_MBP_2_2] = { "mbp22", 0x80010000, 1472 * 4, 1440, 900 }, -- [M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900 }, -- [M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200 }, -- [M_MBP_5_1] = { "mbp51", 0xc0010000, 2048 * 4, 1440, 900 }, -- [M_MBP_5_2] = { "mbp52", 0xc0010000, 2048 * 4, 1920, 1200 }, -- [M_MBP_5_3] = { "mbp53", 0xd0010000, 2048 * 4, 1440, 900 }, -- [M_MBP_6_1] = { "mbp61", 0x90030000, 2048 * 4, 1920, 1200 }, -- [M_MBP_6_2] = { "mbp62", 0x90030000, 2048 * 4, 1680, 1050 }, -- [M_MBP_7_1] = { "mbp71", 0xc0010000, 2048 * 4, 1280, 800 }, -- [M_UNKNOWN] = { NULL, 0, 0, 0, 0 } -+ [M_I17] = { "i17", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE }, -+ [M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE }, /* guess */ -+ [M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE }, -+ [M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, /* guess */ -+ [M_I24_8_1] = { "imac8", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, -+ [M_I24_10_1] = { "imac10", 0xc0010000, 2048 * 4, 1920, 1080, OVERRIDE_NONE }, -+ [M_I27_11_1] = { "imac11", 0xc0010000, 2560 * 4, 2560, 1440, OVERRIDE_NONE }, -+ [M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768, OVERRIDE_NONE }, -+ [M_MINI_3_1] = { "mini31", 0x40010000, 1024 * 4, 1024, 768, OVERRIDE_NONE }, -+ [M_MINI_4_1] = { "mini41", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, -+ [M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, -+ [M_MB_5_1] = { "macbook51", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, -+ [M_MB_6_1] = { "macbook61", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, -+ [M_MB_7_1] = { "macbook71", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, -+ [M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, -+ /* 11" Macbook Air 3,1 passes the wrong stride */ -+ [M_MBA_3] = { "mba3", 0, 2048 * 4, 0, 0, OVERRIDE_STRIDE }, -+ [M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE }, -+ [M_MBP_2] = { "mbp2", 0, 0, 0, 0, OVERRIDE_NONE }, /* placeholder */ -+ [M_MBP_2_2] = { "mbp22", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE }, -+ [M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900, OVERRIDE_NONE }, -+ [M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, -+ [M_MBP_5_1] = { "mbp51", 0xc0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE }, -+ [M_MBP_5_2] = { "mbp52", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, -+ [M_MBP_5_3] = { "mbp53", 0xd0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE }, -+ [M_MBP_6_1] = { "mbp61", 0x90030000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, -+ [M_MBP_6_2] = { "mbp62", 0x90030000, 2048 * 4, 1680, 1050, OVERRIDE_NONE }, -+ [M_MBP_7_1] = { "mbp71", 0xc0010000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, -+ [M_UNKNOWN] = { NULL, 0, 0, 0, 0, OVERRIDE_NONE } - }; - - static int set_system(const struct dmi_system_id *id); -@@ -138,6 +148,7 @@ static const struct dmi_system_id dmi_system_table[] __initconst = { - EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook6,1", M_MB_6_1), - EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook7,1", M_MB_7_1), - EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir1,1", M_MBA), -+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir3,1", M_MBA_3), - EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro1,1", M_MBP), - EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,1", M_MBP_2), - EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,2", M_MBP_2_2), -@@ -154,16 +165,22 @@ static const struct dmi_system_id dmi_system_table[] __initconst = { - {}, - }; - -+#define choose_value(dmivalue, fwvalue, field, flags) ({ \ -+ typeof(fwvalue) _ret_ = fwvalue; \ -+ if ((flags) & (field)) \ -+ _ret_ = dmivalue; \ -+ else if ((fwvalue) == 0) \ -+ _ret_ = dmivalue; \ -+ _ret_; \ -+ }) -+ - static int set_system(const struct dmi_system_id *id) - { - struct efifb_dmi_info *info = id->driver_data; -- if (info->base == 0) -- return 0; - -- printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p " -- "(%dx%d, stride %d)\n", id->ident, -- (void *)info->base, info->width, info->height, -- info->stride); -+ if (info->base == 0 && info->height == 0 && info->width == 0 -+ && info->stride == 0) -+ return 0; - - /* Trust the bootloader over the DMI tables */ - if (screen_info.lfb_base == 0) { -@@ -171,40 +188,47 @@ static int set_system(const struct dmi_system_id *id) - struct pci_dev *dev = NULL; - int found_bar = 0; - #endif -- screen_info.lfb_base = info->base; -+ if (info->base) { -+ screen_info.lfb_base = choose_value(info->base, -+ screen_info.lfb_base, OVERRIDE_BASE, -+ info->flags); - - #if defined(CONFIG_PCI) -- /* make sure that the address in the table is actually on a -- * VGA device's PCI BAR */ -- -- for_each_pci_dev(dev) { -- int i; -- if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) -- continue; -- for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { -- resource_size_t start, end; -- -- start = pci_resource_start(dev, i); -- if (start == 0) -- break; -- end = pci_resource_end(dev, i); -- if (screen_info.lfb_base >= start && -- screen_info.lfb_base < end) { -- found_bar = 1; -+ /* make sure that the address in the table is actually -+ * on a VGA device's PCI BAR */ -+ -+ for_each_pci_dev(dev) { -+ int i; -+ if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) -+ continue; -+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { -+ resource_size_t start, end; -+ -+ start = pci_resource_start(dev, i); -+ if (start == 0) -+ break; -+ end = pci_resource_end(dev, i); -+ if (screen_info.lfb_base >= start && -+ screen_info.lfb_base < end) { -+ found_bar = 1; -+ } - } - } -- } -- if (!found_bar) -- screen_info.lfb_base = 0; -+ if (!found_bar) -+ screen_info.lfb_base = 0; - #endif -+ } - } - if (screen_info.lfb_base) { -- if (screen_info.lfb_linelength == 0) -- screen_info.lfb_linelength = info->stride; -- if (screen_info.lfb_width == 0) -- screen_info.lfb_width = info->width; -- if (screen_info.lfb_height == 0) -- screen_info.lfb_height = info->height; -+ screen_info.lfb_linelength = choose_value(info->stride, -+ screen_info.lfb_linelength, OVERRIDE_STRIDE, -+ info->flags); -+ screen_info.lfb_width = choose_value(info->width, -+ screen_info.lfb_width, OVERRIDE_WIDTH, -+ info->flags); -+ screen_info.lfb_height = choose_value(info->height, -+ screen_info.lfb_height, OVERRIDE_HEIGHT, -+ info->flags); - if (screen_info.orig_video_isVGA == 0) - screen_info.orig_video_isVGA = VIDEO_TYPE_EFI; - } else { -@@ -214,6 +238,13 @@ static int set_system(const struct dmi_system_id *id) - screen_info.orig_video_isVGA = 0; - return 0; - } -+ -+ printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p " -+ "(%dx%d, stride %d)\n", id->ident, -+ (void *)screen_info.lfb_base, screen_info.lfb_width, -+ screen_info.lfb_height, screen_info.lfb_linelength); -+ -+ - return 1; - } - diff --git a/epoll-limit-paths.patch b/epoll-limit-paths.patch new file mode 100644 index 000000000..4ed306af4 --- /dev/null +++ b/epoll-limit-paths.patch @@ -0,0 +1,465 @@ +From 0a6cc45426fe3baaf231efd7efe4300fd879efc8 Mon Sep 17 00:00:00 2001 +From: Jason Baron +Date: Mon, 24 Oct 2011 14:59:02 +1100 +Subject: [PATCH] epoll: limit paths + +epoll: limit paths + +The current epoll code can be tickled to run basically indefinitely in +both loop detection path check (on ep_insert()), and in the wakeup paths. +The programs that tickle this behavior set up deeply linked networks of +epoll file descriptors that cause the epoll algorithms to traverse them +indefinitely. A couple of these sample programs have been previously +posted in this thread: https://lkml.org/lkml/2011/2/25/297. + +To fix the loop detection path check algorithms, I simply keep track of +the epoll nodes that have been already visited. Thus, the loop detection +becomes proportional to the number of epoll file descriptor and links. +This dramatically decreases the run-time of the loop check algorithm. In +one diabolical case I tried it reduced the run-time from 15 mintues (all +in kernel time) to .3 seconds. + +Fixing the wakeup paths could be done at wakeup time in a similar manner +by keeping track of nodes that have already been visited, but the +complexity is harder, since there can be multiple wakeups on different +cpus...Thus, I've opted to limit the number of possible wakeup paths when +the paths are created. + +This is accomplished, by noting that the end file descriptor points that +are found during the loop detection pass (from the newly added link), are +actually the sources for wakeup events. I keep a list of these file +descriptors and limit the number and length of these paths that emanate +from these 'source file descriptors'. In the current implemetation I +allow 1000 paths of length 1, 500 of length 2, 100 of length 3, 50 of +length 4 and 10 of length 5. Note that it is sufficient to check the +'source file descriptors' reachable from the newly added link, since no +other 'source file descriptors' will have newly added links. This allows +us to check only the wakeup paths that may have gotten too long, and not +re-check all possible wakeup paths on the system. + +In terms of the path limit selection, I think its first worth noting that +the most common case for epoll, is probably the model where you have 1 +epoll file descriptor that is monitoring n number of 'source file +descriptors'. In this case, each 'source file descriptor' has a 1 path of +length 1. Thus, I believe that the limits I'm proposing are quite +reasonable and in fact may be too generous. Thus, I'm hoping that the +proposed limits will not prevent any workloads that currently work to +fail. + +In terms of locking, I have extended the use of the 'epmutex' to all +epoll_ctl add and remove operations. Currently its only used in a subset +of the add paths. I need to hold the epmutex, so that we can correctly +traverse a coherent graph, to check the number of paths. I believe that +this additional locking is probably ok, since its in the setup/teardown +paths, and doesn't affect the running paths, but it certainly is going to +add some extra overhead. Also, worth noting is that the epmuex was +recently added to the ep_ctl add operations in the initial path loop +detection code using the argument that it was not on a critical path. + +Another thing to note here, is the length of epoll chains that is allowed. +Currently, eventpoll.c defines: + +/* Maximum number of nesting allowed inside epoll sets */ +#define EP_MAX_NESTS 4 + +This basically means that I am limited to a graph depth of 5 (EP_MAX_NESTS ++ 1). However, this limit is currently only enforced during the loop +check detection code, and only when the epoll file descriptors are added +in a certain order. Thus, this limit is currently easily bypassed. The +newly added check for wakeup paths, stricly limits the wakeup paths to a +length of 5, regardless of the order in which ep's are linked together. +Thus, a side-effect of the new code is a more consistent enforcement of +the graph depth. + +Thus far, I've tested this, using the sample programs previously +mentioned, which now either return quickly or return -EINVAL. I've also +testing using the piptest.c epoll tester, which showed no difference in +performance. I've also created a number of different epoll networks and +tested that they behave as expectded. + +I believe this solves the original diabolical test cases, while still +preserving the sane epoll nesting. + +Signed-off-by: Jason Baron +Cc: Nelson Elhage +Cc: Davide Libenzi +Signed-off-by: Andrew Morton +--- + fs/eventpoll.c | 226 ++++++++++++++++++++++++++++++++++++++++----- + include/linux/eventpoll.h | 1 + + include/linux/fs.h | 1 + + 3 files changed, 203 insertions(+), 25 deletions(-) + +diff --git a/fs/eventpoll.c b/fs/eventpoll.c +index b84fad9..414ac74 100644 +--- a/fs/eventpoll.c ++++ b/fs/eventpoll.c +@@ -197,6 +197,12 @@ struct eventpoll { + + /* The user that created the eventpoll descriptor */ + struct user_struct *user; ++ ++ struct file *file; ++ ++ /* used to optimize loop detection check */ ++ int visited; ++ struct list_head visitedllink; + }; + + /* Wait structure used by the poll hooks */ +@@ -255,6 +261,12 @@ static struct kmem_cache *epi_cache __read_mostly; + /* Slab cache used to allocate "struct eppoll_entry" */ + static struct kmem_cache *pwq_cache __read_mostly; + ++/* Visited nodes during ep_loop_check(), so we can unset them when we finish */ ++LIST_HEAD(visited_list); ++ ++/* Files with newly added links, which need a limit on emanating paths */ ++LIST_HEAD(tfile_check_list); ++ + #ifdef CONFIG_SYSCTL + + #include +@@ -276,6 +288,12 @@ ctl_table epoll_table[] = { + }; + #endif /* CONFIG_SYSCTL */ + ++static const struct file_operations eventpoll_fops; ++ ++static inline int is_file_epoll(struct file *f) ++{ ++ return f->f_op == &eventpoll_fops; ++} + + /* Setup the structure that is used as key for the RB tree */ + static inline void ep_set_ffd(struct epoll_filefd *ffd, +@@ -711,12 +729,6 @@ static const struct file_operations eventpoll_fops = { + .llseek = noop_llseek, + }; + +-/* Fast test to see if the file is an eventpoll file */ +-static inline int is_file_epoll(struct file *f) +-{ +- return f->f_op == &eventpoll_fops; +-} +- + /* + * This is called from eventpoll_release() to unlink files from the eventpoll + * interface. We need to have this facility to cleanup correctly files that are +@@ -926,6 +938,96 @@ static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi) + rb_insert_color(&epi->rbn, &ep->rbr); + } + ++ ++ ++#define PATH_ARR_SIZE 5 ++/* These are the number paths of length 1 to 5, that we are allowing to emanate ++ * from a single file of interest. For example, we allow 1000 paths of length ++ * 1, to emanate from each file of interest. This essentially represents the ++ * potential wakeup paths, which need to be limited in order to avoid massive ++ * uncontrolled wakeup storms. The common use case should be a single ep which ++ * is connected to n file sources. In this case each file source has 1 path ++ * of length 1. Thus, the numbers below should be more than sufficient. ++ */ ++int path_limits[PATH_ARR_SIZE] = { 1000, 500, 100, 50, 10 }; ++int path_count[PATH_ARR_SIZE]; ++ ++static int path_count_inc(int nests) ++{ ++ if (++path_count[nests] > path_limits[nests]) ++ return -1; ++ return 0; ++} ++ ++static void path_count_init(void) ++{ ++ int i; ++ ++ for (i = 0; i < PATH_ARR_SIZE; i++) ++ path_count[i] = 0; ++} ++ ++static int reverse_path_check_proc(void *priv, void *cookie, int call_nests) ++{ ++ int error = 0; ++ struct file *file = priv; ++ struct file *child_file; ++ struct epitem *epi; ++ ++ list_for_each_entry(epi, &file->f_ep_links, fllink) { ++ child_file = epi->ep->file; ++ if (is_file_epoll(child_file)) { ++ if (list_empty(&child_file->f_ep_links)) { ++ if (path_count_inc(call_nests)) { ++ error = -1; ++ break; ++ } ++ } else { ++ error = ep_call_nested(&poll_loop_ncalls, ++ EP_MAX_NESTS, ++ reverse_path_check_proc, ++ child_file, child_file, ++ current); ++ } ++ if (error != 0) ++ break; ++ } else { ++ printk(KERN_ERR "reverse_path_check_proc: " ++ "file is not an ep!\n"); ++ } ++ } ++ return error; ++} ++ ++/** ++ * reverse_path_check - The tfile_check_list is list of file *, which have ++ * links that are proposed to be newly added. We need to ++ * make sure that those added links don't add too many ++ * paths such that we will spend all our time waking up ++ * eventpoll objects. ++ * ++ * Returns: Returns zero if the proposed links don't create too many paths, ++ * -1 otherwise. ++ */ ++static int reverse_path_check(void) ++{ ++ int length = 0; ++ int error = 0; ++ struct file *current_file; ++ ++ /* let's call this for all tfiles */ ++ list_for_each_entry(current_file, &tfile_check_list, f_tfile_llink) { ++ length++; ++ path_count_init(); ++ error = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS, ++ reverse_path_check_proc, current_file, ++ current_file, current); ++ if (error) ++ break; ++ } ++ return error; ++} ++ + /* + * Must be called with "mtx" held. + */ +@@ -987,6 +1089,11 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, + */ + ep_rbtree_insert(ep, epi); + ++ /* now check if we've created too many backpaths */ ++ error = -EINVAL; ++ if (reverse_path_check()) ++ goto error_remove_epi; ++ + /* We have to drop the new item inside our item list to keep track of it */ + spin_lock_irqsave(&ep->lock, flags); + +@@ -1011,6 +1118,14 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, + + return 0; + ++error_remove_epi: ++ spin_lock(&tfile->f_lock); ++ if (ep_is_linked(&epi->fllink)) ++ list_del_init(&epi->fllink); ++ spin_unlock(&tfile->f_lock); ++ ++ rb_erase(&epi->rbn, &ep->rbr); ++ + error_unregister: + ep_unregister_pollwait(ep, epi); + +@@ -1275,18 +1390,35 @@ static int ep_loop_check_proc(void *priv, void *cookie, int call_nests) + int error = 0; + struct file *file = priv; + struct eventpoll *ep = file->private_data; ++ struct eventpoll *ep_tovisit; + struct rb_node *rbp; + struct epitem *epi; + + mutex_lock_nested(&ep->mtx, call_nests + 1); ++ ep->visited = 1; ++ list_add(&ep->visitedllink, &visited_list); + for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) { + epi = rb_entry(rbp, struct epitem, rbn); + if (unlikely(is_file_epoll(epi->ffd.file))) { ++ ep_tovisit = epi->ffd.file->private_data; ++ if (ep_tovisit->visited) ++ continue; + error = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS, +- ep_loop_check_proc, epi->ffd.file, +- epi->ffd.file->private_data, current); ++ ep_loop_check_proc, epi->ffd.file, ++ ep_tovisit, current); + if (error != 0) + break; ++ } else { ++ /* if we've reached a file that is not associated with ++ * an ep, then then we need to check if the newly added ++ * links are going to add too many wakeup paths. We do ++ * this by adding it to the tfile_check_list, if it's ++ * not already there, and calling reverse_path_check() ++ * during ep_insert() ++ */ ++ if (list_empty(&epi->ffd.file->f_tfile_llink)) ++ list_add(&epi->ffd.file->f_tfile_llink, ++ &tfile_check_list); + } + } + mutex_unlock(&ep->mtx); +@@ -1307,8 +1439,30 @@ static int ep_loop_check_proc(void *priv, void *cookie, int call_nests) + */ + static int ep_loop_check(struct eventpoll *ep, struct file *file) + { +- return ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS, ++ int ret; ++ struct eventpoll *ep_cur, *ep_next; ++ ++ ret = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS, + ep_loop_check_proc, file, ep, current); ++ /* clear visited list */ ++ list_for_each_entry_safe(ep_cur, ep_next, &visited_list, visitedllink) { ++ ep_cur->visited = 0; ++ list_del(&ep_cur->visitedllink); ++ } ++ return ret; ++} ++ ++static void clear_tfile_check_list(void) ++{ ++ struct file *file; ++ ++ /* first clear the tfile_check_list */ ++ while (!list_empty(&tfile_check_list)) { ++ file = list_first_entry(&tfile_check_list, struct file, ++ f_tfile_llink); ++ list_del_init(&file->f_tfile_llink); ++ } ++ INIT_LIST_HEAD(&tfile_check_list); + } + + /* +@@ -1316,8 +1470,9 @@ static int ep_loop_check(struct eventpoll *ep, struct file *file) + */ + SYSCALL_DEFINE1(epoll_create1, int, flags) + { +- int error; ++ int error, fd; + struct eventpoll *ep = NULL; ++ struct file *file; + + /* Check the EPOLL_* constant for consistency. */ + BUILD_BUG_ON(EPOLL_CLOEXEC != O_CLOEXEC); +@@ -1334,11 +1489,25 @@ SYSCALL_DEFINE1(epoll_create1, int, flags) + * Creates all the items needed to setup an eventpoll file. That is, + * a file structure and a free file descriptor. + */ +- error = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep, ++ fd = get_unused_fd_flags(O_RDWR | (flags & O_CLOEXEC)); ++ if (fd < 0) { ++ error = fd; ++ goto out_free_ep; ++ } ++ file = anon_inode_getfile("[eventpoll]", &eventpoll_fops, ep, + O_RDWR | (flags & O_CLOEXEC)); +- if (error < 0) +- ep_free(ep); +- ++ if (IS_ERR(file)) { ++ error = PTR_ERR(file); ++ goto out_free_fd; ++ } ++ fd_install(fd, file); ++ ep->file = file; ++ return fd; ++ ++out_free_fd: ++ put_unused_fd(fd); ++out_free_ep: ++ ep_free(ep); + return error; + } + +@@ -1404,21 +1573,27 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, + /* + * When we insert an epoll file descriptor, inside another epoll file + * descriptor, there is the change of creating closed loops, which are +- * better be handled here, than in more critical paths. ++ * better be handled here, than in more critical paths. While we are ++ * checking for loops we also determine the list of files reachable ++ * and hang them on the tfile_check_list, so we can check that we ++ * haven't created too many possible wakeup paths. + * +- * We hold epmutex across the loop check and the insert in this case, in +- * order to prevent two separate inserts from racing and each doing the +- * insert "at the same time" such that ep_loop_check passes on both +- * before either one does the insert, thereby creating a cycle. ++ * We need to hold the epmutex across both ep_insert and ep_remove ++ * b/c we want to make sure we are looking at a coherent view of ++ * epoll network. + */ +- if (unlikely(is_file_epoll(tfile) && op == EPOLL_CTL_ADD)) { ++ if (op == EPOLL_CTL_ADD || op == EPOLL_CTL_DEL) { + mutex_lock(&epmutex); + did_lock_epmutex = 1; +- error = -ELOOP; +- if (ep_loop_check(ep, tfile) != 0) +- goto error_tgt_fput; + } +- ++ if (op == EPOLL_CTL_ADD) { ++ if (is_file_epoll(tfile)) { ++ error = -ELOOP; ++ if (ep_loop_check(ep, tfile) != 0) ++ goto error_tgt_fput; ++ } else ++ list_add(&tfile->f_tfile_llink, &tfile_check_list); ++ } + + mutex_lock_nested(&ep->mtx, 0); + +@@ -1437,6 +1612,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, + error = ep_insert(ep, &epds, tfile, fd); + } else + error = -EEXIST; ++ clear_tfile_check_list(); + break; + case EPOLL_CTL_DEL: + if (epi) +@@ -1455,7 +1631,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, + mutex_unlock(&ep->mtx); + + error_tgt_fput: +- if (unlikely(did_lock_epmutex)) ++ if (did_lock_epmutex) + mutex_unlock(&epmutex); + + fput(tfile); +diff --git a/include/linux/eventpoll.h b/include/linux/eventpoll.h +index f362733..657ab55 100644 +--- a/include/linux/eventpoll.h ++++ b/include/linux/eventpoll.h +@@ -61,6 +61,7 @@ struct file; + static inline void eventpoll_init_file(struct file *file) + { + INIT_LIST_HEAD(&file->f_ep_links); ++ INIT_LIST_HEAD(&file->f_tfile_llink); + } + + +diff --git a/include/linux/fs.h b/include/linux/fs.h +index ba98668..d393a68 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -985,6 +985,7 @@ struct file { + #ifdef CONFIG_EPOLL + /* Used by fs/eventpoll.c to link all the hooks to this file */ + struct list_head f_ep_links; ++ struct list_head f_tfile_llink; + #endif /* #ifdef CONFIG_EPOLL */ + struct address_space *f_mapping; + #ifdef CONFIG_DEBUG_WRITECOUNT +-- +1.7.6.4 + diff --git a/ext4-Support-check-none-nocheck-mount-options.patch b/ext4-Support-check-none-nocheck-mount-options.patch new file mode 100644 index 000000000..281e4237a --- /dev/null +++ b/ext4-Support-check-none-nocheck-mount-options.patch @@ -0,0 +1,51 @@ +From ea75f7357e3a881bd1bd0db5e483fc6a8681567b Mon Sep 17 00:00:00 2001 +From: Josh Boyer +Date: Tue, 10 Jan 2012 09:39:02 -0500 +Subject: [PATCH] ext4: Support "check=none" "nocheck" mount options + +The ext2/ext3 filesystems supported "check=none" and "nocheck" as mount options +even though that was already the default behavior and it essentially did +nothing. When using ext4 to mount ext2/ext3 filesystems, that mount option +causes the mount to fail. That isn't as backward compatible as it could be, +so add support to ext4 to accept the option. + +Signed-off-by: Josh Boyer +--- + fs/ext4/super.c | 7 ++++++- + 1 files changed, 6 insertions(+), 1 deletions(-) + +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index 3e1329e..5ff09e7 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -1333,7 +1333,7 @@ enum { + Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity, + Opt_inode_readahead_blks, Opt_journal_ioprio, + Opt_dioread_nolock, Opt_dioread_lock, +- Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable, ++ Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable, Opt_nocheck, + }; + + static const match_table_t tokens = { +@@ -1409,6 +1409,8 @@ static const match_table_t tokens = { + {Opt_init_itable, "init_itable=%u"}, + {Opt_init_itable, "init_itable"}, + {Opt_noinit_itable, "noinit_itable"}, ++ {Opt_nocheck, "check=none"}, ++ {Opt_nocheck, "nocheck"}, + {Opt_err, NULL}, + }; + +@@ -1905,6 +1907,9 @@ set_qf_format: + case Opt_noinit_itable: + clear_opt(sb, INIT_INODE_TABLE); + break; ++ case Opt_nocheck: ++ /* ext2/ext3 used to "support" this option. Silently eat it */ ++ break; + default: + ext4_msg(sb, KERN_ERR, + "Unrecognized mount option \"%s\" " +-- +1.7.7.5 + diff --git a/flexcop-fix-xlate_proc_name-warning.patch b/flexcop-fix-xlate_proc_name-warning.patch deleted file mode 100644 index 82b50a47f..000000000 --- a/flexcop-fix-xlate_proc_name-warning.patch +++ /dev/null @@ -1,30 +0,0 @@ -diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c -index 227c020..7465308 100644 ---- a/drivers/media/dvb/b2c2/flexcop-pci.c -+++ b/drivers/media/dvb/b2c2/flexcop-pci.c -@@ -39,6 +39,7 @@ MODULE_PARM_DESC(debug, - - #define DRIVER_VERSION "0.1" - #define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver" -+#define FLEXCOP_MODULE_NAME "b2c2-flexcop" - #define DRIVER_AUTHOR "Patrick Boettcher " - - struct flexcop_pci { -@@ -299,7 +300,7 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci) - return ret; - pci_set_master(fc_pci->pdev); - -- if ((ret = pci_request_regions(fc_pci->pdev, DRIVER_NAME)) != 0) -+ if ((ret = pci_request_regions(fc_pci->pdev, FLEXCOP_MODULE_NAME)) != 0) - goto err_pci_disable_device; - - fc_pci->io_mem = pci_iomap(fc_pci->pdev, 0, 0x800); -@@ -313,7 +314,7 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci) - pci_set_drvdata(fc_pci->pdev, fc_pci); - spin_lock_init(&fc_pci->irq_lock); - if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr, -- IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0) -+ IRQF_SHARED, FLEXCOP_MODULE_NAME, fc_pci)) != 0) - goto err_pci_iounmap; - - fc_pci->init_state |= FC_PCI_INIT; diff --git a/floppy-drop-disable_hlt-warning.patch b/floppy-drop-disable_hlt-warning.patch new file mode 100644 index 000000000..8f0849e1e --- /dev/null +++ b/floppy-drop-disable_hlt-warning.patch @@ -0,0 +1,13 @@ +diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c +index 9955a53..aef66d1 100644 +--- a/drivers/block/floppy.c ++++ b/drivers/block/floppy.c +@@ -1038,7 +1038,7 @@ static void floppy_disable_hlt(void) + { + unsigned long flags; + +- WARN_ONCE(1, "floppy_disable_hlt() scheduled for removal in 2012"); ++ printk(KERN_INFO "floppy_disable_hlt() scheduled for removal in 2012"); + spin_lock_irqsave(&floppy_hlt_lock, flags); + if (!hlt_disabled) { + hlt_disabled = 1; diff --git a/force-version-2.6.patch b/force-version-2.6.patch new file mode 100644 index 000000000..c53ff9493 --- /dev/null +++ b/force-version-2.6.patch @@ -0,0 +1,11 @@ +--- a/Makefile ++++ b/Makefile +@@ -951,7 +951,7 @@ $(vmlinux-dirs): prepare scripts + # Store (new) KERNELRELASE string in include/config/kernel.release + include/config/kernel.release: include/config/auto.conf FORCE + $(Q)rm -f $@ +- $(Q)echo "$(KERNELVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))" > $@ ++ $(Q)echo "2.6.$$((40 + $(PATCHLEVEL)))$(EXTRAVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))" > $@ + + + # Things we need to do before we recursively start building the kernel diff --git a/fs-call-security_d_instantiate-in-d_obtain_alias.patch b/fs-call-security_d_instantiate-in-d_obtain_alias.patch deleted file mode 100644 index 3bce47f5e..000000000 --- a/fs-call-security_d_instantiate-in-d_obtain_alias.patch +++ /dev/null @@ -1,64 +0,0 @@ -From linux-fsdevel-owner@vger.kernel.org Thu Nov 18 21:03:11 2010 -From: Josef Bacik -To: linux-fsdevel@vger.kernel.org, eparis@redhat.com, - linux-kernel@vger.kernel.org, sds@tycho.nsa.gov, - selinux@tycho.nsa.gov, bfields@fieldses.org -Subject: [PATCH] fs: call security_d_instantiate in d_obtain_alias V2 -Date: Thu, 18 Nov 2010 20:52:55 -0500 -Message-Id: <1290131575-2489-1-git-send-email-josef@redhat.com> -X-Mailing-List: linux-fsdevel@vger.kernel.org - -While trying to track down some NFS problems with BTRFS, I kept noticing I was -getting -EACCESS for no apparent reason. Eric Paris and printk() helped me -figure out that it was SELinux that was giving me grief, with the following -denial - -type=AVC msg=audit(1290013638.413:95): avc: denied { 0x800000 } for pid=1772 -comm="nfsd" name="" dev=sda1 ino=256 scontext=system_u:system_r:kernel_t:s0 -tcontext=system_u:object_r:unlabeled_t:s0 tclass=file - -Turns out this is because in d_obtain_alias if we can't find an alias we create -one and do all the normal instantiation stuff, but we don't do the -security_d_instantiate. - -Usually we are protected from getting a hashed dentry that hasn't yet run -security_d_instantiate() by the parent's i_mutex, but obviously this isn't an -option there, so in order to deal with the case that a second thread comes in -and finds our new dentry before we get to run security_d_instantiate(), we go -ahead and call it if we find a dentry already. Eric assures me that this is ok -as the code checks to see if the dentry has been initialized already so calling -security_d_instantiate() against the same dentry multiple times is ok. With -this patch I'm no longer getting errant -EACCESS values. - -Signed-off-by: Josef Bacik ---- -V1->V2: --added second security_d_instantiate() call - - fs/dcache.c | 3 +++ - 1 files changed, 3 insertions(+), 0 deletions(-) - -diff --git a/fs/dcache.c b/fs/dcache.c -index 5699d4c..85388fc 100644 ---- a/fs/dcache.c -+++ b/fs/dcache.c -@@ -1577,9 +1577,13 @@ struct dentry *d_obtain_alias(struct inode *inode) - spin_unlock(&tmp->d_lock); - spin_unlock(&inode->i_lock); - -+ security_d_instantiate(tmp, inode); -+ - return tmp; - - out_iput: -+ if (res && !IS_ERR(res)) -+ security_d_instantiate(res, inode); - iput(inode); - return res; - } - --- -To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in -the body of a message to majordomo@vger.kernel.org -More majordomo info at http://vger.kernel.org/majordomo-info.html - diff --git a/hda_intel-prealloc-4mb-dmabuffer.patch b/hda_intel-prealloc-4mb-dmabuffer.patch deleted file mode 100644 index 36e6aca4f..000000000 --- a/hda_intel-prealloc-4mb-dmabuffer.patch +++ /dev/null @@ -1,47 +0,0 @@ -From c69fcbd1f60b0842f7c1ad2c95692ffd19c4932b Mon Sep 17 00:00:00 2001 -From: Kyle McMartin -Date: Mon, 29 Mar 2010 23:56:08 -0400 -Subject: hda_intel-prealloc-4mb-dmabuffer - ---- - sound/pci/hda/hda_intel.c | 14 +++++++++++++- - 1 files changed, 13 insertions(+), 1 deletions(-) - -diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c -index 4bb9067..37db515 100644 ---- a/sound/pci/hda/hda_intel.c -+++ b/sound/pci/hda/hda_intel.c -@@ -1986,6 +1986,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, - struct azx_pcm *apcm; - int pcm_dev = cpcm->device; - int s, err; -+ size_t prealloc_min = 64*1024; /* 64KB */ - - if (pcm_dev >= HDA_MAX_PCMS) { - snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n", -@@ -2019,10 +2020,21 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, - if (cpcm->stream[s].substreams) - snd_pcm_set_ops(pcm, s, &azx_pcm_ops); - } -+ - /* buffer pre-allocation */ -+ -+ /* subtle, don't allocate a big buffer for modems... -+ * also, don't just test 32BIT_MASK, since azx supports -+ * 64-bit DMA in some cases. -+ */ -+ /* lennart wants a 2.2MB buffer for 2sec of 48khz */ -+ if (pcm->dev_class == SNDRV_PCM_CLASS_GENERIC && -+ chip->pci->dma_mask >= DMA_32BIT_MASK) -+ prealloc_min = 4 * 1024 * 1024; /* 4MB */ -+ - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(chip->pci), -- 1024 * 64, 32 * 1024 * 1024); -+ prealloc_min, 32 * 1024 * 1024); - return 0; - } - --- -1.7.0.1 - diff --git a/hdpvr-ir-enable.patch b/hdpvr-ir-enable.patch deleted file mode 100644 index e73c42122..000000000 --- a/hdpvr-ir-enable.patch +++ /dev/null @@ -1,229 +0,0 @@ -diff --git a/drivers/media/video/hdpvr/Makefile b/drivers/media/video/hdpvr/Makefile -index e0230fc..3baa9f6 100644 ---- a/drivers/media/video/hdpvr/Makefile -+++ b/drivers/media/video/hdpvr/Makefile -@@ -1,6 +1,4 @@ --hdpvr-objs := hdpvr-control.o hdpvr-core.o hdpvr-video.o -- --hdpvr-$(CONFIG_I2C) += hdpvr-i2c.o -+hdpvr-objs := hdpvr-control.o hdpvr-core.o hdpvr-video.o hdpvr-i2c.o - - obj-$(CONFIG_VIDEO_HDPVR) += hdpvr.o - -diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c -index 830d47b..70cfdc8 100644 ---- a/drivers/media/video/hdpvr/hdpvr-core.c -+++ b/drivers/media/video/hdpvr/hdpvr-core.c -@@ -364,14 +364,13 @@ static int hdpvr_probe(struct usb_interface *interface, - goto error; - } - --#ifdef CONFIG_I2C -- /* until i2c is working properly */ -- retval = 0; /* hdpvr_register_i2c_adapter(dev); */ -+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -+ retval = hdpvr_register_i2c_adapter(dev); - if (retval < 0) { - v4l2_err(&dev->v4l2_dev, "registering i2c adapter failed\n"); - goto error; - } --#endif /* CONFIG_I2C */ -+#endif - - /* let the user know what node this device is now attached to */ - v4l2_info(&dev->v4l2_dev, "device now attached to %s\n", -diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/video/hdpvr/hdpvr-i2c.c -index 463b81b..60cdc06 100644 ---- a/drivers/media/video/hdpvr/hdpvr-i2c.c -+++ b/drivers/media/video/hdpvr/hdpvr-i2c.c -@@ -10,6 +10,8 @@ - * - */ - -+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -+ - #include - #include - -@@ -22,8 +24,11 @@ - #define REQTYPE_I2C_WRITE 0xb0 - #define REQTYPE_I2C_WRITE_STATT 0xd0 - --static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr, -- char *data, int len) -+#define HDPVR_HW_Z8F0811_IR_TX_I2C_ADDR 0x70 -+#define HDPVR_HW_Z8F0811_IR_RX_I2C_ADDR 0x71 -+ -+static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus, -+ unsigned char addr, char *data, int len) - { - int ret; - char *buf = kmalloc(len, GFP_KERNEL); -@@ -33,7 +38,7 @@ static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr, - ret = usb_control_msg(dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - REQTYPE_I2C_READ, CTRL_READ_REQUEST, -- 0x100|addr, 0, buf, len, 1000); -+ (bus << 8) | addr, 0, buf, len, 1000); - - if (ret == len) { - memcpy(data, buf, len); -@@ -46,8 +51,8 @@ static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr, - return ret; - } - --static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr, -- char *data, int len) -+static int hdpvr_i2c_write(struct hdpvr_device *dev, int bus, -+ unsigned char addr, char *data, int len) - { - int ret; - char *buf = kmalloc(len, GFP_KERNEL); -@@ -58,7 +63,7 @@ static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr, - ret = usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), - REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST, -- 0x100|addr, 0, buf, len, 1000); -+ (bus << 8) | addr, 0, buf, len, 1000); - - if (ret < 0) - goto error; -@@ -68,7 +73,7 @@ static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr, - REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST, - 0, 0, buf, 2, 1000); - -- if (ret == 2) -+ if ((ret == 2) && (buf[1] == (len - 1))) - ret = 0; - else if (ret >= 0) - ret = -EIO; -@@ -93,10 +98,10 @@ static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs, - addr = msgs[i].addr << 1; - - if (msgs[i].flags & I2C_M_RD) -- retval = hdpvr_i2c_read(dev, addr, msgs[i].buf, -+ retval = hdpvr_i2c_read(dev, 1, addr, msgs[i].buf, - msgs[i].len); - else -- retval = hdpvr_i2c_write(dev, addr, msgs[i].buf, -+ retval = hdpvr_i2c_write(dev, 1, addr, msgs[i].buf, - msgs[i].len); - } - -@@ -115,30 +120,58 @@ static struct i2c_algorithm hdpvr_algo = { - .functionality = hdpvr_functionality, - }; - -+static struct i2c_adapter hdpvr_i2c_adapter_template = { -+ .name = "Hauppage HD PVR I2C", -+ .owner = THIS_MODULE, -+ .id = I2C_HW_B_HDPVR, -+ .algo = &hdpvr_algo, -+}; -+ -+static struct i2c_board_info hdpvr_i2c_board_info = { -+ I2C_BOARD_INFO("ir_tx_z8f0811_haup", HDPVR_HW_Z8F0811_IR_TX_I2C_ADDR), -+ I2C_BOARD_INFO("ir_rx_z8f0811_haup", HDPVR_HW_Z8F0811_IR_RX_I2C_ADDR), -+}; -+ -+static int hdpvr_activate_ir(struct hdpvr_device *dev) -+{ -+ char buffer[8]; -+ -+ mutex_lock(&dev->i2c_mutex); -+ -+ hdpvr_i2c_read(dev, 0, 0x54, buffer, 1); -+ -+ buffer[0] = 0; -+ buffer[1] = 0x8; -+ hdpvr_i2c_write(dev, 1, 0x54, buffer, 2); -+ -+ buffer[1] = 0x18; -+ hdpvr_i2c_write(dev, 1, 0x54, buffer, 2); -+ -+ mutex_unlock(&dev->i2c_mutex); -+ -+ return 0; -+} -+ - int hdpvr_register_i2c_adapter(struct hdpvr_device *dev) - { -- struct i2c_adapter *i2c_adap; - int retval = -ENOMEM; - -- i2c_adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); -- if (i2c_adap == NULL) -- goto error; -+ hdpvr_activate_ir(dev); - -- strlcpy(i2c_adap->name, "Hauppauge HD PVR I2C", -- sizeof(i2c_adap->name)); -- i2c_adap->algo = &hdpvr_algo; -- i2c_adap->owner = THIS_MODULE; -- i2c_adap->dev.parent = &dev->udev->dev; -+ memcpy(&dev->i2c_adapter, &hdpvr_i2c_adapter_template, -+ sizeof(struct i2c_adapter)); -+ dev->i2c_adapter.dev.parent = &dev->udev->dev; - -- i2c_set_adapdata(i2c_adap, dev); -+ i2c_set_adapdata(&dev->i2c_adapter, dev); - -- retval = i2c_add_adapter(i2c_adap); -+ retval = i2c_add_adapter(&dev->i2c_adapter); -+ if (retval) -+ goto error; - -- if (!retval) -- dev->i2c_adapter = i2c_adap; -- else -- kfree(i2c_adap); -+ i2c_new_device(&dev->i2c_adapter, &hdpvr_i2c_board_info); - - error: - return retval; - } -+ -+#endif -diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c -index c338f3f..26fd9bf 100644 ---- a/drivers/media/video/hdpvr/hdpvr-video.c -+++ b/drivers/media/video/hdpvr/hdpvr-video.c -@@ -1221,12 +1221,9 @@ static void hdpvr_device_release(struct video_device *vdev) - v4l2_device_unregister(&dev->v4l2_dev); - - /* deregister I2C adapter */ --#ifdef CONFIG_I2C -+#if defined(CONFIG_I2C) || (CONFIG_I2C_MODULE) - mutex_lock(&dev->i2c_mutex); -- if (dev->i2c_adapter) -- i2c_del_adapter(dev->i2c_adapter); -- kfree(dev->i2c_adapter); -- dev->i2c_adapter = NULL; -+ i2c_del_adapter(&dev->i2c_adapter); - mutex_unlock(&dev->i2c_mutex); - #endif /* CONFIG_I2C */ - -diff --git a/drivers/media/video/hdpvr/hdpvr.h b/drivers/media/video/hdpvr/hdpvr.h -index b0f046d..2107055 100644 ---- a/drivers/media/video/hdpvr/hdpvr.h -+++ b/drivers/media/video/hdpvr/hdpvr.h -@@ -102,7 +102,7 @@ struct hdpvr_device { - struct work_struct worker; - - /* I2C adapter */ -- struct i2c_adapter *i2c_adapter; -+ struct i2c_adapter i2c_adapter; - /* I2C lock */ - struct mutex i2c_mutex; - -diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h -index 4bef5c5..4385341 100644 ---- a/include/linux/i2c-id.h -+++ b/include/linux/i2c-id.h -@@ -33,5 +33,6 @@ - - /* --- Bit algorithm adapters */ - #define I2C_HW_B_CX2388x 0x01001b /* connexant 2388x based tv cards */ -+#define I2C_HW_B_HDPVR 0x010025 /* Hauppauge HD PVR */ - - #endif /* LINUX_I2C_ID_H */ diff --git a/hibernate-freeze-filesystems.patch b/hibernate-freeze-filesystems.patch new file mode 100644 index 000000000..841cab643 --- /dev/null +++ b/hibernate-freeze-filesystems.patch @@ -0,0 +1,287 @@ +commit b94887bbc0621e1e8402e7f0ec4bc3adf46c9a6e +Author: Rafael J. Wysocki +Date: Fri Feb 17 12:42:08 2012 -0500 + + Freeze all filesystems during system suspend and (kernel-driven) + hibernation by calling freeze_supers() for all superblocks and thaw + them during the subsequent resume with the help of thaw_supers(). + + This makes filesystems stay in a consistent state in case something + goes wrong between system suspend (or hibernation) and the subsequent + resume (e.g. journal replays won't be necessary in those cases). In + particular, this should help to solve a long-standing issue that, in + some cases, during resume from hibernation the boot loader causes the + journal to be replied for the filesystem containing the kernel image + and/or initrd causing it to become inconsistent with the information + stored in the hibernation image. + + The user-space-driven hibernation (s2disk) is not covered by this + change, because the freezing of filesystems prevents s2disk from + accessing device special files it needs to do its job. + + This change is based on earlier work by Nigel Cunningham. + + Signed-off-by: Rafael J. Wysocki + + Rebased to 3.3-rc3 by Josh Boyer + +diff --git a/fs/super.c b/fs/super.c +index 6015c02..c8057fa 100644 +--- a/fs/super.c ++++ b/fs/super.c +@@ -594,6 +594,79 @@ void iterate_supers_type(struct file_system_type *type, + EXPORT_SYMBOL(iterate_supers_type); + + /** ++ * thaw_supers - call thaw_super() for all superblocks ++ */ ++void thaw_supers(void) ++{ ++ struct super_block *sb, *p = NULL; ++ ++ spin_lock(&sb_lock); ++ list_for_each_entry(sb, &super_blocks, s_list) { ++ if (hlist_unhashed(&sb->s_instances)) ++ continue; ++ sb->s_count++; ++ spin_unlock(&sb_lock); ++ ++ if (sb->s_flags & MS_FROZEN) { ++ thaw_super(sb); ++ sb->s_flags &= ~MS_FROZEN; ++ } ++ ++ spin_lock(&sb_lock); ++ if (p) ++ __put_super(p); ++ p = sb; ++ } ++ if (p) ++ __put_super(p); ++ spin_unlock(&sb_lock); ++} ++ ++/** ++ * freeze_supers - call freeze_super() for all superblocks ++ */ ++int freeze_supers(void) ++{ ++ struct super_block *sb, *p = NULL; ++ int error = 0; ++ ++ spin_lock(&sb_lock); ++ /* ++ * Freeze in reverse order so filesystems depending on others are ++ * frozen in the right order (eg. loopback on ext3). ++ */ ++ list_for_each_entry_reverse(sb, &super_blocks, s_list) { ++ if (hlist_unhashed(&sb->s_instances)) ++ continue; ++ sb->s_count++; ++ spin_unlock(&sb_lock); ++ ++ if (sb->s_root && sb->s_frozen != SB_FREEZE_TRANS ++ && !(sb->s_flags & MS_RDONLY)) { ++ error = freeze_super(sb); ++ if (!error) ++ sb->s_flags |= MS_FROZEN; ++ } ++ ++ spin_lock(&sb_lock); ++ if (error) ++ break; ++ if (p) ++ __put_super(p); ++ p = sb; ++ } ++ if (p) ++ __put_super(p); ++ spin_unlock(&sb_lock); ++ ++ if (error) ++ thaw_supers(); ++ ++ return error; ++} ++ ++ ++/** + * get_super - get the superblock of a device + * @bdev: device to get the superblock for + * +diff --git a/include/linux/fs.h b/include/linux/fs.h +index 386da09..a164f4a 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -210,6 +210,7 @@ struct inodes_stat_t { + #define MS_KERNMOUNT (1<<22) /* this is a kern_mount call */ + #define MS_I_VERSION (1<<23) /* Update inode I_version field */ + #define MS_STRICTATIME (1<<24) /* Always perform atime updates */ ++#define MS_FROZEN (1<<25) /* Frozen filesystem */ + #define MS_NOSEC (1<<28) + #define MS_BORN (1<<29) + #define MS_ACTIVE (1<<30) +@@ -2501,6 +2502,8 @@ extern void drop_super(struct super_block *sb); + extern void iterate_supers(void (*)(struct super_block *, void *), void *); + extern void iterate_supers_type(struct file_system_type *, + void (*)(struct super_block *, void *), void *); ++extern int freeze_supers(void); ++extern void thaw_supers(void); + + extern int dcache_dir_open(struct inode *, struct file *); + extern int dcache_dir_close(struct inode *, struct file *); +diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c +index 6d6d288..492fc62 100644 +--- a/kernel/power/hibernate.c ++++ b/kernel/power/hibernate.c +@@ -626,12 +626,17 @@ int hibernate(void) + if (error) + goto Finish; + +- error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); ++ error = freeze_supers(); + if (error) + goto Thaw; ++ ++ error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); ++ if (error) ++ goto Thaw_fs; ++ + if (freezer_test_done) { + freezer_test_done = false; +- goto Thaw; ++ goto Thaw_fs; + } + + if (in_suspend) { +@@ -655,6 +660,8 @@ int hibernate(void) + pr_debug("PM: Image restored successfully.\n"); + } + ++ Thaw_fs: ++ thaw_supers(); + Thaw: + thaw_processes(); + Finish: +diff --git a/kernel/power/power.h b/kernel/power/power.h +index 21724ee..40d6f64 100644 +--- a/kernel/power/power.h ++++ b/kernel/power/power.h +@@ -1,3 +1,4 @@ ++#include + #include + #include + #include +@@ -227,45 +228,3 @@ enum { + #define TEST_MAX (__TEST_AFTER_LAST - 1) + + extern int pm_test_level; +- +-#ifdef CONFIG_SUSPEND_FREEZER +-static inline int suspend_freeze_processes(void) +-{ +- int error; +- +- error = freeze_processes(); +- +- /* +- * freeze_processes() automatically thaws every task if freezing +- * fails. So we need not do anything extra upon error. +- */ +- if (error) +- goto Finish; +- +- error = freeze_kernel_threads(); +- +- /* +- * freeze_kernel_threads() thaws only kernel threads upon freezing +- * failure. So we have to thaw the userspace tasks ourselves. +- */ +- if (error) +- thaw_processes(); +- +- Finish: +- return error; +-} +- +-static inline void suspend_thaw_processes(void) +-{ +- thaw_processes(); +-} +-#else +-static inline int suspend_freeze_processes(void) +-{ +- return 0; +-} +- +-static inline void suspend_thaw_processes(void) +-{ +-} +-#endif +diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c +index 4fd51be..5f51fc7 100644 +--- a/kernel/power/suspend.c ++++ b/kernel/power/suspend.c +@@ -29,6 +29,62 @@ + + #include "power.h" + ++#ifdef CONFIG_SUSPEND_FREEZER ++ ++static inline int suspend_freeze_processes(void) ++{ ++ int error; ++ ++ error = freeze_processes(); ++ ++ /* ++ * freeze_processes() automatically thaws every task if freezing ++ * fails. So we need not do anything extra upon error. ++ */ ++ ++ if (error) ++ goto Finish; ++ ++ error = freeze_supers(); ++ if (error) { ++ thaw_processes(); ++ goto Finish; ++ } ++ ++ error = freeze_kernel_threads(); ++ ++ /* ++ * freeze_kernel_threads() thaws only kernel threads upon freezing ++ * failure. So we have to thaw the userspace tasks ourselves. ++ */ ++ if (error) { ++ thaw_supers(); ++ thaw_processes(); ++ } ++ ++Finish: ++ return error; ++} ++ ++static inline void suspend_thaw_processes(void) ++{ ++ thaw_supers(); ++ thaw_processes(); ++} ++ ++#else /* !CONFIG_SUSPEND_FREEZER */ ++ ++static inline int suspend_freeze_processes(void) ++{ ++ return 0; ++} ++ ++static inline void suspend_thaw_processes(void) ++{ ++} ++ ++#endif /* !CONFIG_SUSPEND_FREEZER */ ++ + const char *const pm_states[PM_SUSPEND_MAX] = { + [PM_SUSPEND_STANDBY] = "standby", + [PM_SUSPEND_MEM] = "mem", diff --git a/hugetlb-fix-resv_map-leak-in-error-path.patch b/hugetlb-fix-resv_map-leak-in-error-path.patch new file mode 100644 index 000000000..888d5ce70 --- /dev/null +++ b/hugetlb-fix-resv_map-leak-in-error-path.patch @@ -0,0 +1,176 @@ +From c50ac050811d6485616a193eb0f37bfbd191cc89 Mon Sep 17 00:00:00 2001 +From: Dave Hansen +Date: Tue, 29 May 2012 15:06:46 -0700 +Subject: [PATCH] hugetlb: fix resv_map leak in error path + +When called for anonymous (non-shared) mappings, hugetlb_reserve_pages() +does a resv_map_alloc(). It depends on code in hugetlbfs's +vm_ops->close() to release that allocation. + +However, in the mmap() failure path, we do a plain unmap_region() without +the remove_vma() which actually calls vm_ops->close(). + +This is a decent fix. This leak could get reintroduced if new code (say, +after hugetlb_reserve_pages() in hugetlbfs_file_mmap()) decides to return +an error. But, I think it would have to unroll the reservation anyway. + +Christoph's test case: + + http://marc.info/?l=linux-mm&m=133728900729735 + +This patch applies to 3.4 and later. A version for earlier kernels is at +https://lkml.org/lkml/2012/5/22/418. + +Signed-off-by: Dave Hansen +Acked-by: Mel Gorman +Acked-by: KOSAKI Motohiro +Reported-by: Christoph Lameter +Tested-by: Christoph Lameter +Cc: Andrea Arcangeli +Cc: [2.6.32+] +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +--- + mm/hugetlb.c | 28 ++++++++++++++++++++++------ + 1 files changed, 22 insertions(+), 6 deletions(-) + +diff --git a/mm/hugetlb.c b/mm/hugetlb.c +index 41a647d..285a81e 100644 +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -2157,6 +2157,15 @@ static void hugetlb_vm_op_open(struct vm_area_struct *vma) + kref_get(&reservations->refs); + } + ++static void resv_map_put(struct vm_area_struct *vma) ++{ ++ struct resv_map *reservations = vma_resv_map(vma); ++ ++ if (!reservations) ++ return; ++ kref_put(&reservations->refs, resv_map_release); ++} ++ + static void hugetlb_vm_op_close(struct vm_area_struct *vma) + { + struct hstate *h = hstate_vma(vma); +@@ -2173,7 +2182,7 @@ static void hugetlb_vm_op_close(struct vm_area_struct *vma) + reserve = (end - start) - + region_count(&reservations->regions, start, end); + +- kref_put(&reservations->refs, resv_map_release); ++ resv_map_put(vma); + + if (reserve) { + hugetlb_acct_memory(h, -reserve); +@@ -2991,12 +3000,16 @@ int hugetlb_reserve_pages(struct inode *inode, + set_vma_resv_flags(vma, HPAGE_RESV_OWNER); + } + +- if (chg < 0) +- return chg; ++ if (chg < 0) { ++ ret = chg; ++ goto out_err; ++ } + + /* There must be enough pages in the subpool for the mapping */ +- if (hugepage_subpool_get_pages(spool, chg)) +- return -ENOSPC; ++ if (hugepage_subpool_get_pages(spool, chg)) { ++ ret = -ENOSPC; ++ goto out_err; ++ } + + /* + * Check enough hugepages are available for the reservation. +@@ -3005,7 +3018,7 @@ int hugetlb_reserve_pages(struct inode *inode, + ret = hugetlb_acct_memory(h, chg); + if (ret < 0) { + hugepage_subpool_put_pages(spool, chg); +- return ret; ++ goto out_err; + } + + /* +@@ -3022,6 +3035,9 @@ int hugetlb_reserve_pages(struct inode *inode, + if (!vma || vma->vm_flags & VM_MAYSHARE) + region_add(&inode->i_mapping->private_list, from, to); + return 0; ++out_err: ++ resv_map_put(vma); ++ return ret; + } + + void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed) +-- +1.7.7.6 + +From 4523e1458566a0e8ecfaff90f380dd23acc44d27 Mon Sep 17 00:00:00 2001 +From: Dave Hansen +Date: Wed, 30 May 2012 07:51:07 -0700 +Subject: [PATCH] mm: fix vma_resv_map() NULL pointer + +hugetlb_reserve_pages() can be used for either normal file-backed +hugetlbfs mappings, or MAP_HUGETLB. In the MAP_HUGETLB, semi-anonymous +mode, there is not a VMA around. The new call to resv_map_put() assumed +that there was, and resulted in a NULL pointer dereference: + + BUG: unable to handle kernel NULL pointer dereference at 0000000000000030 + IP: vma_resv_map+0x9/0x30 + PGD 141453067 PUD 1421e1067 PMD 0 + Oops: 0000 [#1] PREEMPT SMP + ... + Pid: 14006, comm: trinity-child6 Not tainted 3.4.0+ #36 + RIP: vma_resv_map+0x9/0x30 + ... + Process trinity-child6 (pid: 14006, threadinfo ffff8801414e0000, task ffff8801414f26b0) + Call Trace: + resv_map_put+0xe/0x40 + hugetlb_reserve_pages+0xa6/0x1d0 + hugetlb_file_setup+0x102/0x2c0 + newseg+0x115/0x360 + ipcget+0x1ce/0x310 + sys_shmget+0x5a/0x60 + system_call_fastpath+0x16/0x1b + +This was reported by Dave Jones, but was reproducible with the +libhugetlbfs test cases, so shame on me for not running them in the +first place. + +With this, the oops is gone, and the output of libhugetlbfs's +run_tests.py is identical to plain 3.4 again. + +[ Marked for stable, since this was introduced by commit c50ac050811d + ("hugetlb: fix resv_map leak in error path") which was also marked for + stable ] + +Reported-by: Dave Jones +Cc: Mel Gorman +Cc: KOSAKI Motohiro +Cc: Christoph Lameter +Cc: Andrea Arcangeli +Cc: Andrew Morton +Cc: [2.6.32+] +Signed-off-by: Linus Torvalds +--- + mm/hugetlb.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +diff --git a/mm/hugetlb.c b/mm/hugetlb.c +index 285a81e..e198831 100644 +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -3036,7 +3036,8 @@ int hugetlb_reserve_pages(struct inode *inode, + region_add(&inode->i_mapping->private_list, from, to); + return 0; + out_err: +- resv_map_put(vma); ++ if (vma) ++ resv_map_put(vma); + return ret; + } + +-- +1.7.7.6 + diff --git a/ima-allow-it-to-be-completely-disabled-and-default-off.patch b/ima-allow-it-to-be-completely-disabled-and-default-off.patch deleted file mode 100644 index 4f8f1f180..000000000 --- a/ima-allow-it-to-be-completely-disabled-and-default-off.patch +++ /dev/null @@ -1,145 +0,0 @@ -From 785465d9cffd65b5a69dd2f465d2f7c917713220 Mon Sep 17 00:00:00 2001 -From: Kyle McMartin -Date: Mon, 18 Oct 2010 13:30:39 -0400 -Subject: [PATCH] ima: provide a toggle to disable it entirely - -Signed-off-by: Kyle McMartin ---- - security/integrity/ima/ima.h | 1 + - security/integrity/ima/ima_iint.c | 9 +++++++++ - security/integrity/ima/ima_main.c | 24 +++++++++++++++++++++--- - 3 files changed, 31 insertions(+), 3 deletions(-) - -diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h -index 3fbcd1d..65c3977 100644 ---- a/security/integrity/ima/ima.h -+++ b/security/integrity/ima/ima.h -@@ -37,6 +37,7 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; - /* set during initialization */ - extern int iint_initialized; - extern int ima_initialized; -+extern int ima_enabled; - extern int ima_used_chip; - extern char *ima_hash; - -diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c -index afba4ae..3d191ef 100644 ---- a/security/integrity/ima/ima_iint.c -+++ b/security/integrity/ima/ima_iint.c -@@ -54,6 +54,9 @@ int ima_inode_alloc(struct inode *inode) - struct ima_iint_cache *iint = NULL; - int rc = 0; - -+ if (!ima_enabled) -+ return 0; -+ - iint = kmem_cache_alloc(iint_cache, GFP_NOFS); - if (!iint) - return -ENOMEM; -@@ -116,6 +119,9 @@ void ima_inode_free(struct inode *inode) - { - struct ima_iint_cache *iint; - -+ if (!ima_enabled) -+ return; -+ - spin_lock(&ima_iint_lock); - iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode); - spin_unlock(&ima_iint_lock); -@@ -139,6 +145,9 @@ static void init_once(void *foo) - - static int __init ima_iintcache_init(void) - { -+ if (!ima_enabled) -+ return 0; -+ - iint_cache = - kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0, - SLAB_PANIC, init_once); -diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c -index e662b89..6e91905 100644 ---- a/security/integrity/ima/ima_main.c -+++ b/security/integrity/ima/ima_main.c -@@ -26,6 +26,7 @@ - #include "ima.h" - - int ima_initialized; -+int ima_enabled; - - char *ima_hash = "sha1"; - static int __init hash_setup(char *str) -@@ -36,6 +37,14 @@ static int __init hash_setup(char *str) - } - __setup("ima_hash=", hash_setup); - -+static int __init ima_enable(char *str) -+{ -+ if (strncmp(str, "on", 2) == 0) -+ ima_enabled = 1; -+ return 1; -+} -+__setup("ima=", ima_enable); -+ - struct ima_imbalance { - struct hlist_node node; - unsigned long fsmagic; -@@ -148,7 +157,7 @@ void ima_counts_get(struct file *file) - struct ima_iint_cache *iint; - int rc; - -- if (!iint_initialized || !S_ISREG(inode->i_mode)) -+ if (!ima_enabled || !iint_initialized || !S_ISREG(inode->i_mode)) - return; - iint = ima_iint_find_get(inode); - if (!iint) -@@ -215,7 +224,7 @@ void ima_file_free(struct file *file) - struct inode *inode = file->f_dentry->d_inode; - struct ima_iint_cache *iint; - -- if (!iint_initialized || !S_ISREG(inode->i_mode)) -+ if (!ima_enabled || !iint_initialized || !S_ISREG(inode->i_mode)) - return; - iint = ima_iint_find_get(inode); - if (!iint) -@@ -269,7 +278,7 @@ int ima_file_mmap(struct file *file, unsigned long prot) - { - int rc; - -- if (!file) -+ if (!ima_enabled || !file) - return 0; - if (prot & PROT_EXEC) - rc = process_measurement(file, file->f_dentry->d_name.name, -@@ -294,6 +303,9 @@ int ima_bprm_check(struct linux_binprm *bprm) - { - int rc; - -+ if (!ima_enabled) -+ return 0; -+ - rc = process_measurement(bprm->file, bprm->filename, - MAY_EXEC, BPRM_CHECK); - return 0; -@@ -313,6 +325,9 @@ int ima_file_check(struct file *file, int mask) - { - int rc; - -+ if (!ima_enabled) -+ return 0; -+ - rc = process_measurement(file, file->f_dentry->d_name.name, - mask & (MAY_READ | MAY_WRITE | MAY_EXEC), - FILE_CHECK); -@@ -324,6 +339,9 @@ static int __init init_ima(void) - { - int error; - -+ if (!ima_enabled) -+ return 0; -+ - error = ima_init(); - ima_initialized = 1; - return error; --- -1.7.3.1 - diff --git a/ipw2x00-add-supported-cipher-suites-to-wiphy-initialization.patch b/ipw2x00-add-supported-cipher-suites-to-wiphy-initialization.patch new file mode 100644 index 000000000..705c5eff0 --- /dev/null +++ b/ipw2x00-add-supported-cipher-suites-to-wiphy-initialization.patch @@ -0,0 +1,155 @@ +Path: news.gmane.org!not-for-mail +From: Stanislav Yakovlev +Newsgroups: gmane.linux.kernel.wireless.general +Subject: [PATCH] net/wireless: ipw2x00: add supported cipher suites to wiphy initialization +Date: Tue, 10 Apr 2012 21:44:47 -0400 +Lines: 97 +Approved: news@gmane.org +Message-ID: <1334108687-12954-1-git-send-email-stas.yakovlev@gmail.com> +NNTP-Posting-Host: plane.gmane.org +X-Trace: dough.gmane.org 1334108469 22291 80.91.229.3 (11 Apr 2012 01:41:09 GMT) +X-Complaints-To: usenet@dough.gmane.org +NNTP-Posting-Date: Wed, 11 Apr 2012 01:41:09 +0000 (UTC) +Cc: simar-hi6Y0CQ0nG0@public.gmane.org, linux-wireless-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, + Stanislav Yakovlev +To: linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org +Original-X-From: linux-wireless-owner-u79uwXL29TY76Z2rM5mHXA@public.gmane.org Wed Apr 11 03:41:07 2012 +Return-path: +Envelope-to: glkwg-linux-wireless-wOFGN7rlS/M9smdsby/KFg@public.gmane.org +Original-Received: from vger.kernel.org ([209.132.180.67]) + by plane.gmane.org with esmtp (Exim 4.69) + (envelope-from ) + id 1SHmYV-0004IK-CT + for glkwg-linux-wireless-wOFGN7rlS/M9smdsby/KFg@public.gmane.org; Wed, 11 Apr 2012 03:41:07 +0200 +Original-Received: (majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org) by vger.kernel.org via listexpand + id S1759898Ab2DKBlF (ORCPT + ); + Tue, 10 Apr 2012 21:41:05 -0400 +Original-Received: from mail-ob0-f174.google.com ([209.85.214.174]:60108 "EHLO + mail-ob0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org + with ESMTP id S1753779Ab2DKBlE (ORCPT + ); + Tue, 10 Apr 2012 21:41:04 -0400 +Original-Received: by obbtb18 with SMTP id tb18so567970obb.19 + for ; Tue, 10 Apr 2012 18:41:02 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=gmail.com; s=20120113; + h=from:to:cc:subject:date:message-id:x-mailer; + bh=8+D+Uuo0bIOG6rz8vxd6TGAxmrbuAw2bjWhd058IjOQ=; + b=beOgy1Y9ZAV1Xw5XqsnPDJ1Oc0qOpOo+gCWlwmWbLdVHxUVG+ZVuRW9eCRQkh+5bZm + 5Ic+xOISztYUJp144Fr4flnbGPRKKp7jP8qQ/HvCOo34J6MCgBlnuWNYKbn4/NUvOYAh + SeHpk2D8yOHbiWAMV+JGTqGG+/N4jVvRL147Yg1IfNDAJd8Ahbl0wARLOVg8WGGTSPvn + MU3HNbmKFFBDhnukYr4keCnjixuDkqPYGMYuDrsmKdiAFHBRDI6qudnvaqi8F8gbtaWg + dfssdTbmNYM/R/PJenInoy7IbRps2iW9ZX+zFzydZWp2EyJ4EZkKrYKmnezQgNJzRVex + KHfg== +Original-Received: by 10.60.24.9 with SMTP id q9mr19071024oef.4.1334108462648; + Tue, 10 Apr 2012 18:41:02 -0700 (PDT) +Original-Received: from localhost.localdomain (50-0-191-227.dsl.static.sonic.net. [50.0.191.227]) + by mx.google.com with ESMTPS id tx2sm1309336obb.8.2012.04.10.18.40.54 + (version=TLSv1/SSLv3 cipher=OTHER); + Tue, 10 Apr 2012 18:41:01 -0700 (PDT) +X-Mailer: git-send-email 1.7.2.5 +Original-Sender: linux-wireless-owner-u79uwXL29TY76Z2rM5mHXA@public.gmane.org +Precedence: bulk +List-ID: +X-Mailing-List: linux-wireless-u79uwXL29TY76Z2rM5mHXA@public.gmane.org +Xref: news.gmane.org gmane.linux.kernel.wireless.general:88613 +Archived-At: + +Driver doesn't report its supported cipher suites through cfg80211 +interface. It still uses wext interface and probably will not work +through nl80211, but will at least correctly advertise supported +features. + +Bug was reported by Omar Siam. +https://bugzilla.kernel.org/show_bug.cgi?id=43049 + +Signed-off-by: Stanislav Yakovlev +--- + drivers/net/wireless/ipw2x00/ipw.h | 23 +++++++++++++++++++++++ + drivers/net/wireless/ipw2x00/ipw2100.c | 4 ++++ + drivers/net/wireless/ipw2x00/ipw2200.c | 4 ++++ + 3 files changed, 31 insertions(+), 0 deletions(-) + create mode 100644 drivers/net/wireless/ipw2x00/ipw.h + +diff --git a/drivers/net/wireless/ipw2x00/ipw.h b/drivers/net/wireless/ipw2x00/ipw.h +new file mode 100644 +index 0000000..4007bf5 +--- /dev/null ++++ b/drivers/net/wireless/ipw2x00/ipw.h +@@ -0,0 +1,23 @@ ++/* ++ * Intel Pro/Wireless 2100, 2200BG, 2915ABG network connection driver ++ * ++ * Copyright 2012 Stanislav Yakovlev ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __IPW_H__ ++#define __IPW_H__ ++ ++#include ++ ++static const u32 ipw_cipher_suites[] = { ++ WLAN_CIPHER_SUITE_WEP40, ++ WLAN_CIPHER_SUITE_WEP104, ++ WLAN_CIPHER_SUITE_TKIP, ++ WLAN_CIPHER_SUITE_CCMP, ++}; ++ ++#endif +diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c +index f0551f8..7c8e8b1 100644 +--- a/drivers/net/wireless/ipw2x00/ipw2100.c ++++ b/drivers/net/wireless/ipw2x00/ipw2100.c +@@ -166,6 +166,7 @@ that only one external action is invoked at a time. + #include + + #include "ipw2100.h" ++#include "ipw.h" + + #define IPW2100_VERSION "git-1.2.2" + +@@ -1946,6 +1947,9 @@ static int ipw2100_wdev_init(struct net_device *dev) + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = bg_band; + } + ++ wdev->wiphy->cipher_suites = ipw_cipher_suites; ++ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(ipw_cipher_suites); ++ + set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev); + if (wiphy_register(wdev->wiphy)) { + ipw2100_down(priv); +diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c +index 2b02257..bb4f42a 100644 +--- a/drivers/net/wireless/ipw2x00/ipw2200.c ++++ b/drivers/net/wireless/ipw2x00/ipw2200.c +@@ -34,6 +34,7 @@ + #include + #include + #include "ipw2200.h" ++#include "ipw.h" + + + #ifndef KBUILD_EXTMOD +@@ -11533,6 +11534,9 @@ static int ipw_wdev_init(struct net_device *dev) + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = a_band; + } + ++ wdev->wiphy->cipher_suites = ipw_cipher_suites; ++ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(ipw_cipher_suites); ++ + set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev); + + /* With that information in place, we can now register the wiphy... */ +-- +1.7.2.5 + +-- +To unsubscribe from this list: send the line "unsubscribe linux-wireless" in +the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org +More majordomo info at http://vger.kernel.org/majordomo-info.html + diff --git a/iwlagn-check-for-priv--txq-in-iwlagn_wait_tx_queue_empty.patch b/iwlagn-check-for-priv--txq-in-iwlagn_wait_tx_queue_empty.patch new file mode 100644 index 000000000..855a30da7 --- /dev/null +++ b/iwlagn-check-for-priv--txq-in-iwlagn_wait_tx_queue_empty.patch @@ -0,0 +1,14 @@ +diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +index f803fb6..d6ae444 100644 +--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c ++++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +@@ -1487,6 +1487,9 @@ int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv) + unsigned long now = jiffies; + int ret = 0; + ++ if (!priv->txq) ++ return 0; ++ + /* waiting for all the tx frames complete might take a while */ + for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) { + if (cnt == priv->cmd_queue) diff --git a/jbd-jbd2-validate-sb-s_first-in-journal_get_superblo.patch b/jbd-jbd2-validate-sb-s_first-in-journal_get_superblo.patch new file mode 100644 index 000000000..f5d82914f --- /dev/null +++ b/jbd-jbd2-validate-sb-s_first-in-journal_get_superblo.patch @@ -0,0 +1,95 @@ +From 8762202dd0d6e46854f786bdb6fb3780a1625efe Mon Sep 17 00:00:00 2001 +From: Eryu Guan +Date: Tue, 1 Nov 2011 19:04:59 -0400 +Subject: [PATCH] jbd/jbd2: validate sb->s_first in journal_get_superblock() + +I hit a J_ASSERT(blocknr != 0) failure in cleanup_journal_tail() when +mounting a fsfuzzed ext3 image. It turns out that the corrupted ext3 +image has s_first = 0 in journal superblock, and the 0 is passed to +journal->j_head in journal_reset(), then to blocknr in +cleanup_journal_tail(), in the end the J_ASSERT failed. + +So validate s_first after reading journal superblock from disk in +journal_get_superblock() to ensure s_first is valid. + +The following script could reproduce it: + +fstype=ext3 +blocksize=1024 +img=$fstype.img +offset=0 +found=0 +magic="c0 3b 39 98" + +dd if=/dev/zero of=$img bs=1M count=8 +mkfs -t $fstype -b $blocksize -F $img +filesize=`stat -c %s $img` +while [ $offset -lt $filesize ] +do + if od -j $offset -N 4 -t x1 $img | grep -i "$magic";then + echo "Found journal: $offset" + found=1 + break + fi + offset=`echo "$offset+$blocksize" | bc` +done + +if [ $found -ne 1 ];then + echo "Magic \"$magic\" not found" + exit 1 +fi + +dd if=/dev/zero of=$img seek=$(($offset+23)) conv=notrunc bs=1 count=1 + +mkdir -p ./mnt +mount -o loop $img ./mnt + +Cc: Jan Kara +Signed-off-by: Eryu Guan +Signed-off-by: "Theodore Ts'o" +--- + fs/jbd/journal.c | 8 ++++++++ + fs/jbd2/journal.c | 8 ++++++++ + 2 files changed, 16 insertions(+), 0 deletions(-) + +diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c +index 9fe061f..fea8dd6 100644 +--- a/fs/jbd/journal.c ++++ b/fs/jbd/journal.c +@@ -1135,6 +1135,14 @@ static int journal_get_superblock(journal_t *journal) + goto out; + } + ++ if (be32_to_cpu(sb->s_first) == 0 || ++ be32_to_cpu(sb->s_first) >= journal->j_maxlen) { ++ printk(KERN_WARNING ++ "JBD: Invalid start block of journal: %u\n", ++ be32_to_cpu(sb->s_first)); ++ goto out; ++ } ++ + return 0; + + out: +diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c +index f24df13..d6e93d0 100644 +--- a/fs/jbd2/journal.c ++++ b/fs/jbd2/journal.c +@@ -1251,6 +1251,14 @@ static int journal_get_superblock(journal_t *journal) + goto out; + } + ++ if (be32_to_cpu(sb->s_first) == 0 || ++ be32_to_cpu(sb->s_first) >= journal->j_maxlen) { ++ printk(KERN_WARNING ++ "JBD2: Invalid start block of journal: %u\n", ++ be32_to_cpu(sb->s_first)); ++ goto out; ++ } ++ + return 0; + + out: +-- +1.7.7.1 + diff --git a/kernel.spec b/kernel.spec index 43e9a3a2d..c61d484d5 100644 --- a/kernel.spec +++ b/kernel.spec @@ -3,11 +3,6 @@ Summary: The Linux kernel -# For a stable, released kernel, released_kernel should be 1. For rawhide -# and/or a kernel built from an rc or git snapshot, released_kernel should -# be 0. -%global released_kernel 1 - # Save original buildid for later if it's defined %if 0%{?buildid:1} %global orig_buildid %{buildid} @@ -44,26 +39,19 @@ Summary: The Linux kernel # # We used to have some extra magic weirdness to bump this automatically, # but now we don't. Just use: rpmdev-bumpspec -c 'comment for changelog' -# When changing base_sublevel below or going from rc to a final kernel, -# reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). -# scripts/rebase.sh should be made to do that for you, actually. +# When changing real_sublevel below, reset this by hand to 1 +# (or to 0 and then use rpmdev-bumpspec). # -# For non-released -rc kernels, this will be prepended with "0.", so -# for example a 3 here will become 0.3 -# -%global baserelease 1 +%global baserelease 2 %global fedora_build %{baserelease} -# base_sublevel is the kernel version we're starting with and patching -# on top of -- for example, 2.6.22-rc7-git1 starts with a 2.6.21 base, -# which yields a base_sublevel of 21. -%define base_sublevel 38 - -## If this is a released kernel ## -%if 0%{?released_kernel} +# real_sublevel is the 3.x kernel version we're starting with +%define real_sublevel 3 +# fake_sublevel is the 2.6.x version we're faking +%define fake_sublevel %(echo $((40 + %{real_sublevel}))) # Do we have a -stable update to apply? -%define stable_update 0 +%define stable_update 8 # Is it a -stable RC? %define stable_rc 0 # Set rpm version accordingly @@ -75,20 +63,7 @@ Summary: The Linux kernel %define stable_base %(echo $((%{stable_update} - 1))) %endif %endif -%define rpmversion 2.6.%{base_sublevel}%{?stablerev} - -## The not-released-kernel case ## -%else -# The next upstream release sublevel (base_sublevel+1) -%define upstream_sublevel %(echo $((%{base_sublevel} + 1))) -# The rc snapshot level -%define rcrev 8 -# The git snapshot level -%define gitrev 4 -# Set rpm version accordingly -%define rpmversion 2.6.%{upstream_sublevel} -%endif -# Nb: The above rcrev and gitrev values automagically define Patch00 and Patch01 below. +%define rpmversion 2.6.%{fake_sublevel}%{?stablerev} # What parts do we want to build? We must build at least one kernel. # These are the kernels that are built IF the architecture allows it. @@ -121,14 +96,20 @@ Summary: The Linux kernel %define with_bootwrapper %{?_without_bootwrapper: 0} %{?!_without_bootwrapper: 1} # Want to build a the vsdo directories installed %define with_vdso_install %{?_without_vdso_install: 0} %{?!_without_vdso_install: 1} +# ARM OMAP (Beagle/Panda Board) +%define with_omap %{?_without_omap: 0} %{?!_without_omap: 1} +# kernel-tegra (only valid for arm) +%define with_tegra %{?_without_tegra: 0} %{?!_without_tegra: 1} +# kernel-kirkwood (only valid for arm) +%define with_kirkwood %{?_without_kirkwood: 0} %{?!_without_kirkwood: 1} +# kernel-imx (only valid for arm) +%define with_imx %{?_without_imx: 0} %{?!_without_imx: 1} +# kernel-highbank (only valid for arm) +%define with_highbank %{?_without_highbank: 0} %{?!_without_highbank: 1} # Build the kernel-doc package, but don't fail the build if it botches. # Here "true" means "continue" and "false" means "fail the build". -%if 0%{?released_kernel} %define doc_build_fail false -%else -%define doc_build_fail true -%endif %define rawhide_skip_docs 0 %if 0%{?rawhide_skip_docs} @@ -159,32 +140,17 @@ Summary: The Linux kernel %define with_vanilla %{?_with_vanilla: 1} %{?!_with_vanilla: 0} # pkg_release is what we'll fill in for the rpm Release: field -%if 0%{?released_kernel} %if 0%{?stable_rc} %define stable_rctag .rc%{stable_rc} -%endif -%define pkg_release %{fedora_build}%{?stable_rctag}%{?buildid}%{?dist} - +%define pkg_release 0%{stable_rctag}.%{fedora_build}%{?buildid}%{?dist} %else - -# non-released_kernel -%if 0%{?rcrev} -%define rctag .rc%rcrev -%else -%define rctag .rc0 -%endif -%if 0%{?gitrev} -%define gittag .git%gitrev -%else -%define gittag .git0 -%endif -%define pkg_release 0%{?rctag}%{?gittag}.%{fedora_build}%{?buildid}%{?dist} - +%define pkg_release %{fedora_build}%{?buildid}%{?dist} %endif # The kernel tarball/base version -%define kversion 2.6.%{base_sublevel} +%define realversion 3.%{real_sublevel} +%define fakeversion 2.6.%{fake_sublevel} %define make_target bzImage @@ -229,6 +195,19 @@ Summary: The Linux kernel %define with_pae 0 %endif +# kernel-tegra, omap, imx and highbank are only built on armv7 hard and softfp +%ifnarch armv7hl armv7l +%define with_tegra 0 +%define with_omap 0 +%define with_imx 0 +%define with_highbank 0 +%endif + +# kernel-kirkwood is only built for armv5 +%ifnarch armv5tel +%define with_kirkwood 0 +%endif + # if requested, only build base kernel %if %{with_baseonly} %define with_smp 0 @@ -338,14 +317,13 @@ Summary: The Linux kernel %define image_install_path boot %define make_target image %define kernel_image arch/s390/boot/image -%define with_perf 0 %endif %ifarch sparc64 %define asmarch sparc %define all_arch_configs kernel-%{version}-sparc64*.config -%define make_target image -%define kernel_image arch/sparc/boot/image +%define make_target vmlinux +%define kernel_image vmlinux %define image_install_path boot %define with_perf 0 %endif @@ -364,26 +342,26 @@ Summary: The Linux kernel %define kernel_image_elf 1 %endif -%ifarch ia64 -%define all_arch_configs kernel-%{version}-ia64*.config -%define image_install_path boot/efi/EFI/redhat -%define make_target compressed -%define kernel_image vmlinux.gz -%endif - -%ifarch alpha alphaev56 -%define all_arch_configs kernel-%{version}-alpha*.config -%define image_install_path boot -%define make_target vmlinux -%define kernel_image vmlinux -%endif - %ifarch %{arm} %define all_arch_configs kernel-%{version}-arm*.config %define image_install_path boot +%define asmarch arm %define hdrarch arm -%define make_target vmlinux -%define kernel_image vmlinux +%define make_target bzImage +%define kernel_image arch/arm/boot/zImage +# we build a up kernel on armv5tel. its used for qemu. +%ifnarch armv5tel +%define with_up 0 +%define with_perf 0 +%endif +%ifarch armv7hl +%define with_perf 1 +%endif +# we only build headers on the base arm arches +# just like we used to only build them on i386 for x86 +%ifnarch armv5tel armv7hl +%define with_headers 0 +%endif %endif %if %{nopatches} @@ -406,7 +384,7 @@ Summary: The Linux kernel # Which is a BadThing(tm). # We only build kernel-headers on the following... -%define nobuildarches i386 s390 sparc sparcv9 %{arm} +%define nobuildarches i386 s390 sparc sparcv9 %ifarch %nobuildarches %define with_up 0 @@ -431,7 +409,7 @@ Summary: The Linux kernel # First the general kernel 2.6 required versions as per # Documentation/Changes # -%define kernel_dot_org_conflicts ppp < 2.4.3-3, isdn4k-utils < 3.2-32, nfs-utils < 1.0.7-12, e2fsprogs < 1.37-4, util-linux < 2.12, jfsutils < 1.1.7-2, reiserfs-utils < 3.6.19-2, xfsprogs < 2.6.13-4, procps < 3.2.5-6.3, oprofile < 0.9.1-2 +%define kernel_dot_org_conflicts ppp < 2.4.3-3, isdn4k-utils < 3.2-32, nfs-utils < 1.0.7-12, e2fsprogs < 1.37-4, util-linux < 2.12, jfsutils < 1.1.7-2, reiserfs-utils < 3.6.19-2, xfsprogs < 2.6.13-4, procps < 3.2.5-6.3, oprofile < 0.9.1-2, device-mapper-libs < 1.02.63-2, mdadm < 3.2.1-5 # # Then a series of requirements that are distribution specific, either @@ -449,7 +427,7 @@ Summary: The Linux kernel # Packages that need to be installed before the kernel is, because the %%post # scripts use them. # -%define kernel_prereq fileutils, module-init-tools, initscripts >= 8.11.1-1, grubby >= 7.0.10-1 +%define kernel_prereq fileutils, module-init-tools >= 3.16-2, initscripts >= 8.11.1-1, grubby >= 7.0.16-5 %define initrd_prereq dracut >= 001-7 # @@ -470,7 +448,7 @@ Requires(pre): %{initrd_prereq}\ %if %{with_firmware}\ Requires(pre): kernel-firmware >= %{rpmversion}-%{pkg_release}\ %else\ -Requires(pre): linux-firmware >= 20100806-2\ +Requires(pre): linux-firmware >= 20120206-0.1.git06c8f81\ %endif\ Requires(post): /sbin/new-kernel-pkg\ Requires(preun): /sbin/new-kernel-pkg\ @@ -494,7 +472,7 @@ Version: %{rpmversion} Release: %{pkg_release} # DO NOT CHANGE THE 'ExclusiveArch' LINE TO TEMPORARILY EXCLUDE AN ARCHITECTURE BUILD. # SET %%nobuildarches (ABOVE) INSTEAD -ExclusiveArch: noarch %{all_x86} x86_64 ppc ppc64 ia64 %{sparc} s390 s390x alpha alphaev56 %{arm} +ExclusiveArch: noarch %{all_x86} x86_64 ppc ppc64 %{sparc} s390 s390x alpha alphaev56 %{arm} ExclusiveOS: Linux %kernel_reqprovconf @@ -503,7 +481,7 @@ ExclusiveOS: Linux # List the packages used during the kernel build # BuildRequires: module-init-tools, patch >= 2.5.4, bash >= 2.03, sh-utils, tar -BuildRequires: bzip2, findutils, gzip, m4, perl, make >= 3.78, diffutils, gawk +BuildRequires: bzip2, xz, findutils, gzip, m4, perl, make >= 3.78, diffutils, gawk BuildRequires: gcc >= 3.4.2, binutils >= 2.12, redhat-rpm-config BuildRequires: net-tools BuildRequires: xmlto, asciidoc @@ -528,7 +506,7 @@ BuildRequires: rpm-build >= 4.4.2.1-4 %define debuginfo_args --strict-build-id %endif -Source0: ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-%{kversion}.tar.bz2 +Source0: ftp://ftp.kernel.org/pub/linux/kernel/v3.x/linux-%{realversion}.tar.xz Source11: genkey Source14: find-provides @@ -542,6 +520,7 @@ Source24: config-rhel-generic Source30: config-x86-generic Source31: config-i686-PAE +Source32: config-x86-32-generic Source40: config-x86_64-generic @@ -550,13 +529,16 @@ Source51: config-powerpc32-generic Source52: config-powerpc32-smp Source53: config-powerpc64 -Source60: config-ia64-generic - Source70: config-s390x Source90: config-sparc64-generic -Source100: config-arm +Source100: config-arm-generic +Source110: config-arm-omap-generic +Source111: config-arm-tegra +Source112: config-arm-kirkwood +Source113: config-arm-imx +Source114: config-arm-highbank # This file is intentionally left empty in the stock kernel. Its a nicety # added for those wanting to do custom rebuilds with altered config opts. @@ -567,36 +549,17 @@ Source1000: config-local # For a stable release kernel %if 0%{?stable_update} %if 0%{?stable_base} -%define stable_patch_00 patch-2.6.%{base_sublevel}.%{stable_base}.bz2 +%define stable_patch_00 patch-3.%{real_sublevel}.%{stable_base}.xz Patch00: %{stable_patch_00} %endif %if 0%{?stable_rc} -%define stable_patch_01 patch-2.6.%{base_sublevel}.%{stable_update}-rc%{stable_rc}.bz2 +%define stable_patch_01 patch-3.%{real_sublevel}.%{stable_update}-rc%{stable_rc}.xz Patch01: %{stable_patch_01} %endif - -# non-released_kernel case -# These are automagically defined by the rcrev and gitrev values set up -# near the top of this spec file. -%else -%if 0%{?rcrev} -Patch00: patch-2.6.%{upstream_sublevel}-rc%{rcrev}.bz2 -%if 0%{?gitrev} -Patch01: patch-2.6.%{upstream_sublevel}-rc%{rcrev}-git%{gitrev}.bz2 -%endif -%else -# pre-{base_sublevel+1}-rc1 case -%if 0%{?gitrev} -Patch00: patch-2.6.%{base_sublevel}-git%{gitrev}.bz2 -%endif -%endif %endif -%if %{using_upstream_branch} -### BRANCH PATCH ### -%endif - -Patch02: git-linus.diff +# Patches from git://git.kernel.org/pub/scm/linux/kernel/git/stable/stable-queue.git +Patch02: stable-queue.patch # we also need compile fixes for -vanilla Patch04: linux-2.6-compile-fixes.patch @@ -612,50 +575,33 @@ Patch09: linux-2.6-upstream-reverts.patch # Git trees. # Standalone patches -Patch20: linux-2.6-hotfixes.patch - -Patch29: linux-2.6-utrace-revert-make-ptrace-functions-static.patch -Patch30: linux-2.6-tracehook.patch -Patch31: linux-2.6-utrace.patch -Patch32: linux-2.6-utrace-ptrace.patch - -Patch150: linux-2.6.29-sparc-IOC_TYPECHECK.patch -Patch151: sparc64_fix_build_errors_with_gcc460.patch +Patch100: taint-vbox.patch Patch160: linux-2.6-32bit-mmap-exec-randomization.patch Patch161: linux-2.6-i386-nx-emulation.patch +Patch162: nx-emu-remove-cpuinitdata-for-disable_nx-on-x86_32.patch -Patch200: linux-2.6-debug-sizeof-structs.patch -Patch202: linux-2.6-debug-taint-vm.patch -Patch203: linux-2.6-debug-vm-would-have-oomkilled.patch -Patch204: linux-2.6-debug-always-inline-kzalloc.patch +Patch350: force-version-2.6.patch -Patch380: linux-2.6-defaults-pci_no_msi.patch -Patch381: linux-2.6-defaults-pci_use_crs.patch Patch383: linux-2.6-defaults-aspm.patch -Patch386: pci-_osc-supported-field-should-contain-supported-features-not-enabled-ones.patch - -Patch385: ima-allow-it-to-be-completely-disabled-and-default-off.patch Patch390: linux-2.6-defaults-acpi-video.patch Patch391: linux-2.6-acpi-video-dos.patch -Patch393: acpi-ec-add-delay-before-write.patch Patch394: linux-2.6-acpi-debug-infinite-loop.patch +Patch396: acpi-sony-nonvs-blacklist.patch Patch450: linux-2.6-input-kill-stupid-messages.patch Patch452: linux-2.6.30-no-pcspkr-modalias.patch -Patch454: thinkpad-acpi-fix-backlight.patch Patch460: linux-2.6-serial-460800.patch Patch470: die-floppy-die.patch +Patch471: floppy-drop-disable_hlt-warning.patch Patch510: linux-2.6-silence-noise.patch +Patch511: silence-timekeeping-spew.patch +Patch520: quite-apm.patch Patch530: linux-2.6-silence-fbcon-logo.patch -Patch570: linux-2.6-selinux-mprotect-checks.patch -Patch580: linux-2.6-sparc-selinux-mprotect-checks.patch - -Patch610: hda_intel-prealloc-4mb-dmabuffer.patch Patch700: linux-2.6-e1000-ich9-montevina.patch @@ -664,74 +610,106 @@ Patch800: linux-2.6-crash-driver.patch # crypto/ # virt + ksm patches -Patch1555: fix_xen_guest_on_old_EC2.patch +Patch1500: fix_xen_guest_on_old_EC2.patch # DRM -# nouveau + drm fixes -Patch1810: drm-nouveau-updates.patch -Patch1819: drm-intel-big-hammer.patch # intel drm is all merged upstream Patch1824: drm-intel-next.patch -# make sure the lvds comes back on lid open -Patch1825: drm-intel-make-lvds-work.patch -Patch1826: drm-intel-edp-fixes.patch -Patch1827: drm-i915-gen4-has-non-power-of-two-strides.patch +Patch1825: drm-i915-dp-stfu.patch + +# hush the i915 fbc noise +Patch1826: drm-i915-fbc-stfu.patch Patch1900: linux-2.6-intel-iommu-igfx.patch -# linux1394 git patches -Patch2200: linux-2.6-firewire-git-update.patch -Patch2201: linux-2.6-firewire-git-pending.patch - # Quiet boot fixes # silence the ACPI blacklist code Patch2802: linux-2.6-silence-acpi-blacklist.patch # media patches -Patch2899: linux-2.6-v4l-dvb-fixes.patch -Patch2900: linux-2.6-v4l-dvb-update.patch -Patch2901: linux-2.6-v4l-dvb-experimental.patch -Patch2902: linux-2.6-v4l-dvb-uvcvideo-update.patch - -Patch2910: linux-2.6-v4l-dvb-add-lgdt3304-support.patch -Patch2912: linux-2.6-v4l-dvb-ir-core-update.patch - -#Patch2916: lirc-staging-2.6.36-fixes.patch -#Patch2917: hdpvr-ir-enable.patch - -Patch2918: flexcop-fix-xlate_proc_name-warning.patch +Patch2900: add-poll-requested-events.patch +Patch2901: drivers-media-update.patch # fs fixes +#rhbz 753346 +Patch3500: jbd-jbd2-validate-sb-s_first-in-journal_get_superblo.patch + # NFSv4 +Patch4000: NFSv4-Reduce-the-footprint-of-the-idmapper.patch +Patch4001: NFSv4-Further-reduce-the-footprint-of-the-idmapper.patch +Patch4107: NFSv4-Minor-cleanups-for-nfs4_handle_exception-and-n.patch +Patch4115: NFSv4-Rate-limit-the-state-manager-for-lock-reclaim-.patch # patches headed upstream -Patch12001: perf-gcc460-build-fixes.patch - -Patch12010: add-appleir-usb-driver.patch - Patch12016: disable-i8042-check-on-apple-mac.patch -Patch12017: prevent-runtime-conntrack-changes.patch - -Patch12018: neuter_intel_microcode_load.patch - -Patch12101: apple_backlight.patch -Patch12102: efifb_update.patch -Patch12200: acpi_reboot.patch -Patch12210: efi_default_physical.patch - -# Runtime power management -Patch12202: linux-2.6-ehci-check-port-status.patch -Patch12203: linux-2.6-usb-pci-autosuspend.patch -Patch12204: linux-2.6-enable-more-pci-autosuspend.patch -Patch12205: runtime_pm_fixups.patch - Patch12303: dmar-disable-when-ricoh-multifunction.patch -Patch12421: fs-call-security_d_instantiate-in-d_obtain_alias.patch +Patch13003: efi-dont-map-boot-services-on-32bit.patch + +Patch14010: lis3-improve-handling-of-null-rate.patch + +Patch15000: bluetooth-use-after-free.patch + +Patch20000: utrace.patch + +# Flattened devicetree support +Patch21000: arm-omap-dt-compat.patch +Patch21001: arm-smsc-support-reading-mac-address-from-device-tree.patch +Patch21004: arm-tegra-nvec-kconfig.patch + +Patch21070: ext4-Support-check-none-nocheck-mount-options.patch + +#rhbz 769766 +Patch21072: mac80211-fix-rx-key-NULL-ptr-deref-in-promiscuous-mode.patch + +# Remove overlap between bcma/b43 and brcmsmac and reenable bcm4331 +Patch21091: bcma-brcmsmac-compat.patch + +#rhbz 772772 +Patch21232: rt2x00_fix_MCU_request_failures.patch + +#rhbz 789644 +Patch21237: mcelog-rcu-splat.patch + +Patch21300: unhandled-irqs-switch-to-polling.patch + +#rhbz 804957 CVE-2012-1568 +Patch21306: shlib_base_randomize.patch + +#rhbz 808559 +Patch21530: ALSA-hda-realtek-Add-quirk-for-Mac-Pro-5-1-machines.patch + +#rhbz 806295 +Patch21710: disable-hid-battery.patch + +Patch22000: weird-root-dentry-name-debug.patch + +#rhbz 814278 814289 CVE-2012-2119 +Patch22007: macvtap-zerocopy-validate-vector-length.patch + +#rhbz 817298 +Patch22013: ipw2x00-add-supported-cipher-suites-to-wiphy-initialization.patch + +#rhbz 749276 +Patch22018: atl1c_net_next_update-3.3.patch + +#rhbz 795176 +Patch22019: rtl818x-fix-sleeping-function-called-from-invalid-context.patch + +#rhbz 822825 822821 CVE-2012-2372 +Patch22021: mm-pmd_read_atomic-fix-32bit-PAE-pmd-walk-vs-pmd_populate-SMP-race-condition.patch + +#rhbz 829016 +Patch22022: thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-PAE.patch + +#rhbz 824352 824345 CVE-2012-2390 +Patch22023: hugetlb-fix-resv_map-leak-in-error-path.patch + +# END OF PATCH DEFINITIONS %endif @@ -784,7 +762,7 @@ operate. %package bootwrapper Summary: Boot wrapper files for generating combined kernel + initrd images Group: Development/System -Requires: gzip +Requires: gzip binutils %description bootwrapper Kernel-bootwrapper contains the wrapper code which makes bootable "zImage" files combining both kernel and initial ramdisk. @@ -924,6 +902,36 @@ This variant of the kernel has numerous debugging options enabled. It should only be installed when trying to gather additional information on kernel bugs, as some of these options impact performance noticably. +%define variant_summary The Linux kernel compiled for marvell kirkwood boards +%kernel_variant_package kirkwood +%description kirkwood +This package includes a version of the Linux kernel with support for +marvell kirkwood based systems, i.e., guruplug, sheevaplug + +%define variant_summary The Linux kernel compiled for freescale boards +%kernel_variant_package imx +%description imx +This package includes a version of the Linux kernel with support for +freescale based systems, i.e., efika smartbook. + +%define variant_summary The Linux kernel compiled for Calxeda boards +%kernel_variant_package highbank +%description highbank +This package includes a version of the Linux kernel with support for +Calxeda based systems, i.e., HP arm servers. + +%define variant_summary The Linux kernel compiled for TI-OMAP boards +%kernel_variant_package omap +%description omap +This package includes a version of the Linux kernel with support for +TI-OMAP based systems, i.e., BeagleBoard-xM. + +%define variant_summary The Linux kernel compiled for tegra boards +%kernel_variant_package tegra +%description tegra +This package includes a version of the Linux kernel with support for +nvidia tegra based systems, i.e., trimslice, ac-100. + %prep # do a few sanity-checks for --with *only builds @@ -941,6 +949,11 @@ exit 1 %endif %endif +%if "%{baserelease}" == "0" +echo "baserelease must be greater than zero" +exit 1 +%endif + # more sanity checking; do it quietly if [ "%{patches}" != "%%{patches}" ] ; then for patch in %{patches} ; do @@ -961,7 +974,7 @@ ApplyPatch() fi %if !%{using_upstream_branch} if ! grep -E "^Patch[0-9]+: $patch\$" %{_specdir}/${RPM_PACKAGE_NAME%%%%%{?variant}}.spec ; then - if [ "${patch:0:10}" != "patch-2.6." ] ; then + if [ "${patch:0:8}" != "patch-3." ] ; then echo "ERROR: Patch $patch not listed as a source patch in specfile" exit 1 fi @@ -970,6 +983,7 @@ ApplyPatch() case "$patch" in *.bz2) bunzip2 < "$RPM_SOURCE_DIR/$patch" | $patch_command ${1+"$@"} ;; *.gz) gunzip < "$RPM_SOURCE_DIR/$patch" | $patch_command ${1+"$@"} ;; + *.xz) unxz < "$RPM_SOURCE_DIR/$patch" | $patch_command ${1+"$@"} ;; *) $patch_command ${1+"$@"} < "$RPM_SOURCE_DIR/$patch" ;; esac } @@ -999,46 +1013,24 @@ ApplyOptionalPatch() # which speeds things up quite a bit. # Update to latest upstream. -%if 0%{?released_kernel} -%define vanillaversion 2.6.%{base_sublevel} -# non-released_kernel case -%else -%if 0%{?rcrev} -%define vanillaversion 2.6.%{upstream_sublevel}-rc%{rcrev} -%if 0%{?gitrev} -%define vanillaversion 2.6.%{upstream_sublevel}-rc%{rcrev}-git%{gitrev} -%endif -%else -# pre-{base_sublevel+1}-rc1 case -%if 0%{?gitrev} -%define vanillaversion 2.6.%{base_sublevel}-git%{gitrev} -%else -%define vanillaversion 2.6.%{base_sublevel} -%endif -%endif -%endif - -# %%{vanillaversion} : the full version name, e.g. 2.6.35-rc6-git3 -# %%{kversion} : the base version, e.g. 2.6.34 - -# Use kernel-%%{kversion}%%{?dist} as the top-level directory name +# Use kernel-%%{fakeversion}%%{?dist} as the top-level directory name # so we can prep different trees within a single git directory. # Build a list of the other top-level kernel tree directories. # This will be used to hardlink identical vanilla subdirs. -sharedirs=$(find "$PWD" -maxdepth 1 -type d -name 'kernel-2.6.*' \ - | grep -x -v "$PWD"/kernel-%{kversion}%{?dist}) ||: +sharedirs=$(find "$PWD" -maxdepth 1 -type d -name 'kernel-3.*' \ + | grep -x -v "$PWD"/kernel-%{fakeversion}%{?dist}) ||: -if [ ! -d kernel-%{kversion}%{?dist}/vanilla-%{vanillaversion} ]; then +if [ ! -d kernel-%{fakeversion}%{?dist}/vanilla-%{realversion} ]; then - if [ -d kernel-%{kversion}%{?dist}/vanilla-%{kversion} ]; then + if [ -d kernel-%{fakeversion}%{?dist}/vanilla-%{realversion} ]; then # The base vanilla version already exists. - cd kernel-%{kversion}%{?dist} + cd kernel-%{fakeversion}%{?dist} # Any vanilla-* directories other than the base one are stale. for dir in vanilla-*; do - [ "$dir" = vanilla-%{kversion} ] || rm -rf $dir & + [ "$dir" = vanilla-%{realversion} ] || rm -rf $dir & done else @@ -1046,84 +1038,39 @@ if [ ! -d kernel-%{kversion}%{?dist}/vanilla-%{vanillaversion} ]; then rm -f pax_global_header # Look for an identical base vanilla dir that can be hardlinked. for sharedir in $sharedirs ; do - if [[ ! -z $sharedir && -d $sharedir/vanilla-%{kversion} ]] ; then + if [[ ! -z $sharedir && -d $sharedir/vanilla-%{realversion} ]] ; then break fi done - if [[ ! -z $sharedir && -d $sharedir/vanilla-%{kversion} ]] ; then -%setup -q -n kernel-%{kversion}%{?dist} -c -T - cp -rl $sharedir/vanilla-%{kversion} . + if [[ ! -z $sharedir && -d $sharedir/vanilla-%{realversion} ]] ; then +%setup -q -n kernel-%{fakeversion}%{?dist} -c -T + cp -rl $sharedir/vanilla-%{realversion} . else -%setup -q -n kernel-%{kversion}%{?dist} -c - mv linux-%{kversion} vanilla-%{kversion} +%setup -q -n kernel-%{fakeversion}%{?dist} -c + mv linux-%{realversion} vanilla-%{realversion} fi fi -%if "%{kversion}" != "%{vanillaversion}" - - for sharedir in $sharedirs ; do - if [[ ! -z $sharedir && -d $sharedir/vanilla-%{vanillaversion} ]] ; then - break - fi - done - if [[ ! -z $sharedir && -d $sharedir/vanilla-%{vanillaversion} ]] ; then - - cp -rl $sharedir/vanilla-%{vanillaversion} . - - else - - # Need to apply patches to the base vanilla version. - cp -rl vanilla-%{kversion} vanilla-%{vanillaversion} - cd vanilla-%{vanillaversion} - -# Update vanilla to the latest upstream. -# (non-released_kernel case only) -%if 0%{?rcrev} - ApplyPatch patch-2.6.%{upstream_sublevel}-rc%{rcrev}.bz2 -%if 0%{?gitrev} - ApplyPatch patch-2.6.%{upstream_sublevel}-rc%{rcrev}-git%{gitrev}.bz2 -%endif -%else -# pre-{base_sublevel+1}-rc1 case -%if 0%{?gitrev} - ApplyPatch patch-2.6.%{base_sublevel}-git%{gitrev}.bz2 -%endif -%endif - - cd .. - - fi - -%endif - else # We already have all vanilla dirs, just change to the top-level directory. - cd kernel-%{kversion}%{?dist} + cd kernel-%{fakeversion}%{?dist} fi # Now build the fedora kernel tree. -if [ -d linux-%{kversion}.%{_target_cpu} ]; then +if [ -d linux-%{fakeversion}.%{_target_cpu} ]; then # Just in case we ctrl-c'd a prep already rm -rf deleteme.%{_target_cpu} # Move away the stale away, and delete in background. - mv linux-%{kversion}.%{_target_cpu} deleteme.%{_target_cpu} + mv linux-%{fakeversion}.%{_target_cpu} deleteme.%{_target_cpu} rm -rf deleteme.%{_target_cpu} & fi -cp -rl vanilla-%{vanillaversion} linux-%{kversion}.%{_target_cpu} +cp -rl vanilla-%{realversion} linux-%{fakeversion}.%{_target_cpu} -cd linux-%{kversion}.%{_target_cpu} - -# released_kernel with possible stable updates -%if 0%{?stable_base} -ApplyPatch %{stable_patch_00} -%endif -%if 0%{?stable_rc} -ApplyPatch %{stable_patch_01} -%endif +cd linux-%{fakeversion}.%{_target_cpu} %if %{using_upstream_branch} ### BRANCH APPLY ### @@ -1156,7 +1103,15 @@ do done %endif -ApplyOptionalPatch git-linus.diff +# released_kernel with possible stable updates +%if 0%{?stable_base} +ApplyPatch %{stable_patch_00} +%endif +%if 0%{?stable_rc} +ApplyPatch %{stable_patch_01} +%endif + +ApplyOptionalPatch stable-queue.patch ApplyPatch linux-2.6-makefile-after_link.patch @@ -1170,42 +1125,35 @@ ApplyOptionalPatch linux-2.6-compile-fixes.patch # revert patches from upstream that conflict or that we get via other means ApplyOptionalPatch linux-2.6-upstream-reverts.patch -R -ApplyPatch linux-2.6-hotfixes.patch - -# Roland's utrace ptrace replacement. -ApplyPatch linux-2.6-utrace-revert-make-ptrace-functions-static.patch -ApplyPatch linux-2.6-tracehook.patch -ApplyPatch linux-2.6-utrace.patch -ApplyPatch linux-2.6-utrace-ptrace.patch # Architecture patches # x86(-64) # -# Intel IOMMU +# ARM # +#ApplyPatch arm-omap-dt-compat.patch +ApplyPatch arm-smsc-support-reading-mac-address-from-device-tree.patch +ApplyPatch arm-tegra-nvec-kconfig.patch +ApplyPatch taint-vbox.patch # -# PowerPC +# NX Emulation # +#ApplyPatch linux-2.6-32bit-mmap-exec-randomization.patch +#ApplyPatch linux-2.6-i386-nx-emulation.patch +#ApplyPatch nx-emu-remove-cpuinitdata-for-disable_nx-on-x86_32.patch +#rhbz 804957 CVE-2012-1568 +#ApplyPatch shlib_base_randomize.patch -# -# SPARC64 -# -ApplyPatch linux-2.6.29-sparc-IOC_TYPECHECK.patch -ApplyPatch sparc64_fix_build_errors_with_gcc460.patch - -# -# Exec shield -# -ApplyPatch linux-2.6-i386-nx-emulation.patch -ApplyPatch linux-2.6-32bit-mmap-exec-randomization.patch # # bugfixes to drivers and filesystems # # ext4 +#rhbz 753346 +ApplyPatch jbd-jbd2-validate-sb-s_first-in-journal_get_superblo.patch # xfs @@ -1215,6 +1163,10 @@ ApplyPatch linux-2.6-32bit-mmap-exec-randomization.patch # eCryptfs # NFSv4 +ApplyPatch NFSv4-Reduce-the-footprint-of-the-idmapper.patch +ApplyPatch NFSv4-Further-reduce-the-footprint-of-the-idmapper.patch +ApplyPatch NFSv4-Minor-cleanups-for-nfs4_handle_exception-and-n.patch +ApplyPatch NFSv4-Rate-limit-the-state-manager-for-lock-reclaim-.patch # USB @@ -1223,27 +1175,17 @@ ApplyPatch linux-2.6-32bit-mmap-exec-randomization.patch # ACPI ApplyPatch linux-2.6-defaults-acpi-video.patch ApplyPatch linux-2.6-acpi-video-dos.patch -ApplyPatch acpi-ec-add-delay-before-write.patch ApplyPatch linux-2.6-acpi-debug-infinite-loop.patch +ApplyPatch acpi-sony-nonvs-blacklist.patch -# Various low-impact patches to aid debugging. -ApplyPatch linux-2.6-debug-sizeof-structs.patch -ApplyPatch linux-2.6-debug-taint-vm.patch -ApplyPatch linux-2.6-debug-vm-would-have-oomkilled.patch -ApplyPatch linux-2.6-debug-always-inline-kzalloc.patch +# force UTSNAME to show version 2.6.4X +ApplyPatch force-version-2.6.patch # # PCI # -# make default state of PCI MSI a config option -ApplyPatch linux-2.6-defaults-pci_no_msi.patch -ApplyPatch linux-2.6-defaults-pci_use_crs.patch # enable ASPM by default on hardware we expect to work ApplyPatch linux-2.6-defaults-aspm.patch -# rhbz#638912 -#ApplyPatch pci-_osc-supported-field-should-contain-supported-features-not-enabled-ones.patch - -#ApplyPatch ima-allow-it-to-be-completely-disabled-and-default-off.patch # # SCSI Bits. @@ -1252,36 +1194,34 @@ ApplyPatch linux-2.6-defaults-aspm.patch # ACPI # ALSA -ApplyPatch hda_intel-prealloc-4mb-dmabuffer.patch + +#rhbz 808559 +ApplyPatch ALSA-hda-realtek-Add-quirk-for-Mac-Pro-5-1-machines.patch # Networking + # Misc fixes # The input layer spews crap no-one cares about. ApplyPatch linux-2.6-input-kill-stupid-messages.patch # stop floppy.ko from autoloading during udev... ApplyPatch die-floppy-die.patch +ApplyPatch floppy-drop-disable_hlt-warning.patch ApplyPatch linux-2.6.30-no-pcspkr-modalias.patch -#ApplyPatch thinkpad-acpi-fix-backlight.patch - # Allow to use 480600 baud on 16C950 UARTs ApplyPatch linux-2.6-serial-460800.patch # Silence some useless messages that still get printed with 'quiet' ApplyPatch linux-2.6-silence-noise.patch +ApplyPatch silence-timekeeping-spew.patch + # Make fbcon not show the penguins with 'quiet' ApplyPatch linux-2.6-silence-fbcon-logo.patch -# Fix the SELinux mprotect checks on executable mappings -#ApplyPatch linux-2.6-selinux-mprotect-checks.patch -# Fix SELinux for sparc -# FIXME: Can we drop this now? See updated linux-2.6-selinux-mprotect-checks.patch -#ApplyPatch linux-2.6-sparc-selinux-mprotect-checks.patch - # Changes to upstream defaults. @@ -1298,71 +1238,74 @@ ApplyPatch fix_xen_guest_on_old_EC2.patch # DRM core -# Nouveau DRM -ApplyOptionalPatch drm-nouveau-updates.patch - # Intel DRM ApplyOptionalPatch drm-intel-next.patch -ApplyPatch drm-intel-big-hammer.patch -ApplyPatch drm-intel-make-lvds-work.patch -ApplyPatch linux-2.6-intel-iommu-igfx.patch -ApplyPatch drm-intel-edp-fixes.patch -# rhbz#681285 (i965: crash in brw_wm_surface_state.c::prepare_wm_surfaces() -# where intelObj->mt == NULL) -#ApplyPatch drm-i915-gen4-has-non-power-of-two-strides.patch +ApplyPatch drm-i915-dp-stfu.patch +ApplyPatch drm-i915-fbc-stfu.patch -# linux1394 git patches -#ApplyPatch linux-2.6-firewire-git-update.patch -#ApplyOptionalPatch linux-2.6-firewire-git-pending.patch +ApplyPatch linux-2.6-intel-iommu-igfx.patch # silence the ACPI blacklist code ApplyPatch linux-2.6-silence-acpi-blacklist.patch +ApplyPatch quite-apm.patch -# V4L/DVB updates/fixes/experimental drivers +# Media (V4L/DVB/IR) updates/fixes/experimental drivers # apply if non-empty -ApplyOptionalPatch linux-2.6-v4l-dvb-fixes.patch -ApplyOptionalPatch linux-2.6-v4l-dvb-update.patch -ApplyOptionalPatch linux-2.6-v4l-dvb-experimental.patch -#ApplyPatch linux-2.6-v4l-dvb-uvcvideo-update.patch -#ApplyPatch linux-2.6-v4l-dvb-ir-core-update.patch - -###FIX###ApplyPatch linux-2.6-v4l-dvb-add-lgdt3304-support.patch - -# http://www.lirc.org/ -#ApplyOptionalPatch lirc-staging-2.6.36-fixes.patch -# enable IR receiver on Hauppauge HD PVR (v4l-dvb merge pending) -#ApplyPatch hdpvr-ir-enable.patch - -# rhbz#664852 -ApplyPatch flexcop-fix-xlate_proc_name-warning.patch +ApplyPatch add-poll-requested-events.patch +ApplyOptionalPatch drivers-media-update.patch # Patches headed upstream -ApplyPatch perf-gcc460-build-fixes.patch ApplyPatch disable-i8042-check-on-apple-mac.patch -ApplyPatch add-appleir-usb-driver.patch - -ApplyPatch neuter_intel_microcode_load.patch - -# various fixes for Apple and EFI -ApplyPatch apple_backlight.patch -ApplyPatch efifb_update.patch -ApplyPatch acpi_reboot.patch -ApplyPatch efi_default_physical.patch - -# Runtime PM -ApplyPatch linux-2.6-ehci-check-port-status.patch -#ApplyPatch linux-2.6-usb-pci-autosuspend.patch -### Broken by implicit notify support & ACPICA rebase -###ApplyPatch linux-2.6-enable-more-pci-autosuspend.patch -#ApplyPatch runtime_pm_fixups.patch - # rhbz#605888 ApplyPatch dmar-disable-when-ricoh-multifunction.patch -# rhbz#662344,600690 -ApplyPatch fs-call-security_d_instantiate-in-d_obtain_alias.patch +ApplyPatch efi-dont-map-boot-services-on-32bit.patch + +ApplyPatch lis3-improve-handling-of-null-rate.patch + +ApplyPatch bluetooth-use-after-free.patch + +# utrace. +ApplyPatch utrace.patch + +ApplyPatch ext4-Support-check-none-nocheck-mount-options.patch + +#rhbz 772772 +ApplyPatch rt2x00_fix_MCU_request_failures.patch + +# Remove overlap between bcma/b43 and brcmsmac and reenable bcm4331 +ApplyPatch bcma-brcmsmac-compat.patch + +#rhbz 789644 +ApplyPatch mcelog-rcu-splat.patch + +ApplyPatch unhandled-irqs-switch-to-polling.patch + +ApplyPatch weird-root-dentry-name-debug.patch + +#rhbz 806295 +ApplyPatch disable-hid-battery.patch + +#rhbz 814278 814289 CVE-2012-2119 +ApplyPatch macvtap-zerocopy-validate-vector-length.patch + +#rhbz 817298 +ApplyPatch ipw2x00-add-supported-cipher-suites-to-wiphy-initialization.patch + +#rhbz 749276 +ApplyPatch atl1c_net_next_update-3.3.patch + +#rhbz 795176 +ApplyPatch rtl818x-fix-sleeping-function-called-from-invalid-context.patch + +#rhbz 822825 822821 CVE-2012-2372 +ApplyPatch mm-pmd_read_atomic-fix-32bit-PAE-pmd-walk-vs-pmd_populate-SMP-race-condition.patch +ApplyPatch thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-PAE.patch + +#rhbz 824352 824345 CVE-2012-2390 +ApplyPatch hugetlb-fix-resv_map-leak-in-error-path.patch # END OF PATCH APPLICATIONS @@ -1468,13 +1411,6 @@ BuildKernel() { # make sure EXTRAVERSION says what we want it to say perl -p -i -e "s/^EXTRAVERSION.*/EXTRAVERSION = %{?stablerev}-%{release}.%{_target_cpu}${Flavour:+.${Flavour}}/" Makefile - # if pre-rc1 devel kernel, must fix up SUBLEVEL for our versioning scheme - %if !0%{?rcrev} - %if 0%{?gitrev} - perl -p -i -e 's/^SUBLEVEL.*/SUBLEVEL = %{upstream_sublevel}/' Makefile - %endif - %endif - # and now to start the build process make -s mrproper @@ -1484,7 +1420,12 @@ BuildKernel() { echo USING ARCH=$Arch make -s ARCH=$Arch oldnoconfig >/dev/null +%ifarch %{arm} + # http://lists.infradead.org/pipermail/linux-arm-kernel/2012-March/091404.html + make -s ARCH=$Arch V=1 %{?_smp_mflags} $MakeTarget %{?sparse_mflags} KALLSYMS_EXTRA_PASS=1 +%else make -s ARCH=$Arch V=1 %{?_smp_mflags} $MakeTarget %{?sparse_mflags} +%endif make -s ARCH=$Arch V=1 %{?_smp_mflags} modules %{?sparse_mflags} || exit 1 # Start installing the results @@ -1562,6 +1503,12 @@ BuildKernel() { if [ -d arch/%{asmarch}/include ]; then cp -a --parents arch/%{asmarch}/include $RPM_BUILD_ROOT/lib/modules/$KernelVer/build/ fi + # include the machine specific headers for ARM variants, if available. +%ifarch %{arm} + if [ -d arch/%{asmarch}/mach-${Flavour}/include ]; then + cp -a --parents arch/%{asmarch}/mach-${Flavour}/include $RPM_BUILD_ROOT/lib/modules/$KernelVer/build/ + fi +%endif cp -a include $RPM_BUILD_ROOT/lib/modules/$KernelVer/build/include # Make sure the Makefile and version.h have a matching timestamp so that @@ -1605,7 +1552,7 @@ BuildKernel() { } collect_modules_list networking \ - 'register_netdev|ieee80211_register_hw|usbnet_probe|phy_driver_register' + 'register_netdev|ieee80211_register_hw|usbnet_probe|phy_driver_register|rt(l_|2x00)(pci|usb)_probe' collect_modules_list block \ 'ata_scsi_ioctl|scsi_add_host|scsi_add_host_with_dma|blk_init_queue|register_mtd_blktrans|scsi_esp_register|scsi_register_device_handler' collect_modules_list drm \ @@ -1651,7 +1598,7 @@ rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT/boot mkdir -p $RPM_BUILD_ROOT%{_libexecdir} -cd linux-%{kversion}.%{_target_cpu} +cd linux-%{fakeversion}.%{_target_cpu} %if %{with_debug} BuildKernel %make_target %kernel_image debug @@ -1665,6 +1612,26 @@ BuildKernel %make_target %kernel_image PAEdebug BuildKernel %make_target %kernel_image PAE %endif +%if %{with_kirkwood} +BuildKernel %make_target %kernel_image kirkwood +%endif + +%if %{with_imx} +BuildKernel %make_target %kernel_image imx +%endif + +%if %{with_highbank} +BuildKernel %make_target %kernel_image highbank +%endif + +%if %{with_omap} +BuildKernel %make_target %kernel_image omap +%endif + +%if %{with_tegra} +BuildKernel %make_target %kernel_image tegra +%endif + %if %{with_up} BuildKernel %make_target %kernel_image %endif @@ -1674,7 +1641,7 @@ BuildKernel %make_target %kernel_image smp %endif %global perf_make \ - make %{?_smp_mflags} -C tools/perf -s V=1 HAVE_CPLUS_DEMANGLE=1 prefix=%{_prefix} + make %{?_smp_mflags} -C tools/perf -s V=1 HAVE_CPLUS_DEMANGLE=1 EXTRA_CFLAGS="-Wno-error=array-bounds" prefix=%{_prefix} %if %{with_perf} %{perf_make} all %{perf_make} man || %{doc_build_fail} @@ -1716,7 +1683,7 @@ find Documentation -type d | xargs chmod u+w %install -cd linux-%{kversion}.%{_target_cpu} +cd linux-%{fakeversion}.%{_target_cpu} %if %{with_doc} docdir=$RPM_BUILD_ROOT%{_datadir}/doc/kernel-doc-%{rpmversion} @@ -1724,7 +1691,7 @@ man9dir=$RPM_BUILD_ROOT%{_datadir}/man/man9 # copy the source over mkdir -p $docdir -tar -f - --exclude=man --exclude='.*' -c Documentation | tar xf - -C $docdir +tar -h -f - --exclude=man --exclude='.*' -c Documentation | tar xf - -C $docdir # Install man pages for the kernel API. mkdir -p $man9dir @@ -1857,6 +1824,21 @@ fi}\ %kernel_variant_post -v PAEdebug -r (kernel|kernel-smp) %kernel_variant_preun PAEdebug +%kernel_variant_preun kirkwood +%kernel_variant_post -v kirkwood + +%kernel_variant_preun imx +%kernel_variant_post -v imx + +%kernel_variant_preun highbank +%kernel_variant_post -v highbank + +%kernel_variant_preun omap +%kernel_variant_post -v omap + +%kernel_variant_preun tegra +%kernel_variant_post -v tegra + if [ -x /sbin/ldconfig ] then /sbin/ldconfig -X || exit $? @@ -1876,7 +1858,7 @@ fi %files firmware %defattr(-,root,root) /lib/firmware/* -%doc linux-%{kversion}.%{_target_cpu}/firmware/WHENCE +%doc linux-%{fakeversion}.%{_target_cpu}/firmware/WHENCE %endif %if %{with_bootwrapper} @@ -1967,1004 +1949,850 @@ fi %kernel_variant_files %{with_debug} debug %kernel_variant_files %{with_pae} PAE %kernel_variant_files %{with_pae_debug} PAEdebug +%kernel_variant_files %{with_kirkwood} kirkwood +%kernel_variant_files %{with_imx} imx +%kernel_variant_files %{with_highbank} highbank +%kernel_variant_files %{with_omap} omap +%kernel_variant_files %{with_tegra} tegra # plz don't put in a version string unless you're going to tag # and build. %changelog -* Tue Mar 15 2011 Chuck Ebbert 2.6.38-1 -- Linux 2.6.38 +* Fri Jun 22 2012 Josh Boyer 2.6.43.8-2 +- Add patch to fix xen domU 32bit (rhbz 834671) -* Mon Mar 14 2011 Chuck Ebbert 2.6.38-0.rc8.git4.1 -- Linux 2.6.38-rc8-git4 +* Mon Jun 04 2012 Josh Boyer 2.6.43.8-1 +- Linux v3.3.8 -* Thu Mar 10 2011 Chuck Ebbert -- Linux 2.6.38-rc8-git3 +* Mon Jun 04 2012 Dave Jones +- Disable 32bit NX emulation. -* Thu Mar 10 2011 Chuck Ebbert 2.6.38-0.rc8.git2.1 -- Linux 2.6.38-rc8-git2 +* Wed May 30 2012 Josh Boyer +- CVE-2012-2390 huge pages: memory leak on mmap failure (rhbz 824352 824345) -* Wed Mar 09 2011 Chuck Ebbert -- Linux 2.6.38-rc8-git1 +* Thu May 24 2012 Josh Boyer +- CVE-2012-2372 mm: 32bit PAE pmd walk vs populate SMP race (rhbz 822821 822825) -* Wed Mar 09 2011 Dennis Gilmore -- apply sparc64 gcc-4.6.0 buildfix patch +* Mon May 21 2012 Justin M. Forbes 3.3.7-1 +- Linux 3.3.7 -* Wed Mar 09 2011 Ben Skeggs 2.6.38-0.rc8.git0.2 -- nouveau: allow max clients on nv4x (679629), better error reporting +* Fri May 18 2012 Josh Boyer +- Additional fixes for CVE-2011-4131 (rhbz 822874 822869) -* Tue Mar 08 2011 Chuck Ebbert 2.6.38-0.rc8.git0.1 -- Linux 2.6.38-rc8 +* Thu May 17 2012 Josh Boyer +- Fix rtlwifi async firmware load race condition (rhbz 822120) -* Sat Mar 05 2011 Chuck Ebbert 2.6.38-0.rc7.git4.1 -- Linux 2.6.38-rc7-git4 -- Revert upstream commit e3e89cc535223433a619d0969db3fa05cdd946b8 - for now to fix utrace build. +* Wed May 16 2012 Justin M. Forbes 2.6.43.6-3 +- fix rtl8187: ->brightness_set can not sleep (rhbz 795176) -* Fri Mar 04 2011 Roland McGrath - 2.6.38-0.rc7.git2.3 -- Split out perf-debuginfo subpackage. +* Tue May 15 2012 Josh Boyer +- Fixup atl1c register programming (rhbz 749276) -* Fri Mar 04 2011 Kyle McMartin 2.6.38-0.rc7.git2.2 -- Disable drm-i915-gen4-has-non-power-of-two-strides.patch for now, breaks - my mutter. +* Mon May 14 2012 Justin M. Forbes 2.6.43.6-1 +- Linux 3.3.6 -* Fri Mar 04 2011 Kyle McMartin 2.6.38-0.rc7.git2.1 -- Linux 2.6.38-rc7-git2 -- drm-i915-gen4-has-non-power-of-two-strides.patch (#681285) +* Mon May 07 2012 Mauro Carvalho Chehab 2.6.43.5-2 +- Add patch to fix DVB-S zigzag (rhbz 814404) -* Thu Mar 03 2011 Chuck Ebbert 2.6.38-0.rc7.git1.1 -- Linux 2.6.38-rc7-git1 +* Mon May 07 2012 Josh Boyer 2.6.43.5-1 +- Linux 3.3.5 +- Add patch to rate limit NFSv4 message (rhbz 732748) -* Tue Mar 01 2011 Kyle McMartin 2.6.38-0.rc7.git0.1 -- Linux 2.6.38-rc7 +* Fri May 04 2012 Josh Boyer +- unfiltered netdev rio_ioctl access by users (rhbz 818820) -* Fri Feb 25 2011 Chuck Ebbert 2.6.38-0.rc6.git6.1 -- Linux 2.6.38-rc6-git6 -- Build in virtio_pci driver so virtio_console will be built-in (#677713) +* Mon Apr 30 2012 Josh Boyer +- Backport ipw2x00 nl80211 cipher suite reporting (rhbz 817298) -* Thu Feb 24 2011 Chuck Ebbert 2.6.38-0.rc6.git4.1 -- Linux 2.6.38-rc6-git4 +* Mon Apr 30 2012 Dave Jones +- Disable CONFIG_RCU_FAST_NO_HZ for now. (rhbz 806548) -* Thu Feb 24 2011 Matthew Garrett 2.6.38-0.rc6.git2.2 -- linux-2.6-acpi-fix-implicit-notify.patch: Fix implicit notify when there's - more than one device per GPE +* Mon Apr 30 2012 Justin M. Forbes 2.6.43.4-1 +- Linux 3.3.4 -* Wed Feb 23 2011 Chuck Ebbert 2.6.38-0.rc6.git2.1 -- Linux 2.6.38-rc6-git2 +* Tue Apr 24 2012 Josh Boyer +- Add patch to fix perf build due to incorrect cherry-pick in 3.3.3 +- Add patch to fix ipw2200 (rhbz 783708) -* Wed Feb 23 2011 Ben Skeggs 2.6.38-0.rc6.git0.2 -- nouveau: nv4x pciegart fixes, nvc0 accel improvements +* Mon Apr 23 2012 Josh Boyer +- Linux 3.3.3 -* Tue Feb 22 2011 Kyle McMartin 2.6.38-0.rc6.git0.1 -- Linux 2.6.38-rc6 +* Mon Apr 23 2012 Peter Hutterer +- Fix regression on clickpads -* Tue Feb 22 2011 Chuck Ebbert 2.6.38-0.rc5.git7.1 -- Linux 2.6.38-rc5-git7 +* Sat Apr 21 2012 Josh Boyer - 2.6.43.2-6 +- Fix error check in memblock that prevented boot on various Dells (rhbz 811225) -* Mon Feb 21 2011 Dave Jones 2.6.38-0.rc5.git6.1 -- Linux 2.6.38-rc5-git6 +* Fri Apr 20 2012 Josh Boyer +- CVE-2012-2123 fcaps: clear the same personality flags as suid when fcaps + are used (rhbz 814523 806722) -* Sat Feb 19 2011 Chuck Ebbert 2.6.38-0.rc5.git5.1 -- Linux 2.6.38-rc5-git5 +* Thu Apr 19 2012 Justin M. Forbes 2.6.43.2-4 +- CVE-2012-2119 macvtap: zerocopy: vector length is not validated before + pinning user pages (rhbz 814278 814289) -* Wed Feb 16 2011 Chuck Ebbert 2.6.38-0.rc5.git1.1 -- Linux 2.6.38-rc5-git1 -- Add support for Airprime/Sierra USB IP modem (#676860) -- Make virtio_console built-in on x86_64 (#677713) -- Revert check for read-only block device added in .38 (#672265) +* Thu Apr 19 2012 Justin M. Forbes +- Fix KVM device assignment page leak (rhbz 814149 814155) -* Tue Feb 15 2011 Kyle McMartin 2.6.38-0.rc5.git0.1 -- Linux 2.6.38-rc5 (81 minutes later...) +* Wed Apr 18 2012 Josh Boyer +- Change patch to resolve libata hotplug (rhbz 807632) +- Disable CONFIG_HID_BATTERY_STRENGTH (rhbz 806295) -* Sun Feb 13 2011 Chuck Ebbert 2.6.38-0.rc4.git7.1 -- Linux 2.6.38-rc4-git7 +* Tue Apr 17 2012 Josh Boyer +- Fix oops in nfs_have_delegation (rhbz 811138) +- Fix oops on invalid AMD microcode load (rhbz 797559) -* Sat Feb 12 2011 Chuck Ebbert 2.6.38-0.rc4.git6.1 -- Linux 2.6.38-rc4-git6 -- Fix memory corruption caused by bug in bridge code. +* Sat Apr 14 2012 Josh Boyer +- Add ALSA quirk for MacPro 5,1 machines (rhbz 808559) -* Thu Feb 10 2011 Chuck Ebbert 2.6.38-0.rc4.git3.1 -- Linux 2.6.38-rc4-git3 +* Fri Apr 13 2012 Josh Boyer +- Reapply rebased drivers-media-update.patch -* Mon Feb 07 2011 Fedora Release Engineering - 2.6.38-0.rc4.git0.2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild +* Fri Apr 13 2012 Dave Jones 2.6.43.2-1 +- Linux 3.3.2 -* Mon Feb 07 2011 Kyle McMartin 2.6.38-0.rc4.git0.1 -- Linux 2.6.38-rc4 +* Thu Apr 12 2012 Dennis Gilmore +- KALLSYMS_EXTRA_PASS=1 has to be passed in on the command line so do so only for arm -* Fri Feb 04 2011 Chuck Ebbert 2.6.38-0.rc3.git4.1 -- Linux 2.6.38-rc3-git4 +* Tue Apr 10 2012 Mauro Carvalho Chehab +- Backport dvb-core and a few driver fixes from media tree (rhbz808871) -* Thu Feb 03 2011 Chuck Ebbert -- Linux 2.6.38-rc3-git3 -- Enable Advansys SCSI driver on x86_64 (#589115) +* Tue Apr 10 2012 Josh Boyer +- Apply upstream patch to add USB device 13d3:3375 (rhbz 811087) +- Backport fixes for correct register constraints in cmpxchg.h (rhbz 809014) -* Thu Feb 03 2011 Kyle McMartin 2.6.38-0.rc3.git2.1 -- Linux 2.6.38-rc3-git2 snapshot -- [sgruszka] ath5k: fix fast channel change (#672778) +* Thu Apr 05 2012 Dave Jones +- Better watermark the number of pages used by hibernation I/O (Bojan Smojver) (rhbz 785384) -* Wed Feb 02 2011 Kyle McMartin 2.6.38-0.rc3.git1.1 -- Linux 2.6.38-rc3-git1 snapshot. +* Wed Apr 04 2012 Josh Boyer +- Disable runtime PM for hotpluggable ATA ports (rhbz 806676 807632) +- Fix NULL pointer dereference in i2400m (rhbz 808603) -* Wed Feb 02 2011 Chuck Ebbert -- Fix autoload of atl1c driver for latest hardware (#607499) +* Tue Apr 03 2012 Josh Boyer +- Fix crash in uvc_video_clock_update from Laurent Pinchart (rhbz 806433) +- iwl{wifi,legacy}: Fix warnings on remove interface from Stanislaw Gruszka + (rhbz 770467) -* Tue Feb 01 2011 Chuck Ebbert 2.6.38-0.rc3.git0.1 -- Linux 2.6.38-rc3 -- Try to fix some obvious bugs in hfsplus mount failure handling (#673857) +* Tue Apr 03 2012 Dave Jones 2.6.43.1-2 +- Disable CONFIG_DEBUG_PAGEALLOC in -debug builds again. -* Mon Jan 31 2011 Chuck Ebbert 2.6.38-0.rc2.git9.1 -- Linux 2.6.38-rc2-git9 +* Mon Apr 02 2012 Dave Jones +- Linux 3.3.1 -* Mon Jan 31 2011 Kyle McMartin -- disable CONFIG_SERIAL_8250_DETECT_IRQ (from mschmidt@redhat.com) +* Mon Apr 02 2012 Dave Jones +- Linux 3.3 -* Mon Jan 31 2011 Chuck Ebbert -- Linux 2.6.38-rc2-git8 -- Add Trond's NFS bugfixes branch from git.linux-nfs.org +* Fri Mar 30 2012 Dave Jones +- Silence the timekeeping "Adjusting tsc more then 11%" spew. (rhbz 798600) -* Mon Jan 31 2011 Chuck Ebbert 2.6.38-0.rc2.git7.2 -- Fix build failure on s390. +* Fri Mar 30 2012 Josh Boyer +- CVE-2012-1601: kvm: NULL dereference from irqchip_in_kernel and + vcpu->arch.apic inconsistency (rhbz 808207) +- Add patch to fix incorrect buffer length in __nfs4_get_acl_uncached -* Fri Jan 28 2011 Chuck Ebbert 2.6.38-0.rc2.git7.1 -- Linux 2.6.38-rc2-git7 +* Thu Mar 29 2012 Josh Boyer +- Drop __cpuinitdata on disable_nx for x86_32 (rhbz 808075) -* Wed Jan 26 2011 Kyle McMartin 2.6.38-0.rc2.git5.1 -- Linux 2.6.38-rc2-git5 -- [x86] Re-enable TRANSPARENT_HUGEPAGE, should be fixed by cacf061c. +* Mon Mar 26 2012 Dave Jones +- Linux 3.2.13 -* Tue Jan 25 2011 Kyle McMartin 2.6.38-0.rc2.git3.2 -- [x86] Disable TRANSPARENT_HUGEPAGE for now, there be dragons there. +* Tue Mar 20 2012 Justin M. Forbes 2.6.42.12-1 +- Linux 3.2.10 +- CVE-2012-1568 SHLIB_BASE randomization (rhbz 804947) -* Tue Jan 25 2011 Kyle McMartin 2.6.38-0.rc2.git3.1 -- Linux 2.6.38-rc2-git3 -- perf-gcc460-build-fixes.patch: fix context from [9486aa38] +* Tue Mar 20 2012 Steve Dickson +- NFSv4: Save the owner/group name string when doing open (bz 794780) -* Mon Jan 24 2011 Kyle McMartin 2.6.38-0.rc2.git1.3 -- Disable usb/pci/acpi autosuspend goo until it can be checked. +* Tue Mar 20 2012 Josh Boyer +- mac80211: fix possible tid_rx->reorder_timer use after free + from Stanislaw Gruska (rhbz 804007) -* Mon Jan 24 2011 Kyle McMartin -- debug-tty-print-dev-name.patch: drop, haven't seen any warnings recently. -- runtime_pm_fixups.patch: rebase and re-enable, make acpi_power_transition - in pci_bind actually do the right thing instead of (likely) always - trying to transition to D0. +* Fri Mar 16 2012 Justin M. Forbes +- re-enable threading on hibernate compression/decompression -* Mon Jan 24 2011 Kyle McMartin 2.6.38-0.rc2.git1.1 -- Linux 2.6.38-rc2-git1 -- [e5cce6c1] tpm: fix panic caused by "tpm: Autodetect itpm devices" - may fix some boot issues people were having. -- tpm-fix-stall-on-boot.patch: upstream. -- perf-gcc460-build-fixes.patch: fix build issues with warn-unused-but-set - in gcc 4.6.0 +* Fri Mar 16 2012 Josh Boyer +- Fix irqpoll patch to really only apply for ASM108x machines (rhbz 800520) -* Sat Jan 22 2011 Kyle McMartin 2.6.38-0.rc2.git0.1 -- Linux 2.6.38-rc2 -- linux-2.6-serial-460800.patch, drivers/serial => drivers/tty/serial +* Thu Mar 15 2012 Justin M. Forbes - 2.6.42.10-3 +- CVE-2012-1179 fix pmd_bad() triggering in code paths holding mmap_sem read mode (rhbz 803809) -* Thu Jan 20 2011 Kyle McMartin 2.6.38-0.rc1.git1.1 -- Linux 2.6.38-rc1-git1, should fix boot failure in -rc1. +* Wed Mar 14 2012 Josh Boyer +- Fixup irqpoll patch to only activate on machines with ASM108x PCI bridge -* Wed Jan 19 2011 Roland McGrath -- utrace update +* Wed Mar 14 2012 Steve Dickson +- Reduce the foot print of the NFSv4 idmapping coda (bz 593035) -* Wed Jan 19 2011 Kyle McMartin 2.6.38-0.rc1.git0.1 -- Linux 2.6.38-rc1 +* Mon Mar 12 2012 Justin M. Forbes - 2.6.42.10-1 +- Linux 3.2.10 -* Tue Jan 18 2011 Kyle McMartin 2.6.38-0.rc0.git18.1 -- Linux 2.6.37-git18 +* Mon Mar 12 2012 Josh Boyer +- Add patch to ignore bogus io-apic entries (rhbz 801501) -* Mon Jan 17 2011 Kyle McMartin 2.6.38-0.rc0.git16.1 -- Linux 2.6.37-git16 -- config changes: - - CONFIG_SQUASHFS_XZ=y [generic] - - CONFIG_SPARSE_IRQ=y [arm] +* Wed Mar 07 2012 Dave Jones +- Add debug patch for bugs 787171/766277 -* Sat Jan 15 2011 Kyle McMartin 2.6.38-0.rc0.git13.1 -- Linux 2.6.37-git13 -- Drop xen_export-arbitrary_virt_to_machine.patch, upstream. +* Wed Mar 07 2012 Josh Boyer +- CVE-2012-1146: memcg: unregister events attached to the same eventfd can + oops (rhbz 800817) -* Fri Jan 14 2011 Kyle McMartin -- xen_export-arbitrary_virt_to_machine.patch: pull patch from upstream - to fix build error. +* Mon Mar 05 2012 Josh Boyer +- CVE-2012-1097 regset: Prevent null pointer reference on readonly regsets +- Add patch to fix BUG_ON mm->nr_ptes (rhbz 786632) -* Fri Jan 14 2011 Kyle McMartin 2.6.38-0.rc0.git12.1 -- Linux 2.6.37-git12 -- 0001-use-__devexit-not-__exit-in-n2_unregister_algs-fixes.patch: drop - upstream patch. -- acpi-update-battery-information-on-notification-0x81.patch: drop upstream +* Fri Mar 02 2012 Dave Jones +- Enable VM debugging in non-debug kernels too. + +* Fri Mar 02 2012 Justin M. Forbes +- Disable threading in hibernate compression/decompression + +* Fri Mar 02 2012 Adam Jackson +- drm-intel-crtc-dpms-fix.patch: Fix system hang on gen2 kit on DPMS (#730853) + +* Thu Mar 01 2012 Justin M. Forbes 2.6.42.9-1 +- Linux 3.2.9 + +* Thu Mar 01 2012 Dave Jones +- Temporarily enable CONFIG_DEBUG_PAGEALLOC in -debug builds to help track + down some long-standing bugs. + Note: This will make -debug builds even slower than normal. + +* Thu Mar 01 2012 Dave Jones +- temporarily switch to low-performance polling IRQ mode when + unexpected IRQs occur. + +* Tue Feb 28 2012 Josh Boyer +- Add patch to enable keyboard backlight on Sony laptops (rhbz 728478) + +* Tue Feb 28 2012 Justin M. Forbes 2.6.42.7-3 +- CVE-2012-1090 CIFS: fix dentry refcount leak when opening a FIFO on lookup (rhbz 798296) + +* Mon Feb 27 2012 Josh Boyer +- Add patch to fix regression in FADT revision checks (rhbz 730007 727865) + +* Mon Feb 20 2012 Dave Jones 2.6.42.7-1 +- Do not call drivers when invalidating partitions for -ENOMEDIUM + +* Mon Feb 20 2012 Dave Jones +- Linux 3.2.7 + +* Mon Feb 20 2012 Dave Jones +- NFSv4: Fix an Oops in the NFSv4 getacl code + +* Fri Feb 17 2012 Dave Jones +- improve handling of null rate in LIS3LV02Dx accelerometer driver. (rhbz 785814) + +* Fri Feb 17 2012 Dave Jones +- Reenable radio drivers. (rhbz 784824) + +* Thu Feb 16 2012 Dave Jones +- Freeze all filesystems during system suspend/hibernate. + +* Wed Feb 15 2012 Josh Boyer +- Require newer linux-firmware for updated bnx2/bnx2x drivers + +* Mon Feb 13 2012 Dave Jones 2.6.42.6-3 +- Linux 3.2.6 + +* Fri Feb 10 2012 Josh Boyer +- Patch to prevent NULL pointer dereference in sd_revalidate_disk (rhbz 754518) + +* Fri Feb 10 2012 Dave Jones +- Implement TIOCGSERIAL for acm_tty_ioctl (rhbz 787607) + +* Thu Feb 09 2012 Dave Jones +- bsg: fix sysfs link remove warning (#787862) + +* Wed Feb 08 2012 Josh Boyer 2.6.42.3-2.fc15 +- CVE-2011-4086: jbd2: unmapped buffer with _Unwritten or _Delay flags + set can lead to DoS (rhbz 788260) +- Drop patch that was NAKd upstream (rhbz 783211) +- Fix e1000e Tx hang check (rhbz 785806) + +* Sun Feb 05 2012 Dave Jones +- Remove unnecessary block-stray-block-put-after-teardown.patch +- readahead: fix pipeline break caused by block plug + +* Fri Feb 03 2012 Dave Jones +- Linux 3.2.3 + +* Thu Feb 02 2012 Dennis Gilmore +- add patch to ensure that mfd-core is builtin when building nvec on tegra +- build nvec-leds on tegra kernel + +* Wed Feb 01 2012 Dave Jones +- Revert more f16 config changes that shouldn't be in f15. + +* Wed Feb 01 2012 Dave Jones +- Revert the f16 use-ext4-for-ext2/ext3 change. + +* Tue Jan 31 2012 Dennis Gilmore +- diable TOUCHSCREEN_EETI on all arm arches +- add patch for arm mtd +- add patch for stmmac on arm +- disable USB_IMX21_HCD pn imx +- enable CACHE_L2X0 on imx + +* Mon Jan 30 2012 Dave Jones +- Enable kmemleak (off by default) in kernel-debug (rhbz 782419) + +* Mon Jan 30 2012 Dave Jones +- Test fix for realtek_async_autopm oops from Stanislaw Gruszka (rhbz 784345) + +* Mon Jan 30 2012 Dave Jones +- Restore the Savage DRM and several others that were accidentally early-deprecated. + +* Mon Jan 30 2012 John W. Linville +- Reinstate patch to remove overlap between bcma/b43 and brcmsmac + +* Mon Jan 30 2012 Dave Jones 2.6.42.2-1 +- Rebase to 3.2.2 + +* Mon Jan 23 2012 Josh Boyer 2.6.41.10-3 +- Fix NULL pointer dereference in sym53c8xx module (rhbz 781625) + +* Fri Jan 20 2012 Josh Boyer +- Add mac80211 deauth fix pointed out by Stanislaw Gruszka + +* Wed Jan 18 2012 Josh Boyer 2.6.41.10-2 +- Fix broken procfs backport (rhbz 782961) + +* Wed Jan 18 2012 Josh Boyer 2.6.41.10-1 +- Linux 3.1.10 +- /proc/pid/* information leak (rhbz 782686) + +* Wed Jan 18 2012 Dennis Gilmore +- build perf on armv7hl + +* Wed Jan 18 2012 Josh Boyer +- CVE-2012-0056 proc: clean up and fix /proc//mem (rhbz 782681) +- loop: prevent information leak after failed read (rhbz 782687) + +* Tue Jan 17 2012 Josh Boyer +- CVE-2011-4127 possible privilege escalation via SG_IO ioctl (rhbz 769911) + +* Sun Jan 15 2012 Josh Boyer +- Avoid packaging symlinks for kernel-doc files (rhbz 767351) + +* Fri Jan 13 2012 Josh Boyer +- Fix verbose logging messages in the rtl8192cu driver (rhbz 728740) + +* Fri Jan 13 2012 Josh Boyer 2.6.41.9-1 +- Linux 3.1.9 +- CVE-2012-0045 kvm: syscall instruction induced guest panic (rhbz 773392) + +* Wed Jan 11 2012 Josh Boyer +- Patch from Stanislaw Gruszka to fix NULL ptr deref in mac80211 (rhbz 769766) + +* Tue Jan 10 2012 Josh Boyer +- Fix ext3/ext4 corrupted bitmap error path (pointed out by Eric Sandeen) + +* Fri Jan 06 2012 Josh Boyer 2.6.41.8-1 +- Linux 3.1.8 + +* Wed Jan 04 2012 Josh Boyer +- CVE-2011-4347 kvm: device assignment DoS (rhbz 770096) + +* Tue Jan 03 2012 Josh Boyer 2.6.41.7-1 +- Linux 3.1.7 + +* Tue Jan 03 2012 Josh Boyer +- Add bluetooth support for BCM20102A0 (rhbz 770233) + +* Tue Jan 03 2012 Josh Boyer +- CVE-2011-4622 kvm: pit timer with no irqchip crashes the system (rhbz 770102) + +* Tue Jan 03 2012 Dave Jones +- thp: reduce khugepaged freezing latency (rhbz 771006) + +* Wed Dec 21 2011 Dave Jones 2.6.41.6-1 +- Linux 3.1.6 (Fedora 2.6.31.6) + +* Wed Dec 21 2011 Dave Jones 2.6.41.5-5 +- Reinstate the route cache garbage collector. + +* Tue Dec 20 2011 Josh Boyer +- Fix config options in arm configs after latest commits +- Backport upstream fix for b44_poll oops (rhbz #741117) + +* Mon Dec 19 2011 Dave Jones +- x86, dumpstack: Fix code bytes breakage due to missing KERN_CONT + +* Thu Dec 15 2011 Dennis Gilmore +- build imx highbank and kirkwood kernel variants on arm +- add patch for tegra usb storage resets +- omap config cleanups from dmarlin + +* Thu Dec 15 2011 Josh Boyer - 2.6.41.5-4 +- Add patch to fix Intel wifi regression in 3.1.5 (rhbz 767173) +- Add patch from Jeff Layton to fix suspend with NFS (rhbz #717735) +- Backport ALPS touchpad patches from input/next branch (rhbz #590880) + +* Thu Dec 15 2011 Dave Jones - 2.6.41.5-3 +- Disable Intel IOMMU by default. + +* Fri Dec 09 2011 Josh Boyer 2.6.41.5-1 +- Linux 3.1.5 (Fedora 2.6.41.5) + +* Thu Dec 08 2011 Chuck Ebbert 2.6.41.5-0.rc2.1 +- Linux 3.1.5-rc2 (Fedora 2.6.41.5-rc2) +- Fix wrong link speed on some sky2 network adapters (rhbz #757839) + +* Wed Dec 07 2011 Chuck Ebbert +- Linux 3.1.5-rc1 (Fedora 2.6.41.5-rc1) +- Comment out merged patches: + xfs-Fix-possible-memory-corruption-in-xfs_readlink.patch + rtlwifi-fix-lps_lock-deadlock.patch + +* Tue Dec 06 2011 Chuck Ebbert +- Disable uas until someone can fix it (rhbz #717633) + +* Tue Dec 06 2011 Josh Boyer +- Add reworked pci ASPM patch from Matthew Garrett + +* Mon Dec 05 2011 Josh Boyer +- Only print the apm_cpu_idle message once (rhbz #760341) + +* Mon Dec 05 2011 Dave Jones +- Switch from -Os to -O2 + +* Thu Dec 01 2011 Josh Boyer +- Apply patch to revert mac80211 scan optimizations (rhbz #731365) +- Disable the existing brcm80211 staging drivers (rhbz #759109) + +* Wed Nov 30 2011 Josh Boyer +- Include commit 3940d6185 from JJ Ding in elantech.patch + +* Tue Nov 29 2011 Josh Boyer +- Add patch to fix deadlock in rtlwifi (rhbz #755154) +- Drop drm-intel-make-lvds-work.patch (rhbz #731296) + +* Mon Nov 28 2011 Chuck Ebbert 2.6.41.4-1 +- Linux 3.1.4 (Fedora 2.6.41.4) + +* Mon Nov 28 2011 Chuck Ebbert 3.1.4-1 +- Linux 3.1.4 + +* Mon Nov 28 2011 Chuck Ebbert +- Fix IRQ error preventing load of cciss module (rhbz#754907) + +* Mon Nov 28 2011 Ben Skeggs +- nouveau: fix two instances of an oops in ttm clear() (rhbz#751753) + +* Mon Nov 28 2011 Chuck Ebbert 2.6.41.3-1 +- Fake version 2.6.4X by changing UTSNAME + (instead of changing the internal kernel version) + +* Sun Nov 27 2011 Chuck Ebbert +- Linux 3.1.3 (Fedora 2.6.41.3) + +* Wed Nov 23 2011 Chuck Ebbert 2.6.41.3-0.rc1.1 +- Linux 3.1.3-rc1 (Fedora 2.6.41.3-rc1) +- Comment out merged patches: + usb-add-quirk-for-logitech-webcams.patch + ip6_tunnel-copy-parms.name-after-register_netdevice.patch + +* Tue Nov 22 2011 Chuck Ebbert 2.6.41.2-1 +- Linux 3.1.2 (Fedora 2.6.41.2) + +* Sat Nov 19 2011 Chuck Ebbert 2.6.41.2-0.rc1.1 +- Linux 3.1.2-rc1 (Fedora 2.6.41.2-rc1) + +* Fri Nov 18 2011 Dennis Gilmore +- enable selinux to work on arm + +* Wed Nov 16 2011 Kyle McMartin +- Work around #663080 on s390x and restore building perf there. + +* Tue Nov 15 2011 Dave Jones +- mm: Do not stall in synchronous compaction for THP allocations + +* Mon Nov 14 2011 Josh Boyer +- Patch from Joshua Roys to add rtl8192* to modules.networking (rhbz 753645) +- Add patch for wacom tablets for Bastien Nocera (upstream 3797ef6b6) +- Add patch to fix ip6_tunnel naming (rhbz 751165) +- Quite warning in apm_cpu_idle (rhbz 753776) + +* Mon Nov 14 2011 Josh Boyer 2.6.41.1-2 +- CVE-2011-4131: nfs4_getfacl decoding kernel oops (rhbz 753236) +- CVE-2011-4132: jbd/jbd2: invalid value of first log block leads to oops (rhbz 753346) + +* Fri Nov 11 2011 Chuck Ebbert +- Use the same naming scheme as rawhide for -stable RC kernels + (e.g. 2.6.41.1-0.rc1.1 instead of 2.6.41.1-1.rc1) + +* Fri Nov 11 2011 Josh Boyer 2.6.41.1-1 +- Linux 3.1.1 + +* Fri Nov 11 2011 John W. Linville +- Remove overlap between bcma/b43 and brcmsmac and reenable bcm4331 + +* Thu Nov 10 2011 Chuck Ebbert +- Sync samsung-laptop driver with what's in 3.2 (rhbz 747560) + +* Wed Nov 09 2011 Chuck Ebbert 2.6.41.1-1.rc1 +- Linux 3.1.1-rc1 (Fedora 2.6.41.1-rc1) +- Comment out merged patches, will drop when release is final: + ums-realtek-driver-uses-stack-memory-for-DMA.patch + epoll-fix-spurious-lockdep-warnings.patch + crypto-register-cryptd-first.patch + add-macbookair41-keyboard.patch + powerpc-Fix-deadlock-in-icswx-code.patch + iwlagn-fix-ht_params-NULL-pointer-dereference.patch + mmc-Always-check-for-lower-base-frequency-quirk-for-.patch + media-DiBcom-protect-the-I2C-bufer-access.patch + media-dib0700-protect-the-dib0700-buffer-access.patch + WMI-properly-cleanup-devices-to-avoid-crashes.patch + +* Wed Nov 09 2011 John W. Linville +- Backport brcm80211 from 3.2-rc1 + +* Mon Nov 07 2011 Dave Jones +- Rebase to 3.1.0 + +* Thu Nov 03 2011 Josh Boyer +- Add patches queued for 3.2 for elantech driver (rhbz 728607) + +* Wed Nov 02 2011 Josh Boyer +- Add patch to fix oops when removing wmi module (rhbz 706574) + +* Tue Nov 01 2011 Dave Jones 2.6.40.8-5 +- allow building the perf rpm for ARM (rhbz 741325) + +* Tue Nov 01 2011 Josh Boyer 2.6.40.8-4 +- Drop x86-efi-Calling-__pa-with-an-ioremap-address-is-invalid (rhbz 748516) + +* Tue Nov 01 2011 Dave Jones +- Add another Sony laptop to the nonvs blacklist. (rhbz 641789) + +* Mon Oct 31 2011 Josh Boyer +- CVE-2011-4097: oom_badness() integer overflow (rhbz 750402) + +* Fri Oct 28 2011 Josh Boyer +- Add patch to prevent tracebacks on a warning in floppy.c (rhbz 749887) + +* Wed Oct 26 2011 Josh Boyer 2.6.40.8-2 +- CVE-2011-4077: xfs: potential buffer overflow in xfs_readlink() (rhbz 749166) + +* Tue Oct 25 2011 Josh Boyer +- CVE-2011-3347: be2net: promiscuous mode and non-member VLAN packets DoS (rhbz 748691) +- CVE-2011-1083: excessive in kernel CPU consumption when creating large nested epoll structures (rhbz 748668) + +* Tue Oct 25 2011 Josh Boyer +- Linux 3.0.8 stable release + +* Mon Oct 24 2011 Chuck Ebbert +- Add patch from LKML to fix Samsung notebook brightness flicker (rhbz 737108) + +* Mon Oct 24 2011 Dave Jones +- Print modules list from bad_page() + +* Mon Oct 24 2011 Josh Boyer 2.6.40.7-3 +- Backport 3 fixed from linux-next to fix dib0700 playback (rhbz 733827) + +* Fri Oct 21 2011 Dave Jones +- Lower severity of Radeon lockup messages. + +* Thu Oct 20 2011 Josh Boyer +- Add backport for P4 watchdog and perf support from Don Zickus (rhbz 713675) + +* Wed Oct 19 2011 Dave Jones +- Add Sony VGN-FW21E to nonvs blacklist. (rhbz 641789) + +* Tue Oct 18 2011 Josh Boyer +- Add patch to fix invalid EFI remap calls from Matt Fleming +- Add patch to fix lock inversion introduced in 3.0.7 + +* Mon Oct 17 2011 Josh Boyer 2.6.40.7-0 +- Linux 3.0.7 stable release +- Add two patches to fix stalls in khugepaged (rhbz 735946) + +* Thu Oct 13 2011 Josh Boyer +- Update usb-add-quirk-for-logitech-webcams.patch with C600 ID (rhbz 742010) + +* Thu Oct 13 2011 Adam Jackson +- drm/i915: Treat SDVO LVDS as digital when parsing EDID (#729882) + +* Tue Oct 11 2011 Josh Boyer +- fix memory leak in fuse (rhbz 745241) + +* Tue Oct 11 2011 Dave Jones +- add e1000e workaround for packet drop on 82579 at 100Mbps (rhbz 713315) + +* Thu Oct 06 2011 Josh Boyer +- Add patch to fix base frequency check for Ricoh e823 devices (rhbz 722509) + +* Mon Oct 03 2011 Josh Boyer 2.6.40.6-0 +- Linux 3.0.6 stable release + +* Mon Oct 03 2011 Josh Boyer 2.6.40.4-6 +- Add patch to fix PIE execution when ASLR is disabled at runtime (rhbz 708563) + +* Thu Sep 29 2011 Josh Boyer +- Backport two upstream patches to fix rhbz 700718 + +* Wed Sep 28 2011 Josh Boyer +- Backport upstream block patch to try and fix a number of oopses we're seeing + with USB drive removals +- Update usb-add-quirk-for-logitech-webcams.patch (rhbz 742010) + +* Tue Sep 27 2011 Josh Boyer +- Backport support for Samsung n150 class machines (rhbz 496975) + +* Mon Sep 26 2011 Chuck Ebbert +- Fix breakage of Apple MagicMouse/Trackpad (rhbz #714381) + +* Fri Sep 23 2011 Josh Boyer +- Add patch to fix 1 second delay from MD driver during shutdown (rhbz 740645) +- CVE-2011-1161 CVE-2011-1162: tpm: infoleaks + +* Thu Sep 22 2011 Dennis Gilmore +- build a vmlinux image on sparc64 + +* Thu Sep 15 2011 Josh Boyer +- CVE-2011-3191: cifs: fix possible memory corruption in CIFSFindNext + +* Wed Sep 07 2011 Josh Boyer +- Add patch to fix oops when linking entities in ucvideo (rhbz 735437) + +* Wed Aug 31 2011 Dave Jones +- Reinstate some conflicts: that disappeared during the rebase (rhbz 710646) + +* Tue Aug 30 2011 Josh Boyer 2.6.40.4-5 +- Fix kconfig error in patch for rhbz 606017 + +* Tue Aug 30 2011 Chuck Ebbert 2.6.40.4-4 +- Fix unsafe pointer access in sendmsg/sendmmsg + +* Tue Aug 30 2011 Josh Boyer +- Add patch to fix rhbz 606017 + +* Mon Aug 29 2011 Chuck Ebbert 2.6.40.4-3 +- Linux 3.0.4 + +* Sat Aug 27 2011 Dave Jones +- Fix get_gate_vma usage in 32bit NX emulation. + +* Fri Aug 26 2011 Chuck Ebbert +- Add fixes for cifs mount oopses (rhbz#727927 rhbz#731278 rhbz#732934) + +* Thu Aug 25 2011 Chuck Ebbert +- Reduce severity of host bridge window conflict warnings (rhbz#729652) + +* Thu Aug 25 2011 Chuck Ebbert 2.6.40.3-2 +- Add patches queued for 3.0.4 +- Comment out xen-blkfront-name-adjust.patch, now queued for -stable + +* Thu Aug 25 2011 Chuck Ebbert +- VFS: Fix automount for negative autofs dentries (rhbz#719607) + +* Thu Aug 25 2011 Ben Skeggs +- nouveau: add patch fixing ttm issues that lead to oopses/corruption (rhbz#699551) + +* Wed Aug 24 2011 Chuck Ebbert +- Automate the kernel version faking. + +* Tue Aug 23 2011 Ben Skeggs +- nouveau: pull patches from 3.1 to fix some suspend/hibernate problems (rhbz#730582) + +* Mon Aug 22 2011 Dave Jones +- Revert 'iwlwifi: advertise max aggregate size'. (rhbz 708747) + +* Mon Aug 22 2011 Chuck Ebbert +- Update to 3.0.3-final + +* Mon Aug 22 2011 Dave Jones +- Avoid false quiescent states in rcutree with CONFIG_RCU_FAST_NO_HZ. (rhbz 577968) + +* Fri Aug 19 2011 Josh Boyer +- Add patch to fix race between cryptd and aesni (rhbz 721002) + +* Wed Aug 17 2011 Dennis Gilmore +- add patch to correctly initialise usb on trimslice systems +- build in usb-storage on tegra, internal ssd on trimslice is connected to usb + +* Tue Aug 16 2011 Dennis Gilmore +- add patch to work around gcc bug on arm + +* Mon Aug 15 2011 Dave Jones 2.6.40.3-0 +- Apply patches from 3.0.3-rc1 + +* Mon Aug 15 2011 Dave Jones +- Apply patches from 3.0.2 + +* Mon Aug 15 2011 Dave Jones +- CVE-2011-2905 perf tools may parse user-controlled config file. (rhbz 729809) + +* Sat Aug 13 2011 Dave Jones +- Apply patches from 3.0.2rc1 + +* Thu Aug 11 2011 Dennis Gilmore +- add config for arm tegra devices +- setup kernel to build omap image (patch from David Marlin) +- setup kernel to build tegra image based on omap work +- add arm device tree patches + +* Thu Aug 11 2011 Josh Boyer +- Add munged together patch for rhbz 729269 + +* Thu Aug 11 2011 Dave Jones +- Fix Xen blk device naming (rhbz 729340) + +* Tue Aug 09 2011 Josh Boyer +- Add Makefile.config and ARM config changes from David Marlin + +* Tue Aug 09 2011 Dave Jones +- ptrace_report_syscall: check if TIF_SYSCALL_EMU is defined + +* Tue Aug 09 2011 Dave Jones +- Enable CONFIG_SAMSUNG_LAPTOP (rhbz 729363) + +* Tue Aug 09 2011 Dave Jones 2.6.40.1-2 +- Fix stray block put after queue teardown (rhbz 728872) + +* Sun Aug 07 2011 Dave Jones +- Utrace fixes. (rhbz 728379) + +* Fri Aug 05 2011 Dave Jones 2.6.40.1-1 +- Revert f16-only change that made IPV6 built-in. + +* Fri Aug 05 2011 Dave Jones +- Final 3.0.1 diff. + +* Thu Aug 04 2011 Dave Jones +- Drop neuter_intel_microcode_load.patch (rhbz 690930) + +* Wed Aug 03 2011 Dave Jones +- iwlagn: check for !priv->txq in iwlagn_wait_tx_queue_empty (rhbz 728044) + +* Wed Aug 03 2011 Dave Jones +- Apply patches from patch-3.0.1-rc1 + +* Wed Aug 03 2011 John W. Linville +- Disable CONFIG_BCMA since no driver currently uses it (rhbz 727796) + +* Wed Aug 03 2011 Josh Boyer +- rt2x00: Add device ID for RT539F device. (rhbz 720594) +- Add patch to fix backtrace in cdc_ncm driver (rhbz 720128) +- Add patch to fix backtrace in usm-realtek driver (rhbz 720054) + +* Tue Aug 02 2011 Josh Boyer +- Fix epoll recursive lockdep warnings (rhbz 722472) + +* Tue Aug 02 2011 Josh Boyer +- Add patch to fix HFSPlus filesystem mounting (rhbz 720771) + +* Tue Aug 02 2011 Dave Jones +- Change USB_SERIAL_OPTION back to modular. (rhbz 727680) + +* Tue Aug 02 2011 Josh Boyer 2.6.40-5 +- Add change from Yanko Kaneti to get the rt2x00 drivers in modules.networking + (rhbz 708314) + +* Fri Jul 29 2011 Dave Jones 2.6.40-4 +- Re-add utrace, which got accidentally dropped during the rebase. + +* Thu Jul 28 2011 Dave Jones 2.6.40-3 +- Fix module-init-tools conflict: + +* Thu Jul 28 2011 Dave Jones 2.6.40-2 +- fix crash in scsi_dispatch_cmd() + +* Thu Jul 28 2011 Dave Jones 2.6.40-1 +- Turn off debugging options. (make release) + +* Tue Jul 26 2011 Dave Jones 2.6.40-0 +- Rebase to final 3.0 (munge to 2.6.40-0) + +* Thu Jun 30 2011 Kyle McMartin 2.6.40-0.rc5.git0.1 +- More than meets the eye, it's Linux 3.0-rc5 in disguise. + +* Mon Jun 27 2011 Dave Jones +- Disable CONFIG_CRYPTO_MANAGER_DISABLE_TESTS, as this also disables FIPS (rhbz 716942) + +* Thu Jun 23 2011 Kyle McMartin 3.0-0.rc4.git3.1 +- Linux 3.0-rc4-git3 +- Drop linux-3.0-fix-uts-release.patch, and instead just perl the Makefile +- linux-2.6-silence-noise.patch: fix context +- iwlagn-fix-dma-direction.patch: fix DMAR errors (for me at least) + +* Wed Jun 22 2011 Kyle McMartin 3.0-0.rc4.git0.2 +- Re-enable debuginfo generation. Thanks to Richard Jones for noticing... no + wonder builds had been so quick lately. + +* Tue Jun 21 2011 Kyle McMartin 3.0-0.rc4.git0.1 +- Linux 3.0-rc4 (getting closer...) + +* Fri Jun 17 2011 Kyle McMartin 3.0-0.rc3.git6.1 +- Update to 3.0-rc3-git6 + +* Fri Jun 17 2011 Dave Jones +- drop qcserial 'compile fix' that was just duplicating an include. +- drop struct sizeof debug patch. (no real value. not upstreamable) +- drop linux-2.6-debug-always-inline-kzalloc.patch. + Can't recall why this was added. Can easily re-add if deemed necessary. + +* Fri Jun 17 2011 Kyle McMartin +- linux-2.6-defaults-pci_no_msi.patch: drop, haven't toggled the default + in many moons. +- linux-2.6-defaults-pci_use_crs.patch: ditto. +- linux-2.6-selinux-mprotect-checks.patch: upstream a while ago. +- drm-i915-gen4-has-non-power-of-two-strides.patch: drop buggy bugfix +- drop some more unapplied crud. +- We haven't applied firewire patches in a dogs age. + +* Fri Jun 17 2011 Kyle McMartin 3.0-0.rc3.git5.1 +- Try updating to a git snapshot for the first time in 3.0-rc, + update to 3.0-rc3-git5 +- Fix a subtle bug I introduced in 3.0-rc1, "patch-3." is 9 letters, not 10. + +* Thu Jun 16 2011 Kyle McMartin +- Disable mm patches which had been submitted against 2.6.39, as Rik reports + they seem to aggravate a VM_BUG_ON. More investigation is necessary. + +* Wed Jun 15 2011 Kyle McMartin +- Conflict with pre-3.2.1-5 versions of mdadm. (#710646) + +* Wed Jun 15 2011 Kyle McMartin +- Build in aesni-intel on i686 for symmetry with 64-bit. + +* Tue Jun 14 2011 Kyle McMartin 3.0-0.rc3.git0.3 +- Fix libdm conflict (whose bright idea was it to give subpackages differing + version numbers?) + +* Tue Jun 14 2011 Kyle McMartin +- Update to 3.0-rc3, add another conflicts to deal with 2 digit + versions (libdm.) +- Simplify linux-3.0-fix-uts-release.patch now that SUBLEVEL is optional. +- revert-ftrace-remove-unnecessary-disabling-of-irqs.patch: drop upstreamed patch. -- mm-*.patch: drop upstream patches. -- important config changes: - ACPI_IPMI=m - CRYPTO_AES_NI_INTEL=m [i386] - TRANSPARENT_HUGEPAGE=y +- drm-intel-eeebox-eb1007-quirk.patch: ditto. +- ath5k-disable-fast-channel-switching-by-default.patch: ditto. -* Wed Jan 12 2011 Kyle McMartin 2.6.38-0.rc0.git9.1 -- Linux 2.6.37-git9 -- Re-enable DEBUG_SET_MODULE_RONX since commit 94462ad3 fixed it. -- Enable some more new random HID and sensor junk as modules. +* Thu Jun 09 2011 Kyle McMartin +- ath5k-disable-fast-channel-switching-by-default.patch (rhbz#709122) + (korgbz#34992) [a99168ee in wireless-next] -* Tue Jan 11 2011 Matthew Garrett -- linux-2.6-ehci-check-port-status.patch - fix USB resume on some AMD systems +* Thu Jun 09 2011 Kyle McMartin 3.0-0.rc2.git0.2 +- rhbz#710921: revert-ftrace-remove-unnecessary-disabling-of-irqs.patch -* Mon Jan 10 2011 Jarod Wilson -- Add support for local rebuild config option overrides -- Add missing --with/--without pae build flag support +* Wed Jun 08 2011 Kyle McMartin 3.0-0.rc2.git0.1 +- Update to 3.0-rc2, rebase utsname fix. +- Build IPv6 into the kernel for a variety of reasons + (http://lists.fedoraproject.org/pipermail/kernel/2011-June/003105.html) -* Mon Jan 10 2011 Kyle McMartin 2.6.38-0.rc0.git4.2 -- Disable DEBUG_SET_MODULE_RONX for now, it causes boot-up to fail since - dynamic ftrace is trying to rewrite instructions on module load. +* Mon Jun 06 2011 Kyle McMartin 3.0-0.rc1.git0.3 +- Conflict with module-init-tools older than 3.13 to ensure the + 3.0 transition is handled correctly. -* Mon Jan 10 2011 Kyle McMartin -- Drop obsolete linux-2.6-debug-nmi-timeout.patch +* Wed Jun 01 2011 Kyle McMartin 3.0-0.rc1.git0.2 +- Fix utsname for 3.0-rc1 -* Mon Jan 10 2011 Kyle McMartin 2.6.38-0.rc0.git4.1 -- Branch for 2.6.38 -- Rebase trivial patches. -- Switch debug configs back on. -- config changes: - DEBUG_SET_MODULE_RONX=y - B43_PHY_N=y - RT2800USB_RT33XX=y | - RT2800PCI_RT33XX=y | experimental - WL12XX=m - RTL8192CE=m - CAN_SLCAN=m - SCHED_AUTOGROUP=n +* Mon May 30 2011 Kyle McMartin 3.0-0.rc1.git0.1 +- Linux 3.0-rc1 (won't build until module-init-tools gets an update.) -* Fri Jan 07 2011 Kyle McMartin 2.6.37-2 -- drm_i915-check-eDP-encoder-correctly-when-setting-modes.patch reported to - fix HP/Sony eDP issues by adamw and airlied. - -* Wed Jan 05 2011 Dennis Gilmore -- build sparc headers on sparcv9 - -* Tue Jan 04 2011 Dennis Gilmore -- add patch for sparc build failure - -* Tue Jan 04 2011 Kyle McMartin 2.6.37-1 -- Track release of 2.6.37 - -* Mon Jan 03 2011 Kyle McMartin 2.6.37-0.rc8.git3.1 -- Linux 2.6.37-rc8-git3 -- Merged acpi battery notification patch and -rc8. - -* Thu Dec 23 2010 Kyle McMartin -- Pull in flexcop procfs rename patch since it's still not upstream. (#664852) - -* Tue Dec 21 2010 Kyle McMartin 2.6.37.0.rc7.git0.2 -- Linux 2.6.37-rc7 -- CONFIG_USB_OTG=n (seems unnecessary?) -- Enable release builds until .37 releases in rawhide. - -* Sun Dec 19 2010 Kyle McMartin 2.6.37-0.rc6.git5.1 -- Linux 2.6.37-rc6-git5 -- sched-cure-more-NO_HZ-load-average-woes.patch: upstream. - -* Sat Dec 18 2010 Kyle McMartin -- Patch from nhorman against f13: - Enhance AF_PACKET to allow non-contiguous buffer alloc (#637619) - -* Sat Dec 18 2010 Kyle McMartin -- Fix SELinux issues with NFS/btrfs and/or xfsdump. (#662344) - -* Fri Dec 17 2010 Matthew Garrett 2.6.37-0.rc6.git0.3 -- efi_default_physical.patch: Revert hunk that breaks boot -- linux-next-macbook-air-input.patch: Add input support for new Macbook Airs - -* Thu Dec 16 2010 Matthew Garrett 2.6.37-0.rc6.git0.2 -- applesmc_update.patch: Make the driver more generic. Should help Apples. -- apple_backlight.patch: Make sure that this loads on all hardware. -- efifb_update.patch: Fixes for the 11 inch Macbook Air -- acpi_reboot.patch: Should make reboot work better on most hardware -- efi_default_physical.patch: Some machines dislike EFI virtual mode - -* Wed Dec 15 2010 Kyle McMartin 2.6.37-0.rc6.git0.1 -- Linux 2.6.37-rc6 -- Re-activate acpi patch which rejected on the previous commit. - -* Wed Dec 15 2010 Kyle McMartin 2.6.37-0.rc5.git5.1 -- 2.6.37-rc5-git5 - -* Fri Dec 10 2010 Kyle McMartin -- Another patch from mjg59: Set _OSC supported field correctly (#638912) - -* Fri Dec 10 2010 Kyle McMartin -- pci-disable-aspm-if-bios-asks-us-to.patch: Patch from mjg59 to disable - ASPM if the BIOS has disabled it, but enabled it already on some devices. - -* Thu Dec 09 2010 Kyle McMartin -- Snarf patch from wireless-next to fix mdomsch's orinico wifi. - (orinoco: initialise priv->hw before assigning the interrupt) - [229bd792] (#657864) - -* Wed Dec 08 2010 Kyle McMartin 2.6.37-0.rc5.git2.1 -- Linux 2.6.37-rc5-git2 -- sched-cure-more-NO_HZ-load-average-woes.patch: fix some of the complaints - in 2.6.35+ about load average with dynticks. (rhbz#650934) - -* Tue Dec 07 2010 Kyle McMartin 2.6.37-0.rc5.git0.1 -- Linux 2.6.37-rc5 - -* Sat Dec 04 2010 Kyle McMartin -- Enable C++ symbol demangling with perf by linking against libiberty.a, - which is LGPL2. - -* Fri Dec 03 2010 Kyle McMartin -- Linux 2.6.37-rc4-git3 -- Enable HP ILO on x86_64 for (#571329) -- Drop merged drm-fixes.patch, split out edp-fixes. -- tty-dont-allow-reopen-when-ldisc-is-changing.patch: upstream. -- tty-ldisc-fix-open-flag-handling.patch: upstream. -- Enable CIFS_ACL. - -* Thu Dec 02 2010 Kyle McMartin -- Grab some of Mel's fixes from -mmotm to hopefully sort out #649694. - -* Wed Dec 01 2010 Kyle McMartin 2.6.37-0.rc4.git1.1 -- Linux 2.6.37-rc4-git1 -- Pull in DRM fixes that are queued for -rc5 [3074adc8] - + edp-fixes on top - -* Tue Nov 30 2010 Kyle McMartin 2.6.37-0.rc4.git0.1 -- Linux 2.6.37-rc4 - -* Mon Nov 29 2010 Kyle McMartin -- Update debug-vm-would_have_oomkilled patch. - -* Mon Nov 29 2010 Kyle McMartin 2.6.37-0.rc3.git6.1 -- Linux 2.6.37-rc3-git6 -- TTY: open/hangup race fixup (rhbz#630464) - -* Fri Nov 26 2010 Kyle McMartin 2.6.37-0.rc3.git3.1 -- Linux 2.6.37-rc3-git3 -- Print tty->flags as well in debugging patch... - -* Fri Nov 26 2010 Kyle McMartin -- Copy tty_open WARN_ON debugging patch from rawhide. - -* Fri Nov 26 2010 Kyle McMartin 2.6.37-0.rc3.git2.1 -- Linux 2.6.37-rc3-git2 -- CGROUP_MEM_RES_CTLR_SWAP_ENABLED is not set, so the cgroup memory - resource controller swap accounting is disabled by default. You can - enable it with 'swapaccount' if desired. -- TTY: don't allow reopen when ldisc is changing (rhbz#630464) - -* Wed Nov 24 2010 Kyle McMartin 2.6.37-0.rc3.git1.1 -- Linux 2.6.37-rc3-git1 - -* Mon Nov 22 2010 Kyle McMartin 2.6.37-0.rc3.git0.1 -- Linux 2.6.37-rc3 - -* Sat Nov 20 2010 Kyle McMartin 2.6.37-0.rc2.git7.1 -- Linux 2.6.37-rc2-git7 - -* Fri Nov 19 2010 Kyle McMartin 2.6.37-0.rc2.git5.1 -- Linux 2.6.37-rc2-git5 - -* Thu Nov 18 2010 Kyle McMartin -- Move %{fedora_build} in the un-released (ie: -git/-rc) kernel case for - a variety of reasons, principally so that: - 1: Bumping %baserelease isn't needed if we're just updating snapshots. - 2: %buildid will sort as newer so we don't need to bump baserelease when - building bugzilla fixes. - -* Wed Nov 17 2010 Kyle McMartin 2.6.37-0.1.rc2.git2 -- Linux 2.6.37-rc2-git2 -- enable STRICT_DEVMEM on s390x. - -* Wed Nov 17 2010 Kyle McMartin -- Make vmlinuz/System.map root read-write only by default. You can just - chmod 644 them later if you (unlikely) need them without root. - -* Mon Nov 15 2010 Kyle McMartin 2.6.37-0.1.rc2.git0 -- Linux 2.6.37-rc2 - -* Sat Nov 13 2010 Kyle McMartin 2.6.37-0.1.rc1.git10 -- Linux 2.6.37-rc1-git10 -- SECURITY_DMESG_RESTRICT added, the principle of least surprise dictates - we should probably have it off. If you want to restrict dmesg access - you may use the kernel.dmesg_restrict sysctl. -- linux-2.6-bluetooth-autosuspend.patch: merged upstream. - -* Tue Nov 09 2010 Kyle McMartin 2.6.37-0.1.rc1.git7 -- Linux 2.6.37-rc1-git7 - -* Mon Nov 08 2010 Kyle McMartin 2.6.37-0.1.rc1.git5 -- Linux 2.6.37-rc1-git5 - -* Mon Nov 08 2010 Kyle McMartin -- Cherry-pick utrace-ptrace fixes from mayoung. Thanks! - -* Tue Nov 02 2010 Kyle McMartin 2.6.37-0.1.rc1.git0 -- Linux 2.6.37-rc1 - -* Tue Oct 26 2010 Kyle McMartin 2.6.37-0.1.rc0.git8 -- Linux 2.6.36-git8 - -* Fri Oct 22 2010 Kyle McMartin 2.6.37-0.1.rc0.git2 -- Switch to tracking git snapshots of what will become 2.6.37. -- Fix context rejects in utrace and a few other patches. - -* Wed Oct 20 2010 Chuck Ebbert 2.6.36-1 -- Linux 2.6.36 - -* Wed Oct 20 2010 Matthew Garrett 2.6.36-0.42.rc8.git5 -- runtime_pm_fixups.patch: should fix this on Thinkpads - -* Tue Oct 19 2010 Chuck Ebbert 2.6.36-0.41.rc8.git5 -- Linux 2.6.36-rc8-git5 -- Update PCI _CRS fixes - -* Mon Oct 18 2010 Kyle McMartin 2.6.36-0.40.rc8.git0 -- Backport xHCI suspend/resume code from linux-next. - -* Mon Oct 18 2010 Kyle McMartin -- ima: Default it to off, pass ima=on to enable. Reduce impact of the option - when disabled. - -* Mon Oct 18 2010 Kyle McMartin -- Quirk to disable DMAR with Ricoh card reader/firewire. (rhbz#605888) - -* Fri Oct 15 2010 Kyle McMartin -- Switched to pci=use_crs by default (it should have been fixed since - cebbert sucked in the patches anyway.) - -* Fri Oct 15 2010 Kyle McMartin -- backport pnpacpi-cope-with-invalid-device-ids from linux-next. - (rhbz#641468) - -* Fri Oct 15 2010 Kyle McMartin 2.6.36-0.39.rc8.git0 -- Linux 2.6.36-rc8. - -* Thu Oct 14 2010 Kyle McMartin 2.6.36-0.38.rc7.git5 -- Linux 2.6.36-rc7-git5 -- Disable runtime PM until it can be poked at. - -* Tue Oct 12 2010 Kyle McMartin 2.6.36-0.36.rc7.git3 -- Linux 2.6.36-rc7-git3 -- Drop fix-oldnoconfig-to-dtrt.patch, nonintconfig patches are upstream! - -* Mon Oct 11 2010 Matthew Garrett 2.6.36-0.35.rc7.git1 -- linux-2.6-enable-more-pci-autosuspend.patch: Enable more PCI autosuspend - -* Wed Oct 06 2010 Kyle McMartin 2.6.36-0.35.rc7.git0 -- Linux 2.6.36-rc7 upstream. - -* Wed Oct 06 2010 Dave Jones -- Another day, another rcu_dereference warning. (#640673) - -* Tue Oct 05 2010 Kyle McMartin 2.6.36-0.34.rc6.git3 -- Linux 2.6.36-rc6-git3 -- Drop intel_ips patches merged upstream. - -* Sun Oct 03 2010 Kyle McMartin 2.6.36-0.32.rc6.git2 -- Enable printk.time by default for more useful logs. - -* Sat Oct 02 2010 Kyle McMartin 2.6.36-0.31.rc6.git2 -- Linux 2.6.36-rc6-git2 - -* Thu Sep 30 2010 Dave Jones -- silence another rcu_reference warning - -* Thu Sep 30 2010 Kyle McMartin 2.6.36-0.30.rc6 -- Collection of patches to make intel_ips work properly. - -* Wed Sep 29 2010 Dave Jones -- Add back an old hack to make an SDV e1000e variant work. - -* Wed Sep 29 2010 Dave Jones -- Enable IB700 watchdog (used by qemu/kvm). (#637152) - -* Tue Sep 28 2010 Kyle McMartin 2.6.36-0.28.rc6 -- Linux 2.6.36-rc6 - -* Fri Sep 24 2010 Chuck Ebbert 2.6.36-0.27.rc5.git6 -- Linux 2.6.36-rc5-git6 - -* Thu Sep 23 2010 Kyle McMartin -- Bump x86 NR_CPUS to 64. (Still 512/256 on x86_64.) - -* Thu Sep 23 2010 Chuck Ebbert 2.6.36-0.26.rc5.git4 -- Linux 2.6.36-rc5-git4 -- Drop merged patches: - fix-icebp-breakpoints.patch - linux-2.6.35.4-virtio_console-fix-poll.patch -- Add patches to fix problems with PCI _CRS - -* Thu Sep 23 2010 Kyle McMartin 2.6.36-0.25.rc5 -- Add s390 vdso AFTER_LINK to Roland's linux-2.6-makefile-after_link.patch - -* Thu Sep 23 2010 Kyle McMartin -- Snipe ACPI patch from mjg59 to fix battery levels on some laptops. - -* Tue Sep 21 2010 Kyle McMartin -- Add new btusb ids for MacBookPro from wwoods@. - -* Mon Sep 20 2010 Chuck Ebbert - 2.6.36-0.24.rc5 -- Linux 2.6.36-rc5 - -* Sun Sep 19 2010 Chuck Ebbert - 2.6.36-0.23.rc4.git4 -- Linux 2.6.36-rc4-git4 -- Drop alsa-fix-substream-proc-status-read.patch, now merged. - -* Fri Sep 17 2010 Matthew Garrett -- linux-2.6-bluetooth-autosuspend.patch - linux-2.6-uvc-autosuspend.patch - linux-2.6-qcserial-autosuspend.patch - linux-2.6-usb-pci-autosuspend.patch - Get some more devices into USB - autosuspend by default, and then put unused USB controllers to sleep - -* Thu Sep 16 2010 Hans de Goede -- Small fix to virtio_console poll fix from upstream review - -* Wed Sep 15 2010 Hans de Goede -- virtio_console: Fix poll/select blocking even though there is data to read - -* Wed Sep 15 2010 Chuck Ebbert - 2.6.36-0.22.rc4.git2 -- Linux 2.6.36-rc4-git2 -- Fix up add-appleir-usb-driver.patch after HID core changes. - -* Mon Sep 13 2010 Chuck Ebbert - 2.6.36-0.21.rc4.git1 -- Linux 2.6.36-rc4-git1 -- Add preliminary support for Wacom Bamboo pen and touch devices. -- Require python-devel and perl(ExtUtils::Embed) when building perf package (#632942) - -* Sat Sep 11 2010 Chuck Ebbert - 2.6.36-0.20.rc3.git4 -- Linux 2.6.36-rc3-git4 -- Drop revert-drm-i915-enable-rc6-on-ironlake.patch, now merged - -* Fri Sep 10 2010 Bastien Nocera - 2.6.36-0.19.rc3.git1 -- Update AppleIR patch to work, and support the enter key on - newer remotes - -* Wed Sep 08 2010 Kyle McMartin -- Enable GPIO_SYSFS. (#631958) - -* Wed Sep 08 2010 Kyle McMartin -- Make pci=use_crs a compile-time config option we can switch the default - value of easily. - -* Wed Sep 08 2010 Kyle McMartin 2.6.36-0.18.rc3.git1 -- 2.6.36-rc3-git1 -- Set CONFIG_CRYPTO_MANAGER_DISABLE_TESTS for nodebug, and unset for debug. - Which seems like the sensible thing to do given the Kconfig default is y. - -* Tue Sep 07 2010 Dave Jones -- Disable hung task checker, it only ever causes false positives. (#630777) - -* Tue Sep 07 2010 Kyle McMartin 2.6.36-0.17.rc3.git0 -- Revert ce171780 which breaks my graphics on resume. - (drm/i915: Enable RC6 on Ironlake.) - -* Fri Sep 03 2010 Kyle McMartin -- Restore AppleIR USB driver which got lost between F-13 and now. - -* Fri Sep 03 2010 Dave Jones 2.6.36-0.16.rc3.git0 -- exec-randomization: brk away from exec rand area (Kees Cook) - -* Fri Sep 03 2010 Dave Jones -- Remove the execshield boot parameter. - Based on a patch from Kees Cook - -* Thu Sep 02 2010 Chuck Ebbert - 2.6.36-0.15.rc3.git0 -- Add patch from ALSA mailing list to try to fix bug #628404 -- tpm-fix-stall-on-boot.patch: attempt to fix stalls during boot (#530393) - -* Wed Sep 01 2010 Kyle McMartin - 2.6.36-0.14.rc3.git0 -- Fix icebp breakpoints, patch from Frederic Weisbecker. - (https://bugzilla.kernel.org/show_bug.cgi?id=16315#c26) - -* Wed Sep 01 2010 Kyle McMartin - 2.6.36-0.13.rc3.git0 -- Swap back to roland's auto-updated utrace patches. - -* Mon Aug 30 2010 Kyle McMartin - 2.6.36-0.12.rc3.git0 -- Linux 2.6.36-rc3 - -* Sun Aug 29 2010 Chuck Ebbert - 2.6.36-0.11.rc2.git5 -- Linux 2.6.36-rc2-git5 - -* Wed Aug 25 2010 Chuck Ebbert - 2.6.36-0.10.rc2.git4 -- Linux 2.6.36-rc2-git4 - -* Tue Aug 24 2010 Chuck Ebbert - 2.6.36-0.9.rc2.git3 -- Linux 2.6.36-rc2-git3 - -* Mon Aug 23 2010 Roland McGrath - 2.6.36-0.8.rc2.git0 -- utrace update - -* Sun Aug 22 2010 Chuck Ebbert - 2.6.36-0.7.rc2.git0 -- Linux 2.6.36-rc2 - -* Sun Aug 22 2010 Chuck Ebbert - 2.6.36-0.7.rc1.git4 -- Linux 2.6.36-rc1-git4 -- Fix context in linux-2.6-i386-nx-emulation.patch - -* Sat Aug 21 2010 Chuck Ebbert - 2.6.36-0.6.rc1.git3 -- Drop utrace patch that causes hang on boot. - -* Fri Aug 20 2010 Chuck Ebbert - 2.6.36-0.5.rc1.git3 -- Linux 2.6.36-rc1-git3 -- Drop x86-cpu-fix-regression-in-amd-errata-checking-code.patch, now merged. - -* Thu Aug 19 2010 Kyle McMartin - 2.6.36-0.4.rc1.git1 -- Run oldnoconfig on the configs during make prep. -- Make the fix oldnoconfig patch a one liner. - -* Wed Aug 18 2010 Chuck Ebbert - 2.6.36-0.3.rc1.git1 -- Fix hangs on boot with some AMD processors - (x86-cpu-fix-regression-in-amd-errata-checking-code.patch) -- Drop unused ssb_check_for_sprom.patch - -* Wed Aug 18 2010 Dave Jones -- systemd is dependant upon autofs, so build it in instead of modular. - -* Wed Aug 18 2010 Chuck Ebbert -- Linux 2.6.36-rc1-git1 - -* Wed Aug 18 2010 Kyle McMartin - 2.6.36-0.2.rc1.git0 -- Link perf against libnewt for TUI support. - -* Tue Aug 17 2010 Kyle McMartin - 2.6.36-0.1.rc1.git0 -- Fix 'oldnoconfig' to do what nonint_loose_oldconfig did. - -* Tue Aug 17 2010 Kyle McMartin -- explicitly set KERNEL_GZIP - -* Tue Aug 17 2010 Kyle McMartin -- Linux 2.6.36-rc1 - -* Tue Aug 17 2010 Kyle McMartin -- Prevent scripts/setlocalversion from mucking with our version - numbers. - -* Wed Aug 04 2010 Kyle McMartin -- Disable %%released_kernel. -- This is properly 2.6.36-0.git1, unlike the last commit. Had to make - a mistake sometime, I'm glad it was early. - -* Wed Aug 04 2010 Kyle McMartin -- Linux 2.6.35-git1, beginning of rawhide for 2.6.36... - -* Sun Aug 01 2010 Dave Jones -- Linux 2.6.35 - -* Sun Aug 01 2010 Dave Jones -- 2.6.35-rc6-git6 - -* Fri Jul 30 2010 Jarod Wilson -- lirc staging update -- update kworld patch to one committed upstream -- can't believe how much nicer dist-git is than dist-cvs -- patch memory leaks in mceusb and imon drivers - -* Fri Jul 30 2010 Dave Jones -- Enable PPS (#619392) - -* Thu Jul 29 2010 Dave Jones -- 2.6.35-rc6-git5 - -* Mon Jul 27 2010 Kyle McMartin -- Patch from linville to only use the country code to set band limits. - (Fixes Apple Airport base stations from limiting you from associating - with other channels.) - -* Fri Jul 23 2010 Chuck Ebbert 2.6.35-0.56.rc6.git1 -- Linux 2.6.35-rc6-git1 - -* Thu Jul 22 2010 Dave Jones -- 2.6.35-rc6 - -* Thu Jul 22 2010 Ben Skeggsb -- drm-nouveau-updates: bring back, most patches *weren't* upstream yet, - they're queued for 2.6.36. - -* Wed Jul 21 2010 Chuck Ebbert 2.6.35-0.53.rc5.git7 -- Linux 2.6.35-rc5-git7 - -* Wed Jul 21 2010 Dave Jones -- Remove the %%verify (no mtime) on kernel-devel's files. - If they got modified, they should fail rpm verify. - -* Wed Jul 21 2010 Dave Jones -- Linux 2.6.35-rc5-git6 -- Removed drm-nouveau-updates.patch (upstreamed) - -* Mon Jul 19 2010 Chuck Ebbert -- Linux 2.6.35-rc5-git4 - -* Mon Jul 19 2010 Jarod Wilson 2.6.35-0.49.rc5.git2 -- Fix from Kyle for input_set_key oops introduced by ir-core patches (#615707) -- Update lirc-staging patches to match what's about to be submitted upstream, - complete with updated copy_from_user overflow check fixages - -* Sun Jul 18 2010 Chuck Ebbert 2.6.35-0.47.rc5.git2 -- Linux 2.6.35-rc5-git2 - -* Sun Jul 18 2010 Chuck Ebbert -- lirc-staging-2.6.36-fixes.patch: Fix up buffer size checking in - lirc code, found by CONFIG_DEBUG_STRICT_USER_COPY_CHECKS - -* Sun Jul 18 2010 Hans de Goede -- Add support for dynamic menu controls to the uvcvideo driver (#576023) - -* Sun Jul 18 2010 Jarod Wilson 2.6.35-0.44.rc5.git1 -- Oops, minor oversight when moving lirc bits into staging resulted - in the modules themselves not getting built. Fix that. - -* Fri Jul 16 2010 Dave Jones -- Limit some alsa spew that the nuforce udac makes happen a lot. - -* Fri Jul 16 2010 Jarod Wilson 2.6.35-0.41.rc5.git1 -- Pull in ir-core update from v4l/dvb staging for 2.6.36, which includes - new in-kernel lirc_dev and ir-core mceusb driver -- Move not-yet-merged/ported lirc bits to drivers/staging/, patch to be - sent upstream for 2.6.36 staging tree RSN - -* Thu Jul 15 2010 Chuck Ebbert 2.6.35-0.40.rc5.git1 -- Replace pci-acpi-disable-aspm-if-no-osc.patch with - updated version from F-13 - -* Thu Jul 15 2010 Chuck Ebbert -- Linux 2.6.35-rc5-git1 - -* Tue Jul 13 2010 Chuck Ebbert -- Linux 2.6.35-rc5 - -* Tue Jul 13 2010 Ben Skeggs -- nouveau: miscellanous fixes - -* Mon Jul 12 2010 Dave Jones -- 2.6.35-rc4-git5 - -* Mon Jul 12 2010 Dave Jones -- Remove a bunch of x86 options from config files that get set - automatically, and can't be overridden. - -* Fri Jul 9 2010 Roland McGrath -- Split execshield into two patches. - -* Thu Jul 08 2010 Chuck Ebbert 2.6.35-0.31.rc4.git4 -- Linux 2.6.35-rc4-git4 - -* Thu Jul 8 2010 Roland McGrath -- Remove exec-shield=2 setting, some other cruft from execshield. - -* Wed Jul 7 2010 Roland McGrath 2.6.35-0.29.rc4.git0.fc14 -- Revamp perf packaging. - -* Wed Jul 07 2010 Chuck Ebbert -- pci-acpi-disable-aspm-if-no-osc.patch, pci-aspm-dont-enable-too-early.patch - PCI layer fixes for problems with hardware that doesn't support ASPM. - -* Wed Jul 07 2010 Ben Skeggs -- nouveau: bring in nouveau upstream - -* Mon Jul 05 2010 Dave Jones -- 2.6.35-rc4 - -* Fri Jul 02 2010 Dave Jones -- 2.6.35-rc3-git7 - dropped: i915-fix-crt-hotplug-regression.patch (upstream) - dropped: drm-i915-fix-edp-panels.patch (upstream) - -* Fri Jul 02 2010 Dave Jones -- 2.6.35-rc3-git6 - -* Thu Jul 01 2010 Dave Jones -- Add a patch to debug an infinite loop warning from acpi. - -* Thu Jul 01 2010 Dave Jones -- 2.6.35-rc3-git5 - -* Thu Jul 01 2010 Chuck Ebbert -- Copy fix for BZ#220892 from F-13. - -* Wed Jun 30 2010 Kyle McMartin 2.6.35-0.19.rc3.git4 -- 2.6.35-rc3-git4 - -* Tue Jun 29 2010 Chuck Ebbert -- Disable Intel Moorestown support -- it breaks PC keyboard controllers. - -* Tue Jun 29 2010 Dave Jones -- Building external modules requires perl. (#608525) - -* Tue Jun 29 2010 Kyle McMartin 2.6.35-0.15.rc3.git3 -- 2.6.35-rc3-git3 -- i915-fix-crt-hotplug-regression.patch: attempt to solve the gm45 hotplug - irq storm. - -* Mon Jun 28 2010 Chuck Ebbert -- ppc64: enable active memory sharing and DLPAR memory remove (#607175) - -* Mon Jun 28 2010 Dave Jones -- 2.6.35-rc3-git2 - -* Mon Jun 28 2010 Dave Jones -- 2.6.35-rc3-git1 - -* Mon Jun 28 2010 Dave Airlie -- drm-i915-fix-edp-panels.patch: update to newer version - -* Fri Jun 25 2010 Kyle McMartin -- drm-i915-fix-edp-panels.patch: copy from rawhide. - -* Wed Jun 23 2010 Eric Sandeen -- Fix ext4 freeze deadlock (#607245) - -* Wed Jun 23 2010 Kyle McMartin -- Override generic's CONFIG_HZ_1000 on s390. - -* Tue Jun 22 2010 Dave Jones -- Fix localhost networking. - -* Tue Jun 22 2010 Kyle McMartin 2.6.35-0.1.rc3.git0 -- Putting the raw back into rawhide... Yeehaw. -- 2.6.35-rc3 -- Drop a tonne of patches that were merged upstream, or were backports. -- Rebase execshield, utrace. -- Fix up a bunch of rejects, build failures. -- Fix up lirc to build with strict copy_from_user checking. - -* Mon Jun 21 2010 Dave Jones -- Disable workaround for obscure SMP pentium pro errata. - I miss the 1990s too, but it's time to move on. - If anyone actually needs this it would be better done using - the apply_alternatives infrastructure. - -* Mon Jun 21 2010 Kyle McMartin 2.6.34-45 -- drm-revert-drm-fbdev-rework-output-polling-to-be-back-in-core.patch - Revert eb1f8e4f, bisected by Nicolas Kaiser. Thanks! (rhbz#599190) - (If this works, will try to root-cause.) -- rebase previous patch on top of above reversion - -* Mon Jun 21 2010 Kyle McMartin 2.6.34-44 -- revert-drm-kms-toggle-poll-around-switcheroo.patch (rhbz#599190) - -* Thu Jun 17 2010 Kyle McMartin 2.6.34-43 -- Suck in patch from Dave Miller in 2.6.35 to add async hash testing, - hopefully fixes error from previous commit. (But making it modular - is still a good idea.) - -* Thu Jun 17 2010 Kyle McMartin -- make ghash-clmulni modular to get rid of early boot noise (rhbz#586954) - (not a /fix/ but it should at least quiet boot down a bit if you have - the cpu support) - -* Wed Jun 16 2010 Kyle McMartin 2.6.34-40 -- Snag some more DRM commits into drm-next.patch that I missed the first - time. -- Fix up radeon_pm toggle to work with the upstream code. - -* Tue Jun 15 2010 Prarit Bhargava -- Turn off CONFIG_I2O on x86. - It is broken on 64-bit address spaces (i686/PAE, x86_64), and frankly, I'm - having trouble finding anyone who actually uses it. - -* Tue Jun 15 2010 Kyle McMartin 2.6.34-38 -- Fix build by nuking superfluous "%%{expand" which was missing a - trailing '}'. You may now reward me with an array of alcoholic - beverages, I so richly deserve for spending roughly a full - day staring at the diff of the spec. - -* Mon Jun 14 2010 Kyle McMartin 2.6.34-37 -- btrfs ACL fixes from CVE-2010-2071. - -* Sun Jun 13 2010 Kyle McMartin 2.6.34-36 -- remunge and reapply hdpvr-ir-enable - -* Sun Jun 13 2010 Kyle McMartin 2.6.34-35 -- mac80211/iwlwifi fix connections to some APs (rhbz#558002) - patches from sgruszka@. - -* Sun Jun 13 2010 Kyle McMartin 2.6.34-34 -- Provide a knob to enable radeon_pm to allow users to test - that functionality. Add radeon.pm=1 to your kernel cmdline - in order to enable it. (It still defaults to off though.) - -* Sun Jun 13 2010 Kyle McMartin 2.6.34-33 -- Update drm-next to include fixes since 2.6.35-rc1. - -* Fri Jun 11 2010 Justin M. Forbes -- Disable xsave for so that kernel will boot on ancient EC2 hosts. - -* Wed Jun 09 2010 John W. Linville -- Disable rt20xx and rt35xx chipset support in rt2800 drivers (#570869) - -* Wed Jun 09 2010 David Woodhouse -- Include PHY modules in modules.networking (#602155) - -* Tue Jun 08 2010 Dave Jones -- Remove useless -kdump kernel support - -* Tue Jun 08 2010 Dave Jones -- Remove ia64 ata quirk which had no explanation, and still - isn't upstream. No-one cares. - -* Tue Jun 08 2010 Dave Jones -- Drop linux-2.6-vio-modalias.patch - Two years should have been long enough to get upstream if this is important. - -* Tue Jun 08 2010 Dave Jones -- Remove crufty Xen remnants from specfile. - -* Tue Jun 08 2010 Dave Jones -- Remove mkinitrd ifdefs. Dracut or GTFO. - -* Thu Jun 03 2010 Kyle McMartin -- Build kernel headers on s390. - -* Wed Jun 02 2010 Kyle McMartin 2.6.34-20 -- Disable doc_build_fail because xmlto et al. are crud. - -* Wed Jun 02 2010 Kyle McMartin 2.6.34-19 -- Enable -debug flavour builds, until we branch for 2.6.35-rcX. - -* Wed Jun 02 2010 Kyle McMartin -- revert writeback fixes for now, there appear to be dragons - lurking there still. - -* Tue Jun 01 2010 Kyle McMartin 2.6.34-18 -- fix mismerge in i915_gem.c, drm_gem_object_alloc is now - i915_gem_alloc_object. -- add a hunk to rcu_read{,un}lock in sched_fair too. - -* Tue Jun 01 2010 Kyle McMartin 2.6.34-17 -- backport writeback fixes from Jens until stable@ picks them up. - -* Tue Jun 01 2010 Kyle McMartin 2.6.34-16 -- quiet-prove_RCU-in-cgroups.patch: shut RCU lockdep up - as in 8b08ca52f5942c21564bbb90ccfb61053f2c26a1. - -* Tue Jun 01 2010 Kyle McMartin -- disable radeon_pm for now. - -* Mon May 31 2010 Kyle McMartin 2.6.34-14 -- re-add drm-next.patch, should be in sync with 2.6.35 and what - was backported to Fedora 13. -- drop patches merged in drm-next to 2.6.35 -- rebase relevant iwl fixes on top of 2.6.34 from the ones committed - to F-13 by linville. - -* Wed May 26 2010 Adam Jackson -- config-generic: Stop building i830.ko - -* Wed May 26 2010 Kyle McMartin -- iwlwifi-recover_from_tx_stall.patch: copy from F-13. - -* Fri May 21 2010 Roland McGrath 2.6.34-11 -- utrace update - -* Fri May 21 2010 Dave Jones -- Update the SELinux mprotect patch with a newer version from Stephen - -* Fri May 21 2010 Roland McGrath -- perf requires libdw now, not libdwarf - -* Fri May 21 2010 Kyle McMartin 2.6.34-6 -- Fixups for virt_console from Amit Shah, thanks! - -* Thu May 20 2010 Kyle McMartin 2.6.34-5 -- disable intel sdvo fixes until dependent code is backported. - -* Thu May 20 2010 Kyle McMartin 2.6.34-4 -- resync a lot of stuff with F-13... -- linux-2.6-acpi-video-export-edid.patch: rebase & copy from F-13 -- acpi-ec-add-delay-before-write.patch: copy from F-13 -- ... and a whole lot more that I can't be bothered typing. - -* Mon May 17 2010 Matthew Garrett -- thinkpad-acpi-fix-backlight.patch: Fix backlight support on some recent - Thinkpads - -* Sun May 16 2010 Kyle McMartin 2.6.34-2 -- Disable strict copy_from_user checking until lirc is fixed. - -* Sun May 16 2010 Kyle McMartin 2.6.34-1 -- Linux 2.6.34 - -* Sun May 16 2010 Kyle McMartin -- Trimmed changelog, see CVS. +* Mon May 30 2011 Kyle McMartin +- Trimmed changelog, see fedpkg git for earlier history. ### # The following Emacs magic makes C-c C-e use UTC dates. diff --git a/linux-2.6-32bit-mmap-exec-randomization.patch b/linux-2.6-32bit-mmap-exec-randomization.patch index dd40b60df..c25323323 100644 --- a/linux-2.6-32bit-mmap-exec-randomization.patch +++ b/linux-2.6-32bit-mmap-exec-randomization.patch @@ -1,3 +1,13 @@ +Before: +Heap randomisation test (PIE) : 16 bits (guessed) +Main executable randomisation (PIE) : 8 bits (guessed) + +after: +Heap randomisation test (PIE) : 19 bits (guessed) +Main executable randomisation (PIE) : 12 bits (guessed) + + + --- b/include/linux/sched.h +++ b/include/linux/sched.h @@ -397,6 +397,10 @@ @@ -142,7 +152,7 @@ struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr) --- a/arch/x86/mm/mmap.c +++ b/arch/x86/mm/mmap.c -@@ -124,13 +124,16 @@ static unsigned long mmap_legacy_base(void) +@@ -124,13 +124,19 @@ static unsigned long mmap_legacy_base(void) */ void arch_pick_mmap_layout(struct mm_struct *mm) { @@ -153,9 +163,12 @@ } else { mm->mmap_base = mmap_base(); mm->get_unmapped_area = arch_get_unmapped_area_topdown; ++#ifdef CONFIG_X86_32 + if (!(current->personality & READ_IMPLIES_EXEC) ++ && !(__supported_pte_mask & _PAGE_NX) + && mmap_is_ia32()) + mm->get_unmapped_exec_area = arch_get_unmapped_exec_area; ++#endif mm->unmap_area = arch_unmap_area_topdown; } } @@ -214,3 +227,25 @@ if (new_addr & ~PAGE_MASK) { ret = new_addr; goto out; +diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c +index 57d1868..29c0c35 100644 +--- a/arch/x86/kernel/process.c ++++ b/arch/x86/kernel/process.c +@@ -669,6 +669,16 @@ unsigned long arch_align_stack(unsigned long sp) + unsigned long arch_randomize_brk(struct mm_struct *mm) + { + unsigned long range_end = mm->brk + 0x02000000; +- return randomize_range(mm->brk, range_end, 0) ? : mm->brk; ++ unsigned long bump = 0; ++#ifdef CONFIG_X86_32 ++ /* in the case of NX emulation, shove the brk segment way out of the ++ way of the exec randomization area, since it can collide with ++ future allocations if not. */ ++ if ( (mm->get_unmapped_exec_area == arch_get_unmapped_exec_area) && ++ (mm->brk < 0x08000000) ) { ++ bump = (TASK_SIZE/6); ++ } ++#endif ++ return bump + (randomize_range(mm->brk, range_end, 0) ? : mm->brk); + } + diff --git a/linux-2.6-acpi-debug-infinite-loop.patch b/linux-2.6-acpi-debug-infinite-loop.patch index 45cb05165..d20025224 100644 --- a/linux-2.6-acpi-debug-infinite-loop.patch +++ b/linux-2.6-acpi-debug-infinite-loop.patch @@ -1,16 +1,3 @@ ---- linux-2.6.34.noarch/drivers/acpi/acpica/dsopcode.c~ 2010-07-01 14:40:44.000000000 -0400 -+++ linux-2.6.34.noarch/drivers/acpi/acpica/dsopcode.c 2010-07-01 14:48:56.000000000 -0400 -@@ -1276,6 +1276,10 @@ acpi_ds_exec_end_control_op(struct acpi_ - * loop does not implement a timeout. - */ - control_state->control.loop_count++; -+ if ((control_state->control.loop_count > 1) && (control_state->control.loop_count % 0xffff == 0)) -+ printk("ACPI: While loop taking a really long time. loop_count=0x%x\n", -+ control_state->control.loop_count); -+ - if (control_state->control.loop_count > - ACPI_MAX_LOOP_ITERATIONS) { - status = AE_AML_INFINITE_LOOP; --- linux-2.6.34.noarch/drivers/acpi/acpica/acconfig.h~ 2010-07-01 14:49:03.000000000 -0400 +++ linux-2.6.34.noarch/drivers/acpi/acpica/acconfig.h 2010-07-01 14:49:17.000000000 -0400 @@ -117,7 +117,7 @@ @@ -22,3 +9,17 @@ /* Maximum sleep allowed via Sleep() operator */ +--- a/drivers/acpi/acpica/dscontrol.c ++++ b/drivers/acpi/acpica/dscontrol.c +@@ -212,6 +212,11 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, + * loop does not implement a timeout. + */ + control_state->control.loop_count++; ++ if ((control_state->control.loop_count > 1) && ++ (control_state->control.loop_count % 0xffff == 0)) ++ printk("ACPI: While loop taking a really long time. loop_count=0x%x\n", ++ control_state->control.loop_count); ++ + if (control_state->control.loop_count > + ACPI_MAX_LOOP_ITERATIONS) { + status = AE_AML_INFINITE_LOOP; diff --git a/linux-2.6-crash-driver.patch b/linux-2.6-crash-driver.patch index 0f11aba0d..239f0f6a0 100644 --- a/linux-2.6-crash-driver.patch +++ b/linux-2.6-crash-driver.patch @@ -1,17 +1,17 @@ -From df42d15cd28f468ecd4c30465b98a53cce90617c Mon Sep 17 00:00:00 2001 +From f72d640713d01b3b704c6e84ab49b62f19fc9c22 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Tue, 30 Mar 2010 00:16:25 -0400 -Subject: dev-crash-driver.patch +Subject: [PATCH] dev-crash-driver.patch --- arch/ia64/include/asm/crash.h | 90 +++++++++++++++++++++++++++++ arch/ia64/kernel/ia64_ksyms.c | 3 + arch/x86/include/asm/crash.h | 75 ++++++++++++++++++++++++ arch/x86/mm/ioremap.c | 2 + - drivers/char/Kconfig | 2 + + drivers/char/Kconfig | 3 + drivers/char/Makefile | 2 + drivers/char/crash.c | 128 +++++++++++++++++++++++++++++++++++++++++ - 7 files changed, 302 insertions(+), 0 deletions(-) + 7 files changed, 303 insertions(+), 0 deletions(-) create mode 100644 arch/ia64/include/asm/crash.h create mode 100644 arch/x86/include/asm/crash.h create mode 100644 drivers/char/crash.c @@ -208,7 +208,7 @@ index 0000000..dfcc006 + +#endif /* _ASM_I386_CRASH_H */ diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c -index 5eb1ba7..3e525d2 100644 +index be1ef57..ac659f7 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c @@ -24,6 +24,8 @@ @@ -221,19 +221,29 @@ index 5eb1ba7..3e525d2 100644 * Fix up the linear direct mapping of the kernel to avoid cache attribute * conflicts. diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig -index 3141dd3..153658c 100644 +index 423fd56..e04a561 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig -@@ -471,6 +471,8 @@ config LEGACY_PTYS - security. This option enables these legacy devices; on most - systems, it is safe to say N. +@@ -4,6 +4,9 @@ + + menu "Character devices" +config CRASH -+ tristate "Crash Utility memory driver" ++ tristate "Crash Utility memory driver" ++ + source "drivers/tty/Kconfig" - config LEGACY_PTY_COUNT - int "Maximum number of legacy PTY in use" + config DEVKMEM +diff --git a/drivers/char/Makefile b/drivers/char/Makefile +index 32762ba..3d5d525 100644 +--- a/drivers/char/Makefile ++++ b/drivers/char/Makefile +@@ -65,3 +65,5 @@ obj-$(CONFIG_JS_RTC) += js-rtc.o + js-rtc-y = rtc.o + obj-$(CONFIG_TILE_SROM) += tile-srom.o ++ ++obj-$(CONFIG_CRASH) += crash.o diff --git a/drivers/char/crash.c b/drivers/char/crash.c new file mode 100644 index 0000000..e5437de @@ -368,14 +378,6 @@ index 0000000..e5437de +module_exit(crash_cleanup_module); + +MODULE_LICENSE("GPL"); +-- +1.7.6 -diff --git a/drivers/char/Makefile b/drivers/char/Makefile -index ba53ec9..6588b33 100644 ---- a/drivers/char/Makefile -+++ b/drivers/char/Makefile -@@ -98,3 +98,5 @@ obj-$(CONFIG_RAMOOPS) += ramoops.o - - obj-$(CONFIG_JS_RTC) += js-rtc.o - js-rtc-y = rtc.o -+ -+obj-$(CONFIG_CRASH) += crash.o diff --git a/linux-2.6-debug-always-inline-kzalloc.patch b/linux-2.6-debug-always-inline-kzalloc.patch deleted file mode 100644 index 24f665ca6..000000000 --- a/linux-2.6-debug-always-inline-kzalloc.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 76ec0e2e6d6edf81abc0331d5e7873ef7b2f6019 Mon Sep 17 00:00:00 2001 -From: Kyle McMartin -Date: Wed, 8 Jul 2009 13:06:01 -0400 -Subject: [PATCH 6/6] fedora: linux-2.6-debug-always-inline-kzalloc.patch - ---- - include/linux/slab.h | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/include/linux/slab.h b/include/linux/slab.h -index 2da8372..d4ef74f 100644 ---- a/include/linux/slab.h -+++ b/include/linux/slab.h -@@ -310,7 +310,7 @@ static inline void *kmem_cache_zalloc(struct kmem_cache *k, gfp_t flags) - * @size: how many bytes of memory are required. - * @flags: the type of memory to allocate (see kmalloc). - */ --static inline void *kzalloc(size_t size, gfp_t flags) -+static __always_inline void *kzalloc(size_t size, gfp_t flags) - { - return kmalloc(size, flags | __GFP_ZERO); - } --- -1.6.2.5 - diff --git a/linux-2.6-debug-sizeof-structs.patch b/linux-2.6-debug-sizeof-structs.patch deleted file mode 100644 index e027d98a1..000000000 --- a/linux-2.6-debug-sizeof-structs.patch +++ /dev/null @@ -1,33 +0,0 @@ -diff --git a/init/main.c b/init/main.c -index 7449819..98cfaae 100644 ---- a/init/main.c -+++ b/init/main.c -@@ -369,6 +369,11 @@ static void __init setup_nr_cpu_ids(void) - nr_cpu_ids = find_last_bit(cpumask_bits(cpu_possible_mask),NR_CPUS) + 1; - } - -+#include <../fs/ext4/ext4.h> -+#include -+#include -+#include -+ - /* Called by boot processor to activate the rest. */ - static void __init smp_init(void) - { -@@ -391,6 +395,16 @@ static void __init smp_init(void) - /* Any cleanup work */ - printk(KERN_INFO "Brought up %ld CPUs\n", (long)num_online_cpus()); - smp_cpus_done(setup_max_cpus); -+ -+ printk(KERN_DEBUG "sizeof(vma)=%u bytes\n", (unsigned int) sizeof(struct vm_area_struct)); -+ printk(KERN_DEBUG "sizeof(page)=%u bytes\n", (unsigned int) sizeof(struct page)); -+ printk(KERN_DEBUG "sizeof(inode)=%u bytes\n", (unsigned int) sizeof(struct inode)); -+ printk(KERN_DEBUG "sizeof(dentry)=%u bytes\n", (unsigned int) sizeof(struct dentry)); -+ printk(KERN_DEBUG "sizeof(ext3inode)=%u bytes\n", (unsigned int) sizeof(struct ext3_inode_info)); -+ printk(KERN_DEBUG "sizeof(ext4inode)=%u bytes\n", (unsigned int) sizeof(struct ext4_inode_info)); -+ printk(KERN_DEBUG "sizeof(buffer_head)=%u bytes\n", (unsigned int) sizeof(struct buffer_head)); -+ printk(KERN_DEBUG "sizeof(skbuff)=%u bytes\n", (unsigned int) sizeof(struct sk_buff)); -+ printk(KERN_DEBUG "sizeof(task_struct)=%u bytes\n", (unsigned int) sizeof(struct task_struct)); - } - - #endif diff --git a/linux-2.6-debug-taint-vm.patch b/linux-2.6-debug-taint-vm.patch deleted file mode 100644 index ee367d45a..000000000 --- a/linux-2.6-debug-taint-vm.patch +++ /dev/null @@ -1,65 +0,0 @@ -From b04c57d9dc889462951312be2ac81ff6c702e954 Mon Sep 17 00:00:00 2001 -From: Kyle McMartin -Date: Wed, 8 Jul 2009 13:05:09 -0400 -Subject: [PATCH 3/6] fedora: linux-2.6-debug-taint-vm.patch - ---- - kernel/panic.c | 4 +++- - mm/slab.c | 8 ++++---- - mm/slub.c | 2 +- - 4 files changed, 11 insertions(+), 8 deletions(-) - -diff --git a/kernel/panic.c b/kernel/panic.c -index 984b3ec..6d1c3be 100644 ---- a/kernel/panic.c -+++ b/kernel/panic.c -@@ -199,6 +199,7 @@ const char *print_tainted(void) - - return buf; - } -+EXPORT_SYMBOL(print_tainted); - - int test_taint(unsigned flag) - { -diff --git a/mm/slab.c b/mm/slab.c -index e74a16e..7bc287e 100644 ---- a/mm/slab.c -+++ b/mm/slab.c -@@ -1803,8 +1803,8 @@ static void check_poison_obj(struct kmem_cache *cachep, void *objp) - /* Print header */ - if (lines == 0) { - printk(KERN_ERR -- "Slab corruption: %s start=%p, len=%d\n", -- cachep->name, realobj, size); -+ "Slab corruption (%s): %s start=%p, len=%d\n", -+ print_tainted(), cachep->name, realobj, size); - print_objinfo(cachep, objp, 0); - } - /* Hexdump the affected line */ -@@ -2902,8 +2902,8 @@ static void check_slabp(struct kmem_cache *cachep, struct slab *slabp) - if (entries != cachep->num - slabp->inuse) { - bad: - printk(KERN_ERR "slab: Internal list corruption detected in " -- "cache '%s'(%d), slabp %p(%d). Hexdump:\n", -- cachep->name, cachep->num, slabp, slabp->inuse); -+ "cache '%s'(%d), slabp %p(%d). Tainted(%s). Hexdump:\n", -+ cachep->name, cachep->num, slabp, slabp->inuse, print_tainted()); - for (i = 0; - i < sizeof(*slabp) + cachep->num * sizeof(kmem_bufctl_t); - i++) { -diff --git a/mm/slub.c b/mm/slub.c -index 819f056..8eff0f4 100644 ---- a/mm/slub.c -+++ b/mm/slub.c -@@ -433,7 +433,7 @@ static void slab_bug(struct kmem_cache *s, char *fmt, ...) - va_end(args); - printk(KERN_ERR "========================================" - "=====================================\n"); -- printk(KERN_ERR "BUG %s: %s\n", s->name, buf); -+ printk(KERN_ERR "BUG %s (%s): %s\n", s->name, print_tainted(), buf); - printk(KERN_ERR "----------------------------------------" - "-------------------------------------\n\n"); - } --- -1.6.2.5 - diff --git a/linux-2.6-debug-vm-would-have-oomkilled.patch b/linux-2.6-debug-vm-would-have-oomkilled.patch deleted file mode 100644 index 8bd05ab06..000000000 --- a/linux-2.6-debug-vm-would-have-oomkilled.patch +++ /dev/null @@ -1,69 +0,0 @@ -From beb764ac03e52eba1a654afb4273fab1f9de3cff Mon Sep 17 00:00:00 2001 -From: Kyle McMartin -Date: Mon, 29 Nov 2010 20:59:14 -0500 -Subject: [PATCH] linux-2.6-debug-vm-would_have_oomkilled - ---- - include/linux/oom.h | 1 + - kernel/sysctl.c | 7 +++++++ - mm/oom_kill.c | 8 ++++++++ - 3 files changed, 16 insertions(+), 0 deletions(-) - -diff --git a/include/linux/oom.h b/include/linux/oom.h -index 5e3aa83..79a27b4 100644 ---- a/include/linux/oom.h -+++ b/include/linux/oom.h -@@ -72,5 +72,6 @@ extern struct task_struct *find_lock_task_mm(struct task_struct *p); - extern int sysctl_oom_dump_tasks; - extern int sysctl_oom_kill_allocating_task; - extern int sysctl_panic_on_oom; -+extern int sysctl_would_have_oomkilled; - #endif /* __KERNEL__*/ - #endif /* _INCLUDE_LINUX_OOM_H */ -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index 5abfa15..a0fed6d 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -1000,6 +1000,13 @@ static struct ctl_table vm_table[] = { - .proc_handler = proc_dointvec, - }, - { -+ .procname = "would_have_oomkilled", -+ .data = &sysctl_would_have_oomkilled, -+ .maxlen = sizeof(sysctl_would_have_oomkilled), -+ .mode = 0644, -+ .proc_handler = proc_dointvec, -+ }, -+ { - .procname = "overcommit_ratio", - .data = &sysctl_overcommit_ratio, - .maxlen = sizeof(sysctl_overcommit_ratio), -diff --git a/mm/oom_kill.c b/mm/oom_kill.c -index 7dcca55..281ac39 100644 ---- a/mm/oom_kill.c -+++ b/mm/oom_kill.c -@@ -35,6 +35,7 @@ - int sysctl_panic_on_oom; - int sysctl_oom_kill_allocating_task; - int sysctl_oom_dump_tasks = 1; -+int sysctl_would_have_oomkilled; - static DEFINE_SPINLOCK(zone_scan_lock); - - #ifdef CONFIG_NUMA -@@ -477,6 +478,13 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, - } - - task_lock(p); -+ if (sysctl_would_have_oomkilled) { -+ printk(KERN_ERR "%s: would have killed process %d (%s), but continuing instead...\n", -+ __func__, task_pid_nr(p), p->comm); -+ task_unlock(p); -+ return 0; -+ } -+ - pr_err("%s: Kill process %d (%s) score %d or sacrifice child\n", - message, task_pid_nr(p), p->comm, points); - task_unlock(p); --- -1.7.3.2 - diff --git a/linux-2.6-defaults-acpi-video.patch b/linux-2.6-defaults-acpi-video.patch index af883b0d3..b83f4b614 100644 --- a/linux-2.6-defaults-acpi-video.patch +++ b/linux-2.6-defaults-acpi-video.patch @@ -1,13 +1,13 @@ diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c -index d8d7596..a1b7117 100644 +index eaef02a..2029819 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c -@@ -71,7 +71,7 @@ MODULE_AUTHOR("Bruno Ducrot"); +@@ -69,7 +69,7 @@ MODULE_AUTHOR("Bruno Ducrot"); MODULE_DESCRIPTION("ACPI Video Driver"); MODULE_LICENSE("GPL"); --static int brightness_switch_enabled = 1; -+static int brightness_switch_enabled = 0; +-static bool brightness_switch_enabled = 1; ++static bool brightness_switch_enabled = 0; module_param(brightness_switch_enabled, bool, 0644); - static int acpi_video_bus_add(struct acpi_device *device); + /* diff --git a/linux-2.6-defaults-pci_no_msi.patch b/linux-2.6-defaults-pci_no_msi.patch deleted file mode 100644 index 29a84e8d2..000000000 --- a/linux-2.6-defaults-pci_no_msi.patch +++ /dev/null @@ -1,110 +0,0 @@ -From 14bdd0d36f5284108468bb73afd50726b07c7a84 Mon Sep 17 00:00:00 2001 -From: Kyle McMartin -Date: Mon, 29 Mar 2010 23:43:49 -0400 -Subject: linux-2.6-defaults-pci_no_msi - ---- - Documentation/kernel-parameters.txt | 3 +++ - drivers/pci/Kconfig | 12 ++++++++++++ - drivers/pci/msi.c | 9 +++++++++ - drivers/pci/pci.c | 2 ++ - drivers/pci/pci.h | 2 ++ - 5 files changed, 28 insertions(+), 0 deletions(-) - -diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt -index e4cbca5..8154a0f 100644 ---- a/Documentation/kernel-parameters.txt -+++ b/Documentation/kernel-parameters.txt -@@ -1911,6 +1911,9 @@ and is between 256 and 4096 characters. It is defined in the file - check_enable_amd_mmconf [X86] check for and enable - properly configured MMIO access to PCI - config space on AMD family 10h CPU -+ msi [MSI] If the PCI_MSI kernel config parameter is -+ enabled, this kernel boot option can be used to -+ enable the use of MSI interrupts system-wide. - nomsi [MSI] If the PCI_MSI kernel config parameter is - enabled, this kernel boot option can be used to - disable the use of MSI interrupts system-wide. -diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig -index 7858a11..b12fcad 100644 ---- a/drivers/pci/Kconfig -+++ b/drivers/pci/Kconfig -@@ -21,6 +21,18 @@ config PCI_MSI - - If you don't know what to do here, say Y. - -+config PCI_MSI_DEFAULT_ON -+ def_bool y -+ prompt "Use Message Signaled Interrupts by default" -+ depends on PCI_MSI -+ help -+ Selecting this option will enable use of PCI MSI where applicable -+ by default. Support for MSI can be disabled through the use of the -+ pci=nomsi boot flag. Conversely, if this option is not selected, -+ support for PCI MSI can be enabled by passing the pci=msi flag. -+ -+ If you don't know what to do here, say N. -+ - config PCI_DEBUG - bool "PCI Debugging" - depends on PCI && DEBUG_KERNEL -diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c -index f9cf317..6b0539a 100644 ---- a/drivers/pci/msi.c -+++ b/drivers/pci/msi.c -@@ -22,7 +22,11 @@ - #include "pci.h" - #include "msi.h" - -+#ifdef CONFIG_PCI_MSI_DEFAULT_ON - static int pci_msi_enable = 1; -+#else -+static int pci_msi_enable = 0; -+#endif /*CONFIG_PCI_MSI_DEFAULT_ON*/ - - /* Arch hooks */ - -@@ -836,6 +840,11 @@ int pci_msi_enabled(void) - } - EXPORT_SYMBOL(pci_msi_enabled); - -+void pci_yes_msi(void) -+{ -+ pci_msi_enable = 1; -+} -+ - void pci_msi_init_pci_dev(struct pci_dev *dev) - { - INIT_LIST_HEAD(&dev->msi_list); -diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c -index 1531f3a..3cb332b 100644 ---- a/drivers/pci/pci.c -+++ b/drivers/pci/pci.c -@@ -2983,6 +2983,8 @@ static int __init pci_setup(char *str) - if (*str && (str = pcibios_setup(str)) && *str) { - if (!strcmp(str, "nomsi")) { - pci_no_msi(); -+ } else if (!strcmp(str, "msi")) { -+ pci_yes_msi(); - } else if (!strcmp(str, "noaer")) { - pci_no_aer(); - } else if (!strcmp(str, "nodomains")) { -diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h -index 4eb10f4..caa051e 100644 ---- a/drivers/pci/pci.h -+++ b/drivers/pci/pci.h -@@ -122,9 +122,11 @@ extern unsigned int pci_pm_d3_delay; - - #ifdef CONFIG_PCI_MSI - void pci_no_msi(void); -+void pci_yes_msi(void); - extern void pci_msi_init_pci_dev(struct pci_dev *dev); - #else - static inline void pci_no_msi(void) { } -+static inline void pci_yes_msi(void) { } - static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { } - #endif - --- -1.7.0.1 - diff --git a/linux-2.6-defaults-pci_use_crs.patch b/linux-2.6-defaults-pci_use_crs.patch deleted file mode 100644 index 18acee12d..000000000 --- a/linux-2.6-defaults-pci_use_crs.patch +++ /dev/null @@ -1,29 +0,0 @@ -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index cea0cd9..c326065 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -2142,3 +2142,8 @@ source "crypto/Kconfig" - source "arch/x86/kvm/Kconfig" - - source "lib/Kconfig" -+ -+config PCI_DEFAULT_USE_CRS -+ def_bool y -+ prompt "Use PCI Host Bridge Windows from ACPI by default?" -+ depends on ACPI -diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c -index 15466c0..3099406 100644 ---- a/arch/x86/pci/acpi.c -+++ b/arch/x86/pci/acpi.c -@@ -16,7 +16,11 @@ struct pci_root_info { - int busnum; - }; - -+#ifdef CONFIG_PCI_DEFAULT_USE_CRS - static bool pci_use_crs = true; -+#else -+static bool pci_use_crs = false; -+#endif - - static int __init set_use_crs(const struct dmi_system_id *id) - { diff --git a/linux-2.6-e1000-ich9-montevina.patch b/linux-2.6-e1000-ich9-montevina.patch index d45fd5673..ec38a3902 100644 --- a/linux-2.6-e1000-ich9-montevina.patch +++ b/linux-2.6-e1000-ich9-montevina.patch @@ -1,11 +1,22 @@ +From 802e6d8c8477a553a677b23a247d6d2638e01958 Mon Sep 17 00:00:00 2001 +From: Dave Jones +Date: Wed, 26 Oct 2011 13:31:47 -0400 +Subject: [PATCH] e1000e: ich9 montevina + This only showed up in one SDV (Montevina). The PCIE slots don't seem to like network cards, so this is the only hope to get networking working. It's never going upstream, but it's low impact enough to carry just to keep those SDVs working. +--- + drivers/net/ethernet/intel/e1000e/ich8lan.c | 6 ++++++ + drivers/net/ethernet/intel/e1000e/netdev.c | 1 + + 2 files changed, 7 insertions(+), 0 deletions(-) ---- linux-2.6.35.noarch/drivers/net/e1000e/ich8lan.c~ 2010-09-29 17:53:13.000000000 -0400 -+++ linux-2.6.35.noarch/drivers/net/e1000e/ich8lan.c 2010-09-29 17:54:00.000000000 -0400 -@@ -424,6 +424,12 @@ static s32 e1000_init_phy_params_ich8lan +diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c +index 6a17c62..0e40975 100644 +--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c ++++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c +@@ -452,6 +452,12 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) /* Verify phy id */ switch (phy->id) { @@ -18,9 +29,11 @@ enough to carry just to keep those SDVs working. case IGP03E1000_E_PHY_ID: phy->type = e1000_phy_igp_3; phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; ---- linux-2.6.35.noarch/drivers/net/e1000e/netdev.c~ 2010-09-29 17:54:07.000000000 -0400 -+++ linux-2.6.35.noarch/drivers/net/e1000e/netdev.c 2010-09-29 17:54:29.000000000 -0400 -@@ -5994,6 +5994,7 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci +diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c +index a855db1..edac30b 100644 +--- a/drivers/net/ethernet/intel/e1000e/netdev.c ++++ b/drivers/net/ethernet/intel/e1000e/netdev.c +@@ -6359,6 +6359,7 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M), board_ich9lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_AMT), board_ich9lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_V), board_ich9lan }, @@ -28,3 +41,6 @@ enough to carry just to keep those SDVs working. { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LM), board_ich9lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LF), board_ich9lan }, +-- +1.7.6.4 + diff --git a/linux-2.6-ehci-check-port-status.patch b/linux-2.6-ehci-check-port-status.patch deleted file mode 100644 index f3c5faf70..000000000 --- a/linux-2.6-ehci-check-port-status.patch +++ /dev/null @@ -1,54 +0,0 @@ -commit e17a07a9e0b62d5a5f0a5683ecbabad3aa95a4d5 -Author: Matthew Garrett -Date: Tue Jan 11 12:19:40 2011 -0500 - - ehci: Check individual port status registers on resume - - If a device plug/unplug is detected on an ATI SB700 USB controller in D3, - it appears to set the port status register but not the controller status - register. As a result we'll fail to detect the plug event. Check the port - status register on resume as well in order to catch this case. - - Signed-off-by: Matthew Garrett - -diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c -index 796ea0c..d9c0748 100644 ---- a/drivers/usb/host/ehci-hub.c -+++ b/drivers/usb/host/ehci-hub.c -@@ -106,6 +106,27 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci) - ehci->owned_ports = 0; - } - -+static int ehci_port_change(struct ehci_hcd *ehci) -+{ -+ int i = HCS_N_PORTS(ehci->hcs_params); -+ -+ /* First check if the controller indicates a change event */ -+ -+ if (ehci_readl(ehci, &ehci->regs->status) & STS_PCD) -+ return 1; -+ -+ /* -+ * Not all controllers appear to update this while going from D3 to D0, -+ * so check the individual port status registers as well -+ */ -+ -+ while (i--) -+ if (ehci_readl(ehci, &ehci->regs->port_status[i]) & PORT_CSC) -+ return 1; -+ -+ return 0; -+} -+ - static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, - bool suspending, bool do_wakeup) - { -@@ -168,7 +189,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, - } - - /* Does the root hub have a port wakeup pending? */ -- if (!suspending && (ehci_readl(ehci, &ehci->regs->status) & STS_PCD)) -+ if (!suspending && ehci_port_change(ehci)) - usb_hcd_resume_root_hub(ehci_to_hcd(ehci)); - - spin_unlock_irqrestore(&ehci->lock, flags); diff --git a/linux-2.6-firewire-git-pending.patch b/linux-2.6-firewire-git-pending.patch deleted file mode 100644 index e05471f1b..000000000 --- a/linux-2.6-firewire-git-pending.patch +++ /dev/null @@ -1,4 +0,0 @@ -# -# Patches under review and/or pending inclusion in the linux1394-git -# tree (and/or in by the time your read this), which we want... -# diff --git a/linux-2.6-firewire-git-update.patch b/linux-2.6-firewire-git-update.patch deleted file mode 100644 index 685808133..000000000 --- a/linux-2.6-firewire-git-update.patch +++ /dev/null @@ -1,3682 +0,0 @@ -linux1394-2.6.git tree vs. linus v2.6.29-rc3-git1 on 20090130 by jarod - ---- - firewire-git/drivers/firewire/fw-card.c | 68 - - firewire-git/drivers/firewire/fw-cdev.c | 1014 +++++++++++++++++-------- - firewire-git/drivers/firewire/fw-device.c | 43 - - firewire-git/drivers/firewire/fw-device.h | 7 - firewire-git/drivers/firewire/fw-iso.c | 225 ++++- - firewire-git/drivers/firewire/fw-ohci.c | 236 ++--- - firewire-git/drivers/firewire/fw-sbp2.c | 57 - - firewire-git/drivers/firewire/fw-topology.c | 28 - firewire-git/drivers/firewire/fw-topology.h | 19 - firewire-git/drivers/firewire/fw-transaction.c | 151 +-- - firewire-git/drivers/firewire/fw-transaction.h | 125 --- - include/linux/firewire-cdev.h | 170 +++- - 12 files changed, 1359 insertions(+), 784 deletions(-) - -diff -Naurp linux-2.6-git/drivers/firewire/fw-card.c firewire-git/drivers/firewire/fw-card.c ---- linux-2.6-git/drivers/firewire/fw-card.c 2009-01-30 13:39:02.989651512 -0500 -+++ firewire-git/drivers/firewire/fw-card.c 2009-01-30 13:35:51.859771884 -0500 -@@ -63,8 +63,7 @@ static int descriptor_count; - #define BIB_CMC ((1) << 30) - #define BIB_IMC ((1) << 31) - --static u32 * --generate_config_rom(struct fw_card *card, size_t *config_rom_length) -+static u32 *generate_config_rom(struct fw_card *card, size_t *config_rom_length) - { - struct fw_descriptor *desc; - static u32 config_rom[256]; -@@ -128,8 +127,7 @@ generate_config_rom(struct fw_card *card - return config_rom; - } - --static void --update_config_roms(void) -+static void update_config_roms(void) - { - struct fw_card *card; - u32 *config_rom; -@@ -141,8 +139,7 @@ update_config_roms(void) - } - } - --int --fw_core_add_descriptor(struct fw_descriptor *desc) -+int fw_core_add_descriptor(struct fw_descriptor *desc) - { - size_t i; - -@@ -171,8 +168,7 @@ fw_core_add_descriptor(struct fw_descrip - return 0; - } - --void --fw_core_remove_descriptor(struct fw_descriptor *desc) -+void fw_core_remove_descriptor(struct fw_descriptor *desc) - { - mutex_lock(&card_mutex); - -@@ -189,8 +185,7 @@ static const char gap_count_table[] = { - 63, 5, 7, 8, 10, 13, 16, 18, 21, 24, 26, 29, 32, 35, 37, 40 - }; - --void --fw_schedule_bm_work(struct fw_card *card, unsigned long delay) -+void fw_schedule_bm_work(struct fw_card *card, unsigned long delay) - { - int scheduled; - -@@ -200,8 +195,7 @@ fw_schedule_bm_work(struct fw_card *card - fw_card_put(card); - } - --static void --fw_card_bm_work(struct work_struct *work) -+static void fw_card_bm_work(struct work_struct *work) - { - struct fw_card *card = container_of(work, struct fw_card, work.work); - struct fw_device *root_device; -@@ -371,17 +365,16 @@ fw_card_bm_work(struct work_struct *work - fw_card_put(card); - } - --static void --flush_timer_callback(unsigned long data) -+static void flush_timer_callback(unsigned long data) - { - struct fw_card *card = (struct fw_card *)data; - - fw_flush_transactions(card); - } - --void --fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver, -- struct device *device) -+void fw_card_initialize(struct fw_card *card, -+ const struct fw_card_driver *driver, -+ struct device *device) - { - static atomic_t index = ATOMIC_INIT(-1); - -@@ -406,9 +399,8 @@ fw_card_initialize(struct fw_card *card, - } - EXPORT_SYMBOL(fw_card_initialize); - --int --fw_card_add(struct fw_card *card, -- u32 max_receive, u32 link_speed, u64 guid) -+int fw_card_add(struct fw_card *card, -+ u32 max_receive, u32 link_speed, u64 guid) - { - u32 *config_rom; - size_t length; -@@ -435,23 +427,20 @@ EXPORT_SYMBOL(fw_card_add); - * dummy driver just fails all IO. - */ - --static int --dummy_enable(struct fw_card *card, u32 *config_rom, size_t length) -+static int dummy_enable(struct fw_card *card, u32 *config_rom, size_t length) - { - BUG(); - return -1; - } - --static int --dummy_update_phy_reg(struct fw_card *card, int address, -- int clear_bits, int set_bits) -+static int dummy_update_phy_reg(struct fw_card *card, int address, -+ int clear_bits, int set_bits) - { - return -ENODEV; - } - --static int --dummy_set_config_rom(struct fw_card *card, -- u32 *config_rom, size_t length) -+static int dummy_set_config_rom(struct fw_card *card, -+ u32 *config_rom, size_t length) - { - /* - * We take the card out of card_list before setting the dummy -@@ -461,27 +450,23 @@ dummy_set_config_rom(struct fw_card *car - return -1; - } - --static void --dummy_send_request(struct fw_card *card, struct fw_packet *packet) -+static void dummy_send_request(struct fw_card *card, struct fw_packet *packet) - { - packet->callback(packet, card, -ENODEV); - } - --static void --dummy_send_response(struct fw_card *card, struct fw_packet *packet) -+static void dummy_send_response(struct fw_card *card, struct fw_packet *packet) - { - packet->callback(packet, card, -ENODEV); - } - --static int --dummy_cancel_packet(struct fw_card *card, struct fw_packet *packet) -+static int dummy_cancel_packet(struct fw_card *card, struct fw_packet *packet) - { - return -ENOENT; - } - --static int --dummy_enable_phys_dma(struct fw_card *card, -- int node_id, int generation) -+static int dummy_enable_phys_dma(struct fw_card *card, -+ int node_id, int generation) - { - return -ENODEV; - } -@@ -496,16 +481,14 @@ static struct fw_card_driver dummy_drive - .enable_phys_dma = dummy_enable_phys_dma, - }; - --void --fw_card_release(struct kref *kref) -+void fw_card_release(struct kref *kref) - { - struct fw_card *card = container_of(kref, struct fw_card, kref); - - complete(&card->done); - } - --void --fw_core_remove_card(struct fw_card *card) -+void fw_core_remove_card(struct fw_card *card) - { - card->driver->update_phy_reg(card, 4, - PHY_LINK_ACTIVE | PHY_CONTENDER, 0); -@@ -529,8 +512,7 @@ fw_core_remove_card(struct fw_card *card - } - EXPORT_SYMBOL(fw_core_remove_card); - --int --fw_core_initiate_bus_reset(struct fw_card *card, int short_reset) -+int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset) - { - int reg = short_reset ? 5 : 1; - int bit = short_reset ? PHY_BUS_SHORT_RESET : PHY_BUS_RESET; -diff -Naurp linux-2.6-git/drivers/firewire/fw-cdev.c firewire-git/drivers/firewire/fw-cdev.c ---- linux-2.6-git/drivers/firewire/fw-cdev.c 2008-11-04 11:19:19.000000000 -0500 -+++ firewire-git/drivers/firewire/fw-cdev.c 2009-01-30 13:35:51.860646788 -0500 -@@ -18,87 +18,162 @@ - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - --#include --#include --#include --#include -+#include -+#include - #include --#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include - #include - #include -+#include - #include --#include --#include --#include --#include --#include -+#include -+#include -+#include -+ - #include - #include --#include "fw-transaction.h" --#include "fw-topology.h" -+ - #include "fw-device.h" -+#include "fw-topology.h" -+#include "fw-transaction.h" -+ -+struct client { -+ u32 version; -+ struct fw_device *device; -+ -+ spinlock_t lock; -+ bool in_shutdown; -+ struct idr resource_idr; -+ struct list_head event_list; -+ wait_queue_head_t wait; -+ u64 bus_reset_closure; -+ -+ struct fw_iso_context *iso_context; -+ u64 iso_closure; -+ struct fw_iso_buffer buffer; -+ unsigned long vm_start; - --struct client; --struct client_resource { - struct list_head link; -- void (*release)(struct client *client, struct client_resource *r); -- u32 handle; -+ struct kref kref; -+}; -+ -+static inline void client_get(struct client *client) -+{ -+ kref_get(&client->kref); -+} -+ -+static void client_release(struct kref *kref) -+{ -+ struct client *client = container_of(kref, struct client, kref); -+ -+ fw_device_put(client->device); -+ kfree(client); -+} -+ -+static void client_put(struct client *client) -+{ -+ kref_put(&client->kref, client_release); -+} -+ -+struct client_resource; -+typedef void (*client_resource_release_fn_t)(struct client *, -+ struct client_resource *); -+struct client_resource { -+ client_resource_release_fn_t release; -+ int handle; -+}; -+ -+struct address_handler_resource { -+ struct client_resource resource; -+ struct fw_address_handler handler; -+ __u64 closure; -+ struct client *client; -+}; -+ -+struct outbound_transaction_resource { -+ struct client_resource resource; -+ struct fw_transaction transaction; -+}; -+ -+struct inbound_transaction_resource { -+ struct client_resource resource; -+ struct fw_request *request; -+ void *data; -+ size_t length; - }; - -+struct descriptor_resource { -+ struct client_resource resource; -+ struct fw_descriptor descriptor; -+ u32 data[0]; -+}; -+ -+struct iso_resource { -+ struct client_resource resource; -+ struct client *client; -+ /* Schedule work and access todo only with client->lock held. */ -+ struct delayed_work work; -+ enum {ISO_RES_ALLOC, ISO_RES_REALLOC, ISO_RES_DEALLOC, -+ ISO_RES_ALLOC_ONCE, ISO_RES_DEALLOC_ONCE,} todo; -+ int generation; -+ u64 channels; -+ s32 bandwidth; -+ struct iso_resource_event *e_alloc, *e_dealloc; -+}; -+ -+static void schedule_iso_resource(struct iso_resource *); -+static void release_iso_resource(struct client *, struct client_resource *); -+ - /* - * dequeue_event() just kfree()'s the event, so the event has to be -- * the first field in the struct. -+ * the first field in a struct XYZ_event. - */ -- - struct event { - struct { void *data; size_t size; } v[2]; - struct list_head link; - }; - --struct bus_reset { -+struct bus_reset_event { - struct event event; - struct fw_cdev_event_bus_reset reset; - }; - --struct response { -+struct outbound_transaction_event { - struct event event; -- struct fw_transaction transaction; - struct client *client; -- struct client_resource resource; -+ struct outbound_transaction_resource r; - struct fw_cdev_event_response response; - }; - --struct iso_interrupt { -+struct inbound_transaction_event { - struct event event; -- struct fw_cdev_event_iso_interrupt interrupt; -+ struct fw_cdev_event_request request; - }; - --struct client { -- u32 version; -- struct fw_device *device; -- spinlock_t lock; -- u32 resource_handle; -- struct list_head resource_list; -- struct list_head event_list; -- wait_queue_head_t wait; -- u64 bus_reset_closure; -- -- struct fw_iso_context *iso_context; -- u64 iso_closure; -- struct fw_iso_buffer buffer; -- unsigned long vm_start; -+struct iso_interrupt_event { -+ struct event event; -+ struct fw_cdev_event_iso_interrupt interrupt; -+}; - -- struct list_head link; -+struct iso_resource_event { -+ struct event event; -+ struct fw_cdev_event_iso_resource resource; - }; - --static inline void __user * --u64_to_uptr(__u64 value) -+static inline void __user *u64_to_uptr(__u64 value) - { - return (void __user *)(unsigned long)value; - } - --static inline __u64 --uptr_to_u64(void __user *ptr) -+static inline __u64 uptr_to_u64(void __user *ptr) - { - return (__u64)(unsigned long)ptr; - } -@@ -107,7 +182,6 @@ static int fw_device_op_open(struct inod - { - struct fw_device *device; - struct client *client; -- unsigned long flags; - - device = fw_device_get_by_devt(inode->i_rdev); - if (device == NULL) -@@ -125,16 +199,17 @@ static int fw_device_op_open(struct inod - } - - client->device = device; -- INIT_LIST_HEAD(&client->event_list); -- INIT_LIST_HEAD(&client->resource_list); - spin_lock_init(&client->lock); -+ idr_init(&client->resource_idr); -+ INIT_LIST_HEAD(&client->event_list); - init_waitqueue_head(&client->wait); -+ kref_init(&client->kref); - - file->private_data = client; - -- spin_lock_irqsave(&device->card->lock, flags); -+ mutex_lock(&device->client_list_mutex); - list_add_tail(&client->link, &device->client_list); -- spin_unlock_irqrestore(&device->card->lock, flags); -+ mutex_unlock(&device->client_list_mutex); - - return 0; - } -@@ -150,68 +225,69 @@ static void queue_event(struct client *c - event->v[1].size = size1; - - spin_lock_irqsave(&client->lock, flags); -- list_add_tail(&event->link, &client->event_list); -+ if (client->in_shutdown) -+ kfree(event); -+ else -+ list_add_tail(&event->link, &client->event_list); - spin_unlock_irqrestore(&client->lock, flags); - - wake_up_interruptible(&client->wait); - } - --static int --dequeue_event(struct client *client, char __user *buffer, size_t count) -+static int dequeue_event(struct client *client, -+ char __user *buffer, size_t count) - { -- unsigned long flags; - struct event *event; - size_t size, total; -- int i, retval; -+ int i, ret; - -- retval = wait_event_interruptible(client->wait, -- !list_empty(&client->event_list) || -- fw_device_is_shutdown(client->device)); -- if (retval < 0) -- return retval; -+ ret = wait_event_interruptible(client->wait, -+ !list_empty(&client->event_list) || -+ fw_device_is_shutdown(client->device)); -+ if (ret < 0) -+ return ret; - - if (list_empty(&client->event_list) && - fw_device_is_shutdown(client->device)) - return -ENODEV; - -- spin_lock_irqsave(&client->lock, flags); -- event = container_of(client->event_list.next, struct event, link); -+ spin_lock_irq(&client->lock); -+ event = list_first_entry(&client->event_list, struct event, link); - list_del(&event->link); -- spin_unlock_irqrestore(&client->lock, flags); -+ spin_unlock_irq(&client->lock); - - total = 0; - for (i = 0; i < ARRAY_SIZE(event->v) && total < count; i++) { - size = min(event->v[i].size, count - total); - if (copy_to_user(buffer + total, event->v[i].data, size)) { -- retval = -EFAULT; -+ ret = -EFAULT; - goto out; - } - total += size; - } -- retval = total; -+ ret = total; - - out: - kfree(event); - -- return retval; -+ return ret; - } - --static ssize_t --fw_device_op_read(struct file *file, -- char __user *buffer, size_t count, loff_t *offset) -+static ssize_t fw_device_op_read(struct file *file, char __user *buffer, -+ size_t count, loff_t *offset) - { - struct client *client = file->private_data; - - return dequeue_event(client, buffer, count); - } - --/* caller must hold card->lock so that node pointers can be dereferenced here */ --static void --fill_bus_reset_event(struct fw_cdev_event_bus_reset *event, -- struct client *client) -+static void fill_bus_reset_event(struct fw_cdev_event_bus_reset *event, -+ struct client *client) - { - struct fw_card *card = client->device->card; - -+ spin_lock_irq(&card->lock); -+ - event->closure = client->bus_reset_closure; - event->type = FW_CDEV_EVENT_BUS_RESET; - event->generation = client->device->generation; -@@ -220,39 +296,49 @@ fill_bus_reset_event(struct fw_cdev_even - event->bm_node_id = 0; /* FIXME: We don't track the BM. */ - event->irm_node_id = card->irm_node->node_id; - event->root_node_id = card->root_node->node_id; -+ -+ spin_unlock_irq(&card->lock); - } - --static void --for_each_client(struct fw_device *device, -- void (*callback)(struct client *client)) -+static void for_each_client(struct fw_device *device, -+ void (*callback)(struct client *client)) - { -- struct fw_card *card = device->card; - struct client *c; -- unsigned long flags; -- -- spin_lock_irqsave(&card->lock, flags); - -+ mutex_lock(&device->client_list_mutex); - list_for_each_entry(c, &device->client_list, link) - callback(c); -+ mutex_unlock(&device->client_list_mutex); -+} -+ -+static int schedule_reallocations(int id, void *p, void *data) -+{ -+ struct client_resource *r = p; - -- spin_unlock_irqrestore(&card->lock, flags); -+ if (r->release == release_iso_resource) -+ schedule_iso_resource(container_of(r, -+ struct iso_resource, resource)); -+ return 0; - } - --static void --queue_bus_reset_event(struct client *client) -+static void queue_bus_reset_event(struct client *client) - { -- struct bus_reset *bus_reset; -+ struct bus_reset_event *e; - -- bus_reset = kzalloc(sizeof(*bus_reset), GFP_ATOMIC); -- if (bus_reset == NULL) { -+ e = kzalloc(sizeof(*e), GFP_KERNEL); -+ if (e == NULL) { - fw_notify("Out of memory when allocating bus reset event\n"); - return; - } - -- fill_bus_reset_event(&bus_reset->reset, client); -+ fill_bus_reset_event(&e->reset, client); -+ -+ queue_event(client, &e->event, -+ &e->reset, sizeof(e->reset), NULL, 0); - -- queue_event(client, &bus_reset->event, -- &bus_reset->reset, sizeof(bus_reset->reset), NULL, 0); -+ spin_lock_irq(&client->lock); -+ idr_for_each(&client->resource_idr, schedule_reallocations, client); -+ spin_unlock_irq(&client->lock); - } - - void fw_device_cdev_update(struct fw_device *device) -@@ -274,11 +360,11 @@ static int ioctl_get_info(struct client - { - struct fw_cdev_get_info *get_info = buffer; - struct fw_cdev_event_bus_reset bus_reset; -- struct fw_card *card = client->device->card; - unsigned long ret = 0; - - client->version = get_info->version; - get_info->version = FW_CDEV_VERSION; -+ get_info->card = client->device->card->index; - - down_read(&fw_device_rwsem); - -@@ -300,49 +386,61 @@ static int ioctl_get_info(struct client - client->bus_reset_closure = get_info->bus_reset_closure; - if (get_info->bus_reset != 0) { - void __user *uptr = u64_to_uptr(get_info->bus_reset); -- unsigned long flags; - -- spin_lock_irqsave(&card->lock, flags); - fill_bus_reset_event(&bus_reset, client); -- spin_unlock_irqrestore(&card->lock, flags); -- - if (copy_to_user(uptr, &bus_reset, sizeof(bus_reset))) - return -EFAULT; - } - -- get_info->card = card->index; -- - return 0; - } - --static void --add_client_resource(struct client *client, struct client_resource *resource) -+static int add_client_resource(struct client *client, -+ struct client_resource *resource, gfp_t gfp_mask) - { - unsigned long flags; -+ int ret; -+ -+ retry: -+ if (idr_pre_get(&client->resource_idr, gfp_mask | __GFP_ZERO) == 0) -+ return -ENOMEM; - - spin_lock_irqsave(&client->lock, flags); -- list_add_tail(&resource->link, &client->resource_list); -- resource->handle = client->resource_handle++; -+ if (client->in_shutdown) -+ ret = -ECANCELED; -+ else -+ ret = idr_get_new(&client->resource_idr, resource, -+ &resource->handle); -+ if (ret >= 0) { -+ client_get(client); -+ if (resource->release == release_iso_resource) -+ schedule_iso_resource(container_of(resource, -+ struct iso_resource, resource)); -+ } - spin_unlock_irqrestore(&client->lock, flags); -+ -+ if (ret == -EAGAIN) -+ goto retry; -+ -+ return ret < 0 ? ret : 0; - } - --static int --release_client_resource(struct client *client, u32 handle, -- struct client_resource **resource) -+static int release_client_resource(struct client *client, u32 handle, -+ client_resource_release_fn_t release, -+ struct client_resource **resource) - { - struct client_resource *r; -- unsigned long flags; - -- spin_lock_irqsave(&client->lock, flags); -- list_for_each_entry(r, &client->resource_list, link) { -- if (r->handle == handle) { -- list_del(&r->link); -- break; -- } -- } -- spin_unlock_irqrestore(&client->lock, flags); -+ spin_lock_irq(&client->lock); -+ if (client->in_shutdown) -+ r = NULL; -+ else -+ r = idr_find(&client->resource_idr, handle); -+ if (r && r->release == release) -+ idr_remove(&client->resource_idr, handle); -+ spin_unlock_irq(&client->lock); - -- if (&r->link == &client->resource_list) -+ if (!(r && r->release == release)) - return -EINVAL; - - if (resource) -@@ -350,203 +448,242 @@ release_client_resource(struct client *c - else - r->release(client, r); - -+ client_put(client); -+ - return 0; - } - --static void --release_transaction(struct client *client, struct client_resource *resource) -+static void release_transaction(struct client *client, -+ struct client_resource *resource) - { -- struct response *response = -- container_of(resource, struct response, resource); -+ struct outbound_transaction_resource *r = container_of(resource, -+ struct outbound_transaction_resource, resource); - -- fw_cancel_transaction(client->device->card, &response->transaction); -+ fw_cancel_transaction(client->device->card, &r->transaction); - } - --static void --complete_transaction(struct fw_card *card, int rcode, -- void *payload, size_t length, void *data) -+static void complete_transaction(struct fw_card *card, int rcode, -+ void *payload, size_t length, void *data) - { -- struct response *response = data; -- struct client *client = response->client; -+ struct outbound_transaction_event *e = data; -+ struct fw_cdev_event_response *rsp = &e->response; -+ struct client *client = e->client; - unsigned long flags; -- struct fw_cdev_event_response *r = &response->response; - -- if (length < r->length) -- r->length = length; -+ if (length < rsp->length) -+ rsp->length = length; - if (rcode == RCODE_COMPLETE) -- memcpy(r->data, payload, r->length); -+ memcpy(rsp->data, payload, rsp->length); - - spin_lock_irqsave(&client->lock, flags); -- list_del(&response->resource.link); -+ /* -+ * 1. If called while in shutdown, the idr tree must be left untouched. -+ * The idr handle will be removed and the client reference will be -+ * dropped later. -+ * 2. If the call chain was release_client_resource -> -+ * release_transaction -> complete_transaction (instead of a normal -+ * conclusion of the transaction), i.e. if this resource was already -+ * unregistered from the idr, the client reference will be dropped -+ * by release_client_resource and we must not drop it here. -+ */ -+ if (!client->in_shutdown && -+ idr_find(&client->resource_idr, e->r.resource.handle)) { -+ idr_remove(&client->resource_idr, e->r.resource.handle); -+ /* Drop the idr's reference */ -+ client_put(client); -+ } - spin_unlock_irqrestore(&client->lock, flags); - -- r->type = FW_CDEV_EVENT_RESPONSE; -- r->rcode = rcode; -+ rsp->type = FW_CDEV_EVENT_RESPONSE; -+ rsp->rcode = rcode; - - /* -- * In the case that sizeof(*r) doesn't align with the position of the -+ * In the case that sizeof(*rsp) doesn't align with the position of the - * data, and the read is short, preserve an extra copy of the data - * to stay compatible with a pre-2.6.27 bug. Since the bug is harmless - * for short reads and some apps depended on it, this is both safe - * and prudent for compatibility. - */ -- if (r->length <= sizeof(*r) - offsetof(typeof(*r), data)) -- queue_event(client, &response->event, r, sizeof(*r), -- r->data, r->length); -+ if (rsp->length <= sizeof(*rsp) - offsetof(typeof(*rsp), data)) -+ queue_event(client, &e->event, rsp, sizeof(*rsp), -+ rsp->data, rsp->length); - else -- queue_event(client, &response->event, r, sizeof(*r) + r->length, -+ queue_event(client, &e->event, rsp, sizeof(*rsp) + rsp->length, - NULL, 0); -+ -+ /* Drop the transaction callback's reference */ -+ client_put(client); - } - --static int ioctl_send_request(struct client *client, void *buffer) -+static int init_request(struct client *client, -+ struct fw_cdev_send_request *request, -+ int destination_id, int speed) - { -- struct fw_device *device = client->device; -- struct fw_cdev_send_request *request = buffer; -- struct response *response; -+ struct outbound_transaction_event *e; -+ int ret; - -- /* What is the biggest size we'll accept, really? */ -- if (request->length > 4096) -- return -EINVAL; -+ if (request->length > 4096 || request->length > 512 << speed) -+ return -EIO; - -- response = kmalloc(sizeof(*response) + request->length, GFP_KERNEL); -- if (response == NULL) -+ e = kmalloc(sizeof(*e) + request->length, GFP_KERNEL); -+ if (e == NULL) - return -ENOMEM; - -- response->client = client; -- response->response.length = request->length; -- response->response.closure = request->closure; -+ e->client = client; -+ e->response.length = request->length; -+ e->response.closure = request->closure; - - if (request->data && -- copy_from_user(response->response.data, -+ copy_from_user(e->response.data, - u64_to_uptr(request->data), request->length)) { -- kfree(response); -- return -EFAULT; -+ ret = -EFAULT; -+ goto failed; - } - -- response->resource.release = release_transaction; -- add_client_resource(client, &response->resource); -- -- fw_send_request(device->card, &response->transaction, -- request->tcode & 0x1f, -- device->node->node_id, -- request->generation, -- device->max_speed, -- request->offset, -- response->response.data, request->length, -- complete_transaction, response); -+ e->r.resource.release = release_transaction; -+ ret = add_client_resource(client, &e->r.resource, GFP_KERNEL); -+ if (ret < 0) -+ goto failed; -+ -+ /* Get a reference for the transaction callback */ -+ client_get(client); -+ -+ fw_send_request(client->device->card, &e->r.transaction, -+ request->tcode & 0x1f, destination_id, -+ request->generation, speed, request->offset, -+ e->response.data, request->length, -+ complete_transaction, e); - - if (request->data) - return sizeof(request) + request->length; - else - return sizeof(request); -+ failed: -+ kfree(e); -+ -+ return ret; - } - --struct address_handler { -- struct fw_address_handler handler; -- __u64 closure; -- struct client *client; -- struct client_resource resource; --}; -+static int ioctl_send_request(struct client *client, void *buffer) -+{ -+ struct fw_cdev_send_request *request = buffer; - --struct request { -- struct fw_request *request; -- void *data; -- size_t length; -- struct client_resource resource; --}; -+ switch (request->tcode) { -+ case TCODE_WRITE_QUADLET_REQUEST: -+ case TCODE_WRITE_BLOCK_REQUEST: -+ case TCODE_READ_QUADLET_REQUEST: -+ case TCODE_READ_BLOCK_REQUEST: -+ case TCODE_LOCK_MASK_SWAP: -+ case TCODE_LOCK_COMPARE_SWAP: -+ case TCODE_LOCK_FETCH_ADD: -+ case TCODE_LOCK_LITTLE_ADD: -+ case TCODE_LOCK_BOUNDED_ADD: -+ case TCODE_LOCK_WRAP_ADD: -+ case TCODE_LOCK_VENDOR_DEPENDENT: -+ break; -+ default: -+ return -EINVAL; -+ } - --struct request_event { -- struct event event; -- struct fw_cdev_event_request request; --}; -+ return init_request(client, request, client->device->node->node_id, -+ client->device->max_speed); -+} - --static void --release_request(struct client *client, struct client_resource *resource) -+static void release_request(struct client *client, -+ struct client_resource *resource) - { -- struct request *request = -- container_of(resource, struct request, resource); -+ struct inbound_transaction_resource *r = container_of(resource, -+ struct inbound_transaction_resource, resource); - -- fw_send_response(client->device->card, request->request, -+ fw_send_response(client->device->card, r->request, - RCODE_CONFLICT_ERROR); -- kfree(request); -+ kfree(r); - } - --static void --handle_request(struct fw_card *card, struct fw_request *r, -- int tcode, int destination, int source, -- int generation, int speed, -- unsigned long long offset, -- void *payload, size_t length, void *callback_data) --{ -- struct address_handler *handler = callback_data; -- struct request *request; -- struct request_event *e; -- struct client *client = handler->client; -+static void handle_request(struct fw_card *card, struct fw_request *request, -+ int tcode, int destination, int source, -+ int generation, int speed, -+ unsigned long long offset, -+ void *payload, size_t length, void *callback_data) -+{ -+ struct address_handler_resource *handler = callback_data; -+ struct inbound_transaction_resource *r; -+ struct inbound_transaction_event *e; -+ int ret; - -- request = kmalloc(sizeof(*request), GFP_ATOMIC); -+ r = kmalloc(sizeof(*r), GFP_ATOMIC); - e = kmalloc(sizeof(*e), GFP_ATOMIC); -- if (request == NULL || e == NULL) { -- kfree(request); -- kfree(e); -- fw_send_response(card, r, RCODE_CONFLICT_ERROR); -- return; -- } -- -- request->request = r; -- request->data = payload; -- request->length = length; -+ if (r == NULL || e == NULL) -+ goto failed; - -- request->resource.release = release_request; -- add_client_resource(client, &request->resource); -+ r->request = request; -+ r->data = payload; -+ r->length = length; -+ -+ r->resource.release = release_request; -+ ret = add_client_resource(handler->client, &r->resource, GFP_ATOMIC); -+ if (ret < 0) -+ goto failed; - - e->request.type = FW_CDEV_EVENT_REQUEST; - e->request.tcode = tcode; - e->request.offset = offset; - e->request.length = length; -- e->request.handle = request->resource.handle; -+ e->request.handle = r->resource.handle; - e->request.closure = handler->closure; - -- queue_event(client, &e->event, -+ queue_event(handler->client, &e->event, - &e->request, sizeof(e->request), payload, length); -+ return; -+ -+ failed: -+ kfree(r); -+ kfree(e); -+ fw_send_response(card, request, RCODE_CONFLICT_ERROR); - } - --static void --release_address_handler(struct client *client, -- struct client_resource *resource) -+static void release_address_handler(struct client *client, -+ struct client_resource *resource) - { -- struct address_handler *handler = -- container_of(resource, struct address_handler, resource); -+ struct address_handler_resource *r = -+ container_of(resource, struct address_handler_resource, resource); - -- fw_core_remove_address_handler(&handler->handler); -- kfree(handler); -+ fw_core_remove_address_handler(&r->handler); -+ kfree(r); - } - - static int ioctl_allocate(struct client *client, void *buffer) - { - struct fw_cdev_allocate *request = buffer; -- struct address_handler *handler; -+ struct address_handler_resource *r; - struct fw_address_region region; -+ int ret; - -- handler = kmalloc(sizeof(*handler), GFP_KERNEL); -- if (handler == NULL) -+ r = kmalloc(sizeof(*r), GFP_KERNEL); -+ if (r == NULL) - return -ENOMEM; - - region.start = request->offset; - region.end = request->offset + request->length; -- handler->handler.length = request->length; -- handler->handler.address_callback = handle_request; -- handler->handler.callback_data = handler; -- handler->closure = request->closure; -- handler->client = client; -- -- if (fw_core_add_address_handler(&handler->handler, ®ion) < 0) { -- kfree(handler); -- return -EBUSY; -+ r->handler.length = request->length; -+ r->handler.address_callback = handle_request; -+ r->handler.callback_data = r; -+ r->closure = request->closure; -+ r->client = client; -+ -+ ret = fw_core_add_address_handler(&r->handler, ®ion); -+ if (ret < 0) { -+ kfree(r); -+ return ret; - } - -- handler->resource.release = release_address_handler; -- add_client_resource(client, &handler->resource); -- request->handle = handler->resource.handle; -+ r->resource.release = release_address_handler; -+ ret = add_client_resource(client, &r->resource, GFP_KERNEL); -+ if (ret < 0) { -+ release_address_handler(client, &r->resource); -+ return ret; -+ } -+ request->handle = r->resource.handle; - - return 0; - } -@@ -555,18 +692,22 @@ static int ioctl_deallocate(struct clien - { - struct fw_cdev_deallocate *request = buffer; - -- return release_client_resource(client, request->handle, NULL); -+ return release_client_resource(client, request->handle, -+ release_address_handler, NULL); - } - - static int ioctl_send_response(struct client *client, void *buffer) - { - struct fw_cdev_send_response *request = buffer; - struct client_resource *resource; -- struct request *r; -+ struct inbound_transaction_resource *r; - -- if (release_client_resource(client, request->handle, &resource) < 0) -+ if (release_client_resource(client, request->handle, -+ release_request, &resource) < 0) - return -EINVAL; -- r = container_of(resource, struct request, resource); -+ -+ r = container_of(resource, struct inbound_transaction_resource, -+ resource); - if (request->length < r->length) - r->length = request->length; - if (copy_from_user(r->data, u64_to_uptr(request->data), r->length)) -@@ -588,85 +729,84 @@ static int ioctl_initiate_bus_reset(stru - return fw_core_initiate_bus_reset(client->device->card, short_reset); - } - --struct descriptor { -- struct fw_descriptor d; -- struct client_resource resource; -- u32 data[0]; --}; -- - static void release_descriptor(struct client *client, - struct client_resource *resource) - { -- struct descriptor *descriptor = -- container_of(resource, struct descriptor, resource); -+ struct descriptor_resource *r = -+ container_of(resource, struct descriptor_resource, resource); - -- fw_core_remove_descriptor(&descriptor->d); -- kfree(descriptor); -+ fw_core_remove_descriptor(&r->descriptor); -+ kfree(r); - } - - static int ioctl_add_descriptor(struct client *client, void *buffer) - { - struct fw_cdev_add_descriptor *request = buffer; -- struct descriptor *descriptor; -- int retval; -+ struct descriptor_resource *r; -+ int ret; - - if (request->length > 256) - return -EINVAL; - -- descriptor = -- kmalloc(sizeof(*descriptor) + request->length * 4, GFP_KERNEL); -- if (descriptor == NULL) -+ r = kmalloc(sizeof(*r) + request->length * 4, GFP_KERNEL); -+ if (r == NULL) - return -ENOMEM; - -- if (copy_from_user(descriptor->data, -+ if (copy_from_user(r->data, - u64_to_uptr(request->data), request->length * 4)) { -- kfree(descriptor); -- return -EFAULT; -+ ret = -EFAULT; -+ goto failed; - } - -- descriptor->d.length = request->length; -- descriptor->d.immediate = request->immediate; -- descriptor->d.key = request->key; -- descriptor->d.data = descriptor->data; -- -- retval = fw_core_add_descriptor(&descriptor->d); -- if (retval < 0) { -- kfree(descriptor); -- return retval; -+ r->descriptor.length = request->length; -+ r->descriptor.immediate = request->immediate; -+ r->descriptor.key = request->key; -+ r->descriptor.data = r->data; -+ -+ ret = fw_core_add_descriptor(&r->descriptor); -+ if (ret < 0) -+ goto failed; -+ -+ r->resource.release = release_descriptor; -+ ret = add_client_resource(client, &r->resource, GFP_KERNEL); -+ if (ret < 0) { -+ fw_core_remove_descriptor(&r->descriptor); -+ goto failed; - } -- -- descriptor->resource.release = release_descriptor; -- add_client_resource(client, &descriptor->resource); -- request->handle = descriptor->resource.handle; -+ request->handle = r->resource.handle; - - return 0; -+ failed: -+ kfree(r); -+ -+ return ret; - } - - static int ioctl_remove_descriptor(struct client *client, void *buffer) - { - struct fw_cdev_remove_descriptor *request = buffer; - -- return release_client_resource(client, request->handle, NULL); -+ return release_client_resource(client, request->handle, -+ release_descriptor, NULL); - } - --static void --iso_callback(struct fw_iso_context *context, u32 cycle, -- size_t header_length, void *header, void *data) -+static void iso_callback(struct fw_iso_context *context, u32 cycle, -+ size_t header_length, void *header, void *data) - { - struct client *client = data; -- struct iso_interrupt *irq; -+ struct iso_interrupt_event *e; - -- irq = kzalloc(sizeof(*irq) + header_length, GFP_ATOMIC); -- if (irq == NULL) -+ e = kzalloc(sizeof(*e) + header_length, GFP_ATOMIC); -+ if (e == NULL) - return; - -- irq->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT; -- irq->interrupt.closure = client->iso_closure; -- irq->interrupt.cycle = cycle; -- irq->interrupt.header_length = header_length; -- memcpy(irq->interrupt.header, header, header_length); -- queue_event(client, &irq->event, &irq->interrupt, -- sizeof(irq->interrupt) + header_length, NULL, 0); -+ e->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT; -+ e->interrupt.closure = client->iso_closure; -+ e->interrupt.cycle = cycle; -+ e->interrupt.header_length = header_length; -+ memcpy(e->interrupt.header, header, header_length); -+ queue_event(client, &e->event, &e->interrupt, -+ sizeof(e->interrupt) + header_length, NULL, 0); - } - - static int ioctl_create_iso_context(struct client *client, void *buffer) -@@ -871,6 +1011,237 @@ static int ioctl_get_cycle_timer(struct - return 0; - } - -+static void iso_resource_work(struct work_struct *work) -+{ -+ struct iso_resource_event *e; -+ struct iso_resource *r = -+ container_of(work, struct iso_resource, work.work); -+ struct client *client = r->client; -+ int generation, channel, bandwidth, todo; -+ bool skip, free, success; -+ -+ spin_lock_irq(&client->lock); -+ generation = client->device->generation; -+ todo = r->todo; -+ /* Allow 1000ms grace period for other reallocations. */ -+ if (todo == ISO_RES_ALLOC && -+ time_is_after_jiffies(client->device->card->reset_jiffies + HZ)) { -+ if (schedule_delayed_work(&r->work, DIV_ROUND_UP(HZ, 3))) -+ client_get(client); -+ skip = true; -+ } else { -+ /* We could be called twice within the same generation. */ -+ skip = todo == ISO_RES_REALLOC && -+ r->generation == generation; -+ } -+ free = todo == ISO_RES_DEALLOC || -+ todo == ISO_RES_ALLOC_ONCE || -+ todo == ISO_RES_DEALLOC_ONCE; -+ r->generation = generation; -+ spin_unlock_irq(&client->lock); -+ -+ if (skip) -+ goto out; -+ -+ bandwidth = r->bandwidth; -+ -+ fw_iso_resource_manage(client->device->card, generation, -+ r->channels, &channel, &bandwidth, -+ todo == ISO_RES_ALLOC || -+ todo == ISO_RES_REALLOC || -+ todo == ISO_RES_ALLOC_ONCE); -+ /* -+ * Is this generation outdated already? As long as this resource sticks -+ * in the idr, it will be scheduled again for a newer generation or at -+ * shutdown. -+ */ -+ if (channel == -EAGAIN && -+ (todo == ISO_RES_ALLOC || todo == ISO_RES_REALLOC)) -+ goto out; -+ -+ success = channel >= 0 || bandwidth > 0; -+ -+ spin_lock_irq(&client->lock); -+ /* -+ * Transit from allocation to reallocation, except if the client -+ * requested deallocation in the meantime. -+ */ -+ if (r->todo == ISO_RES_ALLOC) -+ r->todo = ISO_RES_REALLOC; -+ /* -+ * Allocation or reallocation failure? Pull this resource out of the -+ * idr and prepare for deletion, unless the client is shutting down. -+ */ -+ if (r->todo == ISO_RES_REALLOC && !success && -+ !client->in_shutdown && -+ idr_find(&client->resource_idr, r->resource.handle)) { -+ idr_remove(&client->resource_idr, r->resource.handle); -+ client_put(client); -+ free = true; -+ } -+ spin_unlock_irq(&client->lock); -+ -+ if (todo == ISO_RES_ALLOC && channel >= 0) -+ r->channels = 1ULL << channel; -+ -+ if (todo == ISO_RES_REALLOC && success) -+ goto out; -+ -+ if (todo == ISO_RES_ALLOC || todo == ISO_RES_ALLOC_ONCE) { -+ e = r->e_alloc; -+ r->e_alloc = NULL; -+ } else { -+ e = r->e_dealloc; -+ r->e_dealloc = NULL; -+ } -+ e->resource.handle = r->resource.handle; -+ e->resource.channel = channel; -+ e->resource.bandwidth = bandwidth; -+ -+ queue_event(client, &e->event, -+ &e->resource, sizeof(e->resource), NULL, 0); -+ -+ if (free) { -+ cancel_delayed_work(&r->work); -+ kfree(r->e_alloc); -+ kfree(r->e_dealloc); -+ kfree(r); -+ } -+ out: -+ client_put(client); -+} -+ -+static void schedule_iso_resource(struct iso_resource *r) -+{ -+ client_get(r->client); -+ if (!schedule_delayed_work(&r->work, 0)) -+ client_put(r->client); -+} -+ -+static void release_iso_resource(struct client *client, -+ struct client_resource *resource) -+{ -+ struct iso_resource *r = -+ container_of(resource, struct iso_resource, resource); -+ -+ spin_lock_irq(&client->lock); -+ r->todo = ISO_RES_DEALLOC; -+ schedule_iso_resource(r); -+ spin_unlock_irq(&client->lock); -+} -+ -+static int init_iso_resource(struct client *client, -+ struct fw_cdev_allocate_iso_resource *request, int todo) -+{ -+ struct iso_resource_event *e1, *e2; -+ struct iso_resource *r; -+ int ret; -+ -+ if ((request->channels == 0 && request->bandwidth == 0) || -+ request->bandwidth > BANDWIDTH_AVAILABLE_INITIAL || -+ request->bandwidth < 0) -+ return -EINVAL; -+ -+ r = kmalloc(sizeof(*r), GFP_KERNEL); -+ e1 = kmalloc(sizeof(*e1), GFP_KERNEL); -+ e2 = kmalloc(sizeof(*e2), GFP_KERNEL); -+ if (r == NULL || e1 == NULL || e2 == NULL) { -+ ret = -ENOMEM; -+ goto fail; -+ } -+ -+ INIT_DELAYED_WORK(&r->work, iso_resource_work); -+ r->client = client; -+ r->todo = todo; -+ r->generation = -1; -+ r->channels = request->channels; -+ r->bandwidth = request->bandwidth; -+ r->e_alloc = e1; -+ r->e_dealloc = e2; -+ -+ e1->resource.closure = request->closure; -+ e1->resource.type = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED; -+ e2->resource.closure = request->closure; -+ e2->resource.type = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED; -+ -+ if (todo == ISO_RES_ALLOC) { -+ r->resource.release = release_iso_resource; -+ ret = add_client_resource(client, &r->resource, GFP_KERNEL); -+ if (ret < 0) -+ goto fail; -+ } else { -+ r->resource.release = NULL; -+ r->resource.handle = -1; -+ schedule_iso_resource(r); -+ } -+ request->handle = r->resource.handle; -+ -+ return 0; -+ fail: -+ kfree(r); -+ kfree(e1); -+ kfree(e2); -+ -+ return ret; -+} -+ -+static int ioctl_allocate_iso_resource(struct client *client, void *buffer) -+{ -+ struct fw_cdev_allocate_iso_resource *request = buffer; -+ -+ return init_iso_resource(client, request, ISO_RES_ALLOC); -+} -+ -+static int ioctl_deallocate_iso_resource(struct client *client, void *buffer) -+{ -+ struct fw_cdev_deallocate *request = buffer; -+ -+ return release_client_resource(client, request->handle, -+ release_iso_resource, NULL); -+} -+ -+static int ioctl_allocate_iso_resource_once(struct client *client, void *buffer) -+{ -+ struct fw_cdev_allocate_iso_resource *request = buffer; -+ -+ return init_iso_resource(client, request, ISO_RES_ALLOC_ONCE); -+} -+ -+static int ioctl_deallocate_iso_resource_once(struct client *client, void *buffer) -+{ -+ struct fw_cdev_allocate_iso_resource *request = buffer; -+ -+ return init_iso_resource(client, request, ISO_RES_DEALLOC_ONCE); -+} -+ -+static int ioctl_get_speed(struct client *client, void *buffer) -+{ -+ struct fw_cdev_get_speed *request = buffer; -+ -+ request->max_speed = client->device->max_speed; -+ -+ return 0; -+} -+ -+static int ioctl_send_broadcast_request(struct client *client, void *buffer) -+{ -+ struct fw_cdev_send_request *request = buffer; -+ -+ switch (request->tcode) { -+ case TCODE_WRITE_QUADLET_REQUEST: -+ case TCODE_WRITE_BLOCK_REQUEST: -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ /* Security policy: Only allow accesses to Units Space. */ -+ if (request->offset < CSR_REGISTER_BASE + CSR_CONFIG_ROM_END) -+ return -EACCES; -+ -+ return init_request(client, request, LOCAL_BUS | 0x3f, SCODE_100); -+} -+ - static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { - ioctl_get_info, - ioctl_send_request, -@@ -885,13 +1256,19 @@ static int (* const ioctl_handlers[])(st - ioctl_start_iso, - ioctl_stop_iso, - ioctl_get_cycle_timer, -+ ioctl_allocate_iso_resource, -+ ioctl_deallocate_iso_resource, -+ ioctl_allocate_iso_resource_once, -+ ioctl_deallocate_iso_resource_once, -+ ioctl_get_speed, -+ ioctl_send_broadcast_request, - }; - --static int --dispatch_ioctl(struct client *client, unsigned int cmd, void __user *arg) -+static int dispatch_ioctl(struct client *client, -+ unsigned int cmd, void __user *arg) - { - char buffer[256]; -- int retval; -+ int ret; - - if (_IOC_TYPE(cmd) != '#' || - _IOC_NR(cmd) >= ARRAY_SIZE(ioctl_handlers)) -@@ -903,9 +1280,9 @@ dispatch_ioctl(struct client *client, un - return -EFAULT; - } - -- retval = ioctl_handlers[_IOC_NR(cmd)](client, buffer); -- if (retval < 0) -- return retval; -+ ret = ioctl_handlers[_IOC_NR(cmd)](client, buffer); -+ if (ret < 0) -+ return ret; - - if (_IOC_DIR(cmd) & _IOC_READ) { - if (_IOC_SIZE(cmd) > sizeof(buffer) || -@@ -913,12 +1290,11 @@ dispatch_ioctl(struct client *client, un - return -EFAULT; - } - -- return retval; -+ return ret; - } - --static long --fw_device_op_ioctl(struct file *file, -- unsigned int cmd, unsigned long arg) -+static long fw_device_op_ioctl(struct file *file, -+ unsigned int cmd, unsigned long arg) - { - struct client *client = file->private_data; - -@@ -929,9 +1305,8 @@ fw_device_op_ioctl(struct file *file, - } - - #ifdef CONFIG_COMPAT --static long --fw_device_op_compat_ioctl(struct file *file, -- unsigned int cmd, unsigned long arg) -+static long fw_device_op_compat_ioctl(struct file *file, -+ unsigned int cmd, unsigned long arg) - { - struct client *client = file->private_data; - -@@ -947,7 +1322,7 @@ static int fw_device_op_mmap(struct file - struct client *client = file->private_data; - enum dma_data_direction direction; - unsigned long size; -- int page_count, retval; -+ int page_count, ret; - - if (fw_device_is_shutdown(client->device)) - return -ENODEV; -@@ -973,48 +1348,57 @@ static int fw_device_op_mmap(struct file - else - direction = DMA_FROM_DEVICE; - -- retval = fw_iso_buffer_init(&client->buffer, client->device->card, -- page_count, direction); -- if (retval < 0) -- return retval; -+ ret = fw_iso_buffer_init(&client->buffer, client->device->card, -+ page_count, direction); -+ if (ret < 0) -+ return ret; - -- retval = fw_iso_buffer_map(&client->buffer, vma); -- if (retval < 0) -+ ret = fw_iso_buffer_map(&client->buffer, vma); -+ if (ret < 0) - fw_iso_buffer_destroy(&client->buffer, client->device->card); - -- return retval; -+ return ret; -+} -+ -+static int shutdown_resource(int id, void *p, void *data) -+{ -+ struct client_resource *r = p; -+ struct client *client = data; -+ -+ r->release(client, r); -+ client_put(client); -+ -+ return 0; - } - - static int fw_device_op_release(struct inode *inode, struct file *file) - { - struct client *client = file->private_data; - struct event *e, *next_e; -- struct client_resource *r, *next_r; -- unsigned long flags; - -- if (client->buffer.pages) -- fw_iso_buffer_destroy(&client->buffer, client->device->card); -+ mutex_lock(&client->device->client_list_mutex); -+ list_del(&client->link); -+ mutex_unlock(&client->device->client_list_mutex); - - if (client->iso_context) - fw_iso_context_destroy(client->iso_context); - -- list_for_each_entry_safe(r, next_r, &client->resource_list, link) -- r->release(client, r); -+ if (client->buffer.pages) -+ fw_iso_buffer_destroy(&client->buffer, client->device->card); - -- /* -- * FIXME: We should wait for the async tasklets to stop -- * running before freeing the memory. -- */ -+ /* Freeze client->resource_idr and client->event_list */ -+ spin_lock_irq(&client->lock); -+ client->in_shutdown = true; -+ spin_unlock_irq(&client->lock); -+ -+ idr_for_each(&client->resource_idr, shutdown_resource, client); -+ idr_remove_all(&client->resource_idr); -+ idr_destroy(&client->resource_idr); - - list_for_each_entry_safe(e, next_e, &client->event_list, link) - kfree(e); - -- spin_lock_irqsave(&client->device->card->lock, flags); -- list_del(&client->link); -- spin_unlock_irqrestore(&client->device->card->lock, flags); -- -- fw_device_put(client->device); -- kfree(client); -+ client_put(client); - - return 0; - } -diff -Naurp linux-2.6-git/drivers/firewire/fw-device.c firewire-git/drivers/firewire/fw-device.c ---- linux-2.6-git/drivers/firewire/fw-device.c 2009-01-30 13:39:02.989651512 -0500 -+++ firewire-git/drivers/firewire/fw-device.c 2009-01-30 13:35:51.860646788 -0500 -@@ -27,8 +27,10 @@ - #include - #include - #include -+#include - #include - #include -+#include - #include - #include - #include "fw-transaction.h" -@@ -132,8 +134,7 @@ static int get_modalias(struct fw_unit * - vendor, model, specifier_id, version); - } - --static int --fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env) -+static int fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env) - { - struct fw_unit *unit = fw_unit(dev); - char modalias[64]; -@@ -191,8 +192,8 @@ struct config_rom_attribute { - u32 key; - }; - --static ssize_t --show_immediate(struct device *dev, struct device_attribute *dattr, char *buf) -+static ssize_t show_immediate(struct device *dev, -+ struct device_attribute *dattr, char *buf) - { - struct config_rom_attribute *attr = - container_of(dattr, struct config_rom_attribute, attr); -@@ -223,8 +224,8 @@ show_immediate(struct device *dev, struc - #define IMMEDIATE_ATTR(name, key) \ - { __ATTR(name, S_IRUGO, show_immediate, NULL), key } - --static ssize_t --show_text_leaf(struct device *dev, struct device_attribute *dattr, char *buf) -+static ssize_t show_text_leaf(struct device *dev, -+ struct device_attribute *dattr, char *buf) - { - struct config_rom_attribute *attr = - container_of(dattr, struct config_rom_attribute, attr); -@@ -293,10 +294,9 @@ static struct config_rom_attribute confi - TEXT_LEAF_ATTR(hardware_version_name, CSR_HARDWARE_VERSION), - }; - --static void --init_fw_attribute_group(struct device *dev, -- struct device_attribute *attrs, -- struct fw_attribute_group *group) -+static void init_fw_attribute_group(struct device *dev, -+ struct device_attribute *attrs, -+ struct fw_attribute_group *group) - { - struct device_attribute *attr; - int i, j; -@@ -319,9 +319,8 @@ init_fw_attribute_group(struct device *d - dev->groups = group->groups; - } - --static ssize_t --modalias_show(struct device *dev, -- struct device_attribute *attr, char *buf) -+static ssize_t modalias_show(struct device *dev, -+ struct device_attribute *attr, char *buf) - { - struct fw_unit *unit = fw_unit(dev); - int length; -@@ -332,9 +331,8 @@ modalias_show(struct device *dev, - return length + 1; - } - --static ssize_t --rom_index_show(struct device *dev, -- struct device_attribute *attr, char *buf) -+static ssize_t rom_index_show(struct device *dev, -+ struct device_attribute *attr, char *buf) - { - struct fw_device *device = fw_device(dev->parent); - struct fw_unit *unit = fw_unit(dev); -@@ -349,8 +347,8 @@ static struct device_attribute fw_unit_a - __ATTR_NULL, - }; - --static ssize_t --config_rom_show(struct device *dev, struct device_attribute *attr, char *buf) -+static ssize_t config_rom_show(struct device *dev, -+ struct device_attribute *attr, char *buf) - { - struct fw_device *device = fw_device(dev); - size_t length; -@@ -363,8 +361,8 @@ config_rom_show(struct device *dev, stru - return length; - } - --static ssize_t --guid_show(struct device *dev, struct device_attribute *attr, char *buf) -+static ssize_t guid_show(struct device *dev, -+ struct device_attribute *attr, char *buf) - { - struct fw_device *device = fw_device(dev); - int ret; -@@ -383,8 +381,8 @@ static struct device_attribute fw_device - __ATTR_NULL, - }; - --static int --read_rom(struct fw_device *device, int generation, int index, u32 *data) -+static int read_rom(struct fw_device *device, -+ int generation, int index, u32 *data) - { - int rcode; - -@@ -1004,6 +1002,7 @@ void fw_node_event(struct fw_card *card, - device->node = fw_node_get(node); - device->node_id = node->node_id; - device->generation = card->generation; -+ mutex_init(&device->client_list_mutex); - INIT_LIST_HEAD(&device->client_list); - - /* -diff -Naurp linux-2.6-git/drivers/firewire/fw-device.h firewire-git/drivers/firewire/fw-device.h ---- linux-2.6-git/drivers/firewire/fw-device.h 2009-01-30 13:39:02.989651512 -0500 -+++ firewire-git/drivers/firewire/fw-device.h 2009-01-30 13:35:51.860646788 -0500 -@@ -23,6 +23,7 @@ - #include - #include - #include -+#include - #include - - enum fw_device_state { -@@ -64,7 +65,10 @@ struct fw_device { - bool cmc; - struct fw_card *card; - struct device device; -+ -+ struct mutex client_list_mutex; - struct list_head client_list; -+ - u32 *config_rom; - size_t config_rom_length; - int config_rom_retries; -@@ -176,8 +180,7 @@ struct fw_driver { - const struct fw_device_id *id_table; - }; - --static inline struct fw_driver * --fw_driver(struct device_driver *drv) -+static inline struct fw_driver *fw_driver(struct device_driver *drv) - { - return container_of(drv, struct fw_driver, driver); - } -diff -Naurp linux-2.6-git/drivers/firewire/fw-iso.c firewire-git/drivers/firewire/fw-iso.c ---- linux-2.6-git/drivers/firewire/fw-iso.c 2008-11-04 11:18:33.000000000 -0500 -+++ firewire-git/drivers/firewire/fw-iso.c 2009-01-30 13:35:51.860646788 -0500 -@@ -1,5 +1,7 @@ - /* -- * Isochronous IO functionality -+ * Isochronous I/O functionality: -+ * - Isochronous DMA context management -+ * - Isochronous bus resource management (channels, bandwidth), client side - * - * Copyright (C) 2006 Kristian Hoegsberg - * -@@ -18,21 +20,25 @@ - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - --#include --#include - #include --#include -+#include -+#include -+#include - #include -+#include -+#include - --#include "fw-transaction.h" - #include "fw-topology.h" --#include "fw-device.h" -+#include "fw-transaction.h" - --int --fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card, -- int page_count, enum dma_data_direction direction) -+/* -+ * Isochronous DMA context management -+ */ -+ -+int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card, -+ int page_count, enum dma_data_direction direction) - { -- int i, j, retval = -ENOMEM; -+ int i, j; - dma_addr_t address; - - buffer->page_count = page_count; -@@ -69,19 +75,19 @@ fw_iso_buffer_init(struct fw_iso_buffer - kfree(buffer->pages); - out: - buffer->pages = NULL; -- return retval; -+ return -ENOMEM; - } - - int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma) - { - unsigned long uaddr; -- int i, retval; -+ int i, ret; - - uaddr = vma->vm_start; - for (i = 0; i < buffer->page_count; i++) { -- retval = vm_insert_page(vma, uaddr, buffer->pages[i]); -- if (retval) -- return retval; -+ ret = vm_insert_page(vma, uaddr, buffer->pages[i]); -+ if (ret) -+ return ret; - uaddr += PAGE_SIZE; - } - -@@ -105,14 +111,14 @@ void fw_iso_buffer_destroy(struct fw_iso - buffer->pages = NULL; - } - --struct fw_iso_context * --fw_iso_context_create(struct fw_card *card, int type, -- int channel, int speed, size_t header_size, -- fw_iso_callback_t callback, void *callback_data) -+struct fw_iso_context *fw_iso_context_create(struct fw_card *card, -+ int type, int channel, int speed, size_t header_size, -+ fw_iso_callback_t callback, void *callback_data) - { - struct fw_iso_context *ctx; - -- ctx = card->driver->allocate_iso_context(card, type, header_size); -+ ctx = card->driver->allocate_iso_context(card, -+ type, channel, header_size); - if (IS_ERR(ctx)) - return ctx; - -@@ -134,25 +140,186 @@ void fw_iso_context_destroy(struct fw_is - card->driver->free_iso_context(ctx); - } - --int --fw_iso_context_start(struct fw_iso_context *ctx, int cycle, int sync, int tags) -+int fw_iso_context_start(struct fw_iso_context *ctx, -+ int cycle, int sync, int tags) - { - return ctx->card->driver->start_iso(ctx, cycle, sync, tags); - } - --int --fw_iso_context_queue(struct fw_iso_context *ctx, -- struct fw_iso_packet *packet, -- struct fw_iso_buffer *buffer, -- unsigned long payload) -+int fw_iso_context_queue(struct fw_iso_context *ctx, -+ struct fw_iso_packet *packet, -+ struct fw_iso_buffer *buffer, -+ unsigned long payload) - { - struct fw_card *card = ctx->card; - - return card->driver->queue_iso(ctx, packet, buffer, payload); - } - --int --fw_iso_context_stop(struct fw_iso_context *ctx) -+int fw_iso_context_stop(struct fw_iso_context *ctx) - { - return ctx->card->driver->stop_iso(ctx); - } -+ -+/* -+ * Isochronous bus resource management (channels, bandwidth), client side -+ */ -+ -+static int manage_bandwidth(struct fw_card *card, int irm_id, int generation, -+ int bandwidth, bool allocate) -+{ -+ __be32 data[2]; -+ int try, new, old = allocate ? BANDWIDTH_AVAILABLE_INITIAL : 0; -+ -+ /* -+ * On a 1394a IRM with low contention, try < 1 is enough. -+ * On a 1394-1995 IRM, we need at least try < 2. -+ * Let's just do try < 5. -+ */ -+ for (try = 0; try < 5; try++) { -+ new = allocate ? old - bandwidth : old + bandwidth; -+ if (new < 0 || new > BANDWIDTH_AVAILABLE_INITIAL) -+ break; -+ -+ data[0] = cpu_to_be32(old); -+ data[1] = cpu_to_be32(new); -+ switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, -+ irm_id, generation, SCODE_100, -+ CSR_REGISTER_BASE + CSR_BANDWIDTH_AVAILABLE, -+ data, sizeof(data))) { -+ case RCODE_GENERATION: -+ /* A generation change frees all bandwidth. */ -+ return allocate ? -EAGAIN : bandwidth; -+ -+ case RCODE_COMPLETE: -+ if (be32_to_cpup(data) == old) -+ return bandwidth; -+ -+ old = be32_to_cpup(data); -+ /* Fall through. */ -+ } -+ } -+ -+ return -EIO; -+} -+ -+static int manage_channel(struct fw_card *card, int irm_id, int generation, -+ u32 channels_mask, u64 offset, bool allocate) -+{ -+ __be32 data[2], c, all, old; -+ int i, retry = 5; -+ -+ old = all = allocate ? cpu_to_be32(~0) : 0; -+ -+ for (i = 0; i < 32; i++) { -+ if (!(channels_mask & 1 << i)) -+ continue; -+ -+ c = cpu_to_be32(1 << (31 - i)); -+ if ((old & c) != (all & c)) -+ continue; -+ -+ data[0] = old; -+ data[1] = old ^ c; -+ switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, -+ irm_id, generation, SCODE_100, -+ offset, data, sizeof(data))) { -+ case RCODE_GENERATION: -+ /* A generation change frees all channels. */ -+ return allocate ? -EAGAIN : i; -+ -+ case RCODE_COMPLETE: -+ if (data[0] == old) -+ return i; -+ -+ old = data[0]; -+ -+ /* Is the IRM 1394a-2000 compliant? */ -+ if ((data[0] & c) == (data[1] & c)) -+ continue; -+ -+ /* 1394-1995 IRM, fall through to retry. */ -+ default: -+ if (retry--) -+ i--; -+ } -+ } -+ -+ return -EIO; -+} -+ -+static void deallocate_channel(struct fw_card *card, int irm_id, -+ int generation, int channel) -+{ -+ u32 mask; -+ u64 offset; -+ -+ mask = channel < 32 ? 1 << channel : 1 << (channel - 32); -+ offset = channel < 32 ? CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI : -+ CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO; -+ -+ manage_channel(card, irm_id, generation, mask, offset, false); -+} -+ -+/** -+ * fw_iso_resource_manage - Allocate or deallocate a channel and/or bandwidth -+ * -+ * In parameters: card, generation, channels_mask, bandwidth, allocate -+ * Out parameters: channel, bandwidth -+ * This function blocks (sleeps) during communication with the IRM. -+ * -+ * Allocates or deallocates at most one channel out of channels_mask. -+ * channels_mask is a bitfield with MSB for channel 63 and LSB for channel 0. -+ * (Note, the IRM's CHANNELS_AVAILABLE is a big-endian bitfield with MSB for -+ * channel 0 and LSB for channel 63.) -+ * Allocates or deallocates as many bandwidth allocation units as specified. -+ * -+ * Returns channel < 0 if no channel was allocated or deallocated. -+ * Returns bandwidth = 0 if no bandwidth was allocated or deallocated. -+ * -+ * If generation is stale, deallocations succeed but allocations fail with -+ * channel = -EAGAIN. -+ * -+ * If channel allocation fails, no bandwidth will be allocated either. -+ * If bandwidth allocation fails, no channel will be allocated either. -+ * But deallocations of channel and bandwidth are tried independently -+ * of each other's success. -+ */ -+void fw_iso_resource_manage(struct fw_card *card, int generation, -+ u64 channels_mask, int *channel, int *bandwidth, -+ bool allocate) -+{ -+ u32 channels_hi = channels_mask; /* channels 31...0 */ -+ u32 channels_lo = channels_mask >> 32; /* channels 63...32 */ -+ int irm_id, ret, c = -EINVAL; -+ -+ spin_lock_irq(&card->lock); -+ irm_id = card->irm_node->node_id; -+ spin_unlock_irq(&card->lock); -+ -+ if (channels_hi) -+ c = manage_channel(card, irm_id, generation, channels_hi, -+ CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI, allocate); -+ if (channels_lo && c < 0) { -+ c = manage_channel(card, irm_id, generation, channels_lo, -+ CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO, allocate); -+ if (c >= 0) -+ c += 32; -+ } -+ *channel = c; -+ -+ if (allocate && channels_mask != 0 && c < 0) -+ *bandwidth = 0; -+ -+ if (*bandwidth == 0) -+ return; -+ -+ ret = manage_bandwidth(card, irm_id, generation, *bandwidth, allocate); -+ if (ret < 0) -+ *bandwidth = 0; -+ -+ if (allocate && ret < 0 && c >= 0) { -+ deallocate_channel(card, irm_id, generation, c); -+ *channel = ret; -+ } -+} -diff -Naurp linux-2.6-git/drivers/firewire/fw-ohci.c firewire-git/drivers/firewire/fw-ohci.c ---- linux-2.6-git/drivers/firewire/fw-ohci.c 2009-01-30 13:39:02.990772025 -0500 -+++ firewire-git/drivers/firewire/fw-ohci.c 2009-01-30 13:35:51.861646907 -0500 -@@ -205,6 +205,7 @@ struct fw_ohci { - - u32 it_context_mask; - struct iso_context *it_context_list; -+ u64 ir_context_channels; - u32 ir_context_mask; - struct iso_context *ir_context_list; - }; -@@ -441,9 +442,8 @@ static inline void flush_writes(const st - reg_read(ohci, OHCI1394_Version); - } - --static int --ohci_update_phy_reg(struct fw_card *card, int addr, -- int clear_bits, int set_bits) -+static int ohci_update_phy_reg(struct fw_card *card, int addr, -+ int clear_bits, int set_bits) - { - struct fw_ohci *ohci = fw_ohci(card); - u32 val, old; -@@ -658,8 +658,8 @@ static void ar_context_tasklet(unsigned - } - } - --static int --ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci, u32 regs) -+static int ar_context_init(struct ar_context *ctx, -+ struct fw_ohci *ohci, u32 regs) - { - struct ar_buffer ab; - -@@ -690,8 +690,7 @@ static void ar_context_run(struct ar_con - flush_writes(ctx->ohci); - } - --static struct descriptor * --find_branch_descriptor(struct descriptor *d, int z) -+static struct descriptor *find_branch_descriptor(struct descriptor *d, int z) - { - int b, key; - -@@ -751,8 +750,7 @@ static void context_tasklet(unsigned lon - * Allocate a new buffer and add it to the list of free buffers for this - * context. Must be called with ohci->lock held. - */ --static int --context_add_buffer(struct context *ctx) -+static int context_add_buffer(struct context *ctx) - { - struct descriptor_buffer *desc; - dma_addr_t uninitialized_var(bus_addr); -@@ -781,9 +779,8 @@ context_add_buffer(struct context *ctx) - return 0; - } - --static int --context_init(struct context *ctx, struct fw_ohci *ohci, -- u32 regs, descriptor_callback_t callback) -+static int context_init(struct context *ctx, struct fw_ohci *ohci, -+ u32 regs, descriptor_callback_t callback) - { - ctx->ohci = ohci; - ctx->regs = regs; -@@ -814,8 +811,7 @@ context_init(struct context *ctx, struct - return 0; - } - --static void --context_release(struct context *ctx) -+static void context_release(struct context *ctx) - { - struct fw_card *card = &ctx->ohci->card; - struct descriptor_buffer *desc, *tmp; -@@ -827,8 +823,8 @@ context_release(struct context *ctx) - } - - /* Must be called with ohci->lock held */ --static struct descriptor * --context_get_descriptors(struct context *ctx, int z, dma_addr_t *d_bus) -+static struct descriptor *context_get_descriptors(struct context *ctx, -+ int z, dma_addr_t *d_bus) - { - struct descriptor *d = NULL; - struct descriptor_buffer *desc = ctx->buffer_tail; -@@ -912,8 +908,8 @@ struct driver_data { - * Must always be called with the ochi->lock held to ensure proper - * generation handling and locking around packet queue manipulation. - */ --static int --at_context_queue_packet(struct context *ctx, struct fw_packet *packet) -+static int at_context_queue_packet(struct context *ctx, -+ struct fw_packet *packet) - { - struct fw_ohci *ohci = ctx->ohci; - dma_addr_t d_bus, uninitialized_var(payload_bus); -@@ -1095,8 +1091,8 @@ static int handle_at_packet(struct conte - #define HEADER_GET_DATA_LENGTH(q) (((q) >> 16) & 0xffff) - #define HEADER_GET_EXTENDED_TCODE(q) (((q) >> 0) & 0xffff) - --static void --handle_local_rom(struct fw_ohci *ohci, struct fw_packet *packet, u32 csr) -+static void handle_local_rom(struct fw_ohci *ohci, -+ struct fw_packet *packet, u32 csr) - { - struct fw_packet response; - int tcode, length, i; -@@ -1122,8 +1118,8 @@ handle_local_rom(struct fw_ohci *ohci, s - fw_core_handle_response(&ohci->card, &response); - } - --static void --handle_local_lock(struct fw_ohci *ohci, struct fw_packet *packet, u32 csr) -+static void handle_local_lock(struct fw_ohci *ohci, -+ struct fw_packet *packet, u32 csr) - { - struct fw_packet response; - int tcode, length, ext_tcode, sel; -@@ -1164,8 +1160,7 @@ handle_local_lock(struct fw_ohci *ohci, - fw_core_handle_response(&ohci->card, &response); - } - --static void --handle_local_request(struct context *ctx, struct fw_packet *packet) -+static void handle_local_request(struct context *ctx, struct fw_packet *packet) - { - u64 offset; - u32 csr; -@@ -1205,11 +1200,10 @@ handle_local_request(struct context *ctx - } - } - --static void --at_context_transmit(struct context *ctx, struct fw_packet *packet) -+static void at_context_transmit(struct context *ctx, struct fw_packet *packet) - { - unsigned long flags; -- int retval; -+ int ret; - - spin_lock_irqsave(&ctx->ohci->lock, flags); - -@@ -1220,10 +1214,10 @@ at_context_transmit(struct context *ctx, - return; - } - -- retval = at_context_queue_packet(ctx, packet); -+ ret = at_context_queue_packet(ctx, packet); - spin_unlock_irqrestore(&ctx->ohci->lock, flags); - -- if (retval < 0) -+ if (ret < 0) - packet->callback(packet, &ctx->ohci->card, packet->ack); - - } -@@ -1590,12 +1584,12 @@ static int ohci_enable(struct fw_card *c - return 0; - } - --static int --ohci_set_config_rom(struct fw_card *card, u32 *config_rom, size_t length) -+static int ohci_set_config_rom(struct fw_card *card, -+ u32 *config_rom, size_t length) - { - struct fw_ohci *ohci; - unsigned long flags; -- int retval = -EBUSY; -+ int ret = -EBUSY; - __be32 *next_config_rom; - dma_addr_t uninitialized_var(next_config_rom_bus); - -@@ -1649,7 +1643,7 @@ ohci_set_config_rom(struct fw_card *card - - reg_write(ohci, OHCI1394_ConfigROMmap, - ohci->next_config_rom_bus); -- retval = 0; -+ ret = 0; - } - - spin_unlock_irqrestore(&ohci->lock, flags); -@@ -1661,13 +1655,13 @@ ohci_set_config_rom(struct fw_card *card - * controller could need to access it before the bus reset - * takes effect. - */ -- if (retval == 0) -+ if (ret == 0) - fw_core_initiate_bus_reset(&ohci->card, 1); - else - dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, - next_config_rom, next_config_rom_bus); - -- return retval; -+ return ret; - } - - static void ohci_send_request(struct fw_card *card, struct fw_packet *packet) -@@ -1689,7 +1683,7 @@ static int ohci_cancel_packet(struct fw_ - struct fw_ohci *ohci = fw_ohci(card); - struct context *ctx = &ohci->at_request_ctx; - struct driver_data *driver_data = packet->driver_data; -- int retval = -ENOENT; -+ int ret = -ENOENT; - - tasklet_disable(&ctx->tasklet); - -@@ -1704,23 +1698,22 @@ static int ohci_cancel_packet(struct fw_ - driver_data->packet = NULL; - packet->ack = RCODE_CANCELLED; - packet->callback(packet, &ohci->card, packet->ack); -- retval = 0; -- -+ ret = 0; - out: - tasklet_enable(&ctx->tasklet); - -- return retval; -+ return ret; - } - --static int --ohci_enable_phys_dma(struct fw_card *card, int node_id, int generation) -+static int ohci_enable_phys_dma(struct fw_card *card, -+ int node_id, int generation) - { - #ifdef CONFIG_FIREWIRE_OHCI_REMOTE_DMA - return 0; - #else - struct fw_ohci *ohci = fw_ohci(card); - unsigned long flags; -- int n, retval = 0; -+ int n, ret = 0; - - /* - * FIXME: Make sure this bitmask is cleared when we clear the busReset -@@ -1730,7 +1723,7 @@ ohci_enable_phys_dma(struct fw_card *car - spin_lock_irqsave(&ohci->lock, flags); - - if (ohci->generation != generation) { -- retval = -ESTALE; -+ ret = -ESTALE; - goto out; - } - -@@ -1748,12 +1741,12 @@ ohci_enable_phys_dma(struct fw_card *car - flush_writes(ohci); - out: - spin_unlock_irqrestore(&ohci->lock, flags); -- return retval; -+ -+ return ret; - #endif /* CONFIG_FIREWIRE_OHCI_REMOTE_DMA */ - } - --static u64 --ohci_get_bus_time(struct fw_card *card) -+static u64 ohci_get_bus_time(struct fw_card *card) - { - struct fw_ohci *ohci = fw_ohci(card); - u32 cycle_time; -@@ -1765,6 +1758,28 @@ ohci_get_bus_time(struct fw_card *card) - return bus_time; - } - -+static void copy_iso_headers(struct iso_context *ctx, void *p) -+{ -+ int i = ctx->header_length; -+ -+ if (i + ctx->base.header_size > PAGE_SIZE) -+ return; -+ -+ /* -+ * The iso header is byteswapped to little endian by -+ * the controller, but the remaining header quadlets -+ * are big endian. We want to present all the headers -+ * as big endian, so we have to swap the first quadlet. -+ */ -+ if (ctx->base.header_size > 0) -+ *(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4)); -+ if (ctx->base.header_size > 4) -+ *(u32 *) (ctx->header + i + 4) = __swab32(*(u32 *) p); -+ if (ctx->base.header_size > 8) -+ memcpy(ctx->header + i + 8, p + 8, ctx->base.header_size - 8); -+ ctx->header_length += ctx->base.header_size; -+} -+ - static int handle_ir_dualbuffer_packet(struct context *context, - struct descriptor *d, - struct descriptor *last) -@@ -1775,7 +1790,6 @@ static int handle_ir_dualbuffer_packet(s - __le32 *ir_header; - size_t header_length; - void *p, *end; -- int i; - - if (db->first_res_count != 0 && db->second_res_count != 0) { - if (ctx->excess_bytes <= le16_to_cpu(db->second_req_count)) { -@@ -1788,25 +1802,14 @@ static int handle_ir_dualbuffer_packet(s - header_length = le16_to_cpu(db->first_req_count) - - le16_to_cpu(db->first_res_count); - -- i = ctx->header_length; - p = db + 1; - end = p + header_length; -- while (p < end && i + ctx->base.header_size <= PAGE_SIZE) { -- /* -- * The iso header is byteswapped to little endian by -- * the controller, but the remaining header quadlets -- * are big endian. We want to present all the headers -- * as big endian, so we have to swap the first -- * quadlet. -- */ -- *(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4)); -- memcpy(ctx->header + i + 4, p + 8, ctx->base.header_size - 4); -- i += ctx->base.header_size; -+ while (p < end) { -+ copy_iso_headers(ctx, p); - ctx->excess_bytes += - (le32_to_cpu(*(__le32 *)(p + 4)) >> 16) & 0xffff; -- p += ctx->base.header_size + 4; -+ p += max(ctx->base.header_size, (size_t)8); - } -- ctx->header_length = i; - - ctx->excess_bytes -= le16_to_cpu(db->second_req_count) - - le16_to_cpu(db->second_res_count); -@@ -1832,7 +1835,6 @@ static int handle_ir_packet_per_buffer(s - struct descriptor *pd; - __le32 *ir_header; - void *p; -- int i; - - for (pd = d; pd <= last; pd++) { - if (pd->transfer_status) -@@ -1842,21 +1844,8 @@ static int handle_ir_packet_per_buffer(s - /* Descriptor(s) not done yet, stop iteration */ - return 0; - -- i = ctx->header_length; -- p = last + 1; -- -- if (ctx->base.header_size > 0 && -- i + ctx->base.header_size <= PAGE_SIZE) { -- /* -- * The iso header is byteswapped to little endian by -- * the controller, but the remaining header quadlets -- * are big endian. We want to present all the headers -- * as big endian, so we have to swap the first quadlet. -- */ -- *(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4)); -- memcpy(ctx->header + i + 4, p + 8, ctx->base.header_size - 4); -- ctx->header_length += ctx->base.header_size; -- } -+ p = last + 1; -+ copy_iso_headers(ctx, p); - - if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) { - ir_header = (__le32 *) p; -@@ -1888,21 +1877,24 @@ static int handle_it_packet(struct conte - return 1; - } - --static struct fw_iso_context * --ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size) -+static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card, -+ int type, int channel, size_t header_size) - { - struct fw_ohci *ohci = fw_ohci(card); - struct iso_context *ctx, *list; - descriptor_callback_t callback; -+ u64 *channels, dont_care = ~0ULL; - u32 *mask, regs; - unsigned long flags; -- int index, retval = -ENOMEM; -+ int index, ret = -ENOMEM; - - if (type == FW_ISO_CONTEXT_TRANSMIT) { -+ channels = &dont_care; - mask = &ohci->it_context_mask; - list = ohci->it_context_list; - callback = handle_it_packet; - } else { -+ channels = &ohci->ir_context_channels; - mask = &ohci->ir_context_mask; - list = ohci->ir_context_list; - if (ohci->use_dualbuffer) -@@ -1912,9 +1904,11 @@ ohci_allocate_iso_context(struct fw_card - } - - spin_lock_irqsave(&ohci->lock, flags); -- index = ffs(*mask) - 1; -- if (index >= 0) -+ index = *channels & 1ULL << channel ? ffs(*mask) - 1 : -1; -+ if (index >= 0) { -+ *channels &= ~(1ULL << channel); - *mask &= ~(1 << index); -+ } - spin_unlock_irqrestore(&ohci->lock, flags); - - if (index < 0) -@@ -1932,8 +1926,8 @@ ohci_allocate_iso_context(struct fw_card - if (ctx->header == NULL) - goto out; - -- retval = context_init(&ctx->context, ohci, regs, callback); -- if (retval < 0) -+ ret = context_init(&ctx->context, ohci, regs, callback); -+ if (ret < 0) - goto out_with_header; - - return &ctx->base; -@@ -1945,7 +1939,7 @@ ohci_allocate_iso_context(struct fw_card - *mask |= 1 << index; - spin_unlock_irqrestore(&ohci->lock, flags); - -- return ERR_PTR(retval); -+ return ERR_PTR(ret); - } - - static int ohci_start_iso(struct fw_iso_context *base, -@@ -2024,16 +2018,16 @@ static void ohci_free_iso_context(struct - } else { - index = ctx - ohci->ir_context_list; - ohci->ir_context_mask |= 1 << index; -+ ohci->ir_context_channels |= 1ULL << base->channel; - } - - spin_unlock_irqrestore(&ohci->lock, flags); - } - --static int --ohci_queue_iso_transmit(struct fw_iso_context *base, -- struct fw_iso_packet *packet, -- struct fw_iso_buffer *buffer, -- unsigned long payload) -+static int ohci_queue_iso_transmit(struct fw_iso_context *base, -+ struct fw_iso_packet *packet, -+ struct fw_iso_buffer *buffer, -+ unsigned long payload) - { - struct iso_context *ctx = container_of(base, struct iso_context, base); - struct descriptor *d, *last, *pd; -@@ -2128,11 +2122,10 @@ ohci_queue_iso_transmit(struct fw_iso_co - return 0; - } - --static int --ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base, -- struct fw_iso_packet *packet, -- struct fw_iso_buffer *buffer, -- unsigned long payload) -+static int ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base, -+ struct fw_iso_packet *packet, -+ struct fw_iso_buffer *buffer, -+ unsigned long payload) - { - struct iso_context *ctx = container_of(base, struct iso_context, base); - struct db_descriptor *db = NULL; -@@ -2151,11 +2144,11 @@ ohci_queue_iso_receive_dualbuffer(struct - z = 2; - - /* -- * The OHCI controller puts the status word in the header -- * buffer too, so we need 4 extra bytes per packet. -+ * The OHCI controller puts the isochronous header and trailer in the -+ * buffer, so we need at least 8 bytes. - */ - packet_count = p->header_length / ctx->base.header_size; -- header_size = packet_count * (ctx->base.header_size + 4); -+ header_size = packet_count * max(ctx->base.header_size, (size_t)8); - - /* Get header size in number of descriptors. */ - header_z = DIV_ROUND_UP(header_size, sizeof(*d)); -@@ -2173,7 +2166,8 @@ ohci_queue_iso_receive_dualbuffer(struct - db = (struct db_descriptor *) d; - db->control = cpu_to_le16(DESCRIPTOR_STATUS | - DESCRIPTOR_BRANCH_ALWAYS); -- db->first_size = cpu_to_le16(ctx->base.header_size + 4); -+ db->first_size = -+ cpu_to_le16(max(ctx->base.header_size, (size_t)8)); - if (p->skip && rest == p->payload_length) { - db->control |= cpu_to_le16(DESCRIPTOR_WAIT); - db->first_req_count = db->first_size; -@@ -2208,11 +2202,10 @@ ohci_queue_iso_receive_dualbuffer(struct - return 0; - } - --static int --ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base, -- struct fw_iso_packet *packet, -- struct fw_iso_buffer *buffer, -- unsigned long payload) -+static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base, -+ struct fw_iso_packet *packet, -+ struct fw_iso_buffer *buffer, -+ unsigned long payload) - { - struct iso_context *ctx = container_of(base, struct iso_context, base); - struct descriptor *d = NULL, *pd = NULL; -@@ -2223,11 +2216,11 @@ ohci_queue_iso_receive_packet_per_buffer - int page, offset, packet_count, header_size, payload_per_buffer; - - /* -- * The OHCI controller puts the status word in the -- * buffer too, so we need 4 extra bytes per packet. -+ * The OHCI controller puts the isochronous header and trailer in the -+ * buffer, so we need at least 8 bytes. - */ - packet_count = p->header_length / ctx->base.header_size; -- header_size = ctx->base.header_size + 4; -+ header_size = max(ctx->base.header_size, (size_t)8); - - /* Get header size in number of descriptors. */ - header_z = DIV_ROUND_UP(header_size, sizeof(*d)); -@@ -2286,29 +2279,27 @@ ohci_queue_iso_receive_packet_per_buffer - return 0; - } - --static int --ohci_queue_iso(struct fw_iso_context *base, -- struct fw_iso_packet *packet, -- struct fw_iso_buffer *buffer, -- unsigned long payload) -+static int ohci_queue_iso(struct fw_iso_context *base, -+ struct fw_iso_packet *packet, -+ struct fw_iso_buffer *buffer, -+ unsigned long payload) - { - struct iso_context *ctx = container_of(base, struct iso_context, base); - unsigned long flags; -- int retval; -+ int ret; - - spin_lock_irqsave(&ctx->context.ohci->lock, flags); - if (base->type == FW_ISO_CONTEXT_TRANSMIT) -- retval = ohci_queue_iso_transmit(base, packet, buffer, payload); -+ ret = ohci_queue_iso_transmit(base, packet, buffer, payload); - else if (ctx->context.ohci->use_dualbuffer) -- retval = ohci_queue_iso_receive_dualbuffer(base, packet, -- buffer, payload); -+ ret = ohci_queue_iso_receive_dualbuffer(base, packet, -+ buffer, payload); - else -- retval = ohci_queue_iso_receive_packet_per_buffer(base, packet, -- buffer, -- payload); -+ ret = ohci_queue_iso_receive_packet_per_buffer(base, packet, -+ buffer, payload); - spin_unlock_irqrestore(&ctx->context.ohci->lock, flags); - -- return retval; -+ return ret; - } - - static const struct fw_card_driver ohci_driver = { -@@ -2357,8 +2348,8 @@ static void ohci_pmac_off(struct pci_dev - #define ohci_pmac_off(dev) - #endif /* CONFIG_PPC_PMAC */ - --static int __devinit --pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) -+static int __devinit pci_probe(struct pci_dev *dev, -+ const struct pci_device_id *ent) - { - struct fw_ohci *ohci; - u32 bus_options, max_receive, link_speed, version; -@@ -2440,6 +2431,7 @@ pci_probe(struct pci_dev *dev, const str - ohci->it_context_list = kzalloc(size, GFP_KERNEL); - - reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0); -+ ohci->ir_context_channels = ~0ULL; - ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet); - reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0); - size = sizeof(struct iso_context) * hweight32(ohci->ir_context_mask); -diff -Naurp linux-2.6-git/drivers/firewire/fw-sbp2.c firewire-git/drivers/firewire/fw-sbp2.c ---- linux-2.6-git/drivers/firewire/fw-sbp2.c 2009-01-30 13:39:02.991771976 -0500 -+++ firewire-git/drivers/firewire/fw-sbp2.c 2009-01-30 13:35:51.861646907 -0500 -@@ -392,20 +392,18 @@ static const struct { - } - }; - --static void --free_orb(struct kref *kref) -+static void free_orb(struct kref *kref) - { - struct sbp2_orb *orb = container_of(kref, struct sbp2_orb, kref); - - kfree(orb); - } - --static void --sbp2_status_write(struct fw_card *card, struct fw_request *request, -- int tcode, int destination, int source, -- int generation, int speed, -- unsigned long long offset, -- void *payload, size_t length, void *callback_data) -+static void sbp2_status_write(struct fw_card *card, struct fw_request *request, -+ int tcode, int destination, int source, -+ int generation, int speed, -+ unsigned long long offset, -+ void *payload, size_t length, void *callback_data) - { - struct sbp2_logical_unit *lu = callback_data; - struct sbp2_orb *orb; -@@ -451,9 +449,8 @@ sbp2_status_write(struct fw_card *card, - fw_send_response(card, request, RCODE_COMPLETE); - } - --static void --complete_transaction(struct fw_card *card, int rcode, -- void *payload, size_t length, void *data) -+static void complete_transaction(struct fw_card *card, int rcode, -+ void *payload, size_t length, void *data) - { - struct sbp2_orb *orb = data; - unsigned long flags; -@@ -482,9 +479,8 @@ complete_transaction(struct fw_card *car - kref_put(&orb->kref, free_orb); - } - --static void --sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu, -- int node_id, int generation, u64 offset) -+static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu, -+ int node_id, int generation, u64 offset) - { - struct fw_device *device = fw_device(lu->tgt->unit->device.parent); - unsigned long flags; -@@ -531,8 +527,8 @@ static int sbp2_cancel_orbs(struct sbp2_ - return retval; - } - --static void --complete_management_orb(struct sbp2_orb *base_orb, struct sbp2_status *status) -+static void complete_management_orb(struct sbp2_orb *base_orb, -+ struct sbp2_status *status) - { - struct sbp2_management_orb *orb = - container_of(base_orb, struct sbp2_management_orb, base); -@@ -542,10 +538,9 @@ complete_management_orb(struct sbp2_orb - complete(&orb->done); - } - --static int --sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, -- int generation, int function, int lun_or_login_id, -- void *response) -+static int sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, -+ int generation, int function, -+ int lun_or_login_id, void *response) - { - struct fw_device *device = fw_device(lu->tgt->unit->device.parent); - struct sbp2_management_orb *orb; -@@ -652,9 +647,8 @@ static void sbp2_agent_reset(struct sbp2 - &d, sizeof(d)); - } - --static void --complete_agent_reset_write_no_wait(struct fw_card *card, int rcode, -- void *payload, size_t length, void *data) -+static void complete_agent_reset_write_no_wait(struct fw_card *card, -+ int rcode, void *payload, size_t length, void *data) - { - kfree(data); - } -@@ -1299,8 +1293,7 @@ static void sbp2_unmap_scatterlist(struc - sizeof(orb->page_table), DMA_TO_DEVICE); - } - --static unsigned int --sbp2_status_to_sense_data(u8 *sbp2_status, u8 *sense_data) -+static unsigned int sbp2_status_to_sense_data(u8 *sbp2_status, u8 *sense_data) - { - int sam_status; - -@@ -1337,8 +1330,8 @@ sbp2_status_to_sense_data(u8 *sbp2_statu - } - } - --static void --complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status) -+static void complete_command_orb(struct sbp2_orb *base_orb, -+ struct sbp2_status *status) - { - struct sbp2_command_orb *orb = - container_of(base_orb, struct sbp2_command_orb, base); -@@ -1384,9 +1377,8 @@ complete_command_orb(struct sbp2_orb *ba - orb->done(orb->cmd); - } - --static int --sbp2_map_scatterlist(struct sbp2_command_orb *orb, struct fw_device *device, -- struct sbp2_logical_unit *lu) -+static int sbp2_map_scatterlist(struct sbp2_command_orb *orb, -+ struct fw_device *device, struct sbp2_logical_unit *lu) - { - struct scatterlist *sg = scsi_sglist(orb->cmd); - int i, n; -@@ -1584,9 +1576,8 @@ static int sbp2_scsi_abort(struct scsi_c - * This is the concatenation of target port identifier and logical unit - * identifier as per SAM-2...SAM-4 annex A. - */ --static ssize_t --sbp2_sysfs_ieee1394_id_show(struct device *dev, struct device_attribute *attr, -- char *buf) -+static ssize_t sbp2_sysfs_ieee1394_id_show(struct device *dev, -+ struct device_attribute *attr, char *buf) - { - struct scsi_device *sdev = to_scsi_device(dev); - struct sbp2_logical_unit *lu; -diff -Naurp linux-2.6-git/drivers/firewire/fw-topology.c firewire-git/drivers/firewire/fw-topology.c ---- linux-2.6-git/drivers/firewire/fw-topology.c 2009-01-30 13:39:02.991771976 -0500 -+++ firewire-git/drivers/firewire/fw-topology.c 2009-01-30 13:35:51.862647087 -0500 -@@ -314,9 +314,8 @@ typedef void (*fw_node_callback_t)(struc - struct fw_node * node, - struct fw_node * parent); - --static void --for_each_fw_node(struct fw_card *card, struct fw_node *root, -- fw_node_callback_t callback) -+static void for_each_fw_node(struct fw_card *card, struct fw_node *root, -+ fw_node_callback_t callback) - { - struct list_head list; - struct fw_node *node, *next, *child, *parent; -@@ -349,9 +348,8 @@ for_each_fw_node(struct fw_card *card, s - fw_node_put(node); - } - --static void --report_lost_node(struct fw_card *card, -- struct fw_node *node, struct fw_node *parent) -+static void report_lost_node(struct fw_card *card, -+ struct fw_node *node, struct fw_node *parent) - { - fw_node_event(card, node, FW_NODE_DESTROYED); - fw_node_put(node); -@@ -360,9 +358,8 @@ report_lost_node(struct fw_card *card, - card->bm_retries = 0; - } - --static void --report_found_node(struct fw_card *card, -- struct fw_node *node, struct fw_node *parent) -+static void report_found_node(struct fw_card *card, -+ struct fw_node *node, struct fw_node *parent) - { - int b_path = (node->phy_speed == SCODE_BETA); - -@@ -415,8 +412,7 @@ static void move_tree(struct fw_node *no - * found, lost or updated. Update the nodes in the card topology tree - * as we go. - */ --static void --update_tree(struct fw_card *card, struct fw_node *root) -+static void update_tree(struct fw_card *card, struct fw_node *root) - { - struct list_head list0, list1; - struct fw_node *node0, *node1, *next1; -@@ -497,8 +493,8 @@ update_tree(struct fw_card *card, struct - } - } - --static void --update_topology_map(struct fw_card *card, u32 *self_ids, int self_id_count) -+static void update_topology_map(struct fw_card *card, -+ u32 *self_ids, int self_id_count) - { - int node_count; - -@@ -510,10 +506,8 @@ update_topology_map(struct fw_card *card - fw_compute_block_crc(card->topology_map); - } - --void --fw_core_handle_bus_reset(struct fw_card *card, -- int node_id, int generation, -- int self_id_count, u32 * self_ids) -+void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation, -+ int self_id_count, u32 *self_ids) - { - struct fw_node *local_node; - unsigned long flags; -diff -Naurp linux-2.6-git/drivers/firewire/fw-topology.h firewire-git/drivers/firewire/fw-topology.h ---- linux-2.6-git/drivers/firewire/fw-topology.h 2008-11-04 11:18:33.000000000 -0500 -+++ firewire-git/drivers/firewire/fw-topology.h 2009-01-30 13:35:51.862647087 -0500 -@@ -19,6 +19,11 @@ - #ifndef __fw_topology_h - #define __fw_topology_h - -+#include -+#include -+ -+#include -+ - enum { - FW_NODE_CREATED, - FW_NODE_UPDATED, -@@ -51,26 +56,22 @@ struct fw_node { - struct fw_node *ports[0]; - }; - --static inline struct fw_node * --fw_node_get(struct fw_node *node) -+static inline struct fw_node *fw_node_get(struct fw_node *node) - { - atomic_inc(&node->ref_count); - - return node; - } - --static inline void --fw_node_put(struct fw_node *node) -+static inline void fw_node_put(struct fw_node *node) - { - if (atomic_dec_and_test(&node->ref_count)) - kfree(node); - } - --void --fw_destroy_nodes(struct fw_card *card); -- --int --fw_compute_block_crc(u32 *block); -+struct fw_card; -+void fw_destroy_nodes(struct fw_card *card); - -+int fw_compute_block_crc(u32 *block); - - #endif /* __fw_topology_h */ -diff -Naurp linux-2.6-git/drivers/firewire/fw-transaction.c firewire-git/drivers/firewire/fw-transaction.c ---- linux-2.6-git/drivers/firewire/fw-transaction.c 2009-01-30 13:39:02.991771976 -0500 -+++ firewire-git/drivers/firewire/fw-transaction.c 2009-01-30 13:35:51.862647087 -0500 -@@ -64,10 +64,9 @@ - #define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23)) - #define PHY_IDENTIFIER(id) ((id) << 30) - --static int --close_transaction(struct fw_transaction *transaction, -- struct fw_card *card, int rcode, -- u32 *payload, size_t length) -+static int close_transaction(struct fw_transaction *transaction, -+ struct fw_card *card, int rcode, -+ u32 *payload, size_t length) - { - struct fw_transaction *t; - unsigned long flags; -@@ -94,9 +93,8 @@ close_transaction(struct fw_transaction - * Only valid for transactions that are potentially pending (ie have - * been sent). - */ --int --fw_cancel_transaction(struct fw_card *card, -- struct fw_transaction *transaction) -+int fw_cancel_transaction(struct fw_card *card, -+ struct fw_transaction *transaction) - { - /* - * Cancel the packet transmission if it's still queued. That -@@ -116,9 +114,8 @@ fw_cancel_transaction(struct fw_card *ca - } - EXPORT_SYMBOL(fw_cancel_transaction); - --static void --transmit_complete_callback(struct fw_packet *packet, -- struct fw_card *card, int status) -+static void transmit_complete_callback(struct fw_packet *packet, -+ struct fw_card *card, int status) - { - struct fw_transaction *t = - container_of(packet, struct fw_transaction, packet); -@@ -151,8 +148,7 @@ transmit_complete_callback(struct fw_pac - } - } - --static void --fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, -+static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, - int destination_id, int source_id, int generation, int speed, - unsigned long long offset, void *payload, size_t length) - { -@@ -247,12 +243,10 @@ fw_fill_request(struct fw_packet *packet - * @param callback_data pointer to arbitrary data, which will be - * passed to the callback - */ --void --fw_send_request(struct fw_card *card, struct fw_transaction *t, -- int tcode, int destination_id, int generation, int speed, -- unsigned long long offset, -- void *payload, size_t length, -- fw_transaction_callback_t callback, void *callback_data) -+void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode, -+ int destination_id, int generation, int speed, -+ unsigned long long offset, void *payload, size_t length, -+ fw_transaction_callback_t callback, void *callback_data) - { - unsigned long flags; - int tlabel; -@@ -322,8 +316,8 @@ static void transaction_callback(struct - * Returns the RCODE. - */ - int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, -- int generation, int speed, unsigned long long offset, -- void *data, size_t length) -+ int generation, int speed, unsigned long long offset, -+ void *data, size_t length) - { - struct transaction_callback_data d; - struct fw_transaction t; -@@ -399,9 +393,8 @@ void fw_flush_transactions(struct fw_car - } - } - --static struct fw_address_handler * --lookup_overlapping_address_handler(struct list_head *list, -- unsigned long long offset, size_t length) -+static struct fw_address_handler *lookup_overlapping_address_handler( -+ struct list_head *list, unsigned long long offset, size_t length) - { - struct fw_address_handler *handler; - -@@ -414,9 +407,8 @@ lookup_overlapping_address_handler(struc - return NULL; - } - --static struct fw_address_handler * --lookup_enclosing_address_handler(struct list_head *list, -- unsigned long long offset, size_t length) -+static struct fw_address_handler *lookup_enclosing_address_handler( -+ struct list_head *list, unsigned long long offset, size_t length) - { - struct fw_address_handler *handler; - -@@ -449,36 +441,44 @@ const struct fw_address_region fw_unit_s - #endif /* 0 */ - - /** -- * Allocate a range of addresses in the node space of the OHCI -- * controller. When a request is received that falls within the -- * specified address range, the specified callback is invoked. The -- * parameters passed to the callback give the details of the -- * particular request. -+ * fw_core_add_address_handler - register for incoming requests -+ * @handler: callback -+ * @region: region in the IEEE 1212 node space address range -+ * -+ * region->start, ->end, and handler->length have to be quadlet-aligned. -+ * -+ * When a request is received that falls within the specified address range, -+ * the specified callback is invoked. The parameters passed to the callback -+ * give the details of the particular request. - * - * Return value: 0 on success, non-zero otherwise. - * The start offset of the handler's address region is determined by - * fw_core_add_address_handler() and is returned in handler->offset. -- * The offset is quadlet-aligned. - */ --int --fw_core_add_address_handler(struct fw_address_handler *handler, -- const struct fw_address_region *region) -+int fw_core_add_address_handler(struct fw_address_handler *handler, -+ const struct fw_address_region *region) - { - struct fw_address_handler *other; - unsigned long flags; - int ret = -EBUSY; - -+ if (region->start & 0xffff000000000003ULL || -+ region->end & 0xffff000000000003ULL || -+ region->start >= region->end || -+ handler->length & 3 || -+ handler->length == 0) -+ return -EINVAL; -+ - spin_lock_irqsave(&address_handler_lock, flags); - -- handler->offset = roundup(region->start, 4); -+ handler->offset = region->start; - while (handler->offset + handler->length <= region->end) { - other = - lookup_overlapping_address_handler(&address_handler_list, - handler->offset, - handler->length); - if (other != NULL) { -- handler->offset = -- roundup(other->offset + other->length, 4); -+ handler->offset += other->length; - } else { - list_add_tail(&handler->link, &address_handler_list); - ret = 0; -@@ -493,12 +493,7 @@ fw_core_add_address_handler(struct fw_ad - EXPORT_SYMBOL(fw_core_add_address_handler); - - /** -- * Deallocate a range of addresses allocated with fw_allocate. This -- * will call the associated callback one last time with a the special -- * tcode TCODE_DEALLOCATE, to let the client destroy the registered -- * callback data. For convenience, the callback parameters offset and -- * length are set to the start and the length respectively for the -- * deallocated region, payload is set to NULL. -+ * fw_core_remove_address_handler - unregister an address handler - */ - void fw_core_remove_address_handler(struct fw_address_handler *handler) - { -@@ -518,9 +513,8 @@ struct fw_request { - u32 data[0]; - }; - --static void --free_response_callback(struct fw_packet *packet, -- struct fw_card *card, int status) -+static void free_response_callback(struct fw_packet *packet, -+ struct fw_card *card, int status) - { - struct fw_request *request; - -@@ -528,9 +522,8 @@ free_response_callback(struct fw_packet - kfree(request); - } - --void --fw_fill_response(struct fw_packet *response, u32 *request_header, -- int rcode, void *payload, size_t length) -+void fw_fill_response(struct fw_packet *response, u32 *request_header, -+ int rcode, void *payload, size_t length) - { - int tcode, tlabel, extended_tcode, source, destination; - -@@ -588,8 +581,7 @@ fw_fill_response(struct fw_packet *respo - } - EXPORT_SYMBOL(fw_fill_response); - --static struct fw_request * --allocate_request(struct fw_packet *p) -+static struct fw_request *allocate_request(struct fw_packet *p) - { - struct fw_request *request; - u32 *data, length; -@@ -649,8 +641,8 @@ allocate_request(struct fw_packet *p) - return request; - } - --void --fw_send_response(struct fw_card *card, struct fw_request *request, int rcode) -+void fw_send_response(struct fw_card *card, -+ struct fw_request *request, int rcode) - { - /* unified transaction or broadcast transaction: don't respond */ - if (request->ack != ACK_PENDING || -@@ -670,8 +662,7 @@ fw_send_response(struct fw_card *card, s - } - EXPORT_SYMBOL(fw_send_response); - --void --fw_core_handle_request(struct fw_card *card, struct fw_packet *p) -+void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) - { - struct fw_address_handler *handler; - struct fw_request *request; -@@ -719,8 +710,7 @@ fw_core_handle_request(struct fw_card *c - } - EXPORT_SYMBOL(fw_core_handle_request); - --void --fw_core_handle_response(struct fw_card *card, struct fw_packet *p) -+void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) - { - struct fw_transaction *t; - unsigned long flags; -@@ -793,12 +783,10 @@ static const struct fw_address_region to - { .start = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP, - .end = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP_END, }; - --static void --handle_topology_map(struct fw_card *card, struct fw_request *request, -- int tcode, int destination, int source, -- int generation, int speed, -- unsigned long long offset, -- void *payload, size_t length, void *callback_data) -+static void handle_topology_map(struct fw_card *card, struct fw_request *request, -+ int tcode, int destination, int source, int generation, -+ int speed, unsigned long long offset, -+ void *payload, size_t length, void *callback_data) - { - int i, start, end; - __be32 *map; -@@ -832,12 +820,10 @@ static const struct fw_address_region re - { .start = CSR_REGISTER_BASE, - .end = CSR_REGISTER_BASE | CSR_CONFIG_ROM, }; - --static void --handle_registers(struct fw_card *card, struct fw_request *request, -- int tcode, int destination, int source, -- int generation, int speed, -- unsigned long long offset, -- void *payload, size_t length, void *callback_data) -+static void handle_registers(struct fw_card *card, struct fw_request *request, -+ int tcode, int destination, int source, int generation, -+ int speed, unsigned long long offset, -+ void *payload, size_t length, void *callback_data) - { - int reg = offset & ~CSR_REGISTER_BASE; - unsigned long long bus_time; -@@ -939,11 +925,11 @@ static struct fw_descriptor model_id_des - - static int __init fw_core_init(void) - { -- int retval; -+ int ret; - -- retval = bus_register(&fw_bus_type); -- if (retval < 0) -- return retval; -+ ret = bus_register(&fw_bus_type); -+ if (ret < 0) -+ return ret; - - fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops); - if (fw_cdev_major < 0) { -@@ -951,19 +937,10 @@ static int __init fw_core_init(void) - return fw_cdev_major; - } - -- retval = fw_core_add_address_handler(&topology_map, -- &topology_map_region); -- BUG_ON(retval < 0); -- -- retval = fw_core_add_address_handler(®isters, -- ®isters_region); -- BUG_ON(retval < 0); -- -- /* Add the vendor textual descriptor. */ -- retval = fw_core_add_descriptor(&vendor_id_descriptor); -- BUG_ON(retval < 0); -- retval = fw_core_add_descriptor(&model_id_descriptor); -- BUG_ON(retval < 0); -+ fw_core_add_address_handler(&topology_map, &topology_map_region); -+ fw_core_add_address_handler(®isters, ®isters_region); -+ fw_core_add_descriptor(&vendor_id_descriptor); -+ fw_core_add_descriptor(&model_id_descriptor); - - return 0; - } -diff -Naurp linux-2.6-git/drivers/firewire/fw-transaction.h firewire-git/drivers/firewire/fw-transaction.h ---- linux-2.6-git/drivers/firewire/fw-transaction.h 2009-01-30 13:39:02.992772636 -0500 -+++ firewire-git/drivers/firewire/fw-transaction.h 2009-01-30 13:35:51.862647087 -0500 -@@ -82,14 +82,14 @@ - #define CSR_SPEED_MAP 0x2000 - #define CSR_SPEED_MAP_END 0x3000 - -+#define BANDWIDTH_AVAILABLE_INITIAL 4915 - #define BROADCAST_CHANNEL_INITIAL (1 << 31 | 31) - #define BROADCAST_CHANNEL_VALID (1 << 30) - - #define fw_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, ## args) - #define fw_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args) - --static inline void --fw_memcpy_from_be32(void *_dst, void *_src, size_t size) -+static inline void fw_memcpy_from_be32(void *_dst, void *_src, size_t size) - { - u32 *dst = _dst; - __be32 *src = _src; -@@ -99,8 +99,7 @@ fw_memcpy_from_be32(void *_dst, void *_s - dst[i] = be32_to_cpu(src[i]); - } - --static inline void --fw_memcpy_to_be32(void *_dst, void *_src, size_t size) -+static inline void fw_memcpy_to_be32(void *_dst, void *_src, size_t size) - { - fw_memcpy_from_be32(_dst, _src, size); - } -@@ -125,8 +124,7 @@ typedef void (*fw_packet_callback_t)(str - struct fw_card *card, int status); - - typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode, -- void *data, -- size_t length, -+ void *data, size_t length, - void *callback_data); - - /* -@@ -141,12 +139,6 @@ typedef void (*fw_address_callback_t)(st - void *data, size_t length, - void *callback_data); - --typedef void (*fw_bus_reset_callback_t)(struct fw_card *handle, -- int node_id, int generation, -- u32 *self_ids, -- int self_id_count, -- void *callback_data); -- - struct fw_packet { - int speed; - int generation; -@@ -187,12 +179,6 @@ struct fw_transaction { - void *callback_data; - }; - --static inline struct fw_packet * --fw_packet(struct list_head *l) --{ -- return list_entry(l, struct fw_packet, link); --} -- - struct fw_address_handler { - u64 offset; - size_t length; -@@ -201,7 +187,6 @@ struct fw_address_handler { - struct list_head link; - }; - -- - struct fw_address_region { - u64 start; - u64 end; -@@ -315,10 +300,8 @@ struct fw_iso_packet { - struct fw_iso_context; - - typedef void (*fw_iso_callback_t)(struct fw_iso_context *context, -- u32 cycle, -- size_t header_length, -- void *header, -- void *data); -+ u32 cycle, size_t header_length, -+ void *header, void *data); - - /* - * An iso buffer is just a set of pages mapped for DMA in the -@@ -344,36 +327,25 @@ struct fw_iso_context { - void *callback_data; - }; - --int --fw_iso_buffer_init(struct fw_iso_buffer *buffer, -- struct fw_card *card, -- int page_count, -- enum dma_data_direction direction); --int --fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma); --void --fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, struct fw_card *card); -- --struct fw_iso_context * --fw_iso_context_create(struct fw_card *card, int type, -- int channel, int speed, size_t header_size, -- fw_iso_callback_t callback, void *callback_data); -- --void --fw_iso_context_destroy(struct fw_iso_context *ctx); -- --int --fw_iso_context_queue(struct fw_iso_context *ctx, -- struct fw_iso_packet *packet, -- struct fw_iso_buffer *buffer, -- unsigned long payload); -- --int --fw_iso_context_start(struct fw_iso_context *ctx, -- int cycle, int sync, int tags); -+int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card, -+ int page_count, enum dma_data_direction direction); -+int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma); -+void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, struct fw_card *card); -+ -+struct fw_iso_context *fw_iso_context_create(struct fw_card *card, -+ int type, int channel, int speed, size_t header_size, -+ fw_iso_callback_t callback, void *callback_data); -+int fw_iso_context_queue(struct fw_iso_context *ctx, -+ struct fw_iso_packet *packet, -+ struct fw_iso_buffer *buffer, -+ unsigned long payload); -+int fw_iso_context_start(struct fw_iso_context *ctx, -+ int cycle, int sync, int tags); -+int fw_iso_context_stop(struct fw_iso_context *ctx); -+void fw_iso_context_destroy(struct fw_iso_context *ctx); - --int --fw_iso_context_stop(struct fw_iso_context *ctx); -+void fw_iso_resource_manage(struct fw_card *card, int generation, -+ u64 channels_mask, int *channel, int *bandwidth, bool allocate); - - struct fw_card_driver { - /* -@@ -415,7 +387,7 @@ struct fw_card_driver { - - struct fw_iso_context * - (*allocate_iso_context)(struct fw_card *card, -- int type, size_t header_size); -+ int type, int channel, size_t header_size); - void (*free_iso_context)(struct fw_iso_context *ctx); - - int (*start_iso)(struct fw_iso_context *ctx, -@@ -429,24 +401,18 @@ struct fw_card_driver { - int (*stop_iso)(struct fw_iso_context *ctx); - }; - --int --fw_core_initiate_bus_reset(struct fw_card *card, int short_reset); -+int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset); - --void --fw_send_request(struct fw_card *card, struct fw_transaction *t, -+void fw_send_request(struct fw_card *card, struct fw_transaction *t, - int tcode, int destination_id, int generation, int speed, - unsigned long long offset, void *data, size_t length, - fw_transaction_callback_t callback, void *callback_data); -- --int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, -- int generation, int speed, unsigned long long offset, -- void *data, size_t length); -- - int fw_cancel_transaction(struct fw_card *card, - struct fw_transaction *transaction); -- - void fw_flush_transactions(struct fw_card *card); -- -+int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, -+ int generation, int speed, unsigned long long offset, -+ void *data, size_t length); - void fw_send_phy_config(struct fw_card *card, - int node_id, int generation, int gap_count); - -@@ -454,29 +420,18 @@ void fw_send_phy_config(struct fw_card * - * Called by the topology code to inform the device code of node - * activity; found, lost, or updated nodes. - */ --void --fw_node_event(struct fw_card *card, struct fw_node *node, int event); -+void fw_node_event(struct fw_card *card, struct fw_node *node, int event); - - /* API used by card level drivers */ - --void --fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver, -- struct device *device); --int --fw_card_add(struct fw_card *card, -- u32 max_receive, u32 link_speed, u64 guid); -- --void --fw_core_remove_card(struct fw_card *card); -- --void --fw_core_handle_bus_reset(struct fw_card *card, -- int node_id, int generation, -- int self_id_count, u32 *self_ids); --void --fw_core_handle_request(struct fw_card *card, struct fw_packet *request); -- --void --fw_core_handle_response(struct fw_card *card, struct fw_packet *packet); -+void fw_card_initialize(struct fw_card *card, -+ const struct fw_card_driver *driver, struct device *device); -+int fw_card_add(struct fw_card *card, -+ u32 max_receive, u32 link_speed, u64 guid); -+void fw_core_remove_card(struct fw_card *card); -+void fw_core_handle_bus_reset(struct fw_card *card, int node_id, -+ int generation, int self_id_count, u32 *self_ids); -+void fw_core_handle_request(struct fw_card *card, struct fw_packet *request); -+void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet); - - #endif /* __fw_transaction_h */ ---- linux-2.6-git/include/linux/firewire-cdev.h 2008-11-04 11:19:21.000000000 -0500 -+++ firewire-git/include/linux/firewire-cdev.h 2009-01-30 13:35:54.327647015 -0500 -@@ -25,10 +25,12 @@ - #include - #include - --#define FW_CDEV_EVENT_BUS_RESET 0x00 --#define FW_CDEV_EVENT_RESPONSE 0x01 --#define FW_CDEV_EVENT_REQUEST 0x02 --#define FW_CDEV_EVENT_ISO_INTERRUPT 0x03 -+#define FW_CDEV_EVENT_BUS_RESET 0x00 -+#define FW_CDEV_EVENT_RESPONSE 0x01 -+#define FW_CDEV_EVENT_REQUEST 0x02 -+#define FW_CDEV_EVENT_ISO_INTERRUPT 0x03 -+#define FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED 0x04 -+#define FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED 0x05 - - /** - * struct fw_cdev_event_common - Common part of all fw_cdev_event_ types -@@ -136,7 +138,24 @@ struct fw_cdev_event_request { - * This event is sent when the controller has completed an &fw_cdev_iso_packet - * with the %FW_CDEV_ISO_INTERRUPT bit set. In the receive case, the headers - * stripped of all packets up until and including the interrupt packet are -- * returned in the @header field. -+ * returned in the @header field. The amount of header data per packet is as -+ * specified at iso context creation by &fw_cdev_create_iso_context.header_size. -+ * -+ * In version 1 of this ABI, header data consisted of the 1394 isochronous -+ * packet header, followed by quadlets from the packet payload if -+ * &fw_cdev_create_iso_context.header_size > 4. -+ * -+ * In version 2 of this ABI, header data consist of the 1394 isochronous -+ * packet header, followed by a timestamp quadlet if -+ * &fw_cdev_create_iso_context.header_size > 4, followed by quadlets from the -+ * packet payload if &fw_cdev_create_iso_context.header_size > 8. -+ * -+ * Behaviour of ver. 1 of this ABI is no longer available since ABI ver. 2. -+ * -+ * Format of 1394 iso packet header: 16 bits len, 2 bits tag, 6 bits channel, -+ * 4 bits tcode, 4 bits sy, in big endian byte order. Format of timestamp: -+ * 16 bits invalid, 3 bits cycleSeconds, 13 bits cycleCount, in big endian byte -+ * order. - */ - struct fw_cdev_event_iso_interrupt { - __u64 closure; -@@ -147,12 +166,44 @@ struct fw_cdev_event_iso_interrupt { - }; - - /** -+ * struct fw_cdev_event_iso_resource - Iso resources were allocated or freed -+ * @closure: See &fw_cdev_event_common; -+ * set by %FW_CDEV_IOC_(DE)ALLOCATE_ISO_RESOURCE(_ONCE) ioctl -+ * @type: %FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED or -+ * %FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED -+ * @handle: Reference by which an allocated resource can be deallocated -+ * @channel: Isochronous channel which was (de)allocated, if any -+ * @bandwidth: Bandwidth allocation units which were (de)allocated, if any -+ * -+ * An %FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED event is sent after an isochronous -+ * resource was allocated at the IRM. The client has to check @channel and -+ * @bandwidth for whether the allocation actually succeeded. -+ * -+ * An %FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED event is sent after an isochronous -+ * resource was deallocated at the IRM. It is also sent when automatic -+ * reallocation after a bus reset failed. -+ * -+ * @channel is <0 if no channel was (de)allocated or if reallocation failed. -+ * @bandwidth is 0 if no bandwidth was (de)allocated or if reallocation failed. -+ */ -+struct fw_cdev_event_iso_resource { -+ __u64 closure; -+ __u32 type; -+ __u32 handle; -+ __s32 channel; -+ __s32 bandwidth; -+}; -+ -+/** - * union fw_cdev_event - Convenience union of fw_cdev_event_ types - * @common: Valid for all types - * @bus_reset: Valid if @common.type == %FW_CDEV_EVENT_BUS_RESET - * @response: Valid if @common.type == %FW_CDEV_EVENT_RESPONSE - * @request: Valid if @common.type == %FW_CDEV_EVENT_REQUEST - * @iso_interrupt: Valid if @common.type == %FW_CDEV_EVENT_ISO_INTERRUPT -+ * @iso_resource: Valid if @common.type == -+ * %FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED or -+ * %FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED - * - * Convenience union for userspace use. Events could be read(2) into an - * appropriately aligned char buffer and then cast to this union for further -@@ -163,13 +214,15 @@ struct fw_cdev_event_iso_interrupt { - * not fit will be discarded so that the next read(2) will return a new event. - */ - union fw_cdev_event { -- struct fw_cdev_event_common common; -- struct fw_cdev_event_bus_reset bus_reset; -- struct fw_cdev_event_response response; -- struct fw_cdev_event_request request; -- struct fw_cdev_event_iso_interrupt iso_interrupt; -+ struct fw_cdev_event_common common; -+ struct fw_cdev_event_bus_reset bus_reset; -+ struct fw_cdev_event_response response; -+ struct fw_cdev_event_request request; -+ struct fw_cdev_event_iso_interrupt iso_interrupt; -+ struct fw_cdev_event_iso_resource iso_resource; - }; - -+/* available since kernel version 2.6.22 */ - #define FW_CDEV_IOC_GET_INFO _IOWR('#', 0x00, struct fw_cdev_get_info) - #define FW_CDEV_IOC_SEND_REQUEST _IOW('#', 0x01, struct fw_cdev_send_request) - #define FW_CDEV_IOC_ALLOCATE _IOWR('#', 0x02, struct fw_cdev_allocate) -@@ -178,18 +231,29 @@ union fw_cdev_event { - #define FW_CDEV_IOC_INITIATE_BUS_RESET _IOW('#', 0x05, struct fw_cdev_initiate_bus_reset) - #define FW_CDEV_IOC_ADD_DESCRIPTOR _IOWR('#', 0x06, struct fw_cdev_add_descriptor) - #define FW_CDEV_IOC_REMOVE_DESCRIPTOR _IOW('#', 0x07, struct fw_cdev_remove_descriptor) -- - #define FW_CDEV_IOC_CREATE_ISO_CONTEXT _IOWR('#', 0x08, struct fw_cdev_create_iso_context) - #define FW_CDEV_IOC_QUEUE_ISO _IOWR('#', 0x09, struct fw_cdev_queue_iso) - #define FW_CDEV_IOC_START_ISO _IOW('#', 0x0a, struct fw_cdev_start_iso) - #define FW_CDEV_IOC_STOP_ISO _IOW('#', 0x0b, struct fw_cdev_stop_iso) -+ -+/* available since kernel version 2.6.24 */ - #define FW_CDEV_IOC_GET_CYCLE_TIMER _IOR('#', 0x0c, struct fw_cdev_get_cycle_timer) - --/* FW_CDEV_VERSION History -- * -- * 1 Feb 18, 2007: Initial version. -+/* available since kernel version 2.6.30 */ -+#define FW_CDEV_IOC_ALLOCATE_ISO_RESOURCE _IOWR('#', 0x0d, struct fw_cdev_allocate_iso_resource) -+#define FW_CDEV_IOC_DEALLOCATE_ISO_RESOURCE _IOW('#', 0x0e, struct fw_cdev_deallocate) -+#define FW_CDEV_IOC_ALLOCATE_ISO_RESOURCE_ONCE _IOW('#', 0x0f, struct fw_cdev_allocate_iso_resource) -+#define FW_CDEV_IOC_DEALLOCATE_ISO_RESOURCE_ONCE _IOW('#', 0x10, struct fw_cdev_allocate_iso_resource) -+#define FW_CDEV_IOC_GET_SPEED _IOR('#', 0x11, struct fw_cdev_get_speed) -+#define FW_CDEV_IOC_SEND_BROADCAST_REQUEST _IOW('#', 0x12, struct fw_cdev_send_request) -+ -+/* -+ * FW_CDEV_VERSION History -+ * 1 (2.6.22) - initial version -+ * 2 (2.6.30) - changed &fw_cdev_event_iso_interrupt.header if -+ * &fw_cdev_create_iso_context.header_size is 8 or more - */ --#define FW_CDEV_VERSION 1 -+#define FW_CDEV_VERSION 2 - - /** - * struct fw_cdev_get_info - General purpose information ioctl -@@ -201,7 +265,7 @@ union fw_cdev_event { - * case, @rom_length is updated with the actual length of the - * configuration ROM. - * @rom: If non-zero, address of a buffer to be filled by a copy of the -- * local node's configuration ROM -+ * device's configuration ROM - * @bus_reset: If non-zero, address of a buffer to be filled by a - * &struct fw_cdev_event_bus_reset with the current state - * of the bus. This does not cause a bus reset to happen. -@@ -229,7 +293,7 @@ struct fw_cdev_get_info { - * Send a request to the device. This ioctl implements all outgoing requests. - * Both quadlet and block request specify the payload as a pointer to the data - * in the @data field. Once the transaction completes, the kernel writes an -- * &fw_cdev_event_request event back. The @closure field is passed back to -+ * &fw_cdev_event_response event back. The @closure field is passed back to - * user space in the response event. - */ - struct fw_cdev_send_request { -@@ -284,9 +348,9 @@ struct fw_cdev_allocate { - }; - - /** -- * struct fw_cdev_deallocate - Free an address range allocation -- * @handle: Handle to the address range, as returned by the kernel when the -- * range was allocated -+ * struct fw_cdev_deallocate - Free a CSR address range or isochronous resource -+ * @handle: Handle to the address range or iso resource, as returned by the -+ * kernel when the range or resource was allocated - */ - struct fw_cdev_deallocate { - __u32 handle; -@@ -370,6 +434,9 @@ struct fw_cdev_remove_descriptor { - * - * If a context was successfully created, the kernel writes back a handle to the - * context, which must be passed in for subsequent operations on that context. -+ * -+ * Note that the effect of a @header_size > 4 depends on -+ * &fw_cdev_get_info.version, as documented at &fw_cdev_event_iso_interrupt. - */ - struct fw_cdev_create_iso_context { - __u32 type; -@@ -473,10 +540,73 @@ struct fw_cdev_stop_iso { - * The %FW_CDEV_IOC_GET_CYCLE_TIMER ioctl reads the isochronous cycle timer - * and also the system clock. This allows to express the receive time of an - * isochronous packet as a system time with microsecond accuracy. -+ * -+ * @cycle_timer consists of 7 bits cycleSeconds, 13 bits cycleCount, and -+ * 12 bits cycleOffset, in host byte order. - */ - struct fw_cdev_get_cycle_timer { - __u64 local_time; - __u32 cycle_timer; - }; - -+/** -+ * struct fw_cdev_allocate_iso_resource - (De)allocate a channel or bandwidth -+ * @closure: Passed back to userspace in correponding iso resource events -+ * @channels: Isochronous channels of which one is to be (de)allocated -+ * @bandwidth: Isochronous bandwidth units to be (de)allocated -+ * @handle: Handle to the allocation, written by the kernel (only valid in -+ * case of %FW_CDEV_IOC_ALLOCATE_ISO_RESOURCE ioctls) -+ * -+ * The %FW_CDEV_IOC_ALLOCATE_ISO_RESOURCE ioctl initiates allocation of an -+ * isochronous channel and/or of isochronous bandwidth at the isochronous -+ * resource manager (IRM). Only one of the channels specified in @channels is -+ * allocated. An %FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED is sent after -+ * communication with the IRM, indicating success or failure in the event data. -+ * The kernel will automatically reallocate the resources after bus resets. -+ * Should a reallocation fail, an %FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED event -+ * will be sent. The kernel will also automatically deallocate the resources -+ * when the file descriptor is closed. -+ * -+ * The %FW_CDEV_IOC_DEALLOCATE_ISO_RESOURCE ioctl can be used to initiate -+ * deallocation of resources which were allocated as described above. -+ * An %FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED event concludes this operation. -+ * -+ * The %FW_CDEV_IOC_ALLOCATE_ISO_RESOURCE_ONCE ioctl is a variant of allocation -+ * without automatic re- or deallocation. -+ * An %FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED event concludes this operation, -+ * indicating success or failure in its data. -+ * -+ * The %FW_CDEV_IOC_DEALLOCATE_ISO_RESOURCE_ONCE ioctl works like -+ * %FW_CDEV_IOC_ALLOCATE_ISO_RESOURCE_ONCE except that resources are freed -+ * instead of allocated. -+ * An %FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED event concludes this operation. -+ * -+ * To summarize, %FW_CDEV_IOC_DEALLOCATE_ISO_RESOURCE allocates iso resources -+ * for the lifetime of the fd or handle. -+ * In contrast, %FW_CDEV_IOC_ALLOCATE_ISO_RESOURCE_ONCE allocates iso resources -+ * for the duration of a bus generation. -+ * -+ * @channels is a host-endian bitfield with the least significant bit -+ * representing channel 0 and the most significant bit representing channel 63: -+ * 1ULL << c for each channel c that is a candidate for (de)allocation. -+ * -+ * @bandwidth is expressed in bandwidth allocation units, i.e. the time to send -+ * one quadlet of data (payload or header data) at speed S1600. -+ */ -+struct fw_cdev_allocate_iso_resource { -+ __u64 closure; -+ __u64 channels; -+ __u32 bandwidth; -+ __u32 handle; -+}; -+ -+/** -+ * struct fw_cdev_get_speed - Query maximum speed to or from this device -+ * @max_speed: Speed code; minimum of the device's link speed, the local node's -+ * link speed, and all PHY port speeds between the two links -+ */ -+struct fw_cdev_get_speed { -+ __u32 max_speed; -+}; -+ - #endif /* _LINUX_FIREWIRE_CDEV_H */ diff --git a/linux-2.6-hotfixes.patch b/linux-2.6-hotfixes.patch deleted file mode 100644 index 494947322..000000000 --- a/linux-2.6-hotfixes.patch +++ /dev/null @@ -1,15 +0,0 @@ -fixes: -implicit declaration of function kzalloc - ---- linux-2.6.34.noarch/drivers/usb/serial/qcserial.c~ 2010-06-08 15:19:41.000000000 -0400 -+++ linux-2.6.34.noarch/drivers/usb/serial/qcserial.c 2010-06-08 15:19:47.000000000 -0400 -@@ -11,6 +11,7 @@ - * - */ - -+#include - #include - #include - #include - - diff --git a/linux-2.6-i386-nx-emulation.patch b/linux-2.6-i386-nx-emulation.patch index da84cc672..d97d52999 100644 --- a/linux-2.6-i386-nx-emulation.patch +++ b/linux-2.6-i386-nx-emulation.patch @@ -1,23 +1,25 @@ +diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h +index 41935fa..6e9259b 100644 --- a/arch/x86/include/asm/desc.h +++ b/arch/x86/include/asm/desc.h @@ -5,6 +5,7 @@ #include #include - #include + +#include + #include - static inline void fill_ldt(struct desc_struct *desc, - const struct user_desc *info) -@@ -93,6 +94,9 @@ static inline int desc_empty(const void *ptr) + static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *info) +@@ -97,6 +98,9 @@ static inline int desc_empty(const void *ptr) - #define load_TLS(t, cpu) native_load_tls(t, cpu) - #define set_ldt native_set_ldt + #define load_TLS(t, cpu) native_load_tls(t, cpu) + #define set_ldt native_set_ldt +#ifdef CONFIG_X86_32 -+#define load_user_cs_desc native_load_user_cs_desc ++#define load_user_cs_desc native_load_user_cs_desc +#endif /*CONFIG_X86_32*/ - #define write_ldt_entry(dt, entry, desc) \ - native_write_ldt_entry(dt, entry, desc) + #define write_ldt_entry(dt, entry, desc) native_write_ldt_entry(dt, entry, desc) + #define write_gdt_entry(dt, entry, desc, type) native_write_gdt_entry(dt, entry, desc, type) @@ -392,4 +396,25 @@ static inline void set_system_intr_gate_ist(int n, void *addr, unsigned ist) _set_gate(n, GATE_INTERRUPT, addr, 0x3, ist, __KERNEL_CS); } @@ -44,9 +46,11 @@ +#endif /* CONFIG_X86_32 */ + #endif /* _ASM_X86_DESC_H */ +diff --git a/arch/x86/include/asm/mmu.h b/arch/x86/include/asm/mmu.h +index 5f55e69..aba94f0 100644 --- a/arch/x86/include/asm/mmu.h +++ b/arch/x86/include/asm/mmu.h -@@ -7,12 +7,19 @@ +@@ -7,6 +7,9 @@ /* * The x86 doesn't have a mmu context, but * we put the segment information here. @@ -56,9 +60,11 @@ */ typedef struct { void *ldt; - int size; +@@ -19,6 +22,11 @@ typedef struct { + struct mutex lock; void *vdso; ++ +#ifdef CONFIG_X86_32 + struct desc_struct user_cs; + unsigned long exec_limit; @@ -66,9 +72,11 @@ } mm_context_t; #ifdef CONFIG_SMP +diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h +index a7d2db9..cc4ad60 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h -@@ -289,6 +289,12 @@ static inline void set_ldt(const void *addr, unsigned entries) +@@ -298,6 +298,12 @@ static inline void set_ldt(const void *addr, unsigned entries) { PVOP_VCALL2(pv_cpu_ops.set_ldt, addr, entries); } @@ -81,9 +89,11 @@ static inline void store_gdt(struct desc_ptr *dtr) { PVOP_VCALL1(pv_cpu_ops.store_gdt, dtr); +diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h +index 8e8b9a4..cca421e 100644 --- a/arch/x86/include/asm/paravirt_types.h +++ b/arch/x86/include/asm/paravirt_types.h -@@ -118,6 +118,9 @@ struct pv_cpu_ops { +@@ -125,6 +125,9 @@ struct pv_cpu_ops { void (*store_gdt)(struct desc_ptr *); void (*store_idt)(struct desc_ptr *); void (*set_ldt)(const void *desc, unsigned entries); @@ -93,9 +103,11 @@ unsigned long (*store_tr)(void); void (*load_tls)(struct thread_struct *t, unsigned int cpu); #ifdef CONFIG_X86_64 +diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c +index aa003b1..c094152 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c -@@ -802,6 +802,22 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c) +@@ -844,6 +844,22 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c) /* Filter out anything that depends on CPUID levels we don't have */ filter_cpuid_features(c, true); @@ -118,9 +130,11 @@ /* If the model name is still unset, do table lookup. */ if (!c->x86_model_id[0]) { const char *p; +diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c +index d90272e..cc594fc 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c -@@ -345,6 +345,9 @@ struct pv_cpu_ops pv_cpu_ops = { +@@ -358,6 +358,9 @@ struct pv_cpu_ops pv_cpu_ops = { .read_tscp = native_read_tscp, .load_tr_desc = native_load_tr_desc, .set_ldt = native_set_ldt, @@ -130,9 +144,11 @@ .load_gdt = native_load_gdt, .load_idt = native_load_idt, .store_gdt = native_store_gdt, +diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c +index 8598296..641ae48 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c -@@ -243,7 +243,10 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, +@@ -247,7 +247,10 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, void start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) { @@ -141,9 +157,9 @@ set_user_gs(regs, 0); + regs->fs = 0; - set_fs(USER_DS); regs->ds = __USER_DS; -@@ -252,6 +255,11 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) + regs->es = __USER_DS; +@@ -255,6 +258,11 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) regs->cs = __USER_CS; regs->ip = new_ip; regs->sp = new_sp; @@ -155,17 +171,17 @@ /* * Free the old FP and other extended state */ -@@ -311,6 +319,9 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) - if (preload_fpu) - prefetch(next->fpu.state); +@@ -320,6 +328,9 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) + */ + lazy_save_gs(prev->gs); + if (next_p->mm) + load_user_cs_desc(cpu, next_p->mm); + /* - * Reload esp0. + * Load the per-thread Thread-Local Storage descriptor. */ -@@ -404,3 +415,40 @@ unsigned long get_wchan(struct task_struct *p) +@@ -390,3 +401,40 @@ unsigned long get_wchan(struct task_struct *p) return 0; } @@ -206,9 +222,11 @@ + mm->context.exec_limit = 0; + set_user_cs(&mm->context.user_cs, 0); +} +diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c +index 31d9d0f..f7c210d 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c -@@ -109,6 +109,78 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) +@@ -107,6 +107,78 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) dec_preempt_count(); } @@ -247,7 +265,7 @@ + for (vma = current->mm->mmap; vma; vma = vma->vm_next) + if ((vma->vm_flags & VM_EXEC) && (vma->vm_end > limit)) + limit = vma->vm_end; -+ vma = get_gate_vma(current); ++ vma = get_gate_vma(current->mm); + if (vma && (vma->vm_flags & VM_EXEC) && (vma->vm_end > limit)) + limit = vma->vm_end; + spin_unlock(¤t->mm->page_table_lock); @@ -287,7 +305,7 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, long error_code, siginfo_t *info) -@@ -265,6 +337,29 @@ do_general_protection(struct pt_regs *regs, long error_code) +@@ -263,6 +335,29 @@ do_general_protection(struct pt_regs *regs, long error_code) if (!user_mode(regs)) goto gp_in_kernel; @@ -317,7 +335,7 @@ tsk->thread.error_code = error_code; tsk->thread.trap_no = 13; -@@ -792,19 +887,37 @@ do_device_not_available(struct pt_regs *regs, long error_code) +@@ -649,19 +744,37 @@ do_device_not_available(struct pt_regs *regs, long error_code) } #ifdef CONFIG_X86_32 @@ -364,6 +382,8 @@ } #endif +diff --git a/arch/x86/mm/setup_nx.c b/arch/x86/mm/setup_nx.c +index 410531d..eb040ad 100644 --- a/arch/x86/mm/setup_nx.c +++ b/arch/x86/mm/setup_nx.c @@ -1,3 +1,4 @@ @@ -371,16 +391,16 @@ #include #include #include -@@ -6,7 +6,7 @@ +@@ -5,7 +6,7 @@ #include #include - + -static int disable_nx __cpuinitdata; +int disable_nx __cpuinitdata; - + /* * noexec = on|off -@@ -40,6 +42,10 @@ void __cpuinit x86_configure_nx(void) +@@ -40,6 +41,10 @@ void __cpuinit x86_configure_nx(void) void __init x86_report_nx(void) { if (!cpu_has_nx) { @@ -391,9 +411,11 @@ printk(KERN_NOTICE "Notice: NX (Execute Disable) protection " "missing in CPU!\n"); } else { +diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c +index d6c0418..c15b765 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c -@@ -6,6 +6,7 @@ +@@ -7,6 +7,7 @@ #include #include @@ -401,7 +423,7 @@ #include #include #include -@@ -131,6 +132,12 @@ void smp_invalidate_interrupt(struct pt_regs *regs) +@@ -134,6 +135,12 @@ void smp_invalidate_interrupt(struct pt_regs *regs) union smp_flush_state *f; cpu = smp_processor_id(); @@ -414,9 +436,11 @@ /* * orig_rax contains the negated interrupt vector. * Use that to determine where the sender put the data. +diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c +index 1f92865..b8f4319 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c -@@ -335,6 +335,24 @@ static void xen_set_ldt(const void *addr, unsigned entries) +@@ -354,6 +354,24 @@ static void xen_set_ldt(const void *addr, unsigned entries) xen_mc_issue(PARAVIRT_LAZY_CPU); } @@ -441,7 +465,7 @@ static void xen_load_gdt(const struct desc_ptr *dtr) { unsigned long va = dtr->address; -@@ -961,6 +979,9 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = { +@@ -994,6 +1012,9 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = { .load_tr_desc = paravirt_nop, .set_ldt = xen_set_ldt, @@ -451,9 +475,11 @@ .load_gdt = xen_load_gdt, .load_idt = xen_load_idt, .load_tls = xen_load_tls, +diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c +index 21ac5ee..3f26963 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c -@@ -717,6 +722,15 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) +@@ -711,6 +711,15 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) if (retval) goto out_free_dentry; @@ -469,11 +495,13 @@ /* OK, This is the point of no return */ current->flags &= ~PF_FORKNOEXEC; current->mm->def_flags = def_flags; +diff --git a/include/linux/sched.h b/include/linux/sched.h +index 1c4f3e9..52011a7 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h -@@ -101,6 +101,9 @@ struct bio_list; - struct fs_struct; +@@ -102,6 +102,9 @@ struct fs_struct; struct perf_event_context; + struct blk_plug; +extern int disable_nx; +extern int print_fatal_signals; @@ -481,9 +509,11 @@ /* * List of flags we want to share for kernel threads, * if only because they are not used by them anyway. ---- b/mm/mmap.c +diff --git a/mm/mmap.c b/mm/mmap.c +index eae90af..f4de6c0 100644 +--- a/mm/mmap.c +++ b/mm/mmap.c -@@ -44,6 +45,18 @@ +@@ -46,6 +46,18 @@ #define arch_rebalance_pgtables(addr, len) (addr) #endif @@ -502,17 +532,16 @@ static void unmap_region(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev, unsigned long start, unsigned long end); -@@ -388,6 +401,9 @@ +@@ -424,6 +436,8 @@ __vma_link(struct mm_struct *mm, struct vm_area_struct *vma, + struct vm_area_struct *prev, struct rb_node **rb_link, + struct rb_node *rb_parent) { - struct vm_area_struct *next; - + if (vma->vm_flags & VM_EXEC) + arch_add_exec_range(mm, vma->vm_end); -+ - vma->vm_prev = prev; - if (prev) { - next = prev->vm_next; -@@ -489,6 +504,8 @@ + __vma_link_list(mm, vma, prev, rb_parent); + __vma_link_rb(mm, vma, rb_link, rb_parent); + } +@@ -478,6 +492,8 @@ __vma_unlink(struct mm_struct *mm, struct vm_area_struct *vma, rb_erase(&vma->vm_rb, &mm->mm_rb); if (mm->mmap_cache == vma) mm->mmap_cache = prev; @@ -521,7 +550,7 @@ } /* -@@ -790,6 +807,8 @@ +@@ -794,6 +810,8 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm, } else /* cases 2, 5, 7 */ err = vma_adjust(prev, prev->vm_start, end, prev->vm_pgoff, NULL); @@ -529,8 +558,8 @@ + arch_add_exec_range(mm, prev->vm_end); if (err) return NULL; - return prev; -@@ -1966,10 +2075,14 @@ + khugepaged_enter_vma_merge(prev); +@@ -1972,10 +1990,14 @@ static int __split_vma(struct mm_struct * mm, struct vm_area_struct * vma, if (new->vm_ops && new->vm_ops->open) new->vm_ops->open(new); @@ -547,14 +576,16 @@ err = vma_adjust(vma, vma->vm_start, addr, vma->vm_pgoff, new); /* Success. */ -@@ -2254,6 +2367,7 @@ +@@ -2263,6 +2285,7 @@ void exit_mmap(struct mm_struct *mm) - free_pgtables(tlb, vma, FIRST_USER_ADDRESS, 0); - tlb_finish_mmu(tlb, 0, end); + free_pgtables(&tlb, vma, FIRST_USER_ADDRESS, 0); + tlb_finish_mmu(&tlb, 0, end); + arch_flush_exec_range(mm); /* * Walk the list again, actually closing and freeing it, +diff --git a/mm/mprotect.c b/mm/mprotect.c +index 5a688a2..128d996 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -25,9 +25,14 @@ @@ -572,7 +603,7 @@ #ifndef pgprot_modify static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot) { -@@ -138,7 +143,7 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, +@@ -148,7 +153,7 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, struct mm_struct *mm = vma->vm_mm; unsigned long oldflags = vma->vm_flags; long nrpages = (end - start) >> PAGE_SHIFT; @@ -581,7 +612,7 @@ pgoff_t pgoff; int error; int dirty_accountable = 0; -@@ -203,6 +208,9 @@ success: +@@ -213,6 +218,9 @@ success: dirty_accountable = 1; } @@ -591,25 +622,3 @@ mmu_notifier_invalidate_range_start(mm, start, end); if (is_vm_hugetlb_page(vma)) hugetlb_change_protection(vma, start, end, vma->vm_page_prot); -diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c -index 57d1868..29c0c35 100644 ---- a/arch/x86/kernel/process.c -+++ b/arch/x86/kernel/process.c -@@ -669,6 +669,16 @@ unsigned long arch_align_stack(unsigned long sp) - unsigned long arch_randomize_brk(struct mm_struct *mm) - { - unsigned long range_end = mm->brk + 0x02000000; -- return randomize_range(mm->brk, range_end, 0) ? : mm->brk; -+ unsigned long bump = 0; -+#ifdef CONFIG_X86_32 -+ /* in the case of NX emulation, shove the brk segment way out of the -+ way of the exec randomization area, since it can collide with -+ future allocations if not. */ -+ if ( (mm->get_unmapped_exec_area == arch_get_unmapped_exec_area) && -+ (mm->brk < 0x08000000) ) { -+ bump = (TASK_SIZE/6); -+ } -+#endif -+ return bump + (randomize_range(mm->brk, range_end, 0) ? : mm->brk); - } - diff --git a/linux-2.6-intel-iommu-igfx.patch b/linux-2.6-intel-iommu-igfx.patch index 44fd14186..3a45abaec 100644 --- a/linux-2.6-intel-iommu-igfx.patch +++ b/linux-2.6-intel-iommu-igfx.patch @@ -1,6 +1,7 @@ -Subject: [PATCH] [intel_iommu] Default to igfx_off +From 602e1f209dd983e40d989e871cd253e8187899b8 Mon Sep 17 00:00:00 2001 From: drago01 -To: fedora-kernel-list +Date: Wed, 26 Oct 2011 13:37:27 -0400 +Subject: [PATCH] Default to igfx_off This option seems to causes way to many issues, it is being investigated by Intel's chipset team for months now and @@ -16,14 +17,14 @@ Signed-off-by: Adel Gadllah Reviewed-by: Adam Jackson --- Documentation/kernel-parameters.txt | 11 +++++------ - drivers/pci/intel-iommu.c | 9 +++++---- + drivers/iommu/intel-iommu.c | 9 +++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt -index e7848a0..9914485 100644 +index 81c287f..ee5693b 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt -@@ -992,12 +992,11 @@ and is between 256 and 4096 characters. It is defined in the file +@@ -1014,12 +1014,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. Enable intel iommu driver. off Disable intel iommu driver. @@ -40,22 +41,22 @@ index e7848a0..9914485 100644 + mapped as normal device. forcedac [x86_64] With this option iommu will not optimize to look - for io virtual address below 32 bit forcing dual -diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c -index 4173125..8f36786 100644 ---- a/drivers/pci/intel-iommu.c -+++ b/drivers/pci/intel-iommu.c -@@ -340,7 +340,8 @@ int dmar_disabled = 0; - int dmar_disabled = 1; - #endif /*CONFIG_DMAR_DEFAULT_ON*/ - + for io virtual address below 32-bit forcing dual +diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c +index bdc447f..240db6b 100644 +--- a/drivers/iommu/intel-iommu.c ++++ b/drivers/iommu/intel-iommu.c +@@ -408,7 +408,8 @@ int dmar_disabled = 1; + int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); + -static int dmar_map_gfx = 1; +/* disabled by default; causes way too many issues */ +static int dmar_map_gfx = 0; static int dmar_forcedac; static int intel_iommu_strict; - -@@ -361,10 +362,10 @@ static int __init intel_iommu_setup(char *str) + static int intel_iommu_superpage = 1; +@@ -433,10 +434,10 @@ static int __init intel_iommu_setup(char *str) } else if (!strncmp(str, "off", 3)) { dmar_disabled = 1; printk(KERN_INFO "Intel-IOMMU: disabled\n"); @@ -70,9 +71,5 @@ index 4173125..8f36786 100644 printk(KERN_INFO "Intel-IOMMU: Forcing DAC for PCI devices\n"); -- -1.6.6.1 -_______________________________________________ -kernel mailing list -kernel@lists.fedoraproject.org -https://admin.fedoraproject.org/mailman/listinfo/kernel +1.7.7.4 diff --git a/linux-2.6-selinux-mprotect-checks.patch b/linux-2.6-selinux-mprotect-checks.patch deleted file mode 100644 index 010a63c43..000000000 --- a/linux-2.6-selinux-mprotect-checks.patch +++ /dev/null @@ -1,124 +0,0 @@ -This needs a fixed toolchain, and a userspace rebuild to work. -For these reasons, it's had difficulty getting upstream. - -ie, Fedora has a new enough toolchain, and has been rebuilt, so we don't need -the ifdefs. Other distros don't/haven't, and this patch would break them -if pushed upstream. - - -Subject: [Fwd: Re: [PATCH] Disable execmem for sparc] -From: Stephen Smalley -To: Dave Jones -Date: Wed, 28 Apr 2010 16:04:56 -0400 -Message-Id: <1272485096.6013.326.camel@moss-pluto.epoch.ncsc.mil> - --------- Forwarded Message -------- -From: Stephen Smalley -To: David Miller -Cc: tcallawa@redhat.com, dennis@ausil.us, sparclinux@vger.kernel.org, dgilmore@redhat.com, jmorris@namei.org, eparis@parisplace.org -Subject: Re: [PATCH] Disable execmem for sparc -Date: Wed, 28 Apr 2010 15:57:57 -0400 - -On Tue, 2010-04-27 at 11:47 -0700, David Miller wrote: -> From: "Tom \"spot\" Callaway" -> Date: Tue, 27 Apr 2010 14:20:21 -0400 -> -> > [root@apollo ~]$ cat /proc/2174/maps -> > 00010000-00014000 r-xp 00000000 fd:00 15466577 -> > /sbin/mingetty -> > 00022000-00024000 rwxp 00002000 fd:00 15466577 -> > /sbin/mingetty -> > 00024000-00046000 rwxp 00000000 00:00 0 -> > [heap] -> -> SELINUX probably barfs on the executable heap, the PLT is in the HEAP -> just like powerpc32 and that's why VM_DATA_DEFAULT_FLAGS has to set -> both executable and writable. -> -> You also can't remove the CONFIG_PPC32 ifdefs in selinux, since -> because of the VM_DATA_DEFAULT_FLAGS setting used still in that arch, -> the heap will always have executable permission, just like sparc does. -> You have to support those binaries forever, whether you like it or not. -> -> Let's just replace the CONFIG_PPC32 ifdef in SELINUX with CONFIG_PPC32 -> || CONFIG_SPARC as in Tom's original patch and let's be done with -> this. -> -> In fact I would go through all the arch/ header files and check the -> VM_DATA_DEFAULT_FLAGS settings and add the necessary new ifdefs to the -> SELINUX code so that other platforms don't have the pain of having to -> go through this process too. - -To avoid maintaining per-arch ifdefs, it seems that we could just -directly use (VM_DATA_DEFAULT_FLAGS & VM_EXEC) as the basis for deciding -whether to enable or disable these checks. VM_DATA_DEFAULT_FLAGS isn't -constant on some architectures but instead depends on -current->personality, but we want this applied uniformly. So we'll just -use the initial task state to determine whether or not to enable these -checks. - -Signed-off-by: Stephen Smalley - -diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c -index ebee467..a03fd74 100644 ---- a/security/selinux/hooks.c -+++ b/security/selinux/hooks.c -@@ -2999,13 +2999,15 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, - return file_has_perm(cred, file, av); - } - -+static int default_noexec; -+ - static int file_map_prot_check(struct file *file, unsigned long prot, int shared) - { - const struct cred *cred = current_cred(); - int rc = 0; - --#ifndef CONFIG_PPC32 -- if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) { -+ if (default_noexec && -+ (prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) { - /* - * We are making executable an anonymous mapping or a - * private file mapping that will also be writable. -@@ -3015,7 +3017,6 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared - if (rc) - goto error; - } --#endif - - if (file) { - /* read access is always possible with a mapping */ -@@ -3076,8 +3077,8 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, - if (selinux_checkreqprot) - prot = reqprot; - --#ifndef CONFIG_PPC32 -- if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) { -+ if (default_noexec && -+ (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) { - int rc = 0; - if (vma->vm_start >= vma->vm_mm->start_brk && - vma->vm_end <= vma->vm_mm->brk) { -@@ -3099,7 +3100,6 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, - if (rc) - return rc; - } --#endif - - return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED); - } -@@ -5662,6 +5662,8 @@ static __init int selinux_init(void) - /* Set the security state for the initial task. */ - cred_init_security(); - -+ default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC); -+ - sel_inode_cache = kmem_cache_create("selinux_inode_security", - sizeof(struct inode_security_struct), - 0, SLAB_PANIC, NULL); - --- -Stephen Smalley -National Security Agency - diff --git a/linux-2.6-serial-460800.patch b/linux-2.6-serial-460800.patch index 9aa392c9e..979b248d5 100644 --- a/linux-2.6-serial-460800.patch +++ b/linux-2.6-serial-460800.patch @@ -1,7 +1,7 @@ diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 2209620..659c1bb 100644 ---- a/drivers/tty/serial/8250.c -+++ b/drivers/tty/serial/8250.c +--- a/drivers/tty/serial/8250/8250.c ++++ b/drivers/tty/serial/8250/8250.c @@ -7,6 +7,9 @@ * * Copyright (C) 2001 Russell King. diff --git a/linux-2.6-silence-noise.patch b/linux-2.6-silence-noise.patch index 32c678b1f..1e4d7c57f 100644 --- a/linux-2.6-silence-noise.patch +++ b/linux-2.6-silence-noise.patch @@ -34,23 +34,24 @@ ratelimited. It isn't particularly useful, so just remove it. Signed-off-by: Dave Jones ---- linux-2.6.27.noarch/net/can/af_can.c~ 2008-12-11 16:53:48.000000000 -0500 -+++ linux-2.6.27.noarch/net/can/af_can.c 2008-12-11 16:54:42.000000000 -0500 -@@ -134,13 +134,9 @@ static int can_create(struct net *net, s +--- a/net/can/af_can.c ++++ b/net/can/af_can.c +@@ -157,13 +157,9 @@ static int can_create(struct net *net, struct socket *sock, int protocol, err = request_module("can-proto-%d", protocol); /* - * In case of error we only print a message but don't - * return the error code immediately. Below we will - * return -EPROTONOSUPPORT -+ * In case of error we don't return the error code immediately. ++ * In case of error we but don't return the error code immediately. + * Below we will return -EPROTONOSUPPORT */ -- if (err && printk_ratelimit()) -- printk(KERN_ERR "can: request_module " +- if (err) +- printk_ratelimited(KERN_ERR "can: request_module " - "(can-proto-%d) failed.\n", protocol); + + cp = can_get_proto(protocol); } - #endif This was removed in revision 1.6 of linux-2.6-silence-noise.patch in ye olde CVS tree. I have no idea why. Originally the pr_debug in @@ -68,5 +69,5 @@ index 2a52270..bacbdd2 100644 - pr_debug("PM: Adding info for %s:%s\n", - dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); mutex_lock(&dpm_list_mtx); - if (dev->parent && dev->parent->power.in_suspend) + if (dev->parent && dev->parent->power.is_prepared) dev_warn(dev, "parent %s should not be sleeping\n", diff --git a/linux-2.6-sparc-selinux-mprotect-checks.patch b/linux-2.6-sparc-selinux-mprotect-checks.patch deleted file mode 100644 index cc821e323..000000000 --- a/linux-2.6-sparc-selinux-mprotect-checks.patch +++ /dev/null @@ -1,35 +0,0 @@ -diff -up linux-2.6.24.sparc64/security/selinux/hooks.c.BAD linux-2.6.24.sparc64/security/selinux/hooks.c ---- linux-2.6.24.sparc64/security/selinux/hooks.c.BAD 2008-03-21 14:28:06.000000000 -0400 -+++ linux-2.6.24.sparc64/security/selinux/hooks.c 2008-03-21 14:29:10.000000000 -0400 -@@ -3018,6 +3018,7 @@ static int file_map_prot_check(struct fi - const struct cred *cred = current_cred(); - int rc = 0; - -+#ifndef CONFIG_SPARC - if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) { - /* - * We are making executable an anonymous mapping or a -@@ -3028,6 +3029,7 @@ static int file_map_prot_check(struct fi - if (rc) - goto error; - } -+#endif - - if (file) { - /* read access is always possible with a mapping */ -@@ -3081,6 +3081,7 @@ static int selinux_file_mprotect(struct - if (selinux_checkreqprot) - prot = reqprot; - -+#ifndef CONFIG_SPARC - if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) { - rc = 0; - if (vma->vm_start >= vma->vm_mm->start_brk && -@@ -3103,6 +3103,7 @@ static int selinux_file_mprotect(struct - if (rc) - return rc; - } -+#endif - - return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED); - } diff --git a/linux-2.6-tracehook.patch b/linux-2.6-tracehook.patch deleted file mode 100644 index 027c6d533..000000000 --- a/linux-2.6-tracehook.patch +++ /dev/null @@ -1,129 +0,0 @@ -From: Oleg Nesterov - -[PATCH] signals: check ->group_stop_count after tracehook_get_signal() - -Move the call to do_signal_stop() down, after tracehook call. -This makes ->group_stop_count condition visible to tracers before -do_signal_stop() will participate in this group-stop. - -Currently the patch has no effect, tracehook_get_signal() always -returns 0. - -Signed-off-by: Oleg Nesterov -Signed-off-by: Roland McGrath ---- - include/linux/ptrace.h | 1 + - include/linux/sched.h | 1 + - include/linux/tracehook.h | 10 +++++----- - kernel/ptrace.c | 2 +- - kernel/signal.c | 4 ++-- - 5 files changed, 10 insertions(+), 8 deletions(-) - -diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h -index 092a04f..619cdf0 100644 ---- a/include/linux/ptrace.h -+++ b/include/linux/ptrace.h -@@ -106,6 +106,7 @@ extern int ptrace_traceme(void); - extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len); - extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len); - extern int ptrace_attach(struct task_struct *tsk); -+extern bool __ptrace_detach(struct task_struct *tracer, struct task_struct *tracee); - extern int ptrace_detach(struct task_struct *, unsigned int); - extern void ptrace_disable(struct task_struct *); - extern int ptrace_check_attach(struct task_struct *task, int kill); -diff --git a/include/linux/sched.h b/include/linux/sched.h -index 2238745..09f26df 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -2061,6 +2061,7 @@ extern int kill_pgrp(struct pid *pid, in - extern int kill_pid(struct pid *pid, int sig, int priv); - extern int kill_proc_info(int, struct siginfo *, pid_t); - extern int do_notify_parent(struct task_struct *, int); -+extern void do_notify_parent_cldstop(struct task_struct *, int); - extern void __wake_up_parent(struct task_struct *p, struct task_struct *parent); - extern void force_sig(int, struct task_struct *); - extern int send_sig(int, struct task_struct *, int); -diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h -index 3a2e66d..98917e9 100644 ---- a/include/linux/tracehook.h -+++ b/include/linux/tracehook.h -@@ -134,7 +134,7 @@ static inline __must_check int tracehook - */ - static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) - { -- if (step) { -+ if (step && (task_ptrace(current) & PT_PTRACED)) { - siginfo_t info; - user_single_step_siginfo(current, regs, &info); - force_sig_info(SIGTRAP, &info, current); -@@ -156,7 +156,7 @@ static inline int tracehook_unsafe_exec( - { - int unsafe = 0; - int ptrace = task_ptrace(task); -- if (ptrace & PT_PTRACED) { -+ if (ptrace) { - if (ptrace & PT_PTRACE_CAP) - unsafe |= LSM_UNSAFE_PTRACE_CAP; - else -@@ -178,7 +178,7 @@ static inline int tracehook_unsafe_exec( - */ - static inline struct task_struct *tracehook_tracer_task(struct task_struct *tsk) - { -- if (task_ptrace(tsk) & PT_PTRACED) -+ if (task_ptrace(tsk)) - return rcu_dereference(tsk->parent); - return NULL; - } -@@ -386,7 +386,7 @@ static inline void tracehook_signal_hand - const struct k_sigaction *ka, - struct pt_regs *regs, int stepping) - { -- if (stepping) -+ if (stepping && (task_ptrace(current) & PT_PTRACED)) - ptrace_notify(SIGTRAP); - } - -@@ -492,7 +492,7 @@ static inline int tracehook_get_signal(s - */ - static inline int tracehook_notify_jctl(int notify, int why) - { -- return notify ?: (current->ptrace & PT_PTRACED) ? why : 0; -+ return notify ?: task_ptrace(current) ? why : 0; - } - - /** -diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index 99bbaa3..84d9f8f 100644 ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -270,7 +270,7 @@ static int ignoring_children(struct sigh - * reap it now, in that case we must also wake up sub-threads sleeping in - * do_wait(). - */ --static bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p) -+bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p) - { - __ptrace_unlink(p); - -diff --git a/kernel/signal.c b/kernel/signal.c -index 4e3cff1..b74324d 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -1522,7 +1522,7 @@ int do_notify_parent(struct task_struct - return ret; - } - --static void do_notify_parent_cldstop(struct task_struct *tsk, int why) -+void do_notify_parent_cldstop(struct task_struct *tsk, int why) - { - struct siginfo info; - unsigned long flags; -@@ -1794,7 +1794,7 @@ static int do_signal_stop(int signr) - static int ptrace_signal(int signr, siginfo_t *info, - struct pt_regs *regs, void *cookie) - { -- if (!task_ptrace(current)) -+ if (!(task_ptrace(current) & PT_PTRACED)) - return signr; - - ptrace_signal_deliver(regs, cookie); diff --git a/linux-2.6-utrace-ptrace.patch b/linux-2.6-utrace-ptrace.patch deleted file mode 100644 index bc5681d95..000000000 --- a/linux-2.6-utrace-ptrace.patch +++ /dev/null @@ -1,2028 +0,0 @@ -implement utrace-ptrace - -The patch adds the new file, kernel/ptrace-utrace.c, which contains -the new implementation of ptrace over utrace. - -This file is not compiled until we have CONFIG_UTRACE option, will be -added by the next "utrace core" patch. - -It's supposed to be an invisible implementation change, nothing should -change to userland when CONFIG_UTRACE is enabled. - -Signed-off-by: Roland McGrath -Signed-off-by: Oleg Nesterov ---- - include/linux/ptrace.h | 1 + - kernel/Makefile | 1 + - kernel/ptrace-utrace.c | 1187 ++++++++++++++++++++++++++++++++++++++++++++++++ - kernel/ptrace.c | 690 ++++++++++++++-------------- - kernel/utrace.c | 16 + - 5 files changed, 1544 insertions(+), 351 deletions(-) - -diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h -index 619cdf0..e391bdb 100644 ---- a/include/linux/ptrace.h -+++ b/include/linux/ptrace.h -@@ -100,6 +100,7 @@ - #include /* For struct task_struct. */ - - -+extern void ptrace_notify_stop(struct task_struct *tracee); - extern long arch_ptrace(struct task_struct *child, long request, - unsigned long addr, unsigned long data); - extern int ptrace_traceme(void); -diff --git a/kernel/Makefile b/kernel/Makefile -index 1172528..9a815a5 100644 ---- a/kernel/Makefile -+++ b/kernel/Makefile -@@ -71,6 +71,7 @@ obj-$(CONFIG_RESOURCE_COUNTERS) += res_c - obj-$(CONFIG_SMP) += stop_machine.o - obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o - obj-$(CONFIG_UTRACE) += utrace.o -+obj-$(CONFIG_UTRACE) += ptrace-utrace.o - obj-$(CONFIG_AUDIT) += audit.o auditfilter.o - obj-$(CONFIG_AUDITSYSCALL) += auditsc.o - obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o -diff --git a/kernel/ptrace-utrace.c b/kernel/ptrace-utrace.c -new file mode 100644 -index ...a5bcb9e 100644 ---- /dev/null -+++ b/kernel/ptrace-utrace.c -@@ -0,0 +1,1187 @@ -+/* -+ * linux/kernel/ptrace.c -+ * -+ * (C) Copyright 1999 Linus Torvalds -+ * -+ * Common interfaces for "ptrace()" which we do not want -+ * to continually duplicate across every architecture. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * ptrace a task: make the debugger its new parent and -+ * move it to the ptrace list. -+ * -+ * Must be called with the tasklist lock write-held. -+ */ -+void __ptrace_link(struct task_struct *child, struct task_struct *new_parent) -+{ -+ BUG_ON(!list_empty(&child->ptrace_entry)); -+ list_add(&child->ptrace_entry, &new_parent->ptraced); -+ child->parent = new_parent; -+} -+ -+/* -+ * unptrace a task: move it back to its original parent and -+ * remove it from the ptrace list. -+ * -+ * Must be called with the tasklist lock write-held. -+ */ -+void __ptrace_unlink(struct task_struct *child) -+{ -+ BUG_ON(!child->ptrace); -+ -+ child->ptrace = 0; -+ child->parent = child->real_parent; -+ list_del_init(&child->ptrace_entry); -+} -+ -+struct ptrace_context { -+ int options; -+ -+ int signr; -+ siginfo_t *siginfo; -+ -+ int stop_code; -+ unsigned long eventmsg; -+ -+ enum utrace_resume_action resume; -+}; -+ -+#define PT_UTRACED 0x00001000 -+ -+#define PTRACE_O_SYSEMU 0x100 -+#define PTRACE_O_DETACHED 0x200 -+ -+#define PTRACE_EVENT_SYSCALL (1 << 16) -+#define PTRACE_EVENT_SIGTRAP (2 << 16) -+#define PTRACE_EVENT_SIGNAL (3 << 16) -+/* events visible to user-space */ -+#define PTRACE_EVENT_MASK 0xFFFF -+ -+static inline bool ptrace_event_pending(struct ptrace_context *ctx) -+{ -+ return ctx->stop_code != 0; -+} -+ -+static inline int get_stop_event(struct ptrace_context *ctx) -+{ -+ return ctx->stop_code >> 8; -+} -+ -+static inline void set_stop_code(struct ptrace_context *ctx, int event) -+{ -+ ctx->stop_code = (event << 8) | SIGTRAP; -+} -+ -+static inline struct ptrace_context * -+ptrace_context(struct utrace_engine *engine) -+{ -+ return engine->data; -+} -+ -+static const struct utrace_engine_ops ptrace_utrace_ops; /* forward decl */ -+ -+static struct utrace_engine *ptrace_lookup_engine(struct task_struct *tracee) -+{ -+ return utrace_attach_task(tracee, UTRACE_ATTACH_MATCH_OPS, -+ &ptrace_utrace_ops, NULL); -+} -+ -+static int utrace_barrier_uninterruptible(struct task_struct *target, -+ struct utrace_engine *engine) -+{ -+ for (;;) { -+ int err = utrace_barrier(target, engine); -+ -+ if (err != -ERESTARTSYS) -+ return err; -+ -+ schedule_timeout_uninterruptible(1); -+ } -+} -+ -+static struct utrace_engine * -+ptrace_reuse_engine(struct task_struct *tracee) -+{ -+ struct utrace_engine *engine; -+ struct ptrace_context *ctx; -+ int err = -EPERM; -+ -+ engine = ptrace_lookup_engine(tracee); -+ if (IS_ERR(engine)) -+ return engine; -+ -+ ctx = ptrace_context(engine); -+ if (unlikely(ctx->options == PTRACE_O_DETACHED)) { -+ /* -+ * Try to reuse this self-detaching engine. -+ * The only caller which can hit this case is ptrace_attach(), -+ * it holds ->cred_guard_mutex. -+ */ -+ ctx->options = 0; -+ ctx->eventmsg = 0; -+ -+ /* make sure we don't get unwanted reports */ -+ err = utrace_set_events(tracee, engine, UTRACE_EVENT(QUIESCE)); -+ if (!err || err == -EINPROGRESS) { -+ ctx->resume = UTRACE_RESUME; -+ /* synchronize with ptrace_report_signal() */ -+ err = utrace_barrier_uninterruptible(tracee, engine); -+ } -+ -+ if (!err) { -+ WARN_ON(engine->ops != &ptrace_utrace_ops && -+ !tracee->exit_state); -+ return engine; -+ } -+ -+ WARN_ON(engine->ops == &ptrace_utrace_ops); -+ } -+ -+ utrace_engine_put(engine); -+ return ERR_PTR(err); -+} -+ -+static struct utrace_engine * -+ptrace_attach_engine(struct task_struct *tracee) -+{ -+ struct utrace_engine *engine; -+ struct ptrace_context *ctx; -+ -+ if (unlikely(task_utrace_flags(tracee))) { -+ engine = ptrace_reuse_engine(tracee); -+ if (!IS_ERR(engine) || IS_ERR(engine) == -EPERM) -+ return engine; -+ } -+ -+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); -+ if (unlikely(!ctx)) -+ return ERR_PTR(-ENOMEM); -+ -+ ctx->resume = UTRACE_RESUME; -+ -+ engine = utrace_attach_task(tracee, UTRACE_ATTACH_CREATE | -+ UTRACE_ATTACH_EXCLUSIVE | -+ UTRACE_ATTACH_MATCH_OPS, -+ &ptrace_utrace_ops, ctx); -+ if (unlikely(IS_ERR(engine))) { -+ if (engine != ERR_PTR(-ESRCH) && -+ engine != ERR_PTR(-ERESTARTNOINTR)) -+ engine = ERR_PTR(-EPERM); -+ kfree(ctx); -+ } -+ -+ return engine; -+} -+ -+static inline int ptrace_set_events(struct task_struct *target, -+ struct utrace_engine *engine, -+ unsigned long options) -+{ -+ struct ptrace_context *ctx = ptrace_context(engine); -+ /* -+ * We need QUIESCE for resume handling, CLONE to check -+ * for CLONE_PTRACE, other events are always reported. -+ */ -+ unsigned long events = UTRACE_EVENT(QUIESCE) | UTRACE_EVENT(CLONE) | -+ UTRACE_EVENT(EXEC) | UTRACE_EVENT_SIGNAL_ALL; -+ -+ ctx->options = options; -+ if (options & PTRACE_O_TRACEEXIT) -+ events |= UTRACE_EVENT(EXIT); -+ -+ return utrace_set_events(target, engine, events); -+} -+ -+/* -+ * Attach a utrace engine for ptrace and set up its event mask. -+ * Returns error code or 0 on success. -+ */ -+static int ptrace_attach_task(struct task_struct *tracee, int options) -+{ -+ struct utrace_engine *engine; -+ int err; -+ -+ engine = ptrace_attach_engine(tracee); -+ if (IS_ERR(engine)) -+ return PTR_ERR(engine); -+ /* -+ * It can fail only if the tracee is dead, the caller -+ * must notice this before setting PT_UTRACED. -+ */ -+ err = ptrace_set_events(tracee, engine, options); -+ WARN_ON(err && !tracee->exit_state); -+ utrace_engine_put(engine); -+ return 0; -+} -+ -+static int ptrace_wake_up(struct task_struct *tracee, -+ struct utrace_engine *engine, -+ enum utrace_resume_action action, -+ bool force_wakeup) -+{ -+ if (force_wakeup) { -+ unsigned long flags; -+ /* -+ * Preserve the compatibility bug. Historically ptrace -+ * wakes up the tracee even if it should not. Clear -+ * SIGNAL_STOP_STOPPED for utrace_wakeup(). -+ */ -+ if (lock_task_sighand(tracee, &flags)) { -+ tracee->signal->flags &= ~SIGNAL_STOP_STOPPED; -+ unlock_task_sighand(tracee, &flags); -+ } -+ } -+ -+ if (action != UTRACE_REPORT) -+ ptrace_context(engine)->stop_code = 0; -+ -+ return utrace_control(tracee, engine, action); -+} -+ -+static void ptrace_detach_task(struct task_struct *tracee, int sig) -+{ -+ /* -+ * If true, the caller is PTRACE_DETACH, otherwise -+ * the tracer detaches implicitly during exit. -+ */ -+ bool explicit = (sig >= 0); -+ struct utrace_engine *engine = ptrace_lookup_engine(tracee); -+ enum utrace_resume_action action = UTRACE_DETACH; -+ struct ptrace_context *ctx; -+ -+ if (unlikely(IS_ERR(engine))) -+ return; -+ -+ ctx = ptrace_context(engine); -+ -+ if (!explicit) { -+ int err; -+ -+ /* -+ * We are going to detach, the tracee can be running. -+ * Ensure ptrace_report_signal() won't report a signal. -+ */ -+ ctx->resume = UTRACE_DETACH; -+ err = utrace_barrier_uninterruptible(tracee, engine); -+ -+ if (!err && ctx->siginfo) { -+ /* -+ * The tracee has already reported a signal -+ * before utrace_barrier(). -+ * -+ * Resume it like we do in PTRACE_EVENT_SIGNAL -+ * case below. The difference is that we can race -+ * with ptrace_report_signal() if the tracee is -+ * running but this doesn't matter. In any case -+ * UTRACE_SIGNAL_REPORT must be pending and it -+ * can return nothing but UTRACE_DETACH. -+ */ -+ action = UTRACE_RESUME; -+ } -+ -+ } else if (sig) { -+ switch (get_stop_event(ctx)) { -+ case PTRACE_EVENT_SYSCALL: -+ send_sig_info(sig, SEND_SIG_PRIV, tracee); -+ break; -+ -+ case PTRACE_EVENT_SIGNAL: -+ ctx->signr = sig; -+ ctx->resume = UTRACE_DETACH; -+ action = UTRACE_RESUME; -+ break; -+ } -+ } -+ -+ ptrace_wake_up(tracee, engine, action, explicit); -+ -+ if (action != UTRACE_DETACH) -+ ctx->options = PTRACE_O_DETACHED; -+ -+ utrace_engine_put(engine); -+} -+ -+static void ptrace_abort_attach(struct task_struct *tracee) -+{ -+ ptrace_detach_task(tracee, 0); -+} -+ -+static u32 ptrace_report_exit(u32 action, struct utrace_engine *engine, -+ long orig_code, long *code) -+{ -+ struct ptrace_context *ctx = ptrace_context(engine); -+ -+ WARN_ON(ptrace_event_pending(ctx) && -+ !signal_group_exit(current->signal)); -+ -+ set_stop_code(ctx, PTRACE_EVENT_EXIT); -+ ctx->eventmsg = *code; -+ -+ return UTRACE_STOP; -+} -+ -+static void ptrace_clone_attach(struct task_struct *child, -+ int options) -+{ -+ struct task_struct *parent = current; -+ struct task_struct *tracer; -+ bool abort = true; -+ -+ if (unlikely(ptrace_attach_task(child, options))) { -+ WARN_ON(1); -+ return; -+ } -+ -+ write_lock_irq(&tasklist_lock); -+ tracer = parent->parent; -+ if (!(tracer->flags & PF_EXITING) && parent->ptrace) { -+ child->ptrace = parent->ptrace; -+ __ptrace_link(child, tracer); -+ abort = false; -+ } -+ write_unlock_irq(&tasklist_lock); -+ if (unlikely(abort)) { -+ ptrace_abort_attach(child); -+ return; -+ } -+ -+ sigaddset(&child->pending.signal, SIGSTOP); -+ set_tsk_thread_flag(child, TIF_SIGPENDING); -+} -+ -+static u32 ptrace_report_clone(u32 action, struct utrace_engine *engine, -+ unsigned long clone_flags, -+ struct task_struct *child) -+{ -+ struct ptrace_context *ctx = ptrace_context(engine); -+ int event = 0; -+ -+ WARN_ON(ptrace_event_pending(ctx)); -+ -+ if (clone_flags & CLONE_UNTRACED) { -+ /* no events reported */ -+ } else if (clone_flags & CLONE_VFORK) { -+ if (ctx->options & PTRACE_O_TRACEVFORK) -+ event = PTRACE_EVENT_VFORK; -+ else if (ctx->options & PTRACE_O_TRACEVFORKDONE) -+ event = PTRACE_EVENT_VFORK_DONE; -+ } else if ((clone_flags & CSIGNAL) != SIGCHLD) { -+ if (ctx->options & PTRACE_O_TRACECLONE) -+ event = PTRACE_EVENT_CLONE; -+ } else if (ctx->options & PTRACE_O_TRACEFORK) { -+ event = PTRACE_EVENT_FORK; -+ } -+ /* -+ * Any of these reports implies auto-attaching the new child. -+ * So does CLONE_PTRACE, even with no event to report. -+ */ -+ if ((event && event != PTRACE_EVENT_VFORK_DONE) || -+ (clone_flags & CLONE_PTRACE)) -+ ptrace_clone_attach(child, ctx->options); -+ -+ if (!event) -+ return UTRACE_RESUME; -+ -+ set_stop_code(ctx, event); -+ ctx->eventmsg = child->pid; -+ /* -+ * We shouldn't stop now, inside the do_fork() path. -+ * We will stop later, before return to user-mode. -+ */ -+ if (event == PTRACE_EVENT_VFORK_DONE) -+ return UTRACE_REPORT; -+ else -+ return UTRACE_STOP; -+} -+ -+static inline void set_syscall_code(struct ptrace_context *ctx) -+{ -+ set_stop_code(ctx, PTRACE_EVENT_SYSCALL); -+ if (ctx->options & PTRACE_O_TRACESYSGOOD) -+ ctx->stop_code |= 0x80; -+} -+ -+static u32 ptrace_report_syscall_entry(u32 action, struct utrace_engine *engine, -+ struct pt_regs *regs) -+{ -+ struct ptrace_context *ctx = ptrace_context(engine); -+ -+ if (action & UTRACE_SYSCALL_RESUMED) { -+ /* -+ * We already reported the first time. -+ * Nothing more to do now. -+ */ -+ if (unlikely(ctx->options & PTRACE_O_SYSEMU)) -+ return UTRACE_SYSCALL_ABORT | UTRACE_REPORT; -+ return utrace_syscall_action(action) | UTRACE_RESUME; -+ } -+ -+ WARN_ON(ptrace_event_pending(ctx)); -+ -+ set_syscall_code(ctx); -+ -+ if (unlikely(ctx->options & PTRACE_O_SYSEMU)) -+ return UTRACE_SYSCALL_ABORT | UTRACE_REPORT; -+ /* -+ * Stop now to report. We will get another callback after -+ * we resume, with the UTRACE_SYSCALL_RESUMED flag set. -+ */ -+ return UTRACE_SYSCALL_RUN | UTRACE_STOP; -+} -+ -+static inline bool is_step_resume(enum utrace_resume_action resume) -+{ -+ return resume == UTRACE_BLOCKSTEP || resume == UTRACE_SINGLESTEP; -+} -+ -+static u32 ptrace_report_syscall_exit(u32 action, struct utrace_engine *engine, -+ struct pt_regs *regs) -+{ -+ struct ptrace_context *ctx = ptrace_context(engine); -+ -+ if (ptrace_event_pending(ctx)) -+ return UTRACE_STOP; -+ -+ if (is_step_resume(ctx->resume)) { -+ ctx->signr = SIGTRAP; -+ return UTRACE_INTERRUPT; -+ } -+ -+ set_syscall_code(ctx); -+ return UTRACE_STOP; -+} -+ -+static u32 ptrace_report_exec(u32 action, struct utrace_engine *engine, -+ const struct linux_binfmt *fmt, -+ const struct linux_binprm *bprm, -+ struct pt_regs *regs) -+{ -+ struct ptrace_context *ctx = ptrace_context(engine); -+ -+ WARN_ON(ptrace_event_pending(ctx)); -+ -+ if (!(ctx->options & PTRACE_O_TRACEEXEC)) { -+ /* -+ * Old-fashioned ptrace'd exec just posts a plain signal. -+ */ -+ send_sig(SIGTRAP, current, 0); -+ return UTRACE_RESUME; -+ } -+ -+ set_stop_code(ctx, PTRACE_EVENT_EXEC); -+ return UTRACE_STOP; -+} -+ -+static enum utrace_signal_action resume_signal(struct ptrace_context *ctx, -+ struct k_sigaction *return_ka) -+{ -+ siginfo_t *info = ctx->siginfo; -+ int signr = ctx->signr; -+ -+ ctx->siginfo = NULL; -+ ctx->signr = 0; -+ -+ /* Did the debugger cancel the sig? */ -+ if (!signr) -+ return UTRACE_SIGNAL_IGN; -+ /* -+ * Update the siginfo structure if the signal has changed. -+ * If the debugger wanted something specific in the siginfo -+ * then it should have updated *info via PTRACE_SETSIGINFO. -+ */ -+ if (info->si_signo != signr) { -+ info->si_signo = signr; -+ info->si_errno = 0; -+ info->si_code = SI_USER; -+ info->si_pid = task_pid_vnr(current->parent); -+ info->si_uid = task_uid(current->parent); -+ } -+ -+ /* If the (new) signal is now blocked, requeue it. */ -+ if (sigismember(¤t->blocked, signr)) { -+ send_sig_info(signr, info, current); -+ return UTRACE_SIGNAL_IGN; -+ } -+ -+ spin_lock_irq(¤t->sighand->siglock); -+ *return_ka = current->sighand->action[signr - 1]; -+ spin_unlock_irq(¤t->sighand->siglock); -+ -+ return UTRACE_SIGNAL_DELIVER; -+} -+ -+static u32 ptrace_report_signal(u32 action, struct utrace_engine *engine, -+ struct pt_regs *regs, -+ siginfo_t *info, -+ const struct k_sigaction *orig_ka, -+ struct k_sigaction *return_ka) -+{ -+ struct ptrace_context *ctx = ptrace_context(engine); -+ enum utrace_resume_action resume = ctx->resume; -+ -+ if (ptrace_event_pending(ctx)) { -+ action = utrace_signal_action(action); -+ WARN_ON(action != UTRACE_SIGNAL_REPORT); -+ return action | UTRACE_STOP; -+ } -+ -+ switch (utrace_signal_action(action)) { -+ case UTRACE_SIGNAL_HANDLER: -+ if (WARN_ON(ctx->siginfo)) -+ ctx->siginfo = NULL; -+ -+ if (is_step_resume(resume)) { -+ set_stop_code(ctx, PTRACE_EVENT_SIGTRAP); -+ return UTRACE_STOP | UTRACE_SIGNAL_IGN; -+ } -+ -+ case UTRACE_SIGNAL_REPORT: -+ if (!ctx->siginfo) { -+ if (ctx->signr) { -+ /* set by ptrace_resume(SYSCALL_EXIT) */ -+ WARN_ON(ctx->signr != SIGTRAP); -+ user_single_step_siginfo(current, regs, info); -+ force_sig_info(SIGTRAP, info, current); -+ } -+ -+ return resume | UTRACE_SIGNAL_IGN; -+ } -+ -+ if (WARN_ON(ctx->siginfo != info)) -+ return resume | UTRACE_SIGNAL_IGN; -+ -+ return resume | resume_signal(ctx, return_ka); -+ -+ default: -+ break; -+ } -+ -+ WARN_ON(ctx->siginfo); -+ -+ /* Raced with the exiting tracer ? */ -+ if (resume == UTRACE_DETACH) -+ return action; -+ -+ ctx->siginfo = info; -+ /* -+ * ctx->siginfo points to the caller's stack. -+ * Make sure the subsequent UTRACE_SIGNAL_REPORT clears -+ * ->siginfo before return from get_signal_to_deliver(). -+ */ -+ if (utrace_control(current, engine, UTRACE_INTERRUPT)) -+ WARN_ON(1); -+ -+ ctx->signr = info->si_signo; -+ ctx->stop_code = (PTRACE_EVENT_SIGNAL << 8) | ctx->signr; -+ -+ return UTRACE_STOP | UTRACE_SIGNAL_IGN; -+} -+ -+static u32 ptrace_report_quiesce(u32 action, struct utrace_engine *engine, -+ unsigned long event) -+{ -+ struct ptrace_context *ctx = ptrace_context(engine); -+ -+ if (ptrace_event_pending(ctx)) -+ return UTRACE_STOP; -+ -+ return event ? UTRACE_RESUME : ctx->resume; -+} -+ -+static void ptrace_release(void *data) -+{ -+ kfree(data); -+} -+ -+static const struct utrace_engine_ops ptrace_utrace_ops = { -+ .report_signal = ptrace_report_signal, -+ .report_quiesce = ptrace_report_quiesce, -+ .report_exec = ptrace_report_exec, -+ .report_exit = ptrace_report_exit, -+ .report_clone = ptrace_report_clone, -+ .report_syscall_entry = ptrace_report_syscall_entry, -+ .report_syscall_exit = ptrace_report_syscall_exit, -+ .release = ptrace_release, -+}; -+ -+int ptrace_check_attach(struct task_struct *child, int kill) -+{ -+ struct utrace_engine *engine; -+ struct utrace_examiner exam; -+ int ret = -ESRCH; -+ -+ engine = ptrace_lookup_engine(child); -+ if (IS_ERR(engine)) -+ return ret; -+ -+ if (child->parent != current) -+ goto out; -+ -+ if (unlikely(kill)) -+ ret = 0; -+ -+ if (!task_is_stopped_or_traced(child)) -+ goto out; -+ /* -+ * Make sure our engine has already stopped the child. -+ * Then wait for it to be off the CPU. -+ */ -+ if (!utrace_control(child, engine, UTRACE_STOP) && -+ !utrace_prepare_examine(child, engine, &exam)) -+ ret = 0; -+out: -+ utrace_engine_put(engine); -+ return ret; -+} -+ -+int ptrace_attach(struct task_struct *task) -+{ -+ int retval; -+ -+ audit_ptrace(task); -+ -+ retval = -EPERM; -+ if (unlikely(task->flags & PF_KTHREAD)) -+ goto out; -+ if (same_thread_group(task, current)) -+ goto out; -+ -+ /* -+ * Protect exec's credential calculations against our interference; -+ * interference; SUID, SGID and LSM creds get determined differently -+ * under ptrace. -+ */ -+ retval = -ERESTARTNOINTR; -+ if (mutex_lock_interruptible(&task->signal->cred_guard_mutex)) -+ goto out; -+ -+ task_lock(task); -+ retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH); -+ task_unlock(task); -+ if (retval) -+ goto unlock_creds; -+ -+ retval = ptrace_attach_task(task, 0); -+ if (unlikely(retval)) -+ goto unlock_creds; -+ -+ write_lock_irq(&tasklist_lock); -+ retval = -EPERM; -+ if (unlikely(task->exit_state)) -+ goto unlock_tasklist; -+ -+ BUG_ON(task->ptrace); -+ task->ptrace = PT_UTRACED; -+ if (capable(CAP_SYS_PTRACE)) -+ task->ptrace |= PT_PTRACE_CAP; -+ -+ __ptrace_link(task, current); -+ send_sig_info(SIGSTOP, SEND_SIG_FORCED, task); -+ -+ retval = 0; -+unlock_tasklist: -+ write_unlock_irq(&tasklist_lock); -+unlock_creds: -+ mutex_unlock(&task->signal->cred_guard_mutex); -+out: -+ return retval; -+} -+ -+/* -+ * Performs checks and sets PT_UTRACED. -+ * Should be used by all ptrace implementations for PTRACE_TRACEME. -+ */ -+int ptrace_traceme(void) -+{ -+ bool detach = true; -+ int ret = ptrace_attach_task(current, 0); -+ -+ if (unlikely(ret)) -+ return ret; -+ -+ ret = -EPERM; -+ write_lock_irq(&tasklist_lock); -+ BUG_ON(current->ptrace); -+ ret = security_ptrace_traceme(current->parent); -+ /* -+ * Check PF_EXITING to ensure ->real_parent has not passed -+ * exit_ptrace(). Otherwise we don't report the error but -+ * pretend ->real_parent untraces us right after return. -+ */ -+ if (!ret && !(current->real_parent->flags & PF_EXITING)) { -+ current->ptrace = PT_UTRACED; -+ __ptrace_link(current, current->real_parent); -+ detach = false; -+ } -+ write_unlock_irq(&tasklist_lock); -+ -+ if (detach) -+ ptrace_abort_attach(current); -+ return ret; -+} -+ -+static void ptrace_do_detach(struct task_struct *tracee, unsigned int data) -+{ -+ bool detach, release; -+ -+ write_lock_irq(&tasklist_lock); -+ /* -+ * This tracee can be already killed. Make sure de_thread() or -+ * our sub-thread doing do_wait() didn't do release_task() yet. -+ */ -+ detach = tracee->ptrace != 0; -+ release = false; -+ if (likely(detach)) -+ release = __ptrace_detach(current, tracee); -+ write_unlock_irq(&tasklist_lock); -+ -+ if (unlikely(release)) -+ release_task(tracee); -+ else if (likely(detach)) -+ ptrace_detach_task(tracee, data); -+} -+ -+int ptrace_detach(struct task_struct *child, unsigned int data) -+{ -+ if (!valid_signal(data)) -+ return -EIO; -+ -+ ptrace_do_detach(child, data); -+ -+ return 0; -+} -+ -+/* -+ * Detach all tasks we were using ptrace on. Called with tasklist held -+ * for writing, and returns with it held too. But note it can release -+ * and reacquire the lock. -+ */ -+void exit_ptrace(struct task_struct *tracer) -+{ -+ bool locked = true; -+ -+ for (;;) { -+ struct task_struct *tracee = NULL; -+ -+ if (!locked) -+ read_lock(&tasklist_lock); -+ if (!list_empty(&tracer->ptraced)) { -+ tracee = list_first_entry(&tracer->ptraced, -+ struct task_struct, ptrace_entry); -+ get_task_struct(tracee); -+ } -+ if (!locked) -+ read_unlock(&tasklist_lock); -+ if (!tracee) -+ break; -+ -+ if (locked) { -+ write_unlock_irq(&tasklist_lock); -+ locked = false; -+ } -+ ptrace_do_detach(tracee, -1); -+ put_task_struct(tracee); -+ } -+ -+ if (!locked) -+ write_lock_irq(&tasklist_lock); -+} -+ -+static int ptrace_set_options(struct task_struct *tracee, -+ struct utrace_engine *engine, long data) -+{ -+ BUILD_BUG_ON(PTRACE_O_MASK & (PTRACE_O_SYSEMU | PTRACE_O_DETACHED)); -+ -+ ptrace_set_events(tracee, engine, data & PTRACE_O_MASK); -+ return (data & ~PTRACE_O_MASK) ? -EINVAL : 0; -+} -+ -+static int ptrace_rw_siginfo(struct task_struct *tracee, -+ struct ptrace_context *ctx, -+ siginfo_t *info, bool write) -+{ -+ unsigned long flags; -+ int err; -+ -+ switch (get_stop_event(ctx)) { -+ case 0: /* jctl stop */ -+ return -EINVAL; -+ -+ case PTRACE_EVENT_SIGNAL: -+ err = -ESRCH; -+ if (lock_task_sighand(tracee, &flags)) { -+ if (likely(task_is_traced(tracee))) { -+ if (write) -+ *ctx->siginfo = *info; -+ else -+ *info = *ctx->siginfo; -+ err = 0; -+ } -+ unlock_task_sighand(tracee, &flags); -+ } -+ -+ return err; -+ -+ default: -+ if (!write) { -+ memset(info, 0, sizeof(*info)); -+ info->si_signo = SIGTRAP; -+ info->si_code = ctx->stop_code & PTRACE_EVENT_MASK; -+ info->si_pid = task_pid_vnr(tracee); -+ info->si_uid = task_uid(tracee); -+ } -+ -+ return 0; -+ } -+} -+ -+static void do_ptrace_notify_stop(struct ptrace_context *ctx, -+ struct task_struct *tracee) -+{ -+ /* -+ * This can race with SIGKILL, but we borrow this race from -+ * the old ptrace implementation. ->exit_code is only needed -+ * for wait_task_stopped()->task_stopped_code(), we should -+ * change it to use ptrace_context. -+ */ -+ tracee->exit_code = ctx->stop_code & PTRACE_EVENT_MASK; -+ WARN_ON(!tracee->exit_code); -+ -+ read_lock(&tasklist_lock); -+ /* -+ * Don't want to allow preemption here, because -+ * sys_ptrace() needs this task to be inactive. -+ */ -+ preempt_disable(); -+ /* -+ * It can be killed and then released by our subthread, -+ * or ptrace_attach() has not completed yet. -+ */ -+ if (task_ptrace(tracee)) -+ do_notify_parent_cldstop(tracee, CLD_TRAPPED); -+ read_unlock(&tasklist_lock); -+ preempt_enable_no_resched(); -+} -+ -+void ptrace_notify_stop(struct task_struct *tracee) -+{ -+ struct utrace_engine *engine = ptrace_lookup_engine(tracee); -+ -+ if (IS_ERR(engine)) -+ return; -+ -+ do_ptrace_notify_stop(ptrace_context(engine), tracee); -+ utrace_engine_put(engine); -+} -+ -+static int ptrace_resume_action(struct task_struct *tracee, -+ struct utrace_engine *engine, long request) -+{ -+ struct ptrace_context *ctx = ptrace_context(engine); -+ unsigned long events; -+ int action; -+ -+ ctx->options &= ~PTRACE_O_SYSEMU; -+ events = engine->flags & ~UTRACE_EVENT_SYSCALL; -+ action = UTRACE_RESUME; -+ -+ switch (request) { -+#ifdef PTRACE_SINGLEBLOCK -+ case PTRACE_SINGLEBLOCK: -+ if (unlikely(!arch_has_block_step())) -+ return -EIO; -+ action = UTRACE_BLOCKSTEP; -+ events |= UTRACE_EVENT(SYSCALL_EXIT); -+ break; -+#endif -+ -+#ifdef PTRACE_SINGLESTEP -+ case PTRACE_SINGLESTEP: -+ if (unlikely(!arch_has_single_step())) -+ return -EIO; -+ action = UTRACE_SINGLESTEP; -+ events |= UTRACE_EVENT(SYSCALL_EXIT); -+ break; -+#endif -+ -+#ifdef PTRACE_SYSEMU -+ case PTRACE_SYSEMU_SINGLESTEP: -+ if (unlikely(!arch_has_single_step())) -+ return -EIO; -+ action = UTRACE_SINGLESTEP; -+ case PTRACE_SYSEMU: -+ ctx->options |= PTRACE_O_SYSEMU; -+ events |= UTRACE_EVENT(SYSCALL_ENTRY); -+ break; -+#endif -+ -+ case PTRACE_SYSCALL: -+ events |= UTRACE_EVENT_SYSCALL; -+ break; -+ -+ case PTRACE_CONT: -+ break; -+ default: -+ return -EIO; -+ } -+ -+ if (events != engine->flags && -+ utrace_set_events(tracee, engine, events)) -+ return -ESRCH; -+ -+ return action; -+} -+ -+static int ptrace_resume(struct task_struct *tracee, -+ struct utrace_engine *engine, -+ long request, long data) -+{ -+ struct ptrace_context *ctx = ptrace_context(engine); -+ int action; -+ -+ if (!valid_signal(data)) -+ return -EIO; -+ -+ action = ptrace_resume_action(tracee, engine, request); -+ if (action < 0) -+ return action; -+ -+ switch (get_stop_event(ctx)) { -+ case PTRACE_EVENT_VFORK: -+ if (ctx->options & PTRACE_O_TRACEVFORKDONE) { -+ set_stop_code(ctx, PTRACE_EVENT_VFORK_DONE); -+ action = UTRACE_REPORT; -+ } -+ break; -+ -+ case PTRACE_EVENT_EXEC: -+ case PTRACE_EVENT_FORK: -+ case PTRACE_EVENT_CLONE: -+ case PTRACE_EVENT_VFORK_DONE: -+ if (request == PTRACE_SYSCALL) { -+ set_syscall_code(ctx); -+ do_ptrace_notify_stop(ctx, tracee); -+ return 0; -+ } -+ -+ if (action != UTRACE_RESUME) { -+ /* -+ * single-stepping. UTRACE_SIGNAL_REPORT will -+ * synthesize a trap to follow the syscall insn. -+ */ -+ ctx->signr = SIGTRAP; -+ action = UTRACE_INTERRUPT; -+ } -+ break; -+ -+ case PTRACE_EVENT_SYSCALL: -+ if (data) -+ send_sig_info(data, SEND_SIG_PRIV, tracee); -+ break; -+ -+ case PTRACE_EVENT_SIGNAL: -+ ctx->signr = data; -+ break; -+ } -+ -+ ctx->resume = action; -+ ptrace_wake_up(tracee, engine, action, true); -+ return 0; -+} -+ -+extern int ptrace_regset(struct task_struct *task, int req, unsigned int type, -+ struct iovec *kiov); -+ -+int ptrace_request(struct task_struct *child, long request, -+ unsigned long addr, unsigned long data) -+{ -+ struct utrace_engine *engine = ptrace_lookup_engine(child); -+ siginfo_t siginfo; -+ int ret; -+ -+ if (unlikely(IS_ERR(engine))) -+ return -ESRCH; -+ -+ switch (request) { -+ case PTRACE_PEEKTEXT: -+ case PTRACE_PEEKDATA: -+ ret = generic_ptrace_peekdata(child, addr, data); -+ break; -+ case PTRACE_POKETEXT: -+ case PTRACE_POKEDATA: -+ ret = generic_ptrace_pokedata(child, addr, data); -+ break; -+ -+#ifdef PTRACE_OLDSETOPTIONS -+ case PTRACE_OLDSETOPTIONS: -+#endif -+ case PTRACE_SETOPTIONS: -+ ret = ptrace_set_options(child, engine, data); -+ break; -+ case PTRACE_GETEVENTMSG: -+ ret = put_user(ptrace_context(engine)->eventmsg, -+ (unsigned long __user *) data); -+ break; -+ -+ case PTRACE_GETSIGINFO: -+ ret = ptrace_rw_siginfo(child, ptrace_context(engine), -+ &siginfo, false); -+ if (!ret) -+ ret = copy_siginfo_to_user((siginfo_t __user *) data, -+ &siginfo); -+ break; -+ -+ case PTRACE_SETSIGINFO: -+ if (copy_from_user(&siginfo, (siginfo_t __user *) data, -+ sizeof siginfo)) -+ ret = -EFAULT; -+ else -+ ret = ptrace_rw_siginfo(child, ptrace_context(engine), -+ &siginfo, true); -+ break; -+ -+ case PTRACE_DETACH: /* detach a process that was attached. */ -+ ret = ptrace_detach(child, data); -+ break; -+ -+ case PTRACE_KILL: -+ /* Ugly historical behaviour. */ -+ if (task_is_traced(child)) -+ ptrace_resume(child, engine, PTRACE_CONT, SIGKILL); -+ ret = 0; -+ break; -+ -+ case PTRACE_GETREGSET: -+ case PTRACE_SETREGSET: -+ { -+ struct iovec kiov; -+ struct iovec __user *uiov = (struct iovec __user *) data; -+ -+ if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov))) -+ return -EFAULT; -+ -+ if (__get_user(kiov.iov_base, &uiov->iov_base) || -+ __get_user(kiov.iov_len, &uiov->iov_len)) -+ return -EFAULT; -+ -+ ret = ptrace_regset(child, request, addr, &kiov); -+ if (!ret) -+ ret = __put_user(kiov.iov_len, &uiov->iov_len); -+ break; -+ } -+ -+ default: -+ ret = ptrace_resume(child, engine, request, data); -+ break; -+ } -+ -+ utrace_engine_put(engine); -+ return ret; -+} -+ -+#if defined CONFIG_COMPAT -+#include -+ -+int compat_ptrace_request(struct task_struct *child, compat_long_t request, -+ compat_ulong_t addr, compat_ulong_t data) -+{ -+ struct utrace_engine *engine = ptrace_lookup_engine(child); -+ compat_ulong_t __user *datap = compat_ptr(data); -+ compat_ulong_t word; -+ siginfo_t siginfo; -+ int ret; -+ -+ if (unlikely(IS_ERR(engine))) -+ return -ESRCH; -+ -+ switch (request) { -+ case PTRACE_PEEKTEXT: -+ case PTRACE_PEEKDATA: -+ ret = access_process_vm(child, addr, &word, sizeof(word), 0); -+ if (ret != sizeof(word)) -+ ret = -EIO; -+ else -+ ret = put_user(word, datap); -+ break; -+ -+ case PTRACE_POKETEXT: -+ case PTRACE_POKEDATA: -+ ret = access_process_vm(child, addr, &data, sizeof(data), 1); -+ ret = (ret != sizeof(data) ? -EIO : 0); -+ break; -+ -+ case PTRACE_GETEVENTMSG: -+ ret = put_user((compat_ulong_t)ptrace_context(engine)->eventmsg, -+ datap); -+ break; -+ -+ case PTRACE_GETSIGINFO: -+ ret = ptrace_rw_siginfo(child, ptrace_context(engine), -+ &siginfo, false); -+ if (!ret) -+ ret = copy_siginfo_to_user32( -+ (struct compat_siginfo __user *) datap, -+ &siginfo); -+ break; -+ -+ case PTRACE_SETSIGINFO: -+ memset(&siginfo, 0, sizeof siginfo); -+ if (copy_siginfo_from_user32( -+ &siginfo, (struct compat_siginfo __user *) datap)) -+ ret = -EFAULT; -+ else -+ ret = ptrace_rw_siginfo(child, ptrace_context(engine), -+ &siginfo, true); -+ break; -+ -+ case PTRACE_GETREGSET: -+ case PTRACE_SETREGSET: -+ { -+ struct iovec kiov; -+ struct compat_iovec __user *uiov = -+ (struct compat_iovec __user *) datap; -+ compat_uptr_t ptr; -+ compat_size_t len; -+ -+ if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov))) -+ return -EFAULT; -+ -+ if (__get_user(ptr, &uiov->iov_base) || -+ __get_user(len, &uiov->iov_len)) -+ return -EFAULT; -+ -+ kiov.iov_base = compat_ptr(ptr); -+ kiov.iov_len = len; -+ -+ ret = ptrace_regset(child, request, addr, &kiov); -+ if (!ret) -+ ret = __put_user(kiov.iov_len, &uiov->iov_len); -+ break; -+ } -+ -+ default: -+ ret = ptrace_request(child, request, addr, data); -+ } -+ -+ utrace_engine_put(engine); -+ return ret; -+} -+#endif /* CONFIG_COMPAT */ -diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index e275608..72ea65c 100644 ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -15,7 +15,6 @@ - #include - #include - #include --#include - #include - #include - #include -@@ -24,7 +23,320 @@ - #include - #include - -+int __ptrace_may_access(struct task_struct *task, unsigned int mode) -+{ -+ const struct cred *cred = current_cred(), *tcred; -+ -+ /* May we inspect the given task? -+ * This check is used both for attaching with ptrace -+ * and for allowing access to sensitive information in /proc. -+ * -+ * ptrace_attach denies several cases that /proc allows -+ * because setting up the necessary parent/child relationship -+ * or halting the specified task is impossible. -+ */ -+ int dumpable = 0; -+ /* Don't let security modules deny introspection */ -+ if (task == current) -+ return 0; -+ rcu_read_lock(); -+ tcred = __task_cred(task); -+ if ((cred->uid != tcred->euid || -+ cred->uid != tcred->suid || -+ cred->uid != tcred->uid || -+ cred->gid != tcred->egid || -+ cred->gid != tcred->sgid || -+ cred->gid != tcred->gid) && -+ !capable(CAP_SYS_PTRACE)) { -+ rcu_read_unlock(); -+ return -EPERM; -+ } -+ rcu_read_unlock(); -+ smp_rmb(); -+ if (task->mm) -+ dumpable = get_dumpable(task->mm); -+ if (!dumpable && !capable(CAP_SYS_PTRACE)) -+ return -EPERM; -+ -+ return security_ptrace_access_check(task, mode); -+} -+ -+bool ptrace_may_access(struct task_struct *task, unsigned int mode) -+{ -+ int err; -+ task_lock(task); -+ err = __ptrace_may_access(task, mode); -+ task_unlock(task); -+ return !err; -+} -+ -+/* -+ * Called with irqs disabled, returns true if childs should reap themselves. -+ */ -+static int ignoring_children(struct sighand_struct *sigh) -+{ -+ int ret; -+ spin_lock(&sigh->siglock); -+ ret = (sigh->action[SIGCHLD-1].sa.sa_handler == SIG_IGN) || -+ (sigh->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT); -+ spin_unlock(&sigh->siglock); -+ return ret; -+} -+ -+/* -+ * Called with tasklist_lock held for writing. -+ * Unlink a traced task, and clean it up if it was a traced zombie. -+ * Return true if it needs to be reaped with release_task(). -+ * (We can't call release_task() here because we already hold tasklist_lock.) -+ * -+ * If it's a zombie, our attachedness prevented normal parent notification -+ * or self-reaping. Do notification now if it would have happened earlier. -+ * If it should reap itself, return true. -+ * -+ * If it's our own child, there is no notification to do. But if our normal -+ * children self-reap, then this child was prevented by ptrace and we must -+ * reap it now, in that case we must also wake up sub-threads sleeping in -+ * do_wait(). -+ */ -+bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p) -+{ -+ __ptrace_unlink(p); -+ -+ if (p->exit_state == EXIT_ZOMBIE) { -+ if (!task_detached(p) && thread_group_empty(p)) { -+ if (!same_thread_group(p->real_parent, tracer)) -+ do_notify_parent(p, p->exit_signal); -+ else if (ignoring_children(tracer->sighand)) { -+ __wake_up_parent(p, tracer); -+ p->exit_signal = -1; -+ } -+ } -+ if (task_detached(p)) { -+ /* Mark it as in the process of being reaped. */ -+ p->exit_state = EXIT_DEAD; -+ return true; -+ } -+ } -+ -+ return false; -+} -+ -+int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len) -+{ -+ int copied = 0; -+ -+ while (len > 0) { -+ char buf[128]; -+ int this_len, retval; -+ -+ this_len = (len > sizeof(buf)) ? sizeof(buf) : len; -+ retval = access_process_vm(tsk, src, buf, this_len, 0); -+ if (!retval) { -+ if (copied) -+ break; -+ return -EIO; -+ } -+ if (copy_to_user(dst, buf, retval)) -+ return -EFAULT; -+ copied += retval; -+ src += retval; -+ dst += retval; -+ len -= retval; -+ } -+ return copied; -+} -+ -+int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len) -+{ -+ int copied = 0; -+ -+ while (len > 0) { -+ char buf[128]; -+ int this_len, retval; -+ -+ this_len = (len > sizeof(buf)) ? sizeof(buf) : len; -+ if (copy_from_user(buf, src, this_len)) -+ return -EFAULT; -+ retval = access_process_vm(tsk, dst, buf, this_len, 1); -+ if (!retval) { -+ if (copied) -+ break; -+ return -EIO; -+ } -+ copied += retval; -+ src += retval; -+ dst += retval; -+ len -= retval; -+ } -+ return copied; -+} -+ -+#ifdef CONFIG_HAVE_ARCH_TRACEHOOK -+ -+static const struct user_regset * -+find_regset(const struct user_regset_view *view, unsigned int type) -+{ -+ const struct user_regset *regset; -+ int n; -+ -+ for (n = 0; n < view->n; ++n) { -+ regset = view->regsets + n; -+ if (regset->core_note_type == type) -+ return regset; -+ } -+ -+ return NULL; -+} -+ -+int ptrace_regset(struct task_struct *task, int req, unsigned int type, -+ struct iovec *kiov) -+{ -+ const struct user_regset_view *view = task_user_regset_view(task); -+ const struct user_regset *regset = find_regset(view, type); -+ int regset_no; -+ -+ if (!regset || (kiov->iov_len % regset->size) != 0) -+ return -EINVAL; -+ -+ regset_no = regset - view->regsets; -+ kiov->iov_len = min(kiov->iov_len, -+ (__kernel_size_t) (regset->n * regset->size)); -+ -+ if (req == PTRACE_GETREGSET) -+ return copy_regset_to_user(task, view, regset_no, 0, -+ kiov->iov_len, kiov->iov_base); -+ else -+ return copy_regset_from_user(task, view, regset_no, 0, -+ kiov->iov_len, kiov->iov_base); -+} -+ -+#endif -+ -+static struct task_struct *ptrace_get_task_struct(pid_t pid) -+{ -+ struct task_struct *child; -+ -+ rcu_read_lock(); -+ child = find_task_by_vpid(pid); -+ if (child) -+ get_task_struct(child); -+ rcu_read_unlock(); -+ -+ if (!child) -+ return ERR_PTR(-ESRCH); -+ return child; -+} -+ -+#ifndef arch_ptrace_attach -+#define arch_ptrace_attach(child) do { } while (0) -+#endif -+ -+SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, -+ unsigned long, data) -+{ -+ struct task_struct *child; -+ long ret; -+ -+ if (request == PTRACE_TRACEME) { -+ ret = ptrace_traceme(); -+ if (!ret) -+ arch_ptrace_attach(current); -+ goto out; -+ } - -+ child = ptrace_get_task_struct(pid); -+ if (IS_ERR(child)) { -+ ret = PTR_ERR(child); -+ goto out; -+ } -+ -+ if (request == PTRACE_ATTACH) { -+ ret = ptrace_attach(child); -+ /* -+ * Some architectures need to do book-keeping after -+ * a ptrace attach. -+ */ -+ if (!ret) -+ arch_ptrace_attach(child); -+ goto out_put_task_struct; -+ } -+ -+ ret = ptrace_check_attach(child, request == PTRACE_KILL); -+ if (ret < 0) -+ goto out_put_task_struct; -+ -+ ret = arch_ptrace(child, request, addr, data); -+ -+ out_put_task_struct: -+ put_task_struct(child); -+ out: -+ return ret; -+} -+ -+int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr, -+ unsigned long data) -+{ -+ unsigned long tmp; -+ int copied; -+ -+ copied = access_process_vm(tsk, addr, &tmp, sizeof(tmp), 0); -+ if (copied != sizeof(tmp)) -+ return -EIO; -+ return put_user(tmp, (unsigned long __user *)data); -+} -+ -+int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr, -+ unsigned long data) -+{ -+ int copied; -+ -+ copied = access_process_vm(tsk, addr, &data, sizeof(data), 1); -+ return (copied == sizeof(data)) ? 0 : -EIO; -+} -+ -+#if defined CONFIG_COMPAT -+#include -+ -+asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, -+ compat_long_t addr, compat_long_t data) -+{ -+ struct task_struct *child; -+ long ret; -+ -+ if (request == PTRACE_TRACEME) { -+ ret = ptrace_traceme(); -+ goto out; -+ } -+ -+ child = ptrace_get_task_struct(pid); -+ if (IS_ERR(child)) { -+ ret = PTR_ERR(child); -+ goto out; -+ } -+ -+ if (request == PTRACE_ATTACH) { -+ ret = ptrace_attach(child); -+ /* -+ * Some architectures need to do book-keeping after -+ * a ptrace attach. -+ */ -+ if (!ret) -+ arch_ptrace_attach(child); -+ goto out_put_task_struct; -+ } -+ -+ ret = ptrace_check_attach(child, request == PTRACE_KILL); -+ if (!ret) -+ ret = compat_arch_ptrace(child, request, addr, data); -+ -+ out_put_task_struct: -+ put_task_struct(child); -+ out: -+ return ret; -+} -+#endif /* CONFIG_COMPAT */ -+ -+#ifndef CONFIG_UTRACE - /* - * ptrace a task: make the debugger its new parent and - * move it to the ptrace list. -@@ -117,61 +429,6 @@ int ptrace_check_attach(struct task_stru - return ret; - } - --int __ptrace_may_access(struct task_struct *task, unsigned int mode) --{ -- const struct cred *cred = current_cred(), *tcred; -- -- /* May we inspect the given task? -- * This check is used both for attaching with ptrace -- * and for allowing access to sensitive information in /proc. -- * -- * ptrace_attach denies several cases that /proc allows -- * because setting up the necessary parent/child relationship -- * or halting the specified task is impossible. -- */ -- int dumpable = 0; -- /* Don't let security modules deny introspection */ -- if (task == current) -- return 0; -- rcu_read_lock(); -- tcred = __task_cred(task); -- if ((cred->uid != tcred->euid || -- cred->uid != tcred->suid || -- cred->uid != tcred->uid || -- cred->gid != tcred->egid || -- cred->gid != tcred->sgid || -- cred->gid != tcred->gid) && -- !capable(CAP_SYS_PTRACE)) { -- rcu_read_unlock(); -- return -EPERM; -- } -- rcu_read_unlock(); -- smp_rmb(); -- if (task->mm) -- dumpable = get_dumpable(task->mm); -- if (!dumpable && !capable(CAP_SYS_PTRACE)) -- return -EPERM; -- -- return security_ptrace_access_check(task, mode); --} -- --bool ptrace_may_access(struct task_struct *task, unsigned int mode) --{ -- int err; -- task_lock(task); -- err = __ptrace_may_access(task, mode); -- task_unlock(task); -- return !err; --} -- --/* -- * For experimental use of utrace, exclude ptrace on the same task. -- */ --static inline bool exclude_ptrace(struct task_struct *task) --{ -- return unlikely(!!task_utrace_flags(task)); --} -- - int ptrace_attach(struct task_struct *task) - { - int retval; -@@ -195,8 +452,6 @@ int ptrace_attach(struct task_struct *ta - - task_lock(task); - retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH); -- if (!retval && exclude_ptrace(task)) -- retval = -EBUSY; - task_unlock(task); - if (retval) - goto unlock_creds; -@@ -220,91 +475,37 @@ unlock_tasklist: - write_unlock_irq(&tasklist_lock); - unlock_creds: - mutex_unlock(&task->signal->cred_guard_mutex); --out: -- return retval; --} -- --/** -- * ptrace_traceme -- helper for PTRACE_TRACEME -- * -- * Performs checks and sets PT_PTRACED. -- * Should be used by all ptrace implementations for PTRACE_TRACEME. -- */ --int ptrace_traceme(void) --{ -- int ret = -EPERM; -- -- if (exclude_ptrace(current)) /* XXX locking */ -- return -EBUSY; -- -- write_lock_irq(&tasklist_lock); -- /* Are we already being traced? */ -- if (!current->ptrace) { -- ret = security_ptrace_traceme(current->parent); -- /* -- * Check PF_EXITING to ensure ->real_parent has not passed -- * exit_ptrace(). Otherwise we don't report the error but -- * pretend ->real_parent untraces us right after return. -- */ -- if (!ret && !(current->real_parent->flags & PF_EXITING)) { -- current->ptrace = PT_PTRACED; -- __ptrace_link(current, current->real_parent); -- } -- } -- write_unlock_irq(&tasklist_lock); -- -- return ret; --} -- --/* -- * Called with irqs disabled, returns true if childs should reap themselves. -- */ --static int ignoring_children(struct sighand_struct *sigh) --{ -- int ret; -- spin_lock(&sigh->siglock); -- ret = (sigh->action[SIGCHLD-1].sa.sa_handler == SIG_IGN) || -- (sigh->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT); -- spin_unlock(&sigh->siglock); -- return ret; --} -- --/* -- * Called with tasklist_lock held for writing. -- * Unlink a traced task, and clean it up if it was a traced zombie. -- * Return true if it needs to be reaped with release_task(). -- * (We can't call release_task() here because we already hold tasklist_lock.) -- * -- * If it's a zombie, our attachedness prevented normal parent notification -- * or self-reaping. Do notification now if it would have happened earlier. -- * If it should reap itself, return true. -+out: -+ return retval; -+} -+ -+/** -+ * ptrace_traceme -- helper for PTRACE_TRACEME - * -- * If it's our own child, there is no notification to do. But if our normal -- * children self-reap, then this child was prevented by ptrace and we must -- * reap it now, in that case we must also wake up sub-threads sleeping in -- * do_wait(). -+ * Performs checks and sets PT_PTRACED. -+ * Should be used by all ptrace implementations for PTRACE_TRACEME. - */ --bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p) -+int ptrace_traceme(void) - { -- __ptrace_unlink(p); -+ int ret = -EPERM; - -- if (p->exit_state == EXIT_ZOMBIE) { -- if (!task_detached(p) && thread_group_empty(p)) { -- if (!same_thread_group(p->real_parent, tracer)) -- do_notify_parent(p, p->exit_signal); -- else if (ignoring_children(tracer->sighand)) { -- __wake_up_parent(p, tracer); -- p->exit_signal = -1; -- } -- } -- if (task_detached(p)) { -- /* Mark it as in the process of being reaped. */ -- p->exit_state = EXIT_DEAD; -- return true; -+ write_lock_irq(&tasklist_lock); -+ /* Are we already being traced? */ -+ if (!current->ptrace) { -+ ret = security_ptrace_traceme(current->parent); -+ /* -+ * Check PF_EXITING to ensure ->real_parent has not passed -+ * exit_ptrace(). Otherwise we don't report the error but -+ * pretend ->real_parent untraces us right after return. -+ */ -+ if (!ret && !(current->real_parent->flags & PF_EXITING)) { -+ current->ptrace = PT_PTRACED; -+ __ptrace_link(current, current->real_parent); - } - } -+ write_unlock_irq(&tasklist_lock); - -- return false; -+ return ret; - } - - int ptrace_detach(struct task_struct *child, unsigned int data) -@@ -368,57 +569,7 @@ void exit_ptrace(struct task_struct *tra - write_lock_irq(&tasklist_lock); - } - --int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len) --{ -- int copied = 0; -- -- while (len > 0) { -- char buf[128]; -- int this_len, retval; -- -- this_len = (len > sizeof(buf)) ? sizeof(buf) : len; -- retval = access_process_vm(tsk, src, buf, this_len, 0); -- if (!retval) { -- if (copied) -- break; -- return -EIO; -- } -- if (copy_to_user(dst, buf, retval)) -- return -EFAULT; -- copied += retval; -- src += retval; -- dst += retval; -- len -= retval; -- } -- return copied; --} -- --int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len) --{ -- int copied = 0; -- -- while (len > 0) { -- char buf[128]; -- int this_len, retval; -- -- this_len = (len > sizeof(buf)) ? sizeof(buf) : len; -- if (copy_from_user(buf, src, this_len)) -- return -EFAULT; -- retval = access_process_vm(tsk, dst, buf, this_len, 1); -- if (!retval) { -- if (copied) -- break; -- return -EIO; -- } -- copied += retval; -- src += retval; -- dst += retval; -- len -= retval; -- } -- return copied; --} -- --static int ptrace_setoptions(struct task_struct *child, unsigned long data) -+static int ptrace_setoptions(struct task_struct *child, long data) - { - child->ptrace &= ~PT_TRACE_MASK; - -@@ -533,47 +683,6 @@ static int ptrace_resume(struct task_str - return 0; - } - --#ifdef CONFIG_HAVE_ARCH_TRACEHOOK -- --static const struct user_regset * --find_regset(const struct user_regset_view *view, unsigned int type) --{ -- const struct user_regset *regset; -- int n; -- -- for (n = 0; n < view->n; ++n) { -- regset = view->regsets + n; -- if (regset->core_note_type == type) -- return regset; -- } -- -- return NULL; --} -- --static int ptrace_regset(struct task_struct *task, int req, unsigned int type, -- struct iovec *kiov) --{ -- const struct user_regset_view *view = task_user_regset_view(task); -- const struct user_regset *regset = find_regset(view, type); -- int regset_no; -- -- if (!regset || (kiov->iov_len % regset->size) != 0) -- return -EINVAL; -- -- regset_no = regset - view->regsets; -- kiov->iov_len = min(kiov->iov_len, -- (__kernel_size_t) (regset->n * regset->size)); -- -- if (req == PTRACE_GETREGSET) -- return copy_regset_to_user(task, view, regset_no, 0, -- kiov->iov_len, kiov->iov_base); -- else -- return copy_regset_from_user(task, view, regset_no, 0, -- kiov->iov_len, kiov->iov_base); --} -- --#endif -- - int ptrace_request(struct task_struct *child, long request, - unsigned long addr, unsigned long data) - { -@@ -689,91 +798,7 @@ int ptrace_request(struct task_struct *c - return ret; - } - --static struct task_struct *ptrace_get_task_struct(pid_t pid) --{ -- struct task_struct *child; -- -- rcu_read_lock(); -- child = find_task_by_vpid(pid); -- if (child) -- get_task_struct(child); -- rcu_read_unlock(); -- -- if (!child) -- return ERR_PTR(-ESRCH); -- return child; --} -- --#ifndef arch_ptrace_attach --#define arch_ptrace_attach(child) do { } while (0) --#endif -- --SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, -- unsigned long, data) --{ -- struct task_struct *child; -- long ret; -- -- if (request == PTRACE_TRACEME) { -- ret = ptrace_traceme(); -- if (!ret) -- arch_ptrace_attach(current); -- goto out; -- } -- -- child = ptrace_get_task_struct(pid); -- if (IS_ERR(child)) { -- ret = PTR_ERR(child); -- goto out; -- } -- -- if (request == PTRACE_ATTACH) { -- ret = ptrace_attach(child); -- /* -- * Some architectures need to do book-keeping after -- * a ptrace attach. -- */ -- if (!ret) -- arch_ptrace_attach(child); -- goto out_put_task_struct; -- } -- -- ret = ptrace_check_attach(child, request == PTRACE_KILL); -- if (ret < 0) -- goto out_put_task_struct; -- -- ret = arch_ptrace(child, request, addr, data); -- -- out_put_task_struct: -- put_task_struct(child); -- out: -- return ret; --} -- --int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr, -- unsigned long data) --{ -- unsigned long tmp; -- int copied; -- -- copied = access_process_vm(tsk, addr, &tmp, sizeof(tmp), 0); -- if (copied != sizeof(tmp)) -- return -EIO; -- return put_user(tmp, (unsigned long __user *)data); --} -- --int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr, -- unsigned long data) --{ -- int copied; -- -- copied = access_process_vm(tsk, addr, &data, sizeof(data), 1); -- return (copied == sizeof(data)) ? 0 : -EIO; --} -- - #if defined CONFIG_COMPAT --#include -- - int compat_ptrace_request(struct task_struct *child, compat_long_t request, - compat_ulong_t addr, compat_ulong_t data) - { -@@ -851,42 +876,5 @@ int compat_ptrace_request(struct task_st - - return ret; - } -- --asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, -- compat_long_t addr, compat_long_t data) --{ -- struct task_struct *child; -- long ret; -- -- if (request == PTRACE_TRACEME) { -- ret = ptrace_traceme(); -- goto out; -- } -- -- child = ptrace_get_task_struct(pid); -- if (IS_ERR(child)) { -- ret = PTR_ERR(child); -- goto out; -- } -- -- if (request == PTRACE_ATTACH) { -- ret = ptrace_attach(child); -- /* -- * Some architectures need to do book-keeping after -- * a ptrace attach. -- */ -- if (!ret) -- arch_ptrace_attach(child); -- goto out_put_task_struct; -- } -- -- ret = ptrace_check_attach(child, request == PTRACE_KILL); -- if (!ret) -- ret = compat_arch_ptrace(child, request, addr, data); -- -- out_put_task_struct: -- put_task_struct(child); -- out: -- return ret; --} - #endif /* CONFIG_COMPAT */ -+#endif /* CONFIG_UTRACE */ -diff --git a/kernel/utrace.c b/kernel/utrace.c -index 26d6faf..37dce16 100644 ---- a/kernel/utrace.c -+++ b/kernel/utrace.c -@@ -816,6 +816,22 @@ relock: - spin_unlock_irq(&task->sighand->siglock); - spin_unlock(&utrace->lock); - -+ /* -+ * If ptrace is among the reasons for this stop, do its -+ * notification now. This could not just be done in -+ * ptrace's own event report callbacks because it has to -+ * be done after we are in TASK_TRACED. This makes the -+ * synchronization with ptrace_do_wait() work right. -+ * -+ * It's only because of the bad old overloading of the do_wait() -+ * logic for handling ptrace stops that we need this special case -+ * here. One day we will clean up ptrace so it does not need to -+ * work this way. New things that are designed sensibly don't need -+ * a wakeup that synchronizes with tasklist_lock and ->state, so -+ * the proper utrace API does not try to support this weirdness. -+ */ -+ ptrace_notify_stop(task); -+ - schedule(); - - utrace_finish_stop(); diff --git a/linux-2.6-utrace-revert-make-ptrace-functions-static.patch b/linux-2.6-utrace-revert-make-ptrace-functions-static.patch deleted file mode 100644 index 5e3dcc21d..000000000 --- a/linux-2.6-utrace-revert-make-ptrace-functions-static.patch +++ /dev/null @@ -1,47 +0,0 @@ -Revert: -commit e3e89cc535223433a619d0969db3fa05cdd946b8 -("Mark ptrace_{traceme,attach,detach} static") - ---- b/include/linux/ptrace.h -+++ a/include/linux/ptrace.h -@@ -102,8 +102,11 @@ - - extern long arch_ptrace(struct task_struct *child, long request, - unsigned long addr, unsigned long data); -+extern int ptrace_traceme(void); - extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len); - extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len); -+extern int ptrace_attach(struct task_struct *tsk); -+extern int ptrace_detach(struct task_struct *, unsigned int); - extern void ptrace_disable(struct task_struct *); - extern int ptrace_check_attach(struct task_struct *task, int kill); - extern int ptrace_request(struct task_struct *child, long request, ---- b/kernel/ptrace.c -+++ a/kernel/ptrace.c -@@ -163,7 +163,7 @@ - return !err; - } - -+int ptrace_attach(struct task_struct *task) --static int ptrace_attach(struct task_struct *task) - { - int retval; - -@@ -219,7 +219,7 @@ - * Performs checks and sets PT_PTRACED. - * Should be used by all ptrace implementations for PTRACE_TRACEME. - */ -+int ptrace_traceme(void) --static int ptrace_traceme(void) - { - int ret = -EPERM; - -@@ -293,7 +293,7 @@ - return false; - } - -+int ptrace_detach(struct task_struct *child, unsigned int data) --static int ptrace_detach(struct task_struct *child, unsigned int data) - { - bool dead = false; - diff --git a/linux-2.6-v4l-dvb-add-lgdt3304-support.patch b/linux-2.6-v4l-dvb-add-lgdt3304-support.patch deleted file mode 100644 index 30c50434f..000000000 --- a/linux-2.6-v4l-dvb-add-lgdt3304-support.patch +++ /dev/null @@ -1,350 +0,0 @@ -From b71e18093e2e7f240797875c50c49552722f8825 Mon Sep 17 00:00:00 2001 -From: Jarod Wilson -Date: Mon, 15 Feb 2010 17:13:25 -0500 -Subject: [PATCH 1/2] dvb: add lgdt3304 support to lgdt3305 driver - -There's a currently-unused lgdt3304 demod driver, which leaves a lot to -be desired as far as functionality. The 3304 is unsurprisingly quite -similar to the 3305, and empirical testing yeilds far better results -and more complete functionality by merging 3304 support into the 3305 -driver. (For example, the current lgdt3304 driver lacks support for -signal strength, snr, ucblocks, etc., which we get w/the lgdt3305). - -For the moment, not dropping the lgdt3304 driver, and its still up to -a given device's config setup to choose which demod driver to use, but -I'd suggest dropping the 3304 driver entirely. - -As a follow-up to this patch, I've got another patch that adds support -for the KWorld PlusTV 340U (ATSC) em2870-based tuner stick, driving -its lgdt3304 demod via this lgdt3305 driver, which is what I used to -successfully test this patch with both VSB_8 and QAM_256 signals. - -A few pieces are still a touch crude, but I think its a solid start, -as well as much cleaner and more feature-complete than the existing -lgdt3304 driver. - -Signed-off-by: Jarod Wilson ---- - drivers/media/dvb/frontends/lgdt3305.c | 206 ++++++++++++++++++++++++++++++-- - drivers/media/dvb/frontends/lgdt3305.h | 6 + - 2 files changed, 203 insertions(+), 9 deletions(-) - -diff --git a/drivers/media/dvb/frontends/lgdt3305.c b/drivers/media/dvb/frontends/lgdt3305.c -index fde8c59..40695e6 100644 ---- a/drivers/media/dvb/frontends/lgdt3305.c -+++ b/drivers/media/dvb/frontends/lgdt3305.c -@@ -1,5 +1,5 @@ - /* -- * Support for LGDT3305 - VSB/QAM -+ * Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM - * - * Copyright (C) 2008, 2009 Michael Krufky - * -@@ -357,7 +357,10 @@ static int lgdt3305_rfagc_loop(struct lgdt3305_state *state, - case QAM_256: - agcdelay = 0x046b; - rfbw = 0x8889; -- ifbw = 0x8888; -+ if (state->cfg->demod_chip == LGDT3305) -+ ifbw = 0x8888; -+ else -+ ifbw = 0x6666; - break; - default: - return -EINVAL; -@@ -409,8 +412,18 @@ static int lgdt3305_agc_setup(struct lgdt3305_state *state, - lg_dbg("lockdten = %d, acqen = %d\n", lockdten, acqen); - - /* control agc function */ -- lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1); -- lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen); -+ switch (state->cfg->demod_chip) { -+ case LGDT3304: -+ lgdt3305_write_reg(state, 0x0314, 0xe1 | lockdten << 1); -+ lgdt3305_set_reg_bit(state, 0x030e, 2, acqen); -+ break; -+ case LGDT3305: -+ lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1); -+ lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen); -+ break; -+ default: -+ return -EINVAL; -+ } - - return lgdt3305_rfagc_loop(state, param); - } -@@ -543,6 +556,11 @@ static int lgdt3305_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) - enable ? 0 : 1); - } - -+static int lgdt3304_sleep(struct dvb_frontend *fe) -+{ -+ return 0; -+} -+ - static int lgdt3305_sleep(struct dvb_frontend *fe) - { - struct lgdt3305_state *state = fe->demodulator_priv; -@@ -571,6 +589,55 @@ static int lgdt3305_sleep(struct dvb_frontend *fe) - return 0; - } - -+static int lgdt3304_init(struct dvb_frontend *fe) -+{ -+ struct lgdt3305_state *state = fe->demodulator_priv; -+ int ret; -+ -+ static struct lgdt3305_reg lgdt3304_init_data[] = { -+ { .reg = LGDT3305_GEN_CTRL_1, .val = 0x03, }, -+ { .reg = 0x000d, .val = 0x02, }, -+ { .reg = 0x000e, .val = 0x02, }, -+ { .reg = LGDT3305_DGTL_AGC_REF_1, .val = 0x32, }, -+ { .reg = LGDT3305_DGTL_AGC_REF_2, .val = 0xc4, }, -+ { .reg = LGDT3305_CR_CTR_FREQ_1, .val = 0x00, }, -+ { .reg = LGDT3305_CR_CTR_FREQ_2, .val = 0x00, }, -+ { .reg = LGDT3305_CR_CTR_FREQ_3, .val = 0x00, }, -+ { .reg = LGDT3305_CR_CTR_FREQ_4, .val = 0x00, }, -+ { .reg = LGDT3305_CR_CTRL_7, .val = 0xf9, }, -+ { .reg = 0x0112, .val = 0x17, }, -+ { .reg = 0x0113, .val = 0x15, }, -+ { .reg = 0x0114, .val = 0x18, }, -+ { .reg = 0x0115, .val = 0xff, }, -+ { .reg = 0x0116, .val = 0x3c, }, -+ { .reg = 0x0214, .val = 0x67, }, -+ { .reg = 0x0424, .val = 0x8d, }, -+ { .reg = 0x0427, .val = 0x12, }, -+ { .reg = 0x0428, .val = 0x4f, }, -+ { .reg = LGDT3305_IFBW_1, .val = 0x80, }, -+ { .reg = LGDT3305_IFBW_2, .val = 0x00, }, -+ { .reg = 0x030a, .val = 0x08, }, -+ { .reg = 0x030b, .val = 0x9b, }, -+ { .reg = 0x030d, .val = 0x00, }, -+ { .reg = 0x030e, .val = 0x1c, }, -+ { .reg = 0x0314, .val = 0xe1, }, -+ { .reg = 0x000d, .val = 0x82, }, -+ { .reg = LGDT3305_TP_CTRL_1, .val = 0x5b, }, -+ { .reg = LGDT3305_TP_CTRL_1, .val = 0x5b, }, -+ }; -+ -+ lg_dbg("\n"); -+ -+ ret = lgdt3305_write_regs(state, lgdt3304_init_data, -+ ARRAY_SIZE(lgdt3304_init_data)); -+ if (lg_fail(ret)) -+ goto fail; -+ -+ ret = lgdt3305_soft_reset(state); -+fail: -+ return ret; -+} -+ - static int lgdt3305_init(struct dvb_frontend *fe) - { - struct lgdt3305_state *state = fe->demodulator_priv; -@@ -639,6 +706,88 @@ fail: - return ret; - } - -+static int lgdt3304_set_parameters(struct dvb_frontend *fe, -+ struct dvb_frontend_parameters *param) -+{ -+ struct lgdt3305_state *state = fe->demodulator_priv; -+ int ret; -+ -+ lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation); -+ -+ if (fe->ops.tuner_ops.set_params) { -+ ret = fe->ops.tuner_ops.set_params(fe, param); -+ if (fe->ops.i2c_gate_ctrl) -+ fe->ops.i2c_gate_ctrl(fe, 0); -+ if (lg_fail(ret)) -+ goto fail; -+ state->current_frequency = param->frequency; -+ } -+ -+ ret = lgdt3305_set_modulation(state, param); -+ if (lg_fail(ret)) -+ goto fail; -+ -+ ret = lgdt3305_passband_digital_agc(state, param); -+ if (lg_fail(ret)) -+ goto fail; -+ -+ ret = lgdt3305_agc_setup(state, param); -+ if (lg_fail(ret)) -+ goto fail; -+ -+ /* reg 0x030d is 3304-only... seen in vsb and qam usbsnoops... */ -+ switch (param->u.vsb.modulation) { -+ case VSB_8: -+ lgdt3305_write_reg(state, 0x030d, 0x00); -+#if 1 -+ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, 0x4f); -+ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, 0x0c); -+ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, 0xac); -+ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, 0xba); -+#endif -+ break; -+ case QAM_64: -+ case QAM_256: -+ lgdt3305_write_reg(state, 0x030d, 0x14); -+#if 1 -+ ret = lgdt3305_set_if(state, param); -+ if (lg_fail(ret)) -+ goto fail; -+#endif -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+#if 0 -+ /* the set_if vsb formula doesn't work for the 3304, we end up sending -+ * 0x40851e07 instead of 0x4f0cacba (which works back to 94050, rather -+ * than 3250, in the case of the kworld 340u) */ -+ ret = lgdt3305_set_if(state, param); -+ if (lg_fail(ret)) -+ goto fail; -+#endif -+ -+ ret = lgdt3305_spectral_inversion(state, param, -+ state->cfg->spectral_inversion -+ ? 1 : 0); -+ if (lg_fail(ret)) -+ goto fail; -+ -+ state->current_modulation = param->u.vsb.modulation; -+ -+ ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode); -+ if (lg_fail(ret)) -+ goto fail; -+ -+ /* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */ -+ ret = lgdt3305_mpeg_mode_polarity(state, -+ state->cfg->tpclk_edge, -+ state->cfg->tpvalid_polarity); -+fail: -+ return ret; -+} -+ - static int lgdt3305_set_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) - { -@@ -847,6 +996,10 @@ static int lgdt3305_read_status(struct dvb_frontend *fe, fe_status_t *status) - switch (state->current_modulation) { - case QAM_256: - case QAM_64: -+#if 0 /* needed w/3304 to set FE_HAS_SIGNAL */ -+ if (cr_lock) -+ *status |= FE_HAS_SIGNAL; -+#endif - ret = lgdt3305_read_fec_lock_status(state, &fec_lock); - if (lg_fail(ret)) - goto fail; -@@ -992,6 +1145,7 @@ static void lgdt3305_release(struct dvb_frontend *fe) - kfree(state); - } - -+static struct dvb_frontend_ops lgdt3304_ops; - static struct dvb_frontend_ops lgdt3305_ops; - - struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config, -@@ -1012,11 +1166,21 @@ struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config, - state->cfg = config; - state->i2c_adap = i2c_adap; - -- memcpy(&state->frontend.ops, &lgdt3305_ops, -- sizeof(struct dvb_frontend_ops)); -+ switch (config->demod_chip) { -+ case LGDT3304: -+ memcpy(&state->frontend.ops, &lgdt3304_ops, -+ sizeof(struct dvb_frontend_ops)); -+ break; -+ case LGDT3305: -+ memcpy(&state->frontend.ops, &lgdt3305_ops, -+ sizeof(struct dvb_frontend_ops)); -+ break; -+ default: -+ goto fail; -+ } - state->frontend.demodulator_priv = state; - -- /* verify that we're talking to a lg dt3305 */ -+ /* verify that we're talking to a lg dt3304/5 */ - ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_2, &val); - if ((lg_fail(ret)) | (val == 0)) - goto fail; -@@ -1035,12 +1199,36 @@ struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config, - - return &state->frontend; - fail: -- lg_warn("unable to detect LGDT3305 hardware\n"); -+ lg_warn("unable to detect %s hardware\n", -+ config->demod_chip ? "LGDT3304" : "LGDT3305"); - kfree(state); - return NULL; - } - EXPORT_SYMBOL(lgdt3305_attach); - -+static struct dvb_frontend_ops lgdt3304_ops = { -+ .info = { -+ .name = "LG Electronics LGDT3304 VSB/QAM Frontend", -+ .type = FE_ATSC, -+ .frequency_min = 54000000, -+ .frequency_max = 858000000, -+ .frequency_stepsize = 62500, -+ .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB -+ }, -+ .i2c_gate_ctrl = lgdt3305_i2c_gate_ctrl, -+ .init = lgdt3304_init, -+ .sleep = lgdt3304_sleep, -+ .set_frontend = lgdt3304_set_parameters, -+ .get_frontend = lgdt3305_get_frontend, -+ .get_tune_settings = lgdt3305_get_tune_settings, -+ .read_status = lgdt3305_read_status, -+ .read_ber = lgdt3305_read_ber, -+ .read_signal_strength = lgdt3305_read_signal_strength, -+ .read_snr = lgdt3305_read_snr, -+ .read_ucblocks = lgdt3305_read_ucblocks, -+ .release = lgdt3305_release, -+}; -+ - static struct dvb_frontend_ops lgdt3305_ops = { - .info = { - .name = "LG Electronics LGDT3305 VSB/QAM Frontend", -@@ -1064,7 +1252,7 @@ static struct dvb_frontend_ops lgdt3305_ops = { - .release = lgdt3305_release, - }; - --MODULE_DESCRIPTION("LG Electronics LGDT3305 ATSC/QAM-B Demodulator Driver"); -+MODULE_DESCRIPTION("LG Electronics LGDT3304/5 ATSC/QAM-B Demodulator Driver"); - MODULE_AUTHOR("Michael Krufky "); - MODULE_LICENSE("GPL"); - MODULE_VERSION("0.1"); -diff --git a/drivers/media/dvb/frontends/lgdt3305.h b/drivers/media/dvb/frontends/lgdt3305.h -index 9cb11c9..a7f30c2 100644 ---- a/drivers/media/dvb/frontends/lgdt3305.h -+++ b/drivers/media/dvb/frontends/lgdt3305.h -@@ -41,6 +41,11 @@ enum lgdt3305_tp_valid_polarity { - LGDT3305_TP_VALID_HIGH = 1, - }; - -+enum lgdt_demod_chip_type { -+ LGDT3305 = 0, -+ LGDT3304 = 1, -+}; -+ - struct lgdt3305_config { - u8 i2c_addr; - -@@ -65,6 +70,7 @@ struct lgdt3305_config { - enum lgdt3305_mpeg_mode mpeg_mode; - enum lgdt3305_tp_clock_edge tpclk_edge; - enum lgdt3305_tp_valid_polarity tpvalid_polarity; -+ enum lgdt_demod_chip_type demod_chip; - }; - - #if defined(CONFIG_DVB_LGDT3305) || (defined(CONFIG_DVB_LGDT3305_MODULE) && \ --- -1.6.6 - diff --git a/linux-2.6-v4l-dvb-experimental.patch b/linux-2.6-v4l-dvb-experimental.patch deleted file mode 100644 index e69de29bb..000000000 diff --git a/linux-2.6-v4l-dvb-fixes.patch b/linux-2.6-v4l-dvb-fixes.patch deleted file mode 100644 index e69de29bb..000000000 diff --git a/linux-2.6-v4l-dvb-ir-core-update.patch b/linux-2.6-v4l-dvb-ir-core-update.patch deleted file mode 100644 index c1105a330..000000000 --- a/linux-2.6-v4l-dvb-ir-core-update.patch +++ /dev/null @@ -1,6741 +0,0 @@ -Patch generated from the linuxtv staging/other branch, with a few -additional pending fixes merged in, and just about everything not -essential to the ir-core update chopped out. - -(Patch generated 2010.07.16) - -Signed-off-by: Jarod Wilson - ---- - Documentation/DocBook/media-entities.tmpl | 1 - Documentation/DocBook/media.tmpl | 8 - Documentation/DocBook/v4l/lirc_device_interface.xml | 235 ++++ - Documentation/DocBook/v4l/remote_controllers.xml | 2 - Documentation/dvb/get_dvb_firmware | 19 - Documentation/video4linux/CARDLIST.cx23885 | 6 - drivers/input/evdev.c | 39 - drivers/input/input.c | 268 ++++ - drivers/media/IR/Kconfig | 34 - drivers/media/IR/Makefile | 3 - drivers/media/IR/imon.c | 5 - drivers/media/IR/ir-core-priv.h | 54 - drivers/media/IR/ir-jvc-decoder.c | 152 -- - drivers/media/IR/ir-lirc-codec.c | 283 ++++ - drivers/media/IR/ir-nec-decoder.c | 151 -- - drivers/media/IR/ir-raw-event.c | 167 +- - drivers/media/IR/ir-rc5-decoder.c | 167 -- - drivers/media/IR/ir-rc6-decoder.c | 153 -- - drivers/media/IR/ir-sony-decoder.c | 155 -- - drivers/media/IR/ir-sysfs.c | 261 ++-- - drivers/media/IR/keymaps/Makefile | 2 - drivers/media/IR/keymaps/rc-lirc.c | 41 - drivers/media/IR/keymaps/rc-rc6-mce.c | 105 + - drivers/media/IR/lirc_dev.c | 764 +++++++++++++ - drivers/media/IR/mceusb.c | 1143 ++++++++++++++++++++ - drivers/media/common/tuners/tda18271-fe.c | 8 - drivers/media/dvb/mantis/Kconfig | 14 - drivers/media/dvb/mantis/mantis_input.c | 5 - drivers/media/video/cx23885/cx23885-cards.c | 40 - drivers/media/video/cx23885/cx23885-core.c | 11 - drivers/media/video/cx23885/cx23885-dvb.c | 2 - drivers/media/video/cx23885/cx23885-input.c | 317 +---- - drivers/media/video/cx23885/cx23885-ir.c | 2 - drivers/media/video/cx23885/cx23885.h | 12 - drivers/media/video/cx88/cx88-cards.c | 9 - drivers/media/video/cx88/cx88-i2c.c | 6 - drivers/media/video/cx88/cx88-input.c | 46 - drivers/media/video/cx88/cx88.h | 1 - drivers/media/video/em28xx/em28xx-input.c | 80 - - drivers/media/video/em28xx/em28xx-video.c | 4 - drivers/media/video/em28xx/em28xx.h | 1 - drivers/media/video/hdpvr/hdpvr-core.c | 5 - drivers/media/video/ir-kbd-i2c.c | 14 - drivers/media/video/pvrusb2/pvrusb2-ioread.c | 5 - include/linux/input.h | 39 - include/media/ir-core.h | 8 - include/media/ir-kbd-i2c.h | 2 - include/media/lirc.h | 165 ++ - include/media/lirc_dev.h | 225 +++ - include/media/rc-map.h | 7 - 50 files changed, 3971 insertions(+), 1275 deletions(-) - -diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl -index 5d4d40f..6ae9715 100644 ---- a/Documentation/DocBook/media-entities.tmpl -+++ b/Documentation/DocBook/media-entities.tmpl -@@ -218,6 +218,7 @@ - - - -+ - - - -diff --git a/Documentation/DocBook/media.tmpl b/Documentation/DocBook/media.tmpl -index eea564b..f11048d 100644 ---- a/Documentation/DocBook/media.tmpl -+++ b/Documentation/DocBook/media.tmpl -@@ -28,7 +28,7 @@ - LINUX MEDIA INFRASTRUCTURE API - - -- 2009 -+ 2009-2010 - LinuxTV Developers - - -@@ -61,7 +61,7 @@ Foundation. A copy of the license is included in the chapter entitled - in fact it covers several different video standards including - DVB-T, DVB-S, DVB-C and ATSC. The API is currently being updated - to documment support also for DVB-S2, ISDB-T and ISDB-S. -- The third part covers other API's used by all media infrastructure devices -+ The third part covers Remote Controller API - For additional information and for the latest development code, - see: http://linuxtv.org. - For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: Linux Media Mailing List (LMML).. -@@ -86,7 +86,7 @@ Foundation. A copy of the license is included in the chapter entitled - - - -- 2009 -+ 2009-2010 - Mauro Carvalho Chehab - - -@@ -101,7 +101,7 @@ Foundation. A copy of the license is included in the chapter entitled - - - --Other API's used by media infrastructure drivers -+Remote Controller API - - &sub-remote_controllers; - -diff --git a/Documentation/DocBook/v4l/lirc_device_interface.xml b/Documentation/DocBook/v4l/lirc_device_interface.xml -new file mode 100644 -index 0000000..0413234 ---- /dev/null -+++ b/Documentation/DocBook/v4l/lirc_device_interface.xml -@@ -0,0 +1,235 @@ -+
-+LIRC Device Interface -+ -+ -+
-+Introduction -+ -+The LIRC device interface is a bi-directional interface for -+transporting raw IR data between userspace and kernelspace. Fundamentally, -+it is just a chardev (/dev/lircX, for X = 0, 1, 2, ...), with a number -+of standard struct file_operations defined on it. With respect to -+transporting raw IR data to and fro, the essential fops are read, write -+and ioctl. -+ -+Example dmesg output upon a driver registering w/LIRC: -+
-+ $ dmesg |grep lirc_dev -+ lirc_dev: IR Remote Control driver registered, major 248 -+ rc rc0: lirc_dev: driver ir-lirc-codec (mceusb) registered at minor = 0 -+
-+ -+What you should see for a chardev: -+
-+ $ ls -l /dev/lirc* -+ crw-rw---- 1 root root 248, 0 Jul 2 22:20 /dev/lirc0 -+
-+
-+ -+
-+LIRC read fop -+ -+The lircd userspace daemon reads raw IR data from the LIRC chardev. The -+exact format of the data depends on what modes a driver supports, and what -+mode has been selected. lircd obtains supported modes and sets the active mode -+via the ioctl interface, detailed at . The generally -+preferred mode is LIRC_MODE_MODE2, in which packets containing an int value -+describing an IR signal are read from the chardev. -+ -+See also http://www.lirc.org/html/technical.html for more info. -+
-+ -+
-+LIRC write fop -+ -+The data written to the chardev is a pulse/space sequence of integer -+values. Pulses and spaces are only marked implicitly by their position. The -+data must start and end with a pulse, therefore, the data must always include -+an unevent number of samples. The write function must block until the data has -+been transmitted by the hardware. -+
-+ -+
-+LIRC ioctl fop -+ -+The LIRC device's ioctl definition is bound by the ioctl function -+definition of struct file_operations, leaving us with an unsigned int -+for the ioctl command and an unsigned long for the arg. For the purposes -+of ioctl portability across 32-bit and 64-bit, these values are capped -+to their 32-bit sizes. -+ -+The following ioctls can be used to change specific hardware settings. -+In general each driver should have a default set of settings. The driver -+implementation is expected to re-apply the default settings when the device -+is closed by user-space, so that every application opening the device can rely -+on working with the default settings initially. -+ -+ -+ -+ LIRC_GET_FEATURES -+ -+ Obviously, get the underlying hardware device's features. If a driver -+ does not announce support of certain features, calling of the corresponding -+ ioctls is undefined. -+ -+ -+ -+ LIRC_GET_SEND_MODE -+ -+ Get supported transmit mode. Only LIRC_MODE_PULSE is supported by lircd. -+ -+ -+ -+ LIRC_GET_REC_MODE -+ -+ Get supported receive modes. Only LIRC_MODE_MODE2 and LIRC_MODE_LIRCCODE -+ are supported by lircd. -+ -+ -+ -+ LIRC_GET_SEND_CARRIER -+ -+ Get carrier frequency (in Hz) currently used for transmit. -+ -+ -+ -+ LIRC_GET_REC_CARRIER -+ -+ Get carrier frequency (in Hz) currently used for IR reception. -+ -+ -+ -+ LIRC_{G,S}ET_{SEND,REC}_DUTY_CYCLE -+ -+ Get/set the duty cycle (from 0 to 100) of the carrier signal. Currently, -+ no special meaning is defined for 0 or 100, but this could be used to switch -+ off carrier generation in the future, so these values should be reserved. -+ -+ -+ -+ LIRC_GET_REC_RESOLUTION -+ -+ Some receiver have maximum resolution which is defined by internal -+ sample rate or data format limitations. E.g. it's common that signals can -+ only be reported in 50 microsecond steps. This integer value is used by -+ lircd to automatically adjust the aeps tolerance value in the lircd -+ config file. -+ -+ -+ -+ LIRC_GET_M{IN,AX}_TIMEOUT -+ -+ Some devices have internal timers that can be used to detect when -+ there's no IR activity for a long time. This can help lircd in detecting -+ that a IR signal is finished and can speed up the decoding process. -+ Returns an integer value with the minimum/maximum timeout that can be -+ set. Some devices have a fixed timeout, in that case both ioctls will -+ return the same value even though the timeout cannot be changed. -+ -+ -+ -+ LIRC_GET_M{IN,AX}_FILTER_{PULSE,SPACE} -+ -+ Some devices are able to filter out spikes in the incoming signal -+ using given filter rules. These ioctls return the hardware capabilities -+ that describe the bounds of the possible filters. Filter settings depend -+ on the IR protocols that are expected. lircd derives the settings from -+ all protocols definitions found in its config file. -+ -+ -+ -+ LIRC_GET_LENGTH -+ -+ Retrieves the code length in bits (only for LIRC_MODE_LIRCCODE). -+ Reads on the device must be done in blocks matching the bit count. -+ The bit could should be rounded up so that it matches full bytes. -+ -+ -+ -+ LIRC_SET_{SEND,REC}_MODE -+ -+ Set send/receive mode. Largely obsolete for send, as only -+ LIRC_MODE_PULSE is supported. -+ -+ -+ -+ LIRC_SET_{SEND,REC}_CARRIER -+ -+ Set send/receive carrier (in Hz). -+ -+ -+ -+ LIRC_SET_TRANSMITTER_MASK -+ -+ This enables the given set of transmitters. The first transmitter -+ is encoded by the least significant bit, etc. When an invalid bit mask -+ is given, i.e. a bit is set, even though the device does not have so many -+ transitters, then this ioctl returns the number of available transitters -+ and does nothing otherwise. -+ -+ -+ -+ LIRC_SET_REC_TIMEOUT -+ -+ Sets the integer value for IR inactivity timeout (cf. -+ LIRC_GET_MIN_TIMEOUT and LIRC_GET_MAX_TIMEOUT). A value of 0 (if -+ supported by the hardware) disables all hardware timeouts and data should -+ be reported as soon as possible. If the exact value cannot be set, then -+ the next possible value _greater_ than the given value should be set. -+ -+ -+ -+ LIRC_SET_REC_TIMEOUT_REPORTS -+ -+ Enable (1) or disable (0) timeout reports in LIRC_MODE_MODE2. By -+ default, timeout reports should be turned off. -+ -+ -+ -+ LIRC_SET_REC_FILTER_{,PULSE,SPACE} -+ -+ Pulses/spaces shorter than this are filtered out by hardware. If -+ filters cannot be set independently for pulse/space, the corresponding -+ ioctls must return an error and LIRC_SET_REC_FILTER shall be used instead. -+ -+ -+ -+ LIRC_SET_MEASURE_CARRIER_MODE -+ -+ Enable (1)/disable (0) measure mode. If enabled, from the next key -+ press on, the driver will send LIRC_MODE2_FREQUENCY packets. By default -+ this should be turned off. -+ -+ -+ -+ LIRC_SET_REC_{DUTY_CYCLE,CARRIER}_RANGE -+ -+ To set a range use LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE -+ with the lower bound first and later LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER -+ with the upper bound. -+ -+ -+ -+ LIRC_NOTIFY_DECODE -+ -+ This ioctl is called by lircd whenever a successful decoding of an -+ incoming IR signal could be done. This can be used by supporting hardware -+ to give visual feedback to the user e.g. by flashing a LED. -+ -+ -+ -+ LIRC_SETUP_{START,END} -+ -+ Setting of several driver parameters can be optimized by encapsulating -+ the according ioctl calls with LIRC_SETUP_START/LIRC_SETUP_END. When a -+ driver receives a LIRC_SETUP_START ioctl it can choose to not commit -+ further setting changes to the hardware until a LIRC_SETUP_END is received. -+ But this is open to the driver implementation and every driver must also -+ handle parameter changes which are not encapsulated by LIRC_SETUP_START -+ and LIRC_SETUP_END. Drivers can also choose to ignore these ioctls. -+ -+ -+ -+ -+
-+
-diff --git a/Documentation/DocBook/v4l/remote_controllers.xml b/Documentation/DocBook/v4l/remote_controllers.xml -index 73f5eab..3c3b667 100644 ---- a/Documentation/DocBook/v4l/remote_controllers.xml -+++ b/Documentation/DocBook/v4l/remote_controllers.xml -@@ -173,3 +173,5 @@ keymapping.
- This program demonstrates how to replace the keymap tables. - &sub-keytable-c; -
-+ -+&sub-lirc_device_interface; -diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware -index 239cbdb..9ea94dc 100644 ---- a/Documentation/dvb/get_dvb_firmware -+++ b/Documentation/dvb/get_dvb_firmware -@@ -26,7 +26,7 @@ use IO::Handle; - "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004", - "or51211", "or51132_qam", "or51132_vsb", "bluebird", - "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718", -- "af9015", "ngene"); -+ "af9015", "ngene", "az6027"); - - # Check args - syntax() if (scalar(@ARGV) != 1); -@@ -567,6 +567,23 @@ sub ngene { - "$file1, $file2"; - } - -+sub az6027{ -+ my $file = "AZ6027_Linux_Driver.tar.gz"; -+ my $url = "http://linux.terratec.de/files/$file"; -+ my $firmware = "dvb-usb-az6027-03.fw"; -+ -+ wgetfile($file, $url); -+ -+ #untar -+ if( system("tar xzvf $file $firmware")){ -+ die "failed to untar firmware"; -+ } -+ if( system("rm $file")){ -+ die ("unable to remove unnecessary files"); -+ } -+ -+ $firmware; -+} - # --------------------------------------------------------------- - # Utilities - -diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885 -index 16ca030..87c4634 100644 ---- a/Documentation/video4linux/CARDLIST.cx23885 -+++ b/Documentation/video4linux/CARDLIST.cx23885 -@@ -17,9 +17,9 @@ - 16 -> DVBWorld DVB-S2 2005 [0001:2005] - 17 -> NetUP Dual DVB-S2 CI [1b55:2a2c] - 18 -> Hauppauge WinTV-HVR1270 [0070:2211] -- 19 -> Hauppauge WinTV-HVR1275 [0070:2215] -- 20 -> Hauppauge WinTV-HVR1255 [0070:2251] -- 21 -> Hauppauge WinTV-HVR1210 [0070:2291,0070:2295] -+ 19 -> Hauppauge WinTV-HVR1275 [0070:2215,0070:221d,0070:22f2] -+ 20 -> Hauppauge WinTV-HVR1255 [0070:2251,0070:2259,0070:22f1] -+ 21 -> Hauppauge WinTV-HVR1210 [0070:2291,0070:2295,0070:2299,0070:229d,0070:22f0,0070:22f3,0070:22f4,0070:22f5] - 22 -> Mygica X8506 DMB-TH [14f1:8651] - 23 -> Magic-Pro ProHDTV Extreme 2 [14f1:8657] - 24 -> Hauppauge WinTV-HVR1850 [0070:8541] -diff --git a/Documentation/video4linux/extract_xc3028.pl b/Documentation/video4linux/extract_xc3028.pl -old mode 100644 -new mode 100755 -diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c -index 2ee6c7a..b8a5673 100644 ---- a/drivers/input/evdev.c -+++ b/drivers/input/evdev.c -@@ -515,6 +515,8 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, - struct input_absinfo abs; - struct ff_effect effect; - int __user *ip = (int __user *)p; -+ struct keycode_table_entry kt, *kt_p = p; -+ char scancode[16]; - unsigned int i, t, u, v; - int error; - -@@ -569,6 +571,43 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, - - return input_set_keycode(dev, t, v); - -+ case EVIOCGKEYCODEBIG: -+ if (copy_from_user(&kt, kt_p, sizeof(kt))) -+ return -EFAULT; -+ -+ if (kt.len > sizeof(scancode)) -+ return -EINVAL; -+ -+ kt.scancode = scancode; -+ -+ error = input_get_keycode_big(dev, &kt); -+ if (error) -+ return error; -+ -+ if (copy_to_user(kt_p, &kt, sizeof(kt))) -+ return -EFAULT; -+ -+ /* FIXME: probably need some compat32 code */ -+ if (copy_to_user(kt_p->scancode, kt.scancode, kt.len)) -+ return -EFAULT; -+ -+ return 0; -+ -+ case EVIOCSKEYCODEBIG: -+ if (copy_from_user(&kt, kt_p, sizeof(kt))) -+ return -EFAULT; -+ -+ if (kt.len > sizeof(scancode)) -+ return -EINVAL; -+ -+ kt.scancode = scancode; -+ -+ /* FIXME: probably need some compat32 code */ -+ if (copy_from_user(kt.scancode, kt_p->scancode, kt.len)) -+ return -EFAULT; -+ -+ return input_set_keycode_big(dev, &kt); -+ - case EVIOCRMFF: - return input_ff_erase(dev, (int)(unsigned long) p, file); - -diff --git a/drivers/input/input.c b/drivers/input/input.c -index 9c79bd5..43aeb71 100644 ---- a/drivers/input/input.c -+++ b/drivers/input/input.c -@@ -568,6 +568,11 @@ static void input_disconnect_device(struct input_dev *dev) - spin_unlock_irq(&dev->event_lock); - } - -+/* -+ * Those routines handle the default case where no [gs]etkeycode() is -+ * defined. In this case, an array indexed by the scancode is used. -+ */ -+ - static int input_fetch_keycode(struct input_dev *dev, int scancode) - { - switch (dev->keycodesize) { -@@ -582,27 +587,74 @@ static int input_fetch_keycode(struct input_dev *dev, int scancode) - } - } - --static int input_default_getkeycode(struct input_dev *dev, -- unsigned int scancode, -- unsigned int *keycode) -+/* -+ * Supports only 8, 16 and 32 bit scancodes. It wouldn't be that -+ * hard to write some machine-endian logic to support 24 bit scancodes, -+ * but it seemed overkill. It should also be noticed that, since there -+ * are, in general, less than 256 scancodes sparsed into the scancode -+ * space, even with 16 bits, the codespace is sparsed, with leads into -+ * memory and code ineficiency, when retrieving the entire scancode -+ * space. -+ * So, it is highly recommended to implement getkeycodebig/setkeycodebig -+ * instead of using a normal table approach, when more than 8 bits is -+ * needed for the scancode. -+ */ -+static int input_fetch_scancode(struct keycode_table_entry *kt_entry, -+ u32 *scancode) - { -+ switch (kt_entry->len) { -+ case 1: -+ *scancode = *((u8 *)kt_entry->scancode); -+ break; -+ case 2: -+ *scancode = *((u16 *)kt_entry->scancode); -+ break; -+ case 4: -+ *scancode = *((u32 *)kt_entry->scancode); -+ break; -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+ -+static int input_default_getkeycode_from_index(struct input_dev *dev, -+ struct keycode_table_entry *kt_entry) -+{ -+ u32 scancode = kt_entry->index; -+ - if (!dev->keycodesize) - return -EINVAL; - - if (scancode >= dev->keycodemax) - return -EINVAL; - -- *keycode = input_fetch_keycode(dev, scancode); -+ kt_entry->keycode = input_fetch_keycode(dev, scancode); -+ memcpy(kt_entry->scancode, &scancode, 4); - - return 0; - } - -+static int input_default_getkeycode_from_scancode(struct input_dev *dev, -+ struct keycode_table_entry *kt_entry) -+{ -+ if (input_fetch_scancode(kt_entry, &kt_entry->index)) -+ return -EINVAL; -+ -+ return input_default_getkeycode_from_index(dev, kt_entry); -+} -+ -+ - static int input_default_setkeycode(struct input_dev *dev, -- unsigned int scancode, -- unsigned int keycode) -+ struct keycode_table_entry *kt_entry) - { -- int old_keycode; -+ u32 old_keycode; - int i; -+ u32 scancode; -+ -+ if (input_fetch_scancode(kt_entry, &scancode)) -+ return -EINVAL; - - if (scancode >= dev->keycodemax) - return -EINVAL; -@@ -610,32 +662,33 @@ static int input_default_setkeycode(struct input_dev *dev, - if (!dev->keycodesize) - return -EINVAL; - -- if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8))) -+ if (dev->keycodesize < sizeof(dev->keycode) && -+ (kt_entry->keycode >> (dev->keycodesize * 8))) - return -EINVAL; - - switch (dev->keycodesize) { - case 1: { - u8 *k = (u8 *)dev->keycode; - old_keycode = k[scancode]; -- k[scancode] = keycode; -+ k[scancode] = kt_entry->keycode; - break; - } - case 2: { - u16 *k = (u16 *)dev->keycode; - old_keycode = k[scancode]; -- k[scancode] = keycode; -+ k[scancode] = kt_entry->keycode; - break; - } - default: { - u32 *k = (u32 *)dev->keycode; - old_keycode = k[scancode]; -- k[scancode] = keycode; -+ k[scancode] = kt_entry->keycode; - break; - } - } - - __clear_bit(old_keycode, dev->keybit); -- __set_bit(keycode, dev->keybit); -+ __set_bit(kt_entry->keycode, dev->keybit); - - for (i = 0; i < dev->keycodemax; i++) { - if (input_fetch_keycode(dev, i) == old_keycode) { -@@ -648,6 +701,110 @@ static int input_default_setkeycode(struct input_dev *dev, - } - - /** -+ * input_get_keycode_big - retrieve keycode currently mapped to a given scancode -+ * @dev: input device which keymap is being queried -+ * @kt_entry: keytable entry -+ * -+ * This function should be called by anyone interested in retrieving current -+ * keymap. Presently evdev handlers use it. -+ */ -+int input_get_keycode_big(struct input_dev *dev, -+ struct keycode_table_entry *kt_entry) -+{ -+ if (dev->getkeycode) { -+ u32 scancode = kt_entry->index; -+ -+ /* -+ * Support for legacy drivers, that don't implement the new -+ * ioctls -+ */ -+ memcpy(kt_entry->scancode, &scancode, 4); -+ return dev->getkeycode(dev, scancode, -+ &kt_entry->keycode); -+ } else -+ return dev->getkeycodebig_from_index(dev, kt_entry); -+} -+EXPORT_SYMBOL(input_get_keycode_big); -+ -+/** -+ * input_set_keycode_big - attribute a keycode to a given scancode -+ * @dev: input device which keymap is being queried -+ * @kt_entry: keytable entry -+ * -+ * This function should be called by anyone needing to update current -+ * keymap. Presently keyboard and evdev handlers use it. -+ */ -+int input_set_keycode_big(struct input_dev *dev, -+ struct keycode_table_entry *kt_entry) -+{ -+ unsigned long flags; -+ int old_keycode; -+ int retval = -EINVAL; -+ u32 uninitialized_var(scancode); -+ -+ if (kt_entry->keycode < 0 || kt_entry->keycode > KEY_MAX) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&dev->event_lock, flags); -+ -+ /* -+ * We need to know the old scancode, in order to generate a -+ * keyup effect, if the set operation happens successfully -+ */ -+ if (dev->getkeycode) { -+ /* -+ * Support for legacy drivers, that don't implement the new -+ * ioctls -+ */ -+ if (!dev->setkeycode) -+ goto out; -+ -+ retval = input_fetch_scancode(kt_entry, &scancode); -+ if (retval) -+ goto out; -+ -+ retval = dev->getkeycode(dev, scancode, -+ &old_keycode); -+ } else { -+ int new_keycode = kt_entry->keycode; -+ -+ retval = dev->getkeycodebig_from_scancode(dev, kt_entry); -+ old_keycode = kt_entry->keycode; -+ kt_entry->keycode = new_keycode; -+ } -+ -+ if (retval) -+ goto out; -+ -+ if (dev->getkeycode) -+ retval = dev->setkeycode(dev, scancode, -+ kt_entry->keycode); -+ else -+ retval = dev->setkeycodebig(dev, kt_entry); -+ if (retval) -+ goto out; -+ -+ /* -+ * Simulate keyup event if keycode is not present -+ * in the keymap anymore -+ */ -+ if (test_bit(EV_KEY, dev->evbit) && -+ !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && -+ __test_and_clear_bit(old_keycode, dev->key)) { -+ -+ input_pass_event(dev, EV_KEY, old_keycode, 0); -+ if (dev->sync) -+ input_pass_event(dev, EV_SYN, SYN_REPORT, 1); -+ } -+ -+ out: -+ spin_unlock_irqrestore(&dev->event_lock, flags); -+ -+ return retval; -+} -+EXPORT_SYMBOL(input_set_keycode_big); -+ -+/** - * input_get_keycode - retrieve keycode currently mapped to a given scancode - * @dev: input device which keymap is being queried - * @scancode: scancode (or its equivalent for device in question) for which -@@ -661,13 +818,35 @@ int input_get_keycode(struct input_dev *dev, - unsigned int scancode, unsigned int *keycode) - { - unsigned long flags; -- int retval; - -- spin_lock_irqsave(&dev->event_lock, flags); -- retval = dev->getkeycode(dev, scancode, keycode); -- spin_unlock_irqrestore(&dev->event_lock, flags); -+ if (dev->getkeycode) { -+ /* -+ * Use the legacy calls -+ */ -+ return dev->getkeycode(dev, scancode, keycode); -+ } else { -+ int retval; -+ struct keycode_table_entry kt_entry; - -- return retval; -+ /* -+ * Userspace is using a legacy call with a driver ported -+ * to the new way. This is a bad idea with long sparsed -+ * tables, since lots of the retrieved values will be in -+ * blank. Also, it makes sense only if the table size is -+ * lower than 2^32. -+ */ -+ memset(&kt_entry, 0, sizeof(kt_entry)); -+ kt_entry.len = 4; -+ kt_entry.index = scancode; -+ kt_entry.scancode = (char *)&scancode; -+ -+ spin_lock_irqsave(&dev->event_lock, flags); -+ retval = dev->getkeycodebig_from_index(dev, &kt_entry); -+ spin_unlock_irqrestore(&dev->event_lock, flags); -+ -+ *keycode = kt_entry.keycode; -+ return retval; -+ } - } - EXPORT_SYMBOL(input_get_keycode); - -@@ -692,13 +871,42 @@ int input_set_keycode(struct input_dev *dev, - - spin_lock_irqsave(&dev->event_lock, flags); - -- retval = dev->getkeycode(dev, scancode, &old_keycode); -- if (retval) -- goto out; -+ if (dev->getkeycode) { -+ /* -+ * Use the legacy calls -+ */ -+ retval = dev->getkeycode(dev, scancode, &old_keycode); -+ if (retval) -+ goto out; - -- retval = dev->setkeycode(dev, scancode, keycode); -- if (retval) -- goto out; -+ retval = dev->setkeycode(dev, scancode, keycode); -+ if (retval) -+ goto out; -+ } else { -+ struct keycode_table_entry kt_entry; -+ -+ /* -+ * Userspace is using a legacy call with a driver ported -+ * to the new way. This is a bad idea with long sparsed -+ * tables, since lots of the retrieved values will be in -+ * blank. Also, it makes sense only if the table size is -+ * lower than 2^32. -+ */ -+ memset(&kt_entry, 0, sizeof(kt_entry)); -+ kt_entry.len = 4; -+ kt_entry.scancode = (char *)&scancode; -+ -+ retval = dev->getkeycodebig_from_scancode(dev, &kt_entry); -+ if (retval) -+ goto out; -+ -+ old_keycode = kt_entry.keycode; -+ kt_entry.keycode = keycode; -+ -+ retval = dev->setkeycodebig(dev, &kt_entry); -+ if (retval) -+ goto out; -+ } - - /* Make sure KEY_RESERVED did not get enabled. */ - __clear_bit(KEY_RESERVED, dev->keybit); -@@ -1636,11 +1843,17 @@ int input_register_device(struct input_dev *dev) - dev->rep[REP_PERIOD] = 33; - } - -- if (!dev->getkeycode) -- dev->getkeycode = input_default_getkeycode; -+ if (!dev->getkeycode) { -+ if (!dev->getkeycodebig_from_index) -+ dev->getkeycodebig_from_index = input_default_getkeycode_from_index; -+ if (!dev->getkeycodebig_from_scancode) -+ dev->getkeycodebig_from_scancode = input_default_getkeycode_from_scancode; -+ } - -- if (!dev->setkeycode) -- dev->setkeycode = input_default_setkeycode; -+ if (!dev->setkeycode) { -+ if (!dev->setkeycodebig) -+ dev->setkeycodebig = input_default_setkeycode; -+ } - - dev_set_name(&dev->dev, "input%ld", - (unsigned long) atomic_inc_return(&input_no) - 1); -diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig -index d22a8ec..e557ae0 100644 ---- a/drivers/media/IR/Kconfig -+++ b/drivers/media/IR/Kconfig -@@ -8,6 +8,17 @@ config VIDEO_IR - depends on IR_CORE - default IR_CORE - -+config LIRC -+ tristate -+ default y -+ -+ ---help--- -+ Enable this option to build the Linux Infrared Remote -+ Control (LIRC) core device interface driver. The LIRC -+ interface passes raw IR to and from userspace, where the -+ LIRC daemon handles protocol decoding for IR reception ann -+ encoding for IR transmitting (aka "blasting"). -+ - source "drivers/media/IR/keymaps/Kconfig" - - config IR_NEC_DECODER -@@ -42,6 +53,7 @@ config IR_RC6_DECODER - config IR_JVC_DECODER - tristate "Enable IR raw decoder for the JVC protocol" - depends on IR_CORE -+ select BITREVERSE - default y - - ---help--- -@@ -57,6 +69,16 @@ config IR_SONY_DECODER - Enable this option if you have an infrared remote control which - uses the Sony protocol, and you need software decoding support. - -+config IR_LIRC_CODEC -+ tristate "Enable IR to LIRC bridge" -+ depends on IR_CORE -+ depends on LIRC -+ default y -+ -+ ---help--- -+ Enable this option to pass raw IR to and from userspace via -+ the LIRC interface. -+ - config IR_IMON - tristate "SoundGraph iMON Receiver and Display" - depends on USB_ARCH_HAS_HCD -@@ -68,3 +90,15 @@ config IR_IMON - - To compile this driver as a module, choose M here: the - module will be called imon. -+ -+config IR_MCEUSB -+ tristate "Windows Media Center Ed. eHome Infrared Transceiver" -+ depends on USB_ARCH_HAS_HCD -+ depends on IR_CORE -+ select USB -+ ---help--- -+ Say Y here if you want to use a Windows Media Center Edition -+ eHome Infrared Transceiver. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called mceusb. -diff --git a/drivers/media/IR/Makefile b/drivers/media/IR/Makefile -index b998fcc..2ae4f3a 100644 ---- a/drivers/media/IR/Makefile -+++ b/drivers/media/IR/Makefile -@@ -5,11 +5,14 @@ obj-y += keymaps/ - - obj-$(CONFIG_IR_CORE) += ir-core.o - obj-$(CONFIG_VIDEO_IR) += ir-common.o -+obj-$(CONFIG_LIRC) += lirc_dev.o - obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o - obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o - obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o - obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o - obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o -+obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o - - # stand-alone IR receivers/transmitters - obj-$(CONFIG_IR_IMON) += imon.o -+obj-$(CONFIG_IR_MCEUSB) += mceusb.o -diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c -index 4bbd45f..0195dd5 100644 ---- a/drivers/media/IR/imon.c -+++ b/drivers/media/IR/imon.c -@@ -1943,7 +1943,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) - return ictx; - - urb_submit_failed: -- input_unregister_device(ictx->idev); -+ ir_input_unregister(ictx->idev); - input_free_device(ictx->idev); - idev_setup_failed: - find_endpoint_failed: -@@ -2067,6 +2067,7 @@ static void imon_get_ffdc_type(struct imon_context *ictx) - detected_display_type = IMON_DISPLAY_TYPE_VFD; - break; - /* iMON LCD, MCE IR */ -+ case 0x9e: - case 0x9f: - dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR"); - detected_display_type = IMON_DISPLAY_TYPE_LCD; -@@ -2306,7 +2307,7 @@ static void __devexit imon_disconnect(struct usb_interface *interface) - if (ifnum == 0) { - ictx->dev_present_intf0 = false; - usb_kill_urb(ictx->rx_urb_intf0); -- input_unregister_device(ictx->idev); -+ ir_input_unregister(ictx->idev); - if (ictx->display_supported) { - if (ictx->display_type == IMON_DISPLAY_TYPE_LCD) - usb_deregister_dev(interface, &imon_lcd_class); -diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h -index 9a5e65a..babd520 100644 ---- a/drivers/media/IR/ir-core-priv.h -+++ b/drivers/media/IR/ir-core-priv.h -@@ -22,17 +22,62 @@ - struct ir_raw_handler { - struct list_head list; - -+ u64 protocols; /* which are handled by this handler */ - int (*decode)(struct input_dev *input_dev, struct ir_raw_event event); -+ -+ /* These two should only be used by the lirc decoder */ - int (*raw_register)(struct input_dev *input_dev); - int (*raw_unregister)(struct input_dev *input_dev); - }; - - struct ir_raw_event_ctrl { -+ struct list_head list; /* to keep track of raw clients */ - struct work_struct rx_work; /* for the rx decoding workqueue */ - struct kfifo kfifo; /* fifo for the pulse/space durations */ - ktime_t last_event; /* when last event occurred */ - enum raw_event_type last_type; /* last event type */ - struct input_dev *input_dev; /* pointer to the parent input_dev */ -+ u64 enabled_protocols; /* enabled raw protocol decoders */ -+ -+ /* raw decoder state follows */ -+ struct ir_raw_event prev_ev; -+ struct nec_dec { -+ int state; -+ unsigned count; -+ u32 bits; -+ } nec; -+ struct rc5_dec { -+ int state; -+ u32 bits; -+ unsigned count; -+ unsigned wanted_bits; -+ } rc5; -+ struct rc6_dec { -+ int state; -+ u8 header; -+ u32 body; -+ bool toggle; -+ unsigned count; -+ unsigned wanted_bits; -+ } rc6; -+ struct sony_dec { -+ int state; -+ u32 bits; -+ unsigned count; -+ } sony; -+ struct jvc_dec { -+ int state; -+ u16 bits; -+ u16 old_bits; -+ unsigned count; -+ bool first; -+ bool toggle; -+ } jvc; -+ struct lirc_codec { -+ struct ir_input_dev *ir_dev; -+ struct lirc_driver *drv; -+ int lircdata; -+ } lirc; - }; - - /* macros for IR decoders */ -@@ -74,6 +119,7 @@ void ir_unregister_class(struct input_dev *input_dev); - /* - * Routines from ir-raw-event.c to be used internally and by decoders - */ -+u64 ir_raw_get_allowed_protocols(void); - int ir_raw_event_register(struct input_dev *input_dev); - void ir_raw_event_unregister(struct input_dev *input_dev); - int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler); -@@ -123,4 +169,12 @@ void ir_raw_init(void); - #define load_sony_decode() 0 - #endif - -+/* from ir-lirc-codec.c */ -+#ifdef CONFIG_IR_LIRC_CODEC_MODULE -+#define load_lirc_codec() request_module("ir-lirc-codec") -+#else -+#define load_lirc_codec() 0 -+#endif -+ -+ - #endif /* _IR_RAW_EVENT */ -diff --git a/drivers/media/IR/ir-jvc-decoder.c b/drivers/media/IR/ir-jvc-decoder.c -index 0b80494..8894d8b 100644 ---- a/drivers/media/IR/ir-jvc-decoder.c -+++ b/drivers/media/IR/ir-jvc-decoder.c -@@ -25,10 +25,6 @@ - #define JVC_TRAILER_PULSE (1 * JVC_UNIT) - #define JVC_TRAILER_SPACE (35 * JVC_UNIT) - --/* Used to register jvc_decoder clients */ --static LIST_HEAD(decoder_list); --DEFINE_SPINLOCK(decoder_lock); -- - enum jvc_state { - STATE_INACTIVE, - STATE_HEADER_SPACE, -@@ -38,87 +34,6 @@ enum jvc_state { - STATE_TRAILER_SPACE, - }; - --struct decoder_data { -- struct list_head list; -- struct ir_input_dev *ir_dev; -- int enabled:1; -- -- /* State machine control */ -- enum jvc_state state; -- u16 jvc_bits; -- u16 jvc_old_bits; -- unsigned count; -- bool first; -- bool toggle; --}; -- -- --/** -- * get_decoder_data() - gets decoder data -- * @input_dev: input device -- * -- * Returns the struct decoder_data that corresponds to a device -- */ --static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev) --{ -- struct decoder_data *data = NULL; -- -- spin_lock(&decoder_lock); -- list_for_each_entry(data, &decoder_list, list) { -- if (data->ir_dev == ir_dev) -- break; -- } -- spin_unlock(&decoder_lock); -- return data; --} -- --static ssize_t store_enabled(struct device *d, -- struct device_attribute *mattr, -- const char *buf, -- size_t len) --{ -- unsigned long value; -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (strict_strtoul(buf, 10, &value) || value > 1) -- return -EINVAL; -- -- data->enabled = value; -- -- return len; --} -- --static ssize_t show_enabled(struct device *d, -- struct device_attribute *mattr, char *buf) --{ -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (data->enabled) -- return sprintf(buf, "1\n"); -- else -- return sprintf(buf, "0\n"); --} -- --static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled); -- --static struct attribute *decoder_attributes[] = { -- &dev_attr_enabled.attr, -- NULL --}; -- --static struct attribute_group decoder_attribute_group = { -- .name = "jvc_decoder", -- .attrs = decoder_attributes, --}; -- - /** - * ir_jvc_decode() - Decode one JVC pulse or space - * @input_dev: the struct input_dev descriptor of the device -@@ -128,14 +43,10 @@ static struct attribute_group decoder_attribute_group = { - */ - static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev) - { -- struct decoder_data *data; - struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -+ struct jvc_dec *data = &ir_dev->raw->jvc; - -- data = get_decoder_data(ir_dev); -- if (!data) -- return -EINVAL; -- -- if (!data->enabled) -+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_JVC)) - return 0; - - if (IS_RESET(ev)) { -@@ -188,9 +99,9 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev) - if (ev.pulse) - break; - -- data->jvc_bits <<= 1; -+ data->bits <<= 1; - if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) { -- data->jvc_bits |= 1; -+ data->bits |= 1; - decrease_duration(&ev, JVC_BIT_1_SPACE); - } else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2)) - decrease_duration(&ev, JVC_BIT_0_SPACE); -@@ -223,13 +134,13 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev) - - if (data->first) { - u32 scancode; -- scancode = (bitrev8((data->jvc_bits >> 8) & 0xff) << 8) | -- (bitrev8((data->jvc_bits >> 0) & 0xff) << 0); -+ scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) | -+ (bitrev8((data->bits >> 0) & 0xff) << 0); - IR_dprintk(1, "JVC scancode 0x%04x\n", scancode); - ir_keydown(input_dev, scancode, data->toggle); - data->first = false; -- data->jvc_old_bits = data->jvc_bits; -- } else if (data->jvc_bits == data->jvc_old_bits) { -+ data->old_bits = data->bits; -+ } else if (data->bits == data->old_bits) { - IR_dprintk(1, "JVC repeat\n"); - ir_repeat(input_dev); - } else { -@@ -249,54 +160,9 @@ out: - return -EINVAL; - } - --static int ir_jvc_register(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- struct decoder_data *data; -- int rc; -- -- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- if (rc < 0) -- return rc; -- -- data = kzalloc(sizeof(*data), GFP_KERNEL); -- if (!data) { -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- return -ENOMEM; -- } -- -- data->ir_dev = ir_dev; -- data->enabled = 1; -- -- spin_lock(&decoder_lock); -- list_add_tail(&data->list, &decoder_list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- --static int ir_jvc_unregister(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- static struct decoder_data *data; -- -- data = get_decoder_data(ir_dev); -- if (!data) -- return 0; -- -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- -- spin_lock(&decoder_lock); -- list_del(&data->list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- - static struct ir_raw_handler jvc_handler = { -+ .protocols = IR_TYPE_JVC, - .decode = ir_jvc_decode, -- .raw_register = ir_jvc_register, -- .raw_unregister = ir_jvc_unregister, - }; - - static int __init ir_jvc_decode_init(void) -diff --git a/drivers/media/IR/ir-lirc-codec.c b/drivers/media/IR/ir-lirc-codec.c -new file mode 100644 -index 0000000..afb1ada ---- /dev/null -+++ b/drivers/media/IR/ir-lirc-codec.c -@@ -0,0 +1,283 @@ -+/* ir-lirc-codec.c - ir-core to classic lirc interface bridge -+ * -+ * Copyright (C) 2010 by Jarod Wilson -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation version 2 of the License. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "ir-core-priv.h" -+ -+#define LIRCBUF_SIZE 256 -+ -+/** -+ * ir_lirc_decode() - Send raw IR data to lirc_dev to be relayed to the -+ * lircd userspace daemon for decoding. -+ * @input_dev: the struct input_dev descriptor of the device -+ * @duration: the struct ir_raw_event descriptor of the pulse/space -+ * -+ * This function returns -EINVAL if the lirc interfaces aren't wired up. -+ */ -+static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev) -+{ -+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -+ -+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_LIRC)) -+ return 0; -+ -+ if (!ir_dev->raw->lirc.drv || !ir_dev->raw->lirc.drv->rbuf) -+ return -EINVAL; -+ -+ IR_dprintk(2, "LIRC data transfer started (%uus %s)\n", -+ TO_US(ev.duration), TO_STR(ev.pulse)); -+ -+ ir_dev->raw->lirc.lircdata += ev.duration / 1000; -+ if (ev.pulse) -+ ir_dev->raw->lirc.lircdata |= PULSE_BIT; -+ -+ lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf, -+ (unsigned char *) &ir_dev->raw->lirc.lircdata); -+ wake_up(&ir_dev->raw->lirc.drv->rbuf->wait_poll); -+ -+ ir_dev->raw->lirc.lircdata = 0; -+ -+ return 0; -+} -+ -+static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf, -+ size_t n, loff_t *ppos) -+{ -+ struct lirc_codec *lirc; -+ struct ir_input_dev *ir_dev; -+ int *txbuf; /* buffer with values to transmit */ -+ int ret = 0, count; -+ -+ lirc = lirc_get_pdata(file); -+ if (!lirc) -+ return -EFAULT; -+ -+ if (n % sizeof(int)) -+ return -EINVAL; -+ -+ count = n / sizeof(int); -+ if (count > LIRCBUF_SIZE || count % 2 == 0) -+ return -EINVAL; -+ -+ txbuf = kzalloc(sizeof(int) * LIRCBUF_SIZE, GFP_KERNEL); -+ if (!txbuf) -+ return -ENOMEM; -+ -+ if (copy_from_user(txbuf, buf, n)) { -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ ir_dev = lirc->ir_dev; -+ if (!ir_dev) { -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ if (ir_dev->props && ir_dev->props->tx_ir) -+ ret = ir_dev->props->tx_ir(ir_dev->props->priv, txbuf, (u32)n); -+ -+out: -+ kfree(txbuf); -+ return ret; -+} -+ -+static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -+{ -+ struct lirc_codec *lirc; -+ struct ir_input_dev *ir_dev; -+ int ret = 0; -+ void *drv_data; -+ unsigned long val; -+ -+ lirc = lirc_get_pdata(filep); -+ if (!lirc) -+ return -EFAULT; -+ -+ ir_dev = lirc->ir_dev; -+ if (!ir_dev || !ir_dev->props || !ir_dev->props->priv) -+ return -EFAULT; -+ -+ drv_data = ir_dev->props->priv; -+ -+ switch (cmd) { -+ case LIRC_SET_TRANSMITTER_MASK: -+ ret = get_user(val, (unsigned long *)arg); -+ if (ret) -+ return ret; -+ -+ if (ir_dev->props && ir_dev->props->s_tx_mask) -+ ret = ir_dev->props->s_tx_mask(drv_data, (u32)val); -+ else -+ return -EINVAL; -+ break; -+ -+ case LIRC_SET_SEND_CARRIER: -+ ret = get_user(val, (unsigned long *)arg); -+ if (ret) -+ return ret; -+ -+ if (ir_dev->props && ir_dev->props->s_tx_carrier) -+ ir_dev->props->s_tx_carrier(drv_data, (u32)val); -+ else -+ return -EINVAL; -+ break; -+ -+ case LIRC_GET_SEND_MODE: -+ val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK; -+ ret = put_user(val, (unsigned long *)arg); -+ break; -+ -+ case LIRC_SET_SEND_MODE: -+ ret = get_user(val, (unsigned long *)arg); -+ if (ret) -+ return ret; -+ -+ if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK)) -+ return -EINVAL; -+ break; -+ -+ default: -+ return lirc_dev_fop_ioctl(filep, cmd, arg); -+ } -+ -+ return ret; -+} -+ -+static int ir_lirc_open(void *data) -+{ -+ return 0; -+} -+ -+static void ir_lirc_close(void *data) -+{ -+ return; -+} -+ -+static struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .write = ir_lirc_transmit_ir, -+ .unlocked_ioctl = ir_lirc_ioctl, -+ .read = lirc_dev_fop_read, -+ .poll = lirc_dev_fop_poll, -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+}; -+ -+static int ir_lirc_register(struct input_dev *input_dev) -+{ -+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -+ struct lirc_driver *drv; -+ struct lirc_buffer *rbuf; -+ int rc = -ENOMEM; -+ unsigned long features; -+ -+ drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ if (!drv) -+ return rc; -+ -+ rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!drv) -+ goto rbuf_alloc_failed; -+ -+ rc = lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE); -+ if (rc) -+ goto rbuf_init_failed; -+ -+ features = LIRC_CAN_REC_MODE2; -+ if (ir_dev->props->tx_ir) { -+ features |= LIRC_CAN_SEND_PULSE; -+ if (ir_dev->props->s_tx_mask) -+ features |= LIRC_CAN_SET_TRANSMITTER_MASK; -+ if (ir_dev->props->s_tx_carrier) -+ features |= LIRC_CAN_SET_SEND_CARRIER; -+ } -+ -+ snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)", -+ ir_dev->driver_name); -+ drv->minor = -1; -+ drv->features = features; -+ drv->data = &ir_dev->raw->lirc; -+ drv->rbuf = rbuf; -+ drv->set_use_inc = &ir_lirc_open; -+ drv->set_use_dec = &ir_lirc_close; -+ drv->code_length = sizeof(struct ir_raw_event) * 8; -+ drv->fops = &lirc_fops; -+ drv->dev = &ir_dev->dev; -+ drv->owner = THIS_MODULE; -+ -+ drv->minor = lirc_register_driver(drv); -+ if (drv->minor < 0) { -+ rc = -ENODEV; -+ goto lirc_register_failed; -+ } -+ -+ ir_dev->raw->lirc.drv = drv; -+ ir_dev->raw->lirc.ir_dev = ir_dev; -+ ir_dev->raw->lirc.lircdata = PULSE_MASK; -+ -+ return 0; -+ -+lirc_register_failed: -+rbuf_init_failed: -+ kfree(rbuf); -+rbuf_alloc_failed: -+ kfree(drv); -+ -+ return rc; -+} -+ -+static int ir_lirc_unregister(struct input_dev *input_dev) -+{ -+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -+ struct lirc_codec *lirc = &ir_dev->raw->lirc; -+ -+ lirc_unregister_driver(lirc->drv->minor); -+ lirc_buffer_free(lirc->drv->rbuf); -+ kfree(lirc->drv); -+ -+ return 0; -+} -+ -+static struct ir_raw_handler lirc_handler = { -+ .protocols = IR_TYPE_LIRC, -+ .decode = ir_lirc_decode, -+ .raw_register = ir_lirc_register, -+ .raw_unregister = ir_lirc_unregister, -+}; -+ -+static int __init ir_lirc_codec_init(void) -+{ -+ ir_raw_handler_register(&lirc_handler); -+ -+ printk(KERN_INFO "IR LIRC bridge handler initialized\n"); -+ return 0; -+} -+ -+static void __exit ir_lirc_codec_exit(void) -+{ -+ ir_raw_handler_unregister(&lirc_handler); -+} -+ -+module_init(ir_lirc_codec_init); -+module_exit(ir_lirc_codec_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jarod Wilson "); -+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); -+MODULE_DESCRIPTION("LIRC IR handler bridge"); -diff --git a/drivers/media/IR/ir-nec-decoder.c b/drivers/media/IR/ir-nec-decoder.c -index ba79233..52e0f37 100644 ---- a/drivers/media/IR/ir-nec-decoder.c -+++ b/drivers/media/IR/ir-nec-decoder.c -@@ -27,10 +27,6 @@ - #define NEC_TRAILER_PULSE (1 * NEC_UNIT) - #define NEC_TRAILER_SPACE (10 * NEC_UNIT) /* even longer in reality */ - --/* Used to register nec_decoder clients */ --static LIST_HEAD(decoder_list); --static DEFINE_SPINLOCK(decoder_lock); -- - enum nec_state { - STATE_INACTIVE, - STATE_HEADER_SPACE, -@@ -40,84 +36,6 @@ enum nec_state { - STATE_TRAILER_SPACE, - }; - --struct decoder_data { -- struct list_head list; -- struct ir_input_dev *ir_dev; -- int enabled:1; -- -- /* State machine control */ -- enum nec_state state; -- u32 nec_bits; -- unsigned count; --}; -- -- --/** -- * get_decoder_data() - gets decoder data -- * @input_dev: input device -- * -- * Returns the struct decoder_data that corresponds to a device -- */ --static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev) --{ -- struct decoder_data *data = NULL; -- -- spin_lock(&decoder_lock); -- list_for_each_entry(data, &decoder_list, list) { -- if (data->ir_dev == ir_dev) -- break; -- } -- spin_unlock(&decoder_lock); -- return data; --} -- --static ssize_t store_enabled(struct device *d, -- struct device_attribute *mattr, -- const char *buf, -- size_t len) --{ -- unsigned long value; -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (strict_strtoul(buf, 10, &value) || value > 1) -- return -EINVAL; -- -- data->enabled = value; -- -- return len; --} -- --static ssize_t show_enabled(struct device *d, -- struct device_attribute *mattr, char *buf) --{ -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (data->enabled) -- return sprintf(buf, "1\n"); -- else -- return sprintf(buf, "0\n"); --} -- --static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled); -- --static struct attribute *decoder_attributes[] = { -- &dev_attr_enabled.attr, -- NULL --}; -- --static struct attribute_group decoder_attribute_group = { -- .name = "nec_decoder", -- .attrs = decoder_attributes, --}; -- - /** - * ir_nec_decode() - Decode one NEC pulse or space - * @input_dev: the struct input_dev descriptor of the device -@@ -127,16 +45,12 @@ static struct attribute_group decoder_attribute_group = { - */ - static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev) - { -- struct decoder_data *data; - struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -+ struct nec_dec *data = &ir_dev->raw->nec; - u32 scancode; - u8 address, not_address, command, not_command; - -- data = get_decoder_data(ir_dev); -- if (!data) -- return -EINVAL; -- -- if (!data->enabled) -+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_NEC)) - return 0; - - if (IS_RESET(ev)) { -@@ -191,9 +105,9 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev) - if (ev.pulse) - break; - -- data->nec_bits <<= 1; -+ data->bits <<= 1; - if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2)) -- data->nec_bits |= 1; -+ data->bits |= 1; - else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2)) - break; - data->count++; -@@ -222,14 +136,14 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev) - if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2)) - break; - -- address = bitrev8((data->nec_bits >> 24) & 0xff); -- not_address = bitrev8((data->nec_bits >> 16) & 0xff); -- command = bitrev8((data->nec_bits >> 8) & 0xff); -- not_command = bitrev8((data->nec_bits >> 0) & 0xff); -+ address = bitrev8((data->bits >> 24) & 0xff); -+ not_address = bitrev8((data->bits >> 16) & 0xff); -+ command = bitrev8((data->bits >> 8) & 0xff); -+ not_command = bitrev8((data->bits >> 0) & 0xff); - - if ((command ^ not_command) != 0xff) { - IR_dprintk(1, "NEC checksum error: received 0x%08x\n", -- data->nec_bits); -+ data->bits); - break; - } - -@@ -256,54 +170,9 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev) - return -EINVAL; - } - --static int ir_nec_register(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- struct decoder_data *data; -- int rc; -- -- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- if (rc < 0) -- return rc; -- -- data = kzalloc(sizeof(*data), GFP_KERNEL); -- if (!data) { -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- return -ENOMEM; -- } -- -- data->ir_dev = ir_dev; -- data->enabled = 1; -- -- spin_lock(&decoder_lock); -- list_add_tail(&data->list, &decoder_list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- --static int ir_nec_unregister(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- static struct decoder_data *data; -- -- data = get_decoder_data(ir_dev); -- if (!data) -- return 0; -- -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- -- spin_lock(&decoder_lock); -- list_del(&data->list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- - static struct ir_raw_handler nec_handler = { -+ .protocols = IR_TYPE_NEC, - .decode = ir_nec_decode, -- .raw_register = ir_nec_register, -- .raw_unregister = ir_nec_unregister, - }; - - static int __init ir_nec_decode_init(void) -diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c -index ea68a3f..6f192ef 100644 ---- a/drivers/media/IR/ir-raw-event.c -+++ b/drivers/media/IR/ir-raw-event.c -@@ -20,35 +20,13 @@ - /* Define the max number of pulse/space transitions to buffer */ - #define MAX_IR_EVENT_SIZE 512 - -+/* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */ -+static LIST_HEAD(ir_raw_client_list); -+ - /* Used to handle IR raw handler extensions */ --static LIST_HEAD(ir_raw_handler_list); - static DEFINE_SPINLOCK(ir_raw_handler_lock); -- --/** -- * RUN_DECODER() - runs an operation on all IR decoders -- * @ops: IR raw handler operation to be called -- * @arg: arguments to be passed to the callback -- * -- * Calls ir_raw_handler::ops for all registered IR handlers. It prevents -- * new decode addition/removal while running, by locking ir_raw_handler_lock -- * mutex. If an error occurs, it stops the ops. Otherwise, it returns a sum -- * of the return codes. -- */ --#define RUN_DECODER(ops, ...) ({ \ -- struct ir_raw_handler *_ir_raw_handler; \ -- int _sumrc = 0, _rc; \ -- spin_lock(&ir_raw_handler_lock); \ -- list_for_each_entry(_ir_raw_handler, &ir_raw_handler_list, list) { \ -- if (_ir_raw_handler->ops) { \ -- _rc = _ir_raw_handler->ops(__VA_ARGS__); \ -- if (_rc < 0) \ -- break; \ -- _sumrc += _rc; \ -- } \ -- } \ -- spin_unlock(&ir_raw_handler_lock); \ -- _sumrc; \ --}) -+static LIST_HEAD(ir_raw_handler_list); -+static u64 available_protocols; - - #ifdef MODULE - /* Used to load the decoders */ -@@ -58,57 +36,17 @@ static struct work_struct wq_load; - static void ir_raw_event_work(struct work_struct *work) - { - struct ir_raw_event ev; -+ struct ir_raw_handler *handler; - struct ir_raw_event_ctrl *raw = - container_of(work, struct ir_raw_event_ctrl, rx_work); - -- while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) -- RUN_DECODER(decode, raw->input_dev, ev); --} -- --int ir_raw_event_register(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir = input_get_drvdata(input_dev); -- int rc; -- -- ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL); -- if (!ir->raw) -- return -ENOMEM; -- -- ir->raw->input_dev = input_dev; -- INIT_WORK(&ir->raw->rx_work, ir_raw_event_work); -- -- rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE, -- GFP_KERNEL); -- if (rc < 0) { -- kfree(ir->raw); -- ir->raw = NULL; -- return rc; -- } -- -- rc = RUN_DECODER(raw_register, input_dev); -- if (rc < 0) { -- kfifo_free(&ir->raw->kfifo); -- kfree(ir->raw); -- ir->raw = NULL; -- return rc; -+ while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) { -+ spin_lock(&ir_raw_handler_lock); -+ list_for_each_entry(handler, &ir_raw_handler_list, list) -+ handler->decode(raw->input_dev, ev); -+ spin_unlock(&ir_raw_handler_lock); -+ raw->prev_ev = ev; - } -- -- return rc; --} -- --void ir_raw_event_unregister(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir = input_get_drvdata(input_dev); -- -- if (!ir->raw) -- return; -- -- cancel_work_sync(&ir->raw->rx_work); -- RUN_DECODER(raw_unregister, input_dev); -- -- kfifo_free(&ir->raw->kfifo); -- kfree(ir->raw); -- ir->raw = NULL; - } - - /** -@@ -204,23 +142,103 @@ void ir_raw_event_handle(struct input_dev *input_dev) - } - EXPORT_SYMBOL_GPL(ir_raw_event_handle); - -+/* used internally by the sysfs interface */ -+u64 -+ir_raw_get_allowed_protocols() -+{ -+ u64 protocols; -+ spin_lock(&ir_raw_handler_lock); -+ protocols = available_protocols; -+ spin_unlock(&ir_raw_handler_lock); -+ return protocols; -+} -+ -+/* -+ * Used to (un)register raw event clients -+ */ -+int ir_raw_event_register(struct input_dev *input_dev) -+{ -+ struct ir_input_dev *ir = input_get_drvdata(input_dev); -+ int rc; -+ struct ir_raw_handler *handler; -+ -+ ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL); -+ if (!ir->raw) -+ return -ENOMEM; -+ -+ ir->raw->input_dev = input_dev; -+ INIT_WORK(&ir->raw->rx_work, ir_raw_event_work); -+ ir->raw->enabled_protocols = ~0; -+ rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE, -+ GFP_KERNEL); -+ if (rc < 0) { -+ kfree(ir->raw); -+ ir->raw = NULL; -+ return rc; -+ } -+ -+ spin_lock(&ir_raw_handler_lock); -+ list_add_tail(&ir->raw->list, &ir_raw_client_list); -+ list_for_each_entry(handler, &ir_raw_handler_list, list) -+ if (handler->raw_register) -+ handler->raw_register(ir->raw->input_dev); -+ spin_unlock(&ir_raw_handler_lock); -+ -+ return 0; -+} -+ -+void ir_raw_event_unregister(struct input_dev *input_dev) -+{ -+ struct ir_input_dev *ir = input_get_drvdata(input_dev); -+ struct ir_raw_handler *handler; -+ -+ if (!ir->raw) -+ return; -+ -+ cancel_work_sync(&ir->raw->rx_work); -+ -+ spin_lock(&ir_raw_handler_lock); -+ list_del(&ir->raw->list); -+ list_for_each_entry(handler, &ir_raw_handler_list, list) -+ if (handler->raw_unregister) -+ handler->raw_unregister(ir->raw->input_dev); -+ spin_unlock(&ir_raw_handler_lock); -+ -+ kfifo_free(&ir->raw->kfifo); -+ kfree(ir->raw); -+ ir->raw = NULL; -+} -+ - /* - * Extension interface - used to register the IR decoders - */ - - int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler) - { -+ struct ir_raw_event_ctrl *raw; -+ - spin_lock(&ir_raw_handler_lock); - list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list); -+ if (ir_raw_handler->raw_register) -+ list_for_each_entry(raw, &ir_raw_client_list, list) -+ ir_raw_handler->raw_register(raw->input_dev); -+ available_protocols |= ir_raw_handler->protocols; - spin_unlock(&ir_raw_handler_lock); -+ - return 0; - } - EXPORT_SYMBOL(ir_raw_handler_register); - - void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler) - { -+ struct ir_raw_event_ctrl *raw; -+ - spin_lock(&ir_raw_handler_lock); - list_del(&ir_raw_handler->list); -+ if (ir_raw_handler->raw_unregister) -+ list_for_each_entry(raw, &ir_raw_client_list, list) -+ ir_raw_handler->raw_unregister(raw->input_dev); -+ available_protocols &= ~ir_raw_handler->protocols; - spin_unlock(&ir_raw_handler_lock); - } - EXPORT_SYMBOL(ir_raw_handler_unregister); -@@ -235,6 +253,7 @@ static void init_decoders(struct work_struct *work) - load_rc6_decode(); - load_jvc_decode(); - load_sony_decode(); -+ load_lirc_codec(); - - /* If needed, we may later add some init code. In this case, - it is needed to change the CONFIG_MODULE test at ir-core.h -diff --git a/drivers/media/IR/ir-rc5-decoder.c b/drivers/media/IR/ir-rc5-decoder.c -index 23cdb1b..df4770d 100644 ---- a/drivers/media/IR/ir-rc5-decoder.c -+++ b/drivers/media/IR/ir-rc5-decoder.c -@@ -30,10 +30,6 @@ - #define RC5_BIT_END (1 * RC5_UNIT) - #define RC5X_SPACE (4 * RC5_UNIT) - --/* Used to register rc5_decoder clients */ --static LIST_HEAD(decoder_list); --static DEFINE_SPINLOCK(decoder_lock); -- - enum rc5_state { - STATE_INACTIVE, - STATE_BIT_START, -@@ -42,87 +38,6 @@ enum rc5_state { - STATE_FINISHED, - }; - --struct decoder_data { -- struct list_head list; -- struct ir_input_dev *ir_dev; -- int enabled:1; -- -- /* State machine control */ -- enum rc5_state state; -- u32 rc5_bits; -- struct ir_raw_event prev_ev; -- unsigned count; -- unsigned wanted_bits; --}; -- -- --/** -- * get_decoder_data() - gets decoder data -- * @input_dev: input device -- * -- * Returns the struct decoder_data that corresponds to a device -- */ -- --static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev) --{ -- struct decoder_data *data = NULL; -- -- spin_lock(&decoder_lock); -- list_for_each_entry(data, &decoder_list, list) { -- if (data->ir_dev == ir_dev) -- break; -- } -- spin_unlock(&decoder_lock); -- return data; --} -- --static ssize_t store_enabled(struct device *d, -- struct device_attribute *mattr, -- const char *buf, -- size_t len) --{ -- unsigned long value; -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (strict_strtoul(buf, 10, &value) || value > 1) -- return -EINVAL; -- -- data->enabled = value; -- -- return len; --} -- --static ssize_t show_enabled(struct device *d, -- struct device_attribute *mattr, char *buf) --{ -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (data->enabled) -- return sprintf(buf, "1\n"); -- else -- return sprintf(buf, "0\n"); --} -- --static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled); -- --static struct attribute *decoder_attributes[] = { -- &dev_attr_enabled.attr, -- NULL --}; -- --static struct attribute_group decoder_attribute_group = { -- .name = "rc5_decoder", -- .attrs = decoder_attributes, --}; -- - /** - * ir_rc5_decode() - Decode one RC-5 pulse or space - * @input_dev: the struct input_dev descriptor of the device -@@ -132,17 +47,13 @@ static struct attribute_group decoder_attribute_group = { - */ - static int ir_rc5_decode(struct input_dev *input_dev, struct ir_raw_event ev) - { -- struct decoder_data *data; - struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -+ struct rc5_dec *data = &ir_dev->raw->rc5; - u8 toggle; - u32 scancode; - -- data = get_decoder_data(ir_dev); -- if (!data) -- return -EINVAL; -- -- if (!data->enabled) -- return 0; -+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5)) -+ return 0; - - if (IS_RESET(ev)) { - data->state = STATE_INACTIVE; -@@ -176,16 +87,15 @@ again: - if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2)) - break; - -- data->rc5_bits <<= 1; -+ data->bits <<= 1; - if (!ev.pulse) -- data->rc5_bits |= 1; -+ data->bits |= 1; - data->count++; -- data->prev_ev = ev; - data->state = STATE_BIT_END; - return 0; - - case STATE_BIT_END: -- if (!is_transition(&ev, &data->prev_ev)) -+ if (!is_transition(&ev, &ir_dev->raw->prev_ev)) - break; - - if (data->count == data->wanted_bits) -@@ -217,11 +127,11 @@ again: - if (data->wanted_bits == RC5X_NBITS) { - /* RC5X */ - u8 xdata, command, system; -- xdata = (data->rc5_bits & 0x0003F) >> 0; -- command = (data->rc5_bits & 0x00FC0) >> 6; -- system = (data->rc5_bits & 0x1F000) >> 12; -- toggle = (data->rc5_bits & 0x20000) ? 1 : 0; -- command += (data->rc5_bits & 0x01000) ? 0 : 0x40; -+ xdata = (data->bits & 0x0003F) >> 0; -+ command = (data->bits & 0x00FC0) >> 6; -+ system = (data->bits & 0x1F000) >> 12; -+ toggle = (data->bits & 0x20000) ? 1 : 0; -+ command += (data->bits & 0x01000) ? 0 : 0x40; - scancode = system << 16 | command << 8 | xdata; - - IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n", -@@ -230,10 +140,10 @@ again: - } else { - /* RC5 */ - u8 command, system; -- command = (data->rc5_bits & 0x0003F) >> 0; -- system = (data->rc5_bits & 0x007C0) >> 6; -- toggle = (data->rc5_bits & 0x00800) ? 1 : 0; -- command += (data->rc5_bits & 0x01000) ? 0 : 0x40; -+ command = (data->bits & 0x0003F) >> 0; -+ system = (data->bits & 0x007C0) >> 6; -+ toggle = (data->bits & 0x00800) ? 1 : 0; -+ command += (data->bits & 0x01000) ? 0 : 0x40; - scancode = system << 8 | command; - - IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n", -@@ -252,54 +162,9 @@ out: - return -EINVAL; - } - --static int ir_rc5_register(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- struct decoder_data *data; -- int rc; -- -- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- if (rc < 0) -- return rc; -- -- data = kzalloc(sizeof(*data), GFP_KERNEL); -- if (!data) { -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- return -ENOMEM; -- } -- -- data->ir_dev = ir_dev; -- data->enabled = 1; -- -- spin_lock(&decoder_lock); -- list_add_tail(&data->list, &decoder_list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- --static int ir_rc5_unregister(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- static struct decoder_data *data; -- -- data = get_decoder_data(ir_dev); -- if (!data) -- return 0; -- -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- -- spin_lock(&decoder_lock); -- list_del(&data->list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- - static struct ir_raw_handler rc5_handler = { -+ .protocols = IR_TYPE_RC5, - .decode = ir_rc5_decode, -- .raw_register = ir_rc5_register, -- .raw_unregister = ir_rc5_unregister, - }; - - static int __init ir_rc5_decode_init(void) -diff --git a/drivers/media/IR/ir-rc6-decoder.c b/drivers/media/IR/ir-rc6-decoder.c -index 2bf479f..f1624b8 100644 ---- a/drivers/media/IR/ir-rc6-decoder.c -+++ b/drivers/media/IR/ir-rc6-decoder.c -@@ -36,10 +36,6 @@ - #define RC6_STARTBIT_MASK 0x08 /* for the header bits */ - #define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */ - --/* Used to register rc6_decoder clients */ --static LIST_HEAD(decoder_list); --static DEFINE_SPINLOCK(decoder_lock); -- - enum rc6_mode { - RC6_MODE_0, - RC6_MODE_6A, -@@ -58,89 +54,8 @@ enum rc6_state { - STATE_FINISHED, - }; - --struct decoder_data { -- struct list_head list; -- struct ir_input_dev *ir_dev; -- int enabled:1; -- -- /* State machine control */ -- enum rc6_state state; -- u8 header; -- u32 body; -- struct ir_raw_event prev_ev; -- bool toggle; -- unsigned count; -- unsigned wanted_bits; --}; -- -- --/** -- * get_decoder_data() - gets decoder data -- * @input_dev: input device -- * -- * Returns the struct decoder_data that corresponds to a device -- */ --static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev) --{ -- struct decoder_data *data = NULL; -- -- spin_lock(&decoder_lock); -- list_for_each_entry(data, &decoder_list, list) { -- if (data->ir_dev == ir_dev) -- break; -- } -- spin_unlock(&decoder_lock); -- return data; --} -- --static ssize_t store_enabled(struct device *d, -- struct device_attribute *mattr, -- const char *buf, -- size_t len) -+static enum rc6_mode rc6_mode(struct rc6_dec *data) - { -- unsigned long value; -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (strict_strtoul(buf, 10, &value) || value > 1) -- return -EINVAL; -- -- data->enabled = value; -- -- return len; --} -- --static ssize_t show_enabled(struct device *d, -- struct device_attribute *mattr, char *buf) --{ -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (data->enabled) -- return sprintf(buf, "1\n"); -- else -- return sprintf(buf, "0\n"); --} -- --static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled); -- --static struct attribute *decoder_attributes[] = { -- &dev_attr_enabled.attr, -- NULL --}; -- --static struct attribute_group decoder_attribute_group = { -- .name = "rc6_decoder", -- .attrs = decoder_attributes, --}; -- --static enum rc6_mode rc6_mode(struct decoder_data *data) { - switch (data->header & RC6_MODE_MASK) { - case 0: - return RC6_MODE_0; -@@ -162,16 +77,12 @@ static enum rc6_mode rc6_mode(struct decoder_data *data) { - */ - static int ir_rc6_decode(struct input_dev *input_dev, struct ir_raw_event ev) - { -- struct decoder_data *data; - struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -+ struct rc6_dec *data = &ir_dev->raw->rc6; - u32 scancode; - u8 toggle; - -- data = get_decoder_data(ir_dev); -- if (!data) -- return -EINVAL; -- -- if (!data->enabled) -+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC6)) - return 0; - - if (IS_RESET(ev)) { -@@ -223,12 +134,11 @@ again: - if (ev.pulse) - data->header |= 1; - data->count++; -- data->prev_ev = ev; - data->state = STATE_HEADER_BIT_END; - return 0; - - case STATE_HEADER_BIT_END: -- if (!is_transition(&ev, &data->prev_ev)) -+ if (!is_transition(&ev, &ir_dev->raw->prev_ev)) - break; - - if (data->count == RC6_HEADER_NBITS) -@@ -244,12 +154,11 @@ again: - break; - - data->toggle = ev.pulse; -- data->prev_ev = ev; - data->state = STATE_TOGGLE_END; - return 0; - - case STATE_TOGGLE_END: -- if (!is_transition(&ev, &data->prev_ev) || -+ if (!is_transition(&ev, &ir_dev->raw->prev_ev) || - !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2)) - break; - -@@ -259,7 +168,6 @@ again: - } - - data->state = STATE_BODY_BIT_START; -- data->prev_ev = ev; - decrease_duration(&ev, RC6_TOGGLE_END); - data->count = 0; - -@@ -291,13 +199,11 @@ again: - if (ev.pulse) - data->body |= 1; - data->count++; -- data->prev_ev = ev; -- - data->state = STATE_BODY_BIT_END; - return 0; - - case STATE_BODY_BIT_END: -- if (!is_transition(&ev, &data->prev_ev)) -+ if (!is_transition(&ev, &ir_dev->raw->prev_ev)) - break; - - if (data->count == data->wanted_bits) -@@ -348,54 +254,9 @@ out: - return -EINVAL; - } - --static int ir_rc6_register(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- struct decoder_data *data; -- int rc; -- -- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- if (rc < 0) -- return rc; -- -- data = kzalloc(sizeof(*data), GFP_KERNEL); -- if (!data) { -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- return -ENOMEM; -- } -- -- data->ir_dev = ir_dev; -- data->enabled = 1; -- -- spin_lock(&decoder_lock); -- list_add_tail(&data->list, &decoder_list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- --static int ir_rc6_unregister(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- static struct decoder_data *data; -- -- data = get_decoder_data(ir_dev); -- if (!data) -- return 0; -- -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- -- spin_lock(&decoder_lock); -- list_del(&data->list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- - static struct ir_raw_handler rc6_handler = { -+ .protocols = IR_TYPE_RC6, - .decode = ir_rc6_decode, -- .raw_register = ir_rc6_register, -- .raw_unregister = ir_rc6_unregister, - }; - - static int __init ir_rc6_decode_init(void) -diff --git a/drivers/media/IR/ir-sony-decoder.c b/drivers/media/IR/ir-sony-decoder.c -index 9f440c5..b9074f0 100644 ---- a/drivers/media/IR/ir-sony-decoder.c -+++ b/drivers/media/IR/ir-sony-decoder.c -@@ -23,10 +23,6 @@ - #define SONY_BIT_SPACE (1 * SONY_UNIT) - #define SONY_TRAILER_SPACE (10 * SONY_UNIT) /* minimum */ - --/* Used to register sony_decoder clients */ --static LIST_HEAD(decoder_list); --static DEFINE_SPINLOCK(decoder_lock); -- - enum sony_state { - STATE_INACTIVE, - STATE_HEADER_SPACE, -@@ -35,84 +31,6 @@ enum sony_state { - STATE_FINISHED, - }; - --struct decoder_data { -- struct list_head list; -- struct ir_input_dev *ir_dev; -- int enabled:1; -- -- /* State machine control */ -- enum sony_state state; -- u32 sony_bits; -- unsigned count; --}; -- -- --/** -- * get_decoder_data() - gets decoder data -- * @input_dev: input device -- * -- * Returns the struct decoder_data that corresponds to a device -- */ --static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev) --{ -- struct decoder_data *data = NULL; -- -- spin_lock(&decoder_lock); -- list_for_each_entry(data, &decoder_list, list) { -- if (data->ir_dev == ir_dev) -- break; -- } -- spin_unlock(&decoder_lock); -- return data; --} -- --static ssize_t store_enabled(struct device *d, -- struct device_attribute *mattr, -- const char *buf, -- size_t len) --{ -- unsigned long value; -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (strict_strtoul(buf, 10, &value) || value > 1) -- return -EINVAL; -- -- data->enabled = value; -- -- return len; --} -- --static ssize_t show_enabled(struct device *d, -- struct device_attribute *mattr, char *buf) --{ -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (data->enabled) -- return sprintf(buf, "1\n"); -- else -- return sprintf(buf, "0\n"); --} -- --static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled); -- --static struct attribute *decoder_attributes[] = { -- &dev_attr_enabled.attr, -- NULL --}; -- --static struct attribute_group decoder_attribute_group = { -- .name = "sony_decoder", -- .attrs = decoder_attributes, --}; -- - /** - * ir_sony_decode() - Decode one Sony pulse or space - * @input_dev: the struct input_dev descriptor of the device -@@ -122,16 +40,12 @@ static struct attribute_group decoder_attribute_group = { - */ - static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev) - { -- struct decoder_data *data; - struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -+ struct sony_dec *data = &ir_dev->raw->sony; - u32 scancode; - u8 device, subdevice, function; - -- data = get_decoder_data(ir_dev); -- if (!data) -- return -EINVAL; -- -- if (!data->enabled) -+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_SONY)) - return 0; - - if (IS_RESET(ev)) { -@@ -172,9 +86,9 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev) - if (!ev.pulse) - break; - -- data->sony_bits <<= 1; -+ data->bits <<= 1; - if (eq_margin(ev.duration, SONY_BIT_1_PULSE, SONY_UNIT / 2)) -- data->sony_bits |= 1; -+ data->bits |= 1; - else if (!eq_margin(ev.duration, SONY_BIT_0_PULSE, SONY_UNIT / 2)) - break; - -@@ -208,19 +122,19 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev) - - switch (data->count) { - case 12: -- device = bitrev8((data->sony_bits << 3) & 0xF8); -+ device = bitrev8((data->bits << 3) & 0xF8); - subdevice = 0; -- function = bitrev8((data->sony_bits >> 4) & 0xFE); -+ function = bitrev8((data->bits >> 4) & 0xFE); - break; - case 15: -- device = bitrev8((data->sony_bits >> 0) & 0xFF); -+ device = bitrev8((data->bits >> 0) & 0xFF); - subdevice = 0; -- function = bitrev8((data->sony_bits >> 7) & 0xFD); -+ function = bitrev8((data->bits >> 7) & 0xFD); - break; - case 20: -- device = bitrev8((data->sony_bits >> 5) & 0xF8); -- subdevice = bitrev8((data->sony_bits >> 0) & 0xFF); -- function = bitrev8((data->sony_bits >> 12) & 0xFE); -+ device = bitrev8((data->bits >> 5) & 0xF8); -+ subdevice = bitrev8((data->bits >> 0) & 0xFF); -+ function = bitrev8((data->bits >> 12) & 0xFE); - break; - default: - IR_dprintk(1, "Sony invalid bitcount %u\n", data->count); -@@ -241,54 +155,9 @@ out: - return -EINVAL; - } - --static int ir_sony_register(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- struct decoder_data *data; -- int rc; -- -- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- if (rc < 0) -- return rc; -- -- data = kzalloc(sizeof(*data), GFP_KERNEL); -- if (!data) { -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- return -ENOMEM; -- } -- -- data->ir_dev = ir_dev; -- data->enabled = 1; -- -- spin_lock(&decoder_lock); -- list_add_tail(&data->list, &decoder_list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- --static int ir_sony_unregister(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- static struct decoder_data *data; -- -- data = get_decoder_data(ir_dev); -- if (!data) -- return 0; -- -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- -- spin_lock(&decoder_lock); -- list_del(&data->list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- - static struct ir_raw_handler sony_handler = { -+ .protocols = IR_TYPE_SONY, - .decode = ir_sony_decode, -- .raw_register = ir_sony_register, -- .raw_unregister = ir_sony_unregister, - }; - - static int __init ir_sony_decode_init(void) -diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c -index 2098dd1..a841e51 100644 ---- a/drivers/media/IR/ir-sysfs.c -+++ b/drivers/media/IR/ir-sysfs.c -@@ -34,122 +34,186 @@ static struct class ir_input_class = { - }; - - /** -- * show_protocol() - shows the current IR protocol -+ * show_protocols() - shows the current IR protocol(s) - * @d: the device descriptor - * @mattr: the device attribute struct (unused) - * @buf: a pointer to the output buffer - * -- * This routine is a callback routine for input read the IR protocol type. -- * it is trigged by reading /sys/class/rc/rc?/current_protocol. -- * It returns the protocol name, as understood by the driver. -+ * This routine is a callback routine for input read the IR protocol type(s). -+ * it is trigged by reading /sys/class/rc/rc?/protocols. -+ * It returns the protocol names of supported protocols. -+ * Enabled protocols are printed in brackets. - */ --static ssize_t show_protocol(struct device *d, -- struct device_attribute *mattr, char *buf) -+static ssize_t show_protocols(struct device *d, -+ struct device_attribute *mattr, char *buf) - { -- char *s; - struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- u64 ir_type = ir_dev->rc_tab.ir_type; -- -- IR_dprintk(1, "Current protocol is %lld\n", (long long)ir_type); -- -- /* FIXME: doesn't support multiple protocols at the same time */ -- if (ir_type == IR_TYPE_UNKNOWN) -- s = "Unknown"; -- else if (ir_type == IR_TYPE_RC5) -- s = "rc-5"; -- else if (ir_type == IR_TYPE_NEC) -- s = "nec"; -- else if (ir_type == IR_TYPE_RC6) -- s = "rc6"; -- else if (ir_type == IR_TYPE_JVC) -- s = "jvc"; -- else if (ir_type == IR_TYPE_SONY) -- s = "sony"; -- else -- s = "other"; -+ u64 allowed, enabled; -+ char *tmp = buf; -+ -+ if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) { -+ enabled = ir_dev->rc_tab.ir_type; -+ allowed = ir_dev->props->allowed_protos; -+ } else { -+ enabled = ir_dev->raw->enabled_protocols; -+ allowed = ir_raw_get_allowed_protocols(); -+ } - -- return sprintf(buf, "%s\n", s); -+ IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n", -+ (long long)allowed, -+ (long long)enabled); -+ -+ if (allowed & enabled & IR_TYPE_UNKNOWN) -+ tmp += sprintf(tmp, "[unknown] "); -+ else if (allowed & IR_TYPE_UNKNOWN) -+ tmp += sprintf(tmp, "unknown "); -+ -+ if (allowed & enabled & IR_TYPE_RC5) -+ tmp += sprintf(tmp, "[rc5] "); -+ else if (allowed & IR_TYPE_RC5) -+ tmp += sprintf(tmp, "rc5 "); -+ -+ if (allowed & enabled & IR_TYPE_NEC) -+ tmp += sprintf(tmp, "[nec] "); -+ else if (allowed & IR_TYPE_NEC) -+ tmp += sprintf(tmp, "nec "); -+ -+ if (allowed & enabled & IR_TYPE_RC6) -+ tmp += sprintf(tmp, "[rc6] "); -+ else if (allowed & IR_TYPE_RC6) -+ tmp += sprintf(tmp, "rc6 "); -+ -+ if (allowed & enabled & IR_TYPE_JVC) -+ tmp += sprintf(tmp, "[jvc] "); -+ else if (allowed & IR_TYPE_JVC) -+ tmp += sprintf(tmp, "jvc "); -+ -+ if (allowed & enabled & IR_TYPE_SONY) -+ tmp += sprintf(tmp, "[sony] "); -+ else if (allowed & IR_TYPE_SONY) -+ tmp += sprintf(tmp, "sony "); -+ -+ if (allowed & enabled & IR_TYPE_LIRC) -+ tmp += sprintf(tmp, "[lirc] "); -+ else if (allowed & IR_TYPE_LIRC) -+ tmp += sprintf(tmp, "lirc "); -+ -+ if (tmp != buf) -+ tmp--; -+ *tmp = '\n'; -+ return tmp + 1 - buf; - } - - /** -- * store_protocol() - shows the current IR protocol -+ * store_protocols() - changes the current IR protocol(s) - * @d: the device descriptor - * @mattr: the device attribute struct (unused) - * @buf: a pointer to the input buffer - * @len: length of the input buffer - * - * This routine is a callback routine for changing the IR protocol type. -- * it is trigged by reading /sys/class/rc/rc?/current_protocol. -- * It changes the IR the protocol name, if the IR type is recognized -- * by the driver. -- * If an unknown protocol name is used, returns -EINVAL. -+ * It is trigged by writing to /sys/class/rc/rc?/protocols. -+ * Writing "+proto" will add a protocol to the list of enabled protocols. -+ * Writing "-proto" will remove a protocol from the list of enabled protocols. -+ * Writing "proto" will enable only "proto". -+ * Returns -EINVAL if an invalid protocol combination or unknown protocol name -+ * is used, otherwise @len. - */ --static ssize_t store_protocol(struct device *d, -- struct device_attribute *mattr, -- const char *data, -- size_t len) -+static ssize_t store_protocols(struct device *d, -+ struct device_attribute *mattr, -+ const char *data, -+ size_t len) - { - struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- u64 ir_type = 0; -- int rc = -EINVAL; -+ bool enable, disable; -+ const char *tmp; -+ u64 type; -+ u64 mask; -+ int rc; - unsigned long flags; -- char *buf; -- -- while ((buf = strsep((char **) &data, " \n")) != NULL) { -- if (!strcasecmp(buf, "rc-5") || !strcasecmp(buf, "rc5")) -- ir_type |= IR_TYPE_RC5; -- if (!strcasecmp(buf, "nec")) -- ir_type |= IR_TYPE_NEC; -- if (!strcasecmp(buf, "jvc")) -- ir_type |= IR_TYPE_JVC; -- if (!strcasecmp(buf, "sony")) -- ir_type |= IR_TYPE_SONY; -+ -+ tmp = skip_spaces(data); -+ -+ if (*tmp == '+') { -+ enable = true; -+ disable = false; -+ tmp++; -+ } else if (*tmp == '-') { -+ enable = false; -+ disable = true; -+ tmp++; -+ } else { -+ enable = false; -+ disable = false; - } - -- if (!ir_type) { -+ if (!strncasecmp(tmp, "unknown", 7)) { -+ tmp += 7; -+ mask = IR_TYPE_UNKNOWN; -+ } else if (!strncasecmp(tmp, "rc5", 3)) { -+ tmp += 3; -+ mask = IR_TYPE_RC5; -+ } else if (!strncasecmp(tmp, "nec", 3)) { -+ tmp += 3; -+ mask = IR_TYPE_NEC; -+ } else if (!strncasecmp(tmp, "rc6", 3)) { -+ tmp += 3; -+ mask = IR_TYPE_RC6; -+ } else if (!strncasecmp(tmp, "jvc", 3)) { -+ tmp += 3; -+ mask = IR_TYPE_JVC; -+ } else if (!strncasecmp(tmp, "sony", 4)) { -+ tmp += 4; -+ mask = IR_TYPE_SONY; -+ } else if (!strncasecmp(tmp, "lirc", 4)) { -+ tmp += 4; -+ mask = IR_TYPE_LIRC; -+ } else { - IR_dprintk(1, "Unknown protocol\n"); - return -EINVAL; - } - -- if (ir_dev->props && ir_dev->props->change_protocol) -- rc = ir_dev->props->change_protocol(ir_dev->props->priv, -- ir_type); -- -- if (rc < 0) { -- IR_dprintk(1, "Error setting protocol to %lld\n", -- (long long)ir_type); -+ tmp = skip_spaces(tmp); -+ if (*tmp != '\0') { -+ IR_dprintk(1, "Invalid trailing characters\n"); - return -EINVAL; - } - -- spin_lock_irqsave(&ir_dev->rc_tab.lock, flags); -- ir_dev->rc_tab.ir_type = ir_type; -- spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags); -+ if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) -+ type = ir_dev->rc_tab.ir_type; -+ else -+ type = ir_dev->raw->enabled_protocols; - -- IR_dprintk(1, "Current protocol(s) is(are) %lld\n", -- (long long)ir_type); -+ if (enable) -+ type |= mask; -+ else if (disable) -+ type &= ~mask; -+ else -+ type = mask; - -- return len; --} -+ if (ir_dev->props && ir_dev->props->change_protocol) { -+ rc = ir_dev->props->change_protocol(ir_dev->props->priv, -+ type); -+ if (rc < 0) { -+ IR_dprintk(1, "Error setting protocols to 0x%llx\n", -+ (long long)type); -+ return -EINVAL; -+ } -+ } - --static ssize_t show_supported_protocols(struct device *d, -- struct device_attribute *mattr, char *buf) --{ -- char *orgbuf = buf; -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -+ if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) { -+ spin_lock_irqsave(&ir_dev->rc_tab.lock, flags); -+ ir_dev->rc_tab.ir_type = type; -+ spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags); -+ } else { -+ ir_dev->raw->enabled_protocols = type; -+ } - -- /* FIXME: doesn't support multiple protocols at the same time */ -- if (ir_dev->props->allowed_protos == IR_TYPE_UNKNOWN) -- buf += sprintf(buf, "unknown "); -- if (ir_dev->props->allowed_protos & IR_TYPE_RC5) -- buf += sprintf(buf, "rc-5 "); -- if (ir_dev->props->allowed_protos & IR_TYPE_NEC) -- buf += sprintf(buf, "nec "); -- if (buf == orgbuf) -- buf += sprintf(buf, "other "); - -- buf += sprintf(buf - 1, "\n"); -+ IR_dprintk(1, "Current protocol(s): 0x%llx\n", -+ (long long)type); - -- return buf - orgbuf; -+ return len; - } - - #define ADD_HOTPLUG_VAR(fmt, val...) \ -@@ -159,7 +223,7 @@ static ssize_t show_supported_protocols(struct device *d, - return err; \ - } while (0) - --static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env) -+static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) - { - struct ir_input_dev *ir_dev = dev_get_drvdata(device); - -@@ -174,34 +238,26 @@ static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env) - /* - * Static device attribute struct with the sysfs attributes for IR's - */ --static DEVICE_ATTR(protocol, S_IRUGO | S_IWUSR, -- show_protocol, store_protocol); -- --static DEVICE_ATTR(supported_protocols, S_IRUGO | S_IWUSR, -- show_supported_protocols, NULL); -+static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR, -+ show_protocols, store_protocols); - --static struct attribute *ir_hw_dev_attrs[] = { -- &dev_attr_protocol.attr, -- &dev_attr_supported_protocols.attr, -+static struct attribute *rc_dev_attrs[] = { -+ &dev_attr_protocols.attr, - NULL, - }; - --static struct attribute_group ir_hw_dev_attr_grp = { -- .attrs = ir_hw_dev_attrs, -+static struct attribute_group rc_dev_attr_grp = { -+ .attrs = rc_dev_attrs, - }; - --static const struct attribute_group *ir_hw_dev_attr_groups[] = { -- &ir_hw_dev_attr_grp, -+static const struct attribute_group *rc_dev_attr_groups[] = { -+ &rc_dev_attr_grp, - NULL - }; - - static struct device_type rc_dev_type = { -- .groups = ir_hw_dev_attr_groups, -- .uevent = ir_dev_uevent, --}; -- --static struct device_type ir_raw_dev_type = { -- .uevent = ir_dev_uevent, -+ .groups = rc_dev_attr_groups, -+ .uevent = rc_dev_uevent, - }; - - /** -@@ -221,12 +277,7 @@ int ir_register_class(struct input_dev *input_dev) - if (unlikely(devno < 0)) - return devno; - -- if (ir_dev->props) { -- if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) -- ir_dev->dev.type = &rc_dev_type; -- } else -- ir_dev->dev.type = &ir_raw_dev_type; -- -+ ir_dev->dev.type = &rc_dev_type; - ir_dev->dev.class = &ir_input_class; - ir_dev->dev.parent = input_dev->dev.parent; - dev_set_name(&ir_dev->dev, "rc%d", devno); -diff --git a/drivers/media/IR/keymaps/Makefile b/drivers/media/IR/keymaps/Makefile -index aea649f..86d3d1f 100644 ---- a/drivers/media/IR/keymaps/Makefile -+++ b/drivers/media/IR/keymaps/Makefile -@@ -37,6 +37,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ - rc-kaiomy.o \ - rc-kworld-315u.o \ - rc-kworld-plus-tv-analog.o \ -+ rc-lirc.o \ - rc-manli.o \ - rc-msi-tvanywhere.o \ - rc-msi-tvanywhere-plus.o \ -@@ -57,6 +58,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ - rc-pv951.o \ - rc-rc5-hauppauge-new.o \ - rc-rc5-tv.o \ -+ rc-rc6-mce.o \ - rc-real-audio-220-32-keys.o \ - rc-tbs-nec.o \ - rc-terratec-cinergy-xs.o \ -diff --git a/drivers/media/IR/keymaps/rc-lirc.c b/drivers/media/IR/keymaps/rc-lirc.c -new file mode 100644 -index 0000000..43fcf90 ---- /dev/null -+++ b/drivers/media/IR/keymaps/rc-lirc.c -@@ -0,0 +1,41 @@ -+/* rc-lirc.c - Empty dummy keytable, for use when its preferred to pass -+ * all raw IR data to the lirc userspace decoder. -+ * -+ * Copyright (c) 2010 by Jarod Wilson -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#include -+ -+static struct ir_scancode lirc[] = { -+ { }, -+}; -+ -+static struct rc_keymap lirc_map = { -+ .map = { -+ .scan = lirc, -+ .size = ARRAY_SIZE(lirc), -+ .ir_type = IR_TYPE_LIRC, -+ .name = RC_MAP_LIRC, -+ } -+}; -+ -+static int __init init_rc_map_lirc(void) -+{ -+ return ir_register_map(&lirc_map); -+} -+ -+static void __exit exit_rc_map_lirc(void) -+{ -+ ir_unregister_map(&lirc_map); -+} -+ -+module_init(init_rc_map_lirc) -+module_exit(exit_rc_map_lirc) -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jarod Wilson "); -diff --git a/drivers/media/IR/keymaps/rc-rc6-mce.c b/drivers/media/IR/keymaps/rc-rc6-mce.c -new file mode 100644 -index 0000000..c6726a8 ---- /dev/null -+++ b/drivers/media/IR/keymaps/rc-rc6-mce.c -@@ -0,0 +1,105 @@ -+/* rc-rc6-mce.c - Keytable for Windows Media Center RC-6 remotes for use -+ * with the Media Center Edition eHome Infrared Transceiver. -+ * -+ * Copyright (c) 2010 by Jarod Wilson -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#include -+ -+static struct ir_scancode rc6_mce[] = { -+ { 0x800f0415, KEY_REWIND }, -+ { 0x800f0414, KEY_FASTFORWARD }, -+ { 0x800f041b, KEY_PREVIOUS }, -+ { 0x800f041a, KEY_NEXT }, -+ -+ { 0x800f0416, KEY_PLAY }, -+ { 0x800f0418, KEY_PAUSE }, -+ { 0x800f0419, KEY_STOP }, -+ { 0x800f0417, KEY_RECORD }, -+ -+ { 0x800f041e, KEY_UP }, -+ { 0x800f041f, KEY_DOWN }, -+ { 0x800f0420, KEY_LEFT }, -+ { 0x800f0421, KEY_RIGHT }, -+ -+ { 0x800f040b, KEY_ENTER }, -+ { 0x800f0422, KEY_OK }, -+ { 0x800f0423, KEY_EXIT }, -+ { 0x800f040a, KEY_DELETE }, -+ -+ { 0x800f040e, KEY_MUTE }, -+ { 0x800f0410, KEY_VOLUMEUP }, -+ { 0x800f0411, KEY_VOLUMEDOWN }, -+ { 0x800f0412, KEY_CHANNELUP }, -+ { 0x800f0413, KEY_CHANNELDOWN }, -+ -+ { 0x800f0401, KEY_NUMERIC_1 }, -+ { 0x800f0402, KEY_NUMERIC_2 }, -+ { 0x800f0403, KEY_NUMERIC_3 }, -+ { 0x800f0404, KEY_NUMERIC_4 }, -+ { 0x800f0405, KEY_NUMERIC_5 }, -+ { 0x800f0406, KEY_NUMERIC_6 }, -+ { 0x800f0407, KEY_NUMERIC_7 }, -+ { 0x800f0408, KEY_NUMERIC_8 }, -+ { 0x800f0409, KEY_NUMERIC_9 }, -+ { 0x800f0400, KEY_NUMERIC_0 }, -+ -+ { 0x800f041d, KEY_NUMERIC_STAR }, -+ { 0x800f041c, KEY_NUMERIC_POUND }, -+ -+ { 0x800f0446, KEY_TV }, -+ { 0x800f0447, KEY_AUDIO }, /* My Music */ -+ { 0x800f0448, KEY_PVR }, /* RecordedTV */ -+ { 0x800f0449, KEY_CAMERA }, -+ { 0x800f044a, KEY_VIDEO }, -+ { 0x800f0424, KEY_DVD }, -+ { 0x800f0425, KEY_TUNER }, /* LiveTV */ -+ { 0x800f0450, KEY_RADIO }, -+ -+ { 0x800f044c, KEY_LANGUAGE }, -+ { 0x800f0427, KEY_ZOOM }, /* Aspect */ -+ -+ { 0x800f045b, KEY_RED }, -+ { 0x800f045c, KEY_GREEN }, -+ { 0x800f045d, KEY_YELLOW }, -+ { 0x800f045e, KEY_BLUE }, -+ -+ { 0x800f040f, KEY_INFO }, -+ { 0x800f0426, KEY_EPG }, /* Guide */ -+ { 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */ -+ { 0x800f044d, KEY_TITLE }, -+ -+ { 0x800f040c, KEY_POWER }, -+ { 0x800f040d, KEY_PROG1 }, /* Windows MCE button */ -+ -+}; -+ -+static struct rc_keymap rc6_mce_map = { -+ .map = { -+ .scan = rc6_mce, -+ .size = ARRAY_SIZE(rc6_mce), -+ .ir_type = IR_TYPE_RC6, -+ .name = RC_MAP_RC6_MCE, -+ } -+}; -+ -+static int __init init_rc_map_rc6_mce(void) -+{ -+ return ir_register_map(&rc6_mce_map); -+} -+ -+static void __exit exit_rc_map_rc6_mce(void) -+{ -+ ir_unregister_map(&rc6_mce_map); -+} -+ -+module_init(init_rc_map_rc6_mce) -+module_exit(exit_rc_map_rc6_mce) -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jarod Wilson "); -diff --git a/drivers/media/IR/lirc_dev.c b/drivers/media/IR/lirc_dev.c -new file mode 100644 -index 0000000..899891b ---- /dev/null -+++ b/drivers/media/IR/lirc_dev.c -@@ -0,0 +1,764 @@ -+/* -+ * LIRC base driver -+ * -+ * by Artur Lipowski -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+static int debug; -+ -+#define IRCTL_DEV_NAME "BaseRemoteCtl" -+#define NOPLUG -1 -+#define LOGHEAD "lirc_dev (%s[%d]): " -+ -+static dev_t lirc_base_dev; -+ -+struct irctl { -+ struct lirc_driver d; -+ int attached; -+ int open; -+ -+ struct mutex irctl_lock; -+ struct lirc_buffer *buf; -+ unsigned int chunk_size; -+ -+ struct task_struct *task; -+ long jiffies_to_wait; -+ -+ struct cdev cdev; -+}; -+ -+static DEFINE_MUTEX(lirc_dev_lock); -+ -+static struct irctl *irctls[MAX_IRCTL_DEVICES]; -+ -+/* Only used for sysfs but defined to void otherwise */ -+static struct class *lirc_class; -+ -+/* helper function -+ * initializes the irctl structure -+ */ -+static void init_irctl(struct irctl *ir) -+{ -+ dev_dbg(ir->d.dev, LOGHEAD "initializing irctl\n", -+ ir->d.name, ir->d.minor); -+ mutex_init(&ir->irctl_lock); -+ ir->d.minor = NOPLUG; -+} -+ -+static void cleanup(struct irctl *ir) -+{ -+ dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor); -+ -+ device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); -+ -+ if (ir->buf != ir->d.rbuf) { -+ lirc_buffer_free(ir->buf); -+ kfree(ir->buf); -+ } -+ ir->buf = NULL; -+} -+ -+/* helper function -+ * reads key codes from driver and puts them into buffer -+ * returns 0 on success -+ */ -+static int add_to_buf(struct irctl *ir) -+{ -+ if (ir->d.add_to_buf) { -+ int res = -ENODATA; -+ int got_data = 0; -+ -+ /* -+ * service the device as long as it is returning -+ * data and we have space -+ */ -+get_data: -+ res = ir->d.add_to_buf(ir->d.data, ir->buf); -+ if (res == 0) { -+ got_data++; -+ goto get_data; -+ } -+ -+ if (res == -ENODEV) -+ kthread_stop(ir->task); -+ -+ return got_data ? 0 : res; -+ } -+ -+ return 0; -+} -+ -+/* main function of the polling thread -+ */ -+static int lirc_thread(void *irctl) -+{ -+ struct irctl *ir = irctl; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "poll thread started\n", -+ ir->d.name, ir->d.minor); -+ -+ do { -+ if (ir->open) { -+ if (ir->jiffies_to_wait) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(ir->jiffies_to_wait); -+ } -+ if (kthread_should_stop()) -+ break; -+ if (!add_to_buf(ir)) -+ wake_up_interruptible(&ir->buf->wait_poll); -+ } else { -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule(); -+ } -+ } while (!kthread_should_stop()); -+ -+ dev_dbg(ir->d.dev, LOGHEAD "poll thread ended\n", -+ ir->d.name, ir->d.minor); -+ -+ return 0; -+} -+ -+ -+static struct file_operations fops = { -+ .owner = THIS_MODULE, -+ .read = lirc_dev_fop_read, -+ .write = lirc_dev_fop_write, -+ .poll = lirc_dev_fop_poll, -+ .unlocked_ioctl = lirc_dev_fop_ioctl, -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+}; -+ -+static int lirc_cdev_add(struct irctl *ir) -+{ -+ int retval; -+ struct lirc_driver *d = &ir->d; -+ -+ if (d->fops) { -+ cdev_init(&ir->cdev, d->fops); -+ ir->cdev.owner = d->owner; -+ } else { -+ cdev_init(&ir->cdev, &fops); -+ ir->cdev.owner = THIS_MODULE; -+ } -+ kobject_set_name(&ir->cdev.kobj, "lirc%d", d->minor); -+ -+ retval = cdev_add(&ir->cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); -+ if (retval) -+ kobject_put(&ir->cdev.kobj); -+ -+ return retval; -+} -+ -+int lirc_register_driver(struct lirc_driver *d) -+{ -+ struct irctl *ir; -+ int minor; -+ int bytes_in_key; -+ unsigned int chunk_size; -+ unsigned int buffer_size; -+ int err; -+ -+ if (!d) { -+ printk(KERN_ERR "lirc_dev: lirc_register_driver: " -+ "driver pointer must be not NULL!\n"); -+ err = -EBADRQC; -+ goto out; -+ } -+ -+ if (MAX_IRCTL_DEVICES <= d->minor) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "\"minor\" must be between 0 and %d (%d)!\n", -+ MAX_IRCTL_DEVICES-1, d->minor); -+ err = -EBADRQC; -+ goto out; -+ } -+ -+ if (1 > d->code_length || (BUFLEN * 8) < d->code_length) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "code length in bits for minor (%d) " -+ "must be less than %d!\n", -+ d->minor, BUFLEN * 8); -+ err = -EBADRQC; -+ goto out; -+ } -+ -+ dev_dbg(d->dev, "lirc_dev: lirc_register_driver: sample_rate: %d\n", -+ d->sample_rate); -+ if (d->sample_rate) { -+ if (2 > d->sample_rate || HZ < d->sample_rate) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "sample_rate must be between 2 and %d!\n", HZ); -+ err = -EBADRQC; -+ goto out; -+ } -+ if (!d->add_to_buf) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "add_to_buf cannot be NULL when " -+ "sample_rate is set\n"); -+ err = -EBADRQC; -+ goto out; -+ } -+ } else if (!(d->fops && d->fops->read) && !d->rbuf) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "fops->read and rbuf cannot all be NULL!\n"); -+ err = -EBADRQC; -+ goto out; -+ } else if (!d->rbuf) { -+ if (!(d->fops && d->fops->read && d->fops->poll && -+ d->fops->unlocked_ioctl)) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "neither read, poll nor unlocked_ioctl can be NULL!\n"); -+ err = -EBADRQC; -+ goto out; -+ } -+ } -+ -+ mutex_lock(&lirc_dev_lock); -+ -+ minor = d->minor; -+ -+ if (minor < 0) { -+ /* find first free slot for driver */ -+ for (minor = 0; minor < MAX_IRCTL_DEVICES; minor++) -+ if (!irctls[minor]) -+ break; -+ if (MAX_IRCTL_DEVICES == minor) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "no free slots for drivers!\n"); -+ err = -ENOMEM; -+ goto out_lock; -+ } -+ } else if (irctls[minor]) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "minor (%d) just registered!\n", minor); -+ err = -EBUSY; -+ goto out_lock; -+ } -+ -+ ir = kzalloc(sizeof(struct irctl), GFP_KERNEL); -+ if (!ir) { -+ err = -ENOMEM; -+ goto out_lock; -+ } -+ init_irctl(ir); -+ irctls[minor] = ir; -+ d->minor = minor; -+ -+ if (d->sample_rate) { -+ ir->jiffies_to_wait = HZ / d->sample_rate; -+ } else { -+ /* it means - wait for external event in task queue */ -+ ir->jiffies_to_wait = 0; -+ } -+ -+ /* some safety check 8-) */ -+ d->name[sizeof(d->name)-1] = '\0'; -+ -+ bytes_in_key = BITS_TO_LONGS(d->code_length) + -+ (d->code_length % 8 ? 1 : 0); -+ buffer_size = d->buffer_size ? d->buffer_size : BUFLEN / bytes_in_key; -+ chunk_size = d->chunk_size ? d->chunk_size : bytes_in_key; -+ -+ if (d->rbuf) { -+ ir->buf = d->rbuf; -+ } else { -+ ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!ir->buf) { -+ err = -ENOMEM; -+ goto out_lock; -+ } -+ err = lirc_buffer_init(ir->buf, chunk_size, buffer_size); -+ if (err) { -+ kfree(ir->buf); -+ goto out_lock; -+ } -+ } -+ ir->chunk_size = ir->buf->chunk_size; -+ -+ if (d->features == 0) -+ d->features = LIRC_CAN_REC_LIRCCODE; -+ -+ ir->d = *d; -+ ir->d.minor = minor; -+ -+ device_create(lirc_class, ir->d.dev, -+ MKDEV(MAJOR(lirc_base_dev), ir->d.minor), NULL, -+ "lirc%u", ir->d.minor); -+ -+ if (d->sample_rate) { -+ /* try to fire up polling thread */ -+ ir->task = kthread_run(lirc_thread, (void *)ir, "lirc_dev"); -+ if (IS_ERR(ir->task)) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "cannot run poll thread for minor = %d\n", -+ d->minor); -+ err = -ECHILD; -+ goto out_sysfs; -+ } -+ } -+ -+ err = lirc_cdev_add(ir); -+ if (err) -+ goto out_sysfs; -+ -+ ir->attached = 1; -+ mutex_unlock(&lirc_dev_lock); -+ -+ dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n", -+ ir->d.name, ir->d.minor); -+ return minor; -+ -+out_sysfs: -+ device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); -+out_lock: -+ mutex_unlock(&lirc_dev_lock); -+out: -+ return err; -+} -+EXPORT_SYMBOL(lirc_register_driver); -+ -+int lirc_unregister_driver(int minor) -+{ -+ struct irctl *ir; -+ -+ if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { -+ printk(KERN_ERR "lirc_dev: lirc_unregister_driver: " -+ "\"minor (%d)\" must be between 0 and %d!\n", -+ minor, MAX_IRCTL_DEVICES-1); -+ return -EBADRQC; -+ } -+ -+ ir = irctls[minor]; -+ -+ mutex_lock(&lirc_dev_lock); -+ -+ if (ir->d.minor != minor) { -+ printk(KERN_ERR "lirc_dev: lirc_unregister_driver: " -+ "minor (%d) device not registered!", minor); -+ mutex_unlock(&lirc_dev_lock); -+ return -ENOENT; -+ } -+ -+ /* end up polling thread */ -+ if (ir->task) -+ kthread_stop(ir->task); -+ -+ dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n", -+ ir->d.name, ir->d.minor); -+ -+ ir->attached = 0; -+ if (ir->open) { -+ dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n", -+ ir->d.name, ir->d.minor); -+ wake_up_interruptible(&ir->buf->wait_poll); -+ mutex_lock(&ir->irctl_lock); -+ ir->d.set_use_dec(ir->d.data); -+ module_put(ir->d.owner); -+ mutex_unlock(&ir->irctl_lock); -+ cdev_del(&ir->cdev); -+ } else { -+ cleanup(ir); -+ cdev_del(&ir->cdev); -+ kfree(ir); -+ irctls[minor] = NULL; -+ } -+ -+ mutex_unlock(&lirc_dev_lock); -+ -+ return 0; -+} -+EXPORT_SYMBOL(lirc_unregister_driver); -+ -+int lirc_dev_fop_open(struct inode *inode, struct file *file) -+{ -+ struct irctl *ir; -+ int retval = 0; -+ -+ if (iminor(inode) >= MAX_IRCTL_DEVICES) { -+ printk(KERN_WARNING "lirc_dev [%d]: open result = -ENODEV\n", -+ iminor(inode)); -+ return -ENODEV; -+ } -+ -+ if (mutex_lock_interruptible(&lirc_dev_lock)) -+ return -ERESTARTSYS; -+ -+ ir = irctls[iminor(inode)]; -+ if (!ir) { -+ retval = -ENODEV; -+ goto error; -+ } -+ file->private_data = ir; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor); -+ -+ if (ir->d.minor == NOPLUG) { -+ retval = -ENODEV; -+ goto error; -+ } -+ -+ if (ir->open) { -+ retval = -EBUSY; -+ goto error; -+ } -+ -+ if (try_module_get(ir->d.owner)) { -+ ++ir->open; -+ retval = ir->d.set_use_inc(ir->d.data); -+ -+ if (retval) { -+ module_put(ir->d.owner); -+ --ir->open; -+ } else { -+ lirc_buffer_clear(ir->buf); -+ } -+ if (ir->task) -+ wake_up_process(ir->task); -+ } -+ -+error: -+ if (ir) -+ dev_dbg(ir->d.dev, LOGHEAD "open result = %d\n", -+ ir->d.name, ir->d.minor, retval); -+ -+ mutex_unlock(&lirc_dev_lock); -+ -+ return retval; -+} -+EXPORT_SYMBOL(lirc_dev_fop_open); -+ -+int lirc_dev_fop_close(struct inode *inode, struct file *file) -+{ -+ struct irctl *ir = irctls[iminor(inode)]; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor); -+ -+ WARN_ON(mutex_lock_killable(&lirc_dev_lock)); -+ -+ --ir->open; -+ if (ir->attached) { -+ ir->d.set_use_dec(ir->d.data); -+ module_put(ir->d.owner); -+ } else { -+ cleanup(ir); -+ irctls[ir->d.minor] = NULL; -+ kfree(ir); -+ } -+ -+ mutex_unlock(&lirc_dev_lock); -+ -+ return 0; -+} -+EXPORT_SYMBOL(lirc_dev_fop_close); -+ -+unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait) -+{ -+ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; -+ unsigned int ret; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor); -+ -+ if (!ir->attached) { -+ mutex_unlock(&ir->irctl_lock); -+ return POLLERR; -+ } -+ -+ poll_wait(file, &ir->buf->wait_poll, wait); -+ -+ if (ir->buf) -+ if (lirc_buffer_empty(ir->buf)) -+ ret = 0; -+ else -+ ret = POLLIN | POLLRDNORM; -+ else -+ ret = POLLERR; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "poll result = %d\n", -+ ir->d.name, ir->d.minor, ret); -+ -+ return ret; -+} -+EXPORT_SYMBOL(lirc_dev_fop_poll); -+ -+long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ unsigned long mode; -+ int result = 0; -+ struct irctl *ir = file->private_data; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n", -+ ir->d.name, ir->d.minor, cmd); -+ -+ if (ir->d.minor == NOPLUG || !ir->attached) { -+ dev_dbg(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n", -+ ir->d.name, ir->d.minor); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&ir->irctl_lock); -+ -+ switch (cmd) { -+ case LIRC_GET_FEATURES: -+ result = put_user(ir->d.features, (unsigned long *)arg); -+ break; -+ case LIRC_GET_REC_MODE: -+ if (!(ir->d.features & LIRC_CAN_REC_MASK)) { -+ result = -ENOSYS; -+ break; -+ } -+ -+ result = put_user(LIRC_REC2MODE -+ (ir->d.features & LIRC_CAN_REC_MASK), -+ (unsigned long *)arg); -+ break; -+ case LIRC_SET_REC_MODE: -+ if (!(ir->d.features & LIRC_CAN_REC_MASK)) { -+ result = -ENOSYS; -+ break; -+ } -+ -+ result = get_user(mode, (unsigned long *)arg); -+ if (!result && !(LIRC_MODE2REC(mode) & ir->d.features)) -+ result = -EINVAL; -+ /* -+ * FIXME: We should actually set the mode somehow but -+ * for now, lirc_serial doesn't support mode changing either -+ */ -+ break; -+ case LIRC_GET_LENGTH: -+ result = put_user(ir->d.code_length, (unsigned long *)arg); -+ break; -+ case LIRC_GET_MIN_TIMEOUT: -+ if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || -+ ir->d.min_timeout == 0) { -+ result = -ENOSYS; -+ break; -+ } -+ -+ result = put_user(ir->d.min_timeout, (unsigned long *)arg); -+ break; -+ case LIRC_GET_MAX_TIMEOUT: -+ if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || -+ ir->d.max_timeout == 0) { -+ result = -ENOSYS; -+ break; -+ } -+ -+ result = put_user(ir->d.max_timeout, (unsigned long *)arg); -+ break; -+ default: -+ result = -EINVAL; -+ } -+ -+ dev_dbg(ir->d.dev, LOGHEAD "ioctl result = %d\n", -+ ir->d.name, ir->d.minor, result); -+ -+ mutex_unlock(&ir->irctl_lock); -+ -+ return result; -+} -+EXPORT_SYMBOL(lirc_dev_fop_ioctl); -+ -+ssize_t lirc_dev_fop_read(struct file *file, -+ char *buffer, -+ size_t length, -+ loff_t *ppos) -+{ -+ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; -+ unsigned char buf[ir->chunk_size]; -+ int ret = 0, written = 0; -+ DECLARE_WAITQUEUE(wait, current); -+ -+ dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor); -+ -+ if (mutex_lock_interruptible(&ir->irctl_lock)) -+ return -ERESTARTSYS; -+ if (!ir->attached) { -+ mutex_unlock(&ir->irctl_lock); -+ return -ENODEV; -+ } -+ -+ if (length % ir->chunk_size) { -+ dev_dbg(ir->d.dev, LOGHEAD "read result = -EINVAL\n", -+ ir->d.name, ir->d.minor); -+ mutex_unlock(&ir->irctl_lock); -+ return -EINVAL; -+ } -+ -+ /* -+ * we add ourselves to the task queue before buffer check -+ * to avoid losing scan code (in case when queue is awaken somewhere -+ * between while condition checking and scheduling) -+ */ -+ add_wait_queue(&ir->buf->wait_poll, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ /* -+ * while we didn't provide 'length' bytes, device is opened in blocking -+ * mode and 'copy_to_user' is happy, wait for data. -+ */ -+ while (written < length && ret == 0) { -+ if (lirc_buffer_empty(ir->buf)) { -+ /* According to the read(2) man page, 'written' can be -+ * returned as less than 'length', instead of blocking -+ * again, returning -EWOULDBLOCK, or returning -+ * -ERESTARTSYS */ -+ if (written) -+ break; -+ if (file->f_flags & O_NONBLOCK) { -+ ret = -EWOULDBLOCK; -+ break; -+ } -+ if (signal_pending(current)) { -+ ret = -ERESTARTSYS; -+ break; -+ } -+ -+ mutex_unlock(&ir->irctl_lock); -+ schedule(); -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ if (mutex_lock_interruptible(&ir->irctl_lock)) { -+ ret = -ERESTARTSYS; -+ remove_wait_queue(&ir->buf->wait_poll, &wait); -+ set_current_state(TASK_RUNNING); -+ goto out_unlocked; -+ } -+ -+ if (!ir->attached) { -+ ret = -ENODEV; -+ break; -+ } -+ } else { -+ lirc_buffer_read(ir->buf, buf); -+ ret = copy_to_user((void *)buffer+written, buf, -+ ir->buf->chunk_size); -+ written += ir->buf->chunk_size; -+ } -+ } -+ -+ remove_wait_queue(&ir->buf->wait_poll, &wait); -+ set_current_state(TASK_RUNNING); -+ mutex_unlock(&ir->irctl_lock); -+ -+out_unlocked: -+ dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n", -+ ir->d.name, ir->d.minor, ret ? "-EFAULT" : "OK", ret); -+ -+ return ret ? ret : written; -+} -+EXPORT_SYMBOL(lirc_dev_fop_read); -+ -+void *lirc_get_pdata(struct file *file) -+{ -+ void *data = NULL; -+ -+ if (file && file->f_dentry && file->f_dentry->d_inode && -+ file->f_dentry->d_inode->i_rdev) { -+ struct irctl *ir; -+ ir = irctls[iminor(file->f_dentry->d_inode)]; -+ data = ir->d.data; -+ } -+ -+ return data; -+} -+EXPORT_SYMBOL(lirc_get_pdata); -+ -+ -+ssize_t lirc_dev_fop_write(struct file *file, const char *buffer, -+ size_t length, loff_t *ppos) -+{ -+ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor); -+ -+ if (!ir->attached) -+ return -ENODEV; -+ -+ return -EINVAL; -+} -+EXPORT_SYMBOL(lirc_dev_fop_write); -+ -+ -+static int __init lirc_dev_init(void) -+{ -+ int retval; -+ -+ lirc_class = class_create(THIS_MODULE, "lirc"); -+ if (IS_ERR(lirc_class)) { -+ retval = PTR_ERR(lirc_class); -+ printk(KERN_ERR "lirc_dev: class_create failed\n"); -+ goto error; -+ } -+ -+ retval = alloc_chrdev_region(&lirc_base_dev, 0, MAX_IRCTL_DEVICES, -+ IRCTL_DEV_NAME); -+ if (retval) { -+ class_destroy(lirc_class); -+ printk(KERN_ERR "lirc_dev: alloc_chrdev_region failed\n"); -+ goto error; -+ } -+ -+ -+ printk(KERN_INFO "lirc_dev: IR Remote Control driver registered, " -+ "major %d \n", MAJOR(lirc_base_dev)); -+ -+error: -+ return retval; -+} -+ -+ -+ -+static void __exit lirc_dev_exit(void) -+{ -+ class_destroy(lirc_class); -+ unregister_chrdev_region(lirc_base_dev, MAX_IRCTL_DEVICES); -+ printk(KERN_INFO "lirc_dev: module unloaded\n"); -+} -+ -+module_init(lirc_dev_init); -+module_exit(lirc_dev_exit); -+ -+MODULE_DESCRIPTION("LIRC base driver module"); -+MODULE_AUTHOR("Artur Lipowski"); -+MODULE_LICENSE("GPL"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff --git a/drivers/media/IR/mceusb.c b/drivers/media/IR/mceusb.c -new file mode 100644 -index 0000000..78bf7f7 ---- /dev/null -+++ b/drivers/media/IR/mceusb.c -@@ -0,0 +1,1143 @@ -+/* -+ * Driver for USB Windows Media Center Ed. eHome Infrared Transceivers -+ * -+ * Copyright (c) 2010 by Jarod Wilson -+ * -+ * Based on the original lirc_mceusb and lirc_mceusb2 drivers, by Dan -+ * Conti, Martin Blatter and Daniel Melander, the latter of which was -+ * in turn also based on the lirc_atiusb driver by Paul Miller. The -+ * two mce drivers were merged into one by Jarod Wilson, with transmit -+ * support for the 1st-gen device added primarily by Patrick Calhoun, -+ * with a bit of tweaks by Jarod. Debugging improvements and proper -+ * support for what appears to be 3rd-gen hardware added by Jarod. -+ * Initial port from lirc driver to ir-core drivery by Jarod, based -+ * partially on a port to an earlier proposed IR infrastructure by -+ * Jon Smirl, which included enhancements and simplifications to the -+ * incoming IR buffer parsing routines. -+ * -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DRIVER_VERSION "1.91" -+#define DRIVER_AUTHOR "Jarod Wilson " -+#define DRIVER_DESC "Windows Media Center Ed. eHome Infrared Transceiver " \ -+ "device driver" -+#define DRIVER_NAME "mceusb" -+ -+#define USB_BUFLEN 32 /* USB reception buffer length */ -+#define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */ -+#define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */ -+ -+/* MCE constants */ -+#define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */ -+#define MCE_TIME_UNIT 50 /* Approx 50us resolution */ -+#define MCE_CODE_LENGTH 5 /* Normal length of packet (with header) */ -+#define MCE_PACKET_SIZE 4 /* Normal length of packet (without header) */ -+#define MCE_PACKET_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */ -+#define MCE_CONTROL_HEADER 0x9F /* MCE status header */ -+#define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */ -+#define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */ -+#define MCE_DEFAULT_TX_MASK 0x03 /* Val opts: TX1=0x01, TX2=0x02, ALL=0x03 */ -+#define MCE_PULSE_BIT 0x80 /* Pulse bit, MSB set == PULSE else SPACE */ -+#define MCE_PULSE_MASK 0x7F /* Pulse mask */ -+#define MCE_MAX_PULSE_LENGTH 0x7F /* Longest transmittable pulse symbol */ -+#define MCE_PACKET_LENGTH_MASK 0x1F /* Packet length mask */ -+ -+ -+/* module parameters */ -+#ifdef CONFIG_USB_DEBUG -+static int debug = 1; -+#else -+static int debug; -+#endif -+ -+/* general constants */ -+#define SEND_FLAG_IN_PROGRESS 1 -+#define SEND_FLAG_COMPLETE 2 -+#define RECV_FLAG_IN_PROGRESS 3 -+#define RECV_FLAG_COMPLETE 4 -+ -+#define MCEUSB_RX 1 -+#define MCEUSB_TX 2 -+ -+#define VENDOR_PHILIPS 0x0471 -+#define VENDOR_SMK 0x0609 -+#define VENDOR_TATUNG 0x1460 -+#define VENDOR_GATEWAY 0x107b -+#define VENDOR_SHUTTLE 0x1308 -+#define VENDOR_SHUTTLE2 0x051c -+#define VENDOR_MITSUMI 0x03ee -+#define VENDOR_TOPSEED 0x1784 -+#define VENDOR_RICAVISION 0x179d -+#define VENDOR_ITRON 0x195d -+#define VENDOR_FIC 0x1509 -+#define VENDOR_LG 0x043e -+#define VENDOR_MICROSOFT 0x045e -+#define VENDOR_FORMOSA 0x147a -+#define VENDOR_FINTEK 0x1934 -+#define VENDOR_PINNACLE 0x2304 -+#define VENDOR_ECS 0x1019 -+#define VENDOR_WISTRON 0x0fb8 -+#define VENDOR_COMPRO 0x185b -+#define VENDOR_NORTHSTAR 0x04eb -+#define VENDOR_REALTEK 0x0bda -+#define VENDOR_TIVO 0x105a -+ -+static struct usb_device_id mceusb_dev_table[] = { -+ /* Original Microsoft MCE IR Transceiver (often HP-branded) */ -+ { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) }, -+ /* Philips Infrared Transceiver - Sahara branded */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x0608) }, -+ /* Philips Infrared Transceiver - HP branded */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x060c) }, -+ /* Philips SRM5100 */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x060d) }, -+ /* Philips Infrared Transceiver - Omaura */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x060f) }, -+ /* Philips Infrared Transceiver - Spinel plus */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x0613) }, -+ /* Philips eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x0815) }, -+ /* Realtek MCE IR Receiver */ -+ { USB_DEVICE(VENDOR_REALTEK, 0x0161) }, -+ /* SMK/Toshiba G83C0004D410 */ -+ { USB_DEVICE(VENDOR_SMK, 0x031d) }, -+ /* SMK eHome Infrared Transceiver (Sony VAIO) */ -+ { USB_DEVICE(VENDOR_SMK, 0x0322) }, -+ /* bundled with Hauppauge PVR-150 */ -+ { USB_DEVICE(VENDOR_SMK, 0x0334) }, -+ /* SMK eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_SMK, 0x0338) }, -+ /* Tatung eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TATUNG, 0x9150) }, -+ /* Shuttle eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_SHUTTLE, 0xc001) }, -+ /* Shuttle eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_SHUTTLE2, 0xc001) }, -+ /* Gateway eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_GATEWAY, 0x3009) }, -+ /* Mitsumi */ -+ { USB_DEVICE(VENDOR_MITSUMI, 0x2501) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0001) }, -+ /* Topseed HP eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0006) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0007) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0008) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x000a) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0011) }, -+ /* Ricavision internal Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_RICAVISION, 0x0010) }, -+ /* Itron ione Libra Q-11 */ -+ { USB_DEVICE(VENDOR_ITRON, 0x7002) }, -+ /* FIC eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_FIC, 0x9242) }, -+ /* LG eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_LG, 0x9803) }, -+ /* Microsoft MCE Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_MICROSOFT, 0x00a0) }, -+ /* Formosa eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe015) }, -+ /* Formosa21 / eHome Infrared Receiver */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe016) }, -+ /* Formosa aim / Trust MCE Infrared Receiver */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe017) }, -+ /* Formosa Industrial Computing / Beanbag Emulation Device */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe018) }, -+ /* Formosa21 / eHome Infrared Receiver */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe03a) }, -+ /* Formosa Industrial Computing AIM IR605/A */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe03c) }, -+ /* Formosa Industrial Computing */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe03e) }, -+ /* Fintek eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_FINTEK, 0x0602) }, -+ /* Fintek eHome Infrared Transceiver (in the AOpen MP45) */ -+ { USB_DEVICE(VENDOR_FINTEK, 0x0702) }, -+ /* Pinnacle Remote Kit */ -+ { USB_DEVICE(VENDOR_PINNACLE, 0x0225) }, -+ /* Elitegroup Computer Systems IR */ -+ { USB_DEVICE(VENDOR_ECS, 0x0f38) }, -+ /* Wistron Corp. eHome Infrared Receiver */ -+ { USB_DEVICE(VENDOR_WISTRON, 0x0002) }, -+ /* Compro K100 */ -+ { USB_DEVICE(VENDOR_COMPRO, 0x3020) }, -+ /* Compro K100 v2 */ -+ { USB_DEVICE(VENDOR_COMPRO, 0x3082) }, -+ /* Northstar Systems, Inc. eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) }, -+ /* TiVo PC IR Receiver */ -+ { USB_DEVICE(VENDOR_TIVO, 0x2000) }, -+ /* Terminating entry */ -+ { } -+}; -+ -+static struct usb_device_id gen3_list[] = { -+ { USB_DEVICE(VENDOR_PINNACLE, 0x0225) }, -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0008) }, -+ {} -+}; -+ -+static struct usb_device_id microsoft_gen1_list[] = { -+ { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) }, -+ {} -+}; -+ -+static struct usb_device_id std_tx_mask_list[] = { -+ { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) }, -+ { USB_DEVICE(VENDOR_PHILIPS, 0x060c) }, -+ { USB_DEVICE(VENDOR_SMK, 0x031d) }, -+ { USB_DEVICE(VENDOR_SMK, 0x0322) }, -+ { USB_DEVICE(VENDOR_SMK, 0x0334) }, -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0001) }, -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0006) }, -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0007) }, -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0008) }, -+ { USB_DEVICE(VENDOR_TOPSEED, 0x000a) }, -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0011) }, -+ { USB_DEVICE(VENDOR_PINNACLE, 0x0225) }, -+ {} -+}; -+ -+/* data structure for each usb transceiver */ -+struct mceusb_dev { -+ /* ir-core bits */ -+ struct ir_input_dev *irdev; -+ struct ir_dev_props *props; -+ struct ir_raw_event rawir; -+ -+ /* core device bits */ -+ struct device *dev; -+ struct input_dev *idev; -+ -+ /* usb */ -+ struct usb_device *usbdev; -+ struct urb *urb_in; -+ struct usb_endpoint_descriptor *usb_ep_in; -+ struct usb_endpoint_descriptor *usb_ep_out; -+ -+ /* buffers and dma */ -+ unsigned char *buf_in; -+ unsigned int len_in; -+ u8 cmd; /* MCE command type */ -+ u8 rem; /* Remaining IR data bytes in packet */ -+ dma_addr_t dma_in; -+ dma_addr_t dma_out; -+ -+ struct { -+ u32 connected:1; -+ u32 tx_mask_inverted:1; -+ u32 microsoft_gen1:1; -+ u32 reserved:29; -+ } flags; -+ -+ /* transmit support */ -+ int send_flags; -+ u32 carrier; -+ unsigned char tx_mask; -+ -+ char name[128]; -+ char phys[64]; -+}; -+ -+/* -+ * MCE Device Command Strings -+ * Device command responses vary from device to device... -+ * - DEVICE_RESET resets the hardware to its default state -+ * - GET_REVISION fetches the hardware/software revision, common -+ * replies are ff 0b 45 ff 1b 08 and ff 0b 50 ff 1b 42 -+ * - GET_CARRIER_FREQ gets the carrier mode and frequency of the -+ * device, with replies in the form of 9f 06 MM FF, where MM is 0-3, -+ * meaning clk of 10000000, 2500000, 625000 or 156250, and FF is -+ * ((clk / frequency) - 1) -+ * - GET_RX_TIMEOUT fetches the receiver timeout in units of 50us, -+ * response in the form of 9f 0c msb lsb -+ * - GET_TX_BITMASK fetches the transmitter bitmask, replies in -+ * the form of 9f 08 bm, where bm is the bitmask -+ * - GET_RX_SENSOR fetches the RX sensor setting -- long-range -+ * general use one or short-range learning one, in the form of -+ * 9f 14 ss, where ss is either 01 for long-range or 02 for short -+ * - SET_CARRIER_FREQ sets a new carrier mode and frequency -+ * - SET_TX_BITMASK sets the transmitter bitmask -+ * - SET_RX_TIMEOUT sets the receiver timeout -+ * - SET_RX_SENSOR sets which receiver sensor to use -+ */ -+static char DEVICE_RESET[] = {0x00, 0xff, 0xaa}; -+static char GET_REVISION[] = {0xff, 0x0b}; -+static char GET_UNKNOWN[] = {0xff, 0x18}; -+static char GET_UNKNOWN2[] = {0x9f, 0x05}; -+static char GET_CARRIER_FREQ[] = {0x9f, 0x07}; -+static char GET_RX_TIMEOUT[] = {0x9f, 0x0d}; -+static char GET_TX_BITMASK[] = {0x9f, 0x13}; -+static char GET_RX_SENSOR[] = {0x9f, 0x15}; -+/* sub in desired values in lower byte or bytes for full command */ -+/* FIXME: make use of these for transmit. -+static char SET_CARRIER_FREQ[] = {0x9f, 0x06, 0x00, 0x00}; -+static char SET_TX_BITMASK[] = {0x9f, 0x08, 0x00}; -+static char SET_RX_TIMEOUT[] = {0x9f, 0x0c, 0x00, 0x00}; -+static char SET_RX_SENSOR[] = {0x9f, 0x14, 0x00}; -+*/ -+ -+static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, -+ int len, bool out) -+{ -+ char codes[USB_BUFLEN * 3 + 1]; -+ char inout[9]; -+ int i; -+ u8 cmd, subcmd, data1, data2; -+ struct device *dev = ir->dev; -+ int idx = 0; -+ -+ /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ -+ if (ir->flags.microsoft_gen1 && !out) -+ idx = 2; -+ -+ if (len <= idx) -+ return; -+ -+ for (i = 0; i < len && i < USB_BUFLEN; i++) -+ snprintf(codes + i * 3, 4, "%02x ", buf[i] & 0xFF); -+ -+ dev_info(dev, "%sx data: %s (length=%d)\n", -+ (out ? "t" : "r"), codes, len); -+ -+ if (out) -+ strcpy(inout, "Request\0"); -+ else -+ strcpy(inout, "Got\0"); -+ -+ cmd = buf[idx] & 0xff; -+ subcmd = buf[idx + 1] & 0xff; -+ data1 = buf[idx + 2] & 0xff; -+ data2 = buf[idx + 3] & 0xff; -+ -+ switch (cmd) { -+ case 0x00: -+ if (subcmd == 0xff && data1 == 0xaa) -+ dev_info(dev, "Device reset requested\n"); -+ else -+ dev_info(dev, "Unknown command 0x%02x 0x%02x\n", -+ cmd, subcmd); -+ break; -+ case 0xff: -+ switch (subcmd) { -+ case 0x0b: -+ if (len == 2) -+ dev_info(dev, "Get hw/sw rev?\n"); -+ else -+ dev_info(dev, "hw/sw rev 0x%02x 0x%02x " -+ "0x%02x 0x%02x\n", data1, data2, -+ buf[idx + 4], buf[idx + 5]); -+ break; -+ case 0xaa: -+ dev_info(dev, "Device reset requested\n"); -+ break; -+ case 0xfe: -+ dev_info(dev, "Previous command not supported\n"); -+ break; -+ case 0x18: -+ case 0x1b: -+ default: -+ dev_info(dev, "Unknown command 0x%02x 0x%02x\n", -+ cmd, subcmd); -+ break; -+ } -+ break; -+ case 0x9f: -+ switch (subcmd) { -+ case 0x03: -+ dev_info(dev, "Ping\n"); -+ break; -+ case 0x04: -+ dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n", -+ data1, data2); -+ break; -+ case 0x06: -+ dev_info(dev, "%s carrier mode and freq of " -+ "0x%02x 0x%02x\n", inout, data1, data2); -+ break; -+ case 0x07: -+ dev_info(dev, "Get carrier mode and freq\n"); -+ break; -+ case 0x08: -+ dev_info(dev, "%s transmit blaster mask of 0x%02x\n", -+ inout, data1); -+ break; -+ case 0x0c: -+ /* value is in units of 50us, so x*50/100 or x/2 ms */ -+ dev_info(dev, "%s receive timeout of %d ms\n", -+ inout, ((data1 << 8) | data2) / 2); -+ break; -+ case 0x0d: -+ dev_info(dev, "Get receive timeout\n"); -+ break; -+ case 0x13: -+ dev_info(dev, "Get transmit blaster mask\n"); -+ break; -+ case 0x14: -+ dev_info(dev, "%s %s-range receive sensor in use\n", -+ inout, data1 == 0x02 ? "short" : "long"); -+ break; -+ case 0x15: -+ if (len == 2) -+ dev_info(dev, "Get receive sensor\n"); -+ else -+ dev_info(dev, "Received pulse count is %d\n", -+ ((data1 << 8) | data2)); -+ break; -+ case 0xfe: -+ dev_info(dev, "Error! Hardware is likely wedged...\n"); -+ break; -+ case 0x05: -+ case 0x09: -+ case 0x0f: -+ default: -+ dev_info(dev, "Unknown command 0x%02x 0x%02x\n", -+ cmd, subcmd); -+ break; -+ } -+ break; -+ default: -+ break; -+ } -+} -+ -+static void usb_async_callback(struct urb *urb, struct pt_regs *regs) -+{ -+ struct mceusb_dev *ir; -+ int len; -+ -+ if (!urb) -+ return; -+ -+ ir = urb->context; -+ if (ir) { -+ len = urb->actual_length; -+ -+ dev_dbg(ir->dev, "callback called (status=%d len=%d)\n", -+ urb->status, len); -+ -+ if (debug) -+ mceusb_dev_printdata(ir, urb->transfer_buffer, -+ len, true); -+ } -+ -+} -+ -+/* request incoming or send outgoing usb packet - used to initialize remote */ -+static void mce_request_packet(struct mceusb_dev *ir, -+ struct usb_endpoint_descriptor *ep, -+ unsigned char *data, int size, int urb_type) -+{ -+ int res; -+ struct urb *async_urb; -+ struct device *dev = ir->dev; -+ unsigned char *async_buf; -+ -+ if (urb_type == MCEUSB_TX) { -+ async_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (unlikely(!async_urb)) { -+ dev_err(dev, "Error, couldn't allocate urb!\n"); -+ return; -+ } -+ -+ async_buf = kzalloc(size, GFP_KERNEL); -+ if (!async_buf) { -+ dev_err(dev, "Error, couldn't allocate buf!\n"); -+ usb_free_urb(async_urb); -+ return; -+ } -+ -+ /* outbound data */ -+ usb_fill_int_urb(async_urb, ir->usbdev, -+ usb_sndintpipe(ir->usbdev, ep->bEndpointAddress), -+ async_buf, size, (usb_complete_t) usb_async_callback, -+ ir, ep->bInterval); -+ memcpy(async_buf, data, size); -+ -+ } else if (urb_type == MCEUSB_RX) { -+ /* standard request */ -+ async_urb = ir->urb_in; -+ ir->send_flags = RECV_FLAG_IN_PROGRESS; -+ -+ } else { -+ dev_err(dev, "Error! Unknown urb type %d\n", urb_type); -+ return; -+ } -+ -+ dev_dbg(dev, "receive request called (size=%#x)\n", size); -+ -+ async_urb->transfer_buffer_length = size; -+ async_urb->dev = ir->usbdev; -+ -+ res = usb_submit_urb(async_urb, GFP_ATOMIC); -+ if (res) { -+ dev_dbg(dev, "receive request FAILED! (res=%d)\n", res); -+ return; -+ } -+ dev_dbg(dev, "receive request complete (res=%d)\n", res); -+} -+ -+static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size) -+{ -+ mce_request_packet(ir, ir->usb_ep_out, data, size, MCEUSB_TX); -+} -+ -+static void mce_sync_in(struct mceusb_dev *ir, unsigned char *data, int size) -+{ -+ mce_request_packet(ir, ir->usb_ep_in, data, size, MCEUSB_RX); -+} -+ -+/* Send data out the IR blaster port(s) */ -+static int mceusb_tx_ir(void *priv, int *txbuf, u32 n) -+{ -+ struct mceusb_dev *ir = priv; -+ int i, ret = 0; -+ int count, cmdcount = 0; -+ unsigned char *cmdbuf; /* MCE command buffer */ -+ long signal_duration = 0; /* Singnal length in us */ -+ struct timeval start_time, end_time; -+ -+ do_gettimeofday(&start_time); -+ -+ count = n / sizeof(int); -+ -+ cmdbuf = kzalloc(sizeof(int) * MCE_CMDBUF_SIZE, GFP_KERNEL); -+ if (!cmdbuf) -+ return -ENOMEM; -+ -+ /* MCE tx init header */ -+ cmdbuf[cmdcount++] = MCE_CONTROL_HEADER; -+ cmdbuf[cmdcount++] = 0x08; -+ cmdbuf[cmdcount++] = ir->tx_mask; -+ -+ /* Generate mce packet data */ -+ for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) { -+ signal_duration += txbuf[i]; -+ txbuf[i] = txbuf[i] / MCE_TIME_UNIT; -+ -+ do { /* loop to support long pulses/spaces > 127*50us=6.35ms */ -+ -+ /* Insert mce packet header every 4th entry */ -+ if ((cmdcount < MCE_CMDBUF_SIZE) && -+ (cmdcount - MCE_TX_HEADER_LENGTH) % -+ MCE_CODE_LENGTH == 0) -+ cmdbuf[cmdcount++] = MCE_PACKET_HEADER; -+ -+ /* Insert mce packet data */ -+ if (cmdcount < MCE_CMDBUF_SIZE) -+ cmdbuf[cmdcount++] = -+ (txbuf[i] < MCE_PULSE_BIT ? -+ txbuf[i] : MCE_MAX_PULSE_LENGTH) | -+ (i & 1 ? 0x00 : MCE_PULSE_BIT); -+ else { -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ } while ((txbuf[i] > MCE_MAX_PULSE_LENGTH) && -+ (txbuf[i] -= MCE_MAX_PULSE_LENGTH)); -+ } -+ -+ /* Fix packet length in last header */ -+ cmdbuf[cmdcount - (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH] = -+ 0x80 + (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH - 1; -+ -+ /* Check if we have room for the empty packet at the end */ -+ if (cmdcount >= MCE_CMDBUF_SIZE) { -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ /* All mce commands end with an empty packet (0x80) */ -+ cmdbuf[cmdcount++] = 0x80; -+ -+ /* Transmit the command to the mce device */ -+ mce_async_out(ir, cmdbuf, cmdcount); -+ -+ /* -+ * The lircd gap calculation expects the write function to -+ * wait the time it takes for the ircommand to be sent before -+ * it returns. -+ */ -+ do_gettimeofday(&end_time); -+ signal_duration -= (end_time.tv_usec - start_time.tv_usec) + -+ (end_time.tv_sec - start_time.tv_sec) * 1000000; -+ -+ /* delay with the closest number of ticks */ -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(usecs_to_jiffies(signal_duration)); -+ -+out: -+ kfree(cmdbuf); -+ return ret ? ret : n; -+} -+ -+/* Sets active IR outputs -- mce devices typically (all?) have two */ -+static int mceusb_set_tx_mask(void *priv, u32 mask) -+{ -+ struct mceusb_dev *ir = priv; -+ -+ if (ir->flags.tx_mask_inverted) -+ ir->tx_mask = (mask != 0x03 ? mask ^ 0x03 : mask) << 1; -+ else -+ ir->tx_mask = mask; -+ -+ return 0; -+} -+ -+/* Sets the send carrier frequency and mode */ -+static int mceusb_set_tx_carrier(void *priv, u32 carrier) -+{ -+ struct mceusb_dev *ir = priv; -+ int clk = 10000000; -+ int prescaler = 0, divisor = 0; -+ unsigned char cmdbuf[4] = { 0x9f, 0x06, 0x00, 0x00 }; -+ -+ /* Carrier has changed */ -+ if (ir->carrier != carrier) { -+ -+ if (carrier == 0) { -+ ir->carrier = carrier; -+ cmdbuf[2] = 0x01; -+ cmdbuf[3] = 0x80; -+ dev_dbg(ir->dev, "%s: disabling carrier " -+ "modulation\n", __func__); -+ mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); -+ return carrier; -+ } -+ -+ for (prescaler = 0; prescaler < 4; ++prescaler) { -+ divisor = (clk >> (2 * prescaler)) / carrier; -+ if (divisor <= 0xFF) { -+ ir->carrier = carrier; -+ cmdbuf[2] = prescaler; -+ cmdbuf[3] = divisor; -+ dev_dbg(ir->dev, "%s: requesting %u HZ " -+ "carrier\n", __func__, carrier); -+ -+ /* Transmit new carrier to mce device */ -+ mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); -+ return carrier; -+ } -+ } -+ -+ return -EINVAL; -+ -+ } -+ -+ return carrier; -+} -+ -+static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) -+{ -+ struct ir_raw_event rawir = { .pulse = false, .duration = 0 }; -+ int i, start_index = 0; -+ u8 hdr = MCE_CONTROL_HEADER; -+ -+ /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ -+ if (ir->flags.microsoft_gen1) -+ start_index = 2; -+ -+ for (i = start_index; i < buf_len;) { -+ if (ir->rem == 0) { -+ /* decode mce packets of the form (84),AA,BB,CC,DD */ -+ /* IR data packets can span USB messages - rem */ -+ hdr = ir->buf_in[i]; -+ ir->rem = (hdr & MCE_PACKET_LENGTH_MASK); -+ ir->cmd = (hdr & ~MCE_PACKET_LENGTH_MASK); -+ dev_dbg(ir->dev, "New data. rem: 0x%02x, cmd: 0x%02x\n", -+ ir->rem, ir->cmd); -+ i++; -+ } -+ -+ /* don't process MCE commands */ -+ if (hdr == MCE_CONTROL_HEADER || hdr == 0xff) { -+ ir->rem = 0; -+ return; -+ } -+ -+ for (; (ir->rem > 0) && (i < buf_len); i++) { -+ ir->rem--; -+ -+ rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0); -+ rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK) -+ * MCE_TIME_UNIT * 1000; -+ -+ if ((ir->buf_in[i] & MCE_PULSE_MASK) == 0x7f) { -+ if (ir->rawir.pulse == rawir.pulse) -+ ir->rawir.duration += rawir.duration; -+ else { -+ ir->rawir.duration = rawir.duration; -+ ir->rawir.pulse = rawir.pulse; -+ } -+ continue; -+ } -+ rawir.duration += ir->rawir.duration; -+ ir->rawir.duration = 0; -+ ir->rawir.pulse = rawir.pulse; -+ -+ dev_dbg(ir->dev, "Storing %s with duration %d\n", -+ rawir.pulse ? "pulse" : "space", -+ rawir.duration); -+ -+ ir_raw_event_store(ir->idev, &rawir); -+ } -+ -+ if (ir->buf_in[i] == 0x80 || ir->buf_in[i] == 0x9f) -+ ir->rem = 0; -+ -+ dev_dbg(ir->dev, "calling ir_raw_event_handle\n"); -+ ir_raw_event_handle(ir->idev); -+ } -+} -+ -+static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) -+{ -+ struct mceusb_dev *ir; -+ int buf_len; -+ -+ if (!urb) -+ return; -+ -+ ir = urb->context; -+ if (!ir) { -+ usb_unlink_urb(urb); -+ return; -+ } -+ -+ buf_len = urb->actual_length; -+ -+ if (debug) -+ mceusb_dev_printdata(ir, urb->transfer_buffer, buf_len, false); -+ -+ if (ir->send_flags == RECV_FLAG_IN_PROGRESS) { -+ ir->send_flags = SEND_FLAG_COMPLETE; -+ dev_dbg(&ir->irdev->dev, "setup answer received %d bytes\n", -+ buf_len); -+ } -+ -+ switch (urb->status) { -+ /* success */ -+ case 0: -+ mceusb_process_ir_data(ir, buf_len); -+ break; -+ -+ case -ECONNRESET: -+ case -ENOENT: -+ case -ESHUTDOWN: -+ usb_unlink_urb(urb); -+ return; -+ -+ case -EPIPE: -+ default: -+ break; -+ } -+ -+ usb_submit_urb(urb, GFP_ATOMIC); -+} -+ -+static void mceusb_gen1_init(struct mceusb_dev *ir) -+{ -+ int ret; -+ int maxp = ir->len_in; -+ struct device *dev = ir->dev; -+ char *data; -+ -+ data = kzalloc(USB_CTRL_MSG_SZ, GFP_KERNEL); -+ if (!data) { -+ dev_err(dev, "%s: memory allocation failed!\n", __func__); -+ return; -+ } -+ -+ /* -+ * This is a strange one. Windows issues a set address to the device -+ * on the receive control pipe and expect a certain value pair back -+ */ -+ ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), -+ USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0, -+ data, USB_CTRL_MSG_SZ, HZ * 3); -+ dev_dbg(dev, "%s - ret = %d\n", __func__, ret); -+ dev_dbg(dev, "%s - data[0] = %d, data[1] = %d\n", -+ __func__, data[0], data[1]); -+ -+ /* set feature: bit rate 38400 bps */ -+ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), -+ USB_REQ_SET_FEATURE, USB_TYPE_VENDOR, -+ 0xc04e, 0x0000, NULL, 0, HZ * 3); -+ -+ dev_dbg(dev, "%s - ret = %d\n", __func__, ret); -+ -+ /* bRequest 4: set char length to 8 bits */ -+ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), -+ 4, USB_TYPE_VENDOR, -+ 0x0808, 0x0000, NULL, 0, HZ * 3); -+ dev_dbg(dev, "%s - retB = %d\n", __func__, ret); -+ -+ /* bRequest 2: set handshaking to use DTR/DSR */ -+ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), -+ 2, USB_TYPE_VENDOR, -+ 0x0000, 0x0100, NULL, 0, HZ * 3); -+ dev_dbg(dev, "%s - retC = %d\n", __func__, ret); -+ -+ /* device reset */ -+ mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* get hw/sw revision? */ -+ mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ kfree(data); -+}; -+ -+static void mceusb_gen2_init(struct mceusb_dev *ir) -+{ -+ int maxp = ir->len_in; -+ -+ /* device reset */ -+ mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* get hw/sw revision? */ -+ mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* unknown what the next two actually return... */ -+ mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN)); -+ mce_sync_in(ir, NULL, maxp); -+ mce_async_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2)); -+ mce_sync_in(ir, NULL, maxp); -+} -+ -+static void mceusb_get_parameters(struct mceusb_dev *ir) -+{ -+ int maxp = ir->len_in; -+ -+ /* get the carrier and frequency */ -+ mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* get the transmitter bitmask */ -+ mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* get receiver timeout value */ -+ mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* get receiver sensor setting */ -+ mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR)); -+ mce_sync_in(ir, NULL, maxp); -+} -+ -+static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir) -+{ -+ struct input_dev *idev; -+ struct ir_dev_props *props; -+ struct ir_input_dev *irdev; -+ struct device *dev = ir->dev; -+ int ret = -ENODEV; -+ -+ idev = input_allocate_device(); -+ if (!idev) { -+ dev_err(dev, "remote input dev allocation failed\n"); -+ goto idev_alloc_failed; -+ } -+ -+ ret = -ENOMEM; -+ props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL); -+ if (!props) { -+ dev_err(dev, "remote ir dev props allocation failed\n"); -+ goto props_alloc_failed; -+ } -+ -+ irdev = kzalloc(sizeof(struct ir_input_dev), GFP_KERNEL); -+ if (!irdev) { -+ dev_err(dev, "remote ir input dev allocation failed\n"); -+ goto ir_dev_alloc_failed; -+ } -+ -+ snprintf(ir->name, sizeof(ir->name), "Media Center Ed. eHome " -+ "Infrared Remote Transceiver (%04x:%04x)", -+ le16_to_cpu(ir->usbdev->descriptor.idVendor), -+ le16_to_cpu(ir->usbdev->descriptor.idProduct)); -+ -+ idev->name = ir->name; -+ usb_make_path(ir->usbdev, ir->phys, sizeof(ir->phys)); -+ strlcat(ir->phys, "/input0", sizeof(ir->phys)); -+ idev->phys = ir->phys; -+ -+ props->priv = ir; -+ props->driver_type = RC_DRIVER_IR_RAW; -+ props->allowed_protos = IR_TYPE_ALL; -+ props->s_tx_mask = mceusb_set_tx_mask; -+ props->s_tx_carrier = mceusb_set_tx_carrier; -+ props->tx_ir = mceusb_tx_ir; -+ -+ ir->props = props; -+ ir->irdev = irdev; -+ -+ input_set_drvdata(idev, irdev); -+ -+ ret = ir_input_register(idev, RC_MAP_RC6_MCE, props, DRIVER_NAME); -+ if (ret < 0) { -+ dev_err(dev, "remote input device register failed\n"); -+ goto irdev_failed; -+ } -+ -+ return idev; -+ -+irdev_failed: -+ kfree(irdev); -+ir_dev_alloc_failed: -+ kfree(props); -+props_alloc_failed: -+ input_free_device(idev); -+idev_alloc_failed: -+ return NULL; -+} -+ -+static int __devinit mceusb_dev_probe(struct usb_interface *intf, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *dev = interface_to_usbdev(intf); -+ struct usb_host_interface *idesc; -+ struct usb_endpoint_descriptor *ep = NULL; -+ struct usb_endpoint_descriptor *ep_in = NULL; -+ struct usb_endpoint_descriptor *ep_out = NULL; -+ struct usb_host_config *config; -+ struct mceusb_dev *ir = NULL; -+ int pipe, maxp, i; -+ char buf[63], name[128] = ""; -+ bool is_gen3; -+ bool is_microsoft_gen1; -+ bool tx_mask_inverted; -+ -+ dev_dbg(&intf->dev, ": %s called\n", __func__); -+ -+ config = dev->actconfig; -+ idesc = intf->cur_altsetting; -+ -+ is_gen3 = usb_match_id(intf, gen3_list) ? 1 : 0; -+ is_microsoft_gen1 = usb_match_id(intf, microsoft_gen1_list) ? 1 : 0; -+ tx_mask_inverted = usb_match_id(intf, std_tx_mask_list) ? 0 : 1; -+ -+ /* step through the endpoints to find first bulk in and out endpoint */ -+ for (i = 0; i < idesc->desc.bNumEndpoints; ++i) { -+ ep = &idesc->endpoint[i].desc; -+ -+ if ((ep_in == NULL) -+ && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) -+ == USB_DIR_IN) -+ && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ == USB_ENDPOINT_XFER_BULK) -+ || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ == USB_ENDPOINT_XFER_INT))) { -+ -+ ep_in = ep; -+ ep_in->bmAttributes = USB_ENDPOINT_XFER_INT; -+ ep_in->bInterval = 1; -+ dev_dbg(&intf->dev, ": acceptable inbound endpoint " -+ "found\n"); -+ } -+ -+ if ((ep_out == NULL) -+ && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) -+ == USB_DIR_OUT) -+ && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ == USB_ENDPOINT_XFER_BULK) -+ || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ == USB_ENDPOINT_XFER_INT))) { -+ -+ ep_out = ep; -+ ep_out->bmAttributes = USB_ENDPOINT_XFER_INT; -+ ep_out->bInterval = 1; -+ dev_dbg(&intf->dev, ": acceptable outbound endpoint " -+ "found\n"); -+ } -+ } -+ if (ep_in == NULL) { -+ dev_dbg(&intf->dev, ": inbound and/or endpoint not found\n"); -+ return -ENODEV; -+ } -+ -+ pipe = usb_rcvintpipe(dev, ep_in->bEndpointAddress); -+ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); -+ -+ ir = kzalloc(sizeof(struct mceusb_dev), GFP_KERNEL); -+ if (!ir) -+ goto mem_alloc_fail; -+ -+ ir->buf_in = usb_alloc_coherent(dev, maxp, GFP_ATOMIC, &ir->dma_in); -+ if (!ir->buf_in) -+ goto buf_in_alloc_fail; -+ -+ ir->urb_in = usb_alloc_urb(0, GFP_KERNEL); -+ if (!ir->urb_in) -+ goto urb_in_alloc_fail; -+ -+ ir->usbdev = dev; -+ ir->dev = &intf->dev; -+ ir->len_in = maxp; -+ ir->flags.microsoft_gen1 = is_microsoft_gen1; -+ ir->flags.tx_mask_inverted = tx_mask_inverted; -+ -+ /* Saving usb interface data for use by the transmitter routine */ -+ ir->usb_ep_in = ep_in; -+ ir->usb_ep_out = ep_out; -+ -+ if (dev->descriptor.iManufacturer -+ && usb_string(dev, dev->descriptor.iManufacturer, -+ buf, sizeof(buf)) > 0) -+ strlcpy(name, buf, sizeof(name)); -+ if (dev->descriptor.iProduct -+ && usb_string(dev, dev->descriptor.iProduct, -+ buf, sizeof(buf)) > 0) -+ snprintf(name + strlen(name), sizeof(name) - strlen(name), -+ " %s", buf); -+ -+ ir->idev = mceusb_init_input_dev(ir); -+ if (!ir->idev) -+ goto input_dev_fail; -+ -+ /* flush buffers on the device */ -+ mce_sync_in(ir, NULL, maxp); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* wire up inbound data handler */ -+ usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, -+ maxp, (usb_complete_t) mceusb_dev_recv, ir, ep_in->bInterval); -+ ir->urb_in->transfer_dma = ir->dma_in; -+ ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -+ -+ /* initialize device */ -+ if (ir->flags.microsoft_gen1) -+ mceusb_gen1_init(ir); -+ else if (!is_gen3) -+ mceusb_gen2_init(ir); -+ -+ mceusb_get_parameters(ir); -+ -+ mceusb_set_tx_mask(ir, MCE_DEFAULT_TX_MASK); -+ -+ usb_set_intfdata(intf, ir); -+ -+ dev_info(&intf->dev, "Registered %s on usb%d:%d\n", name, -+ dev->bus->busnum, dev->devnum); -+ -+ return 0; -+ -+ /* Error-handling path */ -+input_dev_fail: -+ usb_free_urb(ir->urb_in); -+urb_in_alloc_fail: -+ usb_free_coherent(dev, maxp, ir->buf_in, ir->dma_in); -+buf_in_alloc_fail: -+ kfree(ir); -+mem_alloc_fail: -+ dev_err(&intf->dev, "%s: device setup failed!\n", __func__); -+ -+ return -ENOMEM; -+} -+ -+ -+static void __devexit mceusb_dev_disconnect(struct usb_interface *intf) -+{ -+ struct usb_device *dev = interface_to_usbdev(intf); -+ struct mceusb_dev *ir = usb_get_intfdata(intf); -+ -+ usb_set_intfdata(intf, NULL); -+ -+ if (!ir) -+ return; -+ -+ ir->usbdev = NULL; -+ ir_input_unregister(ir->idev); -+ usb_kill_urb(ir->urb_in); -+ usb_free_urb(ir->urb_in); -+ usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in); -+ -+ kfree(ir); -+} -+ -+static int mceusb_dev_suspend(struct usb_interface *intf, pm_message_t message) -+{ -+ struct mceusb_dev *ir = usb_get_intfdata(intf); -+ dev_info(ir->dev, "suspend\n"); -+ usb_kill_urb(ir->urb_in); -+ return 0; -+} -+ -+static int mceusb_dev_resume(struct usb_interface *intf) -+{ -+ struct mceusb_dev *ir = usb_get_intfdata(intf); -+ dev_info(ir->dev, "resume\n"); -+ if (usb_submit_urb(ir->urb_in, GFP_ATOMIC)) -+ return -EIO; -+ return 0; -+} -+ -+static struct usb_driver mceusb_dev_driver = { -+ .name = DRIVER_NAME, -+ .probe = mceusb_dev_probe, -+ .disconnect = mceusb_dev_disconnect, -+ .suspend = mceusb_dev_suspend, -+ .resume = mceusb_dev_resume, -+ .reset_resume = mceusb_dev_resume, -+ .id_table = mceusb_dev_table -+}; -+ -+static int __init mceusb_dev_init(void) -+{ -+ int ret; -+ -+ ret = usb_register(&mceusb_dev_driver); -+ if (ret < 0) -+ printk(KERN_ERR DRIVER_NAME -+ ": usb register failed, result = %d\n", ret); -+ -+ return ret; -+} -+ -+static void __exit mceusb_dev_exit(void) -+{ -+ usb_deregister(&mceusb_dev_driver); -+} -+ -+module_init(mceusb_dev_init); -+module_exit(mceusb_dev_exit); -+ -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_AUTHOR(DRIVER_AUTHOR); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(usb, mceusb_dev_table); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Debug enabled or not"); -diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c -index b2e1545..7955e49 100644 ---- a/drivers/media/common/tuners/tda18271-fe.c -+++ b/drivers/media/common/tuners/tda18271-fe.c -@@ -1249,7 +1249,7 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, - struct tda18271_config *cfg) - { - struct tda18271_priv *priv = NULL; -- int instance; -+ int instance, ret; - - mutex_lock(&tda18271_list_mutex); - -@@ -1268,10 +1268,12 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, - priv->cal_initialized = false; - mutex_init(&priv->lock); - -- if (tda_fail(tda18271_get_id(fe))) -+ ret = tda18271_get_id(fe); -+ if (tda_fail(ret)) - goto fail; - -- if (tda_fail(tda18271_assign_map_layout(fe))) -+ ret = tda18271_assign_map_layout(fe); -+ if (tda_fail(ret)) - goto fail; - - mutex_lock(&priv->lock); -diff --git a/drivers/media/dvb/mantis/Kconfig b/drivers/media/dvb/mantis/Kconfig -index f7b72a3..decdeda 100644 ---- a/drivers/media/dvb/mantis/Kconfig -+++ b/drivers/media/dvb/mantis/Kconfig -@@ -10,9 +10,15 @@ config MANTIS_CORE - config DVB_MANTIS - tristate "MANTIS based cards" - depends on MANTIS_CORE && DVB_CORE && PCI && I2C -- select DVB_MB86A16 -- select DVB_ZL10353 -- select DVB_STV0299 -+ select DVB_MB86A16 if !DVB_FE_CUSTOMISE -+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE -+ select DVB_STV0299 if !DVB_FE_CUSTOMISE -+ select DVB_LNBP21 if !DVB_FE_CUSTOMISE -+ select DVB_STB0899 if !DVB_FE_CUSTOMISE -+ select DVB_STB6100 if !DVB_FE_CUSTOMISE -+ select DVB_TDA665x if !DVB_FE_CUSTOMISE -+ select DVB_TDA10021 if !DVB_FE_CUSTOMISE -+ select DVB_TDA10023 if !DVB_FE_CUSTOMISE - select DVB_PLL - help - Support for PCI cards based on the Mantis PCI bridge. -@@ -23,7 +29,7 @@ config DVB_MANTIS - config DVB_HOPPER - tristate "HOPPER based cards" - depends on MANTIS_CORE && DVB_CORE && PCI && I2C -- select DVB_ZL10353 -+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_PLL - help - Support for PCI cards based on the Hopper PCI bridge. -diff --git a/drivers/media/dvb/mantis/mantis_input.c b/drivers/media/dvb/mantis/mantis_input.c -index 3d4e466..a99489b 100644 ---- a/drivers/media/dvb/mantis/mantis_input.c -+++ b/drivers/media/dvb/mantis/mantis_input.c -@@ -19,7 +19,7 @@ - */ - - #include --#include -+#include - #include - - #include "dmxdev.h" -@@ -104,7 +104,6 @@ EXPORT_SYMBOL_GPL(ir_mantis); - int mantis_input_init(struct mantis_pci *mantis) - { - struct input_dev *rc; -- struct ir_input_state rc_state; - char name[80], dev[80]; - int err; - -@@ -120,8 +119,6 @@ int mantis_input_init(struct mantis_pci *mantis) - rc->name = name; - rc->phys = dev; - -- ir_input_init(rc, &rc_state, IR_TYPE_OTHER); -- - rc->id.bustype = BUS_PCI; - rc->id.vendor = mantis->vendor_id; - rc->id.product = mantis->device_id; -diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c -index d639186..2014dae 100644 ---- a/drivers/media/video/cx23885/cx23885-cards.c -+++ b/drivers/media/video/cx23885/cx23885-cards.c -@@ -408,10 +408,18 @@ struct cx23885_subid cx23885_subids[] = { - .card = CX23885_BOARD_HAUPPAUGE_HVR1275, - }, { - .subvendor = 0x0070, -+ .subdevice = 0x221d, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1275, -+ }, { -+ .subvendor = 0x0070, - .subdevice = 0x2251, - .card = CX23885_BOARD_HAUPPAUGE_HVR1255, - }, { - .subvendor = 0x0070, -+ .subdevice = 0x2259, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1255, -+ }, { -+ .subvendor = 0x0070, - .subdevice = 0x2291, - .card = CX23885_BOARD_HAUPPAUGE_HVR1210, - }, { -@@ -419,6 +427,38 @@ struct cx23885_subid cx23885_subids[] = { - .subdevice = 0x2295, - .card = CX23885_BOARD_HAUPPAUGE_HVR1210, - }, { -+ .subvendor = 0x0070, -+ .subdevice = 0x2299, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, -+ }, { -+ .subvendor = 0x0070, -+ .subdevice = 0x229d, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ -+ }, { -+ .subvendor = 0x0070, -+ .subdevice = 0x22f0, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, -+ }, { -+ .subvendor = 0x0070, -+ .subdevice = 0x22f1, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1255, -+ }, { -+ .subvendor = 0x0070, -+ .subdevice = 0x22f2, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1275, -+ }, { -+ .subvendor = 0x0070, -+ .subdevice = 0x22f3, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ -+ }, { -+ .subvendor = 0x0070, -+ .subdevice = 0x22f4, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, -+ }, { -+ .subvendor = 0x0070, -+ .subdevice = 0x22f5, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ -+ }, { - .subvendor = 0x14f1, - .subdevice = 0x8651, - .card = CX23885_BOARD_MYGICA_X8506, -diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c -index 0dde57e..ff76f64 100644 ---- a/drivers/media/video/cx23885/cx23885-core.c -+++ b/drivers/media/video/cx23885/cx23885-core.c -@@ -1142,7 +1142,7 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) - - BUG_ON(in_interrupt()); - videobuf_waiton(&buf->vb, 0, 0); -- videobuf_dma_unmap(q, dma); -+ videobuf_dma_unmap(q->dev, dma); - videobuf_dma_free(dma); - btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -@@ -1953,8 +1953,12 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev, - goto fail_irq; - } - -- err = request_irq(pci_dev->irq, cx23885_irq, -- IRQF_SHARED | IRQF_DISABLED, dev->name, dev); -+ if (!pci_enable_msi(pci_dev)) -+ err = request_irq(pci_dev->irq, cx23885_irq, -+ IRQF_DISABLED, dev->name, dev); -+ else -+ err = request_irq(pci_dev->irq, cx23885_irq, -+ IRQF_SHARED | IRQF_DISABLED, dev->name, dev); - if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d\n", - dev->name, pci_dev->irq); -@@ -2000,6 +2004,7 @@ static void __devexit cx23885_finidev(struct pci_dev *pci_dev) - - /* unregister stuff */ - free_irq(pci_dev->irq, dev); -+ pci_disable_msi(pci_dev); - - cx23885_dev_unregister(dev); - v4l2_device_unregister(v4l2_dev); -diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c -index 0a199d7..3d70af2 100644 ---- a/drivers/media/video/cx23885/cx23885-dvb.c -+++ b/drivers/media/video/cx23885/cx23885-dvb.c -@@ -991,7 +991,7 @@ static int dvb_register(struct cx23885_tsport *port) - ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, - &dev->pci->dev, adapter_nr, 0, - cx23885_dvb_fe_ioctl_override); -- if (!ret) -+ if (ret) - return ret; - - /* init CI & MAC */ -diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c -index 5de6ba9..d0b1613 100644 ---- a/drivers/media/video/cx23885/cx23885-input.c -+++ b/drivers/media/video/cx23885/cx23885-input.c -@@ -37,161 +37,55 @@ - - #include - #include --#include -+#include - #include - - #include "cx23885.h" - --#define RC5_BITS 14 --#define RC5_HALF_BITS (2*RC5_BITS) --#define RC5_HALF_BITS_MASK ((1 << RC5_HALF_BITS) - 1) -- --#define RC5_START_BITS_NORMAL 0x3 /* Command range 0 - 63 */ --#define RC5_START_BITS_EXTENDED 0x2 /* Command range 64 - 127 */ -- --#define RC5_EXTENDED_COMMAND_OFFSET 64 -- - #define MODULE_NAME "cx23885" - --static inline unsigned int rc5_command(u32 rc5_baseband) -+static void convert_measurement(u32 x, struct ir_raw_event *y) - { -- return RC5_INSTR(rc5_baseband) + -- ((RC5_START(rc5_baseband) == RC5_START_BITS_EXTENDED) -- ? RC5_EXTENDED_COMMAND_OFFSET : 0); --} -- --static void cx23885_input_process_raw_rc5(struct cx23885_dev *dev) --{ -- struct card_ir *ir_input = dev->ir_input; -- unsigned int code, command; -- u32 rc5; -- -- /* Ignore codes that are too short to be valid RC-5 */ -- if (ir_input->last_bit < (RC5_HALF_BITS - 1)) -- return; -- -- /* The library has the manchester coding backwards; XOR to adapt. */ -- code = (ir_input->code & RC5_HALF_BITS_MASK) ^ RC5_HALF_BITS_MASK; -- rc5 = ir_rc5_decode(code); -- -- switch (RC5_START(rc5)) { -- case RC5_START_BITS_NORMAL: -- break; -- case RC5_START_BITS_EXTENDED: -- /* Don't allow if the remote only emits standard commands */ -- if (ir_input->start == RC5_START_BITS_NORMAL) -- return; -- break; -- default: -+ if (x == V4L2_SUBDEV_IR_PULSE_RX_SEQ_END) { -+ y->pulse = false; -+ y->duration = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS; - return; - } - -- if (ir_input->addr != RC5_ADDR(rc5)) -- return; -- -- /* Don't generate a keypress for RC-5 auto-repeated keypresses */ -- command = rc5_command(rc5); -- if (RC5_TOGGLE(rc5) != RC5_TOGGLE(ir_input->last_rc5) || -- command != rc5_command(ir_input->last_rc5) || -- /* Catch T == 0, CMD == 0 (e.g. '0') as first keypress after init */ -- RC5_START(ir_input->last_rc5) == 0) { -- /* This keypress is differnet: not an auto repeat */ -- ir_input_nokey(ir_input->dev, &ir_input->ir); -- ir_input_keydown(ir_input->dev, &ir_input->ir, command); -- } -- ir_input->last_rc5 = rc5; -- -- /* Schedule when we should do the key up event: ir_input_nokey() */ -- mod_timer(&ir_input->timer_keyup, -- jiffies + msecs_to_jiffies(ir_input->rc5_key_timeout)); -+ y->pulse = (x & V4L2_SUBDEV_IR_PULSE_LEVEL_MASK) ? true : false; -+ y->duration = x & V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS; - } - --static void cx23885_input_next_pulse_width_rc5(struct cx23885_dev *dev, -- u32 ns_pulse) -+static void cx23885_input_process_measurements(struct cx23885_dev *dev, -+ bool overrun) - { -- const int rc5_quarterbit_ns = 444444; /* 32 cycles/36 kHz/2 = 444 us */ -- struct card_ir *ir_input = dev->ir_input; -- int i, level, quarterbits, halfbits; -- -- if (!ir_input->active) { -- ir_input->active = 1; -- /* assume an initial space that we may not detect or measure */ -- ir_input->code = 0; -- ir_input->last_bit = 0; -- } -+ struct cx23885_kernel_ir *kernel_ir = dev->kernel_ir; -+ struct ir_raw_event kernel_ir_event; - -- if (ns_pulse == V4L2_SUBDEV_IR_PULSE_RX_SEQ_END) { -- ir_input->last_bit++; /* Account for the final space */ -- ir_input->active = 0; -- cx23885_input_process_raw_rc5(dev); -- return; -- } -- -- level = (ns_pulse & V4L2_SUBDEV_IR_PULSE_LEVEL_MASK) ? 1 : 0; -- -- /* Skip any leading space to sync to the start bit */ -- if (ir_input->last_bit == 0 && level == 0) -- return; -- -- /* -- * With valid RC-5 we can get up to two consecutive half-bits in a -- * single pulse measurment. Experiments have shown that the duration -- * of a half-bit can vary. Make sure we always end up with an even -- * number of quarter bits at the same level (mark or space). -- */ -- ns_pulse &= V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS; -- quarterbits = ns_pulse / rc5_quarterbit_ns; -- if (quarterbits & 1) -- quarterbits++; -- halfbits = quarterbits / 2; -- -- for (i = 0; i < halfbits; i++) { -- ir_input->last_bit++; -- ir_input->code |= (level << ir_input->last_bit); -- -- if (ir_input->last_bit >= RC5_HALF_BITS-1) { -- ir_input->active = 0; -- cx23885_input_process_raw_rc5(dev); -- /* -- * If level is 1, a leading mark is invalid for RC5. -- * If level is 0, we scan past extra intial space. -- * Either way we don't want to reactivate collecting -- * marks or spaces here with any left over half-bits. -- */ -- break; -- } -- } --} -- --static void cx23885_input_process_pulse_widths_rc5(struct cx23885_dev *dev, -- bool add_eom) --{ -- struct card_ir *ir_input = dev->ir_input; -- struct ir_input_state *ir_input_state = &ir_input->ir; -- -- u32 ns_pulse[RC5_HALF_BITS+1]; -- ssize_t num = 0; -+ u32 sd_ir_data[64]; -+ ssize_t num; - int count, i; -+ bool handle = false; - - do { -- v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ns_pulse, -- sizeof(ns_pulse), &num); -+ num = 0; -+ v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) sd_ir_data, -+ sizeof(sd_ir_data), &num); - - count = num / sizeof(u32); - -- /* Append an end of Rx seq, if the caller requested */ -- if (add_eom && count < ARRAY_SIZE(ns_pulse)) { -- ns_pulse[count] = V4L2_SUBDEV_IR_PULSE_RX_SEQ_END; -- count++; -+ for (i = 0; i < count; i++) { -+ convert_measurement(sd_ir_data[i], &kernel_ir_event); -+ ir_raw_event_store(kernel_ir->inp_dev, -+ &kernel_ir_event); -+ handle = true; - } -- -- /* Just drain the Rx FIFO, if we're called, but not RC-5 */ -- if (ir_input_state->ir_type != IR_TYPE_RC5) -- continue; -- -- for (i = 0; i < count; i++) -- cx23885_input_next_pulse_width_rc5(dev, ns_pulse[i]); - } while (num != 0); -+ -+ if (overrun) -+ ir_raw_event_reset(kernel_ir->inp_dev); -+ else if (handle) -+ ir_raw_event_handle(kernel_ir->inp_dev); - } - - void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) -@@ -230,7 +124,7 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) - } - - if (data_available) -- cx23885_input_process_pulse_widths_rc5(dev, overrun); -+ cx23885_input_process_measurements(dev, overrun); - - if (overrun) { - /* If there was a FIFO overrun, clear & restart the device */ -@@ -241,34 +135,15 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) - } - } - --static void cx23885_input_ir_start(struct cx23885_dev *dev) -+static int cx23885_input_ir_start(struct cx23885_dev *dev) - { -- struct card_ir *ir_input = dev->ir_input; -- struct ir_input_state *ir_input_state = &ir_input->ir; - struct v4l2_subdev_ir_parameters params; - - if (dev->sd_ir == NULL) -- return; -+ return -ENODEV; - - atomic_set(&dev->ir_input_stopping, 0); - -- /* keyup timer set up, if needed */ -- switch (dev->board) { -- case CX23885_BOARD_HAUPPAUGE_HVR1850: -- case CX23885_BOARD_HAUPPAUGE_HVR1290: -- setup_timer(&ir_input->timer_keyup, -- ir_rc5_timer_keyup, /* Not actually RC-5 specific */ -- (unsigned long) ir_input); -- if (ir_input_state->ir_type == IR_TYPE_RC5) { -- /* -- * RC-5 repeats a held key every -- * 64 bits * (2 * 32/36000) sec/bit = 113.778 ms -- */ -- ir_input->rc5_key_timeout = 115; -- } -- break; -- } -- - v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1850: -@@ -299,11 +174,21 @@ static void cx23885_input_ir_start(struct cx23885_dev *dev) - break; - } - v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); -+ return 0; -+} -+ -+static int cx23885_input_ir_open(void *priv) -+{ -+ struct cx23885_kernel_ir *kernel_ir = priv; -+ -+ if (kernel_ir->cx == NULL) -+ return -ENODEV; -+ -+ return cx23885_input_ir_start(kernel_ir->cx); - } - - static void cx23885_input_ir_stop(struct cx23885_dev *dev) - { -- struct card_ir *ir_input = dev->ir_input; - struct v4l2_subdev_ir_parameters params; - - if (dev->sd_ir == NULL) -@@ -327,21 +212,26 @@ static void cx23885_input_ir_stop(struct cx23885_dev *dev) - } - - flush_scheduled_work(); -+} - -- switch (dev->board) { -- case CX23885_BOARD_HAUPPAUGE_HVR1850: -- case CX23885_BOARD_HAUPPAUGE_HVR1290: -- del_timer_sync(&ir_input->timer_keyup); -- break; -- } -+static void cx23885_input_ir_close(void *priv) -+{ -+ struct cx23885_kernel_ir *kernel_ir = priv; -+ -+ if (kernel_ir->cx != NULL) -+ cx23885_input_ir_stop(kernel_ir->cx); - } - - int cx23885_input_init(struct cx23885_dev *dev) - { -- struct card_ir *ir; -- struct input_dev *input_dev; -- char *ir_codes = NULL; -- int ir_type, ir_addr, ir_start; -+ struct cx23885_kernel_ir *kernel_ir; -+ struct input_dev *inp_dev; -+ struct ir_dev_props *props; -+ -+ char *rc_map; -+ enum rc_driver_type driver_type; -+ unsigned long allowed_protos; -+ - int ret; - - /* -@@ -354,53 +244,59 @@ int cx23885_input_init(struct cx23885_dev *dev) - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1850: - case CX23885_BOARD_HAUPPAUGE_HVR1290: -- /* Parameters for the grey Hauppauge remote for the HVR-1850 */ -- ir_codes = RC_MAP_HAUPPAUGE_NEW; -- ir_type = IR_TYPE_RC5; -- ir_addr = 0x1e; /* RC-5 system bits emitted by the remote */ -- ir_start = RC5_START_BITS_NORMAL; /* A basic RC-5 remote */ -+ /* Integrated CX23888 IR controller */ -+ driver_type = RC_DRIVER_IR_RAW; -+ allowed_protos = IR_TYPE_ALL; -+ /* The grey Hauppauge RC-5 remote */ -+ rc_map = RC_MAP_RC5_HAUPPAUGE_NEW; - break; -- } -- if (ir_codes == NULL) -+ default: - return -ENODEV; -- -- ir = kzalloc(sizeof(*ir), GFP_KERNEL); -- input_dev = input_allocate_device(); -- if (!ir || !input_dev) { -- ret = -ENOMEM; -- goto err_out_free; - } - -- ir->dev = input_dev; -- ir->addr = ir_addr; -- ir->start = ir_start; -+ /* cx23885 board instance kernel IR state */ -+ kernel_ir = kzalloc(sizeof(struct cx23885_kernel_ir), GFP_KERNEL); -+ if (kernel_ir == NULL) -+ return -ENOMEM; - -- /* init input device */ -- snprintf(ir->name, sizeof(ir->name), "cx23885 IR (%s)", -- cx23885_boards[dev->board].name); -- snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(dev->pci)); -+ kernel_ir->cx = dev; -+ kernel_ir->name = kasprintf(GFP_KERNEL, "cx23885 IR (%s)", -+ cx23885_boards[dev->board].name); -+ kernel_ir->phys = kasprintf(GFP_KERNEL, "pci-%s/ir0", -+ pci_name(dev->pci)); - -- ret = ir_input_init(input_dev, &ir->ir, ir_type); -- if (ret < 0) -+ /* input device */ -+ inp_dev = input_allocate_device(); -+ if (inp_dev == NULL) { -+ ret = -ENOMEM; - goto err_out_free; -+ } - -- input_dev->name = ir->name; -- input_dev->phys = ir->phys; -- input_dev->id.bustype = BUS_PCI; -- input_dev->id.version = 1; -+ kernel_ir->inp_dev = inp_dev; -+ inp_dev->name = kernel_ir->name; -+ inp_dev->phys = kernel_ir->phys; -+ inp_dev->id.bustype = BUS_PCI; -+ inp_dev->id.version = 1; - if (dev->pci->subsystem_vendor) { -- input_dev->id.vendor = dev->pci->subsystem_vendor; -- input_dev->id.product = dev->pci->subsystem_device; -+ inp_dev->id.vendor = dev->pci->subsystem_vendor; -+ inp_dev->id.product = dev->pci->subsystem_device; - } else { -- input_dev->id.vendor = dev->pci->vendor; -- input_dev->id.product = dev->pci->device; -+ inp_dev->id.vendor = dev->pci->vendor; -+ inp_dev->id.product = dev->pci->device; - } -- input_dev->dev.parent = &dev->pci->dev; -- -- dev->ir_input = ir; -- cx23885_input_ir_start(dev); -- -- ret = ir_input_register(ir->dev, ir_codes, NULL, MODULE_NAME); -+ inp_dev->dev.parent = &dev->pci->dev; -+ -+ /* kernel ir device properties */ -+ props = &kernel_ir->props; -+ props->driver_type = driver_type; -+ props->allowed_protos = allowed_protos; -+ props->priv = kernel_ir; -+ props->open = cx23885_input_ir_open; -+ props->close = cx23885_input_ir_close; -+ -+ /* Go */ -+ dev->kernel_ir = kernel_ir; -+ ret = ir_input_register(inp_dev, rc_map, props, MODULE_NAME); - if (ret) - goto err_out_stop; - -@@ -408,9 +304,12 @@ int cx23885_input_init(struct cx23885_dev *dev) - - err_out_stop: - cx23885_input_ir_stop(dev); -- dev->ir_input = NULL; -+ dev->kernel_ir = NULL; -+ /* TODO: double check clean-up of kernel_ir->inp_dev */ - err_out_free: -- kfree(ir); -+ kfree(kernel_ir->phys); -+ kfree(kernel_ir->name); -+ kfree(kernel_ir); - return ret; - } - -@@ -419,9 +318,11 @@ void cx23885_input_fini(struct cx23885_dev *dev) - /* Always stop the IR hardware from generating interrupts */ - cx23885_input_ir_stop(dev); - -- if (dev->ir_input == NULL) -+ if (dev->kernel_ir == NULL) - return; -- ir_input_unregister(dev->ir_input->dev); -- kfree(dev->ir_input); -- dev->ir_input = NULL; -+ ir_input_unregister(dev->kernel_ir->inp_dev); -+ kfree(dev->kernel_ir->phys); -+ kfree(dev->kernel_ir->name); -+ kfree(dev->kernel_ir); -+ dev->kernel_ir = NULL; - } -diff --git a/drivers/media/video/cx23885/cx23885-ir.c b/drivers/media/video/cx23885/cx23885-ir.c -index 9a677eb..6ceabd4 100644 ---- a/drivers/media/video/cx23885/cx23885-ir.c -+++ b/drivers/media/video/cx23885/cx23885-ir.c -@@ -53,7 +53,7 @@ void cx23885_ir_rx_work_handler(struct work_struct *work) - if (events == 0) - return; - -- if (dev->ir_input) -+ if (dev->kernel_ir) - cx23885_input_rx_work_handler(dev, events); - } - -diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h -index 8d6a55e..a33f2b7 100644 ---- a/drivers/media/video/cx23885/cx23885.h -+++ b/drivers/media/video/cx23885/cx23885.h -@@ -30,6 +30,7 @@ - #include - #include - #include -+#include - - #include "btcx-risc.h" - #include "cx23885-reg.h" -@@ -304,6 +305,15 @@ struct cx23885_tsport { - void *port_priv; - }; - -+struct cx23885_kernel_ir { -+ struct cx23885_dev *cx; -+ char *name; -+ char *phys; -+ -+ struct input_dev *inp_dev; -+ struct ir_dev_props props; -+}; -+ - struct cx23885_dev { - atomic_t refcount; - struct v4l2_device v4l2_dev; -@@ -363,7 +373,7 @@ struct cx23885_dev { - struct work_struct ir_tx_work; - unsigned long ir_tx_notifications; - -- struct card_ir *ir_input; -+ struct cx23885_kernel_ir *kernel_ir; - atomic_t ir_input_stopping; - - /* V4l */ -diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c -index 2918a6e..e8416b7 100644 ---- a/drivers/media/video/cx88/cx88-cards.c -+++ b/drivers/media/video/cx88/cx88-cards.c -@@ -45,6 +45,10 @@ static unsigned int latency = UNSET; - module_param(latency,int,0444); - MODULE_PARM_DESC(latency,"pci latency timer"); - -+static int disable_ir; -+module_param(disable_ir, int, 0444); -+MODULE_PARM_DESC(latency, "Disable IR support"); -+ - #define info_printk(core, fmt, arg...) \ - printk(KERN_INFO "%s: " fmt, core->name , ## arg) - -@@ -3498,7 +3502,10 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) - } - - cx88_card_setup(core); -- cx88_ir_init(core, pci); -+ if (!disable_ir) { -+ cx88_i2c_init_ir(core); -+ cx88_ir_init(core, pci); -+ } - - return core; - } -diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c -index fb39f11..375ad53 100644 ---- a/drivers/media/video/cx88/cx88-i2c.c -+++ b/drivers/media/video/cx88/cx88-i2c.c -@@ -181,6 +181,11 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) - } else - printk("%s: i2c register FAILED\n", core->name); - -+ return core->i2c_rc; -+} -+ -+void cx88_i2c_init_ir(struct cx88_core *core) -+{ - /* Instantiate the IR receiver device, if present */ - if (0 == core->i2c_rc) { - struct i2c_board_info info; -@@ -207,7 +212,6 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) - } - } - } -- return core->i2c_rc; - } - - /* ----------------------------------------------------------------------- */ -diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c -index e185289..eccc5e4 100644 ---- a/drivers/media/video/cx88/cx88-input.c -+++ b/drivers/media/video/cx88/cx88-input.c -@@ -30,6 +30,7 @@ - #include - - #include "cx88.h" -+#include - #include - - #define MODULE_NAME "cx88xx" -@@ -39,8 +40,8 @@ - struct cx88_IR { - struct cx88_core *core; - struct input_dev *input; -- struct ir_input_state ir; - struct ir_dev_props props; -+ u64 ir_type; - - int users; - -@@ -51,7 +52,6 @@ struct cx88_IR { - u32 sampling; - u32 samples[16]; - int scount; -- unsigned long release; - - /* poll external decoder */ - int polling; -@@ -125,29 +125,21 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) - - data = (data << 4) | ((gpio_key & 0xf0) >> 4); - -- ir_input_keydown(ir->input, &ir->ir, data); -- ir_input_nokey(ir->input, &ir->ir); -+ ir_keydown(ir->input, data, 0); - - } else if (ir->mask_keydown) { - /* bit set on keydown */ -- if (gpio & ir->mask_keydown) { -- ir_input_keydown(ir->input, &ir->ir, data); -- } else { -- ir_input_nokey(ir->input, &ir->ir); -- } -+ if (gpio & ir->mask_keydown) -+ ir_keydown(ir->input, data, 0); - - } else if (ir->mask_keyup) { - /* bit cleared on keydown */ -- if (0 == (gpio & ir->mask_keyup)) { -- ir_input_keydown(ir->input, &ir->ir, data); -- } else { -- ir_input_nokey(ir->input, &ir->ir); -- } -+ if (0 == (gpio & ir->mask_keyup)) -+ ir_keydown(ir->input, data, 0); - - } else { - /* can't distinguish keydown/up :-/ */ -- ir_input_keydown(ir->input, &ir->ir, data); -- ir_input_nokey(ir->input, &ir->ir); -+ ir_keydown(ir->input, data, 0); - } - } - -@@ -439,9 +431,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) - snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name); - snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci)); - -- err = ir_input_init(input_dev, &ir->ir, ir_type); -- if (err < 0) -- goto err_out_free; -+ ir->ir_type = ir_type; - - input_dev->name = ir->name; - input_dev->phys = ir->phys; -@@ -516,8 +506,6 @@ void cx88_ir_irq(struct cx88_core *core) - } - if (!ir->scount) { - /* nothing to sample */ -- if (ir->ir.keypressed && time_after(jiffies, ir->release)) -- ir_input_nokey(ir->input, &ir->ir); - return; - } - -@@ -553,7 +541,7 @@ void cx88_ir_irq(struct cx88_core *core) - - if (ircode == 0) { /* key still pressed */ - ir_dprintk("pulse distance decoded repeat code\n"); -- ir->release = jiffies + msecs_to_jiffies(120); -+ ir_repeat(ir->input); - break; - } - -@@ -567,10 +555,8 @@ void cx88_ir_irq(struct cx88_core *core) - break; - } - -- ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0x7f); -- -- ir_input_keydown(ir->input, &ir->ir, (ircode >> 16) & 0x7f); -- ir->release = jiffies + msecs_to_jiffies(120); -+ ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0xff); -+ ir_keydown(ir->input, (ircode >> 16) & 0xff, 0); - break; - case CX88_BOARD_HAUPPAUGE: - case CX88_BOARD_HAUPPAUGE_DVB_T1: -@@ -606,16 +592,16 @@ void cx88_ir_irq(struct cx88_core *core) - if ( dev != 0x1e && dev != 0x1f ) - /* not a hauppauge remote */ - break; -- ir_input_keydown(ir->input, &ir->ir, code); -- ir->release = jiffies + msecs_to_jiffies(120); -+ ir_keydown(ir->input, code, toggle); - break; - case CX88_BOARD_PINNACLE_PCTV_HD_800i: - ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7); - ir_dprintk("biphase decoded: %x\n", ircode); - if ((ircode & 0xfffff000) != 0x3000) - break; -- ir_input_keydown(ir->input, &ir->ir, ircode & 0x3f); -- ir->release = jiffies + msecs_to_jiffies(120); -+ /* Note: bit 0x800 being the toggle is assumed, not checked -+ with real hardware */ -+ ir_keydown(ir->input, ircode & 0x3f, ircode & 0x0800 ? 1 : 0); - break; - } - -diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h -index bdb03d3..33d161a 100644 ---- a/drivers/media/video/cx88/cx88.h -+++ b/drivers/media/video/cx88/cx88.h -@@ -636,6 +636,7 @@ extern struct videobuf_queue_ops cx8800_vbi_qops; - /* cx88-i2c.c */ - - extern int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci); -+extern void cx88_i2c_init_ir(struct cx88_core *core); - - - /* ----------------------------------------------------------- */ -diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c -index 5c3fd94..6759cd5 100644 ---- a/drivers/media/video/em28xx/em28xx-input.c -+++ b/drivers/media/video/em28xx/em28xx-input.c -@@ -65,17 +65,14 @@ struct em28xx_ir_poll_result { - struct em28xx_IR { - struct em28xx *dev; - struct input_dev *input; -- struct ir_input_state ir; - char name[32]; - char phys[32]; - - /* poll external decoder */ - int polling; - struct delayed_work work; -- unsigned int last_toggle:1; - unsigned int full_code:1; - unsigned int last_readcount; -- unsigned int repeat_interval; - - int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *); - -@@ -291,67 +288,39 @@ static int em2874_polling_getkey(struct em28xx_IR *ir, - static void em28xx_ir_handle_key(struct em28xx_IR *ir) - { - int result; -- int do_sendkey = 0; - struct em28xx_ir_poll_result poll_result; - - /* read the registers containing the IR status */ - result = ir->get_key(ir, &poll_result); -- if (result < 0) { -+ if (unlikely(result < 0)) { - dprintk("ir->get_key() failed %d\n", result); - return; - } - -- dprintk("ir->get_key result tb=%02x rc=%02x lr=%02x data=%02x%02x\n", -- poll_result.toggle_bit, poll_result.read_count, -- ir->last_readcount, poll_result.rc_address, -- poll_result.rc_data[0]); -- -- if (ir->dev->chip_id == CHIP_ID_EM2874) { -- /* The em2874 clears the readcount field every time the -- register is read. The em2860/2880 datasheet says that it -- is supposed to clear the readcount, but it doesn't. So with -- the em2874, we are looking for a non-zero read count as -- opposed to a readcount that is incrementing */ -- ir->last_readcount = 0; -- } -- -- if (poll_result.read_count == 0) { -- /* The button has not been pressed since the last read */ -- } else if (ir->last_toggle != poll_result.toggle_bit) { -- /* A button has been pressed */ -- dprintk("button has been pressed\n"); -- ir->last_toggle = poll_result.toggle_bit; -- ir->repeat_interval = 0; -- do_sendkey = 1; -- } else if (poll_result.toggle_bit == ir->last_toggle && -- poll_result.read_count > 0 && -- poll_result.read_count != ir->last_readcount) { -- /* The button is still being held down */ -- dprintk("button being held down\n"); -- -- /* Debouncer for first keypress */ -- if (ir->repeat_interval++ > 9) { -- /* Start repeating after 1 second */ -- do_sendkey = 1; -- } -- } -- -- if (do_sendkey) { -- dprintk("sending keypress\n"); -- -+ if (unlikely(poll_result.read_count != ir->last_readcount)) { -+ dprintk("%s: toggle: %d, count: %d, key 0x%02x%02x\n", __func__, -+ poll_result.toggle_bit, poll_result.read_count, -+ poll_result.rc_address, poll_result.rc_data[0]); - if (ir->full_code) -- ir_input_keydown(ir->input, &ir->ir, -- poll_result.rc_address << 8 | -- poll_result.rc_data[0]); -+ ir_keydown(ir->input, -+ poll_result.rc_address << 8 | -+ poll_result.rc_data[0], -+ poll_result.toggle_bit); - else -- ir_input_keydown(ir->input, &ir->ir, -- poll_result.rc_data[0]); -- -- ir_input_nokey(ir->input, &ir->ir); -+ ir_keydown(ir->input, -+ poll_result.rc_data[0], -+ poll_result.toggle_bit); -+ -+ if (ir->dev->chip_id == CHIP_ID_EM2874) -+ /* The em2874 clears the readcount field every time the -+ register is read. The em2860/2880 datasheet says that it -+ is supposed to clear the readcount, but it doesn't. So with -+ the em2874, we are looking for a non-zero read count as -+ opposed to a readcount that is incrementing */ -+ ir->last_readcount = 0; -+ else -+ ir->last_readcount = poll_result.read_count; - } -- -- ir->last_readcount = poll_result.read_count; -- return; - } - - static void em28xx_ir_work(struct work_struct *work) -@@ -466,11 +435,6 @@ int em28xx_ir_init(struct em28xx *dev) - usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); - strlcat(ir->phys, "/input0", sizeof(ir->phys)); - -- /* Set IR protocol */ -- err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER); -- if (err < 0) -- goto err_out_free; -- - input_dev->name = ir->name; - input_dev->phys = ir->phys; - input_dev->id.bustype = BUS_USB; -diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c -index 20090e3..7b9ec6e 100644 ---- a/drivers/media/video/em28xx/em28xx-video.c -+++ b/drivers/media/video/em28xx/em28xx-video.c -@@ -654,12 +654,12 @@ static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb) - } - - if (buf != NULL && dev->capture_type == 2) { -- if (len > 4 && p[0] == 0x88 && p[1] == 0x88 && -+ if (len >= 4 && p[0] == 0x88 && p[1] == 0x88 && - p[2] == 0x88 && p[3] == 0x88) { - p += 4; - len -= 4; - } -- if (len > 4 && p[0] == 0x22 && p[1] == 0x5a) { -+ if (len >= 4 && p[0] == 0x22 && p[1] == 0x5a) { - em28xx_isocdbg("Video frame %d, len=%i, %s\n", - p[2], len, (p[2] & 1) ? - "odd" : "even"); -diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h -index b252d1b..6216786 100644 ---- a/drivers/media/video/em28xx/em28xx.h -+++ b/drivers/media/video/em28xx/em28xx.h -@@ -32,6 +32,7 @@ - #include - #include - #include -+#include - #if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE) - #include - #endif -diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c -index 830d47b..0cae5b8 100644 ---- a/drivers/media/video/hdpvr/hdpvr-core.c -+++ b/drivers/media/video/hdpvr/hdpvr-core.c -@@ -286,6 +286,8 @@ static int hdpvr_probe(struct usb_interface *interface, - goto error; - } - -+ dev->workqueue = 0; -+ - /* register v4l2_device early so it can be used for printks */ - if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) { - err("v4l2_device_register failed"); -@@ -380,6 +382,9 @@ static int hdpvr_probe(struct usb_interface *interface, - - error: - if (dev) { -+ /* Destroy single thread */ -+ if (dev->workqueue) -+ destroy_workqueue(dev->workqueue); - /* this frees allocated memory */ - hdpvr_delete(dev); - } -diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c -index 29d4397..27ae8bb 100644 ---- a/drivers/media/video/ir-kbd-i2c.c -+++ b/drivers/media/video/ir-kbd-i2c.c -@@ -47,7 +47,7 @@ - #include - #include - --#include -+#include - #include - - /* ----------------------------------------------------------------------- */ -@@ -272,11 +272,8 @@ static void ir_key_poll(struct IR_i2c *ir) - return; - } - -- if (0 == rc) { -- ir_input_nokey(ir->input, &ir->ir); -- } else { -- ir_input_keydown(ir->input, &ir->ir, ir_key); -- } -+ if (rc) -+ ir_keydown(ir->input, ir_key, 0); - } - - static void ir_work(struct work_struct *work) -@@ -439,10 +436,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) - dev_name(&client->dev)); - - /* init + register input device */ -- err = ir_input_init(input_dev, &ir->ir, ir_type); -- if (err < 0) -- goto err_out_free; -- -+ ir->ir_type = ir_type; - input_dev->id.bustype = BUS_I2C; - input_dev->name = ir->name; - input_dev->phys = ir->phys; -diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/drivers/media/video/pvrusb2/pvrusb2-ioread.c -index b482478..bba6115 100644 ---- a/drivers/media/video/pvrusb2/pvrusb2-ioread.c -+++ b/drivers/media/video/pvrusb2/pvrusb2-ioread.c -@@ -223,7 +223,10 @@ int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp) - " pvr2_ioread_setup (setup) id=%p",cp); - pvr2_stream_kill(sp); - ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT); -- if (ret < 0) return ret; -+ if (ret < 0) { -+ mutex_unlock(&cp->mutex); -+ return ret; -+ } - for (idx = 0; idx < BUFFER_COUNT; idx++) { - bp = pvr2_stream_get_buffer(sp,idx); - pvr2_buffer_set_buffer(bp, -diff --git a/include/linux/input.h b/include/linux/input.h -index 6fcc910..fe2633c 100644 ---- a/include/linux/input.h -+++ b/include/linux/input.h -@@ -34,7 +34,7 @@ struct input_event { - * Protocol version. - */ - --#define EV_VERSION 0x010000 -+#define EV_VERSION 0x010001 - - /* - * IOCTLs (0x00 - 0x7f) -@@ -56,12 +56,22 @@ struct input_absinfo { - __s32 resolution; - }; - -+struct keycode_table_entry { -+ __u32 keycode; /* e.g. KEY_A */ -+ __u32 index; /* Index for the given scan/key table, on EVIOCGKEYCODEBIG */ -+ __u32 len; /* Length of the scancode */ -+ __u32 reserved[2]; /* Reserved for future usage */ -+ char *scancode; /* scancode, in machine-endian */ -+}; -+ - #define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */ - #define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */ - #define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) /* get repeat settings */ - #define EVIOCSREP _IOW('E', 0x03, unsigned int[2]) /* set repeat settings */ - #define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2]) /* get keycode */ - #define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2]) /* set keycode */ -+#define EVIOCGKEYCODEBIG _IOR('E', 0x04, struct keycode_table_entry) /* get keycode */ -+#define EVIOCSKEYCODEBIG _IOW('E', 0x04, struct keycode_table_entry) /* set keycode */ - - #define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */ - #define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */ -@@ -1066,13 +1076,22 @@ struct ff_effect { - * @keycodemax: size of keycode table - * @keycodesize: size of elements in keycode table - * @keycode: map of scancodes to keycodes for this device -- * @setkeycode: optional method to alter current keymap, used to implement -+ * @setkeycode: optional legacy method to alter current keymap, used to -+ * implement sparse keymaps. Shouldn't be used on new drivers -+ * @getkeycode: optional legacy method to retrieve current keymap. -+ * Shouldn't be used on new drivers. -+ * @setkeycodebig: optional method to alter current keymap, used to implement - * sparse keymaps. If not supplied default mechanism will be used. - * The method is being called while holding event_lock and thus must - * not sleep -- * @getkeycode: optional method to retrieve current keymap. If not supplied -- * default mechanism will be used. The method is being called while -- * holding event_lock and thus must not sleep -+ * @getkeycodebig_from_index: optional method to retrieve current keymap from -+ * an array index. If not supplied default mechanism will be used. -+ * The method is being called while holding event_lock and thus must -+ * not sleep -+ * @getkeycodebig_from_scancode: optional method to retrieve current keymap -+ * from an scancode. If not supplied default mechanism will be used. -+ * The method is being called while holding event_lock and thus must -+ * not sleep - * @ff: force feedback structure associated with the device if device - * supports force feedback effects - * @repeat_key: stores key code of the last key pressed; used to implement -@@ -1147,6 +1166,12 @@ struct input_dev { - unsigned int scancode, unsigned int keycode); - int (*getkeycode)(struct input_dev *dev, - unsigned int scancode, unsigned int *keycode); -+ int (*setkeycodebig)(struct input_dev *dev, -+ struct keycode_table_entry *kt_entry); -+ int (*getkeycodebig_from_index)(struct input_dev *dev, -+ struct keycode_table_entry *kt_entry); -+ int (*getkeycodebig_from_scancode)(struct input_dev *dev, -+ struct keycode_table_entry *kt_entry); - - struct ff_device *ff; - -@@ -1422,6 +1447,10 @@ int input_get_keycode(struct input_dev *dev, - unsigned int scancode, unsigned int *keycode); - int input_set_keycode(struct input_dev *dev, - unsigned int scancode, unsigned int keycode); -+int input_get_keycode_big(struct input_dev *dev, -+ struct keycode_table_entry *kt_entry); -+int input_set_keycode_big(struct input_dev *dev, -+ struct keycode_table_entry *kt_entry); - - extern struct class input_class; - -diff --git a/include/media/ir-core.h b/include/media/ir-core.h -index ad1303f..513e60d 100644 ---- a/include/media/ir-core.h -+++ b/include/media/ir-core.h -@@ -47,15 +47,21 @@ enum rc_driver_type { - * is opened. - * @close: callback to allow drivers to disable polling/irq when IR input device - * is opened. -+ * @s_tx_mask: set transmitter mask (for devices with multiple tx outputs) -+ * @s_tx_carrier: set transmit carrier frequency -+ * @tx_ir: transmit IR - */ - struct ir_dev_props { - enum rc_driver_type driver_type; - unsigned long allowed_protos; - u32 scanmask; -- void *priv; -+ void *priv; - int (*change_protocol)(void *priv, u64 ir_type); - int (*open)(void *priv); - void (*close)(void *priv); -+ int (*s_tx_mask)(void *priv, u32 mask); -+ int (*s_tx_carrier)(void *priv, u32 carrier); -+ int (*tx_ir)(void *priv, int *txbuf, u32 n); - }; - - struct ir_input_dev { -diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h -index 0506e45..5e96d7a 100644 ---- a/include/media/ir-kbd-i2c.h -+++ b/include/media/ir-kbd-i2c.h -@@ -11,7 +11,7 @@ struct IR_i2c { - struct i2c_client *c; - struct input_dev *input; - struct ir_input_state ir; -- -+ u64 ir_type; - /* Used to avoid fast repeating */ - unsigned char old; - -diff --git a/include/media/lirc.h b/include/media/lirc.h -new file mode 100644 -index 0000000..42c467c ---- /dev/null -+++ b/include/media/lirc.h -@@ -0,0 +1,165 @@ -+/* -+ * lirc.h - linux infrared remote control header file -+ * last modified 2010/07/13 by Jarod Wilson -+ */ -+ -+#ifndef _LINUX_LIRC_H -+#define _LINUX_LIRC_H -+ -+#include -+#include -+ -+#define PULSE_BIT 0x01000000 -+#define PULSE_MASK 0x00FFFFFF -+ -+#define LIRC_MODE2_SPACE 0x00000000 -+#define LIRC_MODE2_PULSE 0x01000000 -+#define LIRC_MODE2_FREQUENCY 0x02000000 -+#define LIRC_MODE2_TIMEOUT 0x03000000 -+ -+#define LIRC_VALUE_MASK 0x00FFFFFF -+#define LIRC_MODE2_MASK 0xFF000000 -+ -+#define LIRC_SPACE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_SPACE) -+#define LIRC_PULSE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_PULSE) -+#define LIRC_FREQUENCY(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_FREQUENCY) -+#define LIRC_TIMEOUT(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_TIMEOUT) -+ -+#define LIRC_VALUE(val) ((val)&LIRC_VALUE_MASK) -+#define LIRC_MODE2(val) ((val)&LIRC_MODE2_MASK) -+ -+#define LIRC_IS_SPACE(val) (LIRC_MODE2(val) == LIRC_MODE2_SPACE) -+#define LIRC_IS_PULSE(val) (LIRC_MODE2(val) == LIRC_MODE2_PULSE) -+#define LIRC_IS_FREQUENCY(val) (LIRC_MODE2(val) == LIRC_MODE2_FREQUENCY) -+#define LIRC_IS_TIMEOUT(val) (LIRC_MODE2(val) == LIRC_MODE2_TIMEOUT) -+ -+/* used heavily by lirc userspace */ -+#define lirc_t int -+ -+/*** lirc compatible hardware features ***/ -+ -+#define LIRC_MODE2SEND(x) (x) -+#define LIRC_SEND2MODE(x) (x) -+#define LIRC_MODE2REC(x) ((x) << 16) -+#define LIRC_REC2MODE(x) ((x) >> 16) -+ -+#define LIRC_MODE_RAW 0x00000001 -+#define LIRC_MODE_PULSE 0x00000002 -+#define LIRC_MODE_MODE2 0x00000004 -+#define LIRC_MODE_LIRCCODE 0x00000010 -+ -+ -+#define LIRC_CAN_SEND_RAW LIRC_MODE2SEND(LIRC_MODE_RAW) -+#define LIRC_CAN_SEND_PULSE LIRC_MODE2SEND(LIRC_MODE_PULSE) -+#define LIRC_CAN_SEND_MODE2 LIRC_MODE2SEND(LIRC_MODE_MODE2) -+#define LIRC_CAN_SEND_LIRCCODE LIRC_MODE2SEND(LIRC_MODE_LIRCCODE) -+ -+#define LIRC_CAN_SEND_MASK 0x0000003f -+ -+#define LIRC_CAN_SET_SEND_CARRIER 0x00000100 -+#define LIRC_CAN_SET_SEND_DUTY_CYCLE 0x00000200 -+#define LIRC_CAN_SET_TRANSMITTER_MASK 0x00000400 -+ -+#define LIRC_CAN_REC_RAW LIRC_MODE2REC(LIRC_MODE_RAW) -+#define LIRC_CAN_REC_PULSE LIRC_MODE2REC(LIRC_MODE_PULSE) -+#define LIRC_CAN_REC_MODE2 LIRC_MODE2REC(LIRC_MODE_MODE2) -+#define LIRC_CAN_REC_LIRCCODE LIRC_MODE2REC(LIRC_MODE_LIRCCODE) -+ -+#define LIRC_CAN_REC_MASK LIRC_MODE2REC(LIRC_CAN_SEND_MASK) -+ -+#define LIRC_CAN_SET_REC_CARRIER (LIRC_CAN_SET_SEND_CARRIER << 16) -+#define LIRC_CAN_SET_REC_DUTY_CYCLE (LIRC_CAN_SET_SEND_DUTY_CYCLE << 16) -+ -+#define LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE 0x40000000 -+#define LIRC_CAN_SET_REC_CARRIER_RANGE 0x80000000 -+#define LIRC_CAN_GET_REC_RESOLUTION 0x20000000 -+#define LIRC_CAN_SET_REC_TIMEOUT 0x10000000 -+#define LIRC_CAN_SET_REC_FILTER 0x08000000 -+ -+#define LIRC_CAN_MEASURE_CARRIER 0x02000000 -+ -+#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK) -+#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK) -+ -+#define LIRC_CAN_NOTIFY_DECODE 0x01000000 -+ -+/*** IOCTL commands for lirc driver ***/ -+ -+#define LIRC_GET_FEATURES _IOR('i', 0x00000000, __u32) -+ -+#define LIRC_GET_SEND_MODE _IOR('i', 0x00000001, __u32) -+#define LIRC_GET_REC_MODE _IOR('i', 0x00000002, __u32) -+#define LIRC_GET_SEND_CARRIER _IOR('i', 0x00000003, __u32) -+#define LIRC_GET_REC_CARRIER _IOR('i', 0x00000004, __u32) -+#define LIRC_GET_SEND_DUTY_CYCLE _IOR('i', 0x00000005, __u32) -+#define LIRC_GET_REC_DUTY_CYCLE _IOR('i', 0x00000006, __u32) -+#define LIRC_GET_REC_RESOLUTION _IOR('i', 0x00000007, __u32) -+ -+#define LIRC_GET_MIN_TIMEOUT _IOR('i', 0x00000008, __u32) -+#define LIRC_GET_MAX_TIMEOUT _IOR('i', 0x00000009, __u32) -+ -+#define LIRC_GET_MIN_FILTER_PULSE _IOR('i', 0x0000000a, __u32) -+#define LIRC_GET_MAX_FILTER_PULSE _IOR('i', 0x0000000b, __u32) -+#define LIRC_GET_MIN_FILTER_SPACE _IOR('i', 0x0000000c, __u32) -+#define LIRC_GET_MAX_FILTER_SPACE _IOR('i', 0x0000000d, __u32) -+ -+/* code length in bits, currently only for LIRC_MODE_LIRCCODE */ -+#define LIRC_GET_LENGTH _IOR('i', 0x0000000f, __u32) -+ -+#define LIRC_SET_SEND_MODE _IOW('i', 0x00000011, __u32) -+#define LIRC_SET_REC_MODE _IOW('i', 0x00000012, __u32) -+/* Note: these can reset the according pulse_width */ -+#define LIRC_SET_SEND_CARRIER _IOW('i', 0x00000013, __u32) -+#define LIRC_SET_REC_CARRIER _IOW('i', 0x00000014, __u32) -+#define LIRC_SET_SEND_DUTY_CYCLE _IOW('i', 0x00000015, __u32) -+#define LIRC_SET_REC_DUTY_CYCLE _IOW('i', 0x00000016, __u32) -+#define LIRC_SET_TRANSMITTER_MASK _IOW('i', 0x00000017, __u32) -+ -+/* -+ * when a timeout != 0 is set the driver will send a -+ * LIRC_MODE2_TIMEOUT data packet, otherwise LIRC_MODE2_TIMEOUT is -+ * never sent, timeout is disabled by default -+ */ -+#define LIRC_SET_REC_TIMEOUT _IOW('i', 0x00000018, __u32) -+ -+/* 1 enables, 0 disables timeout reports in MODE2 */ -+#define LIRC_SET_REC_TIMEOUT_REPORTS _IOW('i', 0x00000019, __u32) -+ -+/* -+ * pulses shorter than this are filtered out by hardware (software -+ * emulation in lirc_dev?) -+ */ -+#define LIRC_SET_REC_FILTER_PULSE _IOW('i', 0x0000001a, __u32) -+/* -+ * spaces shorter than this are filtered out by hardware (software -+ * emulation in lirc_dev?) -+ */ -+#define LIRC_SET_REC_FILTER_SPACE _IOW('i', 0x0000001b, __u32) -+/* -+ * if filter cannot be set independantly for pulse/space, this should -+ * be used -+ */ -+#define LIRC_SET_REC_FILTER _IOW('i', 0x0000001c, __u32) -+ -+/* -+ * if enabled from the next key press on the driver will send -+ * LIRC_MODE2_FREQUENCY packets -+ */ -+#define LIRC_SET_MEASURE_CARRIER_MODE _IOW('i', 0x0000001d, __u32) -+ -+/* -+ * to set a range use -+ * LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE with the -+ * lower bound first and later -+ * LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER with the upper bound -+ */ -+ -+#define LIRC_SET_REC_DUTY_CYCLE_RANGE _IOW('i', 0x0000001e, __u32) -+#define LIRC_SET_REC_CARRIER_RANGE _IOW('i', 0x0000001f, __u32) -+ -+#define LIRC_NOTIFY_DECODE _IO('i', 0x00000020) -+ -+#define LIRC_SETUP_START _IO('i', 0x00000021) -+#define LIRC_SETUP_END _IO('i', 0x00000022) -+ -+#endif -diff --git a/include/media/lirc_dev.h b/include/media/lirc_dev.h -new file mode 100644 -index 0000000..b1f6066 ---- /dev/null -+++ b/include/media/lirc_dev.h -@@ -0,0 +1,225 @@ -+/* -+ * LIRC base driver -+ * -+ * by Artur Lipowski -+ * This code is licensed under GNU GPL -+ * -+ */ -+ -+#ifndef _LINUX_LIRC_DEV_H -+#define _LINUX_LIRC_DEV_H -+ -+#define MAX_IRCTL_DEVICES 4 -+#define BUFLEN 16 -+ -+#define mod(n, div) ((n) % (div)) -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+struct lirc_buffer { -+ wait_queue_head_t wait_poll; -+ spinlock_t fifo_lock; -+ unsigned int chunk_size; -+ unsigned int size; /* in chunks */ -+ /* Using chunks instead of bytes pretends to simplify boundary checking -+ * And should allow for some performance fine tunning later */ -+ struct kfifo fifo; -+ u8 fifo_initialized; -+}; -+ -+static inline void lirc_buffer_clear(struct lirc_buffer *buf) -+{ -+ unsigned long flags; -+ -+ if (buf->fifo_initialized) { -+ spin_lock_irqsave(&buf->fifo_lock, flags); -+ kfifo_reset(&buf->fifo); -+ spin_unlock_irqrestore(&buf->fifo_lock, flags); -+ } else -+ WARN(1, "calling %s on an uninitialized lirc_buffer\n", -+ __func__); -+} -+ -+static inline int lirc_buffer_init(struct lirc_buffer *buf, -+ unsigned int chunk_size, -+ unsigned int size) -+{ -+ int ret; -+ -+ init_waitqueue_head(&buf->wait_poll); -+ spin_lock_init(&buf->fifo_lock); -+ buf->chunk_size = chunk_size; -+ buf->size = size; -+ ret = kfifo_alloc(&buf->fifo, size * chunk_size, GFP_KERNEL); -+ if (ret == 0) -+ buf->fifo_initialized = 1; -+ -+ return ret; -+} -+ -+static inline void lirc_buffer_free(struct lirc_buffer *buf) -+{ -+ if (buf->fifo_initialized) { -+ kfifo_free(&buf->fifo); -+ buf->fifo_initialized = 0; -+ } else -+ WARN(1, "calling %s on an uninitialized lirc_buffer\n", -+ __func__); -+} -+ -+static inline int lirc_buffer_len(struct lirc_buffer *buf) -+{ -+ int len; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&buf->fifo_lock, flags); -+ len = kfifo_len(&buf->fifo); -+ spin_unlock_irqrestore(&buf->fifo_lock, flags); -+ -+ return len; -+} -+ -+static inline int lirc_buffer_full(struct lirc_buffer *buf) -+{ -+ return lirc_buffer_len(buf) == buf->size * buf->chunk_size; -+} -+ -+static inline int lirc_buffer_empty(struct lirc_buffer *buf) -+{ -+ return !lirc_buffer_len(buf); -+} -+ -+static inline int lirc_buffer_available(struct lirc_buffer *buf) -+{ -+ return buf->size - (lirc_buffer_len(buf) / buf->chunk_size); -+} -+ -+static inline unsigned int lirc_buffer_read(struct lirc_buffer *buf, -+ unsigned char *dest) -+{ -+ unsigned int ret = 0; -+ -+ if (lirc_buffer_len(buf) >= buf->chunk_size) -+ ret = kfifo_out_locked(&buf->fifo, dest, buf->chunk_size, -+ &buf->fifo_lock); -+ return ret; -+ -+} -+ -+static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf, -+ unsigned char *orig) -+{ -+ unsigned int ret; -+ -+ ret = kfifo_in_locked(&buf->fifo, orig, buf->chunk_size, -+ &buf->fifo_lock); -+ -+ return ret; -+} -+ -+struct lirc_driver { -+ char name[40]; -+ int minor; -+ unsigned long code_length; -+ unsigned int buffer_size; /* in chunks holding one code each */ -+ int sample_rate; -+ unsigned long features; -+ -+ unsigned int chunk_size; -+ -+ void *data; -+ int min_timeout; -+ int max_timeout; -+ int (*add_to_buf) (void *data, struct lirc_buffer *buf); -+ struct lirc_buffer *rbuf; -+ int (*set_use_inc) (void *data); -+ void (*set_use_dec) (void *data); -+ struct file_operations *fops; -+ struct device *dev; -+ struct module *owner; -+}; -+ -+/* name: -+ * this string will be used for logs -+ * -+ * minor: -+ * indicates minor device (/dev/lirc) number for registered driver -+ * if caller fills it with negative value, then the first free minor -+ * number will be used (if available) -+ * -+ * code_length: -+ * length of the remote control key code expressed in bits -+ * -+ * sample_rate: -+ * -+ * data: -+ * it may point to any driver data and this pointer will be passed to -+ * all callback functions -+ * -+ * add_to_buf: -+ * add_to_buf will be called after specified period of the time or -+ * triggered by the external event, this behavior depends on value of -+ * the sample_rate this function will be called in user context. This -+ * routine should return 0 if data was added to the buffer and -+ * -ENODATA if none was available. This should add some number of bits -+ * evenly divisible by code_length to the buffer -+ * -+ * rbuf: -+ * if not NULL, it will be used as a read buffer, you will have to -+ * write to the buffer by other means, like irq's (see also -+ * lirc_serial.c). -+ * -+ * set_use_inc: -+ * set_use_inc will be called after device is opened -+ * -+ * set_use_dec: -+ * set_use_dec will be called after device is closed -+ * -+ * fops: -+ * file_operations for drivers which don't fit the current driver model. -+ * -+ * Some ioctl's can be directly handled by lirc_dev if the driver's -+ * ioctl function is NULL or if it returns -ENOIOCTLCMD (see also -+ * lirc_serial.c). -+ * -+ * owner: -+ * the module owning this struct -+ * -+ */ -+ -+ -+/* following functions can be called ONLY from user context -+ * -+ * returns negative value on error or minor number -+ * of the registered device if success -+ * contents of the structure pointed by p is copied -+ */ -+extern int lirc_register_driver(struct lirc_driver *d); -+ -+/* returns negative value on error or 0 if success -+*/ -+extern int lirc_unregister_driver(int minor); -+ -+/* Returns the private data stored in the lirc_driver -+ * associated with the given device file pointer. -+ */ -+void *lirc_get_pdata(struct file *file); -+ -+/* default file operations -+ * used by drivers if they override only some operations -+ */ -+int lirc_dev_fop_open(struct inode *inode, struct file *file); -+int lirc_dev_fop_close(struct inode *inode, struct file *file); -+unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait); -+long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -+ssize_t lirc_dev_fop_read(struct file *file, char *buffer, size_t length, -+ loff_t *ppos); -+ssize_t lirc_dev_fop_write(struct file *file, const char *buffer, size_t length, -+ loff_t *ppos); -+ -+#endif -diff --git a/include/media/rc-map.h b/include/media/rc-map.h -index c78e99a..a329858 100644 ---- a/include/media/rc-map.h -+++ b/include/media/rc-map.h -@@ -17,8 +17,13 @@ - #define IR_TYPE_RC6 (1 << 2) /* Philips RC6 protocol */ - #define IR_TYPE_JVC (1 << 3) /* JVC protocol */ - #define IR_TYPE_SONY (1 << 4) /* Sony12/15/20 protocol */ -+#define IR_TYPE_LIRC (1 << 30) /* Pass raw IR to lirc userspace */ - #define IR_TYPE_OTHER (1u << 31) - -+#define IR_TYPE_ALL (IR_TYPE_RC5 | IR_TYPE_NEC | IR_TYPE_RC6 | \ -+ IR_TYPE_JVC | IR_TYPE_SONY | IR_TYPE_LIRC | \ -+ IR_TYPE_OTHER) -+ - struct ir_scancode { - u32 scancode; - u32 keycode; -@@ -87,6 +92,7 @@ void rc_map_init(void); - #define RC_MAP_KAIOMY "rc-kaiomy" - #define RC_MAP_KWORLD_315U "rc-kworld-315u" - #define RC_MAP_KWORLD_PLUS_TV_ANALOG "rc-kworld-plus-tv-analog" -+#define RC_MAP_LIRC "rc-lirc" - #define RC_MAP_MANLI "rc-manli" - #define RC_MAP_MSI_TVANYWHERE_PLUS "rc-msi-tvanywhere-plus" - #define RC_MAP_MSI_TVANYWHERE "rc-msi-tvanywhere" -@@ -107,6 +113,7 @@ void rc_map_init(void); - #define RC_MAP_PV951 "rc-pv951" - #define RC_MAP_RC5_HAUPPAUGE_NEW "rc-rc5-hauppauge-new" - #define RC_MAP_RC5_TV "rc-rc5-tv" -+#define RC_MAP_RC6_MCE "rc-rc6-mce" - #define RC_MAP_REAL_AUDIO_220_32_KEYS "rc-real-audio-220-32-keys" - #define RC_MAP_TBS_NEC "rc-tbs-nec" - #define RC_MAP_TERRATEC_CINERGY_XS "rc-terratec-cinergy-xs" diff --git a/linux-2.6-v4l-dvb-update.patch b/linux-2.6-v4l-dvb-update.patch deleted file mode 100644 index e69de29bb..000000000 diff --git a/linux-2.6-v4l-dvb-uvcvideo-update.patch b/linux-2.6-v4l-dvb-uvcvideo-update.patch deleted file mode 100644 index 3251c7fa3..000000000 --- a/linux-2.6-v4l-dvb-uvcvideo-update.patch +++ /dev/null @@ -1,362 +0,0 @@ -From: Martin Rubli -Date: Wed, 19 May 2010 22:51:56 +0000 (+0200) -Subject: uvcvideo: Add support for absolute pan/tilt controls -X-Git-Url: http://git.linuxtv.org/pinchartl/uvcvideo.git?a=commitdiff_plain;h=d3c2f664ec76aff14c3841c99e84cd78d7227f79 - -uvcvideo: Add support for absolute pan/tilt controls - -Signed-off-by: Martin Rubli ---- - -diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c -index aa0720a..5ec2f4a 100644 ---- a/drivers/media/video/uvc/uvc_ctrl.c -+++ b/drivers/media/video/uvc/uvc_ctrl.c -@@ -606,6 +606,26 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = { - .set = uvc_ctrl_set_zoom, - }, - { -+ .id = V4L2_CID_PAN_ABSOLUTE, -+ .name = "Pan (Absolute)", -+ .entity = UVC_GUID_UVC_CAMERA, -+ .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL, -+ .size = 32, -+ .offset = 0, -+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER, -+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, -+ }, -+ { -+ .id = V4L2_CID_TILT_ABSOLUTE, -+ .name = "Tilt (Absolute)", -+ .entity = UVC_GUID_UVC_CAMERA, -+ .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL, -+ .size = 32, -+ .offset = 32, -+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER, -+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, -+ }, -+ { - .id = V4L2_CID_PRIVACY, - .name = "Privacy", - .entity = UVC_GUID_UVC_CAMERA, -From: Hans de Goede -Date: Wed, 19 May 2010 23:15:00 +0000 (+0200) -Subject: uvcvideo: Make button controls work properly -X-Git-Url: http://git.linuxtv.org/pinchartl/uvcvideo.git?a=commitdiff_plain;h=2bd47ad4894bfaf1a97660b821cbc46439a614d6 - -uvcvideo: Make button controls work properly - -According to the v4l2 spec, writing any value to a button control should -result in the action belonging to the button control being triggered. -UVC cams however want to see a 1 written, this patch fixes this by -overriding whatever value user space passed in with -1 (0xffffffff) when -the control is a button control. - -Signed-off-by: Hans de Goede ---- - -diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c -index 5ec2f4a..8bb825d 100644 ---- a/drivers/media/video/uvc/uvc_ctrl.c -+++ b/drivers/media/video/uvc/uvc_ctrl.c -@@ -698,6 +698,14 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping, - int offset = mapping->offset; - __u8 mask; - -+ /* According to the v4l2 spec, writing any value to a button control -+ * should result in the action belonging to the button control being -+ * triggered. UVC devices however want to see a 1 written -> override -+ * value. -+ */ -+ if (mapping->v4l2_type == V4L2_CTRL_TYPE_BUTTON) -+ value = -1; -+ - data += offset / 8; - offset &= 7; - -From: Laurent Pinchart -Date: Thu, 18 Feb 2010 19:38:52 +0000 (+0100) -Subject: uvcvideo: Support menu controls in the control mapping API -X-Git-Url: http://git.linuxtv.org/pinchartl/uvcvideo.git?a=commitdiff_plain;h=4930f2662e47d33e5baedac620da401a225bc3a8 - -uvcvideo: Support menu controls in the control mapping API - -The UVCIOC_CTRL_MAP ioctl doesn't support menu entries for menu -controls. As the uvc_xu_control_mapping structure has no reserved -fields, this can't be fixed while keeping ABI compatibility. - -Modify the UVCIOC_CTRL_MAP ioctl to add menu entries support, and define -UVCIOC_CTRL_MAP_OLD that supports the old ABI without any ability to add -menu controls. - -Signed-off-by: Laurent Pinchart ---- - -diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c -index 8bb825d..c88d72e 100644 ---- a/drivers/media/video/uvc/uvc_ctrl.c -+++ b/drivers/media/video/uvc/uvc_ctrl.c -@@ -1606,6 +1606,28 @@ void uvc_ctrl_cleanup_device(struct uvc_device *dev) - } - } - -+void uvc_ctrl_cleanup(void) -+{ -+ struct uvc_control_info *info; -+ struct uvc_control_info *ni; -+ struct uvc_control_mapping *mapping; -+ struct uvc_control_mapping *nm; -+ -+ list_for_each_entry_safe(info, ni, &uvc_driver.controls, list) { -+ if (!(info->flags & UVC_CONTROL_EXTENSION)) -+ continue; -+ -+ list_for_each_entry_safe(mapping, nm, &info->mappings, list) { -+ list_del(&mapping->list); -+ kfree(mapping->menu_info); -+ kfree(mapping); -+ } -+ -+ list_del(&info->list); -+ kfree(info); -+ } -+} -+ - void uvc_ctrl_init(void) - { - struct uvc_control_info *ctrl = uvc_ctrls; -diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c -index 838b56f..34818c1 100644 ---- a/drivers/media/video/uvc/uvc_driver.c -+++ b/drivers/media/video/uvc/uvc_driver.c -@@ -2261,6 +2261,7 @@ static int __init uvc_init(void) - static void __exit uvc_cleanup(void) - { - usb_deregister(&uvc_driver.driver); -+ uvc_ctrl_cleanup(); - } - - module_init(uvc_init); -diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c -index 7c9ab29..485a899 100644 ---- a/drivers/media/video/uvc/uvc_v4l2.c -+++ b/drivers/media/video/uvc/uvc_v4l2.c -@@ -29,6 +29,71 @@ - #include "uvcvideo.h" - - /* ------------------------------------------------------------------------ -+ * UVC ioctls -+ */ -+static int uvc_ioctl_ctrl_map(struct uvc_xu_control_mapping *xmap, int old) -+{ -+ struct uvc_control_mapping *map; -+ unsigned int size; -+ int ret; -+ -+ map = kzalloc(sizeof *map, GFP_KERNEL); -+ if (map == NULL) -+ return -ENOMEM; -+ -+ map->id = xmap->id; -+ memcpy(map->name, xmap->name, sizeof map->name); -+ memcpy(map->entity, xmap->entity, sizeof map->entity); -+ map->selector = xmap->selector; -+ map->size = xmap->size; -+ map->offset = xmap->offset; -+ map->v4l2_type = xmap->v4l2_type; -+ map->data_type = xmap->data_type; -+ -+ switch (xmap->v4l2_type) { -+ case V4L2_CTRL_TYPE_INTEGER: -+ case V4L2_CTRL_TYPE_BOOLEAN: -+ case V4L2_CTRL_TYPE_BUTTON: -+ break; -+ -+ case V4L2_CTRL_TYPE_MENU: -+ if (old) { -+ ret = -EINVAL; -+ goto done; -+ } -+ -+ size = xmap->menu_count * sizeof(*map->menu_info); -+ map->menu_info = kmalloc(size, GFP_KERNEL); -+ if (map->menu_info == NULL) { -+ ret = -ENOMEM; -+ goto done; -+ } -+ -+ if (copy_from_user(map->menu_info, xmap->menu_info, size)) { -+ ret = -EFAULT; -+ goto done; -+ } -+ -+ map->menu_count = xmap->menu_count; -+ break; -+ -+ default: -+ ret = -EINVAL; -+ goto done; -+ } -+ -+ ret = uvc_ctrl_add_mapping(map); -+ -+done: -+ if (ret < 0) { -+ kfree(map->menu_info); -+ kfree(map); -+ } -+ -+ return ret; -+} -+ -+/* ------------------------------------------------------------------------ - * V4L2 interface - */ - -@@ -974,7 +1039,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) - info->flags = xinfo->flags; - - info->flags |= UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX | -- UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF; -+ UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF | -+ UVC_CONTROL_EXTENSION; - - ret = uvc_ctrl_add_info(info); - if (ret < 0) -@@ -982,32 +1048,12 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) - break; - } - -+ case UVCIOC_CTRL_MAP_OLD: - case UVCIOC_CTRL_MAP: -- { -- struct uvc_xu_control_mapping *xmap = arg; -- struct uvc_control_mapping *map; -- - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - -- map = kzalloc(sizeof *map, GFP_KERNEL); -- if (map == NULL) -- return -ENOMEM; -- -- map->id = xmap->id; -- memcpy(map->name, xmap->name, sizeof map->name); -- memcpy(map->entity, xmap->entity, sizeof map->entity); -- map->selector = xmap->selector; -- map->size = xmap->size; -- map->offset = xmap->offset; -- map->v4l2_type = xmap->v4l2_type; -- map->data_type = xmap->data_type; -- -- ret = uvc_ctrl_add_mapping(map); -- if (ret < 0) -- kfree(map); -- break; -- } -+ return uvc_ioctl_ctrl_map(arg, cmd == UVCIOC_CTRL_MAP_OLD); - - case UVCIOC_CTRL_GET: - return uvc_xu_ctrl_query(chain, arg, 0); -diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h -index d1f8840..14f77e4 100644 ---- a/drivers/media/video/uvc/uvcvideo.h -+++ b/drivers/media/video/uvc/uvcvideo.h -@@ -27,6 +27,8 @@ - #define UVC_CONTROL_RESTORE (1 << 6) - /* Control can be updated by the camera. */ - #define UVC_CONTROL_AUTO_UPDATE (1 << 7) -+/* Control is an extension unit control. */ -+#define UVC_CONTROL_EXTENSION (1 << 8) - - #define UVC_CONTROL_GET_RANGE (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \ - UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \ -@@ -40,6 +42,15 @@ struct uvc_xu_control_info { - __u32 flags; - }; - -+struct uvc_menu_info { -+ __u32 value; -+ __u8 name[32]; -+}; -+ -+struct uvc_xu_control_mapping_old { -+ __u8 reserved[64]; -+}; -+ - struct uvc_xu_control_mapping { - __u32 id; - __u8 name[32]; -@@ -50,6 +61,11 @@ struct uvc_xu_control_mapping { - __u8 offset; - enum v4l2_ctrl_type v4l2_type; - __u32 data_type; -+ -+ struct uvc_menu_info __user *menu_info; -+ __u32 menu_count; -+ -+ __u32 reserved[4]; - }; - - struct uvc_xu_control { -@@ -60,6 +76,7 @@ struct uvc_xu_control { - }; - - #define UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info) -+#define UVCIOC_CTRL_MAP_OLD _IOWR('U', 2, struct uvc_xu_control_mapping_old) - #define UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping) - #define UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control) - #define UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control) -@@ -198,11 +215,6 @@ struct uvc_streaming_control { - __u8 bMaxVersion; - }; - --struct uvc_menu_info { -- __u32 value; -- __u8 name[32]; --}; -- - struct uvc_control_info { - struct list_head list; - struct list_head mappings; -@@ -625,6 +637,7 @@ extern int uvc_ctrl_init_device(struct uvc_device *dev); - extern void uvc_ctrl_cleanup_device(struct uvc_device *dev); - extern int uvc_ctrl_resume_device(struct uvc_device *dev); - extern void uvc_ctrl_init(void); -+extern void uvc_ctrl_cleanup(void); - - extern int uvc_ctrl_begin(struct uvc_video_chain *chain); - extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback); -From: Laurent Pinchart -Date: Fri, 25 Jun 2010 07:58:43 +0000 (+0200) -Subject: uvcvideo: Add support for Manta MM-353 Plako -X-Git-Url: http://git.linuxtv.org/pinchartl/uvcvideo.git?a=commitdiff_plain;h=352e661e1f347390a86cf34bc5e41adbdd1caa41 - -uvcvideo: Add support for Manta MM-353 Plako - -The camera requires the PROBE_MINMAX quirk. Add a corresponding entry -in the device IDs list - -Signed-off-by: Laurent Pinchart ---- - -diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c -index 34818c1..1a89384 100644 ---- a/drivers/media/video/uvc/uvc_driver.c -+++ b/drivers/media/video/uvc/uvc_driver.c -@@ -2174,6 +2174,15 @@ static struct usb_device_id uvc_ids[] = { - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_EXTRAFIELDS }, -+ /* Manta MM-353 Plako */ -+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE -+ | USB_DEVICE_ID_MATCH_INT_INFO, -+ .idVendor = 0x18ec, -+ .idProduct = 0x3188, -+ .bInterfaceClass = USB_CLASS_VIDEO, -+ .bInterfaceSubClass = 1, -+ .bInterfaceProtocol = 0, -+ .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* FSC WebCam V30S */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, diff --git a/linux-2.6.29-sparc-IOC_TYPECHECK.patch b/linux-2.6.29-sparc-IOC_TYPECHECK.patch deleted file mode 100644 index d73c30adc..000000000 --- a/linux-2.6.29-sparc-IOC_TYPECHECK.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff -up vanilla-2.6.29-rc7-git2/arch/sparc/include/asm/ioctl.h.BAD vanilla-2.6.29-rc7-git2/arch/sparc/include/asm/ioctl.h ---- vanilla-2.6.29-rc7-git2/arch/sparc/include/asm/ioctl.h.BAD 2009-03-09 17:01:32.000000000 -0400 -+++ vanilla-2.6.29-rc7-git2/arch/sparc/include/asm/ioctl.h 2009-03-09 16:52:27.000000000 -0400 -@@ -41,6 +41,17 @@ - ((nr) << _IOC_NRSHIFT) | \ - ((size) << _IOC_SIZESHIFT)) - -+#ifdef __KERNEL__ -+/* provoke compile error for invalid uses of size argument */ -+extern unsigned int __invalid_size_argument_for_IOC; -+#define _IOC_TYPECHECK(t) \ -+ ((sizeof(t) == sizeof(t[1]) && \ -+ sizeof(t) < (1 << _IOC_SIZEBITS)) ? \ -+ sizeof(t) : __invalid_size_argument_for_IOC) -+#else -+#define _IOC_TYPECHECK(t) (sizeof(t)) -+#endif -+ - #define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) - #define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) - #define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) diff --git a/linux-2.6.30-no-pcspkr-modalias.patch b/linux-2.6.30-no-pcspkr-modalias.patch index c703b8844..439269cef 100644 --- a/linux-2.6.30-no-pcspkr-modalias.patch +++ b/linux-2.6.30-no-pcspkr-modalias.patch @@ -1,11 +1,12 @@ -diff -up linux-2.6.30.noarch/drivers/input/misc/pcspkr.c.jx linux-2.6.30.noarch/drivers/input/misc/pcspkr.c ---- linux-2.6.30.noarch/drivers/input/misc/pcspkr.c.jx 2009-07-28 16:54:44.000000000 -0400 -+++ linux-2.6.30.noarch/drivers/input/misc/pcspkr.c 2009-07-28 16:59:36.000000000 -0400 -@@ -23,7 +23,6 @@ +diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c +index 34f4d2e..3e40c70 100644 +--- a/drivers/input/misc/pcspkr.c ++++ b/drivers/input/misc/pcspkr.c +@@ -24,7 +24,6 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("PC Speaker beeper driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pcspkr"); - #if defined(CONFIG_MIPS) || defined(CONFIG_X86) - /* Use the global PIT lock ! */ + static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) + { diff --git a/lis3-improve-handling-of-null-rate.patch b/lis3-improve-handling-of-null-rate.patch new file mode 100644 index 000000000..98512564a --- /dev/null +++ b/lis3-improve-handling-of-null-rate.patch @@ -0,0 +1,79 @@ +>From 56fb161a9ca0129f8e266e4dbe79346552ff8089 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=89ric=20Piel?= +Date: Thu, 3 Nov 2011 16:22:40 +0100 +Subject: [PATCH] lis3: Improve handling of null rate +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When obtaining a rate of 0, we would disable the device supposely +because it seems to behave incorectly. It actually only comes from the +fact that the device is off and on lis3dc it's reflected in the rate. +So handle this nicely by just waiting a safe time, and then using the +device as normally. + +Signed-off-by: ??ric Piel +--- + drivers/misc/lis3lv02d/lis3lv02d.c | 16 ++++++++-------- + 1 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c +index 35c67e0..42dce2a 100644 +--- a/drivers/misc/lis3lv02d/lis3lv02d.c ++++ b/drivers/misc/lis3lv02d/lis3lv02d.c +@@ -188,7 +188,8 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z) + /* conversion btw sampling rate and the register values */ + static int lis3_12_rates[4] = {40, 160, 640, 2560}; + static int lis3_8_rates[2] = {100, 400}; +-static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000}; ++/* LIS3DC: 0 = power off, above 9 = undefined */ ++static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000, -1, -1, -1, -1, -1, -1}; + + /* ODR is Output Data Rate */ + static int lis3lv02d_get_odr(struct lis3lv02d *lis3) +@@ -202,12 +203,11 @@ static int lis3lv02d_get_odr(struct lis3lv02d *lis3) + return lis3->odrs[(ctrl >> shift)]; + } + +-static int lis3lv02d_get_pwron_wait(struct lis3lv02d *lis3) ++static int lis3lv02d_wait_pwron(struct lis3lv02d *lis3) + { + int div = lis3lv02d_get_odr(lis3); +- +- if (WARN_ONCE(div == 0, "device returned spurious data")) +- return -ENXIO; ++ if (div <= 0) ++ div = 1; /* maximum delay */ + + /* LIS3 power on delay is quite long */ + msleep(lis3->pwron_delay / div); +@@ -274,7 +274,7 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3]) + + lis3->read(lis3, ctlreg, ®); + lis3->write(lis3, ctlreg, (reg | selftest)); +- ret = lis3lv02d_get_pwron_wait(lis3); ++ ret = lis3lv02d_wait_pwron(lis3); + if (ret) + goto fail; + +@@ -285,7 +285,7 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3]) + + /* back to normal settings */ + lis3->write(lis3, ctlreg, reg); +- ret = lis3lv02d_get_pwron_wait(lis3); ++ ret = lis3lv02d_wait_pwron(lis3); + if (ret) + goto fail; + +@@ -397,7 +397,7 @@ int lis3lv02d_poweron(struct lis3lv02d *lis3) + lis3->write(lis3, CTRL_REG2, reg); + } + +- err = lis3lv02d_get_pwron_wait(lis3); ++ err = lis3lv02d_wait_pwron(lis3); + if (err) + return err; + +-- +1.7.7.1 + diff --git a/mac80211-fix-rx-key-NULL-ptr-deref-in-promiscuous-mode.patch b/mac80211-fix-rx-key-NULL-ptr-deref-in-promiscuous-mode.patch new file mode 100644 index 000000000..abacee637 --- /dev/null +++ b/mac80211-fix-rx-key-NULL-ptr-deref-in-promiscuous-mode.patch @@ -0,0 +1,47 @@ +Since: + +commit 816c04fe7ef01dd9649f5ccfe796474db8708be5 +Author: Christian Lamparter +Date: Sat Apr 30 15:24:30 2011 +0200 + + mac80211: consolidate MIC failure report handling + +is possible to that we dereference rx->key == NULL when driver set +RX_FLAG_MMIC_STRIPPED and not RX_FLAG_IV_STRIPPED and we are in +promiscuous mode. This happen with rt73usb and rt61pci at least. + +Before the commit we always check rx->key against NULL, so I assume +fix should be done in mac80211 (also mic_fail path has similar check). + +References: +https://bugzilla.redhat.com/show_bug.cgi?id=769766 +http://rt2x00.serialmonkey.com/pipermail/users_rt2x00.serialmonkey.com/2012-January/004395.html + +Cc: stable@vger.kernel.org # 3.0+ +Reported-by: Stuart D Gathman +Reported-by: Kai Wohlfahrt +Signed-off-by: Stanislaw Gruszka +--- + net/mac80211/wpa.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c +index 93aab07..422b798 100644 +--- a/net/mac80211/wpa.c ++++ b/net/mac80211/wpa.c +@@ -106,7 +106,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) + if (status->flag & RX_FLAG_MMIC_ERROR) + goto mic_fail; + +- if (!(status->flag & RX_FLAG_IV_STRIPPED)) ++ if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key) + goto update_iv; + + return RX_CONTINUE; +-- +1.7.1 + +-- +To unsubscribe from this list: send the line "unsubscribe linux-wireless" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html \ No newline at end of file diff --git a/macvtap-zerocopy-validate-vector-length.patch b/macvtap-zerocopy-validate-vector-length.patch new file mode 100644 index 000000000..3ac31e4b6 --- /dev/null +++ b/macvtap-zerocopy-validate-vector-length.patch @@ -0,0 +1,25 @@ +Currently we do not validate the vector length before calling +get_user_pages_fast(), host stack would be easily overflowed by +malicious guest driver who give us a descriptor with length greater +than MAX_SKB_FRAGS. Solve this problem by checking the free entries +before trying to pin user pages. + +Signed-off-by: Jason Wang +--- + drivers/net/macvtap.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c +index 7cb2684..d197a78 100644 +--- a/drivers/net/macvtap.c ++++ b/drivers/net/macvtap.c +@@ -527,6 +527,8 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from, + } + base = (unsigned long)from->iov_base + offset1; + size = ((base & ~PAGE_MASK) + len + ~PAGE_MASK) >> PAGE_SHIFT; ++ if (i + size >= MAX_SKB_FRAGS) ++ return -EFAULT; + num_pages = get_user_pages_fast(base, size, 0, &page[i]); + if ((num_pages != size) || + (num_pages > MAX_SKB_FRAGS - skb_shinfo(skb)->nr_frags)) + diff --git a/mcelog-rcu-splat.patch b/mcelog-rcu-splat.patch new file mode 100644 index 000000000..12c1fe3ea --- /dev/null +++ b/mcelog-rcu-splat.patch @@ -0,0 +1,15 @@ +diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c +index f22a9f7..f525f99 100644 +--- a/arch/x86/kernel/cpu/mcheck/mce.c ++++ b/arch/x86/kernel/cpu/mcheck/mce.c +@@ -191,7 +191,7 @@ static void drain_mcelog_buffer(void) + { + unsigned int next, i, prev = 0; + +- next = rcu_dereference_check_mce(mcelog.next); ++ next = ACCESS_ONCE(mcelog.next); + + do { + struct mce *m; + + \ No newline at end of file diff --git a/md-dont-delay-reboot-by-1-second-if-no-MD-devices.patch b/md-dont-delay-reboot-by-1-second-if-no-MD-devices.patch new file mode 100644 index 000000000..0ce4896de --- /dev/null +++ b/md-dont-delay-reboot-by-1-second-if-no-MD-devices.patch @@ -0,0 +1,110 @@ +Path: news.gmane.org!not-for-mail +From: "Daniel P. Berrange" +Newsgroups: gmane.linux.raid,gmane.linux.kernel +Subject: [PATCH] md: don't delay reboot by 1 second if no MD devices exist +Date: Fri, 23 Sep 2011 10:40:45 +0100 +Lines: 65 +Approved: news@gmane.org +Message-ID: <1316770845-18171-1-git-send-email-berrange@redhat.com> +NNTP-Posting-Host: lo.gmane.org +X-Trace: dough.gmane.org 1316770900 21954 80.91.229.12 (23 Sep 2011 09:41:40 GMT) +X-Complaints-To: usenet@dough.gmane.org +NNTP-Posting-Date: Fri, 23 Sep 2011 09:41:40 +0000 (UTC) +Cc: linux-raid@vger.kernel.org, linux-kernel@vger.kernel.org, + "Daniel P. Berrange" +To: Neil Brown +Original-X-From: linux-raid-owner@vger.kernel.org Fri Sep 23 11:41:35 2011 +Return-path: +Envelope-to: linux-raid@lo.gmane.org +Original-Received: from vger.kernel.org ([209.132.180.67]) + by lo.gmane.org with esmtp (Exim 4.69) + (envelope-from ) + id 1R72GD-0001vh-7L + for linux-raid@lo.gmane.org; Fri, 23 Sep 2011 11:41:33 +0200 +Original-Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand + id S1752806Ab1IWJlT (ORCPT ); + Fri, 23 Sep 2011 05:41:19 -0400 +Original-Received: from mx1.redhat.com ([209.132.183.28]:18969 "EHLO mx1.redhat.com" + rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP + id S1752669Ab1IWJlS (ORCPT ); + Fri, 23 Sep 2011 05:41:18 -0400 +Original-Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) + by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p8N9fGuK005549 + (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); + Fri, 23 Sep 2011 05:41:16 -0400 +Original-Received: from t500wlan.home.berrange.com.com (vpn1-7-26.ams2.redhat.com [10.36.7.26]) + by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p8N9fDFC018631; + Fri, 23 Sep 2011 05:41:14 -0400 +X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 +Original-Sender: linux-raid-owner@vger.kernel.org +Precedence: bulk +List-ID: +X-Mailing-List: linux-raid@vger.kernel.org +Xref: news.gmane.org gmane.linux.raid:35508 gmane.linux.kernel:1194566 +Archived-At: + +From: "Daniel P. Berrange" + +The md_notify_reboot() method includes a call to mdelay(1000), +to deal with "exotic SCSI devices" which are too volatile on +reboot. The delay is unconditional. Even if the machine does +not have any block devices, let alone MD devices, the kernel +shutdown sequence is slowed down. + +1 second does not matter much with physical hardware, but with +certain virtualization use cases any wasted time in the bootup +& shutdown sequence counts for alot. + +* drivers/md/md.c: md_notify_reboot() - only impose a delay if + there was at least one MD device to be stopped during reboot + +Signed-off-by: Daniel P. Berrange +--- + drivers/md/md.c | 8 ++++++-- + 1 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/md/md.c b/drivers/md/md.c +index 5404b22..ef7ad8d 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -8059,12 +8059,13 @@ static int md_notify_reboot(struct notifier_block *this, + { + struct list_head *tmp; + mddev_t *mddev; ++ int need_delay = 0; + + if ((code == SYS_DOWN) || (code == SYS_HALT) || (code == SYS_POWER_OFF)) { + + printk(KERN_INFO "md: stopping all md devices.\n"); + +- for_each_mddev(mddev, tmp) ++ for_each_mddev(mddev, tmp) { + if (mddev_trylock(mddev)) { + /* Force a switch to readonly even array + * appears to still be in use. Hence +@@ -8073,13 +8074,16 @@ static int md_notify_reboot(struct notifier_block *this, + md_set_readonly(mddev, 100); + mddev_unlock(mddev); + } ++ need_delay = 1; ++ } + /* + * certain more exotic SCSI devices are known to be + * volatile wrt too early system reboots. While the + * right place to handle this issue is the given + * driver, we do want to have a safe RAID driver ... + */ +- mdelay(1000*1); ++ if (need_delay) ++ mdelay(1000*1); + } + return NOTIFY_DONE; + } +-- +1.7.6.2 + +-- +To unsubscribe from this list: send the line "unsubscribe linux-raid" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html + diff --git a/mm-pmd_read_atomic-fix-32bit-PAE-pmd-walk-vs-pmd_populate-SMP-race-condition.patch b/mm-pmd_read_atomic-fix-32bit-PAE-pmd-walk-vs-pmd_populate-SMP-race-condition.patch new file mode 100644 index 000000000..49ff98a62 --- /dev/null +++ b/mm-pmd_read_atomic-fix-32bit-PAE-pmd-walk-vs-pmd_populate-SMP-race-condition.patch @@ -0,0 +1,272 @@ +Path: news.gmane.org!not-for-mail +From: Andrea Arcangeli +Newsgroups: gmane.linux.kernel.mm +Subject: [PATCH] mm: pmd_read_atomic: fix 32bit PAE pmd walk vs pmd_populate SMP race condition +Date: Thu, 24 May 2012 01:39:01 +0200 +Lines: 208 +Approved: news@gmane.org +Message-ID: <1337816341-30743-1-git-send-email-aarcange@redhat.com> +References: <20120518230028.GF32479@redhat.com> +NNTP-Posting-Host: plane.gmane.org +X-Trace: dough.gmane.org 1337816354 18906 80.91.229.3 (23 May 2012 23:39:14 GMT) +X-Complaints-To: usenet@dough.gmane.org +NNTP-Posting-Date: Wed, 23 May 2012 23:39:14 +0000 (UTC) +Cc: Andrew Morton , Mel Gorman , + Hugh Dickins , Larry Woodman , + Petr Matousek , + Ulrich Obergfell , Rik van Riel +To: linux-mm@kvack.org +Original-X-From: owner-linux-mm@kvack.org Thu May 24 01:39:12 2012 +Return-path: +Envelope-to: glkm-linux-mm-2@m.gmane.org +Original-Received: from kanga.kvack.org ([205.233.56.17]) + by plane.gmane.org with esmtp (Exim 4.69) + (envelope-from ) + id 1SXL94-0002ub-3P + for glkm-linux-mm-2@m.gmane.org; Thu, 24 May 2012 01:39:10 +0200 +Original-Received: by kanga.kvack.org (Postfix) + id 1684A6B0083; Wed, 23 May 2012 19:39:09 -0400 (EDT) +Delivered-To: linux-mm-outgoing@kvack.org +Original-Received: by kanga.kvack.org (Postfix, from userid 40) + id 080DD6B0092; Wed, 23 May 2012 19:39:08 -0400 (EDT) +X-Original-To: int-list-linux-mm@kvack.org +Delivered-To: int-list-linux-mm@kvack.org +Original-Received: by kanga.kvack.org (Postfix, from userid 63042) + id C84046B00E7; Wed, 23 May 2012 19:39:08 -0400 (EDT) +X-Original-To: linux-mm@kvack.org +Delivered-To: linux-mm@kvack.org +Original-Received: from psmtp.com (na3sys010amx119.postini.com [74.125.245.119]) + by kanga.kvack.org (Postfix) with SMTP id 0B2DC6B0083 + for ; Wed, 23 May 2012 19:39:07 -0400 (EDT) +Original-Received: from mx1.redhat.com ([209.132.183.28]) (using TLSv1) by na3sys010amx119.postini.com ([74.125.244.10]) with SMTP; + Wed, 23 May 2012 18:39:08 CDT +Original-Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) + by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q4NNd3dP002492 + (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); + Wed, 23 May 2012 19:39:03 -0400 +Original-Received: from random.random (ovpn-113-72.phx2.redhat.com [10.3.113.72]) + by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q4NNd1P7012233; + Wed, 23 May 2012 19:39:02 -0400 +In-Reply-To: <20120518230028.GF32479@redhat.com> +X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 +X-pstn-neptune: 0/0/0.00/0 +X-pstn-levels: (S:99.90000/99.90000 CV:99.9000 FC:95.5390 LC:95.5390 R:95.9108 P:95.9108 M:97.0282 C:98.6951 ) +X-pstn-dkim: 0 skipped:not-enabled +X-pstn-settings: 3 (1.0000:1.0000) s cv gt3 gt2 gt1 r p m c +X-pstn-addresses: from [db-null] +X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.2 +Original-Sender: owner-linux-mm@kvack.org +Precedence: bulk +X-Loop: owner-majordomo@kvack.org +List-ID: +Xref: news.gmane.org gmane.linux.kernel.mm:78936 +Archived-At: + +When holding the mmap_sem for reading, pmd_offset_map_lock should only +run on a pmd_t that has been read atomically from the pmdp +pointer, otherwise we may read only half of it leading to this crash. + +PID: 11679 TASK: f06e8000 CPU: 3 COMMAND: "do_race_2_panic" + #0 [f06a9dd8] crash_kexec at c049b5ec + #1 [f06a9e2c] oops_end at c083d1c2 + #2 [f06a9e40] no_context at c0433ded + #3 [f06a9e64] bad_area_nosemaphore at c043401a + #4 [f06a9e6c] __do_page_fault at c0434493 + #5 [f06a9eec] do_page_fault at c083eb45 + #6 [f06a9f04] error_code (via page_fault) at c083c5d5 + EAX: 01fb470c EBX: fff35000 ECX: 00000003 EDX: 00000100 EBP: + 00000000 + DS: 007b ESI: 9e201000 ES: 007b EDI: 01fb4700 GS: 00e0 + CS: 0060 EIP: c083bc14 ERR: ffffffff EFLAGS: 00010246 + #7 [f06a9f38] _spin_lock at c083bc14 + #8 [f06a9f44] sys_mincore at c0507b7d + #9 [f06a9fb0] system_call at c083becd + start len + EAX: ffffffda EBX: 9e200000 ECX: 00001000 EDX: 6228537f + DS: 007b ESI: 00000000 ES: 007b EDI: 003d0f00 + SS: 007b ESP: 62285354 EBP: 62285388 GS: 0033 + CS: 0073 EIP: 00291416 ERR: 000000da EFLAGS: 00000286 + +This should be a longstanding bug affecting x86 32bit PAE without +THP. Only archs with 64bit large pmd_t and 32bit unsigned long should +be affected. + +With THP enabled the barrier() in +pmd_none_or_trans_huge_or_clear_bad() would partly hide the bug when +the pmd transition from none to stable, by forcing a re-read of the +*pmd in pmd_offset_map_lock, but when THP is enabled a new set of +problem arises by the fact could then transition freely in any of the +none, pmd_trans_huge or pmd_trans_stable states. So making the barrier +in pmd_none_or_trans_huge_or_clear_bad() unconditional isn't good idea +and it would be a flakey solution. + +This should be fully fixed by introducing a pmd_read_atomic that reads +the pmd in order with THP disabled, or by reading the pmd atomically +with cmpxchg8b with THP enabled. + +Luckily this new race condition only triggers in the places that must +already be covered by pmd_none_or_trans_huge_or_clear_bad() so the fix +is localized there but this bug is not related to THP. + +NOTE: this can trigger on x86 32bit systems with PAE enabled with more +than 4G of ram, otherwise the high part of the pmd will never risk to +be truncated because it would be zero at all times, in turn so hiding +the SMP race. + +This bug was discovered and fully debugged by Ulrich, quote: + +---- +[..] +pmd_none_or_trans_huge_or_clear_bad() loads the content of edx and +eax. + + 496 static inline int pmd_none_or_trans_huge_or_clear_bad(pmd_t + *pmd) + 497 { + 498 /* depend on compiler for an atomic pmd read */ + 499 pmd_t pmdval = *pmd; + + // edi = pmd pointer +0xc0507a74 : mov 0x8(%esp),%edi +... + // edx = PTE page table high address +0xc0507a84 : mov 0x4(%edi),%edx +... + // eax = PTE page table low address +0xc0507a8e : mov (%edi),%eax + +[..] + +Please note that the PMD is not read atomically. These are two "mov" +instructions where the high order bits of the PMD entry are fetched +first. Hence, the above machine code is prone to the following race. + +- The PMD entry {high|low} is 0x0000000000000000. + The "mov" at 0xc0507a84 loads 0x00000000 into edx. + +- A page fault (on another CPU) sneaks in between the two "mov" + instructions and instantiates the PMD. + +- The PMD entry {high|low} is now 0x00000003fda38067. + The "mov" at 0xc0507a8e loads 0xfda38067 into eax. +---- + +Reported-by: Ulrich Obergfell +Signed-off-by: Andrea Arcangeli +--- + arch/x86/include/asm/pgtable-3level.h | 50 +++++++++++++++++++++++++++++++++ + include/asm-generic/pgtable.h | 22 +++++++++++++- + 2 files changed, 70 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/include/asm/pgtable-3level.h b/arch/x86/include/asm/pgtable-3level.h +index effff47..43876f1 100644 +--- a/arch/x86/include/asm/pgtable-3level.h ++++ b/arch/x86/include/asm/pgtable-3level.h +@@ -31,6 +31,56 @@ static inline void native_set_pte(pte_t *ptep, pte_t pte) + ptep->pte_low = pte.pte_low; + } + ++#define pmd_read_atomic pmd_read_atomic ++/* ++ * pte_offset_map_lock on 32bit PAE kernels was reading the pmd_t with ++ * a "*pmdp" dereference done by gcc. Problem is, in certain places ++ * where pte_offset_map_lock is called, concurrent page faults are ++ * allowed, if the mmap_sem is hold for reading. An example is mincore ++ * vs page faults vs MADV_DONTNEED. On the page fault side ++ * pmd_populate rightfully does a set_64bit, but if we're reading the ++ * pmd_t with a "*pmdp" on the mincore side, a SMP race can happen ++ * because gcc will not read the 64bit of the pmd atomically. To fix ++ * this all places running pmd_offset_map_lock() while holding the ++ * mmap_sem in read mode, shall read the pmdp pointer using this ++ * function to know if the pmd is null nor not, and in turn to know if ++ * they can run pmd_offset_map_lock or pmd_trans_huge or other pmd ++ * operations. ++ * ++ * Without THP if the mmap_sem is hold for reading, the ++ * pmd can only transition from null to not null while pmd_read_atomic runs. ++ * So there's no need of literally reading it atomically. ++ * ++ * With THP if the mmap_sem is hold for reading, the pmd can become ++ * THP or null or point to a pte (and in turn become "stable") at any ++ * time under pmd_read_atomic, so it's mandatory to read it atomically ++ * with cmpxchg8b. ++ */ ++#ifndef CONFIG_TRANSPARENT_HUGEPAGE ++static inline pmd_t pmd_read_atomic(pmd_t *pmdp) ++{ ++ pmdval_t ret; ++ u32 *tmp = (u32 *)pmdp; ++ ++ ret = (pmdval_t) (*tmp); ++ if (ret) { ++ /* ++ * If the low part is null, we must not read the high part ++ * or we can end up with a partial pmd. ++ */ ++ smp_rmb(); ++ ret |= ((pmdval_t)*(tmp + 1)) << 32; ++ } ++ ++ return (pmd_t) { ret }; ++} ++#else /* CONFIG_TRANSPARENT_HUGEPAGE */ ++static inline pmd_t pmd_read_atomic(pmd_t *pmdp) ++{ ++ return (pmd_t) { atomic64_read((atomic64_t *)pmdp) }; ++} ++#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ ++ + static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte) + { + set_64bit((unsigned long long *)(ptep), native_pte_val(pte)); +diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h +index 125c54e..fa596d9 100644 +--- a/include/asm-generic/pgtable.h ++++ b/include/asm-generic/pgtable.h +@@ -446,6 +446,18 @@ static inline int pmd_write(pmd_t pmd) + #endif /* __HAVE_ARCH_PMD_WRITE */ + #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + ++#ifndef pmd_read_atomic ++static inline pmd_t pmd_read_atomic(pmd_t *pmdp) ++{ ++ /* ++ * Depend on compiler for an atomic pmd read. NOTE: this is ++ * only going to work, if the pmdval_t isn't larger than ++ * an unsigned long. ++ */ ++ return *pmdp; ++} ++#endif ++ + /* + * This function is meant to be used by sites walking pagetables with + * the mmap_sem hold in read mode to protect against MADV_DONTNEED and +@@ -459,11 +471,17 @@ static inline int pmd_write(pmd_t pmd) + * undefined so behaving like if the pmd was none is safe (because it + * can return none anyway). The compiler level barrier() is critically + * important to compute the two checks atomically on the same pmdval. ++ * ++ * For 32bit kernels with a 64bit large pmd_t this automatically takes ++ * care of reading the pmd atomically to avoid SMP race conditions ++ * against pmd_populate() when the mmap_sem is hold for reading by the ++ * caller (a special atomic read not done by "gcc" as in the generic ++ * version above, is also needed when THP is disabled because the page ++ * fault can populate the pmd from under us). + */ + static inline int pmd_none_or_trans_huge_or_clear_bad(pmd_t *pmd) + { +- /* depend on compiler for an atomic pmd read */ +- pmd_t pmdval = *pmd; ++ pmd_t pmdval = pmd_read_atomic(pmd); + /* + * The barrier will stabilize the pmdval in a register or on + * the stack so that it will stop changing under the code. + +-- +To unsubscribe, send a message with 'unsubscribe linux-mm' in +the body to majordomo@kvack.org. For more info on Linux MM, +see: http://www.linux-mm.org/ . +Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ +Don't email: email@kvack.org + diff --git a/neuter_intel_microcode_load.patch b/neuter_intel_microcode_load.patch deleted file mode 100644 index 2766e439d..000000000 --- a/neuter_intel_microcode_load.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c -index ebd193e..c57024a 100644 ---- a/arch/x86/kernel/microcode_intel.c -+++ b/arch/x86/kernel/microcode_intel.c -@@ -453,9 +453,18 @@ static void microcode_fini_cpu(int cpu) - uci->mc = NULL; - } - -+/* we don't ship the broken out files... -+ * instead, we'll just fail here, and load it with microcode_ctl -+ */ -+static enum ucode_state noop_request_microcode_fw(int cpu, -+ struct device *device) -+{ -+ return UCODE_NFOUND; -+} -+ - static struct microcode_ops microcode_intel_ops = { - .request_microcode_user = request_microcode_user, -- .request_microcode_fw = request_microcode_fw, -+ .request_microcode_fw = noop_request_microcode_fw, - .collect_cpu_info = collect_cpu_info, - .apply_microcode = apply_microcode, - .microcode_fini_cpu = microcode_fini_cpu, diff --git a/nfs-oops-getacl.patch b/nfs-oops-getacl.patch new file mode 100644 index 000000000..53e599dd4 --- /dev/null +++ b/nfs-oops-getacl.patch @@ -0,0 +1,96 @@ +From 331818f1c468a24e581aedcbe52af799366a9dfe Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Fri, 3 Feb 2012 18:30:53 -0500 +Subject: [PATCH] NFSv4: Fix an Oops in the NFSv4 getacl code + +Commit bf118a342f10dafe44b14451a1392c3254629a1f (NFSv4: include bitmap +in nfsv4 get acl data) introduces the 'acl_scratch' page for the case +where we may need to decode multi-page data. However it fails to take +into account the fact that the variable may be NULL (for the case where +we're not doing multi-page decode), and it also attaches it to the +encoding xdr_stream rather than the decoding one. + +The immediate result is an Oops in nfs4_xdr_enc_getacl due to the +call to page_address() with a NULL page pointer. + +Signed-off-by: Trond Myklebust +Cc: Andy Adamson +Cc: stable@vger.kernel.org +--- + fs/nfs/nfs4proc.c | 8 ++++---- + fs/nfs/nfs4xdr.c | 5 ++++- + include/linux/nfs_xdr.h | 2 +- + 3 files changed, 9 insertions(+), 6 deletions(-) + +diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c +index f0c849c..d202e04 100644 +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -3575,8 +3575,8 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu + } + if (npages > 1) { + /* for decoding across pages */ +- args.acl_scratch = alloc_page(GFP_KERNEL); +- if (!args.acl_scratch) ++ res.acl_scratch = alloc_page(GFP_KERNEL); ++ if (!res.acl_scratch) + goto out_free; + } + args.acl_len = npages * PAGE_SIZE; +@@ -3612,8 +3612,8 @@ out_free: + for (i = 0; i < npages; i++) + if (pages[i]) + __free_page(pages[i]); +- if (args.acl_scratch) +- __free_page(args.acl_scratch); ++ if (res.acl_scratch) ++ __free_page(res.acl_scratch); + return ret; + } + +diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c +index 95e92e4..33bd8d0 100644 +--- a/fs/nfs/nfs4xdr.c ++++ b/fs/nfs/nfs4xdr.c +@@ -2522,7 +2522,6 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr, + + xdr_inline_pages(&req->rq_rcv_buf, replen << 2, + args->acl_pages, args->acl_pgbase, args->acl_len); +- xdr_set_scratch_buffer(xdr, page_address(args->acl_scratch), PAGE_SIZE); + + encode_nops(&hdr); + } +@@ -6032,6 +6031,10 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr, + struct compound_hdr hdr; + int status; + ++ if (res->acl_scratch != NULL) { ++ void *p = page_address(res->acl_scratch); ++ xdr_set_scratch_buffer(xdr, p, PAGE_SIZE); ++ } + status = decode_compound_hdr(xdr, &hdr); + if (status) + goto out; +diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h +index a764cef..d6ba9a1 100644 +--- a/include/linux/nfs_xdr.h ++++ b/include/linux/nfs_xdr.h +@@ -614,7 +614,6 @@ struct nfs_getaclargs { + size_t acl_len; + unsigned int acl_pgbase; + struct page ** acl_pages; +- struct page * acl_scratch; + struct nfs4_sequence_args seq_args; + }; + +@@ -624,6 +623,7 @@ struct nfs_getaclres { + size_t acl_len; + size_t acl_data_offset; + int acl_flags; ++ struct page * acl_scratch; + struct nfs4_sequence_res seq_res; + }; + +-- +1.7.4.1 + diff --git a/nx-emu-remove-cpuinitdata-for-disable_nx-on-x86_32.patch b/nx-emu-remove-cpuinitdata-for-disable_nx-on-x86_32.patch new file mode 100644 index 000000000..38c96caed --- /dev/null +++ b/nx-emu-remove-cpuinitdata-for-disable_nx-on-x86_32.patch @@ -0,0 +1,47 @@ +>From e540f21852043a4d8e8cf5e505607909d0ab0f51 Mon Sep 17 00:00:00 2001 +From: Tim Gardner +Date: Thu, 29 Mar 2012 06:21:01 -0600 +Subject: [PATCH] UBUNTU: SAUCE: disable_nx should not be in __cpuinitdata + section for X86_32 + +I noticed a section mismatch warning while building 3.2.0-20.33 for X86_32. + + AR arch/x86/lib/lib.a + LD vmlinux.o + MODPOST vmlinux.o +WARNING: vmlinux.o(.text+0x187833): Section mismatch in reference from the function load_elf_binary() to the variable .cpuinit.data:disable_nx +The function load_elf_binary() references +the variable __cpuinitdata disable_nx. +This is often because load_elf_binary lacks a __cpuinitdata +annotation or the annotation of disable_nx is wrong. + +load_elf_binary() is definitely called after initialization. + +This code was added by 'UBUNTU: ubuntu: nx-emu - i386: NX emulation', so +this is not an upstream problem. + +Reported-by: Tetsuo Handa +Signed-off-by: Tim Gardner +--- + arch/x86/mm/setup_nx.c | 4 ++++ + 1 files changed, 4 insertions(+), 0 deletions(-) + +diff --git a/arch/x86/mm/setup_nx.c b/arch/x86/mm/setup_nx.c +index 90c9eff3..89fd946 100644 +--- a/arch/x86/mm/setup_nx.c ++++ b/arch/x86/mm/setup_nx.c +@@ -6,7 +6,11 @@ + #include + #include + ++#ifdef CONFIG_X86_32 ++int disable_nx; /* referenced by load_elf_binary() */ ++#else + int disable_nx __cpuinitdata; ++#endif + + /* + * noexec = on|off +-- +1.7.9.1 + diff --git a/pci-_osc-supported-field-should-contain-supported-features-not-enabled-ones.patch b/pci-_osc-supported-field-should-contain-supported-features-not-enabled-ones.patch deleted file mode 100644 index 0baffd639..000000000 --- a/pci-_osc-supported-field-should-contain-supported-features-not-enabled-ones.patch +++ /dev/null @@ -1,66 +0,0 @@ -commit 885c252ffb059dc493200bdb981bdd21cabe4442 -Author: Matthew Garrett -Date: Thu Dec 9 18:31:59 2010 -0500 - - PCI: _OSC "supported" field should contain supported features, not enabled ones - - From testing with Windows, the call to the PCI root _OSC method includes - the full set of features supported by the operating system even if the - hardware has already indicated that it doesn't support ASPM or MSI. - https://bugzilla.redhat.com/show_bug.cgi?id=638912 is a case where making - the _OSC call will incorrectly configure the chipset unless the supported - field has bits 1, 2 and 4 set. Rework the functionality to ensure that - we match this behaviour. - - Signed-off-by: Matthew Garrett - -diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c -index 96668ad..afb5d08 100644 ---- a/drivers/acpi/pci_root.c -+++ b/drivers/acpi/pci_root.c -@@ -450,7 +450,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) - struct acpi_pci_root *root; - acpi_handle handle; - struct acpi_device *child; -- u32 flags, base_flags; -+ u32 flags; - - root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); - if (!root) -@@ -498,10 +498,15 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) - device->driver_data = root; - - /* -- * All supported architectures that use ACPI have support for -- * PCI domains, so we indicate this in _OSC support capabilities. -+ * Indicate support for various _OSC capabilities. These match -+ * what the operating system supports, not what the hardware supports, -+ * so they shouldn't be conditional on functionality that's been -+ * blacklisted - */ -- flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT; -+ flags = OSC_EXT_PCI_CONFIG_SUPPORT | OSC_ACTIVE_STATE_PWR_SUPPORT | -+ OSC_CLOCK_PWR_CAPABILITY_SUPPORT | -+ OSC_PCI_SEGMENT_GROUPS_SUPPORT | OSC_MSI_SUPPORT; -+ - acpi_pci_osc_support(root, flags); - - /* -@@ -555,17 +560,6 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) - list_for_each_entry(child, &device->children, node) - acpi_pci_bridge_scan(child); - -- /* Indicate support for various _OSC capabilities. */ -- if (pci_ext_cfg_avail(root->bus->self)) -- flags |= OSC_EXT_PCI_CONFIG_SUPPORT; -- if (pcie_aspm_enabled()) -- flags |= OSC_ACTIVE_STATE_PWR_SUPPORT | -- OSC_CLOCK_PWR_CAPABILITY_SUPPORT; -- if (pci_msi_enabled()) -- flags |= OSC_MSI_SUPPORT; -- if (flags != base_flags) -- acpi_pci_osc_support(root, flags); -- - pci_acpi_add_bus_pm_notifier(device, root->bus); - if (device->wakeup.flags.run_wake) - device_set_run_wake(root->bus->bridge, true); diff --git a/perf-gcc460-build-fixes.patch b/perf-gcc460-build-fixes.patch deleted file mode 100644 index 074ab6f20..000000000 --- a/perf-gcc460-build-fixes.patch +++ /dev/null @@ -1,227 +0,0 @@ -From linux-kernel-owner@vger.kernel.org Mon Jan 24 11:13:12 2011 -Date: Mon, 24 Jan 2011 11:13:04 -0500 -From: Kyle McMartin -To: mingo@redhat.com -Cc: linux-kernel@vger.kernel.org, acme@redhat.com -Subject: [PATCH] perf: fix gcc 4.6.0 issues with tools/perf -Message-ID: <20110124161304.GK27353@bombadil.infradead.org> - -Hi Ingo, - -GCC 4.6.0 in Fedora rawhide turned up some compile errors in tools/perf -due to the -Werror=unused-but-set-variable flag. - -I've gone through and annotated some of the assignments that had side -effects (ie: return value from a function) with the __used annotation, -and in some cases, just removed unused code. - -In a few cases, we were assigning something useful, but not using it in -later parts of the function. - -regards, Kyle - -kyle@dreadnought:~/src% gcc --version -gcc (GCC) 4.6.0 20110122 (Red Hat 4.6.0-0.3) - ---- - - bench/sched-pipe.c | 2 +- - builtin-sched.c | 12 +++--------- - builtin-top.c | 5 +---- - util/header.c | 2 +- - util/hist.c | 3 --- - util/scripting-engines/trace-event-python.c | 3 +-- - util/symbol.c | 4 ++-- - util/trace-event-parse.c | 2 +- - util/ui/browsers/map.c | 2 +- - 9 files changed, 11 insertions(+), 24 deletions(-) - -diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c -index d9ab3ce..0c7454f 100644 ---- a/tools/perf/bench/sched-pipe.c -+++ b/tools/perf/bench/sched-pipe.c -@@ -55,7 +55,7 @@ int bench_sched_pipe(int argc, const char **argv, - * discarding returned value of read(), write() - * causes error in building environment for perf - */ -- int ret, wait_stat; -+ int __used ret, wait_stat; - pid_t pid, retpid; - - argc = parse_options(argc, argv, options, -diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c -index 29e7ffd..f9e304f 100644 ---- a/tools/perf/builtin-sched.c -+++ b/tools/perf/builtin-sched.c -@@ -369,11 +369,6 @@ static void - process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom) - { - int ret = 0; -- u64 now; -- long long delta; -- -- now = get_nsecs(); -- delta = start_time + atom->timestamp - now; - - switch (atom->type) { - case SCHED_EVENT_RUN: -@@ -562,7 +557,7 @@ static void wait_for_tasks(void) - - static void run_one_test(void) - { -- u64 T0, T1, delta, avg_delta, fluct, std_dev; -+ u64 T0, T1, delta, avg_delta, fluct; - - T0 = get_nsecs(); - wait_for_tasks(); -@@ -578,7 +573,6 @@ static void run_one_test(void) - else - fluct = delta - avg_delta; - sum_fluct += fluct; -- std_dev = sum_fluct / nr_runs / sqrt(nr_runs); - if (!run_avg) - run_avg = delta; - run_avg = (run_avg*9 + delta)/10; -@@ -799,7 +793,7 @@ replay_switch_event(struct trace_switch_event *switch_event, - u64 timestamp, - struct thread *thread __used) - { -- struct task_desc *prev, *next; -+ struct task_desc *prev, __used *next; - u64 timestamp0; - s64 delta; - -@@ -1404,7 +1398,7 @@ map_switch_event(struct trace_switch_event *switch_event, - u64 timestamp, - struct thread *thread __used) - { -- struct thread *sched_out, *sched_in; -+ struct thread *sched_out __used, *sched_in; - int new_shortname; - u64 timestamp0; - s64 delta; -diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c -index 05344c6..373cfc0 100644 ---- a/tools/perf/builtin-top.c -+++ b/tools/perf/builtin-top.c -@@ -182,7 +182,6 @@ static int parse_source(struct sym_entry *syme) - FILE *file; - char command[PATH_MAX*2]; - const char *path; -- u64 len; - - if (!syme) - return -1; -@@ -211,8 +210,6 @@ static int parse_source(struct sym_entry *syme) - } - path = map->dso->long_name; - -- len = sym->end - sym->start; -- - sprintf(command, - "objdump --start-address=%#0*" PRIx64 " --stop-address=%#0*" PRIx64 " -dS %s", - BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start), -@@ -1295,7 +1292,7 @@ static int __cmd_top(void) - { - pthread_t thread; - struct perf_evsel *counter; -- int i, ret; -+ int i, ret __used; - /* - * FIXME: perf_session__new should allow passing a O_MMAP, so that all this - * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. -diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c -index 989fa2d..c0e5019 100644 ---- a/tools/perf/util/header.c -+++ b/tools/perf/util/header.c -@@ -1139,7 +1139,7 @@ int event__synthesize_tracing_data(int fd, struct list_head *pattrs, - { - event_t ev; - ssize_t size = 0, aligned_size = 0, padding; -- int err = 0; -+ int err __used = 0; - - memset(&ev, 0, sizeof(ev)); - -diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c -index c749ba6..a01a33d 100644 ---- a/tools/perf/util/hist.c -+++ b/tools/perf/util/hist.c -@@ -1091,7 +1091,6 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head, - char command[PATH_MAX * 2]; - FILE *file; - int err = 0; -- u64 len; - char symfs_filename[PATH_MAX]; - - if (filename) { -@@ -1136,8 +1135,6 @@ fallback: - filename, sym->name, map->unmap_ip(map, sym->start), - map->unmap_ip(map, sym->end)); - -- len = sym->end - sym->start; -- - pr_debug("annotating [%p] %30s : [%p] %30s\n", - dso, dso->long_name, sym, sym->name); - -diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c -index c6d9933..2040b85 100644 ---- a/tools/perf/util/scripting-engines/trace-event-python.c -+++ b/tools/perf/util/scripting-engines/trace-event-python.c -@@ -248,8 +248,7 @@ static void python_process_event(int cpu, void *data, - context = PyCObject_FromVoidPtr(scripting_context, NULL); - - PyTuple_SetItem(t, n++, PyString_FromString(handler_name)); -- PyTuple_SetItem(t, n++, -- PyCObject_FromVoidPtr(scripting_context, NULL)); -+ PyTuple_SetItem(t, n++, context); - - if (handler) { - PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); -diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c -index 15ccfba..52e82cf 100644 ---- a/tools/perf/util/symbol.c -+++ b/tools/perf/util/symbol.c -@@ -1517,8 +1517,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) - symbol_conf.symfs, self->long_name); - break; - case DSO__ORIG_GUEST_KMODULE: -- if (map->groups && map->groups->machine) -- root_dir = map->groups->machine->root_dir; -+ if (map->groups && machine) -+ root_dir = machine->root_dir; - else - root_dir = ""; - snprintf(name, size, "%s%s%s", symbol_conf.symfs, -diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c -index 73a0222..d8e622d 100644 ---- a/tools/perf/util/trace-event-parse.c -+++ b/tools/perf/util/trace-event-parse.c -@@ -153,7 +153,7 @@ void parse_proc_kallsyms(char *file, unsigned int size __unused) - char *next = NULL; - char *addr_str; - char ch; -- int ret; -+ int ret __used; - int i; - - line = strtok_r(file, "\n", &next); -diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c -index e35437d..3788cad 100644 ---- a/tools/perf/util/ui/browsers/map.c -+++ b/tools/perf/util/ui/browsers/map.c -@@ -40,7 +40,7 @@ static int ui_entry__read(const char *title, char *bf, size_t size, int width) - out_free_form: - newtPopWindow(); - newtFormDestroy(form); -- return 0; -+ return err; - } - - struct map_browser { --- -To unsubscribe from this list: send the line "unsubscribe linux-kernel" in -the body of a message to majordomo@vger.kernel.org -More majordomo info at http://vger.kernel.org/majordomo-info.html -Please read the FAQ at http://www.tux.org/lkml/ - diff --git a/platform-fix-samsung-brightness-min-max-calculations.patch b/platform-fix-samsung-brightness-min-max-calculations.patch new file mode 100644 index 000000000..6a2c3b8cc --- /dev/null +++ b/platform-fix-samsung-brightness-min-max-calculations.patch @@ -0,0 +1,56 @@ +From: Jason Stubbs +Subject: [PATCH] platform: fix samsung brightness min/max calculations + +For one of the SABI configs, the valid brightness levels are 1 through 8 with +0 being reserved for the BIOS. To make the range 0-based, the driver is meant +to offset values to/from userspace by 1 giving valid levels of 0 through 7. + +Currently, the driver is reporting a max brightness of 8 and doing the offset +the wrong way such that setting a brightness of 8 will set as 7 in hardware +while setting a brightness of 0 will attempt (and fail) to set as -1 in +hardware. + +This patch fixes these calculations as well as a potential miscalculation due +to an assumption of min_brightness being either 0 or 1. + +Signed-off-by: Jason Stubbs +Signed-off-by: Chuck Ebbert + +--- +Originally posted here, context fixed to apply to 3.0/3.1: +[ https://lkml.org/lkml/2011/5/11/548 ] + +diff a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c +--- a/drivers/platform/x86/samsung-laptop.c ++++ b/drivers/platform/x86/samsung-laptop.c +@@ -370,15 +370,17 @@ static u8 read_brightness(void) + &sretval); + if (!retval) { + user_brightness = sretval.retval[0]; +- if (user_brightness != 0) ++ if (user_brightness > sabi_config->min_brightness) + user_brightness -= sabi_config->min_brightness; ++ else ++ user_brightness = 0; + } + return user_brightness; + } + + static void set_brightness(u8 user_brightness) + { +- u8 user_level = user_brightness - sabi_config->min_brightness; ++ u8 user_level = user_brightness + sabi_config->min_brightness; + + sabi_set_command(sabi_config->commands.set_brightness, user_level); + } +@@ -802,7 +804,8 @@ static int __init samsung_init(void) + /* create a backlight device to talk to this one */ + memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; +- props.max_brightness = sabi_config->max_brightness; ++ props.max_brightness = sabi_config->max_brightness - ++ sabi_config->min_brightness; + backlight_device = backlight_device_register("samsung", &sdev->dev, + NULL, &backlight_ops, + &props); +_ diff --git a/prevent-runtime-conntrack-changes.patch b/prevent-runtime-conntrack-changes.patch deleted file mode 100644 index 59d62f3de..000000000 --- a/prevent-runtime-conntrack-changes.patch +++ /dev/null @@ -1,74 +0,0 @@ -Jon Masters correctly points out that conntrack hash sizes -(nf_conntrack_htable_size) are global (not per-netns) and -modifiable at runtime via /sys/module/nf_conntrack/hashsize . - -Steps to reproduce: - clone(CLONE_NEWNET) - [grow /sys/module/nf_conntrack/hashsize] - exit() - -At netns exit we are going to scan random memory for conntracks to be killed. - -Apparently there is a code which deals with hashtable resize for -init_net (and it was there befode netns conntrack code), so prohibit -hashsize modification if there is more than one netns exists. - -To change hashtable sizes, you need to reload module. - -Expectation hashtable size was simply glued to a variable with no code -to rehash expectations, so it was a bug to allow writing to it. -Make "expect_hashsize" readonly. - -This is temporarily until we figure out what to do. - -Signed-off-by: Alexey Dobriyan -Cc: stable@kernel.org ---- - - net/netfilter/nf_conntrack_core.c | 15 +++++++++++++++ - net/netfilter/nf_conntrack_expect.c | 2 +- - 2 files changed, 16 insertions(+), 1 deletion(-) - ---- a/net/netfilter/nf_conntrack_core.c -+++ b/net/netfilter/nf_conntrack_core.c -@@ -21,6 +21,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -1198,6 +1199,20 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) - if (!nf_conntrack_htable_size) - return param_set_uint(val, kp); - -+ { -+ struct net *net; -+ unsigned int nr; -+ -+ nr = 0; -+ rtnl_lock(); -+ for_each_net(net) -+ nr++; -+ rtnl_unlock(); -+ /* init_net always exists */ -+ if (nr != 1) -+ return -EINVAL; -+ } -+ - hashsize = simple_strtoul(val, NULL, 0); - if (!hashsize) - return -EINVAL; ---- a/net/netfilter/nf_conntrack_expect.c -+++ b/net/netfilter/nf_conntrack_expect.c -@@ -569,7 +569,7 @@ static void exp_proc_remove(struct net *net) - #endif /* CONFIG_PROC_FS */ - } - --module_param_named(expect_hashsize, nf_ct_expect_hsize, uint, 0600); -+module_param_named(expect_hashsize, nf_ct_expect_hsize, uint, 0400); - - int nf_conntrack_expect_init(struct net *net) - { - diff --git a/quite-apm.patch b/quite-apm.patch new file mode 100644 index 000000000..c38511c41 --- /dev/null +++ b/quite-apm.patch @@ -0,0 +1,13 @@ +diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c +index a46bd38..416dd12 100644 +--- a/arch/x86/kernel/apm_32.c ++++ b/arch/x86/kernel/apm_32.c +@@ -903,7 +903,7 @@ static void apm_cpu_idle(void) + unsigned int jiffies_since_last_check = jiffies - last_jiffies; + unsigned int bucket; + +- WARN_ONCE(1, "deprecated apm_cpu_idle will be deleted in 2012"); ++ printk_once(KERN_INFO "deprecated apm_cpu_idle will be deleted in 2012"); + recalc: + if (jiffies_since_last_check > IDLE_CALC_LIMIT) { + use_apm_idle = 0; diff --git a/rcu-reintroduce-missing-calls.patch b/rcu-reintroduce-missing-calls.patch new file mode 100644 index 000000000..b887df750 --- /dev/null +++ b/rcu-reintroduce-missing-calls.patch @@ -0,0 +1,632 @@ +commit cf778b00e96df6d64f8e21b8395d1f8a859ecdc7 +Author: Eric Dumazet +Date: Thu Jan 12 04:41:32 2012 +0000 + + net: reintroduce missing rcu_assign_pointer() calls + + commit a9b3cd7f32 (rcu: convert uses of rcu_assign_pointer(x, NULL) to + RCU_INIT_POINTER) did a lot of incorrect changes, since it did a + complete conversion of rcu_assign_pointer(x, y) to RCU_INIT_POINTER(x, + y). + + We miss needed barriers, even on x86, when y is not NULL. + + Signed-off-by: Eric Dumazet + CC: Stephen Hemminger + CC: Paul E. McKenney + Signed-off-by: David S. Miller + +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/core/netpoll.c linux-3.2.net/net/core/netpoll.c +--- linux-3.2.noarch/net/core/netpoll.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/core/netpoll.c 2012-01-20 16:50:26.761797929 -0500 +@@ -763,7 +763,7 @@ int __netpoll_setup(struct netpoll *np) + } + + /* last thing to do is link it to the net device structure */ +- RCU_INIT_POINTER(ndev->npinfo, npinfo); ++ rcu_assign_pointer(ndev->npinfo, npinfo); + + return 0; + +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/core/net-sysfs.c linux-3.2.net/net/core/net-sysfs.c +--- linux-3.2.noarch/net/core/net-sysfs.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/core/net-sysfs.c 2012-01-20 16:50:26.730798974 -0500 +@@ -990,9 +990,9 @@ static ssize_t store_xps_map(struct netd + nonempty = 1; + } + +- if (nonempty) +- RCU_INIT_POINTER(dev->xps_maps, new_dev_maps); +- else { ++ if (nonempty) { ++ rcu_assign_pointer(dev->xps_maps, new_dev_maps); ++ } else { + kfree(new_dev_maps); + RCU_INIT_POINTER(dev->xps_maps, NULL); + } +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/decnet/dn_dev.c linux-3.2.net/net/decnet/dn_dev.c +--- linux-3.2.noarch/net/decnet/dn_dev.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/decnet/dn_dev.c 2012-01-20 16:50:26.793796851 -0500 +@@ -388,7 +388,7 @@ static int dn_dev_insert_ifa(struct dn_d + } + + ifa->ifa_next = dn_db->ifa_list; +- RCU_INIT_POINTER(dn_db->ifa_list, ifa); ++ rcu_assign_pointer(dn_db->ifa_list, ifa); + + dn_ifaddr_notify(RTM_NEWADDR, ifa); + blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa); +@@ -1093,7 +1093,7 @@ static struct dn_dev *dn_dev_create(stru + + memcpy(&dn_db->parms, p, sizeof(struct dn_dev_parms)); + +- RCU_INIT_POINTER(dev->dn_ptr, dn_db); ++ rcu_assign_pointer(dev->dn_ptr, dn_db); + dn_db->dev = dev; + init_timer(&dn_db->timer); + +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/ipv4/devinet.c linux-3.2.net/net/ipv4/devinet.c +--- linux-3.2.noarch/net/ipv4/devinet.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/ipv4/devinet.c 2012-01-20 16:50:26.829795637 -0500 +@@ -258,7 +258,7 @@ static struct in_device *inetdev_init(st + ip_mc_up(in_dev); + + /* we can receive as soon as ip_ptr is set -- do this last */ +- RCU_INIT_POINTER(dev->ip_ptr, in_dev); ++ rcu_assign_pointer(dev->ip_ptr, in_dev); + out: + return in_dev; + out_kfree: +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/ipv4/fib_trie.c linux-3.2.net/net/ipv4/fib_trie.c +--- linux-3.2.noarch/net/ipv4/fib_trie.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/ipv4/fib_trie.c 2012-01-20 16:50:26.865794425 -0500 +@@ -205,7 +205,7 @@ static inline struct tnode *node_parent_ + return (struct tnode *)(parent & ~NODE_TYPE_MASK); + } + +-/* Same as RCU_INIT_POINTER ++/* Same as rcu_assign_pointer + * but that macro() assumes that value is a pointer. + */ + static inline void node_set_parent(struct rt_trie_node *node, struct tnode *ptr) +@@ -529,7 +529,7 @@ static void tnode_put_child_reorg(struct + if (n) + node_set_parent(n, tn); + +- RCU_INIT_POINTER(tn->child[i], n); ++ rcu_assign_pointer(tn->child[i], n); + } + + #define MAX_WORK 10 +@@ -1015,7 +1015,7 @@ static void trie_rebalance(struct trie * + + tp = node_parent((struct rt_trie_node *) tn); + if (!tp) +- RCU_INIT_POINTER(t->trie, (struct rt_trie_node *)tn); ++ rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn); + + tnode_free_flush(); + if (!tp) +@@ -1027,7 +1027,7 @@ static void trie_rebalance(struct trie * + if (IS_TNODE(tn)) + tn = (struct tnode *)resize(t, (struct tnode *)tn); + +- RCU_INIT_POINTER(t->trie, (struct rt_trie_node *)tn); ++ rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn); + tnode_free_flush(); + } + +@@ -1164,7 +1164,7 @@ static struct list_head *fib_insert_node + put_child(t, (struct tnode *)tp, cindex, + (struct rt_trie_node *)tn); + } else { +- RCU_INIT_POINTER(t->trie, (struct rt_trie_node *)tn); ++ rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn); + tp = tn; + } + } +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/ipv4/igmp.c linux-3.2.net/net/ipv4/igmp.c +--- linux-3.2.noarch/net/ipv4/igmp.c 2012-01-20 16:22:44.923961882 -0500 ++++ linux-3.2.net/net/ipv4/igmp.c 2012-01-20 16:50:26.898793315 -0500 +@@ -1244,7 +1244,7 @@ void ip_mc_inc_group(struct in_device *i + + im->next_rcu = in_dev->mc_list; + in_dev->mc_count++; +- RCU_INIT_POINTER(in_dev->mc_list, im); ++ rcu_assign_pointer(in_dev->mc_list, im); + + #ifdef CONFIG_IP_MULTICAST + igmpv3_del_delrec(in_dev, im->multiaddr); +@@ -1816,7 +1816,7 @@ int ip_mc_join_group(struct sock *sk , s + iml->next_rcu = inet->mc_list; + iml->sflist = NULL; + iml->sfmode = MCAST_EXCLUDE; +- RCU_INIT_POINTER(inet->mc_list, iml); ++ rcu_assign_pointer(inet->mc_list, iml); + ip_mc_inc_group(in_dev, addr); + err = 0; + done: +@@ -2003,7 +2003,7 @@ int ip_mc_source(int add, int omode, str + atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); + kfree_rcu(psl, rcu); + } +- RCU_INIT_POINTER(pmc->sflist, newpsl); ++ rcu_assign_pointer(pmc->sflist, newpsl); + psl = newpsl; + } + rv = 1; /* > 0 for insert logic below if sl_count is 0 */ +@@ -2106,7 +2106,7 @@ int ip_mc_msfilter(struct sock *sk, stru + } else + (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, + 0, NULL, 0); +- RCU_INIT_POINTER(pmc->sflist, newpsl); ++ rcu_assign_pointer(pmc->sflist, newpsl); + pmc->sfmode = msf->imsf_fmode; + err = 0; + done: +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/ipv4/ipip.c linux-3.2.net/net/ipv4/ipip.c +--- linux-3.2.noarch/net/ipv4/ipip.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/ipv4/ipip.c 2012-01-20 16:50:26.916792707 -0500 +@@ -231,7 +231,7 @@ static void ipip_tunnel_unlink(struct ip + (iter = rtnl_dereference(*tp)) != NULL; + tp = &iter->next) { + if (t == iter) { +- RCU_INIT_POINTER(*tp, t->next); ++ rcu_assign_pointer(*tp, t->next); + break; + } + } +@@ -241,8 +241,8 @@ static void ipip_tunnel_link(struct ipip + { + struct ip_tunnel __rcu **tp = ipip_bucket(ipn, t); + +- RCU_INIT_POINTER(t->next, rtnl_dereference(*tp)); +- RCU_INIT_POINTER(*tp, t); ++ rcu_assign_pointer(t->next, rtnl_dereference(*tp)); ++ rcu_assign_pointer(*tp, t); + } + + static struct ip_tunnel * ipip_tunnel_locate(struct net *net, +@@ -792,7 +792,7 @@ static int __net_init ipip_fb_tunnel_ini + return -ENOMEM; + + dev_hold(dev); +- RCU_INIT_POINTER(ipn->tunnels_wc[0], tunnel); ++ rcu_assign_pointer(ipn->tunnels_wc[0], tunnel); + return 0; + } + +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/ipv4/ipmr.c linux-3.2.net/net/ipv4/ipmr.c +--- linux-3.2.noarch/net/ipv4/ipmr.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/ipv4/ipmr.c 2012-01-20 16:50:26.946791698 -0500 +@@ -1225,7 +1225,7 @@ int ip_mroute_setsockopt(struct sock *sk + + ret = ip_ra_control(sk, 1, mrtsock_destruct); + if (ret == 0) { +- RCU_INIT_POINTER(mrt->mroute_sk, sk); ++ rcu_assign_pointer(mrt->mroute_sk, sk); + IPV4_DEVCONF_ALL(net, MC_FORWARDING)++; + } + rtnl_unlock(); +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/ipv6/addrconf.c linux-3.2.net/net/ipv6/addrconf.c +--- linux-3.2.noarch/net/ipv6/addrconf.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/ipv6/addrconf.c 2012-01-20 16:50:26.977790653 -0500 +@@ -429,7 +429,7 @@ static struct inet6_dev * ipv6_add_dev(s + ndev->tstamp = jiffies; + addrconf_sysctl_register(ndev); + /* protected by rtnl_lock */ +- RCU_INIT_POINTER(dev->ip6_ptr, ndev); ++ rcu_assign_pointer(dev->ip6_ptr, ndev); + + /* Join all-node multicast group */ + ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes); +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/ipv6/ip6_tunnel.c linux-3.2.net/net/ipv6/ip6_tunnel.c +--- linux-3.2.noarch/net/ipv6/ip6_tunnel.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/ipv6/ip6_tunnel.c 2012-01-20 16:50:27.004789743 -0500 +@@ -218,8 +218,8 @@ ip6_tnl_link(struct ip6_tnl_net *ip6n, s + { + struct ip6_tnl __rcu **tp = ip6_tnl_bucket(ip6n, &t->parms); + +- RCU_INIT_POINTER(t->next , rtnl_dereference(*tp)); +- RCU_INIT_POINTER(*tp, t); ++ rcu_assign_pointer(t->next , rtnl_dereference(*tp)); ++ rcu_assign_pointer(*tp, t); + } + + /** +@@ -237,7 +237,7 @@ ip6_tnl_unlink(struct ip6_tnl_net *ip6n, + (iter = rtnl_dereference(*tp)) != NULL; + tp = &iter->next) { + if (t == iter) { +- RCU_INIT_POINTER(*tp, t->next); ++ rcu_assign_pointer(*tp, t->next); + break; + } + } +@@ -1450,7 +1450,7 @@ static int __net_init ip6_fb_tnl_dev_ini + + t->parms.proto = IPPROTO_IPV6; + dev_hold(dev); +- RCU_INIT_POINTER(ip6n->tnls_wc[0], t); ++ rcu_assign_pointer(ip6n->tnls_wc[0], t); + return 0; + } + +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/ipv6/raw.c linux-3.2.net/net/ipv6/raw.c +--- linux-3.2.noarch/net/ipv6/raw.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/ipv6/raw.c 2012-01-20 16:50:27.022789138 -0500 +@@ -131,7 +131,7 @@ static mh_filter_t __rcu *mh_filter __re + + int rawv6_mh_filter_register(mh_filter_t filter) + { +- RCU_INIT_POINTER(mh_filter, filter); ++ rcu_assign_pointer(mh_filter, filter); + return 0; + } + EXPORT_SYMBOL(rawv6_mh_filter_register); +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/ipv6/sit.c linux-3.2.net/net/ipv6/sit.c +--- linux-3.2.noarch/net/ipv6/sit.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/ipv6/sit.c 2012-01-20 16:50:27.042788464 -0500 +@@ -182,7 +182,7 @@ static void ipip6_tunnel_unlink(struct s + (iter = rtnl_dereference(*tp)) != NULL; + tp = &iter->next) { + if (t == iter) { +- RCU_INIT_POINTER(*tp, t->next); ++ rcu_assign_pointer(*tp, t->next); + break; + } + } +@@ -192,8 +192,8 @@ static void ipip6_tunnel_link(struct sit + { + struct ip_tunnel __rcu **tp = ipip6_bucket(sitn, t); + +- RCU_INIT_POINTER(t->next, rtnl_dereference(*tp)); +- RCU_INIT_POINTER(*tp, t); ++ rcu_assign_pointer(t->next, rtnl_dereference(*tp)); ++ rcu_assign_pointer(*tp, t); + } + + static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) +@@ -393,7 +393,7 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t + p->addr = a->addr; + p->flags = a->flags; + t->prl_count++; +- RCU_INIT_POINTER(t->prl, p); ++ rcu_assign_pointer(t->prl, p); + out: + return err; + } +@@ -1177,7 +1177,7 @@ static int __net_init ipip6_fb_tunnel_in + if (!dev->tstats) + return -ENOMEM; + dev_hold(dev); +- RCU_INIT_POINTER(sitn->tunnels_wc[0], tunnel); ++ rcu_assign_pointer(sitn->tunnels_wc[0], tunnel); + return 0; + } + +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/mac80211/agg-rx.c linux-3.2.net/net/mac80211/agg-rx.c +--- linux-3.2.noarch/net/mac80211/agg-rx.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/mac80211/agg-rx.c 2012-01-20 16:50:27.058787924 -0500 +@@ -326,7 +326,7 @@ void ieee80211_process_addba_request(str + status = WLAN_STATUS_SUCCESS; + + /* activate it for RX */ +- RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx); ++ rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx); + + if (timeout) + mod_timer(&tid_agg_rx->session_timer, TU_TO_EXP_TIME(timeout)); +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/mac80211/cfg.c linux-3.2.net/net/mac80211/cfg.c +--- linux-3.2.noarch/net/mac80211/cfg.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/mac80211/cfg.c 2012-01-20 16:50:27.082787116 -0500 +@@ -575,7 +575,7 @@ static int ieee80211_config_beacon(struc + + sdata->vif.bss_conf.dtim_period = new->dtim_period; + +- RCU_INIT_POINTER(sdata->u.ap.beacon, new); ++ rcu_assign_pointer(sdata->u.ap.beacon, new); + + synchronize_rcu(); + +@@ -922,7 +922,7 @@ static int ieee80211_change_station(stru + return -EBUSY; + } + +- RCU_INIT_POINTER(vlansdata->u.vlan.sta, sta); ++ rcu_assign_pointer(vlansdata->u.vlan.sta, sta); + } + + sta->sdata = vlansdata; +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/mac80211/ibss.c linux-3.2.net/net/mac80211/ibss.c +--- linux-3.2.noarch/net/mac80211/ibss.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/mac80211/ibss.c 2012-01-20 16:50:27.102786444 -0500 +@@ -184,7 +184,7 @@ static void __ieee80211_sta_join_ibss(st + *pos++ = 0; /* U-APSD no in use */ + } + +- RCU_INIT_POINTER(ifibss->presp, skb); ++ rcu_assign_pointer(ifibss->presp, skb); + + sdata->vif.bss_conf.beacon_int = beacon_int; + sdata->vif.bss_conf.basic_rates = basic_rates; +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/mac80211/sta_info.c linux-3.2.net/net/mac80211/sta_info.c +--- linux-3.2.noarch/net/mac80211/sta_info.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/mac80211/sta_info.c 2012-01-20 16:50:27.131785466 -0500 +@@ -73,7 +73,7 @@ static int sta_info_hash_del(struct ieee + if (!s) + return -ENOENT; + if (s == sta) { +- RCU_INIT_POINTER(local->sta_hash[STA_HASH(sta->sta.addr)], ++ rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], + s->hnext); + return 0; + } +@@ -83,7 +83,7 @@ static int sta_info_hash_del(struct ieee + s = rcu_dereference_protected(s->hnext, + lockdep_is_held(&local->sta_lock)); + if (rcu_access_pointer(s->hnext)) { +- RCU_INIT_POINTER(s->hnext, sta->hnext); ++ rcu_assign_pointer(s->hnext, sta->hnext); + return 0; + } + +@@ -232,7 +232,7 @@ static void sta_info_hash_add(struct iee + struct sta_info *sta) + { + sta->hnext = local->sta_hash[STA_HASH(sta->sta.addr)]; +- RCU_INIT_POINTER(local->sta_hash[STA_HASH(sta->sta.addr)], sta); ++ rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta); + } + + static void sta_unblock(struct work_struct *wk) +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/netfilter/nf_conntrack_core.c linux-3.2.net/net/netfilter/nf_conntrack_core.c +--- linux-3.2.noarch/net/netfilter/nf_conntrack_core.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/netfilter/nf_conntrack_core.c 2012-01-20 16:50:27.169784186 -0500 +@@ -776,7 +776,7 @@ init_conntrack(struct net *net, struct n + if (exp->helper) { + help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); + if (help) +- RCU_INIT_POINTER(help->helper, exp->helper); ++ rcu_assign_pointer(help->helper, exp->helper); + } + + #ifdef CONFIG_NF_CONNTRACK_MARK +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/netfilter/nf_conntrack_ecache.c linux-3.2.net/net/netfilter/nf_conntrack_ecache.c +--- linux-3.2.noarch/net/netfilter/nf_conntrack_ecache.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/netfilter/nf_conntrack_ecache.c 2012-01-20 16:50:27.187783578 -0500 +@@ -91,7 +91,7 @@ int nf_conntrack_register_notifier(struc + ret = -EBUSY; + goto out_unlock; + } +- RCU_INIT_POINTER(net->ct.nf_conntrack_event_cb, new); ++ rcu_assign_pointer(net->ct.nf_conntrack_event_cb, new); + mutex_unlock(&nf_ct_ecache_mutex); + return ret; + +@@ -128,7 +128,7 @@ int nf_ct_expect_register_notifier(struc + ret = -EBUSY; + goto out_unlock; + } +- RCU_INIT_POINTER(net->ct.nf_expect_event_cb, new); ++ rcu_assign_pointer(net->ct.nf_expect_event_cb, new); + mutex_unlock(&nf_ct_ecache_mutex); + return ret; + +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/netfilter/nf_conntrack_extend.c linux-3.2.net/net/netfilter/nf_conntrack_extend.c +--- linux-3.2.noarch/net/netfilter/nf_conntrack_extend.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/netfilter/nf_conntrack_extend.c 2012-01-20 16:50:27.204783008 -0500 +@@ -169,7 +169,7 @@ int nf_ct_extend_register(struct nf_ct_e + before updating alloc_size */ + type->alloc_size = ALIGN(sizeof(struct nf_ct_ext), type->align) + + type->len; +- RCU_INIT_POINTER(nf_ct_ext_types[type->id], type); ++ rcu_assign_pointer(nf_ct_ext_types[type->id], type); + update_alloc_size(type); + out: + mutex_unlock(&nf_ct_ext_type_mutex); +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/netfilter/nf_conntrack_helper.c linux-3.2.net/net/netfilter/nf_conntrack_helper.c +--- linux-3.2.noarch/net/netfilter/nf_conntrack_helper.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/netfilter/nf_conntrack_helper.c 2012-01-20 16:50:27.227782232 -0500 +@@ -145,7 +145,7 @@ int __nf_ct_try_assign_helper(struct nf_ + memset(&help->help, 0, sizeof(help->help)); + } + +- RCU_INIT_POINTER(help->helper, helper); ++ rcu_assign_pointer(help->helper, helper); + out: + return ret; + } +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/netfilter/nf_conntrack_netlink.c linux-3.2.net/net/netfilter/nf_conntrack_netlink.c +--- linux-3.2.noarch/net/netfilter/nf_conntrack_netlink.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/netfilter/nf_conntrack_netlink.c 2012-01-20 16:50:27.271780750 -0500 +@@ -1163,7 +1163,7 @@ ctnetlink_change_helper(struct nf_conn * + return -EOPNOTSUPP; + } + +- RCU_INIT_POINTER(help->helper, helper); ++ rcu_assign_pointer(help->helper, helper); + + return 0; + } +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/netfilter/nf_log.c linux-3.2.net/net/netfilter/nf_log.c +--- linux-3.2.noarch/net/netfilter/nf_log.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/netfilter/nf_log.c 2012-01-20 16:50:27.280780448 -0500 +@@ -55,7 +55,7 @@ int nf_log_register(u_int8_t pf, struct + llog = rcu_dereference_protected(nf_loggers[pf], + lockdep_is_held(&nf_log_mutex)); + if (llog == NULL) +- RCU_INIT_POINTER(nf_loggers[pf], logger); ++ rcu_assign_pointer(nf_loggers[pf], logger); + } + + mutex_unlock(&nf_log_mutex); +@@ -92,7 +92,7 @@ int nf_log_bind_pf(u_int8_t pf, const st + mutex_unlock(&nf_log_mutex); + return -ENOENT; + } +- RCU_INIT_POINTER(nf_loggers[pf], logger); ++ rcu_assign_pointer(nf_loggers[pf], logger); + mutex_unlock(&nf_log_mutex); + return 0; + } +@@ -250,7 +250,7 @@ static int nf_log_proc_dostring(ctl_tabl + mutex_unlock(&nf_log_mutex); + return -ENOENT; + } +- RCU_INIT_POINTER(nf_loggers[tindex], logger); ++ rcu_assign_pointer(nf_loggers[tindex], logger); + mutex_unlock(&nf_log_mutex); + } else { + mutex_lock(&nf_log_mutex); +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/netfilter/nfnetlink.c linux-3.2.net/net/netfilter/nfnetlink.c +--- linux-3.2.noarch/net/netfilter/nfnetlink.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/netfilter/nfnetlink.c 2012-01-20 16:50:27.302779705 -0500 +@@ -59,7 +59,7 @@ int nfnetlink_subsys_register(const stru + nfnl_unlock(); + return -EBUSY; + } +- RCU_INIT_POINTER(subsys_table[n->subsys_id], n); ++ rcu_assign_pointer(subsys_table[n->subsys_id], n); + nfnl_unlock(); + + return 0; +@@ -210,7 +210,7 @@ static int __net_init nfnetlink_net_init + if (!nfnl) + return -ENOMEM; + net->nfnl_stash = nfnl; +- RCU_INIT_POINTER(net->nfnl, nfnl); ++ rcu_assign_pointer(net->nfnl, nfnl); + return 0; + } + +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/netfilter/nf_queue.c linux-3.2.net/net/netfilter/nf_queue.c +--- linux-3.2.noarch/net/netfilter/nf_queue.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/netfilter/nf_queue.c 2012-01-20 16:50:27.293780010 -0500 +@@ -40,7 +40,7 @@ int nf_register_queue_handler(u_int8_t p + else if (old) + ret = -EBUSY; + else { +- RCU_INIT_POINTER(queue_handler[pf], qh); ++ rcu_assign_pointer(queue_handler[pf], qh); + ret = 0; + } + mutex_unlock(&queue_handler_mutex); +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/netlabel/netlabel_domainhash.c linux-3.2.net/net/netlabel/netlabel_domainhash.c +--- linux-3.2.noarch/net/netlabel/netlabel_domainhash.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/netlabel/netlabel_domainhash.c 2012-01-20 16:50:27.311779402 -0500 +@@ -282,7 +282,7 @@ int __init netlbl_domhsh_init(u32 size) + INIT_LIST_HEAD(&hsh_tbl->tbl[iter]); + + spin_lock(&netlbl_domhsh_lock); +- RCU_INIT_POINTER(netlbl_domhsh, hsh_tbl); ++ rcu_assign_pointer(netlbl_domhsh, hsh_tbl); + spin_unlock(&netlbl_domhsh_lock); + + return 0; +@@ -330,7 +330,7 @@ int netlbl_domhsh_add(struct netlbl_dom_ + &rcu_dereference(netlbl_domhsh)->tbl[bkt]); + } else { + INIT_LIST_HEAD(&entry->list); +- RCU_INIT_POINTER(netlbl_domhsh_def, entry); ++ rcu_assign_pointer(netlbl_domhsh_def, entry); + } + + if (entry->type == NETLBL_NLTYPE_ADDRSELECT) { +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/netlabel/netlabel_unlabeled.c linux-3.2.net/net/netlabel/netlabel_unlabeled.c +--- linux-3.2.noarch/net/netlabel/netlabel_unlabeled.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/netlabel/netlabel_unlabeled.c 2012-01-20 16:50:27.327778863 -0500 +@@ -354,7 +354,7 @@ static struct netlbl_unlhsh_iface *netlb + INIT_LIST_HEAD(&iface->list); + if (netlbl_unlhsh_rcu_deref(netlbl_unlhsh_def) != NULL) + goto add_iface_failure; +- RCU_INIT_POINTER(netlbl_unlhsh_def, iface); ++ rcu_assign_pointer(netlbl_unlhsh_def, iface); + } + spin_unlock(&netlbl_unlhsh_lock); + +@@ -1447,11 +1447,9 @@ int __init netlbl_unlabel_init(u32 size) + for (iter = 0; iter < hsh_tbl->size; iter++) + INIT_LIST_HEAD(&hsh_tbl->tbl[iter]); + +- rcu_read_lock(); + spin_lock(&netlbl_unlhsh_lock); +- RCU_INIT_POINTER(netlbl_unlhsh, hsh_tbl); ++ rcu_assign_pointer(netlbl_unlhsh, hsh_tbl); + spin_unlock(&netlbl_unlhsh_lock); +- rcu_read_unlock(); + + register_netdevice_notifier(&netlbl_unlhsh_netdev_notifier); + +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/phonet/af_phonet.c linux-3.2.net/net/phonet/af_phonet.c +--- linux-3.2.noarch/net/phonet/af_phonet.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/phonet/af_phonet.c 2012-01-20 16:50:27.345778258 -0500 +@@ -480,7 +480,7 @@ int __init_or_module phonet_proto_regist + if (proto_tab[protocol]) + err = -EBUSY; + else +- RCU_INIT_POINTER(proto_tab[protocol], pp); ++ rcu_assign_pointer(proto_tab[protocol], pp); + mutex_unlock(&proto_tab_lock); + + return err; +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/phonet/pn_dev.c linux-3.2.net/net/phonet/pn_dev.c +--- linux-3.2.noarch/net/phonet/pn_dev.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/phonet/pn_dev.c 2012-01-20 16:50:27.353777988 -0500 +@@ -390,7 +390,7 @@ int phonet_route_add(struct net_device * + daddr = daddr >> 2; + mutex_lock(&routes->lock); + if (routes->table[daddr] == NULL) { +- RCU_INIT_POINTER(routes->table[daddr], dev); ++ rcu_assign_pointer(routes->table[daddr], dev); + dev_hold(dev); + err = 0; + } +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/phonet/socket.c linux-3.2.net/net/phonet/socket.c +--- linux-3.2.noarch/net/phonet/socket.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/phonet/socket.c 2012-01-20 16:50:27.365777583 -0500 +@@ -680,7 +680,7 @@ int pn_sock_bind_res(struct sock *sk, u8 + mutex_lock(&resource_mutex); + if (pnres.sk[res] == NULL) { + sock_hold(sk); +- RCU_INIT_POINTER(pnres.sk[res], sk); ++ rcu_assign_pointer(pnres.sk[res], sk); + ret = 0; + } + mutex_unlock(&resource_mutex); +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/socket.c linux-3.2.net/net/socket.c +--- linux-3.2.noarch/net/socket.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/socket.c 2012-01-20 16:50:27.410776068 -0500 +@@ -2472,7 +2472,7 @@ int sock_register(const struct net_proto + lockdep_is_held(&net_family_lock))) + err = -EEXIST; + else { +- RCU_INIT_POINTER(net_families[ops->family], ops); ++ rcu_assign_pointer(net_families[ops->family], ops); + err = 0; + } + spin_unlock(&net_family_lock); +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/sunrpc/auth_gss/auth_gss.c linux-3.2.net/net/sunrpc/auth_gss/auth_gss.c +--- linux-3.2.noarch/net/sunrpc/auth_gss/auth_gss.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/sunrpc/auth_gss/auth_gss.c 2012-01-20 16:50:27.428775461 -0500 +@@ -122,7 +122,7 @@ gss_cred_set_ctx(struct rpc_cred *cred, + if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags)) + return; + gss_get_ctx(ctx); +- RCU_INIT_POINTER(gss_cred->gc_ctx, ctx); ++ rcu_assign_pointer(gss_cred->gc_ctx, ctx); + set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); + smp_mb__before_clear_bit(); + clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags); +diff -durpN '--exclude-from=/home/davej/.exclude' linux-3.2.noarch/net/xfrm/xfrm_user.c linux-3.2.net/net/xfrm/xfrm_user.c +--- linux-3.2.noarch/net/xfrm/xfrm_user.c 2012-01-04 18:55:44.000000000 -0500 ++++ linux-3.2.net/net/xfrm/xfrm_user.c 2012-01-20 16:50:27.449774754 -0500 +@@ -2927,7 +2927,7 @@ static int __net_init xfrm_user_net_init + if (nlsk == NULL) + return -ENOMEM; + net->xfrm.nlsk_stash = nlsk; /* Don't set to NULL */ +- RCU_INIT_POINTER(net->xfrm.nlsk, nlsk); ++ rcu_assign_pointer(net->xfrm.nlsk, nlsk); + return 0; + } + diff --git a/rt2x00_fix_MCU_request_failures.patch b/rt2x00_fix_MCU_request_failures.patch new file mode 100644 index 000000000..f7b8a6a4c --- /dev/null +++ b/rt2x00_fix_MCU_request_failures.patch @@ -0,0 +1,136 @@ +diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h +index 2571a2f..822f9e5 100644 +--- a/drivers/net/wireless/rt2x00/rt2800.h ++++ b/drivers/net/wireless/rt2x00/rt2800.h +@@ -1627,6 +1627,7 @@ struct mac_iveiv_entry { + + /* + * H2M_MAILBOX_CSR: Host-to-MCU Mailbox. ++ * CMD_TOKEN: Command id, 0xff disable status reporting + */ + #define H2M_MAILBOX_CSR 0x7010 + #define H2M_MAILBOX_CSR_ARG0 FIELD32(0x000000ff) +@@ -1636,6 +1637,8 @@ struct mac_iveiv_entry { + + /* + * H2M_MAILBOX_CID: ++ * Free slots contain 0xff. MCU will store command's token to lowest free slot. ++ * If all slots are occupied status will be dropped. + */ + #define H2M_MAILBOX_CID 0x7014 + #define H2M_MAILBOX_CID_CMD0 FIELD32(0x000000ff) +@@ -1645,6 +1648,7 @@ struct mac_iveiv_entry { + + /* + * H2M_MAILBOX_STATUS: ++ * Command status will be saved to same slot as command id. + */ + #define H2M_MAILBOX_STATUS 0x701c + +@@ -2259,6 +2263,12 @@ struct mac_iveiv_entry { + + /* + * MCU mailbox commands. ++ * MCU_SLEEP - go to power-save mode. ++ * arg1: 1: save as much power as possible, 0: save less power ++ * status: 1: success, 2: already asleep, ++ * 3: maybe MAC is busy so can't finish this task ++ * MCU_RADIO_OFF ++ * arg0: 0: do power-saving, NOT turn off radio + */ + #define MCU_SLEEP 0x30 + #define MCU_WAKEUP 0x31 +@@ -2279,7 +2289,9 @@ struct mac_iveiv_entry { + /* + * MCU mailbox tokens + */ +-#define TOKEN_WAKUP 3 ++#define TOKEN_SLEEP 1 ++#define TOKEN_RADIO_OFF 2 ++#define TOKEN_WAKEUP 3 + + /* + * DMA descriptor defines. +diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c +index dc88bae..9ac3017 100644 +--- a/drivers/net/wireless/rt2x00/rt2800pci.c ++++ b/drivers/net/wireless/rt2x00/rt2800pci.c +@@ -517,23 +517,6 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev) + } + } + +-static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev, +- enum dev_state state) +-{ +- if (state == STATE_AWAKE) { +- rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0x02); +- rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKUP); +- } else if (state == STATE_SLEEP) { +- rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, +- 0xffffffff); +- rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, +- 0xffffffff); +- rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0x01, 0xff, 0x01); +- } +- +- return 0; +-} +- + static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) + { +@@ -541,14 +524,20 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, + + switch (state) { + case STATE_RADIO_ON: +- /* +- * Before the radio can be enabled, the device first has +- * to be woken up. After that it needs a bit of time +- * to be fully awake and then the radio can be enabled. +- */ +- rt2800pci_set_state(rt2x00dev, STATE_AWAKE); +- msleep(1); ++ /* Initialise all registers and send MCU_BOOT_SIGNAL. */ + retval = rt2800pci_enable_radio(rt2x00dev); ++ ++ /* After resume MCU_BOOT_SIGNAL will trash those. */ ++ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); ++ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); ++ ++ /* Finish initialization procedure. */ ++ rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_RADIO_OFF, ++ 0xff, 0x02); ++ rt2800pci_mcu_status(rt2x00dev, TOKEN_RADIO_OFF); ++ ++ rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKEUP, 0, 0); ++ rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKEUP); + break; + case STATE_RADIO_OFF: + /* +@@ -556,7 +545,7 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, + * be put to sleep for powersaving. + */ + rt2800pci_disable_radio(rt2x00dev); +- rt2800pci_set_state(rt2x00dev, STATE_SLEEP); ++ rt2800pci_set_device_state(rt2x00dev, STATE_SLEEP); + break; + case STATE_RADIO_IRQ_ON: + case STATE_RADIO_IRQ_OFF: +@@ -565,8 +554,16 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, + case STATE_DEEP_SLEEP: + case STATE_SLEEP: + case STATE_STANDBY: ++ /* PCIe devices won't report status after SLEEP request. */ ++ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); ++ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); ++ rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_SLEEP, ++ 0xff, 0x01); ++ break; + case STATE_AWAKE: +- retval = rt2800pci_set_state(rt2x00dev, state); ++ rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKEUP, ++ 0, 0x02); ++ rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKEUP); + break; + default: + retval = -ENOTSUPP; diff --git a/rtl818x-fix-sleeping-function-called-from-invalid-context.patch b/rtl818x-fix-sleeping-function-called-from-invalid-context.patch new file mode 100644 index 000000000..141fcd201 --- /dev/null +++ b/rtl818x-fix-sleeping-function-called-from-invalid-context.patch @@ -0,0 +1,49 @@ +Fix: + +BUG: sleeping function called from invalid context at kernel/workqueue.c:2547 +in_atomic(): 1, irqs_disabled(): 0, pid: 629, name: wpa_supplicant +2 locks held by wpa_supplicant/629: + #0: (rtnl_mutex){+.+.+.}, at: [] rtnl_lock+0x14/0x20 + #1: (&trigger->leddev_list_lock){.+.?..}, at: [] led_trigger_event+0x21/0x80 +Pid: 629, comm: wpa_supplicant Not tainted 3.3.0-0.rc3.git5.1.fc17.i686 +Call Trace: + [] __might_sleep+0x126/0x1d0 + [] wait_on_work+0x2c/0x1d0 + [] __cancel_work_timer+0x6a/0x120 + [] cancel_delayed_work_sync+0x10/0x20 + [] rtl8187_led_brightness_set+0x82/0xf0 [rtl8187] + [] led_trigger_event+0x5c/0x80 + [] ieee80211_led_radio+0x1d/0x40 [mac80211] + [] ieee80211_stop_device+0x13/0x230 [mac80211] + +Removing _sync is ok, because if led_on work is currently running +it will be finished before led_off work start to perform, since +they are always queued on the same mac80211 local->workqueue. + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=795176 + +Signed-off-by: Stanislaw Gruszka +--- + drivers/net/wireless/rtl818x/rtl8187/leds.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/net/wireless/rtl818x/rtl8187/leds.c b/drivers/net/wireless/rtl818x/rtl8187/leds.c +index 2e0de2f..c2d5b49 100644 +--- a/drivers/net/wireless/rtl818x/rtl8187/leds.c ++++ b/drivers/net/wireless/rtl818x/rtl8187/leds.c +@@ -117,7 +117,7 @@ static void rtl8187_led_brightness_set(struct led_classdev *led_dev, + radio_on = true; + } else if (radio_on) { + radio_on = false; +- cancel_delayed_work_sync(&priv->led_on); ++ cancel_delayed_work(&priv->led_on); + ieee80211_queue_delayed_work(hw, &priv->led_off, 0); + } + } else if (radio_on) { +-- +1.7.1 + +-- +To unsubscribe from this list: send the line "unsubscribe linux-wireless" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html \ No newline at end of file diff --git a/runtime_pm_fixups.patch b/runtime_pm_fixups.patch deleted file mode 100644 index 1be6149d6..000000000 --- a/runtime_pm_fixups.patch +++ /dev/null @@ -1,138 +0,0 @@ -From 141d0d01ab292d4ea3a6d5e96b4048e10e68c1d3 Mon Sep 17 00:00:00 2001 -From: Kyle McMartin -Date: Mon, 24 Jan 2011 13:01:57 -0500 -Subject: [PATCH] runtime_pm_fixups - ---- - drivers/acpi/bus.c | 3 ++- - drivers/acpi/pci_bind.c | 6 ++++++ - drivers/acpi/power.c | 5 ++++- - drivers/acpi/sleep.c | 2 +- - drivers/acpi/wakeup.c | 2 +- - drivers/pci/pci-acpi.c | 2 +- - include/acpi/acpi_bus.h | 2 +- - 7 files changed, 16 insertions(+), 6 deletions(-) - -diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c -index 7ced61f..e4e0114 100644 ---- a/drivers/acpi/bus.c -+++ b/drivers/acpi/bus.c -@@ -256,7 +256,8 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state) - * a lower-powered state. - */ - if (state < device->power.state) { -- if (device->power.flags.power_resources) { -+ if (device->power.flags.power_resources && -+ !device->wakeup.run_wake_count) { - result = acpi_power_transition(device, state); - if (result) - goto end; -diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c -index 2ef0409..4b0bb68 100644 ---- a/drivers/acpi/pci_bind.c -+++ b/drivers/acpi/pci_bind.c -@@ -32,6 +32,8 @@ - #include - #include - -+#include "internal.h" -+ - #define _COMPONENT ACPI_PCI_COMPONENT - ACPI_MODULE_NAME("pci_bind"); - -@@ -65,6 +67,7 @@ static int acpi_pci_bind(struct acpi_device *device) - acpi_handle handle; - struct pci_bus *bus; - struct pci_dev *dev; -+ int state; - - dev = acpi_get_pci_dev(device->handle); - if (!dev) -@@ -87,6 +90,9 @@ static int acpi_pci_bind(struct acpi_device *device) - device->ops.unbind = acpi_pci_unbind; - } - -+ acpi_power_get_inferred_state(device, &state); -+ acpi_power_transition(device, state); -+ - /* - * Evaluate and parse _PRT, if exists. This code allows parsing of - * _PRT objects within the scope of non-bridge devices. Note that -diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c -index 9ac2a9f..cd6a8df 100644 ---- a/drivers/acpi/power.c -+++ b/drivers/acpi/power.c -@@ -412,7 +412,7 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) - * State Wake) for the device, if present - * 2. Shutdown down the power resources - */ --int acpi_disable_wakeup_device_power(struct acpi_device *dev) -+int acpi_disable_wakeup_device_power(struct acpi_device *dev, int sleep_state) - { - int i, err = 0; - -@@ -435,6 +435,9 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) - if (err) - goto out; - -+ if (sleep_state == ACPI_STATE_S0) -+ goto out; -+ - /* Close power resource */ - for (i = 0; i < dev->wakeup.resources.count; i++) { - int ret = acpi_power_off(dev->wakeup.resources.handles[i]); -diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c -index d6a8cd1..5d68dc0 100644 ---- a/drivers/acpi/sleep.c -+++ b/drivers/acpi/sleep.c -@@ -697,7 +697,7 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable) - - error = enable ? - acpi_enable_wakeup_device_power(adev, acpi_target_sleep_state) : -- acpi_disable_wakeup_device_power(adev); -+ acpi_disable_wakeup_device_power(adev, acpi_target_sleep_state); - if (!error) - dev_info(dev, "wake-up capability %s by ACPI\n", - enable ? "enabled" : "disabled"); -diff --git a/drivers/acpi/wakeup.c b/drivers/acpi/wakeup.c -index ed65014..a0cabc3 100644 ---- a/drivers/acpi/wakeup.c -+++ b/drivers/acpi/wakeup.c -@@ -73,7 +73,7 @@ void acpi_disable_wakeup_devices(u8 sleep_state) - ACPI_GPE_DISABLE); - - if (device_may_wakeup(&dev->dev)) -- acpi_disable_wakeup_device_power(dev); -+ acpi_disable_wakeup_device_power(dev, sleep_state); - } - } - -diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c -index 6fe0772..819fa7a 100644 ---- a/drivers/pci/pci-acpi.c -+++ b/drivers/pci/pci-acpi.c -@@ -302,7 +302,7 @@ static int acpi_dev_run_wake(struct device *phys_dev, bool enable) - if (!--dev->wakeup.run_wake_count) { - acpi_disable_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number); -- acpi_disable_wakeup_device_power(dev); -+ acpi_disable_wakeup_device_power(dev, ACPI_STATE_S0); - } - } else { - error = -EALREADY; -diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h -index 78ca429..92d6e86 100644 ---- a/include/acpi/acpi_bus.h -+++ b/include/acpi/acpi_bus.h -@@ -379,7 +379,7 @@ struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); - #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle)) - - int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state); --int acpi_disable_wakeup_device_power(struct acpi_device *dev); -+int acpi_disable_wakeup_device_power(struct acpi_device *dev, int state); - - #ifdef CONFIG_PM_OPS - int acpi_pm_device_sleep_state(struct device *, int *); --- -1.7.3.5 - diff --git a/scripts/grab-logs.sh b/scripts/grab-logs.sh index 8a445ec99..5df573571 100755 --- a/scripts/grab-logs.sh +++ b/scripts/grab-logs.sh @@ -1,6 +1,6 @@ #!/bin/sh -VER=$(make verrel) +VER=$(fedpkg verrel) ver=$(echo $VER | sed -e 's/-/ /g' | awk '{print $2}') rev=$(echo $VER | sed -e 's/-/ /g' | awk '{print $3}') diff --git a/shlib_base_randomize.patch b/shlib_base_randomize.patch new file mode 100644 index 000000000..80e4d644b --- /dev/null +++ b/shlib_base_randomize.patch @@ -0,0 +1,69 @@ +diff -uNrp kernel-3.2.fc16.orig/arch/x86/mm/mmap.c kernel-3.2.fc16.new/arch/x86/mm/mmap.c +--- kernel-3.2.fc16.orig/arch/x86/mm/mmap.c 2012-03-19 16:47:03.495169091 -0400 ++++ kernel-3.2.fc16.new/arch/x86/mm/mmap.c 2012-03-19 16:50:03.574168052 -0400 +@@ -106,6 +106,10 @@ static unsigned long mmap_legacy_base(vo + return TASK_UNMAPPED_BASE + mmap_rnd(); + } + ++#ifdef CONFIG_X86_32 ++ #define SHLIB_BASE 0x00111000 ++#endif ++ + /* + * This function, called very early during the creation of a new + * process VM image, sets up which VM layout function to use: +@@ -126,8 +126,10 @@ void arch_pick_mmap_layout(struct mm_str + #ifdef CONFIG_X86_32 + if (!(current->personality & READ_IMPLIES_EXEC) + && !(__supported_pte_mask & _PAGE_NX) +- && mmap_is_ia32()) ++ && mmap_is_ia32()) { ++ mm->shlib_base = SHLIB_BASE + mmap_rnd(); + mm->get_unmapped_exec_area = arch_get_unmapped_exec_area; ++ } + #endif + mm->unmap_area = arch_unmap_area_topdown; + } +diff -uNrp kernel-3.2.fc16.orig/include/linux/mm_types.h kernel-3.2.fc16.new/include/linux/mm_types.h +--- kernel-3.2.fc16.orig/include/linux/mm_types.h 2012-03-19 16:46:47.382169153 -0400 ++++ kernel-3.2.fc16.new/include/linux/mm_types.h 2012-03-19 16:50:40.738168219 -0400 +@@ -300,6 +300,7 @@ struct mm_struct { + void (*unmap_area) (struct mm_struct *mm, unsigned long addr); + #endif + unsigned long mmap_base; /* base of mmap area */ ++ unsigned long shlib_base; /* base of lib map area (ASCII armour)*/ + unsigned long task_size; /* size of task vm space */ + unsigned long cached_hole_size; /* if non-zero, the largest hole below free_area_cache */ + unsigned long free_area_cache; /* first hole of size cached_hole_size or larger */ +diff -uNrp kernel-3.2.fc16.orig/mm/mmap.c kernel-3.2.fc16.new/mm/mmap.c +--- kernel-3.2.fc16.orig/mm/mmap.c 2012-03-19 16:46:15.791169274 -0400 ++++ kernel-3.2.fc16.new/mm/mmap.c 2012-03-19 16:51:37.351166875 -0400 +@@ -1594,8 +1594,6 @@ static bool should_randomize(void) + !(current->personality & ADDR_NO_RANDOMIZE); + } + +-#define SHLIB_BASE 0x00110000 +- + unsigned long + arch_get_unmapped_exec_area(struct file *filp, unsigned long addr0, + unsigned long len0, unsigned long pgoff, unsigned long flags) +@@ -1612,8 +1610,8 @@ arch_get_unmapped_exec_area(struct file + return addr; + + if (!addr) +- addr = !should_randomize() ? SHLIB_BASE : +- randomize_range(SHLIB_BASE, 0x01000000, len); ++ addr = !should_randomize() ? mm->shlib_base : ++ randomize_range(mm->shlib_base, 0x01000000, len); + + if (addr) { + addr = PAGE_ALIGN(addr); +@@ -1623,7 +1621,7 @@ arch_get_unmapped_exec_area(struct file + return addr; + } + +- addr = SHLIB_BASE; ++ addr = mm->shlib_base; + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { + /* At this point: (!vma || addr < vma->vm_end). */ + if (TASK_SIZE - len < addr) diff --git a/silence-timekeeping-spew.patch b/silence-timekeeping-spew.patch new file mode 100644 index 000000000..19416d433 --- /dev/null +++ b/silence-timekeeping-spew.patch @@ -0,0 +1,16 @@ +--- linux-3.3.0-4.fc17.noarch/kernel/time/timekeeping.c~ 2012-03-30 14:18:15.591162207 -0400 ++++ linux-3.3.0-4.fc17.noarch/kernel/time/timekeeping.c 2012-03-30 14:18:38.959121171 -0400 +@@ -854,13 +854,6 @@ static void timekeeping_adjust(s64 offse + } else /* No adjustment needed */ + return; + +- WARN_ONCE(timekeeper.clock->maxadj && +- (timekeeper.mult + adj > timekeeper.clock->mult + +- timekeeper.clock->maxadj), +- "Adjusting %s more then 11%% (%ld vs %ld)\n", +- timekeeper.clock->name, (long)timekeeper.mult + adj, +- (long)timekeeper.clock->mult + +- timekeeper.clock->maxadj); + /* + * So the following can be confusing. + * diff --git a/sources b/sources index a051716d2..033ae54df 100644 --- a/sources +++ b/sources @@ -1 +1,2 @@ -7d471477bfa67546f902da62227fa976 linux-2.6.38.tar.bz2 +7133f5a2086a7d7ef97abac610c094f5 linux-3.3.tar.xz +e1714b5136a7f4dab1b5d2d7f98e2891 patch-3.3.8.xz diff --git a/sparc64_fix_build_errors_with_gcc460.patch b/sparc64_fix_build_errors_with_gcc460.patch deleted file mode 100644 index 807032c83..000000000 --- a/sparc64_fix_build_errors_with_gcc460.patch +++ /dev/null @@ -1,305 +0,0 @@ -From dbb988cf34a62e69c8863f212be212c6841004ba Mon Sep 17 00:00:00 2001 -From: David S. Miller -Date: Sat, 26 Feb 2011 23:40:02 -0800 -Subject: [PATCH] sparc64: Fix build errors with gcc-4.6.0 - -Most of the warnings emitted (we fail arch/sparc file -builds with -Werror) were legitimate but harmless, however -one case (n2_pcr_write) was a genuine bug. - -Based almost entirely upon a patch by Sam Ravnborg. - -Reported-by: Dennis Gilmore -Signed-off-by: David S. Miller ---- - arch/sparc/kernel/iommu.c | 3 --- - arch/sparc/kernel/ldc.c | 28 ++++++++++++++++++---------- - arch/sparc/kernel/pci.c | 1 + - arch/sparc/kernel/pci_common.c | 11 +++++++---- - arch/sparc/kernel/pci_fire.c | 2 -- - arch/sparc/kernel/pci_schizo.c | 4 +--- - arch/sparc/kernel/pci_sun4v.c | 3 +-- - arch/sparc/kernel/pcr.c | 2 +- - arch/sparc/kernel/ptrace_64.c | 3 ++- - arch/sparc/kernel/smp_64.c | 11 ++++------- - arch/sparc/kernel/traps_64.c | 3 +-- - 11 files changed, 36 insertions(+), 35 deletions(-) - -diff --git a/arch/sparc/kernel/iommu.c b/arch/sparc/kernel/iommu.c -index 72509d0..6f01e8c 100644 ---- a/arch/sparc/kernel/iommu.c -+++ b/arch/sparc/kernel/iommu.c -@@ -333,13 +333,10 @@ static void dma_4u_free_coherent(struct device *dev, size_t size, - void *cpu, dma_addr_t dvma) - { - struct iommu *iommu; -- iopte_t *iopte; - unsigned long flags, order, npages; - - npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT; - iommu = dev->archdata.iommu; -- iopte = iommu->page_table + -- ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT); - - spin_lock_irqsave(&iommu->lock, flags); - -diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c -index df39a0f..732b0bc 100644 ---- a/arch/sparc/kernel/ldc.c -+++ b/arch/sparc/kernel/ldc.c -@@ -790,16 +790,20 @@ static void send_events(struct ldc_channel *lp, unsigned int event_mask) - static irqreturn_t ldc_rx(int irq, void *dev_id) - { - struct ldc_channel *lp = dev_id; -- unsigned long orig_state, hv_err, flags; -+ unsigned long orig_state, flags; - unsigned int event_mask; - - spin_lock_irqsave(&lp->lock, flags); - - orig_state = lp->chan_state; -- hv_err = sun4v_ldc_rx_get_state(lp->id, -- &lp->rx_head, -- &lp->rx_tail, -- &lp->chan_state); -+ -+ /* We should probably check for hypervisor errors here and -+ * reset the LDC channel if we get one. -+ */ -+ sun4v_ldc_rx_get_state(lp->id, -+ &lp->rx_head, -+ &lp->rx_tail, -+ &lp->chan_state); - - ldcdbg(RX, "RX state[0x%02lx:0x%02lx] head[0x%04lx] tail[0x%04lx]\n", - orig_state, lp->chan_state, lp->rx_head, lp->rx_tail); -@@ -904,16 +908,20 @@ out: - static irqreturn_t ldc_tx(int irq, void *dev_id) - { - struct ldc_channel *lp = dev_id; -- unsigned long flags, hv_err, orig_state; -+ unsigned long flags, orig_state; - unsigned int event_mask = 0; - - spin_lock_irqsave(&lp->lock, flags); - - orig_state = lp->chan_state; -- hv_err = sun4v_ldc_tx_get_state(lp->id, -- &lp->tx_head, -- &lp->tx_tail, -- &lp->chan_state); -+ -+ /* We should probably check for hypervisor errors here and -+ * reset the LDC channel if we get one. -+ */ -+ sun4v_ldc_tx_get_state(lp->id, -+ &lp->tx_head, -+ &lp->tx_tail, -+ &lp->chan_state); - - ldcdbg(TX, " TX state[0x%02lx:0x%02lx] head[0x%04lx] tail[0x%04lx]\n", - orig_state, lp->chan_state, lp->tx_head, lp->tx_tail); -diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c -index 4137579..f255382 100644 ---- a/arch/sparc/kernel/pci.c -+++ b/arch/sparc/kernel/pci.c -@@ -675,6 +675,7 @@ static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus) - * humanoid. - */ - err = sysfs_create_file(&dev->dev.kobj, &dev_attr_obppath.attr); -+ (void) err; - } - list_for_each_entry(child_bus, &bus->children, node) - pci_bus_register_of_sysfs(child_bus); -diff --git a/arch/sparc/kernel/pci_common.c b/arch/sparc/kernel/pci_common.c -index 6c7a33a..6e3874b 100644 ---- a/arch/sparc/kernel/pci_common.c -+++ b/arch/sparc/kernel/pci_common.c -@@ -295,14 +295,17 @@ static int sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, - unsigned int bus = bus_dev->number; - unsigned int device = PCI_SLOT(devfn); - unsigned int func = PCI_FUNC(devfn); -- unsigned long ret; - - if (config_out_of_range(pbm, bus, devfn, where)) { - /* Do nothing. */ - } else { -- ret = pci_sun4v_config_put(devhandle, -- HV_PCI_DEVICE_BUILD(bus, device, func), -- where, size, value); -+ /* We don't check for hypervisor errors here, but perhaps -+ * we should and influence our return value depending upon -+ * what kind of error is thrown. -+ */ -+ pci_sun4v_config_put(devhandle, -+ HV_PCI_DEVICE_BUILD(bus, device, func), -+ where, size, value); - } - return PCIBIOS_SUCCESSFUL; - } -diff --git a/arch/sparc/kernel/pci_fire.c b/arch/sparc/kernel/pci_fire.c -index efb896d..75dfeb6 100644 ---- a/arch/sparc/kernel/pci_fire.c -+++ b/arch/sparc/kernel/pci_fire.c -@@ -214,11 +214,9 @@ static int pci_fire_msi_setup(struct pci_pbm_info *pbm, unsigned long msiqid, - - static int pci_fire_msi_teardown(struct pci_pbm_info *pbm, unsigned long msi) - { -- unsigned long msiqid; - u64 val; - - val = upa_readq(pbm->pbm_regs + MSI_MAP(msi)); -- msiqid = (val & MSI_MAP_EQNUM); - - val &= ~MSI_MAP_VALID; - -diff --git a/arch/sparc/kernel/pci_schizo.c b/arch/sparc/kernel/pci_schizo.c -index 445a47a..4620eb7 100644 ---- a/arch/sparc/kernel/pci_schizo.c -+++ b/arch/sparc/kernel/pci_schizo.c -@@ -1313,7 +1313,7 @@ static int __devinit schizo_pbm_init(struct pci_pbm_info *pbm, - const struct linux_prom64_registers *regs; - struct device_node *dp = op->dev.of_node; - const char *chipset_name; -- int is_pbm_a, err; -+ int err; - - switch (chip_type) { - case PBM_CHIP_TYPE_TOMATILLO: -@@ -1343,8 +1343,6 @@ static int __devinit schizo_pbm_init(struct pci_pbm_info *pbm, - */ - regs = of_get_property(dp, "reg", NULL); - -- is_pbm_a = ((regs[0].phys_addr & 0x00700000) == 0x00600000); -- - pbm->next = pci_pbm_root; - pci_pbm_root = pbm; - -diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c -index 743344a..859abfd 100644 ---- a/arch/sparc/kernel/pci_sun4v.c -+++ b/arch/sparc/kernel/pci_sun4v.c -@@ -580,7 +580,7 @@ static int __devinit pci_sun4v_iommu_init(struct pci_pbm_info *pbm) - { - static const u32 vdma_default[] = { 0x80000000, 0x80000000 }; - struct iommu *iommu = pbm->iommu; -- unsigned long num_tsb_entries, sz, tsbsize; -+ unsigned long num_tsb_entries, sz; - u32 dma_mask, dma_offset; - const u32 *vdma; - -@@ -596,7 +596,6 @@ static int __devinit pci_sun4v_iommu_init(struct pci_pbm_info *pbm) - - dma_mask = (roundup_pow_of_two(vdma[1]) - 1UL); - num_tsb_entries = vdma[1] / IO_PAGE_SIZE; -- tsbsize = num_tsb_entries * sizeof(iopte_t); - - dma_offset = vdma[0]; - -diff --git a/arch/sparc/kernel/pcr.c b/arch/sparc/kernel/pcr.c -index 7c2ced6..8ac23e6 100644 ---- a/arch/sparc/kernel/pcr.c -+++ b/arch/sparc/kernel/pcr.c -@@ -81,7 +81,7 @@ static void n2_pcr_write(u64 val) - unsigned long ret; - - ret = sun4v_niagara2_setperf(HV_N2_PERF_SPARC_CTL, val); -- if (val != HV_EOK) -+ if (ret != HV_EOK) - write_pcr(val); - } - -diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c -index 9ccc812..96ee50a 100644 ---- a/arch/sparc/kernel/ptrace_64.c -+++ b/arch/sparc/kernel/ptrace_64.c -@@ -1086,6 +1086,7 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs) - - asmlinkage void syscall_trace_leave(struct pt_regs *regs) - { -+#ifdef CONFIG_AUDITSYSCALL - if (unlikely(current->audit_context)) { - unsigned long tstate = regs->tstate; - int result = AUDITSC_SUCCESS; -@@ -1095,7 +1096,7 @@ asmlinkage void syscall_trace_leave(struct pt_regs *regs) - - audit_syscall_exit(result, regs->u_regs[UREG_I0]); - } -- -+#endif - if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) - trace_sys_exit(regs, regs->u_regs[UREG_G1]); - -diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c -index 555a76d..3e94a8c 100644 ---- a/arch/sparc/kernel/smp_64.c -+++ b/arch/sparc/kernel/smp_64.c -@@ -189,7 +189,7 @@ static inline long get_delta (long *rt, long *master) - void smp_synchronize_tick_client(void) - { - long i, delta, adj, adjust_latency = 0, done = 0; -- unsigned long flags, rt, master_time_stamp, bound; -+ unsigned long flags, rt, master_time_stamp; - #if DEBUG_TICK_SYNC - struct { - long rt; /* roundtrip time */ -@@ -208,10 +208,8 @@ void smp_synchronize_tick_client(void) - { - for (i = 0; i < NUM_ROUNDS; i++) { - delta = get_delta(&rt, &master_time_stamp); -- if (delta == 0) { -+ if (delta == 0) - done = 1; /* let's lock on to this... */ -- bound = rt; -- } - - if (!done) { - if (i > 0) { -@@ -933,13 +931,12 @@ void smp_flush_dcache_page_impl(struct page *page, int cpu) - void flush_dcache_page_all(struct mm_struct *mm, struct page *page) - { - void *pg_addr; -- int this_cpu; - u64 data0; - - if (tlb_type == hypervisor) - return; - -- this_cpu = get_cpu(); -+ preempt_disable(); - - #ifdef CONFIG_DEBUG_DCFLUSH - atomic_inc(&dcpage_flushes); -@@ -964,7 +961,7 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page) - } - __local_flush_dcache_page(page); - -- put_cpu(); -+ preempt_enable(); - } - - void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs) -diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c -index 42ad2ba..9456472 100644 ---- a/arch/sparc/kernel/traps_64.c -+++ b/arch/sparc/kernel/traps_64.c -@@ -2152,7 +2152,7 @@ static void user_instruction_dump(unsigned int __user *pc) - - void show_stack(struct task_struct *tsk, unsigned long *_ksp) - { -- unsigned long fp, thread_base, ksp; -+ unsigned long fp, ksp; - struct thread_info *tp; - int count = 0; - #ifdef CONFIG_FUNCTION_GRAPH_TRACER -@@ -2173,7 +2173,6 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp) - flushw_all(); - - fp = ksp + STACK_BIAS; -- thread_base = (unsigned long) tp; - - printk("Call Trace:\n"); - do { --- -1.7.4.1 - diff --git a/stable-queue.patch b/stable-queue.patch new file mode 100644 index 000000000..607602cfc --- /dev/null +++ b/stable-queue.patch @@ -0,0 +1 @@ +nil diff --git a/taint-vbox.patch b/taint-vbox.patch new file mode 100644 index 000000000..5cb3e47c9 --- /dev/null +++ b/taint-vbox.patch @@ -0,0 +1,15 @@ +diff --git a/kernel/module.c b/kernel/module.c +index 04379f92..d26c9a3 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -2653,6 +2653,10 @@ static int check_module_license_and_versions(struct module *mod) + if (strcmp(mod->name, "ndiswrapper") == 0) + add_taint(TAINT_PROPRIETARY_MODULE); + ++ /* vbox is garbage. */ ++ if (strcmp(mod->name, "vboxdrv") == 0) ++ add_taint(TAINT_CRAP); ++ + /* driverloader was caught wrongly pretending to be under GPL */ + if (strcmp(mod->name, "driverloader") == 0) + add_taint_module(mod, TAINT_PROPRIETARY_MODULE); diff --git a/thinkpad-acpi-fix-backlight.patch b/thinkpad-acpi-fix-backlight.patch deleted file mode 100644 index 5ed2544fe..000000000 --- a/thinkpad-acpi-fix-backlight.patch +++ /dev/null @@ -1,56 +0,0 @@ -diff -up linux-2.6.34.noarch/drivers/platform/x86/thinkpad_acpi.c.orig linux-2.6.34.noarch/drivers/platform/x86/thinkpad_acpi.c ---- linux-2.6.34.noarch/drivers/platform/x86/thinkpad_acpi.c.orig 2010-05-17 16:28:13.254200070 -0400 -+++ linux-2.6.34.noarch/drivers/platform/x86/thinkpad_acpi.c 2010-05-17 16:29:56.471200083 -0400 -@@ -3397,7 +3397,7 @@ static int __init hotkey_init(struct ibm - /* update bright_acpimode... */ - tpacpi_check_std_acpi_brightness_support(); - -- if (tp_features.bright_acpimode && acpi_video_backlight_support()) { -+ if (acpi_video_backlight_support()) { - printk(TPACPI_INFO - "This ThinkPad has standard ACPI backlight " - "brightness control, supported by the ACPI " -@@ -6189,26 +6189,24 @@ static int __init brightness_init(struct - * going to publish a backlight interface - */ - b = tpacpi_check_std_acpi_brightness_support(); -- if (b > 0) { - -- if (acpi_video_backlight_support()) { -- if (brightness_enable > 1) { -- printk(TPACPI_NOTICE -- "Standard ACPI backlight interface " -- "available, not loading native one.\n"); -- return 1; -- } else if (brightness_enable == 1) { -- printk(TPACPI_NOTICE -- "Backlight control force enabled, even if standard " -- "ACPI backlight interface is available\n"); -- } -- } else { -- if (brightness_enable > 1) { -- printk(TPACPI_NOTICE -- "Standard ACPI backlight interface not " -- "available, thinkpad_acpi native " -- "brightness control enabled\n"); -- } -+ if (acpi_video_backlight_support()) { -+ if (brightness_enable > 1) { -+ printk(TPACPI_NOTICE -+ "Standard ACPI backlight interface " -+ "available, not loading native one.\n"); -+ return 1; -+ } else if (brightness_enable == 1) { -+ printk(TPACPI_NOTICE -+ "Backlight control force enabled, even if standard " -+ "ACPI backlight interface is available\n"); -+ } -+ } else { -+ if (brightness_enable > 1) { -+ printk(TPACPI_NOTICE -+ "Standard ACPI backlight interface not " -+ "available, thinkpad_acpi native " -+ "brightness control enabled\n"); - } - } - diff --git a/thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-PAE.patch b/thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-PAE.patch new file mode 100644 index 000000000..a91e9bbe4 --- /dev/null +++ b/thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-PAE.patch @@ -0,0 +1,228 @@ + +Delivered-To: jwboyer@gmail.com +Received: by 10.229.175.203 with SMTP id bb11csp66243qcb; + Fri, 8 Jun 2012 15:08:27 -0700 (PDT) +Received: by 10.68.222.133 with SMTP id qm5mr23412736pbc.113.1339193307132; + Fri, 08 Jun 2012 15:08:27 -0700 (PDT) +Return-Path: +Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) + by mx.google.com with ESMTP id ku9si12482578pbc.355.2012.06.08.15.08.24; + Fri, 08 Jun 2012 15:08:25 -0700 (PDT) +Received-SPF: pass (google.com: best guess record for domain of stable-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; +Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of stable-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mail=stable-owner@vger.kernel.org +Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand + id S964992Ab2FHWIW (ORCPT + 21 others); + Fri, 8 Jun 2012 18:08:22 -0400 +Received: from mail-bk0-f74.google.com ([209.85.214.74]:41783 "EHLO + mail-bk0-f74.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org + with ESMTP id S964922Ab2FHWIV (ORCPT + ); Fri, 8 Jun 2012 18:08:21 -0400 +Received: by bkty5 with SMTP id y5so128736bkt.1 + for ; Fri, 08 Jun 2012 15:08:20 -0700 (PDT) +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=google.com; s=20120113; + h=subject:to:cc:from:date:message-id:x-gm-message-state; + bh=RSdNZSZcXg/enKaYIM+JR4+Bd890ieO+blY9bsk9giI=; + b=NwTZEmRSdqDAiTV/EW91GXpM/yrRd7CNzfPif0JcF0iFgxGAo4lB7W1I05vmrnPcCQ + Va+P6xXLWle2rAVQLsPooKdtb3u2wnNRDEGvBPZl2alje+qzhKGlQcVgnI5+KCM6GaS+ + YWoE+2gv5UFmF6JlelThyecGTyZ0D93K5aVYewSxg0H7KZ6BgvMnB/qJKFdScatv1uDH + g39MFwJzmD+DmNMn149jeUWYOLLTeMZJkymtJCLgxS8eJzQxXA0nes2Wz/pXCBdxXF2z + mft6LyzKtoEUDeTtalgm9zxkT4XJ+6bsAMEXBFgkcyNq0Ic8P79AP0ynlET2L/Ql3ARP + C5Sg== +Received: by 10.14.101.2 with SMTP id a2mr2823176eeg.6.1339193299969; + Fri, 08 Jun 2012 15:08:19 -0700 (PDT) +Received: from hpza10.eem.corp.google.com ([74.125.121.33]) + by gmr-mx.google.com with ESMTPS id d52si7345113eei.1.2012.06.08.15.08.19 + (version=TLSv1/SSLv3 cipher=AES128-SHA); + Fri, 08 Jun 2012 15:08:19 -0700 (PDT) +Received: from akpm.mtv.corp.google.com (akpm.mtv.corp.google.com [172.18.96.75]) + by hpza10.eem.corp.google.com (Postfix) with ESMTP id 9D09620004E; + Fri, 8 Jun 2012 15:08:19 -0700 (PDT) +Received: from localhost.localdomain (localhost [127.0.0.1]) + by akpm.mtv.corp.google.com (Postfix) with ESMTP id D5FACA0329; + Fri, 8 Jun 2012 15:08:18 -0700 (PDT) +Subject: + thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-pae.patch added to -mm tree +To: mm-commits@vger.kernel.org +Cc: aarcange@redhat.com, hughd@google.com, jbeulich@suse.com, + jrnieder@gmail.com, kosaki.motohiro@gmail.com, lwoodman@redhat.com, + mgorman@suse.de, pmatouse@redhat.com, riel@redhat.com, + stable@vger.kernel.org, uobergfe@redhat.com +From: akpm@linux-foundation.org +Date: Fri, 08 Jun 2012 15:08:18 -0700 +Message-Id: <20120608220818.D5FACA0329@akpm.mtv.corp.google.com> +X-Gm-Message-State: ALoCoQnqC0C+2OVVfC5Yi43jUu5vH03b/RBncPoI4SpE4HFSgaRrM+gM2J8rR6MMoba3nM/OmDAU +Sender: stable-owner@vger.kernel.org +Precedence: bulk +List-ID: +X-Mailing-List: stable@vger.kernel.org + + +The patch titled + Subject: thp: avoid atomic64_read in pmd_read_atomic for 32bit PAE +has been added to the -mm tree. Its filename is + thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-pae.patch + +Before you just go and hit "reply", please: + a) Consider who else should be cc'ed + b) Prefer to cc a suitable mailing list as well + c) Ideally: find the original patch on the mailing list and do a + reply-to-all to that, adding suitable additional cc's + +*** Remember to use Documentation/SubmitChecklist when testing your code *** + +The -mm tree is included into linux-next and is updated +there every 3-4 working days + +------------------------------------------------------ +From: Andrea Arcangeli +Subject: thp: avoid atomic64_read in pmd_read_atomic for 32bit PAE + +In the x86 32bit PAE CONFIG_TRANSPARENT_HUGEPAGE=y case while holding the +mmap_sem for reading, cmpxchg8b cannot be used to read pmd contents under +Xen. + +So instead of dealing only with "consistent" pmdvals in +pmd_none_or_trans_huge_or_clear_bad() (which would be conceptually +simpler) we let pmd_none_or_trans_huge_or_clear_bad() deal with pmdvals +where the low 32bit and high 32bit could be inconsistent (to avoid having +to use cmpxchg8b). + +The only guarantee we get from pmd_read_atomic is that if the low part of +the pmd was found null, the high part will be null too (so the pmd will be +considered unstable). And if the low part of the pmd is found "stable" +later, then it means the whole pmd was read atomically (because after a +pmd is stable, neither MADV_DONTNEED nor page faults can alter it anymore, +and we read the high part after the low part). + +In the 32bit PAE x86 case, it is enough to read the low part of the pmdval +atomically to declare the pmd as "stable" and that's true for THP and no +THP, furthermore in the THP case we also have a barrier() that will +prevent any inconsistent pmdvals to be cached by a later re-read of the +*pmd. + +Signed-off-by: Andrea Arcangeli +Cc: Jonathan Nieder +Cc: Ulrich Obergfell +Cc: Mel Gorman +Cc: Hugh Dickins +Cc: Larry Woodman +Cc: Petr Matousek +Cc: Rik van Riel +Cc: Jan Beulich +Cc: KOSAKI Motohiro +Cc: +Signed-off-by: Andrew Morton +--- + + arch/x86/include/asm/pgtable-3level.h | 30 +++++++++++++----------- + include/asm-generic/pgtable.h | 10 ++++++++ + 2 files changed, 27 insertions(+), 13 deletions(-) + +diff -puN arch/x86/include/asm/pgtable-3level.h~thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-pae arch/x86/include/asm/pgtable-3level.h +--- a/arch/x86/include/asm/pgtable-3level.h~thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-pae ++++ a/arch/x86/include/asm/pgtable-3level.h +@@ -47,16 +47,26 @@ static inline void native_set_pte(pte_t + * they can run pmd_offset_map_lock or pmd_trans_huge or other pmd + * operations. + * +- * Without THP if the mmap_sem is hold for reading, the +- * pmd can only transition from null to not null while pmd_read_atomic runs. +- * So there's no need of literally reading it atomically. ++ * Without THP if the mmap_sem is hold for reading, the pmd can only ++ * transition from null to not null while pmd_read_atomic runs. So ++ * we can always return atomic pmd values with this function. + * + * With THP if the mmap_sem is hold for reading, the pmd can become +- * THP or null or point to a pte (and in turn become "stable") at any +- * time under pmd_read_atomic, so it's mandatory to read it atomically +- * with cmpxchg8b. ++ * trans_huge or none or point to a pte (and in turn become "stable") ++ * at any time under pmd_read_atomic. We could read it really ++ * atomically here with a atomic64_read for the THP enabled case (and ++ * it would be a whole lot simpler), but to avoid using cmpxchg8b we ++ * only return an atomic pmdval if the low part of the pmdval is later ++ * found stable (i.e. pointing to a pte). And we're returning a none ++ * pmdval if the low part of the pmd is none. In some cases the high ++ * and low part of the pmdval returned may not be consistent if THP is ++ * enabled (the low part may point to previously mapped hugepage, ++ * while the high part may point to a more recently mapped hugepage), ++ * but pmd_none_or_trans_huge_or_clear_bad() only needs the low part ++ * of the pmd to be read atomically to decide if the pmd is unstable ++ * or not, with the only exception of when the low part of the pmd is ++ * zero in which case we return a none pmd. + */ +-#ifndef CONFIG_TRANSPARENT_HUGEPAGE + static inline pmd_t pmd_read_atomic(pmd_t *pmdp) + { + pmdval_t ret; +@@ -74,12 +84,6 @@ static inline pmd_t pmd_read_atomic(pmd_ + + return (pmd_t) { ret }; + } +-#else /* CONFIG_TRANSPARENT_HUGEPAGE */ +-static inline pmd_t pmd_read_atomic(pmd_t *pmdp) +-{ +- return (pmd_t) { atomic64_read((atomic64_t *)pmdp) }; +-} +-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + + static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte) + { +diff -puN include/asm-generic/pgtable.h~thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-pae include/asm-generic/pgtable.h +--- a/include/asm-generic/pgtable.h~thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-pae ++++ a/include/asm-generic/pgtable.h +@@ -484,6 +484,16 @@ static inline int pmd_none_or_trans_huge + /* + * The barrier will stabilize the pmdval in a register or on + * the stack so that it will stop changing under the code. ++ * ++ * When CONFIG_TRANSPARENT_HUGEPAGE=y on x86 32bit PAE, ++ * pmd_read_atomic is allowed to return a not atomic pmdval ++ * (for example pointing to an hugepage that has never been ++ * mapped in the pmd). The below checks will only care about ++ * the low part of the pmd with 32bit PAE x86 anyway, with the ++ * exception of pmd_none(). So the important thing is that if ++ * the low part of the pmd is found null, the high part will ++ * be also null or the pmd_none() check below would be ++ * confused. + */ + #ifdef CONFIG_TRANSPARENT_HUGEPAGE + barrier(); +_ +Subject: Subject: thp: avoid atomic64_read in pmd_read_atomic for 32bit PAE + +Patches currently in -mm which might be from aarcange@redhat.com are + +origin.patch +linux-next.patch +mm-fix-slab-page-_count-corruption-when-using-slub.patch +thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-pae.patch +hugetlb-rename-max_hstate-to-hugetlb_max_hstate.patch +hugetlbfs-dont-use-err_ptr-with-vm_fault-values.patch +hugetlbfs-add-an-inline-helper-for-finding-hstate-index.patch +hugetlbfs-add-an-inline-helper-for-finding-hstate-index-fix.patch +hugetlb-use-mmu_gather-instead-of-a-temporary-linked-list-for-accumulating-pages.patch +hugetlb-use-mmu_gather-instead-of-a-temporary-linked-list-for-accumulating-pages-fix.patch +hugetlb-use-mmu_gather-instead-of-a-temporary-linked-list-for-accumulating-pages-fix-fix.patch +hugetlb-avoid-taking-i_mmap_mutex-in-unmap_single_vma-for-hugetlb.patch +hugetlb-simplify-migrate_huge_page.patch +hugetlb-simplify-migrate_huge_page-fix.patch +memcg-add-hugetlb-extension.patch +memcg-add-hugetlb-extension-fix.patch +memcg-add-hugetlb-extension-fix-fix.patch +hugetlb-add-charge-uncharge-calls-for-hugetlb-alloc-free.patch +memcg-track-resource-index-in-cftype-private.patch +hugetlbfs-add-memcg-control-files-for-hugetlbfs.patch +hugetlbfs-add-memcg-control-files-for-hugetlbfs-use-scnprintf-instead-of-sprintf.patch +hugetlbfs-add-memcg-control-files-for-hugetlbfs-use-scnprintf-instead-of-sprintf-fix.patch +hugetlbfs-add-a-list-for-tracking-in-use-hugetlb-pages.patch +memcg-move-hugetlb-resource-count-to-parent-cgroup-on-memcg-removal.patch +memcg-move-hugetlb-resource-count-to-parent-cgroup-on-memcg-removal-fix.patch +memcg-move-hugetlb-resource-count-to-parent-cgroup-on-memcg-removal-fix-fix.patch +hugetlb-migrate-memcg-info-from-oldpage-to-new-page-during-migration.patch +memcg-add-memory-controller-documentation-for-hugetlb-management.patch + +-- +To unsubscribe from this list: send the line "unsubscribe stable" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/unhandled-irqs-switch-to-polling.patch b/unhandled-irqs-switch-to-polling.patch new file mode 100644 index 000000000..2f25cda6f --- /dev/null +++ b/unhandled-irqs-switch-to-polling.patch @@ -0,0 +1,248 @@ +Date: Mon, 30 Jan 2012 22:37:28 +0100 +Message-ID: +Subject: [PATCH] Unhandled IRQs on AMD E-450: temporarily switch to + low-performance polling IRQ mode +From: Jeroen Van den Keybus +To: linux-kernel@vger.kernel.org +Cc: Clemens Ladisch , "Huang, Shane" , + Borislav Petkov , "Nguyen, Dong" , + jesse.brandeburg@gmail.com +Content-Type: text/plain; charset=ISO-8859-1 +Sender: linux-kernel-owner@vger.kernel.org +Precedence: bulk +List-ID: +X-Mailing-List: linux-kernel@vger.kernel.org +X-RedHat-Spam-Score: -4.898 (DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,FREEMAIL_FROM,RCVD_IN_DNSWL_HI,T_DKIM_INVALID,T_RP_MATCHES_RCVD) +X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 +X-Scanned-By: MIMEDefang 2.68 on 10.5.110.19 +Status: RO +Content-Length: 7029 +Lines: 189 + +It seems that some motherboard designs using the ASM1083 PCI/PCIe +bridge (PCI device ID 1b21:1080, Rev. 01) suffer from stuck IRQ lines +on the PCI bus (causing the kernel to emit 'IRQxx: nobody cared' and +disable the IRQ). The following patch is an attempt to mitigate the +serious impact of permanently disabling an IRQ in that case and +actually make PCI devices better usable on this platform. + +It seems that the bridge fails to issue a IRQ deassertion message on +the PCIe bus, when the relevant driver causes the interrupting PCI +device to deassert its IRQ line. To solve this issue, it was tried to +re-issue an IRQ on a PCI device being able to do so (e1000 in this +case), but we suspect that the attempt to re-assert/deassert may have +occurred too soon after the initial IRQ for the ASM1083. Anyway, it +didn't work but if, after some delay, a new IRQ occurred, the related +IRQ deassertion message eventually did clear the IOAPIC IRQ. It would +be useful to re-enable the IRQ here. + +Therefore the patch below to poll_spurious_irqs() in spurious.c is +proposed, It does the following: + +1. lets the kernel decide that an IRQ is unhandled after only 10 +positives (instead of 100,000); +2. briefly (a few seconds or so, currently 1 s) switches to polling +IRQ at a higher rate than usual (100..1,000Hz instead of 10Hz, +currently 100Hz), but not too high to avoid excessive CPU load. Any +device drivers 'see' their interrupts handled with a higher latency +than usual, but they will still operate properly; +3. afterwards, simply reenable the IRQ. + +If proper operation of the PCIe legacy IRQ line emulation is restored +after 3, the system operates again at normal performance. If the IRQ +is still stuck after this procedure, the sequence repeats. + +If a genuinely stuck IRQ is used with this solution, the system would +simply sustain short bursts of 10 unhandled IRQs per second, and use +polling mode indefinitely at a moderate 100Hz rate. It seemed a good +alternative to the default irqpoll behaviour to me, which is why I +left it in poll_spurious_irqs() (instead of creating a new kernel +option). Additionally, if any device happens to share an IRQ with a +faulty one, that device is no longer banned forever. + +Debugging output is still present and may be removed. Bad IRQ +reporting is also commented out now. + +I have now tried it for about 2 months and I can conclude the following: + +1. The patch works and, judging from my Firewire card interrupt on +IRQ16, which repeats every 64 secs, I can confirm that the IRQ usually +gets reset when a new IRQ arrives (polling mode runs for 64 seconds +every time). +2. When testing a SiL-3114 SATA PCI card behind the ASM1083, I could +keep this running at fairly high speeds (50..70MB/s) for an hour or +so, but eventually the SiL driver crashed. In such conditions the PCI +system had to deal with a few hundred IRQs per second / polling mode +kicking in every 5..10 seconds). + +I would like to thank Clemens Ladisch for his invaluable help in +finding a solution (and providing a patch to avoid my SATA going down +every time during debugging). + + +Signed-off-by: Jeroen Van den Keybus + +Make it less chatty. Only kick it in if we detect an ASM1083 PCI bridge. + +Josh Boyer +====== + +--- linux-2.6.orig/kernel/irq/spurious.c ++++ linux-2.6/kernel/irq/spurious.c +@@ -18,6 +18,8 @@ + + static int irqfixup __read_mostly; + ++int irq_poll_and_retry = 0; ++ + #define POLL_SPURIOUS_IRQ_INTERVAL (HZ/10) + static void poll_spurious_irqs(unsigned long dummy); + static DEFINE_TIMER(poll_spurious_irq_timer, poll_spurious_irqs, 0, 0); +@@ -141,12 +143,13 @@ out: + static void poll_spurious_irqs(unsigned long dummy) + { + struct irq_desc *desc; +- int i; ++ int i, poll_again; + + if (atomic_inc_return(&irq_poll_active) != 1) + goto out; + irq_poll_cpu = smp_processor_id(); + ++ poll_again = 0; /* Will stay false as long as no polling candidate is found */ + for_each_irq_desc(i, desc) { + unsigned int state; + +@@ -159,14 +162,33 @@ static void poll_spurious_irqs(unsigned + if (!(state & IRQS_SPURIOUS_DISABLED)) + continue; + +- local_irq_disable(); +- try_one_irq(i, desc, true); +- local_irq_enable(); ++ /* We end up here with a disabled spurious interrupt. ++ desc->irqs_unhandled now tracks the number of times ++ the interrupt has been polled */ ++ if (irq_poll_and_retry) { ++ if (desc->irqs_unhandled < 100) { /* 1 second delay with poll frequency 100 Hz */ ++ local_irq_disable(); ++ try_one_irq(i, desc, true); ++ local_irq_enable(); ++ desc->irqs_unhandled++; ++ poll_again = 1; ++ } else { ++ irq_enable(desc); /* Reenable the interrupt line */ ++ desc->depth--; ++ desc->istate &= (~IRQS_SPURIOUS_DISABLED); ++ desc->irqs_unhandled = 0; ++ } ++ } else { ++ local_irq_disable(); ++ try_one_irq(i, desc, true); ++ local_irq_enable(); ++ } + } ++ if (poll_again) ++ mod_timer(&poll_spurious_irq_timer, ++ jiffies + POLL_SPURIOUS_IRQ_INTERVAL); + out: + atomic_dec(&irq_poll_active); +- mod_timer(&poll_spurious_irq_timer, +- jiffies + POLL_SPURIOUS_IRQ_INTERVAL); + } + + static inline int bad_action_ret(irqreturn_t action_ret) +@@ -177,11 +199,19 @@ static inline int bad_action_ret(irqretu + } + + /* +- * If 99,900 of the previous 100,000 interrupts have not been handled ++ * If 9 of the previous 10 interrupts have not been handled + * then assume that the IRQ is stuck in some manner. Drop a diagnostic + * and try to turn the IRQ off. + * +- * (The other 100-of-100,000 interrupts may have been a correctly ++ * Although this may cause early deactivation of a sporadically ++ * malfunctioning IRQ line, the poll system will: ++ * a) Poll it for 100 cycles at a 100 Hz rate ++ * b) Reenable it afterwards ++ * ++ * In worst case, with current settings, this will cause short bursts ++ * of 10 interrupts every second. ++ * ++ * (The other single interrupt may have been a correctly + * functioning device sharing an IRQ with the failing one) + */ + static void +@@ -269,6 +299,8 @@ try_misrouted_irq(unsigned int irq, stru + void note_interrupt(unsigned int irq, struct irq_desc *desc, + irqreturn_t action_ret) + { ++ int unhandled_thresh = 999000; ++ + if (desc->istate & IRQS_POLL_INPROGRESS) + return; + +@@ -302,19 +334,31 @@ void note_interrupt(unsigned int irq, st + } + + desc->irq_count++; +- if (likely(desc->irq_count < 100000)) +- return; ++ if (!irq_poll_and_retry) ++ if (likely(desc->irq_count < 100000)) ++ return; ++ else ++ if (likely(desc->irq_count < 10)) ++ return; + + desc->irq_count = 0; +- if (unlikely(desc->irqs_unhandled > 99900)) { ++ if (irq_poll_and_retry) ++ unhandled_thresh = 9; ++ ++ if (unlikely(desc->irqs_unhandled >= unhandled_thresh)) { + /* +- * The interrupt is stuck ++ * The interrupt might be stuck + */ +- __report_bad_irq(irq, desc, action_ret); ++ if (!irq_poll_and_retry) { ++ __report_bad_irq(irq, desc, action_ret); ++ printk(KERN_EMERG "Disabling IRQ %d\n", irq); ++ } else { ++ printk(KERN_INFO "IRQ %d might be stuck. Polling\n", ++ irq); ++ } + /* + * Now kill the IRQ + */ +- printk(KERN_EMERG "Disabling IRQ #%d\n", irq); + desc->istate |= IRQS_SPURIOUS_DISABLED; + desc->depth++; + irq_disable(desc); +--- linux-2.6.orig/drivers/pci/quirks.c ++++ linux-2.6/drivers/pci/quirks.c +@@ -1677,6 +1677,22 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260a, quirk_intel_pcie_pm); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm); + ++/* ASM108x transparent PCI bridges apparently have broken IRQ deassert ++ * handling. This causes interrupts to get "stuck" and eventually disabled. ++ * However, the interrupts are often shared and disabling them is fairly bad. ++ * It's been somewhat successful to switch to polling mode and retry after ++ * a bit, so let's do that. ++ */ ++extern int irq_poll_and_retry; ++static void quirk_asm108x_poll_interrupts(struct pci_dev *dev) ++{ ++ dev_info(&dev->dev, "Buggy bridge found [%04x:%04x]\n", ++ dev->vendor, dev->device); ++ dev_info(&dev->dev, "Stuck interrupts will be polled and retried\n"); ++ irq_poll_and_retry = 1; ++} ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ASMEDIA, 0x1080, quirk_asm108x_poll_interrupts); ++ + #ifdef CONFIG_X86_IO_APIC + /* + * Boot interrupts on some chipsets cannot be turned off. For these chipsets, diff --git a/linux-2.6-utrace.patch b/utrace.patch similarity index 83% rename from linux-2.6-utrace.patch rename to utrace.patch index 366b8a176..fdf24a472 100644 --- a/linux-2.6-utrace.patch +++ b/utrace.patch @@ -1,59 +1,94 @@ -utrace core +From d007ce2c3f1f67624fde5e6b7ccc00566b7df9c3 Mon Sep 17 00:00:00 2001 +From: Oleg Nesterov +Date: Sat, 25 Feb 2012 07:29:40 -0500 +Subject: [PATCH] utrace for 3.3-rc4 kernel, on top of + b52b80023f262ce8a0ffdcb490acb23e8678377a. -This adds the utrace facility, a new modular interface in the kernel for -implementing user thread tracing and debugging. This fits on top of the -tracehook_* layer, so the new code is well-isolated. +The split-out series is available in the git repository at: -The new interface is in and the DocBook utrace book -describes it. It allows for multiple separate tracing engines to work in -parallel without interfering with each other. Higher-level tracing -facilities can be implemented as loadable kernel modules using this layer. + git@github.com:utrace/linux.git utrace-3.3 -The new facility is made optional under CONFIG_UTRACE. -When this is not enabled, no new code is added. -It can only be enabled on machines that have all the -prerequisites and select CONFIG_HAVE_ARCH_TRACEHOOK. +Oleg Nesterov (31): + utrace: add utrace_init_task/utrace_free_task calls + tracehooks: add utrace hooks + tracehooks: reintroduce tracehook_consider_fatal_signal() + add utrace hooks into sig_ignored() and recalc_sigpending() + restore the EXEC/EXIT/CLONE utrace hooks + utrace: utrace_report_death() can use task_utrace_struct() + restore the DEATH/REAP utrace hooks + utrace: remove jobctl bits + ptrace: take ->siglock around s/TRACED/RUNNING/ + introduce wake_up_quiescent() + introduce ptrace_signal_wake_up() + wait_task_inactive: treat task->state and match_state as bitmasks + introduce TASK_UTRACED state + utrace: use TASK_UTRACED instead of TASK_TRACED + reintroduce tracehook_finish_jctl() as utrace_end_stop() + teach wake_up_quiescent() to do "selective" wake_up + ptrace_stop: do not assume the task is running after wake_up_quiescent() + get_signal_to_deliver: restore/restructure utrace/ptrace signal reporting + utrace_get_signal: s/JOBCTL_STOP_PENDING/JOBCTL_PENDING_MASK/ + introduce ptrace_set_syscall_trace() + introduce PT_SYSCALL_TRACE flag + utrace: don't clear TIF_SYSCALL_TRACE if it is needed by ptrace + introduce task_utrace_lock/task_utrace_unlock + teach ptrace_set_syscall_trace() to play well with utrace + introduce PT_SINGLE_STEP and PT_SINGLE_BLOCK + utrace: finish_resume_report: don't do user_xxx_step() if ptrace_wants_step() + ptrace: shift user_*_step() from ptrace_resume() to ptrace_stop() + ptrace_disable: no need to disable stepping + ptrace_report_syscall: check TIF_SYSCALL_EMU + utrace_resume: check irqs_disabled() to shut up lockdep + utrace: s390: fix the compile problem with traps.c -In this initial version, utrace and ptrace do not play together at all. -If ptrace is attached to a thread, the attach calls in the utrace kernel -API return -EBUSY. If utrace is attached to a thread, the PTRACE_ATTACH -or PTRACE_TRACEME request will return EBUSY to userland. The old ptrace -code is otherwise unchanged and nothing using ptrace should be affected -by this patch as long as utrace is not used at the same time. In the -future we can clean up the ptrace implementation and rework it to use -the utrace API. +Roland McGrath (1): + utrace core -Signed-off-by: Roland McGrath +Tony Breeds (1): + ptrace_report_syscall: check if TIF_SYSCALL_EMU is defined + +Signed-off-by: Oleg Nesterov --- Documentation/DocBook/Makefile | 2 +- Documentation/DocBook/utrace.tmpl | 589 +++++++++ - fs/proc/array.c | 3 + - include/linux/sched.h | 5 + - include/linux/tracehook.h | 87 ++- - include/linux/utrace.h | 692 +++++++++++ + arch/s390/kernel/traps.c | 6 +- + arch/x86/kernel/ptrace.c | 1 - + fs/exec.c | 5 +- + fs/proc/array.c | 14 +- + include/linux/ptrace.h | 7 + + include/linux/sched.h | 25 +- + include/linux/signal.h | 2 + + include/linux/tracehook.h | 59 +- + include/linux/utrace.h | 774 ++++++++++++ init/Kconfig | 9 + kernel/Makefile | 1 + - kernel/fork.c | 3 + - kernel/ptrace.c | 14 + - kernel/utrace.c | 2440 +++++++++++++++++++++++++++++++++++++ - 11 files changed, 3843 insertions(+), 2 deletions(-) + kernel/exit.c | 5 + + kernel/fork.c | 9 + + kernel/ptrace.c | 57 +- + kernel/sched/core.c | 2 +- + kernel/signal.c | 97 ++- + kernel/utrace.c | 2466 +++++++++++++++++++++++++++++++++++++ + 19 files changed, 4074 insertions(+), 56 deletions(-) + create mode 100644 Documentation/DocBook/utrace.tmpl + create mode 100644 include/linux/utrace.h + create mode 100644 kernel/utrace.c diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile -index 8b6e00a..2740633 100644 +index 66725a3..08ed954 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile -@@ -14,7 +14,7 @@ DOCBOOKS := z8530book.xml mcabook.xml de +@@ -14,7 +14,7 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \ genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \ 80211.xml debugobjects.xml sh.xml regulator.xml \ alsa-driver-api.xml writing-an-alsa-driver.xml \ -- tracepoint.xml media.xml drm.xml -+ tracepoint.xml utrace.xml media.xml drm.xml +- tracepoint.xml drm.xml media_api.xml ++ tracepoint.xml utrace.xml drm.xml media_api.xml + + include $(srctree)/Documentation/DocBook/media/Makefile - ### - # The build process is as follows (targets): diff --git a/Documentation/DocBook/utrace.tmpl b/Documentation/DocBook/utrace.tmpl new file mode 100644 -index ...0c40add 100644 +index 0000000..0c40add --- /dev/null +++ b/Documentation/DocBook/utrace.tmpl @@ -0,0 +1,589 @@ @@ -646,8 +681,69 @@ index ...0c40add 100644 + + + +diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c +index 5ce3750..4f0b32f 100644 +--- a/arch/s390/kernel/traps.c ++++ b/arch/s390/kernel/traps.c +@@ -18,7 +18,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +@@ -330,7 +330,7 @@ void __kprobes do_per_trap(struct pt_regs *regs) + + if (notify_die(DIE_SSTEP, "sstep", regs, 0, 0, SIGTRAP) == NOTIFY_STOP) + return; +- if (!current->ptrace) ++ if (!tracehook_consider_fatal_signal(current, SIGTRAP)) + return; + info.si_signo = SIGTRAP; + info.si_errno = 0; +@@ -415,7 +415,7 @@ static void __kprobes illegal_op(struct pt_regs *regs) + if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) + return; + if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) { +- if (current->ptrace) { ++ if (tracehook_consider_fatal_signal(current, SIGTRAP)) { + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_BRKPT; +diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c +index 5026738..97687f3 100644 +--- a/arch/x86/kernel/ptrace.c ++++ b/arch/x86/kernel/ptrace.c +@@ -809,7 +809,6 @@ static int ioperm_get(struct task_struct *target, + */ + void ptrace_disable(struct task_struct *child) + { +- user_disable_single_step(child); + #ifdef TIF_SYSCALL_EMU + clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); + #endif +diff --git a/fs/exec.c b/fs/exec.c +index 92ce83a..87ff31f 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -1402,9 +1402,12 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) + */ + bprm->recursion_depth = depth; + if (retval >= 0) { +- if (depth == 0) ++ if (depth == 0) { ++ UTRACE_HOOK(current, EXEC, ++ report_exec(fmt, bprm, regs)); + ptrace_event(PTRACE_EVENT_EXEC, + old_pid); ++ } + put_binfmt(fmt); + allow_write_access(bprm->file); + if (bprm->file) diff --git a/fs/proc/array.c b/fs/proc/array.c -index fff6572..a67bd83 100644 +index c602b8d..a700b78 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -81,6 +81,7 @@ @@ -658,7 +754,25 @@ index fff6572..a67bd83 100644 #include #include -@@ -192,6 +193,8 @@ static inline void task_state(struct seq +@@ -137,11 +138,12 @@ static const char * const task_state_array[] = { + "D (disk sleep)", /* 2 */ + "T (stopped)", /* 4 */ + "t (tracing stop)", /* 8 */ +- "Z (zombie)", /* 16 */ +- "X (dead)", /* 32 */ +- "x (dead)", /* 64 */ +- "K (wakekill)", /* 128 */ +- "W (waking)", /* 256 */ ++ "t (tracing stop)", /* 16 (stopped by utrace) */ ++ "Z (zombie)", /* 32 */ ++ "X (dead)", /* 64 */ ++ "x (dead)", /* 128 */ ++ "K (wakekill)", /* 256 */ ++ "W (waking)", /* 512 */ + }; + + static inline const char *get_task_state(struct task_struct *tsk) +@@ -192,6 +194,8 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, cred->uid, cred->euid, cred->suid, cred->fsuid, cred->gid, cred->egid, cred->sgid, cred->fsgid); @@ -667,11 +781,87 @@ index fff6572..a67bd83 100644 task_lock(p); if (p->files) fdt = files_fdtable(p->files); +diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h +index c2f1f6a..236b920 100644 +--- a/include/linux/ptrace.h ++++ b/include/linux/ptrace.h +@@ -104,6 +104,10 @@ + + #define PT_TRACE_MASK 0x000003f4 + ++#define PT_SYSCALL_TRACE 0x00020000 ++#define PT_SINGLE_STEP 0x00040000 ++#define PT_SINGLE_BLOCK 0x00080000 ++ + /* single stepping state bits (used on ARM and PA-RISC) */ + #define PT_SINGLESTEP_BIT 31 + #define PT_SINGLESTEP (1< /* For struct task_struct. */ + #include /* for IS_ERR_VALUE */ + ++extern void ptrace_signal_wake_up(struct task_struct *p, int quiescent); + + extern long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data); +@@ -228,6 +233,8 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace) + + if (unlikely(ptrace) && current->ptrace) { + child->ptrace = current->ptrace; ++ child->ptrace &= ++ ~(PT_SYSCALL_TRACE | PT_SINGLE_STEP | PT_SINGLE_BLOCK); + __ptrace_link(child, current->parent); + + if (child->ptrace & PT_SEIZED) diff --git a/include/linux/sched.h b/include/linux/sched.h -index 09f26df..e6fa5e9 100644 +index 7d379a6..a3c4599 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h -@@ -1357,6 +1357,11 @@ struct task_struct { +@@ -185,16 +185,17 @@ print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) + #define TASK_UNINTERRUPTIBLE 2 + #define __TASK_STOPPED 4 + #define __TASK_TRACED 8 ++#define __TASK_UTRACED 16 + /* in tsk->exit_state */ +-#define EXIT_ZOMBIE 16 +-#define EXIT_DEAD 32 ++#define EXIT_ZOMBIE 32 ++#define EXIT_DEAD 64 + /* in tsk->state again */ +-#define TASK_DEAD 64 +-#define TASK_WAKEKILL 128 +-#define TASK_WAKING 256 +-#define TASK_STATE_MAX 512 ++#define TASK_DEAD 128 ++#define TASK_WAKEKILL 256 ++#define TASK_WAKING 512 ++#define TASK_STATE_MAX 1024 + +-#define TASK_STATE_TO_CHAR_STR "RSDTtZXxKW" ++#define TASK_STATE_TO_CHAR_STR "RSDTtUZXxKW" + + extern char ___assert_task_state[1 - 2*!!( + sizeof(TASK_STATE_TO_CHAR_STR)-1 != ilog2(TASK_STATE_MAX)+1)]; +@@ -203,15 +204,16 @@ extern char ___assert_task_state[1 - 2*!!( + #define TASK_KILLABLE (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE) + #define TASK_STOPPED (TASK_WAKEKILL | __TASK_STOPPED) + #define TASK_TRACED (TASK_WAKEKILL | __TASK_TRACED) ++#define TASK_UTRACED (TASK_WAKEKILL | __TASK_UTRACED) + + /* Convenience macros for the sake of wake_up */ + #define TASK_NORMAL (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE) +-#define TASK_ALL (TASK_NORMAL | __TASK_STOPPED | __TASK_TRACED) ++#define TASK_ALL (TASK_NORMAL | __TASK_STOPPED | __TASK_TRACED | __TASK_UTRACED) + + /* get_task_state() */ + #define TASK_REPORT (TASK_RUNNING | TASK_INTERRUPTIBLE | \ + TASK_UNINTERRUPTIBLE | __TASK_STOPPED | \ +- __TASK_TRACED) ++ __TASK_TRACED | __TASK_UTRACED) + + #define task_is_traced(task) ((task->state & __TASK_TRACED) != 0) + #define task_is_stopped(task) ((task->state & __TASK_STOPPED) != 0) +@@ -1420,6 +1422,11 @@ struct task_struct { #endif seccomp_t seccomp; @@ -683,8 +873,21 @@ index 09f26df..e6fa5e9 100644 /* Thread group tracking */ u32 parent_exec_id; u32 self_exec_id; +diff --git a/include/linux/signal.h b/include/linux/signal.h +index 7987ce74..c320549 100644 +--- a/include/linux/signal.h ++++ b/include/linux/signal.h +@@ -239,6 +239,8 @@ static inline int valid_signal(unsigned long sig) + struct timespec; + struct pt_regs; + ++extern int wake_up_quiescent(struct task_struct *p, unsigned int state); ++ + extern int next_signal(struct sigpending *pending, sigset_t *mask); + extern int do_send_sig_info(int sig, struct siginfo *info, + struct task_struct *p, bool group); diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h -index 98917e9..afba8f8 100644 +index a71a292..a1bac95 100644 --- a/include/linux/tracehook.h +++ b/include/linux/tracehook.h @@ -49,6 +49,7 @@ @@ -694,17 +897,23 @@ index 98917e9..afba8f8 100644 +#include struct linux_binprm; - /** -@@ -63,6 +64,8 @@ struct linux_binprm; - */ - static inline int tracehook_expect_breakpoints(struct task_struct *task) + /* +@@ -58,8 +59,12 @@ static inline void ptrace_report_syscall(struct pt_regs *regs) { -+ if (unlikely(task_utrace_flags(task) & UTRACE_EVENT(SIGNAL_CORE))) -+ return 1; - return (task_ptrace(task) & PT_PTRACED) != 0; - } + int ptrace = current->ptrace; -@@ -111,6 +114,9 @@ static inline void ptrace_report_syscall +- if (!(ptrace & PT_PTRACED)) +- return; ++ if (!(ptrace & PT_SYSCALL_TRACE)) { ++#ifdef TIF_SYSCALL_EMU ++ if (!test_thread_flag(TIF_SYSCALL_EMU)) ++#endif ++ return; ++ } + + ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); + +@@ -96,10 +101,16 @@ static inline void ptrace_report_syscall(struct pt_regs *regs) static inline __must_check int tracehook_report_syscall_entry( struct pt_regs *regs) { @@ -714,191 +923,62 @@ index 98917e9..afba8f8 100644 ptrace_report_syscall(regs); return 0; } -@@ -134,6 +140,9 @@ static inline __must_check int tracehook + ++#define ptrace_wants_step(task) \ ++ ((task)->ptrace & (PT_SINGLE_STEP | PT_SINGLE_BLOCK)) ++ + /** + * tracehook_report_syscall_exit - task has just finished a system call + * @regs: user register state of current task +@@ -119,7 +130,10 @@ static inline __must_check int tracehook_report_syscall_entry( */ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) { +- if (step) { + if (task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_EXIT)) + utrace_report_syscall_exit(regs); + - if (step && (task_ptrace(current) & PT_PTRACED)) { ++ if (step && ptrace_wants_step(current)) { siginfo_t info; user_single_step_siginfo(current, regs, &info); -@@ -201,6 +210,8 @@ static inline void tracehook_report_exec - struct linux_binprm *bprm, - struct pt_regs *regs) - { -+ if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(EXEC))) -+ utrace_report_exec(fmt, bprm, regs); - if (!ptrace_event(PT_TRACE_EXEC, PTRACE_EVENT_EXEC, 0) && - unlikely(task_ptrace(current) & PT_PTRACED)) - send_sig(SIGTRAP, current, 0); -@@ -218,10 +229,37 @@ static inline void tracehook_report_exec - */ - static inline void tracehook_report_exit(long *exit_code) - { -+ if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(EXIT))) -+ utrace_report_exit(exit_code); - ptrace_event(PT_TRACE_EXIT, PTRACE_EVENT_EXIT, *exit_code); - } - - /** -+ * tracehook_init_task - task_struct has just been copied -+ * @task: new &struct task_struct just copied from parent -+ * -+ * Called from do_fork() when @task has just been duplicated. -+ * After this, @task will be passed to tracehook_free_task() -+ * even if the rest of its setup fails before it is fully created. -+ */ -+static inline void tracehook_init_task(struct task_struct *task) -+{ -+ utrace_init_task(task); -+} -+ -+/** -+ * tracehook_free_task - task_struct is being freed -+ * @task: dead &struct task_struct being freed -+ * -+ * Called from free_task() when @task is no longer in use. -+ */ -+static inline void tracehook_free_task(struct task_struct *task) -+{ -+ if (task_utrace_struct(task)) -+ utrace_free_task(task); -+} -+ -+/** - * tracehook_prepare_clone - prepare for new child to be cloned - * @clone_flags: %CLONE_* flags from clone/fork/vfork system call - * -@@ -285,6 +323,8 @@ static inline void tracehook_report_clon - unsigned long clone_flags, - pid_t pid, struct task_struct *child) - { -+ if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(CLONE))) -+ utrace_report_clone(clone_flags, child); - if (unlikely(task_ptrace(child))) { - /* - * It doesn't matter who attached/attaching to this -@@ -317,6 +357,9 @@ static inline void tracehook_report_clon - pid_t pid, - struct task_struct *child) - { -+ if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(CLONE)) && -+ (clone_flags & CLONE_VFORK)) -+ utrace_finish_vfork(current); - if (unlikely(trace)) - ptrace_event(0, trace, pid); - } -@@ -351,6 +394,10 @@ static inline void tracehook_report_vfor - */ - static inline void tracehook_prepare_release_task(struct task_struct *task) - { -+ /* see utrace_add_engine() about this barrier */ -+ smp_mb(); -+ if (task_utrace_flags(task)) -+ utrace_maybe_reap(task, task_utrace_struct(task), true); - } - - /** -@@ -365,6 +412,7 @@ static inline void tracehook_prepare_rel - static inline void tracehook_finish_release_task(struct task_struct *task) - { - ptrace_release_task(task); -+ BUG_ON(task->exit_state != EXIT_DEAD); - } - - /** -@@ -386,6 +434,8 @@ static inline void tracehook_signal_hand + force_sig_info(SIGTRAP, &info, current); +@@ -148,10 +162,34 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info, const struct k_sigaction *ka, struct pt_regs *regs, int stepping) { +- if (stepping) + if (task_utrace_flags(current)) + utrace_signal_handler(current, stepping); - if (stepping && (task_ptrace(current) & PT_PTRACED)) ++ if (stepping && ptrace_wants_step(current)) ptrace_notify(SIGTRAP); } -@@ -403,6 +453,8 @@ static inline void tracehook_signal_hand - static inline int tracehook_consider_ignored_signal(struct task_struct *task, - int sig) - { -+ if (unlikely(task_utrace_flags(task) & UTRACE_EVENT(SIGNAL_IGN))) -+ return 1; - return (task_ptrace(task) & PT_PTRACED) != 0; - } -@@ -422,6 +474,9 @@ static inline int tracehook_consider_ign - static inline int tracehook_consider_fatal_signal(struct task_struct *task, - int sig) - { ++/** ++ * tracehook_consider_fatal_signal - suppress special handling of fatal signal ++ * @task: task receiving the signal ++ * @sig: signal number being sent ++ * ++ * Return nonzero to prevent special handling of this termination signal. ++ * Normally handler for signal is %SIG_DFL. It can be %SIG_IGN if @sig is ++ * ignored, in which case force_sig() is about to reset it to %SIG_DFL. ++ * When this returns zero, this signal might cause a quick termination ++ * that does not give the debugger a chance to intercept the signal. ++ * ++ * Called with or without @task->sighand->siglock held. ++ */ ++static inline int tracehook_consider_fatal_signal(struct task_struct *task, ++ int sig) ++{ + if (unlikely(task_utrace_flags(task) & (UTRACE_EVENT(SIGNAL_TERM) | + UTRACE_EVENT(SIGNAL_CORE)))) + return 1; - return (task_ptrace(task) & PT_PTRACED) != 0; - } - -@@ -436,6 +491,8 @@ static inline int tracehook_consider_fat - */ - static inline int tracehook_force_sigpending(void) - { -+ if (unlikely(task_utrace_flags(current))) -+ return utrace_interrupt_pending(); - return 0; - } - -@@ -465,6 +522,8 @@ static inline int tracehook_get_signal(s - siginfo_t *info, - struct k_sigaction *return_ka) - { -+ if (unlikely(task_utrace_flags(task))) -+ return utrace_get_signal(task, regs, info, return_ka); - return 0; - } - -@@ -492,6 +551,8 @@ static inline int tracehook_get_signal(s - */ - static inline int tracehook_notify_jctl(int notify, int why) - { -+ if (task_utrace_flags(current) & UTRACE_EVENT(JCTL)) -+ utrace_report_jctl(notify, why); - return notify ?: task_ptrace(current) ? why : 0; - } - -@@ -502,6 +563,8 @@ static inline int tracehook_notify_jctl( - */ - static inline void tracehook_finish_jctl(void) - { -+ if (task_utrace_flags(current)) -+ utrace_finish_stop(); - } - - #define DEATH_REAP -1 -@@ -524,6 +587,8 @@ static inline void tracehook_finish_jctl - static inline int tracehook_notify_death(struct task_struct *task, - void **death_cookie, int group_dead) - { -+ *death_cookie = task_utrace_struct(task); ++ return task->ptrace != 0; ++} + - if (task_detached(task)) - return task->ptrace ? SIGCHLD : DEATH_REAP; - -@@ -560,6 +625,15 @@ static inline void tracehook_report_deat - int signal, void *death_cookie, - int group_dead) - { -+ /* -+ * If utrace_set_events() was just called to enable -+ * UTRACE_EVENT(DEATH), then we are obliged to call -+ * utrace_report_death() and not miss it. utrace_set_events() -+ * checks @task->exit_state under tasklist_lock to synchronize -+ * with exit_notify(), the caller. -+ */ -+ if (task_utrace_flags(task) & _UTRACE_DEATH_EVENTS) -+ utrace_report_death(task, death_cookie, group_dead, signal); - } - #ifdef TIF_NOTIFY_RESUME -@@ -589,10 +663,21 @@ static inline void set_notify_resume(str + /** + * set_notify_resume - cause tracehook_notify_resume() to be called +@@ -179,10 +217,21 @@ static inline void set_notify_resume(struct task_struct *task) * asynchronously, this will be called again before we return to * user mode. * @@ -923,10 +1003,10 @@ index 98917e9..afba8f8 100644 diff --git a/include/linux/utrace.h b/include/linux/utrace.h new file mode 100644 -index ...f251efe 100644 +index 0000000..46959af --- /dev/null +++ b/include/linux/utrace.h -@@ -0,0 +1,692 @@ +@@ -0,0 +1,774 @@ +/* + * utrace infrastructure interface for debugging user processes + * @@ -1028,7 +1108,7 @@ index ...f251efe 100644 +void utrace_report_clone(unsigned long, struct task_struct *); +void utrace_finish_vfork(struct task_struct *); +void utrace_report_exit(long *exit_code); -+void utrace_report_death(struct task_struct *, struct utrace *, bool, int); ++void utrace_report_death(struct task_struct *, bool, int); +void utrace_report_jctl(int notify, int type); +void utrace_report_exec(struct linux_binfmt *, struct linux_binprm *, + struct pt_regs *regs); @@ -1036,8 +1116,22 @@ index ...f251efe 100644 +void utrace_report_syscall_exit(struct pt_regs *); +void utrace_signal_handler(struct task_struct *, int); + ++#define UTRACE_FLAG(task, ev) (task_utrace_flags(task) & UTRACE_EVENT(ev)) ++ ++#define UTRACE_HOOK(task, ev, callback) \ ++ do { \ ++ if (UTRACE_FLAG(task, ev)) \ ++ utrace_ ## callback; \ ++ } while (0) ++ +#ifndef CONFIG_UTRACE + ++static inline void task_utrace_lock(struct task_struct *task) ++{ ++} ++static inline void task_utrace_unlock(struct task_struct *task) ++{ ++} +/* + * uses these accessors to avoid #ifdef CONFIG_UTRACE. + */ @@ -1060,6 +1154,9 @@ index ...f251efe 100644 + +#else /* CONFIG_UTRACE */ + ++extern void task_utrace_lock(struct task_struct *task); ++extern void task_utrace_unlock(struct task_struct *task); ++ +static inline unsigned long task_utrace_flags(struct task_struct *task) +{ + return task->utrace_flags; @@ -1229,6 +1326,7 @@ index ...f251efe 100644 +#define UTRACE_ATTACH_MATCH_MASK 0x000f +#define UTRACE_ATTACH_CREATE 0x0010 /* Attach a new engine. */ +#define UTRACE_ATTACH_EXCLUSIVE 0x0020 /* Refuse if existing match. */ ++#define UTRACE_ATTACH_ATOMIC 0x0040 /* For _CREATE, don't sleep */ + +/** + * struct utrace_engine - per-engine structure @@ -1618,14 +1716,78 @@ index ...f251efe 100644 + +#endif /* CONFIG_UTRACE */ + ++static inline void utrace_release_task(struct task_struct *task) ++{ ++ /* see utrace_add_engine() about this barrier */ ++ smp_mb(); ++ if (task_utrace_flags(task)) ++ utrace_maybe_reap(task, task_utrace_struct(task), true); ++} ++ ++static inline void utrace_exit_notify(struct task_struct *task, ++ int signal, int group_dead) ++{ ++ /* ++ * If utrace_set_events() was just called to enable ++ * UTRACE_EVENT(DEATH), then we are obliged to call ++ * utrace_report_death() and not miss it. utrace_set_events() ++ * checks @task->exit_state under tasklist_lock to synchronize ++ * with exit_notify(), the caller. ++ */ ++ if (task_utrace_flags(task) & _UTRACE_DEATH_EVENTS) ++ utrace_report_death(task, group_dead, signal); ++} ++ ++/** ++ * utrace_end_stop - report about return from STOPPED/TRACED ++ * ++ * This is called by do_signal_stop() and ptrace_stop after wakeup. ++ */ ++static inline void utrace_end_stop(void) ++{ ++ if (task_utrace_flags(current)) ++ utrace_finish_stop(); ++} ++ ++/** ++ * utrace_hook_signal - deliver synthetic signal to traced task ++ * @task: @current ++ * @regs: task_pt_regs(@current) ++ * @info: details of synthetic signal ++ * @return_ka: sigaction for synthetic signal ++ * ++ * Return zero to check for a real pending signal normally. ++ * Return -1 after releasing the siglock to repeat the check. ++ * Return a signal number to induce an artificial signal delivery, ++ * setting *@info and *@return_ka to specify its details and behavior. ++ * ++ * The @return_ka->sa_handler value controls the disposition of the ++ * signal, no matter the signal number. For %SIG_DFL, the return value ++ * is a representative signal to indicate the behavior (e.g. %SIGTERM ++ * for death, %SIGQUIT for core dump, %SIGSTOP for job control stop, ++ * %SIGTSTP for stop unless in an orphaned pgrp), but the signal number ++ * reported will be @info->si_signo instead. ++ * ++ * Called with @task->sighand->siglock held, before dequeuing pending signals. ++ */ ++static inline int utrace_hook_signal(struct task_struct *task, ++ struct pt_regs *regs, ++ siginfo_t *info, ++ struct k_sigaction *return_ka) ++{ ++ if (unlikely(task_utrace_flags(task))) ++ return utrace_get_signal(task, regs, info, return_ka); ++ return 0; ++} ++ +#endif /* linux/utrace.h */ diff --git a/init/Kconfig b/init/Kconfig -index c972899..17483b7 100644 +index 3f42cd6..5f4f92e 100644 --- a/init/Kconfig +++ b/init/Kconfig -@@ -339,6 +339,15 @@ config AUDIT_TREE - depends on AUDITSYSCALL - select FSNOTIFY +@@ -386,6 +386,15 @@ config AUDIT_LOGINUID_IMMUTABLE + one to drop potentially dangerous capabilites from the login tasks, + but may not be backwards compatible with older init systems. +config UTRACE + bool "Infrastructure for tracing and debugging user processes" @@ -1640,10 +1802,10 @@ index c972899..17483b7 100644 menu "RCU Subsystem" diff --git a/kernel/Makefile b/kernel/Makefile -index 0b5ff08..1172528 100644 +index 2d9de86..6c6749d 100644 --- a/kernel/Makefile +++ b/kernel/Makefile -@@ -70,6 +70,7 @@ obj-$(CONFIG_IKCONFIG) += configs.o +@@ -67,6 +67,7 @@ obj-$(CONFIG_IKCONFIG) += configs.o obj-$(CONFIG_RESOURCE_COUNTERS) += res_counter.o obj-$(CONFIG_SMP) += stop_machine.o obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o @@ -1651,79 +1813,418 @@ index 0b5ff08..1172528 100644 obj-$(CONFIG_AUDIT) += audit.o auditfilter.o obj-$(CONFIG_AUDITSYSCALL) += auditsc.o obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o +diff --git a/kernel/exit.c b/kernel/exit.c +index 4b4042f..b1e0518 100644 +--- a/kernel/exit.c ++++ b/kernel/exit.c +@@ -169,6 +169,8 @@ void release_task(struct task_struct * p) + struct task_struct *leader; + int zap_leader; + repeat: ++ utrace_release_task(p); ++ + /* don't need to get the RCU readlock here - the process is dead and + * can't be modifying its own credentials. But shut RCU-lockdep up */ + rcu_read_lock(); +@@ -857,6 +859,8 @@ static void exit_notify(struct task_struct *tsk, int group_dead) + wake_up_process(tsk->signal->group_exit_task); + write_unlock_irq(&tasklist_lock); + ++ utrace_exit_notify(tsk, autoreap ? -1 : SIGCHLD, group_dead); ++ + /* If the process is dead, release it - nobody will wait for it */ + if (autoreap) + release_task(tsk); +@@ -910,6 +914,7 @@ void do_exit(long code) + */ + set_fs(USER_DS); + ++ UTRACE_HOOK(current, EXIT, report_exit(&code)); + ptrace_event(PTRACE_EVENT_EXIT, code); + + validate_creds_for_do_exit(tsk); diff --git a/kernel/fork.c b/kernel/fork.c -index 5447dc7..10a39fe 100644 +index e2cd3e2..fa40928 100644 --- a/kernel/fork.c +++ b/kernel/fork.c -@@ -162,6 +162,7 @@ void free_task(struct task_struct *tsk) +@@ -67,6 +67,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -170,6 +171,8 @@ void free_task(struct task_struct *tsk) free_thread_info(tsk->stack); rt_mutex_debug_task_free(tsk); ftrace_graph_exit_task(tsk); -+ tracehook_free_task(tsk); ++ if (task_utrace_struct(tsk)) ++ utrace_free_task(tsk); free_task_struct(tsk); } EXPORT_SYMBOL(free_task); -@@ -1018,6 +1019,8 @@ static struct task_struct *copy_process( +@@ -1115,6 +1118,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, if (!p) goto fork_out; -+ tracehook_init_task(p); ++ utrace_init_task(p); + ftrace_graph_init_task(p); rt_mutex_init_task(p); +@@ -1583,6 +1583,8 @@ long do_fork(unsigned long clone_flags, + get_task_struct(p); + } + ++ UTRACE_HOOK(current, CLONE, report_clone(clone_flags, p)); ++ + wake_up_new_task(p); + + /* forking complete and child started to run, tell ptracer */ +@@ -1561,6 +1568,8 @@ long do_fork(unsigned long clone_flags, + wake_up_new_task(p); + + /* forking complete and child started to run, tell ptracer */ ++ if (clone_flags & CLONE_VFORK) ++ UTRACE_HOOK(current, CLONE, finish_vfork(current)); + if (unlikely(trace)) + ptrace_event(trace, nr); + diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index 84d9f8f..e275608 100644 +index 00ab2ca..a7024b8 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c -@@ -15,6 +15,7 @@ - #include - #include - #include +@@ -24,7 +24,34 @@ + #include + #include + #include +#include - #include - #include - #include -@@ -163,6 +164,14 @@ bool ptrace_may_access(struct task_struc - return !err; - } -+/* -+ * For experimental use of utrace, exclude ptrace on the same task. -+ */ -+static inline bool exclude_ptrace(struct task_struct *task) ++void ptrace_signal_wake_up(struct task_struct *p, int quiescent) +{ -+ return unlikely(!!task_utrace_flags(task)); ++ unsigned int state; ++ ++ set_tsk_thread_flag(p, TIF_SIGPENDING); ++ ++ state = TASK_INTERRUPTIBLE; ++ if (quiescent) ++ state |= (__TASK_STOPPED | __TASK_TRACED); ++ if (!wake_up_quiescent(p, state)) ++ kick_process(p); +} + - int ptrace_attach(struct task_struct *task) - { - int retval; -@@ -186,6 +195,8 @@ int ptrace_attach(struct task_struct *ta ++static void ptrace_set_syscall_trace(struct task_struct *p, bool on) ++{ ++ task_utrace_lock(p); ++ if (on) { ++ p->ptrace |= PT_SYSCALL_TRACE; ++ set_tsk_thread_flag(p, TIF_SYSCALL_TRACE); ++ } else { ++ p->ptrace &= ~PT_SYSCALL_TRACE; ++ if (!(task_utrace_flags(p) & UTRACE_EVENT_SYSCALL)) ++ clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); ++ } ++ task_utrace_unlock(p); ++} - task_lock(task); - retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH); -+ if (!retval && exclude_ptrace(task)) -+ retval = -EBUSY; - task_unlock(task); - if (retval) - goto unlock_creds; -@@ -223,6 +234,9 @@ int ptrace_traceme(void) + static int ptrace_trapping_sleep_fn(void *flags) { - int ret = -EPERM; +@@ -117,7 +144,7 @@ void __ptrace_unlink(struct task_struct *child) + * TASK_KILLABLE sleeps. + */ + if (child->jobctl & JOBCTL_STOP_PENDING || task_is_traced(child)) +- signal_wake_up(child, task_is_traced(child)); ++ ptrace_signal_wake_up(child, task_is_traced(child)); + + spin_unlock(&child->sighand->siglock); + } +@@ -315,7 +342,7 @@ static int ptrace_attach(struct task_struct *task, long request, + */ + if (task_is_stopped(task) && + task_set_jobctl_pending(task, JOBCTL_TRAP_STOP | JOBCTL_TRAPPING)) +- signal_wake_up(task, 1); ++ ptrace_signal_wake_up(task, 1); + + spin_unlock(&task->sighand->siglock); + +@@ -425,7 +452,7 @@ static int ptrace_detach(struct task_struct *child, unsigned int data) + + /* Architecture-specific hardware disable .. */ + ptrace_disable(child); +- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); ++ ptrace_set_syscall_trace(child, false); -+ if (exclude_ptrace(current)) /* XXX locking */ -+ return -EBUSY; -+ write_lock_irq(&tasklist_lock); - /* Are we already being traced? */ - if (!current->ptrace) { + /* +@@ -608,13 +635,12 @@ static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info) + static int ptrace_resume(struct task_struct *child, long request, + unsigned long data) + { ++ unsigned long flags; ++ + if (!valid_signal(data)) + return -EIO; + +- if (request == PTRACE_SYSCALL) +- set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); +- else +- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); ++ ptrace_set_syscall_trace(child, request == PTRACE_SYSCALL); + + #ifdef TIF_SYSCALL_EMU + if (request == PTRACE_SYSEMU || request == PTRACE_SYSEMU_SINGLESTEP) +@@ -623,20 +649,23 @@ static int ptrace_resume(struct task_struct *child, long request, + clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); + #endif + ++ child->ptrace &= ~(PT_SINGLE_STEP | PT_SINGLE_BLOCK); + if (is_singleblock(request)) { + if (unlikely(!arch_has_block_step())) + return -EIO; +- user_enable_block_step(child); ++ child->ptrace |= PT_SINGLE_BLOCK; + } else if (is_singlestep(request) || is_sysemu_singlestep(request)) { + if (unlikely(!arch_has_single_step())) + return -EIO; +- user_enable_single_step(child); +- } else { +- user_disable_single_step(child); ++ child->ptrace |= PT_SINGLE_STEP; + } + + child->exit_code = data; +- wake_up_state(child, __TASK_TRACED); ++ ++ if (lock_task_sighand(child, &flags)) { ++ wake_up_quiescent(child, __TASK_TRACED); ++ unlock_task_sighand(child, &flags); ++ } + + return 0; + } +@@ -744,7 +773,7 @@ int ptrace_request(struct task_struct *child, long request, + * tracee into STOP. + */ + if (likely(task_set_jobctl_pending(child, JOBCTL_TRAP_STOP))) +- signal_wake_up(child, child->jobctl & JOBCTL_LISTENING); ++ ptrace_signal_wake_up(child, child->jobctl & JOBCTL_LISTENING); + + unlock_task_sighand(child, &flags); + ret = 0; +@@ -770,7 +799,7 @@ int ptrace_request(struct task_struct *child, long request, + * start of this trap and now. Trigger re-trap. + */ + if (child->jobctl & JOBCTL_TRAP_NOTIFY) +- signal_wake_up(child, true); ++ ptrace_signal_wake_up(child, true); + ret = 0; + } + unlock_task_sighand(child, &flags); +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index 5255c9d..f1719b8 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -1167,7 +1167,7 @@ unsigned long wait_task_inactive(struct task_struct *p, long match_state) + * is actually now running somewhere else! + */ + while (task_running(rq, p)) { +- if (match_state && unlikely(p->state != match_state)) ++ if (match_state && !likely(p->state & match_state)) + return 0; + cpu_relax(); + } +diff --git a/kernel/signal.c b/kernel/signal.c +index c73c428..0508d93 100644 +--- a/kernel/signal.c ++++ b/kernel/signal.c +@@ -88,7 +88,7 @@ static int sig_ignored(struct task_struct *t, int sig, int from_ancestor_ns) + /* + * Tracers may want to know about even ignored signals. + */ +- return !t->ptrace; ++ return !t->ptrace && !UTRACE_FLAG(t, SIGNAL_IGN); + } + + /* +@@ -151,6 +151,11 @@ void recalc_sigpending_and_wake(struct task_struct *t) + + void recalc_sigpending(void) + { ++ if (task_utrace_flags(current) && utrace_interrupt_pending()) { ++ set_thread_flag(TIF_SIGPENDING); ++ return; ++ } ++ + if (!recalc_sigpending_tsk(current) && !freezing(current)) + clear_thread_flag(TIF_SIGPENDING); + +@@ -495,7 +500,7 @@ int unhandled_signal(struct task_struct *tsk, int sig) + if (handler != SIG_IGN && handler != SIG_DFL) + return 0; + /* if ptraced, let the tracer determine */ +- return !tsk->ptrace; ++ return !tracehook_consider_fatal_signal(tsk, sig); + } + + /* +@@ -697,6 +702,29 @@ void signal_wake_up(struct task_struct *t, int resume) + kick_process(t); + } + ++#define STATE_QUIESCENT (__TASK_STOPPED | __TASK_TRACED | __TASK_UTRACED) ++/* ++ * wakes up the STOPPED/TRACED task, must be called with ->siglock held. ++ */ ++int wake_up_quiescent(struct task_struct *p, unsigned int state) ++{ ++ unsigned int quiescent = (p->state & STATE_QUIESCENT); ++ ++ WARN_ON(state & ~(STATE_QUIESCENT | TASK_INTERRUPTIBLE)); ++ ++ if (quiescent) { ++ state &= ~TASK_INTERRUPTIBLE; ++ if ((quiescent & ~state) != 0) { ++ p->state &= ~state; ++ WARN_ON(!(p->state & STATE_QUIESCENT)); ++ WARN_ON(!(p->state & TASK_WAKEKILL)); ++ return 0; ++ } ++ } ++ ++ return wake_up_state(p, state); ++} ++ + /* + * Remove signals in mask from the pending set and queue. + * Returns 1 if any signals were found. +@@ -842,7 +870,7 @@ static void ptrace_trap_notify(struct task_struct *t) + assert_spin_locked(&t->sighand->siglock); + + task_set_jobctl_pending(t, JOBCTL_TRAP_NOTIFY); +- signal_wake_up(t, t->jobctl & JOBCTL_LISTENING); ++ ptrace_signal_wake_up(t, t->jobctl & JOBCTL_LISTENING); + } + + /* +@@ -884,7 +912,7 @@ static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns) + task_clear_jobctl_pending(t, JOBCTL_STOP_PENDING); + rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending); + if (likely(!(t->ptrace & PT_SEIZED))) +- wake_up_state(t, __TASK_STOPPED); ++ wake_up_quiescent(t, __TASK_STOPPED); + else + ptrace_trap_notify(t); + } while_each_thread(p, t); +@@ -983,7 +1011,7 @@ static void complete_signal(int sig, struct task_struct *p, int group) + if (sig_fatal(p, sig) && + !(signal->flags & (SIGNAL_UNKILLABLE | SIGNAL_GROUP_EXIT)) && + !sigismember(&t->real_blocked, sig) && +- (sig == SIGKILL || !t->ptrace)) { ++ (sig == SIGKILL || !tracehook_consider_fatal_signal(t, sig))) { + /* + * This signal will be fatal to the whole group. + */ +@@ -1913,10 +1941,34 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) + if (gstop_done) + do_notify_parent_cldstop(current, false, why); + +- __set_current_state(TASK_RUNNING); ++ spin_lock_irq(¤t->sighand->siglock); ++ wake_up_quiescent(current, __TASK_TRACED); ++ spin_unlock_irq(¤t->sighand->siglock); ++ + if (clear_code) + current->exit_code = 0; + read_unlock(&tasklist_lock); ++ ++ /* ++ * It is possible that __TASK_UTRACED was added by utrace ++ * while we were __TASK_TRACED and before we take ->siglock ++ * for wake_up_quiescent(), we need to block in this case. ++ * Otherwise this is unnecessary but absolutely harmless. ++ */ ++ schedule(); ++ } ++ ++ utrace_end_stop(); ++ ++ if (current->ptrace & PT_SINGLE_BLOCK) ++ user_enable_block_step(current); ++ else if (current->ptrace & PT_SINGLE_STEP) ++ user_enable_single_step(current); ++ else { ++ user_disable_single_step(current); ++ /* if utrace needs the stepping it should reassert */ ++ if (task_utrace_flags(current)) ++ set_thread_flag(TIF_NOTIFY_RESUME); + } + + /* +@@ -2081,6 +2133,9 @@ static bool do_signal_stop(int signr) + + /* Now we don't run again until woken by SIGCONT or SIGKILL */ + schedule(); ++ ++ utrace_end_stop(); ++ + return true; + } else { + /* +@@ -2231,17 +2286,27 @@ relock: + for (;;) { + struct k_sigaction *ka; + +- if (unlikely(current->jobctl & JOBCTL_STOP_PENDING) && +- do_signal_stop(0)) ++ signr = utrace_hook_signal(current, regs, info, return_ka); ++ if (unlikely(signr < 0)) + goto relock; + +- if (unlikely(current->jobctl & JOBCTL_TRAP_MASK)) { +- do_jobctl_trap(); +- spin_unlock_irq(&sighand->siglock); +- goto relock; +- } ++ if (unlikely(signr != 0)) ++ ka = return_ka; ++ else { ++ if (unlikely(current->jobctl & JOBCTL_STOP_PENDING) && ++ do_signal_stop(0)) ++ goto relock; ++ ++ if (unlikely(current->jobctl & JOBCTL_TRAP_MASK)) { ++ do_jobctl_trap(); ++ spin_unlock_irq(&sighand->siglock); ++ goto relock; ++ } + +- signr = dequeue_signal(current, ¤t->blocked, info); ++ signr = dequeue_signal(current, ¤t->blocked, info); ++ ++ ka = &sighand->action[signr-1]; ++ } + + if (!signr) + break; /* will return 0 */ +@@ -2251,9 +2316,9 @@ relock: + regs, cookie); + if (!signr) + continue; +- } + +- ka = &sighand->action[signr-1]; ++ ka = &sighand->action[signr-1]; ++ } + + /* Trace actually delivered signals. */ + trace_signal_deliver(signr, info, ka); diff --git a/kernel/utrace.c b/kernel/utrace.c new file mode 100644 -index ...26d6faf 100644 +index 0000000..a169e1b --- /dev/null +++ b/kernel/utrace.c -@@ -0,0 +1,2440 @@ +@@ -0,0 +1,2466 @@ +/* + * utrace infrastructure interface for debugging user processes + * @@ -1805,6 +2306,32 @@ index ...26d6faf 100644 +} +module_init(utrace_init); + ++void task_utrace_lock(struct task_struct *task) ++{ ++ struct utrace *utrace = task_utrace_struct(task); ++ ++ if (!utrace) { ++ task_lock(task); ++ utrace = task_utrace_struct(task); ++ if (!utrace) ++ return; ++ ++ task_unlock(task); ++ } ++ ++ spin_lock(&utrace->lock); ++} ++ ++void task_utrace_unlock(struct task_struct *task) ++{ ++ struct utrace *utrace = task_utrace_struct(task); ++ ++ if (utrace) ++ spin_unlock(&utrace->lock); ++ else ++ task_unlock(task); ++} ++ +/* + * Set up @task.utrace for the first time. We can have races + * between two utrace_attach_task() calls here. The task_lock() @@ -1813,9 +2340,9 @@ index ...26d6faf 100644 + * + * This returns false only in case of a memory allocation failure. + */ -+static bool utrace_task_alloc(struct task_struct *task) ++static bool utrace_task_alloc(struct task_struct *task, gfp_t gfp_flags) +{ -+ struct utrace *utrace = kmem_cache_zalloc(utrace_cachep, GFP_KERNEL); ++ struct utrace *utrace = kmem_cache_zalloc(utrace_cachep, gfp_flags); + if (unlikely(!utrace)) + return false; + spin_lock_init(&utrace->lock); @@ -1995,6 +2522,7 @@ index ...26d6faf 100644 +{ + struct utrace *utrace = task_utrace_struct(target); + struct utrace_engine *engine; ++ gfp_t gfp_flags; + int ret; + + if (!(flags & UTRACE_ATTACH_CREATE)) { @@ -2017,13 +2545,16 @@ index ...26d6faf 100644 + */ + return ERR_PTR(-EPERM); + ++ gfp_flags = (flags & UTRACE_ATTACH_ATOMIC) ++ ? GFP_ATOMIC : GFP_KERNEL; ++ + if (!utrace) { -+ if (unlikely(!utrace_task_alloc(target))) ++ if (unlikely(!utrace_task_alloc(target, gfp_flags))) + return ERR_PTR(-ENOMEM); + utrace = task_utrace_struct(target); + } + -+ engine = kmem_cache_alloc(utrace_engine_cachep, GFP_KERNEL); ++ engine = kmem_cache_alloc(utrace_engine_cachep, gfp_flags); + if (unlikely(!engine)) + return ERR_PTR(-ENOMEM); + @@ -2188,6 +2719,8 @@ index ...26d6faf 100644 + */ +#define ENGINE_STOP (1UL << _UTRACE_NEVENTS) + ++#define task_is_utraced(task) ((task->state & __TASK_UTRACED) != 0) ++ +static void mark_engine_wants_stop(struct task_struct *task, + struct utrace_engine *engine) +{ @@ -2302,7 +2835,7 @@ index ...26d6faf 100644 + + ret = 0; + if ((old_flags & ~events) && target != current && -+ !task_is_stopped_or_traced(target) && !target->exit_state) { ++ !task_is_utraced(target) && !target->exit_state) { + /* + * This barrier ensures that our engine->flags changes + * have hit before we examine utrace->reporting, @@ -2349,21 +2882,21 @@ index ...26d6faf 100644 + */ +static bool utrace_do_stop(struct task_struct *target, struct utrace *utrace) +{ -+ if (task_is_stopped(target)) { ++ if (task_is_stopped_or_traced(target)) { + /* + * Stopped is considered quiescent; when it wakes up, it will + * go through utrace_finish_stop() before doing anything else. + */ + spin_lock_irq(&target->sighand->siglock); -+ if (likely(task_is_stopped(target))) -+ __set_task_state(target, TASK_TRACED); ++ if (likely(task_is_stopped_or_traced(target))) ++ target->state |= TASK_UTRACED; + spin_unlock_irq(&target->sighand->siglock); + } else if (utrace->resume > UTRACE_REPORT) { + utrace->resume = UTRACE_REPORT; + set_notify_resume(target); + } + -+ return task_is_traced(target); ++ return task_is_utraced(target); +} + +/* @@ -2374,11 +2907,7 @@ index ...26d6faf 100644 +{ + lockdep_assert_held(&utrace->lock); + spin_lock_irq(&target->sighand->siglock); -+ if (target->signal->flags & SIGNAL_STOP_STOPPED || -+ target->signal->group_stop_count) -+ target->state = TASK_STOPPED; -+ else -+ wake_up_state(target, __TASK_TRACED); ++ wake_up_quiescent(target, __TASK_UTRACED); + spin_unlock_irq(&target->sighand->siglock); +} + @@ -2425,6 +2954,7 @@ index ...26d6faf 100644 + BUG_ON(utrace->death); + flags &= UTRACE_EVENT(REAP); + } else if (!(flags & UTRACE_EVENT_SYSCALL) && ++ !(task->ptrace & PT_SYSCALL_TRACE) && + test_tsk_thread_flag(task, TIF_SYSCALL_TRACE)) { + clear_tsk_thread_flag(task, TIF_SYSCALL_TRACE); + } @@ -2440,7 +2970,7 @@ index ...26d6faf 100644 + /* + * If no more engines want it stopped, wake it up. + */ -+ if (task_is_traced(task) && !(flags & ENGINE_STOP)) { ++ if (task_is_utraced(task) && !(flags & ENGINE_STOP)) { + /* + * It just resumes, so make sure single-step + * is not left set. @@ -2469,7 +2999,7 @@ index ...26d6faf 100644 +void utrace_finish_stop(void) +{ + /* -+ * If we were task_is_traced() and then SIGKILL'ed, make ++ * If we were task_is_utraced() and then SIGKILL'ed, make + * sure we do nothing until the tracer drops utrace->lock. + */ + if (unlikely(__fatal_signal_pending(current))) { @@ -2479,7 +3009,7 @@ index ...26d6faf 100644 +} + +/* -+ * Perform %UTRACE_STOP, i.e. block in TASK_TRACED until woken up. ++ * Perform %UTRACE_STOP, i.e. block in TASK_UTRACED until woken up. + * @task == current, @utrace == current->utrace, which is not locked. + * Return true if we were woken up by SIGKILL even though some utrace + * engine may still want us to stay stopped. @@ -2529,15 +3059,7 @@ index ...26d6faf 100644 + return; + } + -+ __set_current_state(TASK_TRACED); -+ -+ /* -+ * If there is a group stop in progress, -+ * we must participate in the bookkeeping. -+ */ -+ if (unlikely(task->signal->group_stop_count) && -+ !--task->signal->group_stop_count) -+ task->signal->flags = SIGNAL_STOP_STOPPED; ++ __set_current_state(TASK_UTRACED); + + spin_unlock_irq(&task->sighand->siglock); + spin_unlock(&utrace->lock); @@ -2547,14 +3069,14 @@ index ...26d6faf 100644 + utrace_finish_stop(); + + /* -+ * While in TASK_TRACED, we were considered "frozen enough". ++ * While in TASK_UTRACED, we were considered "frozen enough". + * Now that we woke up, it's crucial if we're supposed to be + * frozen that we freeze now before running anything substantial. + */ + try_to_freeze(); + + /* -+ * While we were in TASK_TRACED, complete_signal() considered ++ * While we were in TASK_UTRACED, complete_signal() considered + * us "uninterested" in signal wakeups. Now make sure our + * TIF_SIGPENDING state is correct for normal running. + */ @@ -2825,7 +3347,7 @@ index ...26d6faf 100644 + if (unlikely(IS_ERR(utrace))) + return PTR_ERR(utrace); + -+ reset = task_is_traced(target); ++ reset = task_is_utraced(target); + ret = 0; + + /* @@ -3485,9 +4007,10 @@ index ...26d6faf 100644 + * For this reason, utrace_release_task checks for the event bits that get + * us here, and delays its cleanup for us to do. + */ -+void utrace_report_death(struct task_struct *task, struct utrace *utrace, -+ bool group_dead, int signal) ++void utrace_report_death(struct task_struct *task, bool group_dead, int signal) +{ ++ struct utrace *utrace = task_utrace_struct(task); ++ + INIT_REPORT(report); + + BUG_ON(!task->exit_state); @@ -3537,7 +4060,8 @@ index ...26d6faf 100644 + + case UTRACE_BLOCKSTEP: + if (likely(arch_has_block_step())) { -+ user_enable_block_step(task); ++ if (!ptrace_wants_step(task)) ++ user_enable_block_step(task); + break; + } + @@ -3550,7 +4074,8 @@ index ...26d6faf 100644 + + case UTRACE_SINGLESTEP: + if (likely(arch_has_single_step())) { -+ user_enable_single_step(task); ++ if (!ptrace_wants_step(task)) ++ user_enable_single_step(task); + } else { + /* + * This means some callback is to blame for failing @@ -3565,7 +4090,8 @@ index ...26d6faf 100644 + case UTRACE_REPORT: + case UTRACE_RESUME: + default: -+ user_disable_single_step(task); ++ if (!ptrace_wants_step(task)) ++ user_disable_single_step(task); + break; + } +} @@ -3586,7 +4112,8 @@ index ...26d6faf 100644 + * code path leads to calling into get_signal_to_deliver(), which + * implicitly reenables them by virtue of spin_unlock_irq. + */ -+ local_irq_enable(); ++ if (irqs_disabled()) /* make trace_hardirqs_on() happy */ ++ local_irq_enable(); + + /* + * If this flag is still set it's because there was a signal @@ -3762,7 +4289,7 @@ index ...26d6faf 100644 + ka = NULL; + memset(return_ka, 0, sizeof *return_ka); + } else if (!(task->utrace_flags & UTRACE_EVENT_SIGNAL_ALL) || -+ unlikely(task->signal->group_stop_count)) { ++ unlikely(task->jobctl & JOBCTL_PENDING_MASK)) { + /* + * If no engine is interested in intercepting signals or + * we must stop, let the caller just dequeue them normally @@ -4010,7 +4537,7 @@ index ...26d6faf 100644 + spin_lock_irq(&task->sighand->siglock); + + if (sig_kernel_stop(signr)) -+ task->signal->flags |= SIGNAL_STOP_DEQUEUED; ++ task->jobctl |= JOBCTL_STOP_DEQUEUED; + + return signr; +} @@ -4164,3 +4691,6 @@ index ...26d6faf 100644 +{ + seq_printf(m, "Utrace:\t%lx\n", p->utrace_flags); +} +-- +1.7.9.1 + diff --git a/weird-root-dentry-name-debug.patch b/weird-root-dentry-name-debug.patch new file mode 100644 index 000000000..e2fb2e116 --- /dev/null +++ b/weird-root-dentry-name-debug.patch @@ -0,0 +1,19 @@ +debug patch for bz 787171/766277 + +diff --git a/fs/dcache.c b/fs/dcache.c +index bcbdb33..a6a5fdb 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -2530,8 +2530,10 @@ global_root: + */ + if (IS_ROOT(dentry) && + (dentry->d_name.len != 1 || dentry->d_name.name[0] != '/')) { +- WARN(1, "Root dentry has weird name <%.*s>\n", +- (int) dentry->d_name.len, dentry->d_name.name); ++ WARN(1, "Root dentry has weird name <%.*s> vfsmnt:%s fs:%s\n", ++ (int) dentry->d_name.len, dentry->d_name.name, ++ vfsmnt->mnt_root->d_name.name, ++ vfsmnt->mnt_sb->s_type->name); + } + if (!slash) + error = prepend(buffer, buflen, "/", 1);