]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 23 Jun 2009 18:52:16 +0000 (11:52 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 23 Jun 2009 18:52:16 +0000 (11:52 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6:
  sh: Fix up HAVE_PERF_COUNTERS typo.
  sh: Fix up more dma-mapping fallout.
  sh: SH7786 SMP support.
  sh: Wire up the uncached fixmap on sh64 as well.
  sh: Use local TLB flush in set_pte_phys().
  sh: Provide cpu_idle_wait() to fix up cpuidle/SMP build.

169 files changed:
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/v4l2-framework.txt
Documentation/watchdog/hpwdt.txt
MAINTAINERS
arch/cris/arch-v10/kernel/dma.c
arch/cris/arch-v32/drivers/cryptocop.c
arch/cris/arch-v32/kernel/irq.c
arch/cris/arch-v32/lib/Makefile
arch/cris/arch-v32/lib/strcmp.S [new file with mode: 0644]
arch/cris/include/arch-v32/arch/spinlock.h
arch/cris/include/asm/string.h
block/bsg.c
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/libata-core.c
drivers/ata/pata_at91.c [new file with mode: 0644]
drivers/ata/sata_fsl.c
drivers/ide/cmd64x.c
drivers/infiniband/core/addr.c
drivers/infiniband/core/cma.c
drivers/infiniband/hw/ehca/ehca_hca.c
drivers/infiniband/hw/ehca/ehca_main.c
drivers/infiniband/hw/ehca/ehca_mrmw.c
drivers/infiniband/hw/ehca/ehca_mrmw.h
drivers/infiniband/hw/mthca/mthca_mr.c
drivers/infiniband/hw/nes/nes_cm.c
drivers/infiniband/hw/nes/nes_verbs.c
drivers/media/common/ir-keymaps.c
drivers/media/dvb/frontends/stv0900.h
drivers/media/dvb/frontends/stv0900_core.c
drivers/media/dvb/frontends/stv0900_priv.h
drivers/media/dvb/frontends/stv090x.c
drivers/media/dvb/frontends/tda10048.c
drivers/media/dvb/siano/smscoreapi.c
drivers/media/radio/radio-tea5764.c
drivers/media/video/Kconfig
drivers/media/video/cx18/cx18-controls.c
drivers/media/video/cx231xx/cx231xx-avcore.c
drivers/media/video/cx231xx/cx231xx-video.c
drivers/media/video/cx231xx/cx231xx.h
drivers/media/video/cx2341x.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885-video.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-dvb.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/ov519.c
drivers/media/video/gspca/sonixj.c
drivers/media/video/gspca/stv06xx/Makefile
drivers/media/video/gspca/stv06xx/stv06xx.c
drivers/media/video/gspca/stv06xx/stv06xx.h
drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
drivers/media/video/gspca/stv06xx/stv06xx_st6422.c [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/stv06xx_st6422.h [new file with mode: 0644]
drivers/media/video/ivtv/ivtv-controls.c
drivers/media/video/mt9m001.c
drivers/media/video/mt9t031.c
drivers/media/video/mt9v022.c
drivers/media/video/ov511.c
drivers/media/video/pvrusb2/pvrusb2-audio.c
drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c
drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
drivers/media/video/pxa_camera.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/tcm825x.c
drivers/media/video/usbvideo/Kconfig
drivers/media/video/v4l2-common.c
drivers/media/video/vivi.c
drivers/media/video/w9968cf.c
drivers/media/video/zoran/zoran_driver.c
drivers/message/fusion/mptsas.c
drivers/mfd/twl4030-core.c
drivers/net/cnic.c
drivers/net/cnic_if.h
drivers/net/mlx4/mr.c
drivers/scsi/Kconfig
drivers/scsi/bnx2i/Kconfig
drivers/scsi/cxgb3i/cxgb3i_ddp.c
drivers/scsi/cxgb3i/cxgb3i_ddp.h
drivers/scsi/fcoe/fcoe.c
drivers/scsi/fcoe/fcoe.h
drivers/scsi/fcoe/libfcoe.c
drivers/scsi/hosts.c
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ibmvscsi/ibmvfc.h
drivers/scsi/ipr.c
drivers/scsi/ipr.h
drivers/scsi/iscsi_tcp.c
drivers/scsi/libfc/fc_disc.c
drivers/scsi/libfc/fc_exch.c
drivers/scsi/libfc/fc_fcp.c
drivers/scsi/libfc/fc_lport.c
drivers/scsi/libfc/fc_rport.c
drivers/scsi/libiscsi.c
drivers/scsi/libiscsi_tcp.c
drivers/scsi/qla2xxx/qla_dbg.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_version.h
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_devinfo.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_priv.h
drivers/scsi/scsi_sysfs.c
drivers/scsi/scsi_transport_fc.c
drivers/scsi/scsi_transport_iscsi.c
drivers/scsi/scsi_transport_sas.c
drivers/scsi/scsi_transport_spi.c
drivers/scsi/sd.c
drivers/scsi/sd.h
drivers/scsi/sr.c
drivers/scsi/sym53c8xx_2/sym_hipd.c
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/bcm47xx_wdt.c [new file with mode: 0644]
drivers/watchdog/coh901327_wdt.c [new file with mode: 0644]
drivers/watchdog/hpwdt.c
drivers/watchdog/omap_wdt.c
drivers/watchdog/pnx833x_wdt.c [new file with mode: 0644]
drivers/watchdog/stmp3xxx_wdt.c [new file with mode: 0644]
drivers/watchdog/twl4030_wdt.c [new file with mode: 0644]
drivers/watchdog/wdt_pci.c
include/asm-generic/hardirq.h
include/asm-generic/pgtable.h
include/asm-generic/uaccess.h
include/asm-generic/unistd.h
include/linux/hugetlb.h
include/linux/videodev2.h
include/media/ir-common.h
include/media/v4l2-common.h
include/media/v4l2-i2c-drv.h
include/media/v4l2-subdev.h
include/scsi/fc_encode.h
include/scsi/libfc.h
include/scsi/libiscsi.h
include/scsi/scsi_driver.h
lib/Kconfig.debug
lib/checksum.c
mm/hugetlb.c
mm/kmemleak.c
mm/memory.c
mm/vmscan.c
sound/core/pcm_native.c
sound/core/seq/seq_midi_event.c
sound/pci/ctxfi/ctatc.c
sound/pci/ctxfi/ctatc.h
sound/pci/ctxfi/cthardware.h
sound/pci/ctxfi/cthw20k1.c
sound/pci/ctxfi/cthw20k2.c
sound/pci/ctxfi/ctmixer.c
sound/pci/ctxfi/ctmixer.h
sound/pci/ctxfi/ctpcm.c
sound/pci/ctxfi/xfi.c
sound/pci/hda/Kconfig
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/via82xx.c
sound/soc/blackfin/bf5xx-i2s.c

index 89093f531727766639fc074dcd03cdf528abd7b2..0736518b2f8814114ecbf89d031b7d57ab757d7e 100644 (file)
@@ -6,8 +6,8 @@
   5 -> Leadtek Winfast 2000XP Expert                       [107d:6611,107d:6613]
   6 -> AverTV Studio 303 (M126)                            [1461:000b]
   7 -> MSI TV-@nywhere Master                              [1462:8606]
-  8 -> Leadtek Winfast DV2000                              [107d:6620]
-  9 -> Leadtek PVR 2000                                    [107d:663b,107d:663c,107d:6632]
+  8 -> Leadtek Winfast DV2000                              [107d:6620,107d:6621]
+  9 -> Leadtek PVR 2000                                    [107d:663b,107d:663c,107d:6632,107d:6630,107d:6638,107d:6631,107d:6637,107d:663d]
  10 -> IODATA GV-VCP3/PCI                                  [10fc:d003]
  11 -> Prolink PlayTV PVR
  12 -> ASUS PVR-416                                        [1043:4823,1461:c111]
@@ -59,7 +59,7 @@
  58 -> Pinnacle PCTV HD 800i                               [11bd:0051]
  59 -> DViCO FusionHDTV 5 PCI nano                         [18ac:d530]
  60 -> Pinnacle Hybrid PCTV                                [12ab:1788]
- 61 -> Winfast TV2000 XP Global                            [107d:6f18]
+ 61 -> Leadtek TV2000 XP Global                            [107d:6f18,107d:6618]
  62 -> PowerColor RA330                                    [14f1:ea3d]
  63 -> Geniatech X8000-MT DVBT                             [14f1:8852]
  64 -> DViCO FusionHDTV DVB-T PRO                          [18ac:db30]
index a98a688c11b8b916b0e3e26dba584985b22050e4..873630e7e53eb5859b1cd722c0818865d895cd20 100644 (file)
@@ -65,3 +65,4 @@
  67 -> Terratec Grabby                          (em2860)        [0ccd:0096]
  68 -> Terratec AV350                           (em2860)        [0ccd:0084]
  69 -> KWorld ATSC 315U HDTV TV Box             (em2882)        [eb1a:a313]
+ 70 -> Evga inDtube                             (em2882)
index d54c1e4c6a9cec5f0cb8e8a2a53517b0bac662a7..ba4706afc5fbd6e1302f31acd1c207f657444f5e 100644 (file)
@@ -390,6 +390,30 @@ later date. It differs between i2c drivers and as such can be confusing.
 To see which chip variants are supported you can look in the i2c driver code
 for the i2c_device_id table. This lists all the possibilities.
 
+There are two more helper functions:
+
+v4l2_i2c_new_subdev_cfg: this function adds new irq and platform_data
+arguments and has both 'addr' and 'probed_addrs' arguments: if addr is not
+0 then that will be used (non-probing variant), otherwise the probed_addrs
+are probed.
+
+For example: this will probe for address 0x10:
+
+struct v4l2_subdev *sd = v4l2_i2c_new_subdev_cfg(v4l2_dev, adapter,
+              "module_foo", "chipid", 0, NULL, 0, I2C_ADDRS(0x10));
+
+v4l2_i2c_new_subdev_board uses an i2c_board_info struct which is passed
+to the i2c driver and replaces the irq, platform_data and addr arguments.
+
+If the subdev supports the s_config core ops, then that op is called with
+the irq and platform_data arguments after the subdev was setup. The older
+v4l2_i2c_new_(probed_)subdev functions will call s_config as well, but with
+irq set to 0 and platform_data set to NULL.
+
+Note that in the next kernel release the functions v4l2_i2c_new_subdev,
+v4l2_i2c_new_probed_subdev and v4l2_i2c_new_probed_subdev_addr will all be
+replaced by a single v4l2_i2c_new_subdev that is identical to
+v4l2_i2c_new_subdev_cfg but without the irq and platform_data arguments.
 
 struct video_device
 -------------------
index 127839e530430916532de85f69e0e142a36f0188..9c24d5ffbb06be90460b055fd434f5e58dd9a661 100644 (file)
@@ -19,30 +19,41 @@ Last reviewed: 06/02/2009
  not be updated in a timely fashion and a hardware system reset (also known as
  an Automatic Server Recovery (ASR)) event will occur.
 
- The hpwdt driver also has three (3) module parameters. They are the following:
+ The hpwdt driver also has four (4) module parameters. They are the following:
 
  soft_margin - allows the user to set the watchdog timer value
  allow_kdump - allows the user to save off a kernel dump image after an NMI
  nowayout    - basic watchdog parameter that does not allow the timer to
                be restarted or an impending ASR to be escaped.
+ priority    - determines whether or not the hpwdt driver is first on the
+               die_notify list to handle NMIs or last. The default value
+               for this module parameter is 0 or LAST. If the user wants to
+               enable NMI sourcing then reload the hpwdt driver with
+               priority=1 (and boot with nmi_watchdog=0).
 
  NOTE: More information about watchdog drivers in general, including the ioctl
        interface to /dev/watchdog can be found in
        Documentation/watchdog/watchdog-api.txt and Documentation/IPMI.txt.
 
- The NMI sourcing capability is disabled when the driver discovers that the
- nmi_watchdog is turned on (nmi_watchdog = 1). This is due to the inability to
+ The priority parameter was introduced due to other kernel software that relied
+ on handling NMIs (like oprofile). Keeping hpwdt's priority at 0 (or LAST)
+ enables the users of NMIs for non critical events to be work as expected.
+
+ The NMI sourcing capability is disabled by default due to the inability to
  distinguish between "NMI Watchdog Ticks" and "HW generated NMI events" in the
  Linux kernel. What this means is that the hpwdt nmi handler code is called
  each time the NMI signal fires off. This could amount to several thousands of
  NMIs in a matter of seconds. If a user sees the Linux kernel's "dazed and
  confused" message in the logs or if the system gets into a hung state, then
- the user should reboot with nmi_watchdog=0.
+ the hpwdt driver can be reloaded with the "priority" module parameter set
+ (priority=1).
 
  1. If the kernel has not been booted with nmi_watchdog turned off then
     edit /boot/grub/menu.lst and place the nmi_watchdog=0 at the end of the
     currently booting kernel line.
  2. reboot the sever
+ 3. Once the system comes up perform a rmmod hpwdt
+ 4. insmod /lib/modules/`uname -r`/kernel/drivers/char/watchdog/hpwdt.ko priority=1
 
  Now, the hpwdt can successfully receive and source the NMI and provide a log
  message that details the reason for the NMI (as determined by the HP BIOS).
index 02f6f78b561f4bce68789776d5527ab5dbabcc22..303129ab4b7509bff0ed0ce3960d5c6b7bc53ff9 100644 (file)
@@ -2482,6 +2482,14 @@ F:       drivers/net/wan/pc300too.c
 F:     drivers/net/wan/pci200syn.c
 F:     drivers/net/wan/wanxl*
 
+GENERIC INCLUDE/ASM HEADER FILES
+P:     Arnd Bergmann
+M:     arnd@arndb.de
+L:     linux-arch@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic.git
+S:     Maintained
+F:     include/asm-generic
+
 GFS2 FILE SYSTEM
 P:     Steven Whitehouse
 M:     swhiteho@redhat.com
@@ -2824,10 +2832,10 @@ S:      Supported
 F:     drivers/scsi/ips.*
 
 IDE SUBSYSTEM
-P:     Bartlomiej Zolnierkiewicz
-M:     bzolnier@gmail.com
+P:     David S. Miller
+M:     davem@davemloft.net
 L:     linux-ide@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/bart/ide-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide-2.6.git
 S:     Maintained
 F:     Documentation/ide/
 F:     drivers/ide/
index 929e686662991fd54d4a2bf0dbc899bd1c8a01cf..d31504b4a19e184360fe1916d8a14e670b354557 100644 (file)
@@ -24,7 +24,7 @@ int cris_request_dma(unsigned int dmanr, const char * device_id,
        unsigned long int gens;
        int fail = -EINVAL;
 
-       if ((dmanr < 0) || (dmanr >= MAX_DMA_CHANNELS)) {
+       if (dmanr >= MAX_DMA_CHANNELS) {
                printk(KERN_CRIT "cris_request_dma: invalid DMA channel %u\n", dmanr);
                return -EINVAL;
        }
@@ -213,7 +213,7 @@ int cris_request_dma(unsigned int dmanr, const char * device_id,
 void cris_free_dma(unsigned int dmanr, const char * device_id)
 {
        unsigned long flags;
-       if ((dmanr < 0) || (dmanr >= MAX_DMA_CHANNELS)) {
+       if (dmanr >= MAX_DMA_CHANNELS) {
                printk(KERN_CRIT "cris_free_dma: invalid DMA channel %u\n", dmanr);
                return;
        }
index 67c61ea868136e1f67da952a48ca77f9459f46ea..fd529a0ec758aa3a018df065729616310a39cf12 100644 (file)
@@ -1395,7 +1395,7 @@ static int create_md5_pad(int alloc_flag, unsigned long long hashed_length, char
        if (padlen < MD5_MIN_PAD_LENGTH) padlen += MD5_BLOCK_LENGTH;
 
        p = kmalloc(padlen, alloc_flag);
-       if (!pad) return -ENOMEM;
+       if (!p) return -ENOMEM;
 
        *p = 0x80;
        memset(p+1, 0, padlen - 1);
@@ -1427,7 +1427,7 @@ static int create_sha1_pad(int alloc_flag, unsigned long long hashed_length, cha
        if (padlen < SHA1_MIN_PAD_LENGTH) padlen += SHA1_BLOCK_LENGTH;
 
        p = kmalloc(padlen, alloc_flag);
-       if (!pad) return -ENOMEM;
+       if (!p) return -ENOMEM;
 
        *p = 0x80;
        memset(p+1, 0, padlen - 1);
index d70b445f4a8f0fc82922e848ae4f0bbbae6a1fb5..57668db25031ca34bc965ee5abe1612e9f191e76 100644 (file)
@@ -430,8 +430,8 @@ crisv32_do_multiple(struct pt_regs* regs)
                         masked[i] &= ~TIMER_MASK;
                         do_IRQ(TIMER0_INTR_VECT, regs);
                }
-       }
 #endif
+       }
 
 #ifdef IGNORE_MASK
        /* Remove IRQs that can't be handled as multiple. */
index eb4aad1f115889cf6fce82f8f6bd78257d063ec3..dd296b9db034a5e1d5791ca0069c875fbb5b18e9 100644 (file)
@@ -3,5 +3,5 @@
 #
 
 lib-y  = checksum.o checksumcopy.o string.o usercopy.o memset.o \
-       csumcpfruser.o spinlock.o delay.o
+       csumcpfruser.o spinlock.o delay.o strcmp.o
 
diff --git a/arch/cris/arch-v32/lib/strcmp.S b/arch/cris/arch-v32/lib/strcmp.S
new file mode 100644 (file)
index 0000000..8f7a1ee
--- /dev/null
@@ -0,0 +1,21 @@
+; strcmp.S -- CRISv32 version.
+; Copyright (C) 2008 AXIS Communications AB
+; Written by Edgar E. Iglesias
+;
+; This source code is licensed under the GNU General Public License,
+; Version 2.  See the file COPYING for more details.
+
+       .global strcmp
+       .type   strcmp,@function
+strcmp:
+1:
+       move.b  [$r10+], $r12
+       seq     $r13
+       sub.b   [$r11+], $r12
+       or.b    $r12, $r13
+       beq     1b
+       nop
+
+       ret
+       movs.b  $r12, $r10
+       .size   strcmp, . - strcmp
index 129756b96661257945d768bfe3f5eecee2b4e282..367a53ea10c5714de719888a5ed12de83c97bc87 100644 (file)
@@ -78,7 +78,7 @@ static  inline void __raw_write_lock(raw_rwlock_t *rw)
 {
        __raw_spin_lock(&rw->slock);
        while (rw->lock != RW_LOCK_BIAS);
-       rw->lock == 0;
+       rw->lock = 0;
        __raw_spin_unlock(&rw->slock);
 }
 
@@ -93,7 +93,7 @@ static  inline void __raw_write_unlock(raw_rwlock_t *rw)
 {
        __raw_spin_lock(&rw->slock);
        while (rw->lock != RW_LOCK_BIAS);
-       rw->lock == RW_LOCK_BIAS;
+       rw->lock = RW_LOCK_BIAS;
        __raw_spin_unlock(&rw->slock);
 }
 
@@ -114,7 +114,7 @@ static  inline int __raw_write_trylock(raw_rwlock_t *rw)
        int ret = 0;
        __raw_spin_lock(&rw->slock);
        if (rw->lock == RW_LOCK_BIAS) {
-               rw->lock == 0;
+               rw->lock = 0;
                ret = 1;
        }
        __raw_spin_unlock(&rw->slock);
index 691190e99a27622a3f9a1d79f93c0c96254fba40..d5db39f9eea1535541a4962e0a027df0a6599bf8 100644 (file)
@@ -11,4 +11,10 @@ extern void *memcpy(void *, const void *, size_t);
 #define __HAVE_ARCH_MEMSET
 extern void *memset(void *, int, size_t);
 
+#ifdef CONFIG_ETRAX_ARCH_V32
+/* For v32 we provide strcmp.  */
+#define __HAVE_ARCH_STRCMP
+extern int strcmp(const char *s1, const char *s2);
+#endif
+
 #endif
index 54106f052f707bde6c4b89530d53a585c06366ce..e7d47525424890e24057b7ef4199eeff2322da5a 100644 (file)
@@ -315,7 +315,6 @@ out:
        blk_put_request(rq);
        if (next_rq) {
                blk_rq_unmap_user(next_rq->bio);
-               next_rq->bio = NULL;
                blk_put_request(next_rq);
        }
        return ERR_PTR(ret);
@@ -449,7 +448,6 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
                hdr->dout_resid = rq->resid_len;
                hdr->din_resid = rq->next_rq->resid_len;
                blk_rq_unmap_user(bidi_bio);
-               rq->next_rq->bio = NULL;
                blk_put_request(rq->next_rq);
        } else if (rq_data_dir(rq) == READ)
                hdr->din_resid = rq->resid_len;
@@ -468,7 +466,6 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
        blk_rq_unmap_user(bio);
        if (rq->cmd != rq->__cmd)
                kfree(rq->cmd);
-       rq->bio = NULL;
        blk_put_request(rq);
 
        return ret;
index 2aa1908e5ce0076a92f65367b4cef10e3b92d221..b17c57f850329a02973f4849500759e13a7f7e17 100644 (file)
@@ -679,6 +679,14 @@ config PATA_PLATFORM
 
          If unsure, say N.
 
+config PATA_AT91
+       tristate "PATA support for AT91SAM9260"
+       depends on ARM && ARCH_AT91
+       help
+         This option enables support for IDE devices on the Atmel AT91SAM9260 SoC.
+
+         If unsure, say N.
+
 config PATA_OF_PLATFORM
        tristate "OpenFirmware platform device PATA support"
        depends on PATA_PLATFORM && PPC_OF
index 1558059874f03db15246d39bcc3c049ff6311002..38906f9bbb4e3bdf3a8432c8b346b582516658b6 100644 (file)
@@ -72,6 +72,7 @@ obj-$(CONFIG_PATA_SCH)                += pata_sch.o
 obj-$(CONFIG_PATA_BF54X)       += pata_bf54x.o
 obj-$(CONFIG_PATA_OCTEON_CF)   += pata_octeon_cf.o
 obj-$(CONFIG_PATA_PLATFORM)    += pata_platform.o
+obj-$(CONFIG_PATA_AT91)        += pata_at91.o
 obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform.o
 obj-$(CONFIG_PATA_ICSIDE)      += pata_icside.o
 # Should be last but two libata driver
index ca4d208ddf3ba52fec7574c12a53db5bd6964b95..045a486a09eae25a16174a7c697e52796dcbc503 100644 (file)
@@ -125,19 +125,19 @@ MODULE_PARM_DESC(force, "Force ATA configurations including cable type, link spe
 
 static int atapi_enabled = 1;
 module_param(atapi_enabled, int, 0444);
-MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)");
+MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on [default])");
 
 static int atapi_dmadir = 0;
 module_param(atapi_dmadir, int, 0444);
-MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)");
+MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off [default], 1=on)");
 
 int atapi_passthru16 = 1;
 module_param(atapi_passthru16, int, 0444);
-MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices; on by default (0=off, 1=on)");
+MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices (0=off, 1=on [default])");
 
 int libata_fua = 0;
 module_param_named(fua, libata_fua, int, 0444);
-MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
+MODULE_PARM_DESC(fua, "FUA support (0=off [default], 1=on)");
 
 static int ata_ignore_hpa;
 module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644);
@@ -153,11 +153,11 @@ MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)");
 
 int libata_noacpi = 0;
 module_param_named(noacpi, libata_noacpi, int, 0444);
-MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in probe/suspend/resume when set");
+MODULE_PARM_DESC(noacpi, "Disable the use of ACPI in probe/suspend/resume (0=off [default], 1=on)");
 
 int libata_allow_tpm = 0;
 module_param_named(allow_tpm, libata_allow_tpm, int, 0444);
-MODULE_PARM_DESC(allow_tpm, "Permit the use of TPM commands");
+MODULE_PARM_DESC(allow_tpm, "Permit the use of TPM commands (0=off [default], 1=on)");
 
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("Library module for ATA devices");
@@ -1993,11 +1993,17 @@ unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
  *     Check if the current speed of the device requires IORDY. Used
  *     by various controllers for chip configuration.
  */
-
 unsigned int ata_pio_need_iordy(const struct ata_device *adev)
 {
-       /* Controller doesn't support  IORDY. Probably a pointless check
-          as the caller should know this */
+       /* Don't set IORDY if we're preparing for reset.  IORDY may
+        * lead to controller lock up on certain controllers if the
+        * port is not occupied.  See bko#11703 for details.
+        */
+       if (adev->link->ap->pflags & ATA_PFLAG_RESETTING)
+               return 0;
+       /* Controller doesn't support IORDY.  Probably a pointless
+        * check as the caller should know this.
+        */
        if (adev->link->ap->flags & ATA_FLAG_NO_IORDY)
                return 0;
        /* CF spec. r4.1 Table 22 says no iordy on PIO5 and PIO6.  */
@@ -2020,7 +2026,6 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev)
  *     Compute the highest mode possible if we are not using iordy. Return
  *     -1 if no iordy mode is available.
  */
-
 static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)
 {
        /* If we have no drive specific rule, then PIO 2 is non IORDY */
diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c
new file mode 100644 (file)
index 0000000..4b27617
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * PATA driver for AT91SAM9260 Static Memory Controller
+ * with CompactFlash interface in True IDE mode
+ *
+ * Copyright (C) 2009 Matyukevich Sergey
+ *
+ * Based on:
+ *      * generic platform driver by Paul Mundt: drivers/ata/pata_platform.c
+ *      * pata_at32 driver by Kristoffer Nyborg Gregertsen
+ *      * at91_ide driver by Stanislaw Gruszka
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/clk.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+#include <linux/ata_platform.h>
+
+#include <mach/at91sam9260_matrix.h>
+#include <mach/at91sam9_smc.h>
+#include <mach/at91sam9260.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+
+
+#define DRV_NAME "pata_at91"
+#define DRV_VERSION "0.1"
+
+#define CF_IDE_OFFSET      0x00c00000
+#define CF_ALT_IDE_OFFSET   0x00e00000
+#define CF_IDE_RES_SIZE     0x08
+
+struct at91_ide_info {
+       unsigned long mode;
+       unsigned int cs;
+
+       void __iomem *ide_addr;
+       void __iomem *alt_addr;
+};
+
+const struct ata_timing initial_timing =
+       {XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0};
+
+static unsigned int calc_mck_cycles(unsigned int ns, unsigned int mck_hz)
+{
+       unsigned long mul;
+
+    /*
+     * cycles = x [nsec] * f [Hz] / 10^9 [ns in sec] =
+     *     x * (f / 1_000_000_000) =
+     *     x * ((f * 65536) / 1_000_000_000) / 65536 =
+     *     x * (((f / 10_000) * 65536) / 100_000) / 65536 =
+     */
+
+    mul = (mck_hz / 10000) << 16;
+    mul /= 100000;
+
+    return (ns * mul + 65536) >> 16;    /* rounding */
+}
+
+static void set_smc_mode(struct at91_ide_info *info)
+{
+    at91_sys_write(AT91_SMC_MODE(info->cs), info->mode);
+    return;
+}
+
+static void set_smc_timing(struct device *dev,
+               struct at91_ide_info *info, const struct ata_timing *ata)
+{
+       int read_cycle, write_cycle, active, recover;
+       int nrd_setup, nrd_pulse, nrd_recover;
+       int nwe_setup, nwe_pulse;
+
+       int ncs_write_setup, ncs_write_pulse;
+       int ncs_read_setup, ncs_read_pulse;
+
+       unsigned int mck_hz;
+       struct clk *mck;
+
+       read_cycle  = ata->cyc8b;
+       nrd_setup   = ata->setup;
+       nrd_pulse   = ata->act8b;
+       nrd_recover = ata->rec8b;
+
+       mck = clk_get(NULL, "mck");
+       BUG_ON(IS_ERR(mck));
+       mck_hz = clk_get_rate(mck);
+
+       read_cycle  = calc_mck_cycles(read_cycle, mck_hz);
+       nrd_setup   = calc_mck_cycles(nrd_setup, mck_hz);
+       nrd_pulse   = calc_mck_cycles(nrd_pulse, mck_hz);
+       nrd_recover = calc_mck_cycles(nrd_recover, mck_hz);
+
+       clk_put(mck);
+
+       active  = nrd_setup + nrd_pulse;
+       recover = read_cycle - active;
+
+       /* Need at least two cycles recovery */
+       if (recover < 2)
+               read_cycle = active + 2;
+
+       /* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */
+       ncs_read_setup = 1;
+       ncs_read_pulse = read_cycle - 2;
+
+       /* Write timings same as read timings */
+       write_cycle = read_cycle;
+       nwe_setup = nrd_setup;
+       nwe_pulse = nrd_pulse;
+       ncs_write_setup = ncs_read_setup;
+       ncs_write_pulse = ncs_read_pulse;
+
+       dev_dbg(dev, "ATA timings: nrd_setup = %d nrd_pulse = %d nrd_cycle = %d\n",
+                       nrd_setup, nrd_pulse, read_cycle);
+       dev_dbg(dev, "ATA timings: nwe_setup = %d nwe_pulse = %d nwe_cycle = %d\n",
+                       nwe_setup, nwe_pulse, write_cycle);
+       dev_dbg(dev, "ATA timings: ncs_read_setup = %d ncs_read_pulse = %d\n",
+                       ncs_read_setup, ncs_read_pulse);
+       dev_dbg(dev, "ATA timings: ncs_write_setup = %d ncs_write_pulse = %d\n",
+                       ncs_write_setup, ncs_write_pulse);
+
+       at91_sys_write(AT91_SMC_SETUP(info->cs),
+                       AT91_SMC_NWESETUP_(nwe_setup) |
+                       AT91_SMC_NRDSETUP_(nrd_setup) |
+                       AT91_SMC_NCS_WRSETUP_(ncs_write_setup) |
+                       AT91_SMC_NCS_RDSETUP_(ncs_read_setup));
+
+       at91_sys_write(AT91_SMC_PULSE(info->cs),
+                       AT91_SMC_NWEPULSE_(nwe_pulse) |
+                       AT91_SMC_NRDPULSE_(nrd_pulse) |
+                       AT91_SMC_NCS_WRPULSE_(ncs_write_pulse) |
+                       AT91_SMC_NCS_RDPULSE_(ncs_read_pulse));
+
+       at91_sys_write(AT91_SMC_CYCLE(info->cs),
+                       AT91_SMC_NWECYCLE_(write_cycle) |
+                       AT91_SMC_NRDCYCLE_(read_cycle));
+
+       return;
+}
+
+static void pata_at91_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+       struct at91_ide_info *info = ap->host->private_data;
+       struct ata_timing timing;
+       int ret;
+
+       /* Compute ATA timing and set it to SMC */
+       ret = ata_timing_compute(adev, adev->pio_mode, &timing, 1000, 0);
+       if (ret) {
+               dev_warn(ap->dev, "Failed to compute ATA timing %d, \
+                               set PIO_0 timing\n", ret);
+               set_smc_timing(ap->dev, info, &initial_timing);
+       } else {
+               set_smc_timing(ap->dev, info, &timing);
+       }
+
+       /* Setup SMC mode */
+       set_smc_mode(info);
+
+       return;
+}
+
+static unsigned int pata_at91_data_xfer_noirq(struct ata_device *dev,
+               unsigned char *buf, unsigned int buflen, int rw)
+{
+       struct at91_ide_info *info = dev->link->ap->host->private_data;
+       unsigned int consumed;
+       unsigned long flags;
+       unsigned int mode;
+
+       local_irq_save(flags);
+       mode = at91_sys_read(AT91_SMC_MODE(info->cs));
+
+       /* set 16bit mode before writing data */
+       at91_sys_write(AT91_SMC_MODE(info->cs),
+                       (mode & ~AT91_SMC_DBW) | AT91_SMC_DBW_16);
+
+       consumed = ata_sff_data_xfer(dev, buf, buflen, rw);
+
+       /* restore 8bit mode after data is written */
+       at91_sys_write(AT91_SMC_MODE(info->cs),
+                       (mode & ~AT91_SMC_DBW) | AT91_SMC_DBW_8);
+
+       local_irq_restore(flags);
+       return consumed;
+}
+
+static struct scsi_host_template pata_at91_sht = {
+       ATA_PIO_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations pata_at91_port_ops = {
+       .inherits       = &ata_sff_port_ops,
+
+       .sff_data_xfer  = pata_at91_data_xfer_noirq,
+       .set_piomode    = pata_at91_set_piomode,
+       .cable_detect   = ata_cable_40wire,
+       .port_start     = ATA_OP_NULL,
+};
+
+static int __devinit pata_at91_probe(struct platform_device *pdev)
+{
+       struct at91_cf_data *board = pdev->dev.platform_data;
+       struct device *dev = &pdev->dev;
+       struct at91_ide_info *info;
+       struct resource *mem_res;
+       struct ata_host *host;
+       struct ata_port *ap;
+       int irq_flags = 0;
+       int irq = 0;
+       int ret;
+
+       /*  get platform resources: IO/CTL memories and irq/rst pins */
+
+       if (pdev->num_resources != 1) {
+               dev_err(&pdev->dev, "invalid number of resources\n");
+               return -EINVAL;
+       }
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       if (!mem_res) {
+               dev_err(dev, "failed to get mem resource\n");
+               return -EINVAL;
+       }
+
+       irq = board->irq_pin;
+
+       /* init ata host */
+
+       host = ata_host_alloc(dev, 1);
+
+       if (!host)
+               return -ENOMEM;
+
+       ap = host->ports[0];
+       ap->ops = &pata_at91_port_ops;
+       ap->flags |= ATA_FLAG_SLAVE_POSS;
+       ap->pio_mask = ATA_PIO4;
+
+       if (!irq) {
+               ap->flags |= ATA_FLAG_PIO_POLLING;
+               ata_port_desc(ap, "no IRQ, using PIO polling");
+       }
+
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
+
+       if (!info) {
+               dev_err(dev, "failed to allocate memory for private data\n");
+               return -ENOMEM;
+       }
+
+       info->cs    = board->chipselect;
+       info->mode  = AT91_SMC_READMODE | AT91_SMC_WRITEMODE |
+               AT91_SMC_EXNWMODE_READY | AT91_SMC_BAT_SELECT |
+               AT91_SMC_DBW_8 | AT91_SMC_TDF_(0);
+
+       info->ide_addr = devm_ioremap(dev,
+                       mem_res->start + CF_IDE_OFFSET, CF_IDE_RES_SIZE);
+
+       if (!info->ide_addr) {
+               dev_err(dev, "failed to map IO base\n");
+               ret = -ENOMEM;
+               goto err_ide_ioremap;
+       }
+
+       info->alt_addr = devm_ioremap(dev,
+                       mem_res->start + CF_ALT_IDE_OFFSET, CF_IDE_RES_SIZE);
+
+       if (!info->alt_addr) {
+               dev_err(dev, "failed to map CTL base\n");
+               ret = -ENOMEM;
+               goto err_alt_ioremap;
+       }
+
+       ap->ioaddr.cmd_addr = info->ide_addr;
+       ap->ioaddr.ctl_addr = info->alt_addr + 0x06;
+       ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr;
+
+       ata_sff_std_ports(&ap->ioaddr);
+
+       ata_port_desc(ap, "mmio cmd 0x%llx ctl 0x%llx",
+                       (unsigned long long)mem_res->start + CF_IDE_OFFSET,
+                       (unsigned long long)mem_res->start + CF_ALT_IDE_OFFSET);
+
+       host->private_data = info;
+
+       return ata_host_activate(host, irq ? gpio_to_irq(irq) : 0,
+                       irq ? ata_sff_interrupt : NULL,
+                       irq_flags, &pata_at91_sht);
+
+err_alt_ioremap:
+       devm_iounmap(dev, info->ide_addr);
+
+err_ide_ioremap:
+       kfree(info);
+
+       return ret;
+}
+
+static int __devexit pata_at91_remove(struct platform_device *pdev)
+{
+       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct at91_ide_info *info = host->private_data;
+       struct device *dev = &pdev->dev;
+
+       if (!host)
+               return 0;
+
+       ata_host_detach(host);
+
+       if (!info)
+               return 0;
+
+       devm_iounmap(dev, info->ide_addr);
+       devm_iounmap(dev, info->alt_addr);
+
+       kfree(info);
+       return 0;
+}
+
+static struct platform_driver pata_at91_driver = {
+       .probe          = pata_at91_probe,
+       .remove         = __devexit_p(pata_at91_remove),
+       .driver         = {
+               .name           = DRV_NAME,
+               .owner          = THIS_MODULE,
+       },
+};
+
+static int __init pata_at91_init(void)
+{
+       return platform_driver_register(&pata_at91_driver);
+}
+
+static void __exit pata_at91_exit(void)
+{
+       platform_driver_unregister(&pata_at91_driver);
+}
+
+
+module_init(pata_at91_init);
+module_exit(pata_at91_exit);
+
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Driver for CF in True IDE mode on AT91SAM9260 SoC");
+MODULE_AUTHOR("Matyukevich Sergey");
+MODULE_VERSION(DRV_VERSION);
+
index 36b8629203be2133cb486a1cb13f8d0c226f122e..94eaa432c40a640a883546db805bf43e2ffb88ab 100644 (file)
@@ -1378,6 +1378,37 @@ static int sata_fsl_remove(struct of_device *ofdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int sata_fsl_suspend(struct of_device *op, pm_message_t state)
+{
+       struct ata_host *host = dev_get_drvdata(&op->dev);
+       return ata_host_suspend(host, state);
+}
+
+static int sata_fsl_resume(struct of_device *op)
+{
+       struct ata_host *host = dev_get_drvdata(&op->dev);
+       struct sata_fsl_host_priv *host_priv = host->private_data;
+       int ret;
+       void __iomem *hcr_base = host_priv->hcr_base;
+       struct ata_port *ap = host->ports[0];
+       struct sata_fsl_port_priv *pp = ap->private_data;
+
+       ret = sata_fsl_init_controller(host);
+       if (ret) {
+               dev_printk(KERN_ERR, &op->dev,
+                       "Error initialize hardware\n");
+               return ret;
+       }
+
+       /* Recovery the CHBA register in host controller cmd register set */
+       iowrite32(pp->cmdslot_paddr & 0xffffffff, hcr_base + CHBA);
+
+       ata_host_resume(host);
+       return 0;
+}
+#endif
+
 static struct of_device_id fsl_sata_match[] = {
        {
                .compatible = "fsl,pq-sata",
@@ -1392,6 +1423,10 @@ static struct of_platform_driver fsl_sata_driver = {
        .match_table    = fsl_sata_match,
        .probe          = sata_fsl_probe,
        .remove         = sata_fsl_remove,
+#ifdef CONFIG_PM
+       .suspend        = sata_fsl_suspend,
+       .resume         = sata_fsl_resume,
+#endif
 };
 
 static int __init sata_fsl_init(void)
index 03c86209446f6e2f02b399aa34803a728e4827ed..680e5975217fe59dce8febedc3389e1766704e27 100644 (file)
@@ -389,8 +389,7 @@ static const struct ide_port_info cmd64x_chipsets[] __devinitdata = {
                .init_chipset   = init_chipset_cmd64x,
                .enablebits     = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
                .port_ops       = &cmd648_port_ops,
-               .host_flags     = IDE_HFLAG_SERIALIZE |
-                                 IDE_HFLAG_ABUSE_PREFETCH,
+               .host_flags     = IDE_HFLAG_ABUSE_PREFETCH,
                .pio_mask       = ATA_PIO5,
                .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA2,
index ce511d8748ce6d2923364b5fba4510d4b60d413e..5be1bd4fc7edb8401b94cee52b10cbf5b178c614 100644 (file)
@@ -514,7 +514,7 @@ static struct notifier_block nb = {
        .notifier_call = netevent_callback
 };
 
-static int addr_init(void)
+static int __init addr_init(void)
 {
        addr_wq = create_singlethread_workqueue("ib_addr");
        if (!addr_wq)
@@ -524,7 +524,7 @@ static int addr_init(void)
        return 0;
 }
 
-static void addr_cleanup(void)
+static void __exit addr_cleanup(void)
 {
        unregister_netevent_notifier(&nb);
        destroy_workqueue(addr_wq);
index 851de83ff455ed31ad2c4f343474dcd84ddefe43..075317884b5309f31ee3b8f7fac4821ea5622040 100644 (file)
@@ -2960,7 +2960,7 @@ static void cma_remove_one(struct ib_device *device)
        kfree(cma_dev);
 }
 
-static int cma_init(void)
+static int __init cma_init(void)
 {
        int ret, low, high, remaining;
 
@@ -2990,7 +2990,7 @@ err:
        return ret;
 }
 
-static void cma_cleanup(void)
+static void __exit cma_cleanup(void)
 {
        ib_unregister_client(&cma_client);
        unregister_netdevice_notifier(&cma_nb);
index 9209c5332dfe8f8031849cd12fa6dd4b94874906..8b92f85d4dd0eef382420e9d6dd69d7e1c594af1 100644 (file)
@@ -319,7 +319,7 @@ int ehca_query_gid(struct ib_device *ibdev, u8 port,
                                              ib_device);
        struct hipz_query_port *rblock;
 
-       if (index > 255) {
+       if (index < 0 || index > 255) {
                ehca_err(&shca->ib_device, "Invalid index: %x.", index);
                return -EINVAL;
        }
index ce4e6eff4792519193ebe9aa29d6e8aff5aaf5c5..fab18a2c74a8d55f00e5d2772ef1b448e01d6e59 100644 (file)
@@ -52,7 +52,7 @@
 #include "ehca_tools.h"
 #include "hcp_if.h"
 
-#define HCAD_VERSION "0027"
+#define HCAD_VERSION "0028"
 
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
@@ -506,6 +506,7 @@ static int ehca_init_device(struct ehca_shca *shca)
        shca->ib_device.detach_mcast        = ehca_detach_mcast;
        shca->ib_device.process_mad         = ehca_process_mad;
        shca->ib_device.mmap                = ehca_mmap;
+       shca->ib_device.dma_ops             = &ehca_dma_mapping_ops;
 
        if (EHCA_BMASK_GET(HCA_CAP_SRQ, shca->hca_cap)) {
                shca->ib_device.uverbs_cmd_mask |=
@@ -1028,17 +1029,23 @@ static int __init ehca_module_init(void)
                goto module_init1;
        }
 
+       ret = ehca_create_busmap();
+       if (ret) {
+               ehca_gen_err("Cannot create busmap.");
+               goto module_init2;
+       }
+
        ret = ibmebus_register_driver(&ehca_driver);
        if (ret) {
                ehca_gen_err("Cannot register eHCA device driver");
                ret = -EINVAL;
-               goto module_init2;
+               goto module_init3;
        }
 
        ret = register_memory_notifier(&ehca_mem_nb);
        if (ret) {
                ehca_gen_err("Failed registering memory add/remove notifier");
-               goto module_init3;
+               goto module_init4;
        }
 
        if (ehca_poll_all_eqs != 1) {
@@ -1053,9 +1060,12 @@ static int __init ehca_module_init(void)
 
        return 0;
 
-module_init3:
+module_init4:
        ibmebus_unregister_driver(&ehca_driver);
 
+module_init3:
+       ehca_destroy_busmap();
+
 module_init2:
        ehca_destroy_slab_caches();
 
@@ -1073,6 +1083,8 @@ static void __exit ehca_module_exit(void)
 
        unregister_memory_notifier(&ehca_mem_nb);
 
+       ehca_destroy_busmap();
+
        ehca_destroy_slab_caches();
 
        ehca_destroy_comp_pool();
index 72f83f7df614a47e116c20fdab0e032422a2baa9..7663a2a9f130430c9ba80a8123d519ca9a1fbad9 100644 (file)
 /* max number of rpages (per hcall register_rpages) */
 #define MAX_RPAGES 512
 
+/* DMEM toleration management */
+#define EHCA_SECTSHIFT        SECTION_SIZE_BITS
+#define EHCA_SECTSIZE          (1UL << EHCA_SECTSHIFT)
+#define EHCA_HUGEPAGESHIFT     34
+#define EHCA_HUGEPAGE_SIZE     (1UL << EHCA_HUGEPAGESHIFT)
+#define EHCA_HUGEPAGE_PFN_MASK ((EHCA_HUGEPAGE_SIZE - 1) >> PAGE_SHIFT)
+#define EHCA_INVAL_ADDR        0xFFFFFFFFFFFFFFFFULL
+#define EHCA_DIR_INDEX_SHIFT 13                   /* 8k Entries in 64k block */
+#define EHCA_TOP_INDEX_SHIFT (EHCA_DIR_INDEX_SHIFT * 2)
+#define EHCA_MAP_ENTRIES (1 << EHCA_DIR_INDEX_SHIFT)
+#define EHCA_TOP_MAP_SIZE (0x10000)               /* currently fixed map size */
+#define EHCA_DIR_MAP_SIZE (0x10000)
+#define EHCA_ENT_MAP_SIZE (0x10000)
+#define EHCA_INDEX_MASK (EHCA_MAP_ENTRIES - 1)
+
+static unsigned long ehca_mr_len;
+
+/*
+ * Memory map data structures
+ */
+struct ehca_dir_bmap {
+       u64 ent[EHCA_MAP_ENTRIES];
+};
+struct ehca_top_bmap {
+       struct ehca_dir_bmap *dir[EHCA_MAP_ENTRIES];
+};
+struct ehca_bmap {
+       struct ehca_top_bmap *top[EHCA_MAP_ENTRIES];
+};
+
+static struct ehca_bmap *ehca_bmap;
+
 static struct kmem_cache *mr_cache;
 static struct kmem_cache *mw_cache;
 
@@ -68,6 +100,8 @@ enum ehca_mr_pgsize {
 #define EHCA_MR_PGSHIFT1M  20
 #define EHCA_MR_PGSHIFT16M 24
 
+static u64 ehca_map_vaddr(void *caddr);
+
 static u32 ehca_encode_hwpage_size(u32 pgsize)
 {
        int log = ilog2(pgsize);
@@ -135,7 +169,8 @@ struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
                        goto get_dma_mr_exit0;
                }
 
-               ret = ehca_reg_maxmr(shca, e_maxmr, (u64 *)KERNELBASE,
+               ret = ehca_reg_maxmr(shca, e_maxmr,
+                                    (void *)ehca_map_vaddr((void *)KERNELBASE),
                                     mr_access_flags, e_pd,
                                     &e_maxmr->ib.ib_mr.lkey,
                                     &e_maxmr->ib.ib_mr.rkey);
@@ -251,7 +286,7 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
 
                ret = ehca_reg_mr(shca, e_mr, iova_start, size, mr_access_flags,
                                  e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
-                                 &e_mr->ib.ib_mr.rkey);
+                                 &e_mr->ib.ib_mr.rkey, EHCA_REG_MR);
                if (ret) {
                        ib_mr = ERR_PTR(ret);
                        goto reg_phys_mr_exit1;
@@ -370,7 +405,7 @@ reg_user_mr_fallback:
 
        ret = ehca_reg_mr(shca, e_mr, (u64 *)virt, length, mr_access_flags,
                          e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
-                         &e_mr->ib.ib_mr.rkey);
+                         &e_mr->ib.ib_mr.rkey, EHCA_REG_MR);
        if (ret == -EINVAL && pginfo.hwpage_size > PAGE_SIZE) {
                ehca_warn(pd->device, "failed to register mr "
                          "with hwpage_size=%llx", hwpage_size);
@@ -794,7 +829,7 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
        ret = ehca_reg_mr(shca, e_fmr, NULL,
                          fmr_attr->max_pages * (1 << fmr_attr->page_shift),
                          mr_access_flags, e_pd, &pginfo,
-                         &tmp_lkey, &tmp_rkey);
+                         &tmp_lkey, &tmp_rkey, EHCA_REG_MR);
        if (ret) {
                ib_fmr = ERR_PTR(ret);
                goto alloc_fmr_exit1;
@@ -983,6 +1018,10 @@ free_fmr_exit0:
 
 /*----------------------------------------------------------------------*/
 
+static int ehca_reg_bmap_mr_rpages(struct ehca_shca *shca,
+                                  struct ehca_mr *e_mr,
+                                  struct ehca_mr_pginfo *pginfo);
+
 int ehca_reg_mr(struct ehca_shca *shca,
                struct ehca_mr *e_mr,
                u64 *iova_start,
@@ -991,7 +1030,8 @@ int ehca_reg_mr(struct ehca_shca *shca,
                struct ehca_pd *e_pd,
                struct ehca_mr_pginfo *pginfo,
                u32 *lkey, /*OUT*/
-               u32 *rkey) /*OUT*/
+               u32 *rkey, /*OUT*/
+               enum ehca_reg_type reg_type)
 {
        int ret;
        u64 h_ret;
@@ -1015,7 +1055,13 @@ int ehca_reg_mr(struct ehca_shca *shca,
 
        e_mr->ipz_mr_handle = hipzout.handle;
 
-       ret = ehca_reg_mr_rpages(shca, e_mr, pginfo);
+       if (reg_type == EHCA_REG_BUSMAP_MR)
+               ret = ehca_reg_bmap_mr_rpages(shca, e_mr, pginfo);
+       else if (reg_type == EHCA_REG_MR)
+               ret = ehca_reg_mr_rpages(shca, e_mr, pginfo);
+       else
+               ret = -EINVAL;
+
        if (ret)
                goto ehca_reg_mr_exit1;
 
@@ -1316,7 +1362,7 @@ int ehca_rereg_mr(struct ehca_shca *shca,
                e_mr->fmr_map_cnt = save_mr.fmr_map_cnt;
 
                ret = ehca_reg_mr(shca, e_mr, iova_start, size, acl,
-                                 e_pd, pginfo, lkey, rkey);
+                                 e_pd, pginfo, lkey, rkey, EHCA_REG_MR);
                if (ret) {
                        u32 offset = (u64)(&e_mr->flags) - (u64)e_mr;
                        memcpy(&e_mr->flags, &(save_mr.flags),
@@ -1409,7 +1455,7 @@ int ehca_unmap_one_fmr(struct ehca_shca *shca,
        ret = ehca_reg_mr(shca, e_fmr, NULL,
                          (e_fmr->fmr_max_pages * e_fmr->fmr_page_size),
                          e_fmr->acl, e_pd, &pginfo, &tmp_lkey,
-                         &tmp_rkey);
+                         &tmp_rkey, EHCA_REG_MR);
        if (ret) {
                u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr;
                memcpy(&e_fmr->flags, &(save_mr.flags),
@@ -1478,6 +1524,90 @@ ehca_reg_smr_exit0:
 } /* end ehca_reg_smr() */
 
 /*----------------------------------------------------------------------*/
+static inline void *ehca_calc_sectbase(int top, int dir, int idx)
+{
+       unsigned long ret = idx;
+       ret |= dir << EHCA_DIR_INDEX_SHIFT;
+       ret |= top << EHCA_TOP_INDEX_SHIFT;
+       return abs_to_virt(ret << SECTION_SIZE_BITS);
+}
+
+#define ehca_bmap_valid(entry) \
+       ((u64)entry != (u64)EHCA_INVAL_ADDR)
+
+static u64 ehca_reg_mr_section(int top, int dir, int idx, u64 *kpage,
+                              struct ehca_shca *shca, struct ehca_mr *mr,
+                              struct ehca_mr_pginfo *pginfo)
+{
+       u64 h_ret = 0;
+       unsigned long page = 0;
+       u64 rpage = virt_to_abs(kpage);
+       int page_count;
+
+       void *sectbase = ehca_calc_sectbase(top, dir, idx);
+       if ((unsigned long)sectbase & (pginfo->hwpage_size - 1)) {
+               ehca_err(&shca->ib_device, "reg_mr_section will probably fail:"
+                                          "hwpage_size does not fit to "
+                                          "section start address");
+       }
+       page_count = EHCA_SECTSIZE / pginfo->hwpage_size;
+
+       while (page < page_count) {
+               u64 rnum;
+               for (rnum = 0; (rnum < MAX_RPAGES) && (page < page_count);
+                    rnum++) {
+                       void *pg = sectbase + ((page++) * pginfo->hwpage_size);
+                       kpage[rnum] = virt_to_abs(pg);
+               }
+
+               h_ret = hipz_h_register_rpage_mr(shca->ipz_hca_handle, mr,
+                       ehca_encode_hwpage_size(pginfo->hwpage_size),
+                       0, rpage, rnum);
+
+               if ((h_ret != H_SUCCESS) && (h_ret != H_PAGE_REGISTERED)) {
+                       ehca_err(&shca->ib_device, "register_rpage_mr failed");
+                       return h_ret;
+               }
+       }
+       return h_ret;
+}
+
+static u64 ehca_reg_mr_sections(int top, int dir, u64 *kpage,
+                               struct ehca_shca *shca, struct ehca_mr *mr,
+                               struct ehca_mr_pginfo *pginfo)
+{
+       u64 hret = H_SUCCESS;
+       int idx;
+
+       for (idx = 0; idx < EHCA_MAP_ENTRIES; idx++) {
+               if (!ehca_bmap_valid(ehca_bmap->top[top]->dir[dir]->ent[idx]))
+                       continue;
+
+               hret = ehca_reg_mr_section(top, dir, idx, kpage, shca, mr,
+                                          pginfo);
+               if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
+                               return hret;
+       }
+       return hret;
+}
+
+static u64 ehca_reg_mr_dir_sections(int top, u64 *kpage, struct ehca_shca *shca,
+                                   struct ehca_mr *mr,
+                                   struct ehca_mr_pginfo *pginfo)
+{
+       u64 hret = H_SUCCESS;
+       int dir;
+
+       for (dir = 0; dir < EHCA_MAP_ENTRIES; dir++) {
+               if (!ehca_bmap_valid(ehca_bmap->top[top]->dir[dir]))
+                       continue;
+
+               hret = ehca_reg_mr_sections(top, dir, kpage, shca, mr, pginfo);
+               if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
+                               return hret;
+       }
+       return hret;
+}
 
 /* register internal max-MR to internal SHCA */
 int ehca_reg_internal_maxmr(
@@ -1495,6 +1625,11 @@ int ehca_reg_internal_maxmr(
        u32 num_hwpages;
        u64 hw_pgsize;
 
+       if (!ehca_bmap) {
+               ret = -EFAULT;
+               goto ehca_reg_internal_maxmr_exit0;
+       }
+
        e_mr = ehca_mr_new();
        if (!e_mr) {
                ehca_err(&shca->ib_device, "out of memory");
@@ -1504,8 +1639,8 @@ int ehca_reg_internal_maxmr(
        e_mr->flags |= EHCA_MR_FLAG_MAXMR;
 
        /* register internal max-MR on HCA */
-       size_maxmr = (u64)high_memory - PAGE_OFFSET;
-       iova_start = (u64 *)KERNELBASE;
+       size_maxmr = ehca_mr_len;
+       iova_start = (u64 *)ehca_map_vaddr((void *)KERNELBASE);
        ib_pbuf.addr = 0;
        ib_pbuf.size = size_maxmr;
        num_kpages = NUM_CHUNKS(((u64)iova_start % PAGE_SIZE) + size_maxmr,
@@ -1524,7 +1659,7 @@ int ehca_reg_internal_maxmr(
 
        ret = ehca_reg_mr(shca, e_mr, iova_start, size_maxmr, 0, e_pd,
                          &pginfo, &e_mr->ib.ib_mr.lkey,
-                         &e_mr->ib.ib_mr.rkey);
+                         &e_mr->ib.ib_mr.rkey, EHCA_REG_BUSMAP_MR);
        if (ret) {
                ehca_err(&shca->ib_device, "reg of internal max MR failed, "
                         "e_mr=%p iova_start=%p size_maxmr=%llx num_kpages=%x "
@@ -2077,8 +2212,8 @@ int ehca_mr_is_maxmr(u64 size,
                     u64 *iova_start)
 {
        /* a MR is treated as max-MR only if it fits following: */
-       if ((size == ((u64)high_memory - PAGE_OFFSET)) &&
-           (iova_start == (void *)KERNELBASE)) {
+       if ((size == ehca_mr_len) &&
+           (iova_start == (void *)ehca_map_vaddr((void *)KERNELBASE))) {
                ehca_gen_dbg("this is a max-MR");
                return 1;
        } else
@@ -2184,3 +2319,350 @@ void ehca_cleanup_mrmw_cache(void)
        if (mw_cache)
                kmem_cache_destroy(mw_cache);
 }
+
+static inline int ehca_init_top_bmap(struct ehca_top_bmap *ehca_top_bmap,
+                                    int dir)
+{
+       if (!ehca_bmap_valid(ehca_top_bmap->dir[dir])) {
+               ehca_top_bmap->dir[dir] =
+                       kmalloc(sizeof(struct ehca_dir_bmap), GFP_KERNEL);
+               if (!ehca_top_bmap->dir[dir])
+                       return -ENOMEM;
+               /* Set map block to 0xFF according to EHCA_INVAL_ADDR */
+               memset(ehca_top_bmap->dir[dir], 0xFF, EHCA_ENT_MAP_SIZE);
+       }
+       return 0;
+}
+
+static inline int ehca_init_bmap(struct ehca_bmap *ehca_bmap, int top, int dir)
+{
+       if (!ehca_bmap_valid(ehca_bmap->top[top])) {
+               ehca_bmap->top[top] =
+                       kmalloc(sizeof(struct ehca_top_bmap), GFP_KERNEL);
+               if (!ehca_bmap->top[top])
+                       return -ENOMEM;
+               /* Set map block to 0xFF according to EHCA_INVAL_ADDR */
+               memset(ehca_bmap->top[top], 0xFF, EHCA_DIR_MAP_SIZE);
+       }
+       return ehca_init_top_bmap(ehca_bmap->top[top], dir);
+}
+
+static inline int ehca_calc_index(unsigned long i, unsigned long s)
+{
+       return (i >> s) & EHCA_INDEX_MASK;
+}
+
+void ehca_destroy_busmap(void)
+{
+       int top, dir;
+
+       if (!ehca_bmap)
+               return;
+
+       for (top = 0; top < EHCA_MAP_ENTRIES; top++) {
+               if (!ehca_bmap_valid(ehca_bmap->top[top]))
+                       continue;
+               for (dir = 0; dir < EHCA_MAP_ENTRIES; dir++) {
+                       if (!ehca_bmap_valid(ehca_bmap->top[top]->dir[dir]))
+                               continue;
+
+                       kfree(ehca_bmap->top[top]->dir[dir]);
+               }
+
+               kfree(ehca_bmap->top[top]);
+       }
+
+       kfree(ehca_bmap);
+       ehca_bmap = NULL;
+}
+
+static int ehca_update_busmap(unsigned long pfn, unsigned long nr_pages)
+{
+       unsigned long i, start_section, end_section;
+       int top, dir, idx;
+
+       if (!nr_pages)
+               return 0;
+
+       if (!ehca_bmap) {
+               ehca_bmap = kmalloc(sizeof(struct ehca_bmap), GFP_KERNEL);
+               if (!ehca_bmap)
+                       return -ENOMEM;
+               /* Set map block to 0xFF according to EHCA_INVAL_ADDR */
+               memset(ehca_bmap, 0xFF, EHCA_TOP_MAP_SIZE);
+       }
+
+       start_section = phys_to_abs(pfn * PAGE_SIZE) / EHCA_SECTSIZE;
+       end_section = phys_to_abs((pfn + nr_pages) * PAGE_SIZE) / EHCA_SECTSIZE;
+       for (i = start_section; i < end_section; i++) {
+               int ret;
+               top = ehca_calc_index(i, EHCA_TOP_INDEX_SHIFT);
+               dir = ehca_calc_index(i, EHCA_DIR_INDEX_SHIFT);
+               idx = i & EHCA_INDEX_MASK;
+
+               ret = ehca_init_bmap(ehca_bmap, top, dir);
+               if (ret) {
+                       ehca_destroy_busmap();
+                       return ret;
+               }
+               ehca_bmap->top[top]->dir[dir]->ent[idx] = ehca_mr_len;
+               ehca_mr_len += EHCA_SECTSIZE;
+       }
+       return 0;
+}
+
+static int ehca_is_hugepage(unsigned long pfn)
+{
+       int page_order;
+
+       if (pfn & EHCA_HUGEPAGE_PFN_MASK)
+               return 0;
+
+       page_order = compound_order(pfn_to_page(pfn));
+       if (page_order + PAGE_SHIFT != EHCA_HUGEPAGESHIFT)
+               return 0;
+
+       return 1;
+}
+
+static int ehca_create_busmap_callback(unsigned long initial_pfn,
+                                      unsigned long total_nr_pages, void *arg)
+{
+       int ret;
+       unsigned long pfn, start_pfn, end_pfn, nr_pages;
+
+       if ((total_nr_pages * PAGE_SIZE) < EHCA_HUGEPAGE_SIZE)
+               return ehca_update_busmap(initial_pfn, total_nr_pages);
+
+       /* Given chunk is >= 16GB -> check for hugepages */
+       start_pfn = initial_pfn;
+       end_pfn = initial_pfn + total_nr_pages;
+       pfn = start_pfn;
+
+       while (pfn < end_pfn) {
+               if (ehca_is_hugepage(pfn)) {
+                       /* Add mem found in front of the hugepage */
+                       nr_pages = pfn - start_pfn;
+                       ret = ehca_update_busmap(start_pfn, nr_pages);
+                       if (ret)
+                               return ret;
+                       /* Skip the hugepage */
+                       pfn += (EHCA_HUGEPAGE_SIZE / PAGE_SIZE);
+                       start_pfn = pfn;
+               } else
+                       pfn += (EHCA_SECTSIZE / PAGE_SIZE);
+       }
+
+       /* Add mem found behind the hugepage(s)  */
+       nr_pages = pfn - start_pfn;
+       return ehca_update_busmap(start_pfn, nr_pages);
+}
+
+int ehca_create_busmap(void)
+{
+       int ret;
+
+       ehca_mr_len = 0;
+       ret = walk_memory_resource(0, 1ULL << MAX_PHYSMEM_BITS, NULL,
+                                  ehca_create_busmap_callback);
+       return ret;
+}
+
+static int ehca_reg_bmap_mr_rpages(struct ehca_shca *shca,
+                                  struct ehca_mr *e_mr,
+                                  struct ehca_mr_pginfo *pginfo)
+{
+       int top;
+       u64 hret, *kpage;
+
+       kpage = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
+       if (!kpage) {
+               ehca_err(&shca->ib_device, "kpage alloc failed");
+               return -ENOMEM;
+       }
+       for (top = 0; top < EHCA_MAP_ENTRIES; top++) {
+               if (!ehca_bmap_valid(ehca_bmap->top[top]))
+                       continue;
+               hret = ehca_reg_mr_dir_sections(top, kpage, shca, e_mr, pginfo);
+               if ((hret != H_PAGE_REGISTERED) && (hret != H_SUCCESS))
+                       break;
+       }
+
+       ehca_free_fw_ctrlblock(kpage);
+
+       if (hret == H_SUCCESS)
+               return 0; /* Everything is fine */
+       else {
+               ehca_err(&shca->ib_device, "ehca_reg_bmap_mr_rpages failed, "
+                                "h_ret=%lli e_mr=%p top=%x lkey=%x "
+                                "hca_hndl=%llx mr_hndl=%llx", hret, e_mr, top,
+                                e_mr->ib.ib_mr.lkey,
+                                shca->ipz_hca_handle.handle,
+                                e_mr->ipz_mr_handle.handle);
+               return ehca2ib_return_code(hret);
+       }
+}
+
+static u64 ehca_map_vaddr(void *caddr)
+{
+       int top, dir, idx;
+       unsigned long abs_addr, offset;
+       u64 entry;
+
+       if (!ehca_bmap)
+               return EHCA_INVAL_ADDR;
+
+       abs_addr = virt_to_abs(caddr);
+       top = ehca_calc_index(abs_addr, EHCA_TOP_INDEX_SHIFT + EHCA_SECTSHIFT);
+       if (!ehca_bmap_valid(ehca_bmap->top[top]))
+               return EHCA_INVAL_ADDR;
+
+       dir = ehca_calc_index(abs_addr, EHCA_DIR_INDEX_SHIFT + EHCA_SECTSHIFT);
+       if (!ehca_bmap_valid(ehca_bmap->top[top]->dir[dir]))
+               return EHCA_INVAL_ADDR;
+
+       idx = ehca_calc_index(abs_addr, EHCA_SECTSHIFT);
+
+       entry = ehca_bmap->top[top]->dir[dir]->ent[idx];
+       if (ehca_bmap_valid(entry)) {
+               offset = (unsigned long)caddr & (EHCA_SECTSIZE - 1);
+               return entry | offset;
+       } else
+               return EHCA_INVAL_ADDR;
+}
+
+static int ehca_dma_mapping_error(struct ib_device *dev, u64 dma_addr)
+{
+       return dma_addr == EHCA_INVAL_ADDR;
+}
+
+static u64 ehca_dma_map_single(struct ib_device *dev, void *cpu_addr,
+                              size_t size, enum dma_data_direction direction)
+{
+       if (cpu_addr)
+               return ehca_map_vaddr(cpu_addr);
+       else
+               return EHCA_INVAL_ADDR;
+}
+
+static void ehca_dma_unmap_single(struct ib_device *dev, u64 addr, size_t size,
+                                 enum dma_data_direction direction)
+{
+       /* This is only a stub; nothing to be done here */
+}
+
+static u64 ehca_dma_map_page(struct ib_device *dev, struct page *page,
+                            unsigned long offset, size_t size,
+                            enum dma_data_direction direction)
+{
+       u64 addr;
+
+       if (offset + size > PAGE_SIZE)
+               return EHCA_INVAL_ADDR;
+
+       addr = ehca_map_vaddr(page_address(page));
+       if (!ehca_dma_mapping_error(dev, addr))
+               addr += offset;
+
+       return addr;
+}
+
+static void ehca_dma_unmap_page(struct ib_device *dev, u64 addr, size_t size,
+                               enum dma_data_direction direction)
+{
+       /* This is only a stub; nothing to be done here */
+}
+
+static int ehca_dma_map_sg(struct ib_device *dev, struct scatterlist *sgl,
+                          int nents, enum dma_data_direction direction)
+{
+       struct scatterlist *sg;
+       int i;
+
+       for_each_sg(sgl, sg, nents, i) {
+               u64 addr;
+               addr = ehca_map_vaddr(sg_virt(sg));
+               if (ehca_dma_mapping_error(dev, addr))
+                       return 0;
+
+               sg->dma_address = addr;
+               sg->dma_length = sg->length;
+       }
+       return nents;
+}
+
+static void ehca_dma_unmap_sg(struct ib_device *dev, struct scatterlist *sg,
+                             int nents, enum dma_data_direction direction)
+{
+       /* This is only a stub; nothing to be done here */
+}
+
+static u64 ehca_dma_address(struct ib_device *dev, struct scatterlist *sg)
+{
+       return sg->dma_address;
+}
+
+static unsigned int ehca_dma_len(struct ib_device *dev, struct scatterlist *sg)
+{
+       return sg->length;
+}
+
+static void ehca_dma_sync_single_for_cpu(struct ib_device *dev, u64 addr,
+                                        size_t size,
+                                        enum dma_data_direction dir)
+{
+       dma_sync_single_for_cpu(dev->dma_device, addr, size, dir);
+}
+
+static void ehca_dma_sync_single_for_device(struct ib_device *dev, u64 addr,
+                                           size_t size,
+                                           enum dma_data_direction dir)
+{
+       dma_sync_single_for_device(dev->dma_device, addr, size, dir);
+}
+
+static void *ehca_dma_alloc_coherent(struct ib_device *dev, size_t size,
+                                    u64 *dma_handle, gfp_t flag)
+{
+       struct page *p;
+       void *addr = NULL;
+       u64 dma_addr;
+
+       p = alloc_pages(flag, get_order(size));
+       if (p) {
+               addr = page_address(p);
+               dma_addr = ehca_map_vaddr(addr);
+               if (ehca_dma_mapping_error(dev, dma_addr)) {
+                       free_pages((unsigned long)addr, get_order(size));
+                       return NULL;
+               }
+               if (dma_handle)
+                       *dma_handle = dma_addr;
+               return addr;
+       }
+       return NULL;
+}
+
+static void ehca_dma_free_coherent(struct ib_device *dev, size_t size,
+                                  void *cpu_addr, u64 dma_handle)
+{
+       if (cpu_addr && size)
+               free_pages((unsigned long)cpu_addr, get_order(size));
+}
+
+
+struct ib_dma_mapping_ops ehca_dma_mapping_ops = {
+       .mapping_error          = ehca_dma_mapping_error,
+       .map_single             = ehca_dma_map_single,
+       .unmap_single           = ehca_dma_unmap_single,
+       .map_page               = ehca_dma_map_page,
+       .unmap_page             = ehca_dma_unmap_page,
+       .map_sg                 = ehca_dma_map_sg,
+       .unmap_sg               = ehca_dma_unmap_sg,
+       .dma_address            = ehca_dma_address,
+       .dma_len                = ehca_dma_len,
+       .sync_single_for_cpu    = ehca_dma_sync_single_for_cpu,
+       .sync_single_for_device = ehca_dma_sync_single_for_device,
+       .alloc_coherent         = ehca_dma_alloc_coherent,
+       .free_coherent          = ehca_dma_free_coherent,
+};
index bc8f4e31c1235c75655d84d9e1c1d60ca6a315f1..50d8b51306dd6a7a2b1958fd9edb5ae7e5d15737 100644 (file)
 #ifndef _EHCA_MRMW_H_
 #define _EHCA_MRMW_H_
 
+enum ehca_reg_type {
+       EHCA_REG_MR,
+       EHCA_REG_BUSMAP_MR
+};
+
 int ehca_reg_mr(struct ehca_shca *shca,
                struct ehca_mr *e_mr,
                u64 *iova_start,
@@ -50,7 +55,8 @@ int ehca_reg_mr(struct ehca_shca *shca,
                struct ehca_pd *e_pd,
                struct ehca_mr_pginfo *pginfo,
                u32 *lkey,
-               u32 *rkey);
+               u32 *rkey,
+               enum ehca_reg_type reg_type);
 
 int ehca_reg_mr_rpages(struct ehca_shca *shca,
                       struct ehca_mr *e_mr,
@@ -118,4 +124,9 @@ void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl,
 
 void ehca_mr_deletenew(struct ehca_mr *mr);
 
+int ehca_create_busmap(void);
+
+void ehca_destroy_busmap(void);
+
+extern struct ib_dma_mapping_ops ehca_dma_mapping_ops;
 #endif  /*_EHCA_MRMW_H_*/
index d606edf108589059a75bee4150b960b6c2fea52e..065b208998761b30f50c726c74de0dbfcfe05330 100644 (file)
@@ -352,10 +352,14 @@ static void mthca_arbel_write_mtt_seg(struct mthca_dev *dev,
 
        BUG_ON(!mtts);
 
+       dma_sync_single_for_cpu(&dev->pdev->dev, dma_handle,
+                               list_len * sizeof (u64), DMA_TO_DEVICE);
+
        for (i = 0; i < list_len; ++i)
                mtts[i] = cpu_to_be64(buffer_list[i] | MTHCA_MTT_FLAG_PRESENT);
 
-       dma_sync_single(&dev->pdev->dev, dma_handle, list_len * sizeof (u64), DMA_TO_DEVICE);
+       dma_sync_single_for_device(&dev->pdev->dev, dma_handle,
+                                  list_len * sizeof (u64), DMA_TO_DEVICE);
 }
 
 int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
@@ -803,12 +807,15 @@ int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
 
        wmb();
 
+       dma_sync_single_for_cpu(&dev->pdev->dev, fmr->mem.arbel.dma_handle,
+                               list_len * sizeof(u64), DMA_TO_DEVICE);
+
        for (i = 0; i < list_len; ++i)
                fmr->mem.arbel.mtts[i] = cpu_to_be64(page_list[i] |
                                                     MTHCA_MTT_FLAG_PRESENT);
 
-       dma_sync_single(&dev->pdev->dev, fmr->mem.arbel.dma_handle,
-                       list_len * sizeof(u64), DMA_TO_DEVICE);
+       dma_sync_single_for_device(&dev->pdev->dev, fmr->mem.arbel.dma_handle,
+                                  list_len * sizeof(u64), DMA_TO_DEVICE);
 
        fmr->mem.arbel.mpt->key    = cpu_to_be32(key);
        fmr->mem.arbel.mpt->lkey   = cpu_to_be32(key);
index 11c7d664201450faf31f14676efad9d161ba4cc6..114b802771ada144c5a4df3fc25407e2acb34156 100644 (file)
@@ -472,6 +472,7 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
 
 static void nes_retrans_expired(struct nes_cm_node *cm_node)
 {
+       struct iw_cm_id *cm_id = cm_node->cm_id;
        switch (cm_node->state) {
        case NES_CM_STATE_SYN_RCVD:
        case NES_CM_STATE_CLOSING:
@@ -479,7 +480,9 @@ static void nes_retrans_expired(struct nes_cm_node *cm_node)
                break;
        case NES_CM_STATE_LAST_ACK:
        case NES_CM_STATE_FIN_WAIT1:
-       case NES_CM_STATE_MPAREJ_RCVD:
+               if (cm_node->cm_id)
+                       cm_id->rem_ref(cm_id);
+               cm_node->state = NES_CM_STATE_CLOSED;
                send_reset(cm_node, NULL);
                break;
        default:
@@ -1406,6 +1409,7 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
        case NES_CM_STATE_CLOSED:
                drop_packet(skb);
                break;
+       case NES_CM_STATE_FIN_WAIT1:
        case NES_CM_STATE_LAST_ACK:
                cm_node->cm_id->rem_ref(cm_node->cm_id);
        case NES_CM_STATE_TIME_WAIT:
@@ -1413,8 +1417,6 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
                rem_ref_cm_node(cm_node->cm_core, cm_node);
                drop_packet(skb);
                break;
-       case NES_CM_STATE_FIN_WAIT1:
-               nes_debug(NES_DBG_CM, "Bad state %s[%u]\n", __func__, __LINE__);
        default:
                drop_packet(skb);
                break;
index 64d5cfd8f380f84e18564413bde8bfc879c62d28..21e0fd336cf710196dcbf2fe5bb3daecac7a21f4 100644 (file)
@@ -654,7 +654,7 @@ static int nes_query_device(struct ib_device *ibdev, struct ib_device_attr *prop
                default:
                        props->max_qp_rd_atom = 0;
        }
-       props->max_qp_init_rd_atom = props->max_qp_wr;
+       props->max_qp_init_rd_atom = props->max_qp_rd_atom;
        props->atomic_cap = IB_ATOMIC_NONE;
        props->max_map_per_fmr = 1;
 
index 3fe158ac7bbfdc697ed0dd701f637210169fa636..4216328552f6edad952ca870bf57beabef5b1227 100644 (file)
@@ -2750,3 +2750,26 @@ IR_KEYTAB_TYPE ir_codes_dm1105_nec[IR_KEYTAB_SIZE] = {
        [0x1b] = KEY_B,         /*recall*/
 };
 EXPORT_SYMBOL_GPL(ir_codes_dm1105_nec);
+
+/* EVGA inDtube
+   Devin Heitmueller <devin.heitmueller@gmail.com>
+ */
+IR_KEYTAB_TYPE ir_codes_evga_indtube[IR_KEYTAB_SIZE] = {
+       [0x12] = KEY_POWER,
+       [0x02] = KEY_MODE,      /* TV */
+       [0x14] = KEY_MUTE,
+       [0x1a] = KEY_CHANNELUP,
+       [0x16] = KEY_TV2,       /* PIP */
+       [0x1d] = KEY_VOLUMEUP,
+       [0x05] = KEY_CHANNELDOWN,
+       [0x0f] = KEY_PLAYPAUSE,
+       [0x19] = KEY_VOLUMEDOWN,
+       [0x1c] = KEY_REWIND,
+       [0x0d] = KEY_RECORD,
+       [0x18] = KEY_FORWARD,
+       [0x1e] = KEY_PREVIOUS,
+       [0x1b] = KEY_STOP,
+       [0x1f] = KEY_NEXT,
+       [0x13] = KEY_CAMERA,
+};
+EXPORT_SYMBOL_GPL(ir_codes_evga_indtube);
index 8a1332c2031df6d8c8112cda3e4f52715eb38eff..bf4e9b63304442e0287be0d1705a3c12f30b9c03 100644 (file)
 #include <linux/dvb/frontend.h>
 #include "dvb_frontend.h"
 
+struct stv0900_reg {
+       u16 addr;
+       u8  val;
+};
+
 struct stv0900_config {
        u8 demod_address;
        u32 xtal;
@@ -38,7 +43,7 @@ struct stv0900_config {
 
        u8 path1_mode;
        u8 path2_mode;
-
+       struct stv0900_reg *ts_config_regs;
        u8 tun1_maddress;/* 0, 1, 2, 3 for 0xc0, 0xc2, 0xc4, 0xc6 */
        u8 tun2_maddress;
        u8 tun1_adc;/* 1 for stv6110, 2 for stb6100 */
index 8499bcf7f2510ce097eb3124c7869517dc5f711c..1da045fbb4ef225def8c67afac3b6d528db668e6 100644 (file)
@@ -149,31 +149,31 @@ void stv0900_write_reg(struct stv0900_internal *i_params, u16 reg_addr,
                dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret);
 }
 
-u8 stv0900_read_reg(struct stv0900_internal *i_params, u16 reg_addr)
+u8 stv0900_read_reg(struct stv0900_internal *i_params, u16 reg)
 {
-       u8 data[2];
        int ret;
-       struct i2c_msg i2cmsg = {
-               .addr  = i_params->i2c_addr,
-               .flags = 0,
-               .len   = 2,
-               .buf   = data,
+       u8 b0[] = { MSB(reg), LSB(reg) };
+       u8 buf = 0;
+       struct i2c_msg msg[] = {
+               {
+                       .addr   = i_params->i2c_addr,
+                       .flags  = 0,
+                       .buf = b0,
+                       .len = 2,
+               }, {
+                       .addr   = i_params->i2c_addr,
+                       .flags  = I2C_M_RD,
+                       .buf = &buf,
+                       .len = 1,
+               },
        };
 
-       data[0] = MSB(reg_addr);
-       data[1] = LSB(reg_addr);
-
-       ret = i2c_transfer(i_params->i2c_adap, &i2cmsg, 1);
-       if (ret != 1)
-               dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret);
-
-       i2cmsg.flags = I2C_M_RD;
-       i2cmsg.len = 1;
-       ret = i2c_transfer(i_params->i2c_adap, &i2cmsg, 1);
-       if (ret != 1)
-               dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret);
+       ret = i2c_transfer(i_params->i2c_adap, msg, 2);
+       if (ret != 2)
+               dprintk(KERN_ERR "%s: i2c error %d, reg[0x%02x]\n",
+                               __func__, ret, reg);
 
-       return data[0];
+       return buf;
 }
 
 void extract_mask_pos(u32 label, u8 *mask, u8 *pos)
@@ -712,6 +712,44 @@ static s32 stv0900_carr_get_quality(struct dvb_frontend *fe,
        return c_n;
 }
 
+static int stv0900_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+       struct stv0900_internal *i_params = state->internal;
+       enum fe_stv0900_demod_num demod = state->demod;
+       u8 err_val1, err_val0;
+       s32 err_field1, err_field0;
+       u32 header_err_val = 0;
+
+       *ucblocks = 0x0;
+       if (stv0900_get_standard(fe, demod) == STV0900_DVBS2_STANDARD) {
+               /* DVB-S2 delineator errors count */
+
+               /* retreiving number for errnous headers */
+               dmd_reg(err_field0, R0900_P1_BBFCRCKO0,
+                                       R0900_P2_BBFCRCKO0);
+               dmd_reg(err_field1, R0900_P1_BBFCRCKO1,
+                                       R0900_P2_BBFCRCKO1);
+
+               err_val1 = stv0900_read_reg(i_params, err_field1);
+               err_val0 = stv0900_read_reg(i_params, err_field0);
+               header_err_val = (err_val1<<8) | err_val0;
+
+               /* retreiving number for errnous packets */
+               dmd_reg(err_field0, R0900_P1_UPCRCKO0,
+                                       R0900_P2_UPCRCKO0);
+               dmd_reg(err_field1, R0900_P1_UPCRCKO1,
+                                       R0900_P2_UPCRCKO1);
+
+               err_val1 = stv0900_read_reg(i_params, err_field1);
+               err_val0 = stv0900_read_reg(i_params, err_field0);
+               *ucblocks = (err_val1<<8) | err_val0;
+               *ucblocks += header_err_val;
+       }
+
+       return 0;
+}
+
 static int stv0900_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
        *snr = stv0900_carr_get_quality(fe,
@@ -1355,7 +1393,7 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
        struct stv0900_state *state = fe->demodulator_priv;
        enum fe_stv0900_error error = STV0900_NO_ERROR;
        enum fe_stv0900_error demodError = STV0900_NO_ERROR;
-       int selosci;
+       int selosci, i;
 
        struct stv0900_inode *temp_int = find_inode(state->i2c_adap,
                                                state->config->demod_address);
@@ -1402,7 +1440,23 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
                                stv0900_write_bits(state->internal, F0900_P1_ROLLOFF_CONTROL, p_init->rolloff);
                                stv0900_write_bits(state->internal, F0900_P2_ROLLOFF_CONTROL, p_init->rolloff);
 
-                               stv0900_set_ts_parallel_serial(state->internal, p_init->path1_ts_clock, p_init->path2_ts_clock);
+                               state->internal->ts_config = p_init->ts_config;
+                               if (state->internal->ts_config == NULL)
+                                       stv0900_set_ts_parallel_serial(state->internal,
+                                                       p_init->path1_ts_clock,
+                                                       p_init->path2_ts_clock);
+                               else {
+                                       for (i = 0; state->internal->ts_config[i].addr != 0xffff; i++)
+                                               stv0900_write_reg(state->internal,
+                                                               state->internal->ts_config[i].addr,
+                                                               state->internal->ts_config[i].val);
+
+                                       stv0900_write_bits(state->internal, F0900_P2_RST_HWARE, 1);
+                                       stv0900_write_bits(state->internal, F0900_P2_RST_HWARE, 0);
+                                       stv0900_write_bits(state->internal, F0900_P1_RST_HWARE, 1);
+                                       stv0900_write_bits(state->internal, F0900_P1_RST_HWARE, 0);
+                               }
+
                                stv0900_write_bits(state->internal, F0900_P1_TUN_MADDRESS, p_init->tun1_maddress);
                                switch (p_init->tuner1_adc) {
                                case 1:
@@ -1882,6 +1936,7 @@ static struct dvb_frontend_ops stv0900_ops = {
        .read_ber                       = stv0900_read_ber,
        .read_signal_strength           = stv0900_read_signal_strength,
        .read_snr                       = stv0900_read_snr,
+       .read_ucblocks                  = stv0900_read_ucblocks,
 };
 
 struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
@@ -1915,6 +1970,7 @@ struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
                init_params.tun1_iq_inversion   = STV0900_IQ_NORMAL;
                init_params.tuner1_adc          = config->tun1_adc;
                init_params.path2_ts_clock      = config->path2_mode;
+               init_params.ts_config           = config->ts_config_regs;
                init_params.tun2_maddress       = config->tun2_maddress;
                init_params.tuner2_adc          = config->tun2_adc;
                init_params.tun2_iq_inversion   = STV0900_IQ_SWAPPED;
index 67dc8ec634e2da56790dc7ab17a5f8c57bc7dc58..5ed7a145c7d3aaa7441b8ccda1600c8630d4df77 100644 (file)
@@ -271,6 +271,7 @@ struct stv0900_init_params{
 
        /* IQ from the tuner2 to the demod */
        enum stv0900_iq_inversion       tun2_iq_inversion;
+       struct stv0900_reg              *ts_config;
 };
 
 struct stv0900_search_params {
@@ -363,6 +364,7 @@ struct stv0900_internal{
        u8                      i2c_addr;
        u8                      clkmode;/* 0 for CLKI, 2 for XTALI */
        u8                      chip_id;
+       struct stv0900_reg      *ts_config;
        enum fe_stv0900_error   errs;
        int dmds_used;
 };
index 96ef745a2e4e8e767d358884f650d90f1a5f11cf..488bdfb34fb323babd4db966a272a927536695dc 100644 (file)
@@ -2674,7 +2674,7 @@ static u8 stv090x_optimize_carloop(struct stv090x_state *state, enum stv090x_mod
 
 static u8 stv090x_optimize_carloop_short(struct stv090x_state *state)
 {
-       struct stv090x_short_frame_crloop *short_crl;
+       struct stv090x_short_frame_crloop *short_crl = NULL;
        s32 index = 0;
        u8 aclc = 0x0b;
 
@@ -2694,10 +2694,13 @@ static u8 stv090x_optimize_carloop_short(struct stv090x_state *state)
                break;
        }
 
-       if (state->dev_ver >= 0x30)
-               short_crl = stv090x_s2_short_crl_cut20;
-       else if (state->dev_ver >= 0x20)
+       if (state->dev_ver >= 0x30) {
+               /* Cut 3.0 and up */
                short_crl = stv090x_s2_short_crl_cut30;
+       } else {
+               /* Cut 2.0 and up: we don't support cuts older than 2.0 */
+               short_crl = stv090x_s2_short_crl_cut20;
+       }
 
        if (state->srate <= 3000000)
                aclc = short_crl[index].crl_2;
index 4302c563a6b8950f6bdf045ee55a8adbbf2ea7e7..cc8862ce4aae9fff195506148f229cc4336b9eef 100644 (file)
@@ -210,6 +210,7 @@ static struct pll_tab {
        { TDA10048_CLK_4000,  TDA10048_IF_36130, 10, 0, 0 },
        { TDA10048_CLK_16000, TDA10048_IF_3300,  10, 3, 0 },
        { TDA10048_CLK_16000, TDA10048_IF_3500,  10, 3, 0 },
+       { TDA10048_CLK_16000, TDA10048_IF_3800,  10, 3, 0 },
        { TDA10048_CLK_16000, TDA10048_IF_4000,  10, 3, 0 },
        { TDA10048_CLK_16000, TDA10048_IF_4300,  10, 3, 0 },
        { TDA10048_CLK_16000, TDA10048_IF_36130, 10, 3, 0 },
index 32be382f0e97717f7c2f7c95c40f689374f4a994..a246903c3341bea1ba919f9a6b5262e73e3d6d6a 100644 (file)
@@ -1422,8 +1422,8 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
                struct smscore_gpio_config *pGpioConfig) {
 
        u32 totalLen;
-       u32 TranslatedPinNum;
-       u32 GroupNum;
+       u32 TranslatedPinNum = 0;
+       u32 GroupNum = 0;
        u32 ElectricChar;
        u32 groupCfg;
        void *buffer;
index 393623818ade299a09b61c6d5d245583f06f896a..3cd76dddb6aad7ca6fb0eaff71a66385850165f6 100644 (file)
@@ -322,7 +322,9 @@ static int vidioc_g_tuner(struct file *file, void *priv,
        v->rangehigh  = FREQ_MAX * FREQ_MUL;
        v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
        if (r->tunchk & TEA5764_TUNCHK_STEREO)
-                       v->rxsubchans = V4L2_TUNER_SUB_STEREO;
+               v->rxsubchans = V4L2_TUNER_SUB_STEREO;
+       else
+               v->rxsubchans = V4L2_TUNER_SUB_MONO;
        v->audmode = tea5764_get_audout_mode(radio);
        v->signal = TEA5764_TUNCHK_LEVEL(r->tunchk) * 0xffff / 0xf;
        v->afc = TEA5764_TUNCHK_IFCNT(r->tunchk);
index 94f440535c648896e9e84264ca94b9594542a243..061e147f6f2638d0c573e741a86d2e9dbe4a0630 100644 (file)
@@ -866,9 +866,13 @@ config USB_W9968CF
          module will be called w9968cf.
 
 config USB_OV511
-       tristate "USB OV511 Camera support"
+       tristate "USB OV511 Camera support (DEPRECATED)"
        depends on VIDEO_V4L1
        ---help---
+         This driver is DEPRECATED please use the gspca ov519 module
+         instead. Note that for the ov511 / ov518 support of the gspca module
+         you need atleast version 0.6.0 of libv4l.
+
          Say Y here if you want to connect this type of camera to your
          computer's USB port. See <file:Documentation/video4linux/ov511.txt>
          for more information and for a list of supported cameras.
index 8e35c3aed544a3f9a1e0479b6334fac4363488ba..5136df198338bbbe6855889b84cf0b5486252b2d 100644 (file)
@@ -61,6 +61,8 @@ int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
 
        switch (qctrl->id) {
        /* Standard V4L2 controls */
+       case V4L2_CID_USER_CLASS:
+               return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
        case V4L2_CID_BRIGHTNESS:
        case V4L2_CID_HUE:
        case V4L2_CID_SATURATION:
index 6a9464079b4cf7bb2161f0b1998d421bfbbbbc99..28f48f41f218cf45865f1a5cf730608954a98cce 100644 (file)
@@ -1052,22 +1052,13 @@ int cx231xx_set_audio_decoder_input(struct cx231xx *dev,
 /* Set resolution of the video */
 int cx231xx_resolution_set(struct cx231xx *dev)
 {
-       int width, height;
-       u32 hscale, vscale;
-       int status = 0;
-
-       width = dev->width;
-       height = dev->height;
-
-       get_scale(dev, width, height, &hscale, &vscale);
-
        /* set horzontal scale */
-       status = vid_blk_write_word(dev, HSCALE_CTRL, hscale);
+       int status = vid_blk_write_word(dev, HSCALE_CTRL, dev->hscale);
+       if (status)
+               return status;
 
        /* set vertical scale */
-       status = vid_blk_write_word(dev, VSCALE_CTRL, vscale);
-
-       return status;
+       return vid_blk_write_word(dev, VSCALE_CTRL, dev->vscale);
 }
 
 /******************************************************************************
@@ -2055,7 +2046,7 @@ int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type)
 
 int cx231xx_capture_start(struct cx231xx *dev, int start, u8 media_type)
 {
-       int rc;
+       int rc = -1;
        u32 ep_mask = -1;
        struct pcb_config *pcb_config;
 
index a23ae73fe63497a10dfb92942e6d4be54c0c3fcb..609bae6098d395b6aaee1f81fe683ca3f2771512 100644 (file)
@@ -893,9 +893,9 @@ static int check_dev(struct cx231xx *dev)
        return 0;
 }
 
-void get_scale(struct cx231xx *dev,
-              unsigned int width, unsigned int height,
-              unsigned int *hscale, unsigned int *vscale)
+static void get_scale(struct cx231xx *dev,
+                     unsigned int width, unsigned int height,
+                     unsigned int *hscale, unsigned int *vscale)
 {
        unsigned int maxw = norm_maxw(dev);
        unsigned int maxh = norm_maxh(dev);
@@ -907,10 +907,6 @@ void get_scale(struct cx231xx *dev,
        *vscale = (((unsigned long)maxh) << 12) / height - 4096L;
        if (*vscale >= 0x4000)
                *vscale = 0x3fff;
-
-       dev->hscale = *hscale;
-       dev->vscale = *vscale;
-
 }
 
 /* ------------------------------------------------------------------
@@ -955,8 +951,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 {
        struct cx231xx_fh *fh = priv;
        struct cx231xx *dev = fh->dev;
-       int width = f->fmt.pix.width;
-       int height = f->fmt.pix.height;
+       unsigned int width = f->fmt.pix.width;
+       unsigned int height = f->fmt.pix.height;
        unsigned int maxw = norm_maxw(dev);
        unsigned int maxh = norm_maxh(dev);
        unsigned int hscale, vscale;
@@ -971,17 +967,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 
        /* width must even because of the YUYV format
           height must be even because of interlacing */
-       height &= 0xfffe;
-       width &= 0xfffe;
-
-       if (unlikely(height < 32))
-               height = 32;
-       if (unlikely(height > maxh))
-               height = maxh;
-       if (unlikely(width < 48))
-               width = 48;
-       if (unlikely(width > maxw))
-               width = maxw;
+       v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0);
 
        get_scale(dev, width, height, &hscale, &vscale);
 
index e38eb2d425f78fdfcb03976973e1c445850705d3..a0f823ac6b8d4db3c3c30fe99f7acde86cdff356 100644 (file)
@@ -722,9 +722,6 @@ int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input);
 int cx231xx_set_decoder_video_input(struct cx231xx *dev, u8 pin_type, u8 input);
 int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev);
 int cx231xx_set_audio_input(struct cx231xx *dev, u8 input);
-void get_scale(struct cx231xx *dev,
-              unsigned int width, unsigned int height,
-              unsigned int *hscale, unsigned int *vscale);
 
 /* Provided by cx231xx-video.c */
 int cx231xx_register_extension(struct cx231xx_ops *dev);
index 8ded52946334e2abcec10d04f776492c91952373..4c8e95853fa3377b2fb53ace6659be808f04cbd2 100644 (file)
@@ -500,6 +500,8 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
        int err;
 
        switch (qctrl->id) {
+       case V4L2_CID_MPEG_CLASS:
+               return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
        case V4L2_CID_MPEG_STREAM_TYPE:
                return v4l2_ctrl_query_fill(qctrl,
                                V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
index e236df23370ea52f350fcb7e52e50aead5a56191..48a975134ac5fba0c3d2ab05a85ca0d035a3eb80 100644 (file)
@@ -45,6 +45,7 @@
 #include "dibx000_common.h"
 #include "zl10353.h"
 #include "stv0900.h"
+#include "stv0900_reg.h"
 #include "stv6110.h"
 #include "lnbh24.h"
 #include "cx24116.h"
@@ -242,12 +243,22 @@ static struct tda18271_std_map hauppauge_tda18271_std_map = {
                      .if_lvl = 6, .rfagc_top = 0x37 },
 };
 
+static struct tda18271_std_map hauppauge_hvr1200_tda18271_std_map = {
+       .dvbt_6   = { .if_freq = 3300, .agc_mode = 3, .std = 4,
+                     .if_lvl = 1, .rfagc_top = 0x37, },
+       .dvbt_7   = { .if_freq = 3800, .agc_mode = 3, .std = 5,
+                     .if_lvl = 1, .rfagc_top = 0x37, },
+       .dvbt_8   = { .if_freq = 4300, .agc_mode = 3, .std = 6,
+                     .if_lvl = 1, .rfagc_top = 0x37, },
+};
+
 static struct tda18271_config hauppauge_tda18271_config = {
        .std_map = &hauppauge_tda18271_std_map,
        .gate    = TDA18271_GATE_ANALOG,
 };
 
 static struct tda18271_config hauppauge_hvr1200_tuner_config = {
+       .std_map = &hauppauge_hvr1200_tda18271_std_map,
        .gate    = TDA18271_GATE_ANALOG,
 };
 
@@ -370,13 +381,25 @@ static struct zl10353_config dvico_fusionhdtv_xc3028 = {
        .disable_i2c_gate_ctrl = 1,
 };
 
+static struct stv0900_reg stv0900_ts_regs[] = {
+       { R0900_TSGENERAL, 0x00 },
+       { R0900_P1_TSSPEED, 0x40 },
+       { R0900_P2_TSSPEED, 0x40 },
+       { R0900_P1_TSCFGM, 0xc0 },
+       { R0900_P2_TSCFGM, 0xc0 },
+       { R0900_P1_TSCFGH, 0xe0 },
+       { R0900_P2_TSCFGH, 0xe0 },
+       { R0900_P1_TSCFGL, 0x20 },
+       { R0900_P2_TSCFGL, 0x20 },
+       { 0xffff, 0xff }, /* terminate */
+};
+
 static struct stv0900_config netup_stv0900_config = {
        .demod_address = 0x68,
        .xtal = 27000000,
        .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
        .diseqc_mode = 2,/* 2/3 PWM */
-       .path1_mode = 2,/*Serial continues clock */
-       .path2_mode = 2,/*Serial continues clock */
+       .ts_config_regs = stv0900_ts_regs,
        .tun1_maddress = 0,/* 0x60 */
        .tun2_maddress = 3,/* 0x63 */
        .tun1_adc = 1,/* 1 Vpp */
@@ -736,7 +759,8 @@ static int dvb_register(struct cx23885_tsport *port)
                                        if (!dvb_attach(lnbh24_attach,
                                                        fe0->dvb.frontend,
                                                        &i2c_bus->i2c_adap,
-                                                       LNBH24_PCL, 0, 0x09))
+                                                       LNBH24_PCL,
+                                                       LNBH24_TTX, 0x09))
                                                printk(KERN_ERR
                                                        "No LNBH24 found!\n");
 
@@ -756,7 +780,8 @@ static int dvb_register(struct cx23885_tsport *port)
                                        if (!dvb_attach(lnbh24_attach,
                                                        fe0->dvb.frontend,
                                                        &i2c_bus->i2c_adap,
-                                                       LNBH24_PCL, 0, 0x0a))
+                                                       LNBH24_PCL,
+                                                       LNBH24_TTX, 0x0a))
                                                printk(KERN_ERR
                                                        "No LNBH24 found!\n");
 
index 66bbd2e711057fba20904513ca102640dc425331..70836af3ab4891a624a87225d6ec0bf2cdd8cf32 100644 (file)
@@ -963,15 +963,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        }
 
        f->fmt.pix.field = field;
-       if (f->fmt.pix.height < 32)
-               f->fmt.pix.height = 32;
-       if (f->fmt.pix.height > maxh)
-               f->fmt.pix.height = maxh;
-       if (f->fmt.pix.width < 48)
-               f->fmt.pix.width = 48;
-       if (f->fmt.pix.width > maxw)
-               f->fmt.pix.width = maxw;
-       f->fmt.pix.width &= ~0x03;
+       v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2,
+                             &f->fmt.pix.height, 32, maxh, 0, 0);
        f->fmt.pix.bytesperline =
                (f->fmt.pix.width * fmt->depth) >> 3;
        f->fmt.pix.sizeimage =
index 94b7a52629d057c0bd5295ec7783388026484eae..a5cc1c1fc2d60c30329350a1ee1072c21efe68a5 100644 (file)
@@ -1524,33 +1524,45 @@ static const struct cx88_board cx88_boards[] = {
                },
                .mpeg           = CX88_MPEG_DVB,
        },
+       /* Terry Wu <terrywu2009@gmail.com> */
+       /* TV Audio :      set GPIO 2, 18, 19 value to 0, 1, 0 */
+       /* FM Audio :      set GPIO 2, 18, 19 value to 0, 0, 0 */
+       /* Line-in Audio : set GPIO 2, 18, 19 value to 0, 1, 1 */
+       /* Mute Audio :    set GPIO 2 value to 1               */
        [CX88_BOARD_WINFAST_TV2000_XP_GLOBAL] = {
-               .name           = "Winfast TV2000 XP Global",
+               .name           = "Leadtek TV2000 XP Global",
                .tuner_type     = TUNER_XC2028,
                .tuner_addr     = 0x61,
+               .radio_type     = TUNER_XC2028,
+               .radio_addr     = 0x61,
                .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
-                       .gpio0  = 0x0400, /* pin 2:mute = 0 (off?) */
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
                        .gpio1  = 0x0000,
-                       .gpio2  = 0x0800, /* pin 19:audio = 0 (tv) */
-
+                       .gpio2  = 0x0C04,       /* pin 18 = 1, pin 19 = 0 */
+                       .gpio3  = 0x0000,
                }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
-                       .gpio0  = 0x0400, /* probably?  or 0x0404 to turn mute on */
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
                        .gpio1  = 0x0000,
-                       .gpio2  = 0x0808, /* pin 19:audio = 1 (line) */
-
+                       .gpio2  = 0x0C0C,       /* pin 18 = 1, pin 19 = 1 */
+                       .gpio3  = 0x0000,
                }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x0000,
+                       .gpio2  = 0x0C0C,       /* pin 18 = 1, pin 19 = 1 */
+                       .gpio3  = 0x0000,
                } },
                .radio = {
                        .type   = CX88_RADIO,
-                       .gpio0  = 0x004ff,
-                       .gpio1  = 0x010ff,
-                       .gpio2  = 0x0ff,
+                       .gpio0  = 0x0400,        /* pin 2 = 0 */
+                       .gpio1  = 0x0000,
+                       .gpio2  = 0x0C00,       /* pin 18 = 0, pin 19 = 0 */
+                       .gpio3  = 0x0000,
                },
        },
        [CX88_BOARD_POWERCOLOR_REAL_ANGEL] = {
@@ -2438,6 +2450,41 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0x107d,
                .subdevice = 0x6654,
                .card      = CX88_BOARD_WINFAST_DTV1800H,
+       }, {
+               /* PVR2000 PAL Model [107d:6630] */
+               .subvendor = 0x107d,
+               .subdevice = 0x6630,
+               .card      = CX88_BOARD_LEADTEK_PVR2000,
+       }, {
+               /* PVR2000 PAL Model [107d:6638] */
+               .subvendor = 0x107d,
+               .subdevice = 0x6638,
+               .card      = CX88_BOARD_LEADTEK_PVR2000,
+       }, {
+               /* PVR2000 NTSC Model [107d:6631] */
+               .subvendor = 0x107d,
+               .subdevice = 0x6631,
+               .card      = CX88_BOARD_LEADTEK_PVR2000,
+       }, {
+               /* PVR2000 NTSC Model [107d:6637] */
+               .subvendor = 0x107d,
+               .subdevice = 0x6637,
+               .card      = CX88_BOARD_LEADTEK_PVR2000,
+       }, {
+               /* PVR2000 NTSC Model [107d:663d] */
+               .subvendor = 0x107d,
+               .subdevice = 0x663d,
+               .card      = CX88_BOARD_LEADTEK_PVR2000,
+       }, {
+               /* DV2000 NTSC Model [107d:6621] */
+               .subvendor = 0x107d,
+               .subdevice = 0x6621,
+               .card      = CX88_BOARD_WINFAST_DV2000,
+       }, {
+               /* TV2000 XP Global [107d:6618]  */
+               .subvendor = 0x107d,
+               .subdevice = 0x6618,
+               .card      = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL,
        },
 };
 
@@ -2446,12 +2493,6 @@ static const struct cx88_subid cx88_subids[] = {
 
 static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data)
 {
-       /* This is just for the "Winfast 2000XP Expert" board ATM; I don't have data on
-        * any others.
-        *
-        * Byte 0 is 1 on the NTSC board.
-        */
-
        if (eeprom_data[4] != 0x7d ||
            eeprom_data[5] != 0x10 ||
            eeprom_data[7] != 0x66) {
@@ -2459,8 +2500,19 @@ static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data)
                return;
        }
 
-       core->board.tuner_type = (eeprom_data[6] == 0x13) ?
-               TUNER_PHILIPS_FM1236_MK3 : TUNER_PHILIPS_FM1216ME_MK3;
+       /* Terry Wu <terrywu2009@gmail.com> */
+       switch (eeprom_data[6]) {
+       case 0x13: /* SSID 6613 for TV2000 XP Expert NTSC Model */
+       case 0x21: /* SSID 6621 for DV2000 NTSC Model */
+       case 0x31: /* SSID 6631 for PVR2000 NTSC Model */
+       case 0x37: /* SSID 6637 for PVR2000 NTSC Model */
+       case 0x3d: /* SSID 6637 for PVR2000 NTSC Model */
+               core->board.tuner_type = TUNER_PHILIPS_FM1236_MK3;
+               break;
+       default:
+               core->board.tuner_type = TUNER_PHILIPS_FM1216ME_MK3;
+               break;
+       }
 
        info_printk(core, "Leadtek Winfast 2000XP Expert config: "
                    "tuner=%d, eeprom[0]=0x%02x\n",
@@ -2713,7 +2765,6 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core,
 {
        /* Board-specific callbacks */
        switch (core->boardnr) {
-       case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
        case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
        case CX88_BOARD_GENIATECH_X8000_MT:
        case CX88_BOARD_KWORLD_ATSC_120:
@@ -2725,6 +2776,7 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core,
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
        case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
                return cx88_dvico_xc2028_callback(core, command, arg);
+       case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
        case CX88_BOARD_WINFAST_DTV1800H:
                return cx88_xc3028_winfast1800h_callback(core, command, arg);
        }
@@ -2914,6 +2966,7 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
                udelay(1000);
                break;
 
+       case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
        case CX88_BOARD_WINFAST_DTV1800H:
                /* GPIO 12 (xc3028 tuner reset) */
                cx_set(MO_GP1_IO, 0x1010);
@@ -2950,6 +3003,7 @@ void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl)
        case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
                ctl->demod = XC3028_FE_OREN538;
                break;
+       case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
        case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
        case CX88_BOARD_PROLINK_PV_8000GT:
                /*
@@ -2993,6 +3047,8 @@ static void cx88_card_setup(struct cx88_core *core)
                if (0 == core->i2c_rc)
                        gdi_eeprom(core, eeprom);
                break;
+       case CX88_BOARD_LEADTEK_PVR2000:
+       case CX88_BOARD_WINFAST_DV2000:
        case CX88_BOARD_WINFAST2000XP_EXPERT:
                if (0 == core->i2c_rc)
                        leadtek_eeprom(core, eeprom);
index 0ccac702bea4998e66dc30dfcac3aca9282390eb..b12770848c00161e5355fd05c0816fbb9e0c3134 100644 (file)
@@ -1111,15 +1111,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        }
 
        f->fmt.pix.field = field;
-       if (f->fmt.pix.height < 32)
-               f->fmt.pix.height = 32;
-       if (f->fmt.pix.height > maxh)
-               f->fmt.pix.height = maxh;
-       if (f->fmt.pix.width < 48)
-               f->fmt.pix.width = 48;
-       if (f->fmt.pix.width > maxw)
-               f->fmt.pix.width = maxw;
-       f->fmt.pix.width &= ~0x03;
+       v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2,
+                             &f->fmt.pix.height, 32, maxh, 0, 0);
        f->fmt.pix.bytesperline =
                (f->fmt.pix.width * fmt->depth) >> 3;
        f->fmt.pix.sizeimage =
index 00cc791a9e440a7524aefa017d872e5a1d08894b..c43fdb9bc88810c3f2f658f8cb3495d70940a3c2 100644 (file)
@@ -139,6 +139,24 @@ static struct em28xx_reg_seq kworld_330u_digital[] = {
        { -1,                   -1,     -1,             -1},
 };
 
+/* Evga inDtube
+   GPIO0 - Enable digital power (s5h1409) - low to enable
+   GPIO1 - Enable analog power (tvp5150/emp202) - low to enable
+   GPIO4 - xc3028 reset
+   GOP3  - s5h1409 reset
+ */
+static struct em28xx_reg_seq evga_indtube_analog[] = {
+       {EM28XX_R08_GPIO,       0x79,   0xff,           60},
+       {       -1,             -1,     -1,             -1},
+};
+
+static struct em28xx_reg_seq evga_indtube_digital[] = {
+       {EM28XX_R08_GPIO,       0x7a,   0xff,            1},
+       {EM2880_R04_GPO,        0x04,   0xff,           10},
+       {EM2880_R04_GPO,        0x0c,   0xff,            1},
+       { -1,                   -1,     -1,             -1},
+};
+
 /* Callback for the most boards */
 static struct em28xx_reg_seq default_tuner_gpio[] = {
        {EM28XX_R08_GPIO,       EM_GPIO_4,      EM_GPIO_4,      10},
@@ -1449,6 +1467,33 @@ struct em28xx_board em28xx_boards[] = {
                        .gpio     = terratec_av350_unmute_gpio,
                } },
        },
+       [EM2882_BOARD_EVGA_INDTUBE] = {
+               .name         = "Evga inDtube",
+               .tuner_type   = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
+               .decoder      = EM28XX_TVP5150,
+               .xclk         = EM28XX_XCLK_FREQUENCY_12MHZ, /* NEC IR */
+               .mts_firmware = 1,
+               .has_dvb      = 1,
+               .dvb_gpio     = evga_indtube_digital,
+               .ir_codes     = ir_codes_evga_indtube,
+               .input        = { {
+                       .type     = EM28XX_VMUX_TELEVISION,
+                       .vmux     = TVP5150_COMPOSITE0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = evga_indtube_analog,
+               }, {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = TVP5150_COMPOSITE1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = evga_indtube_analog,
+               }, {
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = TVP5150_SVIDEO,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = evga_indtube_analog,
+               } },
+       },
 };
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
@@ -1571,6 +1616,7 @@ static struct em28xx_hash_table em28xx_eeprom_hash[] = {
        {0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF},
        {0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028},
        {0x9567eb1a, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028},
+       {0xcee44a99, EM2882_BOARD_EVGA_INDTUBE, TUNER_XC2028},
 };
 
 /* I2C devicelist hash table for devices with generic USB IDs */
@@ -1834,6 +1880,10 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
                ctl->demod = XC3028_FE_CHINA;
                ctl->fname = XC2028_DEFAULT_FIRMWARE;
                break;
+       case EM2882_BOARD_EVGA_INDTUBE:
+               ctl->demod = XC3028_FE_CHINA;
+               ctl->fname = XC3028L_DEFAULT_FIRMWARE;
+               break;
        default:
                ctl->demod = XC3028_FE_OREN538;
        }
@@ -2101,6 +2151,12 @@ void em28xx_card_setup(struct em28xx *dev)
        case EM2880_BOARD_MSI_DIGIVOX_AD:
                if (!em28xx_hint_board(dev))
                        em28xx_set_model(dev);
+
+               /* In cases where we had to use a board hint, the call to
+                  em28xx_set_mode() in em28xx_pre_card_setup() was a no-op,
+                  so make the call now so the analog GPIOs are set properly
+                  before probing the i2c bus. */
+               em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
                break;
        }
 
index 563dd2b1c8e90e8d9efc0f8f4b967eb8b0fb7bdb..e7b47c8da8f3e7732208d666d952391717526883 100644 (file)
@@ -445,6 +445,7 @@ static int dvb_init(struct em28xx *dev)
                }
                break;
        case EM2883_BOARD_KWORLD_HYBRID_330U:
+       case EM2882_BOARD_EVGA_INDTUBE:
                dvb->frontend = dvb_attach(s5h1409_attach,
                                           &em28xx_s5h1409_with_xc3028,
                                           &dev->i2c_adap);
index 882796e84dbc7c9da7a1c8d26075d17726060ff1..8fe1beecfffac0919d40a31e713510bad33d2559 100644 (file)
@@ -687,8 +687,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 {
        struct em28xx_fh      *fh    = priv;
        struct em28xx         *dev   = fh->dev;
-       int                   width  = f->fmt.pix.width;
-       int                   height = f->fmt.pix.height;
+       unsigned int          width  = f->fmt.pix.width;
+       unsigned int          height = f->fmt.pix.height;
        unsigned int          maxw   = norm_maxw(dev);
        unsigned int          maxh   = norm_maxh(dev);
        unsigned int          hscale, vscale;
@@ -701,34 +701,20 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                return -EINVAL;
        }
 
-       /* width must even because of the YUYV format
-          height must be even because of interlacing */
-       height &= 0xfffe;
-       width  &= 0xfffe;
-
-       if (unlikely(height < 32))
-               height = 32;
-       if (unlikely(height > maxh))
-               height = maxh;
-       if (unlikely(width < 48))
-               width = 48;
-       if (unlikely(width > maxw))
-               width = maxw;
-
        if (dev->board.is_em2800) {
                /* the em2800 can only scale down to 50% */
-               if (height % (maxh / 2))
-                       height = maxh;
-               if (width % (maxw / 2))
-                       width = maxw;
-               /* according to empiatech support */
-               /* the MaxPacketSize is to small to support */
-               /* framesizes larger than 640x480 @ 30 fps */
-               /* or 640x576 @ 25 fps. As this would cut */
-               /* of a part of the image we prefer */
-               /* 360x576 or 360x480 for now */
+               height = height > (3 * maxh / 4) ? maxh : maxh / 2;
+               width = width > (3 * maxw / 4) ? maxw : maxw / 2;
+               /* According to empiatech support the MaxPacketSize is too small
+                * to support framesizes larger than 640x480 @ 30 fps or 640x576
+                * @ 25 fps.  As this would cut of a part of the image we prefer
+                * 360x576 or 360x480 for now */
                if (width == maxw && height == maxh)
                        width /= 2;
+       } else {
+               /* width must even because of the YUYV format
+                  height must be even because of interlacing */
+               v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0);
        }
 
        get_scale(dev, width, height, &hscale, &vscale);
index 8bf81be1da615eee54c89d5961e19283dd8ef64c..813ce45c2f997286f0df6fb99f1b718a491753ab 100644 (file)
 #define EM2860_BOARD_TERRATEC_GRABBY             67
 #define EM2860_BOARD_TERRATEC_AV350              68
 #define EM2882_BOARD_KWORLD_ATSC_315U            69
+#define EM2882_BOARD_EVGA_INDTUBE                70
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
index f7e0355ad644f5181bcdbbd36bb3fa1b9483f82e..1e89600986c89bd3ce19e2bf8a2d3f78c1ccd097 100644 (file)
@@ -1042,13 +1042,11 @@ static int vidioc_queryctrl(struct file *file, void *priv,
                for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
                        if (gspca_dev->ctrl_dis & (1 << i))
                                continue;
-                       if (ctrls->qctrl.id < id)
+                       if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id)
                                continue;
-                       if (ctrls != NULL) {
-                               if (gspca_dev->sd_desc->ctrls[i].qctrl.id
+                       if (ctrls && gspca_dev->sd_desc->ctrls[i].qctrl.id
                                            > ctrls->qctrl.id)
-                                       continue;
-                       }
+                               continue;
                        ctrls = &gspca_dev->sd_desc->ctrls[i];
                }
        } else {
index 188866ac6cefb8b96045ad497fecfbb3e32421b9..2f6e135d94bc66cca7cab1319cfb673f4ee9b1f9 100644 (file)
@@ -50,12 +50,18 @@ static int i2c_detect_tries = 10;
 struct sd {
        struct gspca_dev gspca_dev;             /* !! must be the first item */
 
+       __u8 packet_nr;
+
        char bridge;
 #define BRIDGE_OV511           0
 #define BRIDGE_OV511PLUS       1
 #define BRIDGE_OV518           2
 #define BRIDGE_OV518PLUS       3
 #define BRIDGE_OV519           4
+#define BRIDGE_MASK            7
+
+       char invert_led;
+#define BRIDGE_INVERT_LED      8
 
        /* Determined by sensor type */
        __u8 sif;
@@ -65,22 +71,25 @@ struct sd {
        __u8 colors;
        __u8 hflip;
        __u8 vflip;
+       __u8 autobrightness;
+       __u8 freq;
 
        __u8 stopped;           /* Streaming is temporarily paused */
 
-       __u8 frame_rate;        /* current Framerate (OV519 only) */
-       __u8 clockdiv;          /* clockdiv override for OV519 only */
+       __u8 frame_rate;        /* current Framerate */
+       __u8 clockdiv;          /* clockdiv override */
 
        char sensor;            /* Type of image sensor chip (SEN_*) */
 #define SEN_UNKNOWN 0
 #define SEN_OV6620 1
 #define SEN_OV6630 2
-#define SEN_OV7610 3
-#define SEN_OV7620 4
-#define SEN_OV7640 5
-#define SEN_OV7670 6
-#define SEN_OV76BE 7
-#define SEN_OV8610 8
+#define SEN_OV66308AF 3
+#define SEN_OV7610 4
+#define SEN_OV7620 5
+#define SEN_OV7640 6
+#define SEN_OV7670 7
+#define SEN_OV76BE 8
+#define SEN_OV8610 9
 };
 
 /* V4L2 controls supported by the driver */
@@ -94,11 +103,17 @@ 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_setautobrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautobrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
 static void setbrightness(struct gspca_dev *gspca_dev);
 static void setcontrast(struct gspca_dev *gspca_dev);
 static void setcolors(struct gspca_dev *gspca_dev);
+static void setautobrightness(struct sd *sd);
+static void setfreq(struct sd *sd);
 
-static struct ctrl sd_ctrls[] = {
+static const struct ctrl sd_ctrls[] = {
        {
            {
                .id      = V4L2_CID_BRIGHTNESS,
@@ -141,7 +156,7 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setcolors,
            .get = sd_getcolors,
        },
-/* next controls work with ov7670 only */
+/* The flip controls work with ov7670 only */
 #define HFLIP_IDX 3
        {
            {
@@ -172,6 +187,51 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setvflip,
            .get = sd_getvflip,
        },
+#define AUTOBRIGHT_IDX 5
+       {
+           {
+               .id      = V4L2_CID_AUTOBRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Auto Brightness",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+#define AUTOBRIGHT_DEF 1
+               .default_value = AUTOBRIGHT_DEF,
+           },
+           .set = sd_setautobrightness,
+           .get = sd_getautobrightness,
+       },
+#define FREQ_IDX 6
+       {
+           {
+               .id      = V4L2_CID_POWER_LINE_FREQUENCY,
+               .type    = V4L2_CTRL_TYPE_MENU,
+               .name    = "Light frequency filter",
+               .minimum = 0,
+               .maximum = 2,   /* 0: 0, 1: 50Hz, 2:60Hz */
+               .step    = 1,
+#define FREQ_DEF 0
+               .default_value = FREQ_DEF,
+           },
+           .set = sd_setfreq,
+           .get = sd_getfreq,
+       },
+#define OV7670_FREQ_IDX 7
+       {
+           {
+               .id      = V4L2_CID_POWER_LINE_FREQUENCY,
+               .type    = V4L2_CTRL_TYPE_MENU,
+               .name    = "Light frequency filter",
+               .minimum = 0,
+               .maximum = 3,   /* 0: 0, 1: 50Hz, 2:60Hz 3: Auto Hz */
+               .step    = 1,
+#define OV7670_FREQ_DEF 3
+               .default_value = OV7670_FREQ_DEF,
+           },
+           .set = sd_setfreq,
+           .get = sd_getfreq,
+       },
 };
 
 static const struct v4l2_pix_format ov519_vga_mode[] = {
@@ -187,11 +247,21 @@ static const struct v4l2_pix_format ov519_vga_mode[] = {
                .priv = 0},
 };
 static const struct v4l2_pix_format ov519_sif_mode[] = {
+       {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 160,
+               .sizeimage = 160 * 120 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 3},
        {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 176,
                .sizeimage = 176 * 144 * 3 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 1},
+       {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 2},
        {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 352,
                .sizeimage = 352 * 288 * 3 / 8 + 590,
@@ -199,42 +269,118 @@ static const struct v4l2_pix_format ov519_sif_mode[] = {
                .priv = 0},
 };
 
+/* Note some of the sizeimage values for the ov511 / ov518 may seem
+   larger then necessary, however they need to be this big as the ov511 /
+   ov518 always fills the entire isoc frame, using 0 padding bytes when
+   it doesn't have any data. So with low framerates the amount of data
+   transfered can become quite large (libv4l will remove all the 0 padding
+   in userspace). */
 static const struct v4l2_pix_format ov518_vga_mode[] = {
        {320, 240, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
                .bytesperline = 320,
-               .sizeimage = 320 * 240 * 3 / 8 + 590,
+               .sizeimage = 320 * 240 * 3,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 1},
        {640, 480, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
                .bytesperline = 640,
-               .sizeimage = 640 * 480 * 3 / 8 + 590,
+               .sizeimage = 640 * 480 * 2,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 0},
 };
 static const struct v4l2_pix_format ov518_sif_mode[] = {
+       {160, 120, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+               .bytesperline = 160,
+               .sizeimage = 70000,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 3},
        {176, 144, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
                .bytesperline = 176,
-               .sizeimage = 40000,
+               .sizeimage = 70000,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 1},
+       {320, 240, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 3,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 2},
        {352, 288, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
                .bytesperline = 352,
-               .sizeimage = 352 * 288 * 3 / 8 + 590,
+               .sizeimage = 352 * 288 * 3,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 0},
 };
 
+static const struct v4l2_pix_format ov511_vga_mode[] = {
+       {320, 240, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 3,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 1},
+       {640, 480, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480 * 2,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 0},
+};
+static const struct v4l2_pix_format ov511_sif_mode[] = {
+       {160, 120, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE,
+               .bytesperline = 160,
+               .sizeimage = 70000,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 3},
+       {176, 144, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE,
+               .bytesperline = 176,
+               .sizeimage = 70000,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 1},
+       {320, 240, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 3,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 2},
+       {352, 288, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE,
+               .bytesperline = 352,
+               .sizeimage = 352 * 288 * 3,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 0},
+};
 
 /* Registers common to OV511 / OV518 */
+#define R51x_FIFO_PSIZE                        0x30    /* 2 bytes wide w/ OV518(+) */
 #define R51x_SYS_RESET                 0x50
+       /* Reset type flags */
+       #define OV511_RESET_OMNICE      0x08
 #define R51x_SYS_INIT                  0x53
 #define R51x_SYS_SNAP                  0x52
 #define R51x_SYS_CUST_ID               0x5F
 #define R51x_COMP_LUT_BEGIN            0x80
 
 /* OV511 Camera interface register numbers */
+#define R511_CAM_DELAY                 0x10
+#define R511_CAM_EDGE                  0x11
+#define R511_CAM_PXCNT                 0x12
+#define R511_CAM_LNCNT                 0x13
+#define R511_CAM_PXDIV                 0x14
+#define R511_CAM_LNDIV                 0x15
+#define R511_CAM_UV_EN                 0x16
+#define R511_CAM_LINE_MODE             0x17
+#define R511_CAM_OPTS                  0x18
+
+#define R511_SNAP_FRAME                        0x19
+#define R511_SNAP_PXCNT                        0x1A
+#define R511_SNAP_LNCNT                        0x1B
+#define R511_SNAP_PXDIV                        0x1C
+#define R511_SNAP_LNDIV                        0x1D
+#define R511_SNAP_UV_EN                        0x1E
+#define R511_SNAP_UV_EN                        0x1E
+#define R511_SNAP_OPTS                 0x1F
+
+#define R511_DRAM_FLOW_CTL             0x20
+#define R511_FIFO_OPTS                 0x31
+#define R511_I2C_CTL                   0x40
 #define R511_SYS_LED_CTL               0x55    /* OV511+ only */
-#define        OV511_RESET_NOREGS              0x3F    /* All but OV511 & regs */
+#define R511_COMP_EN                   0x78
+#define R511_COMP_LUT_EN               0x79
 
 /* OV518 Camera interface register numbers */
 #define R518_GPIO_OUT                  0x56    /* OV518(+) only */
@@ -383,7 +529,7 @@ static const struct ov_i2c_regvals norm_6x20[] = {
        { 0x28, 0x05 },
        { 0x2a, 0x04 }, /* Disable framerate adjust */
 /*     { 0x2b, 0xac },  * Framerate; Set 2a[7] first */
-       { 0x2d, 0x99 },
+       { 0x2d, 0x85 },
        { 0x33, 0xa0 }, /* Color Processing Parameter */
        { 0x34, 0xd2 }, /* Max A/D range */
        { 0x38, 0x8b },
@@ -416,7 +562,7 @@ static const struct ov_i2c_regvals norm_6x30[] = {
        { 0x07, 0x2d }, /* Sharpness */
        { 0x0c, 0x20 },
        { 0x0d, 0x20 },
-       { 0x0e, 0x20 },
+       { 0x0e, 0xa0 }, /* Was 0x20, bit7 enables a 2x gain which we need */
        { 0x0f, 0x05 },
        { 0x10, 0x9a },
        { 0x11, 0x00 }, /* Pixel clock = fastest */
@@ -558,7 +704,7 @@ static const struct ov_i2c_regvals norm_7620[] = {
        { 0x23, 0x00 },
        { 0x26, 0xa2 },
        { 0x27, 0xea },
-       { 0x28, 0x20 },
+       { 0x28, 0x22 }, /* Was 0x20, bit1 enables a 2x gain which we need */
        { 0x29, 0x00 },
        { 0x2a, 0x10 },
        { 0x2b, 0x00 },
@@ -999,13 +1145,128 @@ static int ov518_reg_w32(struct sd *sd, __u16 index, u32 value, int n)
        return ret;
 }
 
+static int ov511_i2c_w(struct sd *sd, __u8 reg, __u8 value)
+{
+       int rc, retries;
+
+       PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
+
+       /* Three byte write cycle */
+       for (retries = 6; ; ) {
+               /* Select camera register */
+               rc = reg_w(sd, R51x_I2C_SADDR_3, reg);
+               if (rc < 0)
+                       return rc;
+
+               /* Write "value" to I2C data port of OV511 */
+               rc = reg_w(sd, R51x_I2C_DATA, value);
+               if (rc < 0)
+                       return rc;
+
+               /* Initiate 3-byte write cycle */
+               rc = reg_w(sd, R511_I2C_CTL, 0x01);
+               if (rc < 0)
+                       return rc;
+
+               do
+                       rc = reg_r(sd, R511_I2C_CTL);
+               while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */
+
+               if (rc < 0)
+                       return rc;
+
+               if ((rc & 2) == 0) /* Ack? */
+                       break;
+               if (--retries < 0) {
+                       PDEBUG(D_USBO, "i2c write retries exhausted");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int ov511_i2c_r(struct sd *sd, __u8 reg)
+{
+       int rc, value, retries;
+
+       /* Two byte write cycle */
+       for (retries = 6; ; ) {
+               /* Select camera register */
+               rc = reg_w(sd, R51x_I2C_SADDR_2, reg);
+               if (rc < 0)
+                       return rc;
+
+               /* Initiate 2-byte write cycle */
+               rc = reg_w(sd, R511_I2C_CTL, 0x03);
+               if (rc < 0)
+                       return rc;
+
+               do
+                       rc = reg_r(sd, R511_I2C_CTL);
+               while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */
+
+               if (rc < 0)
+                       return rc;
+
+               if ((rc & 2) == 0) /* Ack? */
+                       break;
+
+               /* I2C abort */
+               reg_w(sd, R511_I2C_CTL, 0x10);
+
+               if (--retries < 0) {
+                       PDEBUG(D_USBI, "i2c write retries exhausted");
+                       return -1;
+               }
+       }
+
+       /* Two byte read cycle */
+       for (retries = 6; ; ) {
+               /* Initiate 2-byte read cycle */
+               rc = reg_w(sd, R511_I2C_CTL, 0x05);
+               if (rc < 0)
+                       return rc;
+
+               do
+                       rc = reg_r(sd, R511_I2C_CTL);
+               while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */
+
+               if (rc < 0)
+                       return rc;
+
+               if ((rc & 2) == 0) /* Ack? */
+                       break;
+
+               /* I2C abort */
+               rc = reg_w(sd, R511_I2C_CTL, 0x10);
+               if (rc < 0)
+                       return rc;
+
+               if (--retries < 0) {
+                       PDEBUG(D_USBI, "i2c read retries exhausted");
+                       return -1;
+               }
+       }
+
+       value = reg_r(sd, R51x_I2C_DATA);
+
+       PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value);
+
+       /* This is needed to make i2c_w() work */
+       rc = reg_w(sd, R511_I2C_CTL, 0x05);
+       if (rc < 0)
+               return rc;
+
+       return value;
+}
 
 /*
  * The OV518 I2C I/O procedure is different, hence, this function.
  * This is normally only called from i2c_w(). Note that this function
  * always succeeds regardless of whether the sensor is present and working.
  */
-static int i2c_w(struct sd *sd,
+static int ov518_i2c_w(struct sd *sd,
                __u8 reg,
                __u8 value)
 {
@@ -1040,7 +1301,7 @@ static int i2c_w(struct sd *sd,
  * This is normally only called from i2c_r(). Note that this function
  * always succeeds regardless of whether the sensor is present and working.
  */
-static int i2c_r(struct sd *sd, __u8 reg)
+static int ov518_i2c_r(struct sd *sd, __u8 reg)
 {
        int rc, value;
 
@@ -1063,6 +1324,34 @@ static int i2c_r(struct sd *sd, __u8 reg)
        return value;
 }
 
+static int i2c_w(struct sd *sd, __u8 reg, __u8 value)
+{
+       switch (sd->bridge) {
+       case BRIDGE_OV511:
+       case BRIDGE_OV511PLUS:
+               return ov511_i2c_w(sd, reg, value);
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+       case BRIDGE_OV519:
+               return ov518_i2c_w(sd, reg, value);
+       }
+       return -1; /* Should never happen */
+}
+
+static int i2c_r(struct sd *sd, __u8 reg)
+{
+       switch (sd->bridge) {
+       case BRIDGE_OV511:
+       case BRIDGE_OV511PLUS:
+               return ov511_i2c_r(sd, reg);
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+       case BRIDGE_OV519:
+               return ov518_i2c_r(sd, reg);
+       }
+       return -1; /* Should never happen */
+}
+
 /* Writes bits at positions specified by mask to an I2C reg. Bits that are in
  * the same position as 1's in "mask" are cleared and set to "value". Bits
  * that are in the same position as 0's in "mask" are preserved, regardless
@@ -1242,7 +1531,6 @@ static int ov8xx0_configure(struct sd *sd)
        }
 
        /* Set sensor-specific vars */
-/*     sd->sif = 0;            already done */
        return 0;
 }
 
@@ -1279,15 +1567,13 @@ static int ov7xx0_configure(struct sd *sd)
                }
        } else if ((rc & 3) == 1) {
                /* I don't know what's different about the 76BE yet. */
-               if (i2c_r(sd, 0x15) & 1)
+               if (i2c_r(sd, 0x15) & 1) {
                        PDEBUG(D_PROBE, "Sensor is an OV7620AE");
-               else
+                       sd->sensor = SEN_OV7620;
+               } else {
                        PDEBUG(D_PROBE, "Sensor is an OV76BE");
-
-               /* OV511+ will return all zero isoc data unless we
-                * configure the sensor as a 7620. Someone needs to
-                * find the exact reg. setting that causes this. */
-               sd->sensor = SEN_OV76BE;
+                       sd->sensor = SEN_OV76BE;
+               }
        } else if ((rc & 3) == 0) {
                /* try to read product id registers */
                high = i2c_r(sd, 0x0a);
@@ -1333,7 +1619,6 @@ static int ov7xx0_configure(struct sd *sd)
        }
 
        /* Set sensor-specific vars */
-/*     sd->sif = 0;            already done */
        return 0;
 }
 
@@ -1362,13 +1647,14 @@ static int ov6xx0_configure(struct sd *sd)
                break;
        case 0x01:
                sd->sensor = SEN_OV6620;
+               PDEBUG(D_PROBE, "Sensor is an OV6620");
                break;
        case 0x02:
                sd->sensor = SEN_OV6630;
                PDEBUG(D_PROBE, "Sensor is an OV66308AE");
                break;
        case 0x03:
-               sd->sensor = SEN_OV6630;
+               sd->sensor = SEN_OV66308AF;
                PDEBUG(D_PROBE, "Sensor is an OV66308AF");
                break;
        case 0x90:
@@ -1391,6 +1677,9 @@ static int ov6xx0_configure(struct sd *sd)
 /* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */
 static void ov51x_led_control(struct sd *sd, int on)
 {
+       if (sd->invert_led)
+               on = !on;
+
        switch (sd->bridge) {
        /* OV511 has no LED control */
        case BRIDGE_OV511PLUS:
@@ -1406,9 +1695,31 @@ static void ov51x_led_control(struct sd *sd, int on)
        }
 }
 
-/* OV518 quantization tables are 8x4 (instead of 8x8) */
-static int ov518_upload_quan_tables(struct sd *sd)
+static int ov51x_upload_quan_tables(struct sd *sd)
 {
+       const unsigned char yQuanTable511[] = {
+               0, 1, 1, 2, 2, 3, 3, 4,
+               1, 1, 1, 2, 2, 3, 4, 4,
+               1, 1, 2, 2, 3, 4, 4, 4,
+               2, 2, 2, 3, 4, 4, 4, 4,
+               2, 2, 3, 4, 4, 5, 5, 5,
+               3, 3, 4, 4, 5, 5, 5, 5,
+               3, 4, 4, 4, 5, 5, 5, 5,
+               4, 4, 4, 4, 5, 5, 5, 5
+       };
+
+       const unsigned char uvQuanTable511[] = {
+               0, 2, 2, 3, 4, 4, 4, 4,
+               2, 2, 2, 4, 4, 4, 4, 4,
+               2, 2, 3, 4, 4, 4, 4, 4,
+               3, 4, 4, 4, 4, 4, 4, 4,
+               4, 4, 4, 4, 4, 4, 4, 4,
+               4, 4, 4, 4, 4, 4, 4, 4,
+               4, 4, 4, 4, 4, 4, 4, 4,
+               4, 4, 4, 4, 4, 4, 4, 4
+       };
+
+       /* OV518 quantization tables are 8x4 (instead of 8x8) */
        const unsigned char yQuanTable518[] = {
                5, 4, 5, 6, 6, 7, 7, 7,
                5, 5, 5, 5, 6, 7, 7, 7,
@@ -1423,14 +1734,23 @@ static int ov518_upload_quan_tables(struct sd *sd)
                7, 7, 7, 7, 7, 7, 8, 8
        };
 
-       const unsigned char *pYTable = yQuanTable518;
-       const unsigned char *pUVTable = uvQuanTable518;
+       const unsigned char *pYTable, *pUVTable;
        unsigned char val0, val1;
-       int i, rc, reg = R51x_COMP_LUT_BEGIN;
+       int i, size, rc, reg = R51x_COMP_LUT_BEGIN;
 
        PDEBUG(D_PROBE, "Uploading quantization tables");
 
-       for (i = 0; i < 16; i++) {
+       if (sd->bridge == BRIDGE_OV511 || sd->bridge == BRIDGE_OV511PLUS) {
+               pYTable = yQuanTable511;
+               pUVTable = uvQuanTable511;
+               size  = 32;
+       } else {
+               pYTable = yQuanTable518;
+               pUVTable = uvQuanTable518;
+               size  = 16;
+       }
+
+       for (i = 0; i < size; i++) {
                val0 = *pYTable++;
                val1 = *pYTable++;
                val0 &= 0x0f;
@@ -1445,7 +1765,7 @@ static int ov518_upload_quan_tables(struct sd *sd)
                val0 &= 0x0f;
                val1 &= 0x0f;
                val0 |= val1 << 4;
-               rc = reg_w(sd, reg + 16, val0);
+               rc = reg_w(sd, reg + size, val0);
                if (rc < 0)
                        return rc;
 
@@ -1455,6 +1775,87 @@ static int ov518_upload_quan_tables(struct sd *sd)
        return 0;
 }
 
+/* This initializes the OV511/OV511+ and the sensor */
+static int ov511_configure(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int rc;
+
+       /* For 511 and 511+ */
+       const struct ov_regvals init_511[] = {
+               { R51x_SYS_RESET,       0x7f },
+               { R51x_SYS_INIT,        0x01 },
+               { R51x_SYS_RESET,       0x7f },
+               { R51x_SYS_INIT,        0x01 },
+               { R51x_SYS_RESET,       0x3f },
+               { R51x_SYS_INIT,        0x01 },
+               { R51x_SYS_RESET,       0x3d },
+       };
+
+       const struct ov_regvals norm_511[] = {
+               { R511_DRAM_FLOW_CTL,   0x01 },
+               { R51x_SYS_SNAP,        0x00 },
+               { R51x_SYS_SNAP,        0x02 },
+               { R51x_SYS_SNAP,        0x00 },
+               { R511_FIFO_OPTS,       0x1f },
+               { R511_COMP_EN,         0x00 },
+               { R511_COMP_LUT_EN,     0x03 },
+       };
+
+       const struct ov_regvals norm_511_p[] = {
+               { R511_DRAM_FLOW_CTL,   0xff },
+               { R51x_SYS_SNAP,        0x00 },
+               { R51x_SYS_SNAP,        0x02 },
+               { R51x_SYS_SNAP,        0x00 },
+               { R511_FIFO_OPTS,       0xff },
+               { R511_COMP_EN,         0x00 },
+               { R511_COMP_LUT_EN,     0x03 },
+       };
+
+       const struct ov_regvals compress_511[] = {
+               { 0x70, 0x1f },
+               { 0x71, 0x05 },
+               { 0x72, 0x06 },
+               { 0x73, 0x06 },
+               { 0x74, 0x14 },
+               { 0x75, 0x03 },
+               { 0x76, 0x04 },
+               { 0x77, 0x04 },
+       };
+
+       PDEBUG(D_PROBE, "Device custom id %x", reg_r(sd, R51x_SYS_CUST_ID));
+
+       rc = write_regvals(sd, init_511, ARRAY_SIZE(init_511));
+       if (rc < 0)
+               return rc;
+
+       switch (sd->bridge) {
+       case BRIDGE_OV511:
+               rc = write_regvals(sd, norm_511, ARRAY_SIZE(norm_511));
+               if (rc < 0)
+                       return rc;
+               break;
+       case BRIDGE_OV511PLUS:
+               rc = write_regvals(sd, norm_511_p, ARRAY_SIZE(norm_511_p));
+               if (rc < 0)
+                       return rc;
+               break;
+       }
+
+       /* Init compression */
+       rc = write_regvals(sd, compress_511, ARRAY_SIZE(compress_511));
+       if (rc < 0)
+               return rc;
+
+       rc = ov51x_upload_quan_tables(sd);
+       if (rc < 0) {
+               PDEBUG(D_ERR, "Error uploading quantization tables");
+               return rc;
+       }
+
+       return 0;
+}
+
 /* This initializes the OV518/OV518+ and the sensor */
 static int ov518_configure(struct gspca_dev *gspca_dev)
 {
@@ -1462,7 +1863,7 @@ static int ov518_configure(struct gspca_dev *gspca_dev)
        int rc;
 
        /* For 518 and 518+ */
-       static struct ov_regvals init_518[] = {
+       const struct ov_regvals init_518[] = {
                { R51x_SYS_RESET,       0x40 },
                { R51x_SYS_INIT,        0xe1 },
                { R51x_SYS_RESET,       0x3e },
@@ -1473,7 +1874,7 @@ static int ov518_configure(struct gspca_dev *gspca_dev)
                { 0x5d,                 0x03 },
        };
 
-       static struct ov_regvals norm_518[] = {
+       const struct ov_regvals norm_518[] = {
                { R51x_SYS_SNAP,        0x02 }, /* Reset */
                { R51x_SYS_SNAP,        0x01 }, /* Enable */
                { 0x31,                 0x0f },
@@ -1486,7 +1887,7 @@ static int ov518_configure(struct gspca_dev *gspca_dev)
                { 0x2f,                 0x80 },
        };
 
-       static struct ov_regvals norm_518_p[] = {
+       const struct ov_regvals norm_518_p[] = {
                { R51x_SYS_SNAP,        0x02 }, /* Reset */
                { R51x_SYS_SNAP,        0x01 }, /* Enable */
                { 0x31,                 0x0f },
@@ -1531,7 +1932,7 @@ static int ov518_configure(struct gspca_dev *gspca_dev)
                break;
        }
 
-       rc = ov518_upload_quan_tables(sd);
+       rc = ov51x_upload_quan_tables(sd);
        if (rc < 0) {
                PDEBUG(D_ERR, "Error uploading quantization tables");
                return rc;
@@ -1573,9 +1974,14 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct cam *cam;
        int ret = 0;
 
-       sd->bridge = id->driver_info;
+       sd->bridge = id->driver_info & BRIDGE_MASK;
+       sd->invert_led = id->driver_info & BRIDGE_INVERT_LED;
 
        switch (sd->bridge) {
+       case BRIDGE_OV511:
+       case BRIDGE_OV511PLUS:
+               ret = ov511_configure(gspca_dev);
+               break;
        case BRIDGE_OV518:
        case BRIDGE_OV518PLUS:
                ret = ov518_configure(gspca_dev);
@@ -1634,6 +2040,16 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
        cam = &gspca_dev->cam;
        switch (sd->bridge) {
+       case BRIDGE_OV511:
+       case BRIDGE_OV511PLUS:
+               if (!sd->sif) {
+                       cam->cam_mode = ov511_vga_mode;
+                       cam->nmodes = ARRAY_SIZE(ov511_vga_mode);
+               } else {
+                       cam->cam_mode = ov511_sif_mode;
+                       cam->nmodes = ARRAY_SIZE(ov511_sif_mode);
+               }
+               break;
        case BRIDGE_OV518:
        case BRIDGE_OV518PLUS:
                if (!sd->sif) {
@@ -1655,13 +2071,28 @@ static int sd_config(struct gspca_dev *gspca_dev,
                break;
        }
        sd->brightness = BRIGHTNESS_DEF;
-       sd->contrast = CONTRAST_DEF;
+       if (sd->sensor == SEN_OV6630 || sd->sensor == SEN_OV66308AF)
+               sd->contrast = 200; /* The default is too low for the ov6630 */
+       else
+               sd->contrast = CONTRAST_DEF;
        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);
+       sd->autobrightness = AUTOBRIGHT_DEF;
+       if (sd->sensor == SEN_OV7670) {
+               sd->freq = OV7670_FREQ_DEF;
+               gspca_dev->ctrl_dis = 1 << FREQ_IDX;
+       } else {
+               sd->freq = FREQ_DEF;
+               gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) |
+                                     (1 << OV7670_FREQ_IDX);
+       }
+       if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7670)
+               gspca_dev->ctrl_dis |= 1 << AUTOBRIGHT_IDX;
+       /* OV8610 Frequency filter control should work but needs testing */
+       if (sd->sensor == SEN_OV8610)
+               gspca_dev->ctrl_dis |= 1 << FREQ_IDX;
+
        return 0;
 error:
        PDEBUG(D_ERR, "OV519 Config failed");
@@ -1680,6 +2111,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
                        return -EIO;
                break;
        case SEN_OV6630:
+       case SEN_OV66308AF:
                if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30)))
                        return -EIO;
                break;
@@ -1688,6 +2120,8 @@ static int sd_init(struct gspca_dev *gspca_dev)
 /*     case SEN_OV76BE: */
                if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610)))
                        return -EIO;
+               if (i2c_w_mask(sd, 0x0e, 0x00, 0x40))
+                       return -EIO;
                break;
        case SEN_OV7620:
                if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620)))
@@ -1709,6 +2143,126 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
+/* Set up the OV511/OV511+ with the given image parameters.
+ *
+ * Do not put any sensor-specific code in here (including I2C I/O functions)
+ */
+static int ov511_mode_init_regs(struct sd *sd)
+{
+       int hsegs, vsegs, packet_size, fps, needed;
+       int interlaced = 0;
+       struct usb_host_interface *alt;
+       struct usb_interface *intf;
+
+       intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
+       alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
+       if (!alt) {
+               PDEBUG(D_ERR, "Couldn't get altsetting");
+               return -EIO;
+       }
+
+       packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+       reg_w(sd, R51x_FIFO_PSIZE, packet_size >> 5);
+
+       reg_w(sd, R511_CAM_UV_EN, 0x01);
+       reg_w(sd, R511_SNAP_UV_EN, 0x01);
+       reg_w(sd, R511_SNAP_OPTS, 0x03);
+
+       /* Here I'm assuming that snapshot size == image size.
+        * I hope that's always true. --claudio
+        */
+       hsegs = (sd->gspca_dev.width >> 3) - 1;
+       vsegs = (sd->gspca_dev.height >> 3) - 1;
+
+       reg_w(sd, R511_CAM_PXCNT, hsegs);
+       reg_w(sd, R511_CAM_LNCNT, vsegs);
+       reg_w(sd, R511_CAM_PXDIV, 0x00);
+       reg_w(sd, R511_CAM_LNDIV, 0x00);
+
+       /* YUV420, low pass filter on */
+       reg_w(sd, R511_CAM_OPTS, 0x03);
+
+       /* Snapshot additions */
+       reg_w(sd, R511_SNAP_PXCNT, hsegs);
+       reg_w(sd, R511_SNAP_LNCNT, vsegs);
+       reg_w(sd, R511_SNAP_PXDIV, 0x00);
+       reg_w(sd, R511_SNAP_LNDIV, 0x00);
+
+       /******** Set the framerate ********/
+       if (frame_rate > 0)
+               sd->frame_rate = frame_rate;
+
+       switch (sd->sensor) {
+       case SEN_OV6620:
+               /* No framerate control, doesn't like higher rates yet */
+               sd->clockdiv = 3;
+               break;
+
+       /* Note once the FIXME's in mode_init_ov_sensor_regs() are fixed
+          for more sensors we need to do this for them too */
+       case SEN_OV7620:
+       case SEN_OV7640:
+       case SEN_OV76BE:
+               if (sd->gspca_dev.width == 320)
+                       interlaced = 1;
+               /* Fall through */
+       case SEN_OV6630:
+       case SEN_OV7610:
+       case SEN_OV7670:
+               switch (sd->frame_rate) {
+               case 30:
+               case 25:
+                       /* Not enough bandwidth to do 640x480 @ 30 fps */
+                       if (sd->gspca_dev.width != 640) {
+                               sd->clockdiv = 0;
+                               break;
+                       }
+                       /* Fall through for 640x480 case */
+               default:
+/*             case 20: */
+/*             case 15: */
+                       sd->clockdiv = 1;
+                       break;
+               case 10:
+                       sd->clockdiv = 2;
+                       break;
+               case 5:
+                       sd->clockdiv = 5;
+                       break;
+               }
+               if (interlaced) {
+                       sd->clockdiv = (sd->clockdiv + 1) * 2 - 1;
+                       /* Higher then 10 does not work */
+                       if (sd->clockdiv > 10)
+                               sd->clockdiv = 10;
+               }
+               break;
+
+       case SEN_OV8610:
+               /* No framerate control ?? */
+               sd->clockdiv = 0;
+               break;
+       }
+
+       /* Check if we have enough bandwidth to disable compression */
+       fps = (interlaced ? 60 : 30) / (sd->clockdiv + 1) + 1;
+       needed = fps * sd->gspca_dev.width * sd->gspca_dev.height * 3 / 2;
+       /* 1400 is a conservative estimate of the max nr of isoc packets/sec */
+       if (needed > 1400 * packet_size) {
+               /* Enable Y and UV quantization and compression */
+               reg_w(sd, R511_COMP_EN, 0x07);
+               reg_w(sd, R511_COMP_LUT_EN, 0x03);
+       } else {
+               reg_w(sd, R511_COMP_EN, 0x06);
+               reg_w(sd, R511_COMP_LUT_EN, 0x00);
+       }
+
+       reg_w(sd, R51x_SYS_RESET, OV511_RESET_OMNICE);
+       reg_w(sd, R51x_SYS_RESET, 0);
+
+       return 0;
+}
+
 /* Sets up the OV518/OV518+ with the given image parameters
  *
  * OV518 needs a completely different approach, until we can figure out what
@@ -1718,7 +2272,19 @@ static int sd_init(struct gspca_dev *gspca_dev)
  */
 static int ov518_mode_init_regs(struct sd *sd)
 {
-       int hsegs, vsegs;
+       int hsegs, vsegs, packet_size;
+       struct usb_host_interface *alt;
+       struct usb_interface *intf;
+
+       intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
+       alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
+       if (!alt) {
+               PDEBUG(D_ERR, "Couldn't get altsetting");
+               return -EIO;
+       }
+
+       packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+       ov518_reg_w32(sd, R51x_FIFO_PSIZE, packet_size & ~7, 2);
 
        /******** Set the mode ********/
 
@@ -1755,20 +2321,30 @@ static int ov518_mode_init_regs(struct sd *sd)
        /* Windows driver does this here; who knows why */
        reg_w(sd, 0x2f, 0x80);
 
-       /******** Set the framerate (to 30 FPS) ********/
-       if (sd->bridge == BRIDGE_OV518PLUS)
-               sd->clockdiv = 1;
-       else
-               sd->clockdiv = 0;
+       /******** Set the framerate  ********/
+       sd->clockdiv = 1;
 
        /* Mode independent, but framerate dependent, regs */
-       reg_w(sd, 0x51, 0x04);  /* Clock divider; lower==faster */
+       /* 0x51: Clock divider; Only works on some cams which use 2 crystals */
+       reg_w(sd, 0x51, 0x04);
        reg_w(sd, 0x22, 0x18);
        reg_w(sd, 0x23, 0xff);
 
-       if (sd->bridge == BRIDGE_OV518PLUS)
-               reg_w(sd, 0x21, 0x19);
-       else
+       if (sd->bridge == BRIDGE_OV518PLUS) {
+               switch (sd->sensor) {
+               case SEN_OV7620:
+                       if (sd->gspca_dev.width == 320) {
+                               reg_w(sd, 0x20, 0x00);
+                               reg_w(sd, 0x21, 0x19);
+                       } else {
+                               reg_w(sd, 0x20, 0x60);
+                               reg_w(sd, 0x21, 0x1f);
+                       }
+                       break;
+               default:
+                       reg_w(sd, 0x21, 0x19);
+               }
+       } else
                reg_w(sd, 0x71, 0x17);  /* Compression-related? */
 
        /* FIXME: Sensor-specific */
@@ -1879,7 +2455,11 @@ static int ov519_mode_init_regs(struct sd *sd)
 
        reg_w(sd, OV519_R10_H_SIZE,     sd->gspca_dev.width >> 4);
        reg_w(sd, OV519_R11_V_SIZE,     sd->gspca_dev.height >> 3);
-       reg_w(sd, OV519_R12_X_OFFSETL,  0x00);
+       if (sd->sensor == SEN_OV7670 &&
+           sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv)
+               reg_w(sd, OV519_R12_X_OFFSETL, 0x04);
+       else
+               reg_w(sd, OV519_R12_X_OFFSETL, 0x00);
        reg_w(sd, OV519_R13_X_OFFSETH,  0x00);
        reg_w(sd, OV519_R14_Y_OFFSETL,  0x00);
        reg_w(sd, OV519_R15_Y_OFFSETH,  0x00);
@@ -1971,7 +2551,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
        int qvga;
 
        gspca_dev = &sd->gspca_dev;
-       qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+       qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 1;
 
        /******** Mode (VGA/QVGA) and sensor specific regs ********/
        switch (sd->sensor) {
@@ -1983,21 +2563,16 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
                i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
                break;
        case SEN_OV7620:
-/*             i2c_w(sd, 0x2b, 0x00); */
+       case SEN_OV76BE:
                i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
                i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
                i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a);
                i2c_w(sd, 0x25, qvga ? 0x30 : 0x60);
                i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40);
-               i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0);
+               i2c_w_mask(sd, 0x67, qvga ? 0xb0 : 0x90, 0xf0);
                i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);
                break;
-       case SEN_OV76BE:
-/*             i2c_w(sd, 0x2b, 0x00); */
-               i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
-               break;
        case SEN_OV7640:
-/*             i2c_w(sd, 0x2b, 0x00); */
                i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
                i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
 /*             i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a); */
@@ -2016,6 +2591,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
                break;
        case SEN_OV6620:
        case SEN_OV6630:
+       case SEN_OV66308AF:
                i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
                break;
        default:
@@ -2023,10 +2599,6 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
        }
 
        /******** Palette-specific regs ********/
-       if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) {
-               /* not valid on the OV6620/OV7620/6630? */
-               i2c_w_mask(sd, 0x0e, 0x00, 0x40);
-       }
 
        /* The OV518 needs special treatment. Although both the OV518
         * and the OV6630 support a 16-bit video bus, only the 8 bit Y
@@ -2036,25 +2608,12 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
 
        /* OV7640 is 8-bit only */
 
-       if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV7640)
+       if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV66308AF &&
+                                       sd->sensor != SEN_OV7640)
                i2c_w_mask(sd, 0x13, 0x00, 0x20);
 
        /******** Clock programming ********/
-       /* The OV6620 needs special handling. This prevents the
-        * severe banding that normally occurs */
-       if (sd->sensor == SEN_OV6620) {
-
-               /* Clock down */
-               i2c_w(sd, 0x2a, 0x04);
-               i2c_w(sd, 0x11, sd->clockdiv);
-               i2c_w(sd, 0x2a, 0x84);
-               /* This next setting is critical. It seems to improve
-                * the gain or the contrast. The "reserved" bits seem
-                * to have some effect in this case. */
-               i2c_w(sd, 0x2d, 0x85);
-       } else {
-               i2c_w(sd, 0x11, sd->clockdiv);
-       }
+       i2c_w(sd, 0x11, sd->clockdiv);
 
        /******** Special Features ********/
 /* no evidence this is possible with OV7670, either */
@@ -2098,13 +2657,14 @@ static void sethvflip(struct sd *sd)
 static int set_ov_sensor_window(struct sd *sd)
 {
        struct gspca_dev *gspca_dev;
-       int qvga;
+       int qvga, crop;
        int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale;
        int ret, hstart, hstop, vstop, vstart;
        __u8 v;
 
        gspca_dev = &sd->gspca_dev;
-       qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+       qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 1;
+       crop = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 2;
 
        /* The different sensor ICs handle setting up of window differently.
         * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!! */
@@ -2123,14 +2683,19 @@ static int set_ov_sensor_window(struct sd *sd)
                break;
        case SEN_OV6620:
        case SEN_OV6630:
+       case SEN_OV66308AF:
                hwsbase = 0x38;
                hwebase = 0x3a;
                vwsbase = 0x05;
                vwebase = 0x06;
-               if (qvga) {
+               if (sd->sensor == SEN_OV66308AF && qvga)
                        /* HDG: this fixes U and V getting swapped */
-                       hwsbase--;
-                       vwsbase--;
+                       hwsbase++;
+               if (crop) {
+                       hwsbase += 8;
+                       hwebase += 8;
+                       vwsbase += 11;
+                       vwebase += 11;
                }
                break;
        case SEN_OV7620:
@@ -2155,6 +2720,7 @@ static int set_ov_sensor_window(struct sd *sd)
        switch (sd->sensor) {
        case SEN_OV6620:
        case SEN_OV6630:
+       case SEN_OV66308AF:
                if (qvga) {             /* QCIF */
                        hwscale = 0;
                        vwscale = 0;
@@ -2207,7 +2773,7 @@ static int set_ov_sensor_window(struct sd *sd)
                if (qvga) {             /* QVGA from ov7670.c by
                                         * Jonathan Corbet */
                        hstart = 164;
-                       hstop = 20;
+                       hstop = 28;
                        vstart = 14;
                        vstop = 494;
                } else {                /* VGA */
@@ -2233,7 +2799,6 @@ static int set_ov_sensor_window(struct sd *sd)
                msleep(10);     /* need to sleep between read and write to
                                 * same reg! */
                i2c_w(sd, OV7670_REG_VREF, v);
-               sethvflip(sd);
        } else {
                i2c_w(sd, 0x17, hwsbase);
                i2c_w(sd, 0x18, hwebase + (sd->gspca_dev.width >> hwscale));
@@ -2250,6 +2815,10 @@ static int sd_start(struct gspca_dev *gspca_dev)
        int ret = 0;
 
        switch (sd->bridge) {
+       case BRIDGE_OV511:
+       case BRIDGE_OV511PLUS:
+               ret = ov511_mode_init_regs(sd);
+               break;
        case BRIDGE_OV518:
        case BRIDGE_OV518PLUS:
                ret = ov518_mode_init_regs(sd);
@@ -2268,6 +2837,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
        setcontrast(gspca_dev);
        setbrightness(gspca_dev);
        setcolors(gspca_dev);
+       sethvflip(sd);
+       setautobrightness(sd);
+       setfreq(sd);
 
        ret = ov51x_restart(sd);
        if (ret < 0)
@@ -2287,23 +2859,88 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        ov51x_led_control(sd, 0);
 }
 
-static void ov518_pkt_scan(struct gspca_dev *gspca_dev,
+static void ov511_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
-                       __u8 *data,                     /* isoc packet */
+                       __u8 *in,                       /* isoc packet */
                        int len)                        /* iso packet length */
 {
-       PDEBUG(D_STREAM, "ov518_pkt_scan: %d bytes", len);
+       struct sd *sd = (struct sd *) gspca_dev;
 
-       if (len & 7) {
-               len--;
-               PDEBUG(D_STREAM, "packet number: %d\n", (int)data[len]);
+       /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
+        * byte non-zero. The EOF packet has image width/height in the
+        * 10th and 11th bytes. The 9th byte is given as follows:
+        *
+        * bit 7: EOF
+        *     6: compression enabled
+        *     5: 422/420/400 modes
+        *     4: 422/420/400 modes
+        *     3: 1
+        *     2: snapshot button on
+        *     1: snapshot frame
+        *     0: even/odd field
+        */
+       if (!(in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) &&
+           (in[8] & 0x08)) {
+               if (in[8] & 0x80) {
+                       /* Frame end */
+                       if ((in[9] + 1) * 8 != gspca_dev->width ||
+                           (in[10] + 1) * 8 != gspca_dev->height) {
+                               PDEBUG(D_ERR, "Invalid frame size, got: %dx%d,"
+                                       " requested: %dx%d\n",
+                                       (in[9] + 1) * 8, (in[10] + 1) * 8,
+                                       gspca_dev->width, gspca_dev->height);
+                               gspca_dev->last_packet_type = DISCARD_PACKET;
+                               return;
+                       }
+                       /* Add 11 byte footer to frame, might be usefull */
+                       gspca_frame_add(gspca_dev, LAST_PACKET, frame, in, 11);
+                       return;
+               } else {
+                       /* Frame start */
+                       gspca_frame_add(gspca_dev, FIRST_PACKET, frame, in, 0);
+                       sd->packet_nr = 0;
+               }
        }
 
+       /* Ignore the packet number */
+       len--;
+
+       /* intermediate packet */
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame, in, len);
+}
+
+static void ov518_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;
+
        /* A false positive here is likely, until OVT gives me
         * the definitive SOF/EOF format */
        if ((!(data[0] | data[1] | data[2] | data[3] | data[5])) && data[6]) {
                gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0);
                gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, 0);
+               sd->packet_nr = 0;
+       }
+
+       if (gspca_dev->last_packet_type == DISCARD_PACKET)
+               return;
+
+       /* Does this device use packet numbers ? */
+       if (len & 7) {
+               len--;
+               if (sd->packet_nr == data[len])
+                       sd->packet_nr++;
+               /* The last few packets of the frame (which are all 0's
+                  except that they may contain part of the footer), are
+                  numbered 0 */
+               else if (sd->packet_nr == 0 || data[len]) {
+                       PDEBUG(D_ERR, "Invalid packet nr: %d (expect: %d)",
+                               (int)data[len], (int)sd->packet_nr);
+                       gspca_dev->last_packet_type = DISCARD_PACKET;
+                       return;
+               }
        }
 
        /* intermediate packet */
@@ -2364,6 +3001,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        switch (sd->bridge) {
        case BRIDGE_OV511:
        case BRIDGE_OV511PLUS:
+               ov511_pkt_scan(gspca_dev, frame, data, len);
                break;
        case BRIDGE_OV518:
        case BRIDGE_OV518PLUS:
@@ -2389,13 +3027,13 @@ static void setbrightness(struct gspca_dev *gspca_dev)
        case SEN_OV76BE:
        case SEN_OV6620:
        case SEN_OV6630:
+       case SEN_OV66308AF:
        case SEN_OV7640:
                i2c_w(sd, OV7610_REG_BRT, val);
                break;
        case SEN_OV7620:
                /* 7620 doesn't like manual changes when in auto mode */
-/*fixme
- *             if (!sd->auto_brt) */
+               if (!sd->autobrightness)
                        i2c_w(sd, OV7610_REG_BRT, val);
                break;
        case SEN_OV7670:
@@ -2418,6 +3056,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
                i2c_w(sd, OV7610_REG_CNT, val);
                break;
        case SEN_OV6630:
+       case SEN_OV66308AF:
                i2c_w_mask(sd, OV7610_REG_CNT, val >> 4, 0x0f);
                break;
        case SEN_OV8610: {
@@ -2462,6 +3101,7 @@ static void setcolors(struct gspca_dev *gspca_dev)
        case SEN_OV76BE:
        case SEN_OV6620:
        case SEN_OV6630:
+       case SEN_OV66308AF:
                i2c_w(sd, OV7610_REG_SAT, val);
                break;
        case SEN_OV7620:
@@ -2482,6 +3122,72 @@ static void setcolors(struct gspca_dev *gspca_dev)
        }
 }
 
+static void setautobrightness(struct sd *sd)
+{
+       if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7670)
+               return;
+
+       i2c_w_mask(sd, 0x2d, sd->autobrightness ? 0x10 : 0x00, 0x10);
+}
+
+static void setfreq(struct sd *sd)
+{
+       if (sd->sensor == SEN_OV7670) {
+               switch (sd->freq) {
+               case 0: /* Banding filter disabled */
+                       i2c_w_mask(sd, OV7670_REG_COM8, 0, OV7670_COM8_BFILT);
+                       break;
+               case 1: /* 50 hz */
+                       i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_BFILT,
+                                  OV7670_COM8_BFILT);
+                       i2c_w_mask(sd, OV7670_REG_COM11, 0x08, 0x18);
+                       break;
+               case 2: /* 60 hz */
+                       i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_BFILT,
+                                  OV7670_COM8_BFILT);
+                       i2c_w_mask(sd, OV7670_REG_COM11, 0x00, 0x18);
+                       break;
+               case 3: /* Auto hz */
+                       i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_BFILT,
+                                  OV7670_COM8_BFILT);
+                       i2c_w_mask(sd, OV7670_REG_COM11, OV7670_COM11_HZAUTO,
+                                  0x18);
+                       break;
+               }
+       } else {
+               switch (sd->freq) {
+               case 0: /* Banding filter disabled */
+                       i2c_w_mask(sd, 0x2d, 0x00, 0x04);
+                       i2c_w_mask(sd, 0x2a, 0x00, 0x80);
+                       break;
+               case 1: /* 50 hz (filter on and framerate adj) */
+                       i2c_w_mask(sd, 0x2d, 0x04, 0x04);
+                       i2c_w_mask(sd, 0x2a, 0x80, 0x80);
+                       /* 20 fps -> 16.667 fps */
+                       if (sd->sensor == SEN_OV6620 ||
+                           sd->sensor == SEN_OV6630 ||
+                           sd->sensor == SEN_OV66308AF)
+                               i2c_w(sd, 0x2b, 0x5e);
+                       else
+                               i2c_w(sd, 0x2b, 0xac);
+                       break;
+               case 2: /* 60 hz (filter on, ...) */
+                       i2c_w_mask(sd, 0x2d, 0x04, 0x04);
+                       if (sd->sensor == SEN_OV6620 ||
+                           sd->sensor == SEN_OV6630 ||
+                           sd->sensor == SEN_OV66308AF) {
+                               /* 20 fps -> 15 fps */
+                               i2c_w_mask(sd, 0x2a, 0x80, 0x80);
+                               i2c_w(sd, 0x2b, 0xa8);
+                       } else {
+                               /* no framerate adj. */
+                               i2c_w_mask(sd, 0x2a, 0x00, 0x80);
+                       }
+                       break;
+               }
+       }
+}
+
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -2572,6 +3278,71 @@ static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
+static int sd_setautobrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->autobrightness = val;
+       if (gspca_dev->streaming)
+               setautobrightness(sd);
+       return 0;
+}
+
+static int sd_getautobrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->autobrightness;
+       return 0;
+}
+
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->freq = val;
+       if (gspca_dev->streaming)
+               setfreq(sd);
+       return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->freq;
+       return 0;
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+                       struct v4l2_querymenu *menu)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (menu->id) {
+       case V4L2_CID_POWER_LINE_FREQUENCY:
+               switch (menu->index) {
+               case 0:         /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+                       strcpy((char *) menu->name, "NoFliker");
+                       return 0;
+               case 1:         /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+                       strcpy((char *) menu->name, "50 Hz");
+                       return 0;
+               case 2:         /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+                       strcpy((char *) menu->name, "60 Hz");
+                       return 0;
+               case 3:
+                       if (sd->sensor != SEN_OV7670)
+                               return -EINVAL;
+
+                       strcpy((char *) menu->name, "Automatic");
+                       return 0;
+               }
+               break;
+       }
+       return -EINVAL;
+}
+
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
@@ -2582,6 +3353,7 @@ static const struct sd_desc sd_desc = {
        .start = sd_start,
        .stopN = sd_stopN,
        .pkt_scan = sd_pkt_scan,
+       .querymenu = sd_querymenu,
 };
 
 /* -- module initialisation -- */
@@ -2590,17 +3362,22 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 },
        {USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 },
        {USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 },
-       {USB_DEVICE(0x041e, 0x4064), .driver_info = BRIDGE_OV519 },
-       {USB_DEVICE(0x041e, 0x4068), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x041e, 0x4064),
+        .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
+       {USB_DEVICE(0x041e, 0x4068),
+        .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
        {USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 },
        {USB_DEVICE(0x054c, 0x0154), .driver_info = BRIDGE_OV519 },
        {USB_DEVICE(0x054c, 0x0155), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x05a9, 0x0511), .driver_info = BRIDGE_OV511 },
        {USB_DEVICE(0x05a9, 0x0518), .driver_info = BRIDGE_OV518 },
        {USB_DEVICE(0x05a9, 0x0519), .driver_info = BRIDGE_OV519 },
        {USB_DEVICE(0x05a9, 0x0530), .driver_info = BRIDGE_OV519 },
        {USB_DEVICE(0x05a9, 0x4519), .driver_info = BRIDGE_OV519 },
        {USB_DEVICE(0x05a9, 0x8519), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x05a9, 0xa511), .driver_info = BRIDGE_OV511PLUS },
        {USB_DEVICE(0x05a9, 0xa518), .driver_info = BRIDGE_OV518PLUS },
+       {USB_DEVICE(0x0813, 0x0002), .driver_info = BRIDGE_OV511PLUS },
        {}
 };
 
index dc6a6f11354a260ee01f389859c3b352fcb2e6d9..0d02f41fa7d099835e390c23e957806c277b4f16 100644 (file)
@@ -46,6 +46,7 @@ struct sd {
        u8 gamma;
        u8 vflip;                       /* ov7630/ov7648 only */
        u8 infrared;                    /* mt9v111 only */
+       u8 freq;                        /* ov76xx only */
        u8 quality;                     /* image quality */
 #define QUALITY_MIN 60
 #define QUALITY_MAX 95
@@ -96,8 +97,11 @@ 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_setinfrared(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val);
+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,
@@ -113,6 +117,7 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setbrightness,
            .get = sd_getbrightness,
        },
+#define CONTRAST_IDX 1
        {
            {
                .id      = V4L2_CID_CONTRAST,
@@ -128,20 +133,22 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setcontrast,
            .get = sd_getcontrast,
        },
+#define COLOR_IDX 2
        {
            {
                .id      = V4L2_CID_SATURATION,
                .type    = V4L2_CTRL_TYPE_INTEGER,
-               .name    = "Color",
+               .name    = "Saturation",
                .minimum = 0,
                .maximum = 40,
                .step    = 1,
-#define COLOR_DEF 32
+#define COLOR_DEF 25
                .default_value = COLOR_DEF,
            },
            .set = sd_setcolors,
            .get = sd_getcolors,
        },
+#define BLUE_BALANCE_IDX 3
        {
            {
                .id      = V4L2_CID_BLUE_BALANCE,
@@ -156,6 +163,7 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setblue_balance,
            .get = sd_getblue_balance,
        },
+#define RED_BALANCE_IDX 4
        {
            {
                .id      = V4L2_CID_RED_BALANCE,
@@ -170,6 +178,7 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setred_balance,
            .get = sd_getred_balance,
        },
+#define GAMMA_IDX 5
        {
            {
                .id      = V4L2_CID_GAMMA,
@@ -184,7 +193,7 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setgamma,
            .get = sd_getgamma,
        },
-#define AUTOGAIN_IDX 5
+#define AUTOGAIN_IDX 6
        {
            {
                .id      = V4L2_CID_AUTOGAIN,
@@ -200,7 +209,7 @@ static struct ctrl sd_ctrls[] = {
            .get = sd_getautogain,
        },
 /* ov7630/ov7648 only */
-#define VFLIP_IDX 6
+#define VFLIP_IDX 7
        {
            {
                .id      = V4L2_CID_VFLIP,
@@ -209,14 +218,14 @@ static struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 1,
                .step    = 1,
-#define VFLIP_DEF 0                    /* vflip def = 1 for ov7630 */
+#define VFLIP_DEF 0
                .default_value = VFLIP_DEF,
            },
            .set = sd_setvflip,
            .get = sd_getvflip,
        },
 /* mt9v111 only */
-#define INFRARED_IDX 7
+#define INFRARED_IDX 8
        {
            {
                .id      = V4L2_CID_INFRARED,
@@ -231,28 +240,44 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setinfrared,
            .get = sd_getinfrared,
        },
+/* ov7630/ov7648/ov7660 only */
+#define FREQ_IDX 9
+       {
+           {
+               .id      = V4L2_CID_POWER_LINE_FREQUENCY,
+               .type    = V4L2_CTRL_TYPE_MENU,
+               .name    = "Light frequency filter",
+               .minimum = 0,
+               .maximum = 2,   /* 0: 0, 1: 50Hz, 2:60Hz */
+               .step    = 1,
+#define FREQ_DEF 2
+               .default_value = FREQ_DEF,
+           },
+           .set = sd_setfreq,
+           .get = sd_getfreq,
+       },
 };
 
 /* table of the disabled controls */
 static __u32 ctrl_dis[] = {
-       (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+       (1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
                                                /* SENSOR_HV7131R 0 */
-       (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+       (1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
                                                /* SENSOR_MI0360 1 */
-       (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+       (1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
                                                /* SENSOR_MO4000 2 */
-       (1 << VFLIP_IDX),
+       (1 << VFLIP_IDX) | (1 << FREQ_IDX),
                                                /* SENSOR_MT9V111 3 */
-       (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+       (1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
                                                /* SENSOR_OM6802 4 */
-       (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX),
+       (1 << INFRARED_IDX),
                                                /* SENSOR_OV7630 5 */
        (1 << INFRARED_IDX),
                                                /* SENSOR_OV7648 6 */
        (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
                                                /* SENSOR_OV7660 7 */
-       (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
-                                               /* SENSOR_SP80708 8 */
+       (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX) |
+                             (1 << FREQ_IDX),  /* SENSOR_SP80708 8 */
 };
 
 static const struct v4l2_pix_format vga_mode[] = {
@@ -268,7 +293,8 @@ static const struct v4l2_pix_format vga_mode[] = {
                .priv = 1},
        {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 640,
-               .sizeimage = 640 * 480 * 3 / 8 + 590,
+               /* Note 3 / 8 is not large enough, not even 5 / 8 is ?! */
+               .sizeimage = 640 * 480 * 3 / 4 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 0},
 };
@@ -604,7 +630,9 @@ static const u8 ov7630_sensor_init[][8] = {
 /* 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},
+/* HDG: 0x11 was 0x00 change to 0x01 for better exposure (15 fps instead of 30)
+       0x13 was 0xc0 change to 0xc3 for auto gain and exposure */
+       {0xd1, 0x21, 0x11, 0x01, 0x48, 0xc3, 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},
@@ -638,9 +666,8 @@ static const u8 ov7630_sensor_init[][8] = {
        {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, 0x2a, 0x88, 0x00, 0x00, 0x00, 0x10}, * set by setfreq */
+/*     {0xa1, 0x21, 0x2b, 0x34, 0x00, 0x00, 0x00, 0x10}, * set by setfreq */
 /* */
        {0xa1, 0x21, 0x10, 0x83, 0x00, 0x00, 0x00, 0x10},
 /*     {0xb1, 0x21, 0x01, 0x88, 0x70, 0x00, 0x00, 0x10}, */
@@ -673,7 +700,7 @@ static const u8 ov7648_sensor_init[][8] = {
        {0xd1, 0x21, 0x21, 0x86, 0x00, 0xde, 0xa0, 0x10},
 /*     {0xd1, 0x21, 0x25, 0x80, 0x32, 0xfe, 0xa0, 0x10}, jfm done */
 /*     {0xd1, 0x21, 0x29, 0x00, 0x91, 0x00, 0x88, 0x10}, jfm done */
-       {0xb1, 0x21, 0x2d, 0x85, 0x00, 0x00, 0x00, 0x10},
+/*     {0xb1, 0x21, 0x2d, 0x85, 0x00, 0x00, 0x00, 0x10}, set by setfreq */
 /*...*/
 /*     {0xa1, 0x21, 0x12, 0x08, 0x00, 0x00, 0x00, 0x10}, jfm done */
 /*     {0xa1, 0x21, 0x75, 0x06, 0x00, 0x00, 0x00, 0x10},   * COMN
@@ -1294,11 +1321,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->gamma = GAMMA_DEF;
        sd->autogain = AUTOGAIN_DEF;
        sd->ag_cnt = -1;
-       if (sd->sensor != SENSOR_OV7630)
-               sd->vflip = 0;
-       else
-               sd->vflip = 1;
+       sd->vflip = VFLIP_DEF;
        sd->infrared = INFRARED_DEF;
+       sd->freq = FREQ_DEF;
        sd->quality = QUALITY_DEF;
        sd->jpegqual = 80;
 
@@ -1569,7 +1594,7 @@ static void setautogain(struct gspca_dev *gspca_dev)
                else
                        comb = 0xa0;
                if (sd->autogain)
-                       comb |= 0x02;
+                       comb |= 0x03;
                i2c_w1(&sd->gspca_dev, 0x13, comb);
                return;
            }
@@ -1585,12 +1610,15 @@ static void setvflip(struct sd *sd)
 {
        u8 comn;
 
-       if (sd->sensor == SENSOR_OV7630)
+       if (sd->sensor == SENSOR_OV7630) {
                comn = 0x02;
-       else
+               if (!sd->vflip)
+                       comn |= 0x80;
+       } else {
                comn = 0x06;
-       if (sd->vflip)
-               comn |= 0x80;
+               if (sd->vflip)
+                       comn |= 0x80;
+       }
        i2c_w1(&sd->gspca_dev, 0x75, comn);
 }
 
@@ -1602,6 +1630,58 @@ static void setinfrared(struct sd *sd)
                sd->infrared ? 0x66 : 0x64);
 }
 
+static void setfreq(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (sd->sensor == SENSOR_OV7660) {
+               switch (sd->freq) {
+               case 0: /* Banding filter disabled */
+                       i2c_w1(gspca_dev, 0x13, 0xdf);
+                       break;
+               case 1: /* 50 hz */
+                       i2c_w1(gspca_dev, 0x13, 0xff);
+                       i2c_w1(gspca_dev, 0x3b, 0x0a);
+                       break;
+               case 2: /* 60 hz */
+                       i2c_w1(gspca_dev, 0x13, 0xff);
+                       i2c_w1(gspca_dev, 0x3b, 0x02);
+                       break;
+               }
+       } else {
+               u8 reg2a = 0, reg2b = 0, reg2d = 0;
+
+               /* Get reg2a / reg2d base values */
+               switch (sd->sensor) {
+               case SENSOR_OV7630:
+                       reg2a = 0x08;
+                       reg2d = 0x01;
+                       break;
+               case SENSOR_OV7648:
+                       reg2a = 0x11;
+                       reg2d = 0x81;
+                       break;
+               }
+
+               switch (sd->freq) {
+               case 0: /* Banding filter disabled */
+                       break;
+               case 1: /* 50 hz (filter on and framerate adj) */
+                       reg2a |= 0x80;
+                       reg2b = 0xac;
+                       reg2d |= 0x04;
+                       break;
+               case 2: /* 60 hz (filter on, no framerate adj) */
+                       reg2a |= 0x80;
+                       reg2d |= 0x04;
+                       break;
+               }
+               i2c_w1(gspca_dev, 0x2a, reg2a);
+               i2c_w1(gspca_dev, 0x2b, reg2b);
+               i2c_w1(gspca_dev, 0x2d, reg2d);
+       }
+}
+
 static void setjpegqual(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -1828,6 +1908,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
        setbrightness(gspca_dev);
        setcontrast(gspca_dev);
        setautogain(gspca_dev);
+       setfreq(gspca_dev);
        return 0;
 }
 
@@ -2131,6 +2212,24 @@ static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
+static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->freq = val;
+       if (gspca_dev->streaming)
+               setfreq(gspca_dev);
+       return 0;
+}
+
+static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->freq;
+       return 0;
+}
+
 static int sd_set_jcomp(struct gspca_dev *gspca_dev,
                        struct v4l2_jpegcompression *jcomp)
 {
@@ -2159,6 +2258,27 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
        return 0;
 }
 
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+                       struct v4l2_querymenu *menu)
+{
+       switch (menu->id) {
+       case V4L2_CID_POWER_LINE_FREQUENCY:
+               switch (menu->index) {
+               case 0:         /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+                       strcpy((char *) menu->name, "NoFliker");
+                       return 0;
+               case 1:         /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+                       strcpy((char *) menu->name, "50 Hz");
+                       return 0;
+               case 2:         /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+                       strcpy((char *) menu->name, "60 Hz");
+                       return 0;
+               }
+               break;
+       }
+       return -EINVAL;
+}
+
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
@@ -2173,6 +2293,7 @@ static const struct sd_desc sd_desc = {
        .dq_callback = do_autogain,
        .get_jcomp = sd_get_jcomp,
        .set_jcomp = sd_set_jcomp,
+       .querymenu = sd_querymenu,
 };
 
 /* -- module initialisation -- */
@@ -2233,7 +2354,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)},
 #endif
        {USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)},
-/*     {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x??)}, */
+       {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x21)},
        {USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, SP80708, 0x18)},
        {}
 };
index feeaa94ab588d0bf4c21d0591503137d2c0d7524..2f3c3a606ce463b58ba4b15d7f50dc178f70dfd0 100644 (file)
@@ -3,7 +3,8 @@ obj-$(CONFIG_USB_STV06XX) += gspca_stv06xx.o
 gspca_stv06xx-objs := stv06xx.o \
                      stv06xx_vv6410.o \
                      stv06xx_hdcs.o \
-                     stv06xx_pb0100.o
+                     stv06xx_pb0100.o \
+                     stv06xx_st6422.o
 
 EXTRA_CFLAGS += -Idrivers/media/video/gspca
 
index e573c3406324bf7f5a71a2da4804e4cd73b540c9..0da8e0de04566a246213f31408900800e72f6826 100644 (file)
@@ -92,11 +92,10 @@ static int stv06xx_write_sensor_finish(struct sd *sd)
 {
        int err = 0;
 
-       if (IS_850(sd)) {
+       if (sd->bridge == BRIDGE_STV610) {
                struct usb_device *udev = sd->gspca_dev.dev;
                __u8 *buf = sd->gspca_dev.usb_buf;
 
-               /* Quickam Web needs an extra packet */
                buf[0] = 0;
                err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
                                      0x04, 0x40, 0x1704, 0, buf, 1,
@@ -253,7 +252,7 @@ static int stv06xx_init(struct gspca_dev *gspca_dev)
 
        err = sd->sensor->init(sd);
 
-       if (dump_sensor)
+       if (dump_sensor && sd->sensor->dump)
                sd->sensor->dump(sd);
 
        return (err < 0) ? err : 0;
@@ -318,6 +317,8 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev,
                        __u8 *data,                     /* isoc packet */
                        int len)                        /* iso packet length */
 {
+       struct sd *sd = (struct sd *) gspca_dev;
+
        PDEBUG(D_PACK, "Packet of length %d arrived", len);
 
        /* A packet may contain several frames
@@ -343,14 +344,29 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev,
                if (len < chunk_len) {
                        PDEBUG(D_ERR, "URB packet length is smaller"
                                " than the specified chunk length");
+                       gspca_dev->last_packet_type = DISCARD_PACKET;
                        return;
                }
 
+               /* First byte seem to be 02=data 2nd byte is unknown??? */
+               if (sd->bridge == BRIDGE_ST6422 && (id & 0xFF00) == 0x0200)
+                       goto frame_data;
+
                switch (id) {
                case 0x0200:
                case 0x4200:
+frame_data:
                        PDEBUG(D_PACK, "Frame data packet detected");
 
+                       if (sd->to_skip) {
+                               int skip = (sd->to_skip < chunk_len) ?
+                                           sd->to_skip : chunk_len;
+                               data += skip;
+                               len -= skip;
+                               chunk_len -= skip;
+                               sd->to_skip -= skip;
+                       }
+
                        gspca_frame_add(gspca_dev, INTER_PACKET, frame,
                                        data, chunk_len);
                        break;
@@ -365,6 +381,9 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev,
                        gspca_frame_add(gspca_dev, FIRST_PACKET,
                                        frame, data, 0);
 
+                       if (sd->bridge == BRIDGE_ST6422)
+                               sd->to_skip = gspca_dev->width * 4;
+
                        if (chunk_len)
                                PDEBUG(D_ERR, "Chunk length is "
                                              "non-zero on a SOF");
@@ -395,8 +414,12 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev,
                        /* Unknown chunk with 2 bytes of data,
                           occurs 2-3 times per USB interrupt */
                        break;
+               case 0x42ff:
+                       PDEBUG(D_PACK, "Chunk 0x42ff detected");
+                       /* Special chunk seen sometimes on the ST6422 */
+                       break;
                default:
-                       PDEBUG(D_PACK, "Unknown chunk %d detected", id);
+                       PDEBUG(D_PACK, "Unknown chunk 0x%04x detected", id);
                        /* Unknown chunk */
                }
                data    += chunk_len;
@@ -428,11 +451,16 @@ static int stv06xx_config(struct gspca_dev *gspca_dev,
 
        cam = &gspca_dev->cam;
        sd->desc = sd_desc;
+       sd->bridge = id->driver_info;
        gspca_dev->sd_desc = &sd->desc;
 
        if (dump_bridge)
                stv06xx_dump_bridge(sd);
 
+       sd->sensor = &stv06xx_sensor_st6422;
+       if (!sd->sensor->probe(sd))
+               return 0;
+
        sd->sensor = &stv06xx_sensor_vv6410;
        if (!sd->sensor->probe(sd))
                return 0;
@@ -457,9 +485,20 @@ static int stv06xx_config(struct gspca_dev *gspca_dev,
 
 /* -- module initialisation -- */
 static const __devinitdata struct usb_device_id device_table[] = {
-       {USB_DEVICE(0x046d, 0x0840)}, /* QuickCam Express */
-       {USB_DEVICE(0x046d, 0x0850)}, /* LEGO cam / QuickCam Web */
-       {USB_DEVICE(0x046d, 0x0870)}, /* Dexxa WebCam USB */
+       /* QuickCam Express */
+       {USB_DEVICE(0x046d, 0x0840), .driver_info = BRIDGE_STV600 },
+       /* LEGO cam / QuickCam Web */
+       {USB_DEVICE(0x046d, 0x0850), .driver_info = BRIDGE_STV610 },
+       /* Dexxa WebCam USB */
+       {USB_DEVICE(0x046d, 0x0870), .driver_info = BRIDGE_STV602 },
+       /* QuickCam Messenger */
+       {USB_DEVICE(0x046D, 0x08F0), .driver_info = BRIDGE_ST6422 },
+       /* QuickCam Communicate */
+       {USB_DEVICE(0x046D, 0x08F5), .driver_info = BRIDGE_ST6422 },
+       /* QuickCam Messenger (new) */
+       {USB_DEVICE(0x046D, 0x08F6), .driver_info = BRIDGE_ST6422 },
+       /* QuickCam Messenger (new) */
+       {USB_DEVICE(0x046D, 0x08DA), .driver_info = BRIDGE_ST6422 },
        {}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
index 1207e7d17f147885d0efbd5924d450cacf381729..9df7137fe67ec80c19db1a079b70a76688fc6279 100644 (file)
@@ -93,6 +93,17 @@ struct sd {
 
        /* Sensor private data */
        void *sensor_priv;
+
+       /* The first 4 lines produced by the stv6422 are no good, this keeps
+          track of how many bytes we still need to skip during a frame */
+       int to_skip;
+
+       /* Bridge / Camera type */
+       u8 bridge;
+       #define BRIDGE_STV600 0
+       #define BRIDGE_STV602 1
+       #define BRIDGE_STV610 2
+       #define BRIDGE_ST6422 3 /* With integrated sensor */
 };
 
 int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data);
index b1690381420300ddc93843eaeb064c02b0ebdb7f..3039ec208f3a5e37c029cc44876642eb0611867f 100644 (file)
@@ -434,7 +434,7 @@ static int hdcs_probe_1x00(struct sd *sd)
        hdcs->exp.er = 100;
 
        /*
-        * Frame rate on HDCS-1000 0x46D:0x840 depends on PSMP:
+        * Frame rate on HDCS-1000 with STV600 depends on PSMP:
         *  4 = doesn't work at all
         *  5 = 7.8 fps,
         *  6 = 6.9 fps,
@@ -443,7 +443,7 @@ static int hdcs_probe_1x00(struct sd *sd)
         * 15 = 4.4 fps,
         * 31 = 2.8 fps
         *
-        * Frame rate on HDCS-1000 0x46D:0x870 depends on PSMP:
+        * Frame rate on HDCS-1000 with STV602 depends on PSMP:
         * 15 = doesn't work at all
         * 18 = doesn't work at all
         * 19 = 7.3 fps
@@ -453,7 +453,7 @@ static int hdcs_probe_1x00(struct sd *sd)
         * 24 = 6.3 fps
         * 30 = 5.4 fps
         */
-       hdcs->psmp = IS_870(sd) ? 20 : 5;
+       hdcs->psmp = (sd->bridge == BRIDGE_STV602) ? 20 : 5;
 
        sd->sensor_priv = hdcs;
 
@@ -530,7 +530,7 @@ static int hdcs_init(struct sd *sd)
        int i, err = 0;
 
        /* Set the STV0602AA in STV0600 emulation mode */
-       if (IS_870(sd))
+       if (sd->bridge == BRIDGE_STV602)
                stv06xx_write_bridge(sd, STV_STV0600_EMULATION, 1);
 
        /* Execute the bridge init */
@@ -558,7 +558,7 @@ static int hdcs_init(struct sd *sd)
                return err;
 
        /* Set PGA sample duration
-       (was 0x7E for IS_870, but caused slow framerate with HDCS-1020) */
+       (was 0x7E for the STV602, but caused slow framerate with HDCS-1020) */
        if (IS_1020(sd))
                err = stv06xx_write_sensor(sd, HDCS_TCTRL,
                                (HDCS_ADC_START_SIG_DUR << 6) | hdcs->psmp);
index e88c42f7d2f8eda0b2b84c9b11ad330f0ef2e4f7..934b9cebc1abc5f045934697734940f798cb3729 100644 (file)
 
 #include "stv06xx.h"
 
-#define IS_850(sd)     ((sd)->gspca_dev.dev->descriptor.idProduct == 0x850)
-#define IS_870(sd)     ((sd)->gspca_dev.dev->descriptor.idProduct == 0x870)
 #define IS_1020(sd)    ((sd)->sensor == &stv06xx_sensor_hdcs1020)
 
 extern const struct stv06xx_sensor stv06xx_sensor_vv6410;
 extern const struct stv06xx_sensor stv06xx_sensor_hdcs1x00;
 extern const struct stv06xx_sensor stv06xx_sensor_hdcs1020;
 extern const struct stv06xx_sensor stv06xx_sensor_pb0100;
+extern const struct stv06xx_sensor stv06xx_sensor_st6422;
 
 struct stv06xx_sensor {
        /* Defines the name of a sensor */
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
new file mode 100644 (file)
index 0000000..87cb5b9
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * Support for the sensor part which is integrated (I think) into the
+ * st6422 stv06xx alike bridge, as its integrated there are no i2c writes
+ * but instead direct bridge writes.
+ *
+ * Copyright (c) 2009 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Strongly based on qc-usb-messenger, which is:
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ *                   Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "stv06xx_st6422.h"
+
+static struct v4l2_pix_format st6422_mode[] = {
+       /* Note we actually get 124 lines of data, of which we skip the 4st
+          4 as they are garbage */
+       {
+               162,
+               120,
+               V4L2_PIX_FMT_SGRBG8,
+               V4L2_FIELD_NONE,
+               .sizeimage = 162 * 120,
+               .bytesperline = 162,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1
+       },
+       /* Note we actually get 248 lines of data, of which we skip the 4st
+          4 as they are garbage, and we tell the app it only gets the
+          first 240 of the 244 lines it actually gets, so that it ignores
+          the last 4. */
+       {
+               324,
+               240,
+               V4L2_PIX_FMT_SGRBG8,
+               V4L2_FIELD_NONE,
+               .sizeimage = 324 * 244,
+               .bytesperline = 324,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0
+       },
+};
+
+static const struct ctrl st6422_ctrl[] = {
+#define BRIGHTNESS_IDX 0
+       {
+               {
+                       .id             = V4L2_CID_BRIGHTNESS,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "Brightness",
+                       .minimum        = 0,
+                       .maximum        = 31,
+                       .step           = 1,
+                       .default_value  = 3
+               },
+               .set = st6422_set_brightness,
+               .get = st6422_get_brightness
+       },
+#define CONTRAST_IDX 1
+       {
+               {
+                       .id             = V4L2_CID_CONTRAST,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "Contrast",
+                       .minimum        = 0,
+                       .maximum        = 15,
+                       .step           = 1,
+                       .default_value  = 11
+               },
+               .set = st6422_set_contrast,
+               .get = st6422_get_contrast
+       },
+#define GAIN_IDX 2
+       {
+               {
+                       .id             = V4L2_CID_GAIN,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "Gain",
+                       .minimum        = 0,
+                       .maximum        = 255,
+                       .step           = 1,
+                       .default_value  = 64
+               },
+               .set = st6422_set_gain,
+               .get = st6422_get_gain
+       },
+#define EXPOSURE_IDX 3
+       {
+               {
+                       .id             = V4L2_CID_EXPOSURE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "Exposure",
+                       .minimum        = 0,
+                       .maximum        = 1023,
+                       .step           = 1,
+                       .default_value  = 256
+               },
+               .set = st6422_set_exposure,
+               .get = st6422_get_exposure
+       },
+};
+
+static int st6422_probe(struct sd *sd)
+{
+       int i;
+       s32 *sensor_settings;
+
+       if (sd->bridge != BRIDGE_ST6422)
+               return -ENODEV;
+
+       info("st6422 sensor detected");
+
+       sensor_settings = kmalloc(ARRAY_SIZE(st6422_ctrl) * sizeof(s32),
+                                 GFP_KERNEL);
+       if (!sensor_settings)
+               return -ENOMEM;
+
+       sd->gspca_dev.cam.cam_mode = st6422_mode;
+       sd->gspca_dev.cam.nmodes = ARRAY_SIZE(st6422_mode);
+       sd->desc.ctrls = st6422_ctrl;
+       sd->desc.nctrls = ARRAY_SIZE(st6422_ctrl);
+       sd->sensor_priv = sensor_settings;
+
+       for (i = 0; i < sd->desc.nctrls; i++)
+               sensor_settings[i] = st6422_ctrl[i].qctrl.default_value;
+
+       return 0;
+}
+
+static int st6422_init(struct sd *sd)
+{
+       int err = 0, i;
+
+       const u16 st6422_bridge_init[][2] = {
+               { STV_ISO_ENABLE, 0x00 }, /* disable capture */
+               { 0x1436, 0x00 },
+               { 0x1432, 0x03 },       /* 0x00-0x1F brightness */
+               { 0x143a, 0xF9 },       /* 0x00-0x0F contrast */
+               { 0x0509, 0x38 },       /* R */
+               { 0x050a, 0x38 },       /* G */
+               { 0x050b, 0x38 },       /* B */
+               { 0x050c, 0x2A },
+               { 0x050d, 0x01 },
+
+
+               { 0x1431, 0x00 },       /* 0x00-0x07 ??? */
+               { 0x1433, 0x34 },       /* 160x120, 0x00-0x01 night filter */
+               { 0x1438, 0x18 },       /* 640x480 */
+/* 18 bayes */
+/* 10 compressed? */
+
+               { 0x1439, 0x00 },
+/* antiflimmer??  0xa2 ger perfekt bild mot monitor */
+
+               { 0x143b, 0x05 },
+               { 0x143c, 0x00 },       /* 0x00-0x01 - ??? */
+
+
+/* shutter time 0x0000-0x03FF */
+/* low value  give good picures on moving objects (but requires much light) */
+/* high value gives good picures in darkness (but tends to be overexposed) */
+               { 0x143e, 0x01 },
+               { 0x143d, 0x00 },
+
+               { 0x1442, 0xe2 },
+/* write: 1x1x xxxx */
+/* read:  1x1x xxxx */
+/*        bit 5 == button pressed and hold if 0 */
+/* write 0xe2,0xea */
+
+/* 0x144a */
+/* 0x00 init */
+/* bit 7 == button has been pressed, but not handled */
+
+/* interrupt */
+/* if(urb->iso_frame_desc[i].status == 0x80) { */
+/* if(urb->iso_frame_desc[i].status == 0x88) { */
+
+               { 0x1500, 0xd0 },
+               { 0x1500, 0xd0 },
+               { 0x1500, 0x50 },       /* 0x00 - 0xFF  0x80 == compr ? */
+
+               { 0x1501, 0xaf },
+/* high val-> ljus area blir morkare. */
+/* low val -> ljus area blir ljusare. */
+               { 0x1502, 0xc2 },
+/* high val-> ljus area blir morkare. */
+/* low val -> ljus area blir ljusare. */
+               { 0x1503, 0x45 },
+/* high val-> ljus area blir morkare. */
+/* low val -> ljus area blir ljusare. */
+
+               { 0x1505, 0x02 },
+/* 2  : 324x248  80352 bytes */
+/* 7  : 248x162  40176 bytes */
+/* c+f: 162*124  20088 bytes */
+
+               { 0x150e, 0x8e },
+               { 0x150f, 0x37 },
+               { 0x15c0, 0x00 },
+               { 0x15c1, 1023 }, /* 160x120, ISOC_PACKET_SIZE */
+               { 0x15c3, 0x08 },       /* 0x04/0x14 ... test pictures ??? */
+
+
+               { 0x143f, 0x01 },       /* commit settings */
+
+       };
+
+       for (i = 0; i < ARRAY_SIZE(st6422_bridge_init) && !err; i++) {
+               err = stv06xx_write_bridge(sd, st6422_bridge_init[i][0],
+                                              st6422_bridge_init[i][1]);
+       }
+
+       return err;
+}
+
+static void st6422_disconnect(struct sd *sd)
+{
+       sd->sensor = NULL;
+       kfree(sd->sensor_priv);
+}
+
+static int st6422_start(struct sd *sd)
+{
+       int err, packet_size;
+       struct cam *cam = &sd->gspca_dev.cam;
+       s32 *sensor_settings = sd->sensor_priv;
+       struct usb_host_interface *alt;
+       struct usb_interface *intf;
+
+       intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
+       alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
+       if (!alt) {
+               PDEBUG(D_ERR, "Couldn't get altsetting");
+               return -EIO;
+       }
+
+       packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+       err = stv06xx_write_bridge(sd, 0x15c1, packet_size);
+       if (err < 0)
+               return err;
+
+       if (cam->cam_mode[sd->gspca_dev.curr_mode].priv)
+               err = stv06xx_write_bridge(sd, 0x1505, 0x0f);
+       else
+               err = stv06xx_write_bridge(sd, 0x1505, 0x02);
+       if (err < 0)
+               return err;
+
+       err = st6422_set_brightness(&sd->gspca_dev,
+                                   sensor_settings[BRIGHTNESS_IDX]);
+       if (err < 0)
+               return err;
+
+       err = st6422_set_contrast(&sd->gspca_dev,
+                                 sensor_settings[CONTRAST_IDX]);
+       if (err < 0)
+               return err;
+
+       err = st6422_set_exposure(&sd->gspca_dev,
+                                 sensor_settings[EXPOSURE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = st6422_set_gain(&sd->gspca_dev,
+                             sensor_settings[GAIN_IDX]);
+       if (err < 0)
+               return err;
+
+       PDEBUG(D_STREAM, "Starting stream");
+
+       return 0;
+}
+
+static int st6422_stop(struct sd *sd)
+{
+       PDEBUG(D_STREAM, "Halting stream");
+
+       return 0;
+}
+
+static int st6422_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[BRIGHTNESS_IDX];
+
+       PDEBUG(D_V4L2, "Read brightness %d", *val);
+
+       return 0;
+}
+
+static int st6422_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       sensor_settings[BRIGHTNESS_IDX] = val;
+
+       if (!gspca_dev->streaming)
+               return 0;
+
+       /* val goes from 0 -> 31 */
+       PDEBUG(D_V4L2, "Set brightness to %d", val);
+       err = stv06xx_write_bridge(sd, 0x1432, val);
+       if (err < 0)
+               return err;
+
+       /* commit settings */
+       err = stv06xx_write_bridge(sd, 0x143f, 0x01);
+       return (err < 0) ? err : 0;
+}
+
+static int st6422_get_contrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[CONTRAST_IDX];
+
+       PDEBUG(D_V4L2, "Read contrast %d", *val);
+
+       return 0;
+}
+
+static int st6422_set_contrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       sensor_settings[CONTRAST_IDX] = val;
+
+       if (!gspca_dev->streaming)
+               return 0;
+
+       /* Val goes from 0 -> 15 */
+       PDEBUG(D_V4L2, "Set contrast to %d\n", val);
+       err = stv06xx_write_bridge(sd, 0x143a, 0xf0 | val);
+       if (err < 0)
+               return err;
+
+       /* commit settings */
+       err = stv06xx_write_bridge(sd, 0x143f, 0x01);
+       return (err < 0) ? err : 0;
+}
+
+static int st6422_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[GAIN_IDX];
+
+       PDEBUG(D_V4L2, "Read gain %d", *val);
+
+       return 0;
+}
+
+static int st6422_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       sensor_settings[GAIN_IDX] = val;
+
+       if (!gspca_dev->streaming)
+               return 0;
+
+       PDEBUG(D_V4L2, "Set gain to %d", val);
+
+       /* Set red, green, blue, gain */
+       err = stv06xx_write_bridge(sd, 0x0509, val);
+       if (err < 0)
+               return err;
+
+       err = stv06xx_write_bridge(sd, 0x050a, val);
+       if (err < 0)
+               return err;
+
+       err = stv06xx_write_bridge(sd, 0x050b, val);
+       if (err < 0)
+               return err;
+
+       /* 2 mystery writes */
+       err = stv06xx_write_bridge(sd, 0x050c, 0x2a);
+       if (err < 0)
+               return err;
+
+       err = stv06xx_write_bridge(sd, 0x050d, 0x01);
+       if (err < 0)
+               return err;
+
+       /* commit settings */
+       err = stv06xx_write_bridge(sd, 0x143f, 0x01);
+       return (err < 0) ? err : 0;
+}
+
+static int st6422_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[EXPOSURE_IDX];
+
+       PDEBUG(D_V4L2, "Read exposure %d", *val);
+
+       return 0;
+}
+
+static int st6422_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       sensor_settings[EXPOSURE_IDX] = val;
+
+       if (!gspca_dev->streaming)
+               return 0;
+
+       PDEBUG(D_V4L2, "Set exposure to %d\n", val);
+       err = stv06xx_write_bridge(sd, 0x143d, val & 0xff);
+       if (err < 0)
+               return err;
+
+       err = stv06xx_write_bridge(sd, 0x143e, val >> 8);
+       if (err < 0)
+               return err;
+
+       /* commit settings */
+       err = stv06xx_write_bridge(sd, 0x143f, 0x01);
+       return (err < 0) ? err : 0;
+}
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h
new file mode 100644 (file)
index 0000000..b2d45fe
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Support for the sensor part which is integrated (I think) into the
+ * st6422 stv06xx alike bridge, as its integrated there are no i2c writes
+ * but instead direct bridge writes.
+ *
+ * Copyright (c) 2009 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Strongly based on qc-usb-messenger, which is:
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ *                   Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef STV06XX_ST6422_H_
+#define STV06XX_ST6422_H_
+
+#include "stv06xx_sensor.h"
+
+static int st6422_probe(struct sd *sd);
+static int st6422_start(struct sd *sd);
+static int st6422_init(struct sd *sd);
+static int st6422_stop(struct sd *sd);
+static void st6422_disconnect(struct sd *sd);
+
+/* V4L2 controls supported by the driver */
+static int st6422_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int st6422_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
+static int st6422_get_contrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int st6422_set_contrast(struct gspca_dev *gspca_dev, __s32 val);
+static int st6422_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int st6422_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int st6422_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int st6422_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+
+const struct stv06xx_sensor stv06xx_sensor_st6422 = {
+       .name = "ST6422",
+       .init = st6422_init,
+       .probe = st6422_probe,
+       .start = st6422_start,
+       .stop = st6422_stop,
+       .disconnect = st6422_disconnect,
+};
+
+#endif
index 84995bcf4a75a6207ad6beb24191ed23b18809ec..a3b77ed3f08949a58729ea1edda921cb762d0dc7 100644 (file)
@@ -60,6 +60,8 @@ int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
 
        switch (qctrl->id) {
        /* Standard V4L2 controls */
+       case V4L2_CID_USER_CLASS:
+               return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
        case V4L2_CID_BRIGHTNESS:
        case V4L2_CID_HUE:
        case V4L2_CID_SATURATION:
index 459c04cbf69dd0fb9b23efeb869cda79d7135e15..4d794b42d6cdeb1c3f4ce46904a86e7f160dbe2f 100644 (file)
@@ -280,15 +280,9 @@ static int mt9m001_try_fmt(struct soc_camera_device *icd,
 {
        struct v4l2_pix_format *pix = &f->fmt.pix;
 
-       if (pix->height < 32 + icd->y_skip_top)
-               pix->height = 32 + icd->y_skip_top;
-       if (pix->height > 1024 + icd->y_skip_top)
-               pix->height = 1024 + icd->y_skip_top;
-       if (pix->width < 48)
-               pix->width = 48;
-       if (pix->width > 1280)
-               pix->width = 1280;
-       pix->width &= ~0x01; /* has to be even, unsure why was ~3 */
+       v4l_bound_align_image(&pix->width, 48, 1280, 1,
+                             &pix->height, 32 + icd->y_skip_top,
+                             1024 + icd->y_skip_top, 0, 0);
 
        return 0;
 }
index f72aeb7c4deb974afa6241566fd8b922858c9090..4207fb342670d47284e8d5f78db28f83744572ab 100644 (file)
@@ -385,17 +385,9 @@ static int mt9t031_try_fmt(struct soc_camera_device *icd,
 {
        struct v4l2_pix_format *pix = &f->fmt.pix;
 
-       if (pix->height < MT9T031_MIN_HEIGHT)
-               pix->height = MT9T031_MIN_HEIGHT;
-       if (pix->height > MT9T031_MAX_HEIGHT)
-               pix->height = MT9T031_MAX_HEIGHT;
-       if (pix->width < MT9T031_MIN_WIDTH)
-               pix->width = MT9T031_MIN_WIDTH;
-       if (pix->width > MT9T031_MAX_WIDTH)
-               pix->width = MT9T031_MAX_WIDTH;
-
-       pix->width &= ~0x01; /* has to be even */
-       pix->height &= ~0x01; /* has to be even */
+       v4l_bound_align_image(
+               &pix->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1,
+               &pix->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0);
 
        return 0;
 }
index be20d312b1dc5784f8c85a63a367c2e219d467c0..dbdcc86ae50dbb86d0d2dbf2df30fc5229271903 100644 (file)
@@ -364,15 +364,9 @@ static int mt9v022_try_fmt(struct soc_camera_device *icd,
 {
        struct v4l2_pix_format *pix = &f->fmt.pix;
 
-       if (pix->height < 32 + icd->y_skip_top)
-               pix->height = 32 + icd->y_skip_top;
-       if (pix->height > 480 + icd->y_skip_top)
-               pix->height = 480 + icd->y_skip_top;
-       if (pix->width < 48)
-               pix->width = 48;
-       if (pix->width > 752)
-               pix->width = 752;
-       pix->width &= ~0x03; /* ? */
+       v4l_bound_align_image(&pix->width, 48, 752, 2 /* ? */,
+                             &pix->height, 32 + icd->y_skip_top,
+                             480 + icd->y_skip_top, 0, 0);
 
        return 0;
 }
index 08cfd3e4ae8abe8c6b96059b35c76fb42f1db94b..0bc2cf573c764a0aedde5e0353d43cbc8c75176f 100644 (file)
@@ -211,8 +211,6 @@ static const int i2c_detect_tries = 5;
 static struct usb_device_id device_table [] = {
        { USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
        { USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
-       { USB_DEVICE(VEND_OMNIVISION, PROD_OV518) },
-       { USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) },
        { USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) },
        { }  /* Terminating entry */
 };
index 10ef1a2c13eac39adbff08bed37d1c4daa0390e6..416933ca607d28ac6a500907d9e6282399c6775b 100644 (file)
@@ -48,11 +48,13 @@ static const int routing_scheme0[] = {
                                                MSP_DSP_IN_SCART),
 };
 
-static const struct routing_scheme routing_schemes[] = {
-       [PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
-               .def = routing_scheme0,
-               .cnt = ARRAY_SIZE(routing_scheme0),
-       },
+static const struct routing_scheme routing_def0 = {
+       .def = routing_scheme0,
+       .cnt = ARRAY_SIZE(routing_scheme0),
+};
+
+static const struct routing_scheme *routing_schemes[] = {
+       [PVR2_ROUTING_SCHEME_HAUPPAUGE] = &routing_def0,
 };
 
 void pvr2_msp3400_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
@@ -65,7 +67,7 @@ void pvr2_msp3400_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
                pvr2_trace(PVR2_TRACE_CHIPS, "subdev msp3400 v4l2 set_stereo");
 
                if ((sid < ARRAY_SIZE(routing_schemes)) &&
-                   ((sp = routing_schemes + sid) != NULL) &&
+                   ((sp = routing_schemes[sid]) != NULL) &&
                    (hdw->input_val >= 0) &&
                    (hdw->input_val < sp->cnt)) {
                        input = sp->def[hdw->input_val];
index 9023adf3fdcc5f587e64db693d683e65703e895c..68980e19409f8f4a053388530b2c03d8d9e05e8c 100644 (file)
@@ -49,11 +49,13 @@ static const int routing_scheme1[] = {
        [PVR2_CVAL_INPUT_SVIDEO] =  0,
 };
 
-static const struct routing_scheme routing_schemes[] = {
-       [PVR2_ROUTING_SCHEME_ONAIR] = {
-               .def = routing_scheme1,
-               .cnt = ARRAY_SIZE(routing_scheme1),
-       },
+static const struct routing_scheme routing_def1 = {
+       .def = routing_scheme1,
+       .cnt = ARRAY_SIZE(routing_scheme1),
+};
+
+static const struct routing_scheme *routing_schemes[] = {
+       [PVR2_ROUTING_SCHEME_ONAIR] = &routing_def1,
 };
 
 
@@ -65,12 +67,11 @@ void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
                u32 input;
                pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_input(%d)",
                           hdw->input_val);
-               if ((sid < ARRAY_SIZE(routing_schemes)) &&
-                   ((sp = routing_schemes + sid) != NULL) &&
-                   (hdw->input_val >= 0) &&
-                   (hdw->input_val < sp->cnt)) {
-                       input = sp->def[hdw->input_val];
-               } else {
+               sp = (sid < ARRAY_SIZE(routing_schemes)) ?
+                       routing_schemes[sid] : NULL;
+               if ((sp == NULL) ||
+                   (hdw->input_val < 0) ||
+                   (hdw->input_val >= sp->cnt)) {
                        pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                                   "*** WARNING *** subdev v4l2 set_input:"
                                   " Invalid routing scheme (%u)"
@@ -78,6 +79,7 @@ void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
                                   sid, hdw->input_val);
                        return;
                }
+               input = sp->def[hdw->input_val];
                sd->ops->audio->s_routing(sd, input, 0, 0);
        }
 }
index 05e52358ae495a121c94c6722e8f536b5d418eb4..82c13583575350ded7b32edabb8efb2f498a9ca0 100644 (file)
@@ -68,6 +68,11 @@ static const struct routing_scheme_item routing_scheme0[] = {
        },
 };
 
+static const struct routing_scheme routing_def0 = {
+       .def = routing_scheme0,
+       .cnt = ARRAY_SIZE(routing_scheme0),
+};
+
 /* Specific to gotview device */
 static const struct routing_scheme_item routing_schemegv[] = {
        [PVR2_CVAL_INPUT_TV] = {
@@ -90,15 +95,14 @@ static const struct routing_scheme_item routing_schemegv[] = {
        },
 };
 
-static const struct routing_scheme routing_schemes[] = {
-       [PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
-               .def = routing_scheme0,
-               .cnt = ARRAY_SIZE(routing_scheme0),
-       },
-       [PVR2_ROUTING_SCHEME_GOTVIEW] = {
-               .def = routing_schemegv,
-               .cnt = ARRAY_SIZE(routing_schemegv),
-       },
+static const struct routing_scheme routing_defgv = {
+       .def = routing_schemegv,
+       .cnt = ARRAY_SIZE(routing_schemegv),
+};
+
+static const struct routing_scheme *routing_schemes[] = {
+       [PVR2_ROUTING_SCHEME_HAUPPAUGE] = &routing_def0,
+       [PVR2_ROUTING_SCHEME_GOTVIEW] = &routing_defgv,
 };
 
 void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
@@ -110,13 +114,11 @@ void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
                const struct routing_scheme *sp;
                unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
 
-               if ((sid < ARRAY_SIZE(routing_schemes)) &&
-                   ((sp = routing_schemes + sid) != NULL) &&
-                   (hdw->input_val >= 0) &&
-                   (hdw->input_val < sp->cnt)) {
-                       vid_input = sp->def[hdw->input_val].vid;
-                       aud_input = sp->def[hdw->input_val].aud;
-               } else {
+               sp = (sid < ARRAY_SIZE(routing_schemes)) ?
+                       routing_schemes[sid] : NULL;
+               if ((sp == NULL) ||
+                   (hdw->input_val < 0) ||
+                   (hdw->input_val >= sp->cnt)) {
                        pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                                   "*** WARNING *** subdev cx2584x set_input:"
                                   " Invalid routing scheme (%u)"
@@ -124,7 +126,8 @@ void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
                                   sid, hdw->input_val);
                        return;
                }
-
+               vid_input = sp->def[hdw->input_val].vid;
+               aud_input = sp->def[hdw->input_val].aud;
                pvr2_trace(PVR2_TRACE_CHIPS,
                           "subdev cx2584x set_input vid=0x%x aud=0x%x",
                           vid_input, aud_input);
index 0c745b142fb73999c77067aa83ff7eccd29d8bbf..cbc388729d7751fe18ef1afd86d9f5cdac8d0793 100644 (file)
@@ -85,8 +85,8 @@ MODULE_PARM_DESC(video_std,"specify initial video standard");
 module_param_array(tolerance,    int, NULL, 0444);
 MODULE_PARM_DESC(tolerance,"specify stream error tolerance");
 
-/* US Broadcast channel 7 (175.25 MHz) */
-static int default_tv_freq    = 175250000L;
+/* US Broadcast channel 3 (61.25 MHz), to help with testing */
+static int default_tv_freq    = 61250000L;
 /* 104.3 MHz, a usable FM station for my area */
 static int default_radio_freq = 104300000L;
 
@@ -1987,6 +1987,34 @@ static unsigned int pvr2_copy_i2c_addr_list(
 }
 
 
+static void pvr2_hdw_cx25840_vbi_hack(struct pvr2_hdw *hdw)
+{
+       /*
+         Mike Isely <isely@pobox.com> 19-Nov-2006 - This bit of nuttiness
+         for cx25840 causes that module to correctly set up its video
+         scaling.  This is really a problem in the cx25840 module itself,
+         but we work around it here.  The problem has not been seen in
+         ivtv because there VBI is supported and set up.  We don't do VBI
+         here (at least not yet) and thus we never attempted to even set
+         it up.
+       */
+       struct v4l2_format fmt;
+       if (hdw->decoder_client_id != PVR2_CLIENT_ID_CX25840) {
+               /* We're not using a cx25840 so don't enable the hack */
+               return;
+       }
+
+       pvr2_trace(PVR2_TRACE_INIT,
+                  "Module ID %u:"
+                  " Executing cx25840 VBI hack",
+                  hdw->decoder_client_id);
+       memset(&fmt, 0, sizeof(fmt));
+       fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+       v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id,
+                            video, s_fmt, &fmt);
+}
+
+
 static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
                                const struct pvr2_device_client_desc *cd)
 {
@@ -2078,30 +2106,6 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
        /* client-specific setup... */
        switch (mid) {
        case PVR2_CLIENT_ID_CX25840:
-               hdw->decoder_client_id = mid;
-               {
-                       /*
-                         Mike Isely <isely@pobox.com> 19-Nov-2006 - This
-                         bit of nuttiness for cx25840 causes that module
-                         to correctly set up its video scaling.  This is
-                         really a problem in the cx25840 module itself,
-                         but we work around it here.  The problem has not
-                         been seen in ivtv because there VBI is supported
-                         and set up.  We don't do VBI here (at least not
-                         yet) and thus we never attempted to even set it
-                         up.
-                       */
-                       struct v4l2_format fmt;
-                       pvr2_trace(PVR2_TRACE_INIT,
-                                  "Module ID %u:"
-                                  " Executing cx25840 VBI hack",
-                                  mid);
-                       memset(&fmt, 0, sizeof(fmt));
-                       fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
-                       v4l2_device_call_all(&hdw->v4l2_dev, mid,
-                                            video, s_fmt, &fmt);
-               }
-               break;
        case PVR2_CLIENT_ID_SAA7115:
                hdw->decoder_client_id = mid;
                break;
@@ -2202,6 +2206,8 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
                cptr->info->set_value(cptr,~0,cptr->info->default_value);
        }
 
+       pvr2_hdw_cx25840_vbi_hack(hdw);
+
        /* Set up special default values for the television and radio
           frequencies here.  It's not really important what these defaults
           are, but I set them to something usable in the Chicago area just
@@ -2954,6 +2960,7 @@ static void pvr2_subdev_update(struct pvr2_hdw *hdw)
                        vs = hdw->std_mask_cur;
                        v4l2_device_call_all(&hdw->v4l2_dev, 0,
                                             core, s_std, vs);
+                       pvr2_hdw_cx25840_vbi_hack(hdw);
                }
                hdw->tuner_signal_stale = !0;
                hdw->cropcap_stale = !0;
@@ -4076,6 +4083,7 @@ int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw)
        if (hdw->decoder_client_id) {
                v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id,
                                     core, reset, 0);
+               pvr2_hdw_cx25840_vbi_hack(hdw);
                return 0;
        }
        pvr2_trace(PVR2_TRACE_INIT,
index d2fe7c8f2c3a2cb7b6aafe42dfb8fcc46308e024..4c96cf48c79627125b10cce2178141015c4d03d2 100644 (file)
@@ -54,6 +54,11 @@ static const int routing_scheme0[] = {
        [PVR2_CVAL_INPUT_SVIDEO] =  SAA7115_SVIDEO2,
 };
 
+static const struct routing_scheme routing_def0 = {
+       .def = routing_scheme0,
+       .cnt = ARRAY_SIZE(routing_scheme0),
+};
+
 static const int routing_scheme1[] = {
        [PVR2_CVAL_INPUT_TV] = SAA7115_COMPOSITE4,
        [PVR2_CVAL_INPUT_RADIO] = SAA7115_COMPOSITE5,
@@ -61,15 +66,14 @@ static const int routing_scheme1[] = {
        [PVR2_CVAL_INPUT_SVIDEO] =  SAA7115_SVIDEO2, /* or SVIDEO0, it seems */
 };
 
-static const struct routing_scheme routing_schemes[] = {
-       [PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
-               .def = routing_scheme0,
-               .cnt = ARRAY_SIZE(routing_scheme0),
-       },
-       [PVR2_ROUTING_SCHEME_ONAIR] = {
-               .def = routing_scheme1,
-               .cnt = ARRAY_SIZE(routing_scheme1),
-       },
+static const struct routing_scheme routing_def1 = {
+       .def = routing_scheme1,
+       .cnt = ARRAY_SIZE(routing_scheme1),
+};
+
+static const struct routing_scheme *routing_schemes[] = {
+       [PVR2_ROUTING_SCHEME_HAUPPAUGE] = &routing_def0,
+       [PVR2_ROUTING_SCHEME_ONAIR] = &routing_def1,
 };
 
 void pvr2_saa7115_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
@@ -81,12 +85,12 @@ void pvr2_saa7115_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
 
                pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_input(%d)",
                           hdw->input_val);
-               if ((sid < ARRAY_SIZE(routing_schemes)) &&
-                   ((sp = routing_schemes + sid) != NULL) &&
-                   (hdw->input_val >= 0) &&
-                   (hdw->input_val < sp->cnt)) {
-                       input = sp->def[hdw->input_val];
-               } else {
+
+               sp = (sid < ARRAY_SIZE(routing_schemes)) ?
+                       routing_schemes[sid] : NULL;
+               if ((sp == NULL) ||
+                   (hdw->input_val < 0) ||
+                   (hdw->input_val >= sp->cnt)) {
                        pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                                   "*** WARNING *** subdev v4l2 set_input:"
                                   " Invalid routing scheme (%u)"
@@ -94,6 +98,7 @@ void pvr2_saa7115_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
                                   sid, hdw->input_val);
                        return;
                }
+               input = sp->def[hdw->input_val];
                sd->ops->video->s_routing(sd, input, 0, 0);
        }
 }
index f60de40fd21f79d17274dc0fe3769a84639d9f6a..46e0d8ad880fc58e56a3928347e52907f6e70cb7 100644 (file)
                        CICR0_PERRM | CICR0_QDM | CICR0_CDM | CICR0_SOFM | \
                        CICR0_EOFM | CICR0_FOM)
 
-/*
- * YUV422P picture size should be a multiple of 16, so the heuristic aligns
- * height, width on 4 byte boundaries to reach the 16 multiple for the size.
- */
-#define YUV422P_X_Y_ALIGN 4
-#define YUV422P_SIZE_ALIGN YUV422P_X_Y_ALIGN * YUV422P_X_Y_ALIGN
-
 /*
  * Structures
  */
@@ -1398,28 +1391,15 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
                return -EINVAL;
        }
 
-       /* limit to pxa hardware capabilities */
-       if (pix->height < 32)
-               pix->height = 32;
-       if (pix->height > 2048)
-               pix->height = 2048;
-       if (pix->width < 48)
-               pix->width = 48;
-       if (pix->width > 2048)
-               pix->width = 2048;
-       pix->width &= ~0x01;
-
        /*
-        * YUV422P planar format requires images size to be a 16 bytes
-        * multiple. If not, zeros will be inserted between Y and U planes, and
-        * U and V planes, and YUV422P standard would be violated.
+        * Limit to pxa hardware capabilities.  YUV422P planar format requires
+        * images size to be a multiple of 16 bytes.  If not, zeros will be
+        * inserted between Y and U planes, and U and V planes, which violates
+        * the YUV422P standard.
         */
-       if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUV422P) {
-               if (!IS_ALIGNED(pix->width * pix->height, YUV422P_SIZE_ALIGN))
-                       pix->height = ALIGN(pix->height, YUV422P_X_Y_ALIGN);
-               if (!IS_ALIGNED(pix->width * pix->height, YUV422P_SIZE_ALIGN))
-                       pix->width = ALIGN(pix->width, YUV422P_X_Y_ALIGN);
-       }
+       v4l_bound_align_image(&pix->width, 48, 2048, 1,
+                             &pix->height, 32, 2048, 0,
+                             xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUV422P ? 4 : 0);
 
        pix->bytesperline = pix->width *
                DIV_ROUND_UP(xlate->host_fmt->depth, 8);
index e305c1674cee2415432519b2b6caf28062411cd0..ba87128542e03254aa27e5ab3f55dbcca869cffa 100644 (file)
@@ -1640,15 +1640,8 @@ static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
        }
 
        f->fmt.pix.field = field;
-       if (f->fmt.pix.width  < 48)
-               f->fmt.pix.width  = 48;
-       if (f->fmt.pix.height < 32)
-               f->fmt.pix.height = 32;
-       if (f->fmt.pix.width > maxw)
-               f->fmt.pix.width = maxw;
-       if (f->fmt.pix.height > maxh)
-               f->fmt.pix.height = maxh;
-       f->fmt.pix.width &= ~0x03;
+       v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2,
+                             &f->fmt.pix.height, 32, maxh, 0, 0);
        f->fmt.pix.bytesperline =
                (f->fmt.pix.width * fmt->depth) >> 3;
        f->fmt.pix.sizeimage =
index d369e8409ab8bfcd9bb677d189a36b0d7d8068e4..0db88a53d92c54c60830862c6867d4dbe175bdcb 100644 (file)
@@ -689,16 +689,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
 
        /* FIXME: calculate using depth and bus width */
 
-       if (f->fmt.pix.height < 4)
-               f->fmt.pix.height = 4;
-       if (f->fmt.pix.height > 1920)
-               f->fmt.pix.height = 1920;
-       if (f->fmt.pix.width < 2)
-               f->fmt.pix.width = 2;
-       if (f->fmt.pix.width > 2560)
-               f->fmt.pix.width = 2560;
-       f->fmt.pix.width &= ~0x01;
-       f->fmt.pix.height &= ~0x03;
+       v4l_bound_align_image(&f->fmt.pix.width, 2, 2560, 1,
+                             &f->fmt.pix.height, 4, 1920, 2, 0);
 
        f->fmt.pix.bytesperline = f->fmt.pix.width *
                DIV_ROUND_UP(xlate->host_fmt->depth, 8);
index b30c492482175ada8427e87ce36bc8a80405d17d..b90e9da3167dde4e38df0037832375e9aaa48e3f 100644 (file)
@@ -878,7 +878,7 @@ static int tcm825x_probe(struct i2c_client *client,
        return rval;
 }
 
-static int __exit tcm825x_remove(struct i2c_client *client)
+static int tcm825x_remove(struct i2c_client *client)
 {
        struct tcm825x_sensor *sensor = i2c_get_clientdata(client);
 
@@ -902,7 +902,7 @@ static struct i2c_driver tcm825x_i2c_driver = {
                .name = TCM825X_NAME,
        },
        .probe  = tcm825x_probe,
-       .remove = __exit_p(tcm825x_remove),
+       .remove = tcm825x_remove,
        .id_table = tcm825x_id,
 };
 
index e4cb99c1f94be8e930c4aa858ec4a5de69aab019..adb1c044ad7dedcbaf4687e5c934fa196e822886 100644 (file)
@@ -38,10 +38,13 @@ config USB_KONICAWC
          module will be called konicawc.
 
 config USB_QUICKCAM_MESSENGER
-       tristate "USB Logitech Quickcam Messenger"
+       tristate "USB Logitech Quickcam Messenger (DEPRECATED)"
        depends on VIDEO_V4L1
        select VIDEO_USBVIDEO
        ---help---
+         This driver is DEPRECATED please use the gspca stv06xx module
+         instead.
+
          Say Y or M here to enable support for the USB Logitech Quickcam
          Messenger webcam.
 
index f96475626da78949079318fe4372edf0ae7dd37e..b91d66a767d70a3fa825d9c309941fc358d9ee94 100644 (file)
@@ -802,6 +802,17 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
        /* Decrease the module use count to match the first try_module_get. */
        module_put(client->driver->driver.owner);
 
+       if (sd) {
+               /* We return errors from v4l2_subdev_call only if we have the
+                  callback as the .s_config is not mandatory */
+               int err = v4l2_subdev_call(sd, core, s_config, 0, NULL);
+
+               if (err && err != -ENOIOCTLCMD) {
+                       v4l2_device_unregister_subdev(sd);
+                       sd = NULL;
+               }
+       }
+
 error:
        /* If we have a client but no subdev, then something went wrong and
           we must unregister the client. */
@@ -852,6 +863,17 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct v4l2_device *v4l2_dev,
        /* Decrease the module use count to match the first try_module_get. */
        module_put(client->driver->driver.owner);
 
+       if (sd) {
+               /* We return errors from v4l2_subdev_call only if we have the
+                  callback as the .s_config is not mandatory */
+               int err = v4l2_subdev_call(sd, core, s_config, 0, NULL);
+
+               if (err && err != -ENOIOCTLCMD) {
+                       v4l2_device_unregister_subdev(sd);
+                       sd = NULL;
+               }
+       }
+
 error:
        /* If we have a client but no subdev, then something went wrong and
           we must unregister the client. */
@@ -872,6 +894,89 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev_addr(struct v4l2_device *v4l2_dev
 }
 EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev_addr);
 
+/* Load an i2c sub-device. */
+struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
+               struct i2c_adapter *adapter, const char *module_name,
+               struct i2c_board_info *info, const unsigned short *probe_addrs)
+{
+       struct v4l2_subdev *sd = NULL;
+       struct i2c_client *client;
+
+       BUG_ON(!v4l2_dev);
+
+       if (module_name)
+               request_module(module_name);
+
+       /* Create the i2c client */
+       if (info->addr == 0 && probe_addrs)
+               client = i2c_new_probed_device(adapter, info, probe_addrs);
+       else
+               client = i2c_new_device(adapter, info);
+
+       /* Note: by loading the module first we are certain that c->driver
+          will be set if the driver was found. If the module was not loaded
+          first, then the i2c core tries to delay-load the module for us,
+          and then c->driver is still NULL until the module is finally
+          loaded. This delay-load mechanism doesn't work if other drivers
+          want to use the i2c device, so explicitly loading the module
+          is the best alternative. */
+       if (client == NULL || client->driver == NULL)
+               goto error;
+
+       /* Lock the module so we can safely get the v4l2_subdev pointer */
+       if (!try_module_get(client->driver->driver.owner))
+               goto error;
+       sd = i2c_get_clientdata(client);
+
+       /* Register with the v4l2_device which increases the module's
+          use count as well. */
+       if (v4l2_device_register_subdev(v4l2_dev, sd))
+               sd = NULL;
+       /* Decrease the module use count to match the first try_module_get. */
+       module_put(client->driver->driver.owner);
+
+       if (sd) {
+               /* We return errors from v4l2_subdev_call only if we have the
+                  callback as the .s_config is not mandatory */
+               int err = v4l2_subdev_call(sd, core, s_config,
+                               info->irq, info->platform_data);
+
+               if (err && err != -ENOIOCTLCMD) {
+                       v4l2_device_unregister_subdev(sd);
+                       sd = NULL;
+               }
+       }
+
+error:
+       /* If we have a client but no subdev, then something went wrong and
+          we must unregister the client. */
+       if (client && sd == NULL)
+               i2c_unregister_device(client);
+       return sd;
+}
+EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board);
+
+struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
+               struct i2c_adapter *adapter,
+               const char *module_name, const char *client_type,
+               int irq, void *platform_data,
+               u8 addr, const unsigned short *probe_addrs)
+{
+       struct i2c_board_info info;
+
+       /* Setup the i2c board info with the device type and
+          the device address. */
+       memset(&info, 0, sizeof(info));
+       strlcpy(info.type, client_type, sizeof(info.type));
+       info.addr = addr;
+       info.irq = irq;
+       info.platform_data = platform_data;
+
+       return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, module_name,
+                       &info, probe_addrs);
+}
+EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_cfg);
+
 /* Return i2c client address of v4l2_subdev. */
 unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd)
 {
@@ -916,4 +1021,78 @@ const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type)
 }
 EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs);
 
-#endif
+#endif /* defined(CONFIG_I2C) */
+
+/* Clamp x to be between min and max, aligned to a multiple of 2^align.  min
+ * and max don't have to be aligned, but there must be at least one valid
+ * value.  E.g., min=17,max=31,align=4 is not allowed as there are no multiples
+ * of 16 between 17 and 31.  */
+static unsigned int clamp_align(unsigned int x, unsigned int min,
+                               unsigned int max, unsigned int align)
+{
+       /* Bits that must be zero to be aligned */
+       unsigned int mask = ~((1 << align) - 1);
+
+       /* Round to nearest aligned value */
+       if (align)
+               x = (x + (1 << (align - 1))) & mask;
+
+       /* Clamp to aligned value of min and max */
+       if (x < min)
+               x = (min + ~mask) & mask;
+       else if (x > max)
+               x = max & mask;
+
+       return x;
+}
+
+/* Bound an image to have a width between wmin and wmax, and height between
+ * hmin and hmax, inclusive.  Additionally, the width will be a multiple of
+ * 2^walign, the height will be a multiple of 2^halign, and the overall size
+ * (width*height) will be a multiple of 2^salign.  The image may be shrunk
+ * or enlarged to fit the alignment constraints.
+ *
+ * The width or height maximum must not be smaller than the corresponding
+ * minimum.  The alignments must not be so high there are no possible image
+ * sizes within the allowed bounds.  wmin and hmin must be at least 1
+ * (don't use 0).  If you don't care about a certain alignment, specify 0,
+ * as 2^0 is 1 and one byte alignment is equivalent to no alignment.  If
+ * you only want to adjust downward, specify a maximum that's the same as
+ * the initial value.
+ */
+void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
+                          unsigned int walign,
+                          u32 *h, unsigned int hmin, unsigned int hmax,
+                          unsigned int halign, unsigned int salign)
+{
+       *w = clamp_align(*w, wmin, wmax, walign);
+       *h = clamp_align(*h, hmin, hmax, halign);
+
+       /* Usually we don't need to align the size and are done now. */
+       if (!salign)
+               return;
+
+       /* How much alignment do we have? */
+       walign = __ffs(*w);
+       halign = __ffs(*h);
+       /* Enough to satisfy the image alignment? */
+       if (walign + halign < salign) {
+               /* Max walign where there is still a valid width */
+               unsigned int wmaxa = __fls(wmax ^ (wmin - 1));
+               /* Max halign where there is still a valid height */
+               unsigned int hmaxa = __fls(hmax ^ (hmin - 1));
+
+               /* up the smaller alignment until we have enough */
+               do {
+                       if (halign >= hmaxa ||
+                           (walign <= halign && walign < wmaxa)) {
+                               *w = clamp_align(*w, wmin, wmax, walign + 1);
+                               walign = __ffs(*w);
+                       } else {
+                               *h = clamp_align(*h, hmin, hmax, halign + 1);
+                               halign = __ffs(*h);
+                       }
+               } while (halign + walign < salign);
+       }
+}
+EXPORT_SYMBOL_GPL(v4l_bound_align_image);
index fbfefae7886fac4cfc337a9d66b591ed9880fa11..cd72668584626974a4c59b2bc0c739c09d2a3360 100644 (file)
@@ -883,15 +883,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        maxh  = norm_maxh();
 
        f->fmt.pix.field = field;
-       if (f->fmt.pix.height < 32)
-               f->fmt.pix.height = 32;
-       if (f->fmt.pix.height > maxh)
-               f->fmt.pix.height = maxh;
-       if (f->fmt.pix.width < 48)
-               f->fmt.pix.width = 48;
-       if (f->fmt.pix.width > maxw)
-               f->fmt.pix.width = maxw;
-       f->fmt.pix.width &= ~0x03;
+       v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2,
+                             &f->fmt.pix.height, 32, maxh, 0, 0);
        f->fmt.pix.bytesperline =
                (f->fmt.pix.width * fmt->depth) >> 3;
        f->fmt.pix.sizeimage =
index f59b2bd07e898e44a738b4e38d769fb43e8fbfa1..6c3f23e31b5cd19ab2a6bf73726d045bea199753 100644 (file)
@@ -460,7 +460,7 @@ static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture);
 static int w9968cf_set_window(struct w9968cf_device*, struct video_window);
 static int w9968cf_postprocess_frame(struct w9968cf_device*,
                                     struct w9968cf_frame_t*);
-static int w9968cf_adjust_window_size(struct w9968cf_device*, u16* w, u16* h);
+static int w9968cf_adjust_window_size(struct w9968cf_device*, u32 *w, u32 *h);
 static void w9968cf_init_framelist(struct w9968cf_device*);
 static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num);
 static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**);
@@ -1763,8 +1763,7 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
        #define UNSC(x) ((x) >> 10)
 
        /* Make sure we are using a supported resolution */
-       if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width,
-                                             (u16*)&win.height)))
+       if ((err = w9968cf_adjust_window_size(cam, &win.width, &win.height)))
                goto error;
 
        /* Scaling factors */
@@ -1914,12 +1913,9 @@ error:
   Return 0 on success, -1 otherwise.
   --------------------------------------------------------------------------*/
 static int
-w9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height)
+w9968cf_adjust_window_size(struct w9968cf_device *cam, u32 *width, u32 *height)
 {
-       u16 maxw, maxh;
-
-       if ((*width < cam->minwidth) || (*height < cam->minheight))
-               return -ERANGE;
+       unsigned int maxw, maxh, align;
 
        maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
               w9968cf_vpp ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth)
@@ -1927,16 +1923,10 @@ w9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height)
        maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
               w9968cf_vpp ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
                           : cam->maxheight;
+       align = (cam->vpp_flag & VPP_DECOMPRESSION) ? 4 : 0;
 
-       if (*width > maxw)
-               *width = maxw;
-       if (*height > maxh)
-               *height = maxh;
-
-       if (cam->vpp_flag & VPP_DECOMPRESSION) {
-               *width  &= ~15L; /* multiple of 16 */
-               *height &= ~15L;
-       }
+       v4l_bound_align_image(width, cam->minwidth, maxw, align,
+                             height, cam->minheight, maxh, align, 0);
 
        PDBGG("Window size adjusted w=%u, h=%u ", *width, *height)
 
@@ -3043,8 +3033,8 @@ static long w9968cf_v4l_ioctl(struct file *filp,
                if (win.clipcount != 0 || win.flags != 0)
                        return -EINVAL;
 
-               if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width,
-                                                     (u16*)&win.height))) {
+               if ((err = w9968cf_adjust_window_size(cam, &win.width,
+                                                     &win.height))) {
                        DBG(4, "Resolution not supported (%ux%u). "
                               "VIDIOCSWIN failed", win.width, win.height)
                        return err;
@@ -3116,6 +3106,7 @@ static long w9968cf_v4l_ioctl(struct file *filp,
        {
                struct video_mmap mmap;
                struct w9968cf_frame_t* fr;
+               u32 w, h;
                int err = 0;
 
                if (copy_from_user(&mmap, arg, sizeof(mmap)))
@@ -3164,8 +3155,10 @@ static long w9968cf_v4l_ioctl(struct file *filp,
                   }
                }
 
-               if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width,
-                                                     (u16*)&mmap.height))) {
+               w = mmap.width; h = mmap.height;
+               err = w9968cf_adjust_window_size(cam, &w, &h);
+               mmap.width = w; mmap.height = h;
+               if (err) {
                        DBG(4, "Resolution not supported (%dx%d). "
                               "VIDIOCMCAPTURE failed",
                            mmap.width, mmap.height)
index 643cccaa1aab7fc377df18bbcee4eeee9d40fbb0..3d7df32a3d8706d30ac56a88fcbc720e7a25a6d6 100644 (file)
@@ -2088,16 +2088,10 @@ static int zoran_try_fmt_vid_cap(struct file *file, void *__fh,
                return -EINVAL;
        }
 
-       bpp = (zoran_formats[i].depth + 7) / 8;
-       fmt->fmt.pix.width &= ~((bpp == 2) ? 1 : 3);
-       if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
-               fmt->fmt.pix.width = BUZ_MAX_WIDTH;
-       if (fmt->fmt.pix.width < BUZ_MIN_WIDTH)
-               fmt->fmt.pix.width = BUZ_MIN_WIDTH;
-       if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
-               fmt->fmt.pix.height = BUZ_MAX_HEIGHT;
-       if (fmt->fmt.pix.height < BUZ_MIN_HEIGHT)
-               fmt->fmt.pix.height = BUZ_MIN_HEIGHT;
+       bpp = DIV_ROUND_UP(zoran_formats[i].depth, 8);
+       v4l_bound_align_image(
+               &fmt->fmt.pix.width, BUZ_MIN_WIDTH, BUZ_MAX_WIDTH, bpp == 2 ? 1 : 2,
+               &fmt->fmt.pix.height, BUZ_MIN_HEIGHT, BUZ_MAX_HEIGHT, 0, 0);
        mutex_unlock(&zr->resource_lock);
 
        return 0;
index 20e0b447e8e83a0ce07455de4d7f56215f43a568..55ff25244af44a1f2c51002ce8c78fe3b3b699e1 100644 (file)
@@ -3518,7 +3518,7 @@ retry_page:
                } else
                        mptsas_volume_delete(ioc, sas_info->fw.id);
        }
-       mutex_lock(&ioc->sas_device_info_mutex);
+       mutex_unlock(&ioc->sas_device_info_mutex);
 
        /* expanders */
        mutex_lock(&ioc->sas_topology_mutex);
@@ -3549,7 +3549,7 @@ retry_page:
                        goto redo_expander_scan;
                }
        }
-       mutex_lock(&ioc->sas_topology_mutex);
+       mutex_unlock(&ioc->sas_topology_mutex);
 }
 
 /**
index cd1008c19cd77c632a0f197243127b0b1d00859f..ca54996ffd0e74e4fe10362a50d5941bddd4e42f 100644 (file)
 #define twl_has_usb()  false
 #endif
 
+#if defined(CONFIG_TWL4030_WATCHDOG) || \
+       defined(CONFIG_TWL4030_WATCHDOG_MODULE)
+#define twl_has_watchdog()        true
+#else
+#define twl_has_watchdog()        false
+#endif
 
 /* Triton Core internal information (BEGIN) */
 
@@ -526,6 +532,12 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
                usb_transceiver = child;
        }
 
+       if (twl_has_watchdog()) {
+               child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
        if (twl_has_regulator()) {
                /*
                child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1);
index 44f77eb1180f4c57fbf523fc809ea08254ca8454..4d1515f45ba24657777370c151eb26e475f9b85e 100644 (file)
@@ -25,8 +25,6 @@
 #include <linux/delay.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
-#include <linux/module.h>
-
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 #define BCM_VLAN 1
 #endif
@@ -2521,9 +2519,9 @@ static struct cnic_dev *init_bnx2_cnic(struct net_device *dev)
        struct cnic_dev *cdev;
        struct cnic_local *cp;
        struct cnic_eth_dev *ethdev = NULL;
-       struct cnic_eth_dev *(*probe)(void *) = NULL;
+       struct cnic_eth_dev *(*probe)(struct net_device *) = NULL;
 
-       probe = __symbol_get("bnx2_cnic_probe");
+       probe = symbol_get(bnx2_cnic_probe);
        if (probe) {
                ethdev = (*probe)(dev);
                symbol_put_addr(probe);
index 06380963a34e225043bbebbe5b33da64fd41ed32..d1bce27ee99e9a28dc42f1773e889f88fd0b60f6 100644 (file)
@@ -296,4 +296,6 @@ extern int cnic_register_driver(int ulp_type, struct cnic_ulp_ops *ulp_ops);
 
 extern int cnic_unregister_driver(int ulp_type);
 
+extern struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev);
+
 #endif
index 5887e4764d220a7019439d98892b21d87039a2d3..f96948be0a449248243e6f423708dc4b9e1c2b53 100644 (file)
@@ -399,11 +399,14 @@ static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
        if (!mtts)
                return -ENOMEM;
 
+       dma_sync_single_for_cpu(&dev->pdev->dev, dma_handle,
+                               npages * sizeof (u64), DMA_TO_DEVICE);
+
        for (i = 0; i < npages; ++i)
                mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT);
 
-       dma_sync_single_for_cpu(&dev->pdev->dev, dma_handle,
-                               npages * sizeof (u64), DMA_TO_DEVICE);
+       dma_sync_single_for_device(&dev->pdev->dev, dma_handle,
+                                  npages * sizeof (u64), DMA_TO_DEVICE);
 
        return 0;
 }
@@ -547,11 +550,14 @@ int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list
        /* Make sure MPT status is visible before writing MTT entries */
        wmb();
 
+       dma_sync_single_for_cpu(&dev->pdev->dev, fmr->dma_handle,
+                               npages * sizeof(u64), DMA_TO_DEVICE);
+
        for (i = 0; i < npages; ++i)
                fmr->mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT);
 
-       dma_sync_single_for_cpu(&dev->pdev->dev, fmr->dma_handle,
-                               npages * sizeof(u64), DMA_TO_DEVICE);
+       dma_sync_single_for_device(&dev->pdev->dev, fmr->dma_handle,
+                                  npages * sizeof(u64), DMA_TO_DEVICE);
 
        fmr->mpt->key    = cpu_to_be32(key);
        fmr->mpt->lkey   = cpu_to_be32(key);
index 6a19ed9a1194aff51553bed7ad9384f5925d6779..9c23122f755fdae9b2c9de8937abf5b22bd1ec4e 100644 (file)
@@ -258,10 +258,21 @@ config SCSI_SCAN_ASYNC
          or async on the kernel's command line.
 
 config SCSI_WAIT_SCAN
-       tristate
+       tristate  # No prompt here, this is an invisible symbol.
        default m
        depends on SCSI
        depends on MODULES
+# scsi_wait_scan is a loadable module which waits until all the async scans are
+# complete.  The idea is to use it in initrd/ initramfs scripts.  You modprobe
+# it after all the modprobes of the root SCSI drivers and it will wait until
+# they have all finished scanning their buses before allowing the boot to
+# proceed.  (This method is not applicable if targets boot independently in
+# parallel with the initiator, or with transports with non-deterministic target
+# discovery schemes, or if a transport driver does not support scsi_wait_scan.)
+#
+# This symbol is not exposed as a prompt because little is to be gained by
+# disabling it, whereas people who accidentally switch it off may wonder why
+# their mkinitrd gets into trouble.
 
 menu "SCSI Transports"
        depends on SCSI
index b62b482e55e793286a947607e8992a5333483d98..1e9f7141102b631ba5f204f5a95c6cead2cfe0ff 100644 (file)
@@ -1,6 +1,8 @@
 config SCSI_BNX2_ISCSI
        tristate "Broadcom NetXtreme II iSCSI support"
        select SCSI_ISCSI_ATTRS
+       select NETDEVICES
+       select NETDEV_1000
        select CNIC
        depends on PCI
        ---help---
index 99c9125479023144954eb9ba02f93af6faabdd57..344fd53b9954c263ef1189ee489e40d54cd5055a 100644 (file)
@@ -206,6 +206,31 @@ int cxgb3i_ddp_find_page_index(unsigned long pgsz)
        return DDP_PGIDX_MAX;
 }
 
+/**
+ * cxgb3i_ddp_adjust_page_table - adjust page table with PAGE_SIZE
+ * return the ddp page index, if no match is found return DDP_PGIDX_MAX.
+ */
+int cxgb3i_ddp_adjust_page_table(void)
+{
+       int i;
+       unsigned int base_order, order;
+
+       if (PAGE_SIZE < (1UL << ddp_page_shift[0])) {
+               ddp_log_info("PAGE_SIZE 0x%lx too small, min. 0x%lx.\n",
+                               PAGE_SIZE, 1UL << ddp_page_shift[0]);
+               return -EINVAL;
+       }
+
+       base_order = get_order(1UL << ddp_page_shift[0]);
+       order = get_order(1 << PAGE_SHIFT);
+       for (i = 0; i < DDP_PGIDX_MAX; i++) {
+               /* first is the kernel page size, then just doubling the size */
+               ddp_page_order[i] = order - base_order + i;
+               ddp_page_shift[i] = PAGE_SHIFT + i;
+       }
+       return 0;
+}
+
 static inline void ddp_gl_unmap(struct pci_dev *pdev,
                                struct cxgb3i_gather_list *gl)
 {
@@ -598,30 +623,40 @@ int cxgb3i_adapter_ddp_info(struct t3cdev *tdev,
  * release all the resource held by the ddp pagepod manager for a given
  * adapter if needed
  */
-void cxgb3i_ddp_cleanup(struct t3cdev *tdev)
+
+static void ddp_cleanup(struct kref *kref)
 {
+       struct cxgb3i_ddp_info *ddp = container_of(kref,
+                                               struct cxgb3i_ddp_info,
+                                               refcnt);
        int i = 0;
+
+       ddp_log_info("kref release ddp 0x%p, t3dev 0x%p.\n", ddp, ddp->tdev);
+
+       ddp->tdev->ulp_iscsi = NULL;
+       while (i < ddp->nppods) {
+               struct cxgb3i_gather_list *gl = ddp->gl_map[i];
+               if (gl) {
+                       int npods = (gl->nelem + PPOD_PAGES_MAX - 1)
+                                       >> PPOD_PAGES_SHIFT;
+                       ddp_log_info("t3dev 0x%p, ddp %d + %d.\n",
+                                       ddp->tdev, i, npods);
+                       kfree(gl);
+                       ddp_free_gl_skb(ddp, i, npods);
+                       i += npods;
+               } else
+                       i++;
+       }
+       cxgb3i_free_big_mem(ddp);
+}
+
+void cxgb3i_ddp_cleanup(struct t3cdev *tdev)
+{
        struct cxgb3i_ddp_info *ddp = (struct cxgb3i_ddp_info *)tdev->ulp_iscsi;
 
        ddp_log_info("t3dev 0x%p, release ddp 0x%p.\n", tdev, ddp);
-
-       if (ddp) {
-               tdev->ulp_iscsi = NULL;
-               while (i < ddp->nppods) {
-                       struct cxgb3i_gather_list *gl = ddp->gl_map[i];
-                       if (gl) {
-                               int npods = (gl->nelem + PPOD_PAGES_MAX - 1)
-                                               >> PPOD_PAGES_SHIFT;
-                               ddp_log_info("t3dev 0x%p, ddp %d + %d.\n",
-                                               tdev, i, npods);
-                               kfree(gl);
-                               ddp_free_gl_skb(ddp, i, npods);
-                               i += npods;
-                       } else
-                               i++;
-               }
-               cxgb3i_free_big_mem(ddp);
-       }
+       if (ddp)
+               kref_put(&ddp->refcnt, ddp_cleanup);
 }
 
 /**
@@ -631,12 +666,13 @@ void cxgb3i_ddp_cleanup(struct t3cdev *tdev)
  */
 static void ddp_init(struct t3cdev *tdev)
 {
-       struct cxgb3i_ddp_info *ddp;
+       struct cxgb3i_ddp_info *ddp = tdev->ulp_iscsi;
        struct ulp_iscsi_info uinfo;
        unsigned int ppmax, bits;
        int i, err;
 
-       if (tdev->ulp_iscsi) {
+       if (ddp) {
+               kref_get(&ddp->refcnt);
                ddp_log_warn("t3dev 0x%p, ddp 0x%p already set up.\n",
                                tdev, tdev->ulp_iscsi);
                return;
@@ -670,6 +706,7 @@ static void ddp_init(struct t3cdev *tdev)
                                          ppmax *
                                          sizeof(struct cxgb3i_gather_list *));
        spin_lock_init(&ddp->map_lock);
+       kref_init(&ddp->refcnt);
 
        ddp->tdev = tdev;
        ddp->pdev = uinfo.pdev;
@@ -715,6 +752,17 @@ void cxgb3i_ddp_init(struct t3cdev *tdev)
 {
        if (page_idx == DDP_PGIDX_MAX) {
                page_idx = cxgb3i_ddp_find_page_index(PAGE_SIZE);
+
+               if (page_idx == DDP_PGIDX_MAX) {
+                       ddp_log_info("system PAGE_SIZE %lu, update hw.\n",
+                                       PAGE_SIZE);
+                       if (cxgb3i_ddp_adjust_page_table() < 0) {
+                               ddp_log_info("PAGE_SIZE %lu, ddp disabled.\n",
+                                               PAGE_SIZE);
+                               return;
+                       }
+                       page_idx = cxgb3i_ddp_find_page_index(PAGE_SIZE);
+               }
                ddp_log_info("system PAGE_SIZE %lu, ddp idx %u.\n",
                                PAGE_SIZE, page_idx);
        }
index 0d296de7cf32c17d408456f57e4eb840ce0ca00c..87dd56b422bfb4ed07c783765d94c32e38173529 100644 (file)
@@ -54,6 +54,7 @@ struct cxgb3i_gather_list {
  * struct cxgb3i_ddp_info - cxgb3i direct data placement for pdu payload
  *
  * @list:      list head to link elements
+ * @refcnt:    ref. count
  * @tdev:      pointer to t3cdev used by cxgb3 driver
  * @max_txsz:  max tx packet size for ddp
  * @max_rxsz:  max rx packet size for ddp
@@ -70,6 +71,7 @@ struct cxgb3i_gather_list {
  */
 struct cxgb3i_ddp_info {
        struct list_head list;
+       struct kref refcnt;
        struct t3cdev *tdev;
        struct pci_dev *pdev;
        unsigned int max_txsz;
index c15878e881570e6ae6344b92869b1457840e7f69..0a5609bb58172edca3cc4190dba4b31df8ad7f75 100644 (file)
@@ -45,8 +45,6 @@
 
 #include "fcoe.h"
 
-static int debug_fcoe;
-
 MODULE_AUTHOR("Open-FCoE.org");
 MODULE_DESCRIPTION("FCoE");
 MODULE_LICENSE("GPL v2");
@@ -305,23 +303,22 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
 #ifdef NETIF_F_FCOE_CRC
        if (netdev->features & NETIF_F_FCOE_CRC) {
                lp->crc_offload = 1;
-               printk(KERN_DEBUG "fcoe:%s supports FCCRC offload\n",
-                      netdev->name);
+               FCOE_NETDEV_DBG(netdev, "Supports FCCRC offload\n");
        }
 #endif
 #ifdef NETIF_F_FSO
        if (netdev->features & NETIF_F_FSO) {
                lp->seq_offload = 1;
                lp->lso_max = netdev->gso_max_size;
-               printk(KERN_DEBUG "fcoe:%s supports LSO for max len 0x%x\n",
-                      netdev->name, lp->lso_max);
+               FCOE_NETDEV_DBG(netdev, "Supports LSO for max len 0x%x\n",
+                               lp->lso_max);
        }
 #endif
        if (netdev->fcoe_ddp_xid) {
                lp->lro_enabled = 1;
                lp->lro_xid = netdev->fcoe_ddp_xid;
-               printk(KERN_DEBUG "fcoe:%s supports LRO for max xid 0x%x\n",
-                      netdev->name, lp->lro_xid);
+               FCOE_NETDEV_DBG(netdev, "Supports LRO for max xid 0x%x\n",
+                               lp->lro_xid);
        }
        skb_queue_head_init(&fc->fcoe_pending_queue);
        fc->fcoe_pending_queue_active = 0;
@@ -407,7 +404,8 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost,
        /* add the new host to the SCSI-ml */
        rc = scsi_add_host(lp->host, dev);
        if (rc) {
-               FC_DBG("fcoe_shost_config:error on scsi_add_host\n");
+               FCOE_NETDEV_DBG(fcoe_netdev(lp), "fcoe_shost_config: "
+                               "error on scsi_add_host\n");
                return rc;
        }
        sprintf(fc_host_symbolic_name(lp->host), "%s v%s over %s",
@@ -448,8 +446,7 @@ static int fcoe_if_destroy(struct net_device *netdev)
 
        BUG_ON(!netdev);
 
-       printk(KERN_DEBUG "fcoe_if_destroy:interface on %s\n",
-              netdev->name);
+       FCOE_NETDEV_DBG(netdev, "Destroying interface\n");
 
        lp = fcoe_hostlist_lookup(netdev);
        if (!lp)
@@ -560,8 +557,7 @@ static int fcoe_if_create(struct net_device *netdev)
 
        BUG_ON(!netdev);
 
-       printk(KERN_DEBUG "fcoe_if_create:interface on %s\n",
-              netdev->name);
+       FCOE_NETDEV_DBG(netdev, "Create Interface\n");
 
        lp = fcoe_hostlist_lookup(netdev);
        if (lp)
@@ -570,7 +566,7 @@ static int fcoe_if_create(struct net_device *netdev)
        shost = libfc_host_alloc(&fcoe_shost_template,
                                 sizeof(struct fcoe_softc));
        if (!shost) {
-               FC_DBG("Could not allocate host structure\n");
+               FCOE_NETDEV_DBG(netdev, "Could not allocate host structure\n");
                return -ENOMEM;
        }
        lp = shost_priv(shost);
@@ -579,7 +575,8 @@ static int fcoe_if_create(struct net_device *netdev)
        /* configure fc_lport, e.g., em */
        rc = fcoe_lport_config(lp);
        if (rc) {
-               FC_DBG("Could not configure lport\n");
+               FCOE_NETDEV_DBG(netdev, "Could not configure lport for the "
+                               "interface\n");
                goto out_host_put;
        }
 
@@ -593,28 +590,32 @@ static int fcoe_if_create(struct net_device *netdev)
        /* configure lport network properties */
        rc = fcoe_netdev_config(lp, netdev);
        if (rc) {
-               FC_DBG("Could not configure netdev for the interface\n");
+               FCOE_NETDEV_DBG(netdev, "Could not configure netdev for the "
+                               "interface\n");
                goto out_netdev_cleanup;
        }
 
        /* configure lport scsi host properties */
        rc = fcoe_shost_config(lp, shost, &netdev->dev);
        if (rc) {
-               FC_DBG("Could not configure shost for lport\n");
+               FCOE_NETDEV_DBG(netdev, "Could not configure shost for the "
+                               "interface\n");
                goto out_netdev_cleanup;
        }
 
        /* lport exch manager allocation */
        rc = fcoe_em_config(lp);
        if (rc) {
-               FC_DBG("Could not configure em for lport\n");
+               FCOE_NETDEV_DBG(netdev, "Could not configure the EM for the "
+                               "interface\n");
                goto out_netdev_cleanup;
        }
 
        /* Initialize the library */
        rc = fcoe_libfc_config(lp, &fcoe_libfc_fcn_templ);
        if (rc) {
-               FC_DBG("Could not configure libfc for lport!\n");
+               FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the "
+                               "interface\n");
                goto out_lp_destroy;
        }
 
@@ -653,7 +654,7 @@ static int __init fcoe_if_init(void)
                fc_attach_transport(&fcoe_transport_function);
 
        if (!scsi_transport_fcoe_sw) {
-               printk(KERN_ERR "fcoe_init:fc_attach_transport() failed\n");
+               printk(KERN_ERR "fcoe: Failed to attach to the FC transport\n");
                return -ENODEV;
        }
 
@@ -714,7 +715,7 @@ static void fcoe_percpu_thread_destroy(unsigned int cpu)
        unsigned targ_cpu = smp_processor_id();
 #endif /* CONFIG_SMP */
 
-       printk(KERN_DEBUG "fcoe: Destroying receive thread for CPU %d\n", cpu);
+       FCOE_DBG("Destroying receive thread for CPU %d\n", cpu);
 
        /* Prevent any new skbs from being queued for this CPU. */
        p = &per_cpu(fcoe_percpu, cpu);
@@ -736,8 +737,8 @@ static void fcoe_percpu_thread_destroy(unsigned int cpu)
                p0 = &per_cpu(fcoe_percpu, targ_cpu);
                spin_lock_bh(&p0->fcoe_rx_list.lock);
                if (p0->thread) {
-                       FC_DBG("Moving frames from CPU %d to CPU %d\n",
-                              cpu, targ_cpu);
+                       FCOE_DBG("Moving frames from CPU %d to CPU %d\n",
+                                cpu, targ_cpu);
 
                        while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL)
                                __skb_queue_tail(&p0->fcoe_rx_list, skb);
@@ -803,12 +804,12 @@ static int fcoe_cpu_callback(struct notifier_block *nfb,
        switch (action) {
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
-               FC_DBG("CPU %x online: Create Rx thread\n", cpu);
+               FCOE_DBG("CPU %x online: Create Rx thread\n", cpu);
                fcoe_percpu_thread_create(cpu);
                break;
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
-               FC_DBG("CPU %x offline: Remove Rx thread\n", cpu);
+               FCOE_DBG("CPU %x offline: Remove Rx thread\n", cpu);
                fcoe_percpu_thread_destroy(cpu);
                break;
        default:
@@ -846,24 +847,21 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev,
        fc = container_of(ptype, struct fcoe_softc, fcoe_packet_type);
        lp = fc->ctlr.lp;
        if (unlikely(lp == NULL)) {
-               FC_DBG("cannot find hba structure");
+               FCOE_NETDEV_DBG(dev, "Cannot find hba structure");
                goto err2;
        }
        if (!lp->link_up)
                goto err2;
 
-       if (unlikely(debug_fcoe)) {
-               FC_DBG("skb_info: len:%d data_len:%d head:%p data:%p tail:%p "
-                      "end:%p sum:%d dev:%s", skb->len, skb->data_len,
-                      skb->head, skb->data, skb_tail_pointer(skb),
-                      skb_end_pointer(skb), skb->csum,
-                      skb->dev ? skb->dev->name : "<NULL>");
-
-       }
+       FCOE_NETDEV_DBG(dev, "skb_info: len:%d data_len:%d head:%p "
+                       "data:%p tail:%p end:%p sum:%d dev:%s",
+                       skb->len, skb->data_len, skb->head, skb->data,
+                       skb_tail_pointer(skb), skb_end_pointer(skb),
+                       skb->csum, skb->dev ? skb->dev->name : "<NULL>");
 
        /* check for FCOE packet type */
        if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) {
-               FC_DBG("wrong FC type frame");
+               FCOE_NETDEV_DBG(dev, "Wrong FC type frame");
                goto err;
        }
 
@@ -901,8 +899,9 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev,
                 * the first CPU now. For non-SMP systems this
                 * will check the same CPU twice.
                 */
-               FC_DBG("CPU is online, but no receive thread ready "
-                      "for incoming skb- using first online CPU.\n");
+               FCOE_NETDEV_DBG(dev, "CPU is online, but no receive thread "
+                               "ready for incoming skb- using first online "
+                               "CPU.\n");
 
                spin_unlock_bh(&fps->fcoe_rx_list.lock);
                cpu = first_cpu(cpu_online_map);
@@ -1201,19 +1200,17 @@ int fcoe_percpu_receive_thread(void *arg)
                fr = fcoe_dev_from_skb(skb);
                lp = fr->fr_dev;
                if (unlikely(lp == NULL)) {
-                       FC_DBG("invalid HBA Structure");
+                       FCOE_NETDEV_DBG(skb->dev, "Invalid HBA Structure");
                        kfree_skb(skb);
                        continue;
                }
 
-               if (unlikely(debug_fcoe)) {
-                       FC_DBG("skb_info: len:%d data_len:%d head:%p data:%p "
-                              "tail:%p end:%p sum:%d dev:%s",
-                              skb->len, skb->data_len,
-                              skb->head, skb->data, skb_tail_pointer(skb),
-                              skb_end_pointer(skb), skb->csum,
-                              skb->dev ? skb->dev->name : "<NULL>");
-               }
+               FCOE_NETDEV_DBG(skb->dev, "skb_info: len:%d data_len:%d "
+                               "head:%p data:%p tail:%p end:%p sum:%d dev:%s",
+                               skb->len, skb->data_len,
+                               skb->head, skb->data, skb_tail_pointer(skb),
+                               skb_end_pointer(skb), skb->csum,
+                               skb->dev ? skb->dev->name : "<NULL>");
 
                /*
                 * Save source MAC address before discarding header.
@@ -1233,7 +1230,7 @@ int fcoe_percpu_receive_thread(void *arg)
                stats = fc_lport_get_stats(lp);
                if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) {
                        if (stats->ErrorFrames < 5)
-                               printk(KERN_WARNING "FCoE version "
+                               printk(KERN_WARNING "fcoe: FCoE version "
                                       "mismatch: The frame has "
                                       "version %x, but the "
                                       "initiator supports version "
@@ -1286,7 +1283,7 @@ int fcoe_percpu_receive_thread(void *arg)
                if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) {
                        if (le32_to_cpu(fr_crc(fp)) !=
                            ~crc32(~0, skb->data, fr_len)) {
-                               if (debug_fcoe || stats->InvalidCRCCount < 5)
+                               if (stats->InvalidCRCCount < 5)
                                        printk(KERN_WARNING "fcoe: dropping "
                                               "frame with CRC error\n");
                                stats->InvalidCRCCount++;
@@ -1432,7 +1429,8 @@ static int fcoe_device_notification(struct notifier_block *notifier,
        case NETDEV_REGISTER:
                break;
        default:
-               FC_DBG("Unknown event %ld from netdev netlink\n", event);
+               FCOE_NETDEV_DBG(real_dev, "Unknown event %ld "
+                               "from netdev netlink\n", event);
        }
        if (link_possible && !fcoe_link_ok(lp))
                fcoe_ctlr_link_up(&fc->ctlr);
@@ -1505,8 +1503,8 @@ static int fcoe_ethdrv_get(const struct net_device *netdev)
 
        owner = fcoe_netdev_to_module_owner(netdev);
        if (owner) {
-               printk(KERN_DEBUG "fcoe:hold driver module %s for %s\n",
-                      module_name(owner), netdev->name);
+               FCOE_NETDEV_DBG(netdev, "Hold driver module %s\n",
+                               module_name(owner));
                return  try_module_get(owner);
        }
        return -ENODEV;
@@ -1527,8 +1525,8 @@ static int fcoe_ethdrv_put(const struct net_device *netdev)
 
        owner = fcoe_netdev_to_module_owner(netdev);
        if (owner) {
-               printk(KERN_DEBUG "fcoe:release driver module %s for %s\n",
-                      module_name(owner), netdev->name);
+               FCOE_NETDEV_DBG(netdev, "Release driver module %s\n",
+                               module_name(owner));
                module_put(owner);
                return 0;
        }
@@ -1559,7 +1557,7 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp)
        }
        rc = fcoe_if_destroy(netdev);
        if (rc) {
-               printk(KERN_ERR "fcoe: fcoe_if_destroy(%s) failed\n",
+               printk(KERN_ERR "fcoe: Failed to destroy interface (%s)\n",
                       netdev->name);
                rc = -EIO;
                goto out_putdev;
@@ -1598,7 +1596,7 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
 
        rc = fcoe_if_create(netdev);
        if (rc) {
-               printk(KERN_ERR "fcoe: fcoe_if_create(%s) failed\n",
+               printk(KERN_ERR "fcoe: Failed to create interface (%s)\n",
                       netdev->name);
                fcoe_ethdrv_put(netdev);
                rc = -EIO;
index a1eb8c1988b07584bed2a10280a6efbf768f8813..0d724fa0898f0115ac2ea6c5bf5924b35b664a77 100644 (file)
 #define FCOE_MIN_XID           0x0001  /* the min xid supported by fcoe_sw */
 #define FCOE_MAX_XID           0x07ef  /* the max xid supported by fcoe_sw */
 
+unsigned int fcoe_debug_logging;
+module_param_named(debug_logging, fcoe_debug_logging, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
+
+#define FCOE_LOGGING        0x01 /* General logging, not categorized */
+#define FCOE_NETDEV_LOGGING 0x02 /* Netdevice logging */
+
+#define FCOE_CHECK_LOGGING(LEVEL, CMD)                                 \
+do {                                                                   \
+       if (unlikely(fcoe_debug_logging & LEVEL))                       \
+               do {                                                    \
+                       CMD;                                            \
+               } while (0);                                            \
+} while (0);
+
+#define FCOE_DBG(fmt, args...)                                         \
+       FCOE_CHECK_LOGGING(FCOE_LOGGING,                                \
+                          printk(KERN_INFO "fcoe: " fmt, ##args);)
+
+#define FCOE_NETDEV_DBG(netdev, fmt, args...)                  \
+       FCOE_CHECK_LOGGING(FCOE_NETDEV_LOGGING,                 \
+                          printk(KERN_INFO "fcoe: %s" fmt,     \
+                                 netdev->name, ##args);)
+
 /*
  * this percpu struct for fcoe
  */
index 2f5bc7fd3fa90c5c3834fef6a377e025feb70f9f..f544340d318bd1fa16a4187c674a3064d629c8b5 100644 (file)
@@ -56,15 +56,28 @@ static void fcoe_ctlr_recv_work(struct work_struct *);
 
 static u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS;
 
-static u32 fcoe_ctlr_debug;    /* 1 for basic, 2 for noisy debug */
+unsigned int libfcoe_debug_logging;
+module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
 
-#define FIP_DBG_LVL(level, fmt, args...)                               \
+#define LIBFCOE_LOGGING     0x01 /* General logging, not categorized */
+#define LIBFCOE_FIP_LOGGING 0x02 /* FIP logging */
+
+#define LIBFCOE_CHECK_LOGGING(LEVEL, CMD)                              \
+do {                                                                   \
+       if (unlikely(libfcoe_debug_logging & LEVEL))                    \
                do {                                                    \
-                       if (fcoe_ctlr_debug >= (level))                 \
-                               FC_DBG(fmt, ##args);                    \
-               } while (0)
+                       CMD;                                            \
+               } while (0);                                            \
+} while (0);
+
+#define LIBFCOE_DBG(fmt, args...)                                      \
+       LIBFCOE_CHECK_LOGGING(LIBFCOE_LOGGING,                          \
+                             printk(KERN_INFO "libfcoe: " fmt, ##args);)
 
-#define FIP_DBG(fmt, args...)  FIP_DBG_LVL(1, fmt, ##args)
+#define LIBFCOE_FIP_DBG(fmt, args...)                                  \
+       LIBFCOE_CHECK_LOGGING(LIBFCOE_FIP_LOGGING,                      \
+                             printk(KERN_INFO "fip: " fmt, ##args);)
 
 /*
  * Return non-zero if FCF fcoe_size has been validated.
@@ -243,7 +256,7 @@ void fcoe_ctlr_link_up(struct fcoe_ctlr *fip)
                fip->last_link = 1;
                fip->link = 1;
                spin_unlock_bh(&fip->lock);
-               FIP_DBG("%s", "setting AUTO mode.\n");
+               LIBFCOE_FIP_DBG("%s", "setting AUTO mode.\n");
                fc_linkup(fip->lp);
                fcoe_ctlr_solicit(fip, NULL);
        } else
@@ -614,7 +627,8 @@ static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf)
                               ((struct fip_mac_desc *)desc)->fd_mac,
                               ETH_ALEN);
                        if (!is_valid_ether_addr(fcf->fcf_mac)) {
-                               FIP_DBG("invalid MAC addr in FIP adv\n");
+                               LIBFCOE_FIP_DBG("Invalid MAC address "
+                                               "in FIP adv\n");
                                return -EINVAL;
                        }
                        break;
@@ -647,8 +661,8 @@ static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf)
                case FIP_DT_LOGO:
                case FIP_DT_ELP:
                default:
-                       FIP_DBG("unexpected descriptor type %x in FIP adv\n",
-                               desc->fip_dtype);
+                       LIBFCOE_FIP_DBG("unexpected descriptor type %x "
+                                       "in FIP adv\n", desc->fip_dtype);
                        /* standard says ignore unknown descriptors >= 128 */
                        if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
                                return -EINVAL;
@@ -664,8 +678,8 @@ static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf)
        return 0;
 
 len_err:
-       FIP_DBG("FIP length error in descriptor type %x len %zu\n",
-               desc->fip_dtype, dlen);
+       LIBFCOE_FIP_DBG("FIP length error in descriptor type %x len %zu\n",
+                       desc->fip_dtype, dlen);
        return -EINVAL;
 }
 
@@ -728,9 +742,10 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
        }
        mtu_valid = fcoe_ctlr_mtu_valid(fcf);
        fcf->time = jiffies;
-       FIP_DBG_LVL(found ? 2 : 1, "%s FCF for fab %llx map %x val %d\n",
-                   found ? "old" : "new",
-                   fcf->fabric_name, fcf->fc_map, mtu_valid);
+       if (!found) {
+               LIBFCOE_FIP_DBG("New FCF for fab %llx map %x val %d\n",
+                               fcf->fabric_name, fcf->fc_map, mtu_valid);
+       }
 
        /*
         * If this advertisement is not solicited and our max receive size
@@ -807,7 +822,8 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
                               ((struct fip_mac_desc *)desc)->fd_mac,
                               ETH_ALEN);
                        if (!is_valid_ether_addr(granted_mac)) {
-                               FIP_DBG("invalid MAC addrs in FIP ELS\n");
+                               LIBFCOE_FIP_DBG("Invalid MAC address "
+                                               "in FIP ELS\n");
                                goto drop;
                        }
                        break;
@@ -825,8 +841,8 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
                        els_dtype = desc->fip_dtype;
                        break;
                default:
-                       FIP_DBG("unexpected descriptor type %x "
-                               "in FIP adv\n", desc->fip_dtype);
+                       LIBFCOE_FIP_DBG("unexpected descriptor type %x "
+                                       "in FIP adv\n", desc->fip_dtype);
                        /* standard says ignore unknown descriptors >= 128 */
                        if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
                                goto drop;
@@ -867,8 +883,8 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
        return;
 
 len_err:
-       FIP_DBG("FIP length error in descriptor type %x len %zu\n",
-               desc->fip_dtype, dlen);
+       LIBFCOE_FIP_DBG("FIP length error in descriptor type %x len %zu\n",
+                       desc->fip_dtype, dlen);
 drop:
        kfree_skb(skb);
 }
@@ -894,7 +910,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
        struct fc_lport *lp = fip->lp;
        u32     desc_mask;
 
-       FIP_DBG("Clear Virtual Link received\n");
+       LIBFCOE_FIP_DBG("Clear Virtual Link received\n");
        if (!fcf)
                return;
        if (!fcf || !fc_host_port_id(lp->host))
@@ -952,9 +968,9 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
         * reset only if all required descriptors were present and valid.
         */
        if (desc_mask) {
-               FIP_DBG("missing descriptors mask %x\n", desc_mask);
+               LIBFCOE_FIP_DBG("missing descriptors mask %x\n", desc_mask);
        } else {
-               FIP_DBG("performing Clear Virtual Link\n");
+               LIBFCOE_FIP_DBG("performing Clear Virtual Link\n");
                fcoe_ctlr_reset(fip, FIP_ST_ENABLED);
        }
 }
@@ -1002,10 +1018,6 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb)
        op = ntohs(fiph->fip_op);
        sub = fiph->fip_subcode;
 
-       FIP_DBG_LVL(2, "ver %x op %x/%x dl %x fl %x\n",
-                   FIP_VER_DECAPS(fiph->fip_ver), op, sub,
-                   ntohs(fiph->fip_dl_len), ntohs(fiph->fip_flags));
-
        if (FIP_VER_DECAPS(fiph->fip_ver) != FIP_VER)
                goto drop;
        if (ntohs(fiph->fip_dl_len) * FIP_BPW + sizeof(*fiph) > skb->len)
@@ -1017,7 +1029,7 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb)
                fip->map_dest = 0;
                fip->state = FIP_ST_ENABLED;
                state = FIP_ST_ENABLED;
-               FIP_DBG("using FIP mode\n");
+               LIBFCOE_FIP_DBG("Using FIP mode\n");
        }
        spin_unlock_bh(&fip->lock);
        if (state != FIP_ST_ENABLED)
@@ -1052,14 +1064,15 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
        struct fcoe_fcf *best = NULL;
 
        list_for_each_entry(fcf, &fip->fcfs, list) {
-               FIP_DBG("consider FCF for fab %llx VFID %d map %x val %d\n",
-                       fcf->fabric_name, fcf->vfid,
-                       fcf->fc_map, fcoe_ctlr_mtu_valid(fcf));
+               LIBFCOE_FIP_DBG("consider FCF for fab %llx VFID %d map %x "
+                               "val %d\n", fcf->fabric_name, fcf->vfid,
+                               fcf->fc_map, fcoe_ctlr_mtu_valid(fcf));
                if (!fcoe_ctlr_fcf_usable(fcf)) {
-                       FIP_DBG("FCF for fab %llx map %x %svalid %savailable\n",
-                               fcf->fabric_name, fcf->fc_map,
-                               (fcf->flags & FIP_FL_SOL) ? "" : "in",
-                               (fcf->flags & FIP_FL_AVAIL) ? "" : "un");
+                       LIBFCOE_FIP_DBG("FCF for fab %llx map %x %svalid "
+                                       "%savailable\n", fcf->fabric_name,
+                                       fcf->fc_map, (fcf->flags & FIP_FL_SOL)
+                                       ? "" : "in", (fcf->flags & FIP_FL_AVAIL)
+                                       ? "" : "un");
                        continue;
                }
                if (!best) {
@@ -1069,7 +1082,8 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
                if (fcf->fabric_name != best->fabric_name ||
                    fcf->vfid != best->vfid ||
                    fcf->fc_map != best->fc_map) {
-                       FIP_DBG("conflicting fabric, VFID, or FC-MAP\n");
+                       LIBFCOE_FIP_DBG("Conflicting fabric, VFID, "
+                                       "or FC-MAP\n");
                        return;
                }
                if (fcf->pri < best->pri)
@@ -1113,7 +1127,7 @@ static void fcoe_ctlr_timeout(unsigned long arg)
        if (sel != fcf) {
                fcf = sel;              /* the old FCF may have been freed */
                if (sel) {
-                       printk(KERN_INFO "host%d: FIP selected "
+                       printk(KERN_INFO "libfcoe: host%d: FIP selected "
                               "Fibre-Channel Forwarder MAC %s\n",
                               fip->lp->host->host_no,
                               print_mac(buf, sel->fcf_mac));
@@ -1123,7 +1137,7 @@ static void fcoe_ctlr_timeout(unsigned long arg)
                        fip->ctlr_ka_time = jiffies + sel->fka_period;
                        fip->link = 1;
                } else {
-                       printk(KERN_NOTICE "host%d: "
+                       printk(KERN_NOTICE "libfcoe: host%d: "
                               "FIP Fibre-Channel Forwarder timed out.  "
                               "Starting FCF discovery.\n",
                               fip->lp->host->host_no);
@@ -1247,7 +1261,7 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_frame *fp, u8 *sa)
                        return -EINVAL;
                }
                fip->state = FIP_ST_NON_FIP;
-               FIP_DBG("received FLOGI LS_ACC using non-FIP mode\n");
+               LIBFCOE_FIP_DBG("received FLOGI LS_ACC using non-FIP mode\n");
 
                /*
                 * FLOGI accepted.
@@ -1276,7 +1290,7 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_frame *fp, u8 *sa)
                        memcpy(fip->dest_addr, sa, ETH_ALEN);
                        fip->map_dest = 0;
                        if (fip->state == FIP_ST_NON_FIP)
-                               FIP_DBG("received FLOGI REQ, "
+                               LIBFCOE_FIP_DBG("received FLOGI REQ, "
                                                "using non-FIP mode\n");
                        fip->state = FIP_ST_NON_FIP;
                }
index 89d41a424b33a0ede3fa3004e00cdf594a722819..5fd2da494d087da334b65b9bd88b2945191184ff 100644 (file)
@@ -40,7 +40,7 @@
 #include "scsi_logging.h"
 
 
-static int scsi_host_next_hn;          /* host_no for next new host */
+static atomic_t scsi_host_next_hn;     /* host_no for next new host */
 
 
 static void scsi_host_cls_release(struct device *dev)
@@ -333,7 +333,11 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
 
        mutex_init(&shost->scan_mutex);
 
-       shost->host_no = scsi_host_next_hn++; /* XXX(hch): still racy */
+       /*
+        * subtract one because we increment first then return, but we need to
+        * know what the next host number was before increment
+        */
+       shost->host_no = atomic_inc_return(&scsi_host_next_hn) - 1;
        shost->dma_channel = 0xff;
 
        /* These three are default values which can be overridden */
index b4b805e8d7db7aaad258c75f9d8fd30088ff228c..166d96450a0eea134dd5b88ecfbfd48fd906a2de 100644 (file)
@@ -2254,10 +2254,13 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
                                continue;
                        if (crq->node_name && tgt->ids.node_name != crq->node_name)
                                continue;
-                       ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
+                       if (tgt->need_login && crq->event == IBMVFC_AE_ELS_LOGO)
+                               tgt->logo_rcvd = 1;
+                       if (!tgt->need_login || crq->event == IBMVFC_AE_ELS_PLOGI) {
+                               ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
+                               ibmvfc_reinit_host(vhost);
+                       }
                }
-
-               ibmvfc_reinit_host(vhost);
                break;
        case IBMVFC_AE_LINK_DOWN:
        case IBMVFC_AE_ADAPTER_FAILED:
@@ -2783,27 +2786,27 @@ static void ibmvfc_tasklet(void *data)
 
        spin_lock_irqsave(vhost->host->host_lock, flags);
        while (!done) {
-               /* Pull all the valid messages off the CRQ */
-               while ((crq = ibmvfc_next_crq(vhost)) != NULL) {
-                       ibmvfc_handle_crq(crq, vhost);
-                       crq->valid = 0;
-               }
-
                /* Pull all the valid messages off the async CRQ */
                while ((async = ibmvfc_next_async_crq(vhost)) != NULL) {
                        ibmvfc_handle_async(async, vhost);
                        async->valid = 0;
                }
 
-               vio_enable_interrupts(vdev);
-               if ((crq = ibmvfc_next_crq(vhost)) != NULL) {
-                       vio_disable_interrupts(vdev);
+               /* Pull all the valid messages off the CRQ */
+               while ((crq = ibmvfc_next_crq(vhost)) != NULL) {
                        ibmvfc_handle_crq(crq, vhost);
                        crq->valid = 0;
-               } else if ((async = ibmvfc_next_async_crq(vhost)) != NULL) {
+               }
+
+               vio_enable_interrupts(vdev);
+               if ((async = ibmvfc_next_async_crq(vhost)) != NULL) {
                        vio_disable_interrupts(vdev);
                        ibmvfc_handle_async(async, vhost);
                        async->valid = 0;
+               } else if ((crq = ibmvfc_next_crq(vhost)) != NULL) {
+                       vio_disable_interrupts(vdev);
+                       ibmvfc_handle_crq(crq, vhost);
+                       crq->valid = 0;
                } else
                        done = 1;
        }
@@ -2927,7 +2930,11 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt)
                break;
        case IBMVFC_MAD_FAILED:
        default:
-               if (ibmvfc_retry_cmd(rsp->status, rsp->error))
+               if ((rsp->status & IBMVFC_VIOS_FAILURE) && rsp->error == IBMVFC_PLOGI_REQUIRED)
+                       level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi);
+               else if (tgt->logo_rcvd)
+                       level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi);
+               else if (ibmvfc_retry_cmd(rsp->status, rsp->error))
                        level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli);
                else
                        ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
@@ -3054,6 +3061,7 @@ static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *tgt)
                return;
 
        kref_get(&tgt->kref);
+       tgt->logo_rcvd = 0;
        evt = ibmvfc_get_event(vhost);
        vhost->discovery_threads++;
        ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT);
index c2668d7d67f5308cdfc33819f0333e719f842947..007fa1c9ef14eedbab72484577bb5683fe9dda19 100644 (file)
@@ -605,6 +605,7 @@ struct ibmvfc_target {
        int need_login;
        int add_rport;
        int init_retries;
+       int logo_rcvd;
        u32 cancel_key;
        struct ibmvfc_service_parms service_parms;
        struct ibmvfc_service_parms service_parms_change;
index 0f8bc772b1124d910ffd96bf455736152dffcd6e..5f045505a1f4a48eb5f5a1d17ff61508f7cadf7e 100644 (file)
@@ -131,13 +131,13 @@ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = {
 };
 
 static const struct ipr_chip_t ipr_chip[] = {
-       { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, &ipr_chip_cfg[0] },
-       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, &ipr_chip_cfg[0] },
-       { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, &ipr_chip_cfg[0] },
-       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, &ipr_chip_cfg[0] },
-       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, &ipr_chip_cfg[0] },
-       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, &ipr_chip_cfg[1] },
-       { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, &ipr_chip_cfg[1] }
+       { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, IPR_USE_LSI, &ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, IPR_USE_LSI, &ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, IPR_USE_LSI, &ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, IPR_USE_LSI, &ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, IPR_USE_MSI, &ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, IPR_USE_LSI, &ipr_chip_cfg[1] },
+       { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, IPR_USE_LSI, &ipr_chip_cfg[1] }
 };
 
 static int ipr_max_bus_speeds [] = {
@@ -7367,6 +7367,7 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
        INIT_LIST_HEAD(&ioa_cfg->used_res_q);
        INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread);
        init_waitqueue_head(&ioa_cfg->reset_wait_q);
+       init_waitqueue_head(&ioa_cfg->msi_wait_q);
        ioa_cfg->sdt_state = INACTIVE;
        if (ipr_enable_cache)
                ioa_cfg->cache_state = CACHE_ENABLED;
@@ -7398,24 +7399,107 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
 }
 
 /**
- * ipr_get_chip_cfg - Find adapter chip configuration
+ * ipr_get_chip_info - Find adapter chip information
  * @dev_id:            PCI device id struct
  *
  * Return value:
- *     ptr to chip config on success / NULL on failure
+ *     ptr to chip information on success / NULL on failure
  **/
-static const struct ipr_chip_cfg_t * __devinit
-ipr_get_chip_cfg(const struct pci_device_id *dev_id)
+static const struct ipr_chip_t * __devinit
+ipr_get_chip_info(const struct pci_device_id *dev_id)
 {
        int i;
 
        for (i = 0; i < ARRAY_SIZE(ipr_chip); i++)
                if (ipr_chip[i].vendor == dev_id->vendor &&
                    ipr_chip[i].device == dev_id->device)
-                       return ipr_chip[i].cfg;
+                       return &ipr_chip[i];
        return NULL;
 }
 
+/**
+ * ipr_test_intr - Handle the interrupt generated in ipr_test_msi().
+ * @pdev:              PCI device struct
+ *
+ * Description: Simply set the msi_received flag to 1 indicating that
+ * Message Signaled Interrupts are supported.
+ *
+ * Return value:
+ *     0 on success / non-zero on failure
+ **/
+static irqreturn_t __devinit ipr_test_intr(int irq, void *devp)
+{
+       struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp;
+       unsigned long lock_flags = 0;
+       irqreturn_t rc = IRQ_HANDLED;
+
+       spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+
+       ioa_cfg->msi_received = 1;
+       wake_up(&ioa_cfg->msi_wait_q);
+
+       spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+       return rc;
+}
+
+/**
+ * ipr_test_msi - Test for Message Signaled Interrupt (MSI) support.
+ * @pdev:              PCI device struct
+ *
+ * Description: The return value from pci_enable_msi() can not always be
+ * trusted.  This routine sets up and initiates a test interrupt to determine
+ * if the interrupt is received via the ipr_test_intr() service routine.
+ * If the tests fails, the driver will fall back to LSI.
+ *
+ * Return value:
+ *     0 on success / non-zero on failure
+ **/
+static int __devinit ipr_test_msi(struct ipr_ioa_cfg *ioa_cfg,
+                                 struct pci_dev *pdev)
+{
+       int rc;
+       volatile u32 int_reg;
+       unsigned long lock_flags = 0;
+
+       ENTER;
+
+       spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       init_waitqueue_head(&ioa_cfg->msi_wait_q);
+       ioa_cfg->msi_received = 0;
+       ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER);
+       writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, ioa_cfg->regs.clr_interrupt_mask_reg);
+       int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
+       spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
+       rc = request_irq(pdev->irq, ipr_test_intr, 0, IPR_NAME, ioa_cfg);
+       if (rc) {
+               dev_err(&pdev->dev, "Can not assign irq %d\n", pdev->irq);
+               return rc;
+       } else if (ipr_debug)
+               dev_info(&pdev->dev, "IRQ assigned: %d\n", pdev->irq);
+
+       writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, ioa_cfg->regs.sense_interrupt_reg);
+       int_reg = readl(ioa_cfg->regs.sense_interrupt_reg);
+       wait_event_timeout(ioa_cfg->msi_wait_q, ioa_cfg->msi_received, HZ);
+       ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER);
+
+       spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       if (!ioa_cfg->msi_received) {
+               /* MSI test failed */
+               dev_info(&pdev->dev, "MSI test failed.  Falling back to LSI.\n");
+               rc = -EOPNOTSUPP;
+       } else if (ipr_debug)
+               dev_info(&pdev->dev, "MSI test succeeded.\n");
+
+       spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
+       free_irq(pdev->irq, ioa_cfg);
+
+       LEAVE;
+
+       return rc;
+}
+
 /**
  * ipr_probe_ioa - Allocates memory and does first stage of initialization
  * @pdev:              PCI device struct
@@ -7441,11 +7525,6 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
                goto out;
        }
 
-       if (!(rc = pci_enable_msi(pdev)))
-               dev_info(&pdev->dev, "MSI enabled\n");
-       else if (ipr_debug)
-               dev_info(&pdev->dev, "Cannot enable MSI\n");
-
        dev_info(&pdev->dev, "Found IOA with IRQ: %d\n", pdev->irq);
 
        host = scsi_host_alloc(&driver_template, sizeof(*ioa_cfg));
@@ -7461,14 +7540,16 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
        ata_host_init(&ioa_cfg->ata_host, &pdev->dev,
                      sata_port_info.flags, &ipr_sata_ops);
 
-       ioa_cfg->chip_cfg = ipr_get_chip_cfg(dev_id);
+       ioa_cfg->ipr_chip = ipr_get_chip_info(dev_id);
 
-       if (!ioa_cfg->chip_cfg) {
+       if (!ioa_cfg->ipr_chip) {
                dev_err(&pdev->dev, "Unknown adapter chipset 0x%04X 0x%04X\n",
                        dev_id->vendor, dev_id->device);
                goto out_scsi_host_put;
        }
 
+       ioa_cfg->chip_cfg = ioa_cfg->ipr_chip->cfg;
+
        if (ipr_transop_timeout)
                ioa_cfg->transop_timeout = ipr_transop_timeout;
        else if (dev_id->driver_data & IPR_USE_LONG_TRANSOP_TIMEOUT)
@@ -7519,6 +7600,18 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
                goto cleanup_nomem;
        }
 
+       /* Enable MSI style interrupts if they are supported. */
+       if (ioa_cfg->ipr_chip->intr_type == IPR_USE_MSI && !pci_enable_msi(pdev)) {
+               rc = ipr_test_msi(ioa_cfg, pdev);
+               if (rc == -EOPNOTSUPP)
+                       pci_disable_msi(pdev);
+               else if (rc)
+                       goto out_msi_disable;
+               else
+                       dev_info(&pdev->dev, "MSI enabled with IRQ: %d\n", pdev->irq);
+       } else if (ipr_debug)
+               dev_info(&pdev->dev, "Cannot enable MSI.\n");
+
        /* Save away PCI config space for use following IOA reset */
        rc = pci_save_state(pdev);
 
@@ -7556,7 +7649,9 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
                ioa_cfg->ioa_unit_checked = 1;
 
        ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER);
-       rc = request_irq(pdev->irq, ipr_isr, IRQF_SHARED, IPR_NAME, ioa_cfg);
+       rc = request_irq(pdev->irq, ipr_isr,
+                        ioa_cfg->msi_received ? 0 : IRQF_SHARED,
+                        IPR_NAME, ioa_cfg);
 
        if (rc) {
                dev_err(&pdev->dev, "Couldn't register IRQ %d! rc=%d\n",
@@ -7583,12 +7678,13 @@ cleanup_nolog:
        ipr_free_mem(ioa_cfg);
 cleanup_nomem:
        iounmap(ipr_regs);
+out_msi_disable:
+       pci_disable_msi(pdev);
 out_release_regions:
        pci_release_regions(pdev);
 out_scsi_host_put:
        scsi_host_put(host);
 out_disable:
-       pci_disable_msi(pdev);
        pci_disable_device(pdev);
        goto out;
 }
index 79a3ae4fb2c7ea8ebe533b20848dc32ac2b7bc99..4b63dd6b1c813f1ddfa525382b4b37f4ca2aabf5 100644 (file)
@@ -37,8 +37,8 @@
 /*
  * Literals
  */
-#define IPR_DRIVER_VERSION "2.4.2"
-#define IPR_DRIVER_DATE "(January 21, 2009)"
+#define IPR_DRIVER_VERSION "2.4.3"
+#define IPR_DRIVER_DATE "(June 10, 2009)"
 
 /*
  * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@@ -1025,6 +1025,9 @@ struct ipr_chip_cfg_t {
 struct ipr_chip_t {
        u16 vendor;
        u16 device;
+       u16 intr_type;
+#define IPR_USE_LSI                    0x00
+#define IPR_USE_MSI                    0x01
        const struct ipr_chip_cfg_t *cfg;
 };
 
@@ -1094,6 +1097,7 @@ struct ipr_ioa_cfg {
        u8 needs_hard_reset:1;
        u8 dual_raid:1;
        u8 needs_warm_reset:1;
+       u8 msi_received:1;
 
        u8 revid;
 
@@ -1159,6 +1163,7 @@ struct ipr_ioa_cfg {
 
        unsigned int transop_timeout;
        const struct ipr_chip_cfg_t *chip_cfg;
+       const struct ipr_chip_t *ipr_chip;
 
        void __iomem *hdw_dma_regs;     /* iomapped PCI memory space */
        unsigned long hdw_dma_regs_pci; /* raw PCI memory space */
@@ -1179,6 +1184,7 @@ struct ipr_ioa_cfg {
        struct work_struct work_q;
 
        wait_queue_head_t reset_wait_q;
+       wait_queue_head_t msi_wait_q;
 
        struct ipr_dump *dump;
        enum ipr_sdt_state sdt_state;
index b7c092d63bbe257013fd64988b197a99bb3279ef..518dbd91df85ae73db24157464aabdb62ebbedd1 100644 (file)
@@ -253,8 +253,6 @@ static int iscsi_sw_tcp_xmit_segment(struct iscsi_tcp_conn *tcp_conn,
 
                if (r < 0) {
                        iscsi_tcp_segment_unmap(segment);
-                       if (copied || r == -EAGAIN)
-                               break;
                        return r;
                }
                copied += r;
@@ -275,11 +273,17 @@ static int iscsi_sw_tcp_xmit(struct iscsi_conn *conn)
 
        while (1) {
                rc = iscsi_sw_tcp_xmit_segment(tcp_conn, segment);
-               if (rc < 0) {
+               /*
+                * We may not have been able to send data because the conn
+                * is getting stopped. libiscsi will know so propogate err
+                * for it to do the right thing.
+                */
+               if (rc == -EAGAIN)
+                       return rc;
+               else if (rc < 0) {
                        rc = ISCSI_ERR_XMIT_FAILED;
                        goto error;
-               }
-               if (rc == 0)
+               } else if (rc == 0)
                        break;
 
                consumed += rc;
index 4c880656990baab8f275b01316f6a691001f5f01..6fabf66972b92c2a529c407ecb1ffda350e491b1 100644 (file)
 
 #define        FC_DISC_DELAY           3
 
-static int fc_disc_debug;
-
-#define FC_DEBUG_DISC(fmt...)                  \
-       do {                                    \
-               if (fc_disc_debug)              \
-                       FC_DBG(fmt);            \
-       } while (0)
-
 static void fc_disc_gpn_ft_req(struct fc_disc *);
 static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *);
 static int fc_disc_new_target(struct fc_disc *, struct fc_rport *,
@@ -137,8 +129,8 @@ static void fc_disc_rport_callback(struct fc_lport *lport,
        struct fc_rport_libfc_priv *rdata = rport->dd_data;
        struct fc_disc *disc = &lport->disc;
 
-       FC_DEBUG_DISC("Received a %d event for port (%6x)\n", event,
-                     rport->port_id);
+       FC_DISC_DBG(disc, "Received a %d event for port (%6x)\n", event,
+                   rport->port_id);
 
        switch (event) {
        case RPORT_EV_CREATED:
@@ -191,8 +183,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
 
        lport = disc->lport;
 
-       FC_DEBUG_DISC("Received an RSCN event on port (%6x)\n",
-                     fc_host_port_id(lport->host));
+       FC_DISC_DBG(disc, "Received an RSCN event\n");
 
        /* make sure the frame contains an RSCN message */
        rp = fc_frame_payload_get(fp, sizeof(*rp));
@@ -225,8 +216,8 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
                 */
                switch (fmt) {
                case ELS_ADDR_FMT_PORT:
-                       FC_DEBUG_DISC("Port address format for port (%6x)\n",
-                                     ntoh24(pp->rscn_fid));
+                       FC_DISC_DBG(disc, "Port address format for port "
+                                   "(%6x)\n", ntoh24(pp->rscn_fid));
                        dp = kzalloc(sizeof(*dp), GFP_KERNEL);
                        if (!dp) {
                                redisc = 1;
@@ -243,19 +234,19 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
                case ELS_ADDR_FMT_DOM:
                case ELS_ADDR_FMT_FAB:
                default:
-                       FC_DEBUG_DISC("Address format is (%d)\n", fmt);
+                       FC_DISC_DBG(disc, "Address format is (%d)\n", fmt);
                        redisc = 1;
                        break;
                }
        }
        lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
        if (redisc) {
-               FC_DEBUG_DISC("RSCN received: rediscovering\n");
+               FC_DISC_DBG(disc, "RSCN received: rediscovering\n");
                fc_disc_restart(disc);
        } else {
-               FC_DEBUG_DISC("RSCN received: not rediscovering. "
-                             "redisc %d state %d in_prog %d\n",
-                             redisc, lport->state, disc->pending);
+               FC_DISC_DBG(disc, "RSCN received: not rediscovering. "
+                           "redisc %d state %d in_prog %d\n",
+                           redisc, lport->state, disc->pending);
                list_for_each_entry_safe(dp, next, &disc_ports, peers) {
                        list_del(&dp->peers);
                        rport = lport->tt.rport_lookup(lport, dp->ids.port_id);
@@ -270,7 +261,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
        fc_frame_free(fp);
        return;
 reject:
-       FC_DEBUG_DISC("Received a bad RSCN frame\n");
+       FC_DISC_DBG(disc, "Received a bad RSCN frame\n");
        rjt_data.fp = NULL;
        rjt_data.reason = ELS_RJT_LOGIC;
        rjt_data.explan = ELS_EXPL_NONE;
@@ -302,7 +293,8 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp,
                mutex_unlock(&disc->disc_mutex);
                break;
        default:
-               FC_DBG("Received an unsupported request. opcode (%x)\n", op);
+               FC_DISC_DBG(disc, "Received an unsupported request, "
+                           "the opcode is (%x)\n", op);
                break;
        }
 }
@@ -320,12 +312,10 @@ static void fc_disc_restart(struct fc_disc *disc)
        struct fc_rport_libfc_priv *rdata, *next;
        struct fc_lport *lport = disc->lport;
 
-       FC_DEBUG_DISC("Restarting discovery for port (%6x)\n",
-                     fc_host_port_id(lport->host));
+       FC_DISC_DBG(disc, "Restarting discovery\n");
 
        list_for_each_entry_safe(rdata, next, &disc->rports, peers) {
                rport = PRIV_TO_RPORT(rdata);
-               FC_DEBUG_DISC("list_del(%6x)\n", rport->port_id);
                list_del(&rdata->peers);
                lport->tt.rport_logoff(rport);
        }
@@ -485,8 +475,7 @@ static void fc_disc_done(struct fc_disc *disc)
        struct fc_lport *lport = disc->lport;
        enum fc_disc_event event;
 
-       FC_DEBUG_DISC("Discovery complete for port (%6x)\n",
-                     fc_host_port_id(lport->host));
+       FC_DISC_DBG(disc, "Discovery complete\n");
 
        event = disc->event;
        disc->event = DISC_EV_NONE;
@@ -510,10 +499,10 @@ static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp)
 {
        struct fc_lport *lport = disc->lport;
        unsigned long delay = 0;
-       if (fc_disc_debug)
-               FC_DBG("Error %ld, retries %d/%d\n",
-                      PTR_ERR(fp), disc->retry_count,
-                      FC_DISC_RETRY_LIMIT);
+
+       FC_DISC_DBG(disc, "Error %ld, retries %d/%d\n",
+                   PTR_ERR(fp), disc->retry_count,
+                   FC_DISC_RETRY_LIMIT);
 
        if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) {
                /*
@@ -649,9 +638,9 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
                                              &disc->rogue_rports);
                                lport->tt.rport_login(rport);
                        } else
-                               FC_DBG("Failed to allocate memory for "
-                                      "the newly discovered port (%6x)\n",
-                                      dp.ids.port_id);
+                               printk(KERN_WARNING "libfc: Failed to allocate "
+                                      "memory for the newly discovered port "
+                                      "(%6x)\n", dp.ids.port_id);
                }
 
                if (np->fp_flags & FC_NS_FID_LAST) {
@@ -671,9 +660,8 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
         */
        if (error == 0 && len > 0 && len < sizeof(*np)) {
                if (np != &disc->partial_buf) {
-                       FC_DEBUG_DISC("Partial buffer remains "
-                                     "for discovery by (%6x)\n",
-                                     fc_host_port_id(lport->host));
+                       FC_DISC_DBG(disc, "Partial buffer remains "
+                                   "for discovery\n");
                        memcpy(&disc->partial_buf, np, len);
                }
                disc->buf_len = (unsigned char) len;
@@ -721,8 +709,7 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp,
        int error;
 
        mutex_lock(&disc->disc_mutex);
-       FC_DEBUG_DISC("Received a GPN_FT response on port (%6x)\n",
-                     fc_host_port_id(disc->lport->host));
+       FC_DISC_DBG(disc, "Received a GPN_FT response\n");
 
        if (IS_ERR(fp)) {
                fc_disc_error(disc, fp);
@@ -738,30 +725,30 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp,
            disc->seq_count == 0) {
                cp = fc_frame_payload_get(fp, sizeof(*cp));
                if (!cp) {
-                       FC_DBG("GPN_FT response too short, len %d\n",
-                              fr_len(fp));
+                       FC_DISC_DBG(disc, "GPN_FT response too short, len %d\n",
+                                   fr_len(fp));
                } else if (ntohs(cp->ct_cmd) == FC_FS_ACC) {
 
                        /* Accepted, parse the response. */
                        buf = cp + 1;
                        len -= sizeof(*cp);
                } else if (ntohs(cp->ct_cmd) == FC_FS_RJT) {
-                       FC_DBG("GPN_FT rejected reason %x exp %x "
-                              "(check zoning)\n", cp->ct_reason,
-                              cp->ct_explan);
+                       FC_DISC_DBG(disc, "GPN_FT rejected reason %x exp %x "
+                                   "(check zoning)\n", cp->ct_reason,
+                                   cp->ct_explan);
                        disc->event = DISC_EV_FAILED;
                        fc_disc_done(disc);
                } else {
-                       FC_DBG("GPN_FT unexpected response code %x\n",
-                              ntohs(cp->ct_cmd));
+                       FC_DISC_DBG(disc, "GPN_FT unexpected response code "
+                                   "%x\n", ntohs(cp->ct_cmd));
                }
        } else if (fr_sof(fp) == FC_SOF_N3 &&
                   seq_cnt == disc->seq_count) {
                buf = fh + 1;
        } else {
-               FC_DBG("GPN_FT unexpected frame - out of sequence? "
-                      "seq_cnt %x expected %x sof %x eof %x\n",
-                      seq_cnt, disc->seq_count, fr_sof(fp), fr_eof(fp));
+               FC_DISC_DBG(disc, "GPN_FT unexpected frame - out of sequence? "
+                           "seq_cnt %x expected %x sof %x eof %x\n",
+                           seq_cnt, disc->seq_count, fr_sof(fp), fr_eof(fp));
        }
        if (buf) {
                error = fc_disc_gpn_ft_parse(disc, buf, len);
index 7af9bceb8aa9efa467c3ca58ed4da1694ec7d79c..2bc22be5f84944277edc2d7c8b3248a74a4d76e9 100644 (file)
 #include <scsi/libfc.h>
 #include <scsi/fc_encode.h>
 
-/*
- * fc_exch_debug can be set in debugger or at compile time to get more logs.
- */
-static int fc_exch_debug;
-
-#define FC_DEBUG_EXCH(fmt...)                  \
-       do {                                    \
-               if (fc_exch_debug)              \
-                       FC_DBG(fmt);            \
-       } while (0)
-
-static struct kmem_cache *fc_em_cachep;        /* cache for exchanges */
+static struct kmem_cache *fc_em_cachep;        /* cache for exchanges */
 
 /*
  * Structure and function definitions for managing Fibre Channel Exchanges
@@ -333,8 +322,8 @@ static inline void fc_exch_timer_set_locked(struct fc_exch *ep,
        if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE))
                return;
 
-       FC_DEBUG_EXCH("Exchange (%4x) timed out, notifying the upper layer\n",
-                     ep->xid);
+       FC_EXCH_DBG(ep, "Exchange timed out, notifying the upper layer\n");
+
        if (schedule_delayed_work(&ep->timeout_work,
                                  msecs_to_jiffies(timer_msec)))
                fc_exch_hold(ep);               /* hold for timer */
@@ -545,7 +534,7 @@ struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp,
                /* alloc a new xid */
                xid = fc_em_alloc_xid(mp, fp);
                if (!xid) {
-                       printk(KERN_ERR "fc_em_alloc_xid() failed\n");
+                       printk(KERN_WARNING "libfc: Failed to allocate an exhange\n");
                        goto err;
                }
        }
@@ -820,8 +809,8 @@ static struct fc_seq *fc_seq_start_next_locked(struct fc_seq *sp)
        struct fc_exch *ep = fc_seq_exch(sp);
 
        sp = fc_seq_alloc(ep, ep->seq_id++);
-       FC_DEBUG_EXCH("exch %4x f_ctl %6x seq %2x\n",
-                     ep->xid, ep->f_ctl, sp->id);
+       FC_EXCH_DBG(ep, "f_ctl %6x seq %2x\n",
+                   ep->f_ctl, sp->id);
        return sp;
 }
 /*
@@ -901,7 +890,7 @@ void fc_seq_els_rsp_send(struct fc_seq *sp, enum fc_els_cmd els_cmd,
                fc_exch_els_rec(sp, els_data->fp);
                break;
        default:
-               FC_DBG("Invalid ELS CMD:%x\n", els_cmd);
+               FC_EXCH_DBG(fc_seq_exch(sp), "Invalid ELS CMD:%x\n", els_cmd);
        }
 }
 EXPORT_SYMBOL(fc_seq_els_rsp_send);
@@ -1134,7 +1123,7 @@ static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp,
                        lp->tt.lport_recv(lp, sp, fp);
                fc_exch_release(ep);    /* release from lookup */
        } else {
-               FC_DEBUG_EXCH("exch/seq lookup failed: reject %x\n", reject);
+               FC_EM_DBG(mp, "exch/seq lookup failed: reject %x\n", reject);
                fc_frame_free(fp);
        }
 }
@@ -1242,10 +1231,10 @@ static void fc_exch_recv_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
        sp = fc_seq_lookup_orig(mp, fp);        /* doesn't hold sequence */
        if (!sp) {
                atomic_inc(&mp->stats.xid_not_found);
-               FC_DEBUG_EXCH("seq lookup failed\n");
+               FC_EM_DBG(mp, "seq lookup failed\n");
        } else {
                atomic_inc(&mp->stats.non_bls_resp);
-               FC_DEBUG_EXCH("non-BLS response to sequence");
+               FC_EM_DBG(mp, "non-BLS response to sequence");
        }
        fc_frame_free(fp);
 }
@@ -1266,8 +1255,8 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp)
        int rc = 1, has_rec = 0;
 
        fh = fc_frame_header_get(fp);
-       FC_DEBUG_EXCH("exch: BLS rctl %x - %s\n",
-                     fh->fh_r_ctl, fc_exch_rctl_name(fh->fh_r_ctl));
+       FC_EXCH_DBG(ep, "exch: BLS rctl %x - %s\n", fh->fh_r_ctl,
+                   fc_exch_rctl_name(fh->fh_r_ctl));
 
        if (cancel_delayed_work_sync(&ep->timeout_work))
                fc_exch_release(ep);    /* release from pending timer hold */
@@ -1359,9 +1348,9 @@ static void fc_exch_recv_bls(struct fc_exch_mgr *mp, struct fc_frame *fp)
                case FC_RCTL_ACK_0:
                        break;
                default:
-                       FC_DEBUG_EXCH("BLS rctl %x - %s received",
-                                     fh->fh_r_ctl,
-                                     fc_exch_rctl_name(fh->fh_r_ctl));
+                       FC_EXCH_DBG(ep, "BLS rctl %x - %s received",
+                                   fh->fh_r_ctl,
+                                   fc_exch_rctl_name(fh->fh_r_ctl));
                        break;
                }
                fc_frame_free(fp);
@@ -1599,7 +1588,8 @@ static void fc_exch_rrq_resp(struct fc_seq *sp, struct fc_frame *fp, void *arg)
 
                if (err == -FC_EX_CLOSED || err == -FC_EX_TIMEOUT)
                        goto cleanup;
-               FC_DBG("Cannot process RRQ, because of frame error %d\n", err);
+               FC_EXCH_DBG(aborted_ep, "Cannot process RRQ, "
+                           "frame error %d\n", err);
                return;
        }
 
@@ -1608,12 +1598,13 @@ static void fc_exch_rrq_resp(struct fc_seq *sp, struct fc_frame *fp, void *arg)
 
        switch (op) {
        case ELS_LS_RJT:
-               FC_DBG("LS_RJT for RRQ");
+               FC_EXCH_DBG(aborted_ep, "LS_RJT for RRQ");
                /* fall through */
        case ELS_LS_ACC:
                goto cleanup;
        default:
-               FC_DBG("unexpected response op %x for RRQ", op);
+               FC_EXCH_DBG(aborted_ep, "unexpected response op %x "
+                           "for RRQ", op);
                return;
        }
 
@@ -1740,8 +1731,8 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp,
        size_t len;
 
        if (max_xid <= min_xid || min_xid == 0 || max_xid == FC_XID_UNKNOWN) {
-               FC_DBG("Invalid min_xid 0x:%x and max_xid 0x:%x\n",
-                      min_xid, max_xid);
+               FC_LPORT_DBG(lp, "Invalid min_xid 0x:%x and max_xid 0x:%x\n",
+                            min_xid, max_xid);
                return NULL;
        }
 
@@ -1878,7 +1869,8 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp,
 
        /* lport lock ? */
        if (!lp || !mp || (lp->state == LPORT_ST_NONE)) {
-               FC_DBG("fc_lport or EM is not allocated and configured");
+               FC_LPORT_DBG(lp, "Receiving frames for an lport that "
+                            "has not been initialized correctly\n");
                fc_frame_free(fp);
                return;
        }
@@ -1904,7 +1896,7 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp,
                        fc_exch_recv_req(lp, mp, fp);
                break;
        default:
-               FC_DBG("dropping invalid frame (eof %x)", fr_eof(fp));
+               FC_EM_DBG(mp, "dropping invalid frame (eof %x)", fr_eof(fp));
                fc_frame_free(fp);
                break;
        }
index ad8b747837b08c8922f56d4690f091d304e2321e..e303e0d12c4b1c626d7fc3837d0aa35fe9051063 100644 (file)
@@ -43,13 +43,9 @@ MODULE_AUTHOR("Open-FCoE.org");
 MODULE_DESCRIPTION("libfc");
 MODULE_LICENSE("GPL v2");
 
-static int fc_fcp_debug;
-
-#define FC_DEBUG_FCP(fmt...)                   \
-       do {                                    \
-               if (fc_fcp_debug)               \
-                       FC_DBG(fmt);            \
-       } while (0)
+unsigned int fc_debug_logging;
+module_param_named(debug_logging, fc_debug_logging, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
 
 static struct kmem_cache *scsi_pkt_cachep;
 
@@ -347,8 +343,8 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
                if ((fr_flags(fp) & FCPHF_CRC_UNCHECKED) &&
                    fc_frame_crc_check(fp))
                        goto crc_err;
-               FC_DEBUG_FCP("data received past end. len %zx offset %zx "
-                            "data_len %x\n", len, offset, fsp->data_len);
+               FC_FCP_DBG(fsp, "data received past end. len %zx offset %zx "
+                          "data_len %x\n", len, offset, fsp->data_len);
                fc_fcp_retry_cmd(fsp);
                return;
        }
@@ -411,7 +407,8 @@ crc_err:
                        stats->ErrorFrames++;
                        /* FIXME - per cpu count, not total count! */
                        if (stats->InvalidCRCCount++ < 5)
-                               printk(KERN_WARNING "CRC error on data frame for port (%6x)\n",
+                               printk(KERN_WARNING "libfc: CRC error on data "
+                                      "frame for port (%6x)\n",
                                       fc_host_port_id(lp->host));
                        /*
                         * Assume the frame is total garbage.
@@ -475,14 +472,14 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
        WARN_ON(seq_blen <= 0);
        if (unlikely(offset + seq_blen > fsp->data_len)) {
                /* this should never happen */
-               FC_DEBUG_FCP("xfer-ready past end. seq_blen %zx offset %zx\n",
-                            seq_blen, offset);
+               FC_FCP_DBG(fsp, "xfer-ready past end. seq_blen %zx "
+                          "offset %zx\n", seq_blen, offset);
                fc_fcp_send_abort(fsp);
                return 0;
        } else if (offset != fsp->xfer_len) {
                /* Out of Order Data Request - no problem, but unexpected. */
-               FC_DEBUG_FCP("xfer-ready non-contiguous. "
-                            "seq_blen %zx offset %zx\n", seq_blen, offset);
+               FC_FCP_DBG(fsp, "xfer-ready non-contiguous. "
+                          "seq_blen %zx offset %zx\n", seq_blen, offset);
        }
 
        /*
@@ -493,7 +490,7 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
        t_blen = fsp->max_payload;
        if (lp->seq_offload) {
                t_blen = min(seq_blen, (size_t)lp->lso_max);
-               FC_DEBUG_FCP("fsp=%p:lso:blen=%zx lso_max=0x%x t_blen=%zx\n",
+               FC_FCP_DBG(fsp, "fsp=%p:lso:blen=%zx lso_max=0x%x t_blen=%zx\n",
                           fsp, seq_blen, lp->lso_max, t_blen);
        }
 
@@ -694,7 +691,7 @@ static void fc_fcp_reduce_can_queue(struct fc_lport *lp)
        if (!can_queue)
                can_queue = 1;
        lp->host->can_queue = can_queue;
-       shost_printk(KERN_ERR, lp->host, "Could not allocate frame.\n"
+       shost_printk(KERN_ERR, lp->host, "libfc: Could not allocate frame.\n"
                     "Reducing can_queue to %d.\n", can_queue);
 done:
        spin_unlock_irqrestore(lp->host->host_lock, flags);
@@ -768,7 +765,7 @@ static void fc_fcp_recv(struct fc_seq *seq, struct fc_frame *fp, void *arg)
 
                fc_fcp_resp(fsp, fp);
        } else {
-               FC_DBG("unexpected frame.  r_ctl %x\n", r_ctl);
+               FC_FCP_DBG(fsp, "unexpected frame.  r_ctl %x\n", r_ctl);
        }
 unlock:
        fc_fcp_unlock_pkt(fsp);
@@ -877,17 +874,17 @@ static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
                        return;
                }
                fsp->status_code = FC_DATA_OVRRUN;
-               FC_DBG("tgt %6x xfer len %zx greater than expected len %x. "
-                      "data len %x\n",
-                      fsp->rport->port_id,
-                      fsp->xfer_len, expected_len, fsp->data_len);
+               FC_FCP_DBG(fsp, "tgt %6x xfer len %zx greater than expected, "
+                          "len %x, data len %x\n",
+                          fsp->rport->port_id,
+                          fsp->xfer_len, expected_len, fsp->data_len);
        }
        fc_fcp_complete_locked(fsp);
        return;
 
 len_err:
-       FC_DBG("short FCP response. flags 0x%x len %u respl %u snsl %u\n",
-              flags, fr_len(fp), respl, snsl);
+       FC_FCP_DBG(fsp, "short FCP response. flags 0x%x len %u respl %u "
+                  "snsl %u\n", flags, fr_len(fp), respl, snsl);
 err:
        fsp->status_code = FC_ERROR;
        fc_fcp_complete_locked(fsp);
@@ -1107,13 +1104,11 @@ static void fc_fcp_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
        if (fc_fcp_lock_pkt(fsp))
                return;
 
-       switch (error) {
-       case -FC_EX_CLOSED:
+       if (error == -FC_EX_CLOSED) {
                fc_fcp_retry_cmd(fsp);
                goto unlock;
-       default:
-               FC_DBG("unknown error %ld\n", PTR_ERR(fp));
        }
+
        /*
         * clear abort pending, because the lower layer
         * decided to force completion.
@@ -1145,10 +1140,10 @@ static int fc_fcp_pkt_abort(struct fc_lport *lp, struct fc_fcp_pkt *fsp)
        fsp->wait_for_comp = 0;
 
        if (!rc) {
-               FC_DBG("target abort cmd  failed\n");
+               FC_FCP_DBG(fsp, "target abort cmd  failed\n");
                rc = FAILED;
        } else if (fsp->state & FC_SRB_ABORTED) {
-               FC_DBG("target abort cmd  passed\n");
+               FC_FCP_DBG(fsp, "target abort cmd  passed\n");
                rc = SUCCESS;
                fc_fcp_complete_locked(fsp);
        }
@@ -1213,7 +1208,7 @@ static int fc_lun_reset(struct fc_lport *lp, struct fc_fcp_pkt *fsp,
        spin_unlock_bh(&fsp->scsi_pkt_lock);
 
        if (!rc) {
-               FC_DBG("lun reset failed\n");
+               FC_SCSI_DBG(lp, "lun reset failed\n");
                return FAILED;
        }
 
@@ -1221,7 +1216,7 @@ static int fc_lun_reset(struct fc_lport *lp, struct fc_fcp_pkt *fsp,
        if (fsp->cdb_status != FCP_TMF_CMPL)
                return FAILED;
 
-       FC_DBG("lun reset to lun %u completed\n", lun);
+       FC_SCSI_DBG(lp, "lun reset to lun %u completed\n", lun);
        fc_fcp_cleanup_each_cmd(lp, id, lun, FC_CMD_ABORTED);
        return SUCCESS;
 }
@@ -1388,13 +1383,13 @@ static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
                rjt = fc_frame_payload_get(fp, sizeof(*rjt));
                switch (rjt->er_reason) {
                default:
-                       FC_DEBUG_FCP("device %x unexpected REC reject "
-                                    "reason %d expl %d\n",
-                                    fsp->rport->port_id, rjt->er_reason,
-                                    rjt->er_explan);
+                       FC_FCP_DBG(fsp, "device %x unexpected REC reject "
+                                  "reason %d expl %d\n",
+                                  fsp->rport->port_id, rjt->er_reason,
+                                  rjt->er_explan);
                        /* fall through */
                case ELS_RJT_UNSUP:
-                       FC_DEBUG_FCP("device does not support REC\n");
+                       FC_FCP_DBG(fsp, "device does not support REC\n");
                        rp = fsp->rport->dd_data;
                        /*
                         * if we do not spport RECs or got some bogus
@@ -1514,8 +1509,8 @@ static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
                break;
 
        default:
-               FC_DBG("REC %p fid %x error unexpected error %d\n",
-                      fsp, fsp->rport->port_id, error);
+               FC_FCP_DBG(fsp, "REC %p fid %x error unexpected error %d\n",
+                          fsp, fsp->rport->port_id, error);
                fsp->status_code = FC_CMD_PLOGO;
                /* fall through */
 
@@ -1524,9 +1519,9 @@ static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
                 * Assume REC or LS_ACC was lost.
                 * The exchange manager will have aborted REC, so retry.
                 */
-               FC_DBG("REC fid %x error error %d retry %d/%d\n",
-                      fsp->rport->port_id, error, fsp->recov_retry,
-                      FC_MAX_RECOV_RETRY);
+               FC_FCP_DBG(fsp, "REC fid %x error error %d retry %d/%d\n",
+                          fsp->rport->port_id, error, fsp->recov_retry,
+                          FC_MAX_RECOV_RETRY);
                if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
                        fc_fcp_rec(fsp);
                else
@@ -2011,9 +2006,11 @@ int fc_eh_device_reset(struct scsi_cmnd *sc_cmd)
        if (lp->state != LPORT_ST_READY)
                return rc;
 
+       FC_SCSI_DBG(lp, "Resetting rport (%6x)\n", rport->port_id);
+
        fsp = fc_fcp_pkt_alloc(lp, GFP_NOIO);
        if (fsp == NULL) {
-               FC_DBG("could not allocate scsi_pkt\n");
+               printk(KERN_WARNING "libfc: could not allocate scsi_pkt\n");
                sc_cmd->result = DID_NO_CONNECT << 16;
                goto out;
        }
@@ -2048,17 +2045,21 @@ int fc_eh_host_reset(struct scsi_cmnd *sc_cmd)
        struct fc_lport *lp = shost_priv(shost);
        unsigned long wait_tmo;
 
+       FC_SCSI_DBG(lp, "Resetting host\n");
+
        lp->tt.lport_reset(lp);
        wait_tmo = jiffies + FC_HOST_RESET_TIMEOUT;
        while (!fc_fcp_lport_queue_ready(lp) && time_before(jiffies, wait_tmo))
                msleep(1000);
 
        if (fc_fcp_lport_queue_ready(lp)) {
-               shost_printk(KERN_INFO, shost, "Host reset succeeded.\n");
+               shost_printk(KERN_INFO, shost, "libfc: Host reset succeeded "
+                            "on port (%6x)\n", fc_host_port_id(lp->host));
                return SUCCESS;
        } else {
-               shost_printk(KERN_INFO, shost, "Host reset failed. "
-                            "lport not ready.\n");
+               shost_printk(KERN_INFO, shost, "libfc: Host reset failed, "
+                            "port (%6x) is not ready.\n",
+                            fc_host_port_id(lp->host));
                return FAILED;
        }
 }
@@ -2117,7 +2118,8 @@ void fc_fcp_destroy(struct fc_lport *lp)
        struct fc_fcp_internal *si = fc_get_scsi_internal(lp);
 
        if (!list_empty(&si->scsi_pkt_queue))
-               printk(KERN_ERR "Leaked scsi packets.\n");
+               printk(KERN_ERR "libfc: Leaked SCSI packets when destroying "
+                      "port (%6x)\n", fc_host_port_id(lp->host));
 
        mempool_destroy(si->scsi_pkt_pool);
        kfree(si);
@@ -2166,7 +2168,8 @@ static int __init libfc_init(void)
                                            sizeof(struct fc_fcp_pkt),
                                            0, SLAB_HWCACHE_ALIGN, NULL);
        if (scsi_pkt_cachep == NULL) {
-               FC_DBG("Unable to allocate SRB cache...module load failed!");
+               printk(KERN_ERR "libfc: Unable to allocate SRB cache, "
+                      "module load failed!");
                return -ENOMEM;
        }
 
index e0c247724d2bc6aa352db42ffd2028e08bfc7222..745fa5555d6aa646ef527d6290ab1792140d0112 100644 (file)
 
 #define        DNS_DELAY             3 /* Discovery delay after RSCN (in seconds)*/
 
-static int fc_lport_debug;
-
-#define FC_DEBUG_LPORT(fmt...)                 \
-       do {                                    \
-               if (fc_lport_debug)             \
-                       FC_DBG(fmt);            \
-       } while (0)
-
 static void fc_lport_error(struct fc_lport *, struct fc_frame *);
 
 static void fc_lport_enter_reset(struct fc_lport *);
@@ -151,8 +143,8 @@ static void fc_lport_rport_callback(struct fc_lport *lport,
                                    struct fc_rport *rport,
                                    enum fc_rport_event event)
 {
-       FC_DEBUG_LPORT("Received a %d event for port (%6x)\n", event,
-                      rport->port_id);
+       FC_LPORT_DBG(lport, "Received a %d event for port (%6x)\n", event,
+                    rport->port_id);
 
        switch (event) {
        case RPORT_EV_CREATED:
@@ -162,19 +154,19 @@ static void fc_lport_rport_callback(struct fc_lport *lport,
                                lport->dns_rp = rport;
                                fc_lport_enter_rpn_id(lport);
                        } else {
-                               FC_DEBUG_LPORT("Received an CREATED event on "
-                                              "port (%6x) for the directory "
-                                              "server, but the lport is not "
-                                              "in the DNS state, it's in the "
-                                              "%d state", rport->port_id,
-                                              lport->state);
+                               FC_LPORT_DBG(lport, "Received an CREATED event "
+                                            "on port (%6x) for the directory "
+                                            "server, but the lport is not "
+                                            "in the DNS state, it's in the "
+                                            "%d state", rport->port_id,
+                                            lport->state);
                                lport->tt.rport_logoff(rport);
                        }
                        mutex_unlock(&lport->lp_mutex);
                } else
-                       FC_DEBUG_LPORT("Received an event for port (%6x) "
-                                      "which is not the directory server\n",
-                                      rport->port_id);
+                       FC_LPORT_DBG(lport, "Received an event for port (%6x) "
+                                    "which is not the directory server\n",
+                                    rport->port_id);
                break;
        case RPORT_EV_LOGO:
        case RPORT_EV_FAILED:
@@ -185,9 +177,9 @@ static void fc_lport_rport_callback(struct fc_lport *lport,
                        mutex_unlock(&lport->lp_mutex);
 
                } else
-                       FC_DEBUG_LPORT("Received an event for port (%6x) "
-                                      "which is not the directory server\n",
-                                      rport->port_id);
+                       FC_LPORT_DBG(lport, "Received an event for port (%6x) "
+                                    "which is not the directory server\n",
+                                    rport->port_id);
                break;
        case RPORT_EV_NONE:
                break;
@@ -363,8 +355,8 @@ static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type)
 static void fc_lport_recv_rlir_req(struct fc_seq *sp, struct fc_frame *fp,
                                   struct fc_lport *lport)
 {
-       FC_DEBUG_LPORT("Received RLIR request while in state %s\n",
-                      fc_lport_state(lport));
+       FC_LPORT_DBG(lport, "Received RLIR request while in state %s\n",
+                    fc_lport_state(lport));
 
        lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
        fc_frame_free(fp);
@@ -389,8 +381,8 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp,
        void *dp;
        u32 f_ctl;
 
-       FC_DEBUG_LPORT("Received RLIR request while in state %s\n",
-                      fc_lport_state(lport));
+       FC_LPORT_DBG(lport, "Received RLIR request while in state %s\n",
+                    fc_lport_state(lport));
 
        len = fr_len(in_fp) - sizeof(struct fc_frame_header);
        pp = fc_frame_payload_get(in_fp, len);
@@ -437,8 +429,8 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp,
        size_t len;
        u32 f_ctl;
 
-       FC_DEBUG_LPORT("Received RNID request while in state %s\n",
-                      fc_lport_state(lport));
+       FC_LPORT_DBG(lport, "Received RNID request while in state %s\n",
+                    fc_lport_state(lport));
 
        req = fc_frame_payload_get(in_fp, sizeof(*req));
        if (!req) {
@@ -498,8 +490,8 @@ static void fc_lport_recv_adisc_req(struct fc_seq *sp, struct fc_frame *in_fp,
        size_t len;
        u32 f_ctl;
 
-       FC_DEBUG_LPORT("Received ADISC request while in state %s\n",
-                      fc_lport_state(lport));
+       FC_LPORT_DBG(lport, "Received ADISC request while in state %s\n",
+                    fc_lport_state(lport));
 
        req = fc_frame_payload_get(in_fp, sizeof(*req));
        if (!req) {
@@ -574,8 +566,8 @@ EXPORT_SYMBOL(fc_fabric_login);
  */
 void fc_linkup(struct fc_lport *lport)
 {
-       FC_DEBUG_LPORT("Link is up for port (%6x)\n",
-                      fc_host_port_id(lport->host));
+       printk(KERN_INFO "libfc: Link up on port (%6x)\n",
+              fc_host_port_id(lport->host));
 
        mutex_lock(&lport->lp_mutex);
        if (!lport->link_up) {
@@ -595,8 +587,8 @@ EXPORT_SYMBOL(fc_linkup);
 void fc_linkdown(struct fc_lport *lport)
 {
        mutex_lock(&lport->lp_mutex);
-       FC_DEBUG_LPORT("Link is down for port (%6x)\n",
-                      fc_host_port_id(lport->host));
+       printk(KERN_INFO "libfc: Link down on port (%6x)\n",
+              fc_host_port_id(lport->host));
 
        if (lport->link_up) {
                lport->link_up = 0;
@@ -701,12 +693,11 @@ void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event)
 {
        switch (event) {
        case DISC_EV_SUCCESS:
-               FC_DEBUG_LPORT("Got a SUCCESS event for port (%6x)\n",
-                              fc_host_port_id(lport->host));
+               FC_LPORT_DBG(lport, "Discovery succeeded\n");
                break;
        case DISC_EV_FAILED:
-               FC_DEBUG_LPORT("Got a FAILED event for port (%6x)\n",
-                              fc_host_port_id(lport->host));
+               printk(KERN_ERR "libfc: Discovery failed for port (%6x)\n",
+                      fc_host_port_id(lport->host));
                mutex_lock(&lport->lp_mutex);
                fc_lport_enter_reset(lport);
                mutex_unlock(&lport->lp_mutex);
@@ -726,8 +717,8 @@ void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event)
  */
 static void fc_lport_enter_ready(struct fc_lport *lport)
 {
-       FC_DEBUG_LPORT("Port (%6x) entered Ready from state %s\n",
-                      fc_host_port_id(lport->host), fc_lport_state(lport));
+       FC_LPORT_DBG(lport, "Entered READY from state %s\n",
+                    fc_lport_state(lport));
 
        fc_lport_state_enter(lport, LPORT_ST_READY);
 
@@ -762,8 +753,8 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
        u32 local_fid;
        u32 f_ctl;
 
-       FC_DEBUG_LPORT("Received FLOGI request while in state %s\n",
-                      fc_lport_state(lport));
+       FC_LPORT_DBG(lport, "Received FLOGI request while in state %s\n",
+                    fc_lport_state(lport));
 
        fh = fc_frame_header_get(rx_fp);
        remote_fid = ntoh24(fh->fh_s_id);
@@ -772,12 +763,11 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
                goto out;
        remote_wwpn = get_unaligned_be64(&flp->fl_wwpn);
        if (remote_wwpn == lport->wwpn) {
-               FC_DBG("FLOGI from port with same WWPN %llx "
-                      "possible configuration error\n",
-                      (unsigned long long)remote_wwpn);
+               printk(KERN_WARNING "libfc: Received FLOGI from port "
+                      "with same WWPN %llx\n", remote_wwpn);
                goto out;
        }
-       FC_DBG("FLOGI from port WWPN %llx\n", (unsigned long long)remote_wwpn);
+       FC_LPORT_DBG(lport, "FLOGI from port WWPN %llx\n", remote_wwpn);
 
        /*
         * XXX what is the right thing to do for FIDs?
@@ -909,7 +899,8 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,
                        }
                }
        } else {
-               FC_DBG("dropping invalid frame (eof %x)\n", fr_eof(fp));
+               FC_LPORT_DBG(lport, "dropping invalid frame (eof %x)\n",
+                            fr_eof(fp));
                fc_frame_free(fp);
        }
        mutex_unlock(&lport->lp_mutex);
@@ -947,8 +938,8 @@ EXPORT_SYMBOL(fc_lport_reset);
  */
 static void fc_lport_enter_reset(struct fc_lport *lport)
 {
-       FC_DEBUG_LPORT("Port (%6x) entered RESET state from %s state\n",
-                      fc_host_port_id(lport->host), fc_lport_state(lport));
+       FC_LPORT_DBG(lport, "Entered RESET state from %s state\n",
+                    fc_lport_state(lport));
 
        fc_lport_state_enter(lport, LPORT_ST_RESET);
 
@@ -982,9 +973,9 @@ static void fc_lport_enter_reset(struct fc_lport *lport)
 static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp)
 {
        unsigned long delay = 0;
-       FC_DEBUG_LPORT("Error %ld in state %s, retries %d\n",
-                      PTR_ERR(fp), fc_lport_state(lport),
-                      lport->retry_count);
+       FC_LPORT_DBG(lport, "Error %ld in state %s, retries %d\n",
+                    PTR_ERR(fp), fc_lport_state(lport),
+                    lport->retry_count);
 
        if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) {
                /*
@@ -1040,11 +1031,11 @@ static void fc_lport_rft_id_resp(struct fc_seq *sp, struct fc_frame *fp,
 
        mutex_lock(&lport->lp_mutex);
 
-       FC_DEBUG_LPORT("Received a RFT_ID response\n");
+       FC_LPORT_DBG(lport, "Received a RFT_ID response\n");
 
        if (lport->state != LPORT_ST_RFT_ID) {
-               FC_DBG("Received a RFT_ID response, but in state %s\n",
-                      fc_lport_state(lport));
+               FC_LPORT_DBG(lport, "Received a RFT_ID response, but in state "
+                            "%s\n", fc_lport_state(lport));
                if (IS_ERR(fp))
                        goto err;
                goto out;
@@ -1094,11 +1085,11 @@ static void fc_lport_rpn_id_resp(struct fc_seq *sp, struct fc_frame *fp,
 
        mutex_lock(&lport->lp_mutex);
 
-       FC_DEBUG_LPORT("Received a RPN_ID response\n");
+       FC_LPORT_DBG(lport, "Received a RPN_ID response\n");
 
        if (lport->state != LPORT_ST_RPN_ID) {
-               FC_DBG("Received a RPN_ID response, but in state %s\n",
-                      fc_lport_state(lport));
+               FC_LPORT_DBG(lport, "Received a RPN_ID response, but in state "
+                            "%s\n", fc_lport_state(lport));
                if (IS_ERR(fp))
                        goto err;
                goto out;
@@ -1146,11 +1137,11 @@ static void fc_lport_scr_resp(struct fc_seq *sp, struct fc_frame *fp,
 
        mutex_lock(&lport->lp_mutex);
 
-       FC_DEBUG_LPORT("Received a SCR response\n");
+       FC_LPORT_DBG(lport, "Received a SCR response\n");
 
        if (lport->state != LPORT_ST_SCR) {
-               FC_DBG("Received a SCR response, but in state %s\n",
-                      fc_lport_state(lport));
+               FC_LPORT_DBG(lport, "Received a SCR response, but in state "
+                            "%s\n", fc_lport_state(lport));
                if (IS_ERR(fp))
                        goto err;
                goto out;
@@ -1184,8 +1175,8 @@ static void fc_lport_enter_scr(struct fc_lport *lport)
 {
        struct fc_frame *fp;
 
-       FC_DEBUG_LPORT("Port (%6x) entered SCR state from %s state\n",
-                      fc_host_port_id(lport->host), fc_lport_state(lport));
+       FC_LPORT_DBG(lport, "Entered SCR state from %s state\n",
+                    fc_lport_state(lport));
 
        fc_lport_state_enter(lport, LPORT_ST_SCR);
 
@@ -1213,8 +1204,8 @@ static void fc_lport_enter_rft_id(struct fc_lport *lport)
        struct fc_ns_fts *lps;
        int i;
 
-       FC_DEBUG_LPORT("Port (%6x) entered RFT_ID state from %s state\n",
-                      fc_host_port_id(lport->host), fc_lport_state(lport));
+       FC_LPORT_DBG(lport, "Entered RFT_ID state from %s state\n",
+                    fc_lport_state(lport));
 
        fc_lport_state_enter(lport, LPORT_ST_RFT_ID);
 
@@ -1253,8 +1244,8 @@ static void fc_lport_enter_rpn_id(struct fc_lport *lport)
 {
        struct fc_frame *fp;
 
-       FC_DEBUG_LPORT("Port (%6x) entered RPN_ID state from %s state\n",
-                      fc_host_port_id(lport->host), fc_lport_state(lport));
+       FC_LPORT_DBG(lport, "Entered RPN_ID state from %s state\n",
+                    fc_lport_state(lport));
 
        fc_lport_state_enter(lport, LPORT_ST_RPN_ID);
 
@@ -1294,8 +1285,8 @@ static void fc_lport_enter_dns(struct fc_lport *lport)
        dp.ids.roles = FC_RPORT_ROLE_UNKNOWN;
        dp.lp = lport;
 
-       FC_DEBUG_LPORT("Port (%6x) entered DNS state from %s state\n",
-                      fc_host_port_id(lport->host), fc_lport_state(lport));
+       FC_LPORT_DBG(lport, "Entered DNS state from %s state\n",
+                    fc_lport_state(lport));
 
        fc_lport_state_enter(lport, LPORT_ST_DNS);
 
@@ -1374,11 +1365,11 @@ static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
 
        mutex_lock(&lport->lp_mutex);
 
-       FC_DEBUG_LPORT("Received a LOGO response\n");
+       FC_LPORT_DBG(lport, "Received a LOGO response\n");
 
        if (lport->state != LPORT_ST_LOGO) {
-               FC_DBG("Received a LOGO response, but in state %s\n",
-                      fc_lport_state(lport));
+               FC_LPORT_DBG(lport, "Received a LOGO response, but in state "
+                            "%s\n", fc_lport_state(lport));
                if (IS_ERR(fp))
                        goto err;
                goto out;
@@ -1413,8 +1404,8 @@ static void fc_lport_enter_logo(struct fc_lport *lport)
        struct fc_frame *fp;
        struct fc_els_logo *logo;
 
-       FC_DEBUG_LPORT("Port (%6x) entered LOGO state from %s state\n",
-                      fc_host_port_id(lport->host), fc_lport_state(lport));
+       FC_LPORT_DBG(lport, "Entered LOGO state from %s state\n",
+                    fc_lport_state(lport));
 
        fc_lport_state_enter(lport, LPORT_ST_LOGO);
 
@@ -1456,11 +1447,11 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
 
        mutex_lock(&lport->lp_mutex);
 
-       FC_DEBUG_LPORT("Received a FLOGI response\n");
+       FC_LPORT_DBG(lport, "Received a FLOGI response\n");
 
        if (lport->state != LPORT_ST_FLOGI) {
-               FC_DBG("Received a FLOGI response, but in state %s\n",
-                      fc_lport_state(lport));
+               FC_LPORT_DBG(lport, "Received a FLOGI response, but in state "
+                            "%s\n", fc_lport_state(lport));
                if (IS_ERR(fp))
                        goto err;
                goto out;
@@ -1475,7 +1466,8 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
        did = ntoh24(fh->fh_d_id);
        if (fc_frame_payload_op(fp) == ELS_LS_ACC && did != 0) {
 
-               FC_DEBUG_LPORT("Assigned fid %x\n", did);
+               printk(KERN_INFO "libfc: Assigned FID (%6x) in FLOGI response\n",
+                      did);
                fc_host_port_id(lport->host) = did;
 
                flp = fc_frame_payload_get(fp, sizeof(*flp));
@@ -1494,7 +1486,8 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
                                if (e_d_tov > lport->e_d_tov)
                                        lport->e_d_tov = e_d_tov;
                                lport->r_a_tov = 2 * e_d_tov;
-                               FC_DBG("Point-to-Point mode\n");
+                               printk(KERN_INFO "libfc: Port (%6x) entered "
+                                      "point to point mode\n", did);
                                fc_lport_ptp_setup(lport, ntoh24(fh->fh_s_id),
                                                   get_unaligned_be64(
                                                           &flp->fl_wwpn),
@@ -1517,7 +1510,7 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
                        }
                }
        } else {
-               FC_DBG("bad FLOGI response\n");
+               FC_LPORT_DBG(lport, "Bad FLOGI response\n");
        }
 
 out:
@@ -1537,7 +1530,8 @@ void fc_lport_enter_flogi(struct fc_lport *lport)
 {
        struct fc_frame *fp;
 
-       FC_DEBUG_LPORT("Processing FLOGI state\n");
+       FC_LPORT_DBG(lport, "Entered FLOGI state from %s state\n",
+                    fc_lport_state(lport));
 
        fc_lport_state_enter(lport, LPORT_ST_FLOGI);
 
index 7bfbff7e0efb256656d1ef6ce8a5e8ac68fa9c69..7162385f52eb9fffe5eb04e80ab85d17760fc086 100644 (file)
 #include <scsi/libfc.h>
 #include <scsi/fc_encode.h>
 
-static int fc_rport_debug;
-
-#define FC_DEBUG_RPORT(fmt...)                 \
-       do {                                    \
-               if (fc_rport_debug)             \
-                       FC_DBG(fmt);            \
-       } while (0)
-
 struct workqueue_struct *rport_event_queue;
 
 static void fc_rport_enter_plogi(struct fc_rport *);
@@ -97,7 +89,7 @@ static const char *fc_rport_state_names[] = {
 static void fc_rport_rogue_destroy(struct device *dev)
 {
        struct fc_rport *rport = dev_to_rport(dev);
-       FC_DEBUG_RPORT("Destroying rogue rport (%6x)\n", rport->port_id);
+       FC_RPORT_DBG(rport, "Destroying rogue rport\n");
        kfree(rport);
 }
 
@@ -263,8 +255,8 @@ static void fc_rport_work(struct work_struct *work)
 
                        fc_rport_state_enter(new_rport, RPORT_ST_READY);
                } else {
-                       FC_DBG("Failed to create the rport for port "
-                              "(%6x).\n", ids.port_id);
+                       printk(KERN_WARNING "libfc: Failed to allocate "
+                              " memory for rport (%6x)\n", ids.port_id);
                        event = RPORT_EV_FAILED;
                }
                if (rport->port_id != FC_FID_DIR_SERV)
@@ -309,7 +301,7 @@ int fc_rport_login(struct fc_rport *rport)
 
        mutex_lock(&rdata->rp_mutex);
 
-       FC_DEBUG_RPORT("Login to port (%6x)\n", rport->port_id);
+       FC_RPORT_DBG(rport, "Login to port\n");
 
        fc_rport_enter_plogi(rport);
 
@@ -329,16 +321,13 @@ int fc_rport_login(struct fc_rport *rport)
 int fc_rport_logoff(struct fc_rport *rport)
 {
        struct fc_rport_libfc_priv *rdata = rport->dd_data;
-       struct fc_lport *lport = rdata->local_port;
 
        mutex_lock(&rdata->rp_mutex);
 
-       FC_DEBUG_RPORT("Remove port (%6x)\n", rport->port_id);
+       FC_RPORT_DBG(rport, "Remove port\n");
 
        if (rdata->rp_state == RPORT_ST_NONE) {
-               FC_DEBUG_RPORT("(%6x): Port (%6x) in NONE state,"
-                              " not removing", fc_host_port_id(lport->host),
-                              rport->port_id);
+               FC_RPORT_DBG(rport, "Port in NONE state, not removing\n");
                mutex_unlock(&rdata->rp_mutex);
                goto out;
        }
@@ -379,7 +368,7 @@ static void fc_rport_enter_ready(struct fc_rport *rport)
 
        fc_rport_state_enter(rport, RPORT_ST_READY);
 
-       FC_DEBUG_RPORT("Port (%6x) is Ready\n", rport->port_id);
+       FC_RPORT_DBG(rport, "Port is Ready\n");
 
        rdata->event = RPORT_EV_CREATED;
        queue_work(rport_event_queue, &rdata->event_work);
@@ -436,8 +425,8 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp)
 {
        struct fc_rport_libfc_priv *rdata = rport->dd_data;
 
-       FC_DEBUG_RPORT("Error %ld in state %s, retries %d\n",
-                      PTR_ERR(fp), fc_rport_state(rport), rdata->retries);
+       FC_RPORT_DBG(rport, "Error %ld in state %s, retries %d\n",
+                    PTR_ERR(fp), fc_rport_state(rport), rdata->retries);
 
        switch (rdata->rp_state) {
        case RPORT_ST_PLOGI:
@@ -479,8 +468,8 @@ static void fc_rport_error_retry(struct fc_rport *rport, struct fc_frame *fp)
                return fc_rport_error(rport, fp);
 
        if (rdata->retries < rdata->local_port->max_rport_retry_count) {
-               FC_DEBUG_RPORT("Error %ld in state %s, retrying\n",
-                              PTR_ERR(fp), fc_rport_state(rport));
+               FC_RPORT_DBG(rport, "Error %ld in state %s, retrying\n",
+                            PTR_ERR(fp), fc_rport_state(rport));
                rdata->retries++;
                /* no additional delay on exchange timeouts */
                if (PTR_ERR(fp) == -FC_EX_TIMEOUT)
@@ -517,12 +506,11 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
 
        mutex_lock(&rdata->rp_mutex);
 
-       FC_DEBUG_RPORT("Received a PLOGI response from port (%6x)\n",
-                      rport->port_id);
+       FC_RPORT_DBG(rport, "Received a PLOGI response\n");
 
        if (rdata->rp_state != RPORT_ST_PLOGI) {
-               FC_DBG("Received a PLOGI response, but in state %s\n",
-                      fc_rport_state(rport));
+               FC_RPORT_DBG(rport, "Received a PLOGI response, but in state "
+                            "%s\n", fc_rport_state(rport));
                if (IS_ERR(fp))
                        goto err;
                goto out;
@@ -583,8 +571,8 @@ static void fc_rport_enter_plogi(struct fc_rport *rport)
        struct fc_lport *lport = rdata->local_port;
        struct fc_frame *fp;
 
-       FC_DEBUG_RPORT("Port (%6x) entered PLOGI state from %s state\n",
-                      rport->port_id, fc_rport_state(rport));
+       FC_RPORT_DBG(rport, "Port entered PLOGI state from %s state\n",
+                    fc_rport_state(rport));
 
        fc_rport_state_enter(rport, RPORT_ST_PLOGI);
 
@@ -628,12 +616,11 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
 
        mutex_lock(&rdata->rp_mutex);
 
-       FC_DEBUG_RPORT("Received a PRLI response from port (%6x)\n",
-                      rport->port_id);
+       FC_RPORT_DBG(rport, "Received a PRLI response\n");
 
        if (rdata->rp_state != RPORT_ST_PRLI) {
-               FC_DBG("Received a PRLI response, but in state %s\n",
-                      fc_rport_state(rport));
+               FC_RPORT_DBG(rport, "Received a PRLI response, but in state "
+                            "%s\n", fc_rport_state(rport));
                if (IS_ERR(fp))
                        goto err;
                goto out;
@@ -663,7 +650,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
                fc_rport_enter_rtv(rport);
 
        } else {
-               FC_DBG("Bad ELS response\n");
+               FC_RPORT_DBG(rport, "Bad ELS response for PRLI command\n");
                rdata->event = RPORT_EV_FAILED;
                fc_rport_state_enter(rport, RPORT_ST_NONE);
                queue_work(rport_event_queue, &rdata->event_work);
@@ -695,12 +682,11 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
 
        mutex_lock(&rdata->rp_mutex);
 
-       FC_DEBUG_RPORT("Received a LOGO response from port (%6x)\n",
-                      rport->port_id);
+       FC_RPORT_DBG(rport, "Received a LOGO response\n");
 
        if (rdata->rp_state != RPORT_ST_LOGO) {
-               FC_DEBUG_RPORT("Received a LOGO response, but in state %s\n",
-                              fc_rport_state(rport));
+               FC_RPORT_DBG(rport, "Received a LOGO response, but in state "
+                            "%s\n", fc_rport_state(rport));
                if (IS_ERR(fp))
                        goto err;
                goto out;
@@ -715,7 +701,7 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
        if (op == ELS_LS_ACC) {
                fc_rport_enter_rtv(rport);
        } else {
-               FC_DBG("Bad ELS response\n");
+               FC_RPORT_DBG(rport, "Bad ELS response for LOGO command\n");
                rdata->event = RPORT_EV_LOGO;
                fc_rport_state_enter(rport, RPORT_ST_NONE);
                queue_work(rport_event_queue, &rdata->event_work);
@@ -745,8 +731,8 @@ static void fc_rport_enter_prli(struct fc_rport *rport)
        } *pp;
        struct fc_frame *fp;
 
-       FC_DEBUG_RPORT("Port (%6x) entered PRLI state from %s state\n",
-                      rport->port_id, fc_rport_state(rport));
+       FC_RPORT_DBG(rport, "Port entered PRLI state from %s state\n",
+                    fc_rport_state(rport));
 
        fc_rport_state_enter(rport, RPORT_ST_PRLI);
 
@@ -784,12 +770,11 @@ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp,
 
        mutex_lock(&rdata->rp_mutex);
 
-       FC_DEBUG_RPORT("Received a RTV response from port (%6x)\n",
-                      rport->port_id);
+       FC_RPORT_DBG(rport, "Received a RTV response\n");
 
        if (rdata->rp_state != RPORT_ST_RTV) {
-               FC_DBG("Received a RTV response, but in state %s\n",
-                      fc_rport_state(rport));
+               FC_RPORT_DBG(rport, "Received a RTV response, but in state "
+                            "%s\n", fc_rport_state(rport));
                if (IS_ERR(fp))
                        goto err;
                goto out;
@@ -844,8 +829,8 @@ static void fc_rport_enter_rtv(struct fc_rport *rport)
        struct fc_rport_libfc_priv *rdata = rport->dd_data;
        struct fc_lport *lport = rdata->local_port;
 
-       FC_DEBUG_RPORT("Port (%6x) entered RTV state from %s state\n",
-                      rport->port_id, fc_rport_state(rport));
+       FC_RPORT_DBG(rport, "Port entered RTV state from %s state\n",
+                    fc_rport_state(rport));
 
        fc_rport_state_enter(rport, RPORT_ST_RTV);
 
@@ -875,8 +860,8 @@ static void fc_rport_enter_logo(struct fc_rport *rport)
        struct fc_lport *lport = rdata->local_port;
        struct fc_frame *fp;
 
-       FC_DEBUG_RPORT("Port (%6x) entered LOGO state from %s state\n",
-                      rport->port_id, fc_rport_state(rport));
+       FC_RPORT_DBG(rport, "Port entered LOGO state from %s state\n",
+                    fc_rport_state(rport));
 
        fc_rport_state_enter(rport, RPORT_ST_LOGO);
 
@@ -983,14 +968,13 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport,
 
        fh = fc_frame_header_get(fp);
 
-       FC_DEBUG_RPORT("Received PLOGI request from port (%6x) "
-                      "while in state %s\n", ntoh24(fh->fh_s_id),
-                      fc_rport_state(rport));
+       FC_RPORT_DBG(rport, "Received PLOGI request while in state %s\n",
+                    fc_rport_state(rport));
 
        sid = ntoh24(fh->fh_s_id);
        pl = fc_frame_payload_get(fp, sizeof(*pl));
        if (!pl) {
-               FC_DBG("incoming PLOGI from %x too short\n", sid);
+               FC_RPORT_DBG(rport, "Received PLOGI too short\n");
                WARN_ON(1);
                /* XXX TBD: send reject? */
                fc_frame_free(fp);
@@ -1012,26 +996,26 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport,
         */
        switch (rdata->rp_state) {
        case RPORT_ST_INIT:
-               FC_DEBUG_RPORT("incoming PLOGI from %6x wwpn %llx state INIT "
-                              "- reject\n", sid, (unsigned long long)wwpn);
+               FC_RPORT_DBG(rport, "Received PLOGI, wwpn %llx state INIT "
+                            "- reject\n", (unsigned long long)wwpn);
                reject = ELS_RJT_UNSUP;
                break;
        case RPORT_ST_PLOGI:
-               FC_DEBUG_RPORT("incoming PLOGI from %x in PLOGI state %d\n",
-                              sid, rdata->rp_state);
+               FC_RPORT_DBG(rport, "Received PLOGI in PLOGI state %d\n",
+                            rdata->rp_state);
                if (wwpn < lport->wwpn)
                        reject = ELS_RJT_INPROG;
                break;
        case RPORT_ST_PRLI:
        case RPORT_ST_READY:
-               FC_DEBUG_RPORT("incoming PLOGI from %x in logged-in state %d "
-                              "- ignored for now\n", sid, rdata->rp_state);
+               FC_RPORT_DBG(rport, "Received PLOGI in logged-in state %d "
+                            "- ignored for now\n", rdata->rp_state);
                /* XXX TBD - should reset */
                break;
        case RPORT_ST_NONE:
        default:
-               FC_DEBUG_RPORT("incoming PLOGI from %x in unexpected "
-                              "state %d\n", sid, rdata->rp_state);
+               FC_RPORT_DBG(rport, "Received PLOGI in unexpected "
+                            "state %d\n", rdata->rp_state);
                fc_frame_free(fp);
                return;
                break;
@@ -1115,9 +1099,8 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport,
 
        fh = fc_frame_header_get(rx_fp);
 
-       FC_DEBUG_RPORT("Received PRLI request from port (%6x) "
-                      "while in state %s\n", ntoh24(fh->fh_s_id),
-                      fc_rport_state(rport));
+       FC_RPORT_DBG(rport, "Received PRLI request while in state %s\n",
+                    fc_rport_state(rport));
 
        switch (rdata->rp_state) {
        case RPORT_ST_PRLI:
@@ -1252,9 +1235,8 @@ static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp,
 
        fh = fc_frame_header_get(fp);
 
-       FC_DEBUG_RPORT("Received PRLO request from port (%6x) "
-                      "while in state %s\n", ntoh24(fh->fh_s_id),
-                      fc_rport_state(rport));
+       FC_RPORT_DBG(rport, "Received PRLO request while in state %s\n",
+                    fc_rport_state(rport));
 
        if (rdata->rp_state == RPORT_ST_NONE) {
                fc_frame_free(fp);
@@ -1286,9 +1268,8 @@ static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp,
 
        fh = fc_frame_header_get(fp);
 
-       FC_DEBUG_RPORT("Received LOGO request from port (%6x) "
-                      "while in state %s\n", ntoh24(fh->fh_s_id),
-                      fc_rport_state(rport));
+       FC_RPORT_DBG(rport, "Received LOGO request while in state %s\n",
+                    fc_rport_state(rport));
 
        if (rdata->rp_state == RPORT_ST_NONE) {
                fc_frame_free(fp);
@@ -1308,7 +1289,6 @@ static void fc_rport_flush_queue(void)
        flush_workqueue(rport_event_queue);
 }
 
-
 int fc_rport_init(struct fc_lport *lport)
 {
        if (!lport->tt.rport_create)
index 59908aead531e6257ad63f1767cf736c82585956..716cc344c5dfb5253eb5436cd0e19e5fbaa82b66 100644 (file)
 #include <scsi/scsi_transport_iscsi.h>
 #include <scsi/libiscsi.h>
 
-static int iscsi_dbg_lib;
-module_param_named(debug_libiscsi, iscsi_dbg_lib, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug_libiscsi, "Turn on debugging for libiscsi module. "
-                "Set to 1 to turn on, and zero to turn off. Default "
-                "is off.");
+static int iscsi_dbg_lib_conn;
+module_param_named(debug_libiscsi_conn, iscsi_dbg_lib_conn, int,
+                  S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug_libiscsi_conn,
+                "Turn on debugging for connections in libiscsi module. "
+                "Set to 1 to turn on, and zero to turn off. Default is off.");
+
+static int iscsi_dbg_lib_session;
+module_param_named(debug_libiscsi_session, iscsi_dbg_lib_session, int,
+                  S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug_libiscsi_session,
+                "Turn on debugging for sessions in libiscsi module. "
+                "Set to 1 to turn on, and zero to turn off. Default is off.");
+
+static int iscsi_dbg_lib_eh;
+module_param_named(debug_libiscsi_eh, iscsi_dbg_lib_eh, int,
+                  S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug_libiscsi_eh,
+                "Turn on debugging for error handling in libiscsi module. "
+                "Set to 1 to turn on, and zero to turn off. Default is off.");
 
 #define ISCSI_DBG_CONN(_conn, dbg_fmt, arg...)                 \
        do {                                                    \
-               if (iscsi_dbg_lib)                              \
+               if (iscsi_dbg_lib_conn)                         \
                        iscsi_conn_printk(KERN_INFO, _conn,     \
                                             "%s " dbg_fmt,     \
                                             __func__, ##arg);  \
@@ -54,7 +69,15 @@ MODULE_PARM_DESC(debug_libiscsi, "Turn on debugging for libiscsi module. "
 
 #define ISCSI_DBG_SESSION(_session, dbg_fmt, arg...)                   \
        do {                                                            \
-               if (iscsi_dbg_lib)                                      \
+               if (iscsi_dbg_lib_session)                              \
+                       iscsi_session_printk(KERN_INFO, _session,       \
+                                            "%s " dbg_fmt,             \
+                                            __func__, ##arg);          \
+       } while (0);
+
+#define ISCSI_DBG_EH(_session, dbg_fmt, arg...)                                \
+       do {                                                            \
+               if (iscsi_dbg_lib_eh)                                   \
                        iscsi_session_printk(KERN_INFO, _session,       \
                                             "%s " dbg_fmt,             \
                                             __func__, ##arg);          \
@@ -954,6 +977,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                task = iscsi_itt_to_ctask(conn, hdr->itt);
                if (!task)
                        return ISCSI_ERR_BAD_ITT;
+               task->last_xfer = jiffies;
                break;
        case ISCSI_OP_R2T:
                /*
@@ -1192,10 +1216,12 @@ static int iscsi_xmit_task(struct iscsi_conn *conn)
        spin_unlock_bh(&conn->session->lock);
        rc = conn->session->tt->xmit_task(task);
        spin_lock_bh(&conn->session->lock);
-       __iscsi_put_task(task);
-       if (!rc)
+       if (!rc) {
                /* done with this task */
+               task->last_xfer = jiffies;
                conn->task = NULL;
+       }
+       __iscsi_put_task(task);
        return rc;
 }
 
@@ -1361,6 +1387,9 @@ static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn,
        task->state = ISCSI_TASK_PENDING;
        task->conn = conn;
        task->sc = sc;
+       task->have_checked_conn = false;
+       task->last_timeout = jiffies;
+       task->last_xfer = jiffies;
        INIT_LIST_HEAD(&task->running);
        return task;
 }
@@ -1555,10 +1584,10 @@ int iscsi_eh_target_reset(struct scsi_cmnd *sc)
        spin_lock_bh(&session->lock);
        if (session->state == ISCSI_STATE_TERMINATE) {
 failed:
-               iscsi_session_printk(KERN_INFO, session,
-                                    "failing target reset: Could not log "
-                                    "back into target [age %d]\n",
-                                    session->age);
+               ISCSI_DBG_EH(session,
+                            "failing target reset: Could not log back into "
+                            "target [age %d]\n",
+                            session->age);
                spin_unlock_bh(&session->lock);
                mutex_unlock(&session->eh_mutex);
                return FAILED;
@@ -1572,7 +1601,7 @@ failed:
         */
        iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
 
-       ISCSI_DBG_SESSION(session, "wait for relogin\n");
+       ISCSI_DBG_EH(session, "wait for relogin\n");
        wait_event_interruptible(conn->ehwait,
                                 session->state == ISCSI_STATE_TERMINATE ||
                                 session->state == ISCSI_STATE_LOGGED_IN ||
@@ -1582,10 +1611,10 @@ failed:
 
        mutex_lock(&session->eh_mutex);
        spin_lock_bh(&session->lock);
-       if (session->state == ISCSI_STATE_LOGGED_IN)
-               iscsi_session_printk(KERN_INFO, session,
-                                    "target reset succeeded\n");
-       else
+       if (session->state == ISCSI_STATE_LOGGED_IN) {
+               ISCSI_DBG_EH(session,
+                            "target reset succeeded\n");
+       else
                goto failed;
        spin_unlock_bh(&session->lock);
        mutex_unlock(&session->eh_mutex);
@@ -1601,7 +1630,7 @@ static void iscsi_tmf_timedout(unsigned long data)
        spin_lock(&session->lock);
        if (conn->tmf_state == TMF_QUEUED) {
                conn->tmf_state = TMF_TIMEDOUT;
-               ISCSI_DBG_SESSION(session, "tmf timedout\n");
+               ISCSI_DBG_EH(session, "tmf timedout\n");
                /* unblock eh_abort() */
                wake_up(&conn->ehwait);
        }
@@ -1621,7 +1650,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
                spin_unlock_bh(&session->lock);
                iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
                spin_lock_bh(&session->lock);
-               ISCSI_DBG_SESSION(session, "tmf exec failure\n");
+               ISCSI_DBG_EH(session, "tmf exec failure\n");
                return -EPERM;
        }
        conn->tmfcmd_pdus_cnt++;
@@ -1629,7 +1658,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
        conn->tmf_timer.function = iscsi_tmf_timedout;
        conn->tmf_timer.data = (unsigned long)conn;
        add_timer(&conn->tmf_timer);
-       ISCSI_DBG_SESSION(session, "tmf set timeout\n");
+       ISCSI_DBG_EH(session, "tmf set timeout\n");
 
        spin_unlock_bh(&session->lock);
        mutex_unlock(&session->eh_mutex);
@@ -1716,17 +1745,18 @@ static int iscsi_has_ping_timed_out(struct iscsi_conn *conn)
                return 0;
 }
 
-static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
+static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
 {
+       enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED;
+       struct iscsi_task *task = NULL;
        struct iscsi_cls_session *cls_session;
        struct iscsi_session *session;
        struct iscsi_conn *conn;
-       enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED;
 
-       cls_session = starget_to_session(scsi_target(scmd->device));
+       cls_session = starget_to_session(scsi_target(sc->device));
        session = cls_session->dd_data;
 
-       ISCSI_DBG_SESSION(session, "scsi cmd %p timedout\n", scmd);
+       ISCSI_DBG_EH(session, "scsi cmd %p timedout\n", sc);
 
        spin_lock(&session->lock);
        if (session->state != ISCSI_STATE_LOGGED_IN) {
@@ -1745,6 +1775,26 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
                goto done;
        }
 
+       task = (struct iscsi_task *)sc->SCp.ptr;
+       if (!task)
+               goto done;
+       /*
+        * If we have sent (at least queued to the network layer) a pdu or
+        * recvd one for the task since the last timeout ask for
+        * more time. If on the next timeout we have not made progress
+        * we can check if it is the task or connection when we send the
+        * nop as a ping.
+        */
+       if (time_after_eq(task->last_xfer, task->last_timeout)) {
+               ISCSI_DBG_EH(session, "Command making progress. Asking "
+                            "scsi-ml for more time to complete. "
+                            "Last data recv at %lu. Last timeout was at "
+                            "%lu\n.", task->last_xfer, task->last_timeout);
+               task->have_checked_conn = false;
+               rc = BLK_EH_RESET_TIMER;
+               goto done;
+       }
+
        if (!conn->recv_timeout && !conn->ping_timeout)
                goto done;
        /*
@@ -1755,23 +1805,32 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
                rc = BLK_EH_RESET_TIMER;
                goto done;
        }
+
+       /* Assumes nop timeout is shorter than scsi cmd timeout */
+       if (task->have_checked_conn)
+               goto done;
+
        /*
-        * if we are about to check the transport then give the command
-        * more time
+        * Checking the transport already or nop from a cmd timeout still
+        * running
         */
-       if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ),
-                          jiffies)) {
+       if (conn->ping_task) {
+               task->have_checked_conn = true;
                rc = BLK_EH_RESET_TIMER;
                goto done;
        }
 
-       /* if in the middle of checking the transport then give us more time */
-       if (conn->ping_task)
-               rc = BLK_EH_RESET_TIMER;
+       /* Make sure there is a transport check done */
+       iscsi_send_nopout(conn, NULL);
+       task->have_checked_conn = true;
+       rc = BLK_EH_RESET_TIMER;
+
 done:
+       if (task)
+               task->last_timeout = jiffies;
        spin_unlock(&session->lock);
-       ISCSI_DBG_SESSION(session, "return %s\n", rc == BLK_EH_RESET_TIMER ?
-                         "timer reset" : "nh");
+       ISCSI_DBG_EH(session, "return %s\n", rc == BLK_EH_RESET_TIMER ?
+                    "timer reset" : "nh");
        return rc;
 }
 
@@ -1841,7 +1900,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
        cls_session = starget_to_session(scsi_target(sc->device));
        session = cls_session->dd_data;
 
-       ISCSI_DBG_SESSION(session, "aborting sc %p\n", sc);
+       ISCSI_DBG_EH(session, "aborting sc %p\n", sc);
 
        mutex_lock(&session->eh_mutex);
        spin_lock_bh(&session->lock);
@@ -1850,8 +1909,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
         * got the command.
         */
        if (!sc->SCp.ptr) {
-               ISCSI_DBG_SESSION(session, "sc never reached iscsi layer or "
-                                 "it completed.\n");
+               ISCSI_DBG_EH(session, "sc never reached iscsi layer or "
+                                     "it completed.\n");
                spin_unlock_bh(&session->lock);
                mutex_unlock(&session->eh_mutex);
                return SUCCESS;
@@ -1865,7 +1924,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
            sc->SCp.phase != session->age) {
                spin_unlock_bh(&session->lock);
                mutex_unlock(&session->eh_mutex);
-               ISCSI_DBG_SESSION(session, "failing abort due to dropped "
+               ISCSI_DBG_EH(session, "failing abort due to dropped "
                                  "session.\n");
                return FAILED;
        }
@@ -1875,13 +1934,12 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
        age = session->age;
 
        task = (struct iscsi_task *)sc->SCp.ptr;
-       ISCSI_DBG_SESSION(session, "aborting [sc %p itt 0x%x]\n",
-                         sc, task->itt);
+       ISCSI_DBG_EH(session, "aborting [sc %p itt 0x%x]\n",
+                    sc, task->itt);
 
        /* task completed before time out */
        if (!task->sc) {
-               ISCSI_DBG_SESSION(session, "sc completed while abort in "
-                                 "progress\n");
+               ISCSI_DBG_EH(session, "sc completed while abort in progress\n");
                goto success;
        }
 
@@ -1930,8 +1988,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
                if (!sc->SCp.ptr) {
                        conn->tmf_state = TMF_INITIAL;
                        /* task completed before tmf abort response */
-                       ISCSI_DBG_SESSION(session, "sc completed while abort "
-                                         "in progress\n");
+                       ISCSI_DBG_EH(session, "sc completed while abort in "
+                                             "progress\n");
                        goto success;
                }
                /* fall through */
@@ -1943,16 +2001,16 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
 success:
        spin_unlock_bh(&session->lock);
 success_unlocked:
-       ISCSI_DBG_SESSION(session, "abort success [sc %p itt 0x%x]\n",
-                         sc, task->itt);
+       ISCSI_DBG_EH(session, "abort success [sc %p itt 0x%x]\n",
+                    sc, task->itt);
        mutex_unlock(&session->eh_mutex);
        return SUCCESS;
 
 failed:
        spin_unlock_bh(&session->lock);
 failed_unlocked:
-       ISCSI_DBG_SESSION(session, "abort failed [sc %p itt 0x%x]\n", sc,
-                         task ? task->itt : 0);
+       ISCSI_DBG_EH(session, "abort failed [sc %p itt 0x%x]\n", sc,
+                    task ? task->itt : 0);
        mutex_unlock(&session->eh_mutex);
        return FAILED;
 }
@@ -1979,8 +2037,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
        cls_session = starget_to_session(scsi_target(sc->device));
        session = cls_session->dd_data;
 
-       ISCSI_DBG_SESSION(session, "LU Reset [sc %p lun %u]\n",
-                         sc, sc->device->lun);
+       ISCSI_DBG_EH(session, "LU Reset [sc %p lun %u]\n", sc, sc->device->lun);
 
        mutex_lock(&session->eh_mutex);
        spin_lock_bh(&session->lock);
@@ -2034,8 +2091,8 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
 unlock:
        spin_unlock_bh(&session->lock);
 done:
-       ISCSI_DBG_SESSION(session, "dev reset result = %s\n",
-                        rc == SUCCESS ? "SUCCESS" : "FAILED");
+       ISCSI_DBG_EH(session, "dev reset result = %s\n",
+                    rc == SUCCESS ? "SUCCESS" : "FAILED");
        mutex_unlock(&session->eh_mutex);
        return rc;
 }
index 2bc07090321da30562b3b21ef6c2b6b8dc51e887..2e0746d703037fe6b04e84f3cb3acafa0d641807 100644 (file)
@@ -686,6 +686,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
                                     "offset=%d, datalen=%d)\n",
                                      tcp_task->data_offset,
                                      tcp_conn->in.datalen);
+                       task->last_xfer = jiffies;
                        rc = iscsi_segment_seek_sg(&tcp_conn->in.segment,
                                                   sdb->table.sgl,
                                                   sdb->table.nents,
@@ -713,9 +714,10 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
                        rc = ISCSI_ERR_BAD_ITT;
                else if (ahslen)
                        rc = ISCSI_ERR_AHSLEN;
-               else if (task->sc->sc_data_direction == DMA_TO_DEVICE)
+               else if (task->sc->sc_data_direction == DMA_TO_DEVICE) {
+                       task->last_xfer = jiffies;
                        rc = iscsi_tcp_r2t_rsp(conn, task);
-               else
+               else
                        rc = ISCSI_ERR_PROTO;
                spin_unlock(&conn->session->lock);
                break;
index 4a990f4da4ea95254fda1e6c233e202e86ad6cea..cca8e4ab0372fb4625d0e269e0c07a67ea14fa64 100644 (file)
@@ -216,7 +216,7 @@ qla24xx_soft_reset(struct qla_hw_data *ha)
 
 static int
 qla2xxx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint16_t *ram,
-    uint16_t ram_words, void **nxt)
+    uint32_t ram_words, void **nxt)
 {
        int rval;
        uint32_t cnt, stat, timer, words, idx;
index 26202612932534cbd2b0bebcec847d1cb7d3ce6c..f2ce8e3cc91bc661d91f23a699cc68894530030e 100644 (file)
@@ -2301,7 +2301,7 @@ qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
        static char *link_speeds[] = { "1", "2", "?", "4", "8", "10" };
        char *link_speed;
        int rval;
-       uint16_t mb[6];
+       uint16_t mb[4];
        struct qla_hw_data *ha = vha->hw;
 
        if (!IS_IIDMA_CAPABLE(ha))
index 451ece0760b0f6ea49bb7884f5f95b2ac5528783..fe69f30576716a5bceaf0bdd8cd4181910caa63b 100644 (file)
@@ -1267,17 +1267,22 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
 
        mcp->mb[0] = MBC_GET_FIRMWARE_STATE;
        mcp->out_mb = MBX_0;
-       mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+       if (IS_FWI2_CAPABLE(vha->hw))
+               mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+       else
+               mcp->in_mb = MBX_1|MBX_0;
        mcp->tov = MBX_TOV_SECONDS;
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
 
        /* Return firmware states. */
        states[0] = mcp->mb[1];
-       states[1] = mcp->mb[2];
-       states[2] = mcp->mb[3];
-       states[3] = mcp->mb[4];
-       states[4] = mcp->mb[5];
+       if (IS_FWI2_CAPABLE(vha->hw)) {
+               states[1] = mcp->mb[2];
+               states[2] = mcp->mb[3];
+               states[3] = mcp->mb[4];
+               states[4] = mcp->mb[5];
+       }
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
@@ -2697,10 +2702,13 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
        mcp->mb[0] = MBC_PORT_PARAMS;
        mcp->mb[1] = loop_id;
        mcp->mb[2] = BIT_0;
-       mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0);
-       mcp->mb[4] = mcp->mb[5] = 0;
-       mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
-       mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0;
+       if (IS_QLA81XX(vha->hw))
+               mcp->mb[3] = port_speed & (BIT_5|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0);
+       else
+               mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0);
+       mcp->mb[9] = vha->vp_idx;
+       mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0;
+       mcp->in_mb = MBX_3|MBX_1|MBX_0;
        mcp->tov = MBX_TOV_SECONDS;
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
@@ -2710,8 +2718,6 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
                mb[0] = mcp->mb[0];
                mb[1] = mcp->mb[1];
                mb[3] = mcp->mb[3];
-               mb[4] = mcp->mb[4];
-               mb[5] = mcp->mb[5];
        }
 
        if (rval != QLA_SUCCESS) {
index dcf011679c8bbab5de6ab3d0b0dc58af4527ec80..f0396e79b6fa159a4a02226ba23ae171a7516652 100644 (file)
@@ -1663,7 +1663,7 @@ skip_pio:
                /* queue 0 uses two msix vectors */
                if (ql2xmultique_tag) {
                        cpus = num_online_cpus();
-                       ha->max_rsp_queues = (ha->msix_count - 1 - cpus) ?
+                       ha->max_rsp_queues = (ha->msix_count - 1 > cpus) ?
                                (cpus + 1) : (ha->msix_count - 1);
                        ha->max_req_queues = 2;
                } else if (ql2xmaxqueues > 1) {
index b63feaf43126bd27f35c951453265c9e27c896bf..84369705a9adcff8becb2625a5cb9590fefb0e64 100644 (file)
@@ -7,7 +7,7 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.03.01-k3"
+#define QLA2XXX_VERSION      "8.03.01-k4"
 
 #define QLA_DRIVER_MAJOR_VER   8
 #define QLA_DRIVER_MINOR_VER   3
index 41a21772df1289525ad8859608d1d54c73461e76..fb9af207d61dea365d3c3128809ada1da7258258 100644 (file)
@@ -101,6 +101,8 @@ static const char * scsi_debug_version_date = "20070104";
 #define DEF_DIF 0
 #define DEF_GUARD 0
 #define DEF_ATO 1
+#define DEF_PHYSBLK_EXP 0
+#define DEF_LOWEST_ALIGNED 0
 
 /* bit mask values for scsi_debug_opts */
 #define SCSI_DEBUG_OPT_NOISE   1
@@ -156,6 +158,8 @@ static int scsi_debug_dix = DEF_DIX;
 static int scsi_debug_dif = DEF_DIF;
 static int scsi_debug_guard = DEF_GUARD;
 static int scsi_debug_ato = DEF_ATO;
+static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
+static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
 
 static int scsi_debug_cmnd_count = 0;
 
@@ -657,7 +661,12 @@ static unsigned char vpdb0_data[] = {
 
 static int inquiry_evpd_b0(unsigned char * arr)
 {
+       unsigned int gran;
+
        memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
+       gran = 1 << scsi_debug_physblk_exp;
+       arr[2] = (gran >> 8) & 0xff;
+       arr[3] = gran & 0xff;
        if (sdebug_store_sectors > 0x400) {
                arr[4] = (sdebug_store_sectors >> 24) & 0xff;
                arr[5] = (sdebug_store_sectors >> 16) & 0xff;
@@ -945,6 +954,9 @@ static int resp_readcap16(struct scsi_cmnd * scp,
        arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
        arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
        arr[11] = scsi_debug_sector_size & 0xff;
+       arr[13] = scsi_debug_physblk_exp & 0xf;
+       arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
+       arr[15] = scsi_debug_lowest_aligned & 0xff;
 
        if (scsi_debug_dif) {
                arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
@@ -2380,6 +2392,8 @@ module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
 module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
 module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
 module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
+module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
+module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
 
 MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
 MODULE_DESCRIPTION("SCSI debug adapter driver");
@@ -2401,7 +2415,9 @@ MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
 MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
 MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
 MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
-MODULE_PARM_DESC(sector_size, "hardware sector size in bytes (def=512)");
+MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
+MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
+MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
 MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
 MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
 MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
@@ -2874,6 +2890,18 @@ static int __init scsi_debug_init(void)
                return -EINVAL;
        }
 
+       if (scsi_debug_physblk_exp > 15) {
+               printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n",
+                      scsi_debug_physblk_exp);
+               return -EINVAL;
+       }
+
+       if (scsi_debug_lowest_aligned > 0x3fff) {
+               printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n",
+                      scsi_debug_lowest_aligned);
+               return -EINVAL;
+       }
+
        if (scsi_debug_dev_size_mb < 1)
                scsi_debug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
        sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
index 8821df9a277bb8e5f5e536050ffc1bc2103f7bdc..93c2622cb969b1f6dadfa8e1ac8f73a8e6633945 100644 (file)
@@ -24,6 +24,13 @@ struct scsi_dev_info_list {
        unsigned compatible; /* for use with scsi_static_device_list entries */
 };
 
+struct scsi_dev_info_list_table {
+       struct list_head node;  /* our node for being on the master list */
+       struct list_head scsi_dev_info_list; /* head of dev info list */
+       const char *name;       /* name of list for /proc (NULL for global) */
+       int key;                /* unique numeric identifier */
+};
+
 
 static const char spaces[] = "                "; /* 16 of them */
 static unsigned scsi_default_dev_flags;
@@ -247,6 +254,22 @@ static struct {
        { NULL, NULL, NULL, 0 },
 };
 
+static struct scsi_dev_info_list_table *scsi_devinfo_lookup_by_key(int key)
+{
+       struct scsi_dev_info_list_table *devinfo_table;
+       int found = 0;
+
+       list_for_each_entry(devinfo_table, &scsi_dev_info_list, node)
+               if (devinfo_table->key == key) {
+                       found = 1;
+                       break;
+               }
+       if (!found)
+               return ERR_PTR(-EINVAL);
+
+       return devinfo_table;
+}
+
 /*
  * scsi_strcpy_devinfo: called from scsi_dev_info_list_add to copy into
  * devinfo vendor and model strings.
@@ -295,8 +318,39 @@ static void scsi_strcpy_devinfo(char *name, char *to, size_t to_length,
  **/
 static int scsi_dev_info_list_add(int compatible, char *vendor, char *model,
                            char *strflags, int flags)
+{
+       return scsi_dev_info_list_add_keyed(compatible, vendor, model,
+                                           strflags, flags,
+                                           SCSI_DEVINFO_GLOBAL);
+}
+
+/**
+ * scsi_dev_info_list_add_keyed - add one dev_info list entry.
+ * @compatible: if true, null terminate short strings.  Otherwise space pad.
+ * @vendor:    vendor string
+ * @model:     model (product) string
+ * @strflags:  integer string
+ * @flags:     if strflags NULL, use this flag value
+ * @key:       specify list to use
+ *
+ * Description:
+ *     Create and add one dev_info entry for @vendor, @model,
+ *     @strflags or @flag in list specified by @key. If @compatible,
+ *     add to the tail of the list, do not space pad, and set
+ *     devinfo->compatible. The scsi_static_device_list entries are
+ *     added with @compatible 1 and @clfags NULL.
+ *
+ * Returns: 0 OK, -error on failure.
+ **/
+int scsi_dev_info_list_add_keyed(int compatible, char *vendor, char *model,
+                                char *strflags, int flags, int key)
 {
        struct scsi_dev_info_list *devinfo;
+       struct scsi_dev_info_list_table *devinfo_table =
+               scsi_devinfo_lookup_by_key(key);
+
+       if (IS_ERR(devinfo_table))
+               return PTR_ERR(devinfo_table);
 
        devinfo = kmalloc(sizeof(*devinfo), GFP_KERNEL);
        if (!devinfo) {
@@ -317,12 +371,15 @@ static int scsi_dev_info_list_add(int compatible, char *vendor, char *model,
        devinfo->compatible = compatible;
 
        if (compatible)
-               list_add_tail(&devinfo->dev_info_list, &scsi_dev_info_list);
+               list_add_tail(&devinfo->dev_info_list,
+                             &devinfo_table->scsi_dev_info_list);
        else
-               list_add(&devinfo->dev_info_list, &scsi_dev_info_list);
+               list_add(&devinfo->dev_info_list,
+                        &devinfo_table->scsi_dev_info_list);
 
        return 0;
 }
+EXPORT_SYMBOL(scsi_dev_info_list_add_keyed);
 
 /**
  * scsi_dev_info_list_add_str - parse dev_list and add to the scsi_dev_info_list.
@@ -382,22 +439,48 @@ static int scsi_dev_info_list_add_str(char *dev_list)
  * @model:     model name
  *
  * Description:
- *     Search the scsi_dev_info_list for an entry matching @vendor and
- *     @model, if found, return the matching flags value, else return
- *     the host or global default settings.  Called during scan time.
+ *     Search the global scsi_dev_info_list (specified by list zero)
+ *     for an entry matching @vendor and @model, if found, return the
+ *     matching flags value, else return the host or global default
+ *     settings.  Called during scan time.
  **/
 int scsi_get_device_flags(struct scsi_device *sdev,
                          const unsigned char *vendor,
                          const unsigned char *model)
+{
+       return scsi_get_device_flags_keyed(sdev, vendor, model,
+                                          SCSI_DEVINFO_GLOBAL);
+}
+
+
+/**
+ * get_device_flags_keyed - get device specific flags from the dynamic device list.
+ * @sdev:       &scsi_device to get flags for
+ * @vendor:    vendor name
+ * @model:     model name
+ * @key:       list to look up
+ *
+ * Description:
+ *     Search the scsi_dev_info_list specified by @key for an entry
+ *     matching @vendor and @model, if found, return the matching
+ *     flags value, else return the host or global default settings.
+ *     Called during scan time.
+ **/
+int scsi_get_device_flags_keyed(struct scsi_device *sdev,
+                               const unsigned char *vendor,
+                               const unsigned char *model,
+                               int key)
 {
        struct scsi_dev_info_list *devinfo;
-       unsigned int bflags;
+       struct scsi_dev_info_list_table *devinfo_table;
+
+       devinfo_table = scsi_devinfo_lookup_by_key(key);
 
-       bflags = sdev->sdev_bflags;
-       if (!bflags)
-               bflags = scsi_default_dev_flags;
+       if (IS_ERR(devinfo_table))
+               return PTR_ERR(devinfo_table);
 
-       list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) {
+       list_for_each_entry(devinfo, &devinfo_table->scsi_dev_info_list,
+                           dev_info_list) {
                if (devinfo->compatible) {
                        /*
                         * Behave like the older version of get_device_flags.
@@ -447,32 +530,89 @@ int scsi_get_device_flags(struct scsi_device *sdev,
                                return devinfo->flags;
                }
        }
-       return bflags;
+       /* nothing found, return nothing */
+       if (key != SCSI_DEVINFO_GLOBAL)
+               return 0;
+
+       /* except for the global list, where we have an exception */
+       if (sdev->sdev_bflags)
+               return sdev->sdev_bflags;
+
+       return scsi_default_dev_flags;
 }
+EXPORT_SYMBOL(scsi_get_device_flags_keyed);
 
 #ifdef CONFIG_SCSI_PROC_FS
+struct double_list {
+       struct list_head *top;
+       struct list_head *bottom;
+};
+
 static int devinfo_seq_show(struct seq_file *m, void *v)
 {
+       struct double_list *dl = v;
+       struct scsi_dev_info_list_table *devinfo_table =
+               list_entry(dl->top, struct scsi_dev_info_list_table, node);
        struct scsi_dev_info_list *devinfo =
-               list_entry(v, struct scsi_dev_info_list, dev_info_list);
+               list_entry(dl->bottom, struct scsi_dev_info_list,
+                          dev_info_list);
+
+       if (devinfo_table->scsi_dev_info_list.next == dl->bottom &&
+           devinfo_table->name)
+               seq_printf(m, "[%s]:\n", devinfo_table->name);
 
        seq_printf(m, "'%.8s' '%.16s' 0x%x\n",
-                       devinfo->vendor, devinfo->model, devinfo->flags);
+                  devinfo->vendor, devinfo->model, devinfo->flags);
        return 0;
 }
 
-static void * devinfo_seq_start(struct seq_file *m, loff_t *pos)
+static void *devinfo_seq_start(struct seq_file *m, loff_t *ppos)
 {
-       return seq_list_start(&scsi_dev_info_list, *pos);
+       struct double_list *dl = kmalloc(sizeof(*dl), GFP_KERNEL);
+       loff_t pos = *ppos;
+
+       if (!dl)
+               return NULL;
+
+       list_for_each(dl->top, &scsi_dev_info_list) {
+               struct scsi_dev_info_list_table *devinfo_table =
+                       list_entry(dl->top, struct scsi_dev_info_list_table,
+                                  node);
+               list_for_each(dl->bottom, &devinfo_table->scsi_dev_info_list)
+                       if (pos-- == 0)
+                               return dl;
+       }
+
+       kfree(dl);
+       return NULL;
 }
 
-static void * devinfo_seq_next(struct seq_file *m, void *v, loff_t *pos)
+static void *devinfo_seq_next(struct seq_file *m, void *v, loff_t *ppos)
 {
-       return seq_list_next(v, &scsi_dev_info_list, pos);
+       struct double_list *dl = v;
+       struct scsi_dev_info_list_table *devinfo_table =
+               list_entry(dl->top, struct scsi_dev_info_list_table, node);
+
+       ++*ppos;
+       dl->bottom = dl->bottom->next;
+       while (&devinfo_table->scsi_dev_info_list == dl->bottom) {
+               dl->top = dl->top->next;
+               if (dl->top == &scsi_dev_info_list) {
+                       kfree(dl);
+                       return NULL;
+               }
+               devinfo_table = list_entry(dl->top,
+                                          struct scsi_dev_info_list_table,
+                                          node);
+               dl->bottom = devinfo_table->scsi_dev_info_list.next;
+       }
+
+       return dl;
 }
 
 static void devinfo_seq_stop(struct seq_file *m, void *v)
 {
+       kfree(v);
 }
 
 static const struct seq_operations scsi_devinfo_seq_ops = {
@@ -549,19 +689,78 @@ MODULE_PARM_DESC(default_dev_flags,
  **/
 void scsi_exit_devinfo(void)
 {
-       struct list_head *lh, *lh_next;
-       struct scsi_dev_info_list *devinfo;
-
 #ifdef CONFIG_SCSI_PROC_FS
        remove_proc_entry("scsi/device_info", NULL);
 #endif
 
-       list_for_each_safe(lh, lh_next, &scsi_dev_info_list) {
+       scsi_dev_info_remove_list(SCSI_DEVINFO_GLOBAL);
+}
+
+/**
+ * scsi_dev_info_add_list - add a new devinfo list
+ * @key:       key of the list to add
+ * @name:      Name of the list to add (for /proc/scsi/device_info)
+ *
+ * Adds the requested list, returns zero on success, -EEXIST if the
+ * key is already registered to a list, or other error on failure.
+ */
+int scsi_dev_info_add_list(int key, const char *name)
+{
+       struct scsi_dev_info_list_table *devinfo_table =
+               scsi_devinfo_lookup_by_key(key);
+
+       if (!IS_ERR(devinfo_table))
+               /* list already exists */
+               return -EEXIST;
+
+       devinfo_table = kmalloc(sizeof(*devinfo_table), GFP_KERNEL);
+
+       if (!devinfo_table)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&devinfo_table->node);
+       INIT_LIST_HEAD(&devinfo_table->scsi_dev_info_list);
+       devinfo_table->name = name;
+       devinfo_table->key = key;
+       list_add_tail(&devinfo_table->node, &scsi_dev_info_list);
+
+       return 0;
+}
+EXPORT_SYMBOL(scsi_dev_info_add_list);
+
+/**
+ * scsi_dev_info_remove_list - destroy an added devinfo list
+ * @key: key of the list to destroy
+ *
+ * Iterates over the entire list first, freeing all the values, then
+ * frees the list itself.  Returns 0 on success or -EINVAL if the key
+ * can't be found.
+ */
+int scsi_dev_info_remove_list(int key)
+{
+       struct list_head *lh, *lh_next;
+       struct scsi_dev_info_list_table *devinfo_table =
+               scsi_devinfo_lookup_by_key(key);
+
+       if (IS_ERR(devinfo_table))
+               /* no such list */
+               return -EINVAL;
+
+       /* remove from the master list */
+       list_del(&devinfo_table->node);
+
+       list_for_each_safe(lh, lh_next, &devinfo_table->scsi_dev_info_list) {
+               struct scsi_dev_info_list *devinfo;
+
                devinfo = list_entry(lh, struct scsi_dev_info_list,
                                     dev_info_list);
                kfree(devinfo);
        }
+       kfree(devinfo_table);
+
+       return 0;
 }
+EXPORT_SYMBOL(scsi_dev_info_remove_list);
 
 /**
  * scsi_init_devinfo - set up the dynamic device list.
@@ -577,10 +776,14 @@ int __init scsi_init_devinfo(void)
 #endif
        int error, i;
 
-       error = scsi_dev_info_list_add_str(scsi_dev_flags);
+       error = scsi_dev_info_add_list(SCSI_DEVINFO_GLOBAL, NULL);
        if (error)
                return error;
 
+       error = scsi_dev_info_list_add_str(scsi_dev_flags);
+       if (error)
+               goto out;
+
        for (i = 0; scsi_static_device_list[i].vendor; i++) {
                error = scsi_dev_info_list_add(1 /* compatibile */,
                                scsi_static_device_list[i].vendor,
index 30f3275e119ed57473f1fd4e91270d38538eb025..f3c40898fc7d305a9815acccc1e6e366c9f3dd5b 100644 (file)
@@ -1207,6 +1207,7 @@ int scsi_prep_fn(struct request_queue *q, struct request *req)
                ret = scsi_setup_blk_pc_cmnd(sdev, req);
        return scsi_prep_return(q, req, ret);
 }
+EXPORT_SYMBOL(scsi_prep_fn);
 
 /*
  * scsi_dev_queue_ready: if we can send requests to sdev, return 1 else
index fbc83bebdd8efaef5aefaaf40fa5f78d72d42224..021e503c8c447615e651d2635f0981752b4d5860 100644 (file)
@@ -39,9 +39,25 @@ static inline void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
 #endif
 
 /* scsi_devinfo.c */
+
+/* list of keys for the lists */
+enum {
+       SCSI_DEVINFO_GLOBAL = 0,
+       SCSI_DEVINFO_SPI,
+};
+
 extern int scsi_get_device_flags(struct scsi_device *sdev,
                                 const unsigned char *vendor,
                                 const unsigned char *model);
+extern int scsi_get_device_flags_keyed(struct scsi_device *sdev,
+                                      const unsigned char *vendor,
+                                      const unsigned char *model, int key);
+extern int scsi_dev_info_list_add_keyed(int compatible, char *vendor,
+                                       char *model, char *strflags,
+                                       int flags, int key);
+extern int scsi_dev_info_add_list(int key, const char *name);
+extern int scsi_dev_info_remove_list(int key);
+
 extern int __init scsi_init_devinfo(void);
 extern void scsi_exit_devinfo(void);
 
@@ -71,7 +87,6 @@ extern int scsi_init_queue(void);
 extern void scsi_exit_queue(void);
 struct request_queue;
 struct request;
-extern int scsi_prep_fn(struct request_queue *, struct request *);
 extern struct kmem_cache *scsi_sdb_cache;
 
 /* scsi_proc.c */
index fa4711d127449834373a4881f96fc4f48f79aa80..91482f2dcc505ce61ff0b893448e5e717ecdd0c8 100644 (file)
@@ -420,29 +420,12 @@ static int scsi_bus_resume(struct device * dev)
        return err;
 }
 
-static int scsi_bus_remove(struct device *dev)
-{
-       struct device_driver *drv = dev->driver;
-       struct scsi_device *sdev = to_scsi_device(dev);
-       int err = 0;
-
-       /* reset the prep_fn back to the default since the
-        * driver may have altered it and it's being removed */
-       blk_queue_prep_rq(sdev->request_queue, scsi_prep_fn);
-
-       if (drv && drv->remove)
-               err = drv->remove(dev);
-
-       return 0;
-}
-
 struct bus_type scsi_bus_type = {
         .name          = "scsi",
         .match         = scsi_bus_match,
        .uevent         = scsi_bus_uevent,
        .suspend        = scsi_bus_suspend,
        .resume         = scsi_bus_resume,
-       .remove         = scsi_bus_remove,
 };
 EXPORT_SYMBOL_GPL(scsi_bus_type);
 
index 3f64d93b6c8ba7a4ca7e1e11dc91a9d3cd16e461..2eee9e6e4fe8f975eb580329cd4814244b482a0b 100644 (file)
@@ -3397,7 +3397,6 @@ fc_destroy_bsgjob(struct fc_bsg_job *job)
        kfree(job);
 }
 
-
 /**
  * fc_bsg_jobdone - completion routine for bsg requests that the LLD has
  *                  completed
@@ -3408,15 +3407,10 @@ fc_bsg_jobdone(struct fc_bsg_job *job)
 {
        struct request *req = job->req;
        struct request *rsp = req->next_rq;
-       unsigned long flags;
        int err;
 
-       spin_lock_irqsave(&job->job_lock, flags);
-       job->state_flags |= FC_RQST_STATE_DONE;
-       job->ref_cnt--;
-       spin_unlock_irqrestore(&job->job_lock, flags);
-
        err = job->req->errors = job->reply->result;
+
        if (err < 0)
                /* we're only returning the result field in the reply */
                job->req->sense_len = sizeof(uint32_t);
@@ -3433,13 +3427,27 @@ fc_bsg_jobdone(struct fc_bsg_job *job)
                rsp->resid_len -= min(job->reply->reply_payload_rcv_len,
                                      rsp->resid_len);
        }
+       blk_complete_request(req);
+}
 
-       blk_end_request_all(req, err);
+/**
+ * fc_bsg_softirq_done - softirq done routine for destroying the bsg requests
+ * @req:        BSG request that holds the job to be destroyed
+ */
+static void fc_bsg_softirq_done(struct request *rq)
+{
+       struct fc_bsg_job *job = rq->special;
+       unsigned long flags;
 
+       spin_lock_irqsave(&job->job_lock, flags);
+       job->state_flags |= FC_RQST_STATE_DONE;
+       job->ref_cnt--;
+       spin_unlock_irqrestore(&job->job_lock, flags);
+
+       blk_end_request_all(rq, rq->errors);
        fc_destroy_bsgjob(job);
 }
 
-
 /**
  * fc_bsg_job_timeout - handler for when a bsg request timesout
  * @req:       request that timed out
@@ -3471,19 +3479,13 @@ fc_bsg_job_timeout(struct request *req)
                                "abort failed with status %d\n", err);
        }
 
-       if (!done) {
-               spin_lock_irqsave(&job->job_lock, flags);
-               job->ref_cnt--;
-               spin_unlock_irqrestore(&job->job_lock, flags);
-               fc_destroy_bsgjob(job);
-       }
-
        /* the blk_end_sync_io() doesn't check the error */
-       return BLK_EH_HANDLED;
+       if (done)
+               return BLK_EH_NOT_HANDLED;
+       else
+               return BLK_EH_HANDLED;
 }
 
-
-
 static int
 fc_bsg_map_buffer(struct fc_bsg_buffer *buf, struct request *req)
 {
@@ -3859,7 +3861,7 @@ fc_bsg_hostadd(struct Scsi_Host *shost, struct fc_host_attrs *fc_host)
        struct fc_internal *i = to_fc_internal(shost->transportt);
        struct request_queue *q;
        int err;
-       char bsg_name[BUS_ID_SIZE]; /*20*/
+       char bsg_name[20];
 
        fc_host->rqst_q = NULL;
 
@@ -3879,6 +3881,7 @@ fc_bsg_hostadd(struct Scsi_Host *shost, struct fc_host_attrs *fc_host)
 
        q->queuedata = shost;
        queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q);
+       blk_queue_softirq_done(q, fc_bsg_softirq_done);
        blk_queue_rq_timed_out(q, fc_bsg_job_timeout);
        blk_queue_rq_timeout(q, FC_DEFAULT_BSG_TIMEOUT);
 
@@ -3924,6 +3927,7 @@ fc_bsg_rportadd(struct Scsi_Host *shost, struct fc_rport *rport)
 
        q->queuedata = rport;
        queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q);
+       blk_queue_softirq_done(q, fc_bsg_softirq_done);
        blk_queue_rq_timed_out(q, fc_bsg_job_timeout);
        blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT);
 
index f3e664628d7ae273d6e97c2f794d990b7ea9dcfd..783e33c65eb7c354a5e6613f2653c0b95517f51c 100644 (file)
@@ -692,6 +692,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
                                                 "Too many iscsi targets. Max "
                                                 "number of targets is %d.\n",
                                                 ISCSI_MAX_TARGET - 1);
+                       err = -EOVERFLOW;
                        goto release_host;
                }
        }
index d606452297cf3fdc82747b279067fb67613f8779..0895d3c71b03d62b62aee075be5662f7f8004c30 100644 (file)
@@ -173,9 +173,9 @@ static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost,
                ret = handler(shost, rphy, req);
                req->errors = ret;
 
-               spin_lock_irq(q->queue_lock);
+               blk_end_request_all(req, ret);
 
-               req->end_io(req, ret);
+               spin_lock_irq(q->queue_lock);
        }
 }
 
index 654a34fb04cba46792ec1b74e22476f7ba97f3cf..c25bd9a34e02f4fa2b106694d0e93a8fa28b1e3b 100644 (file)
 #define DV_RETRIES     3       /* should only need at most 
                                 * two cc/ua clears */
 
+/* Our blacklist flags */
+enum {
+       SPI_BLIST_NOIUS = 0x1,
+};
+
+/* blacklist table, modelled on scsi_devinfo.c */
+static struct {
+       char *vendor;
+       char *model;
+       unsigned flags;
+} spi_static_device_list[] __initdata = {
+       {"HP", "Ultrium 3-SCSI", SPI_BLIST_NOIUS },
+       {"IBM", "ULTRIUM-TD3", SPI_BLIST_NOIUS },
+       {NULL, NULL, 0}
+};
+
 /* Private data accessors (keep these out of the header file) */
 #define spi_dv_in_progress(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_in_progress)
 #define spi_dv_mutex(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_mutex)
@@ -207,6 +223,9 @@ static int spi_device_configure(struct transport_container *tc,
 {
        struct scsi_device *sdev = to_scsi_device(dev);
        struct scsi_target *starget = sdev->sdev_target;
+       unsigned bflags = scsi_get_device_flags_keyed(sdev, &sdev->inquiry[8],
+                                                     &sdev->inquiry[16],
+                                                     SCSI_DEVINFO_SPI);
 
        /* Populate the target capability fields with the values
         * gleaned from the device inquiry */
@@ -216,6 +235,10 @@ static int spi_device_configure(struct transport_container *tc,
        spi_support_dt(starget) = scsi_device_dt(sdev);
        spi_support_dt_only(starget) = scsi_device_dt_only(sdev);
        spi_support_ius(starget) = scsi_device_ius(sdev);
+       if (bflags & SPI_BLIST_NOIUS) {
+               dev_info(dev, "Information Units disabled by blacklist\n");
+               spi_support_ius(starget) = 0;
+       }
        spi_support_qas(starget) = scsi_device_qas(sdev);
 
        return 0;
@@ -833,7 +856,7 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
                return;
        }
 
-       if (!scsi_device_wide(sdev)) {
+       if (!spi_support_wide(starget)) {
                spi_max_width(starget) = 0;
                max_width = 0;
        }
@@ -860,7 +883,7 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
                return;
 
        /* device can't handle synchronous */
-       if (!scsi_device_sync(sdev) && !scsi_device_dt(sdev))
+       if (!spi_support_sync(starget) && !spi_support_dt(starget))
                return;
 
        /* len == -1 is the signal that we need to ascertain the
@@ -876,13 +899,14 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
 
        /* try QAS requests; this should be harmless to set if the
         * target supports it */
-       if (scsi_device_qas(sdev) && spi_max_qas(starget)) {
+       if (spi_support_qas(starget) && spi_max_qas(starget)) {
                DV_SET(qas, 1);
        } else {
                DV_SET(qas, 0);
        }
 
-       if (scsi_device_ius(sdev) && spi_max_iu(starget) && min_period < 9) {
+       if (spi_support_ius(starget) && spi_max_iu(starget) &&
+           min_period < 9) {
                /* This u320 (or u640). Set IU transfers */
                DV_SET(iu, 1);
                /* Then set the optional parameters */
@@ -902,7 +926,7 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
                i->f->get_signalling(shost);
        if (spi_signalling(shost) == SPI_SIGNAL_SE ||
            spi_signalling(shost) == SPI_SIGNAL_HVD ||
-           !scsi_device_dt(sdev)) {
+           !spi_support_dt(starget)) {
                DV_SET(dt, 0);
        } else {
                DV_SET(dt, 1);
@@ -1523,7 +1547,21 @@ EXPORT_SYMBOL(spi_release_transport);
 
 static __init int spi_transport_init(void)
 {
-       int error = transport_class_register(&spi_transport_class);
+       int error = scsi_dev_info_add_list(SCSI_DEVINFO_SPI,
+                                          "SCSI Parallel Transport Class");
+       if (!error) {
+               int i;
+
+               for (i = 0; spi_static_device_list[i].vendor; i++)
+                       scsi_dev_info_list_add_keyed(1, /* compatible */
+                                                    spi_static_device_list[i].vendor,
+                                                    spi_static_device_list[i].model,
+                                                    NULL,
+                                                    spi_static_device_list[i].flags,
+                                                    SCSI_DEVINFO_SPI);
+       }
+
+       error = transport_class_register(&spi_transport_class);
        if (error)
                return error;
        error = anon_transport_class_register(&spi_device_class);
@@ -1535,6 +1573,7 @@ static void __exit spi_transport_exit(void)
        transport_class_unregister(&spi_transport_class);
        anon_transport_class_unregister(&spi_device_class);
        transport_class_unregister(&spi_host_class);
+       scsi_dev_info_remove_list(SCSI_DEVINFO_SPI);
 }
 
 MODULE_AUTHOR("Martin Hicks");
index 878b17a9af3008ab5fe29afc7a8faa4a9c99d58d..5616cd780ff3504420363d0c42b24af0274218c6 100644 (file)
@@ -1307,6 +1307,7 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
        int sense_valid = 0;
        int the_result;
        int retries = 3;
+       unsigned int alignment;
        unsigned long long lba;
        unsigned sector_size;
 
@@ -1358,6 +1359,16 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
                return -EOVERFLOW;
        }
 
+       /* Logical blocks per physical block exponent */
+       sdkp->hw_sector_size = (1 << (buffer[13] & 0xf)) * sector_size;
+
+       /* Lowest aligned logical block */
+       alignment = ((buffer[14] & 0x3f) << 8 | buffer[15]) * sector_size;
+       blk_queue_alignment_offset(sdp->request_queue, alignment);
+       if (alignment && sdkp->first_scan)
+               sd_printk(KERN_NOTICE, sdkp,
+                         "physical block alignment offset: %u\n", alignment);
+
        sdkp->capacity = lba + 1;
        return sector_size;
 }
@@ -1409,6 +1420,7 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
        }
 
        sdkp->capacity = lba + 1;
+       sdkp->hw_sector_size = sector_size;
        return sector_size;
 }
 
@@ -1521,11 +1533,17 @@ got_data:
                string_get_size(sz, STRING_UNITS_10, cap_str_10,
                                sizeof(cap_str_10));
 
-               if (sdkp->first_scan || old_capacity != sdkp->capacity)
+               if (sdkp->first_scan || old_capacity != sdkp->capacity) {
                        sd_printk(KERN_NOTICE, sdkp,
-                                 "%llu %d-byte hardware sectors: (%s/%s)\n",
+                                 "%llu %d-byte logical blocks: (%s/%s)\n",
                                  (unsigned long long)sdkp->capacity,
                                  sector_size, cap_str_10, cap_str_2);
+
+                       if (sdkp->hw_sector_size != sector_size)
+                               sd_printk(KERN_NOTICE, sdkp,
+                                         "%u-byte physical blocks\n",
+                                         sdkp->hw_sector_size);
+               }
        }
 
        /* Rescale capacity to 512-byte units */
@@ -1538,6 +1556,7 @@ got_data:
        else if (sector_size == 256)
                sdkp->capacity >>= 1;
 
+       blk_queue_physical_block_size(sdp->request_queue, sdkp->hw_sector_size);
        sdkp->device->sector_size = sector_size;
 }
 
@@ -1775,6 +1794,52 @@ void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer)
        return;
 }
 
+/**
+ * sd_read_block_limits - Query disk device for preferred I/O sizes.
+ * @disk: disk to query
+ */
+static void sd_read_block_limits(struct scsi_disk *sdkp)
+{
+       unsigned int sector_sz = sdkp->device->sector_size;
+       char *buffer;
+
+       /* Block Limits VPD */
+       buffer = scsi_get_vpd_page(sdkp->device, 0xb0);
+
+       if (buffer == NULL)
+               return;
+
+       blk_queue_io_min(sdkp->disk->queue,
+                        get_unaligned_be16(&buffer[6]) * sector_sz);
+       blk_queue_io_opt(sdkp->disk->queue,
+                        get_unaligned_be32(&buffer[12]) * sector_sz);
+
+       kfree(buffer);
+}
+
+/**
+ * sd_read_block_characteristics - Query block dev. characteristics
+ * @disk: disk to query
+ */
+static void sd_read_block_characteristics(struct scsi_disk *sdkp)
+{
+       char *buffer;
+       u16 rot;
+
+       /* Block Device Characteristics VPD */
+       buffer = scsi_get_vpd_page(sdkp->device, 0xb1);
+
+       if (buffer == NULL)
+               return;
+
+       rot = get_unaligned_be16(&buffer[4]);
+
+       if (rot == 1)
+               queue_flag_set_unlocked(QUEUE_FLAG_NONROT, sdkp->disk->queue);
+
+       kfree(buffer);
+}
+
 /**
  *     sd_revalidate_disk - called the first time a new disk is seen,
  *     performs disk spin up, read_capacity, etc.
@@ -1812,6 +1877,8 @@ static int sd_revalidate_disk(struct gendisk *disk)
         */
        if (sdkp->media_present) {
                sd_read_capacity(sdkp, buffer);
+               sd_read_block_limits(sdkp);
+               sd_read_block_characteristics(sdkp);
                sd_read_write_protect_flag(sdkp, buffer);
                sd_read_cache_type(sdkp, buffer);
                sd_read_app_tag_own(sdkp, buffer);
@@ -1934,6 +2001,8 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
        add_disk(gd);
        sd_dif_config_host(sdkp);
 
+       sd_revalidate_disk(gd);
+
        sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
                  sdp->removable ? "removable " : "");
 }
@@ -2054,6 +2123,7 @@ static int sd_remove(struct device *dev)
 
        async_synchronize_full();
        sdkp = dev_get_drvdata(dev);
+       blk_queue_prep_rq(sdkp->device->request_queue, scsi_prep_fn);
        device_del(&sdkp->dev);
        del_gendisk(sdkp->disk);
        sd_shutdown(dev);
index 708778cf5f0683d9cdd181d483241e80b96b2107..8474b5bad3fe0076b8042818eb3020a0ea409023 100644 (file)
@@ -45,6 +45,7 @@ struct scsi_disk {
        unsigned int    openers;        /* protected by BKL for now, yuck */
        sector_t        capacity;       /* size in 512-byte sectors */
        u32             index;
+       unsigned short  hw_sector_size;
        u8              media_present;
        u8              write_prot;
        u8              protection_type;/* Data Integrity Field */
index cd350dfc1216f290554ec0cd5c732e866492644b..cce0fe4c8a3b91fb86f535fa2ae6d6bf2f79f226 100644 (file)
@@ -881,6 +881,7 @@ static int sr_remove(struct device *dev)
 {
        struct scsi_cd *cd = dev_get_drvdata(dev);
 
+       blk_queue_prep_rq(cd->device->request_queue, scsi_prep_fn);
        del_gendisk(cd->disk);
 
        mutex_lock(&sr_ref_mutex);
index 69ad4945c9369467f0d2fa5095741845d8156ac8..297deb817a5d2f7076706032f7286398f5edfecc 100644 (file)
@@ -2321,8 +2321,9 @@ static void sym_int_par (struct sym_hcb *np, u_short sist)
        int phase       = cmd & 7;
        struct sym_ccb *cp      = sym_ccb_from_dsa(np, dsa);
 
-       printf("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n",
-               sym_name(np), hsts, dbc, sbcl);
+       if (printk_ratelimit())
+               printf("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n",
+                       sym_name(np), hsts, dbc, sbcl);
 
        /*
         *  Check that the chip is connected to the SCSI BUS.
index b166f2852a64bb50b70252a0c1498322bdd456b7..b1ccc04f3c9ab793705e9df16738578febe8d518 100644 (file)
@@ -240,6 +240,32 @@ config ORION_WATCHDOG
          To compile this driver as a module, choose M here: the
          module will be called orion_wdt.
 
+config COH901327_WATCHDOG
+       bool "ST-Ericsson COH 901 327 watchdog"
+       depends on ARCH_U300
+       default y if MACH_U300
+       help
+         Say Y here to include Watchdog timer support for the
+         watchdog embedded into the ST-Ericsson U300 series platforms.
+         This watchdog is used to reset the system and thus cannot be
+         compiled as a module.
+
+config TWL4030_WATCHDOG
+       tristate "TWL4030 Watchdog"
+       depends on TWL4030_CORE
+       help
+         Support for TI TWL4030 watchdog.  Say 'Y' here to enable the
+         watchdog timer support for TWL4030 chips.
+
+config STMP3XXX_WATCHDOG
+       tristate "Freescale STMP3XXX watchdog"
+       depends on ARCH_STMP3XXX
+       help
+         Say Y here if to include support for the watchdog timer
+         for the Sigmatel STMP37XX/378X SoC.
+         To compile this driver as a module, choose M here: the
+         module will be called stmp3xxx_wdt.
+
 # AVR32 Architecture
 
 config AT32AP700X_WDT
@@ -703,6 +729,12 @@ config SBC_EPX_C3_WATCHDOG
 
 # MIPS Architecture
 
+config BCM47XX_WDT
+       tristate "Broadcom BCM47xx Watchdog Timer"
+       depends on BCM47XX
+       help
+         Hardware driver for the Broadcom BCM47xx Watchog Timer.
+
 config RC32434_WDT
        tristate "IDT RC32434 SoC Watchdog Timer"
        depends on MIKROTIK_RB532
@@ -729,6 +761,15 @@ config WDT_MTX1
          Hardware driver for the MTX-1 boards. This is a watchdog timer that
          will reboot the machine after a 100 seconds timer expired.
 
+config PNX833X_WDT
+       tristate "PNX833x Hardware Watchdog"
+       depends on SOC_PNX8335
+       help
+         Hardware driver for the PNX833x's watchdog. This is a
+         watchdog timer that will reboot the machine after a programable
+         timer has expired and no process has written to /dev/watchdog during
+         that time.
+
 config WDT_RM9K_GPI
        tristate "RM9000/GPI hardware watchdog"
        depends on CPU_RM9000
@@ -966,24 +1007,16 @@ config WDTPCI
        ---help---
          If you have a PCI-WDT500/501 watchdog board, say Y here, otherwise N.
 
-         To compile this driver as a module, choose M here: the
-         module will be called wdt_pci.
-
-config WDT_501_PCI
-       bool "PCI-WDT501 features"
-       depends on WDTPCI
-       help
-         Saying Y here and creating a character special file /dev/temperature
-         with major number 10 and minor number 131 ("man mknod") will give
-         you a thermometer inside your computer: reading from
-         /dev/temperature yields one byte, the temperature in degrees
-         Fahrenheit. This works only if you have a PCI-WDT501 watchdog board
-         installed.
+         If you have a PCI-WDT501 watchdog board then you can enable the
+         temperature sensor by setting the type parameter to 501.
 
          If you want to enable the Fan Tachometer on the PCI-WDT501, then you
          can do this via the tachometer parameter. Only do this if you have a
          fan tachometer actually set up.
 
+         To compile this driver as a module, choose M here: the
+         module will be called wdt_pci.
+
 #
 # USB-based Watchdog Cards
 #
index c3afa14d5be151256bf4e2b555332aef2e0f9c13..3d774294a2b7769af96c232c6fff380a1a48e265 100644 (file)
@@ -28,6 +28,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
 obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
 obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o
 obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
+obj-$(CONFIG_TWL4030_WATCHDOG) += twl4030_wdt.o
 obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
 obj-$(CONFIG_977_WATCHDOG) += wdt977.o
 obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
@@ -41,6 +42,8 @@ obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
 obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
 obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
 obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o
+obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o
+obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3xxx_wdt.o
 
 # AVR32 Architecture
 obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
@@ -98,9 +101,11 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
 # M68KNOMMU Architecture
 
 # MIPS Architecture
+obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o
 obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o
 obj-$(CONFIG_INDYDOG) += indydog.o
 obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
+obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
 obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
 obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
 obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
new file mode 100644 (file)
index 0000000..5c7011c
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ *  Watchdog driver for Broadcom BCM47XX
+ *
+ *  Copyright (C) 2008 Aleksandar Radovanovic <biblbroks@sezampro.rs>
+ *  Copyright (C) 2009 Matthieu CASTET <castet.matthieu@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.
+ */
+
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/reboot.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/watchdog.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/ssb/ssb_embedded.h>
+#include <asm/mach-bcm47xx/bcm47xx.h>
+
+#define DRV_NAME               "bcm47xx_wdt"
+
+#define WDT_DEFAULT_TIME       30      /* seconds */
+#define WDT_MAX_TIME           255     /* seconds */
+
+static int wdt_time = WDT_DEFAULT_TIME;
+static int nowayout = WATCHDOG_NOWAYOUT;
+
+module_param(wdt_time, int, 0);
+MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
+                               __MODULE_STRING(WDT_DEFAULT_TIME) ")");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout,
+               "Watchdog cannot be stopped once started (default="
+                               __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+#endif
+
+static unsigned long bcm47xx_wdt_busy;
+static char expect_release;
+static struct timer_list wdt_timer;
+static atomic_t ticks;
+
+static inline void bcm47xx_wdt_hw_start(void)
+{
+       /* this is 2,5s on 100Mhz clock  and 2s on 133 Mhz */
+       ssb_watchdog_timer_set(&ssb_bcm47xx, 0xfffffff);
+}
+
+static inline int bcm47xx_wdt_hw_stop(void)
+{
+       return ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
+}
+
+static void bcm47xx_timer_tick(unsigned long unused)
+{
+       if (!atomic_dec_and_test(&ticks)) {
+               bcm47xx_wdt_hw_start();
+               mod_timer(&wdt_timer, jiffies + HZ);
+       } else {
+               printk(KERN_CRIT DRV_NAME "Watchdog will fire soon!!!\n");
+       }
+}
+
+static inline void bcm47xx_wdt_pet(void)
+{
+       atomic_set(&ticks, wdt_time);
+}
+
+static void bcm47xx_wdt_start(void)
+{
+       bcm47xx_wdt_pet();
+       bcm47xx_timer_tick(0);
+}
+
+static void bcm47xx_wdt_pause(void)
+{
+       del_timer_sync(&wdt_timer);
+       bcm47xx_wdt_hw_stop();
+}
+
+static void bcm47xx_wdt_stop(void)
+{
+       bcm47xx_wdt_pause();
+}
+
+static int bcm47xx_wdt_settimeout(int new_time)
+{
+       if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
+               return -EINVAL;
+
+       wdt_time = new_time;
+       return 0;
+}
+
+static int bcm47xx_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(0, &bcm47xx_wdt_busy))
+               return -EBUSY;
+
+       bcm47xx_wdt_start();
+       return nonseekable_open(inode, file);
+}
+
+static int bcm47xx_wdt_release(struct inode *inode, struct file *file)
+{
+       if (expect_release == 42) {
+               bcm47xx_wdt_stop();
+       } else {
+               printk(KERN_CRIT DRV_NAME
+                       ": Unexpected close, not stopping watchdog!\n");
+               bcm47xx_wdt_start();
+       }
+
+       clear_bit(0, &bcm47xx_wdt_busy);
+       expect_release = 0;
+       return 0;
+}
+
+static ssize_t bcm47xx_wdt_write(struct file *file, const char __user *data,
+                               size_t len, loff_t *ppos)
+{
+       if (len) {
+               if (!nowayout) {
+                       size_t i;
+
+                       expect_release = 0;
+
+                       for (i = 0; i != len; i++) {
+                               char c;
+                               if (get_user(c, data + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       expect_release = 42;
+                       }
+               }
+               bcm47xx_wdt_pet();
+       }
+       return len;
+}
+
+static struct watchdog_info bcm47xx_wdt_info = {
+       .identity       = DRV_NAME,
+       .options        = WDIOF_SETTIMEOUT |
+                               WDIOF_KEEPALIVEPING |
+                               WDIOF_MAGICCLOSE,
+};
+
+static long bcm47xx_wdt_ioctl(struct file *file,
+                                       unsigned int cmd, unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+       int new_value, retval = -EINVAL;;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               return copy_to_user(argp, &bcm47xx_wdt_info,
+                               sizeof(bcm47xx_wdt_info)) ? -EFAULT : 0;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(0, p);
+
+       case WDIOC_SETOPTIONS:
+               if (get_user(new_value, p))
+                       return -EFAULT;
+
+               if (new_value & WDIOS_DISABLECARD) {
+                       bcm47xx_wdt_stop();
+                       retval = 0;
+               }
+
+               if (new_value & WDIOS_ENABLECARD) {
+                       bcm47xx_wdt_start();
+                       retval = 0;
+               }
+
+               return retval;
+
+       case WDIOC_KEEPALIVE:
+               bcm47xx_wdt_pet();
+               return 0;
+
+       case WDIOC_SETTIMEOUT:
+               if (get_user(new_value, p))
+                       return -EFAULT;
+
+               if (bcm47xx_wdt_settimeout(new_value))
+                       return -EINVAL;
+
+               bcm47xx_wdt_pet();
+
+       case WDIOC_GETTIMEOUT:
+               return put_user(wdt_time, p);
+
+       default:
+               return -ENOTTY;
+       }
+}
+
+static int bcm47xx_wdt_notify_sys(struct notifier_block *this,
+       unsigned long code, void *unused)
+{
+       if (code == SYS_DOWN || code == SYS_HALT)
+               bcm47xx_wdt_stop();
+       return NOTIFY_DONE;
+}
+
+static const struct file_operations bcm47xx_wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .unlocked_ioctl = bcm47xx_wdt_ioctl,
+       .open           = bcm47xx_wdt_open,
+       .release        = bcm47xx_wdt_release,
+       .write          = bcm47xx_wdt_write,
+};
+
+static struct miscdevice bcm47xx_wdt_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &bcm47xx_wdt_fops,
+};
+
+static struct notifier_block bcm47xx_wdt_notifier = {
+       .notifier_call = bcm47xx_wdt_notify_sys,
+};
+
+static int __init bcm47xx_wdt_init(void)
+{
+       int ret;
+
+       if (bcm47xx_wdt_hw_stop() < 0)
+               return -ENODEV;
+
+       setup_timer(&wdt_timer, bcm47xx_timer_tick, 0L);
+
+       if (bcm47xx_wdt_settimeout(wdt_time)) {
+               bcm47xx_wdt_settimeout(WDT_DEFAULT_TIME);
+               printk(KERN_INFO DRV_NAME ": "
+                       "wdt_time value must be 0 < wdt_time < %d, using %d\n",
+                       (WDT_MAX_TIME + 1), wdt_time);
+       }
+
+       ret = register_reboot_notifier(&bcm47xx_wdt_notifier);
+       if (ret)
+               return ret;
+
+       ret = misc_register(&bcm47xx_wdt_miscdev);
+       if (ret) {
+               unregister_reboot_notifier(&bcm47xx_wdt_notifier);
+               return ret;
+       }
+
+       printk(KERN_INFO "BCM47xx Watchdog Timer enabled (%d seconds%s)\n",
+                               wdt_time, nowayout ? ", nowayout" : "");
+       return 0;
+}
+
+static void __exit bcm47xx_wdt_exit(void)
+{
+       if (!nowayout)
+               bcm47xx_wdt_stop();
+
+       misc_deregister(&bcm47xx_wdt_miscdev);
+
+       unregister_reboot_notifier(&bcm47xx_wdt_notifier);
+}
+
+module_init(bcm47xx_wdt_init);
+module_exit(bcm47xx_wdt_exit);
+
+MODULE_AUTHOR("Aleksandar Radovanovic");
+MODULE_DESCRIPTION("Watchdog driver for Broadcom BCM47xx");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c
new file mode 100644 (file)
index 0000000..fecb307
--- /dev/null
@@ -0,0 +1,537 @@
+/*
+ * coh901327_wdt.c
+ *
+ * Copyright (C) 2008-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Watchdog driver for the ST-Ericsson AB COH 901 327 IP core
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+
+#define DRV_NAME "WDOG COH 901 327"
+
+/*
+ * COH 901 327 register definitions
+ */
+
+/* WDOG_FEED Register 32bit (-/W) */
+#define U300_WDOG_FR                                                   0x00
+#define U300_WDOG_FR_FEED_RESTART_TIMER                                        0xFEEDU
+/* WDOG_TIMEOUT Register 32bit (R/W) */
+#define U300_WDOG_TR                                                   0x04
+#define U300_WDOG_TR_TIMEOUT_MASK                                      0x7FFFU
+/* WDOG_DISABLE1 Register 32bit (-/W) */
+#define U300_WDOG_D1R                                                  0x08
+#define U300_WDOG_D1R_DISABLE1_DISABLE_TIMER                           0x2BADU
+/* WDOG_DISABLE2 Register 32bit (R/W) */
+#define U300_WDOG_D2R                                                  0x0C
+#define U300_WDOG_D2R_DISABLE2_DISABLE_TIMER                           0xCAFEU
+#define U300_WDOG_D2R_DISABLE_STATUS_DISABLED                          0xDABEU
+#define U300_WDOG_D2R_DISABLE_STATUS_ENABLED                           0x0000U
+/* WDOG_STATUS Register 32bit (R/W) */
+#define U300_WDOG_SR                                                   0x10
+#define U300_WDOG_SR_STATUS_TIMED_OUT                                  0xCFE8U
+#define U300_WDOG_SR_STATUS_NORMAL                                     0x0000U
+#define U300_WDOG_SR_RESET_STATUS_RESET                                        0xE8B4U
+/* WDOG_COUNT Register 32bit (R/-) */
+#define U300_WDOG_CR                                                   0x14
+#define U300_WDOG_CR_VALID_IND                                         0x8000U
+#define U300_WDOG_CR_VALID_STABLE                                      0x0000U
+#define U300_WDOG_CR_COUNT_VALUE_MASK                                  0x7FFFU
+/* WDOG_JTAGOVR Register 32bit (R/W) */
+#define U300_WDOG_JOR                                                  0x18
+#define U300_WDOG_JOR_JTAG_MODE_IND                                    0x0002U
+#define U300_WDOG_JOR_JTAG_WATCHDOG_ENABLE                             0x0001U
+/* WDOG_RESTART Register 32bit (-/W) */
+#define U300_WDOG_RR                                                   0x1C
+#define U300_WDOG_RR_RESTART_VALUE_RESUME                              0xACEDU
+/* WDOG_IRQ_EVENT Register 32bit (R/W) */
+#define U300_WDOG_IER                                                  0x20
+#define U300_WDOG_IER_WILL_BARK_IRQ_EVENT_IND                          0x0001U
+#define U300_WDOG_IER_WILL_BARK_IRQ_ACK_ENABLE                         0x0001U
+/* WDOG_IRQ_MASK Register 32bit (R/W) */
+#define U300_WDOG_IMR                                                  0x24
+#define U300_WDOG_IMR_WILL_BARK_IRQ_ENABLE                             0x0001U
+/* WDOG_IRQ_FORCE Register 32bit (R/W) */
+#define U300_WDOG_IFR                                                  0x28
+#define U300_WDOG_IFR_WILL_BARK_IRQ_FORCE_ENABLE                       0x0001U
+
+/* Default timeout in seconds = 1 minute */
+static int margin = 60;
+static resource_size_t phybase;
+static resource_size_t physize;
+static int irq;
+static void __iomem *virtbase;
+static unsigned long coh901327_users;
+static unsigned long boot_status;
+static u16 wdogenablestore;
+static u16 irqmaskstore;
+static struct device *parent;
+
+/*
+ * The watchdog block is of course always clocked, the
+ * clk_enable()/clk_disable() calls are mainly for performing reference
+ * counting higher up in the clock hierarchy.
+ */
+static struct clk *clk;
+
+/*
+ * Enabling and disabling functions.
+ */
+static void coh901327_enable(u16 timeout)
+{
+       u16 val;
+
+       clk_enable(clk);
+       /* Restart timer if it is disabled */
+       val = readw(virtbase + U300_WDOG_D2R);
+       if (val == U300_WDOG_D2R_DISABLE_STATUS_DISABLED)
+               writew(U300_WDOG_RR_RESTART_VALUE_RESUME,
+                      virtbase + U300_WDOG_RR);
+       /* Acknowledge any pending interrupt so it doesn't just fire off */
+       writew(U300_WDOG_IER_WILL_BARK_IRQ_ACK_ENABLE,
+              virtbase + U300_WDOG_IER);
+       /* Enable the watchdog interrupt */
+       writew(U300_WDOG_IMR_WILL_BARK_IRQ_ENABLE, virtbase + U300_WDOG_IMR);
+       /* Activate the watchdog timer */
+       writew(timeout, virtbase + U300_WDOG_TR);
+       /* Start the watchdog timer */
+       writew(U300_WDOG_FR_FEED_RESTART_TIMER, virtbase + U300_WDOG_FR);
+       /*
+        * Extra read so that this change propagate in the watchdog.
+        */
+       (void) readw(virtbase + U300_WDOG_CR);
+       val = readw(virtbase + U300_WDOG_D2R);
+       clk_disable(clk);
+       if (val != U300_WDOG_D2R_DISABLE_STATUS_ENABLED)
+               dev_err(parent,
+                       "%s(): watchdog not enabled! D2R value %04x\n",
+                       __func__, val);
+}
+
+static void coh901327_disable(void)
+{
+       u16 val;
+
+       clk_enable(clk);
+       /* Disable the watchdog interrupt if it is active */
+       writew(0x0000U, virtbase + U300_WDOG_IMR);
+       /* If the watchdog is currently enabled, attempt to disable it */
+       val = readw(virtbase + U300_WDOG_D2R);
+       if (val != U300_WDOG_D2R_DISABLE_STATUS_DISABLED) {
+               writew(U300_WDOG_D1R_DISABLE1_DISABLE_TIMER,
+                      virtbase + U300_WDOG_D1R);
+               writew(U300_WDOG_D2R_DISABLE2_DISABLE_TIMER,
+                      virtbase + U300_WDOG_D2R);
+               /* Write this twice (else problems occur) */
+               writew(U300_WDOG_D2R_DISABLE2_DISABLE_TIMER,
+                      virtbase + U300_WDOG_D2R);
+       }
+       val = readw(virtbase + U300_WDOG_D2R);
+       clk_disable(clk);
+       if (val != U300_WDOG_D2R_DISABLE_STATUS_DISABLED)
+               dev_err(parent,
+                       "%s(): watchdog not disabled! D2R value %04x\n",
+                       __func__, val);
+}
+
+static void coh901327_start(void)
+{
+       coh901327_enable(margin * 100);
+}
+
+static void coh901327_keepalive(void)
+{
+       clk_enable(clk);
+       /* Feed the watchdog */
+       writew(U300_WDOG_FR_FEED_RESTART_TIMER,
+              virtbase + U300_WDOG_FR);
+       clk_disable(clk);
+}
+
+static int coh901327_settimeout(int time)
+{
+       /*
+        * Max margin is 327 since the 10ms
+        * timeout register is max
+        * 0x7FFF = 327670ms ~= 327s.
+        */
+       if (time <= 0 || time > 327)
+               return -EINVAL;
+
+       margin = time;
+       clk_enable(clk);
+       /* Set new timeout value */
+       writew(margin * 100, virtbase + U300_WDOG_TR);
+       /* Feed the dog */
+       writew(U300_WDOG_FR_FEED_RESTART_TIMER,
+              virtbase + U300_WDOG_FR);
+       clk_disable(clk);
+       return 0;
+}
+
+/*
+ * This interrupt occurs 10 ms before the watchdog WILL bark.
+ */
+static irqreturn_t coh901327_interrupt(int irq, void *data)
+{
+       u16 val;
+
+       /*
+        * Ack IRQ? If this occurs we're FUBAR anyway, so
+        * just acknowledge, disable the interrupt and await the imminent end.
+        * If you at some point need a host of callbacks to be called
+        * when the system is about to watchdog-reset, add them here!
+        *
+        * NOTE: on future versions of this IP-block, it will be possible
+        * to prevent a watchdog reset by feeding the watchdog at this
+        * point.
+        */
+       clk_enable(clk);
+       val = readw(virtbase + U300_WDOG_IER);
+       if (val == U300_WDOG_IER_WILL_BARK_IRQ_EVENT_IND)
+               writew(U300_WDOG_IER_WILL_BARK_IRQ_ACK_ENABLE,
+                      virtbase + U300_WDOG_IER);
+       writew(0x0000U, virtbase + U300_WDOG_IMR);
+       clk_disable(clk);
+       dev_crit(parent, "watchdog is barking!\n");
+       return IRQ_HANDLED;
+}
+
+/*
+ * Allow only one user (daemon) to open the watchdog
+ */
+static int coh901327_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(1, &coh901327_users))
+               return -EBUSY;
+       coh901327_start();
+       return nonseekable_open(inode, file);
+}
+
+static int coh901327_release(struct inode *inode, struct file *file)
+{
+       clear_bit(1, &coh901327_users);
+       coh901327_disable();
+       return 0;
+}
+
+static ssize_t coh901327_write(struct file *file, const char __user *data,
+                              size_t len, loff_t *ppos)
+{
+       if (len)
+               coh901327_keepalive();
+       return len;
+}
+
+static long coh901327_ioctl(struct file *file, unsigned int cmd,
+                           unsigned long arg)
+{
+       int ret = -ENOTTY;
+       u16 val;
+       int time;
+       int new_options;
+       union {
+               struct watchdog_info __user *ident;
+               int __user *i;
+       } uarg;
+       static struct watchdog_info ident = {
+               .options                = WDIOF_CARDRESET |
+                                         WDIOF_SETTIMEOUT |
+                                         WDIOF_KEEPALIVEPING,
+               .identity               = "COH 901 327 Watchdog",
+               .firmware_version       = 1,
+       };
+       uarg.i = (int __user *)arg;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               ret = copy_to_user(uarg.ident, &ident,
+                                  sizeof(ident)) ? -EFAULT : 0;
+               break;
+
+       case WDIOC_GETSTATUS:
+               ret = put_user(0, uarg.i);
+               break;
+
+       case WDIOC_GETBOOTSTATUS:
+               ret = put_user(boot_status, uarg.i);
+               break;
+
+       case WDIOC_SETOPTIONS:
+               ret = get_user(new_options, uarg.i);
+               if (ret)
+                       break;
+               if (new_options & WDIOS_DISABLECARD)
+                       coh901327_disable();
+               if (new_options & WDIOS_ENABLECARD)
+                       coh901327_start();
+               ret = 0;
+               break;
+
+       case WDIOC_KEEPALIVE:
+               coh901327_keepalive();
+               ret = 0;
+               break;
+
+       case WDIOC_SETTIMEOUT:
+               ret = get_user(time, uarg.i);
+               if (ret)
+                       break;
+
+               ret = coh901327_settimeout(time);
+               if (ret)
+                       break;
+               /* Then fall through to return set value */
+
+       case WDIOC_GETTIMEOUT:
+               ret = put_user(margin, uarg.i);
+               break;
+
+       case WDIOC_GETTIMELEFT:
+               clk_enable(clk);
+               /* Read repeatedly until the value is stable! */
+               val = readw(virtbase + U300_WDOG_CR);
+               while (val & U300_WDOG_CR_VALID_IND)
+                       val = readw(virtbase + U300_WDOG_CR);
+               val &= U300_WDOG_CR_COUNT_VALUE_MASK;
+               clk_disable(clk);
+               if (val != 0)
+                       val /= 100;
+               ret = put_user(val, uarg.i);
+               break;
+       }
+       return ret;
+}
+
+static const struct file_operations coh901327_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = coh901327_write,
+       .unlocked_ioctl = coh901327_ioctl,
+       .open           = coh901327_open,
+       .release        = coh901327_release,
+};
+
+static struct miscdevice coh901327_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &coh901327_fops,
+};
+
+static int __exit coh901327_remove(struct platform_device *pdev)
+{
+       misc_deregister(&coh901327_miscdev);
+       coh901327_disable();
+       free_irq(irq, pdev);
+       clk_put(clk);
+       iounmap(virtbase);
+       release_mem_region(phybase, physize);
+       return 0;
+}
+
+
+static int __init coh901327_probe(struct platform_device *pdev)
+{
+       int ret;
+       u16 val;
+       struct resource *res;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENOENT;
+
+       parent = &pdev->dev;
+       physize = resource_size(res);
+       phybase = res->start;
+
+       if (request_mem_region(phybase, physize, DRV_NAME) == NULL) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       virtbase = ioremap(phybase, physize);
+       if (!virtbase) {
+               ret = -ENOMEM;
+               goto out_no_remap;
+       }
+
+       clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(clk)) {
+               ret = PTR_ERR(clk);
+               dev_err(&pdev->dev, "could not get clock\n");
+               goto out_no_clk;
+       }
+       ret = clk_enable(clk);
+       if (ret) {
+               dev_err(&pdev->dev, "could not enable clock\n");
+               goto out_no_clk_enable;
+       }
+
+       val = readw(virtbase + U300_WDOG_SR);
+       switch (val) {
+       case U300_WDOG_SR_STATUS_TIMED_OUT:
+               dev_info(&pdev->dev,
+                       "watchdog timed out since last chip reset!\n");
+               boot_status = WDIOF_CARDRESET;
+               /* Status will be cleared below */
+               break;
+       case U300_WDOG_SR_STATUS_NORMAL:
+               dev_info(&pdev->dev,
+                       "in normal status, no timeouts have occurred.\n");
+               break;
+       default:
+               dev_info(&pdev->dev,
+                       "contains an illegal status code (%08x)\n", val);
+               break;
+       }
+
+       val = readw(virtbase + U300_WDOG_D2R);
+       switch (val) {
+       case U300_WDOG_D2R_DISABLE_STATUS_DISABLED:
+               dev_info(&pdev->dev, "currently disabled.\n");
+               break;
+       case U300_WDOG_D2R_DISABLE_STATUS_ENABLED:
+               dev_info(&pdev->dev,
+                        "currently enabled! (disabling it now)\n");
+               coh901327_disable();
+               break;
+       default:
+               dev_err(&pdev->dev,
+                       "contains an illegal enable/disable code (%08x)\n",
+                       val);
+               break;
+       }
+
+       /* Reset the watchdog */
+       writew(U300_WDOG_SR_RESET_STATUS_RESET, virtbase + U300_WDOG_SR);
+
+       irq = platform_get_irq(pdev, 0);
+       if (request_irq(irq, coh901327_interrupt, IRQF_DISABLED,
+                       DRV_NAME " Bark", pdev)) {
+               ret = -EIO;
+               goto out_no_irq;
+       }
+
+       clk_disable(clk);
+
+       ret = misc_register(&coh901327_miscdev);
+       if (ret == 0)
+               dev_info(&pdev->dev,
+                        "initialized. timer margin=%d sec\n", margin);
+       else
+               goto out_no_wdog;
+
+       return 0;
+
+out_no_wdog:
+       free_irq(irq, pdev);
+out_no_irq:
+       clk_disable(clk);
+out_no_clk_enable:
+       clk_put(clk);
+out_no_clk:
+       iounmap(virtbase);
+out_no_remap:
+       release_mem_region(phybase, SZ_4K);
+out:
+       return ret;
+}
+
+#ifdef CONFIG_PM
+static int coh901327_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       irqmaskstore = readw(virtbase + U300_WDOG_IMR) & 0x0001U;
+       wdogenablestore = readw(virtbase + U300_WDOG_D2R);
+       /* If watchdog is on, disable it here and now */
+       if (wdogenablestore == U300_WDOG_D2R_DISABLE_STATUS_ENABLED)
+               coh901327_disable();
+       return 0;
+}
+
+static int coh901327_resume(struct platform_device *pdev)
+{
+       /* Restore the watchdog interrupt */
+       writew(irqmaskstore, virtbase + U300_WDOG_IMR);
+       if (wdogenablestore == U300_WDOG_D2R_DISABLE_STATUS_ENABLED) {
+               /* Restart the watchdog timer */
+               writew(U300_WDOG_RR_RESTART_VALUE_RESUME,
+                      virtbase + U300_WDOG_RR);
+               writew(U300_WDOG_FR_FEED_RESTART_TIMER,
+                      virtbase + U300_WDOG_FR);
+       }
+       return 0;
+}
+#else
+#define coh901327_suspend NULL
+#define coh901327_resume  NULL
+#endif
+
+/*
+ * Mistreating the watchdog is the only way to perform a software reset of the
+ * system on EMP platforms. So we implement this and export a symbol for it.
+ */
+void coh901327_watchdog_reset(void)
+{
+       /* Enable even if on JTAG too */
+       writew(U300_WDOG_JOR_JTAG_WATCHDOG_ENABLE,
+              virtbase + U300_WDOG_JOR);
+       /*
+        * Timeout = 5s, we have to wait for the watchdog reset to
+        * actually take place: the watchdog will be reloaded with the
+        * default value immediately, so we HAVE to reboot and get back
+        * into the kernel in 30s, or the device will reboot again!
+        * The boot loader will typically deactivate the watchdog, so we
+        * need time enough for the boot loader to get to the point of
+        * deactivating the watchdog before it is shut down by it.
+        *
+        * NOTE: on future versions of the watchdog, this restriction is
+        * gone: the watchdog will be reloaded with a defaul value (1 min)
+        * instead of last value, and you can conveniently set the watchdog
+        * timeout to 10ms (value = 1) without any problems.
+        */
+       coh901327_enable(500);
+       /* Return and await doom */
+}
+
+static struct platform_driver coh901327_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "coh901327_wdog",
+       },
+       .remove         = __exit_p(coh901327_remove),
+       .suspend        = coh901327_suspend,
+       .resume         = coh901327_resume,
+};
+
+static int __init coh901327_init(void)
+{
+       return platform_driver_probe(&coh901327_driver, coh901327_probe);
+}
+module_init(coh901327_init);
+
+static void __exit coh901327_exit(void)
+{
+       platform_driver_unregister(&coh901327_driver);
+}
+module_exit(coh901327_exit);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
+MODULE_DESCRIPTION("COH 901 327 Watchdog");
+
+module_param(margin, int, 0);
+MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index c0b9169ba5d5f3d24db399b9683708cf16de988f..a6c5674c78e689414d1967d8b07fb90a28e12d3f 100644 (file)
@@ -120,7 +120,8 @@ static int nowayout = WATCHDOG_NOWAYOUT;
 static char expect_release;
 static unsigned long hpwdt_is_open;
 static unsigned int allow_kdump;
-static int hpwdt_nmi_sourcing;
+static unsigned int hpwdt_nmi_sourcing;
+static unsigned int priority;          /* hpwdt at end of die_notify list */
 
 static void __iomem *pci_mem_addr;             /* the PCI-memory address */
 static unsigned long __iomem *hpwdt_timer_reg;
@@ -623,7 +624,7 @@ static struct miscdevice hpwdt_miscdev = {
 
 static struct notifier_block die_notifier = {
        .notifier_call = hpwdt_pretimeout,
-       .priority = 0x7FFFFFFF,
+       .priority = 0,
 };
 
 /*
@@ -641,7 +642,8 @@ static void __devinit hpwdt_check_nmi_sourcing(struct pci_dev *dev)
                hpwdt_nmi_sourcing = 1;
        else
                dev_warn(&dev->dev, "NMI sourcing is disabled. To enable this "
-                       "functionality you must reboot with nmi_watchdog=0.\n");
+                       "functionality you must reboot with nmi_watchdog=0 "
+                       "and load the hpwdt driver with priority=1.\n");
 }
 #else
 static void __devinit hpwdt_check_nmi_sourcing(struct pci_dev *dev)
@@ -714,6 +716,14 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev,
        cmn_regs.u1.rah = 0x0D;
        cmn_regs.u1.ral = 0x02;
 
+       /*
+        * If the priority is set to 1, then we will be put first on the
+        * die notify list to handle a critical NMI. The default is to
+        * be last so other users of the NMI signal can function.
+        */
+       if (priority)
+               die_notifier.priority = 0x7FFFFFFF;
+
        retval = register_die_notifier(&die_notifier);
        if (retval != 0) {
                dev_warn(&dev->dev,
@@ -733,9 +743,11 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev,
        printk(KERN_INFO
                "hp Watchdog Timer Driver: %s"
                ", timer margin: %d seconds (nowayout=%d)"
-               ", allow kernel dump: %s (default = 0/OFF).\n",
+               ", allow kernel dump: %s (default = 0/OFF)"
+               ", priority: %s (default = 0/LAST).\n",
                HPWDT_VERSION, soft_margin, nowayout,
-               (allow_kdump == 0) ? "OFF" : "ON");
+               (allow_kdump == 0) ? "OFF" : "ON",
+               (priority == 0) ? "LAST" : "FIRST");
 
        return 0;
 
@@ -798,5 +810,9 @@ module_param(nowayout, int, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
+module_param(priority, int, 0);
+MODULE_PARM_DESC(priority, "The hpwdt driver handles NMIs first or last"
+               " (default = 0/Last)\n");
+
 module_init(hpwdt_init);
 module_exit(hpwdt_cleanup);
index f2713851aaabeb65cc6d8257ae9d0da3367909fb..3ed571a2ab18712d3bc42c0c421d4a02a6d4bae1 100644 (file)
@@ -159,6 +159,7 @@ static int omap_wdt_open(struct inode *inode, struct file *file)
        file->private_data = (void *) wdev;
 
        omap_wdt_set_timeout(wdev);
+       omap_wdt_ping(wdev); /* trigger loading of new timeout value */
        omap_wdt_enable(wdev);
 
        return nonseekable_open(inode, file);
@@ -313,6 +314,9 @@ static int __devinit omap_wdt_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, wdev);
 
+       clk_enable(wdev->ick);
+       clk_enable(wdev->fck);
+
        omap_wdt_disable(wdev);
        omap_wdt_adjust_timeout(timer_margin);
 
@@ -332,6 +336,9 @@ static int __devinit omap_wdt_probe(struct platform_device *pdev)
        /* autogate OCP interface clock */
        __raw_writel(0x01, wdev->base + OMAP_WATCHDOG_SYS_CONFIG);
 
+       clk_disable(wdev->ick);
+       clk_disable(wdev->fck);
+
        omap_wdt_dev = pdev;
 
        return 0;
diff --git a/drivers/watchdog/pnx833x_wdt.c b/drivers/watchdog/pnx833x_wdt.c
new file mode 100644 (file)
index 0000000..538ec2c
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ *  PNX833x Hardware Watchdog Driver
+ *  Copyright 2008 NXP Semiconductors
+ *  Daniel Laird <daniel.j.laird@nxp.com>
+ *  Andre McCurdy <andre.mccurdy@nxp.com>
+ *
+ *  Heavily based upon - IndyDog       0.3
+ *  A Hardware Watchdog Device for SGI IP22
+ *
+ * (c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * based on softdog.c by Alan Cox <alan@redhat.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <asm/mach-pnx833x/pnx833x.h>
+
+#define PFX "pnx833x: "
+#define WATCHDOG_TIMEOUT 30            /* 30 sec Maximum timeout */
+#define WATCHDOG_COUNT_FREQUENCY 68000000U /* Watchdog counts at 68MHZ. */
+
+/** CONFIG block */
+#define PNX833X_CONFIG                      (0x07000U)
+#define PNX833X_CONFIG_CPU_WATCHDOG         (0x54)
+#define PNX833X_CONFIG_CPU_WATCHDOG_COMPARE (0x58)
+#define PNX833X_CONFIG_CPU_COUNTERS_CONTROL (0x1c)
+
+/** RESET block */
+#define PNX833X_RESET                       (0x08000U)
+#define PNX833X_RESET_CONFIG                (0x08)
+
+static int pnx833x_wdt_alive;
+
+/* Set default timeout in MHZ.*/
+static int pnx833x_wdt_timeout = (WATCHDOG_TIMEOUT * WATCHDOG_COUNT_FREQUENCY);
+module_param(pnx833x_wdt_timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in Mhz. (68Mhz clock), default="
+                       __MODULE_STRING(pnx833x_wdt_timeout) "(30 seconds).");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+                                       __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static int start_enabled = 1;
+module_param(start_enabled, int, 0);
+MODULE_PARM_DESC(start_enabled, "Watchdog is started on module insertion "
+                               "(default=" __MODULE_STRING(start_enabled) ")");
+
+static void pnx833x_wdt_start(void)
+{
+       /* Enable watchdog causing reset. */
+       PNX833X_REG(PNX833X_RESET + PNX833X_RESET_CONFIG) |= 0x1;
+       /* Set timeout.*/
+       PNX833X_REG(PNX833X_CONFIG +
+               PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = pnx833x_wdt_timeout;
+       /* Enable watchdog. */
+       PNX833X_REG(PNX833X_CONFIG +
+                               PNX833X_CONFIG_CPU_COUNTERS_CONTROL) |= 0x1;
+
+       printk(KERN_INFO PFX "Started watchdog timer.\n");
+}
+
+static void pnx833x_wdt_stop(void)
+{
+       /* Disable watchdog causing reset. */
+       PNX833X_REG(PNX833X_RESET + PNX833X_CONFIG) &= 0xFFFFFFFE;
+       /* Disable watchdog.*/
+       PNX833X_REG(PNX833X_CONFIG +
+                       PNX833X_CONFIG_CPU_COUNTERS_CONTROL) &= 0xFFFFFFFE;
+
+       printk(KERN_INFO PFX "Stopped watchdog timer.\n");
+}
+
+static void pnx833x_wdt_ping(void)
+{
+       PNX833X_REG(PNX833X_CONFIG +
+               PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = pnx833x_wdt_timeout;
+}
+
+/*
+ *     Allow only one person to hold it open
+ */
+static int pnx833x_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(0, &pnx833x_wdt_alive))
+               return -EBUSY;
+
+       if (nowayout)
+               __module_get(THIS_MODULE);
+
+       /* Activate timer */
+       if (!start_enabled)
+               pnx833x_wdt_start();
+
+       pnx833x_wdt_ping();
+
+       printk(KERN_INFO "Started watchdog timer.\n");
+
+       return nonseekable_open(inode, file);
+}
+
+static int pnx833x_wdt_release(struct inode *inode, struct file *file)
+{
+       /* Shut off the timer.
+        * Lock it in if it's a module and we defined ...NOWAYOUT */
+       if (!nowayout)
+               pnx833x_wdt_stop(); /* Turn the WDT off */
+
+       clear_bit(0, &pnx833x_wdt_alive);
+       return 0;
+}
+
+static ssize_t pnx833x_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+       /* Refresh the timer. */
+       if (len)
+               pnx833x_wdt_ping();
+
+       return len;
+}
+
+static long pnx833x_wdt_ioctl(struct file *file, unsigned int cmd,
+                                                       unsigned long arg)
+{
+       int options, new_timeout = 0;
+       uint32_t timeout, timeout_left = 0;
+
+       static struct watchdog_info ident = {
+               .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
+               .firmware_version = 0,
+               .identity = "Hardware Watchdog for PNX833x",
+       };
+
+       switch (cmd) {
+       default:
+               return -ENOTTY;
+
+       case WDIOC_GETSUPPORT:
+               if (copy_to_user((struct watchdog_info *)arg,
+                                &ident, sizeof(ident)))
+                       return -EFAULT;
+               return 0;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(0, (int *)arg);
+
+       case WDIOC_SETOPTIONS:
+               if (get_user(options, (int *)arg))
+                       return -EFAULT;
+
+               if (options & WDIOS_DISABLECARD)
+                       pnx833x_wdt_stop();
+
+               if (options & WDIOS_ENABLECARD)
+                       pnx833x_wdt_start();
+
+               return 0;
+
+       case WDIOC_KEEPALIVE:
+               pnx833x_wdt_ping();
+               return 0;
+
+       case WDIOC_SETTIMEOUT:
+       {
+               if (get_user(new_timeout, (int *)arg))
+                       return -EFAULT;
+
+               pnx833x_wdt_timeout = new_timeout;
+               PNX833X_REG(PNX833X_CONFIG +
+                       PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = new_timeout;
+               return put_user(new_timeout, (int *)arg);
+       }
+
+       case WDIOC_GETTIMEOUT:
+               timeout = PNX833X_REG(PNX833X_CONFIG +
+                                       PNX833X_CONFIG_CPU_WATCHDOG_COMPARE);
+               return put_user(timeout, (int *)arg);
+
+       case WDIOC_GETTIMELEFT:
+               timeout_left = PNX833X_REG(PNX833X_CONFIG +
+                                               PNX833X_CONFIG_CPU_WATCHDOG);
+               return put_user(timeout_left, (int *)arg);
+
+       }
+}
+
+static int pnx833x_wdt_notify_sys(struct notifier_block *this,
+                                       unsigned long code, void *unused)
+{
+       if (code == SYS_DOWN || code == SYS_HALT)
+               pnx833x_wdt_stop(); /* Turn the WDT off */
+
+       return NOTIFY_DONE;
+}
+
+static const struct file_operations pnx833x_wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = pnx833x_wdt_write,
+       .unlocked_ioctl = pnx833x_wdt_ioctl,
+       .open           = pnx833x_wdt_open,
+       .release        = pnx833x_wdt_release,
+};
+
+static struct miscdevice pnx833x_wdt_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &pnx833x_wdt_fops,
+};
+
+static struct notifier_block pnx833x_wdt_notifier = {
+       .notifier_call = pnx833x_wdt_notify_sys,
+};
+
+static char banner[] __initdata =
+       KERN_INFO PFX "Hardware Watchdog Timer for PNX833x: Version 0.1\n";
+
+static int __init watchdog_init(void)
+{
+       int ret, cause;
+
+       /* Lets check the reason for the reset.*/
+       cause = PNX833X_REG(PNX833X_RESET);
+       /*If bit 31 is set then watchdog was cause of reset.*/
+       if (cause & 0x80000000) {
+               printk(KERN_INFO PFX "The system was previously reset due to "
+                       "the watchdog firing - please investigate...\n");
+       }
+
+       ret = register_reboot_notifier(&pnx833x_wdt_notifier);
+       if (ret) {
+               printk(KERN_ERR PFX
+                       "cannot register reboot notifier (err=%d)\n", ret);
+               return ret;
+       }
+
+       ret = misc_register(&pnx833x_wdt_miscdev);
+       if (ret) {
+               printk(KERN_ERR PFX
+                       "cannot register miscdev on minor=%d (err=%d)\n",
+                       WATCHDOG_MINOR, ret);
+               unregister_reboot_notifier(&pnx833x_wdt_notifier);
+               return ret;
+       }
+
+       printk(banner);
+       if (start_enabled)
+               pnx833x_wdt_start();
+
+       return 0;
+}
+
+static void __exit watchdog_exit(void)
+{
+       misc_deregister(&pnx833x_wdt_miscdev);
+       unregister_reboot_notifier(&pnx833x_wdt_notifier);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_exit);
+
+MODULE_AUTHOR("Daniel Laird/Andre McCurdy");
+MODULE_DESCRIPTION("Hardware Watchdog Device for PNX833x");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/stmp3xxx_wdt.c b/drivers/watchdog/stmp3xxx_wdt.c
new file mode 100644 (file)
index 0000000..5dd9526
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * Watchdog driver for Freescale STMP37XX/STMP378X
+ *
+ * Author: Vitaly Wool <vital@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+
+#include <mach/platform.h>
+#include <mach/regs-rtc.h>
+
+#define DEFAULT_HEARTBEAT      19
+#define MAX_HEARTBEAT          (0x10000000 >> 6)
+
+/* missing bitmask in headers */
+#define BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER     0x80000000
+
+#define WDT_IN_USE             0
+#define WDT_OK_TO_CLOSE                1
+
+#define WDOG_COUNTER_RATE      1000 /* 1 kHz clock */
+
+static DEFINE_SPINLOCK(stmp3xxx_wdt_io_lock);
+static unsigned long wdt_status;
+static const int nowayout = WATCHDOG_NOWAYOUT;
+static int heartbeat = DEFAULT_HEARTBEAT;
+static unsigned long boot_status;
+
+static void wdt_enable(u32 value)
+{
+       spin_lock(&stmp3xxx_wdt_io_lock);
+       __raw_writel(value, REGS_RTC_BASE + HW_RTC_WATCHDOG);
+       stmp3xxx_setl(BM_RTC_CTRL_WATCHDOGEN, REGS_RTC_BASE + HW_RTC_CTRL);
+       stmp3xxx_setl(BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER,
+                       REGS_RTC_BASE + HW_RTC_PERSISTENT1);
+       spin_unlock(&stmp3xxx_wdt_io_lock);
+}
+
+static void wdt_disable(void)
+{
+       spin_lock(&stmp3xxx_wdt_io_lock);
+       stmp3xxx_clearl(BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER,
+                       REGS_RTC_BASE + HW_RTC_PERSISTENT1);
+       stmp3xxx_clearl(BM_RTC_CTRL_WATCHDOGEN, REGS_RTC_BASE + HW_RTC_CTRL);
+       spin_unlock(&stmp3xxx_wdt_io_lock);
+}
+
+static void wdt_ping(void)
+{
+       wdt_enable(heartbeat * WDOG_COUNTER_RATE);
+}
+
+static int stmp3xxx_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+               return -EBUSY;
+
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+       wdt_ping();
+
+       return nonseekable_open(inode, file);
+}
+
+static ssize_t stmp3xxx_wdt_write(struct file *file, const char __user *data,
+       size_t len, loff_t *ppos)
+{
+       if (len) {
+               if (!nowayout) {
+                       size_t i;
+
+                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+                       for (i = 0; i != len; i++) {
+                               char c;
+
+                               if (get_user(c, data + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+                       }
+               }
+               wdt_ping();
+       }
+
+       return len;
+}
+
+static struct watchdog_info ident = {
+       .options        = WDIOF_CARDRESET |
+                         WDIOF_MAGICCLOSE |
+                         WDIOF_SETTIMEOUT |
+                         WDIOF_KEEPALIVEPING,
+       .identity       = "STMP3XXX Watchdog",
+};
+
+static long stmp3xxx_wdt_ioctl(struct file *file, unsigned int cmd,
+       unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+       int new_heartbeat, opts;
+       int ret = -ENOTTY;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               ret = copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
+               break;
+
+       case WDIOC_GETSTATUS:
+               ret = put_user(0, p);
+               break;
+
+       case WDIOC_GETBOOTSTATUS:
+               ret = put_user(boot_status, p);
+               break;
+
+       case WDIOC_SETOPTIONS:
+               if (get_user(opts, p)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (opts & WDIOS_DISABLECARD)
+                       wdt_disable();
+               else if (opts & WDIOS_ENABLECARD)
+                       wdt_ping();
+               else {
+                       pr_debug("%s: unknown option 0x%x\n", __func__, opts);
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = 0;
+               break;
+
+       case WDIOC_KEEPALIVE:
+               wdt_ping();
+               ret = 0;
+               break;
+
+       case WDIOC_SETTIMEOUT:
+               if (get_user(new_heartbeat, p)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (new_heartbeat <= 0 || new_heartbeat > MAX_HEARTBEAT) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               heartbeat = new_heartbeat;
+               wdt_ping();
+               /* Fall through */
+
+       case WDIOC_GETTIMEOUT:
+               ret = put_user(heartbeat, p);
+               break;
+       }
+       return ret;
+}
+
+static int stmp3xxx_wdt_release(struct inode *inode, struct file *file)
+{
+       int ret = 0;
+
+       if (!nowayout) {
+               if (!test_bit(WDT_OK_TO_CLOSE, &wdt_status)) {
+                       wdt_ping();
+                       pr_debug("%s: Device closed unexpectdly\n", __func__);
+                       ret = -EINVAL;
+               } else {
+                       wdt_disable();
+                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+               }
+       }
+       clear_bit(WDT_IN_USE, &wdt_status);
+
+       return ret;
+}
+
+static const struct file_operations stmp3xxx_wdt_fops = {
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .write = stmp3xxx_wdt_write,
+       .unlocked_ioctl = stmp3xxx_wdt_ioctl,
+       .open = stmp3xxx_wdt_open,
+       .release = stmp3xxx_wdt_release,
+};
+
+static struct miscdevice stmp3xxx_wdt_miscdev = {
+       .minor = WATCHDOG_MINOR,
+       .name = "watchdog",
+       .fops = &stmp3xxx_wdt_fops,
+};
+
+static int __devinit stmp3xxx_wdt_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+
+       if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
+               heartbeat = DEFAULT_HEARTBEAT;
+
+       boot_status = __raw_readl(REGS_RTC_BASE + HW_RTC_PERSISTENT1) &
+                       BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER;
+       boot_status = !!boot_status;
+       stmp3xxx_clearl(BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER,
+                       REGS_RTC_BASE + HW_RTC_PERSISTENT1);
+       wdt_disable();          /* disable for now */
+
+       ret = misc_register(&stmp3xxx_wdt_miscdev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "cannot register misc device\n");
+               return ret;
+       }
+
+       printk(KERN_INFO "stmp3xxx watchdog: initialized, heartbeat %d sec\n",
+               heartbeat);
+
+       return ret;
+}
+
+static int __devexit stmp3xxx_wdt_remove(struct platform_device *pdev)
+{
+       misc_deregister(&stmp3xxx_wdt_miscdev);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int wdt_suspended;
+static u32 wdt_saved_time;
+
+static int stmp3xxx_wdt_suspend(struct platform_device *pdev,
+                               pm_message_t state)
+{
+       if (__raw_readl(REGS_RTC_BASE + HW_RTC_CTRL) &
+               BM_RTC_CTRL_WATCHDOGEN) {
+               wdt_suspended = 1;
+               wdt_saved_time = __raw_readl(REGS_RTC_BASE + HW_RTC_WATCHDOG);
+               wdt_disable();
+       }
+       return 0;
+}
+
+static int stmp3xxx_wdt_resume(struct platform_device *pdev)
+{
+       if (wdt_suspended) {
+               wdt_enable(wdt_saved_time);
+               wdt_suspended = 0;
+       }
+       return 0;
+}
+#else
+#define stmp3xxx_wdt_suspend   NULL
+#define stmp3xxx_wdt_resume    NULL
+#endif
+
+static struct platform_driver platform_wdt_driver = {
+       .driver = {
+               .name = "stmp3xxx_wdt",
+       },
+       .probe = stmp3xxx_wdt_probe,
+       .remove = __devexit_p(stmp3xxx_wdt_remove),
+       .suspend = stmp3xxx_wdt_suspend,
+       .resume = stmp3xxx_wdt_resume,
+};
+
+static int __init stmp3xxx_wdt_init(void)
+{
+       return platform_driver_register(&platform_wdt_driver);
+}
+
+static void __exit stmp3xxx_wdt_exit(void)
+{
+       return platform_driver_unregister(&platform_wdt_driver);
+}
+
+module_init(stmp3xxx_wdt_init);
+module_exit(stmp3xxx_wdt_exit);
+
+MODULE_DESCRIPTION("STMP3XXX Watchdog Driver");
+MODULE_LICENSE("GPL");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat,
+                "Watchdog heartbeat period in seconds from 1 to "
+                __MODULE_STRING(MAX_HEARTBEAT) ", default "
+                __MODULE_STRING(DEFAULT_HEARTBEAT));
+
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/twl4030_wdt.c b/drivers/watchdog/twl4030_wdt.c
new file mode 100644 (file)
index 0000000..cb46556
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) Nokia Corporation
+ *
+ * Written by Timo Kokkonen <timo.t.kokkonen at nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/watchdog.h>
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/i2c/twl4030.h>
+
+#define TWL4030_WATCHDOG_CFG_REG_OFFS  0x3
+
+#define TWL4030_WDT_STATE_OPEN         0x1
+#define TWL4030_WDT_STATE_ACTIVE       0x8
+
+static struct platform_device *twl4030_wdt_dev;
+
+struct twl4030_wdt {
+       struct miscdevice       miscdev;
+       int                     timer_margin;
+       unsigned long           state;
+};
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
+       "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static int twl4030_wdt_write(unsigned char val)
+{
+       return twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, val,
+                                       TWL4030_WATCHDOG_CFG_REG_OFFS);
+}
+
+static int twl4030_wdt_enable(struct twl4030_wdt *wdt)
+{
+       return twl4030_wdt_write(wdt->timer_margin + 1);
+}
+
+static int twl4030_wdt_disable(struct twl4030_wdt *wdt)
+{
+       return twl4030_wdt_write(0);
+}
+
+static int twl4030_wdt_set_timeout(struct twl4030_wdt *wdt, int timeout)
+{
+       if (timeout < 0 || timeout > 30) {
+               dev_warn(wdt->miscdev.parent,
+                       "Timeout can only be in the range [0-30] seconds");
+               return -EINVAL;
+       }
+       wdt->timer_margin = timeout;
+       return twl4030_wdt_enable(wdt);
+}
+
+static ssize_t twl4030_wdt_write_fop(struct file *file,
+               const char __user *data, size_t len, loff_t *ppos)
+{
+       struct twl4030_wdt *wdt = file->private_data;
+
+       if (len)
+               twl4030_wdt_enable(wdt);
+
+       return len;
+}
+
+static long twl4030_wdt_ioctl(struct file *file,
+               unsigned int cmd, unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+       int new_margin;
+       struct twl4030_wdt *wdt = file->private_data;
+
+       static const struct watchdog_info twl4030_wd_ident = {
+               .identity = "TWL4030 Watchdog",
+               .options = WDIOF_SETTIMEOUT,
+               .firmware_version = 0,
+       };
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               return copy_to_user(argp, &twl4030_wd_ident,
+                               sizeof(twl4030_wd_ident)) ? -EFAULT : 0;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(0, p);
+
+       case WDIOC_KEEPALIVE:
+               twl4030_wdt_enable(wdt);
+               break;
+
+       case WDIOC_SETTIMEOUT:
+               if (get_user(new_margin, p))
+                       return -EFAULT;
+               if (twl4030_wdt_set_timeout(wdt, new_margin))
+                       return -EINVAL;
+               return put_user(wdt->timer_margin, p);
+
+       case WDIOC_GETTIMEOUT:
+               return put_user(wdt->timer_margin, p);
+
+       default:
+               return -ENOTTY;
+       }
+
+       return 0;
+}
+
+static int twl4030_wdt_open(struct inode *inode, struct file *file)
+{
+       struct twl4030_wdt *wdt = platform_get_drvdata(twl4030_wdt_dev);
+
+       /* /dev/watchdog can only be opened once */
+       if (test_and_set_bit(0, &wdt->state))
+               return -EBUSY;
+
+       wdt->state |= TWL4030_WDT_STATE_ACTIVE;
+       file->private_data = (void *) wdt;
+
+       twl4030_wdt_enable(wdt);
+       return nonseekable_open(inode, file);
+}
+
+static int twl4030_wdt_release(struct inode *inode, struct file *file)
+{
+       struct twl4030_wdt *wdt = file->private_data;
+       if (nowayout) {
+               dev_alert(wdt->miscdev.parent,
+                      "Unexpected close, watchdog still running!\n");
+               twl4030_wdt_enable(wdt);
+       } else {
+               if (twl4030_wdt_disable(wdt))
+                       return -EFAULT;
+               wdt->state &= ~TWL4030_WDT_STATE_ACTIVE;
+       }
+
+       clear_bit(0, &wdt->state);
+       return 0;
+}
+
+static const struct file_operations twl4030_wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .open           = twl4030_wdt_open,
+       .release        = twl4030_wdt_release,
+       .unlocked_ioctl = twl4030_wdt_ioctl,
+       .write          = twl4030_wdt_write_fop,
+};
+
+static int __devinit twl4030_wdt_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct twl4030_wdt *wdt;
+
+       wdt = kzalloc(sizeof(struct twl4030_wdt), GFP_KERNEL);
+       if (!wdt)
+               return -ENOMEM;
+
+       wdt->state              = 0;
+       wdt->timer_margin       = 30;
+       wdt->miscdev.parent     = &pdev->dev;
+       wdt->miscdev.fops       = &twl4030_wdt_fops;
+       wdt->miscdev.minor      = WATCHDOG_MINOR;
+       wdt->miscdev.name       = "watchdog";
+
+       platform_set_drvdata(pdev, wdt);
+
+       twl4030_wdt_dev = pdev;
+
+       ret = misc_register(&wdt->miscdev);
+       if (ret) {
+               dev_err(wdt->miscdev.parent,
+                       "Failed to register misc device\n");
+               platform_set_drvdata(pdev, NULL);
+               kfree(wdt);
+               twl4030_wdt_dev = NULL;
+               return ret;
+       }
+       return 0;
+}
+
+static int __devexit twl4030_wdt_remove(struct platform_device *pdev)
+{
+       struct twl4030_wdt *wdt = platform_get_drvdata(pdev);
+
+       if (wdt->state & TWL4030_WDT_STATE_ACTIVE)
+               if (twl4030_wdt_disable(wdt))
+                       return -EFAULT;
+
+       wdt->state &= ~TWL4030_WDT_STATE_ACTIVE;
+       misc_deregister(&wdt->miscdev);
+
+       platform_set_drvdata(pdev, NULL);
+       kfree(wdt);
+       twl4030_wdt_dev = NULL;
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int twl4030_wdt_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct twl4030_wdt *wdt = platform_get_drvdata(pdev);
+       if (wdt->state & TWL4030_WDT_STATE_ACTIVE)
+               return twl4030_wdt_disable(wdt);
+
+       return 0;
+}
+
+static int twl4030_wdt_resume(struct platform_device *pdev)
+{
+       struct twl4030_wdt *wdt = platform_get_drvdata(pdev);
+       if (wdt->state & TWL4030_WDT_STATE_ACTIVE)
+               return twl4030_wdt_enable(wdt);
+
+       return 0;
+}
+#else
+#define twl4030_wdt_suspend        NULL
+#define twl4030_wdt_resume         NULL
+#endif
+
+static struct platform_driver twl4030_wdt_driver = {
+       .probe          = twl4030_wdt_probe,
+       .remove         = __devexit_p(twl4030_wdt_remove),
+       .suspend        = twl4030_wdt_suspend,
+       .resume         = twl4030_wdt_resume,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "twl4030_wdt",
+       },
+};
+
+static int __devinit twl4030_wdt_init(void)
+{
+       return platform_driver_register(&twl4030_wdt_driver);
+}
+module_init(twl4030_wdt_init);
+
+static void __devexit twl4030_wdt_exit(void)
+{
+       platform_driver_unregister(&twl4030_wdt_driver);
+}
+module_exit(twl4030_wdt_exit);
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS("platform:twl4030_wdt");
+
index c45839a4a34dfd7e7a58c18674bc1cb680d24b64..7a1bdc7c95a98fdbcc7a897190b4b7634b2e2e85 100644 (file)
@@ -2,7 +2,7 @@
  *     Industrial Computer Source PCI-WDT500/501 driver
  *
  *     (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>,
- *                                              All Rights Reserved.
+ *                                             All Rights Reserved.
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
@@ -99,14 +99,16 @@ MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
-#ifdef CONFIG_WDT_501_PCI
 /* Support for the Fan Tachometer on the PCI-WDT501 */
 static int tachometer;
-
 module_param(tachometer, int, 0);
 MODULE_PARM_DESC(tachometer,
-       "PCI-WDT501 Fan Tachometer support (0=disable, default=0)");
-#endif /* CONFIG_WDT_501_PCI */
+               "PCI-WDT501 Fan Tachometer support (0=disable, default=0)");
+
+static int type = 500;
+module_param(type, int, 0);
+MODULE_PARM_DESC(type,
+               "PCI-WDT501 Card type (500 or 501 , default=500)");
 
 /*
  *     Programming support
@@ -266,22 +268,21 @@ static int wdtpci_get_status(int *status)
                *status |= WDIOF_EXTERN1;
        if (new_status & WDC_SR_ISII1)
                *status |= WDIOF_EXTERN2;
-#ifdef CONFIG_WDT_501_PCI
-       if (!(new_status & WDC_SR_TGOOD))
-               *status |= WDIOF_OVERHEAT;
-       if (!(new_status & WDC_SR_PSUOVER))
-               *status |= WDIOF_POWEROVER;
-       if (!(new_status & WDC_SR_PSUUNDR))
-               *status |= WDIOF_POWERUNDER;
-       if (tachometer) {
-               if (!(new_status & WDC_SR_FANGOOD))
-                       *status |= WDIOF_FANFAULT;
+       if (type == 501) {
+               if (!(new_status & WDC_SR_TGOOD))
+                       *status |= WDIOF_OVERHEAT;
+               if (!(new_status & WDC_SR_PSUOVER))
+                       *status |= WDIOF_POWEROVER;
+               if (!(new_status & WDC_SR_PSUUNDR))
+                       *status |= WDIOF_POWERUNDER;
+               if (tachometer) {
+                       if (!(new_status & WDC_SR_FANGOOD))
+                               *status |= WDIOF_FANFAULT;
+               }
        }
-#endif /* CONFIG_WDT_501_PCI */
        return 0;
 }
 
-#ifdef CONFIG_WDT_501_PCI
 /**
  *     wdtpci_get_temperature:
  *
@@ -300,7 +301,6 @@ static int wdtpci_get_temperature(int *temperature)
        *temperature = (c * 11 / 15) + 7;
        return 0;
 }
-#endif /* CONFIG_WDT_501_PCI */
 
 /**
  *     wdtpci_interrupt:
@@ -327,22 +327,22 @@ static irqreturn_t wdtpci_interrupt(int irq, void *dev_id)
 
        printk(KERN_CRIT PFX "status %d\n", status);
 
-#ifdef CONFIG_WDT_501_PCI
-       if (!(status & WDC_SR_TGOOD)) {
-               u8 alarm = inb(WDT_RT);
-               printk(KERN_CRIT PFX "Overheat alarm.(%d)\n", alarm);
-               udelay(8);
-       }
-       if (!(status & WDC_SR_PSUOVER))
-               printk(KERN_CRIT PFX "PSU over voltage.\n");
-       if (!(status & WDC_SR_PSUUNDR))
-               printk(KERN_CRIT PFX "PSU under voltage.\n");
-       if (tachometer) {
-               if (!(status & WDC_SR_FANGOOD))
-                       printk(KERN_CRIT PFX "Possible fan fault.\n");
+       if (type == 501) {
+               if (!(status & WDC_SR_TGOOD)) {
+                       printk(KERN_CRIT PFX "Overheat alarm.(%d)\n",
+                                                               inb(WDT_RT));
+                       udelay(8);
+               }
+               if (!(status & WDC_SR_PSUOVER))
+                       printk(KERN_CRIT PFX "PSU over voltage.\n");
+               if (!(status & WDC_SR_PSUUNDR))
+                       printk(KERN_CRIT PFX "PSU under voltage.\n");
+               if (tachometer) {
+                       if (!(status & WDC_SR_FANGOOD))
+                               printk(KERN_CRIT PFX "Possible fan fault.\n");
+               }
        }
-#endif /* CONFIG_WDT_501_PCI */
-       if (!(status&WDC_SR_WCCR)) {
+       if (!(status & WDC_SR_WCCR)) {
 #ifdef SOFTWARE_REBOOT
 #ifdef ONLY_TESTING
                printk(KERN_CRIT PFX "Would Reboot.\n");
@@ -371,12 +371,13 @@ static irqreturn_t wdtpci_interrupt(int irq, void *dev_id)
  */
 
 static ssize_t wdtpci_write(struct file *file, const char __user *buf,
-                                       size_t count, loff_t *ppos)
+                                               size_t count, loff_t *ppos)
 {
        if (count) {
                if (!nowayout) {
                        size_t i;
 
+                       /* In case it was set long ago */
                        expect_close = 0;
 
                        for (i = 0; i != count; i++) {
@@ -406,10 +407,10 @@ static ssize_t wdtpci_write(struct file *file, const char __user *buf,
 static long wdtpci_ioctl(struct file *file, unsigned int cmd,
                                                        unsigned long arg)
 {
-       int new_heartbeat;
-       int status;
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
+       int new_heartbeat;
+       int status;
 
        static struct watchdog_info ident = {
                .options =              WDIOF_SETTIMEOUT|
@@ -421,11 +422,12 @@ static long wdtpci_ioctl(struct file *file, unsigned int cmd,
 
        /* Add options according to the card we have */
        ident.options |= (WDIOF_EXTERN1|WDIOF_EXTERN2);
-#ifdef CONFIG_WDT_501_PCI
-       ident.options |= (WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER);
-       if (tachometer)
-               ident.options |= WDIOF_FANFAULT;
-#endif /* CONFIG_WDT_501_PCI */
+       if (type == 501) {
+               ident.options |= (WDIOF_OVERHEAT|WDIOF_POWERUNDER|
+                                                       WDIOF_POWEROVER);
+               if (tachometer)
+                       ident.options |= WDIOF_FANFAULT;
+       }
 
        switch (cmd) {
        case WDIOC_GETSUPPORT:
@@ -503,7 +505,6 @@ static int wdtpci_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-#ifdef CONFIG_WDT_501_PCI
 /**
  *     wdtpci_temp_read:
  *     @file: file handle to the watchdog board
@@ -554,7 +555,6 @@ static int wdtpci_temp_release(struct inode *inode, struct file *file)
 {
        return 0;
 }
-#endif /* CONFIG_WDT_501_PCI */
 
 /**
  *     notify_sys:
@@ -596,7 +596,6 @@ static struct miscdevice wdtpci_miscdev = {
        .fops   = &wdtpci_fops,
 };
 
-#ifdef CONFIG_WDT_501_PCI
 static const struct file_operations wdtpci_temp_fops = {
        .owner          = THIS_MODULE,
        .llseek         = no_llseek,
@@ -610,7 +609,6 @@ static struct miscdevice temp_miscdev = {
        .name   = "temperature",
        .fops   = &wdtpci_temp_fops,
 };
-#endif /* CONFIG_WDT_501_PCI */
 
 /*
  *     The WDT card needs to learn about soft shutdowns in order to
@@ -633,6 +631,11 @@ static int __devinit wdtpci_init_one(struct pci_dev *dev,
                return -ENODEV;
        }
 
+       if (type != 500 && type != 501) {
+               printk(KERN_ERR PFX "unknown card type '%d'.\n", type);
+               return -ENODEV;
+       }
+
        if (pci_enable_device(dev)) {
                printk(KERN_ERR PFX "Not possible to enable PCI Device\n");
                return -ENODEV;
@@ -678,15 +681,15 @@ static int __devinit wdtpci_init_one(struct pci_dev *dev,
                goto out_irq;
        }
 
-#ifdef CONFIG_WDT_501_PCI
-       ret = misc_register(&temp_miscdev);
-       if (ret) {
-               printk(KERN_ERR PFX
+       if (type == 501) {
+               ret = misc_register(&temp_miscdev);
+               if (ret) {
+                       printk(KERN_ERR PFX
                        "cannot register miscdev on minor=%d (err=%d)\n",
-                                       TEMP_MINOR, ret);
-               goto out_rbt;
+                                                       TEMP_MINOR, ret);
+                       goto out_rbt;
+               }
        }
-#endif /* CONFIG_WDT_501_PCI */
 
        ret = misc_register(&wdtpci_miscdev);
        if (ret) {
@@ -698,20 +701,18 @@ static int __devinit wdtpci_init_one(struct pci_dev *dev,
 
        printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
                heartbeat, nowayout);
-#ifdef CONFIG_WDT_501_PCI
-       printk(KERN_INFO "wdt: Fan Tachometer is %s\n",
+       if (type == 501)
+               printk(KERN_INFO "wdt: Fan Tachometer is %s\n",
                                (tachometer ? "Enabled" : "Disabled"));
-#endif /* CONFIG_WDT_501_PCI */
 
        ret = 0;
 out:
        return ret;
 
 out_misc:
-#ifdef CONFIG_WDT_501_PCI
-       misc_deregister(&temp_miscdev);
+       if (type == 501)
+               misc_deregister(&temp_miscdev);
 out_rbt:
-#endif /* CONFIG_WDT_501_PCI */
        unregister_reboot_notifier(&wdtpci_notifier);
 out_irq:
        free_irq(irq, &wdtpci_miscdev);
@@ -728,9 +729,8 @@ static void __devexit wdtpci_remove_one(struct pci_dev *pdev)
        /* here we assume only one device will ever have
         * been picked up and registered by probe function */
        misc_deregister(&wdtpci_miscdev);
-#ifdef CONFIG_WDT_501_PCI
-       misc_deregister(&temp_miscdev);
-#endif /* CONFIG_WDT_501_PCI */
+       if (type == 501)
+               misc_deregister(&temp_miscdev);
        unregister_reboot_notifier(&wdtpci_notifier);
        free_irq(irq, &wdtpci_miscdev);
        release_region(io, 16);
index 3d5d2c906ab3e9f0b48f021ad6d6edd7f65ac106..23bb4dad4962cee55b3d39f9ce14edda6043cb9c 100644 (file)
@@ -11,19 +11,6 @@ typedef struct {
 
 #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
 
-#ifndef HARDIRQ_BITS
-#define HARDIRQ_BITS   8
-#endif
-
-/*
- * The hardirq mask has to be large enough to have
- * space for potentially all IRQ sources in the system
- * nesting on a single CPU:
- */
-#if (1 << HARDIRQ_BITS) < NR_IRQS
-# error HARDIRQ_BITS is too low!
-#endif
-
 #ifndef ack_bad_irq
 static inline void ack_bad_irq(unsigned int irq)
 {
index e410f602cab1b31fdd71681708d17049181026d5..e2bd73e8f9c0b4db75755d1e4f0aadaaa0e20c2a 100644 (file)
@@ -129,6 +129,10 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addres
 #define move_pte(pte, prot, old_addr, new_addr)        (pte)
 #endif
 
+#ifndef pgprot_noncached
+#define pgprot_noncached(prot) (prot)
+#endif
+
 #ifndef pgprot_writecombine
 #define pgprot_writecombine pgprot_noncached
 #endif
index 6d8cab22e2941b943dda136a924f4698114a44a9..b218b8513d04ba968e07fddc977859e6045e1450 100644 (file)
@@ -163,7 +163,7 @@ static inline __must_check long __copy_to_user(void __user *to,
 #define put_user(x, ptr)                                       \
 ({                                                             \
        might_sleep();                                          \
-       __access_ok(ptr, sizeof (*ptr)) ?                       \
+       access_ok(VERIFY_WRITE, ptr, sizeof(*ptr)) ?            \
                __put_user(x, ptr) :                            \
                -EFAULT;                                        \
 })
@@ -219,7 +219,7 @@ extern int __put_user_bad(void) __attribute__((noreturn));
 #define get_user(x, ptr)                                       \
 ({                                                             \
        might_sleep();                                          \
-       __access_ok(ptr, sizeof (*ptr)) ?                       \
+       access_ok(VERIFY_READ, ptr, sizeof(*ptr)) ?             \
                __get_user(x, ptr) :                            \
                -EFAULT;                                        \
 })
@@ -244,7 +244,7 @@ static inline long copy_from_user(void *to,
                const void __user * from, unsigned long n)
 {
        might_sleep();
-       if (__access_ok(from, n))
+       if (access_ok(VERIFY_READ, from, n))
                return __copy_from_user(to, from, n);
        else
                return n;
@@ -254,7 +254,7 @@ static inline long copy_to_user(void __user *to,
                const void *from, unsigned long n)
 {
        might_sleep();
-       if (__access_ok(to, n))
+       if (access_ok(VERIFY_WRITE, to, n))
                return __copy_to_user(to, from, n);
        else
                return n;
@@ -278,7 +278,7 @@ __strncpy_from_user(char *dst, const char __user *src, long count)
 static inline long
 strncpy_from_user(char *dst, const char __user *src, long count)
 {
-       if (!__access_ok(src, 1))
+       if (!access_ok(VERIFY_READ, src, 1))
                return -EFAULT;
        return __strncpy_from_user(dst, src, count);
 }
@@ -291,6 +291,8 @@ strncpy_from_user(char *dst, const char __user *src, long count)
 #ifndef strnlen_user
 static inline long strnlen_user(const char __user *src, long n)
 {
+       if (!access_ok(VERIFY_READ, src, 1))
+               return 0;
        return strlen((void * __force)src) + 1;
 }
 #endif
@@ -316,7 +318,7 @@ static inline __must_check unsigned long
 clear_user(void __user *to, unsigned long n)
 {
        might_sleep();
-       if (!__access_ok(to, n))
+       if (!access_ok(VERIFY_WRITE, to, n))
                return n;
 
        return __clear_user(to, n);
index 5b34b6233d6db6ce32fae64919e597d0bca54959..1125e5a1ee5d0fe67a89df67dc0f0c14a45f7c05 100644 (file)
@@ -618,8 +618,13 @@ __SYSCALL(__NR_migrate_pages, sys_migrate_pages)
 __SYSCALL(__NR_move_pages, sys_move_pages)
 #endif
 
+#define __NR_rt_tgsigqueueinfo 240
+__SYSCALL(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo)
+#define __NR_perf_counter_open 241
+__SYSCALL(__NR_perf_counter_open, sys_perf_counter_open)
+
 #undef __NR_syscalls
-#define __NR_syscalls 240
+#define __NR_syscalls 242
 
 /*
  * All syscalls below here should go away really,
index a05a5ef33391d0e2ef816666f2bb08ca10fba491..2723513a5651b493a27c41191aa7be3e04b5af60 100644 (file)
@@ -33,7 +33,7 @@ void hugetlb_report_meminfo(struct seq_file *);
 int hugetlb_report_node_meminfo(int, char *);
 unsigned long hugetlb_total_pages(void);
 int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
-                       unsigned long address, int write_access);
+                       unsigned long address, unsigned int flags);
 int hugetlb_reserve_pages(struct inode *inode, long from, long to,
                                                struct vm_area_struct *vma,
                                                int acctflags);
@@ -98,7 +98,7 @@ static inline void hugetlb_report_meminfo(struct seq_file *m)
 #define pud_huge(x)    0
 #define is_hugepage_only_range(mm, addr, len)  0
 #define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) ({BUG(); 0; })
-#define hugetlb_fault(mm, vma, addr, write)    ({ BUG(); 0; })
+#define hugetlb_fault(mm, vma, addr, flags)    ({ BUG(); 0; })
 
 #define hugetlb_change_protection(vma, address, end, newprot)
 
index f24eceecc5a602562e5b3d6d1dbae338df319633..8a025d510904609ec4b1b244f10a0d8cd7bdff8b 100644 (file)
@@ -348,6 +348,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_SQ905C   v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB 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 */
+#define V4L2_PIX_FMT_OV511    v4l2_fourcc('O', '5', '1', '1') /* ov511 JPEG */
 #define V4L2_PIX_FMT_OV518    v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */
 
 /*
@@ -894,9 +895,10 @@ enum v4l2_colorfx {
        V4L2_COLORFX_BW         = 1,
        V4L2_COLORFX_SEPIA      = 2,
 };
+#define V4L2_CID_AUTOBRIGHTNESS                        (V4L2_CID_BASE+32)
 
 /* last CID + 1 */
-#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+32)
+#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+33)
 
 /*  MPEG-class control IDs defined by V4L2 */
 #define V4L2_CID_MPEG_BASE                     (V4L2_CTRL_CLASS_MPEG | 0x900)
index 7b5b91f60425d687508856ee50444106b2e0cdff..9dcb632f608324d09e234fad008d427a422d59a7 100644 (file)
@@ -162,6 +162,8 @@ extern IR_KEYTAB_TYPE ir_codes_ati_tv_wonder_hd_600[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_kworld_plus_tv_analog[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_kaiomy[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_dm1105_nec[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_evga_indtube[IR_KEYTAB_SIZE];
+
 #endif
 
 /*
index c48c24e4d0fa44bb6b2df6f646a1fc37ca737a5d..33a18426ab9beea604899bfe5206ac063203a091 100644 (file)
@@ -153,6 +153,22 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct v4l2_device *v4l2_dev,
 struct v4l2_subdev *v4l2_i2c_new_probed_subdev_addr(struct v4l2_device *v4l2_dev,
                struct i2c_adapter *adapter,
                const char *module_name, const char *client_type, u8 addr);
+
+/* Load an i2c module and return an initialized v4l2_subdev struct.
+   Only call request_module if module_name != NULL.
+   The client_type argument is the name of the chip that's on the adapter. */
+struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
+               struct i2c_adapter *adapter,
+               const char *module_name, const char *client_type,
+               int irq, void *platform_data,
+               u8 addr, const unsigned short *probe_addrs);
+
+struct i2c_board_info;
+
+struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
+               struct i2c_adapter *adapter, const char *module_name,
+               struct i2c_board_info *info, const unsigned short *probe_addrs);
+
 /* Initialize an v4l2_subdev with data from an i2c_client struct */
 void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
                const struct v4l2_subdev_ops *ops);
@@ -193,4 +209,14 @@ struct v4l2_routing {
        u32 output;
 };
 
+/* ------------------------------------------------------------------------- */
+
+/* Miscellaneous helper functions */
+
+void v4l_bound_align_image(unsigned int *w, unsigned int wmin,
+                          unsigned int wmax, unsigned int walign,
+                          unsigned int *h, unsigned int hmin,
+                          unsigned int hmax, unsigned int halign,
+                          unsigned int salign);
+
 #endif /* V4L2_COMMON_H_ */
index 10a2882c3cbf295277328a9c3ca62cecee5b1054..74bf741d1a9be9f6d43da7a10664567ef5bc3989 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 /* NOTE: the full version of this header is in the v4l-dvb repository
- * and allows v4l i2c drivers to be compiled on older kernels as well.
+ * and allows v4l i2c drivers to be compiled on pre-2.6.26 kernels.
  * The version of this header as it appears in the kernel is a stripped
  * version (without all the backwards compatibility stuff) and so it
  * looks a bit odd.
@@ -30,6 +30,9 @@
  * If you look at the full version then you will understand the reason
  * for introducing this header since you really don't want to have all
  * the tricky backwards compatibility code in each and every i2c driver.
+ *
+ * If the i2c driver will never be compiled for pre-2.6.26 kernels, then
+ * DO NOT USE this header! Just write it as a regular i2c driver.
  */
 
 #ifndef __V4L2_I2C_DRV_H__
index a503e1cee78bd7e2554faf22310ff78db54c5a57..5dcb36785529152e266909526ff17f673c11cd18 100644 (file)
@@ -79,7 +79,11 @@ struct v4l2_decode_vbi_line {
    not yet implemented) since ops provide proper type-checking.
  */
 
-/* init: initialize the sensor registors to some sort of reasonable default
+/* s_config: if set, then it is always called by the v4l2_i2c_new_subdev*
+       functions after the v4l2_subdev was registered. It is used to pass
+       platform data to the subdev which can be used during initialization.
+
+   init: initialize the sensor registors to some sort of reasonable default
        values. Do not use for new drivers and should be removed in existing
        drivers.
 
@@ -96,6 +100,7 @@ struct v4l2_decode_vbi_line {
 struct v4l2_subdev_core_ops {
        int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip);
        int (*log_status)(struct v4l2_subdev *sd);
+       int (*s_config)(struct v4l2_subdev *sd, int irq, void *platform_data);
        int (*init)(struct v4l2_subdev *sd, u32 val);
        int (*load_fw)(struct v4l2_subdev *sd);
        int (*reset)(struct v4l2_subdev *sd, u32 val);
index 6300f556bce5fac629fb452852ea80791dfb38ad..a0ff61c3e935f4a18b32221b39b924e9e6fefb04 100644 (file)
@@ -107,7 +107,6 @@ static inline int fc_ct_fill(struct fc_lport *lport, struct fc_frame *fp,
                break;
 
        default:
-               FC_DBG("Invalid op code %x \n", op);
                return -EINVAL;
        }
        *r_ctl = FC_RCTL_DD_UNSOL_CTL;
@@ -298,7 +297,6 @@ static inline int fc_els_fill(struct fc_lport *lport, struct fc_rport *rport,
                break;
 
        default:
-               FC_DBG("Invalid op code %x \n", op);
                return -EINVAL;
        }
 
index ebdd9f4cf070da669c2b80a817c9b156e51f360e..b92584a8843ae5282131bc87f022ff897e7c6ad9 100644 (file)
 
 #include <scsi/fc_frame.h>
 
-#define LIBFC_DEBUG
-
-#ifdef LIBFC_DEBUG
-/* Log messages */
-#define FC_DBG(fmt, args...)                                           \
-       do {                                                            \
-               printk(KERN_INFO "%s " fmt, __func__, ##args);          \
-       } while (0)
-#else
-#define FC_DBG(fmt, args...)
-#endif
+#define FC_LIBFC_LOGGING 0x01 /* General logging, not categorized */
+#define FC_LPORT_LOGGING 0x02 /* lport layer logging */
+#define FC_DISC_LOGGING  0x04 /* discovery layer logging */
+#define FC_RPORT_LOGGING 0x08 /* rport layer logging */
+#define FC_FCP_LOGGING   0x10 /* I/O path logging */
+#define FC_EM_LOGGING    0x20 /* Exchange Manager logging */
+#define FC_EXCH_LOGGING  0x40 /* Exchange/Sequence logging */
+#define FC_SCSI_LOGGING  0x80 /* SCSI logging (mostly error handling) */
+
+extern unsigned int fc_debug_logging;
+
+#define FC_CHECK_LOGGING(LEVEL, CMD)                           \
+do {                                                           \
+       if (unlikely(fc_debug_logging & LEVEL))                 \
+               do {                                            \
+                       CMD;                                    \
+               } while (0);                                    \
+} while (0);
+
+#define FC_LIBFC_DBG(fmt, args...)                                     \
+       FC_CHECK_LOGGING(FC_LIBFC_LOGGING,                              \
+                        printk(KERN_INFO "libfc: " fmt, ##args);)
+
+#define FC_LPORT_DBG(lport, fmt, args...)                              \
+       FC_CHECK_LOGGING(FC_LPORT_LOGGING,                              \
+                        printk(KERN_INFO "lport: %6x: " fmt,           \
+                               fc_host_port_id(lport->host), ##args);)
+
+#define FC_DISC_DBG(disc, fmt, args...)                                        \
+       FC_CHECK_LOGGING(FC_DISC_LOGGING,                               \
+                        printk(KERN_INFO "disc: %6x: " fmt,            \
+                               fc_host_port_id(disc->lport->host),     \
+                               ##args);)
+
+#define FC_RPORT_DBG(rport, fmt, args...)                              \
+do {                                                                   \
+       struct fc_rport_libfc_priv *rdata = rport->dd_data;             \
+       struct fc_lport *lport = rdata->local_port;                     \
+       FC_CHECK_LOGGING(FC_RPORT_LOGGING,                              \
+                        printk(KERN_INFO "rport: %6x: %6x: " fmt,      \
+                               fc_host_port_id(lport->host),           \
+                               rport->port_id, ##args);)               \
+} while (0);
+
+#define FC_FCP_DBG(pkt, fmt, args...)                                  \
+       FC_CHECK_LOGGING(FC_FCP_LOGGING,                                \
+                        printk(KERN_INFO "fcp: %6x: %6x: " fmt,        \
+                               fc_host_port_id(pkt->lp->host),         \
+                               pkt->rport->port_id, ##args);)
+
+#define FC_EM_DBG(em, fmt, args...)                                    \
+       FC_CHECK_LOGGING(FC_EM_LOGGING,                                 \
+                        printk(KERN_INFO "em: %6x: " fmt,              \
+                               fc_host_port_id(em->lp->host),          \
+                               ##args);)
+
+#define FC_EXCH_DBG(exch, fmt, args...)                                        \
+       FC_CHECK_LOGGING(FC_EXCH_LOGGING,                               \
+                        printk(KERN_INFO "exch: %6x: %4x: " fmt,       \
+                               fc_host_port_id(exch->lp->host),        \
+                               exch->xid, ##args);)
+
+#define FC_SCSI_DBG(lport, fmt, args...)                               \
+       FC_CHECK_LOGGING(FC_SCSI_LOGGING,                               \
+                        printk(KERN_INFO "scsi: %6x: " fmt,            \
+                               fc_host_port_id(lport->host), ##args);)
 
 /*
  * libfc error codes
index 196525cd402f6a86d09d208557f03217dd9bc08a..61afeb59a8369ce3fdae108bae846589e80a9d02 100644 (file)
@@ -125,6 +125,10 @@ struct iscsi_task {
        struct scsi_cmnd        *sc;            /* associated SCSI cmd*/
        struct iscsi_conn       *conn;          /* used connection    */
 
+       /* data processing tracking */
+       unsigned long           last_xfer;
+       unsigned long           last_timeout;
+       bool                    have_checked_conn;
        /* state set/tested under session->lock */
        int                     state;
        atomic_t                refcount;
index 1f5ca7f621165797ff559203e99b5a1deebe1624..9fd6702f02e2ee540effd667c3af3e37f87e4b42 100644 (file)
@@ -32,5 +32,6 @@ int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req);
 int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req);
 int scsi_prep_state_check(struct scsi_device *sdev, struct request *req);
 int scsi_prep_return(struct request_queue *q, struct request *req, int ret);
+int scsi_prep_fn(struct request_queue *, struct request *);
 
 #endif /* _SCSI_SCSI_DRIVER_H */
index 23067ab1a73cdb471102e0b3b874d724396cf391..4c32b1a1a06e393ad5d8844cdbefa00994965c2a 100644 (file)
@@ -340,8 +340,6 @@ config DEBUG_KMEMLEAK
        bool "Kernel memory leak detector"
        depends on DEBUG_KERNEL && EXPERIMENTAL && (X86 || ARM) && \
                !MEMORY_HOTPLUG
-       select DEBUG_SLAB if SLAB
-       select SLUB_DEBUG if SLUB
        select DEBUG_FS if SYSFS
        select STACKTRACE if STACKTRACE_SUPPORT
        select KALLSYMS
@@ -355,6 +353,9 @@ config DEBUG_KMEMLEAK
          allocations. See Documentation/kmemleak.txt for more
          details.
 
+         Enabling DEBUG_SLAB or SLUB_DEBUG may increase the chances
+         of finding leaks due to the slab objects poisoning.
+
          In order to access the kmemleak file, debugfs needs to be
          mounted (usually at /sys/kernel/debug).
 
index 12e5a1c91cdab8134a88c921236f1559aca5a99b..b2e2fd4684618341adaff20dea8d04edfd99ec90 100644 (file)
@@ -55,7 +55,11 @@ static unsigned int do_csum(const unsigned char *buff, int len)
                goto out;
        odd = 1 & (unsigned long) buff;
        if (odd) {
+#ifdef __LITTLE_ENDIAN
                result = *buff;
+#else
+               result += (*buff << 8);
+#endif
                len--;
                buff++;
        }
@@ -71,7 +75,7 @@ static unsigned int do_csum(const unsigned char *buff, int len)
                if (count) {
                        unsigned long carry = 0;
                        do {
-                               unsigned long w = *(unsigned long *) buff;
+                               unsigned long w = *(unsigned int *) buff;
                                count--;
                                buff += 4;
                                result += carry;
@@ -87,7 +91,11 @@ static unsigned int do_csum(const unsigned char *buff, int len)
                }
        }
        if (len & 1)
+#ifdef __LITTLE_ENDIAN
+               result += *buff;
+#else
                result += (*buff << 8);
+#endif
        result = from32to16(result);
        if (odd)
                result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
index a56e6f3ce97937bc3d28713f67555cf890dc9069..d0351e31f474aa15a275c303b2f797e5d437c226 100644 (file)
@@ -1985,7 +1985,7 @@ static struct page *hugetlbfs_pagecache_page(struct hstate *h,
 }
 
 static int hugetlb_no_page(struct mm_struct *mm, struct vm_area_struct *vma,
-                       unsigned long address, pte_t *ptep, int write_access)
+                       unsigned long address, pte_t *ptep, unsigned int flags)
 {
        struct hstate *h = hstate_vma(vma);
        int ret = VM_FAULT_SIGBUS;
@@ -2053,7 +2053,7 @@ retry:
         * any allocations necessary to record that reservation occur outside
         * the spinlock.
         */
-       if (write_access && !(vma->vm_flags & VM_SHARED))
+       if ((flags & FAULT_FLAG_WRITE) && !(vma->vm_flags & VM_SHARED))
                if (vma_needs_reservation(h, vma, address) < 0) {
                        ret = VM_FAULT_OOM;
                        goto backout_unlocked;
@@ -2072,7 +2072,7 @@ retry:
                                && (vma->vm_flags & VM_SHARED)));
        set_huge_pte_at(mm, address, ptep, new_pte);
 
-       if (write_access && !(vma->vm_flags & VM_SHARED)) {
+       if ((flags & FAULT_FLAG_WRITE) && !(vma->vm_flags & VM_SHARED)) {
                /* Optimization, do the COW without a second fault */
                ret = hugetlb_cow(mm, vma, address, ptep, new_pte, page);
        }
@@ -2091,7 +2091,7 @@ backout_unlocked:
 }
 
 int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
-                       unsigned long address, int write_access)
+                       unsigned long address, unsigned int flags)
 {
        pte_t *ptep;
        pte_t entry;
@@ -2112,7 +2112,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        mutex_lock(&hugetlb_instantiation_mutex);
        entry = huge_ptep_get(ptep);
        if (huge_pte_none(entry)) {
-               ret = hugetlb_no_page(mm, vma, address, ptep, write_access);
+               ret = hugetlb_no_page(mm, vma, address, ptep, flags);
                goto out_mutex;
        }
 
@@ -2126,7 +2126,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
         * page now as it is used to determine if a reservation has been
         * consumed.
         */
-       if (write_access && !pte_write(entry)) {
+       if ((flags & FAULT_FLAG_WRITE) && !pte_write(entry)) {
                if (vma_needs_reservation(h, vma, address) < 0) {
                        ret = VM_FAULT_OOM;
                        goto out_mutex;
@@ -2143,7 +2143,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                goto out_page_table_lock;
 
 
-       if (write_access) {
+       if (flags & FAULT_FLAG_WRITE) {
                if (!pte_write(entry)) {
                        ret = hugetlb_cow(mm, vma, address, ptep, entry,
                                                        pagecache_page);
@@ -2152,7 +2152,8 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                entry = pte_mkdirty(entry);
        }
        entry = pte_mkyoung(entry);
-       if (huge_ptep_set_access_flags(vma, address, ptep, entry, write_access))
+       if (huge_ptep_set_access_flags(vma, address, ptep, entry,
+                                               flags & FAULT_FLAG_WRITE))
                update_mmu_cache(vma, address, entry);
 
 out_page_table_lock:
index ec759b60077a22c4c11f6fe813976930bb9e1905..c96f2c8700aa687f5726eaed2e26a5ccd9d35d87 100644 (file)
@@ -61,6 +61,8 @@
  * structure.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
@@ -311,7 +313,7 @@ static int unreferenced_object(struct kmemleak_object *object)
 
 static void print_referenced(struct kmemleak_object *object)
 {
-       pr_info("kmemleak: referenced object 0x%08lx (size %zu)\n",
+       pr_info("referenced object 0x%08lx (size %zu)\n",
                object->pointer, object->size);
 }
 
@@ -320,7 +322,7 @@ static void print_unreferenced(struct seq_file *seq,
 {
        int i;
 
-       print_helper(seq, "kmemleak: unreferenced object 0x%08lx (size %zu):\n",
+       print_helper(seq, "unreferenced object 0x%08lx (size %zu):\n",
                     object->pointer, object->size);
        print_helper(seq, "  comm \"%s\", pid %d, jiffies %lu\n",
                     object->comm, object->pid, object->jiffies);
@@ -344,7 +346,7 @@ static void dump_object_info(struct kmemleak_object *object)
        trace.nr_entries = object->trace_len;
        trace.entries = object->trace;
 
-       pr_notice("kmemleak: Object 0x%08lx (size %zu):\n",
+       pr_notice("Object 0x%08lx (size %zu):\n",
                  object->tree_node.start, object->size);
        pr_notice("  comm \"%s\", pid %d, jiffies %lu\n",
                  object->comm, object->pid, object->jiffies);
@@ -372,7 +374,7 @@ static struct kmemleak_object *lookup_object(unsigned long ptr, int alias)
                object = prio_tree_entry(node, struct kmemleak_object,
                                         tree_node);
                if (!alias && object->pointer != ptr) {
-                       kmemleak_warn("kmemleak: Found object by alias");
+                       kmemleak_warn("Found object by alias");
                        object = NULL;
                }
        } else
@@ -467,8 +469,7 @@ static void create_object(unsigned long ptr, size_t size, int min_count,
 
        object = kmem_cache_alloc(object_cache, gfp & GFP_KMEMLEAK_MASK);
        if (!object) {
-               kmemleak_stop("kmemleak: Cannot allocate a kmemleak_object "
-                             "structure\n");
+               kmemleak_stop("Cannot allocate a kmemleak_object structure\n");
                return;
        }
 
@@ -527,8 +528,8 @@ static void create_object(unsigned long ptr, size_t size, int min_count,
        if (node != &object->tree_node) {
                unsigned long flags;
 
-               kmemleak_stop("kmemleak: Cannot insert 0x%lx into the object "
-                             "search tree (already existing)\n", ptr);
+               kmemleak_stop("Cannot insert 0x%lx into the object search tree "
+                             "(already existing)\n", ptr);
                object = lookup_object(ptr, 1);
                spin_lock_irqsave(&object->lock, flags);
                dump_object_info(object);
@@ -553,7 +554,7 @@ static void delete_object(unsigned long ptr)
        write_lock_irqsave(&kmemleak_lock, flags);
        object = lookup_object(ptr, 0);
        if (!object) {
-               kmemleak_warn("kmemleak: Freeing unknown object at 0x%08lx\n",
+               kmemleak_warn("Freeing unknown object at 0x%08lx\n",
                              ptr);
                write_unlock_irqrestore(&kmemleak_lock, flags);
                return;
@@ -588,8 +589,7 @@ static void make_gray_object(unsigned long ptr)
 
        object = find_and_get_object(ptr, 0);
        if (!object) {
-               kmemleak_warn("kmemleak: Graying unknown object at 0x%08lx\n",
-                             ptr);
+               kmemleak_warn("Graying unknown object at 0x%08lx\n", ptr);
                return;
        }
 
@@ -610,8 +610,7 @@ static void make_black_object(unsigned long ptr)
 
        object = find_and_get_object(ptr, 0);
        if (!object) {
-               kmemleak_warn("kmemleak: Blacking unknown object at 0x%08lx\n",
-                             ptr);
+               kmemleak_warn("Blacking unknown object at 0x%08lx\n", ptr);
                return;
        }
 
@@ -634,21 +633,20 @@ static void add_scan_area(unsigned long ptr, unsigned long offset,
 
        object = find_and_get_object(ptr, 0);
        if (!object) {
-               kmemleak_warn("kmemleak: Adding scan area to unknown "
-                             "object at 0x%08lx\n", ptr);
+               kmemleak_warn("Adding scan area to unknown object at 0x%08lx\n",
+                             ptr);
                return;
        }
 
        area = kmem_cache_alloc(scan_area_cache, gfp & GFP_KMEMLEAK_MASK);
        if (!area) {
-               kmemleak_warn("kmemleak: Cannot allocate a scan area\n");
+               kmemleak_warn("Cannot allocate a scan area\n");
                goto out;
        }
 
        spin_lock_irqsave(&object->lock, flags);
        if (offset + length > object->size) {
-               kmemleak_warn("kmemleak: Scan area larger than object "
-                             "0x%08lx\n", ptr);
+               kmemleak_warn("Scan area larger than object 0x%08lx\n", ptr);
                dump_object_info(object);
                kmem_cache_free(scan_area_cache, area);
                goto out_unlock;
@@ -677,8 +675,7 @@ static void object_no_scan(unsigned long ptr)
 
        object = find_and_get_object(ptr, 0);
        if (!object) {
-               kmemleak_warn("kmemleak: Not scanning unknown object at "
-                             "0x%08lx\n", ptr);
+               kmemleak_warn("Not scanning unknown object at 0x%08lx\n", ptr);
                return;
        }
 
@@ -699,7 +696,7 @@ static void log_early(int op_type, const void *ptr, size_t size,
        struct early_log *log;
 
        if (crt_early_log >= ARRAY_SIZE(early_log)) {
-               kmemleak_stop("kmemleak: Early log buffer exceeded\n");
+               kmemleak_stop("Early log buffer exceeded\n");
                return;
        }
 
@@ -966,7 +963,7 @@ static void kmemleak_scan(void)
                 * 1 reference to any object at this point.
                 */
                if (atomic_read(&object->use_count) > 1) {
-                       pr_debug("kmemleak: object->use_count = %d\n",
+                       pr_debug("object->use_count = %d\n",
                                 atomic_read(&object->use_count));
                        dump_object_info(object);
                }
@@ -1062,7 +1059,7 @@ static int kmemleak_scan_thread(void *arg)
 {
        static int first_run = 1;
 
-       pr_info("kmemleak: Automatic memory scanning thread started\n");
+       pr_info("Automatic memory scanning thread started\n");
 
        /*
         * Wait before the first scan to allow the system to fully initialize.
@@ -1108,7 +1105,7 @@ static int kmemleak_scan_thread(void *arg)
                        timeout = schedule_timeout_interruptible(timeout);
        }
 
-       pr_info("kmemleak: Automatic memory scanning thread ended\n");
+       pr_info("Automatic memory scanning thread ended\n");
 
        return 0;
 }
@@ -1123,7 +1120,7 @@ void start_scan_thread(void)
                return;
        scan_thread = kthread_run(kmemleak_scan_thread, NULL, "kmemleak");
        if (IS_ERR(scan_thread)) {
-               pr_warning("kmemleak: Failed to create the scan thread\n");
+               pr_warning("Failed to create the scan thread\n");
                scan_thread = NULL;
        }
 }
@@ -1367,7 +1364,7 @@ static void kmemleak_cleanup(void)
        cleanup_thread = kthread_run(kmemleak_cleanup_thread, NULL,
                                     "kmemleak-clean");
        if (IS_ERR(cleanup_thread))
-               pr_warning("kmemleak: Failed to create the clean-up thread\n");
+               pr_warning("Failed to create the clean-up thread\n");
 }
 
 /*
@@ -1488,8 +1485,7 @@ static int __init kmemleak_late_init(void)
        dentry = debugfs_create_file("kmemleak", S_IRUGO, NULL, NULL,
                                     &kmemleak_fops);
        if (!dentry)
-               pr_warning("kmemleak: Failed to create the debugfs kmemleak "
-                          "file\n");
+               pr_warning("Failed to create the debugfs kmemleak file\n");
        mutex_lock(&kmemleak_mutex);
        start_scan_thread();
        mutex_unlock(&kmemleak_mutex);
index 98bcb90d5957010ada3218c06117cc797aa81813..50da9511aa776dd7fb005581454a9b2becdccb9f 100644 (file)
@@ -1311,8 +1311,10 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                        while (!(page = follow_page(vma, start, foll_flags))) {
                                int ret;
 
-                               /* FOLL_WRITE matches FAULT_FLAG_WRITE! */
-                               ret = handle_mm_fault(mm, vma, start, foll_flags & FOLL_WRITE);
+                               ret = handle_mm_fault(mm, vma, start,
+                                       (foll_flags & FOLL_WRITE) ?
+                                       FAULT_FLAG_WRITE : 0);
+
                                if (ret & VM_FAULT_ERROR) {
                                        if (ret & VM_FAULT_OOM)
                                                return i ? i : -ENOMEM;
index e8fa2d9eb212d7cfb739f02305a340fbf023565d..54155268dfcae49634dc016bb168845600a866a0 100644 (file)
@@ -932,7 +932,7 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
                                continue;
                        if (__isolate_lru_page(cursor_page, mode, file) == 0) {
                                list_move(&cursor_page->lru, dst);
-                               mem_cgroup_del_lru(page);
+                               mem_cgroup_del_lru(cursor_page);
                                nr_taken++;
                                scan++;
                        }
index 84da3ba17c86911b0d48799772bd0c0960c90693..ac2150e0670d8541e4023fb21fdb600e4bef6df8 100644 (file)
@@ -320,7 +320,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
                     snd_mask_max(&params->masks[SNDRV_PCM_HW_PARAM_CHANNELS])) {
                        changed = substream->ops->ioctl(substream,
                                        SNDRV_PCM_IOCTL1_FIFO_SIZE, params);
-                       if (params < 0)
+                       if (changed < 0)
                                return changed;
                }
        }
index 8284f176a342c6011f470a9d27581438ba23c73a..b5d6ea4904c091c9b2733308d380cdaa995fe98d 100644 (file)
@@ -504,10 +504,10 @@ static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf,
        if (dev->nostat && count < 12)
                return -ENOMEM;
        cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f);
-       bytes[0] = ev->data.control.param & 0x007f;
-       bytes[1] = (ev->data.control.param & 0x3f80) >> 7;
-       bytes[2] = ev->data.control.value & 0x007f;
-       bytes[3] = (ev->data.control.value & 0x3f80) >> 7;
+       bytes[0] = (ev->data.control.param & 0x3f80) >> 7;
+       bytes[1] = ev->data.control.param & 0x007f;
+       bytes[2] = (ev->data.control.value & 0x3f80) >> 7;
+       bytes[3] = ev->data.control.value & 0x007f;
        if (cmd != dev->lastcmd && !dev->nostat) {
                if (count < 9)
                        return -ENOMEM;
index b0adc8094009912d00db252f7388680299475f7e..a49c766473073e1a6d94b7ed75ed014fd0c2c293 100644 (file)
@@ -46,8 +46,6 @@ static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = {
        SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0031, "SB073x", CTSB073X),
        SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, 0x6000,
                           "UAA", CTUAA),
-       SND_PCI_QUIRK_VENDOR(PCI_VENDOR_ID_CREATIVE,
-                            "Unknown", CT20K1_UNKNOWN),
        { } /* terminator */
 };
 
@@ -67,13 +65,16 @@ static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = {
 };
 
 static const char *ct_subsys_name[NUM_CTCARDS] = {
+       /* 20k1 models */
        [CTSB055X]      = "SB055x",
        [CTSB073X]      = "SB073x",
-       [CTSB0760]      = "SB076x",
        [CTUAA]         = "UAA",
        [CT20K1_UNKNOWN] = "Unknown",
+       /* 20k2 models */
+       [CTSB0760]      = "SB076x",
        [CTHENDRIX]     = "Hendrix",
        [CTSB0880]      = "SB0880",
+       [CT20K2_UNKNOWN] = "Unknown",
 };
 
 static struct {
@@ -260,13 +261,8 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        int device = apcm->substream->pcm->device;
        unsigned int pitch;
 
-       if (NULL != apcm->src) {
-               /* Prepared pcm playback */
-               return 0;
-       }
-
        /* first release old resources */
-       atc->pcm_release_resources(atc, apcm);
+       atc_pcm_release_resources(atc, apcm);
 
        /* Get SRC resource */
        desc.multi = apcm->substream->runtime->channels;
@@ -660,10 +656,7 @@ static int atc_pcm_capture_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        unsigned int pitch;
        int mix_base = 0, imp_base = 0;
 
-       if (NULL != apcm->src) {
-               /* Prepared pcm capture */
-               return 0;
-       }
+       atc_pcm_release_resources(atc, apcm);
 
        /* Get needed resources. */
        err = atc_pcm_capture_get_resources(atc, apcm);
@@ -866,7 +859,7 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
        unsigned int rate = apcm->substream->runtime->rate;
        unsigned int status;
-       int err;
+       int err = 0;
        unsigned char iec958_con_fs;
 
        switch (rate) {
@@ -907,8 +900,7 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        int err;
        int i;
 
-       if (NULL != apcm->src)
-               return 0;
+       atc_pcm_release_resources(atc, apcm);
 
        /* Configure SPDIFOO and PLL to passthrough mode;
         * determine pll_rate. */
@@ -1115,32 +1107,20 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state)
        return err;
 }
 
-static int ct_atc_destroy(struct ct_atc *atc)
+static int atc_release_resources(struct ct_atc *atc)
 {
-       struct daio_mgr *daio_mgr;
-       struct dao *dao;
-       struct dai *dai;
-       struct daio *daio;
-       struct sum_mgr *sum_mgr;
-       struct src_mgr *src_mgr;
-       struct srcimp_mgr *srcimp_mgr;
-       struct srcimp *srcimp;
-       struct ct_mixer *mixer;
-       int i = 0;
-
-       if (NULL == atc)
-               return 0;
-
-       if (atc->timer) {
-               ct_timer_free(atc->timer);
-               atc->timer = NULL;
-       }
-
-       /* Stop hardware and disable all interrupts */
-       if (NULL != atc->hw)
-               ((struct hw *)atc->hw)->card_stop(atc->hw);
-
-       /* Destroy internal mixer objects */
+       int i;
+       struct daio_mgr *daio_mgr = NULL;
+       struct dao *dao = NULL;
+       struct dai *dai = NULL;
+       struct daio *daio = NULL;
+       struct sum_mgr *sum_mgr = NULL;
+       struct src_mgr *src_mgr = NULL;
+       struct srcimp_mgr *srcimp_mgr = NULL;
+       struct srcimp *srcimp = NULL;
+       struct ct_mixer *mixer = NULL;
+
+       /* disconnect internal mixer objects */
        if (NULL != atc->mixer) {
                mixer = atc->mixer;
                mixer->set_input_left(mixer, MIX_LINE_IN, NULL);
@@ -1149,7 +1129,6 @@ static int ct_atc_destroy(struct ct_atc *atc)
                mixer->set_input_right(mixer, MIX_MIC_IN, NULL);
                mixer->set_input_left(mixer, MIX_SPDIF_IN, NULL);
                mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL);
-               ct_mixer_destroy(atc->mixer);
        }
 
        if (NULL != atc->daios) {
@@ -1167,6 +1146,7 @@ static int ct_atc_destroy(struct ct_atc *atc)
                        daio_mgr->put_daio(daio_mgr, daio);
                }
                kfree(atc->daios);
+               atc->daios = NULL;
        }
 
        if (NULL != atc->pcm) {
@@ -1175,6 +1155,7 @@ static int ct_atc_destroy(struct ct_atc *atc)
                        sum_mgr->put_sum(sum_mgr, atc->pcm[i]);
 
                kfree(atc->pcm);
+               atc->pcm = NULL;
        }
 
        if (NULL != atc->srcs) {
@@ -1183,6 +1164,7 @@ static int ct_atc_destroy(struct ct_atc *atc)
                        src_mgr->put_src(src_mgr, atc->srcs[i]);
 
                kfree(atc->srcs);
+               atc->srcs = NULL;
        }
 
        if (NULL != atc->srcimps) {
@@ -1193,8 +1175,30 @@ static int ct_atc_destroy(struct ct_atc *atc)
                        srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]);
                }
                kfree(atc->srcimps);
+               atc->srcimps = NULL;
+       }
+
+       return 0;
+}
+
+static int ct_atc_destroy(struct ct_atc *atc)
+{
+       int i = 0;
+
+       if (NULL == atc)
+               return 0;
+
+       if (atc->timer) {
+               ct_timer_free(atc->timer);
+               atc->timer = NULL;
        }
 
+       atc_release_resources(atc);
+
+       /* Destroy internal mixer objects */
+       if (NULL != atc->mixer)
+               ct_mixer_destroy(atc->mixer);
+
        for (i = 0; i < NUM_RSCTYP; i++) {
                if ((NULL != rsc_mgr_funcs[i].destroy) &&
                    (NULL != atc->rsc_mgrs[i]))
@@ -1240,9 +1244,21 @@ static int __devinit atc_identify_card(struct ct_atc *atc)
                return -ENOENT;
        }
        p = snd_pci_quirk_lookup(atc->pci, list);
-       if (!p)
-               return -ENOENT;
-       atc->model = p->value;
+       if (p) {
+               if (p->value < 0) {
+                       printk(KERN_ERR "ctxfi: "
+                              "Device %04x:%04x is black-listed\n",
+                              atc->pci->subsystem_vendor,
+                              atc->pci->subsystem_device);
+                       return -ENOENT;
+               }
+               atc->model = p->value;
+       } else {
+               if (atc->chip_type == ATC20K1)
+                       atc->model = CT20K1_UNKNOWN;
+               else
+                       atc->model = CT20K2_UNKNOWN;
+       }
        atc->model_name = ct_subsys_name[atc->model];
        snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n",
                   atc->chip_name, atc->model_name,
@@ -1310,7 +1326,7 @@ static int __devinit atc_create_hw_devs(struct ct_atc *atc)
        return 0;
 }
 
-static int __devinit atc_get_resources(struct ct_atc *atc)
+static int atc_get_resources(struct ct_atc *atc)
 {
        struct daio_desc da_desc = {0};
        struct daio_mgr *daio_mgr;
@@ -1407,16 +1423,10 @@ static int __devinit atc_get_resources(struct ct_atc *atc)
                atc->n_pcm++;
        }
 
-       err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer);
-       if (err) {
-               printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n");
-               return err;
-       }
-
        return 0;
 }
 
-static void __devinit
+static void
 atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai,
                struct src **srcs, struct srcimp **srcimps)
 {
@@ -1455,7 +1465,7 @@ atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai,
        src_mgr->commit_write(src_mgr); /* Synchronously enable SRCs */
 }
 
-static void __devinit atc_connect_resources(struct ct_atc *atc)
+static void atc_connect_resources(struct ct_atc *atc)
 {
        struct dai *dai;
        struct dao *dao;
@@ -1501,6 +1511,84 @@ static void __devinit atc_connect_resources(struct ct_atc *atc)
        }
 }
 
+#ifdef CONFIG_PM
+static int atc_suspend(struct ct_atc *atc, pm_message_t state)
+{
+       int i;
+       struct hw *hw = atc->hw;
+
+       snd_power_change_state(atc->card, SNDRV_CTL_POWER_D3hot);
+
+       for (i = FRONT; i < NUM_PCMS; i++) {
+               if (!atc->pcms[i])
+                       continue;
+
+               snd_pcm_suspend_all(atc->pcms[i]);
+       }
+
+       atc_release_resources(atc);
+
+       hw->suspend(hw, state);
+
+       return 0;
+}
+
+static int atc_hw_resume(struct ct_atc *atc)
+{
+       struct hw *hw = atc->hw;
+       struct card_conf info = {0};
+
+       /* Re-initialize card hardware. */
+       info.rsr = atc->rsr;
+       info.msr = atc->msr;
+       info.vm_pgt_phys = atc_get_ptp_phys(atc, 0);
+       return hw->resume(hw, &info);
+}
+
+static int atc_resources_resume(struct ct_atc *atc)
+{
+       struct ct_mixer *mixer;
+       int err = 0;
+
+       /* Get resources */
+       err = atc_get_resources(atc);
+       if (err < 0) {
+               atc_release_resources(atc);
+               return err;
+       }
+
+       /* Build topology */
+       atc_connect_resources(atc);
+
+       mixer = atc->mixer;
+       mixer->resume(mixer);
+
+       return 0;
+}
+
+static int atc_resume(struct ct_atc *atc)
+{
+       int err = 0;
+
+       /* Do hardware resume. */
+       err = atc_hw_resume(atc);
+       if (err < 0) {
+               printk(KERN_ERR "ctxfi: pci_enable_device failed, "
+                      "disabling device\n");
+               snd_card_disconnect(atc->card);
+               return err;
+       }
+
+       err = atc_resources_resume(atc);
+       if (err < 0)
+               return err;
+
+       snd_power_change_state(atc->card, SNDRV_CTL_POWER_D0);
+
+       return 0;
+}
+#endif
+
 static struct ct_atc atc_preset __devinitdata = {
        .map_audio_buffer = ct_map_audio_buffer,
        .unmap_audio_buffer = ct_unmap_audio_buffer,
@@ -1529,6 +1617,10 @@ static struct ct_atc atc_preset __devinitdata = {
        .spdif_out_set_status = atc_spdif_out_set_status,
        .spdif_out_passthru = atc_spdif_out_passthru,
        .have_digit_io_switch = atc_have_digit_io_switch,
+#ifdef CONFIG_PM
+       .suspend = atc_suspend,
+       .resume = atc_resume,
+#endif
 };
 
 /**
@@ -1587,6 +1679,12 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
        if (err < 0)
                goto error1;
 
+       err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer);
+       if (err) {
+               printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n");
+               goto error1;
+       }
+
        /* Get resources */
        err = atc_get_resources(atc);
        if (err < 0)
index 9fe620ea5f3f3bc1ab38125e111c46e134fd2f34..9fd8a57089434d3c16b178664a8980aaa88836c7 100644 (file)
@@ -136,6 +136,13 @@ struct ct_atc {
        unsigned char n_pcm;
 
        struct ct_timer *timer;
+
+#ifdef CONFIG_PM
+       int (*suspend)(struct ct_atc *atc, pm_message_t state);
+       int (*resume)(struct ct_atc *atc);
+#define NUM_PCMS (NUM_CTALSADEVS - 1)
+       struct snd_pcm *pcms[NUM_PCMS];
+#endif
 };
 
 
index 4a8e04f090a4fd0737675db01e8cd3148b0ee69d..af55405f5dec81b0e5d4f7b7829c9ea981b5ee77 100644 (file)
@@ -30,13 +30,16 @@ enum CHIPTYP {
 enum CTCARDS {
        /* 20k1 models */
        CTSB055X,
+       CT20K1_MODEL_FIRST = CTSB055X,
        CTSB073X,
        CTUAA,
        CT20K1_UNKNOWN,
        /* 20k2 models */
        CTSB0760,
+       CT20K2_MODEL_FIRST = CTSB0760,
        CTHENDRIX,
        CTSB0880,
+       CT20K2_UNKNOWN,
        NUM_CTCARDS             /* This should always be the last */
 };
 
@@ -61,6 +64,10 @@ struct hw {
        int (*card_init)(struct hw *hw, struct card_conf *info);
        int (*card_stop)(struct hw *hw);
        int (*pll_init)(struct hw *hw, unsigned int rsr);
+#ifdef CONFIG_PM
+       int (*suspend)(struct hw *hw, pm_message_t state);
+       int (*resume)(struct hw *hw, struct card_conf *info);
+#endif
        int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source);
        int (*select_adc_source)(struct hw *hw, enum ADCSRC source);
        int (*have_digit_io_switch)(struct hw *hw);
index cb69d9ddfbe3d2b61821bc7f700c3c84c05cd213..ad3e1d144464ce639ad8f01f6b5883ab495b2281 100644 (file)
@@ -1911,9 +1911,17 @@ static int hw_card_start(struct hw *hw)
                goto error1;
        }
 
-       err = pci_request_regions(pci, "XFi");
-       if (err < 0)
-               goto error1;
+       if (!hw->io_base) {
+               err = pci_request_regions(pci, "XFi");
+               if (err < 0)
+                       goto error1;
+
+               if (hw->model == CTUAA)
+                       hw->io_base = pci_resource_start(pci, 5);
+               else
+                       hw->io_base = pci_resource_start(pci, 0);
+
+       }
 
        /* Switch to X-Fi mode from UAA mode if neeeded */
        if (hw->model == CTUAA) {
@@ -1921,18 +1929,17 @@ static int hw_card_start(struct hw *hw)
                if (err)
                        goto error2;
 
-               hw->io_base = pci_resource_start(pci, 5);
-       } else {
-               hw->io_base = pci_resource_start(pci, 0);
        }
 
-       err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED,
-                         "ctxfi", hw);
-       if (err < 0) {
-               printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
-               goto error2;
+       if (hw->irq < 0) {
+               err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED,
+                                 "ctxfi", hw);
+               if (err < 0) {
+                       printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
+                       goto error2;
+               }
+               hw->irq = pci->irq;
        }
-       hw->irq = pci->irq;
 
        pci_set_master(pci);
 
@@ -1948,6 +1955,15 @@ error1:
 
 static int hw_card_stop(struct hw *hw)
 {
+       unsigned int data;
+
+       /* disable transport bus master and queueing of request */
+       hw_write_20kx(hw, TRNCTL, 0x00);
+
+       /* disable pll */
+       data = hw_read_20kx(hw, PLLCTL);
+       hw_write_20kx(hw, PLLCTL, (data & (~(0x0F<<12))));
+
        /* TODO: Disable interrupt and so on... */
        if (hw->irq >= 0)
                synchronize_irq(hw->irq);
@@ -1987,11 +2003,9 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
        struct trn_conf trn_info = {0};
 
        /* Get PCI io port base address and do Hendrix switch if needed. */
-       if (!hw->io_base) {
-               err = hw_card_start(hw);
-               if (err)
-                       return err;
-       }
+       err = hw_card_start(hw);
+       if (err)
+               return err;
 
        /* PLL init */
        err = hw_pll_init(hw, info->rsr);
@@ -2064,6 +2078,37 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int hw_suspend(struct hw *hw, pm_message_t state)
+{
+       struct pci_dev *pci = hw->pci;
+
+       hw_card_stop(hw);
+
+       if (hw->model == CTUAA) {
+               /* Switch to UAA config space. */
+               pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x0);
+       }
+
+       pci_disable_device(pci);
+       pci_save_state(pci);
+       pci_set_power_state(pci, pci_choose_state(pci, state));
+
+       return 0;
+}
+
+static int hw_resume(struct hw *hw, struct card_conf *info)
+{
+       struct pci_dev *pci = hw->pci;
+
+       pci_set_power_state(pci, PCI_D0);
+       pci_restore_state(pci);
+
+       /* Re-initialize card hardware. */
+       return hw_card_init(hw, info);
+}
+#endif
+
 static u32 hw_read_20kx(struct hw *hw, u32 reg)
 {
        u32 value;
@@ -2128,6 +2173,10 @@ static struct hw ct20k1_preset __devinitdata = {
        .is_adc_source_selected = hw_is_adc_input_selected,
        .select_adc_source = hw_adc_input_select,
        .have_digit_io_switch = hw_have_digit_io_switch,
+#ifdef CONFIG_PM
+       .suspend = hw_suspend,
+       .resume = hw_resume,
+#endif
 
        .src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk,
        .src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk,
index 4493a51c6b018454eb3fbe200f7e8f43eb46485e..dec46d04b041c7e33072d484f6eedd70b0f4b974 100644 (file)
@@ -1860,16 +1860,18 @@ static int hw_card_start(struct hw *hw)
                goto error1;
        }
 
-       err = pci_request_regions(pci, "XFi");
-       if (err < 0)
-               goto error1;
+       if (!hw->io_base) {
+               err = pci_request_regions(pci, "XFi");
+               if (err < 0)
+                       goto error1;
 
-       hw->io_base = pci_resource_start(hw->pci, 2);
-       hw->mem_base = (unsigned long)ioremap(hw->io_base,
+               hw->io_base = pci_resource_start(hw->pci, 2);
+               hw->mem_base = (unsigned long)ioremap(hw->io_base,
                                        pci_resource_len(hw->pci, 2));
-       if (NULL == (void *)hw->mem_base) {
-               err = -ENOENT;
-               goto error2;
+               if (NULL == (void *)hw->mem_base) {
+                       err = -ENOENT;
+                       goto error2;
+               }
        }
 
        /* Switch to 20k2 mode from UAA mode. */
@@ -1901,6 +1903,15 @@ error1:
 
 static int hw_card_stop(struct hw *hw)
 {
+       unsigned int data;
+
+       /* disable transport bus master and queueing of request */
+       hw_write_20kx(hw, TRANSPORT_CTL, 0x00);
+
+       /* disable pll */
+       data = hw_read_20kx(hw, PLL_ENB);
+       hw_write_20kx(hw, PLL_ENB, (data & (~0x07)));
+
        /* TODO: Disable interrupt and so on... */
        return 0;
 }
@@ -1939,11 +1950,9 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
 
        /* Get PCI io port/memory base address and
         * do 20kx core switch if needed. */
-       if (!hw->io_base) {
-               err = hw_card_start(hw);
-               if (err)
-                       return err;
-       }
+       err = hw_card_start(hw);
+       if (err)
+               return err;
 
        /* PLL init */
        err = hw_pll_init(hw, info->rsr);
@@ -2006,6 +2015,32 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int hw_suspend(struct hw *hw, pm_message_t state)
+{
+       struct pci_dev *pci = hw->pci;
+
+       hw_card_stop(hw);
+
+       pci_disable_device(pci);
+       pci_save_state(pci);
+       pci_set_power_state(pci, pci_choose_state(pci, state));
+
+       return 0;
+}
+
+static int hw_resume(struct hw *hw, struct card_conf *info)
+{
+       struct pci_dev *pci = hw->pci;
+
+       pci_set_power_state(pci, PCI_D0);
+       pci_restore_state(pci);
+
+       /* Re-initialize card hardware. */
+       return hw_card_init(hw, info);
+}
+#endif
+
 static u32 hw_read_20kx(struct hw *hw, u32 reg)
 {
        return readl((void *)(hw->mem_base + reg));
@@ -2025,6 +2060,10 @@ static struct hw ct20k2_preset __devinitdata = {
        .is_adc_source_selected = hw_is_adc_input_selected,
        .select_adc_source = hw_adc_input_select,
        .have_digit_io_switch = hw_have_digit_io_switch,
+#ifdef CONFIG_PM
+       .suspend = hw_suspend,
+       .resume = hw_resume,
+#endif
 
        .src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk,
        .src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk,
index 666722d9de41ae0afca3b9378a24b6175bd27bbd..f26d7cd9db9f531a94ad28a16ff8d84f31c77cea 100644 (file)
@@ -462,6 +462,43 @@ do_digit_io_switch(struct ct_atc *atc, int state)
        return;
 }
 
+static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
+{
+       struct ct_mixer *mixer = atc->mixer;
+
+       /* Do changes in mixer. */
+       if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) {
+               if (state) {
+                       ct_mixer_recording_select(mixer,
+                                                 get_amixer_index(type));
+               } else {
+                       ct_mixer_recording_unselect(mixer,
+                                                   get_amixer_index(type));
+               }
+       }
+       /* Do changes out of mixer. */
+       if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type))
+               do_line_mic_switch(atc, type);
+       else if (MIXER_WAVEF_P_S == type)
+               atc->line_front_unmute(atc, state);
+       else if (MIXER_WAVES_P_S == type)
+               atc->line_surround_unmute(atc, state);
+       else if (MIXER_WAVEC_P_S == type)
+               atc->line_clfe_unmute(atc, state);
+       else if (MIXER_WAVER_P_S == type)
+               atc->line_rear_unmute(atc, state);
+       else if (MIXER_LINEIN_P_S == type)
+               atc->line_in_unmute(atc, state);
+       else if (MIXER_SPDIFO_P_S == type)
+               atc->spdif_out_unmute(atc, state);
+       else if (MIXER_SPDIFI_P_S == type)
+               atc->spdif_in_unmute(atc, state);
+       else if (MIXER_DIGITAL_IO_S == type)
+               do_digit_io_switch(atc, state);
+
+       return;
+}
+
 static int ct_alsa_mix_switch_info(struct snd_kcontrol *kcontrol,
                                   struct snd_ctl_elem_info *uinfo)
 {
@@ -498,35 +535,7 @@ static int ct_alsa_mix_switch_put(struct snd_kcontrol *kcontrol,
                return 0;
 
        set_switch_state(mixer, type, state);
-       /* Do changes in mixer. */
-       if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) {
-               if (state) {
-                       ct_mixer_recording_select(mixer,
-                                                 get_amixer_index(type));
-               } else {
-                       ct_mixer_recording_unselect(mixer,
-                                                   get_amixer_index(type));
-               }
-       }
-       /* Do changes out of mixer. */
-       if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type))
-               do_line_mic_switch(atc, type);
-       else if (MIXER_WAVEF_P_S == type)
-               atc->line_front_unmute(atc, state);
-       else if (MIXER_WAVES_P_S == type)
-               atc->line_surround_unmute(atc, state);
-       else if (MIXER_WAVEC_P_S == type)
-               atc->line_clfe_unmute(atc, state);
-       else if (MIXER_WAVER_P_S == type)
-               atc->line_rear_unmute(atc, state);
-       else if (MIXER_LINEIN_P_S == type)
-               atc->line_in_unmute(atc, state);
-       else if (MIXER_SPDIFO_P_S == type)
-               atc->spdif_out_unmute(atc, state);
-       else if (MIXER_SPDIFI_P_S == type)
-               atc->spdif_in_unmute(atc, state);
-       else if (MIXER_DIGITAL_IO_S == type)
-               do_digit_io_switch(atc, state);
+       do_switch(atc, type, state);
 
        return 1;
 }
@@ -1039,6 +1048,28 @@ mixer_set_input_right(struct ct_mixer *mixer,
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int mixer_resume(struct ct_mixer *mixer)
+{
+       int i, state;
+       struct amixer *amixer;
+
+       /* resume topology and volume gain. */
+       for (i = 0; i < NUM_CT_AMIXERS*CHN_NUM; i++) {
+               amixer = mixer->amixers[i];
+               amixer->ops->commit_write(amixer);
+       }
+
+       /* resume switch state. */
+       for (i = SWH_MIXER_START; i <= SWH_MIXER_END; i++) {
+               state = get_switch_state(mixer, i);
+               do_switch(mixer->atc, i, state);
+       }
+
+       return 0;
+}
+#endif
+
 int ct_mixer_destroy(struct ct_mixer *mixer)
 {
        struct sum_mgr *sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM];
@@ -1087,6 +1118,9 @@ int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer)
        mixer->get_output_ports = mixer_get_output_ports;
        mixer->set_input_left = mixer_set_input_left;
        mixer->set_input_right = mixer_set_input_right;
+#ifdef CONFIG_PM
+       mixer->resume = mixer_resume;
+#endif
 
        /* Allocate chip resources for mixer obj */
        err = ct_mixer_get_resources(mixer);
index e2d96ebde7460e39bb5ac71925a874f1eec90a73..b009e989e77ddcef32cc8451c8eb8b99102f67c0 100644 (file)
@@ -56,6 +56,9 @@ struct ct_mixer {
                              enum MIXER_PORT_T type, struct rsc *rsc);
        int (*set_input_right)(struct ct_mixer *mixer,
                               enum MIXER_PORT_T type, struct rsc *rsc);
+#ifdef CONFIG_PM
+       int (*resume)(struct ct_mixer *mixer);
+#endif
 };
 
 int ct_alsa_mix_create(struct ct_atc *atc,
index 9e5c0c4da7261166faa9659bbef57fd35f90c678..60ea23180acbe1f91443f5ad15b8939ec812698c 100644 (file)
@@ -422,5 +422,9 @@ int ct_alsa_pcm_create(struct ct_atc *atc,
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
                        snd_dma_pci_data(atc->pci), 128*1024, 128*1024);
 
+#ifdef CONFIG_PM
+       atc->pcms[device] = pcm;
+#endif
+
        return 0;
 }
index 2d3dd89af151d3d7de7927d79f6d76fc0bc2edf3..76541748e7bcf8ec43ccd5964d90faf4258f442a 100644 (file)
@@ -121,11 +121,33 @@ static void __devexit ct_card_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
+#ifdef CONFIG_PM
+static int ct_card_suspend(struct pci_dev *pci, pm_message_t state)
+{
+       struct snd_card *card = pci_get_drvdata(pci);
+       struct ct_atc *atc = card->private_data;
+
+       return atc->suspend(atc, state);
+}
+
+static int ct_card_resume(struct pci_dev *pci)
+{
+       struct snd_card *card = pci_get_drvdata(pci);
+       struct ct_atc *atc = card->private_data;
+
+       return atc->resume(atc);
+}
+#endif
+
 static struct pci_driver ct_driver = {
        .name = "SB-XFi",
        .id_table = ct_pci_dev_ids,
        .probe = ct_card_probe,
        .remove = __devexit_p(ct_card_remove),
+#ifdef CONFIG_PM
+       .suspend = ct_card_suspend,
+       .resume = ct_card_resume,
+#endif
 };
 
 static int __init ct_card_init(void)
index c710150d5065d8257c52d38a096e0e80e4d97a7e..04438f1d682dd22f4f24b2e9b518a0d158fdcf97 100644 (file)
@@ -2,7 +2,6 @@ menuconfig SND_HDA_INTEL
        tristate "Intel HD Audio"
        select SND_PCM
        select SND_VMASTER
-       select SND_JACK if INPUT=y || INPUT=SND
        help
          Say Y here to include support for Intel "High Definition
          Audio" (Azalia) and its compatible devices.
@@ -39,6 +38,14 @@ config SND_HDA_INPUT_BEEP
          Say Y here to build a digital beep interface for HD-audio
          driver. This interface is used to generate digital beeps.
 
+config SND_HDA_INPUT_JACK
+       bool "Support jack plugging notification via input layer"
+       depends on INPUT=y || INPUT=SND_HDA_INTEL
+       select SND_JACK
+       help
+         Say Y here to enable the jack plugging notification via
+         input layer.
+
 config SND_HDA_CODEC_REALTEK
        bool "Build Realtek HD-audio codec support"
        default y
index 4fcbe21829abfe27104f7dabeed8fb801a301537..ac868c59f9e334ad0dad50b00f0bb77b9bf59cdb 100644 (file)
@@ -349,7 +349,7 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
                                     &spec->cur_mux[adc_idx]);
 }
 
-#ifdef CONFIG_SND_JACK
+#ifdef CONFIG_SND_HDA_INPUT_JACK
 static void conexant_free_jack_priv(struct snd_jack *jack)
 {
        struct conexant_jack *jacks = jack->private_data;
@@ -463,7 +463,7 @@ static int conexant_init(struct hda_codec *codec)
 
 static void conexant_free(struct hda_codec *codec)
 {
-#ifdef CONFIG_SND_JACK
+#ifdef CONFIG_SND_HDA_INPUT_JACK
        struct conexant_spec *spec = codec->spec;
        if (spec->jacks.list) {
                struct conexant_jack *jacks = spec->jacks.list;
index bf4b78a74a8fec9e4437a74c9d9e097235dc643c..33453319742508251d3b9a96d2ca1c26312cdcd8 100644 (file)
@@ -250,13 +250,6 @@ enum {
        ALC883_MODEL_LAST,
 };
 
-/* styles of capture selection */
-enum {
-       CAPT_MUX = 0,   /* only mux based */
-       CAPT_MIX,       /* only mixer based */
-       CAPT_1MUX_MIX,  /* first mux and other mixers */
-};
-
 /* for GPIO Poll */
 #define GPIO_MASK      0x03
 
@@ -306,7 +299,6 @@ struct alc_spec {
        hda_nid_t *adc_nids;
        hda_nid_t *capsrc_nids;
        hda_nid_t dig_in_nid;           /* digital-in NID; optional */
-       int capture_style;              /* capture style (CAPT_*) */
 
        /* capture source */
        unsigned int num_mux_defs;
@@ -420,12 +412,13 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
        unsigned int mux_idx;
        hda_nid_t nid = spec->capsrc_nids ?
                spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
+       unsigned int type;
 
        mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
        imux = &spec->input_mux[mux_idx];
 
-       if (spec->capture_style &&
-           !(spec->capture_style == CAPT_1MUX_MIX && !adc_idx)) {
+       type = (get_wcaps(codec, nid) & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+       if (type == AC_WID_AUD_MIX) {
                /* Matrix-mixer style (e.g. ALC882) */
                unsigned int *cur_val = &spec->cur_mux[adc_idx];
                unsigned int i, idx;
@@ -7557,7 +7550,6 @@ static int patch_alc882(struct hda_codec *codec)
        spec->stream_digital_playback = &alc882_pcm_digital_playback;
        spec->stream_digital_capture = &alc882_pcm_digital_capture;
 
-       spec->capture_style = CAPT_MIX; /* matrix-style capture */
        if (!spec->adc_nids && spec->input_mux) {
                /* check whether NID 0x07 is valid */
                unsigned int wcap = get_wcaps(codec, 0x07);
@@ -9781,7 +9773,6 @@ static int patch_alc883(struct hda_codec *codec)
                }
                if (!spec->capsrc_nids)
                        spec->capsrc_nids = alc883_capsrc_nids;
-               spec->capture_style = CAPT_MIX; /* matrix-style capture */
                spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */
                break;
        case 0x10ec0889:
@@ -9791,8 +9782,6 @@ static int patch_alc883(struct hda_codec *codec)
                }
                if (!spec->capsrc_nids)
                        spec->capsrc_nids = alc889_capsrc_nids;
-               spec->capture_style = CAPT_1MUX_MIX; /* 1mux/Nmix-style
-                                                       capture */
                break;
        default:
                if (!spec->num_adc_nids) {
@@ -9801,7 +9790,6 @@ static int patch_alc883(struct hda_codec *codec)
                }
                if (!spec->capsrc_nids)
                        spec->capsrc_nids = alc883_capsrc_nids;
-               spec->capture_style = CAPT_MIX; /* matrix-style capture */
                break;
        }
 
@@ -10913,9 +10901,27 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
        return 0;
 }
 
-/* identical with ALC880 */
-#define alc262_auto_create_analog_input_ctls \
-       alc880_auto_create_analog_input_ctls
+static int alc262_auto_create_analog_input_ctls(struct alc_spec *spec,
+                                               const struct auto_pin_cfg *cfg)
+{
+       int err;
+
+       err = alc880_auto_create_analog_input_ctls(spec, cfg);
+       if (err < 0)
+               return err;
+       /* digital-mic input pin is excluded in alc880_auto_create..()
+        * because it's under 0x18
+        */
+       if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
+           cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
+               struct hda_input_mux *imux = &spec->private_imux[0];
+               imux->items[imux->num_items].label = "Int Mic";
+               imux->items[imux->num_items].index = 0x09;
+               imux->num_items++;
+       }
+       return 0;
+}
+
 
 /*
  * generic initialization of ADC, input mixers and output mixers
@@ -11332,6 +11338,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
        SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
        SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
        SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
+       SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
        SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
                           ALC262_SONY_ASSAMD),
        SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
@@ -11539,6 +11546,7 @@ static struct alc_config_preset alc262_presets[] = {
                .capsrc_nids = alc262_dmic_capsrc_nids,
                .dac_nids = alc262_dac_nids,
                .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
+               .num_adc_nids = 1, /* single ADC */
                .dig_out_nid = ALC262_DIGOUT_NID,
                .num_channel_mode = ARRAY_SIZE(alc262_modes),
                .channel_mode = alc262_modes,
@@ -11640,21 +11648,36 @@ static int patch_alc262(struct hda_codec *codec)
        spec->stream_digital_playback = &alc262_pcm_digital_playback;
        spec->stream_digital_capture = &alc262_pcm_digital_capture;
 
-       spec->capture_style = CAPT_MIX;
        if (!spec->adc_nids && spec->input_mux) {
-               /* check whether NID 0x07 is valid */
-               unsigned int wcap = get_wcaps(codec, 0x07);
-
-               /* get type */
-               wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
-               if (wcap != AC_WID_AUD_IN) {
-                       spec->adc_nids = alc262_adc_nids_alt;
-                       spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
-                       spec->capsrc_nids = alc262_capsrc_nids_alt;
+               int i;
+               /* check whether the digital-mic has to be supported */
+               for (i = 0; i < spec->input_mux->num_items; i++) {
+                       if (spec->input_mux->items[i].index >= 9)
+                               break;
+               }
+               if (i < spec->input_mux->num_items) {
+                       /* use only ADC0 */
+                       spec->adc_nids = alc262_dmic_adc_nids;
+                       spec->num_adc_nids = 1;
+                       spec->capsrc_nids = alc262_dmic_capsrc_nids;
                } else {
-                       spec->adc_nids = alc262_adc_nids;
-                       spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
-                       spec->capsrc_nids = alc262_capsrc_nids;
+                       /* all analog inputs */
+                       /* check whether NID 0x07 is valid */
+                       unsigned int wcap = get_wcaps(codec, 0x07);
+
+                       /* get type */
+                       wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+                       if (wcap != AC_WID_AUD_IN) {
+                               spec->adc_nids = alc262_adc_nids_alt;
+                               spec->num_adc_nids =
+                                       ARRAY_SIZE(alc262_adc_nids_alt);
+                               spec->capsrc_nids = alc262_capsrc_nids_alt;
+                       } else {
+                               spec->adc_nids = alc262_adc_nids;
+                               spec->num_adc_nids =
+                                       ARRAY_SIZE(alc262_adc_nids);
+                               spec->capsrc_nids = alc262_capsrc_nids;
+                       }
                }
        }
        if (!spec->cap_mixer && !spec->no_analog)
@@ -13244,26 +13267,8 @@ static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
        return 0;
 }
 
-static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec,
-                                               const struct auto_pin_cfg *cfg)
-{
-       int err;
-
-       err = alc880_auto_create_analog_input_ctls(spec, cfg);
-       if (err < 0)
-               return err;
-       /* digital-mic input pin is excluded in alc880_auto_create..()
-        * because it's under 0x18
-        */
-       if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
-           cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
-               struct hda_input_mux *imux = &spec->private_imux[0];
-               imux->items[imux->num_items].label = "Int Mic";
-               imux->items[imux->num_items].index = 0x05;
-               imux->num_items++;
-       }
-       return 0;
-}
+#define alc269_auto_create_analog_input_ctls \
+       alc262_auto_create_analog_input_ctls
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #define alc269_loopbacks       alc880_loopbacks
@@ -15554,7 +15559,6 @@ static int patch_alc861vd(struct hda_codec *codec)
        spec->adc_nids = alc861vd_adc_nids;
        spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
        spec->capsrc_nids = alc861vd_capsrc_nids;
-       spec->capture_style = CAPT_MIX;
 
        set_capture_mixer(spec);
        set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
@@ -17474,7 +17478,6 @@ static int patch_alc662(struct hda_codec *codec)
        spec->adc_nids = alc662_adc_nids;
        spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
        spec->capsrc_nids = alc662_capsrc_nids;
-       spec->capture_style = CAPT_MIX;
 
        if (!spec->cap_mixer)
                set_capture_mixer(spec);
index 93e47c96a38bce1800a9df2dbfff5aaa85fd7b47..14f3c3e0f62dec7618b97b7d5872148da9d02ef3 100644 (file)
@@ -639,7 +639,7 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
 static unsigned int stac92xx_vref_set(struct hda_codec *codec,
                                        hda_nid_t nid, unsigned int new_vref)
 {
-       unsigned int error;
+       int error;
        unsigned int pincfg;
        pincfg = snd_hda_codec_read(codec, nid, 0,
                                AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
@@ -2703,7 +2703,7 @@ static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        unsigned int new_vref = 0;
-       unsigned int error;
+       int error;
        hda_nid_t nid = kcontrol->private_value;
 
        if (ucontrol->value.enumerated.item[0] == 0)
@@ -4035,7 +4035,7 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
                           AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
 }
 
-#ifdef CONFIG_SND_JACK
+#ifdef CONFIG_SND_HDA_INPUT_JACK
 static void stac92xx_free_jack_priv(struct snd_jack *jack)
 {
        struct sigmatel_jack *jacks = jack->private_data;
@@ -4047,7 +4047,7 @@ static void stac92xx_free_jack_priv(struct snd_jack *jack)
 static int stac92xx_add_jack(struct hda_codec *codec,
                hda_nid_t nid, int type)
 {
-#ifdef CONFIG_SND_JACK
+#ifdef CONFIG_SND_HDA_INPUT_JACK
        struct sigmatel_spec *spec = codec->spec;
        struct sigmatel_jack *jack;
        int def_conf = snd_hda_codec_get_pincfg(codec, nid);
@@ -4336,7 +4336,7 @@ static int stac92xx_init(struct hda_codec *codec)
 
 static void stac92xx_free_jacks(struct hda_codec *codec)
 {
-#ifdef CONFIG_SND_JACK
+#ifdef CONFIG_SND_HDA_INPUT_JACK
        /* free jack instances manually when clearing/reconfiguring */
        struct sigmatel_spec *spec = codec->spec;
        if (!codec->bus->shutdown && spec->jacks.list) {
index 1ef58c51c21343c6d7721b5dedfa6c91ddc4071c..949fcaf6b70ed9454ecd373ec052e8e7b7800fc9 100644 (file)
@@ -85,6 +85,7 @@ static int joystick;
 static int ac97_clock = 48000;
 static char *ac97_quirk;
 static int dxs_support;
+static int nodelay;
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for VIA 82xx bridge.");
@@ -102,6 +103,8 @@ module_param(ac97_quirk, charp, 0444);
 MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
 module_param(dxs_support, int, 0444);
 MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA, 5 = enable any sample rate)");
+module_param(nodelay, int, 0444);
+MODULE_PARM_DESC(nodelay, "Disable 500ms init delay");
 
 /* just for backward compatibility */
 static int enable;
@@ -549,7 +552,8 @@ static void snd_via82xx_codec_wait(struct snd_ac97 *ac97)
        int err;
        err = snd_via82xx_codec_ready(chip, ac97->num);
        /* here we need to wait fairly for long time.. */
-       msleep(500);
+       if (!nodelay)
+               msleep(500);
 }
 
 static void snd_via82xx_codec_write(struct snd_ac97 *ac97,
index 964824419678bfe361b77bab3ce538eb7af6bc38..af06904bab0f8411285fec191995499ffc8effde 100644 (file)
@@ -50,6 +50,7 @@ struct bf5xx_i2s_port {
        u16 tcr2;
        u16 rcr2;
        int counter;
+       int configured;
 };
 
 static struct bf5xx_i2s_port bf5xx_i2s;
@@ -168,7 +169,7 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       if (bf5xx_i2s.counter == 1) {
+       if (!bf5xx_i2s.configured) {
                /*
                 * TX and RX are not independent,they are enabled at the
                 * same time, even if only one side is running. So, we
@@ -177,6 +178,7 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
                 *
                 * CPU DAI:slave mode.
                 */
+               bf5xx_i2s.configured = 1;
                ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1,
                                      bf5xx_i2s.rcr2, 0, 0);
                if (ret) {
@@ -200,6 +202,9 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
 {
        pr_debug("%s enter\n", __func__);
        bf5xx_i2s.counter--;
+       /* No active stream, SPORT is allowed to be configured again. */
+       if (!bf5xx_i2s.counter)
+               bf5xx_i2s.configured = 0;
 }
 
 static int bf5xx_i2s_probe(struct platform_device *pdev,
@@ -244,8 +249,7 @@ static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
        return 0;
 }
 
-static int bf5xx_i2s_resume(struct platform_device *pdev,
-                           struct snd_soc_dai *dai)
+static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
 {
        int ret;
        struct sport_device *sport =