diff options
405 files changed, 6050 insertions, 4653 deletions
diff --git a/Documentation/ABI/testing/sysfs-firmware-sgi_uv b/Documentation/ABI/testing/sysfs-firmware-sgi_uv new file mode 100644 index 000000000000..4573fd4b7876 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-firmware-sgi_uv @@ -0,0 +1,27 @@ +What: /sys/firmware/sgi_uv/ +Date: August 2008 +Contact: Russ Anderson <rja@sgi.com> +Description: + The /sys/firmware/sgi_uv directory contains information + about the SGI UV platform. + + Under that directory are a number of files: + + partition_id + coherence_id + + The partition_id entry contains the partition id. + SGI UV systems can be partitioned into multiple physical + machines, which each partition running a unique copy + of the operating system. Each partition will have a unique + partition id. To display the partition id, use the command: + + cat /sys/firmware/sgi_uv/partition_id + + The coherence_id entry contains the coherence id. + A partitioned SGI UV system can have one or more coherence + domain. The coherence id indicates which coherence domain + this partition is in. To display the coherence id, use the + command: + + cat /sys/firmware/sgi_uv/coherence_id diff --git a/Documentation/dontdiff b/Documentation/dontdiff index 881e6dd03aea..27809357da58 100644 --- a/Documentation/dontdiff +++ b/Documentation/dontdiff @@ -5,6 +5,8 @@ *.css *.dvi *.eps +*.fw.gen.S +*.fw *.gif *.grep *.grp diff --git a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt index e79ee2db183a..ac2a261c5f7d 100644 --- a/Documentation/filesystems/ntfs.txt +++ b/Documentation/filesystems/ntfs.txt @@ -40,7 +40,7 @@ Web site ======== There is plenty of additional information on the linux-ntfs web site -at http://linux-ntfs.sourceforge.net/ +at http://www.linux-ntfs.org/ The web site has a lot of additional information, such as a comprehensive FAQ, documentation on the NTFS on-disk format, information on the Linux-NTFS @@ -272,7 +272,7 @@ And you would know that /dev/hda2 has a size of 37768814 - 4209030 + 1 = For Win2k and later dynamic disks, you can for example use the ldminfo utility which is part of the Linux LDM tools (the latest version at the time of writing is linux-ldm-0.0.8.tar.bz2). You can download it from: - http://linux-ntfs.sourceforge.net/downloads.html + http://www.linux-ntfs.org/ Simply extract the downloaded archive (tar xvjf linux-ldm-0.0.8.tar.bz2), go into it (cd linux-ldm-0.0.8) and change to the test directory (cd test). You will find the precompiled (i386) ldminfo utility there. NOTE: You will not be diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 64557821ee59..394eb2cc1c39 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -1339,6 +1339,25 @@ Enables/Disables the protection of the per-process proc entries "maps" and "smaps". When enabled, the contents of these files are visible only to readers that are allowed to ptrace() the given process. +msgmni +------ + +Maximum number of message queue ids on the system. +This value scales to the amount of lowmem. It is automatically recomputed +upon memory add/remove or ipc namespace creation/removal. +When a value is written into this file, msgmni's value becomes fixed, i.e. it +is not recomputed anymore when one of the above events occurs. +Use auto_msgmni to change this behavior. + +auto_msgmni +----------- + +Enables/Disables automatic recomputing of msgmni upon memory add/remove or +upon ipc namespace creation/removal (see the msgmni description above). +Echoing "1" into this file enables msgmni automatic recomputing. +Echoing "0" turns it off. +auto_msgmni default value is 1. + 2.4 /proc/sys/vm - The virtual memory subsystem ----------------------------------------------- diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index 02dc748b76c4..71f0fe1fc1b0 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -44,7 +44,7 @@ detailed description): - LCD brightness control - Volume control - Fan control and monitoring: fan speed, fan enable/disable - - Experimental: WAN enable and disable + - WAN enable and disable A compatibility table by model and feature is maintained on the web site, http://ibm-acpi.sf.net/. I appreciate any success or failure @@ -1375,18 +1375,13 @@ with EINVAL, try to set pwm1_enable to 1 and pwm1 to at least 128 (255 would be the safest choice, though). -EXPERIMENTAL: WAN ------------------ +WAN +--- procfs: /proc/acpi/ibm/wan sysfs device attribute: wwan_enable (deprecated) sysfs rfkill class: switch "tpacpi_wwan_sw" -This feature is marked EXPERIMENTAL because the implementation -directly accesses hardware registers and may not work as expected. USE -WITH CAUTION! To use this feature, you need to supply the -experimental=1 parameter when loading the module. - This feature shows the presence and current state of a W-WAN (Sierra Wireless EV-DO) device. diff --git a/Documentation/video4linux/CARDLIST.au0828 b/Documentation/video4linux/CARDLIST.au0828 index eedc399e8deb..aa05e5bb22fb 100644 --- a/Documentation/video4linux/CARDLIST.au0828 +++ b/Documentation/video4linux/CARDLIST.au0828 @@ -3,3 +3,4 @@ 2 -> Hauppauge HVR850 (au0828) [2040:7240] 3 -> DViCO FusionHDTV USB (au0828) [0fe9:d620] 4 -> Hauppauge HVR950Q rev xxF8 (au0828) [2040:7201,2040:7211,2040:7281] + 5 -> Hauppauge Woodbury (au0828) [2040:8200] diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt index 78a863ab8a5a..0f03900c48fb 100644 --- a/Documentation/video4linux/gspca.txt +++ b/Documentation/video4linux/gspca.txt @@ -88,14 +88,14 @@ zc3xx 0471:0325 Philips SPC 200 NC zc3xx 0471:0326 Philips SPC 300 NC sonixj 0471:0327 Philips SPC 600 NC sonixj 0471:0328 Philips SPC 700 NC -zc3xx 0471:032d Philips spc210nc -zc3xx 0471:032e Philips spc315nc -sonixj 0471:0330 Philips SPC 710NC +zc3xx 0471:032d Philips SPC 210 NC +zc3xx 0471:032e Philips SPC 315 NC +sonixj 0471:0330 Philips SPC 710 NC spca501 0497:c001 Smile International sunplus 04a5:3003 Benq DC 1300 sunplus 04a5:3008 Benq DC 1500 -sunplus 04a5:300a Benq DC3410 -spca500 04a5:300c Benq DC1016 +sunplus 04a5:300a Benq DC 3410 +spca500 04a5:300c Benq DC 1016 sunplus 04f1:1001 JVC GC A50 spca561 04fc:0561 Flexcam 100 sunplus 04fc:500c Sunplus CA500C @@ -175,19 +175,21 @@ sunplus 08ca:2060 Aiptek PocketDV5300 tv8532 0923:010f ICM532 cams mars 093a:050f Mars-Semi Pc-Camera pac207 093a:2460 PAC207 Qtec Webcam 100 -pac207 093a:2463 Philips spc200nc pac207 +pac207 093a:2463 Philips SPC 220 NC pac207 093a:2464 Labtec Webcam 1200 pac207 093a:2468 PAC207 pac207 093a:2470 Genius GF112 -pac207 093a:2471 PAC207 Genius VideoCam ge111 -pac207 093a:2472 PAC207 Genius VideoCam ge110 +pac207 093a:2471 Genius VideoCam ge111 +pac207 093a:2472 Genius VideoCam ge110 pac7311 093a:2600 PAC7311 Typhoon -pac7311 093a:2601 PAC7311 Phillips SPC610NC +pac7311 093a:2601 Philips SPC 610 NC pac7311 093a:2603 PAC7312 -pac7311 093a:2608 PAC7311 Trust WB-3300p -pac7311 093a:260e PAC7311 Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350 -pac7311 093a:260f PAC7311 SnakeCam +pac7311 093a:2608 Trust WB-3300p +pac7311 093a:260e Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350 +pac7311 093a:260f SnakeCam pac7311 093a:2621 PAC731x +pac7311 093a:2624 PAC7302 +pac7311 093a:2626 Labtec 2200 zc3xx 0ac8:0302 Z-star Vimicro zc0302 vc032x 0ac8:0321 Vimicro generic vc0321 vc032x 0ac8:0323 Vimicro Vc0323 @@ -220,6 +222,7 @@ sonixj 0c45:60c0 Sangha Sn535 sonixj 0c45:60ec SN9C105+MO4000 sonixj 0c45:60fb Surfer NoName sonixj 0c45:60fc LG-LIC300 +sonixj 0c45:6128 Microdia/Sonix SNP325 sonixj 0c45:612a Avant Camera sonixj 0c45:612c Typhoon Rasy Cam 1.3MPix sonixj 0c45:6130 Sonix Pccam @@ -234,7 +237,7 @@ zc3xx 10fd:0128 Typhoon Webshot II USB 300k 0x0128 spca561 10fd:7e50 FlyCam Usb 100 zc3xx 10fd:8050 Typhoon Webshot II USB 300k spca501 1776:501c Arowana 300K CMOS Camera -t613 17a1:0128 T613/TAS5130A +t613 17a1:0128 TASCORP JPEG Webcam, NGS Cyclops vc032x 17ef:4802 Lenovo Vc0323+MI1310_SOC pac207 2001:f115 D-Link DSB-C120 spca500 2899:012c Toptro Industrial diff --git a/MAINTAINERS b/MAINTAINERS index c4ca99cf80df..b3e92fbe336c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -222,8 +222,7 @@ W: http://code.google.com/p/aceracpi S: Maintained ACPI -P: Andi Kleen -M: ak@linux.intel.com +P: Len Brown M: lenb@kernel.org L: linux-acpi@vger.kernel.org W: http://www.lesswatts.org/projects/acpi/ @@ -419,6 +418,12 @@ L: linux-laptop@vger.kernel.org W: http://www.canb.auug.org.au/~sfr/ S: Supported +APPLE BCM5974 MULTITOUCH DRIVER +P: Henrik Rydberg +M: rydberg@euromail.se +L: linux-input@vger.kernel.org +S: Maintained + APPLE SMC DRIVER P: Nicolas Boichat M: nicolas@boichat.ch @@ -1588,7 +1593,7 @@ S: Supported EMBEDDED LINUX P: Paul Gortmaker M: paul.gortmaker@windriver.com -P David Woodhouse +P: David Woodhouse M: dwmw2@infradead.org L: linux-embedded@vger.kernel.org S: Maintained @@ -3051,7 +3056,7 @@ P: Anton Altaparmakov M: aia21@cantab.net L: linux-ntfs-dev@lists.sourceforge.net L: linux-kernel@vger.kernel.org -W: http://linux-ntfs.sf.net/ +W: http://www.linux-ntfs.org/ T: git kernel.org:/pub/scm/linux/kernel/git/aia21/ntfs-2.6.git S: Maintained diff --git a/arch/arm/include/asm/byteorder.h b/arch/arm/include/asm/byteorder.h index d04a7a2bc2e9..4fbfb22f65a0 100644 --- a/arch/arm/include/asm/byteorder.h +++ b/arch/arm/include/asm/byteorder.h @@ -18,15 +18,7 @@ #include <linux/compiler.h> #include <asm/types.h> -#ifdef __ARMEB__ -# define __BIG_ENDIAN -#else -# define __LITTLE_ENDIAN -#endif - -#define __SWAB_64_THRU_32__ - -static inline __attribute_const__ __u32 __arch_swab32(__u32 x) +static inline __attribute_const__ __u32 ___arch__swab32(__u32 x) { __u32 t; @@ -48,8 +40,19 @@ static inline __attribute_const__ __u32 __arch_swab32(__u32 x) return x; } -#define __arch_swab32 __arch_swab32 -#include <linux/byteorder.h> +#define __arch__swab32(x) ___arch__swab32(x) + +#if !defined(__STRICT_ANSI__) || defined(__KERNEL__) +# define __BYTEORDER_HAS_U64__ +# define __SWAB_64_THRU_32__ +#endif + +#ifdef __ARMEB__ +#include <linux/byteorder/big_endian.h> +#else +#include <linux/byteorder/little_endian.h> +#endif #endif + diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index 94a95d7fafd6..71934856fc22 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h @@ -61,8 +61,9 @@ extern void __raw_readsl(const void __iomem *addr, void *data, int longlen); #define MT_DEVICE_NONSHARED 1 #define MT_DEVICE_CACHED 2 #define MT_DEVICE_IXP2000 3 +#define MT_DEVICE_WC 4 /* - * types 4 onwards can be found in asm/mach/map.h and are undefined + * types 5 onwards can be found in asm/mach/map.h and are undefined * for ioremap */ @@ -215,11 +216,13 @@ extern void _memset_io(volatile void __iomem *, int, size_t); #define ioremap(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE) #define ioremap_nocache(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE) #define ioremap_cached(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE_CACHED) +#define ioremap_wc(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE_WC) #define iounmap(cookie) __iounmap(cookie) #else #define ioremap(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE) #define ioremap_nocache(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE) #define ioremap_cached(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE_CACHED) +#define ioremap_wc(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE_WC) #define iounmap(cookie) __arch_iounmap(cookie) #endif diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h index 06f583b13999..9eb936e49cc3 100644 --- a/arch/arm/include/asm/mach/map.h +++ b/arch/arm/include/asm/mach/map.h @@ -18,13 +18,13 @@ struct map_desc { unsigned int type; }; -/* types 0-3 are defined in asm/io.h */ -#define MT_CACHECLEAN 4 -#define MT_MINICLEAN 5 -#define MT_LOW_VECTORS 6 -#define MT_HIGH_VECTORS 7 -#define MT_MEMORY 8 -#define MT_ROM 9 +/* types 0-4 are defined in asm/io.h */ +#define MT_CACHECLEAN 5 +#define MT_MINICLEAN 6 +#define MT_LOW_VECTORS 7 +#define MT_HIGH_VECTORS 8 +#define MT_MEMORY 9 +#define MT_ROM 10 #define MT_NONSHARED_DEVICE MT_DEVICE_NONSHARED #define MT_IXP2000_DEVICE MT_DEVICE_IXP2000 diff --git a/arch/arm/mach-omap1/mcbsp.c b/arch/arm/mach-omap1/mcbsp.c index 826010d5d014..2baeaeb0c900 100644 --- a/arch/arm/mach-omap1/mcbsp.c +++ b/arch/arm/mach-omap1/mcbsp.c @@ -159,6 +159,7 @@ static struct omap_mcbsp_ops omap1_mcbsp_ops = { #ifdef CONFIG_ARCH_OMAP730 static struct omap_mcbsp_platform_data omap730_mcbsp_pdata[] = { { + .phys_base = OMAP730_MCBSP1_BASE, .virt_base = io_p2v(OMAP730_MCBSP1_BASE), .dma_rx_sync = OMAP_DMA_MCBSP1_RX, .dma_tx_sync = OMAP_DMA_MCBSP1_TX, @@ -167,6 +168,7 @@ static struct omap_mcbsp_platform_data omap730_mcbsp_pdata[] = { .ops = &omap1_mcbsp_ops, }, { + .phys_base = OMAP730_MCBSP2_BASE, .virt_base = io_p2v(OMAP730_MCBSP2_BASE), .dma_rx_sync = OMAP_DMA_MCBSP3_RX, .dma_tx_sync = OMAP_DMA_MCBSP3_TX, @@ -184,6 +186,7 @@ static struct omap_mcbsp_platform_data omap730_mcbsp_pdata[] = { #ifdef CONFIG_ARCH_OMAP15XX static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = { { + .phys_base = OMAP1510_MCBSP1_BASE, .virt_base = OMAP1510_MCBSP1_BASE, .dma_rx_sync = OMAP_DMA_MCBSP1_RX, .dma_tx_sync = OMAP_DMA_MCBSP1_TX, @@ -193,6 +196,7 @@ static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = { .clk_name = "mcbsp_clk", }, { + .phys_base = OMAP1510_MCBSP2_BASE, .virt_base = io_p2v(OMAP1510_MCBSP2_BASE), .dma_rx_sync = OMAP_DMA_MCBSP2_RX, .dma_tx_sync = OMAP_DMA_MCBSP2_TX, @@ -201,6 +205,7 @@ static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = { .ops = &omap1_mcbsp_ops, }, { + .phys_base = OMAP1510_MCBSP3_BASE, .virt_base = OMAP1510_MCBSP3_BASE, .dma_rx_sync = OMAP_DMA_MCBSP3_RX, .dma_tx_sync = OMAP_DMA_MCBSP3_TX, @@ -219,6 +224,7 @@ static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = { #ifdef CONFIG_ARCH_OMAP16XX static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = { { + .phys_base = OMAP1610_MCBSP1_BASE, .virt_base = OMAP1610_MCBSP1_BASE, .dma_rx_sync = OMAP_DMA_MCBSP1_RX, .dma_tx_sync = OMAP_DMA_MCBSP1_TX, @@ -228,6 +234,7 @@ static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = { .clk_name = "mcbsp_clk", }, { + .phys_base = OMAP1610_MCBSP2_BASE, .virt_base = io_p2v(OMAP1610_MCBSP2_BASE), .dma_rx_sync = OMAP_DMA_MCBSP2_RX, .dma_tx_sync = OMAP_DMA_MCBSP2_TX, @@ -236,6 +243,7 @@ static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = { .ops = &omap1_mcbsp_ops, }, { + .phys_base = OMAP1610_MCBSP3_BASE, .virt_base = OMAP1610_MCBSP3_BASE, .dma_rx_sync = OMAP_DMA_MCBSP3_RX, .dma_tx_sync = OMAP_DMA_MCBSP3_TX, diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c index 27eb6e3ca926..b261f1f80b5e 100644 --- a/arch/arm/mach-omap2/mcbsp.c +++ b/arch/arm/mach-omap2/mcbsp.c @@ -134,6 +134,7 @@ static struct omap_mcbsp_ops omap2_mcbsp_ops = { #ifdef CONFIG_ARCH_OMAP24XX static struct omap_mcbsp_platform_data omap24xx_mcbsp_pdata[] = { { + .phys_base = OMAP24XX_MCBSP1_BASE, .virt_base = IO_ADDRESS(OMAP24XX_MCBSP1_BASE), .dma_rx_sync = OMAP24XX_DMA_MCBSP1_RX, .dma_tx_sync = OMAP24XX_DMA_MCBSP1_TX, @@ -143,6 +144,7 @@ static struct omap_mcbsp_platform_data omap24xx_mcbsp_pdata[] = { .clk_name = "mcbsp_clk", }, { + .phys_base = OMAP24XX_MCBSP2_BASE, .virt_base = IO_ADDRESS(OMAP24XX_MCBSP2_BASE), .dma_rx_sync = OMAP24XX_DMA_MCBSP2_RX, .dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX, @@ -161,6 +163,7 @@ static struct omap_mcbsp_platform_data omap24xx_mcbsp_pdata[] = { #ifdef CONFIG_ARCH_OMAP34XX static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { { + .phys_base = OMAP34XX_MCBSP1_BASE, .virt_base = IO_ADDRESS(OMAP34XX_MCBSP1_BASE), .dma_rx_sync = OMAP24XX_DMA_MCBSP1_RX, .dma_tx_sync = OMAP24XX_DMA_MCBSP1_TX, @@ -170,6 +173,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { .clk_name = "mcbsp_clk", }, { + .phys_base = OMAP34XX_MCBSP2_BASE, .virt_base = IO_ADDRESS(OMAP34XX_MCBSP2_BASE), .dma_rx_sync = OMAP24XX_DMA_MCBSP2_RX, .dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX, diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 25d9a11eb617..a713e40e1f1a 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -211,6 +211,12 @@ static struct mem_type mem_types[] = { PMD_SECT_TEX(1), .domain = DOMAIN_IO, }, + [MT_DEVICE_WC] = { /* ioremap_wc */ + .prot_pte = PROT_PTE_DEVICE, + .prot_l1 = PMD_TYPE_TABLE, + .prot_sect = PROT_SECT_DEVICE, + .domain = DOMAIN_IO, + }, [MT_CACHECLEAN] = { .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN, .domain = DOMAIN_KERNEL, @@ -273,6 +279,20 @@ static void __init build_mem_type_table(void) } /* + * On non-Xscale3 ARMv5-and-older systems, use CB=01 + * (Uncached/Buffered) for ioremap_wc() mappings. On XScale3 + * and ARMv6+, use TEXCB=00100 mappings (Inner/Outer Uncacheable + * in xsc3 parlance, Uncached Normal in ARMv6 parlance). + */ + if (cpu_is_xsc3() || cpu_arch >= CPU_ARCH_ARMv6) { + mem_types[MT_DEVICE_WC].prot_pte_ext |= PTE_EXT_TEX(1); + mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_TEX(1); + } else { + mem_types[MT_DEVICE_WC].prot_pte |= L_PTE_BUFFERABLE; + mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_BUFFERABLE; + } + + /* * ARMv5 and lower, bit 4 must be set for page tables. * (was: cache "update-able on write" bit on ARM610) * However, Xscale cores require this bit to be cleared. diff --git a/arch/arm/plat-mxc/clock.c b/arch/arm/plat-mxc/clock.c index 2f8627218839..0a38f0b396eb 100644 --- a/arch/arm/plat-mxc/clock.c +++ b/arch/arm/plat-mxc/clock.c @@ -37,7 +37,6 @@ #include <linux/proc_fs.h> #include <linux/semaphore.h> #include <linux/string.h> -#include <linux/version.h> #include <mach/clock.h> diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index 3e76ee2bc731..9e1341ebc14e 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -1488,7 +1488,7 @@ static int __init _omap_gpio_init(void) bank->chip.set = gpio_set; if (bank_is_mpuio(bank)) { bank->chip.label = "mpuio"; -#ifdef CONFIG_ARCH_OMAP1 +#ifdef CONFIG_ARCH_OMAP16XX bank->chip.dev = &omap_mpuio_device.dev; #endif bank->chip.base = OMAP_MPUIO(0); diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/mach/mcbsp.h index 6eb44a92871d..8fdb95e26fcd 100644 --- a/arch/arm/plat-omap/include/mach/mcbsp.h +++ b/arch/arm/plat-omap/include/mach/mcbsp.h @@ -315,6 +315,7 @@ struct omap_mcbsp_ops { }; struct omap_mcbsp_platform_data { + unsigned long phys_base; u32 virt_base; u8 dma_rx_sync, dma_tx_sync; u16 rx_irq, tx_irq; @@ -324,6 +325,7 @@ struct omap_mcbsp_platform_data { struct omap_mcbsp { struct device *dev; + unsigned long phys_base; u32 io_base; u8 id; u8 free; diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index d0844050f2d2..014d26574bb6 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -651,7 +651,7 @@ int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, omap_set_dma_dest_params(mcbsp[id].dma_tx_lch, src_port, OMAP_DMA_AMODE_CONSTANT, - mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1, + mcbsp[id].phys_base + OMAP_MCBSP_REG_DXR1, 0, 0); omap_set_dma_src_params(mcbsp[id].dma_tx_lch, @@ -712,7 +712,7 @@ int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, omap_set_dma_src_params(mcbsp[id].dma_rx_lch, src_port, OMAP_DMA_AMODE_CONSTANT, - mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1, + mcbsp[id].phys_base + OMAP_MCBSP_REG_DRR1, 0, 0); omap_set_dma_dest_params(mcbsp[id].dma_rx_lch, @@ -830,6 +830,7 @@ static int __init omap_mcbsp_probe(struct platform_device *pdev) mcbsp[id].dma_tx_lch = -1; mcbsp[id].dma_rx_lch = -1; + mcbsp[id].phys_base = pdata->phys_base; mcbsp[id].io_base = pdata->virt_base; /* Default I/O is IRQ based */ mcbsp[id].io_type = OMAP_MCBSP_IRQ_IO; diff --git a/arch/avr32/kernel/asm-offsets.c b/arch/avr32/kernel/asm-offsets.c index e4796c67a831..d6a8193a1d2f 100644 --- a/arch/avr32/kernel/asm-offsets.c +++ b/arch/avr32/kernel/asm-offsets.c @@ -4,6 +4,8 @@ * to extract and format the required data. */ +#include <linux/mm.h> +#include <linux/sched.h> #include <linux/thread_info.h> #include <linux/kbuild.h> @@ -17,4 +19,8 @@ void foo(void) OFFSET(TI_rar_saved, thread_info, rar_saved); OFFSET(TI_rsr_saved, thread_info, rsr_saved); OFFSET(TI_restart_block, thread_info, restart_block); + BLANK(); + OFFSET(TSK_active_mm, task_struct, active_mm); + BLANK(); + OFFSET(MM_pgd, mm_struct, pgd); } diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S index 2b398cae110c..33d49377b8be 100644 --- a/arch/avr32/kernel/entry-avr32b.S +++ b/arch/avr32/kernel/entry-avr32b.S @@ -334,9 +334,64 @@ save_full_context_ex: /* Low-level exception handlers */ handle_critical: + /* + * AT32AP700x errata: + * + * After a Java stack overflow or underflow trap, any CPU + * memory access may cause erratic behavior. This will happen + * when the four least significant bits of the JOSP system + * register contains any value between 9 and 15 (inclusive). + * + * Possible workarounds: + * - Don't use the Java Extension Module + * - Ensure that the stack overflow and underflow trap + * handlers do not do any memory access or trigger any + * exceptions before the overflow/underflow condition is + * cleared (by incrementing or decrementing the JOSP) + * - Make sure that JOSP does not contain any problematic + * value before doing any exception or interrupt + * processing. + * - Set up a critical exception handler which writes a + * known-to-be-safe value, e.g. 4, to JOSP before doing + * any further processing. + * + * We'll use the last workaround for now since we cannot + * guarantee that user space processes don't use Java mode. + * Non-well-behaving userland will be terminated with extreme + * prejudice. + */ +#ifdef CONFIG_CPU_AT32AP700X + /* + * There's a chance we can't touch memory, so temporarily + * borrow PTBR to save the stack pointer while we fix things + * up... + */ + mtsr SYSREG_PTBR, sp + mov sp, 4 + mtsr SYSREG_JOSP, sp + mfsr sp, SYSREG_PTBR + sub pc, -2 + + /* Push most of pt_regs on stack. We'll do the rest later */ sub sp, 4 - stmts --sp, r0-lr - rcall save_full_context_ex + pushm r0-r12 + + /* PTBR mirrors current_thread_info()->task->active_mm->pgd */ + get_thread_info r0 + ld.w r1, r0[TI_task] + ld.w r2, r1[TSK_active_mm] + ld.w r3, r2[MM_pgd] + mtsr SYSREG_PTBR, r3 +#else + sub sp, 4 + pushm r0-r12 +#endif + sub r0, sp, -(14 * 4) + mov r1, lr + mfsr r2, SYSREG_RAR_EX + mfsr r3, SYSREG_RSR_EX + pushm r0-r3 + mfsr r12, SYSREG_ECR mov r11, sp rcall do_critical_exception diff --git a/arch/avr32/mach-at32ap/pm-at32ap700x.S b/arch/avr32/mach-at32ap/pm-at32ap700x.S index 5be4de65b209..17503b0ed6c9 100644 --- a/arch/avr32/mach-at32ap/pm-at32ap700x.S +++ b/arch/avr32/mach-at32ap/pm-at32ap700x.S @@ -134,7 +134,7 @@ pm_standby: mov r11, SDRAMC_LPR_LPCB_SELF_RFR bfins r10, r11, 0, 2 /* LPCB <- self Refresh */ sync 0 /* flush write buffer */ - st.w r12[SDRAMC_LPR], r11 /* put SDRAM in self-refresh mode */ + st.w r12[SDRAMC_LPR], r10 /* put SDRAM in self-refresh mode */ ld.w r11, r12[SDRAMC_LPR] unmask_interrupts sleep CPU_SLEEP_FROZEN diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c index 8a2a53b33616..bb959fbab2dc 100644 --- a/arch/m68k/atari/atakeyb.c +++ b/arch/m68k/atari/atakeyb.c @@ -580,13 +580,15 @@ int atari_keyb_init(void) do { /* reset IKBD ACIA */ acia.key_ctrl = ACIA_RESET | - (atari_switches & ATARI_SWITCH_IKBD) ? ACIA_RHTID : 0; + ((atari_switches & ATARI_SWITCH_IKBD) ? + ACIA_RHTID : 0); (void)acia.key_ctrl; (void)acia.key_data; /* reset MIDI ACIA */ acia.mid_ctrl = ACIA_RESET | - (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0; + ((atari_switches & ATARI_SWITCH_MIDI) ? + ACIA_RHTID : 0); (void)acia.mid_ctrl; (void)acia.mid_data; @@ -599,7 +601,8 @@ int atari_keyb_init(void) ACIA_RHTID : ACIA_RLTID); acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | - (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0; + ((atari_switches & ATARI_SWITCH_MIDI) ? + ACIA_RHTID : 0); /* make sure the interrupt line is up */ } while ((mfp.par_dt_reg & 0x10) == 0); diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 4da736e25333..49896a2a1d72 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1886,6 +1886,15 @@ config STACKTRACE_SUPPORT source "init/Kconfig" +config PROBE_INITRD_HEADER + bool "Probe initrd header created by addinitrd" + depends on BLK_DEV_INITRD + help + Probe initrd header at the last page of kernel image. + Say Y here if you are using arch/mips/boot/addinitrd.c to + add initrd or initramfs image to the kernel image. + Otherwise, say N. + menu "Bus options (PCI, PCMCIA, EISA, ISA, TC)" config HW_HAS_EISA diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 2aae76bce293..16f8edfe5cdc 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -160,30 +160,33 @@ early_param("rd_size", rd_size_early); static unsigned long __init init_initrd(void) { unsigned long end; - u32 *initrd_header; /* * Board specific code or command line parser should have * already set up initrd_start and initrd_end. In these cases * perfom sanity checks and use them if all looks good. */ - if (initrd_start && initrd_end > initrd_start) - goto sanitize; + if (!initrd_start || initrd_end <= initrd_start) { +#ifdef CONFIG_PROBE_INITRD_HEADER + u32 *initrd_header; - /* - * See if initrd has been added to the kernel image by - * arch/mips/boot/addinitrd.c. In that case a header is - * prepended to initrd and is made up by 8 bytes. The fisrt - * word is a magic number and the second one is the size of - * initrd. Initrd start must be page aligned in any cases. - */ - initrd_header = __va(PAGE_ALIGN(__pa_symbol(&_end) + 8)) - 8; - if (initrd_header[0] != 0x494E5244) + /* + * See if initrd has been added to the kernel image by + * arch/mips/boot/addinitrd.c. In that case a header is + * prepended to initrd and is made up by 8 bytes. The first + * word is a magic number and the second one is the size of + * initrd. Initrd start must be page aligned in any cases. + */ + initrd_header = __va(PAGE_ALIGN(__pa_symbol(&_end) + 8)) - 8; + if (initrd_header[0] != 0x494E5244) + goto disable; + initrd_start = (unsigned long)(initrd_header + 2); + initrd_end = initrd_start + initrd_header[1]; +#else goto disable; - initrd_start = (unsigned long)(initrd_header + 2); - initrd_end = initrd_start + initrd_header[1]; +#endif + } -sanitize: if (initrd_start & ~PAGE_MASK) { pr_err("initrd start must be page aligned\n"); goto disable; diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 426cced1e9dc..6bee29097a56 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -373,8 +373,8 @@ void __noreturn die(const char * str, const struct pt_regs * regs) do_exit(SIGSEGV); } -extern const struct exception_table_entry __start___dbe_table[]; -extern const struct exception_table_entry __stop___dbe_table[]; +extern struct exception_table_entry __start___dbe_table[]; +extern struct exception_table_entry __stop___dbe_table[]; __asm__( " .section __dbe_table, \"a\"\n" @@ -1200,7 +1200,7 @@ void *set_except_vector(int n, void *addr) if (n == 0 && cpu_has_divec) { *(u32 *)(ebase + 0x200) = 0x08000000 | (0x03ffffff & (handler >> 2)); - flush_icache_range(ebase + 0x200, ebase + 0x204); + local_flush_icache_range(ebase + 0x200, ebase + 0x204); } return (void *)old_handler; } @@ -1283,7 +1283,8 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) *w = (*w & 0xffff0000) | (((u32)handler >> 16) & 0xffff); w = (u32 *)(b + ori_offset); *w = (*w & 0xffff0000) | ((u32)handler & 0xffff); - flush_icache_range((unsigned long)b, (unsigned long)(b+handler_len)); + local_flush_icache_range((unsigned long)b, + (unsigned long)(b+handler_len)); } else { /* @@ -1295,7 +1296,8 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) w = (u32 *)b; *w++ = 0x08000000 | (((u32)handler >> 2) & 0x03fffff); /* j handler */ *w = 0; - flush_icache_range((unsigned long)b, (unsigned long)(b+8)); + local_flush_icache_range((unsigned long)b, + (unsigned long)(b+8)); } return (void *)old_handler; @@ -1515,7 +1517,7 @@ void __cpuinit per_cpu_trap_init(void) void __init set_handler(unsigned long offset, void *addr, unsigned long size) { memcpy((void *)(ebase + offset), addr, size); - flush_icache_range(ebase + offset, ebase + offset + size); + local_flush_icache_range(ebase + offset, ebase + offset + size); } static char panic_null_cerr[] __cpuinitdata = @@ -1680,6 +1682,8 @@ void __init trap_init(void) signal32_init(); #endif - flush_icache_range(ebase, ebase + 0x400); + local_flush_icache_range(ebase, ebase + 0x400); flush_tlb_handlers(); + + sort_extable(__start___dbe_table, __stop___dbe_table); } diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c index 27a5b466c85c..5500c20c79ae 100644 --- a/arch/mips/mm/c-r3k.c +++ b/arch/mips/mm/c-r3k.c @@ -320,6 +320,7 @@ void __cpuinit r3k_cache_init(void) flush_cache_range = r3k_flush_cache_range; flush_cache_page = r3k_flush_cache_page; flush_icache_range = r3k_flush_icache_range; + local_flush_icache_range = r3k_flush_icache_range; flush_cache_sigtramp = r3k_flush_cache_sigtramp; local_flush_data_cache_page = local_r3k_flush_data_cache_page; diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 71df3390c07b..6e99665ae860 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -543,12 +543,8 @@ struct flush_icache_range_args { unsigned long end; }; -static inline void local_r4k_flush_icache_range(void *args) +static inline void local_r4k_flush_icache_range(unsigned long start, unsigned long end) { - struct flush_icache_range_args *fir_args = args; - unsigned long start = fir_args->start; - unsigned long end = fir_args->end; - if (!cpu_has_ic_fills_f_dc) { if (end - start >= dcache_size) { r4k_blast_dcache(); @@ -564,6 +560,15 @@ static inline void local_r4k_flush_icache_range(void *args) protected_blast_icache_range(start, end); } +static inline void local_r4k_flush_icache_range_ipi(void *args) +{ + struct flush_icache_range_args *fir_args = args; + unsigned long start = fir_args->start; + unsigned long end = fir_args->end; + + local_r4k_flush_icache_range(start, end); +} + static void r4k_flush_icache_range(unsigned long start, unsigned long end) { struct flush_icache_range_args args; @@ -571,7 +576,7 @@ static void r4k_flush_icache_range(unsigned long start, unsigned long end) args.start = start; args.end = end; - r4k_on_each_cpu(local_r4k_flush_icache_range, &args, 1); + r4k_on_each_cpu(local_r4k_flush_icache_range_ipi, &args, 1); instruction_hazard(); } @@ -1375,6 +1380,7 @@ void __cpuinit r4k_cache_init(void) local_flush_data_cache_page = local_r4k_flush_data_cache_page; flush_data_cache_page = r4k_flush_data_cache_page; flush_icache_range = r4k_flush_icache_range; + local_flush_icache_range = local_r4k_flush_icache_range; #if defined(CONFIG_DMA_NONCOHERENT) if (coherentio) { diff --git a/arch/mips/mm/c-tx39.c b/arch/mips/mm/c-tx39.c index a9f7f1f5e9b4..f7c8f9ce39c1 100644 --- a/arch/mips/mm/c-tx39.c +++ b/arch/mips/mm/c-tx39.c @@ -362,6 +362,7 @@ void __cpuinit tx39_cache_init(void) flush_cache_range = (void *) tx39h_flush_icache_all; flush_cache_page = (void *) tx39h_flush_icache_all; flush_icache_range = (void *) tx39h_flush_icache_all; + local_flush_icache_range = (void *) tx39h_flush_icache_all; flush_cache_sigtramp = (void *) tx39h_flush_icache_all; local_flush_data_cache_page = (void *) tx39h_flush_icache_all; @@ -390,6 +391,7 @@ void __cpuinit tx39_cache_init(void) flush_cache_range = tx39_flush_cache_range; flush_cache_page = tx39_flush_cache_page; flush_icache_range = tx39_flush_icache_range; + local_flush_icache_range = tx39_flush_icache_range; flush_cache_sigtramp = tx39_flush_cache_sigtramp; local_flush_data_cache_page = local_tx39_flush_data_cache_page; diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 034e8506f6ea..1eb7c71e3d6a 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -29,6 +29,7 @@ void (*flush_cache_range)(struct vm_area_struct *vma, unsigned long start, void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, unsigned long pfn); void (*flush_icache_range)(unsigned long start, unsigned long end); +void (*local_flush_icache_range)(unsigned long start, unsigned long end); void (*__flush_cache_vmap)(void); void (*__flush_cache_vunmap)(void); diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 76da73a5ab3c..979cf9197282 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -1273,10 +1273,10 @@ void __cpuinit build_tlb_refill_handler(void) void __cpuinit flush_tlb_handlers(void) { - flush_icache_range((unsigned long)handle_tlbl, + local_flush_icache_range((unsigned long)handle_tlbl, (unsigned long)handle_tlbl + sizeof(handle_tlbl)); - flush_icache_range((unsigned long)handle_tlbs, + local_flush_icache_range((unsigned long)handle_tlbs, (unsigned long)handle_tlbs + sizeof(handle_tlbs)); - flush_icache_range((unsigned long)handle_tlbm, + local_flush_icache_range((unsigned long)handle_tlbm, (unsigned long)handle_tlbm + sizeof(handle_tlbm)); } diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c index 0afe94c48fb6..fe6bee09cece 100644 --- a/arch/mips/txx9/generic/setup.c +++ b/arch/mips/txx9/generic/setup.c @@ -53,6 +53,7 @@ txx9_reg_res_init(unsigned int pcode, unsigned long base, unsigned long size) txx9_ce_res[i].name = txx9_ce_res_name[i]; } + txx9_pcode = pcode; sprintf(txx9_pcode_str, "TX%x", pcode); if (base) { txx9_reg_res.start = base & 0xfffffffffULL; diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c index 69ff671498e5..12c04c5e558b 100644 --- a/arch/parisc/hpux/fs.c +++ b/arch/parisc/hpux/fs.c @@ -104,7 +104,7 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset, buf->count -= reclen; return 0; Efault: - buffer->error = -EFAULT; + buf->error = -EFAULT; return -EFAULT; } diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 9155c9312c1e..c6be19e9ceae 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -116,6 +116,11 @@ ifeq ($(CONFIG_6xx),y) KBUILD_CFLAGS += -mcpu=powerpc endif +# Work around a gcc code-gen bug with -fno-omit-frame-pointer. +ifeq ($(CONFIG_FTRACE),y) +KBUILD_CFLAGS += -mno-sched-epilog +endif + cpu-as-$(CONFIG_4xx) += -Wa,-m405 cpu-as-$(CONFIG_6xx) += -Wa,-maltivec cpu-as-$(CONFIG_POWER4) += -Wa,-maltivec diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 14174aa24074..717a3bc1352e 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -49,7 +49,7 @@ zlib := inffast.c inflate.c inftrees.c zlibheader := inffast.h inffixed.h inflate.h inftrees.h infutil.h zliblinuxheader := zlib.h zconf.h zutil.h -$(addprefix $(obj)/,$(zlib) gunzip_util.o main.o): \ +$(addprefix $(obj)/,$(zlib) cuboot-c2k.o gunzip_util.o main.o prpmc2800.o): \ $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader)) src-libfdt := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h index db0b8f3b8807..4597c491e9b5 100644 --- a/arch/powerpc/include/asm/pgtable-ppc64.h +++ b/arch/powerpc/include/asm/pgtable-ppc64.h @@ -153,12 +153,10 @@ #define __S110 PAGE_SHARED_X #define __S111 PAGE_SHARED_X -#ifdef CONFIG_HUGETLB_PAGE - +#ifdef CONFIG_PPC_MM_SLICES #define HAVE_ARCH_UNMAPPED_AREA #define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN - -#endif +#endif /* CONFIG_PPC_MM_SLICES */ #ifndef __ASSEMBLY__ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 64f5948ebc9d..946daea780f1 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -14,12 +14,13 @@ endif ifdef CONFIG_FTRACE # Do not trace early boot code -CFLAGS_REMOVE_cputable.o = -pg -CFLAGS_REMOVE_prom_init.o = -pg +CFLAGS_REMOVE_cputable.o = -pg -mno-sched-epilog +CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog +CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog ifdef CONFIG_DYNAMIC_FTRACE # dynamic ftrace setup. -CFLAGS_REMOVE_ftrace.o = -pg +CFLAGS_REMOVE_ftrace.o = -pg -mno-sched-epilog endif endif diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c index 367129789cc0..5af4e9b2dbe2 100644 --- a/arch/powerpc/kernel/align.c +++ b/arch/powerpc/kernel/align.c @@ -647,7 +647,7 @@ static int emulate_vsx(unsigned char __user *addr, unsigned int reg, unsigned int flags, unsigned int length) { char *ptr = (char *) ¤t->thread.TS_FPR(reg); - int ret; + int ret = 0; flush_vsx_to_thread(current); diff --git a/arch/powerpc/kernel/idle_6xx.S b/arch/powerpc/kernel/idle_6xx.S index 019b02d8844f..15c611de1ee2 100644 --- a/arch/powerpc/kernel/idle_6xx.S +++ b/arch/powerpc/kernel/idle_6xx.S @@ -158,7 +158,7 @@ _GLOBAL(power_save_ppc32_restore) stw r9,_NIP(r11) /* make it do a blr */ #ifdef CONFIG_SMP - mfspr r12,SPRN_SPRG3 + rlwinm r12,r11,0,0,31-THREAD_SHIFT lwz r11,TI_CPU(r12) /* get cpu number * 4 */ slwi r11,r11,2 #else diff --git a/arch/powerpc/kernel/idle_e500.S b/arch/powerpc/kernel/idle_e500.S index 06304034b393..47a1a983ff88 100644 --- a/arch/powerpc/kernel/idle_e500.S +++ b/arch/powerpc/kernel/idle_e500.S @@ -84,10 +84,11 @@ _GLOBAL(power_save_ppc32_restore) stw r9,_NIP(r11) /* make it do a blr */ #ifdef CONFIG_SMP - mfspr r12,SPRN_SPRG3 + rlwinm r12,r1,0,0,31-THREAD_SHIFT lwz r11,TI_CPU(r12) /* get cpu number * 4 */ slwi r11,r11,2 #else li r11,0 #endif + b transfer_to_handler_cont diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 4a8ce62fe112..9f6c1ca1739e 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -66,11 +66,12 @@ SECTIONS __got2_end = .; #endif /* CONFIG_PPC32 */ - . = ALIGN(PAGE_SIZE); - _etext = .; - PROVIDE32 (etext = .); } :kernel + . = ALIGN(PAGE_SIZE); + _etext = .; + PROVIDE32 (etext = .); + /* Read-only data */ RODATA diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 14be408dfc9b..8920eea34528 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -191,12 +191,17 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, unsigned long hash, hpteg; unsigned long vsid = get_kernel_vsid(vaddr, ssize); unsigned long va = hpt_va(vaddr, vsid, ssize); + unsigned long tprot = prot; + + /* Make kernel text executable */ + if (in_kernel_text(vaddr)) + tprot &= ~HPTE_R_N; hash = hpt_hash(va, shift, ssize); hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); BUG_ON(!ppc_md.hpte_insert); - ret = ppc_md.hpte_insert(hpteg, va, paddr, prot, + ret = ppc_md.hpte_insert(hpteg, va, paddr, tprot, HPTE_V_BOLTED, psize, ssize); if (ret < 0) @@ -584,7 +589,7 @@ void __init htab_initialize(void) { unsigned long table; unsigned long pteg_count; - unsigned long prot, tprot; + unsigned long prot; unsigned long base = 0, size = 0, limit; int i; @@ -660,10 +665,9 @@ void __init htab_initialize(void) for (i=0; i < lmb.memory.cnt; i++) { base = (unsigned long)__va(lmb.memory.region[i].base); size = lmb.memory.region[i].size; - tprot = prot | (in_kernel_text(base) ? _PAGE_EXEC : 0); DBG("creating mapping for region: %lx..%lx (prot: %x)\n", - base, size, tprot); + base, size, prot); #ifdef CONFIG_U3_DART /* Do not map the DART space. Fortunately, it will be aligned @@ -680,21 +684,21 @@ void __init htab_initialize(void) unsigned long dart_table_end = dart_tablebase + 16 * MB; if (base != dart_tablebase) BUG_ON(htab_bolt_mapping(base, dart_tablebase, - __pa(base), tprot, + __pa(base), prot, mmu_linear_psize, mmu_kernel_ssize)); if ((base + size) > dart_table_end) BUG_ON(htab_bolt_mapping(dart_tablebase+16*MB, base + size, __pa(dart_table_end), - tprot, + prot, mmu_linear_psize, mmu_kernel_ssize)); continue; } #endif /* CONFIG_U3_DART */ BUG_ON(htab_bolt_mapping(base, base + size, __pa(base), - tprot, mmu_linear_psize, mmu_kernel_ssize)); + prot, mmu_linear_psize, mmu_kernel_ssize)); } /* diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 1c1b627ee843..67595bc380dc 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -643,9 +643,10 @@ static struct spu *find_victim(struct spu_context *ctx) !(tmp->flags & SPU_CREATE_NOSCHED) && (!victim || tmp->prio > victim->prio)) { victim = spu->ctx; - get_spu_context(victim); } } + if (victim) + get_spu_context(victim); mutex_unlock(&cbe_spu_info[node].list_mutex); if (victim) { @@ -727,17 +728,33 @@ static void spu_schedule(struct spu *spu, struct spu_context *ctx) /* not a candidate for interruptible because it's called either from the scheduler thread or from spu_deactivate */ mutex_lock(&ctx->state_mutex); - __spu_schedule(spu, ctx); + if (ctx->state == SPU_STATE_SAVED) + __spu_schedule(spu, ctx); spu_release(ctx); } -static void spu_unschedule(struct spu *spu, struct spu_context *ctx) +/** + * spu_unschedule - remove a context from a spu, and possibly release it. + * @spu: The SPU to unschedule from + * @ctx: The context currently scheduled on the SPU + * @free_spu Whether to free the SPU for other contexts + * + * Unbinds the context @ctx from the SPU @spu. If @free_spu is non-zero, the + * SPU is made available for other contexts (ie, may be returned by + * spu_get_idle). If this is zero, the caller is expected to schedule another + * context to this spu. + * + * Should be called with ctx->state_mutex held. + */ +static void spu_unschedule(struct spu *spu, struct spu_context *ctx, + int free_spu) { int node = spu->node; mutex_lock(&cbe_spu_info[node].list_mutex); cbe_spu_info[node].nr_active--; - spu->alloc_state = SPU_FREE; + if (free_spu) + spu->alloc_state = SPU_FREE; spu_unbind_context(spu, ctx); ctx->stats.invol_ctx_switch++; spu->stats.invol_ctx_switch++; @@ -837,7 +854,7 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio) if (spu) { new = grab_runnable_context(max_prio, spu->node); if (new || force) { - spu_unschedule(spu, ctx); + spu_unschedule(spu, ctx, new == NULL); if (new) { if (new->flags & SPU_CREATE_NOSCHED) wake_up(&new->stop_wq); @@ -910,7 +927,7 @@ static noinline void spusched_tick(struct spu_context *ctx) new = grab_runnable_context(ctx->prio + 1, spu->node); if (new) { - spu_unschedule(spu, ctx); + spu_unschedule(spu, ctx, 0); if (test_bit(SPU_SCHED_SPU_RUN, &ctx->sched_flags)) spu_add_to_rq(ctx); } else { diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile index 58ecdd72630f..be60d64be7ad 100644 --- a/arch/powerpc/platforms/powermac/Makefile +++ b/arch/powerpc/platforms/powermac/Makefile @@ -2,7 +2,7 @@ CFLAGS_bootx_init.o += -fPIC ifdef CONFIG_FTRACE # Do not trace early boot code -CFLAGS_REMOVE_bootx_init.o = -pg +CFLAGS_REMOVE_bootx_init.o = -pg -mno-sched-epilog endif obj-y += pic.o setup.o time.o feature.o pci.o \ diff --git a/arch/sh/configs/ap325rxa_defconfig b/arch/sh/configs/ap325rxa_defconfig index 29926a9b9ce2..851c870adf3b 100644 --- a/arch/sh/configs/ap325rxa_defconfig +++ b/arch/sh/configs/ap325rxa_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.26 -# Wed Jul 30 01:18:59 2008 +# Linux kernel version: 2.6.27-rc4 +# Tue Aug 26 14:21:17 2008 # CONFIG_SUPERH=y CONFIG_SUPERH32=y @@ -11,6 +11,7 @@ CONFIG_GENERIC_BUG=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_TIME=y @@ -20,7 +21,6 @@ CONFIG_LOCKDEP_SUPPORT=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_ARCH_NO_VIRT_TO_BUS=y -CONFIG_ARCH_SUPPORTS_AOUT=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # @@ -58,7 +58,6 @@ CONFIG_SYSCTL=y CONFIG_EMBEDDED=y CONFIG_UID16=y CONFIG_SYSCTL_SYSCALL=y -CONFIG_SYSCTL_SYSCALL_CHECK=y # CONFIG_KALLSYMS is not set CONFIG_HOTPLUG=y CONFIG_PRINTK=y @@ -89,6 +88,7 @@ CONFIG_HAVE_OPROFILE=y # CONFIG_USE_GENERIC_SMP_HELPERS is not set CONFIG_HAVE_CLK=y CONFIG_PROC_PAGE_MONITOR=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set @@ -261,9 +261,10 @@ CONFIG_HZ_250=y # CONFIG_HZ_300 is not set # CONFIG_HZ_1000 is not set CONFIG_HZ=250 -# CONFIG_SCHED_HRTICK is not set +CONFIG_SCHED_HRTICK=y # CONFIG_KEXEC is not set # CONFIG_CRASH_DUMP is not set +CONFIG_SECCOMP=y # CONFIG_PREEMPT_NONE is not set # CONFIG_PREEMPT_VOLUNTARY is not set CONFIG_PREEMPT=y @@ -289,10 +290,6 @@ CONFIG_CMDLINE="console=tty1 console=ttySC5,38400 root=/dev/nfs ip=dhcp" # CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set - -# -# Networking -# CONFIG_NET=y # @@ -647,6 +644,7 @@ CONFIG_SSB_POSSIBLE=y # CONFIG_MFD_CORE is not set # CONFIG_MFD_SM501 is not set # CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_TMIO is not set # # Multimedia devices @@ -690,7 +688,10 @@ CONFIG_DUMMY_CONSOLE=y # CONFIG_ACCESSIBILITY is not set # CONFIG_RTC_CLASS is not set # CONFIG_DMADEVICES is not set -# CONFIG_UIO is not set +CONFIG_UIO=y +# CONFIG_UIO_PDRV is not set +CONFIG_UIO_PDRV_GENIRQ=y +# CONFIG_UIO_SMX is not set # # File systems @@ -854,6 +855,7 @@ CONFIG_FRAME_WARN=1024 # CONFIG_DEBUG_KERNEL is not set # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_DEBUG_MEMORY_INIT is not set +CONFIG_SYSCTL_SYSCALL_CHECK=y # CONFIG_SAMPLES is not set # CONFIG_SH_STANDARD_BIOS is not set # CONFIG_EARLY_SCIF_CONSOLE is not set diff --git a/arch/sh/configs/migor_defconfig b/arch/sh/configs/migor_defconfig index c4b3e1d8950d..4f8b1974f2c7 100644 --- a/arch/sh/configs/migor_defconfig +++ b/arch/sh/configs/migor_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.26 -# Wed Jul 30 01:44:41 2008 +# Linux kernel version: 2.6.27-rc4 +# Tue Aug 26 14:18:17 2008 # CONFIG_SUPERH=y CONFIG_SUPERH32=y @@ -11,6 +11,7 @@ CONFIG_GENERIC_BUG=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_TIME=y @@ -21,7 +22,6 @@ CONFIG_LOCKDEP_SUPPORT=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_ARCH_NO_VIRT_TO_BUS=y -CONFIG_ARCH_SUPPORTS_AOUT=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # @@ -87,6 +87,7 @@ CONFIG_HAVE_OPROFILE=y # CONFIG_USE_GENERIC_SMP_HELPERS is not set CONFIG_HAVE_CLK=y CONFIG_PROC_PAGE_MONITOR=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set @@ -270,6 +271,7 @@ CONFIG_HZ=250 # CONFIG_SCHED_HRTICK is not set # CONFIG_KEXEC is not set # CONFIG_CRASH_DUMP is not set +CONFIG_SECCOMP=y CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set @@ -294,10 +296,6 @@ CONFIG_CMDLINE="console=ttySC0,115200 earlyprintk=serial ip=on" # CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set - -# -# Networking -# CONFIG_NET=y # @@ -649,6 +647,7 @@ CONFIG_HW_RANDOM=y CONFIG_I2C=y CONFIG_I2C_BOARDINFO=y # CONFIG_I2C_CHARDEV is not set +CONFIG_I2C_HELPER_AUTO=y # # I2C Hardware Bus support @@ -709,6 +708,7 @@ CONFIG_SSB_POSSIBLE=y # CONFIG_MFD_CORE is not set # CONFIG_MFD_SM501 is not set # CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_TMIO is not set # # Multimedia devices @@ -755,6 +755,8 @@ CONFIG_USB_ARCH_HAS_HCD=y # CONFIG_USB is not set # CONFIG_USB_OTG_WHITELIST is not set # CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_GADGET_MUSB_HDRC is not set # # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' @@ -842,7 +844,10 @@ CONFIG_RTC_DRV_RS5C372=y # CONFIG_RTC_DRV_SH=y # CONFIG_DMADEVICES is not set -# CONFIG_UIO is not set +CONFIG_UIO=y +# CONFIG_UIO_PDRV is not set +CONFIG_UIO_PDRV_GENIRQ=y +# CONFIG_UIO_SMX is not set # # File systems diff --git a/arch/sh/include/asm/uaccess_64.h b/arch/sh/include/asm/uaccess_64.h index 81b3d515fcb3..5580fd471003 100644 --- a/arch/sh/include/asm/uaccess_64.h +++ b/arch/sh/include/asm/uaccess_64.h @@ -76,4 +76,6 @@ extern long __put_user_asm_l(void *, long); extern long __put_user_asm_q(void *, long); extern void __put_user_unknown(void); +extern long __strnlen_user(const char *__s, long __n); + #endif /* __ASM_SH_UACCESS_64_H */ diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S index 04c7da968146..e640c63d5811 100644 --- a/arch/sh/kernel/cpu/sh5/entry.S +++ b/arch/sh/kernel/cpu/sh5/entry.S @@ -2,7 +2,7 @@ * arch/sh/kernel/cpu/sh5/entry.S * * Copyright (C) 2000, 2001 Paolo Alberelli - * Copyright (C) 2004 - 2007 Paul Mundt + * Copyright (C) 2004 - 2008 Paul Mundt * Copyright (C) 2003, 2004 Richard Curnow * * This file is subject to the terms and conditions of the GNU General Public @@ -923,6 +923,8 @@ ret_from_exception: blink tr0, ZERO resume_kernel: + CLI() + pta restore_all, tr0 getcon KCR0, r6 @@ -939,19 +941,11 @@ need_resched: andi r7, 0xf0, r7 bne r7, ZERO, tr0 - movi ((PREEMPT_ACTIVE >> 16) & 65535), r8 - shori (PREEMPT_ACTIVE & 65535), r8 - st.l r6, TI_PRE_COUNT, r8 - - STI() - movi schedule, r7 + movi preempt_schedule_irq, r7 ori r7, 1, r7 ptabs r7, tr1 blink tr1, LINK - st.l r6, TI_PRE_COUNT, ZERO - CLI() - pta need_resched, tr1 blink tr1, ZERO #endif diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S index 0bc17def55a7..efbb4268875e 100644 --- a/arch/sh/kernel/entry-common.S +++ b/arch/sh/kernel/entry-common.S @@ -92,6 +92,7 @@ ENTRY(ret_from_irq) bra resume_userspace nop ENTRY(resume_kernel) + cli mov.l @(TI_PRE_COUNT,r8), r0 ! current_thread_info->preempt_count tst r0, r0 bf noresched @@ -105,28 +106,9 @@ need_resched: and #0xf0, r0 ! interrupts off (exception path)? cmp/eq #0xf0, r0 bt noresched - - mov.l 1f, r0 - mov.l r0, @(TI_PRE_COUNT,r8) - -#ifdef CONFIG_TRACE_IRQFLAGS mov.l 3f, r0 - jsr @r0 - nop -#endif - sti - mov.l 2f, r0 - jsr @r0 - nop - mov #0, r0 - mov.l r0, @(TI_PRE_COUNT,r8) - cli -#ifdef CONFIG_TRACE_IRQFLAGS - mov.l 4f, r0 - jsr @r0 + jsr @r0 ! call preempt_schedule_irq nop -#endif - bra need_resched nop @@ -137,10 +119,7 @@ noresched: .align 2 1: .long PREEMPT_ACTIVE 2: .long schedule -#ifdef CONFIG_TRACE_IRQFLAGS -3: .long trace_hardirqs_on -4: .long trace_hardirqs_off -#endif +3: .long preempt_schedule_irq #endif ENTRY(resume_userspace) diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c index 4703dff174d5..94df56b0d1f6 100644 --- a/arch/sh/kernel/machine_kexec.c +++ b/arch/sh/kernel/machine_kexec.c @@ -102,7 +102,7 @@ void machine_kexec(struct kimage *image) /* now call it */ rnk = (relocate_new_kernel_t) reboot_code_buffer; - (*rnk)(page_list, reboot_code_buffer, image->start, vbr_reg); + (*rnk)(page_list, reboot_code_buffer, P2SEGADDR(image->start), vbr_reg); } void arch_crash_save_vmcoreinfo(void) diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c index 5922edd416db..9c6424892bd3 100644 --- a/arch/sh/kernel/ptrace_64.c +++ b/arch/sh/kernel/ptrace_64.c @@ -131,6 +131,8 @@ void user_enable_single_step(struct task_struct *child) void user_disable_single_step(struct task_struct *child) { + struct pt_regs *regs = child->thread.uregs; + regs->sr &= ~SR_SSTEP; } diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index a35207655e7b..de832056bf1b 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -171,6 +171,7 @@ static void __init reserve_crashkernel(void) (unsigned long)(free_mem >> 20)); crashk_res.start = crash_base; crashk_res.end = crash_base + crash_size - 1; + insert_resource(&iomem_resource, &crashk_res); } } #else @@ -204,11 +205,6 @@ void __init __add_active_range(unsigned int nid, unsigned long start_pfn, request_resource(res, &data_resource); request_resource(res, &bss_resource); -#ifdef CONFIG_KEXEC - if (crashk_res.start != crashk_res.end) - request_resource(res, &crashk_res); -#endif - add_active_range(nid, start_pfn, end_pfn); } diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c index 59cd2859ce9b..9061b86d73fa 100644 --- a/arch/sh/kernel/sys_sh.c +++ b/arch/sh/kernel/sys_sh.c @@ -170,7 +170,7 @@ asmlinkage int sys_ipc(uint call, int first, int second, version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; - if (call <= SEMCTL) + if (call <= SEMTIMEDOP) switch (call) { case SEMOP: return sys_semtimedop(first, diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c index 895bb3f335c7..64b8f7f96f9a 100644 --- a/arch/sh/mm/consistent.c +++ b/arch/sh/mm/consistent.c @@ -101,7 +101,7 @@ static int __init memchunk_setup(char *str) } __setup("memchunk.", memchunk_setup); -static void memchunk_cmdline_override(char *name, unsigned long *sizep) +static void __init memchunk_cmdline_override(char *name, unsigned long *sizep) { char *p = boot_command_line; int k = strlen(name); @@ -118,8 +118,8 @@ static void memchunk_cmdline_override(char *name, unsigned long *sizep) } } -int platform_resource_setup_memory(struct platform_device *pdev, - char *name, unsigned long memsize) +int __init platform_resource_setup_memory(struct platform_device *pdev, + char *name, unsigned long memsize) { struct resource *r; dma_addr_t dma_handle; diff --git a/arch/sparc/include/asm/smp_32.h b/arch/sparc/include/asm/smp_32.h index 7201752cf934..a8180e546a48 100644 --- a/arch/sparc/include/asm/smp_32.h +++ b/arch/sparc/include/asm/smp_32.h @@ -50,27 +50,24 @@ struct seq_file; void smp_bogo(struct seq_file *); void smp_info(struct seq_file *); -BTFIXUPDEF_CALL(void, smp_cross_call, smpfunc_t, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long) +BTFIXUPDEF_CALL(void, smp_cross_call, smpfunc_t, cpumask_t, unsigned long, unsigned long, unsigned long, unsigned long) BTFIXUPDEF_CALL(int, __hard_smp_processor_id, void) BTFIXUPDEF_BLACKBOX(hard_smp_processor_id) BTFIXUPDEF_BLACKBOX(load_current) -#define smp_cross_call(func,arg1,arg2,arg3,arg4,arg5) BTFIXUP_CALL(smp_cross_call)(func,arg1,arg2,arg3,arg4,arg5) +#define smp_cross_call(func,mask,arg1,arg2,arg3,arg4) BTFIXUP_CALL(smp_cross_call)(func,mask,arg1,arg2,arg3,arg4) -static inline void xc0(smpfunc_t func) { smp_cross_call(func, 0, 0, 0, 0, 0); } +static inline void xc0(smpfunc_t func) { smp_cross_call(func, cpu_online_map, 0, 0, 0, 0); } static inline void xc1(smpfunc_t func, unsigned long arg1) -{ smp_cross_call(func, arg1, 0, 0, 0, 0); } +{ smp_cross_call(func, cpu_online_map, arg1, 0, 0, 0); } static inline void xc2(smpfunc_t func, unsigned long arg1, unsigned long arg2) -{ smp_cross_call(func, arg1, arg2, 0, 0, 0); } +{ smp_cross_call(func, cpu_online_map, arg1, arg2, 0, 0); } static inline void xc3(smpfunc_t func, unsigned long arg1, unsigned long arg2, unsigned long arg3) -{ smp_cross_call(func, arg1, arg2, arg3, 0, 0); } +{ smp_cross_call(func, cpu_online_map, arg1, arg2, arg3, 0); } static inline void xc4(smpfunc_t func, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4) -{ smp_cross_call(func, arg1, arg2, arg3, arg4, 0); } -static inline void xc5(smpfunc_t func, unsigned long arg1, unsigned long arg2, - unsigned long arg3, unsigned long arg4, unsigned long arg5) -{ smp_cross_call(func, arg1, arg2, arg3, arg4, arg5); } +{ smp_cross_call(func, cpu_online_map, arg1, arg2, arg3, arg4); } static inline int smp_call_function(void (*func)(void *info), void *info, int wait) { @@ -78,6 +75,14 @@ static inline int smp_call_function(void (*func)(void *info), void *info, int wa return 0; } +static inline int smp_call_function_single(int cpuid, void (*func) (void *info), + void *info, int wait) +{ + smp_cross_call((smpfunc_t)func, cpumask_of_cpu(cpuid), + (unsigned long) info, 0, 0, 0); + return 0; +} + static inline int cpu_logical_map(int cpu) { return cpu; diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c index cc4c235c4f59..c481d45f97b7 100644 --- a/arch/sparc/kernel/of_device.c +++ b/arch/sparc/kernel/of_device.c @@ -70,7 +70,7 @@ struct of_bus { int *addrc, int *sizec); int (*map)(u32 *addr, const u32 *range, int na, int ns, int pna); - unsigned int (*get_flags)(const u32 *addr); + unsigned long (*get_flags)(const u32 *addr, unsigned long); }; /* @@ -130,8 +130,10 @@ static int of_bus_default_map(u32 *addr, const u32 *range, return 0; } -static unsigned int of_bus_default_get_flags(const u32 *addr) +static unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags) { + if (flags) + return flags; return IORESOURCE_MEM; } @@ -194,17 +196,21 @@ static int of_bus_pci_map(u32 *addr, const u32 *range, return 0; } -static unsigned int of_bus_pci_get_flags(const u32 *addr) +static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags) { - unsigned int flags = 0; u32 w = addr[0]; + /* For PCI, we override whatever child busses may have used. */ + flags = 0; switch((w >> 24) & 0x03) { case 0x01: flags |= IORESOURCE_IO; + break; + case 0x02: /* 32 bits */ case 0x03: /* 64 bits */ flags |= IORESOURCE_MEM; + break; } if (w & 0x40000000) flags |= IORESOURCE_PREFETCH; @@ -362,10 +368,11 @@ static void __init build_device_resources(struct of_device *op, int pna, pns; size = of_read_addr(reg + na, ns); - flags = bus->get_flags(reg); memcpy(addr, reg, na * 4); + flags = bus->get_flags(reg, 0); + /* If the immediate parent has no ranges property to apply, * just use a 1<->1 mapping. */ @@ -393,6 +400,8 @@ static void __init build_device_resources(struct of_device *op, dna, dns, pna)) break; + flags = pbus->get_flags(addr, flags); + dna = pna; dns = pns; dbus = pbus; diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index dfde77ff0848..69596402a500 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c @@ -262,8 +262,9 @@ static struct smp_funcall { static DEFINE_SPINLOCK(cross_call_lock); /* Cross calls must be serialized, at least currently. */ -void smp4d_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2, - unsigned long arg3, unsigned long arg4, unsigned long arg5) +static void smp4d_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, + unsigned long arg2, unsigned long arg3, + unsigned long arg4) { if(smp_processors_ready) { register int high = smp_highest_cpu; @@ -278,7 +279,7 @@ void smp4d_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2, register unsigned long a2 asm("i2") = arg2; register unsigned long a3 asm("i3") = arg3; register unsigned long a4 asm("i4") = arg4; - register unsigned long a5 asm("i5") = arg5; + register unsigned long a5 asm("i5") = 0; __asm__ __volatile__( "std %0, [%6]\n\t" @@ -290,11 +291,10 @@ void smp4d_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2, /* Init receive/complete mapping, plus fire the IPI's off. */ { - cpumask_t mask; register int i; - mask = cpumask_of_cpu(hard_smp4d_processor_id()); - cpus_andnot(mask, cpu_online_map, mask); + cpu_clear(smp_processor_id(), mask); + cpus_and(mask, cpu_online_map, mask); for(i = 0; i <= high; i++) { if (cpu_isset(i, mask)) { ccall_info.processors_in[i] = 0; @@ -309,12 +309,16 @@ void smp4d_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2, i = 0; do { + if (!cpu_isset(i, mask)) + continue; while(!ccall_info.processors_in[i]) barrier(); } while(++i <= high); i = 0; do { + if (!cpu_isset(i, mask)) + continue; while(!ccall_info.processors_out[i]) barrier(); } while(++i <= high); diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c index 406ac1abc83a..a14a76ac7f36 100644 --- a/arch/sparc/kernel/sun4m_smp.c +++ b/arch/sparc/kernel/sun4m_smp.c @@ -244,9 +244,9 @@ static struct smp_funcall { static DEFINE_SPINLOCK(cross_call_lock); /* Cross calls must be serialized, at least currently. */ -static void smp4m_cross_call(smpfunc_t func, unsigned long arg1, +static void smp4m_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5) + unsigned long arg4) { register int ncpus = SUN4M_NCPUS; unsigned long flags; @@ -259,14 +259,14 @@ static void smp4m_cross_call(smpfunc_t func, unsigned long arg1, ccall_info.arg2 = arg2; ccall_info.arg3 = arg3; ccall_info.arg4 = arg4; - ccall_info.arg5 = arg5; + ccall_info.arg5 = 0; /* Init receive/complete mapping, plus fire the IPI's off. */ { - cpumask_t mask = cpu_online_map; register int i; cpu_clear(smp_processor_id(), mask); + cpus_and(mask, cpu_online_map, mask); for(i = 0; i < ncpus; i++) { if (cpu_isset(i, mask)) { ccall_info.processors_in[i] = 0; @@ -284,12 +284,16 @@ static void smp4m_cross_call(smpfunc_t func, unsigned long arg1, i = 0; do { + if (!cpu_isset(i, mask)) + continue; while(!ccall_info.processors_in[i]) barrier(); } while(++i < ncpus); i = 0; do { + if (!cpu_isset(i, mask)) + continue; while(!ccall_info.processors_out[i]) barrier(); } while(++i < ncpus); diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index f8b50cbf4bf7..f845f150f565 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -96,7 +96,7 @@ struct of_bus { int *addrc, int *sizec); int (*map)(u32 *addr, const u32 *range, int na, int ns, int pna); - unsigned int (*get_flags)(const u32 *addr); + unsigned long (*get_flags)(const u32 *addr, unsigned long); }; /* @@ -156,8 +156,10 @@ static int of_bus_default_map(u32 *addr, const u32 *range, return 0; } -static unsigned int of_bus_default_get_flags(const u32 *addr) +static unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags) { + if (flags) + return flags; return IORESOURCE_MEM; } @@ -249,17 +251,21 @@ static int of_bus_pci_map(u32 *addr, const u32 *range, return 0; } -static unsigned int of_bus_pci_get_flags(const u32 *addr) +static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags) { - unsigned int flags = 0; u32 w = addr[0]; + /* For PCI, we override whatever child busses may have used. */ + flags = 0; switch((w >> 24) & 0x03) { case 0x01: flags |= IORESOURCE_IO; + break; + case 0x02: /* 32 bits */ case 0x03: /* 64 bits */ flags |= IORESOURCE_MEM; + break; } if (w & 0x40000000) flags |= IORESOURCE_PREFETCH; @@ -478,10 +484,10 @@ static void __init build_device_resources(struct of_device *op, int pna, pns; size = of_read_addr(reg + na, ns); - flags = bus->get_flags(reg); - memcpy(addr, reg, na * 4); + flags = bus->get_flags(addr, 0); + if (use_1to1_mapping(pp)) { result = of_read_addr(addr, na); goto build_res; @@ -506,6 +512,8 @@ static void __init build_device_resources(struct of_device *op, dna, dns, pna)) break; + flags = pbus->get_flags(addr, flags); + dna = pna; dns = pns; dbus = pbus; diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 743ccad61c60..2be166c544ca 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -80,8 +80,6 @@ void smp_bogo(struct seq_file *m) i, cpu_data(i).clock_tick); } -static __cacheline_aligned_in_smp DEFINE_SPINLOCK(call_lock); - extern void setup_sparc64_timer(void); static volatile unsigned long callin_flag = 0; @@ -120,9 +118,9 @@ void __cpuinit smp_callin(void) while (!cpu_isset(cpuid, smp_commenced_mask)) rmb(); - spin_lock(&call_lock); + ipi_call_lock(); cpu_set(cpuid, cpu_online_map); - spin_unlock(&call_lock); + ipi_call_unlock(); /* idle thread is expected to have preempt disabled */ preempt_disable(); @@ -1305,10 +1303,6 @@ int __cpu_disable(void) c->core_id = 0; c->proc_id = -1; - spin_lock(&call_lock); - cpu_clear(cpu, cpu_online_map); - spin_unlock(&call_lock); - smp_wmb(); /* Make sure no interrupts point to this cpu. */ @@ -1318,6 +1312,10 @@ int __cpu_disable(void) mdelay(1); local_irq_disable(); + ipi_call_lock(); + cpu_clear(cpu, cpu_online_map); + ipi_call_unlock(); + return 0; } diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index b4aeb0f696dc..a41df7bef035 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1843,7 +1843,7 @@ static int pavail_rescan_ents __initdata; * memory list again, and make sure it provides at least as much * memory as 'pavail' does. */ -static void setup_valid_addr_bitmap_from_pavail(void) +static void __init setup_valid_addr_bitmap_from_pavail(void) { int i; diff --git a/arch/x86/boot/cpucheck.c b/arch/x86/boot/cpucheck.c index 4b9ae7c56748..4d3ff037201f 100644 --- a/arch/x86/boot/cpucheck.c +++ b/arch/x86/boot/cpucheck.c @@ -38,12 +38,12 @@ static const u32 req_flags[NCAPINTS] = { REQUIRED_MASK0, REQUIRED_MASK1, - REQUIRED_MASK2, - REQUIRED_MASK3, + 0, /* REQUIRED_MASK2 not implemented in this file */ + 0, /* REQUIRED_MASK3 not implemented in this file */ REQUIRED_MASK4, - REQUIRED_MASK5, + 0, /* REQUIRED_MASK5 not implemented in this file */ REQUIRED_MASK6, - REQUIRED_MASK7, + 0, /* REQUIRED_MASK7 not implemented in this file */ }; #define A32(a, b, c, d) (((d) << 24)+((c) << 16)+((b) << 8)+(a)) diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 2763cb37b553..65a0c1b48696 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -145,35 +145,25 @@ static const unsigned char *const p6_nops[ASM_NOP_MAX+1] = { extern char __vsyscall_0; const unsigned char *const *find_nop_table(void) { - return boot_cpu_data.x86_vendor != X86_VENDOR_INTEL || - boot_cpu_data.x86 < 6 ? k8_nops : p6_nops; + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && + boot_cpu_has(X86_FEATURE_NOPL)) + return p6_nops; + else + return k8_nops; } #else /* CONFIG_X86_64 */ -static const struct nop { - int cpuid; - const unsigned char *const *noptable; -} noptypes[] = { - { X86_FEATURE_K8, k8_nops }, - { X86_FEATURE_K7, k7_nops }, - { X86_FEATURE_P4, p6_nops }, - { X86_FEATURE_P3, p6_nops }, - { -1, NULL } -}; - const unsigned char *const *find_nop_table(void) { - const unsigned char *const *noptable = intel_nops; - int i; - - for (i = 0; noptypes[i].cpuid >= 0; i++) { - if (boot_cpu_has(noptypes[i].cpuid)) { - noptable = noptypes[i].noptable; - break; - } - } - return noptable; + if (boot_cpu_has(X86_FEATURE_K8)) + return k8_nops; + else if (boot_cpu_has(X86_FEATURE_K7)) + return k7_nops; + else if (boot_cpu_has(X86_FEATURE_NOPL)) + return p6_nops; + else + return intel_nops; } #endif /* CONFIG_X86_64 */ diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index cae9cabc3031..18514ed26104 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -31,6 +31,11 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) if (c->x86_power & (1<<8)) set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); } + + /* Set MTRR capability flag if appropriate */ + if (c->x86_model == 13 || c->x86_model == 9 || + (c->x86_model == 8 && c->x86_mask >= 8)) + set_cpu_cap(c, X86_FEATURE_K6_MTRR); } static void __cpuinit init_amd(struct cpuinfo_x86 *c) @@ -166,10 +171,6 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) mbytes); } - /* Set MTRR capability flag if appropriate */ - if (c->x86_model == 13 || c->x86_model == 9 || - (c->x86_model == 8 && c->x86_mask >= 8)) - set_cpu_cap(c, X86_FEATURE_K6_MTRR); break; } diff --git a/arch/x86/kernel/cpu/centaur.c b/arch/x86/kernel/cpu/centaur.c index e0f45edd6a55..a0534c04d38a 100644 --- a/arch/x86/kernel/cpu/centaur.c +++ b/arch/x86/kernel/cpu/centaur.c @@ -314,6 +314,16 @@ enum { EAMD3D = 1<<20, }; +static void __cpuinit early_init_centaur(struct cpuinfo_x86 *c) +{ + switch (c->x86) { + case 5: + /* Emulate MTRRs using Centaur's MCR. */ + set_cpu_cap(c, X86_FEATURE_CENTAUR_MCR); + break; + } +} + static void __cpuinit init_centaur(struct cpuinfo_x86 *c) { @@ -462,6 +472,7 @@ centaur_size_cache(struct cpuinfo_x86 *c, unsigned int size) static struct cpu_dev centaur_cpu_dev __cpuinitdata = { .c_vendor = "Centaur", .c_ident = { "CentaurHauls" }, + .c_early_init = early_init_centaur, .c_init = init_centaur, .c_size_cache = centaur_size_cache, }; diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 80ab20d4fa39..8aab8517642e 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -13,6 +13,7 @@ #include <asm/mtrr.h> #include <asm/mce.h> #include <asm/pat.h> +#include <asm/asm.h> #ifdef CONFIG_X86_LOCAL_APIC #include <asm/mpspec.h> #include <asm/apic.h> @@ -334,11 +335,40 @@ static void __init early_cpu_detect(void) get_cpu_vendor(c, 1); + early_get_cap(c); + if (c->x86_vendor != X86_VENDOR_UNKNOWN && cpu_devs[c->x86_vendor]->c_early_init) cpu_devs[c->x86_vendor]->c_early_init(c); +} - early_get_cap(c); +/* + * The NOPL instruction is supposed to exist on all CPUs with + * family >= 6, unfortunately, that's not true in practice because + * of early VIA chips and (more importantly) broken virtualizers that + * are not easy to detect. Hence, probe for it based on first + * principles. + */ +static void __cpuinit detect_nopl(struct cpuinfo_x86 *c) +{ + const u32 nopl_signature = 0x888c53b1; /* Random number */ + u32 has_nopl = nopl_signature; + + clear_cpu_cap(c, X86_FEATURE_NOPL); + if (c->x86 >= 6) { + asm volatile("\n" + "1: .byte 0x0f,0x1f,0xc0\n" /* nopl %eax */ + "2:\n" + " .section .fixup,\"ax\"\n" + "3: xor %0,%0\n" + " jmp 2b\n" + " .previous\n" + _ASM_EXTABLE(1b,3b) + : "+a" (has_nopl)); + + if (has_nopl == nopl_signature) + set_cpu_cap(c, X86_FEATURE_NOPL); + } } static void __cpuinit generic_identify(struct cpuinfo_x86 *c) @@ -395,8 +425,8 @@ static void __cpuinit generic_identify(struct cpuinfo_x86 *c) } init_scattered_cpuid_features(c); + detect_nopl(c); } - } static void __cpuinit squash_the_stupid_serial_number(struct cpuinfo_x86 *c) diff --git a/arch/x86/kernel/cpu/common_64.c b/arch/x86/kernel/cpu/common_64.c index dd6e3f15017e..a11f5d4477cd 100644 --- a/arch/x86/kernel/cpu/common_64.c +++ b/arch/x86/kernel/cpu/common_64.c @@ -18,6 +18,7 @@ #include <asm/mtrr.h> #include <asm/mce.h> #include <asm/pat.h> +#include <asm/asm.h> #include <asm/numa.h> #ifdef CONFIG_X86_LOCAL_APIC #include <asm/mpspec.h> @@ -215,6 +216,39 @@ static void __init early_cpu_support_print(void) } } +/* + * The NOPL instruction is supposed to exist on all CPUs with + * family >= 6, unfortunately, that's not true in practice because + * of early VIA chips and (more importantly) broken virtualizers that + * are not easy to detect. Hence, probe for it based on first + * principles. + * + * Note: no 64-bit chip is known to lack these, but put the code here + * for consistency with 32 bits, and to make it utterly trivial to + * diagnose the problem should it ever surface. + */ +static void __cpuinit detect_nopl(struct cpuinfo_x86 *c) +{ + const u32 nopl_signature = 0x888c53b1; /* Random number */ + u32 has_nopl = nopl_signature; + + clear_cpu_cap(c, X86_FEATURE_NOPL); + if (c->x86 >= 6) { + asm volatile("\n" + "1: .byte 0x0f,0x1f,0xc0\n" /* nopl %eax */ + "2:\n" + " .section .fixup,\"ax\"\n" + "3: xor %0,%0\n" + " jmp 2b\n" + " .previous\n" + _ASM_EXTABLE(1b,3b) + : "+a" (has_nopl)); + + if (has_nopl == nopl_signature) + set_cpu_cap(c, X86_FEATURE_NOPL); + } +} + static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c); void __init early_cpu_init(void) @@ -313,6 +347,8 @@ static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c) c->x86_phys_bits = eax & 0xff; } + detect_nopl(c); + if (c->x86_vendor != X86_VENDOR_UNKNOWN && cpu_devs[c->x86_vendor]->c_early_init) cpu_devs[c->x86_vendor]->c_early_init(c); @@ -493,17 +529,20 @@ void pda_init(int cpu) /* others are initialized in smpboot.c */ pda->pcurrent = &init_task; pda->irqstackptr = boot_cpu_stack; + pda->irqstackptr += IRQSTACKSIZE - 64; } else { - pda->irqstackptr = (char *) - __get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER); - if (!pda->irqstackptr) - panic("cannot allocate irqstack for cpu %d", cpu); + if (!pda->irqstackptr) { + pda->irqstackptr = (char *) + __get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER); + if (!pda->irqstackptr) + panic("cannot allocate irqstack for cpu %d", + cpu); + pda->irqstackptr += IRQSTACKSIZE - 64; + } if (pda->nodenumber == 0 && cpu_to_node(cpu) != NUMA_NO_NODE) pda->nodenumber = cpu_to_node(cpu); } - - pda->irqstackptr += IRQSTACKSIZE-64; } char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + @@ -601,19 +640,22 @@ void __cpuinit cpu_init(void) /* * set up and load the per-CPU TSS */ - for (v = 0; v < N_EXCEPTION_STACKS; v++) { + if (!orig_ist->ist[0]) { static const unsigned int order[N_EXCEPTION_STACKS] = { - [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER, - [DEBUG_STACK - 1] = DEBUG_STACK_ORDER + [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER, + [DEBUG_STACK - 1] = DEBUG_STACK_ORDER }; - if (cpu) { - estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]); - if (!estacks) - panic("Cannot allocate exception stack %ld %d\n", - v, cpu); + for (v = 0; v < N_EXCEPTION_STACKS; v++) { + if (cpu) { + estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]); + if (!estacks) + panic("Cannot allocate exception " + "stack %ld %d\n", v, cpu); + } + estacks += PAGE_SIZE << order[v]; + orig_ist->ist[v] = t->x86_tss.ist[v] = + (unsigned long)estacks; } - estacks += PAGE_SIZE << order[v]; - orig_ist->ist[v] = t->x86_tss.ist[v] = (unsigned long)estacks; } t->x86_tss.io_bitmap_base = offsetof(struct tss_struct, io_bitmap); diff --git a/arch/x86/kernel/cpu/cyrix.c b/arch/x86/kernel/cpu/cyrix.c index e710a21bb6e8..898a5a2002ed 100644 --- a/arch/x86/kernel/cpu/cyrix.c +++ b/arch/x86/kernel/cpu/cyrix.c @@ -15,13 +15,11 @@ /* * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU */ -static void __cpuinit do_cyrix_devid(unsigned char *dir0, unsigned char *dir1) +static void __cpuinit __do_cyrix_devid(unsigned char *dir0, unsigned char *dir1) { unsigned char ccr2, ccr3; - unsigned long flags; /* we test for DEVID by checking whether CCR3 is writable */ - local_irq_save(flags); ccr3 = getCx86(CX86_CCR3); setCx86(CX86_CCR3, ccr3 ^ 0x80); getCx86(0xc0); /* dummy to change bus */ @@ -44,9 +42,16 @@ static void __cpuinit do_cyrix_devid(unsigned char *dir0, unsigned char *dir1) *dir0 = getCx86(CX86_DIR0); *dir1 = getCx86(CX86_DIR1); } - local_irq_restore(flags); } +static void __cpuinit do_cyrix_devid(unsigned char *dir0, unsigned char *dir1) +{ + unsigned long flags; + + local_irq_save(flags); + __do_cyrix_devid(dir0, dir1); + local_irq_restore(flags); +} /* * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in * order to identify the Cyrix CPU model after we're out of setup.c @@ -161,6 +166,24 @@ static void __cpuinit geode_configure(void) local_irq_restore(flags); } +static void __cpuinit early_init_cyrix(struct cpuinfo_x86 *c) +{ + unsigned char dir0, dir0_msn, dir1 = 0; + + __do_cyrix_devid(&dir0, &dir1); + dir0_msn = dir0 >> 4; /* identifies CPU "family" */ + + switch (dir0_msn) { + case 3: /* 6x86/6x86L */ + /* Emulate MTRRs using Cyrix's ARRs. */ + set_cpu_cap(c, X86_FEATURE_CYRIX_ARR); + break; + case 5: /* 6x86MX/M II */ + /* Emulate MTRRs using Cyrix's ARRs. */ + set_cpu_cap(c, X86_FEATURE_CYRIX_ARR); + break; + } +} static void __cpuinit init_cyrix(struct cpuinfo_x86 *c) { @@ -416,6 +439,7 @@ static void __cpuinit cyrix_identify(struct cpuinfo_x86 *c) static struct cpu_dev cyrix_cpu_dev __cpuinitdata = { .c_vendor = "Cyrix", .c_ident = { "CyrixInstead" }, + .c_early_init = early_init_cyrix, .c_init = init_cyrix, .c_identify = cyrix_identify, }; diff --git a/arch/x86/kernel/cpu/feature_names.c b/arch/x86/kernel/cpu/feature_names.c index e43ad4ad4cba..c9017799497c 100644 --- a/arch/x86/kernel/cpu/feature_names.c +++ b/arch/x86/kernel/cpu/feature_names.c @@ -39,7 +39,8 @@ const char * const x86_cap_flags[NCAPINTS*32] = { NULL, NULL, NULL, NULL, "constant_tsc", "up", NULL, "arch_perfmon", "pebs", "bts", NULL, NULL, - "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "rep_good", NULL, NULL, NULL, + "nopl", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* Intel-defined (#2) */ diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 59fd3b6b1303..73deaffadd03 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -210,8 +210,8 @@ static void hpet_legacy_clockevent_register(void) /* Calculate the min / max delta */ hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, &hpet_clockevent); - hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30, - &hpet_clockevent); + /* 5 usec minimum reprogramming delta. */ + hpet_clockevent.min_delta_ns = 5000; /* * Start hpet with the boot cpu mask and make it @@ -270,15 +270,22 @@ static void hpet_legacy_set_mode(enum clock_event_mode mode, } static int hpet_legacy_next_event(unsigned long delta, - struct clock_event_device *evt) + struct clock_event_device *evt) { - unsigned long cnt; + u32 cnt; cnt = hpet_readl(HPET_COUNTER); - cnt += delta; + cnt += (u32) delta; hpet_writel(cnt, HPET_T0_CMP); - return ((long)(hpet_readl(HPET_COUNTER) - cnt ) > 0) ? -ETIME : 0; + /* + * We need to read back the CMP register to make sure that + * what we wrote hit the chip before we compare it to the + * counter. + */ + WARN_ON((u32)hpet_readl(HPET_T0_CMP) != cnt); + + return (s32)((u32)hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0; } /* diff --git a/arch/x86/kernel/io_delay.c b/arch/x86/kernel/io_delay.c index 1c3a66a67f83..720d2607aacb 100644 --- a/arch/x86/kernel/io_delay.c +++ b/arch/x86/kernel/io_delay.c @@ -92,6 +92,14 @@ static struct dmi_system_id __initdata io_delay_0xed_port_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "30BF") } }, + { + .callback = dmi_io_delay_0xed_port, + .ident = "Presario F700", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), + DMI_MATCH(DMI_BOARD_NAME, "30D3") + } + }, { } }; diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 8e786b0d665a..8f98e9de1b82 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -122,80 +122,216 @@ static u64 tsc_read_refs(u64 *pm, u64 *hpet) return ULLONG_MAX; } -/** - * native_calibrate_tsc - calibrate the tsc on boot +/* + * Try to calibrate the TSC against the Programmable + * Interrupt Timer and return the frequency of the TSC + * in kHz. + * + * Return ULONG_MAX on failure to calibrate. */ -unsigned long native_calibrate_tsc(void) +static unsigned long pit_calibrate_tsc(void) { - unsigned long flags; - u64 tsc1, tsc2, tr1, tr2, delta, pm1, pm2, hpet1, hpet2; - int hpet = is_hpet_enabled(); - unsigned int tsc_khz_val = 0; - - local_irq_save(flags); - - tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL); + u64 tsc, t1, t2, delta; + unsigned long tscmin, tscmax; + int pitcnt; + /* Set the Gate high, disable speaker */ outb((inb(0x61) & ~0x02) | 0x01, 0x61); + /* + * Setup CTC channel 2* for mode 0, (interrupt on terminal + * count mode), binary count. Set the latch register to 50ms + * (LSB then MSB) to begin countdown. + */ outb(0xb0, 0x43); outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42); outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42); - tr1 = get_cycles(); - while ((inb(0x61) & 0x20) == 0); - tr2 = get_cycles(); - tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL); + tsc = t1 = t2 = get_cycles(); - local_irq_restore(flags); + pitcnt = 0; + tscmax = 0; + tscmin = ULONG_MAX; + while ((inb(0x61) & 0x20) == 0) { + t2 = get_cycles(); + delta = t2 - tsc; + tsc = t2; + if ((unsigned long) delta < tscmin) + tscmin = (unsigned int) delta; + if ((unsigned long) delta > tscmax) + tscmax = (unsigned int) delta; + pitcnt++; + } /* - * Preset the result with the raw and inaccurate PIT - * calibration value + * Sanity checks: + * + * If we were not able to read the PIT more than 5000 + * times, then we have been hit by a massive SMI + * + * If the maximum is 10 times larger than the minimum, + * then we got hit by an SMI as well. */ - delta = (tr2 - tr1); + if (pitcnt < 5000 || tscmax > 10 * tscmin) + return ULONG_MAX; + + /* Calculate the PIT value */ + delta = t2 - t1; do_div(delta, 50); - tsc_khz_val = delta; + return delta; +} + + +/** + * native_calibrate_tsc - calibrate the tsc on boot + */ +unsigned long native_calibrate_tsc(void) +{ + u64 tsc1, tsc2, delta, pm1, pm2, hpet1, hpet2; + unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX; + unsigned long flags; + int hpet = is_hpet_enabled(), i; - /* hpet or pmtimer available ? */ + /* + * Run 5 calibration loops to get the lowest frequency value + * (the best estimate). We use two different calibration modes + * here: + * + * 1) PIT loop. We set the PIT Channel 2 to oneshot mode and + * load a timeout of 50ms. We read the time right after we + * started the timer and wait until the PIT count down reaches + * zero. In each wait loop iteration we read the TSC and check + * the delta to the previous read. We keep track of the min + * and max values of that delta. The delta is mostly defined + * by the IO time of the PIT access, so we can detect when a + * SMI/SMM disturbance happend between the two reads. If the + * maximum time is significantly larger than the minimum time, + * then we discard the result and have another try. + * + * 2) Reference counter. If available we use the HPET or the + * PMTIMER as a reference to check the sanity of that value. + * We use separate TSC readouts and check inside of the + * reference read for a SMI/SMM disturbance. We dicard + * disturbed values here as well. We do that around the PIT + * calibration delay loop as we have to wait for a certain + * amount of time anyway. + */ + for (i = 0; i < 5; i++) { + unsigned long tsc_pit_khz; + + /* + * Read the start value and the reference count of + * hpet/pmtimer when available. Then do the PIT + * calibration, which will take at least 50ms, and + * read the end value. + */ + local_irq_save(flags); + tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL); + tsc_pit_khz = pit_calibrate_tsc(); + tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL); + local_irq_restore(flags); + + /* Pick the lowest PIT TSC calibration so far */ + tsc_pit_min = min(tsc_pit_min, tsc_pit_khz); + + /* hpet or pmtimer available ? */ + if (!hpet && !pm1 && !pm2) + continue; + + /* Check, whether the sampling was disturbed by an SMI */ + if (tsc1 == ULLONG_MAX || tsc2 == ULLONG_MAX) + continue; + + tsc2 = (tsc2 - tsc1) * 1000000LL; + + if (hpet) { + if (hpet2 < hpet1) + hpet2 += 0x100000000ULL; + hpet2 -= hpet1; + tsc1 = ((u64)hpet2 * hpet_readl(HPET_PERIOD)); + do_div(tsc1, 1000000); + } else { + if (pm2 < pm1) + pm2 += (u64)ACPI_PM_OVRRUN; + pm2 -= pm1; + tsc1 = pm2 * 1000000000LL; + do_div(tsc1, PMTMR_TICKS_PER_SEC); + } + + do_div(tsc2, tsc1); + tsc_ref_min = min(tsc_ref_min, (unsigned long) tsc2); + } + + /* + * Now check the results. + */ + if (tsc_pit_min == ULONG_MAX) { + /* PIT gave no useful value */ + printk(KERN_WARNING "TSC: Unable to calibrate against PIT\n"); + + /* We don't have an alternative source, disable TSC */ + if (!hpet && !pm1 && !pm2) { + printk("TSC: No reference (HPET/PMTIMER) available\n"); + return 0; + } + + /* The alternative source failed as well, disable TSC */ + if (tsc_ref_min == ULONG_MAX) { + printk(KERN_WARNING "TSC: HPET/PMTIMER calibration " + "failed due to SMI disturbance.\n"); + return 0; + } + + /* Use the alternative source */ + printk(KERN_INFO "TSC: using %s reference calibration\n", + hpet ? "HPET" : "PMTIMER"); + + return tsc_ref_min; + } + + /* We don't have an alternative source, use the PIT calibration value */ if (!hpet && !pm1 && !pm2) { - printk(KERN_INFO "TSC calibrated against PIT\n"); - goto out; + printk(KERN_INFO "TSC: Using PIT calibration value\n"); + return tsc_pit_min; } - /* Check, whether the sampling was disturbed by an SMI */ - if (tsc1 == ULLONG_MAX || tsc2 == ULLONG_MAX) { - printk(KERN_WARNING "TSC calibration disturbed by SMI, " - "using PIT calibration result\n"); - goto out; + /* The alternative source failed, use the PIT calibration value */ + if (tsc_ref_min == ULONG_MAX) { + printk(KERN_WARNING "TSC: HPET/PMTIMER calibration failed due " + "to SMI disturbance. Using PIT calibration\n"); + return tsc_pit_min; } - tsc2 = (tsc2 - tsc1) * 1000000LL; - - if (hpet) { - printk(KERN_INFO "TSC calibrated against HPET\n"); - if (hpet2 < hpet1) - hpet2 += 0x100000000ULL; - hpet2 -= hpet1; - tsc1 = ((u64)hpet2 * hpet_readl(HPET_PERIOD)); - do_div(tsc1, 1000000); - } else { - printk(KERN_INFO "TSC calibrated against PM_TIMER\n"); - if (pm2 < pm1) - pm2 += (u64)ACPI_PM_OVRRUN; - pm2 -= pm1; - tsc1 = pm2 * 1000000000LL; - do_div(tsc1, PMTMR_TICKS_PER_SEC); + /* Check the reference deviation */ + delta = ((u64) tsc_pit_min) * 100; + do_div(delta, tsc_ref_min); + + /* + * If both calibration results are inside a 5% window, the we + * use the lower frequency of those as it is probably the + * closest estimate. + */ + if (delta >= 95 && delta <= 105) { + printk(KERN_INFO "TSC: PIT calibration confirmed by %s.\n", + hpet ? "HPET" : "PMTIMER"); + printk(KERN_INFO "TSC: using %s calibration value\n", + tsc_pit_min <= tsc_ref_min ? "PIT" : + hpet ? "HPET" : "PMTIMER"); + return tsc_pit_min <= tsc_ref_min ? tsc_pit_min : tsc_ref_min; } - do_div(tsc2, tsc1); - tsc_khz_val = tsc2; + printk(KERN_WARNING "TSC: PIT calibration deviates from %s: %lu %lu.\n", + hpet ? "HPET" : "PMTIMER", tsc_pit_min, tsc_ref_min); -out: - return tsc_khz_val; + /* + * The calibration values differ too much. In doubt, we use + * the PIT value as we know that there are PMTIMERs around + * running at double speed. + */ + printk(KERN_INFO "TSC: Using PIT calibration value\n"); + return tsc_pit_min; } - #ifdef CONFIG_X86_32 /* Only called from the Powernow K7 cpu freq driver */ int recalibrate_cpu_khz(void) diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index d765da913842..8791fc55e715 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -31,11 +31,8 @@ #include <linux/ioport.h> #include <linux/errno.h> #include <linux/bootmem.h> -#include <linux/acpi.h> #include <asm/pat.h> -#include <asm/hpet.h> -#include <asm/io_apic.h> #include "pci.h" @@ -80,77 +77,6 @@ pcibios_align_resource(void *data, struct resource *res, } EXPORT_SYMBOL(pcibios_align_resource); -static int check_res_with_valid(struct pci_dev *dev, struct resource *res) -{ - unsigned long base; - unsigned long size; - int i; - - base = res->start; - size = (res->start == 0 && res->end == res->start) ? 0 : - (res->end - res->start + 1); - - if (!base || !size) - return 0; - -#ifdef CONFIG_HPET_TIMER - /* for hpet */ - if (base == hpet_address && (res->flags & IORESOURCE_MEM)) { - dev_info(&dev->dev, "BAR has HPET at %08lx-%08lx\n", - base, base + size - 1); - return 1; - } -#endif - -#ifdef CONFIG_X86_IO_APIC - for (i = 0; i < nr_ioapics; i++) { - unsigned long ioapic_phys = mp_ioapics[i].mp_apicaddr; - - if (base == ioapic_phys && (res->flags & IORESOURCE_MEM)) { - dev_info(&dev->dev, "BAR has ioapic at %08lx-%08lx\n", - base, base + size - 1); - return 1; - } - } -#endif - -#ifdef CONFIG_PCI_MMCONFIG - for (i = 0; i < pci_mmcfg_config_num; i++) { - unsigned long addr; - - addr = pci_mmcfg_config[i].address; - if (base == addr && (res->flags & IORESOURCE_MEM)) { - dev_info(&dev->dev, "BAR has MMCONFIG at %08lx-%08lx\n", - base, base + size - 1); - return 1; - } - } -#endif - - return 0; -} - -static int check_platform(struct pci_dev *dev, struct resource *res) -{ - struct resource *root = NULL; - - /* - * forcibly insert it into the - * resource tree - */ - if (res->flags & IORESOURCE_MEM) - root = &iomem_resource; - else if (res->flags & IORESOURCE_IO) - root = &ioport_resource; - - if (root && check_res_with_valid(dev, res)) { - insert_resource(root, res); - - return 1; - } - - return 0; -} /* * Handle resources of PCI devices. If the world were perfect, we could * just allocate all the resource regions and do nothing more. It isn't. @@ -202,10 +128,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) pr = pci_find_parent_resource(dev, r); if (!r->start || !pr || request_resource(pr, r) < 0) { - if (check_platform(dev, r)) - continue; - dev_err(&dev->dev, "BAR %d: can't " - "allocate resource\n", idx); + dev_err(&dev->dev, "BAR %d: can't allocate resource\n", idx); /* * Something is wrong with the region. * Invalidate the resource to prevent @@ -240,17 +163,13 @@ static void __init pcibios_allocate_resources(int pass) else disabled = !(command & PCI_COMMAND_MEMORY); if (pass == disabled) { - dev_dbg(&dev->dev, "resource %#08llx-%#08llx " - "(f=%lx, d=%d, p=%d)\n", + dev_dbg(&dev->dev, "resource %#08llx-%#08llx (f=%lx, d=%d, p=%d)\n", (unsigned long long) r->start, (unsigned long long) r->end, r->flags, disabled, pass); pr = pci_find_parent_resource(dev, r); if (!pr || request_resource(pr, r) < 0) { - if (check_platform(dev, r)) - continue; - dev_err(&dev->dev, "BAR %d: can't " - "allocate resource\n", idx); + dev_err(&dev->dev, "BAR %d: can't allocate resource\n", idx); /* We'll assign a new address later */ r->end -= r->start; r->start = 0; diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 9ff6e3cbf08f..a4e201b47f64 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -1324,7 +1324,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = { .ptep_modify_prot_commit = __ptep_modify_prot_commit, .pte_val = xen_pte_val, - .pte_flags = native_pte_val, + .pte_flags = native_pte_flags, .pgd_val = xen_pgd_val, .make_pte = xen_make_pte, diff --git a/block/cmd-filter.c b/block/cmd-filter.c index 1d4026206ac2..228b6447e89f 100644 --- a/block/cmd-filter.c +++ b/block/cmd-filter.c @@ -223,6 +223,7 @@ int blk_register_filter(struct gendisk *disk) return 0; } +EXPORT_SYMBOL(blk_register_filter); void blk_unregister_filter(struct gendisk *disk) { @@ -231,4 +232,4 @@ void blk_unregister_filter(struct gendisk *disk) kobject_put(&filter->kobj); kobject_put(disk->holder_dir->parent); } - +EXPORT_SYMBOL(blk_unregister_filter); diff --git a/block/genhd.c b/block/genhd.c index 656c2c7abf99..e0ce23ac2ece 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -190,7 +190,6 @@ void add_disk(struct gendisk *disk) disk->minors, NULL, exact_match, exact_lock, disk); register_disk(disk); blk_register_queue(disk); - blk_register_filter(disk); bdi = &disk->queue->backing_dev_info; bdi_register_dev(bdi, MKDEV(disk->major, disk->first_minor)); @@ -203,7 +202,6 @@ EXPORT_SYMBOL(del_gendisk); /* in partitions/check.c */ void unlink_gendisk(struct gendisk *disk) { - blk_unregister_filter(disk); sysfs_remove_link(&disk->dev.kobj, "bdi"); bdi_unregister(&disk->queue->backing_dev_info); blk_unregister_queue(disk); @@ -309,7 +307,7 @@ static void *part_start(struct seq_file *part, loff_t *pos) loff_t k = *pos; if (!k) - seq_puts(part, "major minor #blocks name\n\n"); + part->private = (void *)1LU; /* tell show to print header */ mutex_lock(&block_class_lock); dev = class_find_device(&block_class, NULL, &k, find_start); @@ -351,6 +349,17 @@ static int show_partition(struct seq_file *part, void *v) int n; char buf[BDEVNAME_SIZE]; + /* + * Print header if start told us to do. This is to preserve + * the original behavior of not printing header if no + * partition exists. This hackery will be removed later with + * class iteration clean up. + */ + if (part->private) { + seq_puts(part, "major minor #blocks name\n\n"); + part->private = NULL; + } + /* Don't show non-partitionable removeable devices or empty devices */ if (!get_capacity(sgp) || (sgp->minors == 1 && (sgp->flags & GENHD_FL_REMOVABLE))) diff --git a/crypto/async_tx/async_tx.c b/crypto/async_tx/async_tx.c index 85eaf7b1c531..e8362c1efa30 100644 --- a/crypto/async_tx/async_tx.c +++ b/crypto/async_tx/async_tx.c @@ -137,7 +137,8 @@ async_tx_run_dependencies(struct dma_async_tx_descriptor *tx) spin_lock_bh(&next->lock); next->parent = NULL; _next = next->next; - next->next = NULL; + if (_next && _next->chan == chan) + next->next = NULL; spin_unlock_bh(&next->lock); next->tx_submit(next); diff --git a/crypto/camellia.c b/crypto/camellia.c index b1cc4de6493c..493fee7e0a8b 100644 --- a/crypto/camellia.c +++ b/crypto/camellia.c @@ -35,8 +35,6 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/bitops.h> -#include <asm/unaligned.h> static const u32 camellia_sp1110[256] = { 0x70707000,0x82828200,0x2c2c2c00,0xececec00, @@ -337,6 +335,20 @@ static const u32 camellia_sp4404[256] = { /* * macros */ +#define GETU32(v, pt) \ + do { \ + /* latest breed of gcc is clever enough to use move */ \ + memcpy(&(v), (pt), 4); \ + (v) = be32_to_cpu(v); \ + } while(0) + +/* rotation right shift 1byte */ +#define ROR8(x) (((x) >> 8) + ((x) << 24)) +/* rotation left shift 1bit */ +#define ROL1(x) (((x) << 1) + ((x) >> 31)) +/* rotation left shift 1byte */ +#define ROL8(x) (((x) << 8) + ((x) >> 24)) + #define ROLDQ(ll, lr, rl, rr, w0, w1, bits) \ do { \ w0 = ll; \ @@ -371,7 +383,7 @@ static const u32 camellia_sp4404[256] = { ^ camellia_sp3033[(u8)(il >> 8)] \ ^ camellia_sp4404[(u8)(il )]; \ yl ^= yr; \ - yr = ror32(yr, 8); \ + yr = ROR8(yr); \ yr ^= yl; \ } while(0) @@ -393,7 +405,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) subL[7] ^= subL[1]; subR[7] ^= subR[1]; subL[1] ^= subR[1] & ~subR[9]; dw = subL[1] & subL[9], - subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl2) */ + subR[1] ^= ROL1(dw); /* modified for FLinv(kl2) */ /* round 8 */ subL[11] ^= subL[1]; subR[11] ^= subR[1]; /* round 10 */ @@ -402,7 +414,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) subL[15] ^= subL[1]; subR[15] ^= subR[1]; subL[1] ^= subR[1] & ~subR[17]; dw = subL[1] & subL[17], - subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl4) */ + subR[1] ^= ROL1(dw); /* modified for FLinv(kl4) */ /* round 14 */ subL[19] ^= subL[1]; subR[19] ^= subR[1]; /* round 16 */ @@ -418,7 +430,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) } else { subL[1] ^= subR[1] & ~subR[25]; dw = subL[1] & subL[25], - subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl6) */ + subR[1] ^= ROL1(dw); /* modified for FLinv(kl6) */ /* round 20 */ subL[27] ^= subL[1]; subR[27] ^= subR[1]; /* round 22 */ @@ -438,7 +450,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) subL[26] ^= kw4l; subR[26] ^= kw4r; kw4l ^= kw4r & ~subR[24]; dw = kw4l & subL[24], - kw4r ^= rol32(dw, 1); /* modified for FL(kl5) */ + kw4r ^= ROL1(dw); /* modified for FL(kl5) */ } /* round 17 */ subL[22] ^= kw4l; subR[22] ^= kw4r; @@ -448,7 +460,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) subL[18] ^= kw4l; subR[18] ^= kw4r; kw4l ^= kw4r & ~subR[16]; dw = kw4l & subL[16], - kw4r ^= rol32(dw, 1); /* modified for FL(kl3) */ + kw4r ^= ROL1(dw); /* modified for FL(kl3) */ /* round 11 */ subL[14] ^= kw4l; subR[14] ^= kw4r; /* round 9 */ @@ -457,7 +469,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) subL[10] ^= kw4l; subR[10] ^= kw4r; kw4l ^= kw4r & ~subR[8]; dw = kw4l & subL[8], - kw4r ^= rol32(dw, 1); /* modified for FL(kl1) */ + kw4r ^= ROL1(dw); /* modified for FL(kl1) */ /* round 5 */ subL[6] ^= kw4l; subR[6] ^= kw4r; /* round 3 */ @@ -482,7 +494,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) SUBKEY_R(6) = subR[5] ^ subR[7]; tl = subL[10] ^ (subR[10] & ~subR[8]); dw = tl & subL[8], /* FL(kl1) */ - tr = subR[10] ^ rol32(dw, 1); + tr = subR[10] ^ ROL1(dw); SUBKEY_L(7) = subL[6] ^ tl; /* round 6 */ SUBKEY_R(7) = subR[6] ^ tr; SUBKEY_L(8) = subL[8]; /* FL(kl1) */ @@ -491,7 +503,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) SUBKEY_R(9) = subR[9]; tl = subL[7] ^ (subR[7] & ~subR[9]); dw = tl & subL[9], /* FLinv(kl2) */ - tr = subR[7] ^ rol32(dw, 1); + tr = subR[7] ^ ROL1(dw); SUBKEY_L(10) = tl ^ subL[11]; /* round 7 */ SUBKEY_R(10) = tr ^ subR[11]; SUBKEY_L(11) = subL[10] ^ subL[12]; /* round 8 */ @@ -504,7 +516,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) SUBKEY_R(14) = subR[13] ^ subR[15]; tl = subL[18] ^ (subR[18] & ~subR[16]); dw = tl & subL[16], /* FL(kl3) */ - tr = subR[18] ^ rol32(dw, 1); + tr = subR[18] ^ ROL1(dw); SUBKEY_L(15) = subL[14] ^ tl; /* round 12 */ SUBKEY_R(15) = subR[14] ^ tr; SUBKEY_L(16) = subL[16]; /* FL(kl3) */ @@ -513,7 +525,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) SUBKEY_R(17) = subR[17]; tl = subL[15] ^ (subR[15] & ~subR[17]); dw = tl & subL[17], /* FLinv(kl4) */ - tr = subR[15] ^ rol32(dw, 1); + tr = subR[15] ^ ROL1(dw); SUBKEY_L(18) = tl ^ subL[19]; /* round 13 */ SUBKEY_R(18) = tr ^ subR[19]; SUBKEY_L(19) = subL[18] ^ subL[20]; /* round 14 */ @@ -532,7 +544,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) } else { tl = subL[26] ^ (subR[26] & ~subR[24]); dw = tl & subL[24], /* FL(kl5) */ - tr = subR[26] ^ rol32(dw, 1); + tr = subR[26] ^ ROL1(dw); SUBKEY_L(23) = subL[22] ^ tl; /* round 18 */ SUBKEY_R(23) = subR[22] ^ tr; SUBKEY_L(24) = subL[24]; /* FL(kl5) */ @@ -541,7 +553,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) SUBKEY_R(25) = subR[25]; tl = subL[23] ^ (subR[23] & ~subR[25]); dw = tl & subL[25], /* FLinv(kl6) */ - tr = subR[23] ^ rol32(dw, 1); + tr = subR[23] ^ ROL1(dw); SUBKEY_L(26) = tl ^ subL[27]; /* round 19 */ SUBKEY_R(26) = tr ^ subR[27]; SUBKEY_L(27) = subL[26] ^ subL[28]; /* round 20 */ @@ -561,17 +573,17 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) /* apply the inverse of the last half of P-function */ i = 2; do { - dw = SUBKEY_L(i + 0) ^ SUBKEY_R(i + 0); dw = rol32(dw, 8);/* round 1 */ + dw = SUBKEY_L(i + 0) ^ SUBKEY_R(i + 0); dw = ROL8(dw);/* round 1 */ SUBKEY_R(i + 0) = SUBKEY_L(i + 0) ^ dw; SUBKEY_L(i + 0) = dw; - dw = SUBKEY_L(i + 1) ^ SUBKEY_R(i + 1); dw = rol32(dw, 8);/* round 2 */ + dw = SUBKEY_L(i + 1) ^ SUBKEY_R(i + 1); dw = ROL8(dw);/* round 2 */ SUBKEY_R(i + 1) = SUBKEY_L(i + 1) ^ dw; SUBKEY_L(i + 1) = dw; - dw = SUBKEY_L(i + 2) ^ SUBKEY_R(i + 2); dw = rol32(dw, 8);/* round 3 */ + dw = SUBKEY_L(i + 2) ^ SUBKEY_R(i + 2); dw = ROL8(dw);/* round 3 */ SUBKEY_R(i + 2) = SUBKEY_L(i + 2) ^ dw; SUBKEY_L(i + 2) = dw; - dw = SUBKEY_L(i + 3) ^ SUBKEY_R(i + 3); dw = rol32(dw, 8);/* round 4 */ + dw = SUBKEY_L(i + 3) ^ SUBKEY_R(i + 3); dw = ROL8(dw);/* round 4 */ SUBKEY_R(i + 3) = SUBKEY_L(i + 3) ^ dw; SUBKEY_L(i + 3) = dw; - dw = SUBKEY_L(i + 4) ^ SUBKEY_R(i + 4); dw = rol32(dw, 9);/* round 5 */ + dw = SUBKEY_L(i + 4) ^ SUBKEY_R(i + 4); dw = ROL8(dw);/* round 5 */ SUBKEY_R(i + 4) = SUBKEY_L(i + 4) ^ dw; SUBKEY_L(i + 4) = dw; - dw = SUBKEY_L(i + 5) ^ SUBKEY_R(i + 5); dw = rol32(dw, 8);/* round 6 */ + dw = SUBKEY_L(i + 5) ^ SUBKEY_R(i + 5); dw = ROL8(dw);/* round 6 */ SUBKEY_R(i + 5) = SUBKEY_L(i + 5) ^ dw; SUBKEY_L(i + 5) = dw; i += 8; } while (i < max); @@ -587,10 +599,10 @@ static void camellia_setup128(const unsigned char *key, u32 *subkey) /** * k == kll || klr || krl || krr (|| is concatenation) */ - kll = get_unaligned_be32(key); - klr = get_unaligned_be32(key + 4); - krl = get_unaligned_be32(key + 8); - krr = get_unaligned_be32(key + 12); + GETU32(kll, key ); + GETU32(klr, key + 4); + GETU32(krl, key + 8); + GETU32(krr, key + 12); /* generate KL dependent subkeys */ /* kw1 */ @@ -695,14 +707,14 @@ static void camellia_setup256(const unsigned char *key, u32 *subkey) * key = (kll || klr || krl || krr || krll || krlr || krrl || krrr) * (|| is concatenation) */ - kll = get_unaligned_be32(key); - klr = get_unaligned_be32(key + 4); - krl = get_unaligned_be32(key + 8); - krr = get_unaligned_be32(key + 12); - krll = get_unaligned_be32(key + 16); - krlr = get_unaligned_be32(key + 20); - krrl = get_unaligned_be32(key + 24); - krrr = get_unaligned_be32(key + 28); + GETU32(kll, key ); + GETU32(klr, key + 4); + GETU32(krl, key + 8); + GETU32(krr, key + 12); + GETU32(krll, key + 16); + GETU32(krlr, key + 20); + GETU32(krrl, key + 24); + GETU32(krrr, key + 28); /* generate KL dependent subkeys */ /* kw1 */ @@ -858,13 +870,13 @@ static void camellia_setup192(const unsigned char *key, u32 *subkey) t0 &= ll; \ t2 |= rr; \ rl ^= t2; \ - lr ^= rol32(t0, 1); \ + lr ^= ROL1(t0); \ t3 = krl; \ t1 = klr; \ t3 &= rl; \ t1 |= lr; \ ll ^= t1; \ - rr ^= rol32(t3, 1); \ + rr ^= ROL1(t3); \ } while(0) #define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir) \ @@ -880,7 +892,7 @@ static void camellia_setup192(const unsigned char *key, u32 *subkey) il ^= kl; \ ir ^= il ^ kr; \ yl ^= ir; \ - yr ^= ror32(il, 8) ^ ir; \ + yr ^= ROR8(il) ^ ir; \ } while(0) /* max = 24: 128bit encrypt, max = 32: 256bit encrypt */ diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c index 1022e38994c2..0f2805899210 100644 --- a/drivers/acpi/dispatcher/dsobject.c +++ b/drivers/acpi/dispatcher/dsobject.c @@ -496,7 +496,7 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, arg = arg->common.next; } - ACPI_ERROR((AE_INFO, + ACPI_WARNING((AE_INFO, "Package List length (%X) larger than NumElements count (%X), truncated\n", i, element_count)); } else if (i < element_count) { diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index d3f0a62efcc1..ee68ac54c0d4 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -138,7 +138,7 @@ static struct dmi_system_id __cpuinitdata processor_idle_dmi_table[] = { { set_no_mwait, "Extensa 5220", { DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), - DMI_MATCH(DMI_SYS_VENDOR, "ACER"), + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_VERSION, "0100"), DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL}, {}, diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 80e32093e977..80c251ec6d2a 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -71,7 +71,7 @@ static DEFINE_MUTEX(performance_mutex); * 1 -> ignore _PPC totally -> forced by user through boot param */ static int ignore_ppc = -1; -module_param(ignore_ppc, uint, 0644); +module_param(ignore_ppc, int, 0644); MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \ "limited by BIOS, this should help"); diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index bcf2c70fca87..a4e3767b8c64 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -107,6 +107,13 @@ static int wait_transaction_complete(struct acpi_smb_hc *hc, int timeout) if (wait_event_timeout(hc->wait, smb_check_done(hc), msecs_to_jiffies(timeout))) return 0; + /* + * After the timeout happens, OS will try to check the status of SMbus. + * If the status is what OS expected, it will be regarded as the bogus + * timeout. + */ + if (smb_check_done(hc)) + return 0; else return -ETIME; } diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index c3419182c9a7..775c97a282bd 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -300,6 +300,8 @@ int __init acpi_table_init(void) static int __init acpi_parse_apic_instance(char *str) { + if (!str) + return -EINVAL; acpi_apic_instance = simple_strtoul(str, NULL, 0); diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index ae8494944c45..11c8c19f0fb7 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -448,8 +448,10 @@ config PATA_MARVELL tristate "Marvell PATA support via legacy mode" depends on PCI help - This option enables limited support for the Marvell 88SE6145 ATA - controller. + This option enables limited support for the Marvell 88SE61xx ATA + controllers. If you wish to use only the SATA ports then select + the AHCI driver alone. If you wish to the use the PATA port or + both SATA and PATA include this driver. If unsure, say N. diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c729e6988bbb..2e1a7cb2ed5f 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -420,7 +420,7 @@ static const struct ata_port_info ahci_port_info[] = { /* board_ahci_mv */ { AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI | - AHCI_HFLAG_MV_PATA), + AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP), .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA, .pio_mask = 0x1f, /* pio0-4 */ @@ -487,7 +487,9 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */ { PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */ { PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */ + { PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */ { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */ + { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, @@ -610,6 +612,15 @@ module_param(ahci_em_messages, int, 0444); MODULE_PARM_DESC(ahci_em_messages, "Set AHCI Enclosure Management Message type (0 = disabled, 1 = LED"); +#if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE) +static int marvell_enable; +#else +static int marvell_enable = 1; +#endif +module_param(marvell_enable, int, 0644); +MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)"); + + static inline int ahci_nr_ports(u32 cap) { return (cap & 0x1f) + 1; @@ -732,6 +743,8 @@ static void ahci_save_initial_config(struct pci_dev *pdev, "MV_AHCI HACK: port_map %x -> %x\n", port_map, port_map & mv); + dev_printk(KERN_ERR, &pdev->dev, + "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n"); port_map &= mv; } @@ -2533,6 +2546,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); + /* The AHCI driver can only drive the SATA ports, the PATA driver + can drive them all so if both drivers are selected make sure + AHCI stays out of the way */ + if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable) + return -ENODEV; + /* acquire resources */ rc = pcim_enable_device(pdev); if (rc) diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 304fdc6f1dc2..2a4c516894f0 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -1315,11 +1315,6 @@ fsm_start: break; case HSM_ST_ERR: - /* make sure qc->err_mask is available to - * know what's wrong and recover - */ - WARN_ON(!(qc->err_mask & (AC_ERR_DEV | AC_ERR_HSM))); - ap->hsm_task_state = HSM_ST_IDLE; /* complete taskfile transaction */ diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index 24a011b25024..0d87eec84966 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -20,29 +20,30 @@ #include <linux/ata.h> #define DRV_NAME "pata_marvell" -#define DRV_VERSION "0.1.4" +#define DRV_VERSION "0.1.6" /** - * marvell_pre_reset - check for 40/80 pin - * @link: link - * @deadline: deadline jiffies for the operation + * marvell_pata_active - check if PATA is active + * @pdev: PCI device * - * Perform the PATA port setup we need. + * Returns 1 if the PATA port may be active. We know how to check this + * for the 6145 but not the other devices */ -static int marvell_pre_reset(struct ata_link *link, unsigned long deadline) +static int marvell_pata_active(struct pci_dev *pdev) { - struct ata_port *ap = link->ap; - struct pci_dev *pdev = to_pci_dev(ap->host->dev); + int i; u32 devices; void __iomem *barp; - int i; - /* Check if our port is enabled */ + /* We don't yet know how to do this for other devices */ + if (pdev->device != 0x6145) + return 1; barp = pci_iomap(pdev, 5, 0x10); if (barp == NULL) return -ENOMEM; + printk("BAR5:"); for(i = 0; i <= 0x0F; i++) printk("%02X:%02X ", i, ioread8(barp + i)); @@ -51,9 +52,27 @@ static int marvell_pre_reset(struct ata_link *link, unsigned long deadline) devices = ioread32(barp + 0x0C); pci_iounmap(pdev, barp); - if ((pdev->device == 0x6145) && (ap->port_no == 0) && - (!(devices & 0x10))) /* PATA enable ? */ - return -ENOENT; + if (devices & 0x10) + return 1; + return 0; +} + +/** + * marvell_pre_reset - check for 40/80 pin + * @link: link + * @deadline: deadline jiffies for the operation + * + * Perform the PATA port setup we need. + */ + +static int marvell_pre_reset(struct ata_link *link, unsigned long deadline) +{ + struct ata_port *ap = link->ap; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + + if (pdev->device == 0x6145 && ap->port_no == 0 && + !marvell_pata_active(pdev)) /* PATA enable ? */ + return -ENOENT; return ata_sff_prereset(link, deadline); } @@ -128,6 +147,12 @@ static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *i if (pdev->device == 0x6101) ppi[1] = &ata_dummy_port_info; +#if defined(CONFIG_AHCI) || defined(CONFIG_AHCI_MODULE) + if (!marvell_pata_active(pdev)) { + printk(KERN_INFO DRV_NAME ": PATA port not active, deferring to AHCI driver.\n"); + return -ENODEV; + } +#endif return ata_pci_sff_init_one(pdev, ppi, &marvell_sht, NULL); } diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 720b8645f58a..e970b227fbce 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -322,9 +322,6 @@ static int __devinit sil680_init_one(struct pci_dev *pdev, /* Try to acquire MMIO resources and fallback to PIO if * that fails */ - rc = pcim_enable_device(pdev); - if (rc) - return rc; rc = pcim_iomap_regions(pdev, 1 << SIL680_MMIO_BAR, DRV_NAME); if (rc) goto use_ioports; diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 13c1d2af18ac..c815f8ecf6e6 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -667,7 +667,8 @@ static const struct pci_device_id mv_pci_tbl[] = { { PCI_VDEVICE(MARVELL, 0x5041), chip_504x }, { PCI_VDEVICE(MARVELL, 0x5080), chip_5080 }, { PCI_VDEVICE(MARVELL, 0x5081), chip_508x }, - /* RocketRAID 1740/174x have different identifiers */ + /* RocketRAID 1720/174x have different identifiers */ + { PCI_VDEVICE(TTI, 0x1720), chip_6042 }, { PCI_VDEVICE(TTI, 0x1740), chip_508x }, { PCI_VDEVICE(TTI, 0x1742), chip_508x }, diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 858f70610eda..1e1f3f3757ae 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -309,8 +309,6 @@ static void nv_nf2_freeze(struct ata_port *ap); static void nv_nf2_thaw(struct ata_port *ap); static void nv_ck804_freeze(struct ata_port *ap); static void nv_ck804_thaw(struct ata_port *ap); -static int nv_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline); static int nv_adma_slave_config(struct scsi_device *sdev); static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc); static void nv_adma_qc_prep(struct ata_queued_cmd *qc); @@ -407,7 +405,7 @@ static struct scsi_host_template nv_swncq_sht = { static struct ata_port_operations nv_generic_ops = { .inherits = &ata_bmdma_port_ops, - .hardreset = nv_hardreset, + .hardreset = ATA_OP_NULL, .scr_read = nv_scr_read, .scr_write = nv_scr_write, }; @@ -1588,21 +1586,6 @@ static void nv_mcp55_thaw(struct ata_port *ap) ata_sff_thaw(ap); } -static int nv_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) -{ - int rc; - - /* SATA hardreset fails to retrieve proper device signature on - * some controllers. Request follow up SRST. For more info, - * see http://bugzilla.kernel.org/show_bug.cgi?id=3352 - */ - rc = sata_sff_hardreset(link, class, deadline); - if (rc) - return rc; - return -EAGAIN; -} - static void nv_adma_error_handler(struct ata_port *ap) { struct nv_adma_port_priv *pp = ap->private_data; diff --git a/drivers/char/random.c b/drivers/char/random.c index 1838aa3d24fe..7ce1ac4baa6d 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -407,7 +407,7 @@ struct entropy_store { /* read-write data: */ spinlock_t lock; unsigned add_ptr; - int entropy_count; + int entropy_count; /* Must at no time exceed ->POOLBITS! */ int input_rotate; }; @@ -520,6 +520,7 @@ static void mix_pool_bytes(struct entropy_store *r, const void *in, int bytes) static void credit_entropy_bits(struct entropy_store *r, int nbits) { unsigned long flags; + int entropy_count; if (!nbits) return; @@ -527,20 +528,20 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits) spin_lock_irqsave(&r->lock, flags); DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name); - r->entropy_count += nbits; - if (r->entropy_count < 0) { + entropy_count = r->entropy_count; + entropy_count += nbits; + if (entropy_count < 0) { DEBUG_ENT("negative entropy/overflow\n"); - r->entropy_count = 0; - } else if (r->entropy_count > r->poolinfo->POOLBITS) - r->entropy_count = r->poolinfo->POOLBITS; + entropy_count = 0; + } else if (entropy_count > r->poolinfo->POOLBITS) + entropy_count = r->poolinfo->POOLBITS; + r->entropy_count = entropy_count; /* should we wake readers? */ - if (r == &input_pool && - r->entropy_count >= random_read_wakeup_thresh) { + if (r == &input_pool && entropy_count >= random_read_wakeup_thresh) { wake_up_interruptible(&random_read_wait); kill_fasync(&fasync, SIGIO, POLL_IN); } - spin_unlock_irqrestore(&r->lock, flags); } diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index 5ca1d80de182..4eee533f3f4a 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -21,6 +21,7 @@ #include <linux/errno.h> #include <linux/init.h> #include <linux/pci.h> +#include <linux/delay.h> #include <asm/io.h> /* @@ -151,13 +152,13 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE, */ static int verify_pmtmr_rate(void) { - u32 value1, value2; + cycle_t value1, value2; unsigned long count, delta; mach_prepare_counter(); - value1 = read_pmtmr(); + value1 = clocksource_acpi_pm.read(); mach_countup(&count); - value2 = read_pmtmr(); + value2 = clocksource_acpi_pm.read(); delta = (value2 - value1) & ACPI_PM_MASK; /* Check that the PMTMR delta is within 5% of what we expect */ @@ -175,10 +176,13 @@ static int verify_pmtmr_rate(void) #define verify_pmtmr_rate() (0) #endif +/* Number of monotonicity checks to perform during initialization */ +#define ACPI_PM_MONOTONICITY_CHECKS 10 + static int __init init_acpi_pm_clocksource(void) { - u32 value1, value2; - unsigned int i; + cycle_t value1, value2; + unsigned int i, j, good = 0; if (!pmtmr_ioport) return -ENODEV; @@ -187,24 +191,32 @@ static int __init init_acpi_pm_clocksource(void) clocksource_acpi_pm.shift); /* "verify" this timing source: */ - value1 = read_pmtmr(); - for (i = 0; i < 10000; i++) { - value2 = read_pmtmr(); - if (value2 == value1) - continue; - if (value2 > value1) - goto pm_good; - if ((value2 < value1) && ((value2) < 0xFFF)) - goto pm_good; - printk(KERN_INFO "PM-Timer had inconsistent results:" - " 0x%#x, 0x%#x - aborting.\n", value1, value2); - return -EINVAL; + for (j = 0; j < ACPI_PM_MONOTONICITY_CHECKS; j++) { + value1 = clocksource_acpi_pm.read(); + for (i = 0; i < 10000; i++) { + value2 = clocksource_acpi_pm.read(); + if (value2 == value1) + continue; + if (value2 > value1) + good++; + break; + if ((value2 < value1) && ((value2) < 0xFFF)) + good++; + break; + printk(KERN_INFO "PM-Timer had inconsistent results:" + " 0x%#llx, 0x%#llx - aborting.\n", + value1, value2); + return -EINVAL; + } + udelay(300 * i); + } + + if (good != ACPI_PM_MONOTONICITY_CHECKS) { + printk(KERN_INFO "PM-Timer failed consistency check " + " (0x%#llx) - aborting.\n", value1); + return -ENODEV; } - printk(KERN_INFO "PM-Timer had no reasonable result:" - " 0x%#x - aborting.\n", value1); - return -ENODEV; -pm_good: if (verify_pmtmr_rate() != 0) return -ENODEV; diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c index 8024e3bfd877..b91ef63126ed 100644 --- a/drivers/firmware/iscsi_ibft.c +++ b/drivers/firmware/iscsi_ibft.c @@ -669,8 +669,7 @@ static int __init ibft_register_kobjects(struct ibft_table_header *header, control = (void *)header + sizeof(*header); end = (void *)control + control->hdr.length; - eot_offset = (void *)header + header->length - - (void *)control - sizeof(*header); + eot_offset = (void *)header + header->length - (void *)control; rc = ibft_verify_hdr("control", (struct ibft_hdr *)control, id_control, sizeof(*control)); diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c index 3331f88dcfb6..248ab4a7d39f 100644 --- a/drivers/gpu/drm/radeon/radeon_cp.c +++ b/drivers/gpu/drm/radeon/radeon_cp.c @@ -223,7 +223,7 @@ static int radeon_do_wait_for_fifo(drm_radeon_private_t * dev_priv, int entries) return 0; DRM_UDELAY(1); } - DRM_INFO("wait for fifo failed status : 0x%08X 0x%08X\n", + DRM_DEBUG("wait for fifo failed status : 0x%08X 0x%08X\n", RADEON_READ(RADEON_RBBM_STATUS), RADEON_READ(R300_VAP_CNTL_STATUS)); @@ -252,7 +252,7 @@ static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv) } DRM_UDELAY(1); } - DRM_INFO("wait idle failed status : 0x%08X 0x%08X\n", + DRM_DEBUG("wait idle failed status : 0x%08X 0x%08X\n", RADEON_READ(RADEON_RBBM_STATUS), RADEON_READ(R300_VAP_CNTL_STATUS)); diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 840e634fa31f..640cbb237328 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -31,13 +31,84 @@ #include <linux/clk.h> #include <linux/io.h> +/* Transmit operation: */ +/* */ +/* 0 byte transmit */ +/* BUS: S A8 ACK P */ +/* IRQ: DTE WAIT */ +/* ICIC: */ +/* ICCR: 0x94 0x90 */ +/* ICDR: A8 */ +/* */ +/* 1 byte transmit */ +/* BUS: S A8 ACK D8(1) ACK P */ +/* IRQ: DTE WAIT WAIT */ +/* ICIC: -DTE */ +/* ICCR: 0x94 0x90 */ +/* ICDR: A8 D8(1) */ +/* */ +/* 2 byte transmit */ +/* BUS: S A8 ACK D8(1) ACK D8(2) ACK P */ +/* IRQ: DTE WAIT WAIT WAIT */ +/* ICIC: -DTE */ +/* ICCR: 0x94 0x90 */ +/* ICDR: A8 D8(1) D8(2) */ +/* */ +/* 3 bytes or more, +---------+ gets repeated */ +/* */ +/* */ +/* Receive operation: */ +/* */ +/* 0 byte receive - not supported since slave may hold SDA low */ +/* */ +/* 1 byte receive [TX] | [RX] */ +/* BUS: S A8 ACK | D8(1) ACK P */ +/* IRQ: DTE WAIT | WAIT DTE */ +/* ICIC: -DTE | +DTE */ +/* ICCR: 0x94 0x81 | 0xc0 */ +/* ICDR: A8 | D8(1) */ +/* */ +/* 2 byte receive [TX]| [RX] */ +/* BUS: S A8 ACK | D8(1) ACK D8(2) ACK P */ +/* IRQ: DTE WAIT | WAIT WAIT DTE */ +/* ICIC: -DTE | +DTE */ +/* ICCR: 0x94 0x81 | 0xc0 */ +/* ICDR: A8 | D8(1) D8(2) */ +/* */ +/* 3 byte receive [TX] | [RX] */ +/* BUS: S A8 ACK | D8(1) ACK D8(2) ACK D8(3) ACK P */ +/* IRQ: DTE WAIT | WAIT WAIT WAIT DTE */ +/* ICIC: -DTE | +DTE */ +/* ICCR: 0x94 0x81 | 0xc0 */ +/* ICDR: A8 | D8(1) D8(2) D8(3) */ +/* */ +/* 4 bytes or more, this part is repeated +---------+ */ +/* */ +/* */ +/* Interrupt order and BUSY flag */ +/* ___ _ */ +/* SDA ___\___XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAAAAAAA___/ */ +/* SCL \_/1\_/2\_/3\_/4\_/5\_/6\_/7\_/8\___/9\_____/ */ +/* */ +/* S D7 D6 D5 D4 D3 D2 D1 D0 P */ +/* ___ */ +/* WAIT IRQ ________________________________/ \___________ */ +/* TACK IRQ ____________________________________/ \_______ */ +/* DTE IRQ __________________________________________/ \_ */ +/* AL IRQ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ +/* _______________________________________________ */ +/* BUSY __/ \_ */ +/* */ + enum sh_mobile_i2c_op { OP_START = 0, - OP_TX_ONLY, + OP_TX_FIRST, + OP_TX, OP_TX_STOP, OP_TX_TO_RX, - OP_RX_ONLY, + OP_RX, OP_RX_STOP, + OP_RX_STOP_DATA, }; struct sh_mobile_i2c_data { @@ -127,25 +198,34 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, spin_lock_irqsave(&pd->lock, flags); switch (op) { - case OP_START: + case OP_START: /* issue start and trigger DTE interrupt */ iowrite8(0x94, ICCR(pd)); break; - case OP_TX_ONLY: + case OP_TX_FIRST: /* disable DTE interrupt and write data */ + iowrite8(ICIC_WAITE | ICIC_ALE | ICIC_TACKE, ICIC(pd)); iowrite8(data, ICDR(pd)); break; - case OP_TX_STOP: + case OP_TX: /* write data */ iowrite8(data, ICDR(pd)); - iowrite8(0x90, ICCR(pd)); - iowrite8(ICIC_ALE | ICIC_TACKE, ICIC(pd)); break; - case OP_TX_TO_RX: + case OP_TX_STOP: /* write data and issue a stop afterwards */ iowrite8(data, ICDR(pd)); + iowrite8(0x90, ICCR(pd)); + break; + case OP_TX_TO_RX: /* select read mode */ iowrite8(0x81, ICCR(pd)); break; - case OP_RX_ONLY: + case OP_RX: /* just read data */ ret = ioread8(ICDR(pd)); break; - case OP_RX_STOP: + case OP_RX_STOP: /* enable DTE interrupt, issue stop */ + iowrite8(ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE, + ICIC(pd)); + iowrite8(0xc0, ICCR(pd)); + break; + case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */ + iowrite8(ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE, + ICIC(pd)); ret = ioread8(ICDR(pd)); iowrite8(0xc0, ICCR(pd)); break; @@ -157,58 +237,120 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, return ret; } +static int sh_mobile_i2c_is_first_byte(struct sh_mobile_i2c_data *pd) +{ + if (pd->pos == -1) + return 1; + + return 0; +} + +static int sh_mobile_i2c_is_last_byte(struct sh_mobile_i2c_data *pd) +{ + if (pd->pos == (pd->msg->len - 1)) + return 1; + + return 0; +} + +static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd, + unsigned char *buf) +{ + switch (pd->pos) { + case -1: + *buf = (pd->msg->addr & 0x7f) << 1; + *buf |= (pd->msg->flags & I2C_M_RD) ? 1 : 0; + break; + default: + *buf = pd->msg->buf[pd->pos]; + } +} + +static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd) +{ + unsigned char data; + + if (pd->pos == pd->msg->len) + return 1; + + sh_mobile_i2c_get_data(pd, &data); + + if (sh_mobile_i2c_is_last_byte(pd)) + i2c_op(pd, OP_TX_STOP, data); + else if (sh_mobile_i2c_is_first_byte(pd)) + i2c_op(pd, OP_TX_FIRST, data); + else + i2c_op(pd, OP_TX, data); + + pd->pos++; + return 0; +} + +static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd) +{ + unsigned char data; + int real_pos; + + do { + if (pd->pos <= -1) { + sh_mobile_i2c_get_data(pd, &data); + + if (sh_mobile_i2c_is_first_byte(pd)) + i2c_op(pd, OP_TX_FIRST, data); + else + i2c_op(pd, OP_TX, data); + break; + } + + if (pd->pos == 0) { + i2c_op(pd, OP_TX_TO_RX, 0); + break; + } + + real_pos = pd->pos - 2; + + if (pd->pos == pd->msg->len) { + if (real_pos < 0) { + i2c_op(pd, OP_RX_STOP, 0); + break; + } + data = i2c_op(pd, OP_RX_STOP_DATA, 0); + } else + data = i2c_op(pd, OP_RX, 0); + + pd->msg->buf[real_pos] = data; + } while (0); + + pd->pos++; + return pd->pos == (pd->msg->len + 2); +} + static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) { struct platform_device *dev = dev_id; struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev); - struct i2c_msg *msg = pd->msg; - unsigned char data, sr; - int wakeup = 0; + unsigned char sr; + int wakeup; sr = ioread8(ICSR(pd)); - pd->sr |= sr; + pd->sr |= sr; /* remember state */ dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr, - (msg->flags & I2C_M_RD) ? "read" : "write", - pd->pos, msg->len); + (pd->msg->flags & I2C_M_RD) ? "read" : "write", + pd->pos, pd->msg->len); if (sr & (ICSR_AL | ICSR_TACK)) { - iowrite8(0, ICIC(pd)); /* disable interrupts */ - wakeup = 1; - goto do_wakeup; - } + /* don't interrupt transaction - continue to issue stop */ + iowrite8(sr & ~(ICSR_AL | ICSR_TACK), ICSR(pd)); + wakeup = 0; + } else if (pd->msg->flags & I2C_M_RD) + wakeup = sh_mobile_i2c_isr_rx(pd); + else + wakeup = sh_mobile_i2c_isr_tx(pd); - if (pd->pos == msg->len) { - i2c_op(pd, OP_RX_ONLY, 0); - wakeup = 1; - goto do_wakeup; - } + if (sr & ICSR_WAIT) /* TODO: add delay here to support slow acks */ + iowrite8(sr & ~ICSR_WAIT, ICSR(pd)); - if (pd->pos == -1) { - data = (msg->addr & 0x7f) << 1; - data |= (msg->flags & I2C_M_RD) ? 1 : 0; - } else - data = msg->buf[pd->pos]; - - if ((pd->pos == -1) || !(msg->flags & I2C_M_RD)) { - if (msg->flags & I2C_M_RD) - i2c_op(pd, OP_TX_TO_RX, data); - else if (pd->pos == (msg->len - 1)) { - i2c_op(pd, OP_TX_STOP, data); - wakeup = 1; - } else - i2c_op(pd, OP_TX_ONLY, data); - } else { - if (pd->pos == (msg->len - 1)) - data = i2c_op(pd, OP_RX_STOP, 0); - else - data = i2c_op(pd, OP_RX_ONLY, 0); - - msg->buf[pd->pos] = data; - } - pd->pos++; - - do_wakeup: if (wakeup) { pd->sr |= SW_DONE; wake_up(&pd->wait); @@ -219,6 +361,11 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg) { + if (usr_msg->len == 0 && (usr_msg->flags & I2C_M_RD)) { + dev_err(pd->dev, "Unsupported zero length i2c read\n"); + return -EIO; + } + /* Initialize channel registers */ iowrite8(ioread8(ICCR(pd)) & ~ICCR_ICE, ICCR(pd)); @@ -233,9 +380,8 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg) pd->pos = -1; pd->sr = 0; - /* Enable all interrupts except wait */ - iowrite8(ioread8(ICIC(pd)) | ICIC_ALE | ICIC_TACKE | ICIC_DTEE, - ICIC(pd)); + /* Enable all interrupts to begin with */ + iowrite8(ICIC_WAITE | ICIC_ALE | ICIC_TACKE | ICIC_DTEE, ICIC(pd)); return 0; } @@ -268,25 +414,18 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, if (!k) dev_err(pd->dev, "Transfer request timed out\n"); - retry_count = 10; + retry_count = 1000; again: val = ioread8(ICSR(pd)); dev_dbg(pd->dev, "val 0x%02x pd->sr 0x%02x\n", val, pd->sr); - if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) { - err = -EIO; - break; - } - /* the interrupt handler may wake us up before the * transfer is finished, so poll the hardware * until we're done. */ - - if (!(!(val & ICSR_BUSY) && (val & ICSR_SCLM) && - (val & ICSR_SDAM))) { - msleep(1); + if (val & ICSR_BUSY) { + udelay(10); if (retry_count--) goto again; @@ -294,6 +433,12 @@ again: dev_err(pd->dev, "Polling timed out\n"); break; } + + /* handle missing acknowledge and arbitration lost */ + if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) { + err = -EIO; + break; + } } deactivate_ch(pd); diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index a34758d29516..fc735ab08ff4 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -242,7 +242,7 @@ config BLK_DEV_IDEFLOPPY module will be called ide-floppy. config BLK_DEV_IDESCSI - tristate "SCSI emulation support" + tristate "SCSI emulation support (DEPRECATED)" depends on SCSI select IDE_ATAPI ---help--- @@ -255,20 +255,6 @@ config BLK_DEV_IDESCSI and will allow you to use a SCSI device driver instead of a native ATAPI driver. - This is useful if you have an ATAPI device for which no native - driver has been written (for example, an ATAPI PD-CD drive); - you can then use this emulation together with an appropriate SCSI - device driver. In order to do this, say Y here and to "SCSI support" - and "SCSI generic support", below. You must then provide the kernel - command line "hdx=ide-scsi" (try "man bootparam" or see the - documentation of your boot loader (lilo or loadlin) about how to - pass options to the kernel at boot time) for devices if you want the - native EIDE sub-drivers to skip over the native support, so that - this SCSI emulation can be used instead. - - Note that this option does NOT allow you to attach SCSI devices to a - box that doesn't have a SCSI host adapter installed. - If both this SCSI emulation and native ATAPI support are compiled into the kernel, the native support will be used. diff --git a/drivers/ide/arm/palm_bk3710.c b/drivers/ide/arm/palm_bk3710.c index f788fa5a977b..4fd91dcf1dc2 100644 --- a/drivers/ide/arm/palm_bk3710.c +++ b/drivers/ide/arm/palm_bk3710.c @@ -343,11 +343,10 @@ static struct ide_port_info __devinitdata palm_bk3710_port_info = { .mwdma_mask = ATA_MWDMA2, }; -static int __devinit palm_bk3710_probe(struct platform_device *pdev) +static int __init palm_bk3710_probe(struct platform_device *pdev) { struct clk *clk; struct resource *mem, *irq; - struct ide_host *host; unsigned long base, rate; int i, rc; hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL }; @@ -390,6 +389,7 @@ static int __devinit palm_bk3710_probe(struct platform_device *pdev) hw.io_ports_array[i] = base + IDE_PALM_ATA_PRI_REG_OFFSET + i; hw.io_ports.ctl_addr = base + IDE_PALM_ATA_PRI_CTL_OFFSET; hw.irq = irq->start; + hw.dev = &pdev->dev; hw.chipset = ide_palm3710; palm_bk3710_port_info.udma_mask = rate < 100000000 ? ATA_UDMA4 : @@ -413,13 +413,11 @@ static struct platform_driver platform_bk_driver = { .name = "palm_bk3710", .owner = THIS_MODULE, }, - .probe = palm_bk3710_probe, - .remove = NULL, }; static int __init palm_bk3710_init(void) { - return platform_driver_register(&platform_bk_driver); + return platform_driver_probe(&platform_bk_driver, palm_bk3710_probe); } module_init(palm_bk3710_init); diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 49a8c589e346..f1489999cf91 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -1933,6 +1933,7 @@ static void ide_cd_remove(ide_drive_t *drive) ide_proc_unregister_driver(drive, info->driver); + blk_unregister_filter(info->disk); del_gendisk(info->disk); ide_cd_put(info); @@ -2158,6 +2159,7 @@ static int ide_cd_probe(ide_drive_t *drive) g->fops = &idecd_ops; g->flags |= GENHD_FL_REMOVABLE; add_disk(g); + blk_register_filter(g); return 0; out_free_cd: diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 68b9cf0138b0..07ef88bd109b 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -445,20 +445,6 @@ static void idedisk_check_hpa(ide_drive_t *drive) } } -/* - * Compute drive->capacity, the full capacity of the drive - * Called with drive->id != NULL. - * - * To compute capacity, this uses either of - * - * 1. CHS value set by user (whatever user sets will be trusted) - * 2. LBA value from target drive (require new ATA feature) - * 3. LBA value from system BIOS (new one is OK, old one may break) - * 4. CHS value from system BIOS (traditional style) - * - * in above order (i.e., if value of higher priority is available, - * reset will be ignored). - */ static void init_idedisk_capacity(ide_drive_t *drive) { struct hd_driveid *id = drive->id; diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index 2ec921bf3c60..18f4d7f6ce6d 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -63,7 +63,7 @@ } /* table of devices that work with this driver */ -static const struct usb_device_id bcm5974_table [] = { +static const struct usb_device_id bcm5974_table[] = { /* MacbookAir1.1 */ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ANSI), BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ISO), @@ -105,7 +105,7 @@ struct tp_header { /* trackpad finger structure */ struct tp_finger { - __le16 origin; /* left/right origin? */ + __le16 origin; /* zero when switching track finger */ __le16 abs_x; /* absolute x coodinate */ __le16 abs_y; /* absolute y coodinate */ __le16 rel_x; /* relative x coodinate */ @@ -159,6 +159,7 @@ struct bcm5974 { struct bt_data *bt_data; /* button transferred data */ struct urb *tp_urb; /* trackpad usb request block */ struct tp_data *tp_data; /* trackpad transferred data */ + int fingers; /* number of fingers on trackpad */ }; /* logical dimensions */ @@ -172,6 +173,10 @@ struct bcm5974 { #define SN_WIDTH 100 /* width signal-to-noise ratio */ #define SN_COORD 250 /* coordinate signal-to-noise ratio */ +/* pressure thresholds */ +#define PRESSURE_LOW (2 * DIM_PRESSURE / SN_PRESSURE) +#define PRESSURE_HIGH (3 * PRESSURE_LOW) + /* device constants */ static const struct bcm5974_config bcm5974_config_table[] = { { @@ -248,6 +253,7 @@ static void setup_events_to_report(struct input_dev *input_dev, 0, cfg->y.dim, cfg->y.fuzz, 0); __set_bit(EV_KEY, input_dev->evbit); + __set_bit(BTN_TOUCH, input_dev->keybit); __set_bit(BTN_TOOL_FINGER, input_dev->keybit); __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); @@ -273,32 +279,66 @@ static int report_tp_state(struct bcm5974 *dev, int size) const struct tp_finger *f = dev->tp_data->finger; struct input_dev *input = dev->input; const int fingers = (size - 26) / 28; - int p = 0, w, x, y, n = 0; + int raw_p, raw_w, raw_x, raw_y; + int ptest = 0, origin = 0, nmin = 0, nmax = 0; + int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0; if (size < 26 || (size - 26) % 28 != 0) return -EIO; + /* always track the first finger; when detached, start over */ if (fingers) { - p = raw2int(f->force_major); - w = raw2int(f->size_major); - x = raw2int(f->abs_x); - y = raw2int(f->abs_y); - n = p > 0 ? fingers : 0; + raw_p = raw2int(f->force_major); + raw_w = raw2int(f->size_major); + raw_x = raw2int(f->abs_x); + raw_y = raw2int(f->abs_y); dprintk(9, - "bcm5974: p: %+05d w: %+05d x: %+05d y: %+05d n: %d\n", - p, w, x, y, n); + "bcm5974: raw: p: %+05d w: %+05d x: %+05d y: %+05d\n", + raw_p, raw_w, raw_x, raw_y); + + ptest = int2bound(&c->p, raw_p); + origin = raw2int(f->origin); + } - input_report_abs(input, ABS_TOOL_WIDTH, int2bound(&c->w, w)); - input_report_abs(input, ABS_X, int2bound(&c->x, x - c->x.devmin)); - input_report_abs(input, ABS_Y, int2bound(&c->y, c->y.devmax - y)); + /* while tracking finger still valid, count all fingers */ + if (ptest > PRESSURE_LOW && origin) { + abs_p = ptest; + abs_w = int2bound(&c->w, raw_w); + abs_x = int2bound(&c->x, raw_x - c->x.devmin); + abs_y = int2bound(&c->y, c->y.devmax - raw_y); + for (; f != dev->tp_data->finger + fingers; f++) { + ptest = int2bound(&c->p, raw2int(f->force_major)); + if (ptest > PRESSURE_LOW) + nmax++; + if (ptest > PRESSURE_HIGH) + nmin++; + } } - input_report_abs(input, ABS_PRESSURE, int2bound(&c->p, p)); + if (dev->fingers < nmin) + dev->fingers = nmin; + if (dev->fingers > nmax) + dev->fingers = nmax; + + input_report_key(input, BTN_TOUCH, dev->fingers > 0); + input_report_key(input, BTN_TOOL_FINGER, dev->fingers == 1); + input_report_key(input, BTN_TOOL_DOUBLETAP, dev->fingers == 2); + input_report_key(input, BTN_TOOL_TRIPLETAP, dev->fingers > 2); - input_report_key(input, BTN_TOOL_FINGER, n == 1); - input_report_key(input, BTN_TOOL_DOUBLETAP, n == 2); - input_report_key(input, BTN_TOOL_TRIPLETAP, n > 2); + input_report_abs(input, ABS_PRESSURE, abs_p); + input_report_abs(input, ABS_TOOL_WIDTH, abs_w); + + if (abs_p) { + input_report_abs(input, ABS_X, abs_x); + input_report_abs(input, ABS_Y, abs_y); + + dprintk(8, + "bcm5974: abs: p: %+05d w: %+05d x: %+05d y: %+05d " + "nmin: %d nmax: %d n: %d\n", + abs_p, abs_w, abs_x, abs_y, nmin, nmax, dev->fingers); + + } input_sync(input); diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 3282b741e246..5aafe24984c5 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -305,7 +305,7 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { .ident = "Lenovo 3000 n100", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"), + DMI_MATCH(DMI_PRODUCT_NAME, "076804U"), }, }, { diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 7e65bad522cb..ac89a5deaca2 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -238,15 +238,47 @@ static struct page *read_sb_page(mddev_t *mddev, long offset, unsigned long inde } +static mdk_rdev_t *next_active_rdev(mdk_rdev_t *rdev, mddev_t *mddev) +{ + /* Iterate the disks of an mddev, using rcu to protect access to the + * linked list, and raising the refcount of devices we return to ensure + * they don't disappear while in use. + * As devices are only added or removed when raid_disk is < 0 and + * nr_pending is 0 and In_sync is clear, the entries we return will + * still be in the same position on the list when we re-enter + * list_for_each_continue_rcu. + */ + struct list_head *pos; + rcu_read_lock(); + if (rdev == NULL) + /* start at the beginning */ + pos = &mddev->disks; + else { + /* release the previous rdev and start from there. */ + rdev_dec_pending(rdev, mddev); + pos = &rdev->same_set; + } + list_for_each_continue_rcu(pos, &mddev->disks) { + rdev = list_entry(pos, mdk_rdev_t, same_set); + if (rdev->raid_disk >= 0 && + test_bit(In_sync, &rdev->flags) && + !test_bit(Faulty, &rdev->flags)) { + /* this is a usable devices */ + atomic_inc(&rdev->nr_pending); + rcu_read_unlock(); + return rdev; + } + } + rcu_read_unlock(); + return NULL; +} + static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait) { - mdk_rdev_t *rdev; + mdk_rdev_t *rdev = NULL; mddev_t *mddev = bitmap->mddev; - rcu_read_lock(); - rdev_for_each_rcu(rdev, mddev) - if (test_bit(In_sync, &rdev->flags) - && !test_bit(Faulty, &rdev->flags)) { + while ((rdev = next_active_rdev(rdev, mddev)) != NULL) { int size = PAGE_SIZE; if (page->index == bitmap->file_pages-1) size = roundup(bitmap->last_page_size, @@ -281,8 +313,7 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait) + page->index * (PAGE_SIZE/512), size, page); - } - rcu_read_unlock(); + } if (wait) md_super_wait(mddev); diff --git a/drivers/md/md.c b/drivers/md/md.c index 8cfadc5bd2ba..4790c83d78d0 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3841,8 +3841,6 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open) del_timer_sync(&mddev->safemode_timer); - invalidate_partition(disk, 0); - switch(mode) { case 1: /* readonly */ err = -ENXIO; diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index e8bc7abf2409..99be9e5c85f7 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -1068,7 +1068,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int { v4l2_std_id *id = arg; int found = 0; - int i, err; + int i; DEB_EE(("VIDIOC_S_STD\n")); @@ -1116,7 +1116,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int case VIDIOC_OVERLAY: { int on = *(int *)arg; - int err = 0; DEB_D(("VIDIOC_OVERLAY on:%d\n",on)); if (on != 0) { @@ -1192,7 +1191,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int case VIDIOCGMBUF: { struct video_mbuf *mbuf = arg; - struct videobuf_queue *q; int i; /* fixme: number of capture buffers and sizes for v4l apps */ diff --git a/drivers/media/common/tuners/mt2131.c b/drivers/media/common/tuners/mt2131.c index e254bcfc2efb..e8d3c48f8605 100644 --- a/drivers/media/common/tuners/mt2131.c +++ b/drivers/media/common/tuners/mt2131.c @@ -1,7 +1,7 @@ /* * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" * - * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/common/tuners/mt2131.h b/drivers/media/common/tuners/mt2131.h index cd8376f6f7b4..6632de640df0 100644 --- a/drivers/media/common/tuners/mt2131.h +++ b/drivers/media/common/tuners/mt2131.h @@ -1,7 +1,7 @@ /* * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" * - * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/common/tuners/mt2131_priv.h b/drivers/media/common/tuners/mt2131_priv.h index e930759c2c00..4e05a67e88c1 100644 --- a/drivers/media/common/tuners/mt2131_priv.h +++ b/drivers/media/common/tuners/mt2131_priv.h @@ -1,7 +1,7 @@ /* * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" * - * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c index 0dc2bef9f6a3..227642b044ae 100644 --- a/drivers/media/common/tuners/mxl5005s.c +++ b/drivers/media/common/tuners/mxl5005s.c @@ -2,7 +2,7 @@ MaxLinear MXL5005S VSB/QAM/DVBT tuner driver Copyright (C) 2008 MaxLinear - Copyright (C) 2006 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2006 Steven Toth <stoth@linuxtv.org> Functions: mxl5005s_reset() mxl5005s_writereg() @@ -3837,7 +3837,7 @@ static u16 MXL_Hystersis_Test(struct dvb_frontend *fe, int Hystersis) /* ---------------------------------------------------------------- * Begin: Everything after here is new code to adapt the * proprietary Realtek driver into a Linux API tuner. - * Copyright (C) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> */ static int mxl5005s_reset(struct dvb_frontend *fe) { diff --git a/drivers/media/common/tuners/mxl5005s.h b/drivers/media/common/tuners/mxl5005s.h index 396db150bf0c..7ac6815b30aa 100644 --- a/drivers/media/common/tuners/mxl5005s.h +++ b/drivers/media/common/tuners/mxl5005s.h @@ -2,7 +2,7 @@ MaxLinear MXL5005S VSB/QAM/DVBT tuner driver Copyright (C) 2008 MaxLinear - Copyright (C) 2008 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c index 597e47f5d69c..aa773a658a2a 100644 --- a/drivers/media/common/tuners/tuner-simple.c +++ b/drivers/media/common/tuners/tuner-simple.c @@ -253,7 +253,7 @@ static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe, static int simple_config_lookup(struct dvb_frontend *fe, struct tuner_params *t_params, - int *frequency, u8 *config, u8 *cb) + unsigned *frequency, u8 *config, u8 *cb) { struct tuner_simple_priv *priv = fe->tuner_priv; int i; @@ -587,45 +587,45 @@ static int simple_set_tv_freq(struct dvb_frontend *fe, priv->last_div = div; if (t_params->has_tda9887) { struct v4l2_priv_tun_config tda9887_cfg; - int config = 0; + int tda_config = 0; int is_secam_l = (params->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) && !(params->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)); tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &config; + tda9887_cfg.priv = &tda_config; if (params->std == V4L2_STD_SECAM_LC) { if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc) - config |= TDA9887_PORT1_ACTIVE; + tda_config |= TDA9887_PORT1_ACTIVE; if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc) - config |= TDA9887_PORT2_ACTIVE; + tda_config |= TDA9887_PORT2_ACTIVE; } else { if (t_params->port1_active) - config |= TDA9887_PORT1_ACTIVE; + tda_config |= TDA9887_PORT1_ACTIVE; if (t_params->port2_active) - config |= TDA9887_PORT2_ACTIVE; + tda_config |= TDA9887_PORT2_ACTIVE; } if (t_params->intercarrier_mode) - config |= TDA9887_INTERCARRIER; + tda_config |= TDA9887_INTERCARRIER; if (is_secam_l) { if (i == 0 && t_params->default_top_secam_low) - config |= TDA9887_TOP(t_params->default_top_secam_low); + tda_config |= TDA9887_TOP(t_params->default_top_secam_low); else if (i == 1 && t_params->default_top_secam_mid) - config |= TDA9887_TOP(t_params->default_top_secam_mid); + tda_config |= TDA9887_TOP(t_params->default_top_secam_mid); else if (t_params->default_top_secam_high) - config |= TDA9887_TOP(t_params->default_top_secam_high); + tda_config |= TDA9887_TOP(t_params->default_top_secam_high); } else { if (i == 0 && t_params->default_top_low) - config |= TDA9887_TOP(t_params->default_top_low); + tda_config |= TDA9887_TOP(t_params->default_top_low); else if (i == 1 && t_params->default_top_mid) - config |= TDA9887_TOP(t_params->default_top_mid); + tda_config |= TDA9887_TOP(t_params->default_top_mid); else if (t_params->default_top_high) - config |= TDA9887_TOP(t_params->default_top_high); + tda_config |= TDA9887_TOP(t_params->default_top_high); } if (t_params->default_pll_gating_18) - config |= TDA9887_GATING_18; + tda_config |= TDA9887_GATING_18; i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, &tda9887_cfg); } @@ -813,7 +813,8 @@ static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, static struct tuner_params *t_params; u8 config, cb; u32 div; - int ret, frequency = params->frequency / 62500; + int ret; + unsigned frequency = params->frequency / 62500; t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL); ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb); diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c index 5f99de0ad612..dcddfa803a75 100644 --- a/drivers/media/common/tuners/xc5000.c +++ b/drivers/media/common/tuners/xc5000.c @@ -2,7 +2,7 @@ * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" * * Copyright (c) 2007 Xceive Corporation - * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/common/tuners/xc5000.h index c910715addc9..5389f740945a 100644 --- a/drivers/media/common/tuners/xc5000.h +++ b/drivers/media/common/tuners/xc5000.h @@ -1,7 +1,7 @@ /* * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" * - * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/common/tuners/xc5000_priv.h b/drivers/media/common/tuners/xc5000_priv.h index a72a9887fe7f..b2a0074c99c9 100644 --- a/drivers/media/common/tuners/xc5000_priv.h +++ b/drivers/media/common/tuners/xc5000_priv.h @@ -1,7 +1,7 @@ /* * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" * - * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index f9d087669d5d..4eed783f4bce 100644 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -137,7 +137,8 @@ static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, un flexcop_diseqc_send_byte(fe, 0xff); else { flexcop_set_tone(fe, SEC_TONE_ON); - udelay(12500); + mdelay(12); + udelay(500); flexcop_set_tone(fe, SEC_TONE_OFF); } msleep(20); diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c index 55973eaf3711..43a112ec6d44 100644 --- a/drivers/media/dvb/b2c2/flexcop-i2c.c +++ b/drivers/media/dvb/b2c2/flexcop-i2c.c @@ -221,12 +221,12 @@ int flexcop_i2c_init(struct flexcop_device *fc) fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM; fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER; - strncpy(fc->fc_i2c_adap[0].i2c_adap.name, - "B2C2 FlexCop I2C to demod", I2C_NAME_SIZE); - strncpy(fc->fc_i2c_adap[1].i2c_adap.name, - "B2C2 FlexCop I2C to eeprom", I2C_NAME_SIZE); - strncpy(fc->fc_i2c_adap[2].i2c_adap.name, - "B2C2 FlexCop I2C to tuner", I2C_NAME_SIZE); + strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod", + sizeof(fc->fc_i2c_adap[0].i2c_adap.name)); + strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom", + sizeof(fc->fc_i2c_adap[1].i2c_adap.name)); + strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner", + sizeof(fc->fc_i2c_adap[2].i2c_adap.name)); i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]); i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]); diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index a7637562e742..aa3db57d32d9 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -1244,7 +1244,7 @@ static int dst_command(struct dst_state *state, u8 *data, u8 len) goto error; } if (state->type_flags & DST_TYPE_HAS_FW_1) - udelay(3000); + mdelay(3); if (read_dst(state, &reply, GET_ACK)) { dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); if ((dst_error_recovery(state)) < 0) { @@ -1260,7 +1260,7 @@ static int dst_command(struct dst_state *state, u8 *data, u8 len) if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) goto error; if (state->type_flags & DST_TYPE_HAS_FW_1) - udelay(3000); + mdelay(3); else udelay(2000); if (!dst_wait_dst_ready(state, NO_DELAY)) diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 1cf9fcb6f514..069d847ba887 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -641,7 +641,6 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) struct timespec timeout = { 0 }; struct dmx_pes_filter_params *para = &filter->params.pes; dmx_output_t otype; - int ret; int ts_type; enum dmx_ts_pes ts_pes; struct dmx_ts_feed **tsfeed = &filter->feed.ts; diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 8e5dd7b1f034..98ee16773ff2 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -1032,7 +1032,7 @@ static int dvb_ca_en50221_thread(void *data) /* we need this extra check for annoying interfaces like the budget-av */ if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) && (ca->pub->poll_slot_status)) { - int status = ca->pub->poll_slot_status(ca->pub, slot, 0); + status = ca->pub->poll_slot_status(ca->pub, slot, 0); if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) { ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; dvb_ca_en50221_thread_update_delay(ca); @@ -1089,7 +1089,7 @@ static int dvb_ca_en50221_thread(void *data) /* we need this extra check for annoying interfaces like the budget-av */ if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) && (ca->pub->poll_slot_status)) { - int status = ca->pub->poll_slot_status(ca->pub, slot, 0); + status = ca->pub->poll_slot_status(ca->pub, slot, 0); if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) { ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; dvb_ca_en50221_thread_update_delay(ca); diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 8cbdb218952f..3526e3ee9487 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -889,13 +889,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, * initialization, so parg is 8 bits and does not * include the initialization or start bit */ - unsigned long cmd = ((unsigned long) parg) << 1; + unsigned long swcmd = ((unsigned long) parg) << 1; struct timeval nexttime; struct timeval tv[10]; int i; u8 last = 1; if (dvb_frontend_debug) - printk("%s switch command: 0x%04lx\n", __func__, cmd); + printk("%s switch command: 0x%04lx\n", __func__, swcmd); do_gettimeofday(&nexttime); if (dvb_frontend_debug) memcpy(&tv[0], &nexttime, sizeof(struct timeval)); @@ -908,12 +908,12 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, for (i = 0; i < 9; i++) { if (dvb_frontend_debug) do_gettimeofday(&tv[i + 1]); - if ((cmd & 0x01) != last) { + if ((swcmd & 0x01) != last) { /* set voltage to (last ? 13V : 18V) */ fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18); last = (last) ? 0 : 1; } - cmd = cmd >> 1; + swcmd = swcmd >> 1; if (i != 8) dvb_frontend_sleep_until(&nexttime, 8000); } diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index aaa0b6f0b521..563400277a42 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -210,7 +210,7 @@ static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff) if (d->state == DVB_USB_STATE_INIT && usb_set_interface(d->udev, 0, 0) < 0) err("set interface failed"); - do; while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) && + do {} while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) && !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) && !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0); if (!ret) { diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 3dd20bfbed32..6c0e5c5f4362 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1117,7 +1117,8 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_HT_EXPRESS) }, { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS) }, { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) }, +/* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1373,7 +1374,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { } }, - .num_device_descs = 3, + .num_device_descs = 4, .devices = { { "DiBcom STK7070PD reference design", { &dib0700_usb_id_table[17], NULL }, @@ -1386,6 +1387,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "Hauppauge Nova-TD Stick (52009)", { &dib0700_usb_id_table[35], NULL }, { NULL }, + }, + { "Hauppauge Nova-TD-500 (84xxx)", + { &dib0700_usb_id_table[36], NULL }, + { NULL }, } } }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 029b437caf9a..03dfb9f2fe30 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -129,6 +129,7 @@ #define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301 #define USB_PID_HAUPPAUGE_NOVA_T_500 0x9941 #define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950 +#define USB_PID_HAUPPAUGE_NOVA_T_500_3 0x8400 #define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_3 0x7070 diff --git a/drivers/media/dvb/frontends/au8522.c b/drivers/media/dvb/frontends/au8522.c index f7b71657f0f6..0b82cc2a1e16 100644 --- a/drivers/media/dvb/frontends/au8522.c +++ b/drivers/media/dvb/frontends/au8522.c @@ -1,7 +1,7 @@ /* Auvitek AU8522 QAM/8VSB demodulator driver - Copyright (C) 2008 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -304,6 +304,43 @@ static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse, return ret; } +static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq) +{ + struct au8522_state *state = fe->demodulator_priv; + u8 r0b5, r0b6, r0b7; + char *ifmhz; + + switch (if_freq) { + case AU8522_IF_3_25MHZ: + ifmhz = "3.25"; + r0b5 = 0x00; + r0b6 = 0x3d; + r0b7 = 0xa0; + break; + case AU8522_IF_4MHZ: + ifmhz = "4.00"; + r0b5 = 0x00; + r0b6 = 0x4b; + r0b7 = 0xd9; + break; + case AU8522_IF_6MHZ: + ifmhz = "6.00"; + r0b5 = 0xfb; + r0b6 = 0x8e; + r0b7 = 0x39; + break; + default: + dprintk("%s() IF Frequency not supported\n", __func__); + return -EINVAL; + } + dprintk("%s() %s MHz\n", __func__, ifmhz); + au8522_writereg(state, 0x80b5, r0b5); + au8522_writereg(state, 0x80b6, r0b6); + au8522_writereg(state, 0x80b7, r0b7); + + return 0; +} + /* VSB Modulation table */ static struct { u16 reg; @@ -334,9 +371,6 @@ static struct { { 0x80af, 0x66 }, { 0x821b, 0xcc }, { 0x821d, 0x80 }, - { 0x80b5, 0xfb }, - { 0x80b6, 0x8e }, - { 0x80b7, 0x39 }, { 0x80a4, 0xe8 }, { 0x8231, 0x13 }, }; @@ -350,9 +384,6 @@ static struct { { 0x80a4, 0x00 }, { 0x8081, 0xc4 }, { 0x80a5, 0x40 }, - { 0x80b5, 0xfb }, - { 0x80b6, 0x8e }, - { 0x80b7, 0x39 }, { 0x80aa, 0x77 }, { 0x80ad, 0x77 }, { 0x80a6, 0x67 }, @@ -438,6 +469,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe, au8522_writereg(state, VSB_mod_tab[i].reg, VSB_mod_tab[i].data); + au8522_set_if(fe, state->config->vsb_if); break; case QAM_64: case QAM_256: @@ -446,6 +478,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe, au8522_writereg(state, QAM_mod_tab[i].reg, QAM_mod_tab[i].data); + au8522_set_if(fe, state->config->qam_if); break; default: dprintk("%s() Invalid modulation\n", __func__); diff --git a/drivers/media/dvb/frontends/au8522.h b/drivers/media/dvb/frontends/au8522.h index d7affa3cdb27..595915ade8c3 100644 --- a/drivers/media/dvb/frontends/au8522.h +++ b/drivers/media/dvb/frontends/au8522.h @@ -1,7 +1,7 @@ /* Auvitek AU8522 QAM/8VSB demodulator driver - Copyright (C) 2008 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,6 +24,12 @@ #include <linux/dvb/frontend.h> +enum au8522_if_freq { + AU8522_IF_6MHZ = 0, + AU8522_IF_4MHZ, + AU8522_IF_3_25MHZ, +}; + struct au8522_config { /* the demodulator's i2c address */ u8 demod_address; @@ -32,6 +38,9 @@ struct au8522_config { #define AU8522_TUNERLOCKING 0 #define AU8522_DEMODLOCKING 1 u8 status_mode; + + enum au8522_if_freq vsb_if; + enum au8522_if_freq qam_if; }; #if defined(CONFIG_DVB_AU8522) || \ diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c index cc1db4e371c3..9430e03dba6c 100644 --- a/drivers/media/dvb/frontends/cx22702.c +++ b/drivers/media/dvb/frontends/cx22702.c @@ -7,7 +7,7 @@ Copyright (C) 2001-2002 Convergence Integrated Media GmbH Holger Waechtler <holger@convergence.de> - Copyright (C) 2004 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2004 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h index 8af766a31552..b1e465c6c2ce 100644 --- a/drivers/media/dvb/frontends/cx22702.h +++ b/drivers/media/dvb/frontends/cx22702.h @@ -7,7 +7,7 @@ Copyright (C) 2001-2002 Convergence Integrated Media GmbH Holger Waechtler <holger@convergence.de> - Copyright (C) 2004 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2004 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c index 7f68d78c6558..7156157cb34b 100644 --- a/drivers/media/dvb/frontends/cx24123.c +++ b/drivers/media/dvb/frontends/cx24123.c @@ -1,7 +1,7 @@ /* * Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver * - * Copyright (C) 2005 Steven Toth <stoth@hauppauge.com> + * Copyright (C) 2005 Steven Toth <stoth@linuxtv.org> * * Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc> * @@ -1072,8 +1072,8 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config, if (config->dont_use_pll) cx24123_repeater_mode(state, 1, 0); - strncpy(state->tuner_i2c_adapter.name, - "CX24123 tuner I2C bus", I2C_NAME_SIZE); + strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus", + sizeof(state->tuner_i2c_adapter.name)); state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL, state->tuner_i2c_adapter.algo = &cx24123_tuner_i2c_algo; state->tuner_i2c_adapter.algo_data = NULL; diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h index 81ebc3d2f19f..cc6b411d6d20 100644 --- a/drivers/media/dvb/frontends/cx24123.h +++ b/drivers/media/dvb/frontends/cx24123.h @@ -1,7 +1,7 @@ /* Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver - Copyright (C) 2005 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2005 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index 5ddb2dca305c..7500a1c53e68 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -1,7 +1,7 @@ /* Samsung S5H1409 VSB/QAM demodulator driver - Copyright (C) 2006 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2006 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -404,6 +404,7 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe, break; case QAM_64: case QAM_256: + case QAM_AUTO: dprintk("%s() QAM_AUTO (64/256)\n", __func__); if (state->if_freq != S5H1409_QAM_IF_FREQ) s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ); diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h index 59f4335964c6..d1a1d2eb8e11 100644 --- a/drivers/media/dvb/frontends/s5h1409.h +++ b/drivers/media/dvb/frontends/s5h1409.h @@ -1,7 +1,7 @@ /* Samsung S5H1409 VSB/QAM demodulator driver - Copyright (C) 2006 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2006 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/drivers/media/dvb/frontends/s5h1411.c b/drivers/media/dvb/frontends/s5h1411.c index cff360ce1ba3..2da1a3763de9 100644 --- a/drivers/media/dvb/frontends/s5h1411.c +++ b/drivers/media/dvb/frontends/s5h1411.c @@ -1,7 +1,7 @@ /* Samsung S5H1411 VSB/QAM demodulator driver - Copyright (C) 2008 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -488,6 +488,7 @@ static int s5h1411_enable_modulation(struct dvb_frontend *fe, break; case QAM_64: case QAM_256: + case QAM_AUTO: dprintk("%s() QAM_AUTO (64/256)\n", __func__); s5h1411_set_if_freq(fe, state->config->qam_if); s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x0171); diff --git a/drivers/media/dvb/frontends/s5h1411.h b/drivers/media/dvb/frontends/s5h1411.h index 1855f64ed4d8..7d542bc00c48 100644 --- a/drivers/media/dvb/frontends/s5h1411.h +++ b/drivers/media/dvb/frontends/s5h1411.h @@ -1,7 +1,7 @@ /* Samsung S5H1411 VSB/QAM demodulator driver - Copyright (C) 2008 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c index 720ed9ff7c5f..747d3fa2e5e5 100644 --- a/drivers/media/dvb/frontends/s5h1420.c +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -915,7 +915,8 @@ struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config, state->frontend.demodulator_priv = state; /* create tuner i2c adapter */ - strncpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus", I2C_NAME_SIZE); + strlcpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus", + sizeof(state->tuner_i2c_adapter.name)); state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL, state->tuner_i2c_adapter.algo = &s5h1420_tuner_i2c_algo; state->tuner_i2c_adapter.algo_data = NULL; diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb/frontends/tda10048.c index 0ab8d86b3ae3..04e7f1cc1403 100644 --- a/drivers/media/dvb/frontends/tda10048.c +++ b/drivers/media/dvb/frontends/tda10048.c @@ -1,7 +1,7 @@ /* NXP TDA10048HN DVB OFDM demodulator driver - Copyright (C) 2008 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -303,7 +303,7 @@ static int tda10048_firmware_upload(struct dvb_frontend *fe) if (fw->size != TDA10048_DEFAULT_FIRMWARE_SIZE) { printk(KERN_ERR "%s: firmware incorrect size\n", __func__); - return -EIO; + ret = -EIO; } else { printk(KERN_INFO "%s: firmware uploading\n", __func__); diff --git a/drivers/media/dvb/frontends/tda10048.h b/drivers/media/dvb/frontends/tda10048.h index 2b5c78e62c86..0457b24601fa 100644 --- a/drivers/media/dvb/frontends/tda10048.h +++ b/drivers/media/dvb/frontends/tda10048.h @@ -1,7 +1,7 @@ /* NXP TDA10048HN DVB OFDM demodulator driver - Copyright (C) 2008 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c index e7a8ac0c4049..cc5efb643f33 100644 --- a/drivers/media/dvb/siano/sms-cards.c +++ b/drivers/media/dvb/siano/sms-cards.c @@ -4,7 +4,7 @@ * Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org> * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as + * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * Software distributed under the License is distributed on an "AS IS" diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/dvb/siano/sms-cards.h index 83b39bc203fe..c8f3da6f9bc1 100644 --- a/drivers/media/dvb/siano/sms-cards.h +++ b/drivers/media/dvb/siano/sms-cards.h @@ -4,7 +4,7 @@ * Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org> * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as + * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * Software distributed under the License is distributed on an "AS IS" diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c index c5f45fed69dc..6576fbb40fc6 100644 --- a/drivers/media/dvb/siano/smscoreapi.c +++ b/drivers/media/dvb/siano/smscoreapi.c @@ -8,7 +8,7 @@ * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc. * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as + * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * Software distributed under the License is distributed on an "AS IS" diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h index c1f8f1dccb11..8d973f726fb8 100644 --- a/drivers/media/dvb/siano/smscoreapi.h +++ b/drivers/media/dvb/siano/smscoreapi.h @@ -6,7 +6,7 @@ * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc. * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as + * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * Software distributed under the License is distributed on an "AS IS" diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c index 229274a14110..8d490e133f35 100644 --- a/drivers/media/dvb/siano/smsdvb.c +++ b/drivers/media/dvb/siano/smsdvb.c @@ -6,7 +6,7 @@ * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc. * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as + * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * Software distributed under the License is distributed on an "AS IS" diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c index c10b1849c6a3..87a3c24454b9 100644 --- a/drivers/media/dvb/siano/smsusb.c +++ b/drivers/media/dvb/siano/smsusb.c @@ -6,7 +6,7 @@ * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc. * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as + * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * Software distributed under the License is distributed on an "AS IS" diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c index 39bd0a20f53a..aa5ed4ef19f2 100644 --- a/drivers/media/dvb/ttpci/budget-patch.c +++ b/drivers/media/dvb/ttpci/budget-patch.c @@ -116,7 +116,8 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long DiseqcSendByte(budget, 0xff); else { saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); - udelay(12500); + mdelay(12); + udelay(500); saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); } msleep(20); diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index 2293d80c6e51..f0068996ac07 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -108,7 +108,8 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long DiseqcSendByte(budget, 0xff); else { saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); - udelay(12500); + mdelay(12); + udelay(500); saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); } msleep(20); diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index a30159f6fa42..7ca71ab96b43 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -2,8 +2,6 @@ # Makefile for the kernel character device drivers. # -miropcm20-objs := miropcm20-rds-core.o miropcm20-radio.o - obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o @@ -14,8 +12,6 @@ obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o -obj-$(CONFIG_RADIO_MIROPCM20) += miropcm20.o -obj-$(CONFIG_RADIO_MIROPCM20_RDS) += miropcm20-rds.o obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index 1ed88f3abe61..70c65a745923 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -493,7 +493,7 @@ static int usb_dsbr100_probe(struct usb_interface *intf, radio->usbdev = interface_to_usbdev(intf); radio->curfreq = FREQ_MIN*FREQ_MUL; video_set_drvdata(radio->videodev, radio); - if (video_register_device(radio->videodev, VFL_TYPE_RADIO,radio_nr)) { + if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr) < 0) { warn("Could not register video device"); video_device_release(radio->videodev); kfree(radio->transfer_buffer); diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c deleted file mode 100644 index 7fd7ee2d32c1..000000000000 --- a/drivers/media/radio/miropcm20-radio.c +++ /dev/null @@ -1,266 +0,0 @@ -/* Miro PCM20 radio driver for Linux radio support - * (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl> - * Thanks to Norberto Pellici for the ACI device interface specification - * The API part is based on the radiotrack driver by M. Kirkwood - * This driver relies on the aci mixer (drivers/sound/aci.c) - * Look there for further info... - */ - -/* Revision history: - * - * 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl> - * 2000-09-05 Robert Siemer <Robert.Siemer@gmx.de> - * removed unfinished volume control (maybe adding it later again) - * use OSS-mixer; added stereo control - */ - -/* What ever you think about the ACI, version 0x07 is not very well! - * I can't get frequency, 'tuner status', 'tuner flags' or mute/mono - * conditions... Robert - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/videodev.h> -#include <media/v4l2-common.h> -#include <media/v4l2-ioctl.h> -#include "oss/aci.h" -#include "miropcm20-rds-core.h" - -static int radio_nr = -1; -module_param(radio_nr, int, 0); - -struct pcm20_device { - unsigned long freq; - int muted; - int stereo; -}; - - -static int pcm20_mute(struct pcm20_device *dev, unsigned char mute) -{ - dev->muted = mute; - return aci_write_cmd(ACI_SET_TUNERMUTE, mute); -} - -static int pcm20_stereo(struct pcm20_device *dev, unsigned char stereo) -{ - dev->stereo = stereo; - return aci_write_cmd(ACI_SET_TUNERMONO, !stereo); -} - -static int pcm20_setfreq(struct pcm20_device *dev, unsigned long freq) -{ - unsigned char freql; - unsigned char freqh; - - dev->freq=freq; - - freq /= 160; - if (!(aci_version==0x07 || aci_version>=0xb0)) - freq /= 10; /* I don't know exactly which version - * needs this hack */ - freql = freq & 0xff; - freqh = freq >> 8; - - aci_rds_cmd(RDS_RESET, NULL, 0); - pcm20_stereo(dev, 1); - - return aci_rw_cmd(ACI_WRITE_TUNE, freql, freqh); -} - -static int pcm20_getflags(struct pcm20_device *dev, __u32 *flags, __u16 *signal) -{ - /* okay, check for signal, stereo and rds here... */ - int i; - unsigned char buf; - - if ((i=aci_rw_cmd(ACI_READ_TUNERSTATION, -1, -1))<0) - return i; - pr_debug("check_sig: 0x%x\n", i); - if (i & 0x80) { - /* no signal from tuner */ - *flags=0; - *signal=0; - return 0; - } else - *signal=0xffff; - - if ((i=aci_rw_cmd(ACI_READ_TUNERSTEREO, -1, -1))<0) - return i; - if (i & 0x40) { - *flags=0; - } else { - /* stereo */ - *flags=VIDEO_TUNER_STEREO_ON; - /* I can't see stereo, when forced to mono */ - dev->stereo=1; - } - - if ((i=aci_rds_cmd(RDS_STATUS, &buf, 1))<0) - return i; - if (buf & 1) - /* RDS available */ - *flags|=VIDEO_TUNER_RDS_ON; - else - return 0; - - if ((i=aci_rds_cmd(RDS_RXVALUE, &buf, 1))<0) - return i; - pr_debug("rds-signal: %d\n", buf); - if (buf > 15) { - printk("miropcm20-radio: RX strengths unexpected high...\n"); - buf=15; - } - /* refine signal */ - if ((*signal=SCALE(15, 0xffff, buf))==0) - *signal = 1; - - return 0; -} - -static int pcm20_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) -{ - struct video_device *dev = video_devdata(file); - struct pcm20_device *pcm20 = dev->priv; - int i; - - switch(cmd) - { - case VIDIOCGCAP: - { - struct video_capability *v = arg; - memset(v,0,sizeof(*v)); - v->type=VID_TYPE_TUNER; - strcpy(v->name, "Miro PCM20"); - v->channels=1; - v->audios=1; - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner *v = arg; - if(v->tuner) /* Only 1 tuner */ - return -EINVAL; - v->rangelow=87*16000; - v->rangehigh=108*16000; - pcm20_getflags(pcm20, &v->flags, &v->signal); - v->flags|=VIDEO_TUNER_LOW; - v->mode=VIDEO_MODE_AUTO; - strcpy(v->name, "FM"); - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner *v = arg; - if(v->tuner!=0) - return -EINVAL; - /* Only 1 tuner so no setting needed ! */ - return 0; - } - case VIDIOCGFREQ: - { - unsigned long *freq = arg; - *freq = pcm20->freq; - return 0; - } - case VIDIOCSFREQ: - { - unsigned long *freq = arg; - pcm20->freq = *freq; - i=pcm20_setfreq(pcm20, pcm20->freq); - pr_debug("First view (setfreq): 0x%x\n", i); - return i; - } - case VIDIOCGAUDIO: - { - struct video_audio *v = arg; - memset(v,0, sizeof(*v)); - v->flags=VIDEO_AUDIO_MUTABLE; - if (pcm20->muted) - v->flags|=VIDEO_AUDIO_MUTE; - v->mode=VIDEO_SOUND_STEREO; - if (pcm20->stereo) - v->mode|=VIDEO_SOUND_MONO; - /* v->step=2048; */ - strcpy(v->name, "Radio"); - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio *v = arg; - if(v->audio) - return -EINVAL; - - pcm20_mute(pcm20, !!(v->flags&VIDEO_AUDIO_MUTE)); - if(v->flags&VIDEO_SOUND_MONO) - pcm20_stereo(pcm20, 0); - if(v->flags&VIDEO_SOUND_STEREO) - pcm20_stereo(pcm20, 1); - - return 0; - } - default: - return -ENOIOCTLCMD; - } -} - -static int pcm20_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(inode, file, cmd, arg, pcm20_do_ioctl); -} - -static struct pcm20_device pcm20_unit = { - .freq = 87*16000, - .muted = 1, -}; - -static const struct file_operations pcm20_fops = { - .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, - .ioctl = pcm20_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = v4l_compat_ioctl32, -#endif - .llseek = no_llseek, -}; - -static struct video_device pcm20_radio = { - .name = "Miro PCM 20 radio", - .fops = &pcm20_fops, - .priv = &pcm20_unit -}; - -static int __init pcm20_init(void) -{ - if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO, radio_nr)==-1) - goto video_register_device; - - if(attach_aci_rds()<0) - goto attach_aci_rds; - - printk(KERN_INFO "Miro PCM20 radio card driver.\n"); - - return 0; - - attach_aci_rds: - video_unregister_device(&pcm20_radio); - video_register_device: - return -EINVAL; -} - -MODULE_AUTHOR("Ruurd Reitsma"); -MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card."); -MODULE_LICENSE("GPL"); - -static void __exit pcm20_cleanup(void) -{ - unload_aci_rds(); - video_unregister_device(&pcm20_radio); -} - -module_init(pcm20_init); -module_exit(pcm20_cleanup); diff --git a/drivers/media/radio/miropcm20-rds-core.c b/drivers/media/radio/miropcm20-rds-core.c deleted file mode 100644 index 9428d8b2642c..000000000000 --- a/drivers/media/radio/miropcm20-rds-core.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Many thanks to Fred Seidel <seidel@metabox.de>, the - * designer of the RDS decoder hardware. With his help - * I was able to code this driver. - * Thanks also to Norberto Pellicci, Dominic Mounteney - * <DMounteney@pinnaclesys.com> and www.teleauskunft.de - * for good hints on finding Fred. It was somewhat hard - * to locate him here in Germany... [: - * - * Revision history: - * - * 2000-08-09 Robert Siemer <Robert.Siemer@gmx.de> - * RDS support for MiroSound PCM20 radio - */ - -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/mutex.h> - -#include <asm/io.h> -#include "oss/aci.h" -#include "miropcm20-rds-core.h" - -#define DEBUG 0 - -static struct mutex aci_rds_mutex; - -#define RDS_DATASHIFT 2 /* Bit 2 */ -#define RDS_DATAMASK (1 << RDS_DATASHIFT) -#define RDS_BUSYMASK 0x10 /* Bit 4 */ -#define RDS_CLOCKMASK 0x08 /* Bit 3 */ - -#define RDS_DATA(x) (((x) >> RDS_DATASHIFT) & 1) - - -#if DEBUG -static void print_matrix(char array[], unsigned int length) -{ - int i, j; - - for (i=0; i<length; i++) { - printk(KERN_DEBUG "aci-rds: "); - for (j=7; j>=0; j--) { - printk("%d", (array[i] >> j) & 0x1); - } - if (i%8 == 0) - printk(" byte-border\n"); - else - printk("\n"); - } -} -#endif /* DEBUG */ - -static int byte2trans(unsigned char byte, unsigned char sendbuffer[], int size) -{ - int i; - - if (size != 8) - return -1; - for (i = 7; i >= 0; i--) - sendbuffer[7-i] = (byte & (1 << i)) ? RDS_DATAMASK : 0; - sendbuffer[0] |= RDS_CLOCKMASK; - - return 0; -} - -static int rds_waitread(void) -{ - unsigned char byte; - int i=2000; - - do { - byte=inb(RDS_REGISTER); - i--; - } - while ((byte & RDS_BUSYMASK) && i); - - if (i) { - #if DEBUG - printk(KERN_DEBUG "rds_waitread()"); - print_matrix(&byte, 1); - #endif - return (byte); - } else { - printk(KERN_WARNING "aci-rds: rds_waitread() timeout...\n"); - return -1; - } -} - -/* don't use any ..._nowait() function if you are not sure what you do... */ - -static inline void rds_rawwrite_nowait(unsigned char byte) -{ - #if DEBUG - printk(KERN_DEBUG "rds_rawwrite()"); - print_matrix(&byte, 1); - #endif - outb(byte, RDS_REGISTER); -} - -static int rds_rawwrite(unsigned char byte) -{ - if (rds_waitread() >= 0) { - rds_rawwrite_nowait(byte); - return 0; - } else - return -1; -} - -static int rds_write(unsigned char cmd) -{ - unsigned char sendbuffer[8]; - int i; - - if (byte2trans(cmd, sendbuffer, 8) != 0){ - return -1; - } else { - for (i=0; i<8; i++) { - rds_rawwrite(sendbuffer[i]); - } - } - return 0; -} - -static int rds_readcycle_nowait(void) -{ - rds_rawwrite_nowait(0); - return rds_waitread(); -} - -static int rds_readcycle(void) -{ - if (rds_rawwrite(0) < 0) - return -1; - return rds_waitread(); -} - -static int rds_read(unsigned char databuffer[], int datasize) -{ - #define READSIZE (8*datasize) - - int i,j; - - if (datasize < 1) /* nothing to read */ - return 0; - - /* to be able to use rds_readcycle_nowait() - I have to waitread() here */ - if (rds_waitread() < 0) - return -1; - - memset(databuffer, 0, datasize); - - for (i=0; i< READSIZE; i++) - if((j=rds_readcycle_nowait()) < 0) { - return -1; - } else { - databuffer[i/8]|=(RDS_DATA(j) << (7-(i%8))); - } - - return 0; -} - -static int rds_ack(void) -{ - int i=rds_readcycle(); - - if (i < 0) - return -1; - if (i & RDS_DATAMASK) { - return 0; /* ACK */ - } else { - printk(KERN_DEBUG "aci-rds: NACK\n"); - return 1; /* NACK */ - } -} - -int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize) -{ - int ret; - - if (mutex_lock_interruptible(&aci_rds_mutex)) - return -EINTR; - - rds_write(cmd); - - /* RDS_RESET doesn't need further processing */ - if (cmd!=RDS_RESET && (rds_ack() || rds_read(databuffer, datasize))) - ret = -1; - else - ret = 0; - - mutex_unlock(&aci_rds_mutex); - - return ret; -} -EXPORT_SYMBOL(aci_rds_cmd); - -int __init attach_aci_rds(void) -{ - mutex_init(&aci_rds_mutex); - return 0; -} - -void __exit unload_aci_rds(void) -{ -} -MODULE_LICENSE("GPL"); diff --git a/drivers/media/radio/miropcm20-rds-core.h b/drivers/media/radio/miropcm20-rds-core.h deleted file mode 100644 index aeb5761f0469..000000000000 --- a/drivers/media/radio/miropcm20-rds-core.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _MIROPCM20_RDS_CORE_H_ -#define _MIROPCM20_RDS_CORE_H_ - -extern int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize); - -#define RDS_STATUS 0x01 -#define RDS_STATIONNAME 0x02 -#define RDS_TEXT 0x03 -#define RDS_ALTFREQ 0x04 -#define RDS_TIMEDATE 0x05 -#define RDS_PI_CODE 0x06 -#define RDS_PTYTATP 0x07 -#define RDS_RESET 0x08 -#define RDS_RXVALUE 0x09 - -extern void __exit unload_aci_rds(void); -extern int __init attach_aci_rds(void); - -#endif /* _MIROPCM20_RDS_CORE_H_ */ diff --git a/drivers/media/radio/miropcm20-rds.c b/drivers/media/radio/miropcm20-rds.c deleted file mode 100644 index 3e840f74d45c..000000000000 --- a/drivers/media/radio/miropcm20-rds.c +++ /dev/null @@ -1,136 +0,0 @@ -/* MiroSOUND PCM20 radio rds interface driver - * (c) 2001 Robert Siemer <Robert.Siemer@gmx.de> - * Thanks to Fred Seidel. See miropcm20-rds-core.c for further information. - */ - -/* Revision history: - * - * 2001-04-18 Robert Siemer <Robert.Siemer@gmx.de> - * separate file for user interface driver - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/smp_lock.h> -#include <linux/fs.h> -#include <linux/miscdevice.h> -#include <linux/delay.h> -#include <asm/uaccess.h> -#include "miropcm20-rds-core.h" - -static char * text_buffer; -static int rds_users; - - -static int rds_f_open(struct inode *in, struct file *fi) -{ - if (rds_users) - return -EBUSY; - - lock_kernel(); - rds_users++; - if ((text_buffer=kmalloc(66, GFP_KERNEL)) == 0) { - rds_users--; - printk(KERN_NOTICE "aci-rds: Out of memory by open()...\n"); - unlock_kernel(); - return -ENOMEM; - } - - unlock_kernel(); - return 0; -} - -static int rds_f_release(struct inode *in, struct file *fi) -{ - kfree(text_buffer); - - rds_users--; - return 0; -} - -static void print_matrix(char *ch, char out[]) -{ - int j; - - for (j=7; j>=0; j--) { - out[7-j] = ((*ch >> j) & 0x1) + '0'; - } -} - -static ssize_t rds_f_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) -{ -// i = sprintf(text_buffer, "length: %d, offset: %d\n", length, *offset); - - char c; - char bits[8]; - - msleep(2000); - aci_rds_cmd(RDS_STATUS, &c, 1); - print_matrix(&c, bits); - if (copy_to_user(buffer, bits, 8)) - return -EFAULT; - -/* if ((c >> 3) & 1) { - aci_rds_cmd(RDS_STATIONNAME, text_buffer+1, 8); - text_buffer[0] = ' ' ; - text_buffer[9] = '\n'; - return copy_to_user(buffer+8, text_buffer, 10) ? -EFAULT: 18; - } -*/ -/* if ((c >> 6) & 1) { - aci_rds_cmd(RDS_PTYTATP, &c, 1); - if ( c & 1) - sprintf(text_buffer, " M"); - else - sprintf(text_buffer, " S"); - if ((c >> 1) & 1) - sprintf(text_buffer+2, " TA"); - else - sprintf(text_buffer+2, " --"); - if ((c >> 7) & 1) - sprintf(text_buffer+5, " TP"); - else - sprintf(text_buffer+5, " --"); - sprintf(text_buffer+8, " %2d\n", (c >> 2) & 0x1f); - return copy_to_user(buffer+8, text_buffer, 12) ? -EFAULT: 20; - } -*/ - - if ((c >> 4) & 1) { - aci_rds_cmd(RDS_TEXT, text_buffer, 65); - text_buffer[0] = ' ' ; - text_buffer[65] = '\n'; - return copy_to_user(buffer+8, text_buffer,66) ? -EFAULT : 66+8; - } else { - put_user('\n', buffer+8); - return 9; - } -} - -static const struct file_operations rds_fops = { - .owner = THIS_MODULE, - .read = rds_f_read, - .open = rds_f_open, - .release = rds_f_release -}; - -static struct miscdevice rds_miscdev = { - .minor = MISC_DYNAMIC_MINOR, - .name = "radiotext", - .fops = &rds_fops, -}; - -static int __init miropcm20_rds_init(void) -{ - return misc_register(&rds_miscdev); -} - -static void __exit miropcm20_rds_cleanup(void) -{ - misc_deregister(&rds_miscdev); -} - -module_init(miropcm20_rds_init); -module_exit(miropcm20_rds_cleanup); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index eba9209b3024..1f064f4b32df 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -426,8 +426,7 @@ static int __init rtrack_init(void) rtrack_radio.priv=&rtrack_unit; - if(video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr)==-1) - { + if (video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io, 2); return -EINVAL; } diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c index 3fe5504428c5..628c689e3ffe 100644 --- a/drivers/media/radio/radio-aztech.c +++ b/drivers/media/radio/radio-aztech.c @@ -394,8 +394,7 @@ static int __init aztech_init(void) mutex_init(&lock); aztech_radio.priv=&aztech_unit; - if(video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr)==-1) - { + if (video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io,2); return -EINVAL; } diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 6166e726ed72..04c3698d32e4 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -682,7 +682,7 @@ static int __init cadet_init(void) } if (!request_region(io,2,"cadet")) goto fail; - if(video_register_device(&cadet_radio,VFL_TYPE_RADIO,radio_nr)==-1) { + if (video_register_device(&cadet_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io,2); goto fail; } diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c index 36e754e3ffb2..5cd7f032298d 100644 --- a/drivers/media/radio/radio-gemtek-pci.c +++ b/drivers/media/radio/radio-gemtek-pci.c @@ -425,7 +425,7 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci } *devradio = vdev_template; - if ( video_register_device( devradio, VFL_TYPE_RADIO , nr_radio) == -1 ) { + if (video_register_device(devradio, VFL_TYPE_RADIO, nr_radio) < 0) { kfree( devradio ); goto err_video; } diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 2b1a6221de6d..0a0f956bb308 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -612,8 +612,7 @@ static int __init gemtek_init(void) gemtek_radio.priv = &gemtek_unit; - if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO, - radio_nr) == -1) { + if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io, 1); return -EBUSY; } diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c index 0ada1c697e8a..9ef0a763eeb7 100644 --- a/drivers/media/radio/radio-maestro.c +++ b/drivers/media/radio/radio-maestro.c @@ -409,8 +409,7 @@ static int __devinit maestro_probe(struct pci_dev *pdev, video_set_drvdata(maestro_radio_inst, radio_unit); pci_set_drvdata(pdev, maestro_radio_inst); - retval = video_register_device(maestro_radio_inst, VFL_TYPE_RADIO, - radio_nr); + retval = video_register_device(maestro_radio_inst, VFL_TYPE_RADIO, radio_nr); if (retval) { printk(KERN_ERR "can't register video device!\n"); goto errfr1; diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index 43c75497dc49..0cc6fcb041fd 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -156,28 +156,28 @@ static void set_freq(__u16 io, __u32 freq) { unsigned long int si; int bl; - int data = FREQ2BITS(freq); + int val = FREQ2BITS(freq); /* TEA5757 shift register bits (see pdf) */ - outbit(0,io); // 24 search - outbit(1,io); // 23 search up/down + outbit(0, io); /* 24 search */ + outbit(1, io); /* 23 search up/down */ - outbit(0,io); // 22 stereo/mono + outbit(0, io); /* 22 stereo/mono */ - outbit(0,io); // 21 band - outbit(0,io); // 20 band (only 00=FM works I think) + outbit(0, io); /* 21 band */ + outbit(0, io); /* 20 band (only 00=FM works I think) */ - outbit(0,io); // 19 port ? - outbit(0,io); // 18 port ? + outbit(0, io); /* 19 port ? */ + outbit(0, io); /* 18 port ? */ - outbit(0,io); // 17 search level - outbit(0,io); // 16 search level + outbit(0, io); /* 17 search level */ + outbit(0, io); /* 16 search level */ si = 0x8000; - for (bl = 1; bl <= 16 ; bl++) { - outbit(data & si,io); - si >>=1; + for (bl = 1; bl <= 16; bl++) { + outbit(val & si, io); + si >>= 1; } dprintk(1, "Radio freq set to %d.%02d MHz\n", @@ -410,7 +410,7 @@ static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_d mutex_init(&radio_unit.lock); maxiradio_radio.priv = &radio_unit; - if (video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) { + if (video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr) < 0) { printk("radio-maxiradio: can't register device!"); goto err_out_free_region; } diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index e2dde0807268..6d820e2481e7 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c @@ -332,8 +332,7 @@ static int __init rtrack2_init(void) rtrack2_radio.priv=&rtrack2_unit; spin_lock_init(&lock); - if(video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr)==-1) - { + if (video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io, 4); return -EINVAL; } diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index bb5d92f104af..0d478f54a907 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -377,7 +377,7 @@ static int __init fmi_init(void) mutex_init(&lock); - if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) == -1) { + if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io, 2); return -EINVAL; } diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index a4984ff87c9c..16c7ef20265c 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c @@ -1694,8 +1694,8 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, INIT_DELAYED_WORK(&radio->work, si470x_work); /* register video device */ - if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) { - retval = -EIO; + retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); + if (retval) { printk(KERN_WARNING DRIVER_NAME ": Could not register video device\n"); goto err_all; diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index cefa44fc5aed..0876fecc5f27 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c @@ -405,8 +405,7 @@ static int __init terratec_init(void) spin_lock_init(&lock); - if(video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr)==-1) - { + if (video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io,2); return -EINVAL; } diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c index d70172d23edb..193161956253 100644 --- a/drivers/media/radio/radio-trust.c +++ b/drivers/media/radio/radio-trust.c @@ -378,8 +378,7 @@ static int __init trust_init(void) printk(KERN_ERR "trust: port 0x%x already in use\n", io); return -EBUSY; } - if(video_register_device(&trust_radio, VFL_TYPE_RADIO, radio_nr)==-1) - { + if (video_register_device(&trust_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io, 2); return -EINVAL; } diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index 9f17a332fa11..51d57ed3b3e1 100644 --- a/drivers/media/radio/radio-zoltrix.c +++ b/drivers/media/radio/radio-zoltrix.c @@ -446,8 +446,7 @@ static int __init zoltrix_init(void) return -EBUSY; } - if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO, radio_nr) == -1) - { + if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io, 2); return -EINVAL; } diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index bbc6f8b82297..ef7c8d3ffb18 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -20,6 +20,8 @@ ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y) obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o endif +obj-$(CONFIG_VIDEO_TUNER) += tuner.o + obj-$(CONFIG_VIDEO_BT848) += bt8xx/ obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o @@ -85,8 +87,6 @@ obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o obj-$(CONFIG_VIDEO_DPC) += dpc7146.o obj-$(CONFIG_TUNER_3036) += tuner-3036.o -obj-$(CONFIG_VIDEO_TUNER) += tuner.o - obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig index ed9a50f189fc..018f72b8e3e2 100644 --- a/drivers/media/video/au0828/Kconfig +++ b/drivers/media/video/au0828/Kconfig @@ -7,6 +7,7 @@ config VIDEO_AU0828 select DVB_AU8522 if !DVB_FE_CUSTOMIZE select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE select MEDIA_TUNER_MXL5007T if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE ---help--- This is a video4linux driver for Auvitek's USB device. diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c index 443e59009762..ed48908a9034 100644 --- a/drivers/media/video/au0828/au0828-cards.c +++ b/drivers/media/video/au0828/au0828-cards.c @@ -1,7 +1,7 @@ /* * Driver for the Auvitek USB bridge * - * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -38,6 +38,9 @@ struct au0828_board au0828_boards[] = { [AU0828_BOARD_DVICO_FUSIONHDTV7] = { .name = "DViCO FusionHDTV USB", }, + [AU0828_BOARD_HAUPPAUGE_WOODBURY] = { + .name = "Hauppauge Woodbury", + }, }; /* Tuner callback function for au0828 boards. Currently only needed @@ -115,6 +118,7 @@ void au0828_card_setup(struct au0828_dev *dev) case AU0828_BOARD_HAUPPAUGE_HVR850: case AU0828_BOARD_HAUPPAUGE_HVR950Q: case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: + case AU0828_BOARD_HAUPPAUGE_WOODBURY: if (dev->i2c_rc == 0) hauppauge_eeprom(dev, eeprom+0xa0); break; @@ -134,6 +138,7 @@ void au0828_gpio_setup(struct au0828_dev *dev) case AU0828_BOARD_HAUPPAUGE_HVR850: case AU0828_BOARD_HAUPPAUGE_HVR950Q: case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: + case AU0828_BOARD_HAUPPAUGE_WOODBURY: /* GPIO's * 4 - CS5340 * 5 - AU8522 Demodulator @@ -205,6 +210,8 @@ struct usb_device_id au0828_usb_id_table [] = { .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL }, { USB_DEVICE(0x2040, 0x7281), .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL }, + { USB_DEVICE(0x2040, 0x8200), + .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY }, { }, }; diff --git a/drivers/media/video/au0828/au0828-cards.h b/drivers/media/video/au0828/au0828-cards.h index c37f5fd0fa80..48a1882c2b6b 100644 --- a/drivers/media/video/au0828/au0828-cards.h +++ b/drivers/media/video/au0828/au0828-cards.h @@ -1,7 +1,7 @@ /* * Driver for the Auvitek USB bridge * - * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,3 +24,4 @@ #define AU0828_BOARD_HAUPPAUGE_HVR850 2 #define AU0828_BOARD_DVICO_FUSIONHDTV7 3 #define AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL 4 +#define AU0828_BOARD_HAUPPAUGE_WOODBURY 5 diff --git a/drivers/media/video/au0828/au0828-core.c b/drivers/media/video/au0828/au0828-core.c index 54bfc0f05295..d856de9f742f 100644 --- a/drivers/media/video/au0828/au0828-core.c +++ b/drivers/media/video/au0828/au0828-core.c @@ -1,7 +1,7 @@ /* * Driver for the Auvitek USB bridge * - * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -252,5 +252,5 @@ module_init(au0828_init); module_exit(au0828_exit); MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products"); -MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>"); +MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c index 584a83a94a2a..ba94be7e0ac1 100644 --- a/drivers/media/video/au0828/au0828-dvb.c +++ b/drivers/media/video/au0828/au0828-dvb.c @@ -1,7 +1,7 @@ /* * Driver for the Auvitek USB bridge * - * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,6 +29,7 @@ #include "au8522.h" #include "xc5000.h" #include "mxl5007t.h" +#include "tda18271.h" DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); @@ -38,6 +39,15 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static struct au8522_config hauppauge_hvr950q_config = { .demod_address = 0x8e >> 1, .status_mode = AU8522_DEMODLOCKING, + .qam_if = AU8522_IF_6MHZ, + .vsb_if = AU8522_IF_6MHZ, +}; + +static struct au8522_config hauppauge_woodbury_config = { + .demod_address = 0x8e >> 1, + .status_mode = AU8522_DEMODLOCKING, + .qam_if = AU8522_IF_4MHZ, + .vsb_if = AU8522_IF_3_25MHZ, }; static struct xc5000_config hauppauge_hvr950q_tunerconfig = { @@ -51,6 +61,10 @@ static struct mxl5007t_config mxl5007t_hvr950q_config = { .if_freq_hz = MxL_IF_6_MHZ, }; +static struct tda18271_config hauppauge_woodbury_tunerconfig = { + .gate = TDA18271_GATE_DIGITAL, +}; + /*-------------------------------------------------------------------*/ static void urb_completion(struct urb *purb) { @@ -357,6 +371,15 @@ int au0828_dvb_register(struct au0828_dev *dev) &dev->i2c_adap, 0x60, &mxl5007t_hvr950q_config); break; + case AU0828_BOARD_HAUPPAUGE_WOODBURY: + dvb->frontend = dvb_attach(au8522_attach, + &hauppauge_woodbury_config, + &dev->i2c_adap); + if (dvb->frontend != NULL) + dvb_attach(tda18271_attach, dvb->frontend, + 0x60, &dev->i2c_adap, + &hauppauge_woodbury_tunerconfig); + break; default: printk(KERN_WARNING "The frontend of your DVB/ATSC card " "isn't supported yet\n"); diff --git a/drivers/media/video/au0828/au0828-i2c.c b/drivers/media/video/au0828/au0828-i2c.c index 741a4937b050..d618fbaade1b 100644 --- a/drivers/media/video/au0828/au0828-i2c.c +++ b/drivers/media/video/au0828/au0828-i2c.c @@ -1,7 +1,7 @@ /* * Driver for the Auvitek AU0828 USB bridge * - * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/au0828/au0828-reg.h b/drivers/media/video/au0828/au0828-reg.h index 39827550891c..1e87fa0c6842 100644 --- a/drivers/media/video/au0828/au0828-reg.h +++ b/drivers/media/video/au0828/au0828-reg.h @@ -1,7 +1,7 @@ /* * Driver for the Auvitek USB bridge * - * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/au0828/au0828.h b/drivers/media/video/au0828/au0828.h index 7beb571798e5..4f10ff300135 100644 --- a/drivers/media/video/au0828/au0828.h +++ b/drivers/media/video/au0828/au0828.h @@ -1,7 +1,7 @@ /* * Driver for the Auvitek AU0828 USB bridge * - * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 1c56ae92ce74..6081edc362df 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -3144,8 +3144,9 @@ static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256]) static void flyvideo_gpio(struct bttv *btv) { - int gpio,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821; - int tuner=UNSET,ttype; + int gpio, has_remote, has_radio, is_capture_only; + int is_lr90, has_tda9820_tda9821; + int tuner_type = UNSET, ttype; gpio_inout(0xffffff, 0); udelay(8); /* without this we would see the 0x1800 mask */ @@ -3163,20 +3164,26 @@ static void flyvideo_gpio(struct bttv *btv) * xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered * Note: Some bits are Audio_Mask ! */ - ttype=(gpio&0x0f0000)>>16; - switch(ttype) { - case 0x0: tuner=2; /* NTSC, e.g. TPI8NSR11P */ + ttype = (gpio & 0x0f0000) >> 16; + switch (ttype) { + case 0x0: + tuner_type = 2; /* NTSC, e.g. TPI8NSR11P */ break; - case 0x2: tuner=39;/* LG NTSC (newer TAPC series) TAPC-H701P */ + case 0x2: + tuner_type = 39; /* LG NTSC (newer TAPC series) TAPC-H701P */ break; - case 0x4: tuner=5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */ + case 0x4: + tuner_type = 5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */ break; - case 0x6: tuner=37;/* LG PAL (newer TAPC series) TAPC-G702P */ + case 0x6: + tuner_type = 37; /* LG PAL (newer TAPC series) TAPC-G702P */ break; - case 0xC: tuner=3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */ + case 0xC: + tuner_type = 3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */ break; default: printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->c.nr); + break; } has_remote = gpio & 0x800000; @@ -3189,23 +3196,26 @@ static void flyvideo_gpio(struct bttv *btv) /* * gpio & 0x001000 output bit for audio routing */ - if(is_capture_only) - tuner = TUNER_ABSENT; /* No tuner present */ + if (is_capture_only) + tuner_type = TUNER_ABSENT; /* No tuner present */ printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", - btv->c.nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio); + btv->c.nr, has_radio ? "yes" : "no ", + has_remote ? "yes" : "no ", tuner_type, gpio); printk(KERN_INFO "bttv%d: FlyVideo LR90=%s tda9821/tda9820=%s capture_only=%s\n", - btv->c.nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ", - is_capture_only?"yes":"no "); + btv->c.nr, is_lr90 ? "yes" : "no ", + has_tda9820_tda9821 ? "yes" : "no ", + is_capture_only ? "yes" : "no "); - if (tuner != UNSET) /* only set if known tuner autodetected, else let insmod option through */ - btv->tuner_type = tuner; + if (tuner_type != UNSET) /* only set if known tuner autodetected, else let insmod option through */ + btv->tuner_type = tuner_type; btv->has_radio = has_radio; /* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80 * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00 * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */ - if(has_tda9820_tda9821) btv->audio_mode_gpio = lt9415_audio; + if (has_tda9820_tda9821) + btv->audio_mode_gpio = lt9415_audio; /* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */ } @@ -3962,7 +3972,7 @@ static int tuner_1_table[] = { static void __devinit avermedia_eeprom(struct bttv *btv) { - int tuner_make,tuner_tv_fm,tuner_format,tuner=0; + int tuner_make, tuner_tv_fm, tuner_format, tuner_type = 0; tuner_make = (eeprom_data[0x41] & 0x7); tuner_tv_fm = (eeprom_data[0x41] & 0x18) >> 3; @@ -3970,24 +3980,24 @@ static void __devinit avermedia_eeprom(struct bttv *btv) btv->has_remote = (eeprom_data[0x42] & 0x01); if (tuner_make == 0 || tuner_make == 2) - if(tuner_format <=0x0a) - tuner = tuner_0_table[tuner_format]; + if (tuner_format <= 0x0a) + tuner_type = tuner_0_table[tuner_format]; if (tuner_make == 1) - if(tuner_format <=9) - tuner = tuner_1_table[tuner_format]; + if (tuner_format <= 9) + tuner_type = tuner_1_table[tuner_format]; if (tuner_make == 4) - if(tuner_format == 0x09) - tuner = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */ + if (tuner_format == 0x09) + tuner_type = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */ printk(KERN_INFO "bttv%d: Avermedia eeprom[0x%02x%02x]: tuner=", - btv->c.nr,eeprom_data[0x41],eeprom_data[0x42]); - if(tuner) { - btv->tuner_type=tuner; - printk("%d",tuner); + btv->c.nr, eeprom_data[0x41], eeprom_data[0x42]); + if (tuner_type) { + btv->tuner_type = tuner_type; + printk(KERN_CONT "%d", tuner_type); } else - printk("Unknown type"); - printk(" radio:%s remote control:%s\n", + printk(KERN_CONT "Unknown type"); + printk(KERN_CONT " radio:%s remote control:%s\n", tuner_tv_fm ? "yes" : "no", btv->has_remote ? "yes" : "no"); } @@ -4029,7 +4039,8 @@ static void __devinit boot_msp34xx(struct bttv *btv, int pin) gpio_inout(mask,mask); gpio_bits(mask,0); - udelay(2500); + mdelay(2); + udelay(500); gpio_bits(mask,mask); if (bttv_gpio) diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 85bf31ab8789..6ae4cc860efe 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -96,7 +96,6 @@ static unsigned int irq_iswitch; static unsigned int uv_ratio = 50; static unsigned int full_luma_range; static unsigned int coring; -extern int no_overlay; /* API features (turn on/off stuff for testing) */ static unsigned int v4l2 = 1; diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c index 649682aac1ac..5b1b8e4c78ba 100644 --- a/drivers/media/video/bt8xx/bttv-risc.c +++ b/drivers/media/video/bt8xx/bttv-risc.c @@ -244,7 +244,8 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc, const struct bttv_format *fmt, struct bttv_overlay *ov, int skip_even, int skip_odd) { - int dwords,rc,line,maxy,start,end,skip,nskips; + int dwords, rc, line, maxy, start, end; + unsigned skip, nskips; struct btcx_skiplist *skips; __le32 *rp; u32 ri,ra; diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index 08ef54a22c9e..b4d940b2e447 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h @@ -267,6 +267,11 @@ int bttv_sub_add_device(struct bttv_core *core, char *name); int bttv_sub_del_devices(struct bttv_core *core); /* ---------------------------------------------------------- */ +/* bttv-cards.c */ + +extern int no_overlay; + +/* ---------------------------------------------------------- */ /* bttv-driver.c */ /* insmod options */ diff --git a/drivers/media/video/btcx-risc.c b/drivers/media/video/btcx-risc.c index f42701f82e7f..3324ab38f58c 100644 --- a/drivers/media/video/btcx-risc.c +++ b/drivers/media/video/btcx-risc.c @@ -184,12 +184,12 @@ btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips) } void -btcx_calc_skips(int line, int width, unsigned int *maxy, +btcx_calc_skips(int line, int width, int *maxy, struct btcx_skiplist *skips, unsigned int *nskips, const struct v4l2_clip *clips, unsigned int nclips) { unsigned int clip,skip; - int end,maxline; + int end, maxline; skip=0; maxline = 9999; diff --git a/drivers/media/video/btcx-risc.h b/drivers/media/video/btcx-risc.h index 861bc8112824..f8bc6e8e7b51 100644 --- a/drivers/media/video/btcx-risc.h +++ b/drivers/media/video/btcx-risc.h @@ -23,7 +23,7 @@ int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int mask); void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips); -void btcx_calc_skips(int line, int width, unsigned int *maxy, +void btcx_calc_skips(int line, int width, int *maxy, struct btcx_skiplist *skips, unsigned int *nskips, const struct v4l2_clip *clips, unsigned int nclips); diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index d3b3268bace8..6e39e253ce53 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -946,8 +946,7 @@ static int init_bwqcam(struct parport *port) printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name); - if(video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1) - { + if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { parport_unregister_device(qcam->pdev); kfree(qcam); return -ENODEV; diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c index fe9379b282d3..7f6c6b4bec10 100644 --- a/drivers/media/video/c-qcam.c +++ b/drivers/media/video/c-qcam.c @@ -787,8 +787,7 @@ static int init_cqcam(struct parport *port) parport_release(qcam->pdev); - if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1) - { + if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { printk(KERN_ERR "Unable to register Colour QuickCam on %s\n", qcam->pport->name); parport_unregister_device(qcam->pdev); diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c index dc8cc6115e2f..a661800b0e69 100644 --- a/drivers/media/video/cpia.c +++ b/drivers/media/video/cpia.c @@ -3955,7 +3955,7 @@ struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowleve camera->lowlevel_data = lowlevel; /* register v4l device */ - if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { + if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { kfree(camera); printk(KERN_DEBUG "video_register_device failed\n"); return NULL; diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index 515c8b57a60d..eb9f15cd4c45 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c @@ -1024,7 +1024,6 @@ static int ioctl_queryctrl(void *arg,struct camera_data *cam) if(cam->params.pnp_id.device_type == DEVICE_STV_672 && cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){ // Maximum 15fps - int i; for(i=0; i<c->maximum; ++i) { if(framerate_controls[i].value == CPIA2_VP_FRAMERATE_15) { @@ -1959,8 +1958,7 @@ int cpia2_register_camera(struct camera_data *cam) reset_camera_struct_v4l(cam); /* register v4l device */ - if (video_register_device - (cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { + if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { ERR("video_register_device failed\n"); video_device_release(cam->vdev); return -ENODEV; diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c index 834b9248242e..e996a4e3123a 100644 --- a/drivers/media/video/cx18/cx18-av-firmware.c +++ b/drivers/media/video/cx18/cx18-av-firmware.c @@ -32,7 +32,7 @@ int cx18_av_loadfw(struct cx18 *cx) u32 v; const u8 *ptr; int i; - int retries = 0; + int retries1 = 0; if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) { CX18_ERR("unable to open firmware %s\n", FWFILE); @@ -41,7 +41,7 @@ int cx18_av_loadfw(struct cx18 *cx) /* The firmware load often has byte errors, so allow for several retries, both at byte level and at the firmware load level. */ - while (retries < 5) { + while (retries1 < 5) { cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000); cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); @@ -57,9 +57,9 @@ int cx18_av_loadfw(struct cx18 *cx) for (i = 0; i < size; i++) { u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16); u32 value = 0; - int retries; + int retries2; - for (retries = 0; retries < 5; retries++) { + for (retries2 = 0; retries2 < 5; retries2++) { cx18_av_write4(cx, CXADEC_DL_CTL, dl_control); udelay(10); value = cx18_av_read4(cx, CXADEC_DL_CTL); @@ -69,18 +69,18 @@ int cx18_av_loadfw(struct cx18 *cx) the address. We can only write the lower address byte of the address. */ if ((value & 0x3F00) != (dl_control & 0x3F00)) { - retries = 5; + retries2 = 5; break; } } - if (retries >= 5) + if (retries2 >= 5) break; } if (i == size) break; - retries++; + retries1++; } - if (retries >= 5) { + if (retries1 >= 5) { CX18_ERR("unable to load firmware %s\n", FWFILE); release_firmware(fw); return -EIO; diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 22434aadde31..bd18afebbf86 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c @@ -74,9 +74,9 @@ static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; -static int cardtype_c = 1; -static int tuner_c = 1; -static int radio_c = 1; +static unsigned cardtype_c = 1; +static unsigned tuner_c = 1; +static unsigned radio_c = 1; static char pal[] = "--"; static char secam[] = "--"; static char ntsc[] = "-"; diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c index cae38985b131..1e420a804fc9 100644 --- a/drivers/media/video/cx18/cx18-dvb.c +++ b/drivers/media/video/cx18/cx18-dvb.c @@ -1,7 +1,7 @@ /* * cx18 functions for DVB support * - * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-dvb.h b/drivers/media/video/cx18/cx18-dvb.h index d6a6ccda79a9..bf8d8f6f5455 100644 --- a/drivers/media/video/cx18/cx18-dvb.h +++ b/drivers/media/video/cx18/cx18-dvb.h @@ -1,7 +1,7 @@ /* * cx18 functions for DVB support * - * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c index 25114a5cbd57..ab218315c84b 100644 --- a/drivers/media/video/cx18/cx18-irq.c +++ b/drivers/media/video/cx18/cx18-irq.c @@ -61,7 +61,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) CX18_WARN("Ack struct = %d for %s\n", mb->args[2], s->name); id = read_enc(off); - buf = cx18_queue_find_buf(s, id, read_enc(off + 4)); + buf = cx18_queue_get_buf_irq(s, id, read_enc(off + 4)); CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id); if (buf) { cx18_buf_sync_for_cpu(s, buf); diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c index 6990b77c6200..dbe792ac3001 100644 --- a/drivers/media/video/cx18/cx18-queue.c +++ b/drivers/media/video/cx18/cx18-queue.c @@ -78,12 +78,13 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) return buf; } -struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id, +struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id, u32 bytesused) { struct cx18 *cx = s->cx; struct list_head *p; + spin_lock(&s->qlock); list_for_each(p, &s->q_free.list) { struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list); @@ -92,114 +93,48 @@ struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id, continue; buf->bytesused = bytesused; /* the transport buffers are handled differently, - so there is no need to move them to the full queue */ - if (s->type == CX18_ENC_STREAM_TYPE_TS) - return buf; - s->q_free.buffers--; - s->q_free.length -= s->buf_size; - s->q_full.buffers++; - s->q_full.length += s->buf_size; - s->q_full.bytesused += buf->bytesused; - list_move_tail(&buf->list, &s->q_full.list); + they are not moved to the full queue */ + if (s->type != CX18_ENC_STREAM_TYPE_TS) { + s->q_free.buffers--; + s->q_free.length -= s->buf_size; + s->q_full.buffers++; + s->q_full.length += s->buf_size; + s->q_full.bytesused += buf->bytesused; + list_move_tail(&buf->list, &s->q_full.list); + } + spin_unlock(&s->qlock); return buf; } + spin_unlock(&s->qlock); CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name); return NULL; } -static void cx18_queue_move_buf(struct cx18_stream *s, struct cx18_queue *from, - struct cx18_queue *to, int clear, int full) -{ - struct cx18_buffer *buf = - list_entry(from->list.next, struct cx18_buffer, list); - - list_move_tail(from->list.next, &to->list); - from->buffers--; - from->length -= s->buf_size; - from->bytesused -= buf->bytesused - buf->readpos; - /* special handling for q_free */ - if (clear) - buf->bytesused = buf->readpos = buf->b_flags = 0; - else if (full) { - /* special handling for stolen buffers, assume - all bytes are used. */ - buf->bytesused = s->buf_size; - buf->readpos = buf->b_flags = 0; - } - to->buffers++; - to->length += s->buf_size; - to->bytesused += buf->bytesused - buf->readpos; -} - -/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'. - If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'. - If 'steal' != NULL, then buffers may also taken from that queue if - needed. - - The buffer is automatically cleared if it goes to the free queue. It is - also cleared if buffers need to be taken from the 'steal' queue and - the 'from' queue is the free queue. - - When 'from' is q_free, then needed_bytes is compared to the total - available buffer length, otherwise needed_bytes is compared to the - bytesused value. For the 'steal' queue the total available buffer - length is always used. - - -ENOMEM is returned if the buffers could not be obtained, 0 if all - buffers where obtained from the 'from' list and if non-zero then - the number of stolen buffers is returned. */ -static int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from, - struct cx18_queue *steal, struct cx18_queue *to, - int needed_bytes) +/* Move all buffers of a queue to q_free, while flushing the buffers */ +static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q) { unsigned long flags; - int rc = 0; - int from_free = from == &s->q_free; - int to_free = to == &s->q_free; - int bytes_available; - - spin_lock_irqsave(&s->qlock, flags); - if (needed_bytes == 0) { - from_free = 1; - needed_bytes = from->length; - } - - bytes_available = from_free ? from->length : from->bytesused; - bytes_available += steal ? steal->length : 0; + struct cx18_buffer *buf; - if (bytes_available < needed_bytes) { - spin_unlock_irqrestore(&s->qlock, flags); - return -ENOMEM; - } - if (from_free) { - u32 old_length = to->length; + if (q == &s->q_free) + return; - while (to->length - old_length < needed_bytes) { - if (list_empty(&from->list)) - from = steal; - if (from == steal) - rc++; /* keep track of 'stolen' buffers */ - cx18_queue_move_buf(s, from, to, 1, 0); - } - } else { - u32 old_bytesused = to->bytesused; - - while (to->bytesused - old_bytesused < needed_bytes) { - if (list_empty(&from->list)) - from = steal; - if (from == steal) - rc++; /* keep track of 'stolen' buffers */ - cx18_queue_move_buf(s, from, to, to_free, rc); - } + spin_lock_irqsave(&s->qlock, flags); + while (!list_empty(&q->list)) { + buf = list_entry(q->list.next, struct cx18_buffer, list); + list_move_tail(q->list.next, &s->q_free.list); + buf->bytesused = buf->readpos = buf->b_flags = 0; + s->q_free.buffers++; + s->q_free.length += s->buf_size; } + cx18_queue_init(q); spin_unlock_irqrestore(&s->qlock, flags); - return rc; } void cx18_flush_queues(struct cx18_stream *s) { - cx18_queue_move(s, &s->q_io, NULL, &s->q_free, 0); - cx18_queue_move(s, &s->q_full, NULL, &s->q_free, 0); + cx18_queue_flush(s, &s->q_io); + cx18_queue_flush(s, &s->q_full); } int cx18_stream_alloc(struct cx18_stream *s) @@ -214,10 +149,10 @@ int cx18_stream_alloc(struct cx18_stream *s) s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024); - if (((char *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] - - (char *)cx->scb) > SCB_RESERVED_SIZE) { - unsigned bufsz = (((char *)cx->scb) + SCB_RESERVED_SIZE - - ((char *)cx->scb->cpu_mdl)); + if (((char __iomem *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] - + (char __iomem *)cx->scb) > SCB_RESERVED_SIZE) { + unsigned bufsz = (((char __iomem *)cx->scb) + SCB_RESERVED_SIZE - + ((char __iomem *)cx->scb->cpu_mdl)); CX18_ERR("Too many buffers, cannot fit in SCB area\n"); CX18_ERR("Max buffers = %zd\n", diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h index 91423b9863a4..7f93bb13c09f 100644 --- a/drivers/media/video/cx18/cx18-queue.h +++ b/drivers/media/video/cx18/cx18-queue.h @@ -46,7 +46,7 @@ void cx18_queue_init(struct cx18_queue *q); void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, struct cx18_queue *q); struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q); -struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id, +struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id, u32 bytesused); void cx18_flush_queues(struct cx18_stream *s); diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index 8118091568fc..7b0e8c01692e 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c @@ -4,7 +4,7 @@ * * (c) 2004 Jelle Foks <jelle@foks.8m.com> * (c) 2004 Gerd Knorr <kraxel@bytesex.org> - * (c) 2008 Steven Toth <stoth@hauppauge.com> + * (c) 2008 Steven Toth <stoth@linuxtv.org> * - CX23885/7/8 support * * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/), diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index a19de850955d..c36d3f632104 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -1,7 +1,7 @@ /* * Driver for the Conexant CX23885 PCIe bridge * - * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 6286a9cf957e..25fb09938744 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1,7 +1,7 @@ /* * Driver for the Conexant CX23885 PCIe bridge * - * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,7 +33,7 @@ #include "cx23885.h" MODULE_DESCRIPTION("Driver for cx23885 based TV cards"); -MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>"); +MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); MODULE_LICENSE("GPL"); static unsigned int debug; diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 0a2e6558cd66..291b9d008da8 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -1,7 +1,7 @@ /* * Driver for the Conexant CX23885 PCIe bridge * - * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index c6bb0a05bc1c..f98e476e9617 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -1,7 +1,7 @@ /* * Driver for the Conexant CX23885 PCIe bridge * - * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index bdd11bc513ad..20b68a236260 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -1,7 +1,7 @@ /* * Driver for the Conexant CX23885 PCIe bridge * - * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c index e36e3fcae2fb..35e61cd112fc 100644 --- a/drivers/media/video/cx23885/cx23885-vbi.c +++ b/drivers/media/video/cx23885/cx23885-vbi.c @@ -1,7 +1,7 @@ /* * Driver for the Conexant CX23885 PCIe bridge * - * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index ad2235dab5b1..6047c78d84bf 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -1,7 +1,7 @@ /* * Driver for the Conexant CX23885 PCIe bridge * - * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,7 +41,7 @@ #endif MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards"); -MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>"); +MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); MODULE_LICENSE("GPL"); /* ------------------------------------------------------------------ */ diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 00dfdc89d641..e23d97c071e0 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -1,7 +1,7 @@ /* * Driver for the Conexant CX23885 PCIe bridge * - * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 209d3bcb5dbb..4da8cd74f00e 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -13,7 +13,7 @@ * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca> * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>. * - * CX23885 support by Steven Toth <stoth@hauppauge.com>. + * CX23885 support by Steven Toth <stoth@linuxtv.org>. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c index 48f4b92a8f8b..79faedf58521 100644 --- a/drivers/media/video/dabusb.c +++ b/drivers/media/video/dabusb.c @@ -403,6 +403,7 @@ static int dabusb_fpga_download (pdabusb_t s, const char *fname) ret = request_firmware(&fw, "dabusb/bitstream.bin", &s->usbdev->dev); if (ret) { err("Failed to load \"dabusb/bitstream.bin\": %d\n", ret); + kfree(b); return ret; } diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 2d170d101c21..8db2a05bf9c5 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -2588,6 +2588,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) cam->v4ldev->fops = &et61x251_fops; cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; + cam->v4ldev->parent = &udev->dev; video_set_drvdata(cam->v4ldev, cam); init_completion(&cam->probe); diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c index cd3a3f5829b2..4d9f4cc255a9 100644 --- a/drivers/media/video/gspca/conex.c +++ b/drivers/media/video/gspca/conex.c @@ -124,7 +124,7 @@ static void reg_r(struct gspca_dev *gspca_dev, struct usb_device *dev = gspca_dev->dev; #ifdef GSPCA_DEBUG - if (len > sizeof gspca_dev->usb_buf) { + if (len > USB_BUF_SZ) { err("reg_r: buffer overflow"); return; } @@ -164,7 +164,7 @@ static void reg_w(struct gspca_dev *gspca_dev, struct usb_device *dev = gspca_dev->dev; #ifdef GSPCA_DEBUG - if (len > sizeof gspca_dev->usb_buf) { + if (len > USB_BUF_SZ) { err("reg_w: buffer overflow"); return; } @@ -731,13 +731,13 @@ static void cx11646_jpeg(struct gspca_dev*gspca_dev) reg_w_val(gspca_dev, 0x0000, 0x00); /* wait for completion */ retry = 50; - while (retry--) { + do { reg_r(gspca_dev, 0x0002, 1); /* 0x07 until 0x00 */ if (gspca_dev->usb_buf[0] == 0x00) break; reg_w_val(gspca_dev, 0x0053, 0x00); - } + } while (--retry); if (retry == 0) PDEBUG(D_ERR, "Damned Errors sending jpeg Table"); /* send the qtable now */ @@ -826,8 +826,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { cx11646_init1(gspca_dev); cx11646_initsize(gspca_dev); @@ -845,10 +845,6 @@ static void sd_start(struct gspca_dev *gspca_dev) cx11646_jpeg(gspca_dev); } -static void sd_stopN(struct gspca_dev *gspca_dev) -{ -} - static void sd_stop0(struct gspca_dev *gspca_dev) { int retry = 50; @@ -871,10 +867,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev) reg_w_val(gspca_dev, 0x00fc, 0xe0); } -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -998,11 +990,9 @@ static struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, - .stopN = sd_stopN, .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; @@ -1026,6 +1016,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c index 1dbe92d01e6a..4ff0e386914b 100644 --- a/drivers/media/video/gspca/etoms.c +++ b/drivers/media/video/gspca/etoms.c @@ -81,6 +81,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setcontrast, .get = sd_getcontrast, }, +#define COLOR_IDX 2 { { .id = V4L2_CID_SATURATION, @@ -234,7 +235,7 @@ static void reg_r(struct gspca_dev *gspca_dev, struct usb_device *dev = gspca_dev->dev; #ifdef GSPCA_DEBUG - if (len > sizeof gspca_dev->usb_buf) { + if (len > USB_BUF_SZ) { err("reg_r: buffer overflow"); return; } @@ -272,7 +273,7 @@ static void reg_w(struct gspca_dev *gspca_dev, struct usb_device *dev = gspca_dev->dev; #ifdef GSPCA_DEBUG - if (len > sizeof gspca_dev->usb_buf) { + if (len > USB_BUF_SZ) { err("reg_w: buffer overflow"); return; } @@ -665,6 +666,7 @@ static int sd_config(struct gspca_dev *gspca_dev, } else { cam->cam_mode = vga_mode; cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; + gspca_dev->ctrl_dis = (1 << COLOR_IDX); } sd->brightness = BRIGHTNESS_DEF; sd->contrast = CONTRAST_DEF; @@ -674,8 +676,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -709,14 +711,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) et_video(gspca_dev, 0); /* video off */ } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static __u8 Et_getgainG(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -893,21 +887,19 @@ static struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, .dq_callback = do_autogain, }; /* -- module initialisation -- */ static __devinitdata struct usb_device_id device_table[] = { -#ifndef CONFIG_USB_ET61X251 {USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106}, -#endif +#if !defined CONFIG_USB_ET61X251 && !defined CONFIG_USB_ET61X251_MODULE {USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX}, +#endif {} }; @@ -926,6 +918,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 15d302b28b79..7be69284da03 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -114,7 +114,10 @@ static void fill_frame(struct gspca_dev *gspca_dev, cam_pkt_op pkt_scan; if (urb->status != 0) { - PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); +#ifdef CONFIG_PM + if (!gspca_dev->frozen) +#endif + PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); return; /* disconnection ? */ } pkt_scan = gspca_dev->sd_desc->pkt_scan; @@ -555,10 +558,12 @@ static void gspca_stream_off(struct gspca_dev *gspca_dev) gspca_dev->streaming = 0; atomic_set(&gspca_dev->nevent, 0); if (gspca_dev->present) { - gspca_dev->sd_desc->stopN(gspca_dev); + if (gspca_dev->sd_desc->stopN) + gspca_dev->sd_desc->stopN(gspca_dev); destroy_urbs(gspca_dev); gspca_set_alt0(gspca_dev); - gspca_dev->sd_desc->stop0(gspca_dev); + if (gspca_dev->sd_desc->stop0) + gspca_dev->sd_desc->stop0(gspca_dev); PDEBUG(D_STREAM, "stream off OK"); } } @@ -767,19 +772,7 @@ static int dev_open(struct inode *inode, struct file *file) goto out; } - /* if not done yet, initialize the sensor */ - if (gspca_dev->users == 0) { - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) { - ret = -ERESTARTSYS; - goto out; - } - ret = gspca_dev->sd_desc->open(gspca_dev); - mutex_unlock(&gspca_dev->usb_lock); - if (ret != 0) { - PDEBUG(D_ERR|D_CONF, "init device failed %d", ret); - goto out; - } - } else if (gspca_dev->users > 4) { /* (arbitrary value) */ + if (gspca_dev->users > 4) { /* (arbitrary value) */ ret = -EBUSY; goto out; } @@ -792,6 +785,7 @@ static int dev_open(struct inode *inode, struct file *file) else gspca_dev->vdev.debug &= ~3; #endif + ret = 0; out: mutex_unlock(&gspca_dev->queue_lock); if (ret != 0) @@ -812,11 +806,11 @@ static int dev_close(struct inode *inode, struct file *file) /* if the file did the capture, free the streaming resources */ if (gspca_dev->capt_file == file) { - mutex_lock(&gspca_dev->usb_lock); - if (gspca_dev->streaming) + if (gspca_dev->streaming) { + mutex_lock(&gspca_dev->usb_lock); gspca_stream_off(gspca_dev); - gspca_dev->sd_desc->close(gspca_dev); - mutex_unlock(&gspca_dev->usb_lock); + mutex_unlock(&gspca_dev->usb_lock); + } frame_free(gspca_dev); gspca_dev->capt_file = NULL; gspca_dev->memory = GSPCA_MEMORY_NO; @@ -853,42 +847,44 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -/* the use of V4L2_CTRL_FLAG_NEXT_CTRL asks for the controls to be sorted */ static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *q_ctrl) { struct gspca_dev *gspca_dev = priv; - int i; + int i, ix; u32 id; + ix = -1; id = q_ctrl->id; if (id & V4L2_CTRL_FLAG_NEXT_CTRL) { id &= V4L2_CTRL_ID_MASK; id++; for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { - if (id >= gspca_dev->sd_desc->ctrls[i].qctrl.id) { - memcpy(q_ctrl, - &gspca_dev->sd_desc->ctrls[i].qctrl, - sizeof *q_ctrl); - return 0; + if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id) + continue; + if (ix < 0) { + ix = i; + continue; } + if (gspca_dev->sd_desc->ctrls[i].qctrl.id + > gspca_dev->sd_desc->ctrls[ix].qctrl.id) + continue; + ix = i; } - return -EINVAL; } for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { if (id == gspca_dev->sd_desc->ctrls[i].qctrl.id) { - memcpy(q_ctrl, - &gspca_dev->sd_desc->ctrls[i].qctrl, - sizeof *q_ctrl); - return 0; + ix = i; + break; } } - if (id >= V4L2_CID_BASE - && id <= V4L2_CID_LASTP1) { + if (ix < 0) + return -EINVAL; + memcpy(q_ctrl, &gspca_dev->sd_desc->ctrls[ix].qctrl, + sizeof *q_ctrl); + if (gspca_dev->ctrl_dis & (1 << ix)) q_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED; - return 0; - } - return -EINVAL; + return 0; } static int vidioc_s_ctrl(struct file *file, void *priv, @@ -903,6 +899,8 @@ static int vidioc_s_ctrl(struct file *file, void *priv, i++, ctrls++) { if (ctrl->id != ctrls->qctrl.id) continue; + if (gspca_dev->ctrl_dis & (1 << i)) + return -EINVAL; if (ctrl->value < ctrls->qctrl.minimum || ctrl->value > ctrls->qctrl.maximum) return -ERANGE; @@ -929,6 +927,8 @@ static int vidioc_g_ctrl(struct file *file, void *priv, i++, ctrls++) { if (ctrl->id != ctrls->qctrl.id) continue; + if (gspca_dev->ctrl_dis & (1 << i)) + return -EINVAL; if (mutex_lock_interruptible(&gspca_dev->usb_lock)) return -ERESTARTSYS; ret = ctrls->get(gspca_dev, &ctrl->value); @@ -1403,7 +1403,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, i = ret; /* frame index */ frame = &gspca_dev->frame[i]; if (gspca_dev->memory == V4L2_MEMORY_USERPTR) { - if (copy_to_user((__u8 *) frame->v4l2_buf.m.userptr, + if (copy_to_user((__u8 __user *) frame->v4l2_buf.m.userptr, frame->data, frame->v4l2_buf.bytesused)) { PDEBUG(D_ERR|D_STREAM, @@ -1731,6 +1731,12 @@ int gspca_dev_probe(struct usb_interface *intf, err("couldn't kzalloc gspca struct"); return -EIO; } + gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL); + if (!gspca_dev->usb_buf) { + err("out of memory"); + ret = -EIO; + goto out; + } gspca_dev->dev = dev; gspca_dev->iface = interface->bInterfaceNumber; gspca_dev->nbalt = intf->num_altsetting; @@ -1738,10 +1744,13 @@ int gspca_dev_probe(struct usb_interface *intf, /* gspca_dev->users = 0; (done by kzalloc) */ gspca_dev->nbufread = 2; - /* configure the subdriver */ + /* configure the subdriver and initialize the USB device */ ret = gspca_dev->sd_desc->config(gspca_dev, id); if (ret < 0) goto out; + ret = gspca_dev->sd_desc->init(gspca_dev); + if (ret < 0) + goto out; ret = gspca_set_alt0(gspca_dev); if (ret < 0) goto out; @@ -1771,6 +1780,7 @@ int gspca_dev_probe(struct usb_interface *intf, PDEBUG(D_PROBE, "probe ok"); return 0; out: + kfree(gspca_dev->usb_buf); kfree(gspca_dev); return ret; } @@ -1803,11 +1813,42 @@ void gspca_disconnect(struct usb_interface *intf) /* We don't want people trying to open up the device */ video_unregister_device(&gspca_dev->vdev); /* Free the memory */ + kfree(gspca_dev->usb_buf); kfree(gspca_dev); PDEBUG(D_PROBE, "disconnect complete"); } EXPORT_SYMBOL(gspca_disconnect); +#ifdef CONFIG_PM +int gspca_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct gspca_dev *gspca_dev = usb_get_intfdata(intf); + + if (!gspca_dev->streaming) + return 0; + gspca_dev->frozen = 1; /* avoid urb error messages */ + if (gspca_dev->sd_desc->stopN) + gspca_dev->sd_desc->stopN(gspca_dev); + destroy_urbs(gspca_dev); + gspca_set_alt0(gspca_dev); + if (gspca_dev->sd_desc->stop0) + gspca_dev->sd_desc->stop0(gspca_dev); + return 0; +} +EXPORT_SYMBOL(gspca_suspend); + +int gspca_resume(struct usb_interface *intf) +{ + struct gspca_dev *gspca_dev = usb_get_intfdata(intf); + + gspca_dev->frozen = 0; + gspca_dev->sd_desc->init(gspca_dev); + if (gspca_dev->streaming) + return gspca_init_transfer(gspca_dev); + return 0; +} +EXPORT_SYMBOL(gspca_resume); +#endif /* -- cam driver utility functions -- */ /* auto gain and exposure algorithm based on the knee algorithm described here: diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h index 67e448940eaa..c17625cff9ba 100644 --- a/drivers/media/video/gspca/gspca.h +++ b/drivers/media/video/gspca/gspca.h @@ -56,7 +56,6 @@ extern int gspca_debug; /* device information - set at probe time */ struct cam { - char *dev_name; struct v4l2_pix_format *cam_mode; /* size nmodes */ char nmodes; __u8 epaddr; @@ -91,15 +90,14 @@ struct sd_desc { /* controls */ const struct ctrl *ctrls; int nctrls; -/* operations */ +/* mandatory operations */ cam_cf_op config; /* called on probe */ - cam_op open; /* called on open */ + cam_op init; /* called on probe and resume */ cam_v_op start; /* called on stream on */ - cam_v_op stopN; /* called on stream off - main alt */ - cam_v_op stop0; /* called on stream off - alt 0 */ - cam_v_op close; /* called on close */ cam_pkt_op pkt_scan; /* optional operations */ + cam_v_op stopN; /* called on stream off - main alt */ + cam_v_op stop0; /* called on stream off - alt 0 */ cam_v_op dq_callback; /* called when a frame has been dequeued */ cam_jpg_op get_jcomp; cam_jpg_op set_jcomp; @@ -127,8 +125,10 @@ struct gspca_dev { struct cam cam; /* device information */ const struct sd_desc *sd_desc; /* subdriver description */ + unsigned ctrl_dis; /* disabled controls (bit map) */ - __u8 usb_buf[8]; /* buffer for USB exchanges */ +#define USB_BUF_SZ 64 + __u8 *usb_buf; /* buffer for USB exchanges */ struct urb *urb[MAX_NURBS]; __u8 *frbuf; /* buffer for nframes */ @@ -155,6 +155,9 @@ struct gspca_dev { struct mutex queue_lock; /* ISOC queue protection */ __u32 sequence; /* frame sequence number */ char streaming; +#ifdef CONFIG_PM + char frozen; /* suspend - resume */ +#endif char users; /* number of opens */ char present; /* device connected */ char nbufread; /* number of buffers for read() */ @@ -174,6 +177,10 @@ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev, struct gspca_frame *frame, const __u8 *data, int len); +#ifdef CONFIG_PM +int gspca_suspend(struct usb_interface *intf, pm_message_t message); +int gspca_resume(struct usb_interface *intf); +#endif int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum, int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee); #endif /* GSPCAV2_H */ diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c index 21c4ee56a10a..4d5db47ba8cb 100644 --- a/drivers/media/video/gspca/mars.c +++ b/drivers/media/video/gspca/mars.c @@ -100,22 +100,6 @@ static int reg_w(struct gspca_dev *gspca_dev, return rc; } -static int reg_w_buf(struct gspca_dev *gspca_dev, - __u16 index, __u8 *buf, int len) -{ - int rc; - - rc = usb_control_msg(gspca_dev->dev, - usb_sndbulkpipe(gspca_dev->dev, 4), - 0x12, - 0xc8, /* ?? */ - 0, /* value */ - index, buf, len, 500); - if (rc < 0) - PDEBUG(D_ERR, "reg write [%02x] error %d", index, rc); - return rc; -} - static void bulk_w(struct gspca_dev *gspca_dev, __u16 *pch, __u16 Address) @@ -144,8 +128,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { return 0; } @@ -175,7 +159,6 @@ static void sd_start(struct gspca_dev *gspca_dev) /* Initialize the MR97113 chip register */ - data = kmalloc(16, GFP_KERNEL); data[0] = 0x00; /* address */ data[1] = 0x0c | 0x01; /* reg 0 */ data[2] = 0x01; /* reg 1 */ @@ -195,12 +178,10 @@ static void sd_start(struct gspca_dev *gspca_dev) data[10] = 0x5d; /* reg 9, I2C device address * [for PAS5101 (0x40)] [for MI (0x5d)] */ - err_code = reg_w_buf(gspca_dev, data[0], data, 11); - kfree(data); + err_code = reg_w(gspca_dev, data[0], 11); if (err_code < 0) return; - data = gspca_dev->usb_buf; data[0] = 0x23; /* address */ data[1] = 0x09; /* reg 35, append frame header */ @@ -358,14 +339,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) PDEBUG(D_ERR, "Camera Stop failed"); } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -411,11 +384,9 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; @@ -439,6 +410,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index b4f00ec0885c..4df4eec9f7e7 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -63,11 +63,10 @@ struct sd { #define SEN_OV6630 2 #define SEN_OV7610 3 #define SEN_OV7620 4 -#define SEN_OV7630 5 -#define SEN_OV7640 6 -#define SEN_OV7670 7 -#define SEN_OV76BE 8 -#define SEN_OV8610 9 +#define SEN_OV7640 5 +#define SEN_OV7670 6 +#define SEN_OV76BE 7 +#define SEN_OV8610 8 }; @@ -127,6 +126,7 @@ static struct ctrl sd_ctrls[] = { .get = sd_getcolors, }, /* next controls work with ov7670 only */ +#define HFLIP_IDX 3 { { .id = V4L2_CID_HFLIP, @@ -141,6 +141,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_sethflip, .get = sd_gethflip, }, +#define VFLIP_IDX 4 { { .id = V4L2_CID_VFLIP, @@ -293,6 +294,541 @@ static struct v4l2_pix_format sif_mode[] = { #define OV7670_REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ #define OV7670_REG_BD60MAX 0xab /* 60hz banding step limit */ +struct ov_regvals { + __u8 reg; + __u8 val; +}; +struct ov_i2c_regvals { + __u8 reg; + __u8 val; +}; + +static const struct ov_i2c_regvals norm_6x20[] = { + { 0x12, 0x80 }, /* reset */ + { 0x11, 0x01 }, + { 0x03, 0x60 }, + { 0x05, 0x7f }, /* For when autoadjust is off */ + { 0x07, 0xa8 }, + /* The ratio of 0x0c and 0x0d controls the white point */ + { 0x0c, 0x24 }, + { 0x0d, 0x24 }, + { 0x0f, 0x15 }, /* COMS */ + { 0x10, 0x75 }, /* AEC Exposure time */ + { 0x12, 0x24 }, /* Enable AGC */ + { 0x14, 0x04 }, + /* 0x16: 0x06 helps frame stability with moving objects */ + { 0x16, 0x06 }, +/* { 0x20, 0x30 }, * Aperture correction enable */ + { 0x26, 0xb2 }, /* BLC enable */ + /* 0x28: 0x05 Selects RGB format if RGB on */ + { 0x28, 0x05 }, + { 0x2a, 0x04 }, /* Disable framerate adjust */ +/* { 0x2b, 0xac }, * Framerate; Set 2a[7] first */ + { 0x2d, 0x99 }, + { 0x33, 0xa0 }, /* Color Processing Parameter */ + { 0x34, 0xd2 }, /* Max A/D range */ + { 0x38, 0x8b }, + { 0x39, 0x40 }, + + { 0x3c, 0x39 }, /* Enable AEC mode changing */ + { 0x3c, 0x3c }, /* Change AEC mode */ + { 0x3c, 0x24 }, /* Disable AEC mode changing */ + + { 0x3d, 0x80 }, + /* These next two registers (0x4a, 0x4b) are undocumented. + * They control the color balance */ + { 0x4a, 0x80 }, + { 0x4b, 0x80 }, + { 0x4d, 0xd2 }, /* This reduces noise a bit */ + { 0x4e, 0xc1 }, + { 0x4f, 0x04 }, +/* Do 50-53 have any effect? */ +/* Toggle 0x12[2] off and on here? */ +}; + +static const struct ov_i2c_regvals norm_6x30[] = { + { 0x12, 0x80 }, /* Reset */ + { 0x00, 0x1f }, /* Gain */ + { 0x01, 0x99 }, /* Blue gain */ + { 0x02, 0x7c }, /* Red gain */ + { 0x03, 0xc0 }, /* Saturation */ + { 0x05, 0x0a }, /* Contrast */ + { 0x06, 0x95 }, /* Brightness */ + { 0x07, 0x2d }, /* Sharpness */ + { 0x0c, 0x20 }, + { 0x0d, 0x20 }, + { 0x0e, 0x20 }, + { 0x0f, 0x05 }, + { 0x10, 0x9a }, + { 0x11, 0x00 }, /* Pixel clock = fastest */ + { 0x12, 0x24 }, /* Enable AGC and AWB */ + { 0x13, 0x21 }, + { 0x14, 0x80 }, + { 0x15, 0x01 }, + { 0x16, 0x03 }, + { 0x17, 0x38 }, + { 0x18, 0xea }, + { 0x19, 0x04 }, + { 0x1a, 0x93 }, + { 0x1b, 0x00 }, + { 0x1e, 0xc4 }, + { 0x1f, 0x04 }, + { 0x20, 0x20 }, + { 0x21, 0x10 }, + { 0x22, 0x88 }, + { 0x23, 0xc0 }, /* Crystal circuit power level */ + { 0x25, 0x9a }, /* Increase AEC black ratio */ + { 0x26, 0xb2 }, /* BLC enable */ + { 0x27, 0xa2 }, + { 0x28, 0x00 }, + { 0x29, 0x00 }, + { 0x2a, 0x84 }, /* 60 Hz power */ + { 0x2b, 0xa8 }, /* 60 Hz power */ + { 0x2c, 0xa0 }, + { 0x2d, 0x95 }, /* Enable auto-brightness */ + { 0x2e, 0x88 }, + { 0x33, 0x26 }, + { 0x34, 0x03 }, + { 0x36, 0x8f }, + { 0x37, 0x80 }, + { 0x38, 0x83 }, + { 0x39, 0x80 }, + { 0x3a, 0x0f }, + { 0x3b, 0x3c }, + { 0x3c, 0x1a }, + { 0x3d, 0x80 }, + { 0x3e, 0x80 }, + { 0x3f, 0x0e }, + { 0x40, 0x00 }, /* White bal */ + { 0x41, 0x00 }, /* White bal */ + { 0x42, 0x80 }, + { 0x43, 0x3f }, /* White bal */ + { 0x44, 0x80 }, + { 0x45, 0x20 }, + { 0x46, 0x20 }, + { 0x47, 0x80 }, + { 0x48, 0x7f }, + { 0x49, 0x00 }, + { 0x4a, 0x00 }, + { 0x4b, 0x80 }, + { 0x4c, 0xd0 }, + { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */ + { 0x4e, 0x40 }, + { 0x4f, 0x07 }, /* UV avg., col. killer: max */ + { 0x50, 0xff }, + { 0x54, 0x23 }, /* Max AGC gain: 18dB */ + { 0x55, 0xff }, + { 0x56, 0x12 }, + { 0x57, 0x81 }, + { 0x58, 0x75 }, + { 0x59, 0x01 }, /* AGC dark current comp.: +1 */ + { 0x5a, 0x2c }, + { 0x5b, 0x0f }, /* AWB chrominance levels */ + { 0x5c, 0x10 }, + { 0x3d, 0x80 }, + { 0x27, 0xa6 }, + { 0x12, 0x20 }, /* Toggle AWB */ + { 0x12, 0x24 }, +}; + +/* Lawrence Glaister <lg@jfm.bc.ca> reports: + * + * Register 0x0f in the 7610 has the following effects: + * + * 0x85 (AEC method 1): Best overall, good contrast range + * 0x45 (AEC method 2): Very overexposed + * 0xa5 (spec sheet default): Ok, but the black level is + * shifted resulting in loss of contrast + * 0x05 (old driver setting): very overexposed, too much + * contrast + */ +static const struct ov_i2c_regvals norm_7610[] = { + { 0x10, 0xff }, + { 0x16, 0x06 }, + { 0x28, 0x24 }, + { 0x2b, 0xac }, + { 0x12, 0x00 }, + { 0x38, 0x81 }, + { 0x28, 0x24 }, /* 0c */ + { 0x0f, 0x85 }, /* lg's setting */ + { 0x15, 0x01 }, + { 0x20, 0x1c }, + { 0x23, 0x2a }, + { 0x24, 0x10 }, + { 0x25, 0x8a }, + { 0x26, 0xa2 }, + { 0x27, 0xc2 }, + { 0x2a, 0x04 }, + { 0x2c, 0xfe }, + { 0x2d, 0x93 }, + { 0x30, 0x71 }, + { 0x31, 0x60 }, + { 0x32, 0x26 }, + { 0x33, 0x20 }, + { 0x34, 0x48 }, + { 0x12, 0x24 }, + { 0x11, 0x01 }, + { 0x0c, 0x24 }, + { 0x0d, 0x24 }, +}; + +static const struct ov_i2c_regvals norm_7620[] = { + { 0x00, 0x00 }, /* gain */ + { 0x01, 0x80 }, /* blue gain */ + { 0x02, 0x80 }, /* red gain */ + { 0x03, 0xc0 }, /* OV7670_REG_VREF */ + { 0x06, 0x60 }, + { 0x07, 0x00 }, + { 0x0c, 0x24 }, + { 0x0c, 0x24 }, + { 0x0d, 0x24 }, + { 0x11, 0x01 }, + { 0x12, 0x24 }, + { 0x13, 0x01 }, + { 0x14, 0x84 }, + { 0x15, 0x01 }, + { 0x16, 0x03 }, + { 0x17, 0x2f }, + { 0x18, 0xcf }, + { 0x19, 0x06 }, + { 0x1a, 0xf5 }, + { 0x1b, 0x00 }, + { 0x20, 0x18 }, + { 0x21, 0x80 }, + { 0x22, 0x80 }, + { 0x23, 0x00 }, + { 0x26, 0xa2 }, + { 0x27, 0xea }, + { 0x28, 0x20 }, + { 0x29, 0x00 }, + { 0x2a, 0x10 }, + { 0x2b, 0x00 }, + { 0x2c, 0x88 }, + { 0x2d, 0x91 }, + { 0x2e, 0x80 }, + { 0x2f, 0x44 }, + { 0x60, 0x27 }, + { 0x61, 0x02 }, + { 0x62, 0x5f }, + { 0x63, 0xd5 }, + { 0x64, 0x57 }, + { 0x65, 0x83 }, + { 0x66, 0x55 }, + { 0x67, 0x92 }, + { 0x68, 0xcf }, + { 0x69, 0x76 }, + { 0x6a, 0x22 }, + { 0x6b, 0x00 }, + { 0x6c, 0x02 }, + { 0x6d, 0x44 }, + { 0x6e, 0x80 }, + { 0x6f, 0x1d }, + { 0x70, 0x8b }, + { 0x71, 0x00 }, + { 0x72, 0x14 }, + { 0x73, 0x54 }, + { 0x74, 0x00 }, + { 0x75, 0x8e }, + { 0x76, 0x00 }, + { 0x77, 0xff }, + { 0x78, 0x80 }, + { 0x79, 0x80 }, + { 0x7a, 0x80 }, + { 0x7b, 0xe2 }, + { 0x7c, 0x00 }, +}; + +/* 7640 and 7648. The defaults should be OK for most registers. */ +static const struct ov_i2c_regvals norm_7640[] = { + { 0x12, 0x80 }, + { 0x12, 0x14 }, +}; + +/* 7670. Defaults taken from OmniVision provided data, +* as provided by Jonathan Corbet of OLPC */ +static const struct ov_i2c_regvals norm_7670[] = { + { OV7670_REG_COM7, OV7670_COM7_RESET }, + { OV7670_REG_TSLB, 0x04 }, /* OV */ + { OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */ + { OV7670_REG_CLKRC, 0x01 }, +/* + * Set the hardware window. These values from OV don't entirely + * make sense - hstop is less than hstart. But they work... + */ + { OV7670_REG_HSTART, 0x13 }, + { OV7670_REG_HSTOP, 0x01 }, + { OV7670_REG_HREF, 0xb6 }, + { OV7670_REG_VSTART, 0x02 }, + { OV7670_REG_VSTOP, 0x7a }, + { OV7670_REG_VREF, 0x0a }, + + { OV7670_REG_COM3, 0 }, + { OV7670_REG_COM14, 0 }, +/* Mystery scaling numbers */ + { 0x70, 0x3a }, + { 0x71, 0x35 }, + { 0x72, 0x11 }, + { 0x73, 0xf0 }, + { 0xa2, 0x02 }, +/* { OV7670_REG_COM10, 0x0 }, */ + +/* Gamma curve values */ + { 0x7a, 0x20 }, + { 0x7b, 0x10 }, + { 0x7c, 0x1e }, + { 0x7d, 0x35 }, + { 0x7e, 0x5a }, + { 0x7f, 0x69 }, + { 0x80, 0x76 }, + { 0x81, 0x80 }, + { 0x82, 0x88 }, + { 0x83, 0x8f }, + { 0x84, 0x96 }, + { 0x85, 0xa3 }, + { 0x86, 0xaf }, + { 0x87, 0xc4 }, + { 0x88, 0xd7 }, + { 0x89, 0xe8 }, + +/* AGC and AEC parameters. Note we start by disabling those features, + then turn them only after tweaking the values. */ + { OV7670_REG_COM8, OV7670_COM8_FASTAEC + | OV7670_COM8_AECSTEP + | OV7670_COM8_BFILT }, + { OV7670_REG_GAIN, 0 }, + { OV7670_REG_AECH, 0 }, + { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */ + { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */ + { OV7670_REG_BD50MAX, 0x05 }, + { OV7670_REG_BD60MAX, 0x07 }, + { OV7670_REG_AEW, 0x95 }, + { OV7670_REG_AEB, 0x33 }, + { OV7670_REG_VPT, 0xe3 }, + { OV7670_REG_HAECC1, 0x78 }, + { OV7670_REG_HAECC2, 0x68 }, + { 0xa1, 0x03 }, /* magic */ + { OV7670_REG_HAECC3, 0xd8 }, + { OV7670_REG_HAECC4, 0xd8 }, + { OV7670_REG_HAECC5, 0xf0 }, + { OV7670_REG_HAECC6, 0x90 }, + { OV7670_REG_HAECC7, 0x94 }, + { OV7670_REG_COM8, OV7670_COM8_FASTAEC + | OV7670_COM8_AECSTEP + | OV7670_COM8_BFILT + | OV7670_COM8_AGC + | OV7670_COM8_AEC }, + +/* Almost all of these are magic "reserved" values. */ + { OV7670_REG_COM5, 0x61 }, + { OV7670_REG_COM6, 0x4b }, + { 0x16, 0x02 }, + { OV7670_REG_MVFP, 0x07 }, + { 0x21, 0x02 }, + { 0x22, 0x91 }, + { 0x29, 0x07 }, + { 0x33, 0x0b }, + { 0x35, 0x0b }, + { 0x37, 0x1d }, + { 0x38, 0x71 }, + { 0x39, 0x2a }, + { OV7670_REG_COM12, 0x78 }, + { 0x4d, 0x40 }, + { 0x4e, 0x20 }, + { OV7670_REG_GFIX, 0 }, + { 0x6b, 0x4a }, + { 0x74, 0x10 }, + { 0x8d, 0x4f }, + { 0x8e, 0 }, + { 0x8f, 0 }, + { 0x90, 0 }, + { 0x91, 0 }, + { 0x96, 0 }, + { 0x9a, 0 }, + { 0xb0, 0x84 }, + { 0xb1, 0x0c }, + { 0xb2, 0x0e }, + { 0xb3, 0x82 }, + { 0xb8, 0x0a }, + +/* More reserved magic, some of which tweaks white balance */ + { 0x43, 0x0a }, + { 0x44, 0xf0 }, + { 0x45, 0x34 }, + { 0x46, 0x58 }, + { 0x47, 0x28 }, + { 0x48, 0x3a }, + { 0x59, 0x88 }, + { 0x5a, 0x88 }, + { 0x5b, 0x44 }, + { 0x5c, 0x67 }, + { 0x5d, 0x49 }, + { 0x5e, 0x0e }, + { 0x6c, 0x0a }, + { 0x6d, 0x55 }, + { 0x6e, 0x11 }, + { 0x6f, 0x9f }, + /* "9e for advance AWB" */ + { 0x6a, 0x40 }, + { OV7670_REG_BLUE, 0x40 }, + { OV7670_REG_RED, 0x60 }, + { OV7670_REG_COM8, OV7670_COM8_FASTAEC + | OV7670_COM8_AECSTEP + | OV7670_COM8_BFILT + | OV7670_COM8_AGC + | OV7670_COM8_AEC + | OV7670_COM8_AWB }, + +/* Matrix coefficients */ + { 0x4f, 0x80 }, + { 0x50, 0x80 }, + { 0x51, 0 }, + { 0x52, 0x22 }, + { 0x53, 0x5e }, + { 0x54, 0x80 }, + { 0x58, 0x9e }, + + { OV7670_REG_COM16, OV7670_COM16_AWBGAIN }, + { OV7670_REG_EDGE, 0 }, + { 0x75, 0x05 }, + { 0x76, 0xe1 }, + { 0x4c, 0 }, + { 0x77, 0x01 }, + { OV7670_REG_COM13, OV7670_COM13_GAMMA + | OV7670_COM13_UVSAT + | 2}, /* was 3 */ + { 0x4b, 0x09 }, + { 0xc9, 0x60 }, + { OV7670_REG_COM16, 0x38 }, + { 0x56, 0x40 }, + + { 0x34, 0x11 }, + { OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO }, + { 0xa4, 0x88 }, + { 0x96, 0 }, + { 0x97, 0x30 }, + { 0x98, 0x20 }, + { 0x99, 0x30 }, + { 0x9a, 0x84 }, + { 0x9b, 0x29 }, + { 0x9c, 0x03 }, + { 0x9d, 0x4c }, + { 0x9e, 0x3f }, + { 0x78, 0x04 }, + +/* Extra-weird stuff. Some sort of multiplexor register */ + { 0x79, 0x01 }, + { 0xc8, 0xf0 }, + { 0x79, 0x0f }, + { 0xc8, 0x00 }, + { 0x79, 0x10 }, + { 0xc8, 0x7e }, + { 0x79, 0x0a }, + { 0xc8, 0x80 }, + { 0x79, 0x0b }, + { 0xc8, 0x01 }, + { 0x79, 0x0c }, + { 0xc8, 0x0f }, + { 0x79, 0x0d }, + { 0xc8, 0x20 }, + { 0x79, 0x09 }, + { 0xc8, 0x80 }, + { 0x79, 0x02 }, + { 0xc8, 0xc0 }, + { 0x79, 0x03 }, + { 0xc8, 0x40 }, + { 0x79, 0x05 }, + { 0xc8, 0x30 }, + { 0x79, 0x26 }, +}; + +static const struct ov_i2c_regvals norm_8610[] = { + { 0x12, 0x80 }, + { 0x00, 0x00 }, + { 0x01, 0x80 }, + { 0x02, 0x80 }, + { 0x03, 0xc0 }, + { 0x04, 0x30 }, + { 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */ + { 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */ + { 0x0a, 0x86 }, + { 0x0b, 0xb0 }, + { 0x0c, 0x20 }, + { 0x0d, 0x20 }, + { 0x11, 0x01 }, + { 0x12, 0x25 }, + { 0x13, 0x01 }, + { 0x14, 0x04 }, + { 0x15, 0x01 }, /* Lin and Win think different about UV order */ + { 0x16, 0x03 }, + { 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */ + { 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */ + { 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */ + { 0x1a, 0xf5 }, + { 0x1b, 0x00 }, + { 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */ + { 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */ + { 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */ + { 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */ + { 0x26, 0xa2 }, + { 0x27, 0xea }, + { 0x28, 0x00 }, + { 0x29, 0x00 }, + { 0x2a, 0x80 }, + { 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */ + { 0x2c, 0xac }, + { 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */ + { 0x2e, 0x80 }, + { 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */ + { 0x4c, 0x00 }, + { 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */ + { 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */ + { 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */ + { 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */ + { 0x63, 0xff }, + { 0x64, 0x53 }, /* new windrv 090403 says 0x57, + * maybe thats wrong */ + { 0x65, 0x00 }, + { 0x66, 0x55 }, + { 0x67, 0xb0 }, + { 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */ + { 0x69, 0x02 }, + { 0x6a, 0x22 }, + { 0x6b, 0x00 }, + { 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but + * deleting bit7 colors the first images red */ + { 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */ + { 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */ + { 0x6f, 0x01 }, + { 0x70, 0x8b }, + { 0x71, 0x00 }, + { 0x72, 0x14 }, + { 0x73, 0x54 }, + { 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */ + { 0x75, 0x0e }, + { 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */ + { 0x77, 0xff }, + { 0x78, 0x80 }, + { 0x79, 0x80 }, + { 0x7a, 0x80 }, + { 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */ + { 0x7c, 0x00 }, + { 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */ + { 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */ + { 0x7f, 0xfb }, + { 0x80, 0x28 }, + { 0x81, 0x00 }, + { 0x82, 0x23 }, + { 0x83, 0x0b }, + { 0x84, 0x00 }, + { 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */ + { 0x86, 0xc9 }, + { 0x87, 0x00 }, + { 0x88, 0x00 }, + { 0x89, 0x01 }, + { 0x12, 0x20 }, + { 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */ +}; + static unsigned char ov7670_abs_to_sm(unsigned char v) { if (v > 127) @@ -537,18 +1073,10 @@ static int ov51x_set_slave_ids(struct sd *sd, rc = reg_w(sd, R51x_I2C_W_SID, slave); if (rc < 0) return rc; + sd->primary_i2c_slave = slave; return reg_w(sd, R51x_I2C_R_SID, slave + 1); } -struct ov_regvals { - __u8 reg; - __u8 val; -}; -struct ov_i2c_regvals { - __u8 reg; - __u8 val; -}; - static int write_regvals(struct sd *sd, const struct ov_regvals *regvals, int n) @@ -591,101 +1119,9 @@ static int write_i2c_regvals(struct sd *sd, static int ov8xx0_configure(struct sd *sd) { int rc; - static const struct ov_i2c_regvals norm_8610[] = { - { 0x12, 0x80 }, - { 0x00, 0x00 }, - { 0x01, 0x80 }, - { 0x02, 0x80 }, - { 0x03, 0xc0 }, - { 0x04, 0x30 }, - { 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */ - { 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */ - { 0x0a, 0x86 }, - { 0x0b, 0xb0 }, - { 0x0c, 0x20 }, - { 0x0d, 0x20 }, - { 0x11, 0x01 }, - { 0x12, 0x25 }, - { 0x13, 0x01 }, - { 0x14, 0x04 }, - { 0x15, 0x01 }, /* Lin and Win think different about UV order */ - { 0x16, 0x03 }, - { 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */ - { 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */ - { 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */ - { 0x1a, 0xf5 }, - { 0x1b, 0x00 }, - { 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */ - { 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */ - { 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */ - { 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */ - { 0x26, 0xa2 }, - { 0x27, 0xea }, - { 0x28, 0x00 }, - { 0x29, 0x00 }, - { 0x2a, 0x80 }, - { 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */ - { 0x2c, 0xac }, - { 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */ - { 0x2e, 0x80 }, - { 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */ - { 0x4c, 0x00 }, - { 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */ - { 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */ - { 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */ - { 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */ - { 0x63, 0xff }, - { 0x64, 0x53 }, /* new windrv 090403 says 0x57, - * maybe thats wrong */ - { 0x65, 0x00 }, - { 0x66, 0x55 }, - { 0x67, 0xb0 }, - { 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */ - { 0x69, 0x02 }, - { 0x6a, 0x22 }, - { 0x6b, 0x00 }, - { 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but - deleting bit7 colors the first images red */ - { 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */ - { 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */ - { 0x6f, 0x01 }, - { 0x70, 0x8b }, - { 0x71, 0x00 }, - { 0x72, 0x14 }, - { 0x73, 0x54 }, - { 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */ - { 0x75, 0x0e }, - { 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */ - { 0x77, 0xff }, - { 0x78, 0x80 }, - { 0x79, 0x80 }, - { 0x7a, 0x80 }, - { 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */ - { 0x7c, 0x00 }, - { 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */ - { 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */ - { 0x7f, 0xfb }, - { 0x80, 0x28 }, - { 0x81, 0x00 }, - { 0x82, 0x23 }, - { 0x83, 0x0b }, - { 0x84, 0x00 }, - { 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */ - { 0x86, 0xc9 }, - { 0x87, 0x00 }, - { 0x88, 0x00 }, - { 0x89, 0x01 }, - { 0x12, 0x20 }, - { 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */ - }; PDEBUG(D_PROBE, "starting ov8xx0 configuration"); - if (init_ov_sensor(sd) < 0) - PDEBUG(D_ERR|D_PROBE, "Failed to read sensor ID"); - else - PDEBUG(D_PROBE, "OV86x0 initialized"); - /* Detect sensor (sub)type */ rc = i2c_r(sd, OV7610_REG_COM_I); if (rc < 0) { @@ -698,9 +1134,6 @@ static int ov8xx0_configure(struct sd *sd) PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3); return -1; } - PDEBUG(D_PROBE, "Writing 8610 registers"); - if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610))) - return -1; /* Set sensor-specific vars */ /* sd->sif = 0; already done */ @@ -714,252 +1147,6 @@ static int ov7xx0_configure(struct sd *sd) { int rc, high, low; - /* Lawrence Glaister <lg@jfm.bc.ca> reports: - * - * Register 0x0f in the 7610 has the following effects: - * - * 0x85 (AEC method 1): Best overall, good contrast range - * 0x45 (AEC method 2): Very overexposed - * 0xa5 (spec sheet default): Ok, but the black level is - * shifted resulting in loss of contrast - * 0x05 (old driver setting): very overexposed, too much - * contrast - */ - static const struct ov_i2c_regvals norm_7610[] = { - { 0x10, 0xff }, - { 0x16, 0x06 }, - { 0x28, 0x24 }, - { 0x2b, 0xac }, - { 0x12, 0x00 }, - { 0x38, 0x81 }, - { 0x28, 0x24 }, /* 0c */ - { 0x0f, 0x85 }, /* lg's setting */ - { 0x15, 0x01 }, - { 0x20, 0x1c }, - { 0x23, 0x2a }, - { 0x24, 0x10 }, - { 0x25, 0x8a }, - { 0x26, 0xa2 }, - { 0x27, 0xc2 }, - { 0x2a, 0x04 }, - { 0x2c, 0xfe }, - { 0x2d, 0x93 }, - { 0x30, 0x71 }, - { 0x31, 0x60 }, - { 0x32, 0x26 }, - { 0x33, 0x20 }, - { 0x34, 0x48 }, - { 0x12, 0x24 }, - { 0x11, 0x01 }, - { 0x0c, 0x24 }, - { 0x0d, 0x24 }, - }; - - static const struct ov_i2c_regvals norm_7620[] = { - { 0x00, 0x00 }, /* gain */ - { 0x01, 0x80 }, /* blue gain */ - { 0x02, 0x80 }, /* red gain */ - { 0x03, 0xc0 }, /* OV7670_REG_VREF */ - { 0x06, 0x60 }, - { 0x07, 0x00 }, - { 0x0c, 0x24 }, - { 0x0c, 0x24 }, - { 0x0d, 0x24 }, - { 0x11, 0x01 }, - { 0x12, 0x24 }, - { 0x13, 0x01 }, - { 0x14, 0x84 }, - { 0x15, 0x01 }, - { 0x16, 0x03 }, - { 0x17, 0x2f }, - { 0x18, 0xcf }, - { 0x19, 0x06 }, - { 0x1a, 0xf5 }, - { 0x1b, 0x00 }, - { 0x20, 0x18 }, - { 0x21, 0x80 }, - { 0x22, 0x80 }, - { 0x23, 0x00 }, - { 0x26, 0xa2 }, - { 0x27, 0xea }, - { 0x28, 0x20 }, - { 0x29, 0x00 }, - { 0x2a, 0x10 }, - { 0x2b, 0x00 }, - { 0x2c, 0x88 }, - { 0x2d, 0x91 }, - { 0x2e, 0x80 }, - { 0x2f, 0x44 }, - { 0x60, 0x27 }, - { 0x61, 0x02 }, - { 0x62, 0x5f }, - { 0x63, 0xd5 }, - { 0x64, 0x57 }, - { 0x65, 0x83 }, - { 0x66, 0x55 }, - { 0x67, 0x92 }, - { 0x68, 0xcf }, - { 0x69, 0x76 }, - { 0x6a, 0x22 }, - { 0x6b, 0x00 }, - { 0x6c, 0x02 }, - { 0x6d, 0x44 }, - { 0x6e, 0x80 }, - { 0x6f, 0x1d }, - { 0x70, 0x8b }, - { 0x71, 0x00 }, - { 0x72, 0x14 }, - { 0x73, 0x54 }, - { 0x74, 0x00 }, - { 0x75, 0x8e }, - { 0x76, 0x00 }, - { 0x77, 0xff }, - { 0x78, 0x80 }, - { 0x79, 0x80 }, - { 0x7a, 0x80 }, - { 0x7b, 0xe2 }, - { 0x7c, 0x00 }, - }; - - /* 7640 and 7648. The defaults should be OK for most registers. */ - static const struct ov_i2c_regvals norm_7640[] = { - { 0x12, 0x80 }, - { 0x12, 0x14 }, - }; - - /* 7670. Defaults taken from OmniVision provided data, - * as provided by Jonathan Corbet of OLPC */ - static const struct ov_i2c_regvals norm_7670[] = { - { OV7670_REG_COM7, OV7670_COM7_RESET }, - { OV7670_REG_TSLB, 0x04 }, /* OV */ - { OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */ - { OV7670_REG_CLKRC, 0x01 }, - /* - * Set the hardware window. These values from OV don't entirely - * make sense - hstop is less than hstart. But they work... - */ - { OV7670_REG_HSTART, 0x13 }, { OV7670_REG_HSTOP, 0x01 }, - { OV7670_REG_HREF, 0xb6 }, { OV7670_REG_VSTART, 0x02 }, - { OV7670_REG_VSTOP, 0x7a }, { OV7670_REG_VREF, 0x0a }, - - { OV7670_REG_COM3, 0 }, { OV7670_REG_COM14, 0 }, - /* Mystery scaling numbers */ - { 0x70, 0x3a }, { 0x71, 0x35 }, - { 0x72, 0x11 }, { 0x73, 0xf0 }, - { 0xa2, 0x02 }, -/* { OV7670_REG_COM10, 0x0 }, */ - - /* Gamma curve values */ - { 0x7a, 0x20 }, - { 0x7b, 0x10 }, - { 0x7c, 0x1e }, - { 0x7d, 0x35 }, - { 0x7e, 0x5a }, { 0x7f, 0x69 }, - { 0x80, 0x76 }, { 0x81, 0x80 }, - { 0x82, 0x88 }, { 0x83, 0x8f }, - { 0x84, 0x96 }, { 0x85, 0xa3 }, - { 0x86, 0xaf }, { 0x87, 0xc4 }, - { 0x88, 0xd7 }, { 0x89, 0xe8 }, - - /* AGC and AEC parameters. Note we start by disabling those features, - then turn them only after tweaking the values. */ - { OV7670_REG_COM8, OV7670_COM8_FASTAEC - | OV7670_COM8_AECSTEP - | OV7670_COM8_BFILT }, - { OV7670_REG_GAIN, 0 }, { OV7670_REG_AECH, 0 }, - { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */ - { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */ - { OV7670_REG_BD50MAX, 0x05 }, { OV7670_REG_BD60MAX, 0x07 }, - { OV7670_REG_AEW, 0x95 }, { OV7670_REG_AEB, 0x33 }, - { OV7670_REG_VPT, 0xe3 }, { OV7670_REG_HAECC1, 0x78 }, - { OV7670_REG_HAECC2, 0x68 }, - { 0xa1, 0x03 }, /* magic */ - { OV7670_REG_HAECC3, 0xd8 }, { OV7670_REG_HAECC4, 0xd8 }, - { OV7670_REG_HAECC5, 0xf0 }, { OV7670_REG_HAECC6, 0x90 }, - { OV7670_REG_HAECC7, 0x94 }, - { OV7670_REG_COM8, OV7670_COM8_FASTAEC - | OV7670_COM8_AECSTEP - | OV7670_COM8_BFILT - | OV7670_COM8_AGC - | OV7670_COM8_AEC }, - - /* Almost all of these are magic "reserved" values. */ - { OV7670_REG_COM5, 0x61 }, { OV7670_REG_COM6, 0x4b }, - { 0x16, 0x02 }, - { OV7670_REG_MVFP, 0x07 }, - { 0x21, 0x02 }, { 0x22, 0x91 }, - { 0x29, 0x07 }, { 0x33, 0x0b }, - { 0x35, 0x0b }, { 0x37, 0x1d }, - { 0x38, 0x71 }, { 0x39, 0x2a }, - { OV7670_REG_COM12, 0x78 }, { 0x4d, 0x40 }, - { 0x4e, 0x20 }, { OV7670_REG_GFIX, 0 }, - { 0x6b, 0x4a }, { 0x74, 0x10 }, - { 0x8d, 0x4f }, { 0x8e, 0 }, - { 0x8f, 0 }, { 0x90, 0 }, - { 0x91, 0 }, { 0x96, 0 }, - { 0x9a, 0 }, { 0xb0, 0x84 }, - { 0xb1, 0x0c }, { 0xb2, 0x0e }, - { 0xb3, 0x82 }, { 0xb8, 0x0a }, - - /* More reserved magic, some of which tweaks white balance */ - { 0x43, 0x0a }, { 0x44, 0xf0 }, - { 0x45, 0x34 }, { 0x46, 0x58 }, - { 0x47, 0x28 }, { 0x48, 0x3a }, - { 0x59, 0x88 }, { 0x5a, 0x88 }, - { 0x5b, 0x44 }, { 0x5c, 0x67 }, - { 0x5d, 0x49 }, { 0x5e, 0x0e }, - { 0x6c, 0x0a }, { 0x6d, 0x55 }, - { 0x6e, 0x11 }, { 0x6f, 0x9f }, - /* "9e for advance AWB" */ - { 0x6a, 0x40 }, { OV7670_REG_BLUE, 0x40 }, - { OV7670_REG_RED, 0x60 }, - { OV7670_REG_COM8, OV7670_COM8_FASTAEC - | OV7670_COM8_AECSTEP - | OV7670_COM8_BFILT - | OV7670_COM8_AGC - | OV7670_COM8_AEC - | OV7670_COM8_AWB }, - - /* Matrix coefficients */ - { 0x4f, 0x80 }, { 0x50, 0x80 }, - { 0x51, 0 }, { 0x52, 0x22 }, - { 0x53, 0x5e }, { 0x54, 0x80 }, - { 0x58, 0x9e }, - - { OV7670_REG_COM16, OV7670_COM16_AWBGAIN }, - { OV7670_REG_EDGE, 0 }, - { 0x75, 0x05 }, { 0x76, 0xe1 }, - { 0x4c, 0 }, { 0x77, 0x01 }, - { OV7670_REG_COM13, OV7670_COM13_GAMMA - | OV7670_COM13_UVSAT - | 2}, /* was 3 */ - { 0x4b, 0x09 }, - { 0xc9, 0x60 }, { OV7670_REG_COM16, 0x38 }, - { 0x56, 0x40 }, - - { 0x34, 0x11 }, - { OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO }, - { 0xa4, 0x88 }, { 0x96, 0 }, - { 0x97, 0x30 }, { 0x98, 0x20 }, - { 0x99, 0x30 }, { 0x9a, 0x84 }, - { 0x9b, 0x29 }, { 0x9c, 0x03 }, - { 0x9d, 0x4c }, { 0x9e, 0x3f }, - { 0x78, 0x04 }, - - /* Extra-weird stuff. Some sort of multiplexor register */ - { 0x79, 0x01 }, { 0xc8, 0xf0 }, - { 0x79, 0x0f }, { 0xc8, 0x00 }, - { 0x79, 0x10 }, { 0xc8, 0x7e }, - { 0x79, 0x0a }, { 0xc8, 0x80 }, - { 0x79, 0x0b }, { 0xc8, 0x01 }, - { 0x79, 0x0c }, { 0xc8, 0x0f }, - { 0x79, 0x0d }, { 0xc8, 0x20 }, - { 0x79, 0x09 }, { 0xc8, 0x80 }, - { 0x79, 0x02 }, { 0xc8, 0xc0 }, - { 0x79, 0x03 }, { 0xc8, 0x40 }, - { 0x79, 0x05 }, { 0xc8, 0x30 }, - { 0x79, 0x26 }, - }; PDEBUG(D_PROBE, "starting OV7xx0 configuration"); @@ -1011,8 +1198,9 @@ static int ov7xx0_configure(struct sd *sd) switch (low) { case 0x30: PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635"); - sd->sensor = SEN_OV7630; - break; + PDEBUG(D_ERR, + "7630 is not supported by this driver"); + return -1; case 0x40: PDEBUG(D_PROBE, "Sensor is an OV7645"); sd->sensor = SEN_OV7640; /* FIXME */ @@ -1038,32 +1226,6 @@ static int ov7xx0_configure(struct sd *sd) return -1; } - switch (sd->sensor) { - case SEN_OV7620: - PDEBUG(D_PROBE, "Writing 7620 registers"); - if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620))) - return -1; - break; - case SEN_OV7630: - PDEBUG(D_ERR, "7630 is not supported by this driver version"); - return -1; - case SEN_OV7640: - PDEBUG(D_PROBE, "Writing 7640 registers"); - if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640))) - return -1; - break; - case SEN_OV7670: - PDEBUG(D_PROBE, "Writing 7670 registers"); - if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670))) - return -1; - break; - default: - PDEBUG(D_PROBE, "Writing 7610 registers"); - if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610))) - return -1; - break; - } - /* Set sensor-specific vars */ /* sd->sif = 0; already done */ return 0; @@ -1073,141 +1235,7 @@ static int ov7xx0_configure(struct sd *sd) static int ov6xx0_configure(struct sd *sd) { int rc; - static const struct ov_i2c_regvals norm_6x20[] = { - { 0x12, 0x80 }, /* reset */ - { 0x11, 0x01 }, - { 0x03, 0x60 }, - { 0x05, 0x7f }, /* For when autoadjust is off */ - { 0x07, 0xa8 }, - /* The ratio of 0x0c and 0x0d controls the white point */ - { 0x0c, 0x24 }, - { 0x0d, 0x24 }, - { 0x0f, 0x15 }, /* COMS */ - { 0x10, 0x75 }, /* AEC Exposure time */ - { 0x12, 0x24 }, /* Enable AGC */ - { 0x14, 0x04 }, - /* 0x16: 0x06 helps frame stability with moving objects */ - { 0x16, 0x06 }, -/* { 0x20, 0x30 }, * Aperture correction enable */ - { 0x26, 0xb2 }, /* BLC enable */ - /* 0x28: 0x05 Selects RGB format if RGB on */ - { 0x28, 0x05 }, - { 0x2a, 0x04 }, /* Disable framerate adjust */ -/* { 0x2b, 0xac }, * Framerate; Set 2a[7] first */ - { 0x2d, 0x99 }, - { 0x33, 0xa0 }, /* Color Processing Parameter */ - { 0x34, 0xd2 }, /* Max A/D range */ - { 0x38, 0x8b }, - { 0x39, 0x40 }, - - { 0x3c, 0x39 }, /* Enable AEC mode changing */ - { 0x3c, 0x3c }, /* Change AEC mode */ - { 0x3c, 0x24 }, /* Disable AEC mode changing */ - - { 0x3d, 0x80 }, - /* These next two registers (0x4a, 0x4b) are undocumented. - * They control the color balance */ - { 0x4a, 0x80 }, - { 0x4b, 0x80 }, - { 0x4d, 0xd2 }, /* This reduces noise a bit */ - { 0x4e, 0xc1 }, - { 0x4f, 0x04 }, -/* Do 50-53 have any effect? */ -/* Toggle 0x12[2] off and on here? */ - }; - - static const struct ov_i2c_regvals norm_6x30[] = { - { 0x12, 0x80 }, /* Reset */ - { 0x00, 0x1f }, /* Gain */ - { 0x01, 0x99 }, /* Blue gain */ - { 0x02, 0x7c }, /* Red gain */ - { 0x03, 0xc0 }, /* Saturation */ - { 0x05, 0x0a }, /* Contrast */ - { 0x06, 0x95 }, /* Brightness */ - { 0x07, 0x2d }, /* Sharpness */ - { 0x0c, 0x20 }, - { 0x0d, 0x20 }, - { 0x0e, 0x20 }, - { 0x0f, 0x05 }, - { 0x10, 0x9a }, - { 0x11, 0x00 }, /* Pixel clock = fastest */ - { 0x12, 0x24 }, /* Enable AGC and AWB */ - { 0x13, 0x21 }, - { 0x14, 0x80 }, - { 0x15, 0x01 }, - { 0x16, 0x03 }, - { 0x17, 0x38 }, - { 0x18, 0xea }, - { 0x19, 0x04 }, - { 0x1a, 0x93 }, - { 0x1b, 0x00 }, - { 0x1e, 0xc4 }, - { 0x1f, 0x04 }, - { 0x20, 0x20 }, - { 0x21, 0x10 }, - { 0x22, 0x88 }, - { 0x23, 0xc0 }, /* Crystal circuit power level */ - { 0x25, 0x9a }, /* Increase AEC black ratio */ - { 0x26, 0xb2 }, /* BLC enable */ - { 0x27, 0xa2 }, - { 0x28, 0x00 }, - { 0x29, 0x00 }, - { 0x2a, 0x84 }, /* 60 Hz power */ - { 0x2b, 0xa8 }, /* 60 Hz power */ - { 0x2c, 0xa0 }, - { 0x2d, 0x95 }, /* Enable auto-brightness */ - { 0x2e, 0x88 }, - { 0x33, 0x26 }, - { 0x34, 0x03 }, - { 0x36, 0x8f }, - { 0x37, 0x80 }, - { 0x38, 0x83 }, - { 0x39, 0x80 }, - { 0x3a, 0x0f }, - { 0x3b, 0x3c }, - { 0x3c, 0x1a }, - { 0x3d, 0x80 }, - { 0x3e, 0x80 }, - { 0x3f, 0x0e }, - { 0x40, 0x00 }, /* White bal */ - { 0x41, 0x00 }, /* White bal */ - { 0x42, 0x80 }, - { 0x43, 0x3f }, /* White bal */ - { 0x44, 0x80 }, - { 0x45, 0x20 }, - { 0x46, 0x20 }, - { 0x47, 0x80 }, - { 0x48, 0x7f }, - { 0x49, 0x00 }, - { 0x4a, 0x00 }, - { 0x4b, 0x80 }, - { 0x4c, 0xd0 }, - { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */ - { 0x4e, 0x40 }, - { 0x4f, 0x07 }, /* UV avg., col. killer: max */ - { 0x50, 0xff }, - { 0x54, 0x23 }, /* Max AGC gain: 18dB */ - { 0x55, 0xff }, - { 0x56, 0x12 }, - { 0x57, 0x81 }, - { 0x58, 0x75 }, - { 0x59, 0x01 }, /* AGC dark current comp.: +1 */ - { 0x5a, 0x2c }, - { 0x5b, 0x0f }, /* AWB chrominance levels */ - { 0x5c, 0x10 }, - { 0x3d, 0x80 }, - { 0x27, 0xa6 }, - { 0x12, 0x20 }, /* Toggle AWB */ - { 0x12, 0x24 }, - }; - - PDEBUG(D_PROBE, "starting sensor configuration"); - - if (init_ov_sensor(sd) < 0) { - PDEBUG(D_ERR, "Failed to read sensor ID."); - return -1; - } - PDEBUG(D_PROBE, "OV6xx0 sensor detected"); + PDEBUG(D_PROBE, "starting OV6xx0 configuration"); /* Detect sensor (sub)type */ rc = i2c_r(sd, OV7610_REG_COM_I); @@ -1251,15 +1279,6 @@ static int ov6xx0_configure(struct sd *sd) /* Set sensor-specific vars */ sd->sif = 1; - if (sd->sensor == SEN_OV6620) { - PDEBUG(D_PROBE, "Writing 6x20 registers"); - if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20))) - return -1; - } else { - PDEBUG(D_PROBE, "Writing 6x30 registers"); - if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30))) - return -1; - } return 0; } @@ -1298,22 +1317,31 @@ static int sd_config(struct gspca_dev *gspca_dev, ov51x_led_control(sd, 0); /* turn LED off */ /* Test for 76xx */ - sd->primary_i2c_slave = OV7xx0_SID; if (ov51x_set_slave_ids(sd, OV7xx0_SID) < 0) goto error; /* The OV519 must be more aggressive about sensor detection since * I2C write will never fail if the sensor is not present. We have * to try to initialize the sensor to detect its presence */ - if (init_ov_sensor(sd) < 0) { + if (init_ov_sensor(sd) >= 0) { + if (ov7xx0_configure(sd) < 0) { + PDEBUG(D_ERR, "Failed to configure OV7xx0"); + goto error; + } + } else { + /* Test for 6xx0 */ - sd->primary_i2c_slave = OV6xx0_SID; if (ov51x_set_slave_ids(sd, OV6xx0_SID) < 0) goto error; - if (init_ov_sensor(sd) < 0) { + if (init_ov_sensor(sd) >= 0) { + if (ov6xx0_configure(sd) < 0) { + PDEBUG(D_ERR, "Failed to configure OV6xx0"); + goto error; + } + } else { + /* Test for 8xx0 */ - sd->primary_i2c_slave = OV8xx0_SID; if (ov51x_set_slave_ids(sd, OV8xx0_SID) < 0) goto error; @@ -1321,24 +1349,13 @@ static int sd_config(struct gspca_dev *gspca_dev, PDEBUG(D_ERR, "Can't determine sensor slave IDs"); goto error; - } else { - if (ov8xx0_configure(sd) < 0) { - PDEBUG(D_ERR, - "Failed to configure OV8xx0 sensor"); - goto error; - } } - } else { - if (ov6xx0_configure(sd) < 0) { - PDEBUG(D_ERR, "Failed to configure OV6xx0"); + if (ov8xx0_configure(sd) < 0) { + PDEBUG(D_ERR, + "Failed to configure OV8xx0 sensor"); goto error; } } - } else { - if (ov7xx0_configure(sd) < 0) { - PDEBUG(D_ERR, "Failed to configure OV7xx0"); - goto error; - } } cam = &gspca_dev->cam; @@ -1355,15 +1372,53 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->colors = COLOR_DEF; sd->hflip = HFLIP_DEF; sd->vflip = VFLIP_DEF; + if (sd->sensor != SEN_OV7670) + gspca_dev->ctrl_dis = (1 << HFLIP_IDX) + | (1 << VFLIP_IDX); return 0; error: PDEBUG(D_ERR, "OV519 Config failed"); return -EBUSY; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; + + /* initialize the sensor */ + switch (sd->sensor) { + case SEN_OV6620: + if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20))) + return -EIO; + break; + case SEN_OV6630: + if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30))) + return -EIO; + break; + default: +/* case SEN_OV7610: */ +/* case SEN_OV76BE: */ + if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610))) + return -EIO; + break; + case SEN_OV7620: + if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620))) + return -EIO; + break; + case SEN_OV7640: + if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640))) + return -EIO; + break; + case SEN_OV7670: + if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670))) + return -EIO; + break; + case SEN_OV8610: + if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610))) + return -EIO; + break; + } return 0; } @@ -1827,14 +1882,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) ov51x_led_control((struct sd *) gspca_dev, 0); } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -2091,11 +2138,9 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; @@ -2132,6 +2177,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c index 7ef18d578811..83b5f740c947 100644 --- a/drivers/media/video/gspca/pac207.c +++ b/drivers/media/video/gspca/pac207.c @@ -56,12 +56,6 @@ MODULE_LICENSE("GPL"); #define PAC207_GAIN_KNEE 20 #define PAC207_AUTOGAIN_DEADZONE 30 -/* We calculating the autogain at the end of the transfer of a frame, at this - moment a frame with the old settings is being transmitted, and a frame is - being captured with the old settings. So if we adjust the autogain we must - ignore atleast the 2 next frames for the new settings to come into effect - before doing any other adjustments */ -#define PAC207_AUTOGAIN_IGNORE_FRAMES 3 /* specific webcam descriptor */ struct sd { @@ -131,7 +125,8 @@ static struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 1, .step = 1, - .default_value = 1, +#define AUTOGAIN_DEF 1 + .default_value = AUTOGAIN_DEF, .flags = 0, }, .set = sd_setautogain, @@ -181,9 +176,6 @@ static const __u8 pac207_sensor_init[][8] = { /* 48 reg_72 Rate Control end BalSize_4a =0x36 */ static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 }; -static const unsigned char pac207_sof_marker[5] = - { 0xff, 0xff, 0x00, 0xff, 0x96 }; - static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index, const u8 *buffer, u16 length) { @@ -259,35 +251,32 @@ static int sd_config(struct gspca_dev *gspca_dev, return -ENODEV; } - pac207_write_reg(gspca_dev, 0x41, 0x00); - /* Bit_0=Image Format, - * Bit_1=LED, - * Bit_2=Compression test mode enable */ - pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ - pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */ - PDEBUG(D_PROBE, "Pixart PAC207BCA Image Processor and Control Chip detected" " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x05; cam->cam_mode = sif_mode; cam->nmodes = ARRAY_SIZE(sif_mode); sd->brightness = PAC207_BRIGHTNESS_DEFAULT; sd->exposure = PAC207_EXPOSURE_DEFAULT; sd->gain = PAC207_GAIN_DEFAULT; + sd->autogain = AUTOGAIN_DEF; return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; + pac207_write_reg(gspca_dev, 0x41, 0x00); + /* Bit_0=Image Format, + * Bit_1=LED, + * Bit_2=Compression test mode enable */ + pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ + pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */ - sd->autogain = 1; return 0; } @@ -343,14 +332,8 @@ static void sd_stopN(struct gspca_dev *gspca_dev) pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -/* this function is called at close time */ -static void sd_close(struct gspca_dev *gspca_dev) -{ -} +/* Include pac common sof detection functions */ +#include "pac_common.h" static void pac207_do_auto_gain(struct gspca_dev *gspca_dev) { @@ -365,33 +348,7 @@ static void pac207_do_auto_gain(struct gspca_dev *gspca_dev) else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, 100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE, PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE)) - sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES; -} - -static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev, - unsigned char *m, int len) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - - /* Search for the SOF marker (fixed part) in the header */ - for (i = 0; i < len; i++) { - if (m[i] == pac207_sof_marker[sd->sof_read]) { - sd->sof_read++; - if (sd->sof_read == sizeof(pac207_sof_marker)) { - PDEBUG(D_STREAM, - "SOF found, bytes to analyze: %u." - " Frame starts at byte #%u", - len, i + 1); - sd->sof_read = 0; - return m + i + 1; - } - } else { - sd->sof_read = 0; - } - } - - return NULL; + sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; } static void sd_pkt_scan(struct gspca_dev *gspca_dev, @@ -402,14 +359,14 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; unsigned char *sof; - sof = pac207_find_sof(gspca_dev, data, len); + sof = pac_find_sof(gspca_dev, data, len); if (sof) { int n; /* finish decoding current frame */ n = sof - data; - if (n > sizeof pac207_sof_marker) - n -= sizeof pac207_sof_marker; + if (n > sizeof pac_sof_marker) + n -= sizeof pac_sof_marker; else n = 0; frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, @@ -537,7 +494,7 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) sd->gain = PAC207_GAIN_DEFAULT; if (gspca_dev->streaming) { sd->autogain_ignore_frames = - PAC207_AUTOGAIN_IGNORE_FRAMES; + PAC_AUTOGAIN_IGNORE_FRAMES; setexposure(gspca_dev); setgain(gspca_dev); } @@ -560,11 +517,9 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .dq_callback = pac207_do_auto_gain, .pkt_scan = sd_pkt_scan, }; @@ -597,6 +552,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c index 815bea6edc44..d4be51843286 100644 --- a/drivers/media/video/gspca/pac7311.c +++ b/drivers/media/video/gspca/pac7311.c @@ -19,6 +19,36 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* Some documentation about various registers as determined by trial and error. + When the register addresses differ between the 7202 and the 7311 the 2 + different addresses are written as 7302addr/7311addr, when one of the 2 + addresses is a - sign that register description is not valid for the + matching IC. + + Register page 1: + + Address Description + -/0x08 Unknown compressor related, must always be 8 except when not + in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 ! + -/0x1b Auto white balance related, bit 0 is AWB enable (inverted) + bits 345 seem to toggle per color gains on/off (inverted) + 0x78 Global control, bit 6 controls the LED (inverted) + -/0x80 JPEG compression ratio ? Best not touched + + Register page 3/4: + + Address Description + 0x02 Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on + the 7302, so one of 3, 6, 9, ..., except when between 6 and 12? + -/0x0f Master gain 1-245, low value = high gain + 0x10/- Master gain 0-31 + -/0x10 Another gain 0-15, limited influence (1-2x gain I guess) + 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused + -/0x27 Seems to toggle various gains on / off, Setting bit 7 seems to + completely disable the analog amplification block. Set to 0x68 + for max gain, 0x14 for minimal gain. +*/ + #define MODULE_NAME "pac7311" #include "gspca.h" @@ -31,18 +61,23 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - int lum_sum; - atomic_t avg_lum; - atomic_t do_gain; - unsigned char brightness; unsigned char contrast; unsigned char colors; + unsigned char gain; + unsigned char exposure; unsigned char autogain; + __u8 hflip; + __u8 vflip; + + __u8 sensor; +#define SENSOR_PAC7302 0 +#define SENSOR_PAC7311 1 - char ffseq; - signed char ag_cnt; -#define AG_CNT_START 13 + u8 sof_read; + u8 autogain_ignore_frames; + + atomic_t avg_lum; }; /* V4L2 controls supported by the driver */ @@ -54,8 +89,18 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); +static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); static struct ctrl sd_ctrls[] = { +/* This control is pac7302 only */ +#define BRIGHTNESS_IDX 0 { { .id = V4L2_CID_BRIGHTNESS, @@ -71,13 +116,15 @@ static struct ctrl sd_ctrls[] = { .set = sd_setbrightness, .get = sd_getbrightness, }, +/* This control is for both the 7302 and the 7311 */ { { .id = V4L2_CID_CONTRAST, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Contrast", .minimum = 0, - .maximum = 255, +#define CONTRAST_MAX 255 + .maximum = CONTRAST_MAX, .step = 1, #define CONTRAST_DEF 127 .default_value = CONTRAST_DEF, @@ -85,13 +132,16 @@ static struct ctrl sd_ctrls[] = { .set = sd_setcontrast, .get = sd_getcontrast, }, +/* This control is pac7302 only */ +#define SATURATION_IDX 2 { { .id = V4L2_CID_SATURATION, .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", + .name = "Saturation", .minimum = 0, - .maximum = 255, +#define COLOR_MAX 255 + .maximum = COLOR_MAX, .step = 1, #define COLOR_DEF 127 .default_value = COLOR_DEF, @@ -99,6 +149,39 @@ static struct ctrl sd_ctrls[] = { .set = sd_setcolors, .get = sd_getcolors, }, +/* All controls below are for both the 7302 and the 7311 */ + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, +#define GAIN_MAX 255 + .maximum = GAIN_MAX, + .step = 1, +#define GAIN_DEF 127 +#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */ + .default_value = GAIN_DEF, + }, + .set = sd_setgain, + .get = sd_getgain, + }, + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, +#define EXPOSURE_MAX 255 + .maximum = EXPOSURE_MAX, + .step = 1, +#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */ +#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */ + .default_value = EXPOSURE_DEF, + }, + .set = sd_setexposure, + .get = sd_getexposure, + }, { { .id = V4L2_CID_AUTOGAIN, @@ -113,101 +196,207 @@ static struct ctrl sd_ctrls[] = { .set = sd_setautogain, .get = sd_getautogain, }, + { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror", + .minimum = 0, + .maximum = 1, + .step = 1, +#define HFLIP_DEF 0 + .default_value = HFLIP_DEF, + }, + .set = sd_sethflip, + .get = sd_gethflip, + }, + { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vflip", + .minimum = 0, + .maximum = 1, + .step = 1, +#define VFLIP_DEF 0 + .default_value = VFLIP_DEF, + }, + .set = sd_setvflip, + .get = sd_getvflip, + }, }; static struct v4l2_pix_format vga_mode[] = { - {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, .bytesperline = 160, .sizeimage = 160 * 120 * 3 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 2}, - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, .bytesperline = 320, .sizeimage = 320 * 240 * 3 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 1}, - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, .bytesperline = 640, .sizeimage = 640 * 480 * 3 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 0}, }; -#define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header) /* (594) */ - -static const __u8 pac7311_jpeg_header[] = { - 0xff, 0xd8, - 0xff, 0xe0, 0x00, 0x03, 0x20, - 0xff, 0xc0, 0x00, 0x11, 0x08, - 0x01, 0xe0, /* 12: height */ - 0x02, 0x80, /* 14: width */ - 0x03, /* 16 */ - 0x01, 0x21, 0x00, - 0x02, 0x11, 0x01, - 0x03, 0x11, 0x01, - 0xff, 0xdb, 0x00, 0x84, - 0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d, - 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16, - 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d, - 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, - 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f, - 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64, - 0x78, 0x5c, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, 0x12, 0x18, - 0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, - 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, - 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, - 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, - 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, - 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, - 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, - 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, - 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, - 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, - 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, - 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, - 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, - 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, - 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, - 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, - 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, - 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, - 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, - 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, - 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, - 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, - 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, - 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, - 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, - 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, - 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, - 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, - 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, - 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, - 0x11, 0x00, 0x3f, 0x00 +/* pac 7302 */ +static const __u8 init_7302[] = { +/* index,value */ + 0xff, 0x01, /* page 1 */ + 0x78, 0x00, /* deactivate */ + 0xff, 0x01, + 0x78, 0x40, /* led off */ +}; +static const __u8 start_7302[] = { +/* index, len, [value]* */ + 0xff, 1, 0x00, /* page 0 */ + 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80, + 0x00, 0x00, 0x00, 0x00, + 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00, + 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7, + 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11, + 0x26, 2, 0xaa, 0xaa, + 0x2e, 1, 0x31, + 0x38, 1, 0x01, + 0x3a, 3, 0x14, 0xff, 0x5a, + 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11, + 0x00, 0x54, 0x11, + 0x55, 1, 0x00, + 0x62, 4, 0x10, 0x1e, 0x1e, 0x18, + 0x6b, 1, 0x00, + 0x6e, 3, 0x08, 0x06, 0x00, + 0x72, 3, 0x00, 0xff, 0x00, + 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c, + 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50, + 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00, + 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9, + 0xd2, 0xeb, + 0xaf, 1, 0x02, + 0xb5, 2, 0x08, 0x08, + 0xb8, 2, 0x08, 0x88, + 0xc4, 4, 0xae, 0x01, 0x04, 0x01, + 0xcc, 1, 0x00, + 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9, + 0xc1, 0xd7, 0xec, + 0xdc, 1, 0x01, + 0xff, 1, 0x01, /* page 1 */ + 0x12, 3, 0x02, 0x00, 0x01, + 0x3e, 2, 0x00, 0x00, + 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2, + 0x7c, 1, 0x00, + 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20, + 0x02, 0x00, + 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04, + 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x07, 0x00, 0x01, 0x07, 0x04, 0x01, + 0xd8, 1, 0x01, + 0xdb, 2, 0x00, 0x01, + 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00, + 0xe6, 4, 0x00, 0x00, 0x00, 0x01, + 0xeb, 1, 0x00, + 0xff, 1, 0x02, /* page 2 */ + 0x22, 1, 0x00, + 0xff, 1, 0x03, /* page 3 */ + 0x00, 255, /* load the page 3 */ + 0x11, 1, 0x01, + 0xff, 1, 0x02, /* page 2 */ + 0x13, 1, 0x00, + 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96, + 0x27, 2, 0x14, 0x0c, + 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22, + 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44, + 0x6e, 1, 0x08, + 0xff, 1, 0x01, /* page 1 */ + 0x78, 1, 0x00, + 0, 0 /* end of sequence */ +}; + +/* page 3 - the value 0xaa says skip the index - see reg_w_page() */ +static const __u8 page3_7302[] = { + 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16, + 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00, + 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21, + 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54, + 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8, + 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, + 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00, + 0x00 +}; + +/* pac 7311 */ +static const __u8 init_7311[] = { + 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */ + 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */ + 0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */ + 0xff, 0x04, + 0x27, 0x80, + 0x28, 0xca, + 0x29, 0x53, + 0x2a, 0x0e, + 0xff, 0x01, + 0x3e, 0x20, +}; + +static const __u8 start_7311[] = { +/* index, len, [value]* */ + 0xff, 1, 0x01, /* page 1 */ + 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00, + 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c, + 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e, + 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49, + 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48, + 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78, + 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b, + 0xd0, 0xff, + 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80, + 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84, + 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14, + 0x18, 0x20, + 0x96, 3, 0x01, 0x08, 0x04, + 0xa0, 4, 0x44, 0x44, 0x44, 0x04, + 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00, + 0x3f, 0x00, 0x0a, 0x01, 0x00, + 0xff, 1, 0x04, /* page 4 */ + 0x00, 254, /* load the page 4 */ + 0x11, 1, 0x01, + 0, 0 /* end of sequence */ +}; + +/* page 4 - the value 0xaa says skip the index - see reg_w_page() */ +static const __u8 page4_7311[] = { + 0xaa, 0xaa, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f, + 0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62, + 0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa, + 0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x68, + 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x23, 0x28, 0x04, 0x11, 0x00, 0x00 }; static void reg_w_buf(struct gspca_dev *gspca_dev, - __u16 index, - const char *buffer, __u16 len) + __u8 index, + const char *buffer, int len) { memcpy(gspca_dev->usb_buf, buffer, len); usb_control_msg(gspca_dev->dev, @@ -219,21 +408,9 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, 500); } -static __u8 reg_r(struct gspca_dev *gspca_dev, - __u16 index) -{ - usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - 0, /* request */ - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, /* value */ - index, gspca_dev->usb_buf, 1, - 500); - return gspca_dev->usb_buf[0]; -} static void reg_w(struct gspca_dev *gspca_dev, - __u16 index, + __u8 index, __u8 value) { gspca_dev->usb_buf[0] = value; @@ -241,10 +418,78 @@ static void reg_w(struct gspca_dev *gspca_dev, usb_sndctrlpipe(gspca_dev->dev, 0), 0, /* request */ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, gspca_dev->usb_buf, 1, + 0, index, gspca_dev->usb_buf, 1, 500); } +static void reg_w_seq(struct gspca_dev *gspca_dev, + const __u8 *seq, int len) +{ + while (--len >= 0) { + reg_w(gspca_dev, seq[0], seq[1]); + seq += 2; + } +} + +/* load the beginning of a page */ +static void reg_w_page(struct gspca_dev *gspca_dev, + const __u8 *page, int len) +{ + int index; + + for (index = 0; index < len; index++) { + if (page[index] == 0xaa) /* skip this index */ + continue; + gspca_dev->usb_buf[0] = page[index]; + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, gspca_dev->usb_buf, 1, + 500); + } +} + +/* output a variable sequence */ +static void reg_w_var(struct gspca_dev *gspca_dev, + const __u8 *seq) +{ + int index, len; + + for (;;) { + index = *seq++; + len = *seq++; + switch (len) { + case 0: + return; + case 254: + reg_w_page(gspca_dev, page4_7311, sizeof page4_7311); + break; + case 255: + reg_w_page(gspca_dev, page3_7302, sizeof page3_7302); + break; + default: + if (len > 64) { + PDEBUG(D_ERR|D_STREAM, + "Incorrect variable sequence"); + return; + } + while (len > 0) { + if (len < 8) { + reg_w_buf(gspca_dev, index, seq, len); + seq += len; + break; + } + reg_w_buf(gspca_dev, index, seq, 8); + seq += 8; + index += 8; + len -= 8; + } + } + } + /* not reached */ +} + /* this function is called at probe time */ static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) @@ -252,203 +497,245 @@ static int sd_config(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - PDEBUG(D_CONF, "Find Sensor PAC7311"); - reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */ - reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */ - reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ - reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x27, 0x80); - reg_w(gspca_dev, 0x28, 0xca); - reg_w(gspca_dev, 0x29, 0x53); - reg_w(gspca_dev, 0x2a, 0x0e); - reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x3e, 0x20); - cam = &gspca_dev->cam; cam->epaddr = 0x05; - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); + + sd->sensor = id->driver_info; + if (sd->sensor == SENSOR_PAC7302) { + PDEBUG(D_CONF, "Find Sensor PAC7302"); + cam->cam_mode = &vga_mode[2]; /* only 640x480 */ + cam->nmodes = 1; + } else { + PDEBUG(D_CONF, "Find Sensor PAC7311"); + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX) + | (1 << SATURATION_IDX); + } sd->brightness = BRIGHTNESS_DEF; sd->contrast = CONTRAST_DEF; sd->colors = COLOR_DEF; + sd->gain = GAIN_DEF; + sd->exposure = EXPOSURE_DEF; sd->autogain = AUTOGAIN_DEF; - sd->ag_cnt = -1; + sd->hflip = HFLIP_DEF; + sd->vflip = VFLIP_DEF; return 0; } -static void setbrightness(struct gspca_dev *gspca_dev) +/* This function is used by pac7302 only */ +static void setbrightcont(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, v; + static const __u8 max[10] = + {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb, + 0xd4, 0xec}; + static const __u8 delta[10] = + {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17, + 0x11, 0x0b}; + + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + for (i = 0; i < 10; i++) { + v = max[i]; + v += (sd->brightness - BRIGHTNESS_MAX) + * 150 / BRIGHTNESS_MAX; /* 200 ? */ + v -= delta[i] * sd->contrast / CONTRAST_MAX; + if (v < 0) + v = 0; + else if (v > 0xff) + v = 0xff; + reg_w(gspca_dev, 0xa2 + i, v); + } + reg_w(gspca_dev, 0xdc, 0x01); +} + +/* This function is used by pac7311 only */ +static void setcontrast(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - int brightness; -/*jfm: inverted?*/ - brightness = BRIGHTNESS_MAX - sd->brightness; reg_w(gspca_dev, 0xff, 0x04); -/* reg_w(gspca_dev, 0x0e, 0x00); */ - reg_w(gspca_dev, 0x0f, brightness); + reg_w(gspca_dev, 0x10, sd->contrast >> 4); /* load registers to sensor (Bit 0, auto clear) */ reg_w(gspca_dev, 0x11, 0x01); - PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness); } -static void setcontrast(struct gspca_dev *gspca_dev) +/* This function is used by pac7302 only */ +static void setcolors(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + int i, v; + static const int a[9] = + {217, -212, 0, -101, 170, -67, -38, -315, 355}; + static const int b[9] = + {19, 106, 0, 19, 106, 1, 19, 106, 1}; - reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x80, sd->contrast); - /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ reg_w(gspca_dev, 0x11, 0x01); - PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast); + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + for (i = 0; i < 9; i++) { + v = a[i] * sd->colors / COLOR_MAX + b[i]; + reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07); + reg_w(gspca_dev, 0x0f + 2 * i + 1, v); + } + reg_w(gspca_dev, 0xdc, 0x01); + PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors); } -static void setcolors(struct gspca_dev *gspca_dev) +static void setgain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x10, sd->colors); + if (sd->sensor == SENSOR_PAC7302) { + reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ + reg_w(gspca_dev, 0x10, sd->gain >> 3); + } else { + int gain = GAIN_MAX - sd->gain; + if (gain < 1) + gain = 1; + else if (gain > 245) + gain = 245; + reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ + reg_w(gspca_dev, 0x0e, 0x00); + reg_w(gspca_dev, 0x0f, gain); + } /* load registers to sensor (Bit 0, auto clear) */ reg_w(gspca_dev, 0x11, 0x01); - PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors); } -static void setautogain(struct gspca_dev *gspca_dev) +static void setexposure(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + __u8 reg; + + /* register 2 of frame 3/4 contains the clock divider configuring the + no fps according to the formula: 60 / reg. sd->exposure is the + desired exposure time in ms. */ + reg = 120 * sd->exposure / 1000; + if (reg < 2) + reg = 2; + else if (reg > 63) + reg = 63; + + if (sd->sensor == SENSOR_PAC7302) { + /* On the pac7302 reg2 MUST be a multiple of 3, so round it to + the nearest multiple of 3, except when between 6 and 12? */ + if (reg < 6 || reg > 12) + reg = ((reg + 1) / 3) * 3; + reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ + reg_w(gspca_dev, 0x02, reg); + } else { + reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ + reg_w(gspca_dev, 0x02, reg); + /* Page 1 register 8 must always be 0x08 except when not in + 640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */ + reg_w(gspca_dev, 0xff, 0x01); + if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv && + reg <= 3) + reg_w(gspca_dev, 0x08, 0x09); + else + reg_w(gspca_dev, 0x08, 0x08); + } + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); +} - if (sd->autogain) { - sd->lum_sum = 0; - sd->ag_cnt = AG_CNT_START; +static void sethvflip(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 data; + + if (sd->sensor == SENSOR_PAC7302) { + reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ + data = (sd->hflip ? 0x08 : 0x00) + | (sd->vflip ? 0x04 : 0x00); } else { - sd->ag_cnt = -1; + reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ + data = (sd->hflip ? 0x04 : 0x00) + | (sd->vflip ? 0x08 : 0x00); } + reg_w(gspca_dev, 0x21, data); + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { - reg_w(gspca_dev, 0x78, 0x00); /* Turn on LED */ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_PAC7302) + reg_w_seq(gspca_dev, init_7302, sizeof init_7302); + else + reg_w_seq(gspca_dev, init_7311, sizeof init_7311); + return 0; } static void sd_start(struct gspca_dev *gspca_dev) { - reg_w(gspca_dev, 0xff, 0x01); - reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8); - reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8); - reg_w_buf(gspca_dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8); - reg_w_buf(gspca_dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8); - reg_w_buf(gspca_dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8); - reg_w_buf(gspca_dev, 0x002a, "\x00\x00\x00", 3); - reg_w_buf(gspca_dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8); - reg_w_buf(gspca_dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8); - reg_w_buf(gspca_dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8); - reg_w_buf(gspca_dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8); - reg_w_buf(gspca_dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8); - reg_w_buf(gspca_dev, 0x0066, "\xd0\xff", 2); - reg_w_buf(gspca_dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6); - reg_w_buf(gspca_dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8); - reg_w_buf(gspca_dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8); - reg_w_buf(gspca_dev, 0x008f, "\x18\x20", 2); - reg_w_buf(gspca_dev, 0x0096, "\x01\x08\x04", 3); - reg_w_buf(gspca_dev, 0x00a0, "\x44\x44\x44\x04", 4); - reg_w_buf(gspca_dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8); - reg_w_buf(gspca_dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5); + struct sd *sd = (struct sd *) gspca_dev; - reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x02, 0x04); - reg_w(gspca_dev, 0x03, 0x54); - reg_w(gspca_dev, 0x04, 0x07); - reg_w(gspca_dev, 0x05, 0x2b); - reg_w(gspca_dev, 0x06, 0x09); - reg_w(gspca_dev, 0x07, 0x0f); - reg_w(gspca_dev, 0x08, 0x09); - reg_w(gspca_dev, 0x09, 0x00); - reg_w(gspca_dev, 0x0c, 0x07); - reg_w(gspca_dev, 0x0d, 0x00); - reg_w(gspca_dev, 0x0e, 0x00); - reg_w(gspca_dev, 0x0f, 0x62); - reg_w(gspca_dev, 0x10, 0x08); - reg_w(gspca_dev, 0x12, 0x07); - reg_w(gspca_dev, 0x13, 0x00); - reg_w(gspca_dev, 0x14, 0x00); - reg_w(gspca_dev, 0x15, 0x00); - reg_w(gspca_dev, 0x16, 0x00); - reg_w(gspca_dev, 0x17, 0x00); - reg_w(gspca_dev, 0x18, 0x00); - reg_w(gspca_dev, 0x19, 0x00); - reg_w(gspca_dev, 0x1a, 0x00); - reg_w(gspca_dev, 0x1b, 0x03); - reg_w(gspca_dev, 0x1c, 0xa0); - reg_w(gspca_dev, 0x1d, 0x01); - reg_w(gspca_dev, 0x1e, 0xf4); - reg_w(gspca_dev, 0x21, 0x00); - reg_w(gspca_dev, 0x22, 0x08); - reg_w(gspca_dev, 0x24, 0x03); - reg_w(gspca_dev, 0x26, 0x00); - reg_w(gspca_dev, 0x27, 0x01); - reg_w(gspca_dev, 0x28, 0xca); - reg_w(gspca_dev, 0x29, 0x10); - reg_w(gspca_dev, 0x2a, 0x06); - reg_w(gspca_dev, 0x2b, 0x78); - reg_w(gspca_dev, 0x2c, 0x00); - reg_w(gspca_dev, 0x2d, 0x00); - reg_w(gspca_dev, 0x2e, 0x00); - reg_w(gspca_dev, 0x2f, 0x00); - reg_w(gspca_dev, 0x30, 0x23); - reg_w(gspca_dev, 0x31, 0x28); - reg_w(gspca_dev, 0x32, 0x04); - reg_w(gspca_dev, 0x33, 0x11); - reg_w(gspca_dev, 0x34, 0x00); - reg_w(gspca_dev, 0x35, 0x00); - reg_w(gspca_dev, 0x11, 0x01); - setcontrast(gspca_dev); - setbrightness(gspca_dev); - setcolors(gspca_dev); - setautogain(gspca_dev); + sd->sof_read = 0; + + if (sd->sensor == SENSOR_PAC7302) { + reg_w_var(gspca_dev, start_7302); + setbrightcont(gspca_dev); + setcolors(gspca_dev); + } else { + reg_w_var(gspca_dev, start_7311); + setcontrast(gspca_dev); + } + setgain(gspca_dev); + setexposure(gspca_dev); + sethvflip(gspca_dev); /* set correct resolution */ switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { - case 2: /* 160x120 */ - reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x02, 0x03); + case 2: /* 160x120 pac7311 */ reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x08, 0x09); reg_w(gspca_dev, 0x17, 0x20); - reg_w(gspca_dev, 0x1b, 0x00); -/* reg_w(gspca_dev, 0x80, 0x69); */ reg_w(gspca_dev, 0x87, 0x10); break; - case 1: /* 320x240 */ - reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x02, 0x03); + case 1: /* 320x240 pac7311 */ reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x08, 0x09); reg_w(gspca_dev, 0x17, 0x30); -/* reg_w(gspca_dev, 0x80, 0x3f); */ reg_w(gspca_dev, 0x87, 0x11); break; case 0: /* 640x480 */ - reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x02, 0x03); + if (sd->sensor == SENSOR_PAC7302) + break; reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x08, 0x08); reg_w(gspca_dev, 0x17, 0x00); -/* reg_w(gspca_dev, 0x80, 0x1c); */ reg_w(gspca_dev, 0x87, 0x12); break; } + sd->sof_read = 0; + sd->autogain_ignore_frames = 0; + atomic_set(&sd->avg_lum, -1); + /* start stream */ reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x78, 0x04); - reg_w(gspca_dev, 0x78, 0x05); + if (sd->sensor == SENSOR_PAC7302) + reg_w(gspca_dev, 0x78, 0x01); + else + reg_w(gspca_dev, 0x78, 0x05); } static void sd_stopN(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_PAC7302) { + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x78, 0x00); + reg_w(gspca_dev, 0x78, 0x00); + return; + } reg_w(gspca_dev, 0xff, 0x04); reg_w(gspca_dev, 0x27, 0x80); reg_w(gspca_dev, 0x28, 0xca); @@ -456,187 +743,147 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x2a, 0x0e); reg_w(gspca_dev, 0xff, 0x01); reg_w(gspca_dev, 0x3e, 0x20); - reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */ - reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ - reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ + reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */ + reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */ + reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */ } static void sd_stop0(struct gspca_dev *gspca_dev) { -} + struct sd *sd = (struct sd *) gspca_dev; -/* this function is called at close time */ -static void sd_close(struct gspca_dev *gspca_dev) -{ - reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x27, 0x80); - reg_w(gspca_dev, 0x28, 0xca); - reg_w(gspca_dev, 0x29, 0x53); - reg_w(gspca_dev, 0x2a, 0x0e); - reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x3e, 0x20); - reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */ - reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ - reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ + if (sd->sensor == SENSOR_PAC7302) { + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x78, 0x40); + } } +/* Include pac common sof detection functions */ +#include "pac_common.h" + static void do_autogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - int luma; - int luma_mean = 128; - int luma_delta = 20; - __u8 spring = 5; - int Gbright; + int avg_lum = atomic_read(&sd->avg_lum); + int desired_lum, deadzone; - if (!atomic_read(&sd->do_gain)) + if (avg_lum == -1) return; - atomic_set(&sd->do_gain, 0); - - luma = atomic_read(&sd->avg_lum); - Gbright = reg_r(gspca_dev, 0x02); - PDEBUG(D_FRAM, "luma mean %d", luma); - if (luma < luma_mean - luma_delta || - luma > luma_mean + luma_delta) { - Gbright += (luma_mean - luma) >> spring; - if (Gbright > 0x1a) - Gbright = 0x1a; - else if (Gbright < 4) - Gbright = 4; - PDEBUG(D_FRAM, "gbright %d", Gbright); - reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x0f, Gbright); - /* load registers to sensor (Bit 0, auto clear) */ - reg_w(gspca_dev, 0x11, 0x01); + + if (sd->sensor == SENSOR_PAC7302) { + desired_lum = 270 + sd->brightness * 4; + /* Hack hack, with the 7202 the first exposure step is + pretty large, so if we're about to make the first + exposure increase make the deadzone large to avoid + oscilating */ + if (desired_lum > avg_lum && sd->gain == GAIN_DEF && + sd->exposure > EXPOSURE_DEF && + sd->exposure < 42) + deadzone = 90; + else + deadzone = 30; + } else { + desired_lum = 200; + deadzone = 20; } + + if (sd->autogain_ignore_frames > 0) + sd->autogain_ignore_frames--; + else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum, + deadzone, GAIN_KNEE, EXPOSURE_KNEE)) + sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; } +static const unsigned char pac7311_jpeg_header1[] = { + 0xff, 0xd8, 0xff, 0xc0, 0x00, 0x11, 0x08 +}; + +static const unsigned char pac7311_jpeg_header2[] = { + 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda, + 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00 +}; + +/* this function is run at interrupt level */ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ int len) /* iso packet length */ { struct sd *sd = (struct sd *) gspca_dev; - unsigned char tmpbuf[4]; - int i, p, ffseq; - -/* if (len < 5) { */ - if (len < 6) { -/* gspca_dev->last_packet_type = DISCARD_PACKET; */ - return; - } - - ffseq = sd->ffseq; - - for (p = 0; p < len - 6; p++) { - if ((data[0 + p] == 0xff) - && (data[1 + p] == 0xff) - && (data[2 + p] == 0x00) - && (data[3 + p] == 0xff) - && (data[4 + p] == 0x96)) { - - /* start of frame */ - if (sd->ag_cnt >= 0 && p > 28) { - sd->lum_sum += data[p - 23]; - if (--sd->ag_cnt < 0) { - sd->ag_cnt = AG_CNT_START; - atomic_set(&sd->avg_lum, - sd->lum_sum / AG_CNT_START); - sd->lum_sum = 0; - atomic_set(&sd->do_gain, 1); - } - } + unsigned char *sof; + + sof = pac_find_sof(gspca_dev, data, len); + if (sof) { + unsigned char tmpbuf[4]; + int n, lum_offset, footer_length; + + if (sd->sensor == SENSOR_PAC7302) { + /* 6 bytes after the FF D9 EOF marker a number of lumination + bytes are send corresponding to different parts of the + image, the 14th and 15th byte after the EOF seem to + correspond to the center of the image */ + lum_offset = 61 + sizeof pac_sof_marker; + footer_length = 74; + } else { + lum_offset = 24 + sizeof pac_sof_marker; + footer_length = 26; + } - /* copy the end of data to the current frame */ + /* Finish decoding current frame */ + n = (sof - data) - (footer_length + sizeof pac_sof_marker); + if (n < 0) { + frame->data_end += n; + n = 0; + } + frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame, + data, n); + if (gspca_dev->last_packet_type != DISCARD_PACKET && + frame->data_end[-2] == 0xff && + frame->data_end[-1] == 0xd9) frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, - data, p); - - /* put the JPEG header in the new frame */ - gspca_frame_add(gspca_dev, FIRST_PACKET, frame, - (unsigned char *) pac7311_jpeg_header, - 12); + NULL, 0); + + n = sof - data; + len -= n; + data = sof; + + /* Get average lumination */ + if (gspca_dev->last_packet_type == LAST_PACKET && + n >= lum_offset) + atomic_set(&sd->avg_lum, data[-lum_offset] + + data[-lum_offset + 1]); + else + atomic_set(&sd->avg_lum, -1); + + /* Start the new frame with the jpeg header */ + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + pac7311_jpeg_header1, sizeof(pac7311_jpeg_header1)); + if (sd->sensor == SENSOR_PAC7302) { + /* The PAC7302 has the image rotated 90 degrees */ + tmpbuf[0] = gspca_dev->width >> 8; + tmpbuf[1] = gspca_dev->width & 0xff; + tmpbuf[2] = gspca_dev->height >> 8; + tmpbuf[3] = gspca_dev->height & 0xff; + } else { tmpbuf[0] = gspca_dev->height >> 8; tmpbuf[1] = gspca_dev->height & 0xff; tmpbuf[2] = gspca_dev->width >> 8; tmpbuf[3] = gspca_dev->width & 0xff; - gspca_frame_add(gspca_dev, INTER_PACKET, frame, - tmpbuf, 4); - gspca_frame_add(gspca_dev, INTER_PACKET, frame, - (unsigned char *) &pac7311_jpeg_header[16], - PAC7311_JPEG_HEADER_SIZE - 16); - - data += p + 7; - len -= p + 7; - ffseq = 0; - break; } + gspca_frame_add(gspca_dev, INTER_PACKET, frame, tmpbuf, 4); + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + pac7311_jpeg_header2, sizeof(pac7311_jpeg_header2)); } - - /* remove the 'ff ff ff xx' sequences */ - switch (ffseq) { - case 3: - data += 1; - len -= 1; - break; - case 2: - if (data[0] == 0xff) { - data += 2; - len -= 2; - frame->data_end -= 2; - } - break; - case 1: - if (data[0] == 0xff - && data[1] == 0xff) { - data += 3; - len -= 3; - frame->data_end -= 1; - } - break; - } - for (i = 0; i < len - 4; i++) { - if (data[i] == 0xff - && data[i + 1] == 0xff - && data[i + 2] == 0xff) { - memmove(&data[i], &data[i + 4], len - i - 4); - len -= 4; - } - } - ffseq = 0; - if (data[len - 4] == 0xff) { - if (data[len - 3] == 0xff - && data[len - 2] == 0xff) { - len -= 4; - } - } else if (data[len - 3] == 0xff) { - if (data[len - 2] == 0xff - && data[len - 1] == 0xff) - ffseq = 3; - } else if (data[len - 2] == 0xff) { - if (data[len - 1] == 0xff) - ffseq = 2; - } else if (data[len - 1] == 0xff) - ffseq = 1; - sd->ffseq = ffseq; gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); } -static void getbrightness(struct gspca_dev *gspca_dev) -{ -/* sd->brightness = reg_r(gspca_dev, 0x08); - return sd->brightness; */ -/* PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */ -} - - - static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->brightness = val; if (gspca_dev->streaming) - setbrightness(gspca_dev); + setbrightcont(gspca_dev); return 0; } @@ -644,7 +891,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; - getbrightness(gspca_dev); *val = sd->brightness; return 0; } @@ -654,8 +900,12 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); + if (gspca_dev->streaming) { + if (sd->sensor == SENSOR_PAC7302) + setbrightcont(gspca_dev); + else + setcontrast(gspca_dev); + } return 0; } @@ -663,7 +913,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; -/* getcontrast(gspca_dev); */ *val = sd->contrast; return 0; } @@ -682,18 +931,66 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; -/* getcolors(gspca_dev); */ *val = sd->colors; return 0; } +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gain = val; + if (gspca_dev->streaming) + setgain(gspca_dev); + return 0; +} + +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->gain; + return 0; +} + +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->exposure = val; + if (gspca_dev->streaming) + setexposure(gspca_dev); + return 0; +} + +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->exposure; + return 0; +} + static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->autogain = val; - if (gspca_dev->streaming) - setautogain(gspca_dev); + /* when switching to autogain set defaults to make sure + we are on a valid point of the autogain gain / + exposure knee graph, and give this change time to + take effect before doing autogain. */ + if (sd->autogain) { + sd->exposure = EXPOSURE_DEF; + sd->gain = GAIN_DEF; + if (gspca_dev->streaming) { + sd->autogain_ignore_frames = + PAC_AUTOGAIN_IGNORE_FRAMES; + setexposure(gspca_dev); + setgain(gspca_dev); + } + } + return 0; } @@ -705,30 +1002,67 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) return 0; } +static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->hflip = val; + if (gspca_dev->streaming) + sethvflip(gspca_dev); + return 0; +} + +static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->hflip; + return 0; +} + +static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->vflip = val; + if (gspca_dev->streaming) + sethvflip(gspca_dev); + return 0; +} + +static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->vflip; + return 0; +} + /* sub-driver description */ static struct sd_desc sd_desc = { .name = MODULE_NAME, .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, .dq_callback = do_autogain, }; /* -- module initialisation -- */ static __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x093a, 0x2600)}, - {USB_DEVICE(0x093a, 0x2601)}, - {USB_DEVICE(0x093a, 0x2603)}, - {USB_DEVICE(0x093a, 0x2608)}, - {USB_DEVICE(0x093a, 0x260e)}, - {USB_DEVICE(0x093a, 0x260f)}, - {USB_DEVICE(0x093a, 0x2621)}, + {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311}, + {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311}, + {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311}, + {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311}, + {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311}, + {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311}, + {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302}, + {USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302}, + {USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302}, {} }; MODULE_DEVICE_TABLE(usb, device_table); @@ -746,6 +1080,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/drivers/media/video/gspca/pac_common.h b/drivers/media/video/gspca/pac_common.h new file mode 100644 index 000000000000..34d4b1494cd5 --- /dev/null +++ b/drivers/media/video/gspca/pac_common.h @@ -0,0 +1,60 @@ +/* + * Pixart PAC207BCA / PAC73xx common functions + * + * Copyright (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> + * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li + * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* We calculate the autogain at the end of the transfer of a frame, at this + moment a frame with the old settings is being transmitted, and a frame is + being captured with the old settings. So if we adjust the autogain we must + ignore atleast the 2 next frames for the new settings to come into effect + before doing any other adjustments */ +#define PAC_AUTOGAIN_IGNORE_FRAMES 3 + +static const unsigned char pac_sof_marker[5] = + { 0xff, 0xff, 0x00, 0xff, 0x96 }; + +static unsigned char *pac_find_sof(struct gspca_dev *gspca_dev, + unsigned char *m, int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + + /* Search for the SOF marker (fixed part) in the header */ + for (i = 0; i < len; i++) { + if (m[i] == pac_sof_marker[sd->sof_read]) { + sd->sof_read++; + if (sd->sof_read == sizeof(pac_sof_marker)) { + PDEBUG(D_FRAM, + "SOF found, bytes to analyze: %u." + " Frame starts at byte #%u", + len, i + 1); + sd->sof_read = 0; + return m + i + 1; + } + } else { + sd->sof_read = 0; + } + } + + return NULL; +} diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index 11210c71f66c..5dd78c6766ea 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -20,6 +20,26 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* Some documentation on known sonixb registers: + +Reg Use +0x10 high nibble red gain low nibble blue gain +0x11 low nibble green gain +0x12 hstart +0x13 vstart +0x15 hsize (hsize = register-value * 16) +0x16 vsize (vsize = register-value * 16) +0x17 bit 0 toggle compression quality (according to sn9c102 driver) +0x18 bit 7 enables compression, bit 4-5 set image down scaling: + 00 scale 1, 01 scale 1/2, 10, scale 1/4 +0x19 high-nibble is sensor clock divider, changes exposure on sensors which + use a clock generated by the bridge. Some sensors have their own clock. +0x1c auto_exposure area (for avg_lum) startx (startx = register-value * 32) +0x1d auto_exposure area (for avg_lum) starty (starty = register-value * 32) +0x1e auto_exposure area (for avg_lum) stopx (hsize = (0x1e - 0x1c) * 32) +0x1f auto_exposure area (for avg_lum) stopy (vsize = (0x1f - 0x1d) * 32) +*/ + #define MODULE_NAME "sonixb" #include "gspca.h" @@ -31,10 +51,8 @@ MODULE_LICENSE("GPL"); /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - - struct sd_desc sd_desc; /* our nctrls differ dependend upon the - sensor, so we use a per cam copy */ atomic_t avg_lum; + int prev_avg_lum; unsigned char gain; unsigned char exposure; @@ -44,8 +62,12 @@ struct sd { unsigned char frames_to_drop; unsigned char freq; /* light freq filter setting */ - unsigned char fr_h_sz; /* size of frame header */ - char sensor; /* Type of image sensor chip */ + __u8 bridge; /* Type of bridge */ +#define BRIDGE_101 0 +#define BRIDGE_102 0 /* We make no difference between 101 and 102 */ +#define BRIDGE_103 1 + + __u8 sensor; /* Type of image sensor chip */ #define SENSOR_HV7131R 0 #define SENSOR_OV6650 1 #define SENSOR_OV7630 2 @@ -53,16 +75,35 @@ struct sd { #define SENSOR_PAS202 4 #define SENSOR_TAS5110 5 #define SENSOR_TAS5130CXX 6 - char sensor_has_gain; - __u8 sensor_addr; __u8 reg11; }; -/* flags used in the device id table */ +typedef const __u8 sensor_init_t[8]; + +struct sensor_data { + const __u8 *bridge_init[2]; + int bridge_init_size[2]; + sensor_init_t *sensor_init; + int sensor_init_size; + sensor_init_t *sensor_bridge_init[2]; + int sensor_bridge_init_size[2]; + int flags; + unsigned ctrl_dis; + __u8 sensor_addr; +}; + +/* sensor_data flags */ #define F_GAIN 0x01 /* has gain */ -#define F_AUTO 0x02 /* has autogain */ -#define F_SIF 0x04 /* sif or vga */ -#define F_H18 0x08 /* long (18 b) or short (12 b) frame header */ +#define F_SIF 0x02 /* sif or vga */ + +/* priv field of struct v4l2_pix_format flags (do not use low nibble!) */ +#define MODE_RAW 0x10 /* raw bayer mode */ +#define MODE_REDUCED_SIF 0x20 /* vga mode (320x240 / 160x120) on sif cam */ + +/* ctrl_dis helper macros */ +#define NO_EXPO ((1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)) +#define NO_FREQ (1 << FREQ_IDX) +#define NO_BRIGHTNESS (1 << BRIGHTNESS_IDX) #define COMP2 0x8f #define COMP 0xc7 /* 0x87 //0x07 */ @@ -73,6 +114,18 @@ struct sd { #define SYS_CLK 0x04 +#define SENS(bridge_1, bridge_3, sensor, sensor_1, \ + sensor_3, _flags, _ctrl_dis, _sensor_addr) \ +{ \ + .bridge_init = { bridge_1, bridge_3 }, \ + .bridge_init_size = { sizeof(bridge_1), sizeof(bridge_3) }, \ + .sensor_init = sensor, \ + .sensor_init_size = sizeof(sensor), \ + .sensor_bridge_init = { sensor_1, sensor_3,}, \ + .sensor_bridge_init_size = { sizeof(sensor_1), sizeof(sensor_3)}, \ + .flags = _flags, .ctrl_dis = _ctrl_dis, .sensor_addr = _sensor_addr \ +} + /* We calculate the autogain at the end of the transfer of a frame, at this moment a frame with the old settings is being transmitted, and a frame is being captured with the old settings. So if we adjust the autogain we must @@ -95,6 +148,7 @@ static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); static struct ctrl sd_ctrls[] = { +#define BRIGHTNESS_IDX 0 { { .id = V4L2_CID_BRIGHTNESS, @@ -109,6 +163,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setbrightness, .get = sd_getbrightness, }, +#define GAIN_IDX 1 { { .id = V4L2_CID_GAIN, @@ -124,6 +179,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setgain, .get = sd_getgain, }, +#define EXPOSURE_IDX 2 { { .id = V4L2_CID_EXPOSURE, @@ -140,6 +196,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setexposure, .get = sd_getexposure, }, +#define AUTOGAIN_IDX 3 { { .id = V4L2_CID_AUTOGAIN, @@ -155,6 +212,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setautogain, .get = sd_getautogain, }, +#define FREQ_IDX 4 { { .id = V4L2_CID_POWER_LINE_FREQUENCY, @@ -172,31 +230,56 @@ static struct ctrl sd_ctrls[] = { }; static struct v4l2_pix_format vga_mode[] = { + {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 5 / 4, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2 | MODE_RAW}, {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, .bytesperline = 160, - .sizeimage = 160 * 120, + .sizeimage = 160 * 120 * 5 / 4, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 2}, {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, .bytesperline = 320, - .sizeimage = 320 * 240, + .sizeimage = 320 * 240 * 5 / 4, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 1}, {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, .bytesperline = 640, - .sizeimage = 640 * 480, + .sizeimage = 640 * 480 * 5 / 4, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, }; static struct v4l2_pix_format sif_mode[] = { + {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 | MODE_RAW | MODE_REDUCED_SIF}, + {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 5 / 4, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 | MODE_REDUCED_SIF}, + {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 5 / 4, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 | MODE_RAW}, {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, .bytesperline = 176, - .sizeimage = 176 * 144, + .sizeimage = 176 * 144 * 5 / 4, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 1}, + {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 5 / 4, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 | MODE_REDUCED_SIF}, {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, .bytesperline = 352, - .sizeimage = 352 * 288, + .sizeimage = 352 * 288 * 5 / 4, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, }; @@ -204,7 +287,7 @@ static struct v4l2_pix_format sif_mode[] = { static const __u8 initHv7131[] = { 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */ + 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x28, 0x1e, 0x60, 0x8a, 0x20, 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c }; @@ -218,8 +301,8 @@ static const __u8 hv7131_sensor_init[][8] = { static const __u8 initOv6650[] = { 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b, - 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00 + 0x00, 0x01, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x8b, + 0x10, 0x1d, 0x10, 0x02, 0x02, 0x09, 0x07 }; static const __u8 ov6650_sensor_init[][8] = { @@ -257,15 +340,15 @@ static const __u8 ov6650_sensor_init[][8] = static const __u8 initOv7630[] = { 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */ 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */ - 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */ + 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */ 0x28, 0x1e, /* H & V sizes r15 .. r16 */ - 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */ + 0x68, COMP2, MCK_INIT1, /* r17 .. r19 */ 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */ }; static const __u8 initOv7630_3[] = { 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */ 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */ - 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */ + 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */ 0x28, 0x1e, /* H & V sizes r15 .. r16 */ 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */ 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */ @@ -294,47 +377,65 @@ static const __u8 ov7630_sensor_init[][8] = { {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10}, }; +static const __u8 ov7630_sensor_init_3[][8] = { + {0xa0, 0x21, 0x13, 0x80, 0x00, 0x00, 0x00, 0x10}, +}; + static const __u8 initPas106[] = { 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, - 0x16, 0x12, 0x28, COMP1, MCK_INIT1, - 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c + 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, + 0x16, 0x12, 0x24, COMP1, MCK_INIT1, + 0x18, 0x10, 0x02, 0x02, 0x09, 0x07 }; /* compression 0x86 mckinit1 0x2b */ -static const __u8 pas106_data[][2] = { - {0x02, 0x04}, /* Pixel Clock Divider 6 */ - {0x03, 0x13}, /* Frame Time MSB */ -/* {0x03, 0x12}, * Frame Time MSB */ - {0x04, 0x06}, /* Frame Time LSB */ -/* {0x04, 0x05}, * Frame Time LSB */ - {0x05, 0x65}, /* Shutter Time Line Offset */ -/* {0x05, 0x6d}, * Shutter Time Line Offset */ -/* {0x06, 0xb1}, * Shutter Time Pixel Offset */ - {0x06, 0xcd}, /* Shutter Time Pixel Offset */ - {0x07, 0xc1}, /* Black Level Subtract Sign */ -/* {0x07, 0x00}, * Black Level Subtract Sign */ - {0x08, 0x06}, /* Black Level Subtract Level */ - {0x08, 0x06}, /* Black Level Subtract Level */ -/* {0x08, 0x01}, * Black Level Subtract Level */ - {0x09, 0x05}, /* Color Gain B Pixel 5 a */ - {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */ - {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */ - {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */ - {0x0d, 0x00}, /* Color GainH Pixel */ - {0x0e, 0x0e}, /* Global Gain */ - {0x0f, 0x00}, /* Contrast */ - {0x10, 0x06}, /* H&V synchro polarity */ - {0x11, 0x06}, /* ?default */ - {0x12, 0x06}, /* DAC scale */ - {0x14, 0x02}, /* ?default */ - {0x13, 0x01}, /* Validate Settings */ +static const __u8 pas106_sensor_init[][8] = { + /* Pixel Clock Divider 6 */ + { 0xa1, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x14 }, + /* Frame Time MSB (also seen as 0x12) */ + { 0xa1, 0x40, 0x03, 0x13, 0x00, 0x00, 0x00, 0x14 }, + /* Frame Time LSB (also seen as 0x05) */ + { 0xa1, 0x40, 0x04, 0x06, 0x00, 0x00, 0x00, 0x14 }, + /* Shutter Time Line Offset (also seen as 0x6d) */ + { 0xa1, 0x40, 0x05, 0x65, 0x00, 0x00, 0x00, 0x14 }, + /* Shutter Time Pixel Offset (also seen as 0xb1) */ + { 0xa1, 0x40, 0x06, 0xcd, 0x00, 0x00, 0x00, 0x14 }, + /* Black Level Subtract Sign (also seen 0x00) */ + { 0xa1, 0x40, 0x07, 0xc1, 0x00, 0x00, 0x00, 0x14 }, + /* Black Level Subtract Level (also seen 0x01) */ + { 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 }, + { 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 }, + /* Color Gain B Pixel 5 a */ + { 0xa1, 0x40, 0x09, 0x05, 0x00, 0x00, 0x00, 0x14 }, + /* Color Gain G1 Pixel 1 5 */ + { 0xa1, 0x40, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x14 }, + /* Color Gain G2 Pixel 1 0 5 */ + { 0xa1, 0x40, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x14 }, + /* Color Gain R Pixel 3 1 */ + { 0xa1, 0x40, 0x0c, 0x05, 0x00, 0x00, 0x00, 0x14 }, + /* Color GainH Pixel */ + { 0xa1, 0x40, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x14 }, + /* Global Gain */ + { 0xa1, 0x40, 0x0e, 0x0e, 0x00, 0x00, 0x00, 0x14 }, + /* Contrast */ + { 0xa1, 0x40, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x14 }, + /* H&V synchro polarity */ + { 0xa1, 0x40, 0x10, 0x06, 0x00, 0x00, 0x00, 0x14 }, + /* ?default */ + { 0xa1, 0x40, 0x11, 0x06, 0x00, 0x00, 0x00, 0x14 }, + /* DAC scale */ + { 0xa1, 0x40, 0x12, 0x06, 0x00, 0x00, 0x00, 0x14 }, + /* ?default */ + { 0xa1, 0x40, 0x14, 0x02, 0x00, 0x00, 0x00, 0x14 }, + /* Validate Settings */ + { 0xa1, 0x40, 0x13, 0x01, 0x00, 0x00, 0x00, 0x14 }, }; + static const __u8 initPas202[] = { 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */ - 0x28, 0x1e, 0x28, 0x89, 0x30, + 0x00, 0x00, 0x00, 0x06, 0x03, 0x0a, + 0x28, 0x1e, 0x28, 0x89, 0x20, 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c }; static const __u8 pas202_sensor_init[][8] = { @@ -364,7 +465,7 @@ static const __u8 pas202_sensor_init[][8] = { static const __u8 initTas5110[] = { 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */ + 0x00, 0x01, 0x00, 0x45, 0x09, 0x0a, 0x16, 0x12, 0x60, 0x86, 0x2b, 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07 }; @@ -377,7 +478,7 @@ static const __u8 tas5110_sensor_init[][8] = { static const __u8 initTas5130[] = { 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a, + 0x00, 0x01, 0x00, 0x68, 0x0c, 0x0a, 0x28, 0x1e, 0x60, COMP, MCK_INIT, 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c }; @@ -389,6 +490,21 @@ static const __u8 tas5130_sensor_init[][8] = { {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10}, }; +struct sensor_data sensor_data[] = { +SENS(initHv7131, NULL, hv7131_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, 0), +SENS(initOv6650, NULL, ov6650_sensor_init, NULL, NULL, F_GAIN|F_SIF, 0, 0x60), +SENS(initOv7630, initOv7630_3, ov7630_sensor_init, NULL, ov7630_sensor_init_3, + F_GAIN, 0, 0x21), +SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_SIF, NO_EXPO|NO_FREQ, + 0), +SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, 0, + NO_EXPO|NO_FREQ, 0), +SENS(initTas5110, NULL, tas5110_sensor_init, NULL, NULL, F_GAIN|F_SIF, + NO_BRIGHTNESS|NO_FREQ, 0), +SENS(initTas5130, NULL, tas5130_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, + 0), +}; + /* get one byte in gspca_dev->usb_buf */ static void reg_r(struct gspca_dev *gspca_dev, __u16 value) @@ -409,7 +525,7 @@ static void reg_w(struct gspca_dev *gspca_dev, int len) { #ifdef GSPCA_DEBUG - if (len > sizeof gspca_dev->usb_buf) { + if (len > USB_BUF_SZ) { PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow"); return; } @@ -425,26 +541,6 @@ static void reg_w(struct gspca_dev *gspca_dev, 500); } -static void reg_w_big(struct gspca_dev *gspca_dev, - __u16 value, - const __u8 *buffer, - int len) -{ - __u8 *tmpbuf; - - tmpbuf = kmalloc(len, GFP_KERNEL); - memcpy(tmpbuf, buffer, len); - usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x08, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - value, - 0, /* index */ - tmpbuf, len, - 500); - kfree(tmpbuf); -} - static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer) { int retry = 60; @@ -487,7 +583,7 @@ static void setbrightness(struct gspca_dev *gspca_dev) {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10}; /* change reg 0x06 */ - i2cOV[1] = sd->sensor_addr; + i2cOV[1] = sensor_data[sd->sensor].sensor_addr; i2cOV[3] = sd->brightness; if (i2c_w(gspca_dev, i2cOV) < 0) goto err; @@ -545,9 +641,6 @@ static void setbrightness(struct gspca_dev *gspca_dev) goto err; break; } - case SENSOR_TAS5110: - /* FIXME figure out howto control brightness on TAS5110 */ - break; } return; err: @@ -577,7 +670,7 @@ static void setsensorgain(struct gspca_dev *gspca_dev) case SENSOR_OV7630: { __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; - i2c[1] = sd->sensor_addr; + i2c[1] = sensor_data[sd->sensor].sensor_addr; i2c[3] = gain >> 2; if (i2c_w(gspca_dev, i2c) < 0) goto err; @@ -604,7 +697,7 @@ static void setgain(struct gspca_dev *gspca_dev) rgb_value = gain; reg_w(gspca_dev, 0x11, &rgb_value, 1); - if (sd->sensor_has_gain) + if (sensor_data[sd->sensor].flags & F_GAIN) setsensorgain(gspca_dev); } @@ -665,6 +758,11 @@ static void setexposure(struct gspca_dev *gspca_dev) else if (reg11 > 16) reg11 = 16; + /* In 640x480, if the reg11 has less than 3, the image is + unstable (not enough bandwidth). */ + if (gspca_dev->width == 640 && reg11 < 3) + reg11 = 3; + /* frame exposure time in ms = 1000 * reg11 / 30 -> reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */ reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11); @@ -678,13 +776,8 @@ static void setexposure(struct gspca_dev *gspca_dev) else if (reg10 > reg10_max) reg10 = reg10_max; - /* In 640x480, if the reg11 has less than 3, the image is - unstable (not enough bandwidth). */ - if (gspca_dev->width == 640 && reg11 < 3) - reg11 = 3; - /* Write reg 10 and reg11 low nibble */ - i2c[1] = sd->sensor_addr; + i2c[1] = sensor_data[sd->sensor].sensor_addr; i2c[3] = reg10; i2c[4] |= reg11 - 1; @@ -724,7 +817,7 @@ static void setfreq(struct gspca_dev *gspca_dev) ? 0x4f : 0x8a; break; } - i2c[1] = sd->sensor_addr; + i2c[1] = sensor_data[sd->sensor].sensor_addr; if (i2c_w(gspca_dev, i2c) < 0) PDEBUG(D_ERR, "i2c error setfreq"); break; @@ -757,30 +850,19 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - int sif = 0; - /* nctrls depends upon the sensor, so we use a per cam copy */ - memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc)); - gspca_dev->sd_desc = &sd->sd_desc; + reg_r(gspca_dev, 0x00); + if (gspca_dev->usb_buf[0] != 0x10) + return -ENODEV; /* copy the webcam info from the device id */ - sd->sensor = (id->driver_info >> 24) & 0xff; - if (id->driver_info & (F_GAIN << 16)) - sd->sensor_has_gain = 1; - if (id->driver_info & (F_AUTO << 16)) - sd->sd_desc.dq_callback = do_autogain; - if (id->driver_info & (F_SIF << 16)) - sif = 1; - if (id->driver_info & (F_H18 << 16)) - sd->fr_h_sz = 18; /* size of frame header */ - else - sd->fr_h_sz = 12; - sd->sd_desc.nctrls = (id->driver_info >> 8) & 0xff; - sd->sensor_addr = id->driver_info & 0xff; + sd->sensor = id->driver_info >> 8; + sd->bridge = id->driver_info & 0xff; + gspca_dev->ctrl_dis = sensor_data[sd->sensor].ctrl_dis; cam = &gspca_dev->cam; cam->epaddr = 0x01; - if (!sif) { + if (!(sensor_data[sd->sensor].flags & F_SIF)) { cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); } else { @@ -790,157 +872,98 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->brightness = BRIGHTNESS_DEF; sd->gain = GAIN_DEF; sd->exposure = EXPOSURE_DEF; - sd->autogain = AUTOGAIN_DEF; + if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX)) + sd->autogain = 0; /* Disable do_autogain callback */ + else + sd->autogain = AUTOGAIN_DEF; sd->freq = FREQ_DEF; return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { - reg_r(gspca_dev, 0x00); - if (gspca_dev->usb_buf[0] != 0x10) - return -ENODEV; - return 0; -} + const __u8 stop = 0x09; /* Disable stream turn of LED */ -static void pas106_i2cinit(struct gspca_dev *gspca_dev) -{ - int i; - const __u8 *data; - __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 }; - - i = ARRAY_SIZE(pas106_data); - data = pas106_data[0]; - while (--i >= 0) { - memcpy(&i2c1[2], data, 2); - /* copy 2 bytes from the template */ - if (i2c_w(gspca_dev, i2c1) < 0) - PDEBUG(D_ERR, "i2c error pas106"); - data += 2; - } + reg_w(gspca_dev, 0x01, &stop, 1); + + return 0; } /* -- start the camera -- */ static void sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - int mode, l = 0x1f; + struct cam *cam = &gspca_dev->cam; + int mode, l; const __u8 *sn9c10x; - __u8 reg17_19[3]; - - mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + __u8 reg12_19[8]; + + mode = cam->cam_mode[gspca_dev->curr_mode].priv & 0x07; + sn9c10x = sensor_data[sd->sensor].bridge_init[sd->bridge]; + l = sensor_data[sd->sensor].bridge_init_size[sd->bridge]; + memcpy(reg12_19, &sn9c10x[0x12 - 1], 8); + reg12_19[6] = sn9c10x[0x18 - 1] | (mode << 4); + /* Special cases where reg 17 and or 19 value depends on mode */ switch (sd->sensor) { - case SENSOR_HV7131R: - sn9c10x = initHv7131; - reg17_19[0] = 0x60; - reg17_19[1] = (mode << 4) | 0x8a; - reg17_19[2] = 0x20; - break; - case SENSOR_OV6650: - sn9c10x = initOv6650; - reg17_19[0] = 0x68; - reg17_19[1] = (mode << 4) | 0x8b; - reg17_19[2] = 0x20; - break; - case SENSOR_OV7630: - if (sd->fr_h_sz == 18) { /* SN9C103 */ - sn9c10x = initOv7630_3; - l = sizeof initOv7630_3; - } else - sn9c10x = initOv7630; - reg17_19[0] = 0x68; - reg17_19[1] = (mode << 4) | COMP2; - reg17_19[2] = MCK_INIT1; - break; - case SENSOR_PAS106: - sn9c10x = initPas106; - reg17_19[0] = 0x24; /* 0x28 */ - reg17_19[1] = (mode << 4) | COMP1; - reg17_19[2] = MCK_INIT1; - break; case SENSOR_PAS202: - sn9c10x = initPas202; - reg17_19[0] = mode ? 0x24 : 0x20; - reg17_19[1] = (mode << 4) | 0x89; - reg17_19[2] = 0x20; + reg12_19[5] = mode ? 0x24 : 0x20; break; - case SENSOR_TAS5110: - sn9c10x = initTas5110; - reg17_19[0] = 0x60; - reg17_19[1] = (mode << 4) | 0x86; - reg17_19[2] = 0x2b; /* 0xf3; */ - break; - default: -/* case SENSOR_TAS5130CXX: */ - sn9c10x = initTas5130; - reg17_19[0] = 0x60; - reg17_19[1] = (mode << 4) | COMP; - reg17_19[2] = mode ? 0x23 : 0x43; + case SENSOR_TAS5130CXX: + /* probably not mode specific at all most likely the upper + nibble of 0x19 is exposure (clock divider) just as with + the tas5110, we need someone to test this. */ + reg12_19[7] = mode ? 0x23 : 0x43; break; } + /* Disable compression when the raw bayer format has been selected */ + if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) + reg12_19[6] &= ~0x80; + + /* Vga mode emulation on SIF sensor? */ + if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_REDUCED_SIF) { + reg12_19[0] += 16; /* 0x12: hstart adjust */ + reg12_19[1] += 24; /* 0x13: vstart adjust */ + reg12_19[3] = 320 / 16; /* 0x15: hsize */ + reg12_19[4] = 240 / 16; /* 0x16: vsize */ + } /* reg 0x01 bit 2 video transfert on */ reg_w(gspca_dev, 0x01, &sn9c10x[0x01 - 1], 1); /* reg 0x17 SensorClk enable inv Clk 0x60 */ reg_w(gspca_dev, 0x17, &sn9c10x[0x17 - 1], 1); /* Set the registers from the template */ - reg_w_big(gspca_dev, 0x01, sn9c10x, l); - switch (sd->sensor) { - case SENSOR_HV7131R: - i2c_w_vector(gspca_dev, hv7131_sensor_init, - sizeof hv7131_sensor_init); - break; - case SENSOR_OV6650: - i2c_w_vector(gspca_dev, ov6650_sensor_init, - sizeof ov6650_sensor_init); - break; - case SENSOR_OV7630: - i2c_w_vector(gspca_dev, ov7630_sensor_init, - sizeof ov7630_sensor_init); - if (sd->fr_h_sz == 18) { /* SN9C103 */ - const __u8 i2c[] = { 0xa0, 0x21, 0x13, 0x80, 0x00, - 0x00, 0x00, 0x10 }; - i2c_w(gspca_dev, i2c); - } - break; - case SENSOR_PAS106: - pas106_i2cinit(gspca_dev); - break; - case SENSOR_PAS202: - i2c_w_vector(gspca_dev, pas202_sensor_init, - sizeof pas202_sensor_init); - break; - case SENSOR_TAS5110: - i2c_w_vector(gspca_dev, tas5110_sensor_init, - sizeof tas5110_sensor_init); - break; - default: -/* case SENSOR_TAS5130CXX: */ - i2c_w_vector(gspca_dev, tas5130_sensor_init, - sizeof tas5130_sensor_init); - break; - } + reg_w(gspca_dev, 0x01, sn9c10x, l); + + /* Init the sensor */ + i2c_w_vector(gspca_dev, sensor_data[sd->sensor].sensor_init, + sensor_data[sd->sensor].sensor_init_size); + if (sensor_data[sd->sensor].sensor_bridge_init[sd->bridge]) + i2c_w_vector(gspca_dev, + sensor_data[sd->sensor].sensor_bridge_init[sd->bridge], + sensor_data[sd->sensor].sensor_bridge_init_size[ + sd->bridge]); + /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */ - reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2); + reg_w(gspca_dev, 0x15, ®12_19[3], 2); /* compression register */ - reg_w(gspca_dev, 0x18, ®17_19[1], 1); + reg_w(gspca_dev, 0x18, ®12_19[6], 1); /* H_start */ - reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1); + reg_w(gspca_dev, 0x12, ®12_19[0], 1); /* V_START */ - reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1); + reg_w(gspca_dev, 0x13, ®12_19[1], 1); /* reset 0x17 SensorClk enable inv Clk 0x60 */ /*fixme: ov7630 [17]=68 8f (+20 if 102)*/ - reg_w(gspca_dev, 0x17, ®17_19[0], 1); + reg_w(gspca_dev, 0x17, ®12_19[5], 1); /*MCKSIZE ->3 */ /*fixme: not ov7630*/ - reg_w(gspca_dev, 0x19, ®17_19[2], 1); + reg_w(gspca_dev, 0x19, ®12_19[7], 1); /* AE_STRX AE_STRY AE_ENDX AE_ENDY */ reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4); /* Enable video transfert */ reg_w(gspca_dev, 0x01, &sn9c10x[0], 1); /* Compression */ - reg_w(gspca_dev, 0x18, ®17_19[1], 2); + reg_w(gspca_dev, 0x18, ®12_19[6], 2); msleep(20); sd->reg11 = -1; @@ -957,18 +980,7 @@ static void sd_start(struct gspca_dev *gspca_dev) static void sd_stopN(struct gspca_dev *gspca_dev) { - __u8 ByteSend; - - ByteSend = 0x09; /* 0X00 */ - reg_w(gspca_dev, 0x01, &ByteSend, 1); -} - -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ + sd_init(gspca_dev); } static void sd_pkt_scan(struct gspca_dev *gspca_dev, @@ -978,6 +990,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, { int i; struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam = &gspca_dev->cam; /* frames start with: * ff ff 00 c4 c4 96 synchro @@ -998,20 +1011,31 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, && data[5 + i] == 0x96) { /* start of frame */ int lum = -1; int pkt_type = LAST_PACKET; + int fr_h_sz = (sd->bridge == BRIDGE_103) ? + 18 : 12; - if (len - i < sd->fr_h_sz) { + if (len - i < fr_h_sz) { PDEBUG(D_STREAM, "packet too short to" " get avg brightness"); - } else if (sd->fr_h_sz == 12) { - lum = data[i + 8] + (data[i + 9] << 8); - } else { + } else if (sd->bridge == BRIDGE_103) { lum = data[i + 9] + (data[i + 10] << 8); + } else { + lum = data[i + 8] + (data[i + 9] << 8); } - if (lum == 0) { + /* When exposure changes midway a frame we + get a lum of 0 in this case drop 2 frames + as the frames directly after an exposure + change have an unstable image. Sometimes lum + *really* is 0 (cam used in low light with + low exposure setting), so do not drop frames + if the previous lum was 0 too. */ + if (lum == 0 && sd->prev_avg_lum != 0) { lum = -1; sd->frames_to_drop = 2; - } + sd->prev_avg_lum = 0; + } else + sd->prev_avg_lum = lum; atomic_set(&sd->avg_lum, lum); if (sd->frames_to_drop) { @@ -1021,14 +1045,25 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, frame = gspca_frame_add(gspca_dev, pkt_type, frame, data, 0); - data += i + sd->fr_h_sz; - len -= i + sd->fr_h_sz; + data += i + fr_h_sz; + len -= i + fr_h_sz; gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len); return; } } } + + if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) { + /* In raw mode we sometimes get some garbage after the frame + ignore this */ + int used = frame->data_end - frame->data; + int size = cam->cam_mode[gspca_dev->curr_mode].sizeimage; + + if (used + len > size) + len = size - used; + } + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); } @@ -1162,58 +1197,45 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, .querymenu = sd_querymenu, + .dq_callback = do_autogain, }; /* -- module initialisation -- */ -#define SFCI(sensor, flags, nctrls, i2c_addr) \ - .driver_info = (SENSOR_ ## sensor << 24) \ - | ((flags) << 16) \ - | ((nctrls) << 8) \ - | (i2c_addr) +#define SB(sensor, bridge) \ + .driver_info = (SENSOR_ ## sensor << 8) | BRIDGE_ ## bridge + + static __devinitdata struct usb_device_id device_table[] = { -#ifndef CONFIG_USB_SN9C102 - {USB_DEVICE(0x0c45, 0x6001), /* SN9C102 */ - SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)}, - {USB_DEVICE(0x0c45, 0x6005), /* SN9C101 */ - SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)}, - {USB_DEVICE(0x0c45, 0x6007), /* SN9C101 */ - SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)}, - {USB_DEVICE(0x0c45, 0x6009), /* SN9C101 */ - SFCI(PAS106, F_SIF, 2, 0)}, - {USB_DEVICE(0x0c45, 0x600d), /* SN9C101 */ - SFCI(PAS106, F_SIF, 2, 0)}, + {USB_DEVICE(0x0c45, 0x6001), SB(TAS5110, 102)}, /* TAS5110C1B */ + {USB_DEVICE(0x0c45, 0x6005), SB(TAS5110, 101)}, /* TAS5110C1B */ +#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE + {USB_DEVICE(0x0c45, 0x6007), SB(TAS5110, 101)}, /* TAS5110D */ + {USB_DEVICE(0x0c45, 0x6009), SB(PAS106, 101)}, + {USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)}, #endif - {USB_DEVICE(0x0c45, 0x6011), /* SN9C101 - SN9C101G */ - SFCI(OV6650, F_GAIN|F_AUTO|F_SIF, 5, 0x60)}, -#ifndef CONFIG_USB_SN9C102 - {USB_DEVICE(0x0c45, 0x6019), /* SN9C101 */ - SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)}, - {USB_DEVICE(0x0c45, 0x6024), /* SN9C102 */ - SFCI(TAS5130CXX, 0, 2, 0)}, - {USB_DEVICE(0x0c45, 0x6025), /* SN9C102 */ - SFCI(TAS5130CXX, 0, 2, 0)}, - {USB_DEVICE(0x0c45, 0x6028), /* SN9C102 */ - SFCI(PAS202, 0, 2, 0)}, - {USB_DEVICE(0x0c45, 0x6029), /* SN9C101 */ - SFCI(PAS106, F_SIF, 2, 0)}, - {USB_DEVICE(0x0c45, 0x602c), /* SN9C102 */ - SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)}, - {USB_DEVICE(0x0c45, 0x602d), /* SN9C102 */ - SFCI(HV7131R, 0, 2, 0)}, - {USB_DEVICE(0x0c45, 0x602e), /* SN9C102 */ - SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)}, - {USB_DEVICE(0x0c45, 0x60af), /* SN9C103 */ - SFCI(PAS202, F_H18, 2, 0)}, - {USB_DEVICE(0x0c45, 0x60b0), /* SN9C103 */ - SFCI(OV7630, F_GAIN|F_AUTO|F_H18, 5, 0x21)}, + {USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)}, +#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE + {USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)}, + {USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)}, + {USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)}, + {USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)}, + {USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)}, + {USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)}, #endif + {USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)}, +#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE + {USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)}, +#endif + {USB_DEVICE(0x0c45, 0x608f), SB(OV7630, 103)}, +#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE + {USB_DEVICE(0x0c45, 0x60af), SB(PAS202, 103)}, +#endif + {USB_DEVICE(0x0c45, 0x60b0), SB(OV7630, 103)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); @@ -1231,6 +1253,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 245a30ec5fb1..d75b1d20b318 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -54,8 +54,10 @@ struct sd { #define SENSOR_HV7131R 0 #define SENSOR_MI0360 1 #define SENSOR_MO4000 2 -#define SENSOR_OV7648 3 -#define SENSOR_OV7660 4 +#define SENSOR_OM6802 3 +#define SENSOR_OV7630 4 +#define SENSOR_OV7648 5 +#define SENSOR_OV7660 6 unsigned char i2c_base; }; @@ -76,7 +78,8 @@ static struct ctrl sd_ctrls[] = { .type = V4L2_CTRL_TYPE_INTEGER, .name = "Brightness", .minimum = 0, - .maximum = 0xffff, +#define BRIGHTNESS_MAX 0xffff + .maximum = BRIGHTNESS_MAX, .step = 1, #define BRIGHTNESS_DEF 0x7fff .default_value = BRIGHTNESS_DEF, @@ -90,7 +93,8 @@ static struct ctrl sd_ctrls[] = { .type = V4L2_CTRL_TYPE_INTEGER, .name = "Contrast", .minimum = 0, - .maximum = 127, +#define CONTRAST_MAX 127 + .maximum = CONTRAST_MAX, .step = 1, #define CONTRAST_DEF 63 .default_value = CONTRAST_DEF, @@ -104,14 +108,15 @@ static struct ctrl sd_ctrls[] = { .type = V4L2_CTRL_TYPE_INTEGER, .name = "Color", .minimum = 0, - .maximum = 255, + .maximum = 64, .step = 1, -#define COLOR_DEF 127 +#define COLOR_DEF 32 .default_value = COLOR_DEF, }, .set = sd_setcolors, .get = sd_getcolors, }, +#define AUTOGAIN_IDX 3 { { .id = V4L2_CID_AUTOGAIN, @@ -131,7 +136,7 @@ static struct ctrl sd_ctrls[] = { static struct v4l2_pix_format vga_mode[] = { {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 160, - .sizeimage = 160 * 120 * 3 / 8 + 590, + .sizeimage = 160 * 120 * 4 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 2}, {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, @@ -180,6 +185,31 @@ static const __u8 sn_mo4000[] = { 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const __u8 sn_om6802[] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x23, 0x72, 0x00, 0x1a, 0x34, 0x27, 0x20, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x80, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x51, 0x01, 0x00, 0x28, 0x1e, 0x40, +/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x22, 0x44, 0x63, 0x7d, 0x92, 0xa3, 0xaf, + 0xbc, 0xc4, 0xcd, 0xd5, 0xdc, 0xe1, 0xe8, 0xef, + 0xf7 +}; + +static const __u8 sn_ov7630[] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x21, 0x40, 0x00, 0x1a, 0x20, 0x1f, 0x20, +/* reg8 reg9 rega regb regc regd rege regf */ + 0xa1, 0x21, 0x76, 0x21, 0x00, 0x00, 0x00, 0x10, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x04, 0x01, 0x0a, 0x28, 0x1e, 0xc2, +/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ + 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + static const __u8 sn_ov7648[] = { /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ 0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20, @@ -207,31 +237,22 @@ static const __u8 *sn_tb[] = { sn_hv7131, sn_mi0360, sn_mo4000, + sn_om6802, + sn_ov7630, sn_ov7648, sn_ov7660 }; -static const __u8 regsn20[] = { +static const __u8 gamma_def[] = { 0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99, 0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff }; -static const __u8 regsn20_sn9c325[] = { - 0x0a, 0x3a, 0x56, 0x6c, 0x7e, 0x8d, 0x9a, 0xa4, - 0xaf, 0xbb, 0xc5, 0xcd, 0xd5, 0xde, 0xe8, 0xed, 0xf5 -}; static const __u8 reg84[] = { 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe5, 0x0f, 0xe4, 0x0f, 0x38, 0x00, 0x3e, 0x00, 0xc3, 0x0f, -/* 0x00, 0x00, 0x00, 0x00, 0x00 */ - 0xf7, 0x0f, 0x0a, 0x00, 0x00 -}; -static const __u8 reg84_sn9c325[] = { - 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe4, 0x0f, - 0xd3, 0x0f, 0x4b, 0x00, 0x48, 0x00, 0xc0, 0x0f, - 0xf8, 0x0f, 0x00, 0x00, 0x00 + 0xf7, 0x0f, 0x00, 0x00, 0x00 }; - static const __u8 hv7131r_sensor_init[][8] = { {0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10}, {0xB1, 0x11, 0x34, 0x17, 0x7F, 0x00, 0x00, 0x10}, @@ -340,6 +361,92 @@ static const __u8 mo4000_sensor_init[][8] = { {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10}, {} }; +static __u8 om6802_sensor_init[][8] = { + {0xa0, 0x34, 0x90, 0x05, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x34, 0x49, 0x85, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x34, 0x5a, 0xc0, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x34, 0xdd, 0x18, 0x00, 0x00, 0x00, 0x10}, +/* {0xa0, 0x34, 0xfb, 0x11, 0x00, 0x00, 0x00, 0x10}, */ + {0xa0, 0x34, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x10}, + /* white balance & auto-exposure */ +/* {0xa0, 0x34, 0xf1, 0x02, 0x00, 0x00, 0x00, 0x10}, + * set color mode */ +/* {0xa0, 0x34, 0xfe, 0x5b, 0x00, 0x00, 0x00, 0x10}, + * max AGC value in AE */ +/* {0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10}, + * preset AGC */ +/* {0xa0, 0x34, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x10}, + * preset brightness */ +/* {0xa0, 0x34, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x10}, + * preset contrast */ +/* {0xa0, 0x34, 0xe8, 0x31, 0x00, 0x00, 0x00, 0x10}, + * preset gamma */ + {0xa0, 0x34, 0xe9, 0x0f, 0x00, 0x00, 0x00, 0x10}, + /* luminance mode (0x4f = AE) */ + {0xa0, 0x34, 0xe4, 0xff, 0x00, 0x00, 0x00, 0x10}, + /* preset shutter */ +/* {0xa0, 0x34, 0xef, 0x00, 0x00, 0x00, 0x00, 0x10}, + * auto frame rate */ +/* {0xa0, 0x34, 0xfb, 0xee, 0x00, 0x00, 0x00, 0x10}, */ + +/* {0xa0, 0x34, 0x71, 0x84, 0x00, 0x00, 0x00, 0x10}, */ +/* {0xa0, 0x34, 0x72, 0x05, 0x00, 0x00, 0x00, 0x10}, */ +/* {0xa0, 0x34, 0x68, 0x80, 0x00, 0x00, 0x00, 0x10}, */ +/* {0xa0, 0x34, 0x69, 0x01, 0x00, 0x00, 0x00, 0x10}, */ + {} +}; +static const __u8 ov7630_sensor_init[][8] = { + {0xa1, 0x21, 0x76, 0x01, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10}, +/* win: delay 20ms */ + {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10}, +/* win: delay 20ms */ + {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, +/* win: i2c_r from 00 to 80 */ + {0xd1, 0x21, 0x03, 0x80, 0x10, 0x20, 0x80, 0x10}, + {0xb1, 0x21, 0x0c, 0x20, 0x20, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x11, 0x00, 0x48, 0xc0, 0x00, 0x10}, + {0xb1, 0x21, 0x15, 0x80, 0x03, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10}, + {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x1f, 0x00, 0x80, 0x80, 0x80, 0x10}, + {0xd1, 0x21, 0x23, 0xde, 0x10, 0x8a, 0xa0, 0x10}, + {0xc1, 0x21, 0x27, 0xca, 0xa2, 0x74, 0x00, 0x10}, + {0xd1, 0x21, 0x2a, 0x88, 0x00, 0x88, 0x01, 0x10}, + {0xc1, 0x21, 0x2e, 0x80, 0x00, 0x18, 0x00, 0x10}, + {0xa1, 0x21, 0x21, 0x08, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x32, 0xc2, 0x08, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x60, 0x05, 0x40, 0x12, 0x57, 0x10}, + {0xa1, 0x21, 0x64, 0x73, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x65, 0x00, 0x55, 0x01, 0xac, 0x10}, + {0xa1, 0x21, 0x69, 0x38, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x6f, 0x1f, 0x01, 0x00, 0x10, 0x10}, + {0xd1, 0x21, 0x73, 0x50, 0x20, 0x02, 0x01, 0x10}, + {0xd1, 0x21, 0x77, 0xf3, 0x90, 0x98, 0x98, 0x10}, + {0xc1, 0x21, 0x7b, 0x00, 0x4c, 0xf7, 0x00, 0x10}, + {0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10}, + {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10}, +/* */ + {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, +/*fixme: + 0x12, 0x04*/ + {0xa1, 0x21, 0x75, 0x82, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x01, 0x80, 0x80, 0x00, 0x00, 0x10}, +/* */ + {0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x2a, 0x88, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x2b, 0x34, 0x00, 0x00, 0x00, 0x10}, +/* */ + {0xa1, 0x21, 0x10, 0x83, 0x00, 0x00, 0x00, 0x10}, +/* {0xb1, 0x21, 0x01, 0x88, 0x70, 0x00, 0x00, 0x10}, */ + {} +}; static const __u8 ov7660_sensor_init[][8] = { {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */ /* (delay 20ms) */ @@ -506,10 +613,16 @@ static const __u8 qtable4[] = { 0x29, 0x29, 0x29, 0x29 }; -/* read <len> bytes (len < sizeof gspca_dev->usb_buf) to gspca_dev->usb_buf */ +/* read <len> bytes to gspca_dev->usb_buf */ static void reg_r(struct gspca_dev *gspca_dev, __u16 value, int len) { +#ifdef GSPCA_DEBUG + if (len > USB_BUF_SZ) { + err("reg_r: buffer overflow"); + return; + } +#endif usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0), 0, @@ -542,29 +655,20 @@ static void reg_w(struct gspca_dev *gspca_dev, { PDEBUG(D_USBO, "reg_w [%02x] = %02x %02x ..", value, buffer[0], buffer[1]); - if (len <= sizeof gspca_dev->usb_buf) { - memcpy(gspca_dev->usb_buf, buffer, len); - usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x08, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - value, 0, - gspca_dev->usb_buf, len, - 500); - } else { - __u8 *tmpbuf; - - tmpbuf = kmalloc(len, GFP_KERNEL); - memcpy(tmpbuf, buffer, len); - usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x08, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - value, 0, - tmpbuf, len, - 500); - kfree(tmpbuf); +#ifdef GSPCA_DEBUG + if (len > USB_BUF_SZ) { + err("reg_w: buffer overflow"); + return; } +#endif + memcpy(gspca_dev->usb_buf, buffer, len); + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x08, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, 0, + gspca_dev->usb_buf, len, + 500); } /* I2C write 1 byte */ @@ -665,7 +769,7 @@ static int configure_gpio(struct gspca_dev *gspca_dev, static const __u8 regd4[] = {0x60, 0x00, 0x00}; reg_w1(gspca_dev, 0xf1, 0x00); - reg_w1(gspca_dev, 0x01, 0x00); /*jfm was sn9c1xx[1] in v1*/ + reg_w1(gspca_dev, 0x01, sn9c1xx[1]); /* configure gpio */ reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2); @@ -685,21 +789,41 @@ static int configure_gpio(struct gspca_dev *gspca_dev, reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f); - switch (sd->bridge) { - case BRIDGE_SN9C325: + switch (sd->sensor) { + case SENSOR_OM6802: + reg_w1(gspca_dev, 0x02, 0x71); + reg_w1(gspca_dev, 0x01, 0x42); + reg_w1(gspca_dev, 0x17, 0x64); + reg_w1(gspca_dev, 0x01, 0x42); + break; +/*jfm: from win trace */ + case SENSOR_OV7630: + reg_w1(gspca_dev, 0x01, 0x61); + reg_w1(gspca_dev, 0x17, 0xe2); + reg_w1(gspca_dev, 0x01, 0x60); + reg_w1(gspca_dev, 0x01, 0x40); + break; + case SENSOR_OV7648: reg_w1(gspca_dev, 0x01, 0x43); reg_w1(gspca_dev, 0x17, 0xae); reg_w1(gspca_dev, 0x01, 0x42); break; +/*jfm: from win trace */ + case SENSOR_OV7660: + reg_w1(gspca_dev, 0x01, 0x61); + reg_w1(gspca_dev, 0x17, 0x20); + reg_w1(gspca_dev, 0x01, 0x60); + reg_w1(gspca_dev, 0x01, 0x40); + break; default: reg_w1(gspca_dev, 0x01, 0x43); reg_w1(gspca_dev, 0x17, 0x61); reg_w1(gspca_dev, 0x01, 0x42); - } - - if (sd->sensor == SENSOR_HV7131R) { - if (probesensor(gspca_dev) < 0) - return -ENODEV; + if (sd->sensor == SENSOR_HV7131R) { + if (probesensor(gspca_dev) < 0) + return -ENODEV; + } + break; } return 0; } @@ -737,6 +861,40 @@ static void mo4000_InitSensor(struct gspca_dev *gspca_dev) } } +static void om6802_InitSensor(struct gspca_dev *gspca_dev) +{ + int i = 0; + + while (om6802_sensor_init[i][0]) { + i2c_w8(gspca_dev, om6802_sensor_init[i]); + i++; + } +} + +static void ov7630_InitSensor(struct gspca_dev *gspca_dev) +{ + int i = 0; + + i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 76 01 */ + i++; + i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 c8 (RGB+SRST) */ + i++; + msleep(20); + i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 48 */ + i++; + i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 c8 */ + i++; + msleep(20); + i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 48 */ + i++; +/*jfm:win i2c_r from 00 to 80*/ + + while (ov7630_sensor_init[i][0]) { + i2c_w8(gspca_dev, ov7630_sensor_init[i]); + i++; + } +} + static void ov7648_InitSensor(struct gspca_dev *gspca_dev) { int i = 0; @@ -783,11 +941,19 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->autogain = AUTOGAIN_DEF; sd->ag_cnt = -1; + switch (sd->sensor) { + case SENSOR_OV7630: + case SENSOR_OV7648: + case SENSOR_OV7660: + gspca_dev->ctrl_dis = (1 << AUTOGAIN_IDX); + break; + } + return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; /* const __u8 *sn9c1xx; */ @@ -891,16 +1057,53 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev, | ((expoMo10[3] & 0x30) >> 4)); break; } + case SENSOR_OM6802: { + __u8 gainOm[] = + { 0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10 }; + + if (expo > 0x03ff) + expo = 0x03ff; + if (expo < 0x0001) + expo = 0x0001; + gainOm[3] = expo >> 2; + i2c_w8(gspca_dev, gainOm); + reg_w1(gspca_dev, 0x96, (expo >> 5) & 0x1f); + PDEBUG(D_CONF, "set exposure %d", gainOm[3]); + break; + } } return expo; } +/* this function is used for sensors o76xx only */ +static void setbrightcont(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + unsigned val; + __u8 reg84_full[0x15]; + + memset(reg84_full, 0, sizeof reg84_full); + val = sd->contrast * 0x20 / CONTRAST_MAX + 0x10; /* 10..30 */ + reg84_full[2] = val; + reg84_full[0] = (val + 1) / 2; + reg84_full[4] = (val + 1) / 5; + if (val > BRIGHTNESS_DEF) + val = (sd->brightness - BRIGHTNESS_DEF) * 0x20 + / BRIGHTNESS_MAX; + else + val = 0; + reg84_full[0x12] = val; /* 00..1f */ + reg_w(gspca_dev, 0x84, reg84_full, sizeof reg84_full); +} + +/* sensor != ov76xx */ static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; unsigned int expo; __u8 k2; + k2 = sd->brightness >> 10; switch (sd->sensor) { case SENSOR_HV7131R: expo = sd->brightness << 4; @@ -915,12 +1118,17 @@ static void setbrightness(struct gspca_dev *gspca_dev) expo = sd->brightness >> 4; sd->exposure = setexposure(gspca_dev, expo); break; + case SENSOR_OM6802: + expo = sd->brightness >> 6; + sd->exposure = setexposure(gspca_dev, expo); + k2 = sd->brightness >> 11; + break; } - k2 = sd->brightness >> 10; reg_w1(gspca_dev, 0x96, k2); } +/* sensor != ov76xx */ static void setcontrast(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -937,31 +1145,30 @@ static void setcontrast(struct gspca_dev *gspca_dev) static void setcolors(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - __u8 data; - int colour; + __u8 blue, red; - colour = sd->colors - 128; - if (colour > 0) - data = (colour + 32) & 0x7f; /* blue */ - else - data = (-colour + 32) & 0x7f; /* red */ - reg_w1(gspca_dev, 0x05, data); + if (sd->colors >= 32) { + red = 32 + (sd->colors - 32) / 2; + blue = 64 - sd->colors; + } else { + red = sd->colors; + blue = 32 + (32 - sd->colors) / 2; + } + reg_w1(gspca_dev, 0x05, red); +/* reg_w1(gspca_dev, 0x07, 32); */ + reg_w1(gspca_dev, 0x06, blue); } static void setautogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - switch (sd->sensor) { - case SENSOR_HV7131R: - case SENSOR_MO4000: - case SENSOR_MI0360: - if (sd->autogain) - sd->ag_cnt = AG_CNT_START; - else - sd->ag_cnt = -1; - break; - } + if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX)) + return; + if (sd->autogain) + sd->ag_cnt = AG_CNT_START; + else + sd->ag_cnt = -1; } /* -- start the camera -- */ @@ -975,13 +1182,12 @@ static void sd_start(struct gspca_dev *gspca_dev) static const __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f }; static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec }; static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */ - static const __u8 CE_sn9c325[] = - { 0x32, 0xdd, 0x32, 0xdd }; /* OV7648 - SN9C325 */ + static const __u8 CE_ov76xx[] = + { 0x32, 0xdd, 0x32, 0xdd }; /* OV7630/48 */ sn9c1xx = sn_tb[(int) sd->sensor]; configure_gpio(gspca_dev, sn9c1xx); -/* reg_w1(gspca_dev, 0x01, 0x44); jfm from win trace*/ reg_w1(gspca_dev, 0x15, sn9c1xx[0x15]); reg_w1(gspca_dev, 0x16, sn9c1xx[0x16]); reg_w1(gspca_dev, 0x12, sn9c1xx[0x12]); @@ -994,10 +1200,17 @@ static void sd_start(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0xc8, 0x50); reg_w1(gspca_dev, 0xc9, 0x3c); reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]); - switch (sd->bridge) { - case BRIDGE_SN9C325: + switch (sd->sensor) { + case SENSOR_OV7630: + reg17 = 0xe2; + break; + case SENSOR_OV7648: reg17 = 0xae; break; +/*jfm: from win trace */ + case SENSOR_OV7660: + reg17 = 0xa0; + break; default: reg17 = 0x60; break; @@ -1007,24 +1220,11 @@ static void sd_start(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x07, sn9c1xx[7]); reg_w1(gspca_dev, 0x06, sn9c1xx[6]); reg_w1(gspca_dev, 0x14, sn9c1xx[0x14]); - switch (sd->bridge) { - case BRIDGE_SN9C325: - reg_w(gspca_dev, 0x20, regsn20_sn9c325, - sizeof regsn20_sn9c325); - for (i = 0; i < 8; i++) - reg_w(gspca_dev, 0x84, reg84_sn9c325, - sizeof reg84_sn9c325); - reg_w1(gspca_dev, 0x9a, 0x0a); - reg_w1(gspca_dev, 0x99, 0x60); - break; - default: - reg_w(gspca_dev, 0x20, regsn20, sizeof regsn20); - for (i = 0; i < 8; i++) - reg_w(gspca_dev, 0x84, reg84, sizeof reg84); + reg_w(gspca_dev, 0x20, gamma_def, sizeof gamma_def); + for (i = 0; i < 8; i++) + reg_w(gspca_dev, 0x84, reg84, sizeof reg84); reg_w1(gspca_dev, 0x9a, 0x08); reg_w1(gspca_dev, 0x99, 0x59); - break; - } mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; if (mode) @@ -1049,6 +1249,15 @@ static void sd_start(struct gspca_dev *gspca_dev) /* reg1 = 0x06; * 640 clk 24Mz (done) */ } break; + case SENSOR_OM6802: + om6802_InitSensor(gspca_dev); + reg17 = 0x64; /* 640 MCKSIZE */ + break; + case SENSOR_OV7630: + ov7630_InitSensor(gspca_dev); + reg17 = 0xe2; + reg1 = 0x44; + break; case SENSOR_OV7648: ov7648_InitSensor(gspca_dev); reg17 = 0xa2; @@ -1073,9 +1282,10 @@ static void sd_start(struct gspca_dev *gspca_dev) } reg_w(gspca_dev, 0xc0, C0, 6); reg_w(gspca_dev, 0xca, CA, 4); - switch (sd->bridge) { - case BRIDGE_SN9C325: - reg_w(gspca_dev, 0xce, CE_sn9c325, 4); + switch (sd->sensor) { + case SENSOR_OV7630: + case SENSOR_OV7648: + reg_w(gspca_dev, 0xce, CE_ov76xx, 4); break; default: reg_w(gspca_dev, 0xce, CE, 4); @@ -1093,10 +1303,20 @@ static void sd_start(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x18, reg18); reg_w1(gspca_dev, 0x17, reg17); - reg_w1(gspca_dev, 0x01, reg1); - setbrightness(gspca_dev); - setcontrast(gspca_dev); + switch (sd->sensor) { + case SENSOR_HV7131R: + case SENSOR_MI0360: + case SENSOR_MO4000: + case SENSOR_OM6802: + setbrightness(gspca_dev); + setcontrast(gspca_dev); + break; + default: /* OV76xx */ + setbrightcont(gspca_dev); + break; + } setautogain(gspca_dev); + reg_w1(gspca_dev, 0x01, reg1); } static void sd_stopN(struct gspca_dev *gspca_dev) @@ -1119,6 +1339,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) i2c_w8(gspca_dev, stopmi0360); data = 0x29; break; + case SENSOR_OV7630: case SENSOR_OV7648: data = 0x29; break; @@ -1132,15 +1353,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x17, sn9c1xx[0x17]); reg_w1(gspca_dev, 0x01, sn9c1xx[1]); reg_w1(gspca_dev, 0x01, data); - reg_w1(gspca_dev, 0xf1, 0x01); -} - -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ + reg_w1(gspca_dev, 0xf1, 0x00); } static void do_autogain(struct gspca_dev *gspca_dev) @@ -1174,6 +1387,7 @@ static void do_autogain(struct gspca_dev *gspca_dev) default: /* case SENSOR_MO4000: */ /* case SENSOR_MI0360: */ +/* case SENSOR_OM6802: */ expotimes = sd->exposure; expotimes += (luma_mean - delta) >> 6; if (expotimes < 0) @@ -1229,69 +1443,24 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); } -static unsigned int getexposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u8 hexpo, mexpo, lexpo; - - switch (sd->sensor) { - case SENSOR_HV7131R: - /* read sensor exposure */ - i2c_r5(gspca_dev, 0x25); - return (gspca_dev->usb_buf[0] << 16) - | (gspca_dev->usb_buf[1] << 8) - | gspca_dev->usb_buf[2]; - case SENSOR_MI0360: - /* read sensor exposure */ - i2c_r5(gspca_dev, 0x09); - return (gspca_dev->usb_buf[0] << 8) - | gspca_dev->usb_buf[1]; - case SENSOR_MO4000: - i2c_r5(gspca_dev, 0x0e); - hexpo = 0; /* gspca_dev->usb_buf[1] & 0x07; */ - mexpo = 0x40; /* gspca_dev->usb_buf[2] & 0xff; */ - lexpo = (gspca_dev->usb_buf[1] & 0x30) >> 4; - PDEBUG(D_CONF, "exposure %d", - (hexpo << 10) | (mexpo << 2) | lexpo); - return (hexpo << 10) | (mexpo << 2) | lexpo; - default: -/* case SENSOR_OV7648: * jfm: is it ok for 7648? */ -/* case SENSOR_OV7660: */ - /* read sensor exposure */ - i2c_r5(gspca_dev, 0x04); - hexpo = gspca_dev->usb_buf[3] & 0x2f; - lexpo = gspca_dev->usb_buf[0] & 0x02; - i2c_r5(gspca_dev, 0x08); - mexpo = gspca_dev->usb_buf[2]; - return (hexpo << 10) | (mexpo << 2) | lexpo; - } -} - -static void getbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* hardcoded registers seem not readable */ - switch (sd->sensor) { - case SENSOR_HV7131R: - sd->brightness = getexposure(gspca_dev) >> 4; - break; - case SENSOR_MI0360: - sd->brightness = getexposure(gspca_dev) << 4; - break; - case SENSOR_MO4000: - sd->brightness = getexposure(gspca_dev) << 4; - break; - } -} - static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); + if (gspca_dev->streaming) { + switch (sd->sensor) { + case SENSOR_HV7131R: + case SENSOR_MI0360: + case SENSOR_MO4000: + case SENSOR_OM6802: + setbrightness(gspca_dev); + break; + default: /* OV76xx */ + setbrightcont(gspca_dev); + break; + } + } return 0; } @@ -1299,7 +1468,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; - getbrightness(gspca_dev); *val = sd->brightness; return 0; } @@ -1309,8 +1477,19 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); + if (gspca_dev->streaming) { + switch (sd->sensor) { + case SENSOR_HV7131R: + case SENSOR_MI0360: + case SENSOR_MO4000: + case SENSOR_OM6802: + setcontrast(gspca_dev); + break; + default: /* OV76xx */ + setbrightcont(gspca_dev); + break; + } + } return 0; } @@ -1364,11 +1543,9 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, .dq_callback = do_autogain, }; @@ -1379,7 +1556,7 @@ static const struct sd_desc sd_desc = { | (SENSOR_ ## sensor << 8) \ | (i2c_addr) static const __devinitdata struct usb_device_id device_table[] = { -#ifndef CONFIG_USB_SN9C102 +#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0458, 0x7025), BSI(SN9C120, MI0360, 0x5d)}, {USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)}, {USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)}, @@ -1406,15 +1583,17 @@ static const __devinitdata struct usb_device_id device_table[] = { /* {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */ /* {USB_DEVICE(0x0c45, 0x6122), BSI(SN9C110, ICM105C, 0x??)}, */ /* {USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */ - {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C325, OV7648, 0x21)}, -/* bw600.inf: - {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C110, OV7648, 0x21)}, */ + {USB_DEVICE(0x0c45, 0x6128), BSI(SN9C110, OM6802, 0x21)}, /*sn9c325?*/ +/*bw600.inf:*/ + {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C110, OV7648, 0x21)}, /*sn9c325?*/ {USB_DEVICE(0x0c45, 0x612c), BSI(SN9C110, MO4000, 0x21)}, -/* {USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x??)}, */ + {USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x21)}, /* {USB_DEVICE(0x0c45, 0x612f), BSI(SN9C110, ICM105C, 0x??)}, */ -#ifndef CONFIG_USB_SN9C102 +#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0c45, 0x6130), BSI(SN9C120, MI0360, 0x5d)}, +#endif {USB_DEVICE(0x0c45, 0x6138), BSI(SN9C120, MO4000, 0x21)}, +#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE /* {USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x??)}, */ {USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)}, {USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)}, @@ -1438,6 +1617,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c index 17fe2c2a440d..6e733901fcca 100644 --- a/drivers/media/video/gspca/spca500.c +++ b/drivers/media/video/gspca/spca500.c @@ -645,8 +645,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -880,14 +880,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) gspca_dev->usb_buf[0]); } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -1051,11 +1043,9 @@ static struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; @@ -1093,6 +1083,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c index 51a3c3429ef0..e9eb59bae4fb 100644 --- a/drivers/media/video/gspca/spca501.c +++ b/drivers/media/video/gspca/spca501.c @@ -1953,8 +1953,8 @@ error: return -EINVAL; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -2023,11 +2023,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) static void sd_stop0(struct gspca_dev *gspca_dev) { -} - -/* this function is called at close time */ -static void sd_close(struct gspca_dev *gspca_dev) -{ reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00); } @@ -2120,11 +2115,10 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; @@ -2154,6 +2148,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c index eda29d609359..f601daf19ebe 100644 --- a/drivers/media/video/gspca/spca505.c +++ b/drivers/media/video/gspca/spca505.c @@ -655,8 +655,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int ret; @@ -743,11 +743,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) static void sd_stop0(struct gspca_dev *gspca_dev) { -} - -/* this function is called at close time */ -static void sd_close(struct gspca_dev *gspca_dev) -{ /* This maybe reset or power control */ reg_write(gspca_dev->dev, 0x03, 0x03, 0x20); reg_write(gspca_dev->dev, 0x03, 0x01, 0x0); @@ -825,11 +820,10 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; @@ -855,6 +849,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c index f622fa75766d..195dce96ef06 100644 --- a/drivers/media/video/gspca/spca506.c +++ b/drivers/media/video/gspca/spca506.c @@ -313,8 +313,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { struct usb_device *dev = gspca_dev->dev; @@ -560,14 +560,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_w(dev, 0x03, 0x00, 0x0003); } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -740,11 +732,9 @@ static struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; @@ -772,6 +762,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c index 699340c17dea..281ce02103a3 100644 --- a/drivers/media/video/gspca/spca508.c +++ b/drivers/media/video/gspca/spca508.c @@ -1521,8 +1521,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; /* success */ } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { /* write_vector(gspca_dev, spca508_open_data); */ return 0; @@ -1554,15 +1554,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_write(gspca_dev->dev, 0x8112, 0x20); } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -/* this function is called at close time */ -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -1633,11 +1624,9 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; @@ -1667,6 +1656,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c index 1073ac3d2ec6..cfbc9ebc5c5d 100644 --- a/drivers/media/video/gspca/spca561.c +++ b/drivers/media/video/gspca/spca561.c @@ -32,69 +32,48 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - unsigned short contrast; - __u8 brightness; + __u16 contrast; /* rev72a only */ +#define CONTRAST_MIN 0x0000 +#define CONTRAST_DEF 0x2000 +#define CONTRAST_MAX 0x3fff + + __u16 exposure; /* rev12a only */ +#define EXPOSURE_MIN 1 +#define EXPOSURE_DEF 200 +#define EXPOSURE_MAX (4095 - 900) /* see set_exposure */ + + __u8 brightness; /* rev72a only */ +#define BRIGHTNESS_MIN 0 +#define BRIGHTNESS_DEF 32 +#define BRIGHTNESS_MAX 63 + + __u8 white; /* rev12a only */ +#define WHITE_MIN 1 +#define WHITE_DEF 0x40 +#define WHITE_MAX 0x7f + __u8 autogain; +#define AUTOGAIN_MIN 0 +#define AUTOGAIN_DEF 1 +#define AUTOGAIN_MAX 1 + + __u8 gain; /* rev12a only */ +#define GAIN_MIN 0x0 +#define GAIN_DEF 0x24 +#define GAIN_MAX 0x24 + +#define EXPO12A_DEF 3 + __u8 expo12a; /* expo/gain? for rev 12a */ __u8 chip_revision; +#define Rev012A 0 +#define Rev072A 1 + signed char ag_cnt; #define AG_CNT_START 13 }; -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); - -static struct ctrl sd_ctrls[] = { -#define SD_BRIGHTNESS 0 - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 63, - .step = 1, - .default_value = 32, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -#define SD_CONTRAST 1 - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 0x3fff, - .step = 1, - .default_value = 0x2000, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, -#define SD_AUTOGAIN 2 - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - .set = sd_setautogain, - .get = sd_getautogain, - }, -}; - -static struct v4l2_pix_format sif_mode[] = { +static struct v4l2_pix_format sif_012a_mode[] = { {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, .bytesperline = 160, .sizeimage = 160 * 120, @@ -117,6 +96,29 @@ static struct v4l2_pix_format sif_mode[] = { .priv = 0}, }; +static struct v4l2_pix_format sif_072a_mode[] = { + {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 3}, + {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {320, 240, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + /* * Initialization data * I'm not very sure how to split initialization from open data @@ -143,12 +145,8 @@ static struct v4l2_pix_format sif_mode[] = { #define SPCA561_INDEX_I2C_BASE 0x8800 #define SPCA561_SNAPBIT 0x20 #define SPCA561_SNAPCTRL 0x40 -enum { - Rev072A = 0, - Rev012A, -}; -static void reg_w_val(struct usb_device *dev, __u16 index, __u16 value) +static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value) { int ret; @@ -198,12 +196,6 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, index, gspca_dev->usb_buf, len, 500); } -static void i2c_init(struct gspca_dev *gspca_dev, __u8 mode) -{ - reg_w_val(gspca_dev->dev, 0x92, 0x8804); - reg_w_val(gspca_dev->dev, mode, 0x8802); -} - static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg) { int retry = 60; @@ -212,9 +204,9 @@ static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg) DataLow = valeur; DataHight = valeur >> 8; - reg_w_val(gspca_dev->dev, reg, 0x8801); - reg_w_val(gspca_dev->dev, DataLow, 0x8805); - reg_w_val(gspca_dev->dev, DataHight, 0x8800); + reg_w_val(gspca_dev->dev, 0x8801, reg); + reg_w_val(gspca_dev->dev, 0x8805, DataLow); + reg_w_val(gspca_dev->dev, 0x8800, DataHight); while (retry--) { reg_r(gspca_dev, 0x8803, 1); if (!gspca_dev->usb_buf[0]) @@ -228,14 +220,14 @@ static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode) __u8 value; __u8 vallsb; - reg_w_val(gspca_dev->dev, 0x92, 0x8804); - reg_w_val(gspca_dev->dev, reg, 0x8801); - reg_w_val(gspca_dev->dev, (mode | 0x01), 0x8802); - while (retry--) { + reg_w_val(gspca_dev->dev, 0x8804, 0x92); + reg_w_val(gspca_dev->dev, 0x8801, reg); + reg_w_val(gspca_dev->dev, 0x8802, (mode | 0x01)); + do { reg_r(gspca_dev, 0x8803, 1); if (!gspca_dev->usb_buf) break; - } + } while (--retry); if (retry == 0) return -1; reg_r(gspca_dev, 0x8800, 1); @@ -438,21 +430,10 @@ static const __u16 spca561_init_data[][2] = { {0x0035, 0x8801}, /* 0x14 - set gain general */ {0x001f, 0x8805}, /* 0x14 */ {0x0000, 0x8800}, - {0x0030, 0x8112}, + {0x000e, 0x8112}, /* white balance - was 30 */ {} }; -static void sensor_reset(struct gspca_dev *gspca_dev) -{ - reg_w_val(gspca_dev->dev, 0x8631, 0xc8); - reg_w_val(gspca_dev->dev, 0x8634, 0xc8); - reg_w_val(gspca_dev->dev, 0x8112, 0x00); - reg_w_val(gspca_dev->dev, 0x8114, 0x00); - reg_w_val(gspca_dev->dev, 0x8118, 0x21); - i2c_init(gspca_dev, 0x14); - i2c_write(gspca_dev, 1, 0x0d); - i2c_write(gspca_dev, 0, 0x0d); -} /******************** QC Express etch2 stuff ********************/ static const __u16 Pb100_1map8300[][2] = { @@ -462,9 +443,9 @@ static const __u16 Pb100_1map8300[][2] = { {0x8303, 0x0125}, /* image area */ {0x8304, 0x0169}, {0x8328, 0x000b}, - {0x833c, 0x0001}, + {0x833c, 0x0001}, /*fixme: win:07*/ - {0x832f, 0x0419}, + {0x832f, 0x1904}, /*fixme: was 0419*/ {0x8307, 0x00aa}, {0x8301, 0x0003}, {0x8302, 0x000e}, @@ -478,9 +459,10 @@ static const __u16 Pb100_2map8300[][2] = { }; static const __u16 spca561_161rev12A_data1[][2] = { - {0x21, 0x8118}, - {0x01, 0x8114}, - {0x00, 0x8112}, + {0x29, 0x8118}, /* white balance - was 21 */ + {0x08, 0x8114}, /* white balance - was 01 */ + {0x0e, 0x8112}, /* white balance - was 00 */ + {0x00, 0x8102}, /* white balance - new */ {0x92, 0x8804}, {0x04, 0x8802}, /* windows uses 08 */ {} @@ -505,14 +487,16 @@ static const __u16 spca561_161rev12A_data2[][2] = { {0xb0, 0x8603}, /* sensor gains */ + {0x07, 0x8601}, /* white balance - new */ + {0x07, 0x8602}, /* white balance - new */ {0x00, 0x8610}, /* *red */ {0x00, 0x8611}, /* 3f *green */ {0x00, 0x8612}, /* green *blue */ {0x00, 0x8613}, /* blue *green */ - {0x35, 0x8614}, /* green *red */ - {0x35, 0x8615}, /* 40 *green */ - {0x35, 0x8616}, /* 7a *blue */ - {0x35, 0x8617}, /* 40 *green */ + {0x43, 0x8614}, /* green *red - white balance - was 0x35 */ + {0x40, 0x8615}, /* 40 *green - white balance - was 0x35 */ + {0x71, 0x8616}, /* 7a *blue - white balance - was 0x35 */ + {0x40, 0x8617}, /* 40 *green - white balance - was 0x35 */ {0x0c, 0x8620}, /* 0c */ {0xc8, 0x8631}, /* c8 */ @@ -527,6 +511,7 @@ static const __u16 spca561_161rev12A_data2[][2] = { {0xdf, 0x863c}, /* df */ {0xf0, 0x8505}, {0x32, 0x850a}, +/* {0x99, 0x8700}, * - white balance - new (removed) */ {} }; @@ -545,9 +530,10 @@ static void sensor_mapwrite(struct gspca_dev *gspca_dev, } static void init_161rev12A(struct gspca_dev *gspca_dev) { - sensor_reset(gspca_dev); +/* sensor_reset(gspca_dev); (not in win) */ write_vector(gspca_dev, spca561_161rev12A_data1); sensor_mapwrite(gspca_dev, Pb100_1map8300); +/*fixme: should be in sd_start*/ write_vector(gspca_dev, spca561_161rev12A_data2); sensor_mapwrite(gspca_dev, Pb100_2map8300); } @@ -581,35 +567,38 @@ static int sd_config(struct gspca_dev *gspca_dev, } cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */ - cam->cam_mode = sif_mode; - cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; sd->chip_revision = id->driver_info; - sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; - sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; - sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value; + if (sd->chip_revision == Rev012A) { + cam->cam_mode = sif_012a_mode; + cam->nmodes = ARRAY_SIZE(sif_012a_mode); + } else { + cam->cam_mode = sif_072a_mode; + cam->nmodes = ARRAY_SIZE(sif_072a_mode); + } + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->white = WHITE_DEF; + sd->exposure = EXPOSURE_DEF; + sd->autogain = AUTOGAIN_DEF; + sd->gain = GAIN_DEF; + sd->expo12a = EXPO12A_DEF; return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init_12a(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->chip_revision) { - case Rev072A: - PDEBUG(D_STREAM, "Chip revision id: 072a"); - write_vector(gspca_dev, spca561_init_data); - break; - default: -/* case Rev012A: */ - PDEBUG(D_STREAM, "Chip revision id: 012a"); - init_161rev12A(gspca_dev); - break; - } + PDEBUG(D_STREAM, "Chip revision: 012a"); + init_161rev12A(gspca_dev); + return 0; +} +static int sd_init_72a(struct gspca_dev *gspca_dev) +{ + PDEBUG(D_STREAM, "Chip revision: 072a"); + write_vector(gspca_dev, spca561_init_data); return 0; } @@ -618,25 +607,20 @@ static void setcontrast(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; __u8 lowb; - int expotimes; switch (sd->chip_revision) { case Rev072A: lowb = sd->contrast >> 8; - reg_w_val(dev, lowb, 0x8651); - reg_w_val(dev, lowb, 0x8652); - reg_w_val(dev, lowb, 0x8653); - reg_w_val(dev, lowb, 0x8654); + reg_w_val(dev, 0x8651, lowb); + reg_w_val(dev, 0x8652, lowb); + reg_w_val(dev, 0x8653, lowb); + reg_w_val(dev, 0x8654, lowb); break; - case Rev012A: { - __u8 Reg8391[] = - { 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00 }; - - /* Write camera sensor settings */ - expotimes = (sd->contrast >> 5) & 0x07ff; - Reg8391[0] = expotimes & 0xff; /* exposure */ - Reg8391[1] = 0x18 | (expotimes >> 8); - Reg8391[2] = sd->brightness; /* gain */ + default: { +/* case Rev012A: { */ + static const __u8 Reg8391[] = + { 0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00 }; + reg_w_buf(gspca_dev, 0x8391, Reg8391, 8); reg_w_buf(gspca_dev, 0x8390, Reg8391, 8); break; @@ -644,93 +628,151 @@ static void setcontrast(struct gspca_dev *gspca_dev) } } -static void setautogain(struct gspca_dev *gspca_dev) +/* rev12a only */ +static void setwhite(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + __u16 white; + __u8 reg8614, reg8616; + + white = sd->white; + /* try to emulate MS-win as possible */ + reg8616 = 0x90 - white * 5 / 8; + reg_w_val(gspca_dev->dev, 0x8616, reg8616); + reg8614 = 0x20 + white * 3 / 8; + reg_w_val(gspca_dev->dev, 0x8614, reg8614); +} - if (sd->chip_revision == Rev072A) { - if (sd->autogain) - sd->ag_cnt = AG_CNT_START; - else - sd->ag_cnt = -1; +/* rev 12a only */ +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int expo; + int clock_divider; + __u8 data[2]; + + /* Register 0x8309 controls exposure for the spca561, + the basic exposure setting goes from 1-2047, where 1 is completely + dark and 2047 is very bright. It not only influences exposure but + also the framerate (to allow for longer exposure) from 1 - 300 it + only raises the exposure time then from 300 - 600 it halves the + framerate to be able to further raise the exposure time and for every + 300 more it halves the framerate again. This allows for a maximum + exposure time of circa 0.2 - 0.25 seconds (30 / (2000/3000) fps). + Sometimes this is not enough, the 1-2047 uses bits 0-10, bits 11-12 + configure a divider for the base framerate which us used at the + exposure setting of 1-300. These bits configure the base framerate + according to the following formula: fps = 60 / (value + 2) */ + if (sd->exposure < 2048) { + expo = sd->exposure; + clock_divider = 0; + } else { + /* Add 900 to make the 0 setting of the second part of the + exposure equal to the 2047 setting of the first part. */ + expo = (sd->exposure - 2048) + 900; + clock_divider = 3; } + expo |= clock_divider << 11; + data[0] = expo; + data[1] = expo >> 8; + reg_w_buf(gspca_dev, 0x8309, data, 2); } -static void sd_start(struct gspca_dev *gspca_dev) +/* rev 12a only */ +static void setgain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + __u8 data[2]; + + data[0] = sd->gain; + data[1] = 0; + reg_w_buf(gspca_dev, 0x8335, data, 2); +} + +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->autogain) + sd->ag_cnt = AG_CNT_START; + else + sd->ag_cnt = -1; +} + +static void sd_start_12a(struct gspca_dev *gspca_dev) +{ struct usb_device *dev = gspca_dev->dev; - int Clck; + int Clck = 0x8a; /* lower 0x8X values lead to fps > 30 */ __u8 Reg8307[] = { 0xaa, 0x00 }; int mode; mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; - switch (sd->chip_revision) { - case Rev072A: - switch (mode) { - default: -/* case 0: - case 1: */ - Clck = 0x25; - break; - case 2: - Clck = 0x22; - break; - case 3: - Clck = 0x21; - break; - } - reg_w_val(dev, 0x8500, mode); /* mode */ - reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */ - reg_w_val(dev, 0x8112, 0x10 | 0x20); - setautogain(gspca_dev); - break; + if (mode <= 1) { + /* Use compression on 320x240 and above */ + reg_w_val(dev, 0x8500, 0x10 | mode); + } else { + /* I couldn't get the compression to work below 320x240 + * Fortunately at these resolutions the bandwidth + * is sufficient to push raw frames at ~20fps */ + reg_w_val(dev, 0x8500, mode); + } /* -- qq@kuku.eu.org */ + reg_w_buf(gspca_dev, 0x8307, Reg8307, 2); + reg_w_val(gspca_dev->dev, 0x8700, Clck); + /* 0x8f 0x85 0x27 clock */ + reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20); + reg_w_val(gspca_dev->dev, 0x850b, 0x03); + setcontrast(gspca_dev); + setwhite(gspca_dev); + setautogain(gspca_dev); + setexposure(gspca_dev); +} +static void sd_start_72a(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + int Clck; + int mode; + + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + switch (mode) { default: -/* case Rev012A: */ - switch (mode) { - case 0: - case 1: - Clck = 0x8a; - break; - case 2: - Clck = 0x85; - break; - default: - Clck = 0x83; - break; - } - if (mode <= 1) { - /* Use compression on 320x240 and above */ - reg_w_val(dev, 0x8500, 0x10 | mode); - } else { - /* I couldn't get the compression to work below 320x240 - * Fortunately at these resolutions the bandwidth - * is sufficient to push raw frames at ~20fps */ - reg_w_val(dev, 0x8500, mode); - } /* -- qq@kuku.eu.org */ - reg_w_buf(gspca_dev, 0x8307, Reg8307, 2); - reg_w_val(gspca_dev->dev, 0x8700, Clck); - /* 0x8f 0x85 0x27 clock */ - reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20); - reg_w_val(gspca_dev->dev, 0x850b, 0x03); - setcontrast(gspca_dev); +/* case 0: + case 1: */ + Clck = 0x25; + break; + case 2: + Clck = 0x22; + break; + case 3: + Clck = 0x21; break; } + reg_w_val(dev, 0x8500, mode); /* mode */ + reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */ + reg_w_val(dev, 0x8112, 0x10 | 0x20); + setautogain(gspca_dev); } static void sd_stopN(struct gspca_dev *gspca_dev) { - reg_w_val(gspca_dev->dev, 0x8112, 0x20); + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->chip_revision == Rev012A) { + reg_w_val(gspca_dev->dev, 0x8112, 0x0e); + } else { + reg_w_val(gspca_dev->dev, 0x8112, 0x20); +/* reg_w_val(gspca_dev->dev, 0x8102, 0x00); ?? */ + } } static void sd_stop0(struct gspca_dev *gspca_dev) { -} + struct sd *sd = (struct sd *) gspca_dev; -/* this function is called at close time */ -static void sd_close(struct gspca_dev *gspca_dev) -{ - reg_w_val(gspca_dev->dev, 0x8114, 0); + if (sd->chip_revision == Rev012A) { + reg_w_val(gspca_dev->dev, 0x8118, 0x29); + reg_w_val(gspca_dev->dev, 0x8114, 0x08); + } +/* reg_w_val(gspca_dev->dev, 0x8114, 0); */ } static void do_autogain(struct gspca_dev *gspca_dev) @@ -744,6 +786,7 @@ static void do_autogain(struct gspca_dev *gspca_dev) __u8 luma_mean = 110; __u8 luma_delta = 20; __u8 spring = 4; + __u8 reg8339[2]; if (sd->ag_cnt < 0) return; @@ -798,13 +841,16 @@ static void do_autogain(struct gspca_dev *gspca_dev) } break; case Rev012A: - /* sensor registers is access and memory mapped to 0x8300 */ - /* readind all 0x83xx block the sensor */ - /* - * The data from the header seem wrong where is the luma - * and chroma mean value - * at the moment set exposure in contrast set - */ + reg_r(gspca_dev, 0x8330, 2); + if (gspca_dev->usb_buf[1] > 0x08) { + reg8339[0] = ++sd->expo12a; + reg8339[1] = 0; + reg_w_buf(gspca_dev, 0x8339, reg8339, 2); + } else if (gspca_dev->usb_buf[1] < 0x02) { + reg8339[0] = --sd->expo12a; + reg8339[1] = 0; + reg_w_buf(gspca_dev, 0x8339, reg8339, 2); + } break; } } @@ -814,6 +860,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, __u8 *data, /* isoc packet */ int len) /* iso packet length */ { + struct sd *sd = (struct sd *) gspca_dev; + switch (data[0]) { case 0: /* start of frame */ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, @@ -826,8 +874,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, frame, data, len); } else { /* raw bayer (with a header, which we skip) */ - data += 20; - len -= 20; + if (sd->chip_revision == Rev012A) { + data += 20; + len -= 20; + } else { + data += 16; + len -= 16; + } gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len); } @@ -841,24 +894,17 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); } +/* rev 72a only */ static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; __u8 value; - switch (sd->chip_revision) { - case Rev072A: - value = sd->brightness; - reg_w_val(gspca_dev->dev, value, 0x8611); - reg_w_val(gspca_dev->dev, value, 0x8612); - reg_w_val(gspca_dev->dev, value, 0x8613); - reg_w_val(gspca_dev->dev, value, 0x8614); - break; - default: -/* case Rev012A: */ - setcontrast(gspca_dev); - break; - } + value = sd->brightness; + reg_w_val(gspca_dev->dev, 0x8611, value); + reg_w_val(gspca_dev->dev, 0x8612, value); + reg_w_val(gspca_dev->dev, 0x8613, value); + reg_w_val(gspca_dev->dev, 0x8614, value); } static void getbrightness(struct gspca_dev *gspca_dev) @@ -866,52 +912,38 @@ static void getbrightness(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; __u16 tot; - switch (sd->chip_revision) { - case Rev072A: - tot = 0; - reg_r(gspca_dev, 0x8611, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8612, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8613, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8614, 1); - tot += gspca_dev->usb_buf[0]; - sd->brightness = tot >> 2; - break; - default: -/* case Rev012A: */ - /* no way to read sensor settings */ - break; - } + tot = 0; + reg_r(gspca_dev, 0x8611, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8612, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8613, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8614, 1); + tot += gspca_dev->usb_buf[0]; + sd->brightness = tot >> 2; } +/* rev72a only */ static void getcontrast(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; __u16 tot; - switch (sd->chip_revision) { - case Rev072A: - tot = 0; - reg_r(gspca_dev, 0x8651, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8652, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8653, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8654, 1); - tot += gspca_dev->usb_buf[0]; - sd->contrast = tot << 6; - break; - default: -/* case Rev012A: */ - /* no way to read sensor settings */ - break; - } + tot = 0; + reg_r(gspca_dev, 0x8651, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8652, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8653, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8654, 1); + tot += gspca_dev->usb_buf[0]; + sd->contrast = tot << 6; PDEBUG(D_CONF, "get contrast %d", sd->contrast); } +/* rev 72a only */ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -931,6 +963,7 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) return 0; } +/* rev 72a only */ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -968,20 +1001,190 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) return 0; } +/* rev12a only */ +static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->white = val; + if (gspca_dev->streaming) + setwhite(gspca_dev); + return 0; +} + +static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->white; + return 0; +} + +/* rev12a only */ +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->exposure = val; + if (gspca_dev->streaming) + setexposure(gspca_dev); + return 0; +} + +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->exposure; + return 0; +} + +/* rev12a only */ +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gain = val; + if (gspca_dev->streaming) + setgain(gspca_dev); + return 0; +} + +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->gain; + return 0; +} + +/* control tables */ +static struct ctrl sd_ctrls_12a[] = { + { + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "While Balance", + .minimum = WHITE_MIN, + .maximum = WHITE_MAX, + .step = 1, + .default_value = WHITE_DEF, + }, + .set = sd_setwhite, + .get = sd_getwhite, + }, + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = EXPOSURE_MIN, + .maximum = EXPOSURE_MAX, + .step = 1, + .default_value = EXPOSURE_DEF, + }, + .set = sd_setexposure, + .get = sd_getexposure, + }, + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = AUTOGAIN_MIN, + .maximum = AUTOGAIN_MAX, + .step = 1, + .default_value = AUTOGAIN_DEF, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = GAIN_MIN, + .maximum = GAIN_MAX, + .step = 1, + .default_value = GAIN_DEF, + }, + .set = sd_setgain, + .get = sd_getgain, + }, +}; + +static struct ctrl sd_ctrls_72a[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = BRIGHTNESS_MIN, + .maximum = BRIGHTNESS_MAX, + .step = 1, + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = CONTRAST_MIN, + .maximum = CONTRAST_MAX, + .step = 1, + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = AUTOGAIN_MIN, + .maximum = AUTOGAIN_MAX, + .step = 1, + .default_value = AUTOGAIN_DEF, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, +}; + /* sub-driver description */ -static const struct sd_desc sd_desc = { +static const struct sd_desc sd_desc_12a = { + .name = MODULE_NAME, + .ctrls = sd_ctrls_12a, + .nctrls = ARRAY_SIZE(sd_ctrls_12a), + .config = sd_config, + .init = sd_init_12a, + .start = sd_start_12a, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, +/* .dq_callback = do_autogain, * fixme */ +}; +static const struct sd_desc sd_desc_72a = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), + .ctrls = sd_ctrls_72a, + .nctrls = ARRAY_SIZE(sd_ctrls_72a), .config = sd_config, - .open = sd_open, - .start = sd_start, + .init = sd_init_72a, + .start = sd_start_72a, .stopN = sd_stopN, .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, .dq_callback = do_autogain, }; +static const struct sd_desc *sd_desc[2] = { + &sd_desc_12a, + &sd_desc_72a +}; /* -- module initialisation -- */ static const __devinitdata struct usb_device_id device_table[] = { @@ -1009,7 +1212,9 @@ MODULE_DEVICE_TABLE(usb, device_table); static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + return gspca_dev_probe(intf, id, + sd_desc[id->driver_info], + sizeof(struct sd), THIS_MODULE); } @@ -1018,6 +1223,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c index 16219cf6a6d5..2f2de429e273 100644 --- a/drivers/media/video/gspca/stk014.c +++ b/drivers/media/video/gspca/stk014.c @@ -306,8 +306,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { int ret; @@ -398,14 +398,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) PDEBUG(D_STREAM, "camera stopped"); } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -535,11 +527,9 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, .querymenu = sd_querymenu, }; @@ -564,6 +554,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c index 54efa48bee01..1cfcc6c49558 100644 --- a/drivers/media/video/gspca/sunplus.c +++ b/drivers/media/video/gspca/sunplus.c @@ -449,31 +449,47 @@ static const __u8 qtable_spca504_default[2][64] = { 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e} }; -static void reg_r(struct usb_device *dev, - __u16 req, - __u16 index, - __u8 *buffer, __u16 length) +/* read <len> bytes to gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + __u16 req, + __u16 index, + __u16 len) { - usb_control_msg(dev, - usb_rcvctrlpipe(dev, 0), +#ifdef GSPCA_DEBUG + if (len > USB_BUF_SZ) { + err("reg_r: buffer overflow"); + return; + } +#endif + usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, /* value */ - index, buffer, length, + index, + len ? gspca_dev->usb_buf : NULL, len, 500); } -static void reg_w(struct usb_device *dev, - __u16 req, - __u16 value, - __u16 index, - __u8 *buffer, __u16 length) +/* write <len> bytes from gspca_dev->usb_buf */ +static void reg_w(struct gspca_dev *gspca_dev, + __u16 req, + __u16 value, + __u16 index, + __u16 len) { - usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), +#ifdef GSPCA_DEBUG + if (len > USB_BUF_SZ) { + err("reg_w: buffer overflow"); + return; + } +#endif + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, buffer, length, + value, index, + len ? gspca_dev->usb_buf : NULL, len, 500); } @@ -634,7 +650,7 @@ static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev) int count = 10; while (--count > 0) { - reg_r(gspca_dev->dev, 0x21, 0, gspca_dev->usb_buf, 1); + reg_r(gspca_dev, 0x21, 0, 1); if ((gspca_dev->usb_buf[0] & 0x01) == 0) break; msleep(10); @@ -644,15 +660,14 @@ static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev) static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev) { - struct usb_device *dev = gspca_dev->dev; int count = 50; while (--count > 0) { - reg_r(dev, 0x21, 1, gspca_dev->usb_buf, 1); + reg_r(gspca_dev, 0x21, 1, 1); if (gspca_dev->usb_buf[0] != 0) { gspca_dev->usb_buf[0] = 0; - reg_w(dev, 0x21, 0, 1, gspca_dev->usb_buf, 1); - reg_r(dev, 0x21, 1, gspca_dev->usb_buf, 1); + reg_w(gspca_dev, 0x21, 0, 1, 1); + reg_r(gspca_dev, 0x21, 1, 1); spca504B_PollingDataReady(gspca_dev); break; } @@ -662,16 +677,14 @@ static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev) static void spca50x_GetFirmware(struct gspca_dev *gspca_dev) { - struct usb_device *dev = gspca_dev->dev; __u8 *data; - data = kmalloc(64, GFP_KERNEL); - reg_r(dev, 0x20, 0, data, 5); + data = gspca_dev->usb_buf; + reg_r(gspca_dev, 0x20, 0, 5); PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ", data[0], data[1], data[2], data[3], data[4]); - reg_r(dev, 0x23, 0, data, 64); - reg_r(dev, 0x23, 1, data, 64); - kfree(data); + reg_r(gspca_dev, 0x23, 0, 64); + reg_r(gspca_dev, 0x23, 1, 64); } static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) @@ -686,21 +699,21 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) Type = 0; switch (sd->bridge) { case BRIDGE_SPCA533: - reg_w(dev, 0x31, 0, 0, NULL, 0); + reg_w(gspca_dev, 0x31, 0, 0, 0); spca504B_WaitCmdStatus(gspca_dev); rc = spca504B_PollingDataReady(gspca_dev); spca50x_GetFirmware(gspca_dev); gspca_dev->usb_buf[0] = 2; /* type */ - reg_w(dev, 0x24, 0, 8, gspca_dev->usb_buf, 1); - reg_r(dev, 0x24, 8, gspca_dev->usb_buf, 1); + reg_w(gspca_dev, 0x24, 0, 8, 1); + reg_r(gspca_dev, 0x24, 8, 1); gspca_dev->usb_buf[0] = Size; - reg_w(dev, 0x25, 0, 4, gspca_dev->usb_buf, 1); - reg_r(dev, 0x25, 4, gspca_dev->usb_buf, 1); /* size */ + reg_w(gspca_dev, 0x25, 0, 4, 1); + reg_r(gspca_dev, 0x25, 4, 1); /* size */ rc = spca504B_PollingDataReady(gspca_dev); /* Init the cam width height with some values get on init ? */ - reg_w(dev, 0x31, 0, 4, NULL, 0); + reg_w(gspca_dev, 0x31, 0, 4, 0); spca504B_WaitCmdStatus(gspca_dev); rc = spca504B_PollingDataReady(gspca_dev); break; @@ -708,12 +721,12 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) /* case BRIDGE_SPCA504B: */ /* case BRIDGE_SPCA536: */ gspca_dev->usb_buf[0] = Size; - reg_w(dev, 0x25, 0, 4, gspca_dev->usb_buf, 1); - reg_r(dev, 0x25, 4, gspca_dev->usb_buf, 1); /* size */ + reg_w(gspca_dev, 0x25, 0, 4, 1); + reg_r(gspca_dev, 0x25, 4, 1); /* size */ Type = 6; gspca_dev->usb_buf[0] = Type; - reg_w(dev, 0x27, 0, 0, gspca_dev->usb_buf, 1); - reg_r(dev, 0x27, 0, gspca_dev->usb_buf, 1); /* type */ + reg_w(gspca_dev, 0x27, 0, 0, 1); + reg_r(gspca_dev, 0x27, 0, 1); /* type */ rc = spca504B_PollingDataReady(gspca_dev); break; case BRIDGE_SPCA504: @@ -752,18 +765,15 @@ static void spca504_wait_status(struct gspca_dev *gspca_dev) static void spca504B_setQtable(struct gspca_dev *gspca_dev) { - struct usb_device *dev = gspca_dev->dev; - gspca_dev->usb_buf[0] = 3; - reg_w(dev, 0x26, 0, 0, gspca_dev->usb_buf, 1); - reg_r(dev, 0x26, 0, gspca_dev->usb_buf, 1); + reg_w(gspca_dev, 0x26, 0, 0, 1); + reg_r(gspca_dev, 0x26, 0, 1); spca504B_PollingDataReady(gspca_dev); } static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; int pollreg = 1; switch (sd->bridge) { @@ -774,20 +784,20 @@ static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev) default: /* case BRIDGE_SPCA533: */ /* case BRIDGE_SPCA504B: */ - reg_w(dev, 0, 0, 0x21a7, NULL, 0); /* brightness */ - reg_w(dev, 0, 0x20, 0x21a8, NULL, 0); /* contrast */ - reg_w(dev, 0, 0, 0x21ad, NULL, 0); /* hue */ - reg_w(dev, 0, 1, 0x21ac, NULL, 0); /* sat/hue */ - reg_w(dev, 0, 0x20, 0x21ae, NULL, 0); /* saturation */ - reg_w(dev, 0, 0, 0x21a3, NULL, 0); /* gamma */ + reg_w(gspca_dev, 0, 0, 0x21a7, 0); /* brightness */ + reg_w(gspca_dev, 0, 0x20, 0x21a8, 0); /* contrast */ + reg_w(gspca_dev, 0, 0, 0x21ad, 0); /* hue */ + reg_w(gspca_dev, 0, 1, 0x21ac, 0); /* sat/hue */ + reg_w(gspca_dev, 0, 0x20, 0x21ae, 0); /* saturation */ + reg_w(gspca_dev, 0, 0, 0x21a3, 0); /* gamma */ break; case BRIDGE_SPCA536: - reg_w(dev, 0, 0, 0x20f0, NULL, 0); - reg_w(dev, 0, 0x21, 0x20f1, NULL, 0); - reg_w(dev, 0, 0x40, 0x20f5, NULL, 0); - reg_w(dev, 0, 1, 0x20f4, NULL, 0); - reg_w(dev, 0, 0x40, 0x20f6, NULL, 0); - reg_w(dev, 0, 0, 0x2089, NULL, 0); + reg_w(gspca_dev, 0, 0, 0x20f0, 0); + reg_w(gspca_dev, 0, 0x21, 0x20f1, 0); + reg_w(gspca_dev, 0, 0x40, 0x20f5, 0); + reg_w(gspca_dev, 0, 1, 0x20f4, 0); + reg_w(gspca_dev, 0, 0x40, 0x20f6, 0); + reg_w(gspca_dev, 0, 0, 0x2089, 0); break; } if (pollreg) @@ -799,7 +809,6 @@ static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; struct cam *cam; cam = &gspca_dev->cam; @@ -811,7 +820,7 @@ static int sd_config(struct gspca_dev *gspca_dev, if (sd->subtype == AiptekMiniPenCam13) { /* try to get the firmware as some cam answer 2.0.1.2.2 * and should be a spca504b then overwrite that setting */ - reg_r(dev, 0x20, 0, gspca_dev->usb_buf, 1); + reg_r(gspca_dev, 0x20, 0, 1); switch (gspca_dev->usb_buf[0]) { case 1: break; /* (right bridge/subtype) */ @@ -848,8 +857,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; @@ -860,12 +869,12 @@ static int sd_open(struct gspca_dev *gspca_dev) switch (sd->bridge) { case BRIDGE_SPCA504B: - reg_w(dev, 0x1d, 0, 0, NULL, 0); - reg_w(dev, 0, 1, 0x2306, NULL, 0); - reg_w(dev, 0, 0, 0x0d04, NULL, 0); - reg_w(dev, 0, 0, 0x2000, NULL, 0); - reg_w(dev, 0, 0x13, 0x2301, NULL, 0); - reg_w(dev, 0, 0, 0x2306, NULL, 0); + reg_w(gspca_dev, 0x1d, 0, 0, 0); + reg_w(gspca_dev, 0, 1, 0x2306, 0); + reg_w(gspca_dev, 0, 0, 0x0d04, 0); + reg_w(gspca_dev, 0, 0, 0x2000, 0); + reg_w(gspca_dev, 0, 0x13, 0x2301, 0); + reg_w(gspca_dev, 0, 0, 0x2306, 0); /* fall thru */ case BRIDGE_SPCA533: rc = spca504B_PollingDataReady(gspca_dev); @@ -873,12 +882,12 @@ static int sd_open(struct gspca_dev *gspca_dev) break; case BRIDGE_SPCA536: spca50x_GetFirmware(gspca_dev); - reg_r(dev, 0x00, 0x5002, gspca_dev->usb_buf, 1); + reg_r(gspca_dev, 0x00, 0x5002, 1); gspca_dev->usb_buf[0] = 0; - reg_w(dev, 0x24, 0, 0, gspca_dev->usb_buf, 1); - reg_r(dev, 0x24, 0, gspca_dev->usb_buf, 1); + reg_w(gspca_dev, 0x24, 0, 0, 1); + reg_r(gspca_dev, 0x24, 0, 1); rc = spca504B_PollingDataReady(gspca_dev); - reg_w(dev, 0x34, 0, 0, NULL, 0); + reg_w(gspca_dev, 0x34, 0, 0, 0); spca504B_WaitCmdStatus(gspca_dev); break; case BRIDGE_SPCA504C: /* pccam600 */ @@ -971,12 +980,12 @@ static void sd_start(struct gspca_dev *gspca_dev) /* case BRIDGE_SPCA536: */ if (sd->subtype == MegapixV4 || sd->subtype == LogitechClickSmart820) { - reg_w(dev, 0xf0, 0, 0, NULL, 0); + reg_w(gspca_dev, 0xf0, 0, 0, 0); spca504B_WaitCmdStatus(gspca_dev); - reg_r(dev, 0xf0, 4, NULL, 0); + reg_r(gspca_dev, 0xf0, 4, 0); spca504B_WaitCmdStatus(gspca_dev); } else { - reg_w(dev, 0x31, 0, 4, NULL, 0); + reg_w(gspca_dev, 0x31, 0, 4, 0); spca504B_WaitCmdStatus(gspca_dev); rc = spca504B_PollingDataReady(gspca_dev); } @@ -1045,7 +1054,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) /* case BRIDGE_SPCA533: */ /* case BRIDGE_SPCA536: */ /* case BRIDGE_SPCA504B: */ - reg_w(dev, 0x31, 0, 0, NULL, 0); + reg_w(gspca_dev, 0x31, 0, 0, 0); spca504B_WaitCmdStatus(gspca_dev); spca504B_PollingDataReady(gspca_dev); break; @@ -1069,14 +1078,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) } } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -1369,11 +1370,9 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; @@ -1456,6 +1455,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c index 91b555c34c68..f034c748fc7e 100644 --- a/drivers/media/video/gspca/t613.c +++ b/drivers/media/video/gspca/t613.c @@ -30,7 +30,7 @@ #define MAX_GAMMA 0x10 /* 0 to 15 */ -#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 3) +#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0) MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>"); MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver"); @@ -233,7 +233,7 @@ static char *effects_control[] = { static struct v4l2_pix_format vga_mode_t16[] = { {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 160, - .sizeimage = 160 * 120 * 3 / 8 + 590, + .sizeimage = 160 * 120 * 4 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 4}, {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, @@ -391,7 +391,7 @@ static void reg_w(struct gspca_dev *gspca_dev, NULL, 0, 500); return; } - if (len <= sizeof gspca_dev->usb_buf) { + if (len <= USB_BUF_SZ) { memcpy(gspca_dev->usb_buf, buffer, len); usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), @@ -552,6 +552,13 @@ static int init_default_parameters(struct gspca_dev *gspca_dev) return 0; } +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + init_default_parameters(gspca_dev); + return 0; +} + static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -893,18 +900,6 @@ static void sd_start(struct gspca_dev *gspca_dev) setcolors(gspca_dev); } -static void sd_stopN(struct gspca_dev *gspca_dev) -{ -} - -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -972,24 +967,14 @@ static int sd_querymenu(struct gspca_dev *gspca_dev, return -EINVAL; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) -{ - init_default_parameters(gspca_dev); - return 0; -} - /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, - .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, .querymenu = sd_querymenu, }; @@ -1014,6 +999,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c index 1ff8ba2f7fe5..084af05302a0 100644 --- a/drivers/media/video/gspca/tv8532.c +++ b/drivers/media/video/gspca/tv8532.c @@ -331,8 +331,8 @@ static void tv_8532_PollReg(struct gspca_dev *gspca_dev) } } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32); reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00); @@ -450,14 +450,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b); } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void tv8532_preprocess(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -611,11 +603,9 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; @@ -644,6 +634,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c index f4a52956e0d9..bd4c226c9a07 100644 --- a/drivers/media/video/gspca/vc032x.c +++ b/drivers/media/video/gspca/vc032x.c @@ -69,6 +69,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setautogain, .get = sd_getautogain, }, +#define LIGHTFREQ_IDX 1 { { .id = V4L2_CID_POWER_LINE_FREQUENCY, @@ -87,12 +88,12 @@ static struct ctrl sd_ctrls[] = { }; static struct v4l2_pix_format vc0321_mode[] = { - {320, 240, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE, + {320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE, .bytesperline = 320, .sizeimage = 320 * 240 * 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 1}, - {640, 480, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE, + {640, 480, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE, .bytesperline = 640, .sizeimage = 640 * 480 * 2, .colorspace = V4L2_COLORSPACE_SRGB, @@ -1463,6 +1464,8 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->qindex = 7; sd->autogain = AUTOGAIN_DEF; sd->lightfreq = FREQ_DEF; + if (sd->sensor != SENSOR_OV7670) + gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX); if (sd->bridge == BRIDGE_VC0321) { reg_r(gspca_dev, 0x8a, 0, 3); @@ -1474,8 +1477,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and time */ +static int sd_init(struct gspca_dev *gspca_dev) { return 0; } @@ -1637,19 +1640,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev) reg_w(dev, 0x89, 0xffff, 0xffff); } -/* this function is called at close time */ -static void sd_close(struct gspca_dev *gspca_dev) -{ -/* struct usb_device *dev = gspca_dev->dev; - __u8 buffread; - - reg_w(dev, 0x89, 0xffff, 0xffff); - reg_w(dev, 0xa0, 0x01, 0xb301); - reg_w(dev, 0xa0, 0x09, 0xb303); - reg_w(dev, 0x89, 0xffff, 0xffff); -*/ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -1738,11 +1728,10 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, .querymenu = sd_querymenu, }; @@ -1774,6 +1763,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index bc7d0eedcd81..8d7c27e6ac77 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -85,6 +85,7 @@ static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); static struct ctrl sd_ctrls[] = { +#define BRIGHTNESS_IDX 0 #define SD_BRIGHTNESS 0 { { @@ -141,6 +142,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setautogain, .get = sd_getautogain, }, +#define LIGHTFREQ_IDX 4 #define SD_FREQ 4 { { @@ -6964,8 +6966,13 @@ static int zcxx_probeSensor(struct gspca_dev *gspca_dev) case SENSOR_MC501CB: return -1; /* don't probe */ case SENSOR_TAS5130C_VF0250: - /* may probe but with write in reg 0x0010 */ + /* may probe but with no write in reg 0x0010 */ return -1; /* don't probe */ + case SENSOR_PAS106: + sensor = sif_probe(gspca_dev); + if (sensor >= 0) + return sensor; + break; } sensor = vga_2wr_probe(gspca_dev); if (sensor >= 0) { @@ -6974,12 +6981,10 @@ static int zcxx_probeSensor(struct gspca_dev *gspca_dev) /* next probe is needed for OmniVision ? */ } sensor2 = vga_3wr_probe(gspca_dev); - if (sensor2 >= 0) { - if (sensor >= 0) - return sensor; - return sensor2; - } - return sif_probe(gspca_dev); + if (sensor2 >= 0 + && sensor >= 0) + return sensor; + return sensor2; } /* this function is called at probe time */ @@ -7147,13 +7152,27 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value; sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value; + switch (sd->sensor) { + case SENSOR_GC0305: + case SENSOR_OV7620: + case SENSOR_PO2030: + gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX); + break; + case SENSOR_HDCS2020: + case SENSOR_HV7131B: + case SENSOR_HV7131C: + case SENSOR_OV7630C: + gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX); + break; + } + /* switch the led off */ reg_w(gspca_dev->dev, 0x01, 0x0000); return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { reg_w(gspca_dev->dev, 0x01, 0x0000); return 0; @@ -7314,10 +7333,6 @@ static void sd_start(struct gspca_dev *gspca_dev) } } -static void sd_stopN(struct gspca_dev *gspca_dev) -{ -} - static void sd_stop0(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -7325,11 +7340,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev) send_unknown(gspca_dev->dev, sd->sensor); } -/* this function is called at close time */ -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, __u8 *data, @@ -7489,37 +7499,30 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = sizeof sd_ctrls / sizeof sd_ctrls[0], .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, - .stopN = sd_stopN, .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, .querymenu = sd_querymenu, }; static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x041e, 0x041e)}, -#ifndef CONFIG_USB_ZC0301 {USB_DEVICE(0x041e, 0x4017)}, - {USB_DEVICE(0x041e, 0x401c)}, + {USB_DEVICE(0x041e, 0x401c), .driver_info = SENSOR_PAS106}, {USB_DEVICE(0x041e, 0x401e)}, {USB_DEVICE(0x041e, 0x401f)}, -#endif + {USB_DEVICE(0x041e, 0x4022)}, {USB_DEVICE(0x041e, 0x4029)}, -#ifndef CONFIG_USB_ZC0301 - {USB_DEVICE(0x041e, 0x4034)}, - {USB_DEVICE(0x041e, 0x4035)}, + {USB_DEVICE(0x041e, 0x4034), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x041e, 0x4035), .driver_info = SENSOR_PAS106}, {USB_DEVICE(0x041e, 0x4036)}, {USB_DEVICE(0x041e, 0x403a)}, -#endif {USB_DEVICE(0x041e, 0x4051), .driver_info = SENSOR_TAS5130C_VF0250}, {USB_DEVICE(0x041e, 0x4053), .driver_info = SENSOR_TAS5130C_VF0250}, -#ifndef CONFIG_USB_ZC0301 {USB_DEVICE(0x0458, 0x7007)}, {USB_DEVICE(0x0458, 0x700c)}, {USB_DEVICE(0x0458, 0x700f)}, -#endif {USB_DEVICE(0x0461, 0x0a00)}, {USB_DEVICE(0x046d, 0x08a0)}, {USB_DEVICE(0x046d, 0x08a1)}, @@ -7531,7 +7534,7 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x046d, 0x08aa)}, {USB_DEVICE(0x046d, 0x08ac)}, {USB_DEVICE(0x046d, 0x08ad)}, -#ifndef CONFIG_USB_ZC0301 +#if !defined CONFIG_USB_ZC0301 && !defined CONFIG_USB_ZC0301_MODULE {USB_DEVICE(0x046d, 0x08ae)}, #endif {USB_DEVICE(0x046d, 0x08af)}, @@ -7541,27 +7544,25 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x046d, 0x08d8)}, {USB_DEVICE(0x046d, 0x08da)}, {USB_DEVICE(0x046d, 0x08dd), .driver_info = SENSOR_MC501CB}, - {USB_DEVICE(0x0471, 0x0325)}, - {USB_DEVICE(0x0471, 0x0326)}, - {USB_DEVICE(0x0471, 0x032d)}, - {USB_DEVICE(0x0471, 0x032e)}, + {USB_DEVICE(0x0471, 0x0325), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x0471, 0x0326), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x0471, 0x032d), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x0471, 0x032e), .driver_info = SENSOR_PAS106}, {USB_DEVICE(0x055f, 0xc005)}, -#ifndef CONFIG_USB_ZC0301 {USB_DEVICE(0x055f, 0xd003)}, {USB_DEVICE(0x055f, 0xd004)}, -#endif {USB_DEVICE(0x0698, 0x2003)}, + {USB_DEVICE(0x0ac8, 0x0301), .driver_info = SENSOR_PAS106}, {USB_DEVICE(0x0ac8, 0x0302)}, -#ifndef CONFIG_USB_ZC0301 {USB_DEVICE(0x0ac8, 0x301b)}, +#if !defined CONFIG_USB_ZC0301 && !defined CONFIG_USB_ZC0301_MODULE {USB_DEVICE(0x0ac8, 0x303b)}, #endif {USB_DEVICE(0x0ac8, 0x305b), .driver_info = SENSOR_TAS5130C_VF0250}, -#ifndef CONFIG_USB_ZC0301 {USB_DEVICE(0x0ac8, 0x307b)}, {USB_DEVICE(0x10fd, 0x0128)}, + {USB_DEVICE(0x10fd, 0x804d)}, {USB_DEVICE(0x10fd, 0x8050)}, -#endif {} /* end of entry */ }; #undef DVNAME @@ -7581,6 +7582,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; static int __init sd_mod_init(void) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index aea1664948ce..4afc7ea07e86 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -688,7 +688,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv) spin_lock_init(&itv->lock); spin_lock_init(&itv->dma_reg_lock); - itv->irq_work_queues = create_workqueue(itv->name); + itv->irq_work_queues = create_singlethread_workqueue(itv->name); if (itv->irq_work_queues == NULL) { IVTV_ERR("Could not create ivtv workqueue\n"); return -1; diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index ab287b48fc2b..2ceb5227637c 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -251,6 +251,7 @@ struct ivtv_mailbox_data { #define IVTV_F_I_DEC_PAUSED 20 /* the decoder is paused */ #define IVTV_F_I_INITED 21 /* set after first open */ #define IVTV_F_I_FAILED 22 /* set if first open failed */ +#define IVTV_F_I_WORK_INITED 23 /* worker thread was initialized */ /* Event notifications */ #define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */ diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index fba150a6cd23..34f3ab827858 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -76,6 +76,13 @@ void ivtv_irq_work_handler(struct work_struct *work) DEFINE_WAIT(wait); + if (test_and_clear_bit(IVTV_F_I_WORK_INITED, &itv->i_flags)) { + struct sched_param param = { .sched_priority = 99 }; + + /* This thread must use the FIFO scheduler as it + is realtime sensitive. */ + sched_setscheduler(current, SCHED_FIFO, ¶m); + } if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags)) ivtv_pio_work_handler(itv); @@ -678,34 +685,14 @@ static void ivtv_irq_enc_start_cap(struct ivtv *itv) static void ivtv_irq_enc_vbi_cap(struct ivtv *itv) { - struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG]; u32 data[CX2341X_MBOX_MAX_DATA]; struct ivtv_stream *s; IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n"); s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - /* If more than two VBI buffers are pending, then - clear the old ones and start with this new one. - This can happen during transition stages when MPEG capturing is - started, but the first interrupts haven't arrived yet. During - that period VBI requests can accumulate without being able to - DMA the data. Since at most four VBI DMA buffers are available, - we just drop the old requests when there are already three - requests queued. */ - if (s->sg_pending_size > 2) { - struct ivtv_buffer *buf; - list_for_each_entry(buf, &s->q_predma.list, list) - ivtv_buf_sync_for_cpu(s, buf); - ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0); - s->sg_pending_size = 0; - } - /* if we can append the data, and the MPEG stream isn't capturing, - then start a DMA request for just the VBI data. */ - if (!stream_enc_dma_append(s, data) && - !test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) { + if (!stream_enc_dma_append(s, data)) set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags); - } } static void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv) diff --git a/drivers/media/video/ivtv/ivtv-queue.h b/drivers/media/video/ivtv/ivtv-queue.h index 7cfc0c9ab050..476556afd39a 100644 --- a/drivers/media/video/ivtv/ivtv-queue.h +++ b/drivers/media/video/ivtv/ivtv-queue.h @@ -23,7 +23,7 @@ #define IVTV_QUEUE_H #define IVTV_DMA_UNMAPPED ((u32) -1) -#define SLICED_VBI_PIO 1 +#define SLICED_VBI_PIO 0 /* ivtv_buffer utility functions */ diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 54d2023b26c4..730e85d86fc8 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -363,7 +363,7 @@ static void ivtv_vbi_setup(struct ivtv *itv) /* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */ data[1] = 1; /* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */ - data[2] = raw ? 4 : 8; + data[2] = raw ? 4 : 4 * (itv->vbi.raw_size / itv->vbi.enc_size); /* The start/stop codes determine which VBI lines end up in the raw VBI data area. The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video) diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c index 71798f0da27f..1ce9deb1104f 100644 --- a/drivers/media/video/ivtv/ivtv-vbi.c +++ b/drivers/media/video/ivtv/ivtv-vbi.c @@ -293,6 +293,7 @@ static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 u32 line_size = itv->vbi.sliced_decoder_line_size; struct v4l2_decode_vbi_line vbi; int i; + unsigned lines = 0; /* find the first valid line */ for (i = 0; i < size; i++, buf++) { @@ -313,7 +314,8 @@ static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 } vbi.p = p + 4; itv->video_dec_func(itv, VIDIOC_INT_DECODE_VBI_LINE, &vbi); - if (vbi.type) { + if (vbi.type && !(lines & (1 << vbi.line))) { + lines |= 1 << vbi.line; itv->vbi.sliced_data[line].id = vbi.type; itv->vbi.sliced_data[line].field = vbi.is_second_field; itv->vbi.sliced_data[line].line = vbi.line; diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h index 442f43f11b73..8cd753d30bf7 100644 --- a/drivers/media/video/ivtv/ivtv-version.h +++ b/drivers/media/video/ivtv/ivtv-version.h @@ -22,7 +22,7 @@ #define IVTV_DRIVER_NAME "ivtv" #define IVTV_DRIVER_VERSION_MAJOR 1 -#define IVTV_DRIVER_VERSION_MINOR 3 +#define IVTV_DRIVER_VERSION_MINOR 4 #define IVTV_DRIVER_VERSION_PATCHLEVEL 0 #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c index 4895540be195..2fd4b4a44aa9 100644 --- a/drivers/media/video/ks0127.c +++ b/drivers/media/video/ks0127.c @@ -679,26 +679,27 @@ static int ks0127_command(struct i2c_client *client, case DECODER_ENABLE_OUTPUT: { + int enable; - int *iarg = arg; - int enable = (*iarg != 0); - if (enable) { - dprintk("ks0127: command " + iarg = arg; + enable = (*iarg != 0); + if (enable) { + dprintk("ks0127: command " "DECODER_ENABLE_OUTPUT on " "(%d)\n", enable); - /* All output pins on */ - ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30); - /* Obey the OEN pin */ - ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00); - } else { - dprintk("ks0127: command " + /* All output pins on */ + ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30); + /* Obey the OEN pin */ + ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00); + } else { + dprintk("ks0127: command " "DECODER_ENABLE_OUTPUT off " "(%d)\n", enable); - /* Video output pins off */ - ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00); - /* Ignore the OEN pin */ - ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80); - } + /* Video output pins off */ + ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00); + /* Ignore the OEN pin */ + ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80); + } } break; diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index 7c8ef6ac6c39..a9ef7802eb5f 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -1806,6 +1806,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev, memcpy(meye.video_dev, &meye_template, sizeof(meye_template)); meye.video_dev->parent = &meye.mchip_dev->dev; + ret = -EIO; if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) { printk(KERN_ERR "meye: unable to power on the camera\n"); printk(KERN_ERR "meye: did you enable the camera in " @@ -1813,7 +1814,6 @@ static int __devinit meye_probe(struct pci_dev *pcidev, goto outsonypienable; } - ret = -EIO; if ((ret = pci_enable_device(meye.mchip_dev))) { printk(KERN_ERR "meye: pci_enable_device failed\n"); goto outenabledev; diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c index f68e91fbe7fb..8ef578caba3b 100644 --- a/drivers/media/video/mxb.c +++ b/drivers/media/video/mxb.c @@ -931,27 +931,29 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) return 0; } -static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) +static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard) { - struct mxb* mxb = (struct mxb*)dev->ext_priv; + struct mxb *mxb = (struct mxb *)dev->ext_priv; int zero = 0; int one = 1; - if(V4L2_STD_PAL_I == std->id ) { + if (V4L2_STD_PAL_I == standard->id) { v4l2_std_id std = V4L2_STD_PAL_I; + DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n")); /* set the 7146 gpio register -- I don't know what this does exactly */ saa7146_write(dev, GPIO_CTRL, 0x00404050); /* unset the 7111 gpio register -- I don't know what this does exactly */ - mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &zero); + mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &zero); mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std); } else { v4l2_std_id std = V4L2_STD_PAL_BG; + DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n")); /* set the 7146 gpio register -- I don't know what this does exactly */ saa7146_write(dev, GPIO_CTRL, 0x00404050); /* set the 7111 gpio register -- I don't know what this does exactly */ - mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &one); + mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &one); mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std); } return 0; diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c index 9edaca4371d7..3d3c48db45d9 100644 --- a/drivers/media/video/ov511.c +++ b/drivers/media/video/ov511.c @@ -626,9 +626,9 @@ ov511_i2c_write_internal(struct usb_ov511 *ov, break; /* Retry until idle */ - do + do { rc = reg_r(ov, R511_I2C_CTL); - while (rc > 0 && ((rc&1) == 0)); + } while (rc > 0 && ((rc&1) == 0)); if (rc < 0) break; @@ -703,9 +703,9 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) return rc; /* Retry until idle */ - do - rc = reg_r(ov, R511_I2C_CTL); - while (rc > 0 && ((rc&1) == 0)); + do { + rc = reg_r(ov, R511_I2C_CTL); + } while (rc > 0 && ((rc & 1) == 0)); if (rc < 0) return rc; @@ -729,9 +729,9 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) return rc; /* Retry until idle */ - do + do { rc = reg_r(ov, R511_I2C_CTL); - while (rc > 0 && ((rc&1) == 0)); + } while (rc > 0 && ((rc&1) == 0)); if (rc < 0) return rc; diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c index 00425d743656..7c84f795db54 100644 --- a/drivers/media/video/pms.c +++ b/drivers/media/video/pms.c @@ -1019,10 +1019,23 @@ static int init_mediavision(void) * Initialization and module stuff */ +#ifndef MODULE +static int enable; +module_param(enable, int, 0); +#endif + static int __init init_pms_cards(void) { printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.02\n"); +#ifndef MODULE + if (!enable) { + printk(KERN_INFO "PMS: not enabled, use pms.enable=1 to " + "probe\n"); + return -ENODEV; + } +#endif + data_port = io_port +1; if(init_mediavision()) diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c index 1cccd5c77048..dbc560742553 100644 --- a/drivers/media/video/pwc/pwc-ctrl.c +++ b/drivers/media/video/pwc/pwc-ctrl.c @@ -1635,15 +1635,15 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) case VIDIOCPWCGVIDCMD: { - ARG_DEF(struct pwc_video_command, cmd); - - ARGR(cmd).type = pdev->type; - ARGR(cmd).release = pdev->release; - ARGR(cmd).command_len = pdev->cmd_len; - memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len); - ARGR(cmd).bandlength = pdev->vbandlength; - ARGR(cmd).frame_size = pdev->frame_size; - ARG_OUT(cmd) + ARG_DEF(struct pwc_video_command, vcmd); + + ARGR(vcmd).type = pdev->type; + ARGR(vcmd).release = pdev->release; + ARGR(vcmd).command_len = pdev->cmd_len; + memcpy(&ARGR(vcmd).command_buf, pdev->cmd_buf, pdev->cmd_len); + ARGR(vcmd).bandlength = pdev->vbandlength; + ARGR(vcmd).frame_size = pdev->frame_size; + ARG_OUT(vcmd) break; } /* diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index bcd1c8f6cf6b..ad733caec720 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -1489,10 +1489,9 @@ static int saa7115_probe(struct i2c_client *client, client->addr << 1, client->adapter->name); state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL); - i2c_set_clientdata(client, state); - if (state == NULL) { + if (state == NULL) return -ENOMEM; - } + i2c_set_clientdata(client, state); state->input = -1; state->output = SAA7115_IPORT_ON; state->enable = 1; diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c index f481277892da..acceed5d04ae 100644 --- a/drivers/media/video/se401.c +++ b/drivers/media/video/se401.c @@ -1397,7 +1397,7 @@ static int se401_probe(struct usb_interface *intf, mutex_init(&se401->lock); wmb(); - if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { + if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { kfree(se401); err("video_register_device failed"); return -EIO; diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 23408764d0ef..2da6938718f2 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -3312,6 +3312,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) cam->v4ldev->fops = &sn9c102_fops; cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; + cam->v4ldev->parent = &udev->dev; init_completion(&cam->probe); diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h index 6ff489baacf3..90a401dc3884 100644 --- a/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -40,11 +40,14 @@ struct sn9c102_device; static const struct usb_device_id sn9c102_id_table[] = { /* SN9C101 and SN9C102 */ +#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x6001, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), }, +#endif { SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), }, +/* { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, OV6650 */ { SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), }, @@ -53,29 +56,33 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), }, - { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, +/* { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */ { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), }, /* SN9C103 */ { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), }, +/* { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), }, HY7131D/E */ { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), }, +/* { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), }, CISVF10 */ +#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), }, +#endif { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, +/* { SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), }, PAS106 */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), }, TAS5130 */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, TAS5130 */ { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), }, +#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), }, +#endif { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), }, @@ -105,7 +112,7 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), }, - { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, +/* { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */ { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), }, diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c index 56dc3d6b5b29..dce947439459 100644 --- a/drivers/media/video/stv680.c +++ b/drivers/media/video/stv680.c @@ -1462,7 +1462,7 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id mutex_init (&stv680->lock); wmb (); - if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { + if (video_register_device(stv680->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { PDEBUG (0, "STV(e): video_register_device failed"); retval = -EIO; goto error_vdev; diff --git a/drivers/media/video/usbvideo/ibmcam.c b/drivers/media/video/usbvideo/ibmcam.c index 59166b760104..cc27efe121dd 100644 --- a/drivers/media/video/usbvideo/ibmcam.c +++ b/drivers/media/video/usbvideo/ibmcam.c @@ -736,12 +736,12 @@ static enum ParseState ibmcam_model2_320x240_parse_lines( * make black color and quit the horizontal scanning loop. */ if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) { - const int j = i * V4L_BYTES_PER_PIXEL; + const int offset = i * V4L_BYTES_PER_PIXEL; #if USES_IBMCAM_PUTPIXEL /* Refresh 'f' because we don't use it much with PUTPIXEL */ - f = frame->data + (v4l_linesize * frame->curline) + j; + f = frame->data + (v4l_linesize * frame->curline) + offset; #endif - memset(f, 0, v4l_linesize - j); + memset(f, 0, v4l_linesize - offset); break; } diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c index b7792451a299..2eb45829791c 100644 --- a/drivers/media/video/usbvideo/vicam.c +++ b/drivers/media/video/usbvideo/vicam.c @@ -866,7 +866,7 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) cam->udev = dev; cam->bulkEndpoint = bulkEndpoint; - if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) { + if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) < 0) { kfree(cam); printk(KERN_WARNING "video_register_device failed\n"); return -EIO; diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 6f36006aecda..155fdec9ac7d 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -257,6 +257,9 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, int ret; char *name_base; + if (vfd == NULL) + return -EINVAL; + switch (type) { case VFL_TYPE_GRABBER: base = MINOR_VFL_TYPE_GRABBER_MIN; @@ -281,7 +284,7 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, default: printk(KERN_ERR "%s called with unknown type: %d\n", __func__, type); - return -1; + return -EINVAL; } /* pick a minor number */ diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index fdfe7739c96e..140ef92c19c1 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -499,7 +499,7 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd, p->timestamp.tv_sec / 3600, (int)(p->timestamp.tv_sec / 60) % 60, (int)(p->timestamp.tv_sec % 60), - p->timestamp.tv_usec, + (long)p->timestamp.tv_usec, p->index, prt_names(p->type, v4l2_type_names), p->bytesused, p->flags, @@ -674,7 +674,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, __video_do_ioctl will be called again, with one or more V4L2 ioctls. ********************************************************/ - if (_IOC_TYPE(cmd) == 'v') + if (_IOC_TYPE(cmd) == 'v' && _IOC_NR(cmd) < BASE_VIDIOCPRIVATE) return v4l_compat_translate_ioctl(inode, file, cmd, arg, __video_do_ioctl); #endif diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 3518af071a2e..8ba8daafd7ea 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -1021,13 +1021,13 @@ static int vivi_release(void) dev = list_entry(list, struct vivi_dev, vivi_devlist); if (-1 != dev->vfd->minor) { - video_unregister_device(dev->vfd); - printk(KERN_INFO "%s: /dev/video%d unregistered.\n", + printk(KERN_INFO "%s: unregistering /dev/video%d\n", VIVI_MODULE_NAME, dev->vfd->minor); + video_unregister_device(dev->vfd); } else { - video_device_release(dev->vfd); - printk(KERN_INFO "%s: /dev/video%d released.\n", + printk(KERN_INFO "%s: releasing /dev/video%d\n", VIVI_MODULE_NAME, dev->vfd->minor); + video_device_release(dev->vfd); } kfree(dev); @@ -1104,19 +1104,29 @@ static struct video_device vivi_template = { Initialization and module stuff ------------------------------------------------------------------*/ +/* This routine allocates from 1 to n_devs virtual drivers. + + The real maximum number of virtual drivers will depend on how many drivers + will succeed. This is limited to the maximum number of devices that + videodev supports. Since there are 64 minors for video grabbers, this is + currently the theoretical maximum limit. However, a further limit does + exist at videodev that forbids any driver to register more than 32 video + grabbers. + */ static int __init vivi_init(void) { int ret = -ENOMEM, i; struct vivi_dev *dev; struct video_device *vfd; + if (n_devs <= 0) + n_devs = 1; + for (i = 0; i < n_devs; i++) { dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (NULL == dev) + if (!dev) break; - list_add_tail(&dev->vivi_devlist, &vivi_devlist); - /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); init_waitqueue_head(&dev->vidq.wq); @@ -1126,14 +1136,27 @@ static int __init vivi_init(void) mutex_init(&dev->mutex); vfd = video_device_alloc(); - if (NULL == vfd) + if (!vfd) { + kfree(dev); break; + } *vfd = vivi_template; ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); - if (ret < 0) + if (ret < 0) { + video_device_release(vfd); + kfree(dev); + + /* If some registers succeeded, keep driver */ + if (i) + ret = 0; + break; + } + + /* Now that everything is fine, let's add it to device list */ + list_add_tail(&dev->vivi_devlist, &vivi_devlist); snprintf(vfd->name, sizeof(vfd->name), "%s (%i)", vivi_template.name, vfd->minor); @@ -1149,11 +1172,16 @@ static int __init vivi_init(void) if (ret < 0) { vivi_release(); printk(KERN_INFO "Error %d while loading vivi driver\n", ret); - } else + } else { printk(KERN_INFO "Video Technology Magazine Virtual Video " "Capture Board ver %u.%u.%u successfully loaded.\n", (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF, VIVI_VERSION & 0xFF); + + /* n_devs will reflect the actual number of allocated devices */ + n_devs = i; + } + return ret; } @@ -1169,10 +1197,10 @@ MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board"); MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol"); MODULE_LICENSE("Dual BSD/GPL"); -module_param(video_nr, int, 0); +module_param(video_nr, uint, 0444); MODULE_PARM_DESC(video_nr, "video iminor start number"); -module_param(n_devs, int, 0); +module_param(n_devs, uint, 0444); MODULE_PARM_DESC(n_devs, "number of video devices to create"); module_param_named(debug, vivi_template.debug, int, 0444); diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c index 9402f40095b4..2ff00bc5ad64 100644 --- a/drivers/media/video/w9966.c +++ b/drivers/media/video/w9966.c @@ -334,7 +334,7 @@ static int w9966_init(struct w9966_dev* cam, struct parport* port) memcpy(&cam->vdev, &w9966_template, sizeof(struct video_device)); cam->vdev.priv = cam; - if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) + if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) return -1; w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV); diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c index 550ce7bd5c87..0c3287734c93 100644 --- a/drivers/media/video/zc0301/zc0301_core.c +++ b/drivers/media/video/zc0301/zc0301_core.c @@ -1988,6 +1988,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) cam->v4ldev->fops = &zc0301_fops; cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; + cam->v4ldev->parent = &udev->dev; video_set_drvdata(cam->v4ldev, cam); init_completion(&cam->probe); diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h index 70fe6fc6cdd5..b0cd49c438a3 100644 --- a/drivers/media/video/zc0301/zc0301_sensor.h +++ b/drivers/media/video/zc0301/zc0301_sensor.h @@ -60,27 +60,8 @@ zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor); #define ZC0301_ID_TABLE \ static const struct usb_device_id zc0301_id_table[] = { \ - { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), }, /* ICM105 */ \ - { ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */ \ - { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131 */ \ - { ZC0301_USB_DEVICE(0x041e, 0x401f, 0xff), }, /* TAS5130 */ \ - { ZC0301_USB_DEVICE(0x041e, 0x4022, 0xff), }, \ - { ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */ \ - { ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */ \ - { ZC0301_USB_DEVICE(0x041e, 0x4036, 0xff), }, /* HV7131 */ \ - { ZC0301_USB_DEVICE(0x041e, 0x403a, 0xff), }, /* HV7131 */ \ - { ZC0301_USB_DEVICE(0x0458, 0x7007, 0xff), }, /* TAS5130 */ \ - { ZC0301_USB_DEVICE(0x0458, 0x700c, 0xff), }, /* TAS5130 */ \ - { ZC0301_USB_DEVICE(0x0458, 0x700f, 0xff), }, /* TAS5130 */ \ { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \ - { ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */ \ - { ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */ \ - { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), }, \ - { ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */ \ { ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */ \ - { ZC0301_USB_DEVICE(0x10fd, 0x0128, 0xff), }, /* TAS5130 */ \ - { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130 */ \ - { ZC0301_USB_DEVICE(0x10fd, 0x804e, 0xff), }, /* TAS5130 */ \ { } \ }; diff --git a/drivers/misc/acer-wmi.c b/drivers/misc/acer-wmi.c index c6c77a505ec1..d8b0d326e452 100644 --- a/drivers/misc/acer-wmi.c +++ b/drivers/misc/acer-wmi.c @@ -1189,7 +1189,7 @@ static int create_debugfs(void) return 0; error_debugfs: - remove_debugfs(); + remove_debugfs(); return -ENOMEM; } @@ -1272,6 +1272,7 @@ error_platform_register: static void __exit acer_wmi_exit(void) { remove_sysfs(acer_platform_device); + remove_debugfs(); platform_device_del(acer_platform_device); platform_driver_unregister(&acer_platform_driver); diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/misc/fujitsu-laptop.c index 7a1ef6c262de..3e56203e4947 100644 --- a/drivers/misc/fujitsu-laptop.c +++ b/drivers/misc/fujitsu-laptop.c @@ -463,6 +463,13 @@ static struct dmi_system_id __initdata fujitsu_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"), }, .callback = dmi_check_cb_s6410}, + { + .ident = "FUJITSU LifeBook P8010", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"), + }, + .callback = dmi_check_cb_s6410}, {} }; diff --git a/drivers/misc/hp-wmi.c b/drivers/misc/hp-wmi.c index 1dbcbcb323a2..6d407c2a4f91 100644 --- a/drivers/misc/hp-wmi.c +++ b/drivers/misc/hp-wmi.c @@ -49,6 +49,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); #define HPWMI_ALS_QUERY 0x3 #define HPWMI_DOCK_QUERY 0x4 #define HPWMI_WIRELESS_QUERY 0x5 +#define HPWMI_HOTKEY_QUERY 0xc static int __init hp_wmi_bios_setup(struct platform_device *device); static int __exit hp_wmi_bios_remove(struct platform_device *device); @@ -69,7 +70,7 @@ struct bios_return { struct key_entry { char type; /* See KE_* below */ - u8 code; + u16 code; u16 keycode; }; @@ -79,7 +80,9 @@ static struct key_entry hp_wmi_keymap[] = { {KE_SW, 0x01, SW_DOCK}, {KE_KEY, 0x02, KEY_BRIGHTNESSUP}, {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN}, - {KE_KEY, 0x04, KEY_HELP}, + {KE_KEY, 0x20e6, KEY_PROG1}, + {KE_KEY, 0x2142, KEY_MEDIA}, + {KE_KEY, 0x231b, KEY_HELP}, {KE_END, 0} }; @@ -177,9 +180,9 @@ static int hp_wmi_wifi_state(void) int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); if (wireless & 0x100) - return 1; + return RFKILL_STATE_UNBLOCKED; else - return 0; + return RFKILL_STATE_SOFT_BLOCKED; } static int hp_wmi_bluetooth_state(void) @@ -187,9 +190,9 @@ static int hp_wmi_bluetooth_state(void) int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); if (wireless & 0x10000) - return 1; + return RFKILL_STATE_UNBLOCKED; else - return 0; + return RFKILL_STATE_SOFT_BLOCKED; } static int hp_wmi_wwan_state(void) @@ -197,9 +200,9 @@ static int hp_wmi_wwan_state(void) int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); if (wireless & 0x1000000) - return 1; + return RFKILL_STATE_UNBLOCKED; else - return 0; + return RFKILL_STATE_SOFT_BLOCKED; } static ssize_t show_display(struct device *dev, struct device_attribute *attr, @@ -318,6 +321,9 @@ void hp_wmi_notify(u32 value, void *context) if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == 8) { int eventcode = *((u8 *) obj->buffer.pointer); + if (eventcode == 0x4) + eventcode = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, + 0); key = hp_wmi_get_entry_by_scancode(eventcode); if (key) { switch (key->type) { @@ -338,12 +344,14 @@ void hp_wmi_notify(u32 value, void *context) } } else if (eventcode == 0x5) { if (wifi_rfkill) - wifi_rfkill->state = hp_wmi_wifi_state(); + rfkill_force_state(wifi_rfkill, + hp_wmi_wifi_state()); if (bluetooth_rfkill) - bluetooth_rfkill->state = - hp_wmi_bluetooth_state(); + rfkill_force_state(bluetooth_rfkill, + hp_wmi_bluetooth_state()); if (wwan_rfkill) - wwan_rfkill->state = hp_wmi_wwan_state(); + rfkill_force_state(wwan_rfkill, + hp_wmi_wwan_state()); } else printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n", eventcode); @@ -398,6 +406,7 @@ static void cleanup_sysfs(struct platform_device *device) static int __init hp_wmi_bios_setup(struct platform_device *device) { int err; + int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); err = device_create_file(&device->dev, &dev_attr_display); if (err) @@ -412,28 +421,33 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) if (err) goto add_sysfs_error; - wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN); - wifi_rfkill->name = "hp-wifi"; - wifi_rfkill->state = hp_wmi_wifi_state(); - wifi_rfkill->toggle_radio = hp_wmi_wifi_set; - wifi_rfkill->user_claim_unsupported = 1; - - bluetooth_rfkill = rfkill_allocate(&device->dev, - RFKILL_TYPE_BLUETOOTH); - bluetooth_rfkill->name = "hp-bluetooth"; - bluetooth_rfkill->state = hp_wmi_bluetooth_state(); - bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set; - bluetooth_rfkill->user_claim_unsupported = 1; - - wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WIMAX); - wwan_rfkill->name = "hp-wwan"; - wwan_rfkill->state = hp_wmi_wwan_state(); - wwan_rfkill->toggle_radio = hp_wmi_wwan_set; - wwan_rfkill->user_claim_unsupported = 1; - - rfkill_register(wifi_rfkill); - rfkill_register(bluetooth_rfkill); - rfkill_register(wwan_rfkill); + if (wireless & 0x1) { + wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN); + wifi_rfkill->name = "hp-wifi"; + wifi_rfkill->state = hp_wmi_wifi_state(); + wifi_rfkill->toggle_radio = hp_wmi_wifi_set; + wifi_rfkill->user_claim_unsupported = 1; + rfkill_register(wifi_rfkill); + } + + if (wireless & 0x2) { + bluetooth_rfkill = rfkill_allocate(&device->dev, + RFKILL_TYPE_BLUETOOTH); + bluetooth_rfkill->name = "hp-bluetooth"; + bluetooth_rfkill->state = hp_wmi_bluetooth_state(); + bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set; + bluetooth_rfkill->user_claim_unsupported = 1; + rfkill_register(bluetooth_rfkill); + } + + if (wireless & 0x4) { + wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN); + wwan_rfkill->name = "hp-wwan"; + wwan_rfkill->state = hp_wmi_wwan_state(); + wwan_rfkill->toggle_radio = hp_wmi_wwan_set; + wwan_rfkill->user_claim_unsupported = 1; + rfkill_register(wwan_rfkill); + } return 0; add_sysfs_error: @@ -445,9 +459,12 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device) { cleanup_sysfs(device); - rfkill_unregister(wifi_rfkill); - rfkill_unregister(bluetooth_rfkill); - rfkill_unregister(wwan_rfkill); + if (wifi_rfkill) + rfkill_unregister(wifi_rfkill); + if (bluetooth_rfkill) + rfkill_unregister(bluetooth_rfkill); + if (wwan_rfkill) + rfkill_unregister(wwan_rfkill); return 0; } diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index d3eb7903c346..6b9300779a43 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -3086,7 +3086,6 @@ static struct ibm_struct wan_driver_data = { .read = wan_read, .write = wan_write, .exit = wan_exit, - .flags.experimental = 1, }; /************************************************************************* diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 86dbb366415a..6986f3926244 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -103,8 +103,10 @@ static int mmc_blk_open(struct inode *inode, struct file *filp) check_disk_change(inode->i_bdev); ret = 0; - if ((filp->f_mode & FMODE_WRITE) && md->read_only) + if ((filp->f_mode & FMODE_WRITE) && md->read_only) { + mmc_blk_put(md); ret = -EROFS; + } } return ret; diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index 6915f40ac8ab..1f8b5b36222c 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -621,12 +621,21 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command if (cpu_is_at91sam9260 () || cpu_is_at91sam9263()) if (host->total_length < 12) host->total_length = 12; - host->buffer = dma_alloc_coherent(NULL, - host->total_length, - &host->physical_address, GFP_KERNEL); + + host->buffer = kmalloc(host->total_length, GFP_KERNEL); + if (!host->buffer) { + pr_debug("Can't alloc tx buffer\n"); + cmd->error = -ENOMEM; + mmc_request_done(host->mmc, host->request); + return; + } at91_mci_sg_to_dma(host, data); + host->physical_address = dma_map_single(NULL, + host->buffer, host->total_length, + DMA_TO_DEVICE); + pr_debug("Transmitting %d bytes\n", host->total_length); at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address); @@ -694,7 +703,10 @@ static void at91_mci_completed_command(struct at91mci_host *host, unsigned int s cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3)); if (host->buffer) { - dma_free_coherent(NULL, host->total_length, host->buffer, host->physical_address); + dma_unmap_single(NULL, + host->physical_address, host->total_length, + DMA_TO_DEVICE); + kfree(host->buffer); host->buffer = NULL; } diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index d2f331876e4c..e00d424e6575 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -410,16 +410,20 @@ static int mtd_ioctl(struct inode *inode, struct file *file, case MEMGETREGIONINFO: { - struct region_info_user ur; + uint32_t ur_idx; + struct mtd_erase_region_info *kr; + struct region_info_user *ur = (struct region_info_user *) argp; - if (copy_from_user(&ur, argp, sizeof(struct region_info_user))) + if (get_user(ur_idx, &(ur->regionindex))) return -EFAULT; - if (ur.regionindex >= mtd->numeraseregions) - return -EINVAL; - if (copy_to_user(argp, &(mtd->eraseregions[ur.regionindex]), - sizeof(struct mtd_erase_region_info))) + kr = &(mtd->eraseregions[ur_idx]); + + if (put_user(kr->offset, &(ur->offset)) + || put_user(kr->erasesize, &(ur->erasesize)) + || put_user(kr->numblocks, &(ur->numblocks))) return -EFAULT; + break; } diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index cbab654b03c8..edb1e322113d 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -109,7 +109,7 @@ struct tmio_nand { void __iomem *ccr; void __iomem *fcr; - unsigned long fcr_phys; + unsigned long fcr_base; unsigned int irq; @@ -316,8 +316,8 @@ static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio) tmio_iowrite8(0x81, tmio->ccr + CCR_ICC); /* (10h)BaseAddress 0x1000 spba.spba2 */ - tmio_iowrite16(tmio->fcr_phys, tmio->ccr + CCR_BASE); - tmio_iowrite16(tmio->fcr_phys >> 16, tmio->ccr + CCR_BASE + 16); + tmio_iowrite16(tmio->fcr_base, tmio->ccr + CCR_BASE); + tmio_iowrite16(tmio->fcr_base >> 16, tmio->ccr + CCR_BASE + 2); /* (04h)Command Register I/O spcmd */ tmio_iowrite8(0x02, tmio->ccr + CCR_COMMAND); @@ -395,7 +395,7 @@ static int tmio_probe(struct platform_device *dev) goto err_iomap_ccr; } - tmio->fcr_phys = (unsigned long)fcr->start; + tmio->fcr_base = fcr->start & 0xfffff; tmio->fcr = ioremap(fcr->start, fcr->end - fcr->start + 1); if (!tmio->fcr) { retval = -EIO; diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index a14dba1afcc5..fd705d1295a7 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -151,6 +151,8 @@ struct sw_rx_page { #define PAGES_PER_SGE_SHIFT 0 #define PAGES_PER_SGE (1 << PAGES_PER_SGE_SHIFT) +#define BCM_RX_ETH_PAYLOAD_ALIGN 64 + /* SGE ring related macros */ #define NUM_RX_SGE_PAGES 2 #define RX_SGE_CNT (BCM_PAGE_SIZE / sizeof(struct eth_rx_sge)) @@ -750,8 +752,7 @@ struct bnx2x { u32 rx_csum; u32 rx_offset; - u32 rx_buf_use_size; /* useable size */ - u32 rx_buf_size; /* with alignment */ + u32 rx_buf_size; #define ETH_OVREHEAD (ETH_HLEN + 8) /* 8 for CRC + VLAN */ #define ETH_MIN_PACKET_SIZE 60 #define ETH_MAX_PACKET_SIZE 1500 diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 82deea0a63f5..a8eb3c4a47c8 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -59,8 +59,8 @@ #include "bnx2x.h" #include "bnx2x_init.h" -#define DRV_MODULE_VERSION "1.45.20" -#define DRV_MODULE_RELDATE "2008/08/25" +#define DRV_MODULE_VERSION "1.45.21" +#define DRV_MODULE_RELDATE "2008/09/03" #define BNX2X_BC_VER 0x040200 /* Time in jiffies before concluding the transmitter is hung */ @@ -1027,7 +1027,7 @@ static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp, if (unlikely(skb == NULL)) return -ENOMEM; - mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size, + mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_size, PCI_DMA_FROMDEVICE); if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) { dev_kfree_skb(skb); @@ -1169,7 +1169,7 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue, /* move empty skb from pool to prod and map it */ prod_rx_buf->skb = fp->tpa_pool[queue].skb; mapping = pci_map_single(bp->pdev, fp->tpa_pool[queue].skb->data, - bp->rx_buf_use_size, PCI_DMA_FROMDEVICE); + bp->rx_buf_size, PCI_DMA_FROMDEVICE); pci_unmap_addr_set(prod_rx_buf, mapping, mapping); /* move partial skb from cons to pool (don't unmap yet) */ @@ -1276,7 +1276,7 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp, pool entry status to BNX2X_TPA_STOP even if new skb allocation fails. */ pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping), - bp->rx_buf_use_size, PCI_DMA_FROMDEVICE); + bp->rx_buf_size, PCI_DMA_FROMDEVICE); if (likely(new_skb)) { /* fix ip xsum and give it to the stack */ @@ -1520,7 +1520,7 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) } else if (bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0) { pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping), - bp->rx_buf_use_size, + bp->rx_buf_size, PCI_DMA_FROMDEVICE); skb_reserve(skb, pad); skb_put(skb, len); @@ -4229,7 +4229,7 @@ static inline void bnx2x_free_tpa_pool(struct bnx2x *bp, if (fp->tpa_state[i] == BNX2X_TPA_START) pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping), - bp->rx_buf_use_size, + bp->rx_buf_size, PCI_DMA_FROMDEVICE); dev_kfree_skb(skb); @@ -4245,15 +4245,14 @@ static void bnx2x_init_rx_rings(struct bnx2x *bp) u16 ring_prod, cqe_ring_prod; int i, j; - bp->rx_buf_use_size = bp->dev->mtu; - bp->rx_buf_use_size += bp->rx_offset + ETH_OVREHEAD; - bp->rx_buf_size = bp->rx_buf_use_size + 64; + bp->rx_buf_size = bp->dev->mtu; + bp->rx_buf_size += bp->rx_offset + ETH_OVREHEAD + + BCM_RX_ETH_PAYLOAD_ALIGN; if (bp->flags & TPA_ENABLE_FLAG) { DP(NETIF_MSG_IFUP, - "rx_buf_use_size %d rx_buf_size %d effective_mtu %d\n", - bp->rx_buf_use_size, bp->rx_buf_size, - bp->dev->mtu + ETH_OVREHEAD); + "rx_buf_size %d effective_mtu %d\n", + bp->rx_buf_size, bp->dev->mtu + ETH_OVREHEAD); for_each_queue(bp, j) { struct bnx2x_fastpath *fp = &bp->fp[j]; @@ -4462,9 +4461,10 @@ static void bnx2x_init_context(struct bnx2x *bp) context->ustorm_st_context.common.status_block_id = sb_id; context->ustorm_st_context.common.flags = USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_MC_ALIGNMENT; - context->ustorm_st_context.common.mc_alignment_size = 64; + context->ustorm_st_context.common.mc_alignment_size = + BCM_RX_ETH_PAYLOAD_ALIGN; context->ustorm_st_context.common.bd_buff_size = - bp->rx_buf_use_size; + bp->rx_buf_size; context->ustorm_st_context.common.bd_page_base_hi = U64_HI(fp->rx_desc_mapping); context->ustorm_st_context.common.bd_page_base_lo = @@ -4717,7 +4717,7 @@ static void bnx2x_init_internal_func(struct bnx2x *bp) } /* Init CQ ring mapping and aggregation size */ - max_agg_size = min((u32)(bp->rx_buf_use_size + + max_agg_size = min((u32)(bp->rx_buf_size + 8*BCM_PAGE_SIZE*PAGES_PER_SGE), (u32)0xffff); for_each_queue(bp, i) { @@ -5940,7 +5940,7 @@ static void bnx2x_free_rx_skbs(struct bnx2x *bp) pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping), - bp->rx_buf_use_size, + bp->rx_buf_size, PCI_DMA_FROMDEVICE); rx_buf->skb = NULL; diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 331b86b01fa9..0b6ecef9a849 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -5975,10 +5975,12 @@ static void nv_shutdown(struct pci_dev *pdev) if (netif_running(dev)) nv_close(dev); - pci_enable_wake(pdev, PCI_D3hot, np->wolenabled); - pci_enable_wake(pdev, PCI_D3cold, np->wolenabled); pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); + if (system_state == SYSTEM_POWER_OFF) { + if (pci_enable_wake(pdev, PCI_D3cold, np->wolenabled)) + pci_enable_wake(pdev, PCI_D3hot, np->wolenabled); + pci_set_power_state(pdev, PCI_D3hot); + } } #else #define nv_suspend NULL diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 53f41b649f03..a417be7f8be5 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2304,6 +2304,12 @@ static int __devinit ixgbe_set_interrupt_capability(struct ixgbe_adapter int vector, v_budget; /* + * Set the default interrupt throttle rate. + */ + adapter->rx_eitr = (1000000 / IXGBE_DEFAULT_ITR_RX_USECS); + adapter->tx_eitr = (1000000 / IXGBE_DEFAULT_ITR_TX_USECS); + + /* * It's easy to be greedy for MSI-X vectors, but it really * doesn't do us much good if we have a lot more vectors * than CPU's. So let's be conservative and only ask for diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 32bb47adbe39..008fd6618a5f 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -359,16 +359,6 @@ static void netxen_pcie_strap_init(struct netxen_adapter *adapter) int i, pos; struct pci_dev *pdev; - pdev = pci_get_device(0x1166, 0x0140, NULL); - if (pdev) { - pci_dev_put(pdev); - adapter->hw_read_wx(adapter, - NETXEN_PCIE_REG(PCIE_TGT_SPLIT_CHICKEN), &chicken, 4); - chicken |= 0x4000; - adapter->hw_write_wx(adapter, - NETXEN_PCIE_REG(PCIE_TGT_SPLIT_CHICKEN), &chicken, 4); - } - pdev = adapter->pdev; adapter->hw_read_wx(adapter, diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 3f682d49a4e6..52bf11b73c6e 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -784,6 +784,7 @@ static struct pcmcia_device_id axnet_ids[] = { PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXD", 0x5261440f, 0x436768c5), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEtherII PCC-TXD", 0x5261440f, 0x730df72e), PCMCIA_DEVICE_PROD_ID12("Dynalink", "L100C16", 0x55632fd5, 0x66bc2a90), + PCMCIA_DEVICE_PROD_ID12("IO DATA", "ETXPCM", 0x547e66dc, 0x233adac2), PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V3)", 0x0733cc81, 0x232019a8), PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC3-TX", 0x481e0094, 0xf91af609), PCMCIA_DEVICE_PROD_ID12("PCMCIA", "100BASE", 0x281f1c5d, 0x7c2add04), diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 2d4c4ad89b8d..ebc1ae6bcbe5 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1626,6 +1626,7 @@ static struct pcmcia_device_id pcnet_ids[] = { PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-TD", 0x5261440f, 0xc49bd73d), PCMCIA_DEVICE_PROD_ID12("Corega K.K.", "corega EtherII PCC-TD", 0xd4fdcbd8, 0xc49bd73d), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether PCC-T", 0x5261440f, 0x6705fcaa), + PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether PCC-TD", 0x5261440f, 0x47d5ca83), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FastEther PCC-TX", 0x5261440f, 0x485e85d9), PCMCIA_DEVICE_PROD_ID12("Corega,K.K.", "Ethernet LAN Card", 0x110d26d9, 0x9fd2f0a2), PCMCIA_DEVICE_PROD_ID12("corega,K.K.", "Ethernet LAN Card", 0x9791a90e, 0x9fd2f0a2), @@ -1737,7 +1738,6 @@ static struct pcmcia_device_id pcnet_ids[] = { PCMCIA_DEVICE_PROD_ID1("CyQ've 10 Base-T LAN CARD", 0x94faf360), PCMCIA_DEVICE_PROD_ID1("EP-210 PCMCIA LAN CARD.", 0x8850b4de), PCMCIA_DEVICE_PROD_ID1("ETHER-C16", 0x06a8514f), - PCMCIA_DEVICE_PROD_ID1("IC-CARD", 0x60cb09a6), PCMCIA_DEVICE_PROD_ID1("NE2000 Compatible", 0x75b8ad5a), PCMCIA_DEVICE_PROD_ID2("EN-6200P2", 0xa996d078), /* too generic! */ diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index a84ba487c713..8c19307e5040 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -117,7 +117,7 @@ static void ctrl_callback(struct urb *urb) case -ENOENT: break; default: - if (netif_msg_drv(pegasus)) + if (netif_msg_drv(pegasus) && printk_ratelimit()) dev_dbg(&pegasus->intf->dev, "%s, status %d\n", __FUNCTION__, urb->status); } @@ -166,7 +166,7 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size, set_current_state(TASK_RUNNING); if (ret == -ENODEV) netif_device_detach(pegasus->net); - if (netif_msg_drv(pegasus)) + if (netif_msg_drv(pegasus) && printk_ratelimit()) dev_err(&pegasus->intf->dev, "%s, status %d\n", __FUNCTION__, ret); goto out; @@ -275,7 +275,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data) if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { if (ret == -ENODEV) netif_device_detach(pegasus->net); - if (netif_msg_drv(pegasus)) + if (netif_msg_drv(pegasus) && printk_ratelimit()) dev_err(&pegasus->intf->dev, "%s, status %d\n", __FUNCTION__, ret); goto out; @@ -1209,8 +1209,7 @@ static void pegasus_set_multicast(struct net_device *net) pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS; if (netif_msg_link(pegasus)) pr_info("%s: Promiscuous mode enabled.\n", net->name); - } else if (net->mc_count || - (net->flags & IFF_ALLMULTI)) { + } else if (net->mc_count || (net->flags & IFF_ALLMULTI)) { pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST; pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; if (netif_msg_link(pegasus)) @@ -1220,6 +1219,8 @@ static void pegasus_set_multicast(struct net_device *net) pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; } + pegasus->ctrl_urb->status = 0; + pegasus->flags |= ETH_REGS_CHANGE; ctrl_callback(pegasus->ctrl_urb); } diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index a17eb130f574..6dbfed0b4149 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -7285,15 +7285,15 @@ ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, } break; case ATH9K_CIPHER_WEP: - if (k->kv_len < 40 / NBBY) { + if (k->kv_len < LEN_WEP40) { DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, "%s: WEP key length %u too small\n", __func__, k->kv_len); return false; } - if (k->kv_len <= 40 / NBBY) + if (k->kv_len <= LEN_WEP40) keyType = AR_KEYTABLE_TYPE_40; - else if (k->kv_len <= 104 / NBBY) + else if (k->kv_len <= LEN_WEP104) keyType = AR_KEYTABLE_TYPE_104; else keyType = AR_KEYTABLE_TYPE_128; @@ -7313,7 +7313,7 @@ ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, key2 = get_unaligned_le32(k->kv_val + 6) ^ xorMask; key3 = (get_unaligned_le16(k->kv_val + 10) ^ xorMask) & 0xffff; key4 = get_unaligned_le32(k->kv_val + 12) ^ xorMask; - if (k->kv_len <= 104 / NBBY) + if (k->kv_len <= LEN_WEP104) key4 &= 0xff; if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 2888778040e4..c5107f269f24 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -206,7 +206,8 @@ static int ath_key_config(struct ath_softc *sc, if (!ret) return -EIO; - sc->sc_keytype = hk.kv_type; + if (mac) + sc->sc_keytype = hk.kv_type; return 0; } @@ -756,7 +757,8 @@ static int ath9k_set_key(struct ieee80211_hw *hw, key->hw_key_idx = key->keyidx; /* push IV and Michael MIC generation to stack */ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + if (key->alg == ALG_TKIP) + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; } break; case DISABLE_KEY: @@ -1065,8 +1067,16 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; tx_status->flags &= ~ATH_TX_BAR; } - if (tx_status->flags) - tx_info->status.excessive_retries = 1; + + if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) { + if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { + /* Frame was not ACKed, but an ACK was expected */ + tx_info->status.excessive_retries = 1; + } + } else { + /* Frame was ACKed */ + tx_info->flags |= IEEE80211_TX_STAT_ACK; + } tx_info->status.retry_count = tx_status->retries; diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 2fe806175c01..20ddb7acdb94 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -360,8 +360,9 @@ static void ath_rx_flush_tid(struct ath_softc *sc, struct ath_arx_tid *rxtid, int drop) { struct ath_rxbuf *rxbuf; + unsigned long flag; - spin_lock_bh(&rxtid->tidlock); + spin_lock_irqsave(&rxtid->tidlock, flag); while (rxtid->baw_head != rxtid->baw_tail) { rxbuf = rxtid->rxbuf + rxtid->baw_head; if (!rxbuf->rx_wbuf) { @@ -382,7 +383,7 @@ static void ath_rx_flush_tid(struct ath_softc *sc, INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); } - spin_unlock_bh(&rxtid->tidlock); + spin_unlock_irqrestore(&rxtid->tidlock, flag); } static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 157f830ee6b8..550129f717e2 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -357,9 +357,9 @@ static int ath_tx_prepare(struct ath_softc *sc, txctl->flags = ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) - tx_info->flags |= ATH9K_TXDESC_NOACK; + txctl->flags |= ATH9K_TXDESC_NOACK; if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) - tx_info->flags |= ATH9K_TXDESC_RTSENA; + txctl->flags |= ATH9K_TXDESC_RTSENA; /* * Setup for rate calculations. diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index e2581229d8b2..23fed3298962 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -474,8 +474,8 @@ static void iwl4965_apm_stop(struct iwl_priv *priv) iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); udelay(10); - - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + /* clear "init complete" move adapter D0A* --> D0U state */ + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); spin_unlock_irqrestore(&priv->lock, flags); } diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index cbc01a00eaf4..b08036a9d894 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -145,7 +145,8 @@ static void iwl5000_apm_stop(struct iwl_priv *priv) udelay(10); - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + /* clear "init complete" move adapter D0A* --> D0U state */ + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); spin_unlock_irqrestore(&priv->lock, flags); } @@ -577,14 +578,11 @@ static int iwl5000_load_section(struct iwl_priv *priv, FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); - /* FIME: write the MSB of the phy_addr in CTRL1 - * iwl_write_direct32(priv, - IWL_FH_TFDIB_CTRL1_REG(IWL_FH_SRVC_CHNL), - ((phy_addr & MSB_MSK) - << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_count); - */ iwl_write_direct32(priv, - FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), byte_cnt); + FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), + (iwl_get_dma_hi_address(phy_addr) + << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt); + iwl_write_direct32(priv, FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL), 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM | diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 754fef5b592f..90a2b6dee7c0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1153,7 +1153,8 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, !sta->ht_info.ht_supported) return -1; - if (priv->current_ht_config.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC) + if (((sta->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS) >> 2) + == IWL_MIMO_PS_STATIC) return -1; /* Need both Tx chains/antennas to support MIMO */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 061ffba9c884..e01f048a02dd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -181,14 +181,14 @@ static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon) } /** - * iwl4965_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed + * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed * @priv: staging_rxon is compared to active_rxon * * If the RXON structure is changing enough to require a new tune, * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required. */ -static int iwl4965_full_rxon_required(struct iwl_priv *priv) +static int iwl_full_rxon_required(struct iwl_priv *priv) { /* These items are only settable from the full RXON command */ @@ -207,7 +207,6 @@ static int iwl4965_full_rxon_required(struct iwl_priv *priv) priv->active_rxon.ofdm_ht_single_stream_basic_rates) || (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates != priv->active_rxon.ofdm_ht_dual_stream_basic_rates) || - (priv->staging_rxon.rx_chain != priv->active_rxon.rx_chain) || (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id)) return 1; @@ -263,7 +262,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) /* If we don't need to send a full RXON, we can use * iwl4965_rxon_assoc_cmd which is used to reconfigure filter * and other flags for the current radio configuration. */ - if (!iwl4965_full_rxon_required(priv)) { + if (!iwl_full_rxon_required(priv)) { ret = iwl_send_rxon_assoc(priv); if (ret) { IWL_ERROR("Error setting RXON_ASSOC (%d)\n", ret); @@ -587,8 +586,6 @@ static void iwl4965_ht_conf(struct iwl_priv *priv, iwl_conf->supported_chan_width = 0; } - iwl_conf->tx_mimo_ps_mode = - (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16); iwl_conf->control_channel = ht_bss_conf->primary_channel; @@ -2190,7 +2187,10 @@ static void __iwl4965_down(struct iwl_priv *priv) udelay(5); /* FIXME: apm_ops.suspend(priv) */ - priv->cfg->ops->lib->apm_ops.reset(priv); + if (exit_pending || test_bit(STATUS_IN_SUSPEND, &priv->status)) + priv->cfg->ops->lib->apm_ops.stop(priv); + else + priv->cfg->ops->lib->apm_ops.reset(priv); priv->cfg->ops->lib->free_shared_mem(priv); exit: @@ -2602,6 +2602,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; int ret; + u16 pci_cmd; IWL_DEBUG_MAC80211("enter\n"); @@ -2612,6 +2613,13 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) pci_restore_state(priv->pci_dev); pci_enable_msi(priv->pci_dev); + /* enable interrupts if needed: hw bug w/a */ + pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd); + if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { + pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd); + } + ret = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED, DRV_NAME, priv); if (ret) { @@ -3580,7 +3588,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk priv->assoc_id = 0; timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; - priv->timestamp = le64_to_cpu(timestamp) + (priv->beacon_int * 1000); + priv->timestamp = le64_to_cpu(timestamp); IWL_DEBUG_MAC80211("leave\n"); spin_unlock_irqrestore(&priv->lock, flags); @@ -4364,15 +4372,18 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) iwl_dbgfs_unregister(priv); sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); + /* ieee80211_unregister_hw call wil cause iwl4965_mac_stop to + * to be called and iwl4965_down since we are removing the device + * we need to set STATUS_EXIT_PENDING bit. + */ + set_bit(STATUS_EXIT_PENDING, &priv->status); if (priv->mac80211_registered) { ieee80211_unregister_hw(priv->hw); priv->mac80211_registered = 0; + } else { + iwl4965_down(priv); } - set_bit(STATUS_EXIT_PENDING, &priv->status); - - iwl4965_down(priv); - /* make sure we flush any pending irq or * tasklet for the driver */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c72f72579bea..80f2f84defa8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -592,12 +592,11 @@ static void iwlcore_free_geos(struct iwl_priv *priv) clear_bit(STATUS_GEO_CONFIGURED, &priv->status); } -static u8 is_single_rx_stream(struct iwl_priv *priv) +static bool is_single_rx_stream(struct iwl_priv *priv) { return !priv->current_ht_config.is_ht || ((priv->current_ht_config.supp_mcs_set[1] == 0) && - (priv->current_ht_config.supp_mcs_set[2] == 0)) || - priv->ps_mode == IWL_MIMO_PS_STATIC; + (priv->current_ht_config.supp_mcs_set[2] == 0)); } static u8 iwl_is_channel_extension(struct iwl_priv *priv, @@ -704,33 +703,39 @@ EXPORT_SYMBOL(iwl_set_rxon_ht); * MIMO (dual stream) requires at least 2, but works better with 3. * This does not determine *which* chains to use, just how many. */ -static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv, - u8 *idle_state, u8 *rx_state) +static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) { - u8 is_single = is_single_rx_stream(priv); - u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1; + bool is_single = is_single_rx_stream(priv); + bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); /* # of Rx chains to use when expecting MIMO. */ if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC))) - *rx_state = 2; + return 2; else - *rx_state = 3; + return 3; +} +static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) +{ + int idle_cnt; + bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); /* # Rx chains when idling and maybe trying to save power */ switch (priv->ps_mode) { case IWL_MIMO_PS_STATIC: case IWL_MIMO_PS_DYNAMIC: - *idle_state = (is_cam) ? 2 : 1; + idle_cnt = (is_cam) ? 2 : 1; break; case IWL_MIMO_PS_NONE: - *idle_state = (is_cam) ? *rx_state : 1; + idle_cnt = (is_cam) ? active_cnt : 1; break; + case IWL_MIMO_PS_INVALID: default: - *idle_state = 1; + IWL_ERROR("invalide mimo ps mode %d\n", priv->ps_mode); + WARN_ON(1); + idle_cnt = -1; break; } - - return 0; + return idle_cnt; } /** @@ -741,34 +746,44 @@ static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv, */ void iwl_set_rxon_chain(struct iwl_priv *priv) { - u8 is_single = is_single_rx_stream(priv); - u8 idle_state, rx_state; - - priv->staging_rxon.rx_chain = 0; - rx_state = idle_state = 3; + bool is_single = is_single_rx_stream(priv); + bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); + u8 idle_rx_cnt, active_rx_cnt; + u16 rx_chain; /* Tell uCode which antennas are actually connected. * Before first association, we assume all antennas are connected. * Just after first association, iwl_chain_noise_calibration() * checks which antennas actually *are* connected. */ - priv->staging_rxon.rx_chain |= - cpu_to_le16(priv->hw_params.valid_rx_ant << - RXON_RX_CHAIN_VALID_POS); + rx_chain = priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS; /* How many receivers should we use? */ - iwlcore_get_rx_chain_counter(priv, &idle_state, &rx_state); - priv->staging_rxon.rx_chain |= - cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS); - priv->staging_rxon.rx_chain |= - cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS); - - if (!is_single && (rx_state >= 2) && - !test_bit(STATUS_POWER_PMI, &priv->status)) + active_rx_cnt = iwl_get_active_rx_chain_count(priv); + idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt); + + /* correct rx chain count accoridng hw settings */ + if (priv->hw_params.rx_chains_num < active_rx_cnt) + active_rx_cnt = priv->hw_params.rx_chains_num; + + if (priv->hw_params.rx_chains_num < idle_rx_cnt) + idle_rx_cnt = priv->hw_params.rx_chains_num; + + rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS; + rx_chain |= idle_rx_cnt << RXON_RX_CHAIN_CNT_POS; + + priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain); + + if (!is_single && (active_rx_cnt >= 2) && is_cam) priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK; else priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; - IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain); + IWL_DEBUG_ASSOC("rx_chain=0x%Xi active=%d idle=%d\n", + priv->staging_rxon.rx_chain, + active_rx_cnt, idle_rx_cnt); + + WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 || + active_rx_cnt < idle_rx_cnt); } EXPORT_SYMBOL(iwl_set_rxon_chain); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index c19db438306c..cdfb343c7ec6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -412,7 +412,6 @@ struct iwl_ht_info { /* self configuration data */ u8 is_ht; u8 supported_chan_width; - u16 tx_mimo_ps_mode; u8 is_green_field; u8 sgf; /* HT_SHORT_GI_* short guard interval */ u8 max_amsdu_size; diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 944642450d3d..cd11c0ca2991 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -287,6 +287,7 @@ #define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000) +#define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT 28 /** * Transmit DMA Channel Control/Status Registers (TCSR) diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index f3f6ea49fdd2..e81bfc42a7cb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -1173,7 +1173,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, rx_status.antenna = 0; rx_status.flag = 0; - rx_status.flag |= RX_FLAG_TSFT; + + /* TSF isn't reliable. In order to allow smooth user experience, + * this W/A doesn't propagate it to the mac80211 */ + /*rx_status.flag |= RX_FLAG_TSFT;*/ if ((unlikely(rx_start->cfg_phy_cnt > 20))) { IWL_DEBUG_DROP("dsp size out of range [0,20]: %d/n", diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 9bb6adb28b73..6c8ac3a87d54 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -421,7 +421,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, else scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE; - if ((scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) && n_probes) + if (n_probes) scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes); scan_ch->active_dwell = cpu_to_le16(active_dwell); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index d82823b5c8ab..78b1a7a4ca40 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -402,12 +402,11 @@ static int iwl_hw_tx_queue_init(struct iwl_priv *priv, /** * iwl_tx_queue_init - Allocate and initialize one tx/cmd queue */ -static int iwl_tx_queue_init(struct iwl_priv *priv, - struct iwl_tx_queue *txq, +static int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, int slots_num, u32 txq_id) { int i, len; - int rc = 0; + int ret; /* * Alloc buffer array for commands (Tx or other types of commands). @@ -426,19 +425,16 @@ static int iwl_tx_queue_init(struct iwl_priv *priv, continue; } - txq->cmd[i] = kmalloc(len, GFP_KERNEL | GFP_DMA); + txq->cmd[i] = kmalloc(len, GFP_KERNEL); if (!txq->cmd[i]) - return -ENOMEM; + goto err; } /* Alloc driver data array and TFD circular buffer */ - rc = iwl_tx_queue_alloc(priv, txq, txq_id); - if (rc) { - for (i = 0; i < slots_num; i++) - kfree(txq->cmd[i]); + ret = iwl_tx_queue_alloc(priv, txq, txq_id); + if (ret) + goto err; - return -ENOMEM; - } txq->need_update = 0; /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise @@ -452,6 +448,17 @@ static int iwl_tx_queue_init(struct iwl_priv *priv, iwl_hw_tx_queue_init(priv, txq); return 0; +err: + for (i = 0; i < slots_num; i++) { + kfree(txq->cmd[i]); + txq->cmd[i] = NULL; + } + + if (txq_id == IWL_CMD_QUEUE_NUM) { + kfree(txq->cmd[slots_num]); + txq->cmd[slots_num] = NULL; + } + return -ENOMEM; } /** * iwl_hw_txq_ctx_free - Free TXQ Context diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 04d7a251e3f0..8941919001bb 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -595,7 +595,7 @@ static int if_cs_prog_helper(struct if_cs_card *card) if (ret < 0) { lbs_pr_err("can't download helper at 0x%x, ret %d\n", sent, ret); - goto done; + goto err_release; } if (count == 0) @@ -604,9 +604,8 @@ static int if_cs_prog_helper(struct if_cs_card *card) sent += count; } +err_release: release_firmware(fw); - ret = 0; - done: lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); return ret; @@ -676,14 +675,8 @@ static int if_cs_prog_real(struct if_cs_card *card) } ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a); - if (ret < 0) { + if (ret < 0) lbs_pr_err("firmware download failed\n"); - goto err_release; - } - - ret = 0; - goto done; - err_release: release_firmware(fw); diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 1ebcafe7ca5f..36c004e15602 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -1970,6 +1970,9 @@ __orinoco_set_multicast_list(struct net_device *dev) priv->promiscuous = promisc; } + /* If we're not in promiscuous mode, then we need to set the + * group address if either we want to multicast, or if we were + * multicasting and want to stop */ if (! promisc && (mc_count || priv->mc_count) ) { struct dev_mc_list *p = dev->mc_list; struct hermes_multicast mclist; @@ -1989,9 +1992,10 @@ __orinoco_set_multicast_list(struct net_device *dev) printk(KERN_WARNING "%s: Multicast list is " "longer than mc_count\n", dev->name); - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES, - HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN), - &mclist); + err = hermes_write_ltv(hw, USER_BAP, + HERMES_RID_CNFGROUPADDRESSES, + HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN), + &mclist); if (err) printk(KERN_ERR "%s: Error %d setting multicast list.\n", dev->name, err); diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index 7e88ce5651b9..2ea7866abd5d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h @@ -136,7 +136,7 @@ struct rt2x00_field32 { */ #define is_power_of_two(x) ( !((x) & ((x)-1)) ) #define low_bit_mask(x) ( ((x)-1) & ~(x) ) -#define is_valid_mask(x) is_power_of_two(1 + (x) + low_bit_mask(x)) +#define is_valid_mask(x) is_power_of_two(1LU + (x) + low_bit_mask(x)) /* * Macro's to find first set bit in a variable. @@ -173,8 +173,7 @@ struct rt2x00_field32 { * does not exceed the given typelimit. */ #define FIELD_CHECK(__mask, __type) \ - BUILD_BUG_ON(!__builtin_constant_p(__mask) || \ - !(__mask) || \ + BUILD_BUG_ON(!(__mask) || \ !is_valid_mask(__mask) || \ (__mask) != (__type)(__mask)) \ diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 82634a2f1b1d..1aad599816f7 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -352,11 +352,12 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long continue; r_size = r->end - r->start + 1; /* For bridges size != alignment */ - align = (i < PCI_BRIDGE_RESOURCES) ? r_size : r->start; + align = resource_alignment(r); order = __ffs(align) - 20; if (order > 11) { - dev_warn(&dev->dev, "BAR %d too large: " + dev_warn(&dev->dev, "BAR %d bad alignment %llx: " "%#016llx-%#016llx\n", i, + (unsigned long long)align, (unsigned long long)r->start, (unsigned long long)r->end); r->flags = 0; diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index d7e9f2152df0..95015cbfd33f 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -405,8 +405,6 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: extended_irq = &res->data.extended_irq; - if (extended_irq->producer_consumer == ACPI_PRODUCER) - return AE_OK; if (extended_irq->interrupt_count == 0) pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 6ea349aba3ba..b184367637d0 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -800,7 +800,6 @@ static void __exit cmos_do_remove(struct device *dev) static int cmos_suspend(struct device *dev, pm_message_t mesg) { struct cmos_rtc *cmos = dev_get_drvdata(dev); - int do_wake = device_may_wakeup(dev); unsigned char tmp; /* only the alarm might be a wakeup event source */ @@ -809,7 +808,7 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg) if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) { unsigned char mask; - if (do_wake) + if (device_may_wakeup(dev)) mask = RTC_IRQMASK & ~RTC_AIE; else mask = RTC_IRQMASK; @@ -837,6 +836,17 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg) return 0; } +/* We want RTC alarms to wake us from e.g. ACPI G2/S5 "soft off", even + * after a detour through G3 "mechanical off", although the ACPI spec + * says wakeup should only work from G1/S4 "hibernate". To most users, + * distinctions between S4 and S5 are pointless. So when the hardware + * allows, don't draw that distinction. + */ +static inline int cmos_poweroff(struct device *dev) +{ + return cmos_suspend(dev, PMSG_HIBERNATE); +} + static int cmos_resume(struct device *dev) { struct cmos_rtc *cmos = dev_get_drvdata(dev); @@ -884,6 +894,12 @@ static int cmos_resume(struct device *dev) #else #define cmos_suspend NULL #define cmos_resume NULL + +static inline int cmos_poweroff(struct device *dev) +{ + return -ENOSYS; +} + #endif /*----------------------------------------------------------------*/ @@ -903,10 +919,6 @@ static int cmos_resume(struct device *dev) static int __devinit cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) { - /* REVISIT paranoia argues for a shutdown notifier, since PNP - * drivers can't provide shutdown() methods to disable IRQs. - * Or better yet, fix PNP to allow those methods... - */ if (pnp_port_start(pnp,0) == 0x70 && !pnp_irq_valid(pnp,0)) /* Some machines contain a PNP entry for the RTC, but * don't define the IRQ. It should always be safe to @@ -942,6 +954,13 @@ static int cmos_pnp_resume(struct pnp_dev *pnp) #define cmos_pnp_resume NULL #endif +static void cmos_pnp_shutdown(struct device *pdev) +{ + if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(pdev)) + return; + + cmos_do_shutdown(); +} static const struct pnp_device_id rtc_ids[] = { { .id = "PNP0b00", }, @@ -961,6 +980,10 @@ static struct pnp_driver cmos_pnp_driver = { .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, .suspend = cmos_pnp_suspend, .resume = cmos_pnp_resume, + .driver = { + .name = (char *)driver_name, + .shutdown = cmos_pnp_shutdown, + } }; #endif /* CONFIG_PNP */ @@ -986,6 +1009,9 @@ static int __exit cmos_platform_remove(struct platform_device *pdev) static void cmos_platform_shutdown(struct platform_device *pdev) { + if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(&pdev->dev)) + return; + cmos_do_shutdown(); } diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c index 9f996ec881ce..dd70bf73ce9d 100644 --- a/drivers/rtc/rtc-lib.c +++ b/drivers/rtc/rtc-lib.c @@ -51,10 +51,11 @@ EXPORT_SYMBOL(rtc_year_days); */ void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) { - unsigned int days, month, year; + unsigned int month, year; + int days; days = time / 86400; - time -= days * 86400; + time -= (unsigned int) days * 86400; /* day of the week, 1970-01-01 was a Thursday */ tm->tm_wday = (days + 4) % 7; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index e5e7d7856454..2a2bc89aba83 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1875,6 +1875,7 @@ static int sd_probe(struct device *dev) dev_set_drvdata(dev, sdkp); add_disk(gd); + blk_register_filter(gd); sd_dif_config_host(sdkp); sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", @@ -1908,6 +1909,7 @@ static int sd_remove(struct device *dev) struct scsi_disk *sdkp = dev_get_drvdata(dev); device_del(&sdkp->dev); + blk_unregister_filter(sdkp->disk); del_gendisk(sdkp->disk); sd_shutdown(dev); diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 27f5bfd1def3..3292965bfd84 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -656,6 +656,7 @@ static int sr_probe(struct device *dev) dev_set_drvdata(dev, cd); disk->flags |= GENHD_FL_REMOVABLE; add_disk(disk); + blk_register_filter(disk); sdev_printk(KERN_DEBUG, sdev, "Attached scsi CD-ROM %s\n", cd->cdi.name); @@ -894,6 +895,7 @@ static int sr_remove(struct device *dev) { struct scsi_cd *cd = dev_get_drvdata(dev); + blk_unregister_filter(cd->disk); del_gendisk(cd->disk); mutex_lock(&sr_ref_mutex); diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 342e12fb1c25..9ccc563d8730 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1908,15 +1908,23 @@ static int serial8250_startup(struct uart_port *port) * kick the UART on a regular basis. */ if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) { + up->bugs |= UART_BUG_THRE; pr_debug("ttyS%d - using backup timer\n", port->line); - up->timer.function = serial8250_backup_timeout; - up->timer.data = (unsigned long)up; - mod_timer(&up->timer, jiffies + - poll_timeout(up->port.timeout) + HZ / 5); } } /* + * The above check will only give an accurate result the first time + * the port is opened so this value needs to be preserved. + */ + if (up->bugs & UART_BUG_THRE) { + up->timer.function = serial8250_backup_timeout; + up->timer.data = (unsigned long)up; + mod_timer(&up->timer, jiffies + + poll_timeout(up->port.timeout) + HZ / 5); + } + + /* * If the "interrupt" for this port doesn't correspond with any * hardware interrupt, we use a timer-based system. The original * driver used to do this with IRQ0. diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h index 78c00162b04e..520260326f3d 100644 --- a/drivers/serial/8250.h +++ b/drivers/serial/8250.h @@ -47,6 +47,7 @@ struct serial8250_config { #define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */ #define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */ #define UART_BUG_NOMSR (1 << 2) /* UART has buggy MSR status bits (Au1x00) */ +#define UART_BUG_THRE (1 << 3) /* UART has buggy THRE reassertion */ #define PROBE_RSA (1 << 0) #define PROBE_ANY (~0) diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 1eb64d08b60a..95b3ec89c126 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -208,7 +208,7 @@ static int ohci_omap_init(struct usb_hcd *hcd) if (cpu_is_omap16xx()) ocpi_enable(); -#ifdef CONFIG_ARCH_OMAP_OTG +#ifdef CONFIG_USB_OTG if (need_transceiver) { ohci->transceiver = otg_get_transceiver(); if (ohci->transceiver) { diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 7b74238ad1c7..e980766bb84b 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -161,7 +161,7 @@ static int usb_console_setup(struct console *co, char *options) if (serial->type->set_termios) { termios->c_cflag = cflag; tty_termios_encode_baud_rate(termios, baud, baud); - serial->type->set_termios(NULL, port, &dummy); + serial->type->set_termios(tty, port, &dummy); port->port.tty = NULL; kfree(termios); diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 9c5925927ece..5a24c6411d34 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -939,7 +939,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) ret = register_framebuffer(info); if (ret < 0) { dev_err(dev, "failed to register framebuffer device: %d\n", ret); - goto free_cmap; + goto reset_drvdata; } /* add selected videomode to modelist */ @@ -955,7 +955,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) return 0; - +reset_drvdata: + dev_set_drvdata(dev, NULL); free_cmap: fb_dealloc_cmap(&info->cmap); unregister_irqs: @@ -992,10 +993,11 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct fb_info *info = dev_get_drvdata(dev); - struct atmel_lcdfb_info *sinfo = info->par; + struct atmel_lcdfb_info *sinfo; - if (!sinfo) + if (!info || !info->par) return 0; + sinfo = info->par; cancel_work_sync(&sinfo->task); exit_backlight(sinfo); diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index c14b2435d23e..e729fb279645 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c @@ -628,27 +628,18 @@ static long cirrusfb_get_mclk(long freq, int bpp, long *div) static int cirrusfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { - int nom, den; /* translyting from pixels->bytes */ - int yres, i; - static struct { int xres, yres; } modes[] = - { { 1600, 1280 }, - { 1280, 1024 }, - { 1024, 768 }, - { 800, 600 }, - { 640, 480 }, - { -1, -1 } }; + int yres; + /* memory size in pixels */ + unsigned pixels = info->screen_size * 8 / var->bits_per_pixel; switch (var->bits_per_pixel) { case 1: - nom = 4; - den = 8; + pixels /= 4; break; /* 8 pixel per byte, only 1/4th of mem usable */ case 8: case 16: case 24: case 32: - nom = var->bits_per_pixel / 8; - den = 1; break; /* 1 pixel == 1 byte */ default: printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..." @@ -658,43 +649,29 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, return -EINVAL; } - if (var->xres * nom / den * var->yres > info->screen_size) { - printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..." - "resolution too high to fit into video memory!\n", - var->xres, var->yres, var->bits_per_pixel); - DPRINTK("EXIT - EINVAL error\n"); - return -EINVAL; - } - + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; /* use highest possible virtual resolution */ - if (var->xres_virtual == -1 && - var->yres_virtual == -1) { - printk(KERN_INFO - "cirrusfb: using maximum available virtual resolution\n"); - for (i = 0; modes[i].xres != -1; i++) { - int size = modes[i].xres * nom / den * modes[i].yres; - if (size < info->screen_size / 2) - break; - } - if (modes[i].xres == -1) { - printk(KERN_ERR "cirrusfb: could not find a virtual " - "resolution that fits into video memory!!\n"); - DPRINTK("EXIT - EINVAL error\n"); - return -EINVAL; - } - var->xres_virtual = modes[i].xres; - var->yres_virtual = modes[i].yres; + if (var->yres_virtual == -1) { + var->yres_virtual = pixels / var->xres_virtual; printk(KERN_INFO "cirrusfb: virtual resolution set to " "maximum of %dx%d\n", var->xres_virtual, var->yres_virtual); } - - if (var->xres_virtual < var->xres) - var->xres_virtual = var->xres; if (var->yres_virtual < var->yres) var->yres_virtual = var->yres; + if (var->xres_virtual * var->yres_virtual > pixels) { + printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected... " + "virtual resolution too high to fit into video memory!\n", + var->xres_virtual, var->yres_virtual, + var->bits_per_pixel); + DPRINTK("EXIT - EINVAL error\n"); + return -EINVAL; + } + + if (var->xoffset < 0) var->xoffset = 0; if (var->yoffset < 0) diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 77aafcfae037..4599a4385bc9 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -95,7 +95,6 @@ static inline int mtrr_del(int reg, unsigned long base, #define VOODOO5_MAX_PIXCLOCK 350000 static struct fb_fix_screeninfo tdfx_fix __devinitdata = { - .id = "3Dfx", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_PSEUDOCOLOR, .ypanstep = 1, @@ -426,7 +425,7 @@ static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short dev_id) if (dev_id < PCI_DEVICE_ID_3DFX_VOODOO5) { /* Banshee/Voodoo3 */ chip_size = 2; - if (has_sgram && (draminit0 & DRAMINIT0_SGRAM_TYPE)) + if (has_sgram && !(draminit0 & DRAMINIT0_SGRAM_TYPE)) chip_size = 1; } else { /* Voodoo4/5 */ @@ -1200,15 +1199,15 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, /* Configure the default fb_fix_screeninfo first */ switch (pdev->device) { case PCI_DEVICE_ID_3DFX_BANSHEE: - strcat(tdfx_fix.id, " Banshee"); + strcpy(tdfx_fix.id, "3Dfx Banshee"); default_par->max_pixclock = BANSHEE_MAX_PIXCLOCK; break; case PCI_DEVICE_ID_3DFX_VOODOO3: - strcat(tdfx_fix.id, " Voodoo3"); + strcpy(tdfx_fix.id, "3Dfx Voodoo3"); default_par->max_pixclock = VOODOO3_MAX_PIXCLOCK; break; case PCI_DEVICE_ID_3DFX_VOODOO5: - strcat(tdfx_fix.id, " Voodoo5"); + strcpy(tdfx_fix.id, "3Dfx Voodoo5"); default_par->max_pixclock = VOODOO5_MAX_PIXCLOCK; break; } diff --git a/firmware/Makefile b/firmware/Makefile index 9fe86041f86e..da75a6fbc6ba 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -146,15 +146,27 @@ $(patsubst %,$(obj)/%.gen.o, $(fw-external-y)): $(obj)/%.gen.o: $(fwdir)/% $(obj)/%: $(obj)/%.ihex | $(objtree)/$(obj)/$$(dir %) $(call cmd,ihex) +# Don't depend on ihex2fw if we're installing and it already exists. +# Putting it after | in the dependencies doesn't seem sufficient when +# we're installing after a cross-compile, because ihex2fw has dependencies +# on stuff like /usr/lib/gcc/ppc64-redhat-linux/4.3.0/include/stddef.h and +# thus wants to be rebuilt. Which it can't be, if the prebuilt kernel tree +# is exported read-only for someone to run 'make install'. +ifeq ($(INSTALL):$(wildcard $(obj)/ihex2fw),install:$(obj)/ihex2fw) +ihex2fw_dep := +else +ihex2fw_dep := $(obj)/ihex2fw +endif + # .HEX is also Intel HEX, but where the offset and length in each record # is actually meaningful, because the firmware has to be loaded in a certain # order rather than as a single binary blob. Thus, we convert them into our # more compact binary representation of ihex records (<linux/ihex.h>) -$(obj)/%.fw: $(obj)/%.HEX $(obj)/ihex2fw | $(objtree)/$(obj)/$$(dir %) +$(obj)/%.fw: $(obj)/%.HEX $(ihex2fw_dep) | $(objtree)/$(obj)/$$(dir %) $(call cmd,ihex2fw) # .H16 is our own modified form of Intel HEX, with 16-bit length for records. -$(obj)/%.fw: $(obj)/%.H16 $(obj)/ihex2fw | $(objtree)/$(obj)/$$(dir %) +$(obj)/%.fw: $(obj)/%.H16 $(ihex2fw_dep) | $(objtree)/$(obj)/$$(dir %) $(call cmd,h16tofw) $(firmware-dirs): diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index f9e4ad97a79e..06e521a945c3 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -9,7 +9,10 @@ files (e.g. "cp -a") to Windows servers. For mkdir and create honor setgid bit on parent directory when server supports Unix Extensions but not POSIX create. Update cifs.upcall version to handle new Kerberos sec flags (this requires update of cifs.upcall program from Samba). Fix memory leak -on dns_upcall (resolving DFS referralls). +on dns_upcall (resolving DFS referralls). Fix plain text password +authentication (requires setting SecurityFlags to 0x30030 to enable +lanman and plain text though). Fix writes to be at correct offset when +file is open with O_APPEND and file is on a directio (forcediretio) mount. Version 1.53 ------------ diff --git a/fs/cifs/README b/fs/cifs/README index 68b5c1169d9d..bd2343d4c6a6 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -542,10 +542,20 @@ SecurityFlags Flags which control security negotiation and hashing mechanisms (as "must use") on the other hand does not make much sense. Default flags are 0x07007 - (NTLM, NTLMv2 and packet signing allowed). Maximum + (NTLM, NTLMv2 and packet signing allowed). The maximum allowable flags if you want to allow mounts to servers using weaker password hashes is 0x37037 (lanman, - plaintext, ntlm, ntlmv2, signing allowed): + plaintext, ntlm, ntlmv2, signing allowed). Some + SecurityFlags require the corresponding menuconfig + options to be enabled (lanman and plaintext require + CONFIG_CIFS_WEAK_PW_HASH for example). Enabling + plaintext authentication currently requires also + enabling lanman authentication in the security flags + because the cifs module only supports sending + laintext passwords using the older lanman dialect + form of the session setup SMB. (e.g. for authentication + using plain text passwords, set the SecurityFlags + to 0x30030): may use packet signing 0x00001 must use packet signing 0x01001 diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 83fd40dc1ef0..bd5f13d38450 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -294,6 +294,7 @@ void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key) if ((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0) if (extended_security & CIFSSEC_MAY_PLNTXT) { + memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE); memcpy(lnm_session_key, password_with_pad, CIFS_ENCPWD_SIZE); return; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index ff14d14903a0..cbefe1f1f9fe 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -833,6 +833,10 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, return -EBADF; open_file = (struct cifsFileInfo *) file->private_data; + rc = generic_write_checks(file, poffset, &write_size, 0); + if (rc) + return rc; + xid = GetXid(); if (*poffset > file->f_path.dentry->d_inode->i_size) diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index b537fad3bf50..252fdc0567f1 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -409,6 +409,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, #ifdef CONFIG_CIFS_WEAK_PW_HASH char lnm_session_key[CIFS_SESS_KEY_SIZE]; + pSMB->req.hdr.Flags2 &= ~SMBFLG2_UNICODE; + /* no capabilities flags in old lanman negotiation */ pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 9abcd2b329f7..e9b20173fef3 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1279,6 +1279,12 @@ static int nfs_parse_mount_options(char *raw, } } + if (errors > 0) { + dfprintk(MOUNT, "NFS: parsing encountered %d error%s\n", + errors, (errors == 1 ? "" : "s")); + if (!sloppy) + return 0; + } return 1; out_nomem: diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index b6ed38380ab8..54b8b4140c8f 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c @@ -443,7 +443,7 @@ init_state(struct posix_acl_state *state, int cnt) * enough space for either: */ alloc = sizeof(struct posix_ace_state_array) - + cnt*sizeof(struct posix_ace_state); + + cnt*sizeof(struct posix_user_ace_state); state->users = kzalloc(alloc, GFP_KERNEL); if (!state->users) return -ENOMEM; diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 2e51adac65de..e5b51ffafc6c 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -867,11 +867,6 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, int slack_bytes; __be32 status; - status = nfserr_resource; - cstate = cstate_alloc(); - if (cstate == NULL) - goto out; - resp->xbuf = &rqstp->rq_res; resp->p = rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len; resp->tagp = resp->p; @@ -890,6 +885,11 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, if (args->minorversion > NFSD_SUPPORTED_MINOR_VERSION) goto out; + status = nfserr_resource; + cstate = cstate_alloc(); + if (cstate == NULL) + goto out; + status = nfs_ok; while (!status && resp->opcnt < args->opcnt) { op = &args->ops[resp->opcnt++]; @@ -957,9 +957,9 @@ encode_op: nfsd4_increment_op_stats(op->opnum); } + cstate_free(cstate); out: nfsd4_release_compoundargs(args); - cstate_free(cstate); dprintk("nfsv4 compound returned %d\n", ntohl(status)); return status; } diff --git a/fs/ntfs/usnjrnl.h b/fs/ntfs/usnjrnl.h index 3a8af75351e8..4087fbdac327 100644 --- a/fs/ntfs/usnjrnl.h +++ b/fs/ntfs/usnjrnl.h @@ -113,7 +113,7 @@ typedef struct { * Reason flags (32-bit). Cumulative flags describing the change(s) to the * file since it was last opened. I think the names speak for themselves but * if you disagree check out the descriptions in the Linux NTFS project NTFS - * documentation: http://linux-ntfs.sourceforge.net/ntfs/files/usnjrnl.html + * documentation: http://www.linux-ntfs.org/ */ enum { USN_REASON_DATA_OVERWRITE = const_cpu_to_le32(0x00000001), @@ -145,7 +145,7 @@ typedef le32 USN_REASON_FLAGS; * Source info flags (32-bit). Information about the source of the change(s) * to the file. For detailed descriptions of what these mean, see the Linux * NTFS project NTFS documentation: - * http://linux-ntfs.sourceforge.net/ntfs/files/usnjrnl.html + * http://www.linux-ntfs.org/ */ enum { USN_SOURCE_DATA_MANAGEMENT = const_cpu_to_le32(0x00000001), diff --git a/fs/proc/array.c b/fs/proc/array.c index 0d6eb33597c6..71c9be59c9c2 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -337,65 +337,6 @@ int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, return 0; } -/* - * Use precise platform statistics if available: - */ -#ifdef CONFIG_VIRT_CPU_ACCOUNTING -static cputime_t task_utime(struct task_struct *p) -{ - return p->utime; -} - -static cputime_t task_stime(struct task_struct *p) -{ - return p->stime; -} -#else -static cputime_t task_utime(struct task_struct *p) -{ - clock_t utime = cputime_to_clock_t(p->utime), - total = utime + cputime_to_clock_t(p->stime); - u64 temp; - - /* - * Use CFS's precise accounting: - */ - temp = (u64)nsec_to_clock_t(p->se.sum_exec_runtime); - - if (total) { - temp *= utime; - do_div(temp, total); - } - utime = (clock_t)temp; - - p->prev_utime = max(p->prev_utime, clock_t_to_cputime(utime)); - return p->prev_utime; -} - -static cputime_t task_stime(struct task_struct *p) -{ - clock_t stime; - - /* - * Use CFS's precise accounting. (we subtract utime from - * the total, to make sure the total observed by userspace - * grows monotonically - apps rely on that): - */ - stime = nsec_to_clock_t(p->se.sum_exec_runtime) - - cputime_to_clock_t(task_utime(p)); - - if (stime >= 0) - p->prev_stime = max(p->prev_stime, clock_t_to_cputime(stime)); - - return p->prev_stime; -} -#endif - -static cputime_t task_gtime(struct task_struct *p) -{ - return p->gtime; -} - static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task, int whole) { diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index ded969862960..00f10a2dcf12 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -24,6 +24,7 @@ #include <linux/tty.h> #include <linux/string.h> #include <linux/mman.h> +#include <linux/quicklist.h> #include <linux/proc_fs.h> #include <linux/ioport.h> #include <linux/mm.h> @@ -189,7 +190,8 @@ static int meminfo_read_proc(char *page, char **start, off_t off, "Committed_AS: %8lu kB\n" "VmallocTotal: %8lu kB\n" "VmallocUsed: %8lu kB\n" - "VmallocChunk: %8lu kB\n", + "VmallocChunk: %8lu kB\n" + "Quicklists: %8lu kB\n", K(i.totalram), K(i.freeram), K(i.bufferram), @@ -221,7 +223,8 @@ static int meminfo_read_proc(char *page, char **start, off_t off, K(committed), (unsigned long)VMALLOC_TOTAL >> 10, vmi.used >> 10, - vmi.largest_chunk >> 10 + vmi.largest_chunk >> 10, + K(quicklist_total_size()) ); len += hugetlb_report_meminfo(page + len); diff --git a/include/asm-generic/Kbuild.asm b/include/asm-generic/Kbuild.asm index 1170dc60e638..1870d5e05f1c 100644 --- a/include/asm-generic/Kbuild.asm +++ b/include/asm-generic/Kbuild.asm @@ -1,8 +1,10 @@ -ifneq ($(wildcard $(srctree)/include/asm-$(SRCARCH)/kvm.h),) +ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/kvm.h \ + $(srctree)/include/asm-$(SRCARCH)/kvm.h),) header-y += kvm.h endif -ifneq ($(wildcard $(srctree)/include/asm-$(SRCARCH)/a.out.h),) +ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/a.out.h \ + $(srctree)/include/asm-$(SRCARCH)/a.out.h),) unifdef-y += a.out.h endif unifdef-y += auxvec.h diff --git a/include/asm-generic/syscall.h b/include/asm-generic/syscall.h index abcf34c2fdc7..ea8087b55ffc 100644 --- a/include/asm-generic/syscall.h +++ b/include/asm-generic/syscall.h @@ -126,7 +126,7 @@ void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, * @args: array of argument values to store * * Changes @n arguments to the system call starting with the @i'th argument. - * @n'th argument to @val. Argument @i gets value @args[0], and so on. + * Argument @i gets value @args[0], and so on. * An arch inline version is probably optimal when @i and @n are constants. * * It's only valid to call this when @task is stopped for tracing on diff --git a/include/asm-mips/cacheflush.h b/include/asm-mips/cacheflush.h index d5c0f2fda51b..03b1d69b142f 100644 --- a/include/asm-mips/cacheflush.h +++ b/include/asm-mips/cacheflush.h @@ -63,6 +63,7 @@ static inline void flush_icache_page(struct vm_area_struct *vma, } extern void (*flush_icache_range)(unsigned long start, unsigned long end); +extern void (*local_flush_icache_range)(unsigned long start, unsigned long end); extern void (*__flush_cache_vmap)(void); diff --git a/include/asm-x86/cpufeature.h b/include/asm-x86/cpufeature.h index 762f6a6bc707..9489283a4bcf 100644 --- a/include/asm-x86/cpufeature.h +++ b/include/asm-x86/cpufeature.h @@ -72,14 +72,15 @@ #define X86_FEATURE_UP (3*32+ 9) /* smp kernel running on up */ #define X86_FEATURE_FXSAVE_LEAK (3*32+10) /* FXSAVE leaks FOP/FIP/FOP */ #define X86_FEATURE_ARCH_PERFMON (3*32+11) /* Intel Architectural PerfMon */ -#define X86_FEATURE_PEBS (3*32+12) /* Precise-Event Based Sampling */ -#define X86_FEATURE_BTS (3*32+13) /* Branch Trace Store */ -#define X86_FEATURE_SYSCALL32 (3*32+14) /* syscall in ia32 userspace */ -#define X86_FEATURE_SYSENTER32 (3*32+15) /* sysenter in ia32 userspace */ +#define X86_FEATURE_PEBS (3*32+12) /* Precise-Event Based Sampling */ +#define X86_FEATURE_BTS (3*32+13) /* Branch Trace Store */ +#define X86_FEATURE_SYSCALL32 (3*32+14) /* syscall in ia32 userspace */ +#define X86_FEATURE_SYSENTER32 (3*32+15) /* sysenter in ia32 userspace */ #define X86_FEATURE_REP_GOOD (3*32+16) /* rep microcode works well on this CPU */ #define X86_FEATURE_MFENCE_RDTSC (3*32+17) /* Mfence synchronizes RDTSC */ #define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* Lfence synchronizes RDTSC */ -#define X86_FEATURE_11AP (3*32+19) /* Bad local APIC aka 11AP */ +#define X86_FEATURE_11AP (3*32+19) /* Bad local APIC aka 11AP */ +#define X86_FEATURE_NOPL (3*32+20) /* The NOPL (0F 1F) instructions */ /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ #define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */ diff --git a/include/asm-x86/required-features.h b/include/asm-x86/required-features.h index adec887dd7cd..5c2ff4bc2980 100644 --- a/include/asm-x86/required-features.h +++ b/include/asm-x86/required-features.h @@ -41,6 +41,12 @@ # define NEED_3DNOW 0 #endif +#if defined(CONFIG_X86_P6_NOP) || defined(CONFIG_X86_64) +# define NEED_NOPL (1<<(X86_FEATURE_NOPL & 31)) +#else +# define NEED_NOPL 0 +#endif + #ifdef CONFIG_X86_64 #define NEED_PSE 0 #define NEED_MSR (1<<(X86_FEATURE_MSR & 31)) @@ -67,7 +73,7 @@ #define REQUIRED_MASK1 (NEED_LM|NEED_3DNOW) #define REQUIRED_MASK2 0 -#define REQUIRED_MASK3 0 +#define REQUIRED_MASK3 (NEED_NOPL) #define REQUIRED_MASK4 0 #define REQUIRED_MASK5 0 #define REQUIRED_MASK6 0 diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 7d970678f940..b68ec09399be 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -167,7 +167,8 @@ unifdef-y += acct.h unifdef-y += adb.h unifdef-y += adfs_fs.h unifdef-y += agpgart.h -ifneq ($(wildcard $(srctree)/include/asm-$(SRCARCH)/a.out.h),) +ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/a.out.h \ + $(srctree)/include/asm-$(SRCARCH)/a.out.h),) unifdef-y += a.out.h endif unifdef-y += apm_bios.h @@ -258,7 +259,8 @@ unifdef-y += kd.h unifdef-y += kernelcapi.h unifdef-y += kernel.h unifdef-y += keyboard.h -ifneq ($(wildcard $(srctree)/include/asm-$(SRCARCH)/kvm.h),) +ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/kvm.h \ + $(srctree)/include/asm-$(SRCARCH)/kvm.h),) unifdef-y += kvm.h endif unifdef-y += llc.h @@ -297,7 +299,6 @@ unifdef-y += parport.h unifdef-y += patchkey.h unifdef-y += pci.h unifdef-y += personality.h -unifdef-y += pim.h unifdef-y += pktcdvd.h unifdef-y += pmu.h unifdef-y += poll.h diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index c33b0dc28e4d..ed3a5d473e52 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h @@ -127,6 +127,8 @@ extern int clockevents_register_notifier(struct notifier_block *nb); extern int clockevents_program_event(struct clock_event_device *dev, ktime_t expires, ktime_t now); +extern void clockevents_handle_noop(struct clock_event_device *dev); + #ifdef CONFIG_GENERIC_CLOCKEVENTS extern void clockevents_notify(unsigned long reason, void *arg); #else diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h index e8f450c499b0..2691926fb506 100644 --- a/include/linux/cpuset.h +++ b/include/linux/cpuset.h @@ -160,7 +160,7 @@ static inline int current_cpuset_is_being_rebound(void) static inline void rebuild_sched_domains(void) { - partition_sched_domains(0, NULL, NULL); + partition_sched_domains(1, NULL, NULL); } #endif /* !CONFIG_CPUSETS */ diff --git a/include/linux/ide.h b/include/linux/ide.h index 87c12ed96954..1524829f73f2 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -1111,7 +1111,6 @@ void ide_setup_pci_noise(struct pci_dev *, const struct ide_port_info *); #ifdef CONFIG_BLK_DEV_IDEDMA_PCI int ide_pci_set_master(struct pci_dev *, const char *); unsigned long ide_pci_dma_base(ide_hwif_t *, const struct ide_port_info *); -extern const struct ide_dma_ops sff_dma_ops; int ide_pci_check_simplex(ide_hwif_t *, const struct ide_port_info *); int ide_hwif_setup_dma(ide_hwif_t *, const struct ide_port_info *); #else @@ -1275,6 +1274,7 @@ extern int __ide_dma_end(ide_drive_t *); int ide_dma_test_irq(ide_drive_t *); extern void ide_dma_lost_irq(ide_drive_t *); extern void ide_dma_timeout(ide_drive_t *); +extern const struct ide_dma_ops sff_dma_ops; #endif /* CONFIG_BLK_DEV_IDEDMA_SFF */ #else @@ -1448,8 +1448,7 @@ static inline void ide_dump_identify(u8 *id) static inline int hwif_to_node(ide_hwif_t *hwif) { - struct pci_dev *dev = to_pci_dev(hwif->dev); - return hwif->dev ? pcibus_to_node(dev->bus) : -1; + return hwif->dev ? dev_to_node(hwif->dev) : -1; } static inline ide_drive_t *ide_get_paired_drive(ide_drive_t *drive) diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 22d2115458c6..8d3b7a9afd17 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -109,6 +109,7 @@ extern struct resource iomem_resource; extern int request_resource(struct resource *root, struct resource *new); extern int release_resource(struct resource *new); extern int insert_resource(struct resource *parent, struct resource *new); +extern void insert_resource_expand_to_fit(struct resource *root, struct resource *new); extern int allocate_resource(struct resource *root, struct resource *new, resource_size_t size, resource_size_t min, resource_size_t max, resource_size_t align, diff --git a/include/linux/list.h b/include/linux/list.h index db35ef02e745..969f6e92d089 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -619,6 +619,19 @@ static inline void hlist_add_after(struct hlist_node *n, next->next->pprev = &next->next; } +/* + * Move a list from one list head to another. Fixup the pprev + * reference of the first entry if it exists. + */ +static inline void hlist_move_list(struct hlist_head *old, + struct hlist_head *new) +{ + new->first = old->first; + if (new->first) + new->first->pprev = &new->first; + old->first = NULL; +} + #define hlist_entry(ptr, type, member) container_of(ptr,type,member) #define hlist_for_each(pos, head) \ diff --git a/include/linux/mroute.h b/include/linux/mroute.h index 07112ee9293a..8a455694d682 100644 --- a/include/linux/mroute.h +++ b/include/linux/mroute.h @@ -6,7 +6,6 @@ #ifdef __KERNEL__ #include <linux/in.h> #endif -#include <linux/pim.h> /* * Based on the MROUTING 3.5 defines primarily to keep @@ -130,6 +129,7 @@ struct igmpmsg */ #ifdef __KERNEL__ +#include <linux/pim.h> #include <net/sock.h> #ifdef CONFIG_IP_MROUTE diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h index 5cf50473a10f..6f4c180179e2 100644 --- a/include/linux/mroute6.h +++ b/include/linux/mroute6.h @@ -115,6 +115,7 @@ struct sioc_mif_req6 #ifdef __KERNEL__ +#include <linux/pim.h> #include <linux/skbuff.h> /* for struct sk_buff_head */ #ifdef CONFIG_IPV6_MROUTE diff --git a/include/linux/pim.h b/include/linux/pim.h index 236ffd317394..1ba0661561a4 100644 --- a/include/linux/pim.h +++ b/include/linux/pim.h @@ -3,22 +3,6 @@ #include <asm/byteorder.h> -#ifndef __KERNEL__ -struct pim { -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 pim_type:4, /* PIM message type */ - pim_ver:4; /* PIM version */ -#elif defined(__BIG_ENDIAN_BITFIELD) - __u8 pim_ver:4; /* PIM version */ - pim_type:4; /* PIM message type */ -#endif - __u8 pim_rsv; /* Reserved */ - __be16 pim_cksum; /* Checksum */ -}; - -#define PIM_MINLEN 8 -#endif - /* Message types - V1 */ #define PIM_V1_VERSION __constant_htonl(0x10000000) #define PIM_V1_REGISTER 1 @@ -27,7 +11,6 @@ struct pim { #define PIM_VERSION 2 #define PIM_REGISTER 1 -#if defined(__KERNEL__) #define PIM_NULL_REGISTER __constant_htonl(0x40000000) /* PIMv2 register message header layout (ietf-draft-idmr-pimvsm-v2-00.ps */ @@ -42,4 +25,3 @@ struct pimreghdr struct sk_buff; extern int pim_rcv_v1(struct sk_buff *); #endif -#endif diff --git a/include/linux/quicklist.h b/include/linux/quicklist.h index 39b66713a0bb..bd466439c588 100644 --- a/include/linux/quicklist.h +++ b/include/linux/quicklist.h @@ -80,6 +80,13 @@ void quicklist_trim(int nr, void (*dtor)(void *), unsigned long quicklist_total_size(void); +#else + +static inline unsigned long quicklist_total_size(void) +{ + return 0; +} + #endif #endif /* LINUX_QUICKLIST_H */ diff --git a/include/linux/res_counter.h b/include/linux/res_counter.h index fdeadd9740dc..271c1c2c9f6f 100644 --- a/include/linux/res_counter.h +++ b/include/linux/res_counter.h @@ -166,7 +166,7 @@ static inline int res_counter_set_limit(struct res_counter *cnt, int ret = -EBUSY; spin_lock_irqsave(&cnt->lock, flags); - if (cnt->usage < limit) { + if (cnt->usage <= limit) { cnt->limit = limit; ret = 0; } diff --git a/include/linux/sched.h b/include/linux/sched.h index cfb0d87b99fc..3d9120c5ad15 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1475,6 +1475,10 @@ static inline void put_task_struct(struct task_struct *t) __put_task_struct(t); } +extern cputime_t task_utime(struct task_struct *p); +extern cputime_t task_stime(struct task_struct *p); +extern cputime_t task_gtime(struct task_struct *p); + /* * Per process flags */ diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h index ef2e3a20bf3b..dc05b54bd3a3 100644 --- a/include/linux/sunrpc/svc_rdma.h +++ b/include/linux/sunrpc/svc_rdma.h @@ -143,7 +143,6 @@ struct svcxprt_rdma { unsigned long sc_flags; struct list_head sc_dto_q; /* DTO tasklet I/O pending Q */ struct list_head sc_read_complete_q; - spinlock_t sc_read_complete_lock; struct work_struct sc_work; }; /* sc_flags */ diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h index b48d81969574..6186a789d6c7 100644 --- a/include/linux/tracehook.h +++ b/include/linux/tracehook.h @@ -272,7 +272,7 @@ static inline void tracehook_finish_clone(struct task_struct *child, * tracehook_report_clone_complete(). This must prevent the child from * self-reaping if tracehook_report_clone_complete() uses the @child * pointer; otherwise it might have died and been released by the time - * tracehook_report_report_clone_complete() is called. + * tracehook_report_clone_complete() is called. * * Called with no locks held, but the child cannot run until this returns. */ diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index e65a6bed4e3e..303d93ffd6b2 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -334,6 +334,8 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_SPCA508 v4l2_fourcc('S', '5', '0', '8') /* YUVY per line */ #define V4L2_PIX_FMT_SPCA561 v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */ #define V4L2_PIX_FMT_PAC207 v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */ +#define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */ +#define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */ /* * F O R M A T E N U M E R A T I O N diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h index 95c660c9719b..91324908fccd 100644 --- a/include/net/inet_timewait_sock.h +++ b/include/net/inet_timewait_sock.h @@ -208,6 +208,9 @@ extern void inet_twsk_schedule(struct inet_timewait_sock *tw, extern void inet_twsk_deschedule(struct inet_timewait_sock *tw, struct inet_timewait_death_row *twdr); +extern void inet_twsk_purge(struct net *net, struct inet_hashinfo *hashinfo, + struct inet_timewait_death_row *twdr, int family); + static inline struct net *twsk_net(const struct inet_timewait_sock *twsk) { diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 972f8e61d36a..59cedfb040e7 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -243,10 +243,11 @@ static inline int open_arg(int flags, int mask) static int audit_match_perm(struct audit_context *ctx, int mask) { + unsigned n; if (unlikely(!ctx)) return 0; - unsigned n = ctx->major; + n = ctx->major; switch (audit_classify_syscall(ctx->arch, n)) { case 0: /* native */ if ((mask & AUDIT_PERM_WRITE) && diff --git a/kernel/cpuset.c b/kernel/cpuset.c index d5ab79cf516d..f227bc172690 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -14,6 +14,8 @@ * 2003-10-22 Updates by Stephen Hemminger. * 2004 May-July Rework by Paul Jackson. * 2006 Rework by Paul Menage to use generic cgroups + * 2008 Rework of the scheduler domains and CPU hotplug handling + * by Max Krasnyansky * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of the Linux @@ -236,9 +238,11 @@ static struct cpuset top_cpuset = { static DEFINE_MUTEX(callback_mutex); -/* This is ugly, but preserves the userspace API for existing cpuset +/* + * This is ugly, but preserves the userspace API for existing cpuset * users. If someone tries to mount the "cpuset" filesystem, we - * silently switch it to mount "cgroup" instead */ + * silently switch it to mount "cgroup" instead + */ static int cpuset_get_sb(struct file_system_type *fs_type, int flags, const char *unused_dev_name, void *data, struct vfsmount *mnt) @@ -473,10 +477,9 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial) } /* - * Helper routine for rebuild_sched_domains(). + * Helper routine for generate_sched_domains(). * Do cpusets a, b have overlapping cpus_allowed masks? */ - static int cpusets_overlap(struct cpuset *a, struct cpuset *b) { return cpus_intersects(a->cpus_allowed, b->cpus_allowed); @@ -518,26 +521,15 @@ update_domain_attr_tree(struct sched_domain_attr *dattr, struct cpuset *c) } /* - * rebuild_sched_domains() - * - * This routine will be called to rebuild the scheduler's dynamic - * sched domains: - * - if the flag 'sched_load_balance' of any cpuset with non-empty - * 'cpus' changes, - * - or if the 'cpus' allowed changes in any cpuset which has that - * flag enabled, - * - or if the 'sched_relax_domain_level' of any cpuset which has - * that flag enabled and with non-empty 'cpus' changes, - * - or if any cpuset with non-empty 'cpus' is removed, - * - or if a cpu gets offlined. - * - * This routine builds a partial partition of the systems CPUs - * (the set of non-overlappping cpumask_t's in the array 'part' - * below), and passes that partial partition to the kernel/sched.c - * partition_sched_domains() routine, which will rebuild the - * schedulers load balancing domains (sched domains) as specified - * by that partial partition. A 'partial partition' is a set of - * non-overlapping subsets whose union is a subset of that set. + * generate_sched_domains() + * + * This function builds a partial partition of the systems CPUs + * A 'partial partition' is a set of non-overlapping subsets whose + * union is a subset of that set. + * The output of this function needs to be passed to kernel/sched.c + * partition_sched_domains() routine, which will rebuild the scheduler's + * load balancing domains (sched domains) as specified by that partial + * partition. * * See "What is sched_load_balance" in Documentation/cpusets.txt * for a background explanation of this. @@ -547,13 +539,7 @@ update_domain_attr_tree(struct sched_domain_attr *dattr, struct cpuset *c) * domains when operating in the severe memory shortage situations * that could cause allocation failures below. * - * Call with cgroup_mutex held. May take callback_mutex during - * call due to the kfifo_alloc() and kmalloc() calls. May nest - * a call to the get_online_cpus()/put_online_cpus() pair. - * Must not be called holding callback_mutex, because we must not - * call get_online_cpus() while holding callback_mutex. Elsewhere - * the kernel nests callback_mutex inside get_online_cpus() calls. - * So the reverse nesting would risk an ABBA deadlock. + * Must be called with cgroup_lock held. * * The three key local variables below are: * q - a linked-list queue of cpuset pointers, used to implement a @@ -588,10 +574,10 @@ update_domain_attr_tree(struct sched_domain_attr *dattr, struct cpuset *c) * element of the partition (one sched domain) to be passed to * partition_sched_domains(). */ - -void rebuild_sched_domains(void) +static int generate_sched_domains(cpumask_t **domains, + struct sched_domain_attr **attributes) { - LIST_HEAD(q); /* queue of cpusets to be scanned*/ + LIST_HEAD(q); /* queue of cpusets to be scanned */ struct cpuset *cp; /* scans q */ struct cpuset **csa; /* array of all cpuset ptrs */ int csn; /* how many cpuset ptrs in csa so far */ @@ -601,23 +587,26 @@ void rebuild_sched_domains(void) int ndoms; /* number of sched domains in result */ int nslot; /* next empty doms[] cpumask_t slot */ - csa = NULL; + ndoms = 0; doms = NULL; dattr = NULL; + csa = NULL; /* Special case for the 99% of systems with one, full, sched domain */ if (is_sched_load_balance(&top_cpuset)) { - ndoms = 1; doms = kmalloc(sizeof(cpumask_t), GFP_KERNEL); if (!doms) - goto rebuild; + goto done; + dattr = kmalloc(sizeof(struct sched_domain_attr), GFP_KERNEL); if (dattr) { *dattr = SD_ATTR_INIT; update_domain_attr_tree(dattr, &top_cpuset); } *doms = top_cpuset.cpus_allowed; - goto rebuild; + + ndoms = 1; + goto done; } csa = kmalloc(number_of_cpusets * sizeof(cp), GFP_KERNEL); @@ -680,61 +669,141 @@ restart: } } - /* Convert <csn, csa> to <ndoms, doms> */ + /* + * Now we know how many domains to create. + * Convert <csn, csa> to <ndoms, doms> and populate cpu masks. + */ doms = kmalloc(ndoms * sizeof(cpumask_t), GFP_KERNEL); - if (!doms) - goto rebuild; + if (!doms) { + ndoms = 0; + goto done; + } + + /* + * The rest of the code, including the scheduler, can deal with + * dattr==NULL case. No need to abort if alloc fails. + */ dattr = kmalloc(ndoms * sizeof(struct sched_domain_attr), GFP_KERNEL); for (nslot = 0, i = 0; i < csn; i++) { struct cpuset *a = csa[i]; + cpumask_t *dp; int apn = a->pn; - if (apn >= 0) { - cpumask_t *dp = doms + nslot; - - if (nslot == ndoms) { - static int warnings = 10; - if (warnings) { - printk(KERN_WARNING - "rebuild_sched_domains confused:" - " nslot %d, ndoms %d, csn %d, i %d," - " apn %d\n", - nslot, ndoms, csn, i, apn); - warnings--; - } - continue; + if (apn < 0) { + /* Skip completed partitions */ + continue; + } + + dp = doms + nslot; + + if (nslot == ndoms) { + static int warnings = 10; + if (warnings) { + printk(KERN_WARNING + "rebuild_sched_domains confused:" + " nslot %d, ndoms %d, csn %d, i %d," + " apn %d\n", + nslot, ndoms, csn, i, apn); + warnings--; } + continue; + } - cpus_clear(*dp); - if (dattr) - *(dattr + nslot) = SD_ATTR_INIT; - for (j = i; j < csn; j++) { - struct cpuset *b = csa[j]; - - if (apn == b->pn) { - cpus_or(*dp, *dp, b->cpus_allowed); - b->pn = -1; - if (dattr) - update_domain_attr_tree(dattr - + nslot, b); - } + cpus_clear(*dp); + if (dattr) + *(dattr + nslot) = SD_ATTR_INIT; + for (j = i; j < csn; j++) { + struct cpuset *b = csa[j]; + + if (apn == b->pn) { + cpus_or(*dp, *dp, b->cpus_allowed); + if (dattr) + update_domain_attr_tree(dattr + nslot, b); + + /* Done with this partition */ + b->pn = -1; } - nslot++; } + nslot++; } BUG_ON(nslot != ndoms); -rebuild: - /* Have scheduler rebuild sched domains */ +done: + kfree(csa); + + *domains = doms; + *attributes = dattr; + return ndoms; +} + +/* + * Rebuild scheduler domains. + * + * Call with neither cgroup_mutex held nor within get_online_cpus(). + * Takes both cgroup_mutex and get_online_cpus(). + * + * Cannot be directly called from cpuset code handling changes + * to the cpuset pseudo-filesystem, because it cannot be called + * from code that already holds cgroup_mutex. + */ +static void do_rebuild_sched_domains(struct work_struct *unused) +{ + struct sched_domain_attr *attr; + cpumask_t *doms; + int ndoms; + get_online_cpus(); - partition_sched_domains(ndoms, doms, dattr); + + /* Generate domain masks and attrs */ + cgroup_lock(); + ndoms = generate_sched_domains(&doms, &attr); + cgroup_unlock(); + + /* Have scheduler rebuild the domains */ + partition_sched_domains(ndoms, doms, attr); + put_online_cpus(); +} -done: - kfree(csa); - /* Don't kfree(doms) -- partition_sched_domains() does that. */ - /* Don't kfree(dattr) -- partition_sched_domains() does that. */ +static DECLARE_WORK(rebuild_sched_domains_work, do_rebuild_sched_domains); + +/* + * Rebuild scheduler domains, asynchronously via workqueue. + * + * If the flag 'sched_load_balance' of any cpuset with non-empty + * 'cpus' changes, or if the 'cpus' allowed changes in any cpuset + * which has that flag enabled, or if any cpuset with a non-empty + * 'cpus' is removed, then call this routine to rebuild the + * scheduler's dynamic sched domains. + * + * The rebuild_sched_domains() and partition_sched_domains() + * routines must nest cgroup_lock() inside get_online_cpus(), + * but such cpuset changes as these must nest that locking the + * other way, holding cgroup_lock() for much of the code. + * + * So in order to avoid an ABBA deadlock, the cpuset code handling + * these user changes delegates the actual sched domain rebuilding + * to a separate workqueue thread, which ends up processing the + * above do_rebuild_sched_domains() function. + */ +static void async_rebuild_sched_domains(void) +{ + schedule_work(&rebuild_sched_domains_work); +} + +/* + * Accomplishes the same scheduler domain rebuild as the above + * async_rebuild_sched_domains(), however it directly calls the + * rebuild routine synchronously rather than calling it via an + * asynchronous work thread. + * + * This can only be called from code that is not holding + * cgroup_mutex (not nested in a cgroup_lock() call.) + */ +void rebuild_sched_domains(void) +{ + do_rebuild_sched_domains(NULL); } /** @@ -863,7 +932,7 @@ static int update_cpumask(struct cpuset *cs, const char *buf) return retval; if (is_load_balanced) - rebuild_sched_domains(); + async_rebuild_sched_domains(); return 0; } @@ -1090,7 +1159,7 @@ static int update_relax_domain_level(struct cpuset *cs, s64 val) if (val != cs->relax_domain_level) { cs->relax_domain_level = val; if (!cpus_empty(cs->cpus_allowed) && is_sched_load_balance(cs)) - rebuild_sched_domains(); + async_rebuild_sched_domains(); } return 0; @@ -1131,7 +1200,7 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, mutex_unlock(&callback_mutex); if (cpus_nonempty && balance_flag_changed) - rebuild_sched_domains(); + async_rebuild_sched_domains(); return 0; } @@ -1492,6 +1561,9 @@ static u64 cpuset_read_u64(struct cgroup *cont, struct cftype *cft) default: BUG(); } + + /* Unreachable but makes gcc happy */ + return 0; } static s64 cpuset_read_s64(struct cgroup *cont, struct cftype *cft) @@ -1504,6 +1576,9 @@ static s64 cpuset_read_s64(struct cgroup *cont, struct cftype *cft) default: BUG(); } + + /* Unrechable but makes gcc happy */ + return 0; } @@ -1692,15 +1767,9 @@ static struct cgroup_subsys_state *cpuset_create( } /* - * Locking note on the strange update_flag() call below: - * * If the cpuset being removed has its flag 'sched_load_balance' * enabled, then simulate turning sched_load_balance off, which - * will call rebuild_sched_domains(). The get_online_cpus() - * call in rebuild_sched_domains() must not be made while holding - * callback_mutex. Elsewhere the kernel nests callback_mutex inside - * get_online_cpus() calls. So the reverse nesting would risk an - * ABBA deadlock. + * will call async_rebuild_sched_domains(). */ static void cpuset_destroy(struct cgroup_subsys *ss, struct cgroup *cont) @@ -1719,7 +1788,7 @@ static void cpuset_destroy(struct cgroup_subsys *ss, struct cgroup *cont) struct cgroup_subsys cpuset_subsys = { .name = "cpuset", .create = cpuset_create, - .destroy = cpuset_destroy, + .destroy = cpuset_destroy, .can_attach = cpuset_can_attach, .attach = cpuset_attach, .populate = cpuset_populate, @@ -1811,7 +1880,7 @@ static void move_member_tasks_to_cpuset(struct cpuset *from, struct cpuset *to) } /* - * If common_cpu_mem_hotplug_unplug(), below, unplugs any CPUs + * If CPU and/or memory hotplug handlers, below, unplug any CPUs * or memory nodes, we need to walk over the cpuset hierarchy, * removing that CPU or node from all cpusets. If this removes the * last CPU or node from a cpuset, then move the tasks in the empty @@ -1903,35 +1972,6 @@ static void scan_for_empty_cpusets(const struct cpuset *root) } /* - * The cpus_allowed and mems_allowed nodemasks in the top_cpuset track - * cpu_online_map and node_states[N_HIGH_MEMORY]. Force the top cpuset to - * track what's online after any CPU or memory node hotplug or unplug event. - * - * Since there are two callers of this routine, one for CPU hotplug - * events and one for memory node hotplug events, we could have coded - * two separate routines here. We code it as a single common routine - * in order to minimize text size. - */ - -static void common_cpu_mem_hotplug_unplug(int rebuild_sd) -{ - cgroup_lock(); - - top_cpuset.cpus_allowed = cpu_online_map; - top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY]; - scan_for_empty_cpusets(&top_cpuset); - - /* - * Scheduler destroys domains on hotplug events. - * Rebuild them based on the current settings. - */ - if (rebuild_sd) - rebuild_sched_domains(); - - cgroup_unlock(); -} - -/* * The top_cpuset tracks what CPUs and Memory Nodes are online, * period. This is necessary in order to make cpusets transparent * (of no affect) on systems that are actively using CPU hotplug @@ -1939,40 +1979,52 @@ static void common_cpu_mem_hotplug_unplug(int rebuild_sd) * * This routine ensures that top_cpuset.cpus_allowed tracks * cpu_online_map on each CPU hotplug (cpuhp) event. + * + * Called within get_online_cpus(). Needs to call cgroup_lock() + * before calling generate_sched_domains(). */ - -static int cpuset_handle_cpuhp(struct notifier_block *unused_nb, +static int cpuset_track_online_cpus(struct notifier_block *unused_nb, unsigned long phase, void *unused_cpu) { + struct sched_domain_attr *attr; + cpumask_t *doms; + int ndoms; + switch (phase) { - case CPU_UP_CANCELED: - case CPU_UP_CANCELED_FROZEN: - case CPU_DOWN_FAILED: - case CPU_DOWN_FAILED_FROZEN: case CPU_ONLINE: case CPU_ONLINE_FROZEN: case CPU_DEAD: case CPU_DEAD_FROZEN: - common_cpu_mem_hotplug_unplug(1); break; + default: return NOTIFY_DONE; } + cgroup_lock(); + top_cpuset.cpus_allowed = cpu_online_map; + scan_for_empty_cpusets(&top_cpuset); + ndoms = generate_sched_domains(&doms, &attr); + cgroup_unlock(); + + /* Have scheduler rebuild the domains */ + partition_sched_domains(ndoms, doms, attr); + return NOTIFY_OK; } #ifdef CONFIG_MEMORY_HOTPLUG /* * Keep top_cpuset.mems_allowed tracking node_states[N_HIGH_MEMORY]. - * Call this routine anytime after you change - * node_states[N_HIGH_MEMORY]. - * See also the previous routine cpuset_handle_cpuhp(). + * Call this routine anytime after node_states[N_HIGH_MEMORY] changes. + * See also the previous routine cpuset_track_online_cpus(). */ - void cpuset_track_online_nodes(void) { - common_cpu_mem_hotplug_unplug(0); + cgroup_lock(); + top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY]; + scan_for_empty_cpusets(&top_cpuset); + cgroup_unlock(); } #endif @@ -1987,7 +2039,7 @@ void __init cpuset_init_smp(void) top_cpuset.cpus_allowed = cpu_online_map; top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY]; - hotcpu_notifier(cpuset_handle_cpuhp, 0); + hotcpu_notifier(cpuset_track_online_cpus, 0); } /** diff --git a/kernel/exit.c b/kernel/exit.c index 75c647387639..16395644a98f 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -112,9 +112,9 @@ static void __exit_signal(struct task_struct *tsk) * We won't ever get here for the group leader, since it * will have been the last reference on the signal_struct. */ - sig->utime = cputime_add(sig->utime, tsk->utime); - sig->stime = cputime_add(sig->stime, tsk->stime); - sig->gtime = cputime_add(sig->gtime, tsk->gtime); + sig->utime = cputime_add(sig->utime, task_utime(tsk)); + sig->stime = cputime_add(sig->stime, task_stime(tsk)); + sig->gtime = cputime_add(sig->gtime, task_gtime(tsk)); sig->min_flt += tsk->min_flt; sig->maj_flt += tsk->maj_flt; sig->nvcsw += tsk->nvcsw; @@ -831,26 +831,50 @@ static void reparent_thread(struct task_struct *p, struct task_struct *father) * the child reaper process (ie "init") in our pid * space. */ +static struct task_struct *find_new_reaper(struct task_struct *father) +{ + struct pid_namespace *pid_ns = task_active_pid_ns(father); + struct task_struct *thread; + + thread = father; + while_each_thread(father, thread) { + if (thread->flags & PF_EXITING) + continue; + if (unlikely(pid_ns->child_reaper == father)) + pid_ns->child_reaper = thread; + return thread; + } + + if (unlikely(pid_ns->child_reaper == father)) { + write_unlock_irq(&tasklist_lock); + if (unlikely(pid_ns == &init_pid_ns)) + panic("Attempted to kill init!"); + + zap_pid_ns_processes(pid_ns); + write_lock_irq(&tasklist_lock); + /* + * We can not clear ->child_reaper or leave it alone. + * There may by stealth EXIT_DEAD tasks on ->children, + * forget_original_parent() must move them somewhere. + */ + pid_ns->child_reaper = init_pid_ns.child_reaper; + } + + return pid_ns->child_reaper; +} + static void forget_original_parent(struct task_struct *father) { - struct task_struct *p, *n, *reaper = father; + struct task_struct *p, *n, *reaper; LIST_HEAD(ptrace_dead); write_lock_irq(&tasklist_lock); - + reaper = find_new_reaper(father); /* * First clean up ptrace if we were using it. */ ptrace_exit(father, &ptrace_dead); - do { - reaper = next_thread(reaper); - if (reaper == father) { - reaper = task_child_reaper(father); - break; - } - } while (reaper->flags & PF_EXITING); - list_for_each_entry_safe(p, n, &father->children, sibling) { p->real_parent = reaper; if (p->parent == father) { @@ -959,39 +983,6 @@ static void check_stack_usage(void) static inline void check_stack_usage(void) {} #endif -static inline void exit_child_reaper(struct task_struct *tsk) -{ - if (likely(tsk->group_leader != task_child_reaper(tsk))) - return; - - if (tsk->nsproxy->pid_ns == &init_pid_ns) - panic("Attempted to kill init!"); - - /* - * @tsk is the last thread in the 'cgroup-init' and is exiting. - * Terminate all remaining processes in the namespace and reap them - * before exiting @tsk. - * - * Note that @tsk (last thread of cgroup-init) may not necessarily - * be the child-reaper (i.e main thread of cgroup-init) of the - * namespace i.e the child_reaper may have already exited. - * - * Even after a child_reaper exits, we let it inherit orphaned children, - * because, pid_ns->child_reaper remains valid as long as there is - * at least one living sub-thread in the cgroup init. - - * This living sub-thread of the cgroup-init will be notified when - * a child inherited by the 'child-reaper' exits (do_notify_parent() - * uses __group_send_sig_info()). Further, when reaping child processes, - * do_wait() iterates over children of all living sub threads. - - * i.e even though 'child_reaper' thread is listed as the parent of the - * orphaned children, any living sub-thread in the cgroup-init can - * perform the role of the child_reaper. - */ - zap_pid_ns_processes(tsk->nsproxy->pid_ns); -} - NORET_TYPE void do_exit(long code) { struct task_struct *tsk = current; @@ -1051,7 +1042,6 @@ NORET_TYPE void do_exit(long code) } group_dead = atomic_dec_and_test(&tsk->signal->live); if (group_dead) { - exit_child_reaper(tsk); hrtimer_cancel(&tsk->signal->real_timer); exit_itimers(tsk->signal); } diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index ea567b78d1aa..fab8ea86fac3 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c @@ -179,9 +179,6 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns) rc = sys_wait4(-1, NULL, __WALL, NULL); } while (rc != -ECHILD); - - /* Child reaper for the pid namespace is going away */ - pid_ns->child_reaper = NULL; acct_exit_ns(pid_ns); return; } diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c index da9c2dda6a4e..dfdec524d1b7 100644 --- a/kernel/pm_qos_params.c +++ b/kernel/pm_qos_params.c @@ -43,7 +43,7 @@ #include <linux/uaccess.h> /* - * locking rule: all changes to target_value or requirements or notifiers lists + * locking rule: all changes to requirements or notifiers lists * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock * held, taken with _irqsave. One lock to rule them all */ @@ -66,7 +66,7 @@ struct pm_qos_object { struct miscdevice pm_qos_power_miscdev; char *name; s32 default_value; - s32 target_value; + atomic_t target_value; s32 (*comparitor)(s32, s32); }; @@ -77,7 +77,7 @@ static struct pm_qos_object cpu_dma_pm_qos = { .notifiers = &cpu_dma_lat_notifier, .name = "cpu_dma_latency", .default_value = 2000 * USEC_PER_SEC, - .target_value = 2000 * USEC_PER_SEC, + .target_value = ATOMIC_INIT(2000 * USEC_PER_SEC), .comparitor = min_compare }; @@ -87,7 +87,7 @@ static struct pm_qos_object network_lat_pm_qos = { .notifiers = &network_lat_notifier, .name = "network_latency", .default_value = 2000 * USEC_PER_SEC, - .target_value = 2000 * USEC_PER_SEC, + .target_value = ATOMIC_INIT(2000 * USEC_PER_SEC), .comparitor = min_compare }; @@ -99,7 +99,7 @@ static struct pm_qos_object network_throughput_pm_qos = { .notifiers = &network_throughput_notifier, .name = "network_throughput", .default_value = 0, - .target_value = 0, + .target_value = ATOMIC_INIT(0), .comparitor = max_compare }; @@ -150,11 +150,11 @@ static void update_target(int target) extreme_value = pm_qos_array[target]->comparitor( extreme_value, node->value); } - if (pm_qos_array[target]->target_value != extreme_value) { + if (atomic_read(&pm_qos_array[target]->target_value) != extreme_value) { call_notifier = 1; - pm_qos_array[target]->target_value = extreme_value; + atomic_set(&pm_qos_array[target]->target_value, extreme_value); pr_debug(KERN_ERR "new target for qos %d is %d\n", target, - pm_qos_array[target]->target_value); + atomic_read(&pm_qos_array[target]->target_value)); } spin_unlock_irqrestore(&pm_qos_lock, flags); @@ -193,14 +193,7 @@ static int find_pm_qos_object_by_minor(int minor) */ int pm_qos_requirement(int pm_qos_class) { - int ret_val; - unsigned long flags; - - spin_lock_irqsave(&pm_qos_lock, flags); - ret_val = pm_qos_array[pm_qos_class]->target_value; - spin_unlock_irqrestore(&pm_qos_lock, flags); - - return ret_val; + return atomic_read(&pm_qos_array[pm_qos_class]->target_value); } EXPORT_SYMBOL_GPL(pm_qos_requirement); diff --git a/kernel/resource.c b/kernel/resource.c index f5b518eabefe..03d796c1b2e9 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -362,35 +362,21 @@ int allocate_resource(struct resource *root, struct resource *new, EXPORT_SYMBOL(allocate_resource); -/** - * insert_resource - Inserts a resource in the resource tree - * @parent: parent of the new resource - * @new: new resource to insert - * - * Returns 0 on success, -EBUSY if the resource can't be inserted. - * - * This function is equivalent to request_resource when no conflict - * happens. If a conflict happens, and the conflicting resources - * entirely fit within the range of the new resource, then the new - * resource is inserted and the conflicting resources become children of - * the new resource. +/* + * Insert a resource into the resource tree. If successful, return NULL, + * otherwise return the conflicting resource (compare to __request_resource()) */ -int insert_resource(struct resource *parent, struct resource *new) +static struct resource * __insert_resource(struct resource *parent, struct resource *new) { - int result; struct resource *first, *next; - write_lock(&resource_lock); - for (;; parent = first) { - result = 0; first = __request_resource(parent, new); if (!first) - goto out; + return first; - result = -EBUSY; if (first == parent) - goto out; + return first; if ((first->start > new->start) || (first->end < new->end)) break; @@ -401,15 +387,13 @@ int insert_resource(struct resource *parent, struct resource *new) for (next = first; ; next = next->sibling) { /* Partial overlap? Bad, and unfixable */ if (next->start < new->start || next->end > new->end) - goto out; + return next; if (!next->sibling) break; if (next->sibling->start > new->end) break; } - result = 0; - new->parent = parent; new->sibling = next->sibling; new->child = first; @@ -426,10 +410,64 @@ int insert_resource(struct resource *parent, struct resource *new) next = next->sibling; next->sibling = new; } + return NULL; +} - out: +/** + * insert_resource - Inserts a resource in the resource tree + * @parent: parent of the new resource + * @new: new resource to insert + * + * Returns 0 on success, -EBUSY if the resource can't be inserted. + * + * This function is equivalent to request_resource when no conflict + * happens. If a conflict happens, and the conflicting resources + * entirely fit within the range of the new resource, then the new + * resource is inserted and the conflicting resources become children of + * the new resource. + */ +int insert_resource(struct resource *parent, struct resource *new) +{ + struct resource *conflict; + + write_lock(&resource_lock); + conflict = __insert_resource(parent, new); + write_unlock(&resource_lock); + return conflict ? -EBUSY : 0; +} + +/** + * insert_resource_expand_to_fit - Insert a resource into the resource tree + * @root: root resource descriptor + * @new: new resource to insert + * + * Insert a resource into the resource tree, possibly expanding it in order + * to make it encompass any conflicting resources. + */ +void insert_resource_expand_to_fit(struct resource *root, struct resource *new) +{ + if (new->parent) + return; + + write_lock(&resource_lock); + for (;;) { + struct resource *conflict; + + conflict = __insert_resource(root, new); + if (!conflict) + break; + if (conflict == root) + break; + + /* Ok, expand resource to cover the conflict, then try again .. */ + if (conflict->start < new->start) + new->start = conflict->start; + if (conflict->end > new->end) + new->end = conflict->end; + + printk("Expanded resource %s due to conflict with %s\n", new->name, conflict->name); + } write_unlock(&resource_lock); - return result; } /** diff --git a/kernel/sched.c b/kernel/sched.c index 9a1ddb84e26d..cc1f81b50b82 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4179,6 +4179,65 @@ void account_steal_time(struct task_struct *p, cputime_t steal) } /* + * Use precise platform statistics if available: + */ +#ifdef CONFIG_VIRT_CPU_ACCOUNTING +cputime_t task_utime(struct task_struct *p) +{ + return p->utime; +} + +cputime_t task_stime(struct task_struct *p) +{ + return p->stime; +} +#else +cputime_t task_utime(struct task_struct *p) +{ + clock_t utime = cputime_to_clock_t(p->utime), + total = utime + cputime_to_clock_t(p->stime); + u64 temp; + + /* + * Use CFS's precise accounting: + */ + temp = (u64)nsec_to_clock_t(p->se.sum_exec_runtime); + + if (total) { + temp *= utime; + do_div(temp, total); + } + utime = (clock_t)temp; + + p->prev_utime = max(p->prev_utime, clock_t_to_cputime(utime)); + return p->prev_utime; +} + +cputime_t task_stime(struct task_struct *p) +{ + clock_t stime; + + /* + * Use CFS's precise accounting. (we subtract utime from + * the total, to make sure the total observed by userspace + * grows monotonically - apps rely on that): + */ + stime = nsec_to_clock_t(p->se.sum_exec_runtime) - + cputime_to_clock_t(task_utime(p)); + + if (stime >= 0) + p->prev_stime = max(p->prev_stime, clock_t_to_cputime(stime)); + + return p->prev_stime; +} +#endif + +inline cputime_t task_gtime(struct task_struct *p) +{ + return p->gtime; +} + +/* * This function gets called by the timer code, with HZ frequency. * We call it with interrupts disabled. * @@ -7637,24 +7696,27 @@ static int dattrs_equal(struct sched_domain_attr *cur, int idx_cur, * and partition_sched_domains() will fallback to the single partition * 'fallback_doms', it also forces the domains to be rebuilt. * + * If doms_new==NULL it will be replaced with cpu_online_map. + * ndoms_new==0 is a special case for destroying existing domains. + * It will not create the default domain. + * * Call with hotplug lock held */ void partition_sched_domains(int ndoms_new, cpumask_t *doms_new, struct sched_domain_attr *dattr_new) { - int i, j; + int i, j, n; mutex_lock(&sched_domains_mutex); /* always unregister in case we don't destroy any domains */ unregister_sched_domain_sysctl(); - if (doms_new == NULL) - ndoms_new = 0; + n = doms_new ? ndoms_new : 0; /* Destroy deleted domains */ for (i = 0; i < ndoms_cur; i++) { - for (j = 0; j < ndoms_new; j++) { + for (j = 0; j < n; j++) { if (cpus_equal(doms_cur[i], doms_new[j]) && dattrs_equal(dattr_cur, i, dattr_new, j)) goto match1; @@ -7667,7 +7729,6 @@ match1: if (doms_new == NULL) { ndoms_cur = 0; - ndoms_new = 1; doms_new = &fallback_doms; cpus_andnot(doms_new[0], cpu_online_map, cpu_isolated_map); dattr_new = NULL; @@ -7704,8 +7765,13 @@ match2: int arch_reinit_sched_domains(void) { get_online_cpus(); + + /* Destroy domains first to force the rebuild */ + partition_sched_domains(0, NULL, NULL); + rebuild_sched_domains(); put_online_cpus(); + return 0; } @@ -7789,7 +7855,7 @@ static int update_sched_domains(struct notifier_block *nfb, case CPU_ONLINE_FROZEN: case CPU_DEAD: case CPU_DEAD_FROZEN: - partition_sched_domains(0, NULL, NULL); + partition_sched_domains(1, NULL, NULL); return NOTIFY_OK; default: diff --git a/kernel/softlockup.c b/kernel/softlockup.c index b75b492fbfcf..cb838ee93a82 100644 --- a/kernel/softlockup.c +++ b/kernel/softlockup.c @@ -233,7 +233,8 @@ static void check_hung_uninterruptible_tasks(int this_cpu) do_each_thread(g, t) { if (!--max_count) goto unlock; - if (t->state & TASK_UNINTERRUPTIBLE) + /* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */ + if (t->state == TASK_UNINTERRUPTIBLE) check_hung_task(t, now); } while_each_thread(g, t); unlock: diff --git a/kernel/sysctl.c b/kernel/sysctl.c index fe4713347275..50ec0886fa3d 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -159,6 +159,7 @@ static int proc_dointvec_taint(struct ctl_table *table, int write, struct file * static struct ctl_table root_table[]; static struct ctl_table_root sysctl_table_root; static struct ctl_table_header root_table_header = { + .count = 1, .ctl_table = root_table, .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list), .root = &sysctl_table_root, diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index 3d1e3e1a1971..1876b526c778 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -177,7 +177,7 @@ void clockevents_register_device(struct clock_event_device *dev) /* * Noop handler when we shut down an event device */ -static void clockevents_handle_noop(struct clock_event_device *dev) +void clockevents_handle_noop(struct clock_event_device *dev) { } @@ -199,7 +199,6 @@ void clockevents_exchange_device(struct clock_event_device *old, * released list and do a notify add later. */ if (old) { - old->event_handler = clockevents_handle_noop; clockevents_set_mode(old, CLOCK_EVT_MODE_UNUSED); list_del(&old->list); list_add(&old->list, &clockevents_released); diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 5125ddd8196b..1ad46f3df6e7 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -245,7 +245,7 @@ static void sync_cmos_clock(unsigned long dummy) if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2) fail = update_persistent_clock(now); - next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec; + next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec - (TICK_NSEC / 2); if (next.tv_nsec <= 0) next.tv_nsec += NSEC_PER_SEC; diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 31463d370b94..2f5a38294bf9 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -175,6 +175,8 @@ static void tick_do_periodic_broadcast(void) */ static void tick_handle_periodic_broadcast(struct clock_event_device *dev) { + ktime_t next; + tick_do_periodic_broadcast(); /* @@ -185,10 +187,13 @@ static void tick_handle_periodic_broadcast(struct clock_event_device *dev) /* * Setup the next period for devices, which do not have - * periodic mode: + * periodic mode. We read dev->next_event first and add to it + * when the event alrady expired. clockevents_program_event() + * sets dev->next_event only when the event is really + * programmed to the device. */ - for (;;) { - ktime_t next = ktime_add(dev->next_event, tick_period); + for (next = dev->next_event; ;) { + next = ktime_add(next, tick_period); if (!clockevents_program_event(dev, next, ktime_get())) return; @@ -205,7 +210,7 @@ static void tick_do_broadcast_on_off(void *why) struct clock_event_device *bc, *dev; struct tick_device *td; unsigned long flags, *reason = why; - int cpu; + int cpu, bc_stopped; spin_lock_irqsave(&tick_broadcast_lock, flags); @@ -223,6 +228,8 @@ static void tick_do_broadcast_on_off(void *why) if (!tick_device_is_functional(dev)) goto out; + bc_stopped = cpus_empty(tick_broadcast_mask); + switch (*reason) { case CLOCK_EVT_NOTIFY_BROADCAST_ON: case CLOCK_EVT_NOTIFY_BROADCAST_FORCE: @@ -245,9 +252,10 @@ static void tick_do_broadcast_on_off(void *why) break; } - if (cpus_empty(tick_broadcast_mask)) - clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); - else { + if (cpus_empty(tick_broadcast_mask)) { + if (!bc_stopped) + clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); + } else if (bc_stopped) { if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) tick_broadcast_start_periodic(bc); else @@ -364,16 +372,8 @@ cpumask_t *tick_get_broadcast_oneshot_mask(void) static int tick_broadcast_set_event(ktime_t expires, int force) { struct clock_event_device *bc = tick_broadcast_device.evtdev; - ktime_t now = ktime_get(); - int res; - - for(;;) { - res = clockevents_program_event(bc, expires, now); - if (!res || !force) - return res; - now = ktime_get(); - expires = ktime_add(now, ktime_set(0, bc->min_delta_ns)); - } + + return tick_dev_program_event(bc, expires, force); } int tick_resume_broadcast_oneshot(struct clock_event_device *bc) @@ -491,14 +491,52 @@ static void tick_broadcast_clear_oneshot(int cpu) cpu_clear(cpu, tick_broadcast_oneshot_mask); } +static void tick_broadcast_init_next_event(cpumask_t *mask, ktime_t expires) +{ + struct tick_device *td; + int cpu; + + for_each_cpu_mask_nr(cpu, *mask) { + td = &per_cpu(tick_cpu_device, cpu); + if (td->evtdev) + td->evtdev->next_event = expires; + } +} + /** * tick_broadcast_setup_oneshot - setup the broadcast device */ void tick_broadcast_setup_oneshot(struct clock_event_device *bc) { - bc->event_handler = tick_handle_oneshot_broadcast; - clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT); - bc->next_event.tv64 = KTIME_MAX; + /* Set it up only once ! */ + if (bc->event_handler != tick_handle_oneshot_broadcast) { + int was_periodic = bc->mode == CLOCK_EVT_MODE_PERIODIC; + int cpu = smp_processor_id(); + cpumask_t mask; + + bc->event_handler = tick_handle_oneshot_broadcast; + clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT); + + /* Take the do_timer update */ + tick_do_timer_cpu = cpu; + + /* + * We must be careful here. There might be other CPUs + * waiting for periodic broadcast. We need to set the + * oneshot_mask bits for those and program the + * broadcast device to fire. + */ + mask = tick_broadcast_mask; + cpu_clear(cpu, mask); + cpus_or(tick_broadcast_oneshot_mask, + tick_broadcast_oneshot_mask, mask); + + if (was_periodic && !cpus_empty(mask)) { + tick_broadcast_init_next_event(&mask, tick_next_period); + tick_broadcast_set_event(tick_next_period, 1); + } else + bc->next_event.tv64 = KTIME_MAX; + } } /* diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 80c4336f4188..c4777193d567 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c @@ -161,6 +161,7 @@ static void tick_setup_device(struct tick_device *td, } else { handler = td->evtdev->event_handler; next_event = td->evtdev->next_event; + td->evtdev->event_handler = clockevents_handle_noop; } td->evtdev = newdev; diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h index f13f2b7f4fd4..0ffc2918ea6f 100644 --- a/kernel/time/tick-internal.h +++ b/kernel/time/tick-internal.h @@ -17,6 +17,8 @@ extern void tick_handle_periodic(struct clock_event_device *dev); extern void tick_setup_oneshot(struct clock_event_device *newdev, void (*handler)(struct clock_event_device *), ktime_t nextevt); +extern int tick_dev_program_event(struct clock_event_device *dev, + ktime_t expires, int force); extern int tick_program_event(ktime_t expires, int force); extern void tick_oneshot_notify(void); extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)); diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c index 450c04935b66..2e35501e61dd 100644 --- a/kernel/time/tick-oneshot.c +++ b/kernel/time/tick-oneshot.c @@ -23,24 +23,58 @@ #include "tick-internal.h" /** - * tick_program_event + * tick_program_event internal worker function */ -int tick_program_event(ktime_t expires, int force) +int tick_dev_program_event(struct clock_event_device *dev, ktime_t expires, + int force) { - struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; ktime_t now = ktime_get(); + int i; - while (1) { + for (i = 0;;) { int ret = clockevents_program_event(dev, expires, now); if (!ret || !force) return ret; + + /* + * We tried 2 times to program the device with the given + * min_delta_ns. If that's not working then we double it + * and emit a warning. + */ + if (++i > 2) { + printk(KERN_WARNING "CE: __tick_program_event of %s is " + "stuck %llx %llx\n", dev->name ? dev->name : "?", + now.tv64, expires.tv64); + printk(KERN_WARNING + "CE: increasing min_delta_ns %ld to %ld nsec\n", + dev->min_delta_ns, dev->min_delta_ns << 1); + WARN_ON(1); + + /* Double the min. delta and try again */ + if (!dev->min_delta_ns) + dev->min_delta_ns = 5000; + else + dev->min_delta_ns <<= 1; + i = 0; + } + now = ktime_get(); - expires = ktime_add(now, ktime_set(0, dev->min_delta_ns)); + expires = ktime_add_ns(now, dev->min_delta_ns); } } /** + * tick_program_event + */ +int tick_program_event(ktime_t expires, int force) +{ + struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; + + return tick_dev_program_event(dev, expires, force); +} + +/** * tick_resume_onshot - resume oneshot mode */ void tick_resume_oneshot(void) @@ -61,7 +95,7 @@ void tick_setup_oneshot(struct clock_event_device *newdev, { newdev->event_handler = handler; clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT); - clockevents_program_event(newdev, next_event, ktime_get()); + tick_dev_program_event(newdev, next_event, 1); } /** diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 7a46bde78c66..a87b0468568b 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -162,6 +162,8 @@ void tick_nohz_stop_idle(int cpu) ts->idle_lastupdate = now; ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta); ts->idle_active = 0; + + sched_clock_idle_wakeup_event(0); } } @@ -177,6 +179,7 @@ static ktime_t tick_nohz_start_idle(struct tick_sched *ts) } ts->idle_entrytime = now; ts->idle_active = 1; + sched_clock_idle_sleep_event(); return now; } diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 8b5a7d304a5f..0b504814e378 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -394,7 +394,7 @@ config LOCKDEP bool depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT select STACKTRACE - select FRAME_POINTER if !X86 && !MIPS + select FRAME_POINTER if !X86 && !MIPS && !PPC select KALLSYMS select KALLSYMS_ALL @@ -676,13 +676,13 @@ config FAULT_INJECTION_STACKTRACE_FILTER depends on FAULT_INJECTION_DEBUG_FS && STACKTRACE_SUPPORT depends on !X86_64 select STACKTRACE - select FRAME_POINTER + select FRAME_POINTER if !PPC help Provide stacktrace filter for fault-injection capabilities config LATENCYTOP bool "Latency measuring infrastructure" - select FRAME_POINTER if !MIPS + select FRAME_POINTER if !MIPS && !PPC select KALLSYMS select KALLSYMS_ALL select STACKTRACE diff --git a/lib/debugobjects.c b/lib/debugobjects.c index 45a6bde762d1..e3ab374e1334 100644 --- a/lib/debugobjects.c +++ b/lib/debugobjects.c @@ -112,6 +112,7 @@ static struct debug_obj *lookup_object(void *addr, struct debug_bucket *b) /* * Allocate a new object. If the pool is empty, switch off the debugger. + * Must be called with interrupts disabled. */ static struct debug_obj * alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr) @@ -148,17 +149,18 @@ alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr) static void free_object(struct debug_obj *obj) { unsigned long idx = (unsigned long)(obj - obj_static_pool); + unsigned long flags; if (obj_pool_free < ODEBUG_POOL_SIZE || idx < ODEBUG_POOL_SIZE) { - spin_lock(&pool_lock); + spin_lock_irqsave(&pool_lock, flags); hlist_add_head(&obj->node, &obj_pool); obj_pool_free++; obj_pool_used--; - spin_unlock(&pool_lock); + spin_unlock_irqrestore(&pool_lock, flags); } else { - spin_lock(&pool_lock); + spin_lock_irqsave(&pool_lock, flags); obj_pool_used--; - spin_unlock(&pool_lock); + spin_unlock_irqrestore(&pool_lock, flags); kmem_cache_free(obj_cache, obj); } } @@ -171,6 +173,7 @@ static void debug_objects_oom(void) { struct debug_bucket *db = obj_hash; struct hlist_node *node, *tmp; + HLIST_HEAD(freelist); struct debug_obj *obj; unsigned long flags; int i; @@ -179,11 +182,14 @@ static void debug_objects_oom(void) for (i = 0; i < ODEBUG_HASH_SIZE; i++, db++) { spin_lock_irqsave(&db->lock, flags); - hlist_for_each_entry_safe(obj, node, tmp, &db->list, node) { + hlist_move_list(&db->list, &freelist); + spin_unlock_irqrestore(&db->lock, flags); + + /* Now free them */ + hlist_for_each_entry_safe(obj, node, tmp, &freelist, node) { hlist_del(&obj->node); free_object(obj); } - spin_unlock_irqrestore(&db->lock, flags); } } @@ -498,8 +504,9 @@ void debug_object_free(void *addr, struct debug_obj_descr *descr) return; default: hlist_del(&obj->node); + spin_unlock_irqrestore(&db->lock, flags); free_object(obj); - break; + return; } out_unlock: spin_unlock_irqrestore(&db->lock, flags); @@ -510,6 +517,7 @@ static void __debug_check_no_obj_freed(const void *address, unsigned long size) { unsigned long flags, oaddr, saddr, eaddr, paddr, chunks; struct hlist_node *node, *tmp; + HLIST_HEAD(freelist); struct debug_obj_descr *descr; enum debug_obj_state state; struct debug_bucket *db; @@ -545,11 +553,18 @@ repeat: goto repeat; default: hlist_del(&obj->node); - free_object(obj); + hlist_add_head(&obj->node, &freelist); break; } } spin_unlock_irqrestore(&db->lock, flags); + + /* Now free them */ + hlist_for_each_entry_safe(obj, node, tmp, &freelist, node) { + hlist_del(&obj->node); + free_object(obj); + } + if (cnt > debug_objects_maxchain) debug_objects_maxchain = cnt; } diff --git a/mm/filemap.c b/mm/filemap.c index 54e968650855..876bc595d0f8 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2129,13 +2129,20 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov, * After a write we want buffered reads to be sure to go to disk to get * the new data. We invalidate clean cached page from the region we're * about to write. We do this *before* the write so that we can return - * -EIO without clobbering -EIOCBQUEUED from ->direct_IO(). + * without clobbering -EIOCBQUEUED from ->direct_IO(). */ if (mapping->nrpages) { written = invalidate_inode_pages2_range(mapping, pos >> PAGE_CACHE_SHIFT, end); - if (written) + /* + * If a page can not be invalidated, return 0 to fall back + * to buffered write. + */ + if (written) { + if (written == -EBUSY) + return 0; goto out; + } } written = mapping->a_ops->direct_IO(WRITE, iocb, iov, pos, *nr_segs); diff --git a/mm/mmap.c b/mm/mmap.c index 339cf5c4d5d8..e7a5a68a9c2e 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1030,6 +1030,10 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, } else { switch (flags & MAP_TYPE) { case MAP_SHARED: + /* + * Ignore pgoff. + */ + pgoff = 0; vm_flags |= VM_SHARED | VM_MAYSHARE; break; case MAP_PRIVATE: diff --git a/mm/page_alloc.c b/mm/page_alloc.c index af982f7cdb2a..e293c58bea58 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -694,6 +694,9 @@ static int move_freepages(struct zone *zone, #endif for (page = start_page; page <= end_page;) { + /* Make sure we are not inadvertently changing nodes */ + VM_BUG_ON(page_to_nid(page) != zone_to_nid(zone)); + if (!pfn_valid_within(page_to_pfn(page))) { page++; continue; @@ -2516,6 +2519,10 @@ static void setup_zone_migrate_reserve(struct zone *zone) continue; page = pfn_to_page(pfn); + /* Watch out for overlapping nodes */ + if (page_to_nid(page) != zone_to_nid(zone)) + continue; + /* Blocks with reserved pages will never free, skip them. */ if (PageReserved(page)) continue; @@ -4064,7 +4071,7 @@ void __init set_dma_reserve(unsigned long new_dma_reserve) } #ifndef CONFIG_NEED_MULTIPLE_NODES -struct pglist_data contig_page_data = { .bdata = &bootmem_node_data[0] }; +struct pglist_data __refdata contig_page_data = { .bdata = &bootmem_node_data[0] }; EXPORT_SYMBOL(contig_page_data); #endif diff --git a/mm/page_isolation.c b/mm/page_isolation.c index 3444b58033c8..c69f84fe038d 100644 --- a/mm/page_isolation.c +++ b/mm/page_isolation.c @@ -2,7 +2,6 @@ * linux/mm/page_isolation.c */ -#include <stddef.h> #include <linux/mm.h> #include <linux/page-isolation.h> #include <linux/pageblock-flags.h> diff --git a/mm/quicklist.c b/mm/quicklist.c index 3f703f7cb398..8dbb6805ef35 100644 --- a/mm/quicklist.c +++ b/mm/quicklist.c @@ -26,7 +26,10 @@ DEFINE_PER_CPU(struct quicklist, quicklist)[CONFIG_NR_QUICK]; static unsigned long max_pages(unsigned long min_pages) { unsigned long node_free_pages, max; - struct zone *zones = NODE_DATA(numa_node_id())->node_zones; + int node = numa_node_id(); + struct zone *zones = NODE_DATA(node)->node_zones; + int num_cpus_on_node; + node_to_cpumask_ptr(cpumask_on_node, node); node_free_pages = #ifdef CONFIG_ZONE_DMA @@ -38,6 +41,10 @@ static unsigned long max_pages(unsigned long min_pages) zone_page_state(&zones[ZONE_NORMAL], NR_FREE_PAGES); max = node_free_pages / FRACTION_OF_NODE_MEM; + + num_cpus_on_node = cpus_weight_nr(*cpumask_on_node); + max /= num_cpus_on_node; + return max(max, min_pages); } diff --git a/mm/truncate.c b/mm/truncate.c index 250505091d37..6650c1d878b4 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -380,7 +380,7 @@ static int do_launder_page(struct address_space *mapping, struct page *page) * Any pages which are found to be mapped into pagetables are unmapped prior to * invalidation. * - * Returns -EIO if any pages could not be invalidated. + * Returns -EBUSY if any pages could not be invalidated. */ int invalidate_inode_pages2_range(struct address_space *mapping, pgoff_t start, pgoff_t end) @@ -440,7 +440,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping, ret2 = do_launder_page(mapping, page); if (ret2 == 0) { if (!invalidate_complete_page2(mapping, page)) - ret2 = -EIO; + ret2 = -EBUSY; } if (ret2 < 0) ret = ret2; diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index eeee218eed80..5bbf07362172 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c @@ -188,15 +188,21 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return 0; case BRCTL_SET_BRIDGE_HELLO_TIME: + { + unsigned long t = clock_t_to_jiffies(args[1]); if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (t < HZ) + return -EINVAL; + spin_lock_bh(&br->lock); - br->bridge_hello_time = clock_t_to_jiffies(args[1]); + br->bridge_hello_time = t; if (br_is_root_bridge(br)) br->hello_time = br->bridge_hello_time; spin_unlock_bh(&br->lock); return 0; + } case BRCTL_SET_BRIDGE_MAX_AGE: if (!capable(CAP_NET_ADMIN)) diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 27d6a511c8c1..158dee8b4965 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -29,11 +29,12 @@ */ static ssize_t store_bridge_parm(struct device *d, const char *buf, size_t len, - void (*set)(struct net_bridge *, unsigned long)) + int (*set)(struct net_bridge *, unsigned long)) { struct net_bridge *br = to_bridge(d); char *endp; unsigned long val; + int err; if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -43,9 +44,9 @@ static ssize_t store_bridge_parm(struct device *d, return -EINVAL; spin_lock_bh(&br->lock); - (*set)(br, val); + err = (*set)(br, val); spin_unlock_bh(&br->lock); - return len; + return err ? err : len; } @@ -56,12 +57,13 @@ static ssize_t show_forward_delay(struct device *d, return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay)); } -static void set_forward_delay(struct net_bridge *br, unsigned long val) +static int set_forward_delay(struct net_bridge *br, unsigned long val) { unsigned long delay = clock_t_to_jiffies(val); br->forward_delay = delay; if (br_is_root_bridge(br)) br->bridge_forward_delay = delay; + return 0; } static ssize_t store_forward_delay(struct device *d, @@ -80,12 +82,17 @@ static ssize_t show_hello_time(struct device *d, struct device_attribute *attr, jiffies_to_clock_t(to_bridge(d)->hello_time)); } -static void set_hello_time(struct net_bridge *br, unsigned long val) +static int set_hello_time(struct net_bridge *br, unsigned long val) { unsigned long t = clock_t_to_jiffies(val); + + if (t < HZ) + return -EINVAL; + br->hello_time = t; if (br_is_root_bridge(br)) br->bridge_hello_time = t; + return 0; } static ssize_t store_hello_time(struct device *d, @@ -104,12 +111,13 @@ static ssize_t show_max_age(struct device *d, struct device_attribute *attr, jiffies_to_clock_t(to_bridge(d)->max_age)); } -static void set_max_age(struct net_bridge *br, unsigned long val) +static int set_max_age(struct net_bridge *br, unsigned long val) { unsigned long t = clock_t_to_jiffies(val); br->max_age = t; if (br_is_root_bridge(br)) br->bridge_max_age = t; + return 0; } static ssize_t store_max_age(struct device *d, struct device_attribute *attr, @@ -126,9 +134,10 @@ static ssize_t show_ageing_time(struct device *d, return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time)); } -static void set_ageing_time(struct net_bridge *br, unsigned long val) +static int set_ageing_time(struct net_bridge *br, unsigned long val) { br->ageing_time = clock_t_to_jiffies(val); + return 0; } static ssize_t store_ageing_time(struct device *d, @@ -180,9 +189,10 @@ static ssize_t show_priority(struct device *d, struct device_attribute *attr, (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]); } -static void set_priority(struct net_bridge *br, unsigned long val) +static int set_priority(struct net_bridge *br, unsigned long val) { br_stp_set_bridge_priority(br, (u16) val); + return 0; } static ssize_t store_priority(struct device *d, struct device_attribute *attr, diff --git a/net/core/dev.c b/net/core/dev.c index 60c51f765887..e719ed29310f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1991,8 +1991,13 @@ static void net_tx_action(struct softirq_action *h) spin_unlock(root_lock); } else { if (!test_bit(__QDISC_STATE_DEACTIVATED, - &q->state)) + &q->state)) { __netif_reschedule(q); + } else { + smp_mb__before_clear_bit(); + clear_bit(__QDISC_STATE_SCHED, + &q->state); + } } } } diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 91d3d96805d0..b12dae2b0b2d 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1029,6 +1029,11 @@ skip: } } +static inline bool inetdev_valid_mtu(unsigned mtu) +{ + return mtu >= 68; +} + /* Called only under RTNL semaphore */ static int inetdev_event(struct notifier_block *this, unsigned long event, @@ -1048,6 +1053,10 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, IN_DEV_CONF_SET(in_dev, NOXFRM, 1); IN_DEV_CONF_SET(in_dev, NOPOLICY, 1); } + } else if (event == NETDEV_CHANGEMTU) { + /* Re-enabling IP */ + if (inetdev_valid_mtu(dev->mtu)) + in_dev = inetdev_init(dev); } goto out; } @@ -1058,7 +1067,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, dev->ip_ptr = NULL; break; case NETDEV_UP: - if (dev->mtu < 68) + if (!inetdev_valid_mtu(dev->mtu)) break; if (dev->flags & IFF_LOOPBACK) { struct in_ifaddr *ifa; @@ -1080,9 +1089,9 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, ip_mc_down(in_dev); break; case NETDEV_CHANGEMTU: - if (dev->mtu >= 68) + if (inetdev_valid_mtu(dev->mtu)) break; - /* MTU falled under 68, disable IP */ + /* disable IP when MTU is not enough */ case NETDEV_UNREGISTER: inetdev_destroy(in_dev); break; diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index d985bd613d25..743f011b9a84 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -409,3 +409,38 @@ out: } EXPORT_SYMBOL_GPL(inet_twdr_twcal_tick); + +void inet_twsk_purge(struct net *net, struct inet_hashinfo *hashinfo, + struct inet_timewait_death_row *twdr, int family) +{ + struct inet_timewait_sock *tw; + struct sock *sk; + struct hlist_node *node; + int h; + + local_bh_disable(); + for (h = 0; h < (hashinfo->ehash_size); h++) { + struct inet_ehash_bucket *head = + inet_ehash_bucket(hashinfo, h); + rwlock_t *lock = inet_ehash_lockp(hashinfo, h); +restart: + write_lock(lock); + sk_for_each(sk, node, &head->twchain) { + + tw = inet_twsk(sk); + if (!net_eq(twsk_net(tw), net) || + tw->tw_family != family) + continue; + + atomic_inc(&tw->tw_refcnt); + write_unlock(lock); + inet_twsk_deschedule(tw, twdr); + inet_twsk_put(tw); + + goto restart; + } + write_unlock(lock); + } + local_bh_enable(); +} +EXPORT_SYMBOL_GPL(inet_twsk_purge); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 44c1e934824b..1b4fee20fc93 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2376,6 +2376,7 @@ static int __net_init tcp_sk_init(struct net *net) static void __net_exit tcp_sk_exit(struct net *net) { inet_ctl_sock_destroy(net->ipv4.tcp_sock); + inet_twsk_purge(net, &tcp_hashinfo, &tcp_death_row, AF_INET); } static struct pernet_operations __net_initdata tcp_sk_ops = { diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 01d47674f7e5..e53e493606c5 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -377,14 +377,14 @@ static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) skb_checksum_complete(skb)) { atomic_inc(&sk->sk_drops); kfree_skb(skb); - return 0; + return NET_RX_DROP; } /* Charge it to the socket. */ if (sock_queue_rcv_skb(sk,skb)<0) { atomic_inc(&sk->sk_drops); kfree_skb(skb); - return 0; + return NET_RX_DROP; } return 0; @@ -429,7 +429,7 @@ int rawv6_rcv(struct sock *sk, struct sk_buff *skb) if (skb_checksum_complete(skb)) { atomic_inc(&sk->sk_drops); kfree_skb(skb); - return 0; + return NET_RX_DROP; } } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 5b90b369ccb2..b585c850a89a 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2148,6 +2148,7 @@ static int tcpv6_net_init(struct net *net) static void tcpv6_net_exit(struct net *net) { inet_ctl_sock_destroy(net->ipv6.tcp_sk); + inet_twsk_purge(net, &tcp_hashinfo, &tcp_death_row, AF_INET6); } static struct pernet_operations tcpv6_net_ops = { diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 7439b63df5d0..cf82acec913a 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -265,7 +265,7 @@ void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata) key = sdata->default_key; if (key) { sprintf(buf, "../keys/%d", key->debugfs.cnt); - sdata->debugfs.default_key = + sdata->common_debugfs.default_key = debugfs_create_symlink("default_key", sdata->debugfsdir, buf); } else @@ -277,8 +277,8 @@ void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata) if (!sdata) return; - debugfs_remove(sdata->debugfs.default_key); - sdata->debugfs.default_key = NULL; + debugfs_remove(sdata->common_debugfs.default_key); + sdata->common_debugfs.default_key = NULL; } void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 586a9b49b0fc..4498d8713652 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -496,8 +496,10 @@ struct ieee80211_sub_if_data { struct { struct dentry *mode; } monitor; - struct dentry *default_key; } debugfs; + struct { + struct dentry *default_key; + } common_debugfs; #ifdef CONFIG_MAC80211_MESH struct dentry *mesh_stats_dir; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 9bb68c6a8f44..902cac1bd246 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -478,21 +478,51 @@ int ieee80211_ht_addt_info_ie_to_ht_bss_info( static void ieee80211_sta_send_associnfo(struct net_device *dev, struct ieee80211_if_sta *ifsta) { + char *buf; + size_t len; + int i; union iwreq_data wrqu; + if (!ifsta->assocreq_ies && !ifsta->assocresp_ies) + return; + + buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len + + ifsta->assocresp_ies_len), GFP_KERNEL); + if (!buf) + return; + + len = sprintf(buf, "ASSOCINFO("); if (ifsta->assocreq_ies) { - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = ifsta->assocreq_ies_len; - wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, - ifsta->assocreq_ies); + len += sprintf(buf + len, "ReqIEs="); + for (i = 0; i < ifsta->assocreq_ies_len; i++) { + len += sprintf(buf + len, "%02x", + ifsta->assocreq_ies[i]); + } } - if (ifsta->assocresp_ies) { - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = ifsta->assocresp_ies_len; - wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, - ifsta->assocresp_ies); + if (ifsta->assocreq_ies) + len += sprintf(buf + len, " "); + len += sprintf(buf + len, "RespIEs="); + for (i = 0; i < ifsta->assocresp_ies_len; i++) { + len += sprintf(buf + len, "%02x", + ifsta->assocresp_ies[i]); + } + } + len += sprintf(buf + len, ")"); + + if (len > IW_CUSTOM_MAX) { + len = sprintf(buf, "ASSOCRESPIE="); + for (i = 0; i < ifsta->assocresp_ies_len; i++) { + len += sprintf(buf + len, "%02x", + ifsta->assocresp_ies[i]); + } } + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = len; + wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); + + kfree(buf); } diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c index 1b1226d6653f..20633fdf7e6b 100644 --- a/net/netfilter/nf_conntrack_irc.c +++ b/net/netfilter/nf_conntrack_irc.c @@ -68,11 +68,21 @@ static const char *const dccprotos[] = { static int parse_dcc(char *data, const char *data_end, u_int32_t *ip, u_int16_t *port, char **ad_beg_p, char **ad_end_p) { + char *tmp; + /* at least 12: "AAAAAAAA P\1\n" */ while (*data++ != ' ') if (data > data_end - 12) return -1; + /* Make sure we have a newline character within the packet boundaries + * because simple_strtoul parses until the first invalid character. */ + for (tmp = data; tmp <= data_end; tmp++) + if (*tmp == '\n') + break; + if (tmp > data_end || *tmp != '\n') + return -1; + *ad_beg_p = data; *ip = simple_strtoul(data, &data, 10); diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index 654a4f7f12c6..9bd03967fea4 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -45,12 +45,12 @@ static LIST_HEAD(gre_keymap_list); void nf_ct_gre_keymap_flush(void) { - struct list_head *pos, *n; + struct nf_ct_gre_keymap *km, *tmp; write_lock_bh(&nf_ct_gre_lock); - list_for_each_safe(pos, n, &gre_keymap_list) { - list_del(pos); - kfree(pos); + list_for_each_entry_safe(km, tmp, &gre_keymap_list, list) { + list_del(&km->list); + kfree(km); } write_unlock_bh(&nf_ct_gre_lock); } @@ -97,10 +97,14 @@ int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir, kmp = &help->help.ct_pptp_info.keymap[dir]; if (*kmp) { /* check whether it's a retransmission */ + read_lock_bh(&nf_ct_gre_lock); list_for_each_entry(km, &gre_keymap_list, list) { - if (gre_key_cmpfn(km, t) && km == *kmp) + if (gre_key_cmpfn(km, t) && km == *kmp) { + read_unlock_bh(&nf_ct_gre_lock); return 0; + } } + read_unlock_bh(&nf_ct_gre_lock); pr_debug("trying to override keymap_%s for ct %p\n", dir == IP_CT_DIR_REPLY ? "reply" : "orig", ct); return -EEXIST; diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 2f9bbc058b48..1fa306be60fb 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -1193,7 +1193,6 @@ static const struct sip_handler sip_handlers[] = { static int process_sip_response(struct sk_buff *skb, const char **dptr, unsigned int *datalen) { - static const struct sip_handler *handler; enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); unsigned int matchoff, matchlen; @@ -1214,6 +1213,8 @@ static int process_sip_response(struct sk_buff *skb, dataoff = matchoff + matchlen + 1; for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { + const struct sip_handler *handler; + handler = &sip_handlers[i]; if (handler->response == NULL) continue; @@ -1228,13 +1229,14 @@ static int process_sip_response(struct sk_buff *skb, static int process_sip_request(struct sk_buff *skb, const char **dptr, unsigned int *datalen) { - static const struct sip_handler *handler; enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); unsigned int matchoff, matchlen; unsigned int cseq, i; for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { + const struct sip_handler *handler; + handler = &sip_handlers[i]; if (handler->request == NULL) continue; diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 5cafdd4c8018..8eb79e92e94c 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -205,7 +205,7 @@ replay: } } - root_lock = qdisc_root_lock(q); + root_lock = qdisc_root_sleeping_lock(q); if (tp == NULL) { /* Proto-tcf does not exist, create new one */ diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c index 481260a4f10f..e3d8455eebc2 100644 --- a/net/sched/cls_route.c +++ b/net/sched/cls_route.c @@ -75,7 +75,7 @@ static __inline__ int route4_fastmap_hash(u32 id, int iif) static inline void route4_reset_fastmap(struct Qdisc *q, struct route4_head *head, u32 id) { - spinlock_t *root_lock = qdisc_root_lock(q); + spinlock_t *root_lock = qdisc_root_sleeping_lock(q); spin_lock_bh(root_lock); memset(head->fastmap, 0, sizeof(head->fastmap)); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 506b709510b6..1122c952aa99 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1169,8 +1169,8 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, if (q->stab && qdisc_dump_stab(skb, q->stab) < 0) goto nla_put_failure; - if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, - TCA_XSTATS, qdisc_root_lock(q), &d) < 0) + if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS, + qdisc_root_sleeping_lock(q), &d) < 0) goto nla_put_failure; if (q->ops->dump_stats && q->ops->dump_stats(q, &d) < 0) @@ -1461,8 +1461,8 @@ static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q, if (cl_ops->dump && cl_ops->dump(q, cl, skb, tcm) < 0) goto nla_put_failure; - if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, - TCA_XSTATS, qdisc_root_lock(q), &d) < 0) + if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS, + qdisc_root_sleeping_lock(q), &d) < 0) goto nla_put_failure; if (cl_ops->dump_stats && cl_ops->dump_stats(q, cl, &d) < 0) diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 9b720adedead..8b06fa900482 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1754,7 +1754,7 @@ static void cbq_put(struct Qdisc *sch, unsigned long arg) if (--cl->refcnt == 0) { #ifdef CONFIG_NET_CLS_ACT - spinlock_t *root_lock = qdisc_root_lock(sch); + spinlock_t *root_lock = qdisc_root_sleeping_lock(sch); struct cbq_sched_data *q = qdisc_priv(sch); spin_lock_bh(root_lock); diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 97d4761cc31e..d14f02056ae6 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1043,7 +1043,7 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt) static int htb_dump(struct Qdisc *sch, struct sk_buff *skb) { - spinlock_t *root_lock = qdisc_root_lock(sch); + spinlock_t *root_lock = qdisc_root_sleeping_lock(sch); struct htb_sched *q = qdisc_priv(sch); struct nlattr *nest; struct tc_htb_glob gopt; @@ -1075,7 +1075,7 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb, struct tcmsg *tcm) { struct htb_class *cl = (struct htb_class *)arg; - spinlock_t *root_lock = qdisc_root_lock(sch); + spinlock_t *root_lock = qdisc_root_sleeping_lock(sch); struct nlattr *nest; struct tc_htb_opt opt; diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index fb0294d0b55e..3781e55046d0 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -341,7 +341,7 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr) for (i = 0; i < n; i++) d->table[i] = data[i]; - root_lock = qdisc_root_lock(sch); + root_lock = qdisc_root_sleeping_lock(sch); spin_lock_bh(root_lock); d = xchg(&q->delay_dist, d); diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 2c35c678563b..d35ef059abb1 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -161,7 +161,7 @@ teql_destroy(struct Qdisc* sch) txq = netdev_get_tx_queue(master->dev, 0); master->slaves = NULL; - root_lock = qdisc_root_lock(txq->qdisc); + root_lock = qdisc_root_sleeping_lock(txq->qdisc); spin_lock_bh(root_lock); qdisc_reset(txq->qdisc); spin_unlock_bh(root_lock); diff --git a/net/sunrpc/sysctl.c b/net/sunrpc/sysctl.c index 0f8c439b848a..5231f7aaac0e 100644 --- a/net/sunrpc/sysctl.c +++ b/net/sunrpc/sysctl.c @@ -60,24 +60,14 @@ static int proc_do_xprt(ctl_table *table, int write, struct file *file, void __user *buffer, size_t *lenp, loff_t *ppos) { char tmpbuf[256]; - int len; + size_t len; + if ((*ppos && !write) || !*lenp) { *lenp = 0; return 0; } - if (write) - return -EINVAL; - else { - len = svc_print_xprts(tmpbuf, sizeof(tmpbuf)); - if (!access_ok(VERIFY_WRITE, buffer, len)) - return -EFAULT; - - if (__copy_to_user(buffer, tmpbuf, len)) - return -EFAULT; - } - *lenp -= len; - *ppos += len; - return 0; + len = svc_print_xprts(tmpbuf, sizeof(tmpbuf)); + return simple_read_from_buffer(buffer, *lenp, ppos, tmpbuf, len); } static int diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index b4b17f44cb29..74de31a06616 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c @@ -443,18 +443,18 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp) dprintk("svcrdma: rqstp=%p\n", rqstp); - spin_lock_bh(&rdma_xprt->sc_read_complete_lock); + spin_lock_bh(&rdma_xprt->sc_rq_dto_lock); if (!list_empty(&rdma_xprt->sc_read_complete_q)) { ctxt = list_entry(rdma_xprt->sc_read_complete_q.next, struct svc_rdma_op_ctxt, dto_q); list_del_init(&ctxt->dto_q); } - spin_unlock_bh(&rdma_xprt->sc_read_complete_lock); - if (ctxt) + if (ctxt) { + spin_unlock_bh(&rdma_xprt->sc_rq_dto_lock); return rdma_read_complete(rqstp, ctxt); + } - spin_lock_bh(&rdma_xprt->sc_rq_dto_lock); if (!list_empty(&rdma_xprt->sc_rq_dto_q)) { ctxt = list_entry(rdma_xprt->sc_rq_dto_q.next, struct svc_rdma_op_ctxt, diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index 19ddc382b777..900cb69728c6 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -359,11 +359,11 @@ static void sq_cq_reap(struct svcxprt_rdma *xprt) if (test_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags)) { struct svc_rdma_op_ctxt *read_hdr = ctxt->read_hdr; BUG_ON(!read_hdr); + spin_lock_bh(&xprt->sc_rq_dto_lock); set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags); - spin_lock_bh(&xprt->sc_read_complete_lock); list_add_tail(&read_hdr->dto_q, &xprt->sc_read_complete_q); - spin_unlock_bh(&xprt->sc_read_complete_lock); + spin_unlock_bh(&xprt->sc_rq_dto_lock); svc_xprt_enqueue(&xprt->sc_xprt); } svc_rdma_put_context(ctxt, 0); @@ -428,7 +428,6 @@ static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *serv, init_waitqueue_head(&cma_xprt->sc_send_wait); spin_lock_init(&cma_xprt->sc_lock); - spin_lock_init(&cma_xprt->sc_read_complete_lock); spin_lock_init(&cma_xprt->sc_rq_dto_lock); cma_xprt->sc_ord = svcrdma_ord; diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index b1ff16aa4bdb..3ddaff42d1bb 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -96,8 +96,8 @@ struct bcbearer { struct media media; struct bcbearer_pair bpairs[MAX_BEARERS]; struct bcbearer_pair bpairs_temp[TIPC_MAX_LINK_PRI + 1]; - struct node_map remains; - struct node_map remains_new; + struct tipc_node_map remains; + struct tipc_node_map remains_new; }; /** @@ -110,7 +110,7 @@ struct bcbearer { struct bclink { struct link link; - struct node node; + struct tipc_node node; }; @@ -149,7 +149,7 @@ static void bcbuf_decr_acks(struct sk_buff *buf) * Called with 'node' locked, bc_lock unlocked */ -static void bclink_set_gap(struct node *n_ptr) +static void bclink_set_gap(struct tipc_node *n_ptr) { struct sk_buff *buf = n_ptr->bclink.deferred_head; @@ -202,7 +202,7 @@ static void bclink_retransmit_pkt(u32 after, u32 to) * Node is locked, bc_lock unlocked. */ -void tipc_bclink_acknowledge(struct node *n_ptr, u32 acked) +void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked) { struct sk_buff *crs; struct sk_buff *next; @@ -250,7 +250,7 @@ void tipc_bclink_acknowledge(struct node *n_ptr, u32 acked) * tipc_net_lock and node lock set */ -static void bclink_send_ack(struct node *n_ptr) +static void bclink_send_ack(struct tipc_node *n_ptr) { struct link *l_ptr = n_ptr->active_links[n_ptr->addr & 1]; @@ -264,7 +264,7 @@ static void bclink_send_ack(struct node *n_ptr) * tipc_net_lock and node lock set */ -static void bclink_send_nack(struct node *n_ptr) +static void bclink_send_nack(struct tipc_node *n_ptr) { struct sk_buff *buf; struct tipc_msg *msg; @@ -308,7 +308,7 @@ static void bclink_send_nack(struct node *n_ptr) * tipc_net_lock and node lock set */ -void tipc_bclink_check_gap(struct node *n_ptr, u32 last_sent) +void tipc_bclink_check_gap(struct tipc_node *n_ptr, u32 last_sent) { if (!n_ptr->bclink.supported || less_eq(last_sent, mod(n_ptr->bclink.last_in))) @@ -328,7 +328,7 @@ void tipc_bclink_check_gap(struct node *n_ptr, u32 last_sent) static void tipc_bclink_peek_nack(u32 dest, u32 sender_tag, u32 gap_after, u32 gap_to) { - struct node *n_ptr = tipc_node_find(dest); + struct tipc_node *n_ptr = tipc_node_find(dest); u32 my_after, my_to; if (unlikely(!n_ptr || !tipc_node_is_up(n_ptr))) @@ -418,7 +418,7 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) static int rx_count = 0; #endif struct tipc_msg *msg = buf_msg(buf); - struct node* node = tipc_node_find(msg_prevnode(msg)); + struct tipc_node* node = tipc_node_find(msg_prevnode(msg)); u32 next_in; u32 seqno; struct sk_buff *deferred; @@ -538,7 +538,7 @@ u32 tipc_bclink_get_last_sent(void) return last_sent; } -u32 tipc_bclink_acks_missing(struct node *n_ptr) +u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr) { return (n_ptr->bclink.supported && (tipc_bclink_get_last_sent() != n_ptr->bclink.acked)); diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h index a2416fa6b906..5aa024b99c55 100644 --- a/net/tipc/bcast.h +++ b/net/tipc/bcast.h @@ -41,12 +41,12 @@ #define WSIZE 32 /** - * struct node_map - set of node identifiers + * struct tipc_node_map - set of node identifiers * @count: # of nodes in set * @map: bitmap of node identifiers that are in the set */ -struct node_map { +struct tipc_node_map { u32 count; u32 map[MAX_NODES / WSIZE]; }; @@ -68,7 +68,7 @@ struct port_list { }; -struct node; +struct tipc_node; extern char tipc_bclink_name[]; @@ -77,7 +77,7 @@ extern char tipc_bclink_name[]; * nmap_add - add a node to a node map */ -static inline void tipc_nmap_add(struct node_map *nm_ptr, u32 node) +static inline void tipc_nmap_add(struct tipc_node_map *nm_ptr, u32 node) { int n = tipc_node(node); int w = n / WSIZE; @@ -93,7 +93,7 @@ static inline void tipc_nmap_add(struct node_map *nm_ptr, u32 node) * nmap_remove - remove a node from a node map */ -static inline void tipc_nmap_remove(struct node_map *nm_ptr, u32 node) +static inline void tipc_nmap_remove(struct tipc_node_map *nm_ptr, u32 node) { int n = tipc_node(node); int w = n / WSIZE; @@ -109,7 +109,7 @@ static inline void tipc_nmap_remove(struct node_map *nm_ptr, u32 node) * nmap_equal - test for equality of node maps */ -static inline int tipc_nmap_equal(struct node_map *nm_a, struct node_map *nm_b) +static inline int tipc_nmap_equal(struct tipc_node_map *nm_a, struct tipc_node_map *nm_b) { return !memcmp(nm_a, nm_b, sizeof(*nm_a)); } @@ -121,8 +121,8 @@ static inline int tipc_nmap_equal(struct node_map *nm_a, struct node_map *nm_b) * @nm_diff: output node map A-B (i.e. nodes of A that are not in B) */ -static inline void tipc_nmap_diff(struct node_map *nm_a, struct node_map *nm_b, - struct node_map *nm_diff) +static inline void tipc_nmap_diff(struct tipc_node_map *nm_a, struct tipc_node_map *nm_b, + struct tipc_node_map *nm_diff) { int stop = sizeof(nm_a->map) / sizeof(u32); int w; @@ -195,12 +195,12 @@ static inline void tipc_port_list_free(struct port_list *pl_ptr) int tipc_bclink_init(void); void tipc_bclink_stop(void); -void tipc_bclink_acknowledge(struct node *n_ptr, u32 acked); +void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked); int tipc_bclink_send_msg(struct sk_buff *buf); void tipc_bclink_recv_pkt(struct sk_buff *buf); u32 tipc_bclink_get_last_sent(void); -u32 tipc_bclink_acks_missing(struct node *n_ptr); -void tipc_bclink_check_gap(struct node *n_ptr, u32 seqno); +u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr); +void tipc_bclink_check_gap(struct tipc_node *n_ptr, u32 seqno); int tipc_bclink_stats(char *stats_buf, const u32 buf_size); int tipc_bclink_reset_stats(void); int tipc_bclink_set_queue_limits(u32 limit); diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 6a9aba3edd08..a7a36779b9b3 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -599,7 +599,7 @@ int tipc_block_bearer(const char *name) spin_lock_bh(&b_ptr->publ.lock); b_ptr->publ.blocked = 1; list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { - struct node *n_ptr = l_ptr->owner; + struct tipc_node *n_ptr = l_ptr->owner; spin_lock_bh(&n_ptr->lock); tipc_link_reset(l_ptr); diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index 6a36b6600e6c..ca5734892713 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -104,7 +104,7 @@ struct bearer { u32 continue_count; int active; char net_plane; - struct node_map nodes; + struct tipc_node_map nodes; }; struct bearer_name { diff --git a/net/tipc/cluster.c b/net/tipc/cluster.c index 46ee6c58532d..689fdefe9d04 100644 --- a/net/tipc/cluster.c +++ b/net/tipc/cluster.c @@ -48,8 +48,8 @@ static void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf, u32 lower, u32 upper); static struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest); -struct node **tipc_local_nodes = NULL; -struct node_map tipc_cltr_bcast_nodes = {0,{0,}}; +struct tipc_node **tipc_local_nodes = NULL; +struct tipc_node_map tipc_cltr_bcast_nodes = {0,{0,}}; u32 tipc_highest_allowed_slave = 0; struct cluster *tipc_cltr_create(u32 addr) @@ -115,7 +115,7 @@ void tipc_cltr_delete(struct cluster *c_ptr) u32 tipc_cltr_next_node(struct cluster *c_ptr, u32 addr) { - struct node *n_ptr; + struct tipc_node *n_ptr; u32 n_num = tipc_node(addr) + 1; if (!c_ptr) @@ -133,7 +133,7 @@ u32 tipc_cltr_next_node(struct cluster *c_ptr, u32 addr) return 0; } -void tipc_cltr_attach_node(struct cluster *c_ptr, struct node *n_ptr) +void tipc_cltr_attach_node(struct cluster *c_ptr, struct tipc_node *n_ptr) { u32 n_num = tipc_node(n_ptr->addr); u32 max_n_num = tipc_max_nodes; @@ -196,7 +196,7 @@ u32 tipc_cltr_select_router(struct cluster *c_ptr, u32 ref) * Uses deterministic and fair algorithm. */ -struct node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector) +struct tipc_node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector) { u32 n_num; u32 mask = tipc_max_nodes; @@ -379,7 +379,7 @@ void tipc_cltr_recv_routing_table(struct sk_buff *buf) { struct tipc_msg *msg = buf_msg(buf); struct cluster *c_ptr; - struct node *n_ptr; + struct tipc_node *n_ptr; unchar *node_table; u32 table_size; u32 router; @@ -499,7 +499,7 @@ static void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf, u32 lower, u32 upper) { struct sk_buff *buf_copy; - struct node *n_ptr; + struct tipc_node *n_ptr; u32 n_num; u32 tstop; @@ -534,7 +534,7 @@ void tipc_cltr_broadcast(struct sk_buff *buf) { struct sk_buff *buf_copy; struct cluster *c_ptr; - struct node *n_ptr; + struct tipc_node *n_ptr; u32 n_num; u32 tstart; u32 tstop; diff --git a/net/tipc/cluster.h b/net/tipc/cluster.h index 62df074afaec..333efb0b9c44 100644 --- a/net/tipc/cluster.h +++ b/net/tipc/cluster.h @@ -54,24 +54,24 @@ struct cluster { u32 addr; struct _zone *owner; - struct node **nodes; + struct tipc_node **nodes; u32 highest_node; u32 highest_slave; }; -extern struct node **tipc_local_nodes; +extern struct tipc_node **tipc_local_nodes; extern u32 tipc_highest_allowed_slave; -extern struct node_map tipc_cltr_bcast_nodes; +extern struct tipc_node_map tipc_cltr_bcast_nodes; void tipc_cltr_remove_as_router(struct cluster *c_ptr, u32 router); void tipc_cltr_send_ext_routes(struct cluster *c_ptr, u32 dest); -struct node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector); +struct tipc_node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector); u32 tipc_cltr_select_router(struct cluster *c_ptr, u32 ref); void tipc_cltr_recv_routing_table(struct sk_buff *buf); struct cluster *tipc_cltr_create(u32 addr); void tipc_cltr_delete(struct cluster *c_ptr); -void tipc_cltr_attach_node(struct cluster *c_ptr, struct node *n_ptr); +void tipc_cltr_attach_node(struct cluster *c_ptr, struct tipc_node *n_ptr); void tipc_cltr_send_slave_routes(struct cluster *c_ptr, u32 dest); void tipc_cltr_broadcast(struct sk_buff *buf); int tipc_cltr_init(void); diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 1657f0e795ff..74b7d1e28aec 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -193,7 +193,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr) /* Always accept link here */ struct sk_buff *rbuf; struct tipc_media_addr *addr; - struct node *n_ptr = tipc_node_find(orig); + struct tipc_node *n_ptr = tipc_node_find(orig); int link_fully_up; dbg(" in own cluster\n"); diff --git a/net/tipc/link.c b/net/tipc/link.c index d60113ba4b1b..dd4c18b9a35b 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1155,7 +1155,7 @@ int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf) int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector) { struct link *l_ptr; - struct node *n_ptr; + struct tipc_node *n_ptr; int res = -ELINKCONG; read_lock_bh(&tipc_net_lock); @@ -1226,7 +1226,7 @@ static int link_send_buf_fast(struct link *l_ptr, struct sk_buff *buf, int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode) { struct link *l_ptr; - struct node *n_ptr; + struct tipc_node *n_ptr; int res; u32 selector = msg_origport(buf_msg(buf)) & 1; u32 dummy; @@ -1270,7 +1270,7 @@ int tipc_link_send_sections_fast(struct port *sender, struct tipc_msg *hdr = &sender->publ.phdr; struct link *l_ptr; struct sk_buff *buf; - struct node *node; + struct tipc_node *node; int res; u32 selector = msg_origport(hdr) & 1; @@ -1364,7 +1364,7 @@ static int link_send_sections_long(struct port *sender, u32 destaddr) { struct link *l_ptr; - struct node *node; + struct tipc_node *node; struct tipc_msg *hdr = &sender->publ.phdr; u32 dsz = msg_data_sz(hdr); u32 max_pkt,fragm_sz,rest; @@ -1636,7 +1636,7 @@ void tipc_link_push_queue(struct link *l_ptr) static void link_reset_all(unsigned long addr) { - struct node *n_ptr; + struct tipc_node *n_ptr; char addr_string[16]; u32 i; @@ -1682,7 +1682,7 @@ static void link_retransmit_failure(struct link *l_ptr, struct sk_buff *buf) /* Handle failure on broadcast link */ - struct node *n_ptr; + struct tipc_node *n_ptr; char addr_string[16]; tipc_printf(TIPC_OUTPUT, "Msg seq number: %u, ", msg_seqno(msg)); @@ -1843,7 +1843,7 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) read_lock_bh(&tipc_net_lock); while (head) { struct bearer *b_ptr = (struct bearer *)tb_ptr; - struct node *n_ptr; + struct tipc_node *n_ptr; struct link *l_ptr; struct sk_buff *crs; struct sk_buff *buf = head; @@ -2935,7 +2935,7 @@ void tipc_link_set_queue_limits(struct link *l_ptr, u32 window) * Returns pointer to link (or 0 if invalid link name). */ -static struct link *link_find_link(const char *name, struct node **node) +static struct link *link_find_link(const char *name, struct tipc_node **node) { struct link_name link_name_parts; struct bearer *b_ptr; @@ -2965,7 +2965,7 @@ struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space struct tipc_link_config *args; u32 new_value; struct link *l_ptr; - struct node *node; + struct tipc_node *node; int res; if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_CONFIG)) @@ -3043,7 +3043,7 @@ struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_ { char *link_name; struct link *l_ptr; - struct node *node; + struct tipc_node *node; if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); @@ -3091,7 +3091,7 @@ static int tipc_link_stats(const char *name, char *buf, const u32 buf_size) { struct print_buf pb; struct link *l_ptr; - struct node *node; + struct tipc_node *node; char *status; u32 profile_total = 0; @@ -3207,7 +3207,7 @@ int link_control(const char *name, u32 op, u32 val) int res = -EINVAL; struct link *l_ptr; u32 bearer_id; - struct node * node; + struct tipc_node * node; u32 a; a = link_name2addr(name, &bearer_id); @@ -3249,7 +3249,7 @@ int link_control(const char *name, u32 op, u32 val) u32 tipc_link_get_max_pkt(u32 dest, u32 selector) { - struct node *n_ptr; + struct tipc_node *n_ptr; struct link *l_ptr; u32 res = MAX_PKT_DEFAULT; diff --git a/net/tipc/link.h b/net/tipc/link.h index 52f3e7c1871f..6a51e38ad25c 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -116,7 +116,7 @@ struct link { char name[TIPC_MAX_LINK_NAME]; struct tipc_media_addr media_addr; struct timer_list timer; - struct node *owner; + struct tipc_node *owner; struct list_head link_list; /* Management and link supervision data */ diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h index b9e7cd336d76..139882d4ed00 100644 --- a/net/tipc/name_table.h +++ b/net/tipc/name_table.h @@ -76,7 +76,7 @@ struct publication { u32 node; u32 ref; u32 key; - struct node_subscr subscr; + struct tipc_node_subscr subscr; struct list_head local_list; struct list_head pport_list; struct publication *node_list_next; diff --git a/net/tipc/net.c b/net/tipc/net.c index ec7b04fbdc43..7906608bf510 100644 --- a/net/tipc/net.c +++ b/net/tipc/net.c @@ -118,7 +118,7 @@ DEFINE_RWLOCK(tipc_net_lock); struct network tipc_net = { NULL }; -struct node *tipc_net_select_remote_node(u32 addr, u32 ref) +struct tipc_node *tipc_net_select_remote_node(u32 addr, u32 ref) { return tipc_zone_select_remote_node(tipc_net.zones[tipc_zone(addr)], addr, ref); } diff --git a/net/tipc/net.h b/net/tipc/net.h index d154ac2bda9a..de2b9ad8f646 100644 --- a/net/tipc/net.h +++ b/net/tipc/net.h @@ -55,7 +55,7 @@ extern rwlock_t tipc_net_lock; void tipc_net_remove_as_router(u32 router); void tipc_net_send_external_routes(u32 dest); void tipc_net_route_msg(struct sk_buff *buf); -struct node *tipc_net_select_remote_node(u32 addr, u32 ref); +struct tipc_node *tipc_net_select_remote_node(u32 addr, u32 ref); u32 tipc_net_select_router(u32 addr, u32 ref); int tipc_net_start(u32 addr); diff --git a/net/tipc/node.c b/net/tipc/node.c index ee952ad60218..20d98c56e152 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -46,11 +46,11 @@ #include "bearer.h" #include "name_distr.h" -void node_print(struct print_buf *buf, struct node *n_ptr, char *str); -static void node_lost_contact(struct node *n_ptr); -static void node_established_contact(struct node *n_ptr); +void node_print(struct print_buf *buf, struct tipc_node *n_ptr, char *str); +static void node_lost_contact(struct tipc_node *n_ptr); +static void node_established_contact(struct tipc_node *n_ptr); -struct node *tipc_nodes = NULL; /* sorted list of nodes within cluster */ +struct tipc_node *tipc_nodes = NULL; /* sorted list of nodes within cluster */ static DEFINE_SPINLOCK(node_create_lock); @@ -66,11 +66,11 @@ u32 tipc_own_tag = 0; * but this is a non-trivial change.) */ -struct node *tipc_node_create(u32 addr) +struct tipc_node *tipc_node_create(u32 addr) { struct cluster *c_ptr; - struct node *n_ptr; - struct node **curr_node; + struct tipc_node *n_ptr; + struct tipc_node **curr_node; spin_lock_bh(&node_create_lock); @@ -120,7 +120,7 @@ struct node *tipc_node_create(u32 addr) return n_ptr; } -void tipc_node_delete(struct node *n_ptr) +void tipc_node_delete(struct tipc_node *n_ptr) { if (!n_ptr) return; @@ -146,7 +146,7 @@ void tipc_node_delete(struct node *n_ptr) * Link becomes active (alone or shared) or standby, depending on its priority. */ -void tipc_node_link_up(struct node *n_ptr, struct link *l_ptr) +void tipc_node_link_up(struct tipc_node *n_ptr, struct link *l_ptr) { struct link **active = &n_ptr->active_links[0]; @@ -180,7 +180,7 @@ void tipc_node_link_up(struct node *n_ptr, struct link *l_ptr) * node_select_active_links - select active link */ -static void node_select_active_links(struct node *n_ptr) +static void node_select_active_links(struct tipc_node *n_ptr) { struct link **active = &n_ptr->active_links[0]; u32 i; @@ -208,7 +208,7 @@ static void node_select_active_links(struct node *n_ptr) * tipc_node_link_down - handle loss of link */ -void tipc_node_link_down(struct node *n_ptr, struct link *l_ptr) +void tipc_node_link_down(struct tipc_node *n_ptr, struct link *l_ptr) { struct link **active; @@ -235,30 +235,30 @@ void tipc_node_link_down(struct node *n_ptr, struct link *l_ptr) node_lost_contact(n_ptr); } -int tipc_node_has_active_links(struct node *n_ptr) +int tipc_node_has_active_links(struct tipc_node *n_ptr) { return (n_ptr && ((n_ptr->active_links[0]) || (n_ptr->active_links[1]))); } -int tipc_node_has_redundant_links(struct node *n_ptr) +int tipc_node_has_redundant_links(struct tipc_node *n_ptr) { return (n_ptr->working_links > 1); } -static int tipc_node_has_active_routes(struct node *n_ptr) +static int tipc_node_has_active_routes(struct tipc_node *n_ptr) { return (n_ptr && (n_ptr->last_router >= 0)); } -int tipc_node_is_up(struct node *n_ptr) +int tipc_node_is_up(struct tipc_node *n_ptr) { return (tipc_node_has_active_links(n_ptr) || tipc_node_has_active_routes(n_ptr)); } -struct node *tipc_node_attach_link(struct link *l_ptr) +struct tipc_node *tipc_node_attach_link(struct link *l_ptr) { - struct node *n_ptr = tipc_node_find(l_ptr->addr); + struct tipc_node *n_ptr = tipc_node_find(l_ptr->addr); if (!n_ptr) n_ptr = tipc_node_create(l_ptr->addr); @@ -285,7 +285,7 @@ struct node *tipc_node_attach_link(struct link *l_ptr) return NULL; } -void tipc_node_detach_link(struct node *n_ptr, struct link *l_ptr) +void tipc_node_detach_link(struct tipc_node *n_ptr, struct link *l_ptr) { n_ptr->links[l_ptr->b_ptr->identity] = NULL; tipc_net.zones[tipc_zone(l_ptr->addr)]->links--; @@ -338,7 +338,7 @@ void tipc_node_detach_link(struct node *n_ptr, struct link *l_ptr) * */ -static void node_established_contact(struct node *n_ptr) +static void node_established_contact(struct tipc_node *n_ptr) { struct cluster *c_ptr; @@ -384,10 +384,10 @@ static void node_established_contact(struct node *n_ptr) tipc_highest_allowed_slave); } -static void node_lost_contact(struct node *n_ptr) +static void node_lost_contact(struct tipc_node *n_ptr) { struct cluster *c_ptr; - struct node_subscr *ns, *tns; + struct tipc_node_subscr *ns, *tns; char addr_string[16]; u32 i; @@ -466,9 +466,9 @@ static void node_lost_contact(struct node *n_ptr) * Called by when cluster local lookup has failed. */ -struct node *tipc_node_select_next_hop(u32 addr, u32 selector) +struct tipc_node *tipc_node_select_next_hop(u32 addr, u32 selector) { - struct node *n_ptr; + struct tipc_node *n_ptr; u32 router_addr; if (!tipc_addr_domain_valid(addr)) @@ -513,7 +513,7 @@ struct node *tipc_node_select_next_hop(u32 addr, u32 selector) * Uses a deterministic and fair algorithm for selecting router node. */ -u32 tipc_node_select_router(struct node *n_ptr, u32 ref) +u32 tipc_node_select_router(struct tipc_node *n_ptr, u32 ref) { u32 ulim; u32 mask; @@ -551,7 +551,7 @@ u32 tipc_node_select_router(struct node *n_ptr, u32 ref) return tipc_addr(own_zone(), own_cluster(), r); } -void tipc_node_add_router(struct node *n_ptr, u32 router) +void tipc_node_add_router(struct tipc_node *n_ptr, u32 router) { u32 r_num = tipc_node(router); @@ -562,7 +562,7 @@ void tipc_node_add_router(struct node *n_ptr, u32 router) !n_ptr->routers[n_ptr->last_router]); } -void tipc_node_remove_router(struct node *n_ptr, u32 router) +void tipc_node_remove_router(struct tipc_node *n_ptr, u32 router) { u32 r_num = tipc_node(router); @@ -580,7 +580,7 @@ void tipc_node_remove_router(struct node *n_ptr, u32 router) } #if 0 -void node_print(struct print_buf *buf, struct node *n_ptr, char *str) +void node_print(struct print_buf *buf, struct tipc_node *n_ptr, char *str) { u32 i; @@ -597,7 +597,7 @@ void node_print(struct print_buf *buf, struct node *n_ptr, char *str) u32 tipc_available_nodes(const u32 domain) { - struct node *n_ptr; + struct tipc_node *n_ptr; u32 cnt = 0; read_lock_bh(&tipc_net_lock); @@ -615,7 +615,7 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space) { u32 domain; struct sk_buff *buf; - struct node *n_ptr; + struct tipc_node *n_ptr; struct tipc_node_info node_info; u32 payload_size; @@ -667,7 +667,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space) { u32 domain; struct sk_buff *buf; - struct node *n_ptr; + struct tipc_node *n_ptr; struct tipc_link_info link_info; u32 payload_size; diff --git a/net/tipc/node.h b/net/tipc/node.h index cd1882654bbb..6f990da5d143 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -43,7 +43,7 @@ #include "bearer.h" /** - * struct node - TIPC node structure + * struct tipc_node - TIPC node structure * @addr: network address of node * @lock: spinlock governing access to structure * @owner: pointer to cluster that node belongs to @@ -68,11 +68,11 @@ * @defragm: list of partially reassembled b'cast message fragments from node */ -struct node { +struct tipc_node { u32 addr; spinlock_t lock; struct cluster *owner; - struct node *next; + struct tipc_node *next; struct list_head nsub; struct link *active_links[2]; struct link *links[MAX_BEARERS]; @@ -94,26 +94,26 @@ struct node { } bclink; }; -extern struct node *tipc_nodes; +extern struct tipc_node *tipc_nodes; extern u32 tipc_own_tag; -struct node *tipc_node_create(u32 addr); -void tipc_node_delete(struct node *n_ptr); -struct node *tipc_node_attach_link(struct link *l_ptr); -void tipc_node_detach_link(struct node *n_ptr, struct link *l_ptr); -void tipc_node_link_down(struct node *n_ptr, struct link *l_ptr); -void tipc_node_link_up(struct node *n_ptr, struct link *l_ptr); -int tipc_node_has_active_links(struct node *n_ptr); -int tipc_node_has_redundant_links(struct node *n_ptr); -u32 tipc_node_select_router(struct node *n_ptr, u32 ref); -struct node *tipc_node_select_next_hop(u32 addr, u32 selector); -int tipc_node_is_up(struct node *n_ptr); -void tipc_node_add_router(struct node *n_ptr, u32 router); -void tipc_node_remove_router(struct node *n_ptr, u32 router); +struct tipc_node *tipc_node_create(u32 addr); +void tipc_node_delete(struct tipc_node *n_ptr); +struct tipc_node *tipc_node_attach_link(struct link *l_ptr); +void tipc_node_detach_link(struct tipc_node *n_ptr, struct link *l_ptr); +void tipc_node_link_down(struct tipc_node *n_ptr, struct link *l_ptr); +void tipc_node_link_up(struct tipc_node *n_ptr, struct link *l_ptr); +int tipc_node_has_active_links(struct tipc_node *n_ptr); +int tipc_node_has_redundant_links(struct tipc_node *n_ptr); +u32 tipc_node_select_router(struct tipc_node *n_ptr, u32 ref); +struct tipc_node *tipc_node_select_next_hop(u32 addr, u32 selector); +int tipc_node_is_up(struct tipc_node *n_ptr); +void tipc_node_add_router(struct tipc_node *n_ptr, u32 router); +void tipc_node_remove_router(struct tipc_node *n_ptr, u32 router); struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space); struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space); -static inline struct node *tipc_node_find(u32 addr) +static inline struct tipc_node *tipc_node_find(u32 addr) { if (likely(in_own_cluster(addr))) return tipc_local_nodes[tipc_node(addr)]; @@ -126,19 +126,19 @@ static inline struct node *tipc_node_find(u32 addr) return NULL; } -static inline struct node *tipc_node_select(u32 addr, u32 selector) +static inline struct tipc_node *tipc_node_select(u32 addr, u32 selector) { if (likely(in_own_cluster(addr))) return tipc_local_nodes[tipc_node(addr)]; return tipc_node_select_next_hop(addr, selector); } -static inline void tipc_node_lock(struct node *n_ptr) +static inline void tipc_node_lock(struct tipc_node *n_ptr) { spin_lock_bh(&n_ptr->lock); } -static inline void tipc_node_unlock(struct node *n_ptr) +static inline void tipc_node_unlock(struct tipc_node *n_ptr) { spin_unlock_bh(&n_ptr->lock); } diff --git a/net/tipc/node_subscr.c b/net/tipc/node_subscr.c index 8ecbd0fb6103..19194d476a9e 100644 --- a/net/tipc/node_subscr.c +++ b/net/tipc/node_subscr.c @@ -44,7 +44,7 @@ * tipc_nodesub_subscribe - create "node down" subscription for specified node */ -void tipc_nodesub_subscribe(struct node_subscr *node_sub, u32 addr, +void tipc_nodesub_subscribe(struct tipc_node_subscr *node_sub, u32 addr, void *usr_handle, net_ev_handler handle_down) { if (addr == tipc_own_addr) { @@ -69,7 +69,7 @@ void tipc_nodesub_subscribe(struct node_subscr *node_sub, u32 addr, * tipc_nodesub_unsubscribe - cancel "node down" subscription (if any) */ -void tipc_nodesub_unsubscribe(struct node_subscr *node_sub) +void tipc_nodesub_unsubscribe(struct tipc_node_subscr *node_sub) { if (!node_sub->node) return; diff --git a/net/tipc/node_subscr.h b/net/tipc/node_subscr.h index 5f3f5859b84c..006ed739f515 100644 --- a/net/tipc/node_subscr.h +++ b/net/tipc/node_subscr.h @@ -42,22 +42,22 @@ typedef void (*net_ev_handler) (void *usr_handle); /** - * struct node_subscr - "node down" subscription entry + * struct tipc_node_subscr - "node down" subscription entry * @node: ptr to node structure of interest (or NULL, if none) * @handle_node_down: routine to invoke when node fails * @usr_handle: argument to pass to routine when node fails * @nodesub_list: adjacent entries in list of subscriptions for the node */ -struct node_subscr { - struct node *node; +struct tipc_node_subscr { + struct tipc_node *node; net_ev_handler handle_node_down; void *usr_handle; struct list_head nodesub_list; }; -void tipc_nodesub_subscribe(struct node_subscr *node_sub, u32 addr, +void tipc_nodesub_subscribe(struct tipc_node_subscr *node_sub, u32 addr, void *usr_handle, net_ev_handler handle_down); -void tipc_nodesub_unsubscribe(struct node_subscr *node_sub); +void tipc_nodesub_unsubscribe(struct tipc_node_subscr *node_sub); #endif diff --git a/net/tipc/port.h b/net/tipc/port.h index e5f8c16429bd..ff31ee4a1dc3 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h @@ -105,7 +105,7 @@ struct port { u32 probing_interval; u32 last_in_seqno; struct timer_list timer; - struct node_subscr subscription; + struct tipc_node_subscr subscription; }; extern spinlock_t tipc_port_list_lock; diff --git a/net/tipc/zone.c b/net/tipc/zone.c index 3506f8563441..2c01ba2d86bf 100644 --- a/net/tipc/zone.c +++ b/net/tipc/zone.c @@ -111,10 +111,10 @@ void tipc_zone_send_external_routes(struct _zone *z_ptr, u32 dest) } } -struct node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref) +struct tipc_node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref) { struct cluster *c_ptr; - struct node *n_ptr; + struct tipc_node *n_ptr; u32 c_num; if (!z_ptr) diff --git a/net/tipc/zone.h b/net/tipc/zone.h index 6e7a08df8af5..7bdc3406ba9b 100644 --- a/net/tipc/zone.h +++ b/net/tipc/zone.h @@ -54,7 +54,7 @@ struct _zone { u32 links; }; -struct node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref); +struct tipc_node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref); u32 tipc_zone_select_router(struct _zone *z_ptr, u32 addr, u32 ref); void tipc_zone_remove_as_router(struct _zone *z_ptr, u32 router); void tipc_zone_send_external_routes(struct _zone *z_ptr, u32 dest); diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index ab015c62d561..833b024f8f66 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -39,4 +39,5 @@ config WIRELESS_EXT_SYSFS files in /sys/class/net/*/wireless/. The same information is available via the ioctls as well. - Say Y if you have programs using it (we don't know of any). + Say Y if you have programs using it, like old versions of + hal. diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 841b32a2e680..46914b79d850 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1731,8 +1731,7 @@ restart: * We can't enlist stable bundles either. */ write_unlock_bh(&policy->lock); - if (dst) - dst_free(dst); + dst_free(dst); if (pol_dead) XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLDEAD); @@ -1748,8 +1747,7 @@ restart: err = xfrm_dst_update_origin(dst, fl); if (unlikely(err)) { write_unlock_bh(&policy->lock); - if (dst) - dst_free(dst); + dst_free(dst); XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLECHECKERROR); goto error; } diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 4c6914ef7d92..7bd62f61593f 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -780,11 +780,13 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, { unsigned int h; struct hlist_node *entry; - struct xfrm_state *x, *x0; + struct xfrm_state *x, *x0, *to_put; int acquire_in_progress = 0; int error = 0; struct xfrm_state *best = NULL; + to_put = NULL; + spin_lock_bh(&xfrm_state_lock); h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family); hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { @@ -833,7 +835,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, if (tmpl->id.spi && (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi, tmpl->id.proto, family)) != NULL) { - xfrm_state_put(x0); + to_put = x0; error = -EEXIST; goto out; } @@ -849,7 +851,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); if (error) { x->km.state = XFRM_STATE_DEAD; - xfrm_state_put(x); + to_put = x; x = NULL; goto out; } @@ -870,7 +872,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, xfrm_hash_grow_check(x->bydst.next != NULL); } else { x->km.state = XFRM_STATE_DEAD; - xfrm_state_put(x); + to_put = x; x = NULL; error = -ESRCH; } @@ -881,6 +883,8 @@ out: else *err = acquire_in_progress ? -EAGAIN : error; spin_unlock_bh(&xfrm_state_lock); + if (to_put) + xfrm_state_put(to_put); return x; } @@ -1067,18 +1071,20 @@ static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq); int xfrm_state_add(struct xfrm_state *x) { - struct xfrm_state *x1; + struct xfrm_state *x1, *to_put; int family; int err; int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); family = x->props.family; + to_put = NULL; + spin_lock_bh(&xfrm_state_lock); x1 = __xfrm_state_locate(x, use_spi, family); if (x1) { - xfrm_state_put(x1); + to_put = x1; x1 = NULL; err = -EEXIST; goto out; @@ -1088,7 +1094,7 @@ int xfrm_state_add(struct xfrm_state *x) x1 = __xfrm_find_acq_byseq(x->km.seq); if (x1 && ((x1->id.proto != x->id.proto) || xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { - xfrm_state_put(x1); + to_put = x1; x1 = NULL; } } @@ -1110,6 +1116,9 @@ out: xfrm_state_put(x1); } + if (to_put) + xfrm_state_put(to_put); + return err; } EXPORT_SYMBOL(xfrm_state_add); @@ -1269,10 +1278,12 @@ EXPORT_SYMBOL(xfrm_state_migrate); int xfrm_state_update(struct xfrm_state *x) { - struct xfrm_state *x1; + struct xfrm_state *x1, *to_put; int err; int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); + to_put = NULL; + spin_lock_bh(&xfrm_state_lock); x1 = __xfrm_state_locate(x, use_spi, x->props.family); @@ -1281,7 +1292,7 @@ int xfrm_state_update(struct xfrm_state *x) goto out; if (xfrm_state_kern(x1)) { - xfrm_state_put(x1); + to_put = x1; err = -EEXIST; goto out; } @@ -1295,6 +1306,9 @@ int xfrm_state_update(struct xfrm_state *x) out: spin_unlock_bh(&xfrm_state_lock); + if (to_put) + xfrm_state_put(to_put); + if (err) return err; diff --git a/security/device_cgroup.c b/security/device_cgroup.c index 7bd296cca041..46f23971f7e4 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -508,12 +508,11 @@ int devcgroup_inode_permission(struct inode *inode, int mask) return 0; if (!S_ISBLK(inode->i_mode) && !S_ISCHR(inode->i_mode)) return 0; - dev_cgroup = css_to_devcgroup(task_subsys_state(current, - devices_subsys_id)); - if (!dev_cgroup) - return 0; rcu_read_lock(); + + dev_cgroup = task_devcgroup(current); + list_for_each_entry_rcu(wh, &dev_cgroup->whitelist, list) { if (wh->type & DEV_ALL) goto acc_check; @@ -533,6 +532,7 @@ acc_check: rcu_read_unlock(); return 0; } + rcu_read_unlock(); return -EPERM; @@ -543,12 +543,10 @@ int devcgroup_inode_mknod(int mode, dev_t dev) struct dev_cgroup *dev_cgroup; struct dev_whitelist_item *wh; - dev_cgroup = css_to_devcgroup(task_subsys_state(current, - devices_subsys_id)); - if (!dev_cgroup) - return 0; - rcu_read_lock(); + + dev_cgroup = task_devcgroup(current); + list_for_each_entry(wh, &dev_cgroup->whitelist, list) { if (wh->type & DEV_ALL) goto acc_check; @@ -566,6 +564,8 @@ acc_check: rcu_read_unlock(); return 0; } + rcu_read_unlock(); + return -EPERM; } diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index b52f923ce680..d11a8154500f 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -811,11 +811,12 @@ static int string_to_context_struct(struct policydb *pol, /* Check the validity of the new context. */ if (!policydb_context_isvalid(pol, ctx)) { rc = -EINVAL; - context_destroy(ctx); goto out; } rc = 0; out: + if (rc) + context_destroy(ctx); return rc; } @@ -868,8 +869,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, } else if (rc) goto out; rc = sidtab_context_to_sid(&sidtab, &context, sid); - if (rc) - context_destroy(&context); + context_destroy(&context); out: read_unlock(&policy_rwlock); kfree(scontext2); diff --git a/sound/Kconfig b/sound/Kconfig index a37bee094eba..8ebf512ced6c 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -91,6 +91,9 @@ endif # SOUND_PRIME endif # !M68K +endif # SOUND + +# AC97_BUS is used from both sound and ucb1400 config AC97_BUS tristate help @@ -99,4 +102,3 @@ config AC97_BUS sound although they're sharing the AC97 bus. Concerned drivers should "select" this. -endif # SOUND diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 909f1c101c95..66025161bd69 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6197,7 +6197,6 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x106b, 0x00a0, "Apple iMac 24''", ALC885_IMAC24), SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), @@ -14067,6 +14066,13 @@ static struct hda_verb alc662_auto_init_verbs[] = { { } }; +/* additional verbs for ALC663 */ +static struct hda_verb alc663_auto_init_verbs[] = { + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + { } +}; + static struct hda_verb alc663_m51va_init_verbs[] = { {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -14595,6 +14601,14 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, if (!pin) return 0; + if (pin == 0x17) { + /* ALC663 has a mono output pin on 0x17 */ + sprintf(name, "%s Playback Switch", pfx); + err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT)); + return err; + } + if (alc880_is_fixed_pin(pin)) { nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); /* printk("DAC nid=%x\n",nid); */ @@ -14765,6 +14779,14 @@ static int alc662_parse_auto_config(struct hda_codec *codec) spec->input_mux = &spec->private_imux; spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs; + if (codec->vendor_id == 0x10ec0663) + spec->init_verbs[spec->num_init_verbs++] = + alc663_auto_init_verbs; + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + spec->mixers[spec->num_mixers] = alc662_capture_mixer; spec->num_mixers++; return 1; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 7fdafcb0015d..ad994fcab725 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -560,8 +560,9 @@ static struct hda_verb dell_eq_core_init[] = { }; static struct hda_verb dell_m6_core_init[] = { - /* set master volume and direct control */ - { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, + /* set master volume to max value without distortion + * and direct control */ + { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec}, /* setup audio connections */ { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c index 7442460583dd..dad393ae040a 100644 --- a/sound/pci/oxygen/hifier.c +++ b/sound/pci/oxygen/hifier.c @@ -17,6 +17,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <linux/delay.h> #include <linux/pci.h> #include <sound/control.h> #include <sound/core.h> @@ -107,6 +108,9 @@ static void set_ak4396_params(struct oxygen *chip, else value |= AK4396_DFS_QUAD; data->ak4396_ctl2 = value; + + msleep(1); /* wait for the new MCLK to become stable */ + ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB); ak4396_write(chip, AK4396_CONTROL_2, value); ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 7c8ae31eb468..c5829d30ef86 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -28,6 +28,7 @@ * GPIO 1 -> DFS1 of AK5385 */ +#include <linux/delay.h> #include <linux/mutex.h> #include <linux/pci.h> #include <sound/ac97_codec.h> @@ -213,6 +214,9 @@ static void set_ak4396_params(struct oxygen *chip, else value |= AK4396_DFS_QUAD; data->ak4396_ctl2 = value; + + msleep(1); /* wait for the new MCLK to become stable */ + for (i = 0; i < 4; ++i) { ak4396_write(chip, i, AK4396_CONTROL_1, AK4396_DIF_24_MSB); diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 8548818eea08..c796b1882776 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -16,6 +16,7 @@ #include <linux/device.h> #include <linux/delay.h> #include <linux/clk.h> +#include <linux/platform_device.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/initval.h> @@ -81,7 +82,6 @@ static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - clk_i2s = clk_get(NULL, "I2SCLK"); if (IS_ERR(clk_i2s)) return PTR_ERR(clk_i2s); @@ -152,6 +152,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx); pxa_gpio_mode(gpio_bus[pxa_i2s.master].frm); pxa_gpio_mode(gpio_bus[pxa_i2s.master].clk); + BUG_ON(IS_ERR(clk_i2s)); clk_enable(clk_i2s); pxa_i2s_wait(); @@ -317,6 +318,43 @@ struct snd_soc_dai pxa_i2s_dai = { EXPORT_SYMBOL_GPL(pxa_i2s_dai); +static int pxa2xx_i2s_probe(struct platform_device *dev) +{ + clk_i2s = clk_get(&dev->dev, "I2SCLK"); + return IS_ERR(clk_i2s) ? PTR_ERR(clk_i2s) : 0; +} + +static int __devexit pxa2xx_i2s_remove(struct platform_device *dev) +{ + clk_put(clk_i2s); + clk_i2s = ERR_PTR(-ENOENT); + return 0; +} + +static struct platform_driver pxa2xx_i2s_driver = { + .probe = pxa2xx_i2s_probe, + .remove = __devexit_p(pxa2xx_i2s_remove), + + .driver = { + .name = "pxa2xx-i2s", + .owner = THIS_MODULE, + }, +}; + +static int __init pxa2xx_i2s_init(void) +{ + clk_i2s = ERR_PTR(-ENOENT); + return platform_driver_register(&pxa2xx_i2s_driver); +} + +static void __exit pxa2xx_i2s_exit(void) +{ + platform_driver_unregister(&pxa2xx_i2s_driver); +} + +module_init(pxa2xx_i2s_init); +module_exit(pxa2xx_i2s_exit); + /* Module information */ MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); MODULE_DESCRIPTION("pxa2xx I2S SoC Interface"); |